feat(floating-ai): step 6 — pass uiContext through to the AI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -740,7 +740,7 @@ currentSender = sender;
|
|||||||
|
|
||||||
## Step 6: Pass `uiContext` Through to the AI
|
## Step 6: Pass `uiContext` Through to the AI
|
||||||
|
|
||||||
**Status**: [ ]
|
**Status**: [x] (2026-02-28)
|
||||||
**Prerequisites**: Step 5 completed
|
**Prerequisites**: Step 5 completed
|
||||||
**Modifies**:
|
**Modifies**:
|
||||||
- `src/main/router/index.ts` (line ~550-556)
|
- `src/main/router/index.ts` (line ~550-556)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ let currentSender: Electron.WebContents | undefined;
|
|||||||
|
|
||||||
export interface OrchestrateInput {
|
export interface OrchestrateInput {
|
||||||
message: string;
|
message: string;
|
||||||
context: { type: 'global' | 'project'; projectId?: string };
|
context: { type: 'global' | 'project'; projectId?: string; uiContext?: string };
|
||||||
sender?: Electron.WebContents;
|
sender?: Electron.WebContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,7 +445,7 @@ function buildKnowledgeTools(): StructuredTool[] {
|
|||||||
// System prompts
|
// System prompts
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function makeProjectAgentPrompt(contextData: string, withTools = true): string {
|
function makeProjectAgentPrompt(contextData: string, withTools = true, uiContext?: string): string {
|
||||||
const toolsSection = withTools ? `
|
const toolsSection = withTools ? `
|
||||||
You also have access to the following tools — use them proactively when appropriate:
|
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.
|
- read_project_notes: Fetch full untruncated note content. Use for detailed note questions.
|
||||||
@@ -464,10 +464,10 @@ ${contextData}
|
|||||||
${toolsSection}
|
${toolsSection}
|
||||||
Answer the user's question based on this project context. Be concise and helpful.
|
Answer the user's question based on this project context. Be concise and helpful.
|
||||||
When referencing tasks, notes, or checkpoints, mention them by name.
|
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:<section-id>] 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 ? `
|
const toolsSection = withTools ? `
|
||||||
You also have access to the following tools — use them proactively when appropriate:
|
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.
|
- 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}
|
${contextData}
|
||||||
${toolsSection}
|
${toolsSection}
|
||||||
Help the user with their question based on this workspace context. Provide concise, actionable answers.
|
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:<section-id>] 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 ? `
|
const toolsSection = withTools ? `
|
||||||
You have access to the following tools — use them proactively:
|
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.
|
- 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}
|
${toolsSection}
|
||||||
Your primary job is to find and synthesize information from notes across all projects.
|
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.
|
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:<section-id>] 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 */
|
/** The user's original message */
|
||||||
userMessage: Annotation<string>(),
|
userMessage: Annotation<string>(),
|
||||||
/** Chat context (global vs project-scoped) */
|
/** 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 */
|
/** The route chosen by the orchestrator */
|
||||||
route: Annotation<'project' | 'knowledge' | 'general'>(),
|
route: Annotation<'project' | 'knowledge' | 'general'>(),
|
||||||
/** Messages for the specialist agent */
|
/** Messages for the specialist agent */
|
||||||
@@ -583,7 +583,8 @@ async function projectAgent(state: State): Promise<Partial<State>> {
|
|||||||
// Including text tool descriptions in the system prompt causes the model to output
|
// Including text tool descriptions in the system prompt causes the model to output
|
||||||
// XML <tool_call> blocks instead of using the SDK's API-level mechanism.
|
// XML <tool_call> blocks instead of using the SDK's API-level mechanism.
|
||||||
const includeToolsInPrompt = supportsTools && getActiveProviderName() !== 'copilot';
|
const includeToolsInPrompt = supportsTools && getActiveProviderName() !== 'copilot';
|
||||||
const systemPrompt = makeProjectAgentPrompt(contextData, includeToolsInPrompt);
|
const uiContext = state.chatContext.uiContext;
|
||||||
|
const systemPrompt = makeProjectAgentPrompt(contextData, includeToolsInPrompt, uiContext);
|
||||||
|
|
||||||
if (!supportsTools) {
|
if (!supportsTools) {
|
||||||
console.log('[Orchestrator] projectAgent: using context-only fallback (no tool support)');
|
console.log('[Orchestrator] projectAgent: using context-only fallback (no tool support)');
|
||||||
@@ -671,7 +672,8 @@ async function knowledgeAgent(state: State): Promise<Partial<State>> {
|
|||||||
|
|
||||||
const supportsTools = TOOL_CALLING_PROVIDERS.has(getActiveProviderName());
|
const supportsTools = TOOL_CALLING_PROVIDERS.has(getActiveProviderName());
|
||||||
const includeToolsInPrompt = supportsTools && getActiveProviderName() !== 'copilot';
|
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}`);
|
console.log(`[Orchestrator] knowledgeAgent: provider="${getActiveProviderName()}", supportsTools=${supportsTools}`);
|
||||||
|
|
||||||
@@ -749,7 +751,8 @@ async function generalAgent(state: State): Promise<Partial<State>> {
|
|||||||
|
|
||||||
const supportsTools = TOOL_CALLING_PROVIDERS.has(getActiveProviderName());
|
const supportsTools = TOOL_CALLING_PROVIDERS.has(getActiveProviderName());
|
||||||
const includeToolsInPrompt = supportsTools && getActiveProviderName() !== 'copilot';
|
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}`);
|
console.log(`[Orchestrator] generalAgent: provider="${getActiveProviderName()}", supportsTools=${supportsTools}`);
|
||||||
|
|
||||||
|
|||||||
@@ -552,6 +552,7 @@ const aiRouter = router({
|
|||||||
context: z.object({
|
context: z.object({
|
||||||
type: z.enum(['global', 'project']),
|
type: z.enum(['global', 'project']),
|
||||||
projectId: z.string().optional(),
|
projectId: z.string().optional(),
|
||||||
|
uiContext: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
.mutation(async ({ input, ctx }) => {
|
.mutation(async ({ input, ctx }) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user