agent-accelerator 0.5.9 → 0.6.0
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/README.md +3 -1
- package/examples/prompts/SYSTEM_PROMPT.md +2 -0
- package/examples/prompts/SYSTEM_PROMPT_AGENT.md +4 -0
- package/examples/prompts/SYSTEM_PROMPT_TOOLS.md +1 -0
- package/package.json +4 -1
- package/src/agent/agent.ts +366 -161
- package/src/agent/architecture.md +13 -12
- package/src/agent/config-blocks.ts +39 -12
- package/src/agent/context.ts +8 -3
- package/src/agent/delegation.ts +82 -29
- package/src/agent/loop.ts +444 -365
- package/src/agent/subagent.ts +1 -3
- package/src/agent/subagents-tool.ts +45 -7
- package/src/agent/subagents.md +3 -0
- package/src/agent/turns.ts +3 -1
- package/src/agent/worker.ts +56 -27
- package/src/agent/workers.ts +113 -20
- package/src/architecture.md +16 -15
- package/src/index.ts +34 -10
- package/src/models/architecture.md +4 -3
- package/src/models/catalog-cache.ts +6 -5
- package/src/models/catalog.ts +39 -30
- package/src/providers/architecture.md +10 -8
- package/src/providers/google.ts +147 -59
- package/src/providers/openai-compat.ts +57 -49
- package/src/providers/openai.ts +54 -37
- package/src/providers/openrouter.ts +85 -30
- package/src/providers/registry.ts +6 -21
- package/src/providers/shared.ts +87 -33
- package/src/providers.ts +56 -115
- package/src/scheduler/architecture.md +7 -6
- package/src/scheduler/scheduled-actions.md +4 -0
- package/src/scheduler/scheduler.ts +186 -60
- package/src/scheduler/store.ts +23 -10
- package/src/scheduler/time.ts +17 -3
- package/src/scheduler/tool.ts +33 -7
- package/src/session/architecture.md +7 -6
- package/src/session/journal.ts +38 -12
- package/src/session/store.ts +122 -61
- package/src/session/usage.ts +58 -9
- package/src/streaming/architecture.md +4 -3
- package/src/streaming/event-stream.ts +26 -12
- package/src/telemetry.ts +6 -2
- package/src/tools/architecture.md +8 -7
- package/src/tools/executor.ts +50 -48
- package/src/tools/schema.ts +10 -6
- package/src/tools/subagent-result.ts +6 -1
- package/src/tools/tool.ts +9 -11
- package/src/types/agent.ts +2 -21
- package/src/types/architecture.md +11 -10
- package/src/types/core.ts +1 -9
- package/src/types/errors.ts +26 -4
- package/src/types/model.ts +0 -4
- package/src/types/tool.ts +12 -2
- package/src/update-models.ts +5 -5
- package/src/utils/architecture.md +16 -15
- package/src/utils/cache.ts +1 -3
- package/src/utils/durable.ts +17 -5
- package/src/utils/env.ts +9 -7
- package/src/utils/errors.ts +6 -14
- package/src/utils/headers.ts +3 -10
- package/src/utils/media.ts +23 -8
- package/src/utils/raw-capture.ts +9 -2
- package/src/utils/retry.ts +15 -3
- package/src/utils/safe-io.ts +29 -7
- package/src/utils/serialization.ts +1 -4
- package/src/utils/session.ts +1 -2
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
The agent and everything that runs under it.
|
|
4
4
|
|
|
5
|
-
| File
|
|
6
|
-
|
|
|
7
|
-
| `agent.ts`
|
|
8
|
-
| `loop.ts`
|
|
9
|
-
| `context.ts`
|
|
10
|
-
| `delegation.ts`
|
|
11
|
-
| `worker.ts`
|
|
12
|
-
| `workers.ts`
|
|
13
|
-
| `subagents-tool.ts` + `subagents.md` | The one model-facing `subagents` tool; the `.md` is its description.
|
|
14
|
-
| `subagent.ts`
|
|
15
|
-
| `turns.ts`
|
|
16
|
-
| `config-blocks.ts`
|
|
5
|
+
| File | What it is | Used by |
|
|
6
|
+
| :----------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------- |
|
|
7
|
+
| `agent.ts` | `Agent`: `run`/`stream`/`ask`, `steer`/`queue`/`interrupt`, persistence hooks, `resume()`/`interrupted()`, `usageReport()`, `fork()`, `toConfig()`/`fromConfig()`, the `workers` getter. | callers, workers, scheduler |
|
|
8
|
+
| `loop.ts` | `runAgentLoop` / `streamAgentLoop`: per turn budget, pairing repair, file access, provider call, tool execution, repeat guard. Also `ensureToolPairing`, `accumulateUsage`. | `Agent` |
|
|
9
|
+
| `context.ts` | `AgentContext`: the validated message list with checkpoint/rollback. | `Agent`, loops |
|
|
10
|
+
| `delegation.ts` | Fixed workers (`agentToTool`, `buildAgentTools`), the live worker trace store, session-id helpers, budget helpers, `openWorkerTrace`/`workerMetadata`. | `Agent`, `workers.ts` |
|
|
11
|
+
| `worker.ts` | Worker core: model/tool normalization, `buildDynamicWorkerConfig` (shared preset), `createLiveWorker`. | `Agent`, registry, scheduler |
|
|
12
|
+
| `workers.ts` | `WorkerRegistry` (`agent.workers`): persistent multi-turn workers. | `Agent`, `subagents` tool |
|
|
13
|
+
| `subagents-tool.ts` + `subagents.md` | The one model-facing `subagents` tool; the `.md` is its description. | `Agent` constructor |
|
|
14
|
+
| `subagent.ts` | `SubAgent` class and `agentFromEnv` (thin, kept for compatibility). | callers |
|
|
15
|
+
| `turns.ts` | Pure grouping of messages into finished turns (history cut for workers). | `workers.ts` |
|
|
16
|
+
| `config-blocks.ts` | RSI blocks: only `model`, `instructions`, `tools` are editable; `allowedModels` check. | `Agent` |
|
|
17
17
|
|
|
18
18
|
## Invariants
|
|
19
|
+
|
|
19
20
|
- `runAgentLoop` and `streamAgentLoop` duplicate their turn logic: every loop change goes into both.
|
|
20
21
|
- An `Agent` runs one thing at a time; delegation forks a copy per call so parallel calls never queue.
|
|
21
22
|
- A worker is a plain `Agent` with a parent link and presets. Never duplicate logic between Agent and worker.
|
|
@@ -22,25 +22,37 @@ export function modelKey(model: unknown): string | undefined {
|
|
|
22
22
|
export function assertModelAllowed(allowed: unknown, model: string | undefined): void {
|
|
23
23
|
if (allowed === undefined) return;
|
|
24
24
|
if (!Array.isArray(allowed) || allowed.length === 0 || allowed.some((m) => typeof m !== "string" || !m.trim())) {
|
|
25
|
-
throw new ConfigError(
|
|
25
|
+
throw new ConfigError(
|
|
26
|
+
`[Agent Accelerator] Invalid allowedModels ${JSON.stringify(allowed)}: expected a non-empty list of "provider/model" strings, or omit it to allow any model.`
|
|
27
|
+
);
|
|
26
28
|
}
|
|
27
29
|
if (!model || !allowed.includes(model)) {
|
|
28
|
-
throw new ConfigError(
|
|
30
|
+
throw new ConfigError(
|
|
31
|
+
`[Agent Accelerator] Model ${JSON.stringify(model ?? null)} is not in allowedModels. Allowed: ${allowed.map((m) => JSON.stringify(m)).join(", ")}.`
|
|
32
|
+
);
|
|
29
33
|
}
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
// The editable part of an agent as plain JSON; in: the Agent's model, instructions and the developer's tool list (not the built-in delegation/scheduler tools), out: Agent.toConfig.
|
|
33
|
-
export function toEditableConfig(
|
|
37
|
+
export function toEditableConfig(
|
|
38
|
+
model: unknown,
|
|
39
|
+
instructions: string,
|
|
40
|
+
tools: AgentConfig["tools"]
|
|
41
|
+
): Required<EditableAgentConfig> {
|
|
34
42
|
return { model: modelKey(model) ?? "", instructions, tools: Object.keys(normalizeToolMap(tools)) };
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
// Merges what an agent edited into the developer's config: only model/instructions/tools can change; tools are names picked from base.tools; the model is checked against allowedModels when the Agent is built; in: Agent.fromConfig args, out: the AgentConfig for `new Agent`.
|
|
38
46
|
export function applyEditable(editable: EditableAgentConfig, base: AgentConfig): AgentConfig {
|
|
39
47
|
if (!editable || typeof editable !== "object" || Array.isArray(editable)) {
|
|
40
|
-
throw new ConfigError(
|
|
48
|
+
throw new ConfigError(
|
|
49
|
+
`[Agent Accelerator] Invalid editable config ${JSON.stringify(editable)}: expected an object like { model, instructions, tools } (see Agent.toConfig()).`
|
|
50
|
+
);
|
|
41
51
|
}
|
|
42
52
|
const e = editable as Record<string, unknown>;
|
|
43
|
-
const ignored = Object.keys(e).filter(
|
|
53
|
+
const ignored = Object.keys(e).filter(
|
|
54
|
+
(k) => !(EDITABLE_FIELDS as readonly string[]).includes(k) && e[k] !== undefined
|
|
55
|
+
);
|
|
44
56
|
if (ignored.length > 0) {
|
|
45
57
|
telemetryBus.emitWarning(
|
|
46
58
|
"config.not_editable",
|
|
@@ -51,26 +63,41 @@ export function applyEditable(editable: EditableAgentConfig, base: AgentConfig):
|
|
|
51
63
|
const out: AgentConfig = { ...base };
|
|
52
64
|
if (e.model !== undefined) {
|
|
53
65
|
const next = typeof e.model === "string" ? e.model.trim() : "";
|
|
54
|
-
if (!next)
|
|
66
|
+
if (!next)
|
|
67
|
+
throw new ConfigError(
|
|
68
|
+
`[Agent Accelerator] Invalid editable model ${JSON.stringify(e.model)}: expected a "provider/model" string.`
|
|
69
|
+
);
|
|
55
70
|
// A model helper's key and base URL belong to its own provider: they are never sent to another one.
|
|
56
71
|
const prev = base.model as { model?: unknown; apiKey?: string; baseUrl?: string } | string | undefined;
|
|
57
72
|
const sameProvider = next.includes("/") && next.split("/")[0] === modelKey(prev)?.split("/")[0];
|
|
58
|
-
out.model =
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
out.model =
|
|
74
|
+
prev && typeof prev === "object" && typeof prev.model === "string"
|
|
75
|
+
? { ...prev, model: next, ...(sameProvider ? {} : { apiKey: undefined, baseUrl: undefined }) }
|
|
76
|
+
: next;
|
|
61
77
|
}
|
|
62
78
|
if (e.instructions !== undefined) {
|
|
63
|
-
if (typeof e.instructions !== "string")
|
|
79
|
+
if (typeof e.instructions !== "string")
|
|
80
|
+
throw new ConfigError(
|
|
81
|
+
`[Agent Accelerator] Invalid editable instructions: expected a string, got ${typeof e.instructions}.`
|
|
82
|
+
);
|
|
64
83
|
out.instructions = e.instructions;
|
|
65
84
|
}
|
|
66
85
|
if (e.tools !== undefined) {
|
|
67
86
|
if (!Array.isArray(e.tools) || e.tools.some((n) => typeof n !== "string")) {
|
|
68
|
-
throw new ConfigError(
|
|
87
|
+
throw new ConfigError(
|
|
88
|
+
`[Agent Accelerator] Invalid editable tools ${JSON.stringify(e.tools)}: expected a list of tool names from the developer's tool pool.`
|
|
89
|
+
);
|
|
69
90
|
}
|
|
70
91
|
const pool = normalizeToolMap(base.tools);
|
|
71
92
|
const unknown = (e.tools as string[]).filter((n) => !Object.hasOwn(pool, n));
|
|
72
93
|
if (unknown.length > 0) {
|
|
73
|
-
throw new ConfigError(
|
|
94
|
+
throw new ConfigError(
|
|
95
|
+
`[Agent Accelerator] Unknown tool ${unknown.map((n) => JSON.stringify(n)).join(", ")} in the editable config. Available: ${
|
|
96
|
+
Object.keys(pool)
|
|
97
|
+
.map((n) => JSON.stringify(n))
|
|
98
|
+
.join(", ") || "none"
|
|
99
|
+
}.`
|
|
100
|
+
);
|
|
74
101
|
}
|
|
75
102
|
const picked: Record<string, ToolDefinition> = {};
|
|
76
103
|
for (const n of e.tools as string[]) picked[n] = pool[n]!;
|
package/src/agent/context.ts
CHANGED
|
@@ -3,12 +3,13 @@ import type { ToolCallRecord, ToolResultRecord } from "../types/tool.ts";
|
|
|
3
3
|
import { safeStringify } from "../utils/serialization.ts";
|
|
4
4
|
import { clearSessionRouting } from "../providers.ts";
|
|
5
5
|
import { clearInteractionChains } from "../providers/google.ts";
|
|
6
|
+
import { ValidationError } from "../types/errors.ts";
|
|
6
7
|
|
|
7
8
|
const USER_PART_TYPES = new Set(["text", "image", "audio", "video", "file"]);
|
|
8
9
|
|
|
9
10
|
// Throws the AgentContext validation error with the SDK prefix; in: the add* validators, out: a thrown Error.
|
|
10
11
|
function fail(message: string): never {
|
|
11
|
-
throw new
|
|
12
|
+
throw new ValidationError(`[Agent Accelerator] AgentContext: ${message}`);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/** Deep clone that preserves Uint8Array/ArrayBuffer media (structuredClone may be absent). */
|
|
@@ -192,8 +193,12 @@ export class AgentContext {
|
|
|
192
193
|
if (Array.isArray(cp?.messages)) this.messages = deepCloneValue(cp.messages);
|
|
193
194
|
if (Array.isArray(cp?.signatures)) this.thoughtSignatures = [...cp.signatures];
|
|
194
195
|
if (sessionId) {
|
|
195
|
-
try {
|
|
196
|
-
|
|
196
|
+
try {
|
|
197
|
+
clearInteractionChains(sessionId);
|
|
198
|
+
} catch {}
|
|
199
|
+
try {
|
|
200
|
+
clearSessionRouting(sessionId);
|
|
201
|
+
} catch {}
|
|
197
202
|
}
|
|
198
203
|
}
|
|
199
204
|
}
|
package/src/agent/delegation.ts
CHANGED
|
@@ -61,7 +61,7 @@ export function createFixedChildSessionId(parentId: string, name: string): strin
|
|
|
61
61
|
return `${parentId.slice(0, maxParent - 9)}-${parentHash}${suffix}`;
|
|
62
62
|
}
|
|
63
63
|
if (maxParent > 0) return parentId.slice(0, maxParent) + suffix;
|
|
64
|
-
return
|
|
64
|
+
return `${parentId}-sub-${name}`.slice(0, 64);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
@@ -225,7 +225,9 @@ function notifyTrace(trackingId: string): void {
|
|
|
225
225
|
if (!listeners || listeners.size === 0) return;
|
|
226
226
|
const snap = snapshotTrace(t);
|
|
227
227
|
for (const fn of [...listeners]) {
|
|
228
|
-
try {
|
|
228
|
+
try {
|
|
229
|
+
fn(snap);
|
|
230
|
+
} catch {}
|
|
229
231
|
}
|
|
230
232
|
}
|
|
231
233
|
|
|
@@ -280,15 +282,23 @@ export function subscribeToSubAgent(id: string, fn: (trace: SubAgentTrace) => vo
|
|
|
280
282
|
}
|
|
281
283
|
set.add(fn);
|
|
282
284
|
const timer = setTimeout(() => {
|
|
283
|
-
try {
|
|
285
|
+
try {
|
|
286
|
+
subagentListeners.get(key)?.delete(fn);
|
|
287
|
+
} catch {}
|
|
284
288
|
}, SUBAGENT_SUBSCRIBE_TTL_MS);
|
|
285
|
-
try {
|
|
289
|
+
try {
|
|
290
|
+
(timer as unknown as { unref?: () => void }).unref?.();
|
|
291
|
+
} catch {}
|
|
286
292
|
let done = false;
|
|
287
293
|
return () => {
|
|
288
294
|
if (done) return;
|
|
289
295
|
done = true;
|
|
290
|
-
try {
|
|
291
|
-
|
|
296
|
+
try {
|
|
297
|
+
clearTimeout(timer);
|
|
298
|
+
} catch {}
|
|
299
|
+
try {
|
|
300
|
+
subagentListeners.get(key)?.delete(fn);
|
|
301
|
+
} catch {}
|
|
292
302
|
};
|
|
293
303
|
}
|
|
294
304
|
|
|
@@ -334,7 +344,13 @@ export function openWorkerTrace(a: {
|
|
|
334
344
|
role?: string;
|
|
335
345
|
/** When given, the trace is also kept in this agent's own registry and saved with its session. */
|
|
336
346
|
parent?: Agent;
|
|
337
|
-
emit?: (event: {
|
|
347
|
+
emit?: (event: {
|
|
348
|
+
trackingId: string;
|
|
349
|
+
delta?: string;
|
|
350
|
+
thinkingDelta?: string;
|
|
351
|
+
partialText?: string;
|
|
352
|
+
partialThinking?: string;
|
|
353
|
+
}) => void;
|
|
338
354
|
}): WorkerTraceHandle {
|
|
339
355
|
const trackingId = createTrackingId();
|
|
340
356
|
const displayId = `${a.name}-${trackingId}`;
|
|
@@ -360,9 +376,19 @@ export function openWorkerTrace(a: {
|
|
|
360
376
|
trim: (t) => trimTraceSteps(t),
|
|
361
377
|
touch: (id) => touchTrace(id),
|
|
362
378
|
notify: (id) => notifyTrace(id),
|
|
363
|
-
...(a.parent
|
|
379
|
+
...(a.parent
|
|
380
|
+
? {
|
|
381
|
+
persist: () => {
|
|
382
|
+
try {
|
|
383
|
+
a.parent!.persistNow();
|
|
384
|
+
} catch {}
|
|
385
|
+
},
|
|
386
|
+
}
|
|
387
|
+
: {}),
|
|
364
388
|
emit: (ev) => {
|
|
365
|
-
try {
|
|
389
|
+
try {
|
|
390
|
+
a.emit?.(ev);
|
|
391
|
+
} catch {}
|
|
366
392
|
},
|
|
367
393
|
});
|
|
368
394
|
const settle = (): void => {
|
|
@@ -386,7 +412,11 @@ export function openWorkerTrace(a: {
|
|
|
386
412
|
t.turns = result.turns ?? t.turns;
|
|
387
413
|
t.text = result.text;
|
|
388
414
|
if (result.usage) {
|
|
389
|
-
t.usage = {
|
|
415
|
+
t.usage = {
|
|
416
|
+
inputTokens: result.usage.inputTokens ?? 0,
|
|
417
|
+
outputTokens: result.usage.outputTokens ?? 0,
|
|
418
|
+
totalTokens: result.usage.totalTokens ?? 0,
|
|
419
|
+
};
|
|
390
420
|
}
|
|
391
421
|
}
|
|
392
422
|
settle();
|
|
@@ -492,7 +522,8 @@ function ensureBudgetState(parentAgent: Agent): BudgetState {
|
|
|
492
522
|
function usageTokens(usage: unknown): number {
|
|
493
523
|
const u = usage as { totalTokens?: unknown; inputTokens?: unknown; outputTokens?: unknown } | undefined;
|
|
494
524
|
if (!u || typeof u !== "object") return 0;
|
|
495
|
-
if (typeof u.totalTokens === "number" && Number.isFinite(u.totalTokens))
|
|
525
|
+
if (typeof u.totalTokens === "number" && Number.isFinite(u.totalTokens))
|
|
526
|
+
return Math.max(0, Math.floor(u.totalTokens));
|
|
496
527
|
const inp = typeof u.inputTokens === "number" && Number.isFinite(u.inputTokens) ? u.inputTokens : 0;
|
|
497
528
|
const out = typeof u.outputTokens === "number" && Number.isFinite(u.outputTokens) ? u.outputTokens : 0;
|
|
498
529
|
return Math.max(0, Math.floor(inp + out));
|
|
@@ -532,10 +563,9 @@ export function checkBudget(
|
|
|
532
563
|
);
|
|
533
564
|
}
|
|
534
565
|
if (budget.maxTotalTokens !== undefined && totalTokens > budget.maxTotalTokens) {
|
|
535
|
-
throw new BudgetExceededError(
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
);
|
|
566
|
+
throw new BudgetExceededError(`Token budget exceeded: ${totalTokens} > maxTotalTokens ${budget.maxTotalTokens}.`, {
|
|
567
|
+
context: { partial },
|
|
568
|
+
});
|
|
539
569
|
}
|
|
540
570
|
if (budget.maxCostUsd !== undefined && totalCostUsd > budget.maxCostUsd) {
|
|
541
571
|
throw new BudgetExceededError(
|
|
@@ -601,9 +631,7 @@ export interface AgentAsToolTarget {
|
|
|
601
631
|
*
|
|
602
632
|
* @example `const researchTool = researcher.asTool("research");`
|
|
603
633
|
*/
|
|
604
|
-
export function agentToTool(
|
|
605
|
-
input: Agent | AgentAsToolTarget
|
|
606
|
-
): ToolDefinition {
|
|
634
|
+
export function agentToTool(input: Agent | AgentAsToolTarget): ToolDefinition {
|
|
607
635
|
const agentInstance = "agent" in input ? input.agent : input;
|
|
608
636
|
const rawName =
|
|
609
637
|
("name" in input && (input as any).name) ||
|
|
@@ -635,28 +663,55 @@ export function agentToTool(
|
|
|
635
663
|
task,
|
|
636
664
|
emit: (ev) => ctx?.onSubagentEvent?.(ev),
|
|
637
665
|
});
|
|
638
|
-
const lineage = {
|
|
666
|
+
const lineage = {
|
|
667
|
+
name,
|
|
668
|
+
displayId: live.displayId,
|
|
669
|
+
sessionId: subSessionId,
|
|
670
|
+
parentSessionId,
|
|
671
|
+
task,
|
|
672
|
+
runId: callRunId,
|
|
673
|
+
turnId: callTurnId,
|
|
674
|
+
};
|
|
639
675
|
try {
|
|
640
676
|
// One isolated copy per call: the shared instance is single-flight, so
|
|
641
677
|
// calling it directly would serialize (or steer) parallel tool calls.
|
|
642
678
|
const worker: Agent =
|
|
643
|
-
typeof (agentInstance as Agent).fork === "function"
|
|
644
|
-
|
|
645
|
-
|
|
679
|
+
typeof (agentInstance as Agent).fork === "function"
|
|
680
|
+
? agentInstance.fork(subSessionId, parentSessionId)
|
|
681
|
+
: agentInstance;
|
|
682
|
+
const workerStream = worker.stream(task, {
|
|
683
|
+
signal: ctx?.signal,
|
|
684
|
+
sessionId: subSessionId,
|
|
685
|
+
onTurn: live.onWorkerTurn,
|
|
686
|
+
} as any);
|
|
687
|
+
const detachWorkerListeners = live.attachToStream(
|
|
688
|
+
workerStream as unknown as Parameters<typeof live.attachToStream>[0]
|
|
689
|
+
);
|
|
646
690
|
let response: AgentResponse;
|
|
647
691
|
try {
|
|
648
692
|
response = await workerStream.result();
|
|
649
693
|
} finally {
|
|
650
|
-
try {
|
|
694
|
+
try {
|
|
695
|
+
detachWorkerListeners();
|
|
696
|
+
} catch {}
|
|
651
697
|
// The per-call session id is never reused: drop its provider chain/routing state.
|
|
652
698
|
if (worker !== agentInstance) {
|
|
653
|
-
try {
|
|
654
|
-
|
|
699
|
+
try {
|
|
700
|
+
agentInstance.absorbUsage(worker.usageTotals);
|
|
701
|
+
} catch {} // the template keeps what its copies spent
|
|
702
|
+
try {
|
|
703
|
+
worker.reset();
|
|
704
|
+
} catch {}
|
|
655
705
|
}
|
|
656
706
|
}
|
|
657
707
|
live.finish(response);
|
|
658
708
|
return makeSubagentResult(response.text, [
|
|
659
|
-
workerMetadata({
|
|
709
|
+
workerMetadata({
|
|
710
|
+
...lineage,
|
|
711
|
+
durationMs: Math.max(0, nowMs() - startTime),
|
|
712
|
+
result: response,
|
|
713
|
+
steps: live.steps(),
|
|
714
|
+
}),
|
|
660
715
|
]);
|
|
661
716
|
} catch (err: any) {
|
|
662
717
|
const msg = err?.message || String(err);
|
|
@@ -674,9 +729,7 @@ export function agentToTool(
|
|
|
674
729
|
*
|
|
675
730
|
* @example `const tools = buildAgentTools([researcher, reviewer]);`
|
|
676
731
|
*/
|
|
677
|
-
export function buildAgentTools(
|
|
678
|
-
agents?: (Agent | AgentAsToolTarget)[]
|
|
679
|
-
): Record<string, ToolDefinition> {
|
|
732
|
+
export function buildAgentTools(agents?: (Agent | AgentAsToolTarget)[]): Record<string, ToolDefinition> {
|
|
680
733
|
if (!agents || agents.length === 0) return {};
|
|
681
734
|
|
|
682
735
|
const tools: Record<string, ToolDefinition> = {};
|