@cognipeer/agent-sdk 0.7.0 → 0.7.2

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.mjs CHANGED
@@ -3026,6 +3026,17 @@ function createToolsNode(initialTools, opts) {
3026
3026
  }
3027
3027
  const durationMs = Date.now() - start;
3028
3028
  const executionId = nanoid();
3029
+ if (output && typeof output === "object" && Array.isArray(output.__runtimeToolsDelta)) {
3030
+ const delta = output.__runtimeToolsDelta;
3031
+ delete output.__runtimeToolsDelta;
3032
+ const currentRuntime = state.agent || runtime;
3033
+ const currentTools = currentRuntime?.tools ?? [];
3034
+ const present = new Set(currentTools.map((tool2) => tool2?.name));
3035
+ const additions = delta.filter((tool2) => tool2 && tool2.name && !present.has(tool2.name));
3036
+ if (additions.length > 0 && currentRuntime) {
3037
+ state.agent = { ...currentRuntime, tools: [...currentTools, ...additions] };
3038
+ }
3039
+ }
3029
3040
  if (output && typeof output === "object" && output.__handoff && output.__handoff.runtime) {
3030
3041
  toolHistory.push({ executionId, toolName, args, output: "handoff:ok", rawOutput: output, timestamp: (/* @__PURE__ */ new Date()).toISOString(), tool_call_id: tc.id, status: "handoff" });
3031
3042
  push({ role: "tool", content: "ok", tool_call_id: tc.id || `${tc.name}_${toolCount}`, name: tc.name });
@@ -3335,15 +3346,40 @@ function countToolCallsInLastTurn(state) {
3335
3346
  function stripReflectionAskMessages(messages) {
3336
3347
  return messages.filter((m) => !(m?.role === "user" && m?.name === REFLECTION_ASK_NAME));
3337
3348
  }
3349
+ function lastTwoToolTurns(state) {
3350
+ const groups = [];
3351
+ let cur = [];
3352
+ let sawTool = false;
3353
+ for (let i = state.messages.length - 1; i >= 0; i--) {
3354
+ const m = state.messages[i];
3355
+ if (m?.role === "tool") {
3356
+ if (m.name) cur.push(m.name);
3357
+ sawTool = true;
3358
+ } else if (m?.role === "assistant") {
3359
+ if (sawTool) {
3360
+ groups.push(cur);
3361
+ cur = [];
3362
+ sawTool = false;
3363
+ if (groups.length >= 2) break;
3364
+ }
3365
+ }
3366
+ }
3367
+ if (sawTool && cur.length) groups.push(cur);
3368
+ return { current: groups[0] ?? [], previous: groups[1] ?? [] };
3369
+ }
3338
3370
  function shouldRunReflection(cadence, state, ranToolsThisTurn) {
3339
3371
  if (cadence === "off") return false;
3340
3372
  if (cadence === "every_turn") return true;
3341
3373
  if (cadence === "after_tool") return ranToolsThisTurn;
3374
+ if (cadence === "initial_then_after_tool") return ranToolsThisTurn;
3342
3375
  if (cadence === "on_branch") {
3343
- const reflections = state.reflections || [];
3344
- const lastReflectionTurn = reflections[reflections.length - 1]?.turn ?? -1;
3345
- const currentTurnId = state.toolCallCount ?? 0;
3346
- return currentTurnId - lastReflectionTurn >= 2;
3376
+ const { current, previous } = lastTwoToolTurns(state);
3377
+ if (previous.length === 0) return true;
3378
+ const a = new Set(current);
3379
+ const b = new Set(previous);
3380
+ for (const n of a) if (!b.has(n)) return true;
3381
+ for (const n of b) if (!a.has(n)) return true;
3382
+ return false;
3347
3383
  }
3348
3384
  return false;
3349
3385
  }
@@ -3360,7 +3396,10 @@ function createReflectionNode(opts, resolved) {
3360
3396
  const onEvent = state.ctx?.__onEvent;
3361
3397
  const traceSession = state.ctx?.__traceSession;
3362
3398
  const maxChars = resolved.maxChars;
3363
- const promptBody = (resolved.promptTemplate || DEFAULT_REFLECT_PROMPT).replace(/\$\{maxChars\}/g, String(maxChars));
3399
+ const turnNow = state.toolCallCount ?? 0;
3400
+ const hookCtx = { state, turn: turnNow, trigger, ranToolsThisTurn: true };
3401
+ const defaultPrompt = (resolved.promptTemplate || DEFAULT_REFLECT_PROMPT).replace(/\$\{maxChars\}/g, String(maxChars));
3402
+ const promptBody = resolved.buildPrompt ? String(resolved.buildPrompt({ ...hookCtx, defaultPrompt, maxChars }) ?? defaultPrompt) : defaultPrompt;
3364
3403
  const baseMessages = stripReflectionAskMessages([...state.messages]);
3365
3404
  const askMessage = {
3366
3405
  role: "user",
@@ -3394,6 +3433,8 @@ function createReflectionNode(opts, resolved) {
3394
3433
  const rawText = extractText(response);
3395
3434
  const text = trimToChars(String(rawText ?? "").trim(), maxChars);
3396
3435
  if (!text) return {};
3436
+ const prevText = (state.reflections?.[state.reflections.length - 1]?.text || "").trim();
3437
+ if (prevText && isNearDuplicate(prevText, text)) return {};
3397
3438
  const rawUsage = response?.usage_metadata || response?.response_metadata?.usage || response?.usage || response?.additional_kwargs?.usage;
3398
3439
  const usage = normalizeUsage(rawUsage);
3399
3440
  const { ids, names } = countToolCallsInLastTurn(state);
@@ -3442,6 +3483,12 @@ function createReflectionNode(opts, resolved) {
3442
3483
  } catch (e) {
3443
3484
  }
3444
3485
  }
3486
+ if (resolved.onReflection) {
3487
+ try {
3488
+ resolved.onReflection(record, hookCtx);
3489
+ } catch {
3490
+ }
3491
+ }
3445
3492
  const nextMessages = stripReflectionAskMessages([...state.messages]);
3446
3493
  const reflections = [...state.reflections || [], record];
3447
3494
  const kept = reflections.slice(-Math.max(1, resolved.keepLast));
@@ -3458,7 +3505,20 @@ ${r.text}
3458
3505
  metadata: { reflectionId: r.id, reflectionTurn: r.turn, reflectionTrigger: r.trigger }
3459
3506
  });
3460
3507
  }
3461
- return { messages: prunedMessages, reflections };
3508
+ const patch = { messages: prunedMessages, reflections };
3509
+ if (resolved.feedTo === "memory") {
3510
+ const fact = {
3511
+ key: `reflection_turn_${turn}`,
3512
+ value: text,
3513
+ sourceTurn: turn,
3514
+ confidence: 0.3,
3515
+ tags: ["reflection"]
3516
+ };
3517
+ patch.memoryFacts = [...state.memoryFacts || [], fact];
3518
+ } else if (resolved.feedTo === "plan" && state.plan) {
3519
+ patch.plan = { ...state.plan, lastReflection: text };
3520
+ }
3521
+ return patch;
3462
3522
  };
3463
3523
  }
3464
3524
  function extractText(chunk) {
@@ -3487,24 +3547,75 @@ function safeRandomId() {
3487
3547
  return `r_${Math.random().toString(36).slice(2, 10)}_${Date.now().toString(36)}`;
3488
3548
  }
3489
3549
  }
3550
+ function isNearDuplicate(a, b) {
3551
+ const norm = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
3552
+ const na = norm(a);
3553
+ const nb = norm(b);
3554
+ if (na === nb) return true;
3555
+ const tokensA = new Set(na.split(" ").filter(Boolean));
3556
+ const tokensB = new Set(nb.split(" ").filter(Boolean));
3557
+ if (tokensA.size === 0 || tokensB.size === 0) return false;
3558
+ let inter = 0;
3559
+ for (const t of tokensA) if (tokensB.has(t)) inter++;
3560
+ const union = tokensA.size + tokensB.size - inter;
3561
+ return union > 0 && inter / union >= 0.9;
3562
+ }
3490
3563
 
3491
3564
  // src/smart/reasoning.ts
3492
3565
  var LEVEL_DEFAULTS = {
3566
+ minimal: {
3567
+ native: { effort: "minimal" },
3568
+ reflection: { maxTokens: 150, maxChars: 400, cadence: "off" }
3569
+ },
3493
3570
  low: {
3494
3571
  native: { effort: "low" },
3495
3572
  reflection: { maxTokens: 200, maxChars: 600, cadence: "on_branch" }
3496
3573
  },
3497
3574
  medium: {
3498
3575
  native: { effort: "medium" },
3499
- reflection: { maxTokens: 350, maxChars: 1200, cadence: "after_tool" }
3576
+ reflection: { maxTokens: 350, maxChars: 1200, cadence: "initial_then_after_tool" }
3500
3577
  },
3501
3578
  high: {
3502
3579
  native: { effort: "high" },
3503
- reflection: { maxTokens: 600, maxChars: 2e3, cadence: "after_tool" }
3580
+ reflection: { maxTokens: 600, maxChars: 2e3, cadence: "initial_then_after_tool" }
3504
3581
  }
3505
3582
  };
3583
+ var VALID_LEVELS = ["minimal", "low", "medium", "high"];
3584
+ var VALID_CADENCES = ["off", "every_turn", "after_tool", "on_branch", "initial_then_after_tool"];
3585
+ var VALID_EFFORTS = ["minimal", "low", "medium", "high"];
3586
+ function validateReasoningConfig(input) {
3587
+ if (!input) return;
3588
+ if (input.level !== void 0 && !VALID_LEVELS.includes(input.level)) {
3589
+ throw new Error(`reasoning.level must be one of ${VALID_LEVELS.join(", ")} (got "${input.level}")`);
3590
+ }
3591
+ if (input.native) {
3592
+ const n = input.native;
3593
+ if (n.effort !== void 0 && !VALID_EFFORTS.includes(n.effort)) {
3594
+ throw new Error(`reasoning.native.effort must be one of ${VALID_EFFORTS.join(", ")} (got "${n.effort}")`);
3595
+ }
3596
+ if (n.budgetTokens !== void 0 && (!Number.isFinite(n.budgetTokens) || n.budgetTokens < 0)) {
3597
+ throw new Error(`reasoning.native.budgetTokens must be a non-negative number (got ${n.budgetTokens})`);
3598
+ }
3599
+ }
3600
+ if (input.reflection) {
3601
+ const r = input.reflection;
3602
+ if (r.cadence !== void 0 && !VALID_CADENCES.includes(r.cadence)) {
3603
+ throw new Error(`reasoning.reflection.cadence must be one of ${VALID_CADENCES.join(", ")} (got "${r.cadence}")`);
3604
+ }
3605
+ if (r.maxPerRun !== void 0 && (!Number.isFinite(r.maxPerRun) || r.maxPerRun < 0)) {
3606
+ throw new Error(`reasoning.reflection.maxPerRun must be a non-negative number (got ${r.maxPerRun})`);
3607
+ }
3608
+ if (r.everyNTurns !== void 0 && (!Number.isFinite(r.everyNTurns) || r.everyNTurns < 1)) {
3609
+ throw new Error(`reasoning.reflection.everyNTurns must be >= 1 (got ${r.everyNTurns})`);
3610
+ }
3611
+ if (r.feedTo !== void 0 && !["memory", "plan", "none"].includes(r.feedTo)) {
3612
+ throw new Error(`reasoning.reflection.feedTo must be "memory", "plan", or "none" (got "${r.feedTo}")`);
3613
+ }
3614
+ }
3615
+ }
3506
3616
  function resolveReasoning(input) {
3507
3617
  if (!input || input.enabled === false) return void 0;
3618
+ validateReasoningConfig(input);
3508
3619
  const enabled = input.enabled ?? (input.native !== void 0 || input.reflection !== void 0 || input.level !== void 0);
3509
3620
  if (!enabled) return void 0;
3510
3621
  const level = input.level ?? "medium";
@@ -3529,7 +3640,8 @@ function resolveReflection(input, preset) {
3529
3640
  keepLast: 3,
3530
3641
  summarize: false,
3531
3642
  emitEvents: true,
3532
- everyNTurns: 1
3643
+ everyNTurns: 1,
3644
+ feedTo: "none"
3533
3645
  };
3534
3646
  }
3535
3647
  const cfg = input ?? {};
@@ -3546,7 +3658,11 @@ function resolveReflection(input, preset) {
3546
3658
  promptTemplate: cfg.promptTemplate,
3547
3659
  emitEvents: cfg.emitEvents ?? true,
3548
3660
  maxPerRun: typeof cfg.maxPerRun === "number" && cfg.maxPerRun >= 0 ? cfg.maxPerRun : void 0,
3549
- everyNTurns: Math.max(1, Math.trunc(cfg.everyNTurns ?? 1))
3661
+ everyNTurns: Math.max(1, Math.trunc(cfg.everyNTurns ?? 1)),
3662
+ feedTo: cfg.feedTo ?? "none",
3663
+ shouldReflect: cfg.shouldReflect,
3664
+ buildPrompt: cfg.buildPrompt,
3665
+ onReflection: cfg.onReflection
3550
3666
  };
3551
3667
  }
3552
3668
  function ensureArray(value) {
@@ -4272,12 +4388,14 @@ function createAgent(opts) {
4272
4388
  if (summarizationThreshold === void 0) {
4273
4389
  state = clearNeedsSummarization(state);
4274
4390
  }
4275
- if (resolvedReasoning?.native) {
4391
+ if (resolvedReasoning) {
4276
4392
  const ctx = { ...state.ctx || {} };
4277
- if (!ctx.__reasoning) {
4393
+ if (resolvedReasoning.native) {
4278
4394
  ctx.__reasoning = resolvedReasoning.native;
4279
- state = { ...state, ctx };
4395
+ } else {
4396
+ delete ctx.__reasoning;
4280
4397
  }
4398
+ state = { ...state, ctx: Object.keys(ctx).length > 0 ? ctx : void 0 };
4281
4399
  }
4282
4400
  const mergedLimits = {
4283
4401
  ...opts.limits || {},
@@ -4325,6 +4443,7 @@ function createAgent(opts) {
4325
4443
  return { breached: false };
4326
4444
  };
4327
4445
  let iterations = 0;
4446
+ let reflectionsThisRun = 0;
4328
4447
  const onStateChange = config?.onStateChange;
4329
4448
  const checkpointReason = config?.checkpointReason;
4330
4449
  let pausedStage = null;
@@ -4370,6 +4489,16 @@ function createAgent(opts) {
4370
4489
  pausedStage = stage;
4371
4490
  return true;
4372
4491
  };
4492
+ if (reflectNode && resolvedReasoning?.reflection.enabled && resolvedReasoning.reflection.cadence === "initial_then_after_tool" && resumeStage === null && !state.ctx?.__awaitingApproval && !state.ctx?.__awaitingUserQuestion && !state.messages.some((m) => m?.role === "assistant")) {
4493
+ try {
4494
+ const patch = await reflectNode(state, "initial_then_after_tool");
4495
+ if (patch && Object.keys(patch).length > 0) {
4496
+ state = { ...state, ...patch };
4497
+ reflectionsThisRun++;
4498
+ }
4499
+ } catch {
4500
+ }
4501
+ }
4373
4502
  while (iterations < iterationLimit) {
4374
4503
  iterations++;
4375
4504
  const budget = checkBudgetBreached();
@@ -4546,16 +4675,18 @@ function createAgent(opts) {
4546
4675
  if (reflectNode && resolvedReasoning?.reflection.enabled) {
4547
4676
  const cadence = resolvedReasoning.reflection.cadence;
4548
4677
  const refl = resolvedReasoning.reflection;
4549
- const reflectionsSoFar = state.reflections?.length ?? 0;
4550
4678
  const lastTurn = state.reflections?.at(-1)?.turn ?? -Infinity;
4551
4679
  const currentTurn = state.toolCallCount || 0;
4552
- const budgetExceeded = typeof refl.maxPerRun === "number" && reflectionsSoFar >= refl.maxPerRun;
4553
- const cadenceGap = currentTurn - (Number.isFinite(lastTurn) ? lastTurn : -refl.everyNTurns) < refl.everyNTurns;
4554
- if (!budgetExceeded && !cadenceGap && shouldRunReflection(cadence, state, true)) {
4680
+ const budgetExceeded = typeof refl.maxPerRun === "number" && reflectionsThisRun >= refl.maxPerRun;
4681
+ const sinceLast = currentTurn - (Number.isFinite(lastTurn) ? lastTurn : -refl.everyNTurns);
4682
+ const cadenceGap = sinceLast < refl.everyNTurns;
4683
+ const cadenceWantsIt = refl.shouldReflect ? !!refl.shouldReflect({ state, turn: currentTurn, trigger: cadence, ranToolsThisTurn: true }) : shouldRunReflection(cadence, state, true);
4684
+ if (!budgetExceeded && !cadenceGap && cadenceWantsIt) {
4555
4685
  try {
4556
4686
  const patch = await reflectNode(state, cadence);
4557
4687
  if (patch && Object.keys(patch).length > 0) {
4558
4688
  state = { ...state, ...patch };
4689
+ reflectionsThisRun++;
4559
4690
  }
4560
4691
  } catch {
4561
4692
  }
@@ -6063,6 +6194,190 @@ async function writeSummaryFactsToMemory(store, config, summary, sourceTurn) {
6063
6194
  return store.get(config.memory.scope, { limit: config.context.lastTurnsToKeep + summary.stable_facts.length });
6064
6195
  }
6065
6196
 
6197
+ // src/smart/skills/types.ts
6198
+ var DEFAULT_SKILL_POLICY = {
6199
+ maxOpenSkills: 4,
6200
+ maxBoundToolsPerSkill: 12,
6201
+ maxBoundToolsTotal: 40
6202
+ };
6203
+ var SMALL_TIER_SKILL_POLICY = {
6204
+ maxOpenSkills: 1,
6205
+ maxBoundToolsPerSkill: 6,
6206
+ maxBoundToolsTotal: 18,
6207
+ modelTier: "small"
6208
+ };
6209
+ function createSkillRegistryRef() {
6210
+ return { openedSkillKeys: [], boundSkillTools: [] };
6211
+ }
6212
+
6213
+ // src/smart/skills/registry.ts
6214
+ function composeToolSets(input) {
6215
+ const without = [...input.base, ...input.boundSkillTools];
6216
+ const withRec = input.recoveryTool ? [...without, input.recoveryTool] : [...without];
6217
+ return { toolsWithoutRecovery: without, toolsWithRecovery: withRec };
6218
+ }
6219
+ function appendBoundTools(ref, newTools, policy) {
6220
+ const present = new Set(ref.boundSkillTools.map((tool) => tool.name));
6221
+ const added = [];
6222
+ for (const tool of newTools) {
6223
+ if (ref.boundSkillTools.length >= policy.maxBoundToolsTotal) break;
6224
+ if (present.has(tool.name)) continue;
6225
+ present.add(tool.name);
6226
+ ref.boundSkillTools.push(tool);
6227
+ added.push(tool);
6228
+ }
6229
+ return added;
6230
+ }
6231
+ function canOpenSkill(ref, policy) {
6232
+ if (ref.openedSkillKeys.length >= policy.maxOpenSkills) {
6233
+ return { ok: false, reason: `max ${policy.maxOpenSkills} skill(s) already open` };
6234
+ }
6235
+ if (ref.boundSkillTools.length >= policy.maxBoundToolsTotal) {
6236
+ return { ok: false, reason: "skill tool budget exhausted" };
6237
+ }
6238
+ return { ok: true };
6239
+ }
6240
+ async function resolveAvailableSkills(skills, opts = {}) {
6241
+ const out = [];
6242
+ for (const skill of skills) {
6243
+ if (skill.minModelTier === "large" && opts.modelTier === "small") continue;
6244
+ const available = skill.isAvailable ? await skill.isAvailable() : true;
6245
+ if (available) out.push(skill);
6246
+ }
6247
+ return out;
6248
+ }
6249
+ function buildSkillHeaderBlock(skills) {
6250
+ if (skills.length === 0) return "";
6251
+ const lines = skills.map((skill) => `- ${skill.key}: ${skill.header}`);
6252
+ return [
6253
+ "<available_skills>",
6254
+ "Open a skill with open_skill(skillKey) to load its tools on demand. Only open what the task needs; close nothing \u2014 opened skills stay available for the rest of the run.",
6255
+ ...lines,
6256
+ "</available_skills>"
6257
+ ].join("\n");
6258
+ }
6259
+ function dedupeToolsByName(tools) {
6260
+ const seen = /* @__PURE__ */ new Set();
6261
+ const out = [];
6262
+ for (const tool of tools) {
6263
+ if (seen.has(tool.name)) continue;
6264
+ seen.add(tool.name);
6265
+ out.push(tool);
6266
+ }
6267
+ return out;
6268
+ }
6269
+
6270
+ // src/smart/skills/skillTools.ts
6271
+ var MAX_RETURNED_INDEX = 40;
6272
+ var OPEN_SKILL_DESCRIPTION = "Load a capability on demand. Pass a skillKey from <available_skills>. A small skill binds all its tools immediately; a large one returns a tool index \u2014 then call bind_skill_tools with only the tools you need. Open only what the task needs.";
6273
+ var BIND_SKILL_TOOLS_DESCRIPTION = "After open_skill on a large skill, bind a chosen subset of its tools by name. Pick the few tools the task actually needs.";
6274
+ function findSkill(deps, key) {
6275
+ return deps.skills.find((skill) => skill.key === key);
6276
+ }
6277
+ function createOpenSkillTool(deps) {
6278
+ const tool = createTool({
6279
+ name: "open_skill",
6280
+ description: OPEN_SKILL_DESCRIPTION,
6281
+ schema: z.object({
6282
+ skillKey: z.string().min(1).describe("A key from <available_skills>."),
6283
+ query: z.string().optional().describe("What you need from the skill \u2014 used to rank a large skill's tools.")
6284
+ }).strict(),
6285
+ func: async ({ skillKey, query }) => {
6286
+ const { registryRef: ref, policy } = tool._deps;
6287
+ const skill = findSkill(tool._deps, skillKey);
6288
+ if (!skill) {
6289
+ return { error: `Unknown skill: ${skillKey}. Choose a key listed in <available_skills>.` };
6290
+ }
6291
+ if (skill.isAvailable && !await skill.isAvailable()) {
6292
+ return { error: `Skill ${skillKey} is not available in this workspace.` };
6293
+ }
6294
+ const alreadyOpen = ref.openedSkillKeys.includes(skillKey);
6295
+ if (!alreadyOpen) {
6296
+ const guard = canOpenSkill(ref, policy);
6297
+ if (!guard.ok) {
6298
+ return {
6299
+ error: `Cannot open ${skillKey}: ${guard.reason}. Work with the skills already open.`
6300
+ };
6301
+ }
6302
+ ref.openedSkillKeys.push(skillKey);
6303
+ }
6304
+ const prompt = typeof skill.prompt === "function" ? await skill.prompt() : skill.prompt;
6305
+ const index = await skill.listToolIndex();
6306
+ if (index.length <= policy.maxBoundToolsPerSkill) {
6307
+ const bound = await skill.bindTools();
6308
+ const added = appendBoundTools(ref, bound, policy);
6309
+ if (added.length > 0) ref.__onToolsChanged?.();
6310
+ return {
6311
+ skillKey,
6312
+ prompt,
6313
+ needsSandbox: Boolean(skill.needsSandbox),
6314
+ boundTools: added.map((t) => t.name),
6315
+ // Inject the bound tools into the live runtime for this loop.
6316
+ __runtimeToolsDelta: added
6317
+ };
6318
+ }
6319
+ let defaultBound = [];
6320
+ let defaultAdded = [];
6321
+ if ((!query || query.trim().length < 3) && skill.defaultBindNames?.length) {
6322
+ const bound = await skill.bindTools(skill.defaultBindNames.slice(0, policy.maxBoundToolsPerSkill));
6323
+ defaultAdded = appendBoundTools(ref, bound, policy);
6324
+ if (defaultAdded.length > 0) ref.__onToolsChanged?.();
6325
+ defaultBound = defaultAdded.map((t) => t.name);
6326
+ }
6327
+ const headers = query && query.trim().length >= 3 && skill.rankToolHeaders ? await skill.rankToolHeaders(query, index) : index;
6328
+ return {
6329
+ skillKey,
6330
+ prompt,
6331
+ needsSandbox: Boolean(skill.needsSandbox),
6332
+ boundTools: defaultBound,
6333
+ toolIndex: headers.slice(0, MAX_RETURNED_INDEX).map((h) => ({ name: h.name, description: h.description })),
6334
+ hint: "Call bind_skill_tools(skillKey, toolNames) with only the tools you need.",
6335
+ ...defaultAdded.length > 0 ? { __runtimeToolsDelta: defaultAdded } : {}
6336
+ };
6337
+ }
6338
+ });
6339
+ tool._deps = deps;
6340
+ tool.__source = "smart-skills";
6341
+ return tool;
6342
+ }
6343
+ function createBindSkillToolsTool(deps) {
6344
+ const tool = createTool({
6345
+ name: "bind_skill_tools",
6346
+ description: BIND_SKILL_TOOLS_DESCRIPTION,
6347
+ schema: z.object({
6348
+ skillKey: z.string().min(1),
6349
+ toolNames: z.array(z.string().min(1)).min(1).describe("Tool names from the skill's index.")
6350
+ }).strict(),
6351
+ func: async ({ skillKey, toolNames }) => {
6352
+ const { registryRef: ref, policy } = tool._deps;
6353
+ const skill = findSkill(tool._deps, skillKey);
6354
+ if (!skill) {
6355
+ return { error: `Unknown skill: ${skillKey}.` };
6356
+ }
6357
+ if (!ref.openedSkillKeys.includes(skillKey)) {
6358
+ return { error: `Call open_skill("${skillKey}") before binding its tools.` };
6359
+ }
6360
+ const capped = toolNames.slice(0, policy.maxBoundToolsPerSkill);
6361
+ const bound = await skill.bindTools(capped);
6362
+ const added = appendBoundTools(ref, bound, policy);
6363
+ if (added.length > 0) ref.__onToolsChanged?.();
6364
+ return {
6365
+ skillKey,
6366
+ boundTools: added.map((t) => t.name),
6367
+ requested: capped.length,
6368
+ truncated: toolNames.length > capped.length,
6369
+ ...added.length > 0 ? { __runtimeToolsDelta: added } : {}
6370
+ };
6371
+ }
6372
+ });
6373
+ tool._deps = deps;
6374
+ tool.__source = "smart-skills";
6375
+ return tool;
6376
+ }
6377
+ function createSkillTools(deps) {
6378
+ return [createOpenSkillTool(deps), createBindSkillToolsTool(deps)];
6379
+ }
6380
+
6066
6381
  // src/smart/index.ts
6067
6382
  function createSmartAgent(opts) {
6068
6383
  const resolved = normalizeSmartAgentOptions(opts);
@@ -6097,6 +6412,9 @@ function createSmartAgent(opts) {
6097
6412
  if (askUserConfig) {
6098
6413
  factoryToolsWithoutRecovery.push(createAskUserQuestionTool(factoryStateRef, askUserConfig));
6099
6414
  }
6415
+ const skills = opts.skills ?? [];
6416
+ const skillPolicy = opts.skillPolicy ?? DEFAULT_SKILL_POLICY;
6417
+ const skillsEnabled = skills.length > 0;
6100
6418
  const soManagerFactory = opts.outputSchema ? new StructuredOutputManager(opts.outputSchema, resolveStrategy(opts.model)) : void 0;
6101
6419
  const modelCapabilities = opts.outputSchema ? getModelCapabilities(opts.model) : void 0;
6102
6420
  const responseFinalizeTool = soManagerFactory && modelCapabilities?.structuredOutput !== "native" ? soManagerFactory.getResponseTool() : void 0;
@@ -6104,12 +6422,31 @@ function createSmartAgent(opts) {
6104
6422
  const ref = { toolHistory: void 0, toolHistoryArchived: void 0, todoList: void 0, planVersion: 0, adherenceScore: 0 };
6105
6423
  const ctxTools = createContextTools(ref, { planningEnabled, includeGetToolResponse: false });
6106
6424
  const recoveryTool = createGetToolResponseTool(ref);
6107
- const base2 = [...userTools, ...ctxTools];
6108
- if (responseFinalizeTool) base2.push(responseFinalizeTool);
6109
- if (askUserConfig) base2.push(createAskUserQuestionTool(ref, askUserConfig));
6110
- const without = base2;
6111
- const withRec = [...without, recoveryTool];
6112
- return { stateRef: ref, toolsWithoutRecovery: without, toolsWithRecovery: withRec };
6425
+ const coreBase = [...userTools, ...ctxTools];
6426
+ if (responseFinalizeTool) coreBase.push(responseFinalizeTool);
6427
+ if (askUserConfig) coreBase.push(createAskUserQuestionTool(ref, askUserConfig));
6428
+ if (!skillsEnabled) {
6429
+ const without = coreBase;
6430
+ const withRec = [...without, recoveryTool];
6431
+ return { stateRef: ref, toolsWithoutRecovery: without, toolsWithRecovery: withRec };
6432
+ }
6433
+ const toolSet = { stateRef: ref, toolsWithoutRecovery: [], toolsWithRecovery: [] };
6434
+ const skillRegistryRef = createSkillRegistryRef();
6435
+ const skillMetaTools = createSkillTools({ registryRef: skillRegistryRef, skills, policy: skillPolicy });
6436
+ const baseWithMeta = [...coreBase, ...skillMetaTools];
6437
+ const rebuild = () => {
6438
+ const composed = composeToolSets({
6439
+ base: baseWithMeta,
6440
+ boundSkillTools: skillRegistryRef.boundSkillTools,
6441
+ recoveryTool
6442
+ });
6443
+ toolSet.toolsWithoutRecovery = composed.toolsWithoutRecovery;
6444
+ toolSet.toolsWithRecovery = composed.toolsWithRecovery;
6445
+ };
6446
+ skillRegistryRef.__onToolsChanged = rebuild;
6447
+ toolSet.skillRegistryRef = skillRegistryRef;
6448
+ rebuild();
6449
+ return toolSet;
6113
6450
  };
6114
6451
  const base = createAgent({ ...runtimeOpts, tools: factoryToolsWithoutRecovery });
6115
6452
  base.__runtime.runtimeProfile = resolved.runtimeProfile;
@@ -6160,9 +6497,9 @@ function createSmartAgent(opts) {
6160
6497
  planVersion: ref.planVersion || state.planVersion || 1
6161
6498
  };
6162
6499
  }
6163
- function systemMessage2() {
6500
+ function systemMessage2(extraBlock) {
6164
6501
  const sys = buildSystemPrompt(
6165
- [opts.systemPrompt, runtimeHint, structuredOutputHint].filter(Boolean).join("\n"),
6502
+ [opts.systemPrompt, runtimeHint, structuredOutputHint, extraBlock].filter(Boolean).join("\n"),
6166
6503
  planningEnabled,
6167
6504
  opts.name || "Agent",
6168
6505
  opts.todoListPrompt
@@ -6212,8 +6549,10 @@ function createSmartAgent(opts) {
6212
6549
  stateRef.planVersion = input.planVersion || input.plan?.version || 0;
6213
6550
  stateRef.adherenceScore = input.plan?.adherenceScore || 0;
6214
6551
  const syncPlanFromRef = (state2) => syncPlanStateWith(stateRef, state2);
6552
+ const availableSkills = skillsEnabled ? await resolveAvailableSkills(skills, { modelTier: skillPolicy.modelTier }) : [];
6553
+ const skillBlock = availableSkills.length > 0 ? buildSkillHeaderBlock(availableSkills) : void 0;
6215
6554
  const alreadyHasSystem = Array.isArray(input.messages) && input.messages[0]?.role === "system";
6216
- const seedMessages = alreadyHasSystem ? [...input.messages || []] : [systemMessage2(), ...input.messages || []];
6555
+ const seedMessages = alreadyHasSystem ? [...input.messages || []] : [systemMessage2(skillBlock), ...input.messages || []];
6217
6556
  let state = syncRuntimeTools(await syncMemory({ ...input, messages: seedMessages }), seedMessages, toolSet);
6218
6557
  let lastResult = null;
6219
6558
  let rawMessages = [...seedMessages];
@@ -6818,6 +7157,20 @@ function parseSSEBlock(block) {
6818
7157
  }
6819
7158
 
6820
7159
  // src/providers/utils/reasoning.ts
7160
+ var ANTHROPIC_EFFORT_BUDGET = {
7161
+ minimal: 1024,
7162
+ low: 2048,
7163
+ medium: 8192,
7164
+ high: 16384
7165
+ };
7166
+ var GEMINI_EFFORT_BUDGET = {
7167
+ minimal: 512,
7168
+ low: 1024,
7169
+ medium: 4096,
7170
+ high: 12e3
7171
+ };
7172
+ var THINKING_OUTPUT_RESERVE = 1024;
7173
+ var THINKING_MIN_MAX_TOKENS = 4096;
6821
7174
  function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
6822
7175
  if (!reasoning) return;
6823
7176
  const effort = normalizeEffort(reasoning.effort);
@@ -6834,21 +7187,56 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
6834
7187
  }
6835
7188
  function applyAnthropicReasoning(body, reasoning) {
6836
7189
  if (!reasoning) return;
6837
- const budget = resolveBudget(reasoning, { low: 2048, medium: 8192, high: 16384, minimal: 1024 });
7190
+ let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
6838
7191
  if (!budget) return;
7192
+ const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
7193
+ const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
7194
+ if (currentMax < requiredMax) {
7195
+ body.max_tokens = requiredMax;
7196
+ }
7197
+ budget = clampBudget(budget, body.max_tokens);
6839
7198
  const thinking = { type: "enabled", budget_tokens: budget };
6840
7199
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
6841
7200
  body.thinking = thinking;
7201
+ stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
7202
+ }
7203
+ function applyBedrockReasoning(body, reasoning) {
7204
+ if (!reasoning) return;
7205
+ let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
7206
+ if (!budget) return;
7207
+ const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
7208
+ const currentMax = typeof inference.maxTokens === "number" ? inference.maxTokens : 0;
7209
+ const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
7210
+ if (currentMax < requiredMax) {
7211
+ inference.maxTokens = requiredMax;
7212
+ }
7213
+ budget = clampBudget(budget, inference.maxTokens);
7214
+ const extra = body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
7215
+ const thinking = { type: "enabled", budget_tokens: budget };
7216
+ if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
7217
+ extra.thinking = thinking;
7218
+ stripSamplingParams(inference, ["temperature", "topP"]);
6842
7219
  }
6843
7220
  function applyGeminiReasoning(generationConfig, reasoning) {
6844
7221
  if (!reasoning) return;
6845
- const budget = resolveBudget(reasoning, { low: 1024, medium: 4096, high: 12e3, minimal: 512 });
7222
+ const budget = resolveBudget(reasoning, GEMINI_EFFORT_BUDGET);
6846
7223
  if (budget == null) return;
6847
7224
  const thinkingConfig = { thinkingBudget: budget };
6848
7225
  if (reasoning.includeThoughts) thinkingConfig.includeThoughts = true;
6849
7226
  if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
6850
7227
  generationConfig.thinkingConfig = thinkingConfig;
6851
7228
  }
7229
+ function stripSamplingParams(target, keys) {
7230
+ for (const k of keys) {
7231
+ if (k in target) delete target[k];
7232
+ }
7233
+ }
7234
+ function clampBudget(budget, maxTokens) {
7235
+ if (typeof maxTokens !== "number" || maxTokens <= 0) return budget;
7236
+ const ceiling = maxTokens - THINKING_OUTPUT_RESERVE;
7237
+ if (ceiling < 1024) return Math.max(1024, Math.floor(maxTokens / 2));
7238
+ return Math.min(budget, ceiling);
7239
+ }
6852
7240
  function normalizeEffort(effort) {
6853
7241
  if (!effort) return void 0;
6854
7242
  const allowed = ["minimal", "low", "medium", "high"];
@@ -6877,13 +7265,38 @@ var OpenAIProvider = class extends BaseProvider {
6877
7265
  };
6878
7266
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
6879
7267
  }
7268
+ /** True when the request targets a reasoning model (o-series / gpt-5) so we
7269
+ * should route through the Responses API, which exposes `reasoning.effort`
7270
+ * and reasoning summaries. Chat Completions silently drops these. */
7271
+ useResponsesApi(request) {
7272
+ if (!request.reasoning) return false;
7273
+ return isReasoningModel(request.model || this.defaultModel);
7274
+ }
6880
7275
  async complete(request) {
7276
+ if (this.useResponsesApi(request)) {
7277
+ return this.completeResponses(request);
7278
+ }
6881
7279
  const body = this.buildRequestBody(request, false);
6882
7280
  const res = await this.doFetch(body);
6883
7281
  const json = await res.json();
6884
7282
  return this.parseResponse(json);
6885
7283
  }
6886
7284
  async *completeStream(request) {
7285
+ if (this.useResponsesApi(request)) {
7286
+ const response = await this.completeResponses(request);
7287
+ yield {
7288
+ id: response.id,
7289
+ model: response.model,
7290
+ delta: {
7291
+ content: response.content ?? void 0,
7292
+ toolCalls: response.toolCalls.length > 0 ? response.toolCalls : void 0,
7293
+ reasoning: response.reasoning
7294
+ },
7295
+ usage: response.usage,
7296
+ finishReason: response.finishReason
7297
+ };
7298
+ return;
7299
+ }
6887
7300
  const body = this.buildRequestBody(request, true);
6888
7301
  const res = await this.doFetch(body);
6889
7302
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
@@ -6982,6 +7395,156 @@ var OpenAIProvider = class extends BaseProvider {
6982
7395
  applyOpenAIReasoning(body, request.reasoning, "legacy_effort");
6983
7396
  return body;
6984
7397
  }
7398
+ // ─── Responses API (reasoning models) ──────────────────────────────────────
7399
+ async completeResponses(request) {
7400
+ const body = this.buildResponsesBody(request);
7401
+ const res = await this.responsesFetch(body);
7402
+ const json = await res.json();
7403
+ return this.parseResponsesResponse(json, request.model || this.defaultModel);
7404
+ }
7405
+ buildResponsesBody(request) {
7406
+ const body = {
7407
+ model: request.model || this.defaultModel,
7408
+ input: request.messages.map((m) => this.toResponsesInput(m))
7409
+ };
7410
+ if (request.maxTokens != null) body.max_output_tokens = request.maxTokens;
7411
+ if (request.topP != null) body.top_p = request.topP;
7412
+ if (request.tools?.length) {
7413
+ body.tools = request.tools.map((t) => ({
7414
+ type: "function",
7415
+ name: t.name,
7416
+ description: t.description,
7417
+ parameters: t.parameters,
7418
+ ...t.strict ? { strict: true } : {}
7419
+ }));
7420
+ }
7421
+ if (request.toolChoice != null && request.tools?.length) {
7422
+ if (typeof request.toolChoice === "string") {
7423
+ body.tool_choice = request.toolChoice;
7424
+ } else {
7425
+ body.tool_choice = { type: "function", name: request.toolChoice.name };
7426
+ }
7427
+ }
7428
+ if (request.responseFormat) {
7429
+ if (request.responseFormat.type === "json_schema") {
7430
+ body.text = {
7431
+ format: {
7432
+ type: "json_schema",
7433
+ name: request.responseFormat.name ?? "response",
7434
+ schema: request.responseFormat.schema,
7435
+ strict: true
7436
+ }
7437
+ };
7438
+ } else if (request.responseFormat.type === "json_object") {
7439
+ body.text = { format: { type: "json_object" } };
7440
+ }
7441
+ }
7442
+ if (request.extra) Object.assign(body, request.extra);
7443
+ applyOpenAIReasoning(body, request.reasoning, "responses");
7444
+ return body;
7445
+ }
7446
+ /** Maps a unified message to a Responses API `input` item. */
7447
+ toResponsesInput(m) {
7448
+ if (m.role === "tool" && m.toolCallId) {
7449
+ const output = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
7450
+ return { type: "function_call_output", call_id: m.toolCallId, output };
7451
+ }
7452
+ if (m.role === "assistant" && m.toolCalls?.length) {
7453
+ return {
7454
+ __assistantWithCalls: true,
7455
+ text: typeof m.content === "string" ? m.content : "",
7456
+ calls: m.toolCalls.map((tc) => ({
7457
+ type: "function_call",
7458
+ call_id: tc.id,
7459
+ name: tc.name,
7460
+ arguments: tc.arguments
7461
+ }))
7462
+ };
7463
+ }
7464
+ const role = m.role === "system" ? "system" : m.role === "assistant" ? "assistant" : "user";
7465
+ const textType = role === "assistant" ? "output_text" : "input_text";
7466
+ if (typeof m.content === "string") {
7467
+ return { role, content: [{ type: textType, text: m.content }] };
7468
+ }
7469
+ const content = m.content.map((part) => {
7470
+ if (part.type === "text") return { type: textType, text: part.text };
7471
+ if (part.type === "image") {
7472
+ const src = part.source;
7473
+ const url = src.type === "url" ? src.url : `data:${src.mediaType};base64,${src.data}`;
7474
+ return { type: "input_image", image_url: url };
7475
+ }
7476
+ return { type: textType, text: "" };
7477
+ });
7478
+ return { role, content };
7479
+ }
7480
+ async responsesFetch(body) {
7481
+ body.input = expandResponsesInput(body.input);
7482
+ const url = `${this.baseURL}/responses`;
7483
+ const headers = {
7484
+ "Content-Type": "application/json",
7485
+ Authorization: `Bearer ${this.apiKey}`,
7486
+ ...this.defaultHeaders
7487
+ };
7488
+ const payload = JSON.stringify(body);
7489
+ const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
7490
+ if (!res.ok) {
7491
+ const text = await res.text().catch(() => "");
7492
+ throw new ProviderError(
7493
+ `OpenAI Responses API error ${res.status}: ${text}`,
7494
+ this.providerName,
7495
+ res.status,
7496
+ text
7497
+ );
7498
+ }
7499
+ return res;
7500
+ }
7501
+ parseResponsesResponse(json, modelId) {
7502
+ const textParts = [];
7503
+ const toolCalls = [];
7504
+ const summaryParts = [];
7505
+ for (const item of json.output ?? []) {
7506
+ if (item.type === "message") {
7507
+ for (const c of item.content ?? []) {
7508
+ if (c.type === "output_text" && typeof c.text === "string") textParts.push(c.text);
7509
+ }
7510
+ } else if (item.type === "function_call") {
7511
+ toolCalls.push({
7512
+ id: item.call_id ?? item.id ?? "",
7513
+ name: item.name ?? "",
7514
+ arguments: typeof item.arguments === "string" ? item.arguments : JSON.stringify(item.arguments ?? {})
7515
+ });
7516
+ } else if (item.type === "reasoning") {
7517
+ for (const s of item.summary ?? []) {
7518
+ if (typeof s.text === "string") summaryParts.push(s.text);
7519
+ }
7520
+ }
7521
+ }
7522
+ if (textParts.length === 0 && typeof json.output_text === "string") {
7523
+ textParts.push(json.output_text);
7524
+ }
7525
+ const usage = json.usage ?? {};
7526
+ const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? 0;
7527
+ const tokenUsage = {
7528
+ inputTokens: usage.input_tokens ?? 0,
7529
+ outputTokens: usage.output_tokens ?? 0,
7530
+ totalTokens: usage.total_tokens ?? (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),
7531
+ cachedInputTokens: usage.input_tokens_details?.cached_tokens ?? 0,
7532
+ cachedWriteTokens: 0,
7533
+ cachedOutputTokens: 0,
7534
+ reasoningTokens
7535
+ };
7536
+ const finishReason = toolCalls.length > 0 ? "tool_calls" : json.status === "incomplete" ? "length" : "stop";
7537
+ return {
7538
+ id: json.id ?? "",
7539
+ model: json.model ?? modelId,
7540
+ content: textParts.join("") || null,
7541
+ toolCalls,
7542
+ usage: tokenUsage,
7543
+ finishReason,
7544
+ reasoning: summaryParts.length > 0 ? { summary: summaryParts.join("\n").trim() || void 0 } : void 0,
7545
+ raw: json
7546
+ };
7547
+ }
6985
7548
  toOpenAIMessage(m) {
6986
7549
  const msg = { role: m.role };
6987
7550
  if (typeof m.content === "string") {
@@ -7074,6 +7637,25 @@ var OpenAIProvider = class extends BaseProvider {
7074
7637
  };
7075
7638
  }
7076
7639
  };
7640
+ function isReasoningModel(model) {
7641
+ if (!model) return false;
7642
+ const m = model.toLowerCase();
7643
+ return /(^|[/_-])o[0-9]/.test(m) || m.startsWith("o1") || m.startsWith("o3") || m.startsWith("o4") || m.includes("gpt-5") || m.includes("gpt5");
7644
+ }
7645
+ function expandResponsesInput(input) {
7646
+ const out = [];
7647
+ for (const item of input) {
7648
+ if (item && item.__assistantWithCalls) {
7649
+ if (item.text) {
7650
+ out.push({ role: "assistant", content: [{ type: "output_text", text: item.text }] });
7651
+ }
7652
+ for (const call of item.calls) out.push(call);
7653
+ } else {
7654
+ out.push(item);
7655
+ }
7656
+ }
7657
+ return out;
7658
+ }
7077
7659
  function mapFinishReason(reason) {
7078
7660
  switch (reason) {
7079
7661
  case "stop":
@@ -7119,6 +7701,7 @@ var AnthropicProvider = class extends BaseProvider {
7119
7701
  let cacheReadInputTokens = 0;
7120
7702
  let cacheCreationInputTokens = 0;
7121
7703
  const currentToolCalls = /* @__PURE__ */ new Map();
7704
+ const reasoningBlocks = /* @__PURE__ */ new Map();
7122
7705
  for await (const event of parseSSEStream(res.body)) {
7123
7706
  let data;
7124
7707
  try {
@@ -7148,6 +7731,10 @@ var AnthropicProvider = class extends BaseProvider {
7148
7731
  name: block.name ?? "",
7149
7732
  arguments: ""
7150
7733
  });
7734
+ } else if (block?.type === "thinking") {
7735
+ reasoningBlocks.set(idx, { type: "thinking", text: block.thinking ?? "", signature: block.signature });
7736
+ } else if (block?.type === "redacted_thinking") {
7737
+ reasoningBlocks.set(idx, { type: "redacted_thinking", data: block.data });
7151
7738
  }
7152
7739
  break;
7153
7740
  }
@@ -7160,6 +7747,19 @@ var AnthropicProvider = class extends BaseProvider {
7160
7747
  model,
7161
7748
  delta: { content: delta.text }
7162
7749
  };
7750
+ } else if (delta?.type === "thinking_delta" && delta.thinking) {
7751
+ const blk = reasoningBlocks.get(idx) ?? { type: "thinking", text: "" };
7752
+ blk.text = (blk.text ?? "") + delta.thinking;
7753
+ reasoningBlocks.set(idx, blk);
7754
+ yield {
7755
+ id,
7756
+ model,
7757
+ delta: { reasoning: { summary: delta.thinking } }
7758
+ };
7759
+ } else if (delta?.type === "signature_delta" && delta.signature) {
7760
+ const blk = reasoningBlocks.get(idx) ?? { type: "thinking", text: "" };
7761
+ blk.signature = (blk.signature ?? "") + delta.signature;
7762
+ reasoningBlocks.set(idx, blk);
7163
7763
  } else if (delta?.type === "input_json_delta" && delta.partial_json) {
7164
7764
  const tc = currentToolCalls.get(idx);
7165
7765
  if (tc) {
@@ -7192,10 +7792,13 @@ var AnthropicProvider = class extends BaseProvider {
7192
7792
  cachedOutputTokens: 0,
7193
7793
  reasoningTokens: 0
7194
7794
  };
7795
+ const blocks = [...reasoningBlocks.values()].filter(
7796
+ (b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
7797
+ );
7195
7798
  yield {
7196
7799
  id,
7197
7800
  model,
7198
- delta: {},
7801
+ delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
7199
7802
  finishReason,
7200
7803
  usage
7201
7804
  };
@@ -7287,6 +7890,7 @@ var AnthropicProvider = class extends BaseProvider {
7287
7890
  }
7288
7891
  if (m.role === "assistant" && m.toolCalls?.length) {
7289
7892
  const content = [];
7893
+ appendReasoningBlocks(content, m.reasoning?.blocks);
7290
7894
  if (typeof m.content === "string" && m.content) {
7291
7895
  content.push({ type: "text", text: m.content });
7292
7896
  }
@@ -7300,6 +7904,13 @@ var AnthropicProvider = class extends BaseProvider {
7300
7904
  }
7301
7905
  return { role: "assistant", content };
7302
7906
  }
7907
+ if (m.role === "assistant" && m.reasoning?.blocks?.length) {
7908
+ const content = [];
7909
+ appendReasoningBlocks(content, m.reasoning.blocks);
7910
+ const text = typeof m.content === "string" ? m.content : "";
7911
+ if (text) content.push({ type: "text", text });
7912
+ return { role: "assistant", content };
7913
+ }
7303
7914
  const msg = { role: m.role };
7304
7915
  if (typeof m.content === "string") {
7305
7916
  msg.content = m.content;
@@ -7355,9 +7966,20 @@ var AnthropicProvider = class extends BaseProvider {
7355
7966
  parseResponse(json) {
7356
7967
  const textParts = [];
7357
7968
  const toolCalls = [];
7969
+ const reasoningBlocks = [];
7970
+ const summaryParts = [];
7358
7971
  for (const block of json.content ?? []) {
7359
7972
  if (block.type === "text") {
7360
7973
  textParts.push(block.text);
7974
+ } else if (block.type === "thinking") {
7975
+ reasoningBlocks.push({
7976
+ type: "thinking",
7977
+ text: block.thinking ?? "",
7978
+ signature: block.signature
7979
+ });
7980
+ if (block.thinking) summaryParts.push(block.thinking);
7981
+ } else if (block.type === "redacted_thinking") {
7982
+ reasoningBlocks.push({ type: "redacted_thinking", data: block.data });
7361
7983
  } else if (block.type === "tool_use") {
7362
7984
  toolCalls.push({
7363
7985
  id: block.id,
@@ -7374,6 +7996,9 @@ var AnthropicProvider = class extends BaseProvider {
7374
7996
  cachedInputTokens: usage.cache_read_input_tokens ?? 0,
7375
7997
  cachedWriteTokens: usage.cache_creation_input_tokens ?? 0,
7376
7998
  cachedOutputTokens: 0,
7999
+ // Anthropic bills thinking tokens inside `output_tokens` and does not
8000
+ // expose a separate count, so reasoningTokens stays 0 here (cost is still
8001
+ // captured via outputTokens). See docs for the limitation.
7377
8002
  reasoningTokens: 0
7378
8003
  };
7379
8004
  return {
@@ -7383,6 +8008,7 @@ var AnthropicProvider = class extends BaseProvider {
7383
8008
  toolCalls,
7384
8009
  usage: tokenUsage,
7385
8010
  finishReason: mapAnthropicStopReason(json.stop_reason),
8011
+ reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
7386
8012
  raw: json
7387
8013
  };
7388
8014
  }
@@ -7407,6 +8033,18 @@ function safeJsonParse(str) {
7407
8033
  return {};
7408
8034
  }
7409
8035
  }
8036
+ function appendReasoningBlocks(content, blocks) {
8037
+ if (!blocks?.length) return;
8038
+ for (const b of blocks) {
8039
+ if (b.type === "redacted_thinking") {
8040
+ if (b.data) content.push({ type: "redacted_thinking", data: b.data });
8041
+ } else if (b.type === "thinking") {
8042
+ if (b.signature) {
8043
+ content.push({ type: "thinking", thinking: b.text ?? "", signature: b.signature });
8044
+ }
8045
+ }
8046
+ }
8047
+ }
7410
8048
 
7411
8049
  // src/providers/azure.ts
7412
8050
  var AzureProvider = class extends OpenAIProvider {
@@ -7450,7 +8088,52 @@ var AzureProvider = class extends OpenAIProvider {
7450
8088
  }
7451
8089
  return res;
7452
8090
  }
8091
+ /** Azure exposes the Responses API at /openai/responses with api-key auth.
8092
+ * Reasoning summaries require a preview api-version; callers can override via
8093
+ * the `apiVersion` config. */
8094
+ async responsesFetch(body) {
8095
+ body.input = expandAzureResponsesInput(body.input);
8096
+ const deployment = this.deploymentName ?? body.model;
8097
+ if (!deployment) {
8098
+ throw new ProviderError("Azure requires a deploymentName or model", this.providerName);
8099
+ }
8100
+ const url = `${this.endpoint}/openai/responses?api-version=${this.apiVersion}`;
8101
+ const payload = JSON.stringify({ ...body, model: deployment });
8102
+ const res = await fetch(url, {
8103
+ method: "POST",
8104
+ headers: {
8105
+ "Content-Type": "application/json",
8106
+ "api-key": this.azureApiKey,
8107
+ ...this.defaultHeaders
8108
+ },
8109
+ body: payload
8110
+ });
8111
+ if (!res.ok) {
8112
+ const text = await res.text().catch(() => "");
8113
+ throw new ProviderError(
8114
+ `Azure OpenAI Responses API error ${res.status}: ${text}`,
8115
+ this.providerName,
8116
+ res.status,
8117
+ text
8118
+ );
8119
+ }
8120
+ return res;
8121
+ }
7453
8122
  };
8123
+ function expandAzureResponsesInput(input) {
8124
+ const out = [];
8125
+ for (const item of input) {
8126
+ if (item && item.__assistantWithCalls) {
8127
+ if (item.text) {
8128
+ out.push({ role: "assistant", content: [{ type: "output_text", text: item.text }] });
8129
+ }
8130
+ for (const call of item.calls) out.push(call);
8131
+ } else {
8132
+ out.push(item);
8133
+ }
8134
+ }
8135
+ return out;
8136
+ }
7454
8137
 
7455
8138
  // src/providers/openaiCompatible.ts
7456
8139
  var OpenAICompatibleProvider = class extends OpenAIProvider {
@@ -7623,6 +8306,7 @@ var BedrockProvider = class extends BaseProvider {
7623
8306
  if (request.extra) {
7624
8307
  Object.assign(body, request.extra);
7625
8308
  }
8309
+ applyBedrockReasoning(body, request.reasoning);
7626
8310
  return body;
7627
8311
  }
7628
8312
  splitSystemMessages(messages) {
@@ -7656,6 +8340,7 @@ var BedrockProvider = class extends BaseProvider {
7656
8340
  }
7657
8341
  if (m.role === "assistant" && m.toolCalls?.length) {
7658
8342
  const content2 = [];
8343
+ appendBedrockReasoning(content2, m.reasoning?.blocks);
7659
8344
  if (typeof m.content === "string" && m.content) {
7660
8345
  content2.push({ text: m.content });
7661
8346
  }
@@ -7736,9 +8421,23 @@ var BedrockProvider = class extends BaseProvider {
7736
8421
  const output = json.output?.message;
7737
8422
  const textParts = [];
7738
8423
  const toolCalls = [];
8424
+ const reasoningBlocks = [];
8425
+ const summaryParts = [];
7739
8426
  for (const block of output?.content ?? []) {
7740
8427
  if (block.text) {
7741
8428
  textParts.push(block.text);
8429
+ } else if (block.reasoningContent) {
8430
+ const rc = block.reasoningContent;
8431
+ if (rc.reasoningText) {
8432
+ reasoningBlocks.push({
8433
+ type: "thinking",
8434
+ text: rc.reasoningText.text ?? "",
8435
+ signature: rc.reasoningText.signature
8436
+ });
8437
+ if (rc.reasoningText.text) summaryParts.push(rc.reasoningText.text);
8438
+ } else if (rc.redactedContent) {
8439
+ reasoningBlocks.push({ type: "redacted_thinking", data: rc.redactedContent });
8440
+ }
7742
8441
  } else if (block.toolUse) {
7743
8442
  toolCalls.push({
7744
8443
  id: block.toolUse.toolUseId,
@@ -7755,6 +8454,7 @@ var BedrockProvider = class extends BaseProvider {
7755
8454
  cachedInputTokens: usage.cacheReadInputTokenCount ?? 0,
7756
8455
  cachedWriteTokens: usage.cacheWriteInputTokenCount ?? 0,
7757
8456
  cachedOutputTokens: 0,
8457
+ // Bedrock bills thinking tokens inside outputTokens; no separate count.
7758
8458
  reasoningTokens: 0
7759
8459
  };
7760
8460
  return {
@@ -7764,10 +8464,25 @@ var BedrockProvider = class extends BaseProvider {
7764
8464
  toolCalls,
7765
8465
  usage: tokenUsage,
7766
8466
  finishReason: mapBedrockStopReason(json.stopReason),
8467
+ reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
7767
8468
  raw: json
7768
8469
  };
7769
8470
  }
7770
8471
  };
8472
+ function appendBedrockReasoning(content, blocks) {
8473
+ if (!blocks?.length) return;
8474
+ for (const b of blocks) {
8475
+ if (b.type === "redacted_thinking") {
8476
+ if (b.data) content.push({ reasoningContent: { redactedContent: b.data } });
8477
+ } else if (b.type === "thinking") {
8478
+ if (b.signature) {
8479
+ content.push({
8480
+ reasoningContent: { reasoningText: { text: b.text ?? "", signature: b.signature } }
8481
+ });
8482
+ }
8483
+ }
8484
+ }
8485
+ }
7771
8486
  function mapBedrockStopReason(reason) {
7772
8487
  switch (reason) {
7773
8488
  case "end_turn":
@@ -8090,10 +8805,15 @@ var VertexProvider = class extends BaseProvider {
8090
8805
  const parts = candidate?.content?.parts ?? [];
8091
8806
  const textParts = [];
8092
8807
  const toolCalls = [];
8808
+ const thoughtParts = [];
8093
8809
  let toolCallIdx = 0;
8094
8810
  for (const part of parts) {
8095
8811
  if (part.text) {
8096
- textParts.push(part.text);
8812
+ if (part.thought === true) {
8813
+ thoughtParts.push(part.text);
8814
+ } else {
8815
+ textParts.push(part.text);
8816
+ }
8097
8817
  } else if (part.functionCall) {
8098
8818
  toolCalls.push({
8099
8819
  id: `call_${toolCallIdx++}`,
@@ -8119,6 +8839,7 @@ var VertexProvider = class extends BaseProvider {
8119
8839
  toolCalls,
8120
8840
  usage: tokenUsage,
8121
8841
  finishReason: mapGeminiFinishReason(candidate?.finishReason),
8842
+ reasoning: thoughtParts.length > 0 ? { summary: thoughtParts.join("\n").trim() || void 0 } : void 0,
8122
8843
  raw: json
8123
8844
  };
8124
8845
  }
@@ -8128,7 +8849,11 @@ var VertexProvider = class extends BaseProvider {
8128
8849
  const delta = {};
8129
8850
  for (const part of parts) {
8130
8851
  if (part.text) {
8131
- delta.content = (delta.content ?? "") + part.text;
8852
+ if (part.thought === true) {
8853
+ delta.reasoning = { summary: (delta.reasoning?.summary ?? "") + part.text };
8854
+ } else {
8855
+ delta.content = (delta.content ?? "") + part.text;
8856
+ }
8132
8857
  } else if (part.functionCall) {
8133
8858
  if (!delta.toolCalls) delta.toolCalls = [];
8134
8859
  delta.toolCalls.push({
@@ -8202,12 +8927,16 @@ function fromNativeProvider(provider, options) {
8202
8927
  let fullContent = "";
8203
8928
  let allToolCalls = [];
8204
8929
  let lastUsage;
8930
+ let reasoningBlocks;
8205
8931
  const toolCallBuffers = /* @__PURE__ */ new Map();
8206
8932
  for await (const chunk of provider.completeStream(request)) {
8207
8933
  if (chunk.delta.content) {
8208
8934
  fullContent += chunk.delta.content;
8209
8935
  yield chunk.delta.content;
8210
8936
  }
8937
+ if (chunk.delta.reasoning?.blocks?.length) {
8938
+ reasoningBlocks = chunk.delta.reasoning.blocks;
8939
+ }
8211
8940
  if (chunk.delta.toolCalls) {
8212
8941
  for (const tc of chunk.delta.toolCalls) {
8213
8942
  if (tc.id) {
@@ -8228,6 +8957,9 @@ function fromNativeProvider(provider, options) {
8228
8957
  }
8229
8958
  allToolCalls = [...toolCallBuffers.values()];
8230
8959
  const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
8960
+ if (reasoningBlocks?.length) {
8961
+ finalMessage.reasoning = { blocks: reasoningBlocks };
8962
+ }
8231
8963
  yield finalMessage;
8232
8964
  },
8233
8965
  bindTools: (tools, _bindOptions) => {
@@ -8290,6 +9022,10 @@ function toUnifiedMessage(msg) {
8290
9022
  arguments: tc.function?.arguments ?? tc.arguments ?? "{}"
8291
9023
  }));
8292
9024
  }
9025
+ const reasoning = msg.reasoning;
9026
+ if (reasoning && (reasoning.blocks?.length || reasoning.summary)) {
9027
+ unified.reasoning = reasoning;
9028
+ }
8293
9029
  return unified;
8294
9030
  }
8295
9031
  function convertContent(content) {
@@ -8498,6 +9234,9 @@ function toBaseChatMessage(response) {
8498
9234
  function: { name: tc.name, arguments: tc.arguments }
8499
9235
  }));
8500
9236
  }
9237
+ if (response.reasoning && (response.reasoning.blocks?.length || response.reasoning.summary)) {
9238
+ msg.reasoning = response.reasoning;
9239
+ }
8501
9240
  return msg;
8502
9241
  }
8503
9242
  function assembleMessage(content, toolCalls, usage) {
@@ -8594,6 +9333,6 @@ function createProvider(config) {
8594
9333
  }
8595
9334
  }
8596
9335
 
8597
- export { AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, DEFAULT_PROFILE_CONFIGS, GuardrailPhase, InMemoryMemoryStore, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, ProviderError, StructuredOutputManager, ToolBasedStrategy, VertexProvider, agentVerdictRule, buildSystemPrompt, captureSnapshot, codePresenceRule, cognipeerSink, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createCodeGuardrail, createContextSummarizeNode, createContextTools, createGetToolResponseTool, createGuardrail, createJsonGuardrail, createManageTodoTool, createProvider, createRegexGuardrail, createResolverNode, createSmartAgent, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customSink, defaultTokenCounter, emptyUsage, evaluateGuardrails, fileSink, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasToolResponseRecoveryReference, httpSink, isSmartModel, jsonSchemaRule, normalizeSmartAgentOptions, otlpSink, readMemoryFacts, regexRule, resolveMemoryStore, resolveStrategy, resolveToolApprovalState, resolveUserQuestionState, restoreSnapshot, runSmartAgentEvalHarness, setTokenCounter, startStreamingSession, traceSessionToOtlp, withTools, writeSummaryFactsToMemory };
9336
+ export { AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, GuardrailPhase, InMemoryMemoryStore, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, ToolBasedStrategy, VertexProvider, agentVerdictRule, appendBoundTools, buildSkillHeaderBlock, buildSystemPrompt, canOpenSkill, captureSnapshot, codePresenceRule, cognipeerSink, composeToolSets, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextSummarizeNode, createContextTools, createGetToolResponseTool, createGuardrail, createJsonGuardrail, createManageTodoTool, createOpenSkillTool, createProvider, createRegexGuardrail, createResolverNode, createSkillRegistryRef, createSkillTools, createSmartAgent, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customSink, dedupeToolsByName, defaultTokenCounter, emptyUsage, evaluateGuardrails, fileSink, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasToolResponseRecoveryReference, httpSink, isSmartModel, jsonSchemaRule, normalizeSmartAgentOptions, otlpSink, readMemoryFacts, regexRule, resolveAvailableSkills, resolveMemoryStore, resolveReasoning, resolveStrategy, resolveToolApprovalState, resolveUserQuestionState, restoreSnapshot, runSmartAgentEvalHarness, setTokenCounter, startStreamingSession, traceSessionToOtlp, validateReasoningConfig, withTools, writeSummaryFactsToMemory };
8598
9337
  //# sourceMappingURL=index.mjs.map
8599
9338
  //# sourceMappingURL=index.mjs.map