@cognipeer/agent-sdk 0.8.5 → 0.8.7

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
@@ -420,7 +420,8 @@ function createTool({
420
420
  approvalDefaults,
421
421
  maxExecutionsPerRun,
422
422
  cache,
423
- retry
423
+ retry,
424
+ retention
424
425
  }) {
425
426
  const execute = async (input) => func(input);
426
427
  const toolRecord = {
@@ -451,6 +452,9 @@ function createTool({
451
452
  if (retry !== void 0) {
452
453
  toolRecord.retry = retry;
453
454
  }
455
+ if (retention !== void 0) {
456
+ toolRecord.retention = retention;
457
+ }
454
458
  toolRecord.__source = toolRecord.__source || "smart";
455
459
  toolRecord.__impl = func;
456
460
  return toolRecord;
@@ -1950,6 +1954,270 @@ function estimatePayloadBytes(value) {
1950
1954
  }
1951
1955
  }
1952
1956
 
1957
+ // src/smart/toolResponses.ts
1958
+ init_utilTokens();
1959
+
1960
+ // src/utils/content.ts
1961
+ function contentToString(content) {
1962
+ try {
1963
+ if (content == null) return "";
1964
+ if (typeof content === "string") return content;
1965
+ if (Array.isArray(content)) {
1966
+ return content.map((p) => {
1967
+ if (!p || typeof p !== "object") return String(p);
1968
+ if (p.type === "text") return String(p.text ?? "");
1969
+ if (p.type === "image_url") {
1970
+ const img = p.image_url;
1971
+ const url = typeof img === "string" ? img : img?.url;
1972
+ const detail = typeof img === "string" ? void 0 : img?.detail;
1973
+ return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
1974
+ }
1975
+ return JSON.stringify(p);
1976
+ }).join("\n");
1977
+ }
1978
+ return JSON.stringify(content);
1979
+ } catch {
1980
+ return String(content);
1981
+ }
1982
+ }
1983
+ function mergeContentsToString(contents) {
1984
+ return contents.map((c) => contentToString(c)).join("\n");
1985
+ }
1986
+ function safeStringify(value, pretty = false) {
1987
+ if (value == null) return "";
1988
+ if (typeof value === "string") return value;
1989
+ try {
1990
+ return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
1991
+ } catch {
1992
+ return String(value);
1993
+ }
1994
+ }
1995
+ function extractMessageText2(message) {
1996
+ if (!message) return "";
1997
+ const content = message.content;
1998
+ if (typeof content === "string") return content;
1999
+ if (Array.isArray(content)) {
2000
+ return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
2001
+ }
2002
+ return "";
2003
+ }
2004
+
2005
+ // src/smart/toolResponses.ts
2006
+ var CONTROL_PLANE_TOOL_NAMES = [
2007
+ "response",
2008
+ "manage_todo_list",
2009
+ "get_tool_response",
2010
+ "ask_user_question",
2011
+ "open_skill",
2012
+ "bind_skill_tools",
2013
+ "search_skills"
2014
+ ];
2015
+ var DELEGATION_TOOL_NAMES = [
2016
+ "delegate_to",
2017
+ "spawn_subagent",
2018
+ "spawn_subagents_parallel"
2019
+ ];
2020
+ var INPUT_PROTECTED_TOOL_NAMES = /* @__PURE__ */ new Set([
2021
+ ...CONTROL_PLANE_TOOL_NAMES,
2022
+ ...DELEGATION_TOOL_NAMES
2023
+ ]);
2024
+ var CONTROL_PLANE_OUTPUT_DEFAULTS = new Set(CONTROL_PLANE_TOOL_NAMES);
2025
+ var DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS = 2e3;
2026
+ var DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS = 200;
2027
+ var TOOL_INPUT_DIGEST_KEY = "__digest";
2028
+ function summarizeObject(value) {
2029
+ if (value == null) return "null";
2030
+ if (typeof value === "string") {
2031
+ return value.length > 240 ? `${value.slice(0, 240)}...` : value;
2032
+ }
2033
+ if (Array.isArray(value)) {
2034
+ const preview = value.slice(0, 3).map((entry) => safeStringify(entry).slice(0, 120)).join(" | ");
2035
+ return `array(length=${value.length}) ${preview}`.trim();
2036
+ }
2037
+ if (typeof value === "object") {
2038
+ const keys = Object.keys(value);
2039
+ const preview = keys.slice(0, 6).map((key) => `${key}=${safeStringify(value[key]).slice(0, 80)}`).join("; ");
2040
+ return `object(keys=${keys.length}) ${preview}`.trim();
2041
+ }
2042
+ return safeStringify(value);
2043
+ }
2044
+ function classifyToolResponse(toolName, output, config) {
2045
+ const criticalTools = new Set(config.toolResponses.criticalTools);
2046
+ if (criticalTools.has(toolName)) return "critical";
2047
+ const serialized = safeStringify(output);
2048
+ const tokenCount = countApproxTokens(serialized);
2049
+ if (tokenCount >= config.toolResponses.maxToolResponseTokens || serialized.length >= config.toolResponses.maxToolResponseChars) {
2050
+ return "verbose";
2051
+ }
2052
+ return "informative";
2053
+ }
2054
+ function applyToolResponseHardCap(toolName, output, executionId, config) {
2055
+ const serialized = safeStringify(output);
2056
+ const tokenCount = countApproxTokens(serialized);
2057
+ const classification = classifyToolResponse(toolName, output, config);
2058
+ if (classification !== "verbose") {
2059
+ return { classification, content: serialized, rawOutput: output, tokenCount, truncated: false };
2060
+ }
2061
+ const cap = config.toolResponses.maxToolResponseChars;
2062
+ const head = serialized.slice(0, cap);
2063
+ const note = `
2064
+ ... [TRUNCATED ${serialized.length - cap} chars by hard cap. Use get_tool_response with executionId="${executionId}" to fetch the full payload.]`;
2065
+ return {
2066
+ classification,
2067
+ content: head + note,
2068
+ rawOutput: output,
2069
+ tokenCount,
2070
+ truncated: true
2071
+ };
2072
+ }
2073
+ function collectToolRetentionDeclarations(tools) {
2074
+ const declarations = /* @__PURE__ */ new Map();
2075
+ if (!Array.isArray(tools)) return declarations;
2076
+ for (const tool of tools) {
2077
+ const spec = tool?.retention;
2078
+ const name = typeof tool?.name === "string" ? tool.name : "";
2079
+ if (!name || !spec || typeof spec !== "object") continue;
2080
+ declarations.set(name, spec);
2081
+ }
2082
+ return declarations;
2083
+ }
2084
+ function resolveSummarizationRetention(toolName, config, declarations) {
2085
+ const criticalTools = new Set(config.toolResponses.criticalTools);
2086
+ if (criticalTools.has(toolName)) return "keep_full";
2087
+ const twoAxis = config.toolResponses.retentionByTool?.[toolName]?.output;
2088
+ if (twoAxis) return twoAxis;
2089
+ const legacy = config.toolResponses.toolResponseRetentionByTool[toolName];
2090
+ if (legacy) return legacy;
2091
+ const declared = declarations?.get(toolName)?.output;
2092
+ if (declared) return declared;
2093
+ if (CONTROL_PLANE_OUTPUT_DEFAULTS.has(toolName)) return "keep_full";
2094
+ return config.toolResponses.defaultPolicy;
2095
+ }
2096
+ function resolveInputRetention(toolName, config, declarations) {
2097
+ if (INPUT_PROTECTED_TOOL_NAMES.has(toolName)) return "keep";
2098
+ const criticalTools = new Set(config.toolResponses.criticalTools);
2099
+ if (criticalTools.has(toolName)) return "keep";
2100
+ const twoAxis = config.toolResponses.retentionByTool?.[toolName]?.input;
2101
+ if (twoAxis) return twoAxis;
2102
+ const declared = declarations?.get(toolName)?.input;
2103
+ if (declared) return declared;
2104
+ return config.toolResponses.defaultInputPolicy;
2105
+ }
2106
+ function shortSha256(value) {
2107
+ return crypto.createHash("sha256").update(value, "utf8").digest("hex").slice(0, 16);
2108
+ }
2109
+ function isDigestMarker(value) {
2110
+ return Boolean(
2111
+ value && typeof value === "object" && !Array.isArray(value) && TOOL_INPUT_DIGEST_KEY in value
2112
+ );
2113
+ }
2114
+ function digestToolInputValue(value, options) {
2115
+ const maxFieldChars = options?.maxFieldChars ?? DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS;
2116
+ const headChars = options?.headChars ?? DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS;
2117
+ const executionId = options?.executionId;
2118
+ const digestedPaths = [];
2119
+ let reclaimedChars = 0;
2120
+ const walk = (node, path2) => {
2121
+ if (typeof node === "string") {
2122
+ if (node.length <= maxFieldChars) return node;
2123
+ digestedPaths.push(path2 || "(root)");
2124
+ const marker = {
2125
+ chars: node.length,
2126
+ sha256: shortSha256(node),
2127
+ head: node.slice(0, headChars)
2128
+ };
2129
+ if (executionId) {
2130
+ marker.recover = `get_tool_response executionId="${executionId}" part="input"`;
2131
+ }
2132
+ const replacement = { [TOOL_INPUT_DIGEST_KEY]: marker };
2133
+ reclaimedChars += node.length - safeStringify(replacement).length;
2134
+ return replacement;
2135
+ }
2136
+ if (Array.isArray(node)) {
2137
+ let changed = false;
2138
+ const next = node.map((entry, index) => {
2139
+ const walked = walk(entry, path2 ? `${path2}[${index}]` : `[${index}]`);
2140
+ if (walked !== entry) changed = true;
2141
+ return walked;
2142
+ });
2143
+ return changed ? next : node;
2144
+ }
2145
+ if (node && typeof node === "object") {
2146
+ if (isDigestMarker(node)) return node;
2147
+ let changed = false;
2148
+ const next = {};
2149
+ for (const [key, entry] of Object.entries(node)) {
2150
+ const walked = walk(entry, path2 ? `${path2}.${key}` : key);
2151
+ if (walked !== entry) changed = true;
2152
+ next[key] = walked;
2153
+ }
2154
+ return changed ? next : node;
2155
+ }
2156
+ return node;
2157
+ };
2158
+ const nextValue = walk(value, "");
2159
+ return { value: nextValue, digestedPaths, reclaimedChars: Math.max(0, reclaimedChars) };
2160
+ }
2161
+ function digestToolInputArguments(argumentsJson, options) {
2162
+ const unchanged = { arguments: argumentsJson, digestedPaths: [], reclaimedChars: 0 };
2163
+ if (typeof argumentsJson !== "string" || argumentsJson.length === 0) return unchanged;
2164
+ let parsed;
2165
+ try {
2166
+ parsed = JSON.parse(argumentsJson);
2167
+ } catch {
2168
+ return unchanged;
2169
+ }
2170
+ const digested = digestToolInputValue(parsed, options);
2171
+ if (digested.digestedPaths.length === 0) return unchanged;
2172
+ const serialized = safeStringify(digested.value);
2173
+ if (serialized.length >= argumentsJson.length) return unchanged;
2174
+ return {
2175
+ arguments: serialized,
2176
+ digestedPaths: digested.digestedPaths,
2177
+ reclaimedChars: argumentsJson.length - serialized.length
2178
+ };
2179
+ }
2180
+ function renderRetainedToolMessage(args) {
2181
+ const { policy, rawOutput, toolName, toolCallId, executionId, prebuiltSummary } = args;
2182
+ if (policy === "keep_full") {
2183
+ return typeof rawOutput === "string" ? rawOutput : safeStringify(rawOutput);
2184
+ }
2185
+ const summary = prebuiltSummary || summarizeObject(rawOutput);
2186
+ const refs = [
2187
+ `toolName=${toolName}`,
2188
+ toolCallId ? `toolCallId=${toolCallId}` : null,
2189
+ executionId ? `executionId=${executionId}` : null
2190
+ ].filter(Boolean).join("; ");
2191
+ const refId = executionId || toolCallId || "";
2192
+ if (policy === "keep_structured") {
2193
+ return `STRUCTURED_TOOL_RESPONSE [${refs}]
2194
+ Preview: ${summary}
2195
+ Use get_tool_response with executionId "${refId}" to fetch the full payload when a specific field is needed.`;
2196
+ }
2197
+ if (policy === "summarize_archive") {
2198
+ return `ARCHIVED_TOOL_RESPONSE [${refs}]
2199
+ Summary: ${summary}
2200
+ Use get_tool_response with executionId "${refId}" to fetch the full payload.`;
2201
+ }
2202
+ return `DROPPED_TOOL_RESPONSE [${refs}]
2203
+ Use get_tool_response with executionId "${refId}" only if you must recover the original payload.`;
2204
+ }
2205
+ function validateToolArgs(tool, args) {
2206
+ const schema = tool.schema;
2207
+ if (!schema || typeof schema.parse !== "function") {
2208
+ return { ok: true, value: args };
2209
+ }
2210
+ try {
2211
+ return { ok: true, value: schema.parse(args) };
2212
+ } catch (error) {
2213
+ if (error instanceof zod.ZodError) {
2214
+ const message = error.issues.map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
2215
+ return { ok: false, message };
2216
+ }
2217
+ return { ok: false, message: error instanceof Error ? error.message : String(error) };
2218
+ }
2219
+ }
2220
+
1953
2221
  // src/smart/runtimeConfig.ts
1954
2222
  var DEFAULT_CRITICAL_TOOLS = ["response", "manage_todo_list", "get_tool_response"];
1955
2223
  var BASE_DEFAULTS = {
@@ -2000,6 +2268,11 @@ var BASE_DEFAULTS = {
2000
2268
  maxToolResponseTokens: 8e3,
2001
2269
  defaultPolicy: "summarize_archive",
2002
2270
  toolResponseRetentionByTool: {},
2271
+ // Argument digesting is opt-in: the default never touches a tool's request.
2272
+ defaultInputPolicy: "keep",
2273
+ retentionByTool: {},
2274
+ maxToolInputFieldChars: DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS,
2275
+ maxToolInputDigestHeadChars: DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS,
2003
2276
  criticalTools: [...DEFAULT_CRITICAL_TOOLS],
2004
2277
  schemaValidation: "strict"
2005
2278
  },
@@ -2054,7 +2327,8 @@ function buildProfile(overrides) {
2054
2327
  ...BASE_DEFAULTS.toolResponses,
2055
2328
  ...overrides.toolResponses,
2056
2329
  criticalTools: overrides.toolResponses?.criticalTools ?? [...DEFAULT_CRITICAL_TOOLS],
2057
- toolResponseRetentionByTool: overrides.toolResponses?.toolResponseRetentionByTool ?? {}
2330
+ toolResponseRetentionByTool: overrides.toolResponses?.toolResponseRetentionByTool ?? {},
2331
+ retentionByTool: overrides.toolResponses?.retentionByTool ?? {}
2058
2332
  },
2059
2333
  contextPilot: mergeContextPilot(BASE_DEFAULTS.contextPilot, overrides.contextPilot)
2060
2334
  };
@@ -2208,6 +2482,14 @@ function normalizeSmartAgentOptions(opts) {
2208
2482
  ...customProfile.toolResponses?.toolResponseRetentionByTool || {},
2209
2483
  ...opts.toolResponses?.toolResponseRetentionByTool || {}
2210
2484
  },
2485
+ // Two-axis map merges the same way, so a caller can layer a small override
2486
+ // on top of a profile's table instead of restating it.
2487
+ retentionByTool: {
2488
+ ...preset.toolResponses.retentionByTool,
2489
+ ...customProfile.toolResponses?.retentionByTool || {},
2490
+ ...opts.toolResponses?.retentionByTool || {}
2491
+ },
2492
+ defaultInputPolicy: opts.toolResponses?.defaultInputPolicy ?? customProfile.toolResponses?.defaultInputPolicy ?? preset.toolResponses.defaultInputPolicy,
2211
2493
  criticalTools: opts.toolResponses?.criticalTools ?? customProfile.toolResponses?.criticalTools ?? preset.toolResponses.criticalTools
2212
2494
  },
2213
2495
  contextPilot: mergeContextPilot(mergeContextPilot(preset.contextPilot, customProfile.contextPilot), opts.contextPilot)
@@ -2392,53 +2674,6 @@ function detectVolatileContent(text, limit = 20) {
2392
2674
 
2393
2675
  // src/smart/contextPilot/jsonCrusher.ts
2394
2676
  init_utilTokens();
2395
-
2396
- // src/utils/content.ts
2397
- function contentToString(content) {
2398
- try {
2399
- if (content == null) return "";
2400
- if (typeof content === "string") return content;
2401
- if (Array.isArray(content)) {
2402
- return content.map((p) => {
2403
- if (!p || typeof p !== "object") return String(p);
2404
- if (p.type === "text") return String(p.text ?? "");
2405
- if (p.type === "image_url") {
2406
- const img = p.image_url;
2407
- const url = typeof img === "string" ? img : img?.url;
2408
- const detail = typeof img === "string" ? void 0 : img?.detail;
2409
- return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
2410
- }
2411
- return JSON.stringify(p);
2412
- }).join("\n");
2413
- }
2414
- return JSON.stringify(content);
2415
- } catch {
2416
- return String(content);
2417
- }
2418
- }
2419
- function mergeContentsToString(contents) {
2420
- return contents.map((c) => contentToString(c)).join("\n");
2421
- }
2422
- function safeStringify(value, pretty = false) {
2423
- if (value == null) return "";
2424
- if (typeof value === "string") return value;
2425
- try {
2426
- return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
2427
- } catch {
2428
- return String(value);
2429
- }
2430
- }
2431
- function extractMessageText2(message) {
2432
- if (!message) return "";
2433
- const content = message.content;
2434
- if (typeof content === "string") return content;
2435
- if (Array.isArray(content)) {
2436
- return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
2437
- }
2438
- return "";
2439
- }
2440
-
2441
- // src/smart/contextPilot/jsonCrusher.ts
2442
2677
  var CONTEXT_PILOT_JSON_MARKER_KEY = "__contextPilotDropped";
2443
2678
  function findCompressibleArray(output, minItems) {
2444
2679
  if (Array.isArray(output)) {
@@ -3007,100 +3242,6 @@ function extractToolItems(output) {
3007
3242
  });
3008
3243
  }
3009
3244
 
3010
- // src/smart/toolResponses.ts
3011
- init_utilTokens();
3012
- function summarizeObject(value) {
3013
- if (value == null) return "null";
3014
- if (typeof value === "string") {
3015
- return value.length > 240 ? `${value.slice(0, 240)}...` : value;
3016
- }
3017
- if (Array.isArray(value)) {
3018
- const preview = value.slice(0, 3).map((entry) => safeStringify(entry).slice(0, 120)).join(" | ");
3019
- return `array(length=${value.length}) ${preview}`.trim();
3020
- }
3021
- if (typeof value === "object") {
3022
- const keys = Object.keys(value);
3023
- const preview = keys.slice(0, 6).map((key) => `${key}=${safeStringify(value[key]).slice(0, 80)}`).join("; ");
3024
- return `object(keys=${keys.length}) ${preview}`.trim();
3025
- }
3026
- return safeStringify(value);
3027
- }
3028
- function classifyToolResponse(toolName, output, config) {
3029
- const criticalTools = new Set(config.toolResponses.criticalTools);
3030
- if (criticalTools.has(toolName)) return "critical";
3031
- const serialized = safeStringify(output);
3032
- const tokenCount = countApproxTokens(serialized);
3033
- if (tokenCount >= config.toolResponses.maxToolResponseTokens || serialized.length >= config.toolResponses.maxToolResponseChars) {
3034
- return "verbose";
3035
- }
3036
- return "informative";
3037
- }
3038
- function applyToolResponseHardCap(toolName, output, executionId, config) {
3039
- const serialized = safeStringify(output);
3040
- const tokenCount = countApproxTokens(serialized);
3041
- const classification = classifyToolResponse(toolName, output, config);
3042
- if (classification !== "verbose") {
3043
- return { classification, content: serialized, rawOutput: output, tokenCount, truncated: false };
3044
- }
3045
- const cap = config.toolResponses.maxToolResponseChars;
3046
- const head = serialized.slice(0, cap);
3047
- const note = `
3048
- ... [TRUNCATED ${serialized.length - cap} chars by hard cap. Use get_tool_response with executionId="${executionId}" to fetch the full payload.]`;
3049
- return {
3050
- classification,
3051
- content: head + note,
3052
- rawOutput: output,
3053
- tokenCount,
3054
- truncated: true
3055
- };
3056
- }
3057
- function resolveSummarizationRetention(toolName, config) {
3058
- const criticalTools = new Set(config.toolResponses.criticalTools);
3059
- if (criticalTools.has(toolName)) return "keep_full";
3060
- const byTool = config.toolResponses.toolResponseRetentionByTool[toolName];
3061
- return byTool || config.toolResponses.defaultPolicy;
3062
- }
3063
- function renderRetainedToolMessage(args) {
3064
- const { policy, rawOutput, toolName, toolCallId, executionId, prebuiltSummary } = args;
3065
- if (policy === "keep_full") {
3066
- return typeof rawOutput === "string" ? rawOutput : safeStringify(rawOutput);
3067
- }
3068
- const summary = prebuiltSummary || summarizeObject(rawOutput);
3069
- const refs = [
3070
- `toolName=${toolName}`,
3071
- toolCallId ? `toolCallId=${toolCallId}` : null,
3072
- executionId ? `executionId=${executionId}` : null
3073
- ].filter(Boolean).join("; ");
3074
- const refId = executionId || toolCallId || "";
3075
- if (policy === "keep_structured") {
3076
- return `STRUCTURED_TOOL_RESPONSE [${refs}]
3077
- Preview: ${summary}
3078
- Use get_tool_response with executionId "${refId}" to fetch the full payload when a specific field is needed.`;
3079
- }
3080
- if (policy === "summarize_archive") {
3081
- return `ARCHIVED_TOOL_RESPONSE [${refs}]
3082
- Summary: ${summary}
3083
- Use get_tool_response with executionId "${refId}" to fetch the full payload.`;
3084
- }
3085
- return `DROPPED_TOOL_RESPONSE [${refs}]
3086
- Use get_tool_response with executionId "${refId}" only if you must recover the original payload.`;
3087
- }
3088
- function validateToolArgs(tool, args) {
3089
- const schema = tool.schema;
3090
- if (!schema || typeof schema.parse !== "function") {
3091
- return { ok: true, value: args };
3092
- }
3093
- try {
3094
- return { ok: true, value: schema.parse(args) };
3095
- } catch (error) {
3096
- if (error instanceof zod.ZodError) {
3097
- const message = error.issues.map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
3098
- return { ok: false, message };
3099
- }
3100
- return { ok: false, message: error instanceof Error ? error.message : String(error) };
3101
- }
3102
- }
3103
-
3104
3245
  // src/utils/pendingToolCalls.ts
3105
3246
  function selectPendingToolCalls(messages) {
3106
3247
  if (!Array.isArray(messages) || messages.length === 0) return [];
@@ -5357,7 +5498,10 @@ function createAgent(opts) {
5357
5498
  }
5358
5499
  }
5359
5500
  }
5360
- if (soManager && !state.ctx?.__finalizedDueToStructuredOutput) {
5501
+ const structuredFinalizeBlocked = Boolean(
5502
+ pausedStage || state.ctx?.__awaitingApproval || state.ctx?.__awaitingUserQuestion || state.ctx?.__cancelled || state.ctx?.__needsSummarization || state.ctx?.__limitBreached || state.ctx?.__guardrailBlocked
5503
+ );
5504
+ if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !structuredFinalizeBlocked) {
5361
5505
  const lastForParse = state.messages[state.messages.length - 1];
5362
5506
  if (lastForParse?.role === "assistant") {
5363
5507
  const assistantText = extractMessageText2(lastForParse);
@@ -5374,10 +5518,11 @@ function createAgent(opts) {
5374
5518
  }
5375
5519
  }
5376
5520
  }
5377
- if (soManager && soManager.strategy.kind === "tool_based" && !state.ctx?.__finalizedDueToStructuredOutput) {
5521
+ if (soManager && soManager.strategy.kind === "tool_based" && !state.ctx?.__finalizedDueToStructuredOutput && !structuredFinalizeBlocked) {
5378
5522
  const maxPostLoopRetries = soManager.maxRetries;
5379
5523
  for (let postRetry = 0; postRetry < maxPostLoopRetries; postRetry++) {
5380
5524
  if (state.ctx?.__finalizedDueToStructuredOutput) break;
5525
+ if (state.ctx?.__awaitingApproval || state.ctx?.__awaitingUserQuestion || state.ctx?.__cancelled || state.ctx?.__limitBreached) break;
5381
5526
  const last = state.messages[state.messages.length - 1];
5382
5527
  const lastHasToolCalls = Array.isArray(last?.tool_calls) && last.tool_calls.length > 0;
5383
5528
  if (!lastHasToolCalls) {
@@ -5791,7 +5936,7 @@ function collectRecentTurns(messages, lastTurnsToKeep) {
5791
5936
  if (turnCount >= lastTurnsToKeep) break;
5792
5937
  }
5793
5938
  }
5794
- if (countAssistantTurns && collected.length > 0 && collected[0].role !== "user") {
5939
+ if (collected.length > 0) {
5795
5940
  const firstUserMsg = body.find((m) => m.role === "user");
5796
5941
  if (firstUserMsg && !collected.includes(firstUserMsg)) {
5797
5942
  collected.unshift(firstUserMsg);
@@ -5823,12 +5968,18 @@ function renderMemoryBlock(facts) {
5823
5968
  ...facts.map((fact) => `- ${fact.key}: ${fact.value}`)
5824
5969
  ].join("\n");
5825
5970
  }
5971
+ function isClampProtected(message, index, firstUserIndex) {
5972
+ if (message.role === "system") return true;
5973
+ if (index === firstUserIndex) return true;
5974
+ return false;
5975
+ }
5826
5976
  function clampToBudget(messages, maxContextTokens) {
5827
5977
  let working = [...messages];
5828
5978
  while (working.length > 2) {
5829
5979
  const tokenCount = countApproxTokens(working.map(extractMessageText2).join("\n"));
5830
5980
  if (tokenCount <= maxContextTokens) return working;
5831
- const firstNonSystem = working.findIndex((message, index) => !(index === 0 && message.role === "system"));
5981
+ const firstUserIndex = working.findIndex((message) => message.role === "user");
5982
+ const firstNonSystem = working.findIndex((message, index) => !isClampProtected(message, index, firstUserIndex));
5832
5983
  if (firstNonSystem < 0) break;
5833
5984
  const target = working[firstNonSystem];
5834
5985
  if (target.role === "assistant" && Array.isArray(target.tool_calls) && target.tool_calls.length > 0) {
@@ -6266,9 +6417,42 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
6266
6417
  break;
6267
6418
  }
6268
6419
  }
6420
+ const retentionDeclarations = collectToolRetentionDeclarations(state.agent?.tools);
6421
+ const digestableToolCallIds = /* @__PURE__ */ new Set();
6422
+ for (const m of messages) {
6423
+ if (m.role !== "tool" || isSyntheticSummaryMessage(m)) continue;
6424
+ const toolCallId = m.tool_call_id;
6425
+ if (!toolCallId || !toolCallIdToAssistantIdx.has(toolCallId)) continue;
6426
+ if (protectedToolCallIds.has(toolCallId)) continue;
6427
+ const toolName = m.name || "";
6428
+ if (resolveInputRetention(toolName, resolved, retentionDeclarations) !== "digest") continue;
6429
+ digestableToolCallIds.add(toolCallId);
6430
+ }
6269
6431
  const archivedExecutions = [...state.toolHistoryArchived || []];
6270
6432
  const archivedIds = new Set(archivedExecutions.map((entry) => entry?.executionId).filter(Boolean));
6271
6433
  const newMessages = messages.map((m) => {
6434
+ if (m.role === "assistant" && Array.isArray(m.tool_calls) && m.tool_calls.length > 0) {
6435
+ if (m.reasoning?.blocks?.length) return m;
6436
+ let changed = false;
6437
+ const nextToolCalls = m.tool_calls.map((tc) => {
6438
+ const args = tc?.function?.arguments;
6439
+ if (!tc?.id || !digestableToolCallIds.has(tc.id)) return tc;
6440
+ if (typeof args !== "string") return tc;
6441
+ const historyEntry = findToolHistoryEntry(state, tc.id, tc.function?.name);
6442
+ const digested = digestToolInputArguments(args, {
6443
+ maxFieldChars: resolved.toolResponses.maxToolInputFieldChars,
6444
+ headChars: resolved.toolResponses.maxToolInputDigestHeadChars,
6445
+ executionId: historyEntry?.executionId ?? tc.id
6446
+ });
6447
+ if (digested.digestedPaths.length === 0) return tc;
6448
+ changed = true;
6449
+ return {
6450
+ ...tc,
6451
+ function: { ...tc.function, arguments: digested.arguments }
6452
+ };
6453
+ });
6454
+ return changed ? { ...m, tool_calls: nextToolCalls } : m;
6455
+ }
6272
6456
  if (m.role === "tool") {
6273
6457
  if (isSyntheticSummaryMessage(m)) {
6274
6458
  return m;
@@ -6404,7 +6588,9 @@ var TOOL_RESPONSE_RECOVERY_MARKERS = [
6404
6588
  /STRUCTURED_TOOL_RESPONSE\s*\[/,
6405
6589
  /SUMMARIZED_TOOL_RESPONSE\b/,
6406
6590
  /DROPPED_TOOL_RESPONSE\s*\[/,
6407
- /Use get_tool_response with executionId/i
6591
+ /Use get_tool_response with executionId/i,
6592
+ // Field-level ARGUMENT digest marker (see smart/toolResponses digestToolInputValue).
6593
+ /"__digest"\s*:/
6408
6594
  ];
6409
6595
  var todoStatusSchema = zod.z.enum(["not-started", "in-progress", "completed", "blocked"]);
6410
6596
  var todoWriteItemSchema = zod.z.object({
@@ -6496,6 +6682,24 @@ function flattenRecoveryContent(content) {
6496
6682
  }
6497
6683
  return "";
6498
6684
  }
6685
+ function flattenToolCallArguments(message) {
6686
+ const toolCalls = message?.tool_calls;
6687
+ if (!Array.isArray(toolCalls)) {
6688
+ return "";
6689
+ }
6690
+ return toolCalls.map((call) => {
6691
+ const args = call?.function?.arguments;
6692
+ if (typeof args === "string") return args;
6693
+ if (args && typeof args === "object") {
6694
+ try {
6695
+ return JSON.stringify(args);
6696
+ } catch {
6697
+ return "";
6698
+ }
6699
+ }
6700
+ return "";
6701
+ }).filter(Boolean).join("\n");
6702
+ }
6499
6703
  function hasToolResponseRecoveryReference(messages, executionId) {
6500
6704
  if (!Array.isArray(messages) || messages.length === 0) {
6501
6705
  return false;
@@ -6504,7 +6708,10 @@ function hasToolResponseRecoveryReference(messages, executionId) {
6504
6708
  if (message?.role === "system") {
6505
6709
  return false;
6506
6710
  }
6507
- const content = flattenRecoveryContent(message?.content);
6711
+ const content = [
6712
+ flattenRecoveryContent(message?.content),
6713
+ flattenToolCallArguments(message)
6714
+ ].filter(Boolean).join("\n");
6508
6715
  if (!content) {
6509
6716
  return false;
6510
6717
  }
@@ -6684,12 +6891,15 @@ function createManageTodoTool(stateRef) {
6684
6891
  function createGetToolResponseTool(stateRef) {
6685
6892
  const getTool = createTool({
6686
6893
  name: "get_tool_response",
6687
- description: "RETRIEVE the full output of a tool execution whose response was archived, dropped, truncated, or later compacted in conversation history. This tool is only useful when the visible transcript already shows a reduced tool-response marker for the referenced executionId or tool_call_id. Use it only when a marker such as 'ARCHIVED_TOOL_RESPONSE', 'STRUCTURED_TOOL_RESPONSE', 'SUMMARIZED_TOOL_RESPONSE', 'DROPPED_TOOL_RESPONSE', or an explicit truncation note points you to a missing field you still need. Do not call it to re-fetch a normal tool result that is already present in context.",
6688
- schema: zod.z.object({ executionId: zod.z.string().describe("Tool execution id or original tool_call_id") }),
6894
+ description: `RETRIEVE the full input or output of a tool execution that was reduced in conversation history. This tool is only useful when the visible transcript already shows a reduced marker for the referenced executionId or tool_call_id. Use it when a marker such as 'ARCHIVED_TOOL_RESPONSE', 'STRUCTURED_TOOL_RESPONSE', 'SUMMARIZED_TOOL_RESPONSE', 'DROPPED_TOOL_RESPONSE', an explicit truncation note, or a '__digest' descriptor inside a past tool call's arguments points you to something you still need. Pass part="input" to recover arguments that were digested (their small fields are still visible; only the large payload was replaced), or part="output" (the default) to recover an archived result. Do not call it to re-fetch a normal tool result that is already present in context.`,
6895
+ schema: zod.z.object({
6896
+ executionId: zod.z.string().describe("Tool execution id or original tool_call_id"),
6897
+ part: zod.z.enum(["input", "output"]).optional().describe('Which side of the exchange to recover. Defaults to "output".')
6898
+ }),
6689
6899
  maxExecutionsPerRun: 8,
6690
- func: async ({ executionId }) => {
6900
+ func: async ({ executionId, part }) => {
6691
6901
  if (!hasToolResponseRecoveryReference(stateRef.messages, executionId)) {
6692
- return "Execution not recoverable from the visible transcript. Use this only when the conversation already shows a reduced tool-response marker for that executionId.";
6902
+ return "Execution not recoverable from the visible transcript. Use this only when the conversation already shows a reduced tool-response or __digest marker for that executionId.";
6693
6903
  }
6694
6904
  const matchesExecution = (t) => t?.executionId === executionId || t?.tool_call_id === executionId;
6695
6905
  let execution = stateRef.toolHistory?.find((t) => matchesExecution(t));
@@ -6697,6 +6907,9 @@ function createGetToolResponseTool(stateRef) {
6697
6907
  execution = stateRef.toolHistoryArchived?.find((t) => matchesExecution(t));
6698
6908
  }
6699
6909
  if (execution) {
6910
+ if (part === "input") {
6911
+ return execution.args ?? "Arguments were not recorded for this execution.";
6912
+ }
6700
6913
  return execution.rawOutput || execution.output;
6701
6914
  }
6702
6915
  const ccrStore = stateRef.ctx?.__contextPilot?.ccrStore;
@@ -11036,10 +11249,14 @@ exports.BaseProvider = BaseProvider;
11036
11249
  exports.BedrockProvider = BedrockProvider;
11037
11250
  exports.CCRStore = CCRStore;
11038
11251
  exports.CONTEXT_PILOT_JSON_MARKER_KEY = CONTEXT_PILOT_JSON_MARKER_KEY;
11252
+ exports.CONTROL_PLANE_TOOL_NAMES = CONTROL_PLANE_TOOL_NAMES;
11253
+ exports.DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS = DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS;
11039
11254
  exports.DEFAULT_PROFILE_CONFIGS = DEFAULT_PROFILE_CONFIGS;
11040
11255
  exports.DEFAULT_SKILL_POLICY = DEFAULT_SKILL_POLICY;
11041
11256
  exports.DEFAULT_SUBAGENT_POLICY = DEFAULT_SUBAGENT_POLICY;
11042
11257
  exports.DEFAULT_SUBAGENT_TOOL_NAMES = DEFAULT_SUBAGENT_TOOL_NAMES;
11258
+ exports.DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS = DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS;
11259
+ exports.DELEGATION_TOOL_NAMES = DELEGATION_TOOL_NAMES;
11043
11260
  exports.DedupTracker = DedupTracker;
11044
11261
  exports.GuardrailPhase = GuardrailPhase;
11045
11262
  exports.InMemoryMemoryStore = InMemoryMemoryStore;
@@ -11049,6 +11266,7 @@ exports.OpenAIProvider = OpenAIProvider;
11049
11266
  exports.ProviderError = ProviderError;
11050
11267
  exports.SMALL_TIER_SKILL_POLICY = SMALL_TIER_SKILL_POLICY;
11051
11268
  exports.StructuredOutputManager = StructuredOutputManager;
11269
+ exports.TOOL_INPUT_DIGEST_KEY = TOOL_INPUT_DIGEST_KEY;
11052
11270
  exports.ToolBasedStrategy = ToolBasedStrategy;
11053
11271
  exports.VertexProvider = VertexProvider;
11054
11272
  exports.agentVerdictRule = agentVerdictRule;
@@ -11061,6 +11279,7 @@ exports.canSpawn = canSpawn;
11061
11279
  exports.captureSnapshot = captureSnapshot;
11062
11280
  exports.codePresenceRule = codePresenceRule;
11063
11281
  exports.cognipeerSink = cognipeerSink;
11282
+ exports.collectToolRetentionDeclarations = collectToolRetentionDeclarations;
11064
11283
  exports.composeToolSets = composeToolSets;
11065
11284
  exports.compressDiffOutput = compressDiffOutput;
11066
11285
  exports.compressJsonOutput = compressJsonOutput;
@@ -11104,6 +11323,8 @@ exports.dedupeToolsByName = dedupeToolsByName;
11104
11323
  exports.defaultTokenCounter = defaultTokenCounter;
11105
11324
  exports.detectTextFormat = detectTextFormat;
11106
11325
  exports.detectVolatileContent = detectVolatileContent;
11326
+ exports.digestToolInputArguments = digestToolInputArguments;
11327
+ exports.digestToolInputValue = digestToolInputValue;
11107
11328
  exports.emptyUsage = emptyUsage;
11108
11329
  exports.evaluateGuardrails = evaluateGuardrails;
11109
11330
  exports.extractLatestUserQuery = extractLatestUserQuery;
@@ -11131,10 +11352,12 @@ exports.readMemoryFacts = readMemoryFacts;
11131
11352
  exports.regexRule = regexRule;
11132
11353
  exports.resolveAvailableSkills = resolveAvailableSkills;
11133
11354
  exports.resolveAvailableSubagents = resolveAvailableSubagents;
11355
+ exports.resolveInputRetention = resolveInputRetention;
11134
11356
  exports.resolveMemoryStore = resolveMemoryStore;
11135
11357
  exports.resolveReasoning = resolveReasoning;
11136
11358
  exports.resolveStrategy = resolveStrategy;
11137
11359
  exports.resolveSubagentTools = resolveSubagentTools;
11360
+ exports.resolveSummarizationRetention = resolveSummarizationRetention;
11138
11361
  exports.resolveToolApprovalState = resolveToolApprovalState;
11139
11362
  exports.resolveUserQuestionState = resolveUserQuestionState;
11140
11363
  exports.restoreSnapshot = restoreSnapshot;
@@ -11145,6 +11368,7 @@ exports.seedChildMessages = seedChildMessages;
11145
11368
  exports.selectTopIndicesInOrder = selectTopIndicesInOrder;
11146
11369
  exports.setTokenCounter = setTokenCounter;
11147
11370
  exports.startStreamingSession = startStreamingSession;
11371
+ exports.summarizeObject = summarizeObject;
11148
11372
  exports.tokenize = tokenize;
11149
11373
  exports.traceSessionToOtlp = traceSessionToOtlp;
11150
11374
  exports.validateReasoningConfig = validateReasoningConfig;