Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/clients.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Client } from "@notionhq/client";
import { assertWorkspaceScope, getAccountId, DEFAULT_ACCOUNT_ID } from "./context.js";
import { getAccountToken, ensureAccountToken, onAccountTokensInvalidated } from "./account-tokens.js";
import { NOTION_API_VERSION } from "./notion-version.js";

// PAT tokens — used for ALL operations except /v1/search.
// PATs inherit the creator user's permissions (full read/write by ID) but
Expand Down Expand Up @@ -58,9 +59,9 @@ if (bearerToken && bearerToken.length < 32) {
process.exit(1);
}

// Notion API version. 2025-09-03 unlocks multi-source databases,
// data_sources endpoints, comments threading, and file uploads.
export const NOTION_API_VERSION = "2025-09-03";
// Notion API version: single source of truth in notion-version.ts. Re-exported
// here for the many call sites that already import it from clients.ts.
export { NOTION_API_VERSION };

// PAT clients (default — used everywhere except search).
export const globalcriptoClient = new Client({
Expand Down
4 changes: 1 addition & 3 deletions src/notion-oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import { invalidateAccountTokens } from "./account-tokens.js";
const AUTHORIZE_URL = "https://api.notion.com/v1/oauth/authorize";
const TOKEN_URL = "https://api.notion.com/v1/oauth/token";
const ME_URL = "https://api.notion.com/v1/users/me";
// Keep in sync with NOTION_API_VERSION in clients.ts (not imported — clients.ts
// process.exit()s at load when NOTION_*_TOKEN are unset, which breaks unit tests).
const NOTION_VERSION = "2025-09-03";
import { NOTION_API_VERSION as NOTION_VERSION } from "./notion-version.js";

/** Stable account id for a connected Notion workspace (P1: account = a Notion
* OAuth identity). Prefixed so it never collides with the built-in 'bruno'. */
Expand Down
8 changes: 8 additions & 0 deletions src/notion-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// src/notion-version.ts
// Single source of truth for the pinned Notion API version. Lives in its own
// side-effect-free module (no env validation, no client construction) so any
// file can import it WITHOUT pulling clients.ts's import-time env checks — which
// is exactly why several modules used to redeclare the literal "2025-09-03".
//
// 2025-09-03: multi-source databases, file uploads, comments, schema PATCH.
export const NOTION_API_VERSION = "2025-09-03";
2 changes: 1 addition & 1 deletion src/portal/task-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import {
type Detection,
type DataSourceLite,
} from "./task-tracker-schema.js";
import { NOTION_API_VERSION as NOTION_VERSION } from "../notion-version.js";

const NOTION_VERSION = "2025-09-03"; // manter em sincronia com clients.ts
const NOTION_API = "https://api.notion.com";
const TASKS_DB_KIND = "tasks_db";
// Quantas data sources inspecionar (1 GET de schema cada) na detecção. Bound de
Expand Down
46 changes: 0 additions & 46 deletions src/rag/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,47 +177,6 @@ function maxPerUrlConfig(): number {
return Number.isFinite(v) ? v : 3;
}

/**
* Optional recency boost applied AFTER reranking (or after RRF fallback).
* Controlled by RECENCY_BOOST env var (default "off" / 0).
*
* Formula: final_score = score * (1 + beta * exp(-age_days / halflife))
* beta = RECENCY_BOOST (e.g. 0.15 → max +15% for today's docs)
* halflife = RECENCY_HALFLIFE_DAYS (default 30)
* age_days derived from chunk.metadata.data (ISO date string) or source_updated.
*
* With RECENCY_BOOST=0 (or unset) returns hits unchanged — zero cost.
* Positive beta boosts recent content; negative beta penalizes it (unusual).
*/
export function recencyBoostEnabled(): boolean {
const v = Number(process.env.RECENCY_BOOST);
return Number.isFinite(v) && v !== 0;
}

export function applyRecencyBoost(hits: SearchHit[], now: Date = new Date()): SearchHit[] {
const beta = Number(process.env.RECENCY_BOOST);
if (!Number.isFinite(beta) || beta === 0) return hits;
const halflife = Number(process.env.RECENCY_HALFLIFE_DAYS ?? 30);
const hl = Number.isFinite(halflife) && halflife > 0 ? halflife : 30;
// ln(2)/halflife is the decay constant for exp(-age * lambda)
const lambda = Math.LN2 / hl;

const boosted = hits.map((h) => {
const dateStr =
(typeof h.chunk.metadata?.data === "string" ? h.chunk.metadata.data : undefined) ??
(h.chunk.source_updated instanceof Date ? h.chunk.source_updated.toISOString() : undefined);
if (!dateStr) return h;
const docDate = new Date(dateStr);
if (isNaN(docDate.getTime())) return h;
const ageDays = Math.max(0, (now.getTime() - docDate.getTime()) / 86_400_000);
const boost = 1 + beta * Math.exp(-ageDays * lambda);
return { ...h, score: h.score * boost };
});

// Re-sort by boosted score (recency may reorder).
return boosted.sort((a, b) => b.score - a.score);
}

/**
* Query-time result diversification. Iterates `hits` in their given (already
* ranked) order and KEEPS a hit unless:
Expand Down Expand Up @@ -426,11 +385,6 @@ export async function brainSearch(
}
}

// Optional recency boost (RECENCY_BOOST env, default off). Applied after all
// ranking/diversification so it can only reorder within the already-diversified
// topK set, not expand it. Zero cost when RECENCY_BOOST=0 or unset.
hits = applyRecencyBoost(hits);

// 002-app-v2 — AI search transparency log. Companion to the recordUsage
// metering above, but appended AFTER the hits are computed so the row carries
// the real result count. Only in-request searches are logged (cron/eval have
Expand Down
2 changes: 1 addition & 1 deletion src/tasks/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import {
type CanonicalPriority,
type CanonicalField,
} from "./model.js";
import { NOTION_API_VERSION as NOTION_VERSION } from "../notion-version.js";

const NOTION_API = "https://api.notion.com";
const NOTION_VERSION = "2025-09-03"; // keep in sync with clients.ts

/** The owner's Tasks Tracker data_source (workspace 'personal') — formerly
* hardcoded in briefing/daily-briefing.ts:31. Now ONLY a safety net used when
Expand Down
Loading