From 75e01df3a9131654959aec9cafba948a8e323963 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Fri, 21 Nov 2025 04:42:06 -0500 Subject: [PATCH 1/7] fix: Correct syntax error in app/actions.tsx after Tool Coordinator integration --- app/actions.tsx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/app/actions.tsx b/app/actions.tsx index 1a62a3c1..66bc3c83 100644 --- a/app/actions.tsx +++ b/app/actions.tsx @@ -362,16 +362,13 @@ async function submit(formData?: FormData, skip?: boolean) { : answer.length === 0 && !errorOccurred ) { // If coordinator was used, pass finalMessages and disable tools for researcher - c const { fullResponse, hasError, toolResponses } = await researcher( - currentSystemPrompt, - uiStream, - streamText, - finalMessages, - useSpecificAPI, - !useToolCoordinator // Pass a flag to disable tools if coordinator was used - )cAPI, + const { fullResponse, hasError, toolResponses } = await researcher( + currentSystemPrompt, + uiStream, + streamText, + finalMessages, + useSpecificAPI, !useToolCoordinator // Pass a flag to disable tools if coordinator was used - ) !useToolCoordinator // Pass a flag to disable tools if coordinator was used ) answer = fullResponse toolOutputs = toolResponses From 0311b79df617754b30588a954e6c33b3b6513ef4 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Fri, 21 Nov 2025 04:43:39 -0500 Subject: [PATCH 2/7] fix: Add trailing newline to tool-coordinator.tsx to resolve Unexpected EOF build error --- lib/agents/tool-coordinator.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/agents/tool-coordinator.tsx b/lib/agents/tool-coordinator.tsx index 7af69cb5..24a6cf96 100644 --- a/lib/agents/tool-coordinator.tsx +++ b/lib/agents/tool-coordinator.tsx @@ -167,3 +167,4 @@ The Tool Coordinator executed a multi-step plan to address the user's request. return summary } + From 924bebd5959ffc2d874c8c12d933fd5ff9625d41 Mon Sep 17 00:00:00 2001 From: EreQ Date: Fri, 21 Nov 2025 12:49:35 +0300 Subject: [PATCH 3/7] Fix imports and refactor tool execution logic --- lib/agents/tool-coordinator.tsx | 147 ++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 62 deletions(-) diff --git a/lib/agents/tool-coordinator.tsx b/lib/agents/tool-coordinator.tsx index 24a6cf96..c9c3e12c 100644 --- a/lib/agents/tool-coordinator.tsx +++ b/lib/agents/tool-coordinator.tsx @@ -2,8 +2,9 @@ import { generateObject } from 'ai' import { z } from 'zod' import { getModel } from '@/lib/models' import { Message } from 'ai/react' -import { getTools } from '@/lib/tools' +import { getTools } from '@/lib/agents/tools' // ← Fixed import import { ToolResultPart } from '@/lib/types' +import { createStreamableUI } from '@/lib/streamable' // --- 1. Schema Definition for Structured Planning --- @@ -29,9 +30,14 @@ export type ToolStep = z.infer */ export async function toolCoordinator(messages: Message[]): Promise { const model = getModel() - const tools = getTools({}) // Get tool definitions for the prompt - const toolDescriptions = tools.map(tool => ({ + // getTools now returns an object map: { toolName: toolDefinition } + const toolsObj = getTools({ + uiStream: createStreamableUI(), // dummy stream; real one will be injected during execution + fullResponse: '' + }) + + const toolDescriptions = Object.values(toolsObj).map(tool => ({ name: tool.toolName, description: tool.description, parameters: tool.parameters @@ -61,22 +67,35 @@ ${JSON.stringify(toolDescriptions, null, 2)} // --- 3. Tool Execution Function --- +interface ExecutionContext { + uiStream: ReturnType + fullResponse: string +} + /** - * Executes the tool plan, handling dependencies and parallel execution. + * Executes the tool plan sequentially while respecting dependencies. + * Always returns one ToolResultPart per step (preserves 1:1 alignment with plan.steps). */ -export async function executeToolPlan(plan: ToolPlan): Promise { - const allTools = getTools({}) - const toolMap = new Map(allTools.map(tool => [tool.toolName, tool])) +export async function executeToolPlan( + plan: ToolPlan, + context: ExecutionContext +): Promise { + const { uiStream, fullResponse } = context + + // getTools returns object map → convert to array and build Map for lookup + const toolsObj = getTools({ uiStream, fullResponse }) + const toolsArray = Object.values(toolsObj) + const toolMap = new Map(toolsArray.map(tool => [tool.toolName, tool])) + const results: Map = new Map() const toolResults: ToolResultPart[] = [] - // Function to get results of dependencies - const getDependencyResults = (indices: number[]) => { - return indices.map(index => { - if (!results.has(index)) { - throw new Error(\`Dependency step \${index} has not been executed yet.\`) + const getDependencyResults = (indices: number[] = []) => { + return indices.map(idx => { + if (!results.has(idx)) { + throw new Error(`Dependency step ${idx} has not been executed yet.`) } - return results.get(index) + return results.get(idx) }) } @@ -84,42 +103,40 @@ export async function executeToolPlan(plan: ToolPlan): Promise const step = plan.steps[i] const tool = toolMap.get(step.toolName) - if (!tool) { - console.error(\`Tool \${step.toolName} not found.\`) - results.set(i, { error: \`Tool \${step.toolName} not found.\` }) - continue - } + let result: any + let errorMessage: string | undefined try { - const dependencyResults = step.dependencyIndices ? getDependencyResults(step.dependencyIndices) : [] - - // Inject dependency results into tool arguments for the tool to use + if (!tool) { + throw new Error(`Tool "${step.toolName}" not found among available tools.`) + } + + const dependencyResults = step.dependencyIndices + ? getDependencyResults(step.dependencyIndices) + : [] + const argsWithDependencies = { ...step.toolArgs, - _dependencyResults: dependencyResults.length > 0 ? dependencyResults : undefined + ...(dependencyResults.length > 0 && { _dependencyResults: dependencyResults }) } - console.log(\`Executing step \${i}: \${step.toolName} with args: \${JSON.stringify(argsWithDependencies)}\`) - - // Execute the tool directly - const result = await tool.execute(argsWithDependencies) - - results.set(i, result) - toolResults.push({ - toolName: step.toolName, - toolCallId: \`coord-\${i}\`, - result: result - }) - } catch (error) { - console.error(\`Error executing step \${i} (\${step.toolName}):\`, error) - const errorMessage = error instanceof Error ? error.message : String(error) - results.set(i, { error: errorMessage }) - toolResults.push({ - toolName: step.toolName, - toolCallId: \`coord-\${i}\`, - result: { error: errorMessage } - }) + console.log(`Executing step ${i}: ${step.toolName}`, argsWithDependencies) + + result = await tool.execute(argsWithDependencies) + } catch (err) { + errorMessage = err instanceof Error ? err.message : String(err) + console.error(`Error in step ${i} (${step.toolName}):`, err) + result = { error: errorMessage } } + + // Always store result (even on error) and push a ToolResultPart + results.set(i, result) + + toolResults.push({ + toolName: step.toolName, + toolCallId: `coord-${i}`, + result + }) } return toolResults @@ -128,43 +145,49 @@ export async function executeToolPlan(plan: ToolPlan): Promise // --- 4. Result Aggregation Function --- /** - * Aggregates the tool results into a structured summary for the final agent. + * Aggregates the tool results into a markdown summary for the final agent. */ export function aggregateToolResults(toolResults: ToolResultPart[], plan: ToolPlan): string { - let summary = \`## Tool Coordinator Execution Summary + let summary = `# Tool Coordinator Execution Summary The Tool Coordinator executed a multi-step plan to address the user's request. ### Plan Reasoning -\${plan.reasoning} +${plan.reasoning} ### Execution Steps and Results -\` +` toolResults.forEach((toolResult, index) => { const step = plan.steps[index] const result = toolResult.result - const isError = result && typeof result === 'object' && 'error' in result - - summary += \` -#### Step \${index + 1}: \${step.purpose} (\${step.toolName}) -\` - if (isError) { - summary += \`**Status:** ❌ FAILED -**Error:** \${result.error} -\` + const hasError = result && typeof result === 'object' && 'error' in result + + summary += ` +#### Step ${index + 1}: ${step.purpose} (\`${step.toolName}\`) +` + + if (hasError) { + summary += `**Status:** ❌ FAILED +**Error:** ${result.error} +` } else { - summary += \`**Status:** ✅ SUCCESS -**Result Summary:** \${JSON.stringify(result, null, 2).substring(0, 500)}...\` + const resultStr M= JSON.stringify(result, null, 2) + const truncated = resultStr.length > 500 ? resultStr.substring(0, 500) + '...' : resultStr + summary += `**Status:** ✅ SUCCESS +**Result Summary:** +\`\`\`json +${truncated} +\`\`\` +` } - summary += '\n' }) - summary += \` + summary += ` --- -**INSTRUCTION:** Use the above summary and the original user messages to generate a final, coherent, and helpful response. Do not mention the Tool Coordinator or the plan execution process in the final answer, only the synthesized information. -\` +**INSTRUCTION:** Using the information above and the original user messages, generate a final, coherent, and helpful response to the user. +Do not mention the Tool Coordinator, internal planning, or execution details — only present the synthesized answer naturally. +` return summary } - From 612479d596c2c523b1793685a7b36a33a67cff2d Mon Sep 17 00:00:00 2001 From: EreQ Date: Fri, 21 Nov 2025 12:54:16 +0300 Subject: [PATCH 4/7] Update tool-coordinator.tsx --- lib/agents/tool-coordinator.tsx | 155 ++------------------------------ 1 file changed, 6 insertions(+), 149 deletions(-) diff --git a/lib/agents/tool-coordinator.tsx b/lib/agents/tool-coordinator.tsx index c9c3e12c..5c105ad4 100644 --- a/lib/agents/tool-coordinator.tsx +++ b/lib/agents/tool-coordinator.tsx @@ -1,149 +1,3 @@ -import { generateObject } from 'ai' -import { z } from 'zod' -import { getModel } from '@/lib/models' -import { Message } from 'ai/react' -import { getTools } from '@/lib/agents/tools' // ← Fixed import -import { ToolResultPart } from '@/lib/types' -import { createStreamableUI } from '@/lib/streamable' - -// --- 1. Schema Definition for Structured Planning --- - -const toolStepSchema = z.object({ - toolName: z.string().describe('The name of the tool to be executed (e.g., "geospatialQueryTool", "searchTool").'), - toolArgs: z.record(z.any()).describe('The arguments for the tool function call.'), - dependencyIndices: z.array(z.number()).optional().describe('An array of indices of previous steps whose results are required for this step. Use 0-based indexing.'), - purpose: z.string().describe('A brief explanation of why this tool is being called in this step.') -}) - -const toolPlanSchema = z.object({ - reasoning: z.string().describe('A detailed explanation of the multi-step plan to answer the user query.'), - steps: z.array(toolStepSchema).describe('A sequence of tool execution steps to fulfill the user request.') -}) - -export type ToolPlan = z.infer -export type ToolStep = z.infer - -// --- 2. Tool Coordinator Planning Function --- - -/** - * Analyzes the user query and generates a structured, multi-step tool execution plan. - */ -export async function toolCoordinator(messages: Message[]): Promise { - const model = getModel() - - // getTools now returns an object map: { toolName: toolDefinition } - const toolsObj = getTools({ - uiStream: createStreamableUI(), // dummy stream; real one will be injected during execution - fullResponse: '' - }) - - const toolDescriptions = Object.values(toolsObj).map(tool => ({ - name: tool.toolName, - description: tool.description, - parameters: tool.parameters - })) - - const systemPrompt = `You are an expert Tool Coordinator. Your task is to analyze the user's request and create a structured, multi-step plan to answer it using the available tools. - -Rules: -1. The plan must be a sequence of steps. -2. For steps that depend on the output of a previous step, specify the 'dependencyIndices' array (0-based index). -3. You must use the exact 'toolName' and 'toolArgs' structure as defined in the tool descriptions. -4. The final output must strictly adhere to the provided JSON schema. - -Available Tools: -${JSON.stringify(toolDescriptions, null, 2)} -` - - const { object } = await generateObject({ - model: model, - system: systemPrompt, - messages: messages, - schema: toolPlanSchema - }) - - return object -} - -// --- 3. Tool Execution Function --- - -interface ExecutionContext { - uiStream: ReturnType - fullResponse: string -} - -/** - * Executes the tool plan sequentially while respecting dependencies. - * Always returns one ToolResultPart per step (preserves 1:1 alignment with plan.steps). - */ -export async function executeToolPlan( - plan: ToolPlan, - context: ExecutionContext -): Promise { - const { uiStream, fullResponse } = context - - // getTools returns object map → convert to array and build Map for lookup - const toolsObj = getTools({ uiStream, fullResponse }) - const toolsArray = Object.values(toolsObj) - const toolMap = new Map(toolsArray.map(tool => [tool.toolName, tool])) - - const results: Map = new Map() - const toolResults: ToolResultPart[] = [] - - const getDependencyResults = (indices: number[] = []) => { - return indices.map(idx => { - if (!results.has(idx)) { - throw new Error(`Dependency step ${idx} has not been executed yet.`) - } - return results.get(idx) - }) - } - - for (let i = 0; i < plan.steps.length; i++) { - const step = plan.steps[i] - const tool = toolMap.get(step.toolName) - - let result: any - let errorMessage: string | undefined - - try { - if (!tool) { - throw new Error(`Tool "${step.toolName}" not found among available tools.`) - } - - const dependencyResults = step.dependencyIndices - ? getDependencyResults(step.dependencyIndices) - : [] - - const argsWithDependencies = { - ...step.toolArgs, - ...(dependencyResults.length > 0 && { _dependencyResults: dependencyResults }) - } - - console.log(`Executing step ${i}: ${step.toolName}`, argsWithDependencies) - - result = await tool.execute(argsWithDependencies) - } catch (err) { - errorMessage = err instanceof Error ? err.message : String(err) - console.error(`Error in step ${i} (${step.toolName}):`, err) - result = { error: errorMessage } - } - - // Always store result (even on error) and push a ToolResultPart - results.set(i, result) - - toolResults.push({ - toolName: step.toolName, - toolCallId: `coord-${i}`, - result - }) - } - - return toolResults -} - -// --- 4. Result Aggregation Function --- - /** * Aggregates the tool results into a markdown summary for the final agent. */ @@ -168,13 +22,14 @@ ${plan.reasoning} ` if (hasError) { - summary += `**Status:** ❌ FAILED + summary += `**Status:** Failed **Error:** ${result.error} ` } else { - const resultStr M= JSON.stringify(result, null, 2) + const resultStr = JSON.stringify(result, null, 2) const truncated = resultStr.length > 500 ? resultStr.substring(0, 500) + '...' : resultStr - summary += `**Status:** ✅ SUCCESS + + summary += `**Status:** Success **Result Summary:** \`\`\`json ${truncated} @@ -191,3 +46,5 @@ Do not mention the Tool Coordinator, internal planning, or execution details — return summary } +aker: summary +} From 9e2a308380467db7f2099ddffde52f903c3ce135 Mon Sep 17 00:00:00 2001 From: EreQ Date: Fri, 21 Nov 2025 12:56:59 +0300 Subject: [PATCH 5/7] Update tool-coordinator.tsx --- lib/agents/tool-coordinator.tsx | 163 ++++++++++++++++++++++++++++---- 1 file changed, 143 insertions(+), 20 deletions(-) diff --git a/lib/agents/tool-coordinator.tsx b/lib/agents/tool-coordinator.tsx index 5c105ad4..0a42f37c 100644 --- a/lib/agents/tool-coordinator.tsx +++ b/lib/agents/tool-coordinator.tsx @@ -1,36 +1,161 @@ -/** - * Aggregates the tool results into a markdown summary for the final agent. - */ +import { generateObject } from 'ai' +import { z } from 'zod' +import { getModel } from '@/lib/models' +import { Message } from 'ai/react' +import { getTools } from '@/lib/agents/tools' +import { ToolResultPart } from '@/lib/types' +import { createStreamableUI } from '@/lib/streamable' + +// —————————————————————————————————————— +// 1. Schemas +// —————————————————————————————————————— + +const toolStepSchema = z.object({ + toolName: z.string().describe('Exact tool name, e.g. "geospatialQueryTool"'), + toolArgs: z.record(z.any()).describe('Arguments for the tool call'), + dependencyIndices: z.array(z.number()).optional().describe('0-based indices of steps this step depends on'), + purpose: z.string().describe('Why this tool is being called') +}) + +const toolPlanSchema = z.object({ + reasoning: z.string().describe('Full explanation of the multi-step plan'), + steps: z.array(toolStepSchema) +}) + +export type ToolPlan = z.infer +export type ToolStep = z.infer + +// —————————————————————————————————————— +// 2. Plan generation +// —————————————————————————————————————— + +export async function toolCoordinator(messages: Message[]): Promise { + const model = getModel() + + const toolsObj = getTools({ + uiStream: createStreamableUI(), + fullResponse: '' + }) + + const toolDescriptions = Object.values(toolsObj).map(tool => ({ + name: tool.toolName, + description: tool.description, + parameters: tool.parameters + })) + + const systemPrompt = `You are an expert Tool Coordinator. Create a precise multi-step plan using only the available tools. + +Rules: +- Use exact toolName values. +- Specify dependencyIndices when a step needs prior results. +- Output must match the JSON schema exactly. + +Available Tools: +${JSON.stringify(toolDescriptions, null, 2)} +` + + const { object } = await generateObject({ + model, + system: systemPrompt, + messages, + schema: toolPlanSchema + }) + + return object +} + +// —————————————————————————————————————— +// 3. Execution +// —————————————————————————————————————— + +interface ExecutionContext { + uiStream: ReturnType + fullResponse: string +} + +export async function executeToolPlan( + plan: ToolPlan, + context: ExecutionContext +): Promise { + const { uiStream, fullResponse } = context + + const toolsObj = getTools({ uiStream, fullResponse }) + const toolMap = new Map(Object.values(toolsObj).map(t => [t.toolName, t])) + + const results = new Map() + const toolResults: ToolResultPart[] = [] + + const getDeps = (indices: number[] = []) => + indices.map(i => { + if (!results.has(i)) throw new Error(`Dependency step ${i} not executed yet`) + return results.get(i) + }) + + for (let i = 0; i < plan.steps.length; i++) { + const step = plan.steps[i] + const tool = toolMap.get(step.toolName) + + let result: any = { error: `Tool "${step.toolName}" not found` } + + try { + if (!tool) throw new Error(`Tool "${step.toolName}" not found`) + + const depResults = step.dependencyIndices ? getDeps(step.dependencyIndices) : [] + + const args = { + ...step.toolArgs, + ...(depResults.length > 0 && { _dependencyResults: depResults }) + } + + console.log(`[ToolCoordinator] Step ${i}: ${step.toolName}`, args) + result = await tool.execute(args) + } catch (err) { + const msg = err instanceof Error ? err.message : String(err) + console.error(`[ToolCoordinator] Step ${i} failed:`, err) + result = { error: msg } + } + + results.set(i, result) + toolResults.push({ + toolName: step.toolName, + toolCallId: `coord-${i}`, + result + }) + } + + return toolResults +} + +// —————————————————————————————————————— +// 4. Aggregation (for final LLM) +// —————————————————————————————————————— + export function aggregateToolResults(toolResults: ToolResultPart[], plan: ToolPlan): string { let summary = `# Tool Coordinator Execution Summary -The Tool Coordinator executed a multi-step plan to address the user's request. - ### Plan Reasoning ${plan.reasoning} -### Execution Steps and Results +### Step Results ` - toolResults.forEach((toolResult, index) => { - const step = plan.steps[index] - const result = toolResult.result - const hasError = result && typeof result === 'object' && 'error' in result + toolResults.forEach((tr, i) => { + const step = plan.steps[i] + const hasError = tr.result && typeof tr.result === 'object' && 'error' in tr.result summary += ` -#### Step ${index + 1}: ${step.purpose} (\`${step.toolName}\`) +#### Step ${i + 1}: ${step.purpose} (\`${step.toolName}\`) ` if (hasError) { summary += `**Status:** Failed -**Error:** ${result.error} +**Error:** ${tr.result.error} ` } else { - const resultStr = JSON.stringify(result, null, 2) - const truncated = resultStr.length > 500 ? resultStr.substring(0, 500) + '...' : resultStr - + const json = JSON.stringify(tr.result, null, 2) + const truncated = json.length > 500 ? json.slice(0, 500) + '...' : json summary += `**Status:** Success -**Result Summary:** +**Result:** \`\`\`json ${truncated} \`\`\` @@ -40,11 +165,9 @@ ${truncated} summary += ` --- -**INSTRUCTION:** Using the information above and the original user messages, generate a final, coherent, and helpful response to the user. -Do not mention the Tool Coordinator, internal planning, or execution details — only present the synthesized answer naturally. +**INSTRUCTION:** Using the information above and the original user query, write a clear, natural final response. +Do not mention the Tool Coordinator, planning steps, or internal process — only the synthesized answer. ` return summary } -aker: summary -} From 37290d5ad1f781f981e69555093876f84dfb6f53 Mon Sep 17 00:00:00 2001 From: EreQ Date: Fri, 21 Nov 2025 13:48:41 +0300 Subject: [PATCH 6/7] Update tool-coordinator.tsx --- lib/agents/tool-coordinator.tsx | 120 +++++++++++++++++++------------- 1 file changed, 72 insertions(+), 48 deletions(-) diff --git a/lib/agents/tool-coordinator.tsx b/lib/agents/tool-coordinator.tsx index 0a42f37c..976cb22c 100644 --- a/lib/agents/tool-coordinator.tsx +++ b/lib/agents/tool-coordinator.tsx @@ -1,24 +1,62 @@ import { generateObject } from 'ai' import { z } from 'zod' -import { getModel } from '@/lib/models' import { Message } from 'ai/react' import { getTools } from '@/lib/agents/tools' import { ToolResultPart } from '@/lib/types' -import { createStreamableUI } from '@/lib/streamable' // —————————————————————————————————————— -// 1. Schemas +// Fallbacks if the original files don't exist yet +// —————————————————————————————————————— + +let getModel: () => any +let createStreamableUI: () => any + +try { + // Try the most common real locations first + const models = require('@/lib/models') + getModel = models.getModel || models.default || (() => null) +} catch { + try { + const mod = require('@/lib/ai/models') + getModel = mod.getModel || mod.default + } catch { + getModel = () => { + throw new Error('getModel not available — check your @/lib/models setup') + } + } +} + +try { + const streamable = require('@/lib/streamable') + createStreamableUI = streamable.createStreamableUI || streamable.default +} catch { + try { + const s = require('@/lib/ui/streamable') + createStreamableUI = s.createStreamableUI + } catch { + // Minimal no-op version that won't break tool calling + createStreamableUI = () => ({ + append: () => {}, + update: () => {}, + done: () => {}, + value: null + }) + } +} + +// —————————————————————————————————————— +// Schemas // —————————————————————————————————————— const toolStepSchema = z.object({ - toolName: z.string().describe('Exact tool name, e.g. "geospatialQueryTool"'), - toolArgs: z.record(z.any()).describe('Arguments for the tool call'), - dependencyIndices: z.array(z.number()).optional().describe('0-based indices of steps this step depends on'), - purpose: z.string().describe('Why this tool is being called') + toolName: z.string(), + toolArgs: z.record(z.any()), + dependencyIndices: z.array(z.number()).optional(), + purpose: z.string() }) const toolPlanSchema = z.object({ - reasoning: z.string().describe('Full explanation of the multi-step plan'), + reasoning: z.string(), steps: z.array(toolStepSchema) }) @@ -26,7 +64,7 @@ export type ToolPlan = z.infer export type ToolStep = z.infer // —————————————————————————————————————— -// 2. Plan generation +// 1. Plan Generation // —————————————————————————————————————— export async function toolCoordinator(messages: Message[]): Promise { @@ -43,12 +81,12 @@ export async function toolCoordinator(messages: Message[]): Promise { parameters: tool.parameters })) - const systemPrompt = `You are an expert Tool Coordinator. Create a precise multi-step plan using only the available tools. + const systemPrompt = `You are an expert Tool Coordinator. Create a precise multi-step plan using only these tools. Rules: -- Use exact toolName values. -- Specify dependencyIndices when a step needs prior results. -- Output must match the JSON schema exactly. +- Use exact toolName from the list. +- Use dependencyIndices (0-based) when a step needs prior results. +- Output must be valid JSON matching the schema. Available Tools: ${JSON.stringify(toolDescriptions, null, 2)} @@ -65,11 +103,11 @@ ${JSON.stringify(toolDescriptions, null, 2)} } // —————————————————————————————————————— -// 3. Execution +// 2. Execution // —————————————————————————————————————— interface ExecutionContext { - uiStream: ReturnType + uiStream: any fullResponse: string } @@ -85,9 +123,9 @@ export async function executeToolPlan( const results = new Map() const toolResults: ToolResultPart[] = [] - const getDeps = (indices: number[] = []) => + const resolveDeps = (indices: number[] = []) => indices.map(i => { - if (!results.has(i)) throw new Error(`Dependency step ${i} not executed yet`) + if (!results.has(i)) throw new Error(`Dependency step ${i} missing`) return results.get(i) }) @@ -98,20 +136,19 @@ export async function executeToolPlan( let result: any = { error: `Tool "${step.toolName}" not found` } try { - if (!tool) throw new Error(`Tool "${step.toolName}" not found`) - - const depResults = step.dependencyIndices ? getDeps(step.dependencyIndices) : [] + if (!tool) throw new Error(`Tool not found: ${step.toolName}`) + const deps = step.dependencyIndices ? resolveDeps(step.dependencyIndices) : [] const args = { ...step.toolArgs, - ...(depResults.length > 0 && { _dependencyResults: depResults }) + ...(deps.length > 0 && { _dependencyResults: deps }) } - console.log(`[ToolCoordinator] Step ${i}: ${step.toolName}`, args) + console.log(`[ToolCoordinator] Step ${i}: ${step.toolName}`) result = await tool.execute(args) - } catch (err) { - const msg = err instanceof Error ? err.message : String(err) - console.error(`[ToolCoordinator] Step ${i} failed:`, err) + } catch (err: any) { + const msg = err?.message || String(err) + console.error(`[ToolCoordinator] Step ${i} failed:`, msg) result = { error: msg } } @@ -127,47 +164,34 @@ export async function executeToolPlan( } // —————————————————————————————————————— -// 4. Aggregation (for final LLM) +// 3. Aggregation // —————————————————————————————————————— export function aggregateToolResults(toolResults: ToolResultPart[], plan: ToolPlan): string { - let summary = `# Tool Coordinator Execution Summary + let out = `# Tool Coordinator Results -### Plan Reasoning +### Plan ${plan.reasoning} -### Step Results +### Steps ` toolResults.forEach((tr, i) => { const step = plan.steps[i] const hasError = tr.result && typeof tr.result === 'object' && 'error' in tr.result - summary += ` -#### Step ${i + 1}: ${step.purpose} (\`${step.toolName}\`) -` + out += `\n#### Step ${i + 1}: ${step.purpose} (\`${step.toolName}\`)` if (hasError) { - summary += `**Status:** Failed -**Error:** ${tr.result.error} -` + out += `\n**Status:** Failed\n**Error:** ${tr.result.error}` } else { const json = JSON.stringify(tr.result, null, 2) - const truncated = json.length > 500 ? json.slice(0, 500) + '...' : json - summary += `**Status:** Success -**Result:** -\`\`\`json -${truncated} -\`\`\` -` + const truncated = json.length > 600 ? json.slice(0, 600) + '...' : json + out += `\n**Status:** Success\n**Result:**\n\`\`\`json\n${truncated}\n\`\`\`` } }) - summary += ` ---- -**INSTRUCTION:** Using the information above and the original user query, write a clear, natural final response. -Do not mention the Tool Coordinator, planning steps, or internal process — only the synthesized answer. -` + out += `\n\n---\n**INSTRUCTION:** Write a natural, helpful final answer using only the information above. Do not mention tools, steps, or internal process.` - return summary + return out } From e4dbb38d77498f869e9ab720bf9703a4b9d93234 Mon Sep 17 00:00:00 2001 From: Manus AI Date: Sun, 23 Nov 2025 05:21:44 -0500 Subject: [PATCH 7/7] fix: Correct Spinner component usage in app/actions.tsx to resolve type error --- app/actions.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/actions.tsx b/app/actions.tsx index 66bc3c83..baed33f6 100644 --- a/app/actions.tsx +++ b/app/actions.tsx @@ -323,10 +323,10 @@ async function submit(formData?: FormData, skip?: boolean) { let finalMessages = messages if (useToolCoordinator) { - uiStream.update() + uiStream.update(
Planning tool execution...
) try { const plan = await toolCoordinator(messages) - uiStream.update() + uiStream.update(
Executing tool plan...
) const results = await executeToolPlan(plan) toolOutputs = results const summary = aggregateToolResults(results, plan)