diff --git a/.changeset/drop-preliminary-results.md b/.changeset/drop-preliminary-results.md new file mode 100644 index 0000000..051e397 --- /dev/null +++ b/.changeset/drop-preliminary-results.md @@ -0,0 +1,5 @@ +--- +'@openrouter/agent': patch +--- + +Stop accumulating generator-tool `preliminaryResults` arrays. Yields are still broadcast live; the terminal `tool.result` event no longer copies every yield. diff --git a/packages/agent/src/lib/model-result.ts b/packages/agent/src/lib/model-result.ts index 17bd492..930e777 100644 --- a/packages/agent/src/lib/model-result.ts +++ b/packages/agent/src/lib/model-result.ts @@ -972,7 +972,6 @@ export class ModelResult< toolName: string, source: 'client' | 'mcp', result: InferToolOutputsUnion, - preliminaryResults?: InferToolEventsUnion[], ): void { this.toolEventBroadcaster?.push({ type: 'tool_result' as const, @@ -980,9 +979,6 @@ export class ModelResult< toolName, source, result, - ...(preliminaryResults?.length && { - preliminaryResults, - }), }); this.turnBroadcaster?.push({ type: 'tool.result' as const, @@ -991,9 +987,6 @@ export class ModelResult< source, result, timestamp: Date.now(), - ...(preliminaryResults?.length && { - preliminaryResults, - }), } as CorrelatedResponseStreamEvent); } @@ -3246,7 +3239,6 @@ export class ModelResult< controller: AbortController; timeoutMs: number | undefined; runBinding: RunBinding; - preliminaryResultsForCall: InferToolEventsUnion[]; } | { type: 'execution'; @@ -3256,7 +3248,6 @@ export class ModelResult< result: unknown; error?: Error; }; - preliminaryResultsForCall: InferToolEventsUnion[]; } > { // Universal task-tool dispatch: ONE static tool ("task") handles every @@ -3288,14 +3279,14 @@ export class ModelResult< return hookDenied; } - const preliminaryResultsForCall: InferToolEventsUnion[] = []; - const hasBroadcaster = this.toolEventBroadcaster || this.turnBroadcaster; const onPreliminaryResult = hasBroadcaster ? (callId: string, resultValue: unknown) => { - const typedResult = resultValue as InferToolEventsUnion; - preliminaryResultsForCall.push(typedResult); - this.broadcastPreliminaryResult(callId, String(toolCall.name), typedResult); + this.broadcastPreliminaryResult( + callId, + String(toolCall.name), + resultValue as InferToolEventsUnion, + ); } : undefined; @@ -3364,7 +3355,7 @@ export class ModelResult< ); if (executed === 'timeout') { - return this.buildToolTimeoutOutcome(toolCall, tool, timeoutMs, preliminaryResultsForCall); + return this.buildToolTimeoutOutcome(toolCall, tool, timeoutMs); } if (executed.type === 'parse_error') { @@ -3403,7 +3394,6 @@ export class ModelResult< controller, timeoutMs, runBinding, - preliminaryResultsForCall, }; } @@ -3412,7 +3402,6 @@ export class ModelResult< toolCall: executed.effectiveToolCall, tool, result, - preliminaryResultsForCall, }; } finally { releaseGates(); @@ -3432,7 +3421,6 @@ export class ModelResult< toolCall: ParsedToolCall, tool: Tool, timeoutMs: number | undefined, - preliminaryResultsForCall: InferToolEventsUnion[], ): { type: 'execution'; toolCall: ParsedToolCall; @@ -3441,7 +3429,6 @@ export class ModelResult< result: unknown; error?: Error; }; - preliminaryResultsForCall: InferToolEventsUnion[]; } { const message = `Tool "${toolCall.name}" timed out after ${timeoutMs}ms`; this.broadcastToolResult( @@ -3462,7 +3449,6 @@ export class ModelResult< code: 'tool_timeout', }), }, - preliminaryResultsForCall, }; } @@ -3661,7 +3647,6 @@ export class ModelResult< String(value.toolCall.name), isMcpTool(value.tool) ? 'mcp' : 'client', toolResult, - value.preliminaryResultsForCall.length > 0 ? value.preliminaryResultsForCall : undefined, ); const outputForModel = await this.computeToolOutputForModel(value); @@ -4136,7 +4121,6 @@ export class ModelResult< result: unknown; error?: Error; }; - preliminaryResultsForCall: InferToolEventsUnion[]; }> { const taskTool = buildTaskToolStub(); const answer = (result: unknown, error?: Error) => { @@ -4160,7 +4144,6 @@ export class ModelResult< : { result, }, - preliminaryResultsForCall: [] as InferToolEventsUnion[], }; }; diff --git a/packages/agent/src/lib/tool-executor.ts b/packages/agent/src/lib/tool-executor.ts index 5ccdc7b..5915c93 100644 --- a/packages/agent/src/lib/tool-executor.ts +++ b/packages/agent/src/lib/tool-executor.ts @@ -337,7 +337,6 @@ export async function executeGeneratorTool( extras, ); - const preliminaryResults: unknown[] = []; let finalResult: unknown; let hasFinalResult = false; let lastEmittedValue: unknown; @@ -359,7 +358,6 @@ export async function executeGeneratorTool( hasFinalResult = true; } else { const validatedPreliminary = validateToolOutput(tool.function.eventSchema, event); - preliminaryResults.push(validatedPreliminary); if (onPreliminaryResult) { onPreliminaryResult(toolCall.id, validatedPreliminary); } @@ -387,7 +385,6 @@ export async function executeGeneratorTool( toolName: toolCall.name, source, result: finalResult, - preliminaryResults, }; } catch (error) { return { diff --git a/packages/agent/src/lib/tool-orchestrator.ts b/packages/agent/src/lib/tool-orchestrator.ts index 32341af..5a0df7d 100644 --- a/packages/agent/src/lib/tool-orchestrator.ts +++ b/packages/agent/src/lib/tool-orchestrator.ts @@ -186,7 +186,6 @@ export function toolResultsToMap(results: ToolExecutionResult[]): Map< string, { result: unknown; - preliminaryResults?: unknown[]; } > { const map = new Map(); @@ -194,7 +193,6 @@ export function toolResultsToMap(results: ToolExecutionResult[]): Map< for (const result of results) { map.set(result.toolCallId, { result: result.result, - preliminaryResults: result.preliminaryResults, }); } @@ -211,9 +209,7 @@ export function summarizeToolExecutions(results: ToolExecutionResult[]): s if (result.error) { lines.push(`❌ ${result.toolName} (${result.toolCallId}): ERROR - ${result.error.message}`); } else { - const prelimCount = result.preliminaryResults?.length ?? 0; - const prelimInfo = prelimCount > 0 ? ` (${prelimCount} preliminary results)` : ''; - lines.push(`✅ ${result.toolName} (${result.toolCallId}): SUCCESS${prelimInfo}`); + lines.push(`✅ ${result.toolName} (${result.toolCallId}): SUCCESS`); } } diff --git a/packages/agent/src/lib/tool-types.ts b/packages/agent/src/lib/tool-types.ts index e89d749..470dcaf 100644 --- a/packages/agent/src/lib/tool-types.ts +++ b/packages/agent/src/lib/tool-types.ts @@ -1213,7 +1213,7 @@ export interface ToolExecutionResult { : unknown; // Final result (sent to model) preliminaryResults?: T extends ToolWithGenerator<$ZodObject<$ZodShape>, infer E> ? zodInfer[] - : undefined; // All yielded values from generator + : undefined; // Kept for type compatibility; no longer populated error?: Error; } @@ -1365,6 +1365,7 @@ export type ToolResultEvent< source: 'client' | 'mcp'; result: TResult; timestamp: number; + /** Kept for type compatibility; the runtime no longer copies every yield here. */ preliminaryResults?: TPreliminaryResults[]; }; diff --git a/packages/agent/tests/unit/tool-executor-return.test.ts b/packages/agent/tests/unit/tool-executor-return.test.ts index b7f7ce8..15c50ec 100644 --- a/packages/agent/tests/unit/tool-executor-return.test.ts +++ b/packages/agent/tests/unit/tool-executor-return.test.ts @@ -45,15 +45,7 @@ describe('executeGeneratorTool - return value capture', () => { const result = await executeGeneratorTool(generatorTool, toolCall, mockContext); expect(result.error).toBeUndefined(); - expect(result.preliminaryResults).toHaveLength(2); - expect(result.preliminaryResults).toEqual([ - { - status: 'working', - }, - { - status: 'almost done', - }, - ]); + expect(result.preliminaryResults).toBeUndefined(); // The return value should be captured as the final result expect(result.result).toEqual({ result: 'Done: test', @@ -91,7 +83,7 @@ describe('executeGeneratorTool - return value capture', () => { const result = await executeGeneratorTool(generatorTool, toolCall, mockContext); expect(result.error).toBeUndefined(); - expect(result.preliminaryResults).toHaveLength(0); + expect(result.preliminaryResults).toBeUndefined(); expect(result.result).toEqual({ result: 'Direct: test', }); @@ -134,7 +126,7 @@ describe('executeGeneratorTool - return value capture', () => { const result = await executeGeneratorTool(generatorTool, toolCall, mockContext); expect(result.error).toBeUndefined(); - expect(result.preliminaryResults).toHaveLength(2); + expect(result.preliminaryResults).toBeUndefined(); // Return value should take precedence expect(result.result).toEqual({ finalValue: 'Final: test', diff --git a/packages/agent/tests/unit/tool-name-events.test.ts b/packages/agent/tests/unit/tool-name-events.test.ts index cf21640..62564bd 100644 --- a/packages/agent/tests/unit/tool-name-events.test.ts +++ b/packages/agent/tests/unit/tool-name-events.test.ts @@ -269,15 +269,8 @@ describe('toolName on runtime tool events', () => { result: { done: true, }, - preliminaryResults: [ - { - stage: 'one', - }, - { - stage: 'two', - }, - ], }); + expect(finals[0]?.preliminaryResults).toBeUndefined(); const legacyPrelims = legacyEvents.filter( ( diff --git a/packages/agent/tests/unit/tool-orchestrator.test.ts b/packages/agent/tests/unit/tool-orchestrator.test.ts index b92a0e2..bbaba41 100644 --- a/packages/agent/tests/unit/tool-orchestrator.test.ts +++ b/packages/agent/tests/unit/tool-orchestrator.test.ts @@ -437,12 +437,8 @@ describe('executeToolLoop', () => { result: { done: true, }, - preliminaryResults: [ - { - pct: 50, - }, - ], }); + expect(result.toolExecutionResults[0]?.preliminaryResults).toBeUndefined(); }); it('applies nextTurnParams input changes to the conversation', async () => { @@ -551,9 +547,6 @@ describe('toolResultsToMap', () => { makeResult({ toolCallId: 'b', result: 2, - preliminaryResults: [ - 'p', - ], }), ]; @@ -561,13 +554,9 @@ describe('toolResultsToMap', () => { expect(map.get('a')).toEqual({ result: 1, - preliminaryResults: undefined, }); expect(map.get('b')).toEqual({ result: 2, - preliminaryResults: [ - 'p', - ], }); expect(map.size).toBe(2); }); @@ -587,10 +576,6 @@ describe('summarizeToolExecutions', () => { makeResult({ toolName: 'chatty', toolCallId: 'b', - preliminaryResults: [ - 1, - 2, - ], }), makeResult({ toolName: 'bad', @@ -603,7 +588,7 @@ describe('summarizeToolExecutions', () => { expect(summary).toBe( [ '✅ good (a): SUCCESS', - '✅ chatty (b): SUCCESS (2 preliminary results)', + '✅ chatty (b): SUCCESS', '❌ bad (c): ERROR - nope', ].join('\n'), );