From d12681b79fc19d9b08f27038ee176a6a7faf4ae6 Mon Sep 17 00:00:00 2001 From: Roberto Musso Date: Sat, 28 Feb 2026 09:40:00 +0100 Subject: [PATCH] =?UTF-8?q?feat(floating-ai):=20step=206=20=E2=80=94=20pas?= =?UTF-8?q?s=20uiContext=20through=20to=20the=20AI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- docs/floating-ai-integration-guide.md | 2 +- src/main/ai/orchestrator.ts | 25 ++++++++++++++----------- src/main/router/index.ts | 1 + 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/docs/floating-ai-integration-guide.md b/docs/floating-ai-integration-guide.md index 8371f87..8bda8e0 100644 --- a/docs/floating-ai-integration-guide.md +++ b/docs/floating-ai-integration-guide.md @@ -740,7 +740,7 @@ currentSender = sender; ## Step 6: Pass `uiContext` Through to the AI -**Status**: [ ] +**Status**: [x] (2026-02-28) **Prerequisites**: Step 5 completed **Modifies**: - `src/main/router/index.ts` (line ~550-556) diff --git a/src/main/ai/orchestrator.ts b/src/main/ai/orchestrator.ts index 598da6d..eef4089 100644 --- a/src/main/ai/orchestrator.ts +++ b/src/main/ai/orchestrator.ts @@ -35,7 +35,7 @@ let currentSender: Electron.WebContents | undefined; export interface OrchestrateInput { message: string; - context: { type: 'global' | 'project'; projectId?: string }; + context: { type: 'global' | 'project'; projectId?: string; uiContext?: string }; sender?: Electron.WebContents; } @@ -445,7 +445,7 @@ function buildKnowledgeTools(): StructuredTool[] { // System prompts // --------------------------------------------------------------------------- -function makeProjectAgentPrompt(contextData: string, withTools = true): string { +function makeProjectAgentPrompt(contextData: string, withTools = true, uiContext?: string): string { const toolsSection = withTools ? ` You also have access to the following tools — use them proactively when appropriate: - read_project_notes: Fetch full untruncated note content. Use for detailed note questions. @@ -464,10 +464,10 @@ ${contextData} ${toolsSection} Answer the user's question based on this project context. Be concise and helpful. When referencing tasks, notes, or checkpoints, mention them by name. -If you don't have enough information, say so.`; +If you don't have enough information, say so.${uiContext ? `\nThe user is currently viewing the "${uiContext}" section of the UI.\nIf your response relates to a different section (e.g., user asks about checkpoints while viewing Tasks), prefix your response with [SECTION:] where section-id matches one of: project-summary, project-timeline, project-tasks, project-notes, tasks-overview, tasks-list, timeline-chart, note-editor.\nOnly use this prefix when the answer clearly belongs in a different section than where the user currently is.` : ''}`; } -function makeGeneralAgentPrompt(contextData: string, withTools = true): string { +function makeGeneralAgentPrompt(contextData: string, withTools = true, uiContext?: string): string { const toolsSection = withTools ? ` You also have access to the following tools — use them proactively when appropriate: - add_task: Create a new task. Use whenever the user asks to add, register, or note a to-do item or task. @@ -481,10 +481,10 @@ You have access to the following workspace data: ${contextData} ${toolsSection} Help the user with their question based on this workspace context. Provide concise, actionable answers. -When discussing tasks or projects, reference them by name.`; +When discussing tasks or projects, reference them by name.${uiContext ? `\nThe user is currently viewing the "${uiContext}" section of the UI.\nIf your response relates to a different section (e.g., user asks about checkpoints while viewing Tasks), prefix your response with [SECTION:] where section-id matches one of: project-summary, project-timeline, project-tasks, project-notes, tasks-overview, tasks-list, timeline-chart, note-editor.\nOnly use this prefix when the answer clearly belongs in a different section than where the user currently is.` : ''}`; } -function makeKnowledgeAgentPrompt(contextData: string, withTools = true): string { +function makeKnowledgeAgentPrompt(contextData: string, withTools = true, uiContext?: string): string { const toolsSection = withTools ? ` You have access to the following tools — use them proactively: - vector_search_all: Performs semantic search across ALL project notes. Always use this tool when the user asks a knowledge question. Pass the user's question (or a refined version) as the query. @@ -504,7 +504,7 @@ ${contextData} ${toolsSection} Your primary job is to find and synthesize information from notes across all projects. Always use the vector_search_all tool to search for relevant notes before answering. -If no results are found, say so clearly.`; +If no results are found, say so clearly.${uiContext ? `\nThe user is currently viewing the "${uiContext}" section of the UI.\nIf your response relates to a different section (e.g., user asks about checkpoints while viewing Tasks), prefix your response with [SECTION:] where section-id matches one of: project-summary, project-timeline, project-tasks, project-notes, tasks-overview, tasks-list, timeline-chart, note-editor.\nOnly use this prefix when the answer clearly belongs in a different section than where the user currently is.` : ''}`; } // --------------------------------------------------------------------------- @@ -515,7 +515,7 @@ const OrchestratorState = Annotation.Root({ /** The user's original message */ userMessage: Annotation(), /** Chat context (global vs project-scoped) */ - chatContext: Annotation<{ type: 'global' | 'project'; projectId?: string }>(), + chatContext: Annotation<{ type: 'global' | 'project'; projectId?: string; uiContext?: string }>(), /** The route chosen by the orchestrator */ route: Annotation<'project' | 'knowledge' | 'general'>(), /** Messages for the specialist agent */ @@ -583,7 +583,8 @@ async function projectAgent(state: State): Promise> { // Including text tool descriptions in the system prompt causes the model to output // XML blocks instead of using the SDK's API-level mechanism. const includeToolsInPrompt = supportsTools && getActiveProviderName() !== 'copilot'; - const systemPrompt = makeProjectAgentPrompt(contextData, includeToolsInPrompt); + const uiContext = state.chatContext.uiContext; + const systemPrompt = makeProjectAgentPrompt(contextData, includeToolsInPrompt, uiContext); if (!supportsTools) { console.log('[Orchestrator] projectAgent: using context-only fallback (no tool support)'); @@ -671,7 +672,8 @@ async function knowledgeAgent(state: State): Promise> { const supportsTools = TOOL_CALLING_PROVIDERS.has(getActiveProviderName()); const includeToolsInPrompt = supportsTools && getActiveProviderName() !== 'copilot'; - const systemPrompt = makeKnowledgeAgentPrompt(contextData, includeToolsInPrompt); + const uiContext = state.chatContext.uiContext; + const systemPrompt = makeKnowledgeAgentPrompt(contextData, includeToolsInPrompt, uiContext); console.log(`[Orchestrator] knowledgeAgent: provider="${getActiveProviderName()}", supportsTools=${supportsTools}`); @@ -749,7 +751,8 @@ async function generalAgent(state: State): Promise> { const supportsTools = TOOL_CALLING_PROVIDERS.has(getActiveProviderName()); const includeToolsInPrompt = supportsTools && getActiveProviderName() !== 'copilot'; - const systemPrompt = makeGeneralAgentPrompt(contextData, includeToolsInPrompt); + const uiContext = state.chatContext.uiContext; + const systemPrompt = makeGeneralAgentPrompt(contextData, includeToolsInPrompt, uiContext); console.log(`[Orchestrator] generalAgent: provider="${getActiveProviderName()}", supportsTools=${supportsTools}`); diff --git a/src/main/router/index.ts b/src/main/router/index.ts index 85c2c48..39967e2 100644 --- a/src/main/router/index.ts +++ b/src/main/router/index.ts @@ -552,6 +552,7 @@ const aiRouter = router({ context: z.object({ type: z.enum(['global', 'project']), projectId: z.string().optional(), + uiContext: z.string().optional(), }), })) .mutation(async ({ input, ctx }) => {