@cognipeer/agent-sdk 0.6.6 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -52,7 +52,7 @@ function getTokenCounter() {
52
52
  function countApproxTokens(text) {
53
53
  return activeTokenCounter(text || "");
54
54
  }
55
- function extractMessageText(m) {
55
+ function extractMessageText2(m) {
56
56
  if (!m) return "";
57
57
  const parts = [];
58
58
  parts.push(m.role || "");
@@ -102,7 +102,7 @@ function extractMessageText(m) {
102
102
  }
103
103
  function countMessagesTokens(messages) {
104
104
  if (!Array.isArray(messages) || messages.length === 0) return 0;
105
- const allText = messages.map(extractMessageText).join("\n");
105
+ const allText = messages.map(extractMessageText2).join("\n");
106
106
  return countApproxTokens(allText) + messages.length * 4;
107
107
  }
108
108
  var activeTokenCounter;
@@ -1272,6 +1272,7 @@ function eventToOtlpSpan(event) {
1272
1272
  stringAttr("cognipeer.actor.role", event.actor?.role),
1273
1273
  stringAttr("cognipeer.model", event.model),
1274
1274
  stringAttr("cognipeer.provider", event.provider),
1275
+ stringAttr("cognipeer.tool.details", event.toolDetails ? JSON.stringify(event.toolDetails) : void 0),
1275
1276
  intAttr("cognipeer.tokens.input", event.inputTokens),
1276
1277
  intAttr("cognipeer.tokens.output", event.outputTokens),
1277
1278
  intAttr("cognipeer.tokens.total", event.totalTokens),
@@ -1743,6 +1744,7 @@ function recordTraceEvent(session, event) {
1743
1744
  responseBytes,
1744
1745
  model: resolvedModel,
1745
1746
  provider: resolvedProvider,
1747
+ toolDetails: session.resolvedConfig.logData ? sanitizeTracePayload(event.toolDetails) : void 0,
1746
1748
  toolExecutionId: event.toolExecutionId,
1747
1749
  retryOf: event.retryOf,
1748
1750
  error: event.error ?? (status === "error" ? { message: "Unknown error" } : void 0) ?? void 0,
@@ -2193,16 +2195,99 @@ function createAgentCoreNode(opts) {
2193
2195
  };
2194
2196
  }
2195
2197
 
2198
+ // src/utils/content.ts
2199
+ function contentToString(content) {
2200
+ try {
2201
+ if (content == null) return "";
2202
+ if (typeof content === "string") return content;
2203
+ if (Array.isArray(content)) {
2204
+ return content.map((p) => {
2205
+ if (!p || typeof p !== "object") return String(p);
2206
+ if (p.type === "text") return String(p.text ?? "");
2207
+ if (p.type === "image_url") {
2208
+ const img = p.image_url;
2209
+ const url = typeof img === "string" ? img : img?.url;
2210
+ const detail = typeof img === "string" ? void 0 : img?.detail;
2211
+ return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
2212
+ }
2213
+ return JSON.stringify(p);
2214
+ }).join("\n");
2215
+ }
2216
+ return JSON.stringify(content);
2217
+ } catch {
2218
+ return String(content);
2219
+ }
2220
+ }
2221
+ function mergeContentsToString(contents) {
2222
+ return contents.map((c) => contentToString(c)).join("\n");
2223
+ }
2224
+ function safeStringify(value, pretty = false) {
2225
+ if (value == null) return "";
2226
+ if (typeof value === "string") return value;
2227
+ try {
2228
+ return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
2229
+ } catch {
2230
+ return String(value);
2231
+ }
2232
+ }
2233
+ function extractMessageText(message) {
2234
+ if (!message) return "";
2235
+ const content = message.content;
2236
+ if (typeof content === "string") return content;
2237
+ if (Array.isArray(content)) {
2238
+ return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
2239
+ }
2240
+ return "";
2241
+ }
2242
+
2243
+ // src/utils/traceSections.ts
2244
+ function truncate(text, max = 500) {
2245
+ if (!text) return "";
2246
+ return text.length > max ? `${text.slice(0, max)}\u2026` : text;
2247
+ }
2248
+ function summarizeToolOutput(output) {
2249
+ if (output == null) return "";
2250
+ if (typeof output === "string") return truncate(output.trim());
2251
+ if (Array.isArray(output)) {
2252
+ const preview = output.slice(0, 3).map((item, index) => `${index + 1}. ${truncate(safeStringify(item))}`).join("\n");
2253
+ const suffix = output.length > 3 ? `
2254
+ \u2026 (+${output.length - 3} more)` : "";
2255
+ return `${preview}${suffix}`.trim();
2256
+ }
2257
+ if (typeof output === "object") {
2258
+ if (Array.isArray(output.items)) {
2259
+ return summarizeToolOutput(output.items);
2260
+ }
2261
+ return truncate(safeStringify(output));
2262
+ }
2263
+ return truncate(String(output));
2264
+ }
2265
+ function extractToolItems(output) {
2266
+ const source = Array.isArray(output) ? output : Array.isArray(output?.items) ? output.items : void 0;
2267
+ if (!Array.isArray(source) || source.length === 0) return void 0;
2268
+ return source.slice(0, 5).map((item) => {
2269
+ if (item && typeof item === "object") {
2270
+ const snippetSource = item.content ?? item.snippet ?? item.description ?? item.text ?? item.summary ?? item;
2271
+ return {
2272
+ title: typeof item.title === "string" ? item.title : void 0,
2273
+ url: typeof item.url === "string" ? item.url : void 0,
2274
+ snippet: truncate(safeStringify(snippetSource))
2275
+ };
2276
+ }
2277
+ return { snippet: truncate(safeStringify(item)) };
2278
+ });
2279
+ }
2280
+
2196
2281
  // src/smart/runtimeConfig.ts
2197
2282
  var DEFAULT_CRITICAL_TOOLS = ["response", "manage_todo_list", "get_tool_response"];
2198
2283
  var BASE_DEFAULTS = {
2199
- limits: { maxToolCalls: 8, maxParallelTools: 2, maxContextTokens: 24e3, maxTotalOutputTokens: 0, maxCostUsd: 0, maxWallClockMs: 0 },
2284
+ limits: { maxToolCalls: 20, maxParallelTools: 5, maxContextTokens: 96e3, maxTotalOutputTokens: 0, maxCostUsd: 0, maxWallClockMs: 0 },
2200
2285
  summarization: {
2201
2286
  enable: true,
2202
- maxTokens: 24e3,
2203
- summaryTriggerTokens: 17e3,
2204
- summaryPromptMaxTokens: 7e3,
2205
- summaryCompressionRatioTarget: 0.35,
2287
+ maxTokens: 96e3,
2288
+ summaryTriggerTokens: 72e3,
2289
+ summaryPromptMaxTokens: 12e3,
2290
+ summaryCompressionRatioTarget: 0.45,
2206
2291
  summaryMode: "incremental",
2207
2292
  promptTemplate: "",
2208
2293
  toolFreeCall: true,
@@ -2210,13 +2295,13 @@ var BASE_DEFAULTS = {
2210
2295
  },
2211
2296
  context: {
2212
2297
  policy: "hybrid",
2213
- lastTurnsToKeep: 8,
2298
+ lastTurnsToKeep: 16,
2214
2299
  toolResponsePolicy: "summarize_archive",
2215
2300
  budget: {
2216
- systemReserveTokens: 1200,
2217
- goalsReserveTokens: 1200,
2218
- recentTurnsReserveTokens: 5200,
2219
- toolResponseReserveTokens: 2800
2301
+ systemReserveTokens: 2e3,
2302
+ goalsReserveTokens: 2e3,
2303
+ recentTurnsReserveTokens: 18e3,
2304
+ toolResponseReserveTokens: 9e3
2220
2305
  }
2221
2306
  },
2222
2307
  planning: {
@@ -2233,14 +2318,14 @@ var BASE_DEFAULTS = {
2233
2318
  delegation: {
2234
2319
  mode: "role_based",
2235
2320
  maxDelegationDepth: 2,
2236
- maxChildCalls: 4,
2237
- maxParallelChild: 2,
2321
+ maxChildCalls: 6,
2322
+ maxParallelChild: 3,
2238
2323
  childContextPolicy: "scoped",
2239
2324
  requireJsonOutputContract: true
2240
2325
  },
2241
2326
  toolResponses: {
2242
- maxToolResponseChars: 12e3,
2243
- maxToolResponseTokens: 3e3,
2327
+ maxToolResponseChars: 32e3,
2328
+ maxToolResponseTokens: 8e3,
2244
2329
  defaultPolicy: "summarize_archive",
2245
2330
  toolResponseRetentionByTool: {},
2246
2331
  criticalTools: [...DEFAULT_CRITICAL_TOOLS],
@@ -2269,54 +2354,54 @@ function buildProfile(overrides) {
2269
2354
  }
2270
2355
  var DEFAULT_PROFILE_CONFIGS = {
2271
2356
  fast: buildProfile({
2272
- limits: { maxToolCalls: 4, maxParallelTools: 1, maxContextTokens: 12e3 },
2357
+ limits: { maxToolCalls: 8, maxParallelTools: 3, maxContextTokens: 32e3 },
2273
2358
  summarization: {
2274
- maxTokens: 12e3,
2275
- summaryTriggerTokens: 9e3,
2276
- summaryPromptMaxTokens: 5e3,
2277
- summaryCompressionRatioTarget: 0.4
2359
+ maxTokens: 32e3,
2360
+ summaryTriggerTokens: 24e3,
2361
+ summaryPromptMaxTokens: 6e3,
2362
+ summaryCompressionRatioTarget: 0.5
2278
2363
  },
2279
2364
  context: {
2280
- lastTurnsToKeep: 6,
2365
+ lastTurnsToKeep: 8,
2281
2366
  toolResponsePolicy: "keep_structured",
2282
- budget: { systemReserveTokens: 1e3, goalsReserveTokens: 900, recentTurnsReserveTokens: 3200, toolResponseReserveTokens: 1800 }
2367
+ budget: { systemReserveTokens: 1500, goalsReserveTokens: 1200, recentTurnsReserveTokens: 6e3, toolResponseReserveTokens: 3500 }
2283
2368
  },
2284
2369
  memory: { readPolicy: "recent_only" },
2285
2370
  delegation: { mode: "off", maxDelegationDepth: 1, maxChildCalls: 2, maxParallelChild: 1, childContextPolicy: "minimal" },
2286
- toolResponses: { maxToolResponseChars: 8e3, maxToolResponseTokens: 2e3 }
2371
+ toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 }
2287
2372
  }),
2288
2373
  balanced: buildProfile({}),
2289
2374
  deep: buildProfile({
2290
- limits: { maxToolCalls: 14, maxParallelTools: 3, maxContextTokens: 42e3 },
2375
+ limits: { maxToolCalls: 40, maxParallelTools: 8, maxContextTokens: 2e5 },
2291
2376
  summarization: {
2292
- maxTokens: 42e3,
2293
- summaryTriggerTokens: 3e4,
2294
- summaryPromptMaxTokens: 9e3,
2295
- summaryCompressionRatioTarget: 0.3
2377
+ maxTokens: 2e5,
2378
+ summaryTriggerTokens: 15e4,
2379
+ summaryPromptMaxTokens: 16e3,
2380
+ summaryCompressionRatioTarget: 0.4
2296
2381
  },
2297
2382
  context: {
2298
- lastTurnsToKeep: 12,
2299
- budget: { systemReserveTokens: 1400, goalsReserveTokens: 1600, recentTurnsReserveTokens: 7e3, toolResponseReserveTokens: 3600 }
2383
+ lastTurnsToKeep: 30,
2384
+ budget: { systemReserveTokens: 2500, goalsReserveTokens: 2500, recentTurnsReserveTokens: 36e3, toolResponseReserveTokens: 18e3 }
2300
2385
  },
2301
2386
  memory: { scope: "workspace" },
2302
- delegation: { maxDelegationDepth: 3, maxChildCalls: 6 },
2303
- toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 }
2387
+ delegation: { maxDelegationDepth: 3, maxChildCalls: 10, maxParallelChild: 4 },
2388
+ toolResponses: { maxToolResponseChars: 64e3, maxToolResponseTokens: 16e3 }
2304
2389
  }),
2305
2390
  research: buildProfile({
2306
- limits: { maxToolCalls: 20, maxParallelTools: 4, maxContextTokens: 56e3 },
2391
+ limits: { maxToolCalls: 80, maxParallelTools: 10, maxContextTokens: 4e5 },
2307
2392
  summarization: {
2308
- maxTokens: 56e3,
2309
- summaryTriggerTokens: 42e3,
2310
- summaryPromptMaxTokens: 1e4,
2311
- summaryCompressionRatioTarget: 0.28
2393
+ maxTokens: 4e5,
2394
+ summaryTriggerTokens: 3e5,
2395
+ summaryPromptMaxTokens: 24e3,
2396
+ summaryCompressionRatioTarget: 0.35
2312
2397
  },
2313
2398
  context: {
2314
- lastTurnsToKeep: 20,
2315
- budget: { systemReserveTokens: 1600, goalsReserveTokens: 1800, recentTurnsReserveTokens: 9e3, toolResponseReserveTokens: 4800 }
2399
+ lastTurnsToKeep: 60,
2400
+ budget: { systemReserveTokens: 3e3, goalsReserveTokens: 3e3, recentTurnsReserveTokens: 72e3, toolResponseReserveTokens: 32e3 }
2316
2401
  },
2317
2402
  memory: { scope: "workspace" },
2318
- delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 8, maxParallelChild: 3, childContextPolicy: "full" },
2319
- toolResponses: { maxToolResponseChars: 24e3, maxToolResponseTokens: 6e3 }
2403
+ delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 16, maxParallelChild: 6, childContextPolicy: "full" },
2404
+ toolResponses: { maxToolResponseChars: 96e3, maxToolResponseTokens: 24e3 }
2320
2405
  })
2321
2406
  };
2322
2407
  function mergeLimits(base, override) {
@@ -2406,53 +2491,6 @@ function getResolvedSmartConfig(opts, runtime) {
2406
2491
 
2407
2492
  // src/smart/toolResponses.ts
2408
2493
  init_utilTokens();
2409
-
2410
- // src/utils/content.ts
2411
- function contentToString(content) {
2412
- try {
2413
- if (content == null) return "";
2414
- if (typeof content === "string") return content;
2415
- if (Array.isArray(content)) {
2416
- return content.map((p) => {
2417
- if (!p || typeof p !== "object") return String(p);
2418
- if (p.type === "text") return String(p.text ?? "");
2419
- if (p.type === "image_url") {
2420
- const img = p.image_url;
2421
- const url = typeof img === "string" ? img : img?.url;
2422
- const detail = typeof img === "string" ? void 0 : img?.detail;
2423
- return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
2424
- }
2425
- return JSON.stringify(p);
2426
- }).join("\n");
2427
- }
2428
- return JSON.stringify(content);
2429
- } catch {
2430
- return String(content);
2431
- }
2432
- }
2433
- function mergeContentsToString(contents) {
2434
- return contents.map((c) => contentToString(c)).join("\n");
2435
- }
2436
- function safeStringify(value, pretty = false) {
2437
- if (value == null) return "";
2438
- if (typeof value === "string") return value;
2439
- try {
2440
- return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
2441
- } catch {
2442
- return String(value);
2443
- }
2444
- }
2445
- function extractMessageText2(message) {
2446
- if (!message) return "";
2447
- const content = message.content;
2448
- if (typeof content === "string") return content;
2449
- if (Array.isArray(content)) {
2450
- return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
2451
- }
2452
- return "";
2453
- }
2454
-
2455
- // src/smart/toolResponses.ts
2456
2494
  function summarizeObject(value) {
2457
2495
  if (value == null) return "null";
2458
2496
  if (typeof value === "string") {
@@ -2567,6 +2605,97 @@ function normalizeToolCall(call) {
2567
2605
  args: call.args ?? call.arguments ?? call.input ?? call.function?.arguments ?? call.function_call?.arguments
2568
2606
  };
2569
2607
  }
2608
+ function normalizeToolSchema(tool, toolName) {
2609
+ const schema = tool.schema;
2610
+ if (!schema) return void 0;
2611
+ if (typeof schema === "object" && schema._def) {
2612
+ try {
2613
+ return sanitizeTracePayload(zodToJsonSchema.zodToJsonSchema(schema, { name: toolName }));
2614
+ } catch {
2615
+ }
2616
+ }
2617
+ if (schema && typeof schema === "object" && typeof schema.toJSON === "function") {
2618
+ try {
2619
+ return sanitizeTracePayload(schema.toJSON());
2620
+ } catch {
2621
+ }
2622
+ }
2623
+ return sanitizeTracePayload(schema);
2624
+ }
2625
+ function buildToolDetails(tool, toolName) {
2626
+ if (!tool) return void 0;
2627
+ const details = { name: toolName };
2628
+ if (typeof tool.description === "string" && tool.description.trim().length > 0) {
2629
+ details.description = tool.description;
2630
+ }
2631
+ const inputSchema = normalizeToolSchema(tool, toolName);
2632
+ if (inputSchema !== void 0) details.inputSchema = inputSchema;
2633
+ const needsApproval = typeof tool.needsApproval === "boolean" ? tool.needsApproval : void 0;
2634
+ if (needsApproval !== void 0 || tool.approvalPrompt !== void 0 || tool.approvalDefaults !== void 0) {
2635
+ details.approval = {
2636
+ required: needsApproval,
2637
+ prompt: typeof tool.approvalPrompt === "string" ? tool.approvalPrompt : void 0,
2638
+ defaults: tool.approvalDefaults !== void 0 ? sanitizeTracePayload(tool.approvalDefaults) : void 0
2639
+ };
2640
+ }
2641
+ const cache = tool.cache;
2642
+ if (cache !== void 0) {
2643
+ details.cache = {
2644
+ enabled: Boolean(cache),
2645
+ scope: cache && typeof cache === "object" && typeof cache.scope === "string" ? cache.scope : void 0,
2646
+ ttlMs: cache && typeof cache === "object" && typeof cache.ttlMs === "number" ? cache.ttlMs : void 0,
2647
+ hasKeyFn: Boolean(cache && typeof cache === "object" && typeof cache.keyFn === "function")
2648
+ };
2649
+ }
2650
+ const retry = tool.retry;
2651
+ if (retry && typeof retry === "object") {
2652
+ details.retry = {
2653
+ maxRetries: typeof retry.maxRetries === "number" ? retry.maxRetries : void 0,
2654
+ backoffMs: typeof retry.backoffMs === "number" ? retry.backoffMs : void 0,
2655
+ circuitBreakerThreshold: typeof retry.circuitBreakerThreshold === "number" ? retry.circuitBreakerThreshold : void 0,
2656
+ hasShouldRetry: typeof retry.shouldRetry === "function"
2657
+ };
2658
+ }
2659
+ if (tool.maxExecutionsPerRun !== void 0) {
2660
+ details.limits = { maxExecutionsPerRun: tool.maxExecutionsPerRun };
2661
+ }
2662
+ if (typeof tool.__source === "string") {
2663
+ details.source = tool.__source;
2664
+ }
2665
+ return details;
2666
+ }
2667
+ function buildToolTraceSections(params) {
2668
+ const sanitizedArgs = sanitizeTracePayload(params.args ?? {});
2669
+ const sanitizedOutput = sanitizeTracePayload(params.output);
2670
+ const summary = params.summary ?? summarizeToolOutput(sanitizedOutput);
2671
+ const items = extractToolItems(sanitizedOutput);
2672
+ return [
2673
+ {
2674
+ kind: "tool_call",
2675
+ label: `Tool Call: ${params.toolName}`,
2676
+ tool: params.toolName,
2677
+ arguments: sanitizedArgs,
2678
+ toolDetails: params.toolDetails
2679
+ },
2680
+ {
2681
+ kind: "tool_result",
2682
+ label: `Tool Result: ${params.toolName}`,
2683
+ tool: params.toolName,
2684
+ summary,
2685
+ items,
2686
+ output: sanitizedOutput,
2687
+ toolDetails: params.toolDetails,
2688
+ execution: {
2689
+ id: params.executionId,
2690
+ status: params.status,
2691
+ durationMs: params.durationMs,
2692
+ fromCache: params.fromCache
2693
+ },
2694
+ classification: params.classification,
2695
+ retentionPolicy: params.retentionPolicy
2696
+ }
2697
+ ];
2698
+ }
2570
2699
  function createToolsNode(initialTools, opts) {
2571
2700
  return async (state) => {
2572
2701
  const runtime = state.agent || {
@@ -2675,6 +2804,7 @@ function createToolsNode(initialTools, opts) {
2675
2804
  args = validatedArgs.value;
2676
2805
  }
2677
2806
  const toolName = tool.name || tc.name;
2807
+ const toolDetails = buildToolDetails(tool, toolName);
2678
2808
  const toolStateRef = tool._stateRef && typeof tool._stateRef === "object" ? tool._stateRef : null;
2679
2809
  if (toolStateRef) {
2680
2810
  toolStateRef.pendingApprovals = pendingApprovals;
@@ -2695,21 +2825,17 @@ function createToolsNode(initialTools, opts) {
2695
2825
  label: `Tool Skipped - ${toolName}`,
2696
2826
  actor: { scope: "tool", name: toolName, role: "tool" },
2697
2827
  status: "skipped",
2828
+ toolDetails,
2698
2829
  toolExecutionId: tc.id,
2699
- messageList: [
2700
- {
2701
- role: "assistant",
2702
- name: toolName,
2703
- content: limitMessage,
2704
- tool_calls: [
2705
- {
2706
- id: tc.id,
2707
- type: "function",
2708
- function: { name: toolName, arguments: sanitizeTracePayload(args) }
2709
- }
2710
- ]
2711
- }
2712
- ]
2830
+ sections: buildToolTraceSections({
2831
+ args,
2832
+ executionId: tc.id,
2833
+ output: limitMessage,
2834
+ status: "skipped",
2835
+ summary: limitMessage,
2836
+ toolDetails,
2837
+ toolName
2838
+ })
2713
2839
  });
2714
2840
  toolCount += 1;
2715
2841
  return { status: "error" };
@@ -2796,6 +2922,25 @@ function createToolsNode(initialTools, opts) {
2796
2922
  push({ role: "tool", content: breakerMsg, tool_call_id: toolCallId, name: tc.name });
2797
2923
  markToolFailure(breakerMsg, toolName, toolCallId);
2798
2924
  onEvent?.({ type: "tool_call", phase: "error", name: toolName, id: tc.id, args, error: { message: breakerMsg } });
2925
+ recordTraceEvent(traceSession, {
2926
+ type: "tool_call",
2927
+ label: `Tool Error - ${toolName}`,
2928
+ actor: { scope: "tool", name: toolName, role: "tool" },
2929
+ status: "error",
2930
+ requestBytes: inputBytes,
2931
+ toolDetails,
2932
+ toolExecutionId: toolCallId,
2933
+ error: { message: breakerMsg },
2934
+ sections: buildToolTraceSections({
2935
+ args,
2936
+ executionId: toolCallId,
2937
+ output: { message: breakerMsg },
2938
+ status: "error",
2939
+ summary: breakerMsg,
2940
+ toolDetails,
2941
+ toolName
2942
+ })
2943
+ });
2799
2944
  toolCount += 1;
2800
2945
  return { status: "error" };
2801
2946
  }
@@ -2820,6 +2965,38 @@ function createToolsNode(initialTools, opts) {
2820
2965
  });
2821
2966
  push({ role: "tool", content: responsePolicy2.content, tool_call_id: tc.id || `${tc.name}_${toolCount}`, name: tc.name });
2822
2967
  onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: cachedHit, durationMs: 0 });
2968
+ const sanitizedCachedHit = sanitizeTracePayload(cachedHit);
2969
+ const outputBytes2 = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedCachedHit) : void 0;
2970
+ recordTraceEvent(traceSession, {
2971
+ type: "tool_call",
2972
+ label: `Tool Execution - ${toolName}`,
2973
+ actor: { scope: "tool", name: toolName, role: "tool" },
2974
+ durationMs: 0,
2975
+ requestBytes: inputBytes,
2976
+ responseBytes: outputBytes2,
2977
+ toolDetails,
2978
+ toolExecutionId: executionId2,
2979
+ sections: buildToolTraceSections({
2980
+ args,
2981
+ classification: responsePolicy2.classification,
2982
+ durationMs: 0,
2983
+ executionId: executionId2,
2984
+ fromCache: true,
2985
+ output: sanitizedCachedHit,
2986
+ retentionPolicy: "keep_full",
2987
+ status: "cached",
2988
+ summary: responsePolicy2.content,
2989
+ toolDetails,
2990
+ toolName
2991
+ }),
2992
+ debug: {
2993
+ classification: responsePolicy2.classification,
2994
+ retentionPolicy: "keep_full",
2995
+ originalTokenCount: responsePolicy2.tokenCount,
2996
+ truncated: responsePolicy2.truncated,
2997
+ fromCache: true
2998
+ }
2999
+ });
2823
3000
  toolCount += 1;
2824
3001
  return { status: "success" };
2825
3002
  }
@@ -2940,28 +3117,6 @@ function createToolsNode(initialTools, opts) {
2940
3117
  }
2941
3118
  const sanitizedOutput = sanitizeTracePayload(output);
2942
3119
  const outputBytes = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedOutput) : void 0;
2943
- const messageList = [
2944
- {
2945
- role: "assistant",
2946
- name: toolName,
2947
- content: "",
2948
- tool_calls: [
2949
- {
2950
- id: tc.id || executionId,
2951
- type: "function",
2952
- function: {
2953
- name: toolName,
2954
- arguments: sanitizedArgs
2955
- }
2956
- }
2957
- ]
2958
- },
2959
- {
2960
- role: "tool",
2961
- name: toolName,
2962
- content: responsePolicy.content
2963
- }
2964
- ];
2965
3120
  recordTraceEvent(traceSession, {
2966
3121
  type: "tool_call",
2967
3122
  label: `Tool Execution - ${toolName}`,
@@ -2969,8 +3124,20 @@ function createToolsNode(initialTools, opts) {
2969
3124
  durationMs,
2970
3125
  requestBytes: inputBytes,
2971
3126
  responseBytes: outputBytes,
3127
+ toolDetails,
2972
3128
  toolExecutionId: executionId,
2973
- messageList,
3129
+ sections: buildToolTraceSections({
3130
+ args: sanitizedArgs,
3131
+ classification: responsePolicy.classification,
3132
+ durationMs,
3133
+ executionId,
3134
+ output: sanitizedOutput,
3135
+ retentionPolicy: "keep_full",
3136
+ status: "success",
3137
+ summary: responsePolicy.content,
3138
+ toolDetails,
3139
+ toolName
3140
+ }),
2974
3141
  debug: {
2975
3142
  classification: responsePolicy.classification,
2976
3143
  retentionPolicy: "keep_full",
@@ -2989,6 +3156,7 @@ function createToolsNode(initialTools, opts) {
2989
3156
  markToolFailure(message, toolName, toolCallId);
2990
3157
  onEvent?.({ type: "tool_call", phase: "error", name: toolName, id: tc.id, args, error: { message } });
2991
3158
  onProgress?.({ stage: "tools", message: `Tool ${tc.name} failed`, detail: { error: message } });
3159
+ const errorOutput = { message, stack: error?.stack };
2992
3160
  recordTraceEvent(traceSession, {
2993
3161
  type: "tool_call",
2994
3162
  label: `Tool Error - ${toolName}`,
@@ -2996,27 +3164,20 @@ function createToolsNode(initialTools, opts) {
2996
3164
  status: "error",
2997
3165
  durationMs,
2998
3166
  requestBytes: inputBytes,
3167
+ responseBytes: traceSession?.resolvedConfig.logData ? estimatePayloadBytes(errorOutput) : void 0,
3168
+ toolDetails,
2999
3169
  toolExecutionId: executionId,
3000
3170
  error: { message, stack: error?.stack },
3001
- messageList: [
3002
- {
3003
- role: "assistant",
3004
- name: toolName,
3005
- content: "",
3006
- tool_calls: [
3007
- {
3008
- id: tc.id || executionId,
3009
- type: "function",
3010
- function: { name: toolName, arguments: sanitizedArgs }
3011
- }
3012
- ]
3013
- },
3014
- {
3015
- role: "tool",
3016
- name: toolName,
3017
- content: `Error executing tool: ${message}`
3018
- }
3019
- ]
3171
+ sections: buildToolTraceSections({
3172
+ args: sanitizedArgs,
3173
+ durationMs,
3174
+ executionId,
3175
+ output: errorOutput,
3176
+ status: "error",
3177
+ summary: `Error executing tool: ${message}`,
3178
+ toolDetails,
3179
+ toolName
3180
+ })
3020
3181
  });
3021
3182
  toolCount += 1;
3022
3183
  return { status: "error", approval: approvalEntry };
@@ -3093,29 +3254,26 @@ function createToolsNode(initialTools, opts) {
3093
3254
  }
3094
3255
  for (const tc of skipped) {
3095
3256
  onEvent?.({ type: "tool_call", phase: "skipped", name: tc.name, id: tc.id, args: tc.args });
3096
- const sanitizedArgs = sanitizeTracePayload(tc.args);
3257
+ const toolDetails = buildToolDetails(toolByName.get(tc.name), tc.name);
3258
+ const skipMessage = `Skipped tool due to tool-call limit: ${tc.name}`;
3097
3259
  recordTraceEvent(traceSession, {
3098
3260
  type: "tool_call",
3099
3261
  label: `Tool Skipped - ${tc.name}`,
3100
3262
  actor: { scope: "tool", name: tc.name, role: "tool" },
3101
3263
  status: "skipped",
3264
+ toolDetails,
3102
3265
  toolExecutionId: tc.id,
3103
- messageList: [
3104
- {
3105
- role: "assistant",
3106
- name: tc.name,
3107
- content: `Skipped tool due to tool-call limit: ${tc.name}`,
3108
- tool_calls: [
3109
- {
3110
- id: tc.id,
3111
- type: "function",
3112
- function: { name: tc.name, arguments: sanitizedArgs }
3113
- }
3114
- ]
3115
- }
3116
- ]
3266
+ sections: buildToolTraceSections({
3267
+ args: tc.args,
3268
+ executionId: tc.id,
3269
+ output: skipMessage,
3270
+ status: "skipped",
3271
+ summary: skipMessage,
3272
+ toolDetails,
3273
+ toolName: tc.name
3274
+ })
3117
3275
  });
3118
- appended.push({ role: "tool", content: `Skipped tool due to tool-call limit: ${tc.name}`, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
3276
+ appended.push({ role: "tool", content: skipMessage, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
3119
3277
  toolCount += 1;
3120
3278
  }
3121
3279
  if (!awaitingApproval && state.ctx?.__awaitingApproval) {
@@ -3187,15 +3345,40 @@ function countToolCallsInLastTurn(state) {
3187
3345
  function stripReflectionAskMessages(messages) {
3188
3346
  return messages.filter((m) => !(m?.role === "user" && m?.name === REFLECTION_ASK_NAME));
3189
3347
  }
3348
+ function lastTwoToolTurns(state) {
3349
+ const groups = [];
3350
+ let cur = [];
3351
+ let sawTool = false;
3352
+ for (let i = state.messages.length - 1; i >= 0; i--) {
3353
+ const m = state.messages[i];
3354
+ if (m?.role === "tool") {
3355
+ if (m.name) cur.push(m.name);
3356
+ sawTool = true;
3357
+ } else if (m?.role === "assistant") {
3358
+ if (sawTool) {
3359
+ groups.push(cur);
3360
+ cur = [];
3361
+ sawTool = false;
3362
+ if (groups.length >= 2) break;
3363
+ }
3364
+ }
3365
+ }
3366
+ if (sawTool && cur.length) groups.push(cur);
3367
+ return { current: groups[0] ?? [], previous: groups[1] ?? [] };
3368
+ }
3190
3369
  function shouldRunReflection(cadence, state, ranToolsThisTurn) {
3191
3370
  if (cadence === "off") return false;
3192
3371
  if (cadence === "every_turn") return true;
3193
3372
  if (cadence === "after_tool") return ranToolsThisTurn;
3373
+ if (cadence === "initial_then_after_tool") return ranToolsThisTurn;
3194
3374
  if (cadence === "on_branch") {
3195
- const reflections = state.reflections || [];
3196
- const lastReflectionTurn = reflections[reflections.length - 1]?.turn ?? -1;
3197
- const currentTurnId = state.toolCallCount ?? 0;
3198
- return currentTurnId - lastReflectionTurn >= 2;
3375
+ const { current, previous } = lastTwoToolTurns(state);
3376
+ if (previous.length === 0) return true;
3377
+ const a = new Set(current);
3378
+ const b = new Set(previous);
3379
+ for (const n of a) if (!b.has(n)) return true;
3380
+ for (const n of b) if (!a.has(n)) return true;
3381
+ return false;
3199
3382
  }
3200
3383
  return false;
3201
3384
  }
@@ -3212,7 +3395,10 @@ function createReflectionNode(opts, resolved) {
3212
3395
  const onEvent = state.ctx?.__onEvent;
3213
3396
  const traceSession = state.ctx?.__traceSession;
3214
3397
  const maxChars = resolved.maxChars;
3215
- const promptBody = (resolved.promptTemplate || DEFAULT_REFLECT_PROMPT).replace(/\$\{maxChars\}/g, String(maxChars));
3398
+ const turnNow = state.toolCallCount ?? 0;
3399
+ const hookCtx = { state, turn: turnNow, trigger, ranToolsThisTurn: true };
3400
+ const defaultPrompt = (resolved.promptTemplate || DEFAULT_REFLECT_PROMPT).replace(/\$\{maxChars\}/g, String(maxChars));
3401
+ const promptBody = resolved.buildPrompt ? String(resolved.buildPrompt({ ...hookCtx, defaultPrompt, maxChars }) ?? defaultPrompt) : defaultPrompt;
3216
3402
  const baseMessages = stripReflectionAskMessages([...state.messages]);
3217
3403
  const askMessage = {
3218
3404
  role: "user",
@@ -3246,6 +3432,8 @@ function createReflectionNode(opts, resolved) {
3246
3432
  const rawText = extractText(response);
3247
3433
  const text = trimToChars(String(rawText ?? "").trim(), maxChars);
3248
3434
  if (!text) return {};
3435
+ const prevText = (state.reflections?.[state.reflections.length - 1]?.text || "").trim();
3436
+ if (prevText && isNearDuplicate(prevText, text)) return {};
3249
3437
  const rawUsage = response?.usage_metadata || response?.response_metadata?.usage || response?.usage || response?.additional_kwargs?.usage;
3250
3438
  const usage = normalizeUsage(rawUsage);
3251
3439
  const { ids, names } = countToolCallsInLastTurn(state);
@@ -3294,6 +3482,12 @@ function createReflectionNode(opts, resolved) {
3294
3482
  } catch (e) {
3295
3483
  }
3296
3484
  }
3485
+ if (resolved.onReflection) {
3486
+ try {
3487
+ resolved.onReflection(record, hookCtx);
3488
+ } catch {
3489
+ }
3490
+ }
3297
3491
  const nextMessages = stripReflectionAskMessages([...state.messages]);
3298
3492
  const reflections = [...state.reflections || [], record];
3299
3493
  const kept = reflections.slice(-Math.max(1, resolved.keepLast));
@@ -3310,7 +3504,20 @@ ${r.text}
3310
3504
  metadata: { reflectionId: r.id, reflectionTurn: r.turn, reflectionTrigger: r.trigger }
3311
3505
  });
3312
3506
  }
3313
- return { messages: prunedMessages, reflections };
3507
+ const patch = { messages: prunedMessages, reflections };
3508
+ if (resolved.feedTo === "memory") {
3509
+ const fact = {
3510
+ key: `reflection_turn_${turn}`,
3511
+ value: text,
3512
+ sourceTurn: turn,
3513
+ confidence: 0.3,
3514
+ tags: ["reflection"]
3515
+ };
3516
+ patch.memoryFacts = [...state.memoryFacts || [], fact];
3517
+ } else if (resolved.feedTo === "plan" && state.plan) {
3518
+ patch.plan = { ...state.plan, lastReflection: text };
3519
+ }
3520
+ return patch;
3314
3521
  };
3315
3522
  }
3316
3523
  function extractText(chunk) {
@@ -3339,24 +3546,75 @@ function safeRandomId() {
3339
3546
  return `r_${Math.random().toString(36).slice(2, 10)}_${Date.now().toString(36)}`;
3340
3547
  }
3341
3548
  }
3549
+ function isNearDuplicate(a, b) {
3550
+ const norm = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
3551
+ const na = norm(a);
3552
+ const nb = norm(b);
3553
+ if (na === nb) return true;
3554
+ const tokensA = new Set(na.split(" ").filter(Boolean));
3555
+ const tokensB = new Set(nb.split(" ").filter(Boolean));
3556
+ if (tokensA.size === 0 || tokensB.size === 0) return false;
3557
+ let inter = 0;
3558
+ for (const t of tokensA) if (tokensB.has(t)) inter++;
3559
+ const union = tokensA.size + tokensB.size - inter;
3560
+ return union > 0 && inter / union >= 0.9;
3561
+ }
3342
3562
 
3343
3563
  // src/smart/reasoning.ts
3344
3564
  var LEVEL_DEFAULTS = {
3565
+ minimal: {
3566
+ native: { effort: "minimal" },
3567
+ reflection: { maxTokens: 150, maxChars: 400, cadence: "off" }
3568
+ },
3345
3569
  low: {
3346
3570
  native: { effort: "low" },
3347
3571
  reflection: { maxTokens: 200, maxChars: 600, cadence: "on_branch" }
3348
3572
  },
3349
3573
  medium: {
3350
3574
  native: { effort: "medium" },
3351
- reflection: { maxTokens: 350, maxChars: 1200, cadence: "after_tool" }
3575
+ reflection: { maxTokens: 350, maxChars: 1200, cadence: "initial_then_after_tool" }
3352
3576
  },
3353
3577
  high: {
3354
3578
  native: { effort: "high" },
3355
- reflection: { maxTokens: 600, maxChars: 2e3, cadence: "after_tool" }
3579
+ reflection: { maxTokens: 600, maxChars: 2e3, cadence: "initial_then_after_tool" }
3356
3580
  }
3357
3581
  };
3582
+ var VALID_LEVELS = ["minimal", "low", "medium", "high"];
3583
+ var VALID_CADENCES = ["off", "every_turn", "after_tool", "on_branch", "initial_then_after_tool"];
3584
+ var VALID_EFFORTS = ["minimal", "low", "medium", "high"];
3585
+ function validateReasoningConfig(input) {
3586
+ if (!input) return;
3587
+ if (input.level !== void 0 && !VALID_LEVELS.includes(input.level)) {
3588
+ throw new Error(`reasoning.level must be one of ${VALID_LEVELS.join(", ")} (got "${input.level}")`);
3589
+ }
3590
+ if (input.native) {
3591
+ const n = input.native;
3592
+ if (n.effort !== void 0 && !VALID_EFFORTS.includes(n.effort)) {
3593
+ throw new Error(`reasoning.native.effort must be one of ${VALID_EFFORTS.join(", ")} (got "${n.effort}")`);
3594
+ }
3595
+ if (n.budgetTokens !== void 0 && (!Number.isFinite(n.budgetTokens) || n.budgetTokens < 0)) {
3596
+ throw new Error(`reasoning.native.budgetTokens must be a non-negative number (got ${n.budgetTokens})`);
3597
+ }
3598
+ }
3599
+ if (input.reflection) {
3600
+ const r = input.reflection;
3601
+ if (r.cadence !== void 0 && !VALID_CADENCES.includes(r.cadence)) {
3602
+ throw new Error(`reasoning.reflection.cadence must be one of ${VALID_CADENCES.join(", ")} (got "${r.cadence}")`);
3603
+ }
3604
+ if (r.maxPerRun !== void 0 && (!Number.isFinite(r.maxPerRun) || r.maxPerRun < 0)) {
3605
+ throw new Error(`reasoning.reflection.maxPerRun must be a non-negative number (got ${r.maxPerRun})`);
3606
+ }
3607
+ if (r.everyNTurns !== void 0 && (!Number.isFinite(r.everyNTurns) || r.everyNTurns < 1)) {
3608
+ throw new Error(`reasoning.reflection.everyNTurns must be >= 1 (got ${r.everyNTurns})`);
3609
+ }
3610
+ if (r.feedTo !== void 0 && !["memory", "plan", "none"].includes(r.feedTo)) {
3611
+ throw new Error(`reasoning.reflection.feedTo must be "memory", "plan", or "none" (got "${r.feedTo}")`);
3612
+ }
3613
+ }
3614
+ }
3358
3615
  function resolveReasoning(input) {
3359
3616
  if (!input || input.enabled === false) return void 0;
3617
+ validateReasoningConfig(input);
3360
3618
  const enabled = input.enabled ?? (input.native !== void 0 || input.reflection !== void 0 || input.level !== void 0);
3361
3619
  if (!enabled) return void 0;
3362
3620
  const level = input.level ?? "medium";
@@ -3381,7 +3639,8 @@ function resolveReflection(input, preset) {
3381
3639
  keepLast: 3,
3382
3640
  summarize: false,
3383
3641
  emitEvents: true,
3384
- everyNTurns: 1
3642
+ everyNTurns: 1,
3643
+ feedTo: "none"
3385
3644
  };
3386
3645
  }
3387
3646
  const cfg = input ?? {};
@@ -3398,7 +3657,11 @@ function resolveReflection(input, preset) {
3398
3657
  promptTemplate: cfg.promptTemplate,
3399
3658
  emitEvents: cfg.emitEvents ?? true,
3400
3659
  maxPerRun: typeof cfg.maxPerRun === "number" && cfg.maxPerRun >= 0 ? cfg.maxPerRun : void 0,
3401
- everyNTurns: Math.max(1, Math.trunc(cfg.everyNTurns ?? 1))
3660
+ everyNTurns: Math.max(1, Math.trunc(cfg.everyNTurns ?? 1)),
3661
+ feedTo: cfg.feedTo ?? "none",
3662
+ shouldReflect: cfg.shouldReflect,
3663
+ buildPrompt: cfg.buildPrompt,
3664
+ onReflection: cfg.onReflection
3402
3665
  };
3403
3666
  }
3404
3667
  function ensureArray(value) {
@@ -4124,12 +4387,14 @@ function createAgent(opts) {
4124
4387
  if (summarizationThreshold === void 0) {
4125
4388
  state = clearNeedsSummarization(state);
4126
4389
  }
4127
- if (resolvedReasoning?.native) {
4390
+ if (resolvedReasoning) {
4128
4391
  const ctx = { ...state.ctx || {} };
4129
- if (!ctx.__reasoning) {
4392
+ if (resolvedReasoning.native) {
4130
4393
  ctx.__reasoning = resolvedReasoning.native;
4131
- state = { ...state, ctx };
4394
+ } else {
4395
+ delete ctx.__reasoning;
4132
4396
  }
4397
+ state = { ...state, ctx: Object.keys(ctx).length > 0 ? ctx : void 0 };
4133
4398
  }
4134
4399
  const mergedLimits = {
4135
4400
  ...opts.limits || {},
@@ -4177,6 +4442,7 @@ function createAgent(opts) {
4177
4442
  return { breached: false };
4178
4443
  };
4179
4444
  let iterations = 0;
4445
+ let reflectionsThisRun = 0;
4180
4446
  const onStateChange = config?.onStateChange;
4181
4447
  const checkpointReason = config?.checkpointReason;
4182
4448
  let pausedStage = null;
@@ -4222,6 +4488,16 @@ function createAgent(opts) {
4222
4488
  pausedStage = stage;
4223
4489
  return true;
4224
4490
  };
4491
+ 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")) {
4492
+ try {
4493
+ const patch = await reflectNode(state, "initial_then_after_tool");
4494
+ if (patch && Object.keys(patch).length > 0) {
4495
+ state = { ...state, ...patch };
4496
+ reflectionsThisRun++;
4497
+ }
4498
+ } catch {
4499
+ }
4500
+ }
4225
4501
  while (iterations < iterationLimit) {
4226
4502
  iterations++;
4227
4503
  const budget = checkBudgetBreached();
@@ -4366,7 +4642,7 @@ function createAgent(opts) {
4366
4642
  if (toolCalls.length === 0) {
4367
4643
  if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize) {
4368
4644
  if (soManager.strategy.kind === "native") {
4369
- const assistantText = extractMessageText2(lastMsg);
4645
+ const assistantText = extractMessageText(lastMsg);
4370
4646
  if (assistantText) {
4371
4647
  const parsed = soManager.parseFromContent(assistantText);
4372
4648
  if (parsed.success) {
@@ -4398,16 +4674,18 @@ function createAgent(opts) {
4398
4674
  if (reflectNode && resolvedReasoning?.reflection.enabled) {
4399
4675
  const cadence = resolvedReasoning.reflection.cadence;
4400
4676
  const refl = resolvedReasoning.reflection;
4401
- const reflectionsSoFar = state.reflections?.length ?? 0;
4402
4677
  const lastTurn = state.reflections?.at(-1)?.turn ?? -Infinity;
4403
4678
  const currentTurn = state.toolCallCount || 0;
4404
- const budgetExceeded = typeof refl.maxPerRun === "number" && reflectionsSoFar >= refl.maxPerRun;
4405
- const cadenceGap = currentTurn - (Number.isFinite(lastTurn) ? lastTurn : -refl.everyNTurns) < refl.everyNTurns;
4406
- if (!budgetExceeded && !cadenceGap && shouldRunReflection(cadence, state, true)) {
4679
+ const budgetExceeded = typeof refl.maxPerRun === "number" && reflectionsThisRun >= refl.maxPerRun;
4680
+ const sinceLast = currentTurn - (Number.isFinite(lastTurn) ? lastTurn : -refl.everyNTurns);
4681
+ const cadenceGap = sinceLast < refl.everyNTurns;
4682
+ const cadenceWantsIt = refl.shouldReflect ? !!refl.shouldReflect({ state, turn: currentTurn, trigger: cadence, ranToolsThisTurn: true }) : shouldRunReflection(cadence, state, true);
4683
+ if (!budgetExceeded && !cadenceGap && cadenceWantsIt) {
4407
4684
  try {
4408
4685
  const patch = await reflectNode(state, cadence);
4409
4686
  if (patch && Object.keys(patch).length > 0) {
4410
4687
  state = { ...state, ...patch };
4688
+ reflectionsThisRun++;
4411
4689
  }
4412
4690
  } catch {
4413
4691
  }
@@ -4417,7 +4695,7 @@ function createAgent(opts) {
4417
4695
  if (soManager && !state.ctx?.__finalizedDueToStructuredOutput) {
4418
4696
  const lastForParse = state.messages[state.messages.length - 1];
4419
4697
  if (lastForParse?.role === "assistant") {
4420
- const assistantText = extractMessageText2(lastForParse);
4698
+ const assistantText = extractMessageText(lastForParse);
4421
4699
  if (assistantText) {
4422
4700
  const parsed = soManager.parseFromContent(assistantText);
4423
4701
  if (parsed.success) {
@@ -4570,7 +4848,7 @@ function createAgent(opts) {
4570
4848
  const isTransientSummarizationExit = !!res.ctx?.__needsSummarization;
4571
4849
  const finalAssistantMsg = isTransientSummarizationExit ? void 0 : getLastAssistantMessage(res.messages);
4572
4850
  const finalIsSyntheticSummary = !isTransientSummarizationExit && finalAssistantMsg && isSyntheticSummaryMessage(finalAssistantMsg);
4573
- const content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText2(finalAssistantMsg);
4851
+ const content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText(finalAssistantMsg);
4574
4852
  let parsed = void 0;
4575
4853
  let outputError = void 0;
4576
4854
  if (soManager) {
@@ -4878,7 +5156,7 @@ function renderMemoryBlock(facts) {
4878
5156
  function clampToBudget(messages, maxContextTokens) {
4879
5157
  let working = [...messages];
4880
5158
  while (working.length > 2) {
4881
- const tokenCount = countApproxTokens(working.map(extractMessageText2).join("\n"));
5159
+ const tokenCount = countApproxTokens(working.map(extractMessageText).join("\n"));
4882
5160
  if (tokenCount <= maxContextTokens) return working;
4883
5161
  const firstNonSystem = working.findIndex((message, index) => !(index === 0 && message.role === "system"));
4884
5162
  if (firstNonSystem < 0) break;
@@ -5981,7 +6259,7 @@ function createSmartAgent(opts) {
5981
6259
  ].join("\n");
5982
6260
  function latestUserPrompt(messages) {
5983
6261
  const latest = [...messages].reverse().find((message) => message.role === "user");
5984
- return latest ? extractMessageText2(latest) : "";
6262
+ return latest ? extractMessageText(latest) : "";
5985
6263
  }
5986
6264
  async function syncMemory(state) {
5987
6265
  const query = latestUserPrompt(state.messages || []);
@@ -6670,6 +6948,20 @@ function parseSSEBlock(block) {
6670
6948
  }
6671
6949
 
6672
6950
  // src/providers/utils/reasoning.ts
6951
+ var ANTHROPIC_EFFORT_BUDGET = {
6952
+ minimal: 1024,
6953
+ low: 2048,
6954
+ medium: 8192,
6955
+ high: 16384
6956
+ };
6957
+ var GEMINI_EFFORT_BUDGET = {
6958
+ minimal: 512,
6959
+ low: 1024,
6960
+ medium: 4096,
6961
+ high: 12e3
6962
+ };
6963
+ var THINKING_OUTPUT_RESERVE = 1024;
6964
+ var THINKING_MIN_MAX_TOKENS = 4096;
6673
6965
  function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
6674
6966
  if (!reasoning) return;
6675
6967
  const effort = normalizeEffort(reasoning.effort);
@@ -6686,21 +6978,56 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
6686
6978
  }
6687
6979
  function applyAnthropicReasoning(body, reasoning) {
6688
6980
  if (!reasoning) return;
6689
- const budget = resolveBudget(reasoning, { low: 2048, medium: 8192, high: 16384, minimal: 1024 });
6981
+ let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
6690
6982
  if (!budget) return;
6983
+ const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
6984
+ const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
6985
+ if (currentMax < requiredMax) {
6986
+ body.max_tokens = requiredMax;
6987
+ }
6988
+ budget = clampBudget(budget, body.max_tokens);
6691
6989
  const thinking = { type: "enabled", budget_tokens: budget };
6692
6990
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
6693
6991
  body.thinking = thinking;
6992
+ stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
6993
+ }
6994
+ function applyBedrockReasoning(body, reasoning) {
6995
+ if (!reasoning) return;
6996
+ let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
6997
+ if (!budget) return;
6998
+ const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
6999
+ const currentMax = typeof inference.maxTokens === "number" ? inference.maxTokens : 0;
7000
+ const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
7001
+ if (currentMax < requiredMax) {
7002
+ inference.maxTokens = requiredMax;
7003
+ }
7004
+ budget = clampBudget(budget, inference.maxTokens);
7005
+ const extra = body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
7006
+ const thinking = { type: "enabled", budget_tokens: budget };
7007
+ if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
7008
+ extra.thinking = thinking;
7009
+ stripSamplingParams(inference, ["temperature", "topP"]);
6694
7010
  }
6695
7011
  function applyGeminiReasoning(generationConfig, reasoning) {
6696
7012
  if (!reasoning) return;
6697
- const budget = resolveBudget(reasoning, { low: 1024, medium: 4096, high: 12e3, minimal: 512 });
7013
+ const budget = resolveBudget(reasoning, GEMINI_EFFORT_BUDGET);
6698
7014
  if (budget == null) return;
6699
7015
  const thinkingConfig = { thinkingBudget: budget };
6700
7016
  if (reasoning.includeThoughts) thinkingConfig.includeThoughts = true;
6701
7017
  if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
6702
7018
  generationConfig.thinkingConfig = thinkingConfig;
6703
7019
  }
7020
+ function stripSamplingParams(target, keys) {
7021
+ for (const k of keys) {
7022
+ if (k in target) delete target[k];
7023
+ }
7024
+ }
7025
+ function clampBudget(budget, maxTokens) {
7026
+ if (typeof maxTokens !== "number" || maxTokens <= 0) return budget;
7027
+ const ceiling = maxTokens - THINKING_OUTPUT_RESERVE;
7028
+ if (ceiling < 1024) return Math.max(1024, Math.floor(maxTokens / 2));
7029
+ return Math.min(budget, ceiling);
7030
+ }
6704
7031
  function normalizeEffort(effort) {
6705
7032
  if (!effort) return void 0;
6706
7033
  const allowed = ["minimal", "low", "medium", "high"];
@@ -6729,13 +7056,38 @@ var OpenAIProvider = class extends BaseProvider {
6729
7056
  };
6730
7057
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
6731
7058
  }
7059
+ /** True when the request targets a reasoning model (o-series / gpt-5) so we
7060
+ * should route through the Responses API, which exposes `reasoning.effort`
7061
+ * and reasoning summaries. Chat Completions silently drops these. */
7062
+ useResponsesApi(request) {
7063
+ if (!request.reasoning) return false;
7064
+ return isReasoningModel(request.model || this.defaultModel);
7065
+ }
6732
7066
  async complete(request) {
7067
+ if (this.useResponsesApi(request)) {
7068
+ return this.completeResponses(request);
7069
+ }
6733
7070
  const body = this.buildRequestBody(request, false);
6734
7071
  const res = await this.doFetch(body);
6735
7072
  const json = await res.json();
6736
7073
  return this.parseResponse(json);
6737
7074
  }
6738
7075
  async *completeStream(request) {
7076
+ if (this.useResponsesApi(request)) {
7077
+ const response = await this.completeResponses(request);
7078
+ yield {
7079
+ id: response.id,
7080
+ model: response.model,
7081
+ delta: {
7082
+ content: response.content ?? void 0,
7083
+ toolCalls: response.toolCalls.length > 0 ? response.toolCalls : void 0,
7084
+ reasoning: response.reasoning
7085
+ },
7086
+ usage: response.usage,
7087
+ finishReason: response.finishReason
7088
+ };
7089
+ return;
7090
+ }
6739
7091
  const body = this.buildRequestBody(request, true);
6740
7092
  const res = await this.doFetch(body);
6741
7093
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
@@ -6834,6 +7186,156 @@ var OpenAIProvider = class extends BaseProvider {
6834
7186
  applyOpenAIReasoning(body, request.reasoning, "legacy_effort");
6835
7187
  return body;
6836
7188
  }
7189
+ // ─── Responses API (reasoning models) ──────────────────────────────────────
7190
+ async completeResponses(request) {
7191
+ const body = this.buildResponsesBody(request);
7192
+ const res = await this.responsesFetch(body);
7193
+ const json = await res.json();
7194
+ return this.parseResponsesResponse(json, request.model || this.defaultModel);
7195
+ }
7196
+ buildResponsesBody(request) {
7197
+ const body = {
7198
+ model: request.model || this.defaultModel,
7199
+ input: request.messages.map((m) => this.toResponsesInput(m))
7200
+ };
7201
+ if (request.maxTokens != null) body.max_output_tokens = request.maxTokens;
7202
+ if (request.topP != null) body.top_p = request.topP;
7203
+ if (request.tools?.length) {
7204
+ body.tools = request.tools.map((t) => ({
7205
+ type: "function",
7206
+ name: t.name,
7207
+ description: t.description,
7208
+ parameters: t.parameters,
7209
+ ...t.strict ? { strict: true } : {}
7210
+ }));
7211
+ }
7212
+ if (request.toolChoice != null && request.tools?.length) {
7213
+ if (typeof request.toolChoice === "string") {
7214
+ body.tool_choice = request.toolChoice;
7215
+ } else {
7216
+ body.tool_choice = { type: "function", name: request.toolChoice.name };
7217
+ }
7218
+ }
7219
+ if (request.responseFormat) {
7220
+ if (request.responseFormat.type === "json_schema") {
7221
+ body.text = {
7222
+ format: {
7223
+ type: "json_schema",
7224
+ name: request.responseFormat.name ?? "response",
7225
+ schema: request.responseFormat.schema,
7226
+ strict: true
7227
+ }
7228
+ };
7229
+ } else if (request.responseFormat.type === "json_object") {
7230
+ body.text = { format: { type: "json_object" } };
7231
+ }
7232
+ }
7233
+ if (request.extra) Object.assign(body, request.extra);
7234
+ applyOpenAIReasoning(body, request.reasoning, "responses");
7235
+ return body;
7236
+ }
7237
+ /** Maps a unified message to a Responses API `input` item. */
7238
+ toResponsesInput(m) {
7239
+ if (m.role === "tool" && m.toolCallId) {
7240
+ const output = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
7241
+ return { type: "function_call_output", call_id: m.toolCallId, output };
7242
+ }
7243
+ if (m.role === "assistant" && m.toolCalls?.length) {
7244
+ return {
7245
+ __assistantWithCalls: true,
7246
+ text: typeof m.content === "string" ? m.content : "",
7247
+ calls: m.toolCalls.map((tc) => ({
7248
+ type: "function_call",
7249
+ call_id: tc.id,
7250
+ name: tc.name,
7251
+ arguments: tc.arguments
7252
+ }))
7253
+ };
7254
+ }
7255
+ const role = m.role === "system" ? "system" : m.role === "assistant" ? "assistant" : "user";
7256
+ const textType = role === "assistant" ? "output_text" : "input_text";
7257
+ if (typeof m.content === "string") {
7258
+ return { role, content: [{ type: textType, text: m.content }] };
7259
+ }
7260
+ const content = m.content.map((part) => {
7261
+ if (part.type === "text") return { type: textType, text: part.text };
7262
+ if (part.type === "image") {
7263
+ const src = part.source;
7264
+ const url = src.type === "url" ? src.url : `data:${src.mediaType};base64,${src.data}`;
7265
+ return { type: "input_image", image_url: url };
7266
+ }
7267
+ return { type: textType, text: "" };
7268
+ });
7269
+ return { role, content };
7270
+ }
7271
+ async responsesFetch(body) {
7272
+ body.input = expandResponsesInput(body.input);
7273
+ const url = `${this.baseURL}/responses`;
7274
+ const headers = {
7275
+ "Content-Type": "application/json",
7276
+ Authorization: `Bearer ${this.apiKey}`,
7277
+ ...this.defaultHeaders
7278
+ };
7279
+ const payload = JSON.stringify(body);
7280
+ const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
7281
+ if (!res.ok) {
7282
+ const text = await res.text().catch(() => "");
7283
+ throw new ProviderError(
7284
+ `OpenAI Responses API error ${res.status}: ${text}`,
7285
+ this.providerName,
7286
+ res.status,
7287
+ text
7288
+ );
7289
+ }
7290
+ return res;
7291
+ }
7292
+ parseResponsesResponse(json, modelId) {
7293
+ const textParts = [];
7294
+ const toolCalls = [];
7295
+ const summaryParts = [];
7296
+ for (const item of json.output ?? []) {
7297
+ if (item.type === "message") {
7298
+ for (const c of item.content ?? []) {
7299
+ if (c.type === "output_text" && typeof c.text === "string") textParts.push(c.text);
7300
+ }
7301
+ } else if (item.type === "function_call") {
7302
+ toolCalls.push({
7303
+ id: item.call_id ?? item.id ?? "",
7304
+ name: item.name ?? "",
7305
+ arguments: typeof item.arguments === "string" ? item.arguments : JSON.stringify(item.arguments ?? {})
7306
+ });
7307
+ } else if (item.type === "reasoning") {
7308
+ for (const s of item.summary ?? []) {
7309
+ if (typeof s.text === "string") summaryParts.push(s.text);
7310
+ }
7311
+ }
7312
+ }
7313
+ if (textParts.length === 0 && typeof json.output_text === "string") {
7314
+ textParts.push(json.output_text);
7315
+ }
7316
+ const usage = json.usage ?? {};
7317
+ const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? 0;
7318
+ const tokenUsage = {
7319
+ inputTokens: usage.input_tokens ?? 0,
7320
+ outputTokens: usage.output_tokens ?? 0,
7321
+ totalTokens: usage.total_tokens ?? (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),
7322
+ cachedInputTokens: usage.input_tokens_details?.cached_tokens ?? 0,
7323
+ cachedWriteTokens: 0,
7324
+ cachedOutputTokens: 0,
7325
+ reasoningTokens
7326
+ };
7327
+ const finishReason = toolCalls.length > 0 ? "tool_calls" : json.status === "incomplete" ? "length" : "stop";
7328
+ return {
7329
+ id: json.id ?? "",
7330
+ model: json.model ?? modelId,
7331
+ content: textParts.join("") || null,
7332
+ toolCalls,
7333
+ usage: tokenUsage,
7334
+ finishReason,
7335
+ reasoning: summaryParts.length > 0 ? { summary: summaryParts.join("\n").trim() || void 0 } : void 0,
7336
+ raw: json
7337
+ };
7338
+ }
6837
7339
  toOpenAIMessage(m) {
6838
7340
  const msg = { role: m.role };
6839
7341
  if (typeof m.content === "string") {
@@ -6926,6 +7428,25 @@ var OpenAIProvider = class extends BaseProvider {
6926
7428
  };
6927
7429
  }
6928
7430
  };
7431
+ function isReasoningModel(model) {
7432
+ if (!model) return false;
7433
+ const m = model.toLowerCase();
7434
+ return /(^|[/_-])o[0-9]/.test(m) || m.startsWith("o1") || m.startsWith("o3") || m.startsWith("o4") || m.includes("gpt-5") || m.includes("gpt5");
7435
+ }
7436
+ function expandResponsesInput(input) {
7437
+ const out = [];
7438
+ for (const item of input) {
7439
+ if (item && item.__assistantWithCalls) {
7440
+ if (item.text) {
7441
+ out.push({ role: "assistant", content: [{ type: "output_text", text: item.text }] });
7442
+ }
7443
+ for (const call of item.calls) out.push(call);
7444
+ } else {
7445
+ out.push(item);
7446
+ }
7447
+ }
7448
+ return out;
7449
+ }
6929
7450
  function mapFinishReason(reason) {
6930
7451
  switch (reason) {
6931
7452
  case "stop":
@@ -6971,6 +7492,7 @@ var AnthropicProvider = class extends BaseProvider {
6971
7492
  let cacheReadInputTokens = 0;
6972
7493
  let cacheCreationInputTokens = 0;
6973
7494
  const currentToolCalls = /* @__PURE__ */ new Map();
7495
+ const reasoningBlocks = /* @__PURE__ */ new Map();
6974
7496
  for await (const event of parseSSEStream(res.body)) {
6975
7497
  let data;
6976
7498
  try {
@@ -7000,6 +7522,10 @@ var AnthropicProvider = class extends BaseProvider {
7000
7522
  name: block.name ?? "",
7001
7523
  arguments: ""
7002
7524
  });
7525
+ } else if (block?.type === "thinking") {
7526
+ reasoningBlocks.set(idx, { type: "thinking", text: block.thinking ?? "", signature: block.signature });
7527
+ } else if (block?.type === "redacted_thinking") {
7528
+ reasoningBlocks.set(idx, { type: "redacted_thinking", data: block.data });
7003
7529
  }
7004
7530
  break;
7005
7531
  }
@@ -7012,6 +7538,19 @@ var AnthropicProvider = class extends BaseProvider {
7012
7538
  model,
7013
7539
  delta: { content: delta.text }
7014
7540
  };
7541
+ } else if (delta?.type === "thinking_delta" && delta.thinking) {
7542
+ const blk = reasoningBlocks.get(idx) ?? { type: "thinking", text: "" };
7543
+ blk.text = (blk.text ?? "") + delta.thinking;
7544
+ reasoningBlocks.set(idx, blk);
7545
+ yield {
7546
+ id,
7547
+ model,
7548
+ delta: { reasoning: { summary: delta.thinking } }
7549
+ };
7550
+ } else if (delta?.type === "signature_delta" && delta.signature) {
7551
+ const blk = reasoningBlocks.get(idx) ?? { type: "thinking", text: "" };
7552
+ blk.signature = (blk.signature ?? "") + delta.signature;
7553
+ reasoningBlocks.set(idx, blk);
7015
7554
  } else if (delta?.type === "input_json_delta" && delta.partial_json) {
7016
7555
  const tc = currentToolCalls.get(idx);
7017
7556
  if (tc) {
@@ -7044,10 +7583,13 @@ var AnthropicProvider = class extends BaseProvider {
7044
7583
  cachedOutputTokens: 0,
7045
7584
  reasoningTokens: 0
7046
7585
  };
7586
+ const blocks = [...reasoningBlocks.values()].filter(
7587
+ (b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
7588
+ );
7047
7589
  yield {
7048
7590
  id,
7049
7591
  model,
7050
- delta: {},
7592
+ delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
7051
7593
  finishReason,
7052
7594
  usage
7053
7595
  };
@@ -7139,6 +7681,7 @@ var AnthropicProvider = class extends BaseProvider {
7139
7681
  }
7140
7682
  if (m.role === "assistant" && m.toolCalls?.length) {
7141
7683
  const content = [];
7684
+ appendReasoningBlocks(content, m.reasoning?.blocks);
7142
7685
  if (typeof m.content === "string" && m.content) {
7143
7686
  content.push({ type: "text", text: m.content });
7144
7687
  }
@@ -7152,6 +7695,13 @@ var AnthropicProvider = class extends BaseProvider {
7152
7695
  }
7153
7696
  return { role: "assistant", content };
7154
7697
  }
7698
+ if (m.role === "assistant" && m.reasoning?.blocks?.length) {
7699
+ const content = [];
7700
+ appendReasoningBlocks(content, m.reasoning.blocks);
7701
+ const text = typeof m.content === "string" ? m.content : "";
7702
+ if (text) content.push({ type: "text", text });
7703
+ return { role: "assistant", content };
7704
+ }
7155
7705
  const msg = { role: m.role };
7156
7706
  if (typeof m.content === "string") {
7157
7707
  msg.content = m.content;
@@ -7207,9 +7757,20 @@ var AnthropicProvider = class extends BaseProvider {
7207
7757
  parseResponse(json) {
7208
7758
  const textParts = [];
7209
7759
  const toolCalls = [];
7760
+ const reasoningBlocks = [];
7761
+ const summaryParts = [];
7210
7762
  for (const block of json.content ?? []) {
7211
7763
  if (block.type === "text") {
7212
7764
  textParts.push(block.text);
7765
+ } else if (block.type === "thinking") {
7766
+ reasoningBlocks.push({
7767
+ type: "thinking",
7768
+ text: block.thinking ?? "",
7769
+ signature: block.signature
7770
+ });
7771
+ if (block.thinking) summaryParts.push(block.thinking);
7772
+ } else if (block.type === "redacted_thinking") {
7773
+ reasoningBlocks.push({ type: "redacted_thinking", data: block.data });
7213
7774
  } else if (block.type === "tool_use") {
7214
7775
  toolCalls.push({
7215
7776
  id: block.id,
@@ -7226,6 +7787,9 @@ var AnthropicProvider = class extends BaseProvider {
7226
7787
  cachedInputTokens: usage.cache_read_input_tokens ?? 0,
7227
7788
  cachedWriteTokens: usage.cache_creation_input_tokens ?? 0,
7228
7789
  cachedOutputTokens: 0,
7790
+ // Anthropic bills thinking tokens inside `output_tokens` and does not
7791
+ // expose a separate count, so reasoningTokens stays 0 here (cost is still
7792
+ // captured via outputTokens). See docs for the limitation.
7229
7793
  reasoningTokens: 0
7230
7794
  };
7231
7795
  return {
@@ -7235,6 +7799,7 @@ var AnthropicProvider = class extends BaseProvider {
7235
7799
  toolCalls,
7236
7800
  usage: tokenUsage,
7237
7801
  finishReason: mapAnthropicStopReason(json.stop_reason),
7802
+ reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
7238
7803
  raw: json
7239
7804
  };
7240
7805
  }
@@ -7259,6 +7824,18 @@ function safeJsonParse(str) {
7259
7824
  return {};
7260
7825
  }
7261
7826
  }
7827
+ function appendReasoningBlocks(content, blocks) {
7828
+ if (!blocks?.length) return;
7829
+ for (const b of blocks) {
7830
+ if (b.type === "redacted_thinking") {
7831
+ if (b.data) content.push({ type: "redacted_thinking", data: b.data });
7832
+ } else if (b.type === "thinking") {
7833
+ if (b.signature) {
7834
+ content.push({ type: "thinking", thinking: b.text ?? "", signature: b.signature });
7835
+ }
7836
+ }
7837
+ }
7838
+ }
7262
7839
 
7263
7840
  // src/providers/azure.ts
7264
7841
  var AzureProvider = class extends OpenAIProvider {
@@ -7302,7 +7879,52 @@ var AzureProvider = class extends OpenAIProvider {
7302
7879
  }
7303
7880
  return res;
7304
7881
  }
7882
+ /** Azure exposes the Responses API at /openai/responses with api-key auth.
7883
+ * Reasoning summaries require a preview api-version; callers can override via
7884
+ * the `apiVersion` config. */
7885
+ async responsesFetch(body) {
7886
+ body.input = expandAzureResponsesInput(body.input);
7887
+ const deployment = this.deploymentName ?? body.model;
7888
+ if (!deployment) {
7889
+ throw new ProviderError("Azure requires a deploymentName or model", this.providerName);
7890
+ }
7891
+ const url = `${this.endpoint}/openai/responses?api-version=${this.apiVersion}`;
7892
+ const payload = JSON.stringify({ ...body, model: deployment });
7893
+ const res = await fetch(url, {
7894
+ method: "POST",
7895
+ headers: {
7896
+ "Content-Type": "application/json",
7897
+ "api-key": this.azureApiKey,
7898
+ ...this.defaultHeaders
7899
+ },
7900
+ body: payload
7901
+ });
7902
+ if (!res.ok) {
7903
+ const text = await res.text().catch(() => "");
7904
+ throw new ProviderError(
7905
+ `Azure OpenAI Responses API error ${res.status}: ${text}`,
7906
+ this.providerName,
7907
+ res.status,
7908
+ text
7909
+ );
7910
+ }
7911
+ return res;
7912
+ }
7305
7913
  };
7914
+ function expandAzureResponsesInput(input) {
7915
+ const out = [];
7916
+ for (const item of input) {
7917
+ if (item && item.__assistantWithCalls) {
7918
+ if (item.text) {
7919
+ out.push({ role: "assistant", content: [{ type: "output_text", text: item.text }] });
7920
+ }
7921
+ for (const call of item.calls) out.push(call);
7922
+ } else {
7923
+ out.push(item);
7924
+ }
7925
+ }
7926
+ return out;
7927
+ }
7306
7928
 
7307
7929
  // src/providers/openaiCompatible.ts
7308
7930
  var OpenAICompatibleProvider = class extends OpenAIProvider {
@@ -7475,6 +8097,7 @@ var BedrockProvider = class extends BaseProvider {
7475
8097
  if (request.extra) {
7476
8098
  Object.assign(body, request.extra);
7477
8099
  }
8100
+ applyBedrockReasoning(body, request.reasoning);
7478
8101
  return body;
7479
8102
  }
7480
8103
  splitSystemMessages(messages) {
@@ -7508,6 +8131,7 @@ var BedrockProvider = class extends BaseProvider {
7508
8131
  }
7509
8132
  if (m.role === "assistant" && m.toolCalls?.length) {
7510
8133
  const content2 = [];
8134
+ appendBedrockReasoning(content2, m.reasoning?.blocks);
7511
8135
  if (typeof m.content === "string" && m.content) {
7512
8136
  content2.push({ text: m.content });
7513
8137
  }
@@ -7588,9 +8212,23 @@ var BedrockProvider = class extends BaseProvider {
7588
8212
  const output = json.output?.message;
7589
8213
  const textParts = [];
7590
8214
  const toolCalls = [];
8215
+ const reasoningBlocks = [];
8216
+ const summaryParts = [];
7591
8217
  for (const block of output?.content ?? []) {
7592
8218
  if (block.text) {
7593
8219
  textParts.push(block.text);
8220
+ } else if (block.reasoningContent) {
8221
+ const rc = block.reasoningContent;
8222
+ if (rc.reasoningText) {
8223
+ reasoningBlocks.push({
8224
+ type: "thinking",
8225
+ text: rc.reasoningText.text ?? "",
8226
+ signature: rc.reasoningText.signature
8227
+ });
8228
+ if (rc.reasoningText.text) summaryParts.push(rc.reasoningText.text);
8229
+ } else if (rc.redactedContent) {
8230
+ reasoningBlocks.push({ type: "redacted_thinking", data: rc.redactedContent });
8231
+ }
7594
8232
  } else if (block.toolUse) {
7595
8233
  toolCalls.push({
7596
8234
  id: block.toolUse.toolUseId,
@@ -7607,6 +8245,7 @@ var BedrockProvider = class extends BaseProvider {
7607
8245
  cachedInputTokens: usage.cacheReadInputTokenCount ?? 0,
7608
8246
  cachedWriteTokens: usage.cacheWriteInputTokenCount ?? 0,
7609
8247
  cachedOutputTokens: 0,
8248
+ // Bedrock bills thinking tokens inside outputTokens; no separate count.
7610
8249
  reasoningTokens: 0
7611
8250
  };
7612
8251
  return {
@@ -7616,10 +8255,25 @@ var BedrockProvider = class extends BaseProvider {
7616
8255
  toolCalls,
7617
8256
  usage: tokenUsage,
7618
8257
  finishReason: mapBedrockStopReason(json.stopReason),
8258
+ reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
7619
8259
  raw: json
7620
8260
  };
7621
8261
  }
7622
8262
  };
8263
+ function appendBedrockReasoning(content, blocks) {
8264
+ if (!blocks?.length) return;
8265
+ for (const b of blocks) {
8266
+ if (b.type === "redacted_thinking") {
8267
+ if (b.data) content.push({ reasoningContent: { redactedContent: b.data } });
8268
+ } else if (b.type === "thinking") {
8269
+ if (b.signature) {
8270
+ content.push({
8271
+ reasoningContent: { reasoningText: { text: b.text ?? "", signature: b.signature } }
8272
+ });
8273
+ }
8274
+ }
8275
+ }
8276
+ }
7623
8277
  function mapBedrockStopReason(reason) {
7624
8278
  switch (reason) {
7625
8279
  case "end_turn":
@@ -7942,10 +8596,15 @@ var VertexProvider = class extends BaseProvider {
7942
8596
  const parts = candidate?.content?.parts ?? [];
7943
8597
  const textParts = [];
7944
8598
  const toolCalls = [];
8599
+ const thoughtParts = [];
7945
8600
  let toolCallIdx = 0;
7946
8601
  for (const part of parts) {
7947
8602
  if (part.text) {
7948
- textParts.push(part.text);
8603
+ if (part.thought === true) {
8604
+ thoughtParts.push(part.text);
8605
+ } else {
8606
+ textParts.push(part.text);
8607
+ }
7949
8608
  } else if (part.functionCall) {
7950
8609
  toolCalls.push({
7951
8610
  id: `call_${toolCallIdx++}`,
@@ -7971,6 +8630,7 @@ var VertexProvider = class extends BaseProvider {
7971
8630
  toolCalls,
7972
8631
  usage: tokenUsage,
7973
8632
  finishReason: mapGeminiFinishReason(candidate?.finishReason),
8633
+ reasoning: thoughtParts.length > 0 ? { summary: thoughtParts.join("\n").trim() || void 0 } : void 0,
7974
8634
  raw: json
7975
8635
  };
7976
8636
  }
@@ -7980,7 +8640,11 @@ var VertexProvider = class extends BaseProvider {
7980
8640
  const delta = {};
7981
8641
  for (const part of parts) {
7982
8642
  if (part.text) {
7983
- delta.content = (delta.content ?? "") + part.text;
8643
+ if (part.thought === true) {
8644
+ delta.reasoning = { summary: (delta.reasoning?.summary ?? "") + part.text };
8645
+ } else {
8646
+ delta.content = (delta.content ?? "") + part.text;
8647
+ }
7984
8648
  } else if (part.functionCall) {
7985
8649
  if (!delta.toolCalls) delta.toolCalls = [];
7986
8650
  delta.toolCalls.push({
@@ -8054,12 +8718,16 @@ function fromNativeProvider(provider, options) {
8054
8718
  let fullContent = "";
8055
8719
  let allToolCalls = [];
8056
8720
  let lastUsage;
8721
+ let reasoningBlocks;
8057
8722
  const toolCallBuffers = /* @__PURE__ */ new Map();
8058
8723
  for await (const chunk of provider.completeStream(request)) {
8059
8724
  if (chunk.delta.content) {
8060
8725
  fullContent += chunk.delta.content;
8061
8726
  yield chunk.delta.content;
8062
8727
  }
8728
+ if (chunk.delta.reasoning?.blocks?.length) {
8729
+ reasoningBlocks = chunk.delta.reasoning.blocks;
8730
+ }
8063
8731
  if (chunk.delta.toolCalls) {
8064
8732
  for (const tc of chunk.delta.toolCalls) {
8065
8733
  if (tc.id) {
@@ -8080,6 +8748,9 @@ function fromNativeProvider(provider, options) {
8080
8748
  }
8081
8749
  allToolCalls = [...toolCallBuffers.values()];
8082
8750
  const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
8751
+ if (reasoningBlocks?.length) {
8752
+ finalMessage.reasoning = { blocks: reasoningBlocks };
8753
+ }
8083
8754
  yield finalMessage;
8084
8755
  },
8085
8756
  bindTools: (tools, _bindOptions) => {
@@ -8142,6 +8813,10 @@ function toUnifiedMessage(msg) {
8142
8813
  arguments: tc.function?.arguments ?? tc.arguments ?? "{}"
8143
8814
  }));
8144
8815
  }
8816
+ const reasoning = msg.reasoning;
8817
+ if (reasoning && (reasoning.blocks?.length || reasoning.summary)) {
8818
+ unified.reasoning = reasoning;
8819
+ }
8145
8820
  return unified;
8146
8821
  }
8147
8822
  function convertContent(content) {
@@ -8350,6 +9025,9 @@ function toBaseChatMessage(response) {
8350
9025
  function: { name: tc.name, arguments: tc.arguments }
8351
9026
  }));
8352
9027
  }
9028
+ if (response.reasoning && (response.reasoning.blocks?.length || response.reasoning.summary)) {
9029
+ msg.reasoning = response.reasoning;
9030
+ }
8353
9031
  return msg;
8354
9032
  }
8355
9033
  function assembleMessage(content, toolCalls, usage) {
@@ -8509,6 +9187,7 @@ exports.otlpSink = otlpSink;
8509
9187
  exports.readMemoryFacts = readMemoryFacts;
8510
9188
  exports.regexRule = regexRule;
8511
9189
  exports.resolveMemoryStore = resolveMemoryStore;
9190
+ exports.resolveReasoning = resolveReasoning;
8512
9191
  exports.resolveStrategy = resolveStrategy;
8513
9192
  exports.resolveToolApprovalState = resolveToolApprovalState;
8514
9193
  exports.resolveUserQuestionState = resolveUserQuestionState;
@@ -8517,6 +9196,7 @@ exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
8517
9196
  exports.setTokenCounter = setTokenCounter;
8518
9197
  exports.startStreamingSession = startStreamingSession;
8519
9198
  exports.traceSessionToOtlp = traceSessionToOtlp;
9199
+ exports.validateReasoningConfig = validateReasoningConfig;
8520
9200
  exports.withTools = withTools;
8521
9201
  exports.writeSummaryFactsToMemory = writeSummaryFactsToMemory;
8522
9202
  //# sourceMappingURL=index.cjs.map