@cognipeer/agent-sdk 0.7.3 → 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/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 = Array.isArray(last?.tool_calls) ? last.tool_calls.map((toolCall) => normalizeToolCall(toolCall)).filter((toolCall) => toolCall !== null) : [];
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 = Array.isArray(lastMsg?.tool_calls) ? lastMsg.tool_calls : [];
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
- let childMessages;
4945
- switch (delegationPolicy.childContextPolicy) {
4946
- case "full":
4947
- childMessages = [...parentMessages, { role: "user", content: input }];
4948
- break;
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 res = await instance.invoke({ messages: childMessages, ctx: childCtx });
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 = [...without, recoveryTool];
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
- const sys = buildSystemPrompt(
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(skillBlock), ...input.messages || []];
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) {
@@ -7828,7 +8614,7 @@ var AnthropicProvider = class extends BaseProvider {
7828
8614
  const { system, messages } = this.splitSystemMessages(request.messages);
7829
8615
  const body = {
7830
8616
  model: request.model || this.defaultModel,
7831
- messages: this.toAnthropicMessages(messages),
8617
+ messages: messages.map((m) => this.toAnthropicMessage(m)),
7832
8618
  max_tokens: request.maxTokens ?? 4096,
7833
8619
  stream
7834
8620
  };
@@ -7884,44 +8670,20 @@ var AnthropicProvider = class extends BaseProvider {
7884
8670
  messages: rest
7885
8671
  };
7886
8672
  }
7887
- /**
7888
- * Converts unified messages to Anthropic format, coalescing consecutive
7889
- * tool-result messages into a single `user` turn.
7890
- *
7891
- * The unified message list carries one `role: "tool"` entry per tool call
7892
- * (mirroring OpenAI's shape). Anthropic's Messages API expects every
7893
- * `tool_result` block answering a single assistant turn's `tool_use`
7894
- * block(s) to be batched into ONE `user` message rather than sent as
7895
- * separate consecutive `user` messages.
7896
- */
7897
- toAnthropicMessages(messages) {
7898
- const result = [];
7899
- let mergingToolResults = false;
7900
- for (const m of messages) {
7901
- if (m.role === "tool" && m.toolCallId) {
7902
- const toolResult = this.toAnthropicToolResult(m);
7903
- if (mergingToolResults) {
7904
- result[result.length - 1].content.push(toolResult);
7905
- } else {
7906
- result.push({ role: "user", content: [toolResult] });
7907
- mergingToolResults = true;
7908
- }
7909
- continue;
7910
- }
7911
- mergingToolResults = false;
7912
- result.push(this.toAnthropicMessage(m));
7913
- }
7914
- return result;
7915
- }
7916
- toAnthropicToolResult(m) {
7917
- const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
7918
- return {
7919
- type: "tool_result",
7920
- tool_use_id: m.toolCallId,
7921
- content
7922
- };
7923
- }
7924
8673
  toAnthropicMessage(m) {
8674
+ if (m.role === "tool" && m.toolCallId) {
8675
+ const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
8676
+ return {
8677
+ role: "user",
8678
+ content: [
8679
+ {
8680
+ type: "tool_result",
8681
+ tool_use_id: m.toolCallId,
8682
+ content
8683
+ }
8684
+ ]
8685
+ };
8686
+ }
7925
8687
  if (m.role === "assistant" && m.toolCalls?.length) {
7926
8688
  const content = [];
7927
8689
  appendReasoningBlocks(content, m.reasoning?.blocks);
@@ -8306,7 +9068,7 @@ var BedrockProvider = class extends BaseProvider {
8306
9068
  buildConverseBody(request) {
8307
9069
  const { system, messages } = this.splitSystemMessages(request.messages);
8308
9070
  const body = {
8309
- messages: this.toBedrockMessages(messages)
9071
+ messages: messages.map((m) => this.toBedrockMessage(m))
8310
9072
  };
8311
9073
  if (system.length > 0) {
8312
9074
  const systemBlocks = system.map((s) => ({ text: s }));
@@ -8356,47 +9118,22 @@ var BedrockProvider = class extends BaseProvider {
8356
9118
  }
8357
9119
  return { system, messages: rest };
8358
9120
  }
8359
- /**
8360
- * Converts unified messages to Bedrock Converse format, coalescing
8361
- * consecutive tool-result messages into a single `user` turn.
8362
- *
8363
- * The unified message list carries one `role: "tool"` entry per tool call
8364
- * (mirroring OpenAI's shape). Bedrock's Converse API requires every
8365
- * `toolResult` block answering a single assistant turn's `toolUse`
8366
- * block(s) to be batched into ONE `user` message — sending them as
8367
- * separate consecutive `user` messages triggers: "Expected toolResult
8368
- * blocks at messages.N.content for the following Ids: ...".
8369
- */
8370
- toBedrockMessages(messages) {
8371
- const result = [];
8372
- let mergingToolResults = false;
8373
- for (const m of messages) {
8374
- if (m.role === "tool" && m.toolCallId) {
8375
- const toolResult = this.toBedrockToolResult(m);
8376
- if (mergingToolResults) {
8377
- result[result.length - 1].content.push(toolResult);
8378
- } else {
8379
- result.push({ role: "user", content: [toolResult] });
8380
- mergingToolResults = true;
8381
- }
8382
- continue;
8383
- }
8384
- mergingToolResults = false;
8385
- result.push(this.toBedrockMessage(m));
8386
- }
8387
- return result;
8388
- }
8389
- toBedrockToolResult(m) {
8390
- const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
8391
- return {
8392
- toolResult: {
8393
- toolUseId: m.toolCallId,
8394
- content: [{ text }],
8395
- status: "success"
8396
- }
8397
- };
8398
- }
8399
9121
  toBedrockMessage(m) {
9122
+ if (m.role === "tool" && m.toolCallId) {
9123
+ const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
9124
+ return {
9125
+ role: "user",
9126
+ content: [
9127
+ {
9128
+ toolResult: {
9129
+ toolUseId: m.toolCallId,
9130
+ content: [{ text }],
9131
+ status: "success"
9132
+ }
9133
+ }
9134
+ ]
9135
+ };
9136
+ }
8400
9137
  if (m.role === "assistant" && m.toolCalls?.length) {
8401
9138
  const content2 = [];
8402
9139
  appendBedrockReasoning(content2, m.reasoning?.blocks);
@@ -8702,24 +9439,12 @@ var VertexProvider = class extends BaseProvider {
8702
9439
  buildContents(messages) {
8703
9440
  const systemParts = [];
8704
9441
  const contents = [];
8705
- let mergingToolResults = false;
8706
9442
  for (const m of messages) {
8707
9443
  if (m.role === "system") {
8708
9444
  const text = typeof m.content === "string" ? m.content : m.content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
8709
9445
  if (text) systemParts.push(text);
8710
9446
  continue;
8711
9447
  }
8712
- if (m.role === "tool" && m.toolCallId) {
8713
- const part = this.toGeminiFunctionResponsePart(m);
8714
- if (mergingToolResults) {
8715
- contents[contents.length - 1].parts.push(part);
8716
- } else {
8717
- contents.push({ role: "user", parts: [part] });
8718
- mergingToolResults = true;
8719
- }
8720
- continue;
8721
- }
8722
- mergingToolResults = false;
8723
9448
  contents.push(this.toGeminiContent(m));
8724
9449
  }
8725
9450
  return {
@@ -8727,22 +9452,27 @@ var VertexProvider = class extends BaseProvider {
8727
9452
  contents
8728
9453
  };
8729
9454
  }
8730
- toGeminiFunctionResponsePart(m) {
8731
- const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
8732
- let response;
8733
- try {
8734
- response = JSON.parse(text);
8735
- } catch {
8736
- response = { result: text };
8737
- }
8738
- return {
8739
- functionResponse: {
8740
- name: m.name ?? m.toolCallId,
8741
- response
8742
- }
8743
- };
8744
- }
8745
9455
  toGeminiContent(m) {
9456
+ if (m.role === "tool" && m.toolCallId) {
9457
+ const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
9458
+ let response;
9459
+ try {
9460
+ response = JSON.parse(text);
9461
+ } catch {
9462
+ response = { result: text };
9463
+ }
9464
+ return {
9465
+ role: "user",
9466
+ parts: [
9467
+ {
9468
+ functionResponse: {
9469
+ name: m.name ?? m.toolCallId,
9470
+ response
9471
+ }
9472
+ }
9473
+ ]
9474
+ };
9475
+ }
8746
9476
  if (m.role === "assistant" && m.toolCalls?.length) {
8747
9477
  const parts2 = [];
8748
9478
  if (typeof m.content === "string" && m.content) {
@@ -9405,6 +10135,8 @@ exports.BaseProvider = BaseProvider;
9405
10135
  exports.BedrockProvider = BedrockProvider;
9406
10136
  exports.DEFAULT_PROFILE_CONFIGS = DEFAULT_PROFILE_CONFIGS;
9407
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;
9408
10140
  exports.GuardrailPhase = GuardrailPhase;
9409
10141
  exports.InMemoryMemoryStore = InMemoryMemoryStore;
9410
10142
  exports.NativeJsonSchemaStrategy = NativeJsonSchemaStrategy;
@@ -9418,8 +10150,10 @@ exports.VertexProvider = VertexProvider;
9418
10150
  exports.agentVerdictRule = agentVerdictRule;
9419
10151
  exports.appendBoundTools = appendBoundTools;
9420
10152
  exports.buildSkillHeaderBlock = buildSkillHeaderBlock;
10153
+ exports.buildSubagentCatalogBlock = buildSubagentCatalogBlock;
9421
10154
  exports.buildSystemPrompt = buildSystemPrompt;
9422
10155
  exports.canOpenSkill = canOpenSkill;
10156
+ exports.canSpawn = canSpawn;
9423
10157
  exports.captureSnapshot = captureSnapshot;
9424
10158
  exports.codePresenceRule = codePresenceRule;
9425
10159
  exports.cognipeerSink = cognipeerSink;
@@ -9433,17 +10167,22 @@ exports.createBindSkillToolsTool = createBindSkillToolsTool;
9433
10167
  exports.createCodeGuardrail = createCodeGuardrail;
9434
10168
  exports.createContextSummarizeNode = createContextSummarizeNode;
9435
10169
  exports.createContextTools = createContextTools;
10170
+ exports.createDelegateTool = createDelegateTool;
9436
10171
  exports.createGetToolResponseTool = createGetToolResponseTool;
9437
10172
  exports.createGuardrail = createGuardrail;
9438
10173
  exports.createJsonGuardrail = createJsonGuardrail;
9439
10174
  exports.createManageTodoTool = createManageTodoTool;
9440
10175
  exports.createOpenSkillTool = createOpenSkillTool;
10176
+ exports.createParallelTool = createParallelTool;
9441
10177
  exports.createProvider = createProvider;
9442
10178
  exports.createRegexGuardrail = createRegexGuardrail;
9443
10179
  exports.createResolverNode = createResolverNode;
9444
10180
  exports.createSkillRegistryRef = createSkillRegistryRef;
9445
10181
  exports.createSkillTools = createSkillTools;
9446
10182
  exports.createSmartAgent = createSmartAgent;
10183
+ exports.createSpawnTool = createSpawnTool;
10184
+ exports.createSubagentRegistryRef = createSubagentRegistryRef;
10185
+ exports.createSubagentTools = createSubagentTools;
9447
10186
  exports.createTool = createTool;
9448
10187
  exports.createToolLimitFinalizeNode = createToolLimitFinalizeNode;
9449
10188
  exports.createToolsNode = createToolsNode;
@@ -9454,6 +10193,7 @@ exports.defaultTokenCounter = defaultTokenCounter;
9454
10193
  exports.emptyUsage = emptyUsage;
9455
10194
  exports.evaluateGuardrails = evaluateGuardrails;
9456
10195
  exports.fileSink = fileSink;
10196
+ exports.findSubagent = findSubagent;
9457
10197
  exports.formatZodError = formatZodError;
9458
10198
  exports.fromLangchainModel = fromLangchainModel;
9459
10199
  exports.fromLangchainTools = fromLangchainTools;
@@ -9468,23 +10208,29 @@ exports.hasToolResponseRecoveryReference = hasToolResponseRecoveryReference;
9468
10208
  exports.httpSink = httpSink;
9469
10209
  exports.isSmartModel = isSmartModel;
9470
10210
  exports.jsonSchemaRule = jsonSchemaRule;
10211
+ exports.loadSkillsFromDisk = loadSkillsFromDisk;
9471
10212
  exports.normalizeSmartAgentOptions = normalizeSmartAgentOptions;
9472
10213
  exports.otlpSink = otlpSink;
10214
+ exports.parseSkillFrontmatter = parseSkillFrontmatter;
9473
10215
  exports.readMemoryFacts = readMemoryFacts;
9474
10216
  exports.regexRule = regexRule;
9475
10217
  exports.resolveAvailableSkills = resolveAvailableSkills;
10218
+ exports.resolveAvailableSubagents = resolveAvailableSubagents;
9476
10219
  exports.resolveMemoryStore = resolveMemoryStore;
9477
10220
  exports.resolveReasoning = resolveReasoning;
9478
10221
  exports.resolveStrategy = resolveStrategy;
10222
+ exports.resolveSubagentTools = resolveSubagentTools;
9479
10223
  exports.resolveToolApprovalState = resolveToolApprovalState;
9480
10224
  exports.resolveUserQuestionState = resolveUserQuestionState;
9481
10225
  exports.restoreSnapshot = restoreSnapshot;
9482
10226
  exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
10227
+ exports.seedChildMessages = seedChildMessages;
9483
10228
  exports.setTokenCounter = setTokenCounter;
9484
10229
  exports.startStreamingSession = startStreamingSession;
9485
10230
  exports.traceSessionToOtlp = traceSessionToOtlp;
9486
10231
  exports.validateReasoningConfig = validateReasoningConfig;
9487
10232
  exports.withTools = withTools;
10233
+ exports.withinDepth = withinDepth;
9488
10234
  exports.writeSummaryFactsToMemory = writeSummaryFactsToMemory;
9489
10235
  //# sourceMappingURL=index.cjs.map
9490
10236
  //# sourceMappingURL=index.cjs.map