diff --git a/apps/server/src/core/ai-chat/ai-chat.service.ts b/apps/server/src/core/ai-chat/ai-chat.service.ts index 4c4bc6f4..1c671bb0 100644 --- a/apps/server/src/core/ai-chat/ai-chat.service.ts +++ b/apps/server/src/core/ai-chat/ai-chat.service.ts @@ -257,6 +257,9 @@ export class AiChatService { sessionId, workspace.id, chatId, + // Same open-page value used by the system prompt above; exposed to the + // model via getCurrentPage so page identity survives prompt mangling. + body.openPage, ); // Merge in admin-configured external MCP tools (web search, etc.; §6.8). diff --git a/apps/server/src/core/ai-chat/tools/ai-chat-tools.service.ts b/apps/server/src/core/ai-chat/tools/ai-chat-tools.service.ts index ef7dae56..038e2544 100644 --- a/apps/server/src/core/ai-chat/tools/ai-chat-tools.service.ts +++ b/apps/server/src/core/ai-chat/tools/ai-chat-tools.service.ts @@ -50,6 +50,11 @@ export class AiChatToolsService { // agent write (REST + collab) records { actor:'agent', aiChatId } off a // SIGNED claim — non-spoofable, never a client body field (§6.5/§6.6). aiChatId: string, + // The page the user currently has open (from the request context), exposed + // to the model via getCurrentPage. Optional and last so existing callers + // keep compiling. Kept proxy-robust: the model can CALL for the current + // page instead of relying on it surviving in the system prompt text. + openedPage?: { id?: string; title?: string } | null, ): Promise> { const apiUrl = process.env.MCP_DOCMOST_API_URL || @@ -210,6 +215,23 @@ export class AiChatToolsService { }, }), + getCurrentPage: tool({ + description: + 'Return the page the user is currently viewing — i.e. what "this page", ' + + '"the current page", or "here" refers to. Returns the page id and title, ' + + 'or null if the user is not currently on a page. Call this first whenever ' + + 'the user refers to the current page without giving an explicit id.', + inputSchema: z.object({}), + execute: async () => { + if (!openedPage?.id) { + return { page: null }; + } + return { + page: { id: openedPage.id, title: openedPage.title ?? '' }, + }; + }, + }), + getPage: tool({ description: 'Fetch a single page as Markdown by its page id. Returns the page ' +