@cognipeer/agent-sdk 0.8.6 → 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;
@@ -808,28 +812,6 @@ function normalizeUsage(raw) {
808
812
  };
809
813
  return normalized;
810
814
  }
811
- function recordUsage(state, modelName, normalized) {
812
- const usageState = state.usage || { perRequest: [], totals: {} };
813
- const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
814
- const cachedInput = normalized.prompt_tokens_details?.cached_tokens;
815
- usageState.perRequest.push({
816
- id,
817
- modelName,
818
- usage: normalized,
819
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
820
- turn: usageState.perRequest.length + 1,
821
- cachedInput
822
- });
823
- const previous = usageState.totals[modelName] || { input: 0, output: 0, total: 0, cachedInput: 0 };
824
- usageState.totals[modelName] = {
825
- input: previous.input + (Number(normalized.prompt_tokens) || 0),
826
- output: previous.output + (Number(normalized.completion_tokens) || 0),
827
- total: previous.total + (Number(normalized.total_tokens) || 0),
828
- cachedInput: previous.cachedInput + (Number(cachedInput) || 0)
829
- };
830
- state.usage = usageState;
831
- return id;
832
- }
833
815
  function num(...vals) {
834
816
  for (const v of vals) {
835
817
  if (v === 0) return 0;
@@ -1972,6 +1954,270 @@ function estimatePayloadBytes(value) {
1972
1954
  }
1973
1955
  }
1974
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
+
1975
2221
  // src/smart/runtimeConfig.ts
1976
2222
  var DEFAULT_CRITICAL_TOOLS = ["response", "manage_todo_list", "get_tool_response"];
1977
2223
  var BASE_DEFAULTS = {
@@ -2022,6 +2268,11 @@ var BASE_DEFAULTS = {
2022
2268
  maxToolResponseTokens: 8e3,
2023
2269
  defaultPolicy: "summarize_archive",
2024
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,
2025
2276
  criticalTools: [...DEFAULT_CRITICAL_TOOLS],
2026
2277
  schemaValidation: "strict"
2027
2278
  },
@@ -2076,7 +2327,8 @@ function buildProfile(overrides) {
2076
2327
  ...BASE_DEFAULTS.toolResponses,
2077
2328
  ...overrides.toolResponses,
2078
2329
  criticalTools: overrides.toolResponses?.criticalTools ?? [...DEFAULT_CRITICAL_TOOLS],
2079
- toolResponseRetentionByTool: overrides.toolResponses?.toolResponseRetentionByTool ?? {}
2330
+ toolResponseRetentionByTool: overrides.toolResponses?.toolResponseRetentionByTool ?? {},
2331
+ retentionByTool: overrides.toolResponses?.retentionByTool ?? {}
2080
2332
  },
2081
2333
  contextPilot: mergeContextPilot(BASE_DEFAULTS.contextPilot, overrides.contextPilot)
2082
2334
  };
@@ -2230,6 +2482,14 @@ function normalizeSmartAgentOptions(opts) {
2230
2482
  ...customProfile.toolResponses?.toolResponseRetentionByTool || {},
2231
2483
  ...opts.toolResponses?.toolResponseRetentionByTool || {}
2232
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,
2233
2493
  criticalTools: opts.toolResponses?.criticalTools ?? customProfile.toolResponses?.criticalTools ?? preset.toolResponses.criticalTools
2234
2494
  },
2235
2495
  contextPilot: mergeContextPilot(mergeContextPilot(preset.contextPilot, customProfile.contextPilot), opts.contextPilot)
@@ -2414,53 +2674,6 @@ function detectVolatileContent(text, limit = 20) {
2414
2674
 
2415
2675
  // src/smart/contextPilot/jsonCrusher.ts
2416
2676
  init_utilTokens();
2417
-
2418
- // src/utils/content.ts
2419
- function contentToString(content) {
2420
- try {
2421
- if (content == null) return "";
2422
- if (typeof content === "string") return content;
2423
- if (Array.isArray(content)) {
2424
- return content.map((p) => {
2425
- if (!p || typeof p !== "object") return String(p);
2426
- if (p.type === "text") return String(p.text ?? "");
2427
- if (p.type === "image_url") {
2428
- const img = p.image_url;
2429
- const url = typeof img === "string" ? img : img?.url;
2430
- const detail = typeof img === "string" ? void 0 : img?.detail;
2431
- return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
2432
- }
2433
- return JSON.stringify(p);
2434
- }).join("\n");
2435
- }
2436
- return JSON.stringify(content);
2437
- } catch {
2438
- return String(content);
2439
- }
2440
- }
2441
- function mergeContentsToString(contents) {
2442
- return contents.map((c) => contentToString(c)).join("\n");
2443
- }
2444
- function safeStringify(value, pretty = false) {
2445
- if (value == null) return "";
2446
- if (typeof value === "string") return value;
2447
- try {
2448
- return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
2449
- } catch {
2450
- return String(value);
2451
- }
2452
- }
2453
- function extractMessageText2(message) {
2454
- if (!message) return "";
2455
- const content = message.content;
2456
- if (typeof content === "string") return content;
2457
- if (Array.isArray(content)) {
2458
- return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
2459
- }
2460
- return "";
2461
- }
2462
-
2463
- // src/smart/contextPilot/jsonCrusher.ts
2464
2677
  var CONTEXT_PILOT_JSON_MARKER_KEY = "__contextPilotDropped";
2465
2678
  function findCompressibleArray(output, minItems) {
2466
2679
  if (Array.isArray(output)) {
@@ -2968,7 +3181,24 @@ function createAgentCoreNode(opts) {
2968
3181
  messageList: messagesWithResponse
2969
3182
  });
2970
3183
  if (normalized) {
2971
- recordUsage(state, modelName, normalized);
3184
+ const usageState = state.usage || { perRequest: [], totals: {} };
3185
+ const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
3186
+ const turn = usageState.perRequest.length + 1;
3187
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3188
+ const cachedInputTok = normalized.prompt_tokens_details?.cached_tokens;
3189
+ usageState.perRequest.push({ id, modelName, usage: normalized, timestamp, turn, cachedInput: cachedInputTok });
3190
+ const inputTok = normalized.prompt_tokens;
3191
+ const outputTok = normalized.completion_tokens;
3192
+ const totalTok = normalized.total_tokens;
3193
+ const key = modelName;
3194
+ const agg = usageState.totals[key] || { input: 0, output: 0, total: 0, cachedInput: 0 };
3195
+ usageState.totals[key] = {
3196
+ input: agg.input + (Number(inputTok) || 0),
3197
+ output: agg.output + (Number(outputTok) || 0),
3198
+ total: agg.total + (Number(totalTok) || 0),
3199
+ cachedInput: agg.cachedInput + (Number(cachedInputTok) || 0)
3200
+ };
3201
+ state.usage = usageState;
2972
3202
  }
2973
3203
  return { messages: messagesWithResponse, usage: state.usage };
2974
3204
  };
@@ -3012,100 +3242,6 @@ function extractToolItems(output) {
3012
3242
  });
3013
3243
  }
3014
3244
 
3015
- // src/smart/toolResponses.ts
3016
- init_utilTokens();
3017
- function summarizeObject(value) {
3018
- if (value == null) return "null";
3019
- if (typeof value === "string") {
3020
- return value.length > 240 ? `${value.slice(0, 240)}...` : value;
3021
- }
3022
- if (Array.isArray(value)) {
3023
- const preview = value.slice(0, 3).map((entry) => safeStringify(entry).slice(0, 120)).join(" | ");
3024
- return `array(length=${value.length}) ${preview}`.trim();
3025
- }
3026
- if (typeof value === "object") {
3027
- const keys = Object.keys(value);
3028
- const preview = keys.slice(0, 6).map((key) => `${key}=${safeStringify(value[key]).slice(0, 80)}`).join("; ");
3029
- return `object(keys=${keys.length}) ${preview}`.trim();
3030
- }
3031
- return safeStringify(value);
3032
- }
3033
- function classifyToolResponse(toolName, output, config) {
3034
- const criticalTools = new Set(config.toolResponses.criticalTools);
3035
- if (criticalTools.has(toolName)) return "critical";
3036
- const serialized = safeStringify(output);
3037
- const tokenCount = countApproxTokens(serialized);
3038
- if (tokenCount >= config.toolResponses.maxToolResponseTokens || serialized.length >= config.toolResponses.maxToolResponseChars) {
3039
- return "verbose";
3040
- }
3041
- return "informative";
3042
- }
3043
- function applyToolResponseHardCap(toolName, output, executionId, config) {
3044
- const serialized = safeStringify(output);
3045
- const tokenCount = countApproxTokens(serialized);
3046
- const classification = classifyToolResponse(toolName, output, config);
3047
- if (classification !== "verbose") {
3048
- return { classification, content: serialized, rawOutput: output, tokenCount, truncated: false };
3049
- }
3050
- const cap = config.toolResponses.maxToolResponseChars;
3051
- const head = serialized.slice(0, cap);
3052
- const note = `
3053
- ... [TRUNCATED ${serialized.length - cap} chars by hard cap. Use get_tool_response with executionId="${executionId}" to fetch the full payload.]`;
3054
- return {
3055
- classification,
3056
- content: head + note,
3057
- rawOutput: output,
3058
- tokenCount,
3059
- truncated: true
3060
- };
3061
- }
3062
- function resolveSummarizationRetention(toolName, config) {
3063
- const criticalTools = new Set(config.toolResponses.criticalTools);
3064
- if (criticalTools.has(toolName)) return "keep_full";
3065
- const byTool = config.toolResponses.toolResponseRetentionByTool[toolName];
3066
- return byTool || config.toolResponses.defaultPolicy;
3067
- }
3068
- function renderRetainedToolMessage(args) {
3069
- const { policy, rawOutput, toolName, toolCallId, executionId, prebuiltSummary } = args;
3070
- if (policy === "keep_full") {
3071
- return typeof rawOutput === "string" ? rawOutput : safeStringify(rawOutput);
3072
- }
3073
- const summary = prebuiltSummary || summarizeObject(rawOutput);
3074
- const refs = [
3075
- `toolName=${toolName}`,
3076
- toolCallId ? `toolCallId=${toolCallId}` : null,
3077
- executionId ? `executionId=${executionId}` : null
3078
- ].filter(Boolean).join("; ");
3079
- const refId = executionId || toolCallId || "";
3080
- if (policy === "keep_structured") {
3081
- return `STRUCTURED_TOOL_RESPONSE [${refs}]
3082
- Preview: ${summary}
3083
- Use get_tool_response with executionId "${refId}" to fetch the full payload when a specific field is needed.`;
3084
- }
3085
- if (policy === "summarize_archive") {
3086
- return `ARCHIVED_TOOL_RESPONSE [${refs}]
3087
- Summary: ${summary}
3088
- Use get_tool_response with executionId "${refId}" to fetch the full payload.`;
3089
- }
3090
- return `DROPPED_TOOL_RESPONSE [${refs}]
3091
- Use get_tool_response with executionId "${refId}" only if you must recover the original payload.`;
3092
- }
3093
- function validateToolArgs(tool, args) {
3094
- const schema = tool.schema;
3095
- if (!schema || typeof schema.parse !== "function") {
3096
- return { ok: true, value: args };
3097
- }
3098
- try {
3099
- return { ok: true, value: schema.parse(args) };
3100
- } catch (error) {
3101
- if (error instanceof zod.ZodError) {
3102
- const message = error.issues.map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
3103
- return { ok: false, message };
3104
- }
3105
- return { ok: false, message: error instanceof Error ? error.message : String(error) };
3106
- }
3107
- }
3108
-
3109
3245
  // src/utils/pendingToolCalls.ts
3110
3246
  function selectPendingToolCalls(messages) {
3111
3247
  if (!Array.isArray(messages) || messages.length === 0) return [];
@@ -5362,7 +5498,10 @@ function createAgent(opts) {
5362
5498
  }
5363
5499
  }
5364
5500
  }
5365
- 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) {
5366
5505
  const lastForParse = state.messages[state.messages.length - 1];
5367
5506
  if (lastForParse?.role === "assistant") {
5368
5507
  const assistantText = extractMessageText2(lastForParse);
@@ -5379,10 +5518,11 @@ function createAgent(opts) {
5379
5518
  }
5380
5519
  }
5381
5520
  }
5382
- if (soManager && soManager.strategy.kind === "tool_based" && !state.ctx?.__finalizedDueToStructuredOutput) {
5521
+ if (soManager && soManager.strategy.kind === "tool_based" && !state.ctx?.__finalizedDueToStructuredOutput && !structuredFinalizeBlocked) {
5383
5522
  const maxPostLoopRetries = soManager.maxRetries;
5384
5523
  for (let postRetry = 0; postRetry < maxPostLoopRetries; postRetry++) {
5385
5524
  if (state.ctx?.__finalizedDueToStructuredOutput) break;
5525
+ if (state.ctx?.__awaitingApproval || state.ctx?.__awaitingUserQuestion || state.ctx?.__cancelled || state.ctx?.__limitBreached) break;
5386
5526
  const last = state.messages[state.messages.length - 1];
5387
5527
  const lastHasToolCalls = Array.isArray(last?.tool_calls) && last.tool_calls.length > 0;
5388
5528
  if (!lastHasToolCalls) {
@@ -5751,7 +5891,24 @@ function createAgentNode(opts) {
5751
5891
  messageList: messagesWithResponse
5752
5892
  });
5753
5893
  if (normalized) {
5754
- recordUsage(state, modelName, normalized);
5894
+ const usageState = state.usage || { perRequest: [], totals: {} };
5895
+ const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
5896
+ const turn = usageState.perRequest.length + 1;
5897
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
5898
+ const cachedInputTok = normalized.prompt_tokens_details.cached_tokens;
5899
+ usageState.perRequest.push({ id, modelName, usage: normalized, timestamp, turn, cachedInput: cachedInputTok });
5900
+ const inputTok = normalized.prompt_tokens;
5901
+ const outputTok = normalized.completion_tokens;
5902
+ const totalTok = normalized.total_tokens;
5903
+ const key = modelName;
5904
+ const agg = usageState.totals[key] || { input: 0, output: 0, total: 0, cachedInput: 0 };
5905
+ usageState.totals[key] = {
5906
+ input: agg.input + (Number(inputTok) || 0),
5907
+ output: agg.output + (Number(outputTok) || 0),
5908
+ total: agg.total + (Number(totalTok) || 0),
5909
+ cachedInput: agg.cachedInput + (Number(cachedInputTok) || 0)
5910
+ };
5911
+ state.usage = usageState;
5755
5912
  }
5756
5913
  return { messages: messagesWithResponse, usage: state.usage };
5757
5914
  };
@@ -5779,7 +5936,7 @@ function collectRecentTurns(messages, lastTurnsToKeep) {
5779
5936
  if (turnCount >= lastTurnsToKeep) break;
5780
5937
  }
5781
5938
  }
5782
- if (countAssistantTurns && collected.length > 0 && collected[0].role !== "user") {
5939
+ if (collected.length > 0) {
5783
5940
  const firstUserMsg = body.find((m) => m.role === "user");
5784
5941
  if (firstUserMsg && !collected.includes(firstUserMsg)) {
5785
5942
  collected.unshift(firstUserMsg);
@@ -5811,12 +5968,18 @@ function renderMemoryBlock(facts) {
5811
5968
  ...facts.map((fact) => `- ${fact.key}: ${fact.value}`)
5812
5969
  ].join("\n");
5813
5970
  }
5971
+ function isClampProtected(message, index, firstUserIndex) {
5972
+ if (message.role === "system") return true;
5973
+ if (index === firstUserIndex) return true;
5974
+ return false;
5975
+ }
5814
5976
  function clampToBudget(messages, maxContextTokens) {
5815
5977
  let working = [...messages];
5816
5978
  while (working.length > 2) {
5817
5979
  const tokenCount = countApproxTokens(working.map(extractMessageText2).join("\n"));
5818
5980
  if (tokenCount <= maxContextTokens) return working;
5819
- 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));
5820
5983
  if (firstNonSystem < 0) break;
5821
5984
  const target = working[firstNonSystem];
5822
5985
  if (target.role === "assistant" && Array.isArray(target.tool_calls) && target.tool_calls.length > 0) {
@@ -6195,7 +6358,6 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
6195
6358
  outputTokensActual = normalized.completion_tokens;
6196
6359
  totalTokensActual = normalized.total_tokens;
6197
6360
  cachedInputTokens = normalized.prompt_tokens_details?.cached_tokens;
6198
- recordUsage(state, getModelName(model) || "unknown_model", normalized);
6199
6361
  }
6200
6362
  } catch (err) {
6201
6363
  durationMs = Date.now() - startTime;
@@ -6255,9 +6417,42 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
6255
6417
  break;
6256
6418
  }
6257
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
+ }
6258
6431
  const archivedExecutions = [...state.toolHistoryArchived || []];
6259
6432
  const archivedIds = new Set(archivedExecutions.map((entry) => entry?.executionId).filter(Boolean));
6260
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
+ }
6261
6456
  if (m.role === "tool") {
6262
6457
  if (isSyntheticSummaryMessage(m)) {
6263
6458
  return m;
@@ -6393,7 +6588,9 @@ var TOOL_RESPONSE_RECOVERY_MARKERS = [
6393
6588
  /STRUCTURED_TOOL_RESPONSE\s*\[/,
6394
6589
  /SUMMARIZED_TOOL_RESPONSE\b/,
6395
6590
  /DROPPED_TOOL_RESPONSE\s*\[/,
6396
- /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*:/
6397
6594
  ];
6398
6595
  var todoStatusSchema = zod.z.enum(["not-started", "in-progress", "completed", "blocked"]);
6399
6596
  var todoWriteItemSchema = zod.z.object({
@@ -6485,6 +6682,24 @@ function flattenRecoveryContent(content) {
6485
6682
  }
6486
6683
  return "";
6487
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
+ }
6488
6703
  function hasToolResponseRecoveryReference(messages, executionId) {
6489
6704
  if (!Array.isArray(messages) || messages.length === 0) {
6490
6705
  return false;
@@ -6493,7 +6708,10 @@ function hasToolResponseRecoveryReference(messages, executionId) {
6493
6708
  if (message?.role === "system") {
6494
6709
  return false;
6495
6710
  }
6496
- const content = flattenRecoveryContent(message?.content);
6711
+ const content = [
6712
+ flattenRecoveryContent(message?.content),
6713
+ flattenToolCallArguments(message)
6714
+ ].filter(Boolean).join("\n");
6497
6715
  if (!content) {
6498
6716
  return false;
6499
6717
  }
@@ -6673,12 +6891,15 @@ function createManageTodoTool(stateRef) {
6673
6891
  function createGetToolResponseTool(stateRef) {
6674
6892
  const getTool = createTool({
6675
6893
  name: "get_tool_response",
6676
- 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.",
6677
- 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
+ }),
6678
6899
  maxExecutionsPerRun: 8,
6679
- func: async ({ executionId }) => {
6900
+ func: async ({ executionId, part }) => {
6680
6901
  if (!hasToolResponseRecoveryReference(stateRef.messages, executionId)) {
6681
- 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.";
6682
6903
  }
6683
6904
  const matchesExecution = (t) => t?.executionId === executionId || t?.tool_call_id === executionId;
6684
6905
  let execution = stateRef.toolHistory?.find((t) => matchesExecution(t));
@@ -6686,6 +6907,9 @@ function createGetToolResponseTool(stateRef) {
6686
6907
  execution = stateRef.toolHistoryArchived?.find((t) => matchesExecution(t));
6687
6908
  }
6688
6909
  if (execution) {
6910
+ if (part === "input") {
6911
+ return execution.args ?? "Arguments were not recorded for this execution.";
6912
+ }
6689
6913
  return execution.rawOutput || execution.output;
6690
6914
  }
6691
6915
  const ccrStore = stateRef.ctx?.__contextPilot?.ccrStore;
@@ -11025,10 +11249,14 @@ exports.BaseProvider = BaseProvider;
11025
11249
  exports.BedrockProvider = BedrockProvider;
11026
11250
  exports.CCRStore = CCRStore;
11027
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;
11028
11254
  exports.DEFAULT_PROFILE_CONFIGS = DEFAULT_PROFILE_CONFIGS;
11029
11255
  exports.DEFAULT_SKILL_POLICY = DEFAULT_SKILL_POLICY;
11030
11256
  exports.DEFAULT_SUBAGENT_POLICY = DEFAULT_SUBAGENT_POLICY;
11031
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;
11032
11260
  exports.DedupTracker = DedupTracker;
11033
11261
  exports.GuardrailPhase = GuardrailPhase;
11034
11262
  exports.InMemoryMemoryStore = InMemoryMemoryStore;
@@ -11038,6 +11266,7 @@ exports.OpenAIProvider = OpenAIProvider;
11038
11266
  exports.ProviderError = ProviderError;
11039
11267
  exports.SMALL_TIER_SKILL_POLICY = SMALL_TIER_SKILL_POLICY;
11040
11268
  exports.StructuredOutputManager = StructuredOutputManager;
11269
+ exports.TOOL_INPUT_DIGEST_KEY = TOOL_INPUT_DIGEST_KEY;
11041
11270
  exports.ToolBasedStrategy = ToolBasedStrategy;
11042
11271
  exports.VertexProvider = VertexProvider;
11043
11272
  exports.agentVerdictRule = agentVerdictRule;
@@ -11050,6 +11279,7 @@ exports.canSpawn = canSpawn;
11050
11279
  exports.captureSnapshot = captureSnapshot;
11051
11280
  exports.codePresenceRule = codePresenceRule;
11052
11281
  exports.cognipeerSink = cognipeerSink;
11282
+ exports.collectToolRetentionDeclarations = collectToolRetentionDeclarations;
11053
11283
  exports.composeToolSets = composeToolSets;
11054
11284
  exports.compressDiffOutput = compressDiffOutput;
11055
11285
  exports.compressJsonOutput = compressJsonOutput;
@@ -11093,6 +11323,8 @@ exports.dedupeToolsByName = dedupeToolsByName;
11093
11323
  exports.defaultTokenCounter = defaultTokenCounter;
11094
11324
  exports.detectTextFormat = detectTextFormat;
11095
11325
  exports.detectVolatileContent = detectVolatileContent;
11326
+ exports.digestToolInputArguments = digestToolInputArguments;
11327
+ exports.digestToolInputValue = digestToolInputValue;
11096
11328
  exports.emptyUsage = emptyUsage;
11097
11329
  exports.evaluateGuardrails = evaluateGuardrails;
11098
11330
  exports.extractLatestUserQuery = extractLatestUserQuery;
@@ -11120,10 +11352,12 @@ exports.readMemoryFacts = readMemoryFacts;
11120
11352
  exports.regexRule = regexRule;
11121
11353
  exports.resolveAvailableSkills = resolveAvailableSkills;
11122
11354
  exports.resolveAvailableSubagents = resolveAvailableSubagents;
11355
+ exports.resolveInputRetention = resolveInputRetention;
11123
11356
  exports.resolveMemoryStore = resolveMemoryStore;
11124
11357
  exports.resolveReasoning = resolveReasoning;
11125
11358
  exports.resolveStrategy = resolveStrategy;
11126
11359
  exports.resolveSubagentTools = resolveSubagentTools;
11360
+ exports.resolveSummarizationRetention = resolveSummarizationRetention;
11127
11361
  exports.resolveToolApprovalState = resolveToolApprovalState;
11128
11362
  exports.resolveUserQuestionState = resolveUserQuestionState;
11129
11363
  exports.restoreSnapshot = restoreSnapshot;
@@ -11134,6 +11368,7 @@ exports.seedChildMessages = seedChildMessages;
11134
11368
  exports.selectTopIndicesInOrder = selectTopIndicesInOrder;
11135
11369
  exports.setTokenCounter = setTokenCounter;
11136
11370
  exports.startStreamingSession = startStreamingSession;
11371
+ exports.summarizeObject = summarizeObject;
11137
11372
  exports.tokenize = tokenize;
11138
11373
  exports.traceSessionToOtlp = traceSessionToOtlp;
11139
11374
  exports.validateReasoningConfig = validateReasoningConfig;