@cognipeer/agent-sdk 0.7.2 → 0.8.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 +17 -1
- package/dist/index.cjs +834 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +352 -2
- package/dist/index.d.ts +352 -2
- package/dist/index.mjs +819 -33
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -2583,6 +2583,27 @@ function validateToolArgs(tool, args) {
|
|
|
2583
2583
|
}
|
|
2584
2584
|
}
|
|
2585
2585
|
|
|
2586
|
+
// src/utils/pendingToolCalls.ts
|
|
2587
|
+
function selectPendingToolCalls(messages) {
|
|
2588
|
+
if (!Array.isArray(messages) || messages.length === 0) return [];
|
|
2589
|
+
const last = messages[messages.length - 1];
|
|
2590
|
+
if (last?.role === "assistant") {
|
|
2591
|
+
return Array.isArray(last.tool_calls) ? last.tool_calls : [];
|
|
2592
|
+
}
|
|
2593
|
+
const resolvedIds = /* @__PURE__ */ new Set();
|
|
2594
|
+
for (const m of messages) {
|
|
2595
|
+
if (m?.role === "tool" && m.tool_call_id != null) resolvedIds.add(String(m.tool_call_id));
|
|
2596
|
+
}
|
|
2597
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
2598
|
+
const m = messages[i];
|
|
2599
|
+
if (m?.role !== "assistant") continue;
|
|
2600
|
+
const calls = Array.isArray(m.tool_calls) ? m.tool_calls : [];
|
|
2601
|
+
if (calls.length === 0) return [];
|
|
2602
|
+
return calls.filter((c) => c?.id == null || !resolvedIds.has(String(c.id)));
|
|
2603
|
+
}
|
|
2604
|
+
return [];
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2586
2607
|
// src/nodes/tools.ts
|
|
2587
2608
|
function normalizeMaxExecutionsPerRun(value) {
|
|
2588
2609
|
if (value === null || value === void 0 || value === "") return null;
|
|
@@ -2740,9 +2761,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
2740
2761
|
anyTool._stateRef.parentRuntime = runtime;
|
|
2741
2762
|
}
|
|
2742
2763
|
}
|
|
2743
|
-
const last = state.messages[state.messages.length - 1];
|
|
2744
2764
|
let toolCount = state.toolCallCount || 0;
|
|
2745
|
-
const toolCalls =
|
|
2765
|
+
const toolCalls = selectPendingToolCalls(state.messages).map((toolCall) => normalizeToolCall(toolCall)).filter((toolCall) => toolCall !== null);
|
|
2746
2766
|
const toolHistory = state.toolHistory || [];
|
|
2747
2767
|
const toolHistoryArchived = state.toolHistoryArchived || [];
|
|
2748
2768
|
const remaining = Math.max(0, limits.maxToolCalls - toolCount);
|
|
@@ -3984,12 +4004,20 @@ function resolveUserQuestionState(state, resolution) {
|
|
|
3984
4004
|
entry.notes = resolution.notes;
|
|
3985
4005
|
entry.answeredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3986
4006
|
pending[matchIndex] = entry;
|
|
4007
|
+
const isSubagentQuestion = Boolean(entry.metadata?.__subagent);
|
|
3987
4008
|
const ctx = { ...state.ctx || {} };
|
|
3988
4009
|
delete ctx.__awaitingUserQuestion;
|
|
3989
|
-
if (ctx.__resumeStage === "tools") {
|
|
4010
|
+
if (ctx.__resumeStage === "tools" && !isSubagentQuestion) {
|
|
3990
4011
|
delete ctx.__resumeStage;
|
|
3991
4012
|
}
|
|
3992
4013
|
ctx.__userQuestionResolved = { id: entry.id, status: entry.status };
|
|
4014
|
+
if (isSubagentQuestion) {
|
|
4015
|
+
return {
|
|
4016
|
+
...state,
|
|
4017
|
+
pendingUserQuestions: pending,
|
|
4018
|
+
ctx
|
|
4019
|
+
};
|
|
4020
|
+
}
|
|
3993
4021
|
const toolMessage = {
|
|
3994
4022
|
role: "tool",
|
|
3995
4023
|
name: "ask_user_question",
|
|
@@ -4270,6 +4298,88 @@ var StructuredOutputManager = class {
|
|
|
4270
4298
|
}
|
|
4271
4299
|
};
|
|
4272
4300
|
|
|
4301
|
+
// src/smart/subagents/registry.ts
|
|
4302
|
+
function findSubagent(subagents, name) {
|
|
4303
|
+
return subagents.find((entry) => entry.name === name);
|
|
4304
|
+
}
|
|
4305
|
+
async function resolveAvailableSubagents(subagents) {
|
|
4306
|
+
const out = [];
|
|
4307
|
+
for (const entry of subagents) {
|
|
4308
|
+
const available = entry.isAvailable ? await entry.isAvailable() : true;
|
|
4309
|
+
if (available) out.push(entry);
|
|
4310
|
+
}
|
|
4311
|
+
return out;
|
|
4312
|
+
}
|
|
4313
|
+
function canSpawn(ref, policy, count = 1) {
|
|
4314
|
+
if (policy.mode === "off") {
|
|
4315
|
+
return { ok: false, reason: "sub-agents are disabled by runtime policy" };
|
|
4316
|
+
}
|
|
4317
|
+
if (ref.spawnedCount + count > policy.maxChildCalls) {
|
|
4318
|
+
return {
|
|
4319
|
+
ok: false,
|
|
4320
|
+
reason: `child-call budget exhausted (${policy.maxChildCalls}); ${ref.spawnedCount} already spawned`
|
|
4321
|
+
};
|
|
4322
|
+
}
|
|
4323
|
+
return { ok: true };
|
|
4324
|
+
}
|
|
4325
|
+
function withinDepth(currentDepth, policy) {
|
|
4326
|
+
if (currentDepth >= policy.maxDepth) {
|
|
4327
|
+
return { ok: false, reason: `delegation depth limit reached (${policy.maxDepth})` };
|
|
4328
|
+
}
|
|
4329
|
+
return { ok: true };
|
|
4330
|
+
}
|
|
4331
|
+
function seedChildMessages(policy, parentMessages, input) {
|
|
4332
|
+
const messages = (Array.isArray(parentMessages) ? parentMessages : []).filter((m) => m?.role !== "system");
|
|
4333
|
+
switch (policy) {
|
|
4334
|
+
case "full":
|
|
4335
|
+
return [...messages, { role: "user", content: input }];
|
|
4336
|
+
case "scoped": {
|
|
4337
|
+
const lastUser = [...messages].reverse().find((m) => m?.role === "user");
|
|
4338
|
+
return [
|
|
4339
|
+
...lastUser ? [lastUser] : [],
|
|
4340
|
+
{ role: "user", content: input }
|
|
4341
|
+
];
|
|
4342
|
+
}
|
|
4343
|
+
case "minimal":
|
|
4344
|
+
default:
|
|
4345
|
+
return [{ role: "user", content: input }];
|
|
4346
|
+
}
|
|
4347
|
+
}
|
|
4348
|
+
async function resolveSubagentTools(declared, parentTools) {
|
|
4349
|
+
if (!declared) return [];
|
|
4350
|
+
if (typeof declared === "function") {
|
|
4351
|
+
return await declared();
|
|
4352
|
+
}
|
|
4353
|
+
if (Array.isArray(declared) && declared.length > 0 && typeof declared[0] === "string") {
|
|
4354
|
+
const wanted = new Set(declared);
|
|
4355
|
+
return parentTools.filter((tool) => wanted.has(tool?.name));
|
|
4356
|
+
}
|
|
4357
|
+
return declared;
|
|
4358
|
+
}
|
|
4359
|
+
function buildSubagentCatalogBlock(subagents, policy, toolNames) {
|
|
4360
|
+
const lines = ["<available_subagents>"];
|
|
4361
|
+
const adhoc = policy.mode === "registry_and_adhoc";
|
|
4362
|
+
lines.push(
|
|
4363
|
+
"Delegate self-contained subtasks to focused sub-agents. Each runs with an isolated context and returns a concise result. Use them to decompose hard problems; do NOT delegate trivial steps you can do directly."
|
|
4364
|
+
);
|
|
4365
|
+
if (subagents.length > 0) {
|
|
4366
|
+
lines.push(`Call ${toolNames.delegate}(subagent, input) for a named sub-agent:`);
|
|
4367
|
+
for (const entry of subagents) {
|
|
4368
|
+
lines.push(`- ${entry.name}: ${entry.header}`);
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
if (adhoc) {
|
|
4372
|
+
lines.push(
|
|
4373
|
+
`Call ${toolNames.spawn}({ role, prompt, input, tools? }) to create a sub-agent on the fly.`
|
|
4374
|
+
);
|
|
4375
|
+
}
|
|
4376
|
+
lines.push(
|
|
4377
|
+
`Call ${toolNames.parallel}({ tasks: [...] }) to run up to ${policy.maxParallel} independent subtasks concurrently (no human-input tools inside parallel children).`
|
|
4378
|
+
);
|
|
4379
|
+
lines.push("</available_subagents>");
|
|
4380
|
+
return lines.join("\n");
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4273
4383
|
// src/agent.ts
|
|
4274
4384
|
function getLastAssistantMessage(messages) {
|
|
4275
4385
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
@@ -4641,7 +4751,7 @@ function createAgent(opts) {
|
|
|
4641
4751
|
resumeStage = null;
|
|
4642
4752
|
}
|
|
4643
4753
|
const lastMsg = state.messages[state.messages.length - 1];
|
|
4644
|
-
const toolCalls =
|
|
4754
|
+
const toolCalls = selectPendingToolCalls(state.messages);
|
|
4645
4755
|
const toolCallCount = state.toolCallCount || 0;
|
|
4646
4756
|
if (state.ctx?.__finalizedDueToToolLimit) {
|
|
4647
4757
|
break;
|
|
@@ -4941,27 +5051,28 @@ function createAgent(opts) {
|
|
|
4941
5051
|
error: `Child-call budget exhausted (${delegationPolicy.maxChildCalls}).`
|
|
4942
5052
|
};
|
|
4943
5053
|
}
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
case "scoped": {
|
|
4950
|
-
const systemPrefix = parentMessages[0]?.role === "system" ? [parentMessages[0]] : [];
|
|
4951
|
-
const lastUser = [...parentMessages].reverse().find((m) => m?.role === "user");
|
|
4952
|
-
childMessages = [
|
|
4953
|
-
...systemPrefix,
|
|
4954
|
-
...lastUser ? [lastUser] : [],
|
|
4955
|
-
{ role: "user", content: input }
|
|
4956
|
-
];
|
|
4957
|
-
break;
|
|
4958
|
-
}
|
|
4959
|
-
case "minimal":
|
|
4960
|
-
default:
|
|
4961
|
-
childMessages = [{ role: "user", content: input }];
|
|
4962
|
-
}
|
|
5054
|
+
const childMessages = seedChildMessages(
|
|
5055
|
+
delegationPolicy.childContextPolicy,
|
|
5056
|
+
parentMessages,
|
|
5057
|
+
input
|
|
5058
|
+
);
|
|
4963
5059
|
const childCtx = { __delegationDepth: currentDepth + 1 };
|
|
4964
|
-
const
|
|
5060
|
+
const childConfig = {
|
|
5061
|
+
onEvent: parentCtx.__onEvent ? (e) => {
|
|
5062
|
+
if (e?.type === "finalAnswer" || e?.type === "metadata") return;
|
|
5063
|
+
try {
|
|
5064
|
+
parentCtx.__onEvent({ ...e, delegatedTo: opts.name });
|
|
5065
|
+
} catch {
|
|
5066
|
+
}
|
|
5067
|
+
} : void 0,
|
|
5068
|
+
onProgress: parentCtx.__onProgress,
|
|
5069
|
+
onStream: parentCtx.__streaming && parentCtx.__onStream ? (chunk) => {
|
|
5070
|
+
if (!chunk?.isFinal) parentCtx.__onStream(chunk);
|
|
5071
|
+
} : void 0,
|
|
5072
|
+
stream: Boolean(parentCtx.__streaming),
|
|
5073
|
+
cancellationToken: parentCtx.__cancellationToken ?? parentCtx.__abortSignal
|
|
5074
|
+
};
|
|
5075
|
+
const res = await instance.invoke({ messages: childMessages, ctx: childCtx }, childConfig);
|
|
4965
5076
|
return {
|
|
4966
5077
|
content: res.content,
|
|
4967
5078
|
output: res.output,
|
|
@@ -6388,6 +6499,421 @@ function createSkillTools(deps) {
|
|
|
6388
6499
|
return [createOpenSkillTool(deps), createBindSkillToolsTool(deps)];
|
|
6389
6500
|
}
|
|
6390
6501
|
|
|
6502
|
+
// src/smart/subagents/types.ts
|
|
6503
|
+
var DEFAULT_SUBAGENT_POLICY = {
|
|
6504
|
+
mode: "registry_and_adhoc",
|
|
6505
|
+
maxDepth: 2,
|
|
6506
|
+
maxChildCalls: 8,
|
|
6507
|
+
maxParallel: 4,
|
|
6508
|
+
childContextPolicy: "scoped",
|
|
6509
|
+
allowAdhocTools: true
|
|
6510
|
+
};
|
|
6511
|
+
function createSubagentRegistryRef() {
|
|
6512
|
+
return { spawnedCount: 0, results: [] };
|
|
6513
|
+
}
|
|
6514
|
+
var DEFAULT_SUBAGENT_TOOL_NAMES = {
|
|
6515
|
+
delegate: "delegate_to",
|
|
6516
|
+
spawn: "spawn_subagent",
|
|
6517
|
+
parallel: "spawn_subagents_parallel"
|
|
6518
|
+
};
|
|
6519
|
+
var DEFAULT_DELEGATE_DESCRIPTION = "Delegate a self-contained subtask to a predefined sub-agent. Pass the sub-agent name (from <available_subagents>) and a complete, standalone `input` describing the task and the expected result. The sub-agent runs in isolation and returns a concise result.";
|
|
6520
|
+
var DEFAULT_SPAWN_DESCRIPTION = "Create a sub-agent on the fly. Provide a short `role`, a `prompt` defining how it should behave, and a complete `input` task. Optionally pass `tools` (names of the parent's tools the sub-agent may use). Use for one-off specialist subtasks.";
|
|
6521
|
+
var DEFAULT_PARALLEL_DESCRIPTION = "Run several independent subtasks concurrently. Each task is either a registry `subagent` + `input`, or an ad-hoc `role` + `prompt` + `input`. Returns one result per task in order. Do NOT use for tasks that require human input (approval / questions).";
|
|
6522
|
+
var CTX_CALLBACK_KEYS = /* @__PURE__ */ new Set([
|
|
6523
|
+
"__onEvent",
|
|
6524
|
+
"__onProgress",
|
|
6525
|
+
"__onStream",
|
|
6526
|
+
"__traceSession",
|
|
6527
|
+
"__paused",
|
|
6528
|
+
"__cancellationToken",
|
|
6529
|
+
"__abortSignal",
|
|
6530
|
+
"__deadline"
|
|
6531
|
+
]);
|
|
6532
|
+
function cleanChildState(state) {
|
|
6533
|
+
const { agent: _agent, ctx, ...rest } = state;
|
|
6534
|
+
let cleanCtx2;
|
|
6535
|
+
if (ctx && typeof ctx === "object") {
|
|
6536
|
+
cleanCtx2 = {};
|
|
6537
|
+
for (const [k, v] of Object.entries(ctx)) {
|
|
6538
|
+
if (CTX_CALLBACK_KEYS.has(k)) continue;
|
|
6539
|
+
cleanCtx2[k] = v;
|
|
6540
|
+
}
|
|
6541
|
+
}
|
|
6542
|
+
return { ...rest, ctx: cleanCtx2 };
|
|
6543
|
+
}
|
|
6544
|
+
function makeChildEventForwarder(parentOnEvent, spawnId, name) {
|
|
6545
|
+
return (event) => {
|
|
6546
|
+
if (!parentOnEvent) return;
|
|
6547
|
+
if (event?.type === "finalAnswer" || event?.type === "metadata") return;
|
|
6548
|
+
try {
|
|
6549
|
+
parentOnEvent({ ...event, subagentId: spawnId, subagentName: name });
|
|
6550
|
+
} catch {
|
|
6551
|
+
}
|
|
6552
|
+
};
|
|
6553
|
+
}
|
|
6554
|
+
function buildChildConfig(parentCtx, spawnId, name) {
|
|
6555
|
+
const streaming = Boolean(parentCtx.__streaming);
|
|
6556
|
+
const parentOnStream = parentCtx.__onStream;
|
|
6557
|
+
return {
|
|
6558
|
+
onEvent: makeChildEventForwarder(parentCtx.__onEvent, spawnId, name),
|
|
6559
|
+
onProgress: parentCtx.__onProgress,
|
|
6560
|
+
// Forward streaming deltas but swallow the child's `isFinal` chunk so the
|
|
6561
|
+
// host does not mistake a child completion for the parent's final answer.
|
|
6562
|
+
onStream: streaming && parentOnStream ? (chunk) => {
|
|
6563
|
+
if (!chunk.isFinal) parentOnStream(chunk);
|
|
6564
|
+
} : void 0,
|
|
6565
|
+
stream: streaming,
|
|
6566
|
+
cancellationToken: parentCtx.__cancellationToken ?? parentCtx.__abortSignal
|
|
6567
|
+
};
|
|
6568
|
+
}
|
|
6569
|
+
function summaryOf(state) {
|
|
6570
|
+
const summaries = state?.summaries;
|
|
6571
|
+
return Array.isArray(summaries) && summaries.length > 0 ? summaries[summaries.length - 1] : void 0;
|
|
6572
|
+
}
|
|
6573
|
+
async function runChild(spec, input, deps, ref, opts) {
|
|
6574
|
+
const parentCtx = ref.ctx || {};
|
|
6575
|
+
const parentOnEvent = parentCtx.__onEvent;
|
|
6576
|
+
const spawnId = `sa_${nanoid.nanoid(6)}`;
|
|
6577
|
+
const start = Date.now();
|
|
6578
|
+
const child = deps.buildChild({
|
|
6579
|
+
name: spec.name,
|
|
6580
|
+
model: spec.model,
|
|
6581
|
+
systemPrompt: spec.systemPrompt,
|
|
6582
|
+
tools: spec.tools,
|
|
6583
|
+
outputSchema: spec.outputSchema,
|
|
6584
|
+
limits: spec.limits
|
|
6585
|
+
});
|
|
6586
|
+
const childConfig = buildChildConfig(parentCtx, spawnId, spec.name);
|
|
6587
|
+
let childInput;
|
|
6588
|
+
if (opts.isResume && opts.record) {
|
|
6589
|
+
const restored = { ...opts.record.childState };
|
|
6590
|
+
if (opts.record.pendingKind === "approval") {
|
|
6591
|
+
const entry = (ref.pendingApprovals || []).find((e) => e.id === opts.record.pendingId);
|
|
6592
|
+
if (!entry) {
|
|
6593
|
+
return { kind: "result", result: { name: spec.name, mode: spec.mode, input, error: "Pending approval resolution missing on resume." } };
|
|
6594
|
+
}
|
|
6595
|
+
if (entry.status === "pending") {
|
|
6596
|
+
if (!parentCtx.__awaitingApproval) {
|
|
6597
|
+
parentCtx.__awaitingApproval = { approvalId: entry.id, toolCallId: entry.toolCallId, toolName: entry.toolName, requestedAt: entry.requestedAt };
|
|
6598
|
+
}
|
|
6599
|
+
parentCtx.__resumeStage = "tools";
|
|
6600
|
+
return { kind: "approval", toolCallId: entry.toolCallId, approvalId: entry.id };
|
|
6601
|
+
}
|
|
6602
|
+
childInput = resolveToolApprovalState(restored, {
|
|
6603
|
+
id: opts.record.pendingId,
|
|
6604
|
+
approved: entry.status === "approved",
|
|
6605
|
+
approvedArgs: entry.approvedArgs,
|
|
6606
|
+
decidedBy: entry.decidedBy,
|
|
6607
|
+
comment: entry.comment
|
|
6608
|
+
});
|
|
6609
|
+
} else {
|
|
6610
|
+
const entry = (ref.pendingUserQuestions || []).find((e) => e.id === opts.record.pendingId);
|
|
6611
|
+
if (!entry) {
|
|
6612
|
+
return { kind: "result", result: { name: spec.name, mode: spec.mode, input, error: "Pending question resolution missing on resume." } };
|
|
6613
|
+
}
|
|
6614
|
+
if (entry.status === "pending") {
|
|
6615
|
+
if (!parentCtx.__awaitingUserQuestion) {
|
|
6616
|
+
parentCtx.__awaitingUserQuestion = { id: entry.id, toolCallId: entry.toolCallId, requestedAt: entry.requestedAt };
|
|
6617
|
+
}
|
|
6618
|
+
parentCtx.__resumeStage = "tools";
|
|
6619
|
+
return { kind: "user_question", toolCallId: entry.toolCallId, id: entry.id };
|
|
6620
|
+
}
|
|
6621
|
+
childInput = resolveUserQuestionState(restored, {
|
|
6622
|
+
id: opts.record.pendingId,
|
|
6623
|
+
answers: entry.answers,
|
|
6624
|
+
answeredBy: entry.answeredBy,
|
|
6625
|
+
notes: entry.notes,
|
|
6626
|
+
cancelled: entry.cancelled === true
|
|
6627
|
+
});
|
|
6628
|
+
}
|
|
6629
|
+
} else {
|
|
6630
|
+
parentOnEvent?.({ type: "subagent", phase: "start", name: spec.name, id: spawnId, mode: spec.mode, parallel: opts.parallel, parentToolCallId: opts.parentToolCallId, input });
|
|
6631
|
+
const currentDepth = Number(parentCtx.__delegationDepth) || 0;
|
|
6632
|
+
childInput = {
|
|
6633
|
+
messages: seedChildMessages(spec.childContextPolicy, ref.messages || [], input),
|
|
6634
|
+
ctx: { __delegationDepth: currentDepth + 1 }
|
|
6635
|
+
};
|
|
6636
|
+
}
|
|
6637
|
+
let res;
|
|
6638
|
+
try {
|
|
6639
|
+
res = await child.invoke(childInput, childConfig);
|
|
6640
|
+
} catch (err) {
|
|
6641
|
+
const result2 = { name: spec.name, mode: spec.mode, input, error: err?.message || String(err), durationMs: Date.now() - start };
|
|
6642
|
+
deps.registryRef.results.push(result2);
|
|
6643
|
+
parentOnEvent?.({ type: "subagent", phase: "error", name: spec.name, id: spawnId, mode: spec.mode, error: { message: result2.error }, parentToolCallId: opts.parentToolCallId });
|
|
6644
|
+
return { kind: "result", result: result2 };
|
|
6645
|
+
}
|
|
6646
|
+
const childState = res.state;
|
|
6647
|
+
const awaitingApproval = childState?.ctx?.__awaitingApproval;
|
|
6648
|
+
const awaitingQuestion = childState?.ctx?.__awaitingUserQuestion;
|
|
6649
|
+
if (childState && (awaitingApproval || awaitingQuestion)) {
|
|
6650
|
+
if (!opts.allowHITL) {
|
|
6651
|
+
const result2 = {
|
|
6652
|
+
name: spec.name,
|
|
6653
|
+
mode: spec.mode,
|
|
6654
|
+
input,
|
|
6655
|
+
error: "Sub-agent requested human input, which is not supported inside parallel fan-out. Run it via delegate_to / spawn_subagent instead.",
|
|
6656
|
+
durationMs: Date.now() - start
|
|
6657
|
+
};
|
|
6658
|
+
deps.registryRef.results.push(result2);
|
|
6659
|
+
return { kind: "result", result: result2 };
|
|
6660
|
+
}
|
|
6661
|
+
const pendingStore = parentCtx.__subagentPending || (parentCtx.__subagentPending = {});
|
|
6662
|
+
if (awaitingApproval) {
|
|
6663
|
+
const childEntry = (childState.pendingApprovals || []).find((e) => e.status === "pending");
|
|
6664
|
+
if (childEntry) {
|
|
6665
|
+
const surfaced = { ...childEntry, metadata: { ...childEntry.metadata || {}, __subagent: { parentToolCallId: opts.parentToolCallId, name: spec.name } } };
|
|
6666
|
+
(ref.pendingApprovals || (ref.pendingApprovals = [])).push(surfaced);
|
|
6667
|
+
if (!parentCtx.__awaitingApproval && !parentCtx.__awaitingUserQuestion) {
|
|
6668
|
+
parentCtx.__awaitingApproval = { approvalId: surfaced.id, toolCallId: surfaced.toolCallId, toolName: surfaced.toolName, requestedAt: surfaced.requestedAt };
|
|
6669
|
+
}
|
|
6670
|
+
parentCtx.__resumeStage = "tools";
|
|
6671
|
+
pendingStore[opts.parentToolCallId] = {
|
|
6672
|
+
parentToolCallId: opts.parentToolCallId,
|
|
6673
|
+
name: spec.name,
|
|
6674
|
+
mode: spec.mode,
|
|
6675
|
+
adhoc: spec.adhoc,
|
|
6676
|
+
input,
|
|
6677
|
+
childState: cleanChildState(childState),
|
|
6678
|
+
pendingKind: "approval",
|
|
6679
|
+
pendingId: childEntry.id
|
|
6680
|
+
};
|
|
6681
|
+
parentOnEvent?.({ type: "subagent", phase: "paused", name: spec.name, id: spawnId, mode: spec.mode, parentToolCallId: opts.parentToolCallId });
|
|
6682
|
+
return { kind: "approval", toolCallId: surfaced.toolCallId, approvalId: surfaced.id };
|
|
6683
|
+
}
|
|
6684
|
+
}
|
|
6685
|
+
if (awaitingQuestion) {
|
|
6686
|
+
const childEntry = (childState.pendingUserQuestions || []).find((e) => e.status === "pending");
|
|
6687
|
+
if (childEntry) {
|
|
6688
|
+
const surfaced = { ...childEntry, metadata: { ...childEntry.metadata || {}, __subagent: { parentToolCallId: opts.parentToolCallId, name: spec.name } } };
|
|
6689
|
+
(ref.pendingUserQuestions || (ref.pendingUserQuestions = [])).push(surfaced);
|
|
6690
|
+
if (!parentCtx.__awaitingUserQuestion && !parentCtx.__awaitingApproval) {
|
|
6691
|
+
parentCtx.__awaitingUserQuestion = { id: surfaced.id, toolCallId: surfaced.toolCallId, requestedAt: surfaced.requestedAt };
|
|
6692
|
+
}
|
|
6693
|
+
parentCtx.__resumeStage = "tools";
|
|
6694
|
+
pendingStore[opts.parentToolCallId] = {
|
|
6695
|
+
parentToolCallId: opts.parentToolCallId,
|
|
6696
|
+
name: spec.name,
|
|
6697
|
+
mode: spec.mode,
|
|
6698
|
+
adhoc: spec.adhoc,
|
|
6699
|
+
input,
|
|
6700
|
+
childState: cleanChildState(childState),
|
|
6701
|
+
pendingKind: "user_question",
|
|
6702
|
+
pendingId: childEntry.id
|
|
6703
|
+
};
|
|
6704
|
+
parentOnEvent?.({ type: "subagent", phase: "paused", name: spec.name, id: spawnId, mode: spec.mode, parentToolCallId: opts.parentToolCallId });
|
|
6705
|
+
return { kind: "user_question", toolCallId: surfaced.toolCallId, id: surfaced.id };
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
}
|
|
6709
|
+
if (parentCtx.__subagentPending?.[opts.parentToolCallId]) {
|
|
6710
|
+
delete parentCtx.__subagentPending[opts.parentToolCallId];
|
|
6711
|
+
}
|
|
6712
|
+
const result = {
|
|
6713
|
+
name: spec.name,
|
|
6714
|
+
mode: spec.mode,
|
|
6715
|
+
input,
|
|
6716
|
+
content: res.content,
|
|
6717
|
+
output: res.output,
|
|
6718
|
+
summary: summaryOf(childState),
|
|
6719
|
+
durationMs: Date.now() - start
|
|
6720
|
+
};
|
|
6721
|
+
deps.registryRef.results.push(result);
|
|
6722
|
+
parentOnEvent?.({ type: "subagent", phase: "result", name: spec.name, id: spawnId, mode: spec.mode, content: res.content, durationMs: result.durationMs, parentToolCallId: opts.parentToolCallId });
|
|
6723
|
+
return { kind: "result", result };
|
|
6724
|
+
}
|
|
6725
|
+
async function specFromRegistry(def, deps, parentRuntime) {
|
|
6726
|
+
const tools = await resolveSubagentTools(def.tools, parentRuntime?.tools || []);
|
|
6727
|
+
return {
|
|
6728
|
+
name: def.name,
|
|
6729
|
+
mode: "registry",
|
|
6730
|
+
systemPrompt: def.systemPrompt,
|
|
6731
|
+
model: def.model ?? parentRuntime?.model,
|
|
6732
|
+
tools,
|
|
6733
|
+
outputSchema: def.outputSchema,
|
|
6734
|
+
limits: def.limits,
|
|
6735
|
+
childContextPolicy: def.childContextPolicy ?? deps.policy.childContextPolicy,
|
|
6736
|
+
metadata: def.metadata
|
|
6737
|
+
};
|
|
6738
|
+
}
|
|
6739
|
+
async function specFromAdhoc(args, deps, parentRuntime) {
|
|
6740
|
+
const toolNames = deps.policy.allowAdhocTools ? args.tools ?? args.toolNames ?? [] : [];
|
|
6741
|
+
const tools = await resolveSubagentTools(toolNames, parentRuntime?.tools || []);
|
|
6742
|
+
const systemPrompt = [args.prompt, args.outputContract ? `Output contract: ${args.outputContract}` : ""].filter(Boolean).join("\n\n");
|
|
6743
|
+
return {
|
|
6744
|
+
name: args.role,
|
|
6745
|
+
mode: "adhoc",
|
|
6746
|
+
systemPrompt: systemPrompt || void 0,
|
|
6747
|
+
model: parentRuntime?.model,
|
|
6748
|
+
tools,
|
|
6749
|
+
childContextPolicy: deps.policy.childContextPolicy,
|
|
6750
|
+
adhoc: { role: args.role, prompt: args.prompt, toolNames, outputContract: args.outputContract }
|
|
6751
|
+
};
|
|
6752
|
+
}
|
|
6753
|
+
function toToolReturn(outcome) {
|
|
6754
|
+
if (outcome.kind === "approval") {
|
|
6755
|
+
return { __awaitingToolApproval: true, toolCallId: outcome.toolCallId, approvalId: outcome.approvalId };
|
|
6756
|
+
}
|
|
6757
|
+
if (outcome.kind === "user_question") {
|
|
6758
|
+
return { __awaitingUserQuestion: true, toolCallId: outcome.toolCallId, id: outcome.id };
|
|
6759
|
+
}
|
|
6760
|
+
return outcome.result;
|
|
6761
|
+
}
|
|
6762
|
+
function createDelegateTool(deps) {
|
|
6763
|
+
const names = deps.subagents.map((s) => s.name);
|
|
6764
|
+
const tool = createTool({
|
|
6765
|
+
name: "delegate_to",
|
|
6766
|
+
description: deps.descriptions?.delegate ?? DEFAULT_DELEGATE_DESCRIPTION,
|
|
6767
|
+
schema: zod.z.object({
|
|
6768
|
+
subagent: (names.length > 0 ? zod.z.enum(names) : zod.z.string().min(1)).describe("Name of a sub-agent from <available_subagents>."),
|
|
6769
|
+
input: zod.z.string().min(1).describe("Complete, standalone task for the sub-agent.")
|
|
6770
|
+
}).strict(),
|
|
6771
|
+
func: async ({ subagent, input }) => {
|
|
6772
|
+
const ref = tool._stateRef || {};
|
|
6773
|
+
const d = tool._deps;
|
|
6774
|
+
const parentRuntime = ref.parentRuntime;
|
|
6775
|
+
const parentToolCallId = ref.__currentToolCallId || `delegate_${nanoid.nanoid(6)}`;
|
|
6776
|
+
const parentCtx = ref.ctx || (ref.ctx = {});
|
|
6777
|
+
const def = findSubagent(d.subagents, subagent);
|
|
6778
|
+
if (!def) return { error: `Unknown sub-agent: ${subagent}. Choose one from <available_subagents>.` };
|
|
6779
|
+
if (def.isAvailable && !await def.isAvailable()) return { error: `Sub-agent ${subagent} is not available right now.` };
|
|
6780
|
+
const record = parentCtx.__subagentPending?.[parentToolCallId];
|
|
6781
|
+
const spec = await specFromRegistry(def, d, parentRuntime);
|
|
6782
|
+
if (!record) {
|
|
6783
|
+
const depth = withinDepth(Number(parentCtx.__delegationDepth) || 0, d.policy);
|
|
6784
|
+
if (!depth.ok) return { error: depth.reason };
|
|
6785
|
+
const budget = canSpawn(d.registryRef, d.policy, 1);
|
|
6786
|
+
if (!budget.ok) return { error: budget.reason };
|
|
6787
|
+
d.registryRef.spawnedCount += 1;
|
|
6788
|
+
}
|
|
6789
|
+
return toToolReturn(await runChild(spec, record?.input ?? input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record }));
|
|
6790
|
+
}
|
|
6791
|
+
});
|
|
6792
|
+
tool._deps = deps;
|
|
6793
|
+
tool._stateRef = {};
|
|
6794
|
+
tool.__source = "smart-subagents";
|
|
6795
|
+
return tool;
|
|
6796
|
+
}
|
|
6797
|
+
function createSpawnTool(deps) {
|
|
6798
|
+
const tool = createTool({
|
|
6799
|
+
name: "spawn_subagent",
|
|
6800
|
+
description: deps.descriptions?.spawn ?? DEFAULT_SPAWN_DESCRIPTION,
|
|
6801
|
+
schema: zod.z.object({
|
|
6802
|
+
role: zod.z.string().min(1).describe("Short role name, e.g. 'db-analyst'."),
|
|
6803
|
+
prompt: zod.z.string().optional().describe("System prompt defining how the sub-agent behaves."),
|
|
6804
|
+
input: zod.z.string().min(1).describe("Complete, standalone task for the sub-agent."),
|
|
6805
|
+
tools: zod.z.array(zod.z.string().min(1)).optional().describe("Names of the parent's tools the sub-agent may use."),
|
|
6806
|
+
outputContract: zod.z.string().optional().describe("Optional description of the expected output shape.")
|
|
6807
|
+
}).strict(),
|
|
6808
|
+
func: async (args) => {
|
|
6809
|
+
const ref = tool._stateRef || {};
|
|
6810
|
+
const d = tool._deps;
|
|
6811
|
+
if (d.policy.mode !== "registry_and_adhoc") {
|
|
6812
|
+
return { error: "Ad-hoc sub-agents are disabled (subagentPolicy.mode is not 'registry_and_adhoc'). Use delegate_to." };
|
|
6813
|
+
}
|
|
6814
|
+
const parentRuntime = ref.parentRuntime;
|
|
6815
|
+
const parentToolCallId = ref.__currentToolCallId || `spawn_${nanoid.nanoid(6)}`;
|
|
6816
|
+
const parentCtx = ref.ctx || (ref.ctx = {});
|
|
6817
|
+
const record = parentCtx.__subagentPending?.[parentToolCallId];
|
|
6818
|
+
const spec = record?.adhoc ? await specFromAdhoc(record.adhoc, d, parentRuntime) : await specFromAdhoc(args, d, parentRuntime);
|
|
6819
|
+
if (!record) {
|
|
6820
|
+
const depth = withinDepth(Number(parentCtx.__delegationDepth) || 0, d.policy);
|
|
6821
|
+
if (!depth.ok) return { error: depth.reason };
|
|
6822
|
+
const budget = canSpawn(d.registryRef, d.policy, 1);
|
|
6823
|
+
if (!budget.ok) return { error: budget.reason };
|
|
6824
|
+
d.registryRef.spawnedCount += 1;
|
|
6825
|
+
}
|
|
6826
|
+
return toToolReturn(await runChild(spec, record?.input ?? args.input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record }));
|
|
6827
|
+
}
|
|
6828
|
+
});
|
|
6829
|
+
tool._deps = deps;
|
|
6830
|
+
tool._stateRef = {};
|
|
6831
|
+
tool.__source = "smart-subagents";
|
|
6832
|
+
return tool;
|
|
6833
|
+
}
|
|
6834
|
+
function createParallelTool(deps) {
|
|
6835
|
+
const tool = createTool({
|
|
6836
|
+
name: "spawn_subagents_parallel",
|
|
6837
|
+
description: deps.descriptions?.parallel ?? DEFAULT_PARALLEL_DESCRIPTION,
|
|
6838
|
+
schema: zod.z.object({
|
|
6839
|
+
tasks: zod.z.array(
|
|
6840
|
+
zod.z.object({
|
|
6841
|
+
subagent: zod.z.string().optional().describe("Registry sub-agent name."),
|
|
6842
|
+
role: zod.z.string().optional().describe("Ad-hoc role (when not using `subagent`)."),
|
|
6843
|
+
prompt: zod.z.string().optional(),
|
|
6844
|
+
tools: zod.z.array(zod.z.string().min(1)).optional(),
|
|
6845
|
+
input: zod.z.string().min(1)
|
|
6846
|
+
}).strict()
|
|
6847
|
+
).min(1).max(16).describe("Independent subtasks to run concurrently.")
|
|
6848
|
+
}).strict(),
|
|
6849
|
+
func: async ({ tasks }) => {
|
|
6850
|
+
const ref = tool._stateRef || {};
|
|
6851
|
+
const d = tool._deps;
|
|
6852
|
+
const parentRuntime = ref.parentRuntime;
|
|
6853
|
+
const parentToolCallId = ref.__currentToolCallId || `parallel_${nanoid.nanoid(6)}`;
|
|
6854
|
+
const parentCtx = ref.ctx || (ref.ctx = {});
|
|
6855
|
+
const depth = withinDepth(Number(parentCtx.__delegationDepth) || 0, d.policy);
|
|
6856
|
+
if (!depth.ok) return { error: depth.reason };
|
|
6857
|
+
const specs = [];
|
|
6858
|
+
for (const task of tasks) {
|
|
6859
|
+
if (task.subagent) {
|
|
6860
|
+
const def = findSubagent(d.subagents, task.subagent);
|
|
6861
|
+
if (!def) {
|
|
6862
|
+
specs.push({ error: `Unknown sub-agent: ${task.subagent}`, input: task.input });
|
|
6863
|
+
continue;
|
|
6864
|
+
}
|
|
6865
|
+
specs.push({ spec: await specFromRegistry(def, d, parentRuntime), input: task.input });
|
|
6866
|
+
} else if (task.role) {
|
|
6867
|
+
if (d.policy.mode !== "registry_and_adhoc") {
|
|
6868
|
+
specs.push({ error: "Ad-hoc sub-agents are disabled.", input: task.input });
|
|
6869
|
+
continue;
|
|
6870
|
+
}
|
|
6871
|
+
specs.push({ spec: await specFromAdhoc({ role: task.role, prompt: task.prompt, tools: task.tools }, d, parentRuntime), input: task.input });
|
|
6872
|
+
} else {
|
|
6873
|
+
specs.push({ error: "Each task needs either `subagent` or `role`.", input: task.input });
|
|
6874
|
+
}
|
|
6875
|
+
}
|
|
6876
|
+
const spawnCount = specs.filter((entry) => !("error" in entry)).length;
|
|
6877
|
+
const budget = canSpawn(d.registryRef, d.policy, spawnCount);
|
|
6878
|
+
if (!budget.ok) return { error: budget.reason };
|
|
6879
|
+
d.registryRef.spawnedCount += spawnCount;
|
|
6880
|
+
const results = new Array(specs.length);
|
|
6881
|
+
const concurrency = Math.max(1, Math.min(d.policy.maxParallel, specs.length));
|
|
6882
|
+
let cursor = 0;
|
|
6883
|
+
const worker = async () => {
|
|
6884
|
+
while (true) {
|
|
6885
|
+
const i = cursor++;
|
|
6886
|
+
if (i >= specs.length) return;
|
|
6887
|
+
const entry = specs[i];
|
|
6888
|
+
if ("error" in entry) {
|
|
6889
|
+
results[i] = { name: "?", mode: "adhoc", input: entry.input, error: entry.error };
|
|
6890
|
+
continue;
|
|
6891
|
+
}
|
|
6892
|
+
const outcome = await runChild(entry.spec, entry.input, d, ref, {
|
|
6893
|
+
allowHITL: false,
|
|
6894
|
+
parentToolCallId: `${parentToolCallId}#${i}`,
|
|
6895
|
+
parallel: true
|
|
6896
|
+
});
|
|
6897
|
+
results[i] = outcome.kind === "result" ? outcome.result : { name: entry.spec.name, mode: entry.spec.mode, input: entry.input, error: "Unexpected pause in parallel child." };
|
|
6898
|
+
}
|
|
6899
|
+
};
|
|
6900
|
+
await Promise.all(Array.from({ length: concurrency }, () => worker()));
|
|
6901
|
+
return { results };
|
|
6902
|
+
}
|
|
6903
|
+
});
|
|
6904
|
+
tool._deps = deps;
|
|
6905
|
+
tool._stateRef = {};
|
|
6906
|
+
tool.__source = "smart-subagents";
|
|
6907
|
+
return tool;
|
|
6908
|
+
}
|
|
6909
|
+
function createSubagentTools(deps) {
|
|
6910
|
+
const tools = [];
|
|
6911
|
+
if (deps.subagents.length > 0) tools.push(createDelegateTool(deps));
|
|
6912
|
+
if (deps.policy.mode === "registry_and_adhoc") tools.push(createSpawnTool(deps));
|
|
6913
|
+
tools.push(createParallelTool(deps));
|
|
6914
|
+
return tools;
|
|
6915
|
+
}
|
|
6916
|
+
|
|
6391
6917
|
// src/smart/index.ts
|
|
6392
6918
|
function createSmartAgent(opts) {
|
|
6393
6919
|
const resolved = normalizeSmartAgentOptions(opts);
|
|
@@ -6425,6 +6951,42 @@ function createSmartAgent(opts) {
|
|
|
6425
6951
|
const skills = opts.skills ?? [];
|
|
6426
6952
|
const skillPolicy = opts.skillPolicy ?? DEFAULT_SKILL_POLICY;
|
|
6427
6953
|
const skillsEnabled = skills.length > 0;
|
|
6954
|
+
const subagentsProvided = opts.subagents !== void 0 || opts.subagentPolicy !== void 0;
|
|
6955
|
+
const subagents = opts.subagents ?? [];
|
|
6956
|
+
const subagentPolicy = opts.subagentPolicy ?? DEFAULT_SUBAGENT_POLICY;
|
|
6957
|
+
const subagentsEnabled = subagentsProvided && subagentPolicy.mode !== "off" && (subagents.length > 0 || subagentPolicy.mode === "registry_and_adhoc");
|
|
6958
|
+
const promptHooks = opts.promptHooks;
|
|
6959
|
+
const buildChild = (cfg) => createSmartAgent({
|
|
6960
|
+
name: cfg.name,
|
|
6961
|
+
model: cfg.model,
|
|
6962
|
+
tools: cfg.tools,
|
|
6963
|
+
systemPrompt: cfg.systemPrompt,
|
|
6964
|
+
outputSchema: cfg.outputSchema,
|
|
6965
|
+
limits: cfg.limits,
|
|
6966
|
+
runtimeProfile: resolved.runtimeProfile,
|
|
6967
|
+
humanInTheLoop: opts.humanInTheLoop,
|
|
6968
|
+
reasoning: opts.reasoning,
|
|
6969
|
+
tokenCounter: opts.tokenCounter,
|
|
6970
|
+
costEstimator: opts.costEstimator,
|
|
6971
|
+
promptHooks,
|
|
6972
|
+
// Sub-agents are single-level by design: a child never gets its own spawn
|
|
6973
|
+
// tools, so it cannot delegate further. This keeps decomposition bounded and
|
|
6974
|
+
// is why the depth guard mainly governs `asTool`-composed nesting (which seeds
|
|
6975
|
+
// __delegationDepth externally) rather than sub-agent-of-sub-agent recursion.
|
|
6976
|
+
subagents: [],
|
|
6977
|
+
subagentPolicy: { ...subagentPolicy, mode: "off" }
|
|
6978
|
+
});
|
|
6979
|
+
const decorateToolDescriptions = (tools) => {
|
|
6980
|
+
const overrides = promptHooks?.toolDescriptions;
|
|
6981
|
+
if (!overrides) return tools;
|
|
6982
|
+
return tools.map((tool) => {
|
|
6983
|
+
const override = overrides[tool?.name];
|
|
6984
|
+
if (override === void 0) return tool;
|
|
6985
|
+
const next = typeof override === "function" ? override(tool.description || "") : override;
|
|
6986
|
+
if (next === tool.description) return tool;
|
|
6987
|
+
return { ...tool, description: next };
|
|
6988
|
+
});
|
|
6989
|
+
};
|
|
6428
6990
|
const soManagerFactory = opts.outputSchema ? new StructuredOutputManager(opts.outputSchema, resolveStrategy(opts.model)) : void 0;
|
|
6429
6991
|
const modelCapabilities = opts.outputSchema ? getModelCapabilities(opts.model) : void 0;
|
|
6430
6992
|
const responseFinalizeTool = soManagerFactory && modelCapabilities?.structuredOutput !== "native" ? soManagerFactory.getResponseTool() : void 0;
|
|
@@ -6435,12 +6997,27 @@ function createSmartAgent(opts) {
|
|
|
6435
6997
|
const coreBase = [...userTools, ...ctxTools];
|
|
6436
6998
|
if (responseFinalizeTool) coreBase.push(responseFinalizeTool);
|
|
6437
6999
|
if (askUserConfig) coreBase.push(createAskUserQuestionTool(ref, askUserConfig));
|
|
7000
|
+
let subagentRegistryRef;
|
|
7001
|
+
if (subagentsEnabled) {
|
|
7002
|
+
subagentRegistryRef = createSubagentRegistryRef();
|
|
7003
|
+
const deps = {
|
|
7004
|
+
registryRef: subagentRegistryRef,
|
|
7005
|
+
subagents,
|
|
7006
|
+
policy: subagentPolicy,
|
|
7007
|
+
buildChild
|
|
7008
|
+
// NOTE: promptHooks.toolDescriptions overrides for the sub-agent tools are
|
|
7009
|
+
// applied uniformly (and only) by decorateToolDescriptions below, so the
|
|
7010
|
+
// function form of an override receives the real DEFAULT_* string. Baking
|
|
7011
|
+
// them in here as well would double-apply and stringify the function.
|
|
7012
|
+
};
|
|
7013
|
+
coreBase.push(...createSubagentTools(deps));
|
|
7014
|
+
}
|
|
6438
7015
|
if (!skillsEnabled) {
|
|
6439
|
-
const without = coreBase;
|
|
6440
|
-
const withRec = [...
|
|
6441
|
-
return { stateRef: ref, toolsWithoutRecovery: without, toolsWithRecovery: withRec };
|
|
7016
|
+
const without = decorateToolDescriptions(coreBase);
|
|
7017
|
+
const withRec = decorateToolDescriptions([...coreBase, recoveryTool]);
|
|
7018
|
+
return { stateRef: ref, toolsWithoutRecovery: without, toolsWithRecovery: withRec, subagentRegistryRef };
|
|
6442
7019
|
}
|
|
6443
|
-
const toolSet = { stateRef: ref, toolsWithoutRecovery: [], toolsWithRecovery: [] };
|
|
7020
|
+
const toolSet = { stateRef: ref, toolsWithoutRecovery: [], toolsWithRecovery: [], subagentRegistryRef };
|
|
6444
7021
|
const skillRegistryRef = createSkillRegistryRef();
|
|
6445
7022
|
const skillMetaTools = createSkillTools({ registryRef: skillRegistryRef, skills, policy: skillPolicy });
|
|
6446
7023
|
const baseWithMeta = [...coreBase, ...skillMetaTools];
|
|
@@ -6450,14 +7027,43 @@ function createSmartAgent(opts) {
|
|
|
6450
7027
|
boundSkillTools: skillRegistryRef.boundSkillTools,
|
|
6451
7028
|
recoveryTool
|
|
6452
7029
|
});
|
|
6453
|
-
toolSet.toolsWithoutRecovery = composed.toolsWithoutRecovery;
|
|
6454
|
-
toolSet.toolsWithRecovery = composed.toolsWithRecovery;
|
|
7030
|
+
toolSet.toolsWithoutRecovery = decorateToolDescriptions(composed.toolsWithoutRecovery);
|
|
7031
|
+
toolSet.toolsWithRecovery = decorateToolDescriptions(composed.toolsWithRecovery);
|
|
6455
7032
|
};
|
|
6456
7033
|
skillRegistryRef.__onToolsChanged = rebuild;
|
|
6457
7034
|
toolSet.skillRegistryRef = skillRegistryRef;
|
|
6458
7035
|
rebuild();
|
|
6459
7036
|
return toolSet;
|
|
6460
7037
|
};
|
|
7038
|
+
async function rehydrateSkillRegistry(ref, persisted) {
|
|
7039
|
+
if (!persisted) return false;
|
|
7040
|
+
const opened = Array.isArray(persisted.openedSkillKeys) ? persisted.openedSkillKeys : [];
|
|
7041
|
+
const boundNames = new Set(Array.isArray(persisted.boundToolNames) ? persisted.boundToolNames : []);
|
|
7042
|
+
if (opened.length === 0) return false;
|
|
7043
|
+
let changed = false;
|
|
7044
|
+
for (const key of opened) {
|
|
7045
|
+
if (!ref.openedSkillKeys.includes(key)) ref.openedSkillKeys.push(key);
|
|
7046
|
+
const skill = skills.find((s) => s.key === key);
|
|
7047
|
+
if (!skill) continue;
|
|
7048
|
+
let bound;
|
|
7049
|
+
try {
|
|
7050
|
+
bound = await skill.bindTools();
|
|
7051
|
+
} catch {
|
|
7052
|
+
continue;
|
|
7053
|
+
}
|
|
7054
|
+
const wanted = bound.filter((t) => boundNames.has(t.name));
|
|
7055
|
+
const added = appendBoundTools(ref, wanted, skillPolicy);
|
|
7056
|
+
if (added.length > 0) changed = true;
|
|
7057
|
+
}
|
|
7058
|
+
return changed;
|
|
7059
|
+
}
|
|
7060
|
+
function skillStateFromRegistry(ref) {
|
|
7061
|
+
if (!ref || !Array.isArray(ref.openedSkillKeys) || ref.openedSkillKeys.length === 0) return void 0;
|
|
7062
|
+
return {
|
|
7063
|
+
openedSkillKeys: [...ref.openedSkillKeys],
|
|
7064
|
+
boundToolNames: (ref.boundSkillTools || []).map((t) => t.name)
|
|
7065
|
+
};
|
|
7066
|
+
}
|
|
6461
7067
|
const base = createAgent({ ...runtimeOpts, tools: factoryToolsWithoutRecovery });
|
|
6462
7068
|
base.__runtime.runtimeProfile = resolved.runtimeProfile;
|
|
6463
7069
|
base.__runtime.smart = resolved;
|
|
@@ -6508,12 +7114,19 @@ function createSmartAgent(opts) {
|
|
|
6508
7114
|
};
|
|
6509
7115
|
}
|
|
6510
7116
|
function systemMessage2(extraBlock) {
|
|
6511
|
-
|
|
7117
|
+
let sys = buildSystemPrompt(
|
|
6512
7118
|
[opts.systemPrompt, runtimeHint, structuredOutputHint, extraBlock].filter(Boolean).join("\n"),
|
|
6513
7119
|
planningEnabled,
|
|
6514
7120
|
opts.name || "Agent",
|
|
6515
7121
|
opts.todoListPrompt
|
|
6516
7122
|
);
|
|
7123
|
+
if (promptHooks?.transformSystemPrompt) {
|
|
7124
|
+
try {
|
|
7125
|
+
sys = promptHooks.transformSystemPrompt(sys, { agentName: opts.name || "Agent" });
|
|
7126
|
+
} catch (err) {
|
|
7127
|
+
console.warn("[agent-sdk] promptHooks.transformSystemPrompt error:", err);
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
6517
7130
|
return { role: "system", content: sys };
|
|
6518
7131
|
}
|
|
6519
7132
|
function syncRuntimeTools(currentState, currentMessages, toolSet) {
|
|
@@ -6558,11 +7171,33 @@ function createSmartAgent(opts) {
|
|
|
6558
7171
|
stateRef.todoList = input.plan?.steps;
|
|
6559
7172
|
stateRef.planVersion = input.planVersion || input.plan?.version || 0;
|
|
6560
7173
|
stateRef.adherenceScore = input.plan?.adherenceScore || 0;
|
|
7174
|
+
if (skillsEnabled && toolSet.skillRegistryRef) {
|
|
7175
|
+
const changed = await rehydrateSkillRegistry(toolSet.skillRegistryRef, input.ctx?.__skillState);
|
|
7176
|
+
if (changed) toolSet.skillRegistryRef.__onToolsChanged?.();
|
|
7177
|
+
}
|
|
6561
7178
|
const syncPlanFromRef = (state2) => syncPlanStateWith(stateRef, state2);
|
|
6562
7179
|
const availableSkills = skillsEnabled ? await resolveAvailableSkills(skills, { modelTier: skillPolicy.modelTier }) : [];
|
|
6563
7180
|
const skillBlock = availableSkills.length > 0 ? buildSkillHeaderBlock(availableSkills) : void 0;
|
|
7181
|
+
let subagentBlock;
|
|
7182
|
+
if (subagentsEnabled) {
|
|
7183
|
+
const availableSubagents = await resolveAvailableSubagents(subagents);
|
|
7184
|
+
let block = buildSubagentCatalogBlock(availableSubagents, subagentPolicy, {
|
|
7185
|
+
delegate: "delegate_to",
|
|
7186
|
+
spawn: "spawn_subagent",
|
|
7187
|
+
parallel: "spawn_subagents_parallel"
|
|
7188
|
+
});
|
|
7189
|
+
if (promptHooks?.subagentCatalog) {
|
|
7190
|
+
try {
|
|
7191
|
+
block = promptHooks.subagentCatalog(block, availableSubagents);
|
|
7192
|
+
} catch (err) {
|
|
7193
|
+
console.warn("[agent-sdk] promptHooks.subagentCatalog error:", err);
|
|
7194
|
+
}
|
|
7195
|
+
}
|
|
7196
|
+
subagentBlock = block;
|
|
7197
|
+
}
|
|
7198
|
+
const disclosureBlock = [skillBlock, subagentBlock].filter(Boolean).join("\n\n") || void 0;
|
|
6564
7199
|
const alreadyHasSystem = Array.isArray(input.messages) && input.messages[0]?.role === "system";
|
|
6565
|
-
const seedMessages = alreadyHasSystem ? [...input.messages || []] : [systemMessage2(
|
|
7200
|
+
const seedMessages = alreadyHasSystem ? [...input.messages || []] : [systemMessage2(disclosureBlock), ...input.messages || []];
|
|
6566
7201
|
let state = syncRuntimeTools(await syncMemory({ ...input, messages: seedMessages }), seedMessages, toolSet);
|
|
6567
7202
|
let lastResult = null;
|
|
6568
7203
|
let rawMessages = [...seedMessages];
|
|
@@ -6635,6 +7270,13 @@ function createSmartAgent(opts) {
|
|
|
6635
7270
|
} else if (lastResult.state) {
|
|
6636
7271
|
lastResult = { ...lastResult, state: { ...lastResult.state, memoryFacts: state.memoryFacts, plan: state.plan, planVersion: state.planVersion, messages: rawMessages } };
|
|
6637
7272
|
}
|
|
7273
|
+
if (skillsEnabled && lastResult.state) {
|
|
7274
|
+
const persisted = skillStateFromRegistry(toolSet.skillRegistryRef);
|
|
7275
|
+
if (persisted) {
|
|
7276
|
+
const prevCtx = lastResult.state.ctx || {};
|
|
7277
|
+
lastResult = { ...lastResult, state: { ...lastResult.state, ctx: { ...prevCtx, __skillState: persisted } } };
|
|
7278
|
+
}
|
|
7279
|
+
}
|
|
6638
7280
|
return lastResult;
|
|
6639
7281
|
},
|
|
6640
7282
|
snapshot: base.snapshot,
|
|
@@ -6647,6 +7289,150 @@ function createSmartAgent(opts) {
|
|
|
6647
7289
|
};
|
|
6648
7290
|
return instance;
|
|
6649
7291
|
}
|
|
7292
|
+
var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
7293
|
+
function parseSkillFrontmatter(md) {
|
|
7294
|
+
const match = FRONTMATTER_RE.exec(md);
|
|
7295
|
+
if (!match) return { metadata: {}, body: md.trim() };
|
|
7296
|
+
return { metadata: parseFrontmatterBlock(match[1] ?? ""), body: md.slice(match[0].length).trim() };
|
|
7297
|
+
}
|
|
7298
|
+
var LIST_KEYS = /* @__PURE__ */ new Set([
|
|
7299
|
+
"scripts",
|
|
7300
|
+
"keywords",
|
|
7301
|
+
"tags",
|
|
7302
|
+
"allowed-tools",
|
|
7303
|
+
"allowed_tools",
|
|
7304
|
+
"compatible-models",
|
|
7305
|
+
"compatible_models"
|
|
7306
|
+
]);
|
|
7307
|
+
function parseFrontmatterBlock(raw) {
|
|
7308
|
+
const out = {};
|
|
7309
|
+
let listKey = null;
|
|
7310
|
+
let listAcc = [];
|
|
7311
|
+
const flush = () => {
|
|
7312
|
+
if (listKey) {
|
|
7313
|
+
out[listKey] = listAcc;
|
|
7314
|
+
listAcc = [];
|
|
7315
|
+
listKey = null;
|
|
7316
|
+
}
|
|
7317
|
+
};
|
|
7318
|
+
const splitList = (value) => value.split(",").map((v) => unquote(v.trim())).filter(Boolean);
|
|
7319
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
7320
|
+
if (line.trim() === "") continue;
|
|
7321
|
+
const item = /^\s*-\s+(.*)$/.exec(line);
|
|
7322
|
+
if (item && listKey) {
|
|
7323
|
+
listAcc.push(unquote(item[1].trim()));
|
|
7324
|
+
continue;
|
|
7325
|
+
}
|
|
7326
|
+
flush();
|
|
7327
|
+
const kv = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(line);
|
|
7328
|
+
if (!kv) continue;
|
|
7329
|
+
const [, key, rawValue] = kv;
|
|
7330
|
+
const value = rawValue.trim();
|
|
7331
|
+
if (value === "") {
|
|
7332
|
+
listKey = key;
|
|
7333
|
+
} else if (value.startsWith("[") && value.endsWith("]")) {
|
|
7334
|
+
out[key] = splitList(value.slice(1, -1));
|
|
7335
|
+
} else if (LIST_KEYS.has(key.toLowerCase())) {
|
|
7336
|
+
out[key] = splitList(value);
|
|
7337
|
+
} else {
|
|
7338
|
+
out[key] = unquote(value);
|
|
7339
|
+
}
|
|
7340
|
+
}
|
|
7341
|
+
flush();
|
|
7342
|
+
return out;
|
|
7343
|
+
}
|
|
7344
|
+
function unquote(s) {
|
|
7345
|
+
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
7346
|
+
return s.slice(1, -1);
|
|
7347
|
+
}
|
|
7348
|
+
return s;
|
|
7349
|
+
}
|
|
7350
|
+
function asArray(v) {
|
|
7351
|
+
if (v === void 0) return [];
|
|
7352
|
+
return Array.isArray(v) ? v : [v];
|
|
7353
|
+
}
|
|
7354
|
+
function sanitize(s) {
|
|
7355
|
+
return s.replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
|
|
7356
|
+
}
|
|
7357
|
+
function scriptToolName(skillName, scriptFile) {
|
|
7358
|
+
const base = scriptFile.replace(/\.[^.]+$/, "");
|
|
7359
|
+
return `${sanitize(skillName)}__${sanitize(base)}`;
|
|
7360
|
+
}
|
|
7361
|
+
var join = (...parts) => parts.join("/").replace(/\/{2,}/g, "/");
|
|
7362
|
+
function buildScriptTools(skillName, skillDir, scripts, execution) {
|
|
7363
|
+
const tools = scripts.map(
|
|
7364
|
+
(file) => createTool({
|
|
7365
|
+
name: scriptToolName(skillName, file),
|
|
7366
|
+
description: `Run the bundled "${file}" script from the "${skillName}" skill.`,
|
|
7367
|
+
schema: zod.z.object({
|
|
7368
|
+
args: zod.z.record(zod.z.any()).optional().describe("Arguments passed to the script.")
|
|
7369
|
+
}),
|
|
7370
|
+
needsApproval: true,
|
|
7371
|
+
approvalPrompt: `Run script ${file} from skill ${skillName}?`,
|
|
7372
|
+
func: (input) => execution.executeScript(join(skillDir, "scripts", file), input?.args ?? {})
|
|
7373
|
+
})
|
|
7374
|
+
);
|
|
7375
|
+
const headers = tools.map((t) => ({ name: t.name, description: t.description }));
|
|
7376
|
+
return { headers, tools };
|
|
7377
|
+
}
|
|
7378
|
+
async function loadOneSkill(fs2, skillDir, fallbackName, execution, minModelTier) {
|
|
7379
|
+
let md;
|
|
7380
|
+
try {
|
|
7381
|
+
md = await fs2.readFile(join(skillDir, "SKILL.md"));
|
|
7382
|
+
} catch {
|
|
7383
|
+
return null;
|
|
7384
|
+
}
|
|
7385
|
+
const { metadata, body } = parseSkillFrontmatter(md);
|
|
7386
|
+
const name = metadata.name ?? fallbackName;
|
|
7387
|
+
const description = metadata.description ?? "";
|
|
7388
|
+
const tier = metadata["min-model-tier"] ?? minModelTier;
|
|
7389
|
+
let scripts = asArray(metadata.scripts);
|
|
7390
|
+
if (scripts.length === 0) {
|
|
7391
|
+
try {
|
|
7392
|
+
scripts = await fs2.listDir(join(skillDir, "scripts"));
|
|
7393
|
+
} catch {
|
|
7394
|
+
scripts = [];
|
|
7395
|
+
}
|
|
7396
|
+
}
|
|
7397
|
+
const built = execution && scripts.length > 0 ? buildScriptTools(name, skillDir, scripts, execution) : { headers: [], tools: [] };
|
|
7398
|
+
const skill = {
|
|
7399
|
+
key: `skillmd:${name}`,
|
|
7400
|
+
title: name,
|
|
7401
|
+
header: description,
|
|
7402
|
+
prompt: body,
|
|
7403
|
+
needsSandbox: scripts.length > 0,
|
|
7404
|
+
listToolIndex: () => built.headers,
|
|
7405
|
+
bindTools: (names) => names ? built.tools.filter((t) => names.includes(t.name)) : built.tools
|
|
7406
|
+
};
|
|
7407
|
+
if (tier) skill.minModelTier = tier;
|
|
7408
|
+
return skill;
|
|
7409
|
+
}
|
|
7410
|
+
async function loadSkillsFromDisk(opts) {
|
|
7411
|
+
const skills = [];
|
|
7412
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7413
|
+
for (const root of opts.roots) {
|
|
7414
|
+
let entries;
|
|
7415
|
+
try {
|
|
7416
|
+
entries = await opts.fs.listDir(root);
|
|
7417
|
+
} catch {
|
|
7418
|
+
continue;
|
|
7419
|
+
}
|
|
7420
|
+
for (const entry of entries) {
|
|
7421
|
+
const skill = await loadOneSkill(
|
|
7422
|
+
opts.fs,
|
|
7423
|
+
join(root, entry),
|
|
7424
|
+
entry,
|
|
7425
|
+
opts.execution,
|
|
7426
|
+
opts.minModelTier
|
|
7427
|
+
);
|
|
7428
|
+
if (skill && !seen.has(skill.key)) {
|
|
7429
|
+
seen.add(skill.key);
|
|
7430
|
+
skills.push(skill);
|
|
7431
|
+
}
|
|
7432
|
+
}
|
|
7433
|
+
}
|
|
7434
|
+
return skills;
|
|
7435
|
+
}
|
|
6650
7436
|
|
|
6651
7437
|
// src/smart/eval.ts
|
|
6652
7438
|
function normalizeProfileTarget(target) {
|
|
@@ -9349,6 +10135,8 @@ exports.BaseProvider = BaseProvider;
|
|
|
9349
10135
|
exports.BedrockProvider = BedrockProvider;
|
|
9350
10136
|
exports.DEFAULT_PROFILE_CONFIGS = DEFAULT_PROFILE_CONFIGS;
|
|
9351
10137
|
exports.DEFAULT_SKILL_POLICY = DEFAULT_SKILL_POLICY;
|
|
10138
|
+
exports.DEFAULT_SUBAGENT_POLICY = DEFAULT_SUBAGENT_POLICY;
|
|
10139
|
+
exports.DEFAULT_SUBAGENT_TOOL_NAMES = DEFAULT_SUBAGENT_TOOL_NAMES;
|
|
9352
10140
|
exports.GuardrailPhase = GuardrailPhase;
|
|
9353
10141
|
exports.InMemoryMemoryStore = InMemoryMemoryStore;
|
|
9354
10142
|
exports.NativeJsonSchemaStrategy = NativeJsonSchemaStrategy;
|
|
@@ -9362,8 +10150,10 @@ exports.VertexProvider = VertexProvider;
|
|
|
9362
10150
|
exports.agentVerdictRule = agentVerdictRule;
|
|
9363
10151
|
exports.appendBoundTools = appendBoundTools;
|
|
9364
10152
|
exports.buildSkillHeaderBlock = buildSkillHeaderBlock;
|
|
10153
|
+
exports.buildSubagentCatalogBlock = buildSubagentCatalogBlock;
|
|
9365
10154
|
exports.buildSystemPrompt = buildSystemPrompt;
|
|
9366
10155
|
exports.canOpenSkill = canOpenSkill;
|
|
10156
|
+
exports.canSpawn = canSpawn;
|
|
9367
10157
|
exports.captureSnapshot = captureSnapshot;
|
|
9368
10158
|
exports.codePresenceRule = codePresenceRule;
|
|
9369
10159
|
exports.cognipeerSink = cognipeerSink;
|
|
@@ -9377,17 +10167,22 @@ exports.createBindSkillToolsTool = createBindSkillToolsTool;
|
|
|
9377
10167
|
exports.createCodeGuardrail = createCodeGuardrail;
|
|
9378
10168
|
exports.createContextSummarizeNode = createContextSummarizeNode;
|
|
9379
10169
|
exports.createContextTools = createContextTools;
|
|
10170
|
+
exports.createDelegateTool = createDelegateTool;
|
|
9380
10171
|
exports.createGetToolResponseTool = createGetToolResponseTool;
|
|
9381
10172
|
exports.createGuardrail = createGuardrail;
|
|
9382
10173
|
exports.createJsonGuardrail = createJsonGuardrail;
|
|
9383
10174
|
exports.createManageTodoTool = createManageTodoTool;
|
|
9384
10175
|
exports.createOpenSkillTool = createOpenSkillTool;
|
|
10176
|
+
exports.createParallelTool = createParallelTool;
|
|
9385
10177
|
exports.createProvider = createProvider;
|
|
9386
10178
|
exports.createRegexGuardrail = createRegexGuardrail;
|
|
9387
10179
|
exports.createResolverNode = createResolverNode;
|
|
9388
10180
|
exports.createSkillRegistryRef = createSkillRegistryRef;
|
|
9389
10181
|
exports.createSkillTools = createSkillTools;
|
|
9390
10182
|
exports.createSmartAgent = createSmartAgent;
|
|
10183
|
+
exports.createSpawnTool = createSpawnTool;
|
|
10184
|
+
exports.createSubagentRegistryRef = createSubagentRegistryRef;
|
|
10185
|
+
exports.createSubagentTools = createSubagentTools;
|
|
9391
10186
|
exports.createTool = createTool;
|
|
9392
10187
|
exports.createToolLimitFinalizeNode = createToolLimitFinalizeNode;
|
|
9393
10188
|
exports.createToolsNode = createToolsNode;
|
|
@@ -9398,6 +10193,7 @@ exports.defaultTokenCounter = defaultTokenCounter;
|
|
|
9398
10193
|
exports.emptyUsage = emptyUsage;
|
|
9399
10194
|
exports.evaluateGuardrails = evaluateGuardrails;
|
|
9400
10195
|
exports.fileSink = fileSink;
|
|
10196
|
+
exports.findSubagent = findSubagent;
|
|
9401
10197
|
exports.formatZodError = formatZodError;
|
|
9402
10198
|
exports.fromLangchainModel = fromLangchainModel;
|
|
9403
10199
|
exports.fromLangchainTools = fromLangchainTools;
|
|
@@ -9412,23 +10208,29 @@ exports.hasToolResponseRecoveryReference = hasToolResponseRecoveryReference;
|
|
|
9412
10208
|
exports.httpSink = httpSink;
|
|
9413
10209
|
exports.isSmartModel = isSmartModel;
|
|
9414
10210
|
exports.jsonSchemaRule = jsonSchemaRule;
|
|
10211
|
+
exports.loadSkillsFromDisk = loadSkillsFromDisk;
|
|
9415
10212
|
exports.normalizeSmartAgentOptions = normalizeSmartAgentOptions;
|
|
9416
10213
|
exports.otlpSink = otlpSink;
|
|
10214
|
+
exports.parseSkillFrontmatter = parseSkillFrontmatter;
|
|
9417
10215
|
exports.readMemoryFacts = readMemoryFacts;
|
|
9418
10216
|
exports.regexRule = regexRule;
|
|
9419
10217
|
exports.resolveAvailableSkills = resolveAvailableSkills;
|
|
10218
|
+
exports.resolveAvailableSubagents = resolveAvailableSubagents;
|
|
9420
10219
|
exports.resolveMemoryStore = resolveMemoryStore;
|
|
9421
10220
|
exports.resolveReasoning = resolveReasoning;
|
|
9422
10221
|
exports.resolveStrategy = resolveStrategy;
|
|
10222
|
+
exports.resolveSubagentTools = resolveSubagentTools;
|
|
9423
10223
|
exports.resolveToolApprovalState = resolveToolApprovalState;
|
|
9424
10224
|
exports.resolveUserQuestionState = resolveUserQuestionState;
|
|
9425
10225
|
exports.restoreSnapshot = restoreSnapshot;
|
|
9426
10226
|
exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
|
|
10227
|
+
exports.seedChildMessages = seedChildMessages;
|
|
9427
10228
|
exports.setTokenCounter = setTokenCounter;
|
|
9428
10229
|
exports.startStreamingSession = startStreamingSession;
|
|
9429
10230
|
exports.traceSessionToOtlp = traceSessionToOtlp;
|
|
9430
10231
|
exports.validateReasoningConfig = validateReasoningConfig;
|
|
9431
10232
|
exports.withTools = withTools;
|
|
10233
|
+
exports.withinDepth = withinDepth;
|
|
9432
10234
|
exports.writeSummaryFactsToMemory = writeSummaryFactsToMemory;
|
|
9433
10235
|
//# sourceMappingURL=index.cjs.map
|
|
9434
10236
|
//# sourceMappingURL=index.cjs.map
|