@librechat/agents 3.1.87 → 3.1.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/graphs/Graph.cjs +18 -1
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/stream.cjs +120 -10
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +24 -7
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/toolOutputReferences.cjs +8 -0
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/cjs/utils/events.cjs +3 -1
- package/dist/cjs/utils/events.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +18 -1
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/stream.mjs +120 -10
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +24 -7
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/toolOutputReferences.mjs +8 -1
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/esm/utils/events.mjs +3 -1
- package/dist/esm/utils/events.mjs.map +1 -1
- package/dist/types/graphs/Graph.d.ts +8 -0
- package/dist/types/types/tools.d.ts +9 -0
- package/dist/types/utils/events.d.ts +1 -1
- package/package.json +1 -1
- package/src/__tests__/stream.eagerEventExecution.test.ts +1307 -342
- package/src/graphs/Graph.ts +20 -5
- package/src/specs/subagent.test.ts +87 -1
- package/src/stream.ts +168 -16
- package/src/tools/ToolNode.ts +134 -111
- package/src/tools/__tests__/ToolNode.eagerEventExecution.test.ts +278 -14
- package/src/types/tools.ts +9 -0
- package/src/utils/events.ts +4 -2
package/src/graphs/Graph.ts
CHANGED
|
@@ -145,6 +145,14 @@ export abstract class Graph<
|
|
|
145
145
|
/** Set of invoked tool call IDs from non-message run steps completed mid-run, if any */
|
|
146
146
|
invokedToolIds?: Set<string>;
|
|
147
147
|
handlerRegistry: HandlerRegistry | undefined;
|
|
148
|
+
/**
|
|
149
|
+
* True when event-driven tool execution can be routed through callbacks even
|
|
150
|
+
* though this graph intentionally does not own the full handler registry.
|
|
151
|
+
* Self-spawned subagent graphs use this shape: their callback forwarder sends
|
|
152
|
+
* `ON_TOOL_EXECUTE` to the parent's handler, while child run-step events stay
|
|
153
|
+
* wrapped as `ON_SUBAGENT_UPDATE` instead of leaking as parent events.
|
|
154
|
+
*/
|
|
155
|
+
eventToolExecutionAvailable: boolean = false;
|
|
148
156
|
hookRegistry: HookRegistry | undefined;
|
|
149
157
|
/**
|
|
150
158
|
* Run-scoped HITL configuration. When `humanInTheLoop?.enabled` is
|
|
@@ -167,10 +175,8 @@ export abstract class Graph<
|
|
|
167
175
|
eagerEventToolExecution: t.EagerEventToolExecutionConfig | undefined;
|
|
168
176
|
eagerEventToolExecutions: Map<string, t.EagerEventToolExecution> = new Map();
|
|
169
177
|
eagerEventToolUsageCount: Map<string, number> = new Map();
|
|
170
|
-
private eagerEventToolUsageCountsByAgentId: Map<
|
|
171
|
-
|
|
172
|
-
Map<string, number>
|
|
173
|
-
> = new Map();
|
|
178
|
+
private eagerEventToolUsageCountsByAgentId: Map<string, Map<string, number>> =
|
|
179
|
+
new Map();
|
|
174
180
|
eagerEventToolCallChunks: Map<string, t.EagerEventToolCallChunkState> =
|
|
175
181
|
new Map();
|
|
176
182
|
/**
|
|
@@ -1554,7 +1560,16 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1554
1560
|
parentAgentId: agentContext.agentId,
|
|
1555
1561
|
tokenCounter: agentContext.tokenCounter,
|
|
1556
1562
|
maxDepth: effectiveSubagentDepth,
|
|
1557
|
-
createChildGraph: (input): StandardGraph =>
|
|
1563
|
+
createChildGraph: (input): StandardGraph => {
|
|
1564
|
+
const childGraph = new StandardGraph(input);
|
|
1565
|
+
childGraph.toolOutputReferences = this.toolOutputReferences;
|
|
1566
|
+
childGraph.eagerEventToolExecution = this.eagerEventToolExecution;
|
|
1567
|
+
childGraph.toolExecution = this.toolExecution;
|
|
1568
|
+
childGraph.eventToolExecutionAvailable =
|
|
1569
|
+
this.handlerRegistry?.getHandler(GraphEvents.ON_TOOL_EXECUTE) !=
|
|
1570
|
+
null;
|
|
1571
|
+
return childGraph;
|
|
1572
|
+
},
|
|
1558
1573
|
});
|
|
1559
1574
|
|
|
1560
1575
|
const subagentTool = tool(async (rawInput, config) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HumanMessage } from '@langchain/core/messages';
|
|
1
|
+
import { AIMessage, HumanMessage } from '@langchain/core/messages';
|
|
2
2
|
import { FakeListChatModel } from '@langchain/core/utils/testing';
|
|
3
3
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
4
4
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
@@ -220,6 +220,92 @@ describe('Subagent Integration', () => {
|
|
|
220
220
|
expect(subagentTool).toBeDefined();
|
|
221
221
|
});
|
|
222
222
|
|
|
223
|
+
it('inherits eager event-tool settings into self-spawn child graphs', async () => {
|
|
224
|
+
const originalCreateWorkflow = StandardGraph.prototype.createWorkflow;
|
|
225
|
+
const observedChildGraphs: Array<{
|
|
226
|
+
eagerEventToolExecution: StandardGraph['eagerEventToolExecution'];
|
|
227
|
+
toolOutputReferences: StandardGraph['toolOutputReferences'];
|
|
228
|
+
eventToolExecutionAvailable: boolean;
|
|
229
|
+
}> = [];
|
|
230
|
+
const createWorkflowSpy = jest
|
|
231
|
+
.spyOn(StandardGraph.prototype, 'createWorkflow')
|
|
232
|
+
.mockImplementation(function (this: StandardGraph) {
|
|
233
|
+
if (this.runId?.includes('_sub_') === true) {
|
|
234
|
+
observedChildGraphs.push({
|
|
235
|
+
eagerEventToolExecution: this.eagerEventToolExecution,
|
|
236
|
+
toolOutputReferences: this.toolOutputReferences,
|
|
237
|
+
eventToolExecutionAvailable: this.eventToolExecutionAvailable,
|
|
238
|
+
});
|
|
239
|
+
return {
|
|
240
|
+
invoke: jest.fn(async () => ({
|
|
241
|
+
messages: [new AIMessage('child done')],
|
|
242
|
+
})),
|
|
243
|
+
} as unknown as ReturnType<StandardGraph['createWorkflow']>;
|
|
244
|
+
}
|
|
245
|
+
return originalCreateWorkflow.call(this);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const agentWithSelfSpawn: t.AgentInputs = {
|
|
249
|
+
agentId: 'self-parent',
|
|
250
|
+
provider: Providers.OPENAI,
|
|
251
|
+
clientOptions: { modelName: 'gpt-4o-mini', apiKey: 'test-key' },
|
|
252
|
+
instructions: 'Agent with self-spawn for context isolation.',
|
|
253
|
+
maxContextTokens: 8000,
|
|
254
|
+
toolDefinitions: [{ name: 'mcp_lookup' }],
|
|
255
|
+
subagentConfigs: [
|
|
256
|
+
{
|
|
257
|
+
type: 'isolated',
|
|
258
|
+
name: 'Isolated Worker',
|
|
259
|
+
description: 'Runs a task with isolated context',
|
|
260
|
+
self: true,
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const run = await Run.create<t.IState>({
|
|
266
|
+
runId: `self-spawn-eager-${Date.now()}`,
|
|
267
|
+
graphConfig: {
|
|
268
|
+
type: 'standard',
|
|
269
|
+
agents: [agentWithSelfSpawn],
|
|
270
|
+
},
|
|
271
|
+
customHandlers: {
|
|
272
|
+
[GraphEvents.ON_TOOL_EXECUTE]: {
|
|
273
|
+
handle: async () => undefined,
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
eagerEventToolExecution: { enabled: true },
|
|
277
|
+
toolOutputReferences: { enabled: true },
|
|
278
|
+
returnContent: true,
|
|
279
|
+
skipCleanup: true,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const context = (run.Graph as StandardGraph).agentContexts.get(
|
|
283
|
+
'self-parent'
|
|
284
|
+
);
|
|
285
|
+
const subagentTool = (context?.graphTools as t.GenericTool[]).find(
|
|
286
|
+
(tool) => 'name' in tool && tool.name === Constants.SUBAGENT
|
|
287
|
+
);
|
|
288
|
+
expect(subagentTool).toBeDefined();
|
|
289
|
+
|
|
290
|
+
await subagentTool!.invoke(
|
|
291
|
+
{
|
|
292
|
+
description: 'Use your MCP tool.',
|
|
293
|
+
subagent_type: 'isolated',
|
|
294
|
+
},
|
|
295
|
+
callerConfig
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
expect(observedChildGraphs).toEqual([
|
|
299
|
+
{
|
|
300
|
+
eagerEventToolExecution: { enabled: true },
|
|
301
|
+
toolOutputReferences: { enabled: true },
|
|
302
|
+
eventToolExecutionAvailable: true,
|
|
303
|
+
},
|
|
304
|
+
]);
|
|
305
|
+
|
|
306
|
+
createWorkflowSpy.mockRestore();
|
|
307
|
+
});
|
|
308
|
+
|
|
223
309
|
it('should not create subagent tool when maxSubagentDepth is 0', async () => {
|
|
224
310
|
const agentWithZeroDepth: t.AgentInputs = {
|
|
225
311
|
...createParentAgent(),
|
package/src/stream.ts
CHANGED
|
@@ -27,11 +27,16 @@ import {
|
|
|
27
27
|
coerceRecordArgs,
|
|
28
28
|
normalizeError,
|
|
29
29
|
} from '@/tools/eagerEventExecution';
|
|
30
|
+
import {
|
|
31
|
+
calculateMaxToolResultChars,
|
|
32
|
+
truncateToolResultContent,
|
|
33
|
+
} from '@/utils/truncation';
|
|
30
34
|
import {
|
|
31
35
|
getStreamedToolCallSeal,
|
|
32
36
|
getStreamedToolCallAdapter,
|
|
33
37
|
type StreamedToolCallSeal,
|
|
34
38
|
} from '@/tools/streamedToolCallSeals';
|
|
39
|
+
import { TOOL_OUTPUT_REF_PATTERN } from '@/tools/toolOutputReferences';
|
|
35
40
|
|
|
36
41
|
const LOCAL_CODING_BUNDLE_NAME_SET: ReadonlySet<string> = new Set(
|
|
37
42
|
LOCAL_CODING_BUNDLE_NAMES
|
|
@@ -98,11 +103,22 @@ function getNonEmptyValue(possibleValues: string[]): string | undefined {
|
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
function isBatchSensitiveToolExecution(graph: StandardGraph): boolean {
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
)
|
|
106
|
+
return graph.hookRegistry != null || graph.humanInTheLoop?.enabled === true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function hasToolOutputReference(value: unknown): boolean {
|
|
110
|
+
if (typeof value === 'string') {
|
|
111
|
+
return TOOL_OUTPUT_REF_PATTERN.test(value);
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(value)) {
|
|
114
|
+
return value.some((item) => hasToolOutputReference(item));
|
|
115
|
+
}
|
|
116
|
+
if (value !== null && typeof value === 'object') {
|
|
117
|
+
return Object.values(value as Record<string, unknown>).some((item) =>
|
|
118
|
+
hasToolOutputReference(item)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
106
122
|
}
|
|
107
123
|
|
|
108
124
|
function isDirectGraphTool(
|
|
@@ -194,7 +210,10 @@ function isEagerToolExecutionEnabledForBatch(args: {
|
|
|
194
210
|
) {
|
|
195
211
|
return false;
|
|
196
212
|
}
|
|
197
|
-
if (
|
|
213
|
+
if (
|
|
214
|
+
graph.handlerRegistry?.getHandler(GraphEvents.ON_TOOL_EXECUTE) == null &&
|
|
215
|
+
graph.eventToolExecutionAvailable !== true
|
|
216
|
+
) {
|
|
198
217
|
return false;
|
|
199
218
|
}
|
|
200
219
|
return true;
|
|
@@ -215,10 +234,11 @@ function hasFinalToolCallSignal(chunk: Partial<AIMessageChunk>): boolean {
|
|
|
215
234
|
function canPrestartSequentialStreamedToolChunks(
|
|
216
235
|
agentContext: AgentContext | undefined
|
|
217
236
|
): boolean {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
237
|
+
// Anthropic seals each prior streamed tool-use block when the next indexed
|
|
238
|
+
// tool-use block begins. Live Kimi/Moonshot streams can still revise prior
|
|
239
|
+
// args after advancing to the next index, so keep those on the final
|
|
240
|
+
// tool-call path unless they grow an explicit adapter seal.
|
|
241
|
+
return agentContext?.provider === Providers.ANTHROPIC;
|
|
222
242
|
}
|
|
223
243
|
|
|
224
244
|
function hasExplicitStreamedToolCallSeals(
|
|
@@ -256,13 +276,49 @@ function hasPotentialDirectToolInStreamContext(args: {
|
|
|
256
276
|
if ((agentContext?.graphTools?.length ?? 0) > 0) {
|
|
257
277
|
return true;
|
|
258
278
|
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function hasDirectToolCallChunkInBatch(args: {
|
|
283
|
+
graph: StandardGraph;
|
|
284
|
+
agentContext?: AgentContext;
|
|
285
|
+
toolCallChunks?: ToolCallChunk[];
|
|
286
|
+
}): boolean {
|
|
287
|
+
const { graph, agentContext, toolCallChunks } = args;
|
|
259
288
|
return (
|
|
260
|
-
|
|
261
|
-
|
|
289
|
+
toolCallChunks?.some(
|
|
290
|
+
(toolCallChunk) =>
|
|
291
|
+
toolCallChunk.name != null &&
|
|
292
|
+
toolCallChunk.name !== '' &&
|
|
293
|
+
(isDirectGraphTool(toolCallChunk.name, agentContext) ||
|
|
294
|
+
isDirectLocalTool(toolCallChunk.name, graph))
|
|
262
295
|
) === true
|
|
263
296
|
);
|
|
264
297
|
}
|
|
265
298
|
|
|
299
|
+
function hasDirectToolCallChunkStateInStep(args: {
|
|
300
|
+
graph: StandardGraph;
|
|
301
|
+
agentContext?: AgentContext;
|
|
302
|
+
stepKey: string;
|
|
303
|
+
}): boolean {
|
|
304
|
+
const { graph, agentContext, stepKey } = args;
|
|
305
|
+
const prefix = `${stepKey}\u0000`;
|
|
306
|
+
for (const [key, state] of graph.eagerEventToolCallChunks) {
|
|
307
|
+
if (!key.startsWith(prefix)) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const name = state.name;
|
|
311
|
+
if (
|
|
312
|
+
name != null &&
|
|
313
|
+
name !== '' &&
|
|
314
|
+
(isDirectGraphTool(name, agentContext) || isDirectLocalTool(name, graph))
|
|
315
|
+
) {
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
|
|
266
322
|
type EagerToolExecutionEntry = {
|
|
267
323
|
id: string;
|
|
268
324
|
toolName: string;
|
|
@@ -297,6 +353,12 @@ function createEagerToolExecutionPlan(args: {
|
|
|
297
353
|
if (hasDirectToolCallInBatch({ graph, agentContext, toolCalls })) {
|
|
298
354
|
return undefined;
|
|
299
355
|
}
|
|
356
|
+
if (
|
|
357
|
+
graph.toolOutputReferences?.enabled === true &&
|
|
358
|
+
toolCalls.some((toolCall) => hasToolOutputReference(toolCall.args))
|
|
359
|
+
) {
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
300
362
|
|
|
301
363
|
const candidateToolCalls = skipExisting
|
|
302
364
|
? toolCalls.filter((toolCall) => {
|
|
@@ -368,6 +430,7 @@ function startEagerToolExecutions(args: {
|
|
|
368
430
|
return;
|
|
369
431
|
}
|
|
370
432
|
|
|
433
|
+
const records: t.EagerEventToolExecution[] = [];
|
|
371
434
|
const promise: Promise<t.EagerEventToolExecutionOutcome> = new Promise<
|
|
372
435
|
t.ToolExecuteResult[]
|
|
373
436
|
>((resolve, reject) => {
|
|
@@ -406,20 +469,104 @@ function startEagerToolExecutions(args: {
|
|
|
406
469
|
})
|
|
407
470
|
.catch(reject);
|
|
408
471
|
}).then(
|
|
409
|
-
(results): t.EagerEventToolExecutionOutcome =>
|
|
472
|
+
async (results): Promise<t.EagerEventToolExecutionOutcome> => {
|
|
473
|
+
await dispatchEagerToolCompletions({
|
|
474
|
+
graph,
|
|
475
|
+
agentContext,
|
|
476
|
+
records,
|
|
477
|
+
results,
|
|
478
|
+
});
|
|
479
|
+
return { results };
|
|
480
|
+
},
|
|
410
481
|
(error): t.EagerEventToolExecutionOutcome => ({
|
|
411
482
|
error: normalizeError(error),
|
|
412
483
|
})
|
|
413
484
|
);
|
|
414
485
|
|
|
415
486
|
for (const entry of entries) {
|
|
416
|
-
|
|
487
|
+
const record: t.EagerEventToolExecution = {
|
|
417
488
|
toolCallId: entry.id,
|
|
418
489
|
toolName: entry.toolName,
|
|
419
490
|
args: entry.coercedArgs,
|
|
420
491
|
request: entry.request,
|
|
421
492
|
promise,
|
|
422
|
-
}
|
|
493
|
+
};
|
|
494
|
+
records.push(record);
|
|
495
|
+
graph.eagerEventToolExecutions.set(entry.id, record);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async function dispatchEagerToolCompletions(args: {
|
|
500
|
+
graph: StandardGraph;
|
|
501
|
+
agentContext?: AgentContext;
|
|
502
|
+
records: t.EagerEventToolExecution[];
|
|
503
|
+
results: t.ToolExecuteResult[];
|
|
504
|
+
}): Promise<void> {
|
|
505
|
+
const { graph, agentContext, records, results } = args;
|
|
506
|
+
const recordById = new Map(
|
|
507
|
+
records.map((record) => [record.toolCallId, record])
|
|
508
|
+
);
|
|
509
|
+
const maxToolResultChars =
|
|
510
|
+
agentContext?.maxToolResultChars ??
|
|
511
|
+
calculateMaxToolResultChars(agentContext?.maxContextTokens);
|
|
512
|
+
|
|
513
|
+
for (const result of results) {
|
|
514
|
+
const record = recordById.get(result.toolCallId);
|
|
515
|
+
if (record == null) {
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
if (graph.eagerEventToolExecutions.get(result.toolCallId) !== record) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
const stepId =
|
|
522
|
+
record.request.stepId ??
|
|
523
|
+
graph.toolCallStepIds.get(result.toolCallId) ??
|
|
524
|
+
'';
|
|
525
|
+
if (stepId === '') {
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
const output =
|
|
529
|
+
result.status === 'error'
|
|
530
|
+
? `Error: ${result.errorMessage ?? 'Unknown error'}\n Please fix your mistakes.`
|
|
531
|
+
: truncateToolResultContent(
|
|
532
|
+
typeof result.content === 'string'
|
|
533
|
+
? result.content
|
|
534
|
+
: JSON.stringify(result.content),
|
|
535
|
+
maxToolResultChars
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
try {
|
|
539
|
+
const dispatched = await safeDispatchCustomEvent(
|
|
540
|
+
GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
541
|
+
{
|
|
542
|
+
result: {
|
|
543
|
+
id: stepId,
|
|
544
|
+
index: record.request.turn ?? 0,
|
|
545
|
+
type: 'tool_call' as const,
|
|
546
|
+
eager: true,
|
|
547
|
+
tool_call: {
|
|
548
|
+
args: JSON.stringify(record.request.args),
|
|
549
|
+
name: record.toolName,
|
|
550
|
+
id: result.toolCallId,
|
|
551
|
+
output,
|
|
552
|
+
progress: 1,
|
|
553
|
+
} as t.ProcessedToolCall,
|
|
554
|
+
},
|
|
555
|
+
},
|
|
556
|
+
graph.config
|
|
557
|
+
);
|
|
558
|
+
if (dispatched === false) {
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
record.completionDispatched = true;
|
|
562
|
+
} catch (error) {
|
|
563
|
+
// Let ToolNode dispatch the completion through the normal path later.
|
|
564
|
+
|
|
565
|
+
console.warn(
|
|
566
|
+
`[stream] eager completion dispatch failed for toolCallId=${result.toolCallId}:`,
|
|
567
|
+
error instanceof Error ? error.message : error
|
|
568
|
+
);
|
|
569
|
+
}
|
|
423
570
|
}
|
|
424
571
|
}
|
|
425
572
|
|
|
@@ -698,6 +845,8 @@ function startReadyStreamedEagerToolExecutions(args: {
|
|
|
698
845
|
} = args;
|
|
699
846
|
if (
|
|
700
847
|
hasPotentialDirectToolInStreamContext({ graph, agentContext }) ||
|
|
848
|
+
hasDirectToolCallChunkInBatch({ graph, agentContext, toolCallChunks }) ||
|
|
849
|
+
hasDirectToolCallChunkStateInStep({ graph, agentContext, stepKey }) ||
|
|
701
850
|
!isEagerToolExecutionEnabledForBatch({ graph, metadata, agentContext })
|
|
702
851
|
) {
|
|
703
852
|
return;
|
|
@@ -1264,9 +1413,12 @@ export function createContentAggregator(): t.ContentAggregatorResult {
|
|
|
1264
1413
|
|
|
1265
1414
|
const existingContent = contentParts[index] as
|
|
1266
1415
|
| (Omit<t.ToolCallContent, 'tool_call'> & {
|
|
1267
|
-
tool_call?: t.ToolCallPart;
|
|
1416
|
+
tool_call?: t.ToolCallPart & t.PartMetadata;
|
|
1268
1417
|
})
|
|
1269
1418
|
| undefined;
|
|
1419
|
+
if (!finalUpdate && existingContent?.tool_call?.progress === 1) {
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1270
1422
|
|
|
1271
1423
|
/** When args are a valid object, they are likely already invoked */
|
|
1272
1424
|
let args =
|