@agentforge-io/core 2.3.0 → 2.3.1
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.
|
@@ -379,6 +379,11 @@ class AgentService {
|
|
|
379
379
|
const filter = params.overrides?.extraToolsFilter;
|
|
380
380
|
const fromConnectors = filter && resolvedExtras ? filter(resolvedExtras) : resolvedExtras;
|
|
381
381
|
const extraTools = mergeExtraTools(params.overrides?.extraTools, fromConnectors);
|
|
382
|
+
// Hoisted accumulators so the post-loop persistence (after the
|
|
383
|
+
// try) can see the final list. Defined here, populated inside
|
|
384
|
+
// the for-await loop below.
|
|
385
|
+
const toolCallStartByUseId = new Map();
|
|
386
|
+
const accumulatedToolCalls = [];
|
|
382
387
|
try {
|
|
383
388
|
// Team orchestrators route through OrchestratorService.stream()
|
|
384
389
|
// so the synthetic `delegate_to_*` tools the orchestrator was
|
|
@@ -403,11 +408,56 @@ class AgentService {
|
|
|
403
408
|
messageId: 'streaming',
|
|
404
409
|
agent: { timezone: agent.timezone },
|
|
405
410
|
}, { ...(params.overrides ?? {}), extraTools });
|
|
411
|
+
// Accumulate tool_use / tool_result chunks during streaming so
|
|
412
|
+
// we can persist them on the assistant message row (line ~700).
|
|
413
|
+
// Without this, `getHistory` returns the assistant's text but
|
|
414
|
+
// loses the tool calls — which means clients that render
|
|
415
|
+
// proposal cards (Recording Assist) or generic tool rows from
|
|
416
|
+
// history have nothing to rehydrate. FIFO matching mirrors the
|
|
417
|
+
// runner's heuristic so the shape stays consistent whether the
|
|
418
|
+
// turn streamed or used `run()`.
|
|
406
419
|
for await (const chunk of stream) {
|
|
407
420
|
if (chunk.type === 'text_delta')
|
|
408
421
|
fullContent += chunk.delta;
|
|
409
422
|
if (chunk.type === 'usage')
|
|
410
423
|
finalUsage = chunk.usage;
|
|
424
|
+
if (chunk.type === 'tool_use_start') {
|
|
425
|
+
toolCallStartByUseId.set(chunk.toolUseId, {
|
|
426
|
+
name: chunk.toolName,
|
|
427
|
+
start: Date.now(),
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
if (chunk.type === 'tool_result') {
|
|
431
|
+
// Match by toolUseId when present; otherwise FIFO on toolName
|
|
432
|
+
// (matches AgentRunner.run's heuristic). Older runners that
|
|
433
|
+
// don't emit `toolUseId` on result chunks still produce a
|
|
434
|
+
// usable record.
|
|
435
|
+
let entry = null;
|
|
436
|
+
const useId = chunk.toolUseId;
|
|
437
|
+
if (useId && toolCallStartByUseId.has(useId)) {
|
|
438
|
+
const v = toolCallStartByUseId.get(useId);
|
|
439
|
+
entry = { id: useId, name: v.name, start: v.start };
|
|
440
|
+
toolCallStartByUseId.delete(useId);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
const fifo = Array.from(toolCallStartByUseId.entries()).find(([, v]) => v.name === chunk.toolName);
|
|
444
|
+
if (fifo) {
|
|
445
|
+
entry = { id: fifo[0], name: fifo[1].name, start: fifo[1].start };
|
|
446
|
+
toolCallStartByUseId.delete(fifo[0]);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (entry) {
|
|
450
|
+
accumulatedToolCalls.push({
|
|
451
|
+
toolName: entry.name,
|
|
452
|
+
toolUseId: entry.id,
|
|
453
|
+
input: {},
|
|
454
|
+
output: typeof chunk.result === 'string'
|
|
455
|
+
? chunk.result
|
|
456
|
+
: JSON.stringify(chunk.result),
|
|
457
|
+
durationMs: Date.now() - entry.start,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
411
461
|
yield chunk;
|
|
412
462
|
}
|
|
413
463
|
}
|
|
@@ -507,6 +557,12 @@ class AgentService {
|
|
|
507
557
|
role: 'assistant',
|
|
508
558
|
content: fullContent,
|
|
509
559
|
usage: finalUsage,
|
|
560
|
+
// Persist the accumulated tool calls so `getHistory` can
|
|
561
|
+
// surface them on reload — without this, proposal cards
|
|
562
|
+
// (Recording Assist) and other tool-result-driven UI
|
|
563
|
+
// disappear after refresh. Empty arrays drop to undefined
|
|
564
|
+
// so we don't pollute the column with `[]`.
|
|
565
|
+
toolCalls: accumulatedToolCalls.length > 0 ? accumulatedToolCalls : undefined,
|
|
510
566
|
});
|
|
511
567
|
const now = new Date();
|
|
512
568
|
await this.dispatchUsage({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge-io/core",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Framework-free AI runtime SDK. Owns: agent loop (pluggable LLM provider — Anthropic by default, LangChain-backed providers as drop-ins), conversations, tools, streaming, agent-job queue, SdkHooks. Identity, billing, infra (email/uploads/secrets) live in the host's modules — not here.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|