@cognipeer/agent-sdk 0.5.4 → 0.6.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/README.md +8 -14
- package/dist/index.cjs +415 -190
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +134 -22
- package/dist/index.d.ts +134 -22
- package/dist/index.mjs +416 -191
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import fs from 'fs';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { Buffer as Buffer$1 } from 'buffer';
|
|
7
7
|
import { nanoid } from 'nanoid';
|
|
8
|
-
import crypto, { createHash, createHmac } from 'crypto';
|
|
8
|
+
import crypto, { randomUUID, createHash, createHmac } from 'crypto';
|
|
9
9
|
import AjvModule from 'ajv';
|
|
10
10
|
|
|
11
11
|
// src/adapters/langchain.ts
|
|
@@ -1968,7 +1968,9 @@ function createAgentCoreNode(opts) {
|
|
|
1968
1968
|
const cancellationToken = state.ctx?.__cancellationToken;
|
|
1969
1969
|
const abortSignal = state.ctx?.__abortSignal;
|
|
1970
1970
|
const responseFormat = runtime.responseFormat;
|
|
1971
|
-
const
|
|
1971
|
+
const reasoningForCall = state.ctx?.__reasoning;
|
|
1972
|
+
const reasoningInvokeOpts = reasoningForCall ? { reasoning: reasoningForCall } : void 0;
|
|
1973
|
+
const extractText2 = (chunk) => {
|
|
1972
1974
|
if (chunk == null) return "";
|
|
1973
1975
|
if (typeof chunk === "string") return chunk;
|
|
1974
1976
|
if (typeof chunk?.content === "string") return chunk.content;
|
|
@@ -1986,7 +1988,7 @@ function createAgentCoreNode(opts) {
|
|
|
1986
1988
|
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
1987
1989
|
let streamedText = "";
|
|
1988
1990
|
let streamedMessage;
|
|
1989
|
-
const streamOptions = { signal: abortSignal, cancellationToken, ...responseFormat };
|
|
1991
|
+
const streamOptions = { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts };
|
|
1990
1992
|
for await (const chunk of modelWithTools.stream(normalizedMessages, streamOptions)) {
|
|
1991
1993
|
if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
|
|
1992
1994
|
break;
|
|
@@ -1994,7 +1996,7 @@ function createAgentCoreNode(opts) {
|
|
|
1994
1996
|
if (chunk && typeof chunk === "object" && chunk.role) {
|
|
1995
1997
|
streamedMessage = chunk;
|
|
1996
1998
|
}
|
|
1997
|
-
const text =
|
|
1999
|
+
const text = extractText2(chunk);
|
|
1998
2000
|
if (text) {
|
|
1999
2001
|
streamedText += text;
|
|
2000
2002
|
onStream?.({ text });
|
|
@@ -2010,7 +2012,7 @@ function createAgentCoreNode(opts) {
|
|
|
2010
2012
|
response = { role: "assistant", content: streamedText };
|
|
2011
2013
|
}
|
|
2012
2014
|
} else {
|
|
2013
|
-
response = await modelWithTools.invoke(normalizedMessages, { signal: abortSignal, cancellationToken, ...responseFormat });
|
|
2015
|
+
response = await modelWithTools.invoke(normalizedMessages, { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts });
|
|
2014
2016
|
}
|
|
2015
2017
|
} catch (err) {
|
|
2016
2018
|
const durationMs2 = Date.now() - start;
|
|
@@ -2126,18 +2128,13 @@ var BASE_DEFAULTS = {
|
|
|
2126
2128
|
requireJsonOutputContract: true
|
|
2127
2129
|
},
|
|
2128
2130
|
toolResponses: {
|
|
2129
|
-
maxToolResponseChars:
|
|
2130
|
-
maxToolResponseTokens:
|
|
2131
|
-
|
|
2132
|
-
smallResponsePolicy: "keep_full",
|
|
2133
|
-
defaultPolicy: "keep_structured",
|
|
2134
|
-
largeResponsePolicy: "summarize_archive",
|
|
2131
|
+
maxToolResponseChars: 12e3,
|
|
2132
|
+
maxToolResponseTokens: 3e3,
|
|
2133
|
+
defaultPolicy: "summarize_archive",
|
|
2135
2134
|
toolResponseRetentionByTool: {},
|
|
2136
2135
|
criticalTools: [...DEFAULT_CRITICAL_TOOLS],
|
|
2137
2136
|
schemaValidation: "strict",
|
|
2138
|
-
retryOnSchemaError: true
|
|
2139
|
-
fallbackPolicy: "keep_full",
|
|
2140
|
-
keepRecentFullCount: 0
|
|
2137
|
+
retryOnSchemaError: true
|
|
2141
2138
|
}
|
|
2142
2139
|
};
|
|
2143
2140
|
function buildProfile(overrides) {
|
|
@@ -2176,7 +2173,7 @@ var DEFAULT_PROFILE_CONFIGS = {
|
|
|
2176
2173
|
},
|
|
2177
2174
|
memory: { readPolicy: "recent_only" },
|
|
2178
2175
|
delegation: { mode: "off", maxDelegationDepth: 1, maxChildCalls: 2, maxParallelChild: 1, childContextPolicy: "minimal" },
|
|
2179
|
-
toolResponses: { maxToolResponseChars:
|
|
2176
|
+
toolResponses: { maxToolResponseChars: 8e3, maxToolResponseTokens: 2e3 }
|
|
2180
2177
|
}),
|
|
2181
2178
|
balanced: buildProfile({}),
|
|
2182
2179
|
deep: buildProfile({
|
|
@@ -2193,7 +2190,7 @@ var DEFAULT_PROFILE_CONFIGS = {
|
|
|
2193
2190
|
},
|
|
2194
2191
|
memory: { scope: "workspace" },
|
|
2195
2192
|
delegation: { maxDelegationDepth: 3, maxChildCalls: 6 },
|
|
2196
|
-
toolResponses: { maxToolResponseChars:
|
|
2193
|
+
toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 }
|
|
2197
2194
|
}),
|
|
2198
2195
|
research: buildProfile({
|
|
2199
2196
|
limits: { maxToolCalls: 20, maxParallelTools: 4, maxContextTokens: 56e3 },
|
|
@@ -2209,7 +2206,7 @@ var DEFAULT_PROFILE_CONFIGS = {
|
|
|
2209
2206
|
},
|
|
2210
2207
|
memory: { scope: "workspace" },
|
|
2211
2208
|
delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 8, maxParallelChild: 3, childContextPolicy: "full" },
|
|
2212
|
-
toolResponses: { maxToolResponseChars:
|
|
2209
|
+
toolResponses: { maxToolResponseChars: 24e3, maxToolResponseTokens: 6e3 }
|
|
2213
2210
|
})
|
|
2214
2211
|
};
|
|
2215
2212
|
function mergeLimits(base, override) {
|
|
@@ -2416,63 +2413,65 @@ function summarizeObject(value) {
|
|
|
2416
2413
|
return safeStringify(value);
|
|
2417
2414
|
}
|
|
2418
2415
|
function classifyToolResponse(toolName, output, config) {
|
|
2419
|
-
const serialized = safeStringify(output);
|
|
2420
|
-
const tokenCount = countApproxTokens(serialized);
|
|
2421
2416
|
const criticalTools = new Set(config.toolResponses.criticalTools);
|
|
2422
2417
|
if (criticalTools.has(toolName)) return "critical";
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
}
|
|
2418
|
+
const serialized = safeStringify(output);
|
|
2419
|
+
const tokenCount = countApproxTokens(serialized);
|
|
2426
2420
|
if (tokenCount >= config.toolResponses.maxToolResponseTokens || serialized.length >= config.toolResponses.maxToolResponseChars) {
|
|
2427
2421
|
return "verbose";
|
|
2428
2422
|
}
|
|
2429
|
-
const smallChars = config.toolResponses.smallResponseChars;
|
|
2430
|
-
if (smallChars > 0 && serialized.length <= smallChars) {
|
|
2431
|
-
return "small";
|
|
2432
|
-
}
|
|
2433
2423
|
return "informative";
|
|
2434
2424
|
}
|
|
2435
|
-
function
|
|
2425
|
+
function applyToolResponseHardCap(toolName, output, executionId, config) {
|
|
2436
2426
|
const serialized = safeStringify(output);
|
|
2437
2427
|
const tokenCount = countApproxTokens(serialized);
|
|
2438
2428
|
const classification = classifyToolResponse(toolName, output, config);
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
if (byTool) ; else if (classification === "critical") {
|
|
2442
|
-
retentionPolicy = config.toolResponses.fallbackPolicy;
|
|
2443
|
-
} else if (classification === "verbose") {
|
|
2444
|
-
retentionPolicy = config.toolResponses.largeResponsePolicy;
|
|
2445
|
-
} else if (classification === "small") {
|
|
2446
|
-
retentionPolicy = config.toolResponses.smallResponsePolicy;
|
|
2447
|
-
} else if (classification === "redundant") {
|
|
2448
|
-
retentionPolicy = "drop";
|
|
2449
|
-
}
|
|
2450
|
-
const summary = summarizeObject(output);
|
|
2451
|
-
if (retentionPolicy === "keep_full") {
|
|
2452
|
-
return { classification, retentionPolicy, content: serialized, rawOutput: output, summary, tokenCount };
|
|
2453
|
-
}
|
|
2454
|
-
if (retentionPolicy === "keep_structured") {
|
|
2455
|
-
return { classification, retentionPolicy, content: summary, rawOutput: output, summary, tokenCount };
|
|
2456
|
-
}
|
|
2457
|
-
if (retentionPolicy === "summarize_archive") {
|
|
2458
|
-
return {
|
|
2459
|
-
classification,
|
|
2460
|
-
retentionPolicy,
|
|
2461
|
-
content: `ARCHIVED_TOOL_RESPONSE: ${summary}`,
|
|
2462
|
-
rawOutput: output,
|
|
2463
|
-
summary,
|
|
2464
|
-
tokenCount
|
|
2465
|
-
};
|
|
2429
|
+
if (classification !== "verbose") {
|
|
2430
|
+
return { classification, content: serialized, rawOutput: output, tokenCount, truncated: false };
|
|
2466
2431
|
}
|
|
2432
|
+
const cap = config.toolResponses.maxToolResponseChars;
|
|
2433
|
+
const head = serialized.slice(0, cap);
|
|
2434
|
+
const note = `
|
|
2435
|
+
... [TRUNCATED ${serialized.length - cap} chars by hard cap. Use get_tool_response with executionId="${executionId}" to fetch the full payload.]`;
|
|
2467
2436
|
return {
|
|
2468
2437
|
classification,
|
|
2469
|
-
|
|
2470
|
-
content: `DROPPED_TOOL_RESPONSE: ${summary}`,
|
|
2438
|
+
content: head + note,
|
|
2471
2439
|
rawOutput: output,
|
|
2472
|
-
|
|
2473
|
-
|
|
2440
|
+
tokenCount,
|
|
2441
|
+
truncated: true
|
|
2474
2442
|
};
|
|
2475
2443
|
}
|
|
2444
|
+
function resolveSummarizationRetention(toolName, config) {
|
|
2445
|
+
const criticalTools = new Set(config.toolResponses.criticalTools);
|
|
2446
|
+
if (criticalTools.has(toolName)) return "keep_full";
|
|
2447
|
+
const byTool = config.toolResponses.toolResponseRetentionByTool[toolName];
|
|
2448
|
+
return byTool || config.toolResponses.defaultPolicy;
|
|
2449
|
+
}
|
|
2450
|
+
function renderRetainedToolMessage(args) {
|
|
2451
|
+
const { policy, rawOutput, toolName, toolCallId, executionId, prebuiltSummary } = args;
|
|
2452
|
+
if (policy === "keep_full") {
|
|
2453
|
+
return typeof rawOutput === "string" ? rawOutput : safeStringify(rawOutput);
|
|
2454
|
+
}
|
|
2455
|
+
const summary = prebuiltSummary || summarizeObject(rawOutput);
|
|
2456
|
+
const refs = [
|
|
2457
|
+
`toolName=${toolName}`,
|
|
2458
|
+
toolCallId ? `toolCallId=${toolCallId}` : null,
|
|
2459
|
+
executionId ? `executionId=${executionId}` : null
|
|
2460
|
+
].filter(Boolean).join("; ");
|
|
2461
|
+
const refId = executionId || toolCallId || "";
|
|
2462
|
+
if (policy === "keep_structured") {
|
|
2463
|
+
return `STRUCTURED_TOOL_RESPONSE [${refs}]
|
|
2464
|
+
Preview: ${summary}
|
|
2465
|
+
Use get_tool_response with executionId "${refId}" to fetch the full payload when a specific field is needed.`;
|
|
2466
|
+
}
|
|
2467
|
+
if (policy === "summarize_archive") {
|
|
2468
|
+
return `ARCHIVED_TOOL_RESPONSE [${refs}]
|
|
2469
|
+
Summary: ${summary}
|
|
2470
|
+
Use get_tool_response with executionId "${refId}" to fetch the full payload.`;
|
|
2471
|
+
}
|
|
2472
|
+
return `DROPPED_TOOL_RESPONSE [${refs}]
|
|
2473
|
+
Use get_tool_response with executionId "${refId}" only if you must recover the original payload.`;
|
|
2474
|
+
}
|
|
2476
2475
|
function validateToolArgs(tool, args) {
|
|
2477
2476
|
const schema = tool.schema;
|
|
2478
2477
|
if (!schema || typeof schema.parse !== "function") {
|
|
@@ -2751,52 +2750,25 @@ function createToolsNode(initialTools, opts) {
|
|
|
2751
2750
|
state.ctx.__structuredOutputParsed = output.data;
|
|
2752
2751
|
state.ctx.__finalizedDueToStructuredOutput = true;
|
|
2753
2752
|
}
|
|
2754
|
-
const responsePolicy =
|
|
2753
|
+
const responsePolicy = applyToolResponseHardCap(toolName, output, executionId, resolved);
|
|
2755
2754
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2756
|
-
const storedOutput = responsePolicy.retentionPolicy === "keep_full" ? output : responsePolicy.summary;
|
|
2757
2755
|
toolHistory.push({
|
|
2758
2756
|
executionId,
|
|
2759
2757
|
toolName,
|
|
2760
2758
|
args,
|
|
2761
|
-
output
|
|
2759
|
+
output,
|
|
2762
2760
|
rawOutput: output,
|
|
2763
2761
|
timestamp,
|
|
2764
2762
|
tool_call_id: tc.id,
|
|
2765
|
-
summarized:
|
|
2763
|
+
summarized: false,
|
|
2766
2764
|
originalTokenCount: responsePolicy.tokenCount,
|
|
2767
2765
|
classification: responsePolicy.classification,
|
|
2768
|
-
retentionPolicy:
|
|
2769
|
-
summary:
|
|
2770
|
-
archiveId:
|
|
2766
|
+
retentionPolicy: "keep_full",
|
|
2767
|
+
summary: void 0,
|
|
2768
|
+
archiveId: void 0,
|
|
2771
2769
|
status: "success"
|
|
2772
2770
|
});
|
|
2773
|
-
|
|
2774
|
-
toolHistoryArchived.push({
|
|
2775
|
-
executionId,
|
|
2776
|
-
toolName,
|
|
2777
|
-
args,
|
|
2778
|
-
output,
|
|
2779
|
-
rawOutput: output,
|
|
2780
|
-
timestamp,
|
|
2781
|
-
tool_call_id: tc.id,
|
|
2782
|
-
summarized: true,
|
|
2783
|
-
originalTokenCount: responsePolicy.tokenCount,
|
|
2784
|
-
classification: responsePolicy.classification,
|
|
2785
|
-
retentionPolicy: responsePolicy.retentionPolicy,
|
|
2786
|
-
summary: responsePolicy.summary,
|
|
2787
|
-
archiveId: executionId,
|
|
2788
|
-
status: "success"
|
|
2789
|
-
});
|
|
2790
|
-
}
|
|
2791
|
-
let toolMessageContent = responsePolicy.content;
|
|
2792
|
-
if (responsePolicy.retentionPolicy === "summarize_archive") {
|
|
2793
|
-
toolMessageContent = `ARCHIVED_TOOL_RESPONSE [executionId=${executionId}]: ${responsePolicy.summary}
|
|
2794
|
-
Only use get_tool_response with executionId "${executionId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
2795
|
-
} else if (responsePolicy.retentionPolicy === "drop") {
|
|
2796
|
-
toolMessageContent = `DROPPED_TOOL_RESPONSE [executionId=${executionId}]: ${responsePolicy.summary}
|
|
2797
|
-
Only use get_tool_response with executionId "${executionId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
2798
|
-
}
|
|
2799
|
-
appended.push({ role: "tool", content: toolMessageContent, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
|
|
2771
|
+
appended.push({ role: "tool", content: responsePolicy.content, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
|
|
2800
2772
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: output, durationMs });
|
|
2801
2773
|
onProgress?.({ stage: "tools", message: `Tool ${tc.name} completed`, detail: { durationMs } });
|
|
2802
2774
|
if (needsApproval && approvalEntry) {
|
|
@@ -2840,8 +2812,9 @@ Only use get_tool_response with executionId "${executionId}" if this summary is
|
|
|
2840
2812
|
messageList,
|
|
2841
2813
|
debug: {
|
|
2842
2814
|
classification: responsePolicy.classification,
|
|
2843
|
-
retentionPolicy:
|
|
2844
|
-
originalTokenCount: responsePolicy.tokenCount
|
|
2815
|
+
retentionPolicy: "keep_full",
|
|
2816
|
+
originalTokenCount: responsePolicy.tokenCount,
|
|
2817
|
+
truncated: responsePolicy.truncated
|
|
2845
2818
|
}
|
|
2846
2819
|
});
|
|
2847
2820
|
toolCount += 1;
|
|
@@ -2958,6 +2931,246 @@ function createToolLimitFinalizeNode(_opts) {
|
|
|
2958
2931
|
return { messages: [...state.messages, notice], ctx };
|
|
2959
2932
|
};
|
|
2960
2933
|
}
|
|
2934
|
+
var REFLECTION_SYSTEM_NAME = "agent_reflection";
|
|
2935
|
+
var REFLECTION_ASK_NAME = "agent_reflection_ask";
|
|
2936
|
+
var DEFAULT_REFLECT_PROMPT = `Reflect briefly \u2014 plain text, no JSON, no tool calls.
|
|
2937
|
+
Structure your note (1\u20132 sentences each):
|
|
2938
|
+
1) What the latest tool results actually tell us (facts, surprises).
|
|
2939
|
+
2) What is still missing or uncertain before we can finish the user's task.
|
|
2940
|
+
3) The single next step you plan to take, and why that step over alternatives.
|
|
2941
|
+
Be concrete. Do not repeat the task description. Do not apologize. Max ${"${maxChars}"} characters total.`;
|
|
2942
|
+
function trimToChars(text, maxChars) {
|
|
2943
|
+
if (text.length <= maxChars) return text;
|
|
2944
|
+
return text.slice(0, maxChars - 1).trimEnd() + "\u2026";
|
|
2945
|
+
}
|
|
2946
|
+
function countToolCallsInLastTurn(state) {
|
|
2947
|
+
const ids = [];
|
|
2948
|
+
const names = [];
|
|
2949
|
+
for (let i = state.messages.length - 1; i >= 0; i--) {
|
|
2950
|
+
const m = state.messages[i];
|
|
2951
|
+
if (m?.role === "tool") {
|
|
2952
|
+
if (m.tool_call_id) ids.push(m.tool_call_id);
|
|
2953
|
+
if (m.name) names.push(m.name);
|
|
2954
|
+
} else if (m?.role === "assistant") {
|
|
2955
|
+
break;
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
return { ids, names };
|
|
2959
|
+
}
|
|
2960
|
+
function stripReflectionAskMessages(messages) {
|
|
2961
|
+
return messages.filter((m) => !(m?.role === "user" && m?.name === REFLECTION_ASK_NAME));
|
|
2962
|
+
}
|
|
2963
|
+
function shouldRunReflection(cadence, state, ranToolsThisTurn) {
|
|
2964
|
+
if (cadence === "off") return false;
|
|
2965
|
+
if (cadence === "every_turn") return true;
|
|
2966
|
+
if (cadence === "after_tool") return ranToolsThisTurn;
|
|
2967
|
+
if (cadence === "on_branch") {
|
|
2968
|
+
const reflections = state.reflections || [];
|
|
2969
|
+
const lastReflectionTurn = reflections[reflections.length - 1]?.turn ?? -1;
|
|
2970
|
+
const currentTurnId = state.toolCallCount ?? 0;
|
|
2971
|
+
return currentTurnId - lastReflectionTurn >= 2;
|
|
2972
|
+
}
|
|
2973
|
+
return false;
|
|
2974
|
+
}
|
|
2975
|
+
function createReflectionNode(opts, resolved) {
|
|
2976
|
+
return async function reflectNode(state, trigger) {
|
|
2977
|
+
if (!resolved.enabled) return {};
|
|
2978
|
+
const runtime = state.agent || {
|
|
2979
|
+
model: opts.model,
|
|
2980
|
+
name: opts.name,
|
|
2981
|
+
version: opts.version
|
|
2982
|
+
};
|
|
2983
|
+
const model = runtime.model;
|
|
2984
|
+
if (!model?.invoke && !model?.stream) return {};
|
|
2985
|
+
const onEvent = state.ctx?.__onEvent;
|
|
2986
|
+
const traceSession = state.ctx?.__traceSession;
|
|
2987
|
+
const maxChars = resolved.maxChars;
|
|
2988
|
+
const promptBody = (resolved.promptTemplate || DEFAULT_REFLECT_PROMPT).replace(/\$\{maxChars\}/g, String(maxChars));
|
|
2989
|
+
const baseMessages = stripReflectionAskMessages([...state.messages]);
|
|
2990
|
+
const askMessage = {
|
|
2991
|
+
role: "user",
|
|
2992
|
+
name: REFLECTION_ASK_NAME,
|
|
2993
|
+
content: promptBody
|
|
2994
|
+
};
|
|
2995
|
+
const messagesForCall = resolved.mode === "piggyback" ? [...baseMessages, askMessage] : buildSeparateCallMessages(baseMessages, promptBody);
|
|
2996
|
+
const start = Date.now();
|
|
2997
|
+
let response;
|
|
2998
|
+
try {
|
|
2999
|
+
response = await model.invoke(messagesForCall, {
|
|
3000
|
+
// tool_choice:"none" so the model won't try to call tools during reflection
|
|
3001
|
+
tool_choice: "none",
|
|
3002
|
+
toolChoice: "none",
|
|
3003
|
+
// Override max_tokens for the reflection call. BaseChatModel passes this through
|
|
3004
|
+
// to the adapter which forwards into the provider body.
|
|
3005
|
+
max_tokens: resolved.maxTokens,
|
|
3006
|
+
maxTokens: resolved.maxTokens
|
|
3007
|
+
});
|
|
3008
|
+
} catch (err) {
|
|
3009
|
+
recordTraceEvent(traceSession, {
|
|
3010
|
+
type: "reflection",
|
|
3011
|
+
label: "Reflection error",
|
|
3012
|
+
actor: { scope: "agent", name: opts.name || "agent", role: "reflection" },
|
|
3013
|
+
status: "error",
|
|
3014
|
+
error: { message: err?.message || String(err) }
|
|
3015
|
+
});
|
|
3016
|
+
return {};
|
|
3017
|
+
}
|
|
3018
|
+
const durationMs = Date.now() - start;
|
|
3019
|
+
const rawText = extractText(response);
|
|
3020
|
+
const text = trimToChars(String(rawText ?? "").trim(), maxChars);
|
|
3021
|
+
if (!text) return {};
|
|
3022
|
+
const rawUsage = response?.usage_metadata || response?.response_metadata?.usage || response?.usage || response?.additional_kwargs?.usage;
|
|
3023
|
+
const usage = normalizeUsage(rawUsage);
|
|
3024
|
+
const { ids, names } = countToolCallsInLastTurn(state);
|
|
3025
|
+
const turn = state.toolCallCount ?? 0;
|
|
3026
|
+
const record = {
|
|
3027
|
+
id: safeRandomId(),
|
|
3028
|
+
turn,
|
|
3029
|
+
text,
|
|
3030
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3031
|
+
durationMs,
|
|
3032
|
+
anchorMessageIndex: state.messages.length,
|
|
3033
|
+
trigger,
|
|
3034
|
+
usage: usage ? {
|
|
3035
|
+
inputTokens: usage.prompt_tokens,
|
|
3036
|
+
outputTokens: usage.completion_tokens,
|
|
3037
|
+
cachedInputTokens: usage.prompt_tokens_details?.cached_tokens,
|
|
3038
|
+
totalTokens: usage.total_tokens,
|
|
3039
|
+
reasoningTokens: usage.completion_tokens_details?.reasoning_tokens
|
|
3040
|
+
} : void 0,
|
|
3041
|
+
toolCallIds: ids.length > 0 ? ids : void 0
|
|
3042
|
+
};
|
|
3043
|
+
recordTraceEvent(traceSession, {
|
|
3044
|
+
type: "reflection",
|
|
3045
|
+
label: `Reflection turn ${turn}`,
|
|
3046
|
+
actor: { scope: "agent", name: opts.name || "agent", role: "reflection" },
|
|
3047
|
+
status: "success",
|
|
3048
|
+
durationMs,
|
|
3049
|
+
inputTokens: record.usage?.inputTokens,
|
|
3050
|
+
outputTokens: record.usage?.outputTokens,
|
|
3051
|
+
cachedInputTokens: record.usage?.cachedInputTokens,
|
|
3052
|
+
totalTokens: record.usage?.totalTokens,
|
|
3053
|
+
debug: { text, toolNames: names }
|
|
3054
|
+
});
|
|
3055
|
+
if (resolved.emitEvents) {
|
|
3056
|
+
try {
|
|
3057
|
+
onEvent?.({
|
|
3058
|
+
type: "reflection",
|
|
3059
|
+
id: record.id,
|
|
3060
|
+
turn,
|
|
3061
|
+
text,
|
|
3062
|
+
trigger,
|
|
3063
|
+
durationMs,
|
|
3064
|
+
usage: record.usage,
|
|
3065
|
+
toolCallIds: record.toolCallIds
|
|
3066
|
+
});
|
|
3067
|
+
} catch (e) {
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
const nextMessages = stripReflectionAskMessages([...state.messages]);
|
|
3071
|
+
const reflections = [...state.reflections || [], record];
|
|
3072
|
+
const kept = reflections.slice(-Math.max(1, resolved.keepLast));
|
|
3073
|
+
const prunedMessages = nextMessages.filter(
|
|
3074
|
+
(m) => !(m?.role === "system" && m?.name === REFLECTION_SYSTEM_NAME)
|
|
3075
|
+
);
|
|
3076
|
+
for (const r of kept) {
|
|
3077
|
+
prunedMessages.push({
|
|
3078
|
+
role: "system",
|
|
3079
|
+
name: REFLECTION_SYSTEM_NAME,
|
|
3080
|
+
content: `<agent_reflection turn=${r.turn} at=${r.createdAt}>
|
|
3081
|
+
${r.text}
|
|
3082
|
+
</agent_reflection>`,
|
|
3083
|
+
metadata: { reflectionId: r.id, reflectionTurn: r.turn, reflectionTrigger: r.trigger }
|
|
3084
|
+
});
|
|
3085
|
+
}
|
|
3086
|
+
return { messages: prunedMessages, reflections };
|
|
3087
|
+
};
|
|
3088
|
+
}
|
|
3089
|
+
function extractText(chunk) {
|
|
3090
|
+
if (chunk == null) return "";
|
|
3091
|
+
if (typeof chunk === "string") return chunk;
|
|
3092
|
+
if (typeof chunk?.content === "string") return chunk.content;
|
|
3093
|
+
if (Array.isArray(chunk?.content)) {
|
|
3094
|
+
return chunk.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("");
|
|
3095
|
+
}
|
|
3096
|
+
if (typeof chunk?.text === "string") return chunk.text;
|
|
3097
|
+
return "";
|
|
3098
|
+
}
|
|
3099
|
+
function buildSeparateCallMessages(base, promptBody) {
|
|
3100
|
+
const systemMessages = base.filter((m) => m?.role === "system");
|
|
3101
|
+
const tail = base.slice(-8);
|
|
3102
|
+
return [
|
|
3103
|
+
...systemMessages,
|
|
3104
|
+
...tail,
|
|
3105
|
+
{ role: "user", name: REFLECTION_ASK_NAME, content: promptBody }
|
|
3106
|
+
];
|
|
3107
|
+
}
|
|
3108
|
+
function safeRandomId() {
|
|
3109
|
+
try {
|
|
3110
|
+
return randomUUID();
|
|
3111
|
+
} catch {
|
|
3112
|
+
return `r_${Math.random().toString(36).slice(2, 10)}_${Date.now().toString(36)}`;
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
// src/smart/reasoning.ts
|
|
3117
|
+
var LEVEL_DEFAULTS = {
|
|
3118
|
+
low: {
|
|
3119
|
+
native: { effort: "low" },
|
|
3120
|
+
reflection: { maxTokens: 200, maxChars: 600, cadence: "on_branch" }
|
|
3121
|
+
},
|
|
3122
|
+
medium: {
|
|
3123
|
+
native: { effort: "medium" },
|
|
3124
|
+
reflection: { maxTokens: 350, maxChars: 1200, cadence: "after_tool" }
|
|
3125
|
+
},
|
|
3126
|
+
high: {
|
|
3127
|
+
native: { effort: "high" },
|
|
3128
|
+
reflection: { maxTokens: 600, maxChars: 2e3, cadence: "after_tool" }
|
|
3129
|
+
}
|
|
3130
|
+
};
|
|
3131
|
+
function resolveReasoning(input) {
|
|
3132
|
+
if (!input || input.enabled === false) return void 0;
|
|
3133
|
+
const enabled = input.enabled ?? (input.native !== void 0 || input.reflection !== void 0 || input.level !== void 0);
|
|
3134
|
+
if (!enabled) return void 0;
|
|
3135
|
+
const level = input.level ?? "medium";
|
|
3136
|
+
const presets = LEVEL_DEFAULTS[level];
|
|
3137
|
+
let native;
|
|
3138
|
+
if (input.native === false) {
|
|
3139
|
+
native = void 0;
|
|
3140
|
+
} else {
|
|
3141
|
+
native = { ...presets.native, ...input.native ?? {} };
|
|
3142
|
+
}
|
|
3143
|
+
const reflection = resolveReflection(input.reflection, presets.reflection);
|
|
3144
|
+
return { enabled: true, level, native, reflection };
|
|
3145
|
+
}
|
|
3146
|
+
function resolveReflection(input, preset) {
|
|
3147
|
+
if (input === false) {
|
|
3148
|
+
return {
|
|
3149
|
+
enabled: false,
|
|
3150
|
+
cadence: "off",
|
|
3151
|
+
mode: "piggyback",
|
|
3152
|
+
maxTokens: preset.maxTokens,
|
|
3153
|
+
maxChars: preset.maxChars,
|
|
3154
|
+
keepLast: 3,
|
|
3155
|
+
summarize: false,
|
|
3156
|
+
emitEvents: true
|
|
3157
|
+
};
|
|
3158
|
+
}
|
|
3159
|
+
const cfg = input ?? {};
|
|
3160
|
+
const enabled = cfg.enabled ?? true;
|
|
3161
|
+
const cadence = cfg.cadence ?? preset.cadence;
|
|
3162
|
+
return {
|
|
3163
|
+
enabled: enabled && cadence !== "off",
|
|
3164
|
+
cadence: enabled ? cadence : "off",
|
|
3165
|
+
mode: cfg.mode ?? "piggyback",
|
|
3166
|
+
maxTokens: cfg.maxTokens ?? preset.maxTokens,
|
|
3167
|
+
maxChars: cfg.maxChars ?? preset.maxChars,
|
|
3168
|
+
keepLast: cfg.keepLast ?? 3,
|
|
3169
|
+
summarize: cfg.summarize ?? false,
|
|
3170
|
+
promptTemplate: cfg.promptTemplate,
|
|
3171
|
+
emitEvents: cfg.emitEvents ?? true
|
|
3172
|
+
};
|
|
3173
|
+
}
|
|
2961
3174
|
function ensureArray(value) {
|
|
2962
3175
|
return Array.isArray(value) ? value : [];
|
|
2963
3176
|
}
|
|
@@ -3371,6 +3584,8 @@ function createAgent(opts) {
|
|
|
3371
3584
|
}
|
|
3372
3585
|
const toolsNode = createToolsNode(toolsBase, opts);
|
|
3373
3586
|
const finalizeNode = createToolLimitFinalizeNode();
|
|
3587
|
+
const resolvedReasoning = resolveReasoning(opts.reasoning);
|
|
3588
|
+
const reflectNode = resolvedReasoning?.reflection.enabled ? createReflectionNode(opts, resolvedReasoning.reflection) : void 0;
|
|
3374
3589
|
const mergeGuardrailOutcomes = (prev, next) => {
|
|
3375
3590
|
if (!prev) return next;
|
|
3376
3591
|
return {
|
|
@@ -3425,6 +3640,13 @@ function createAgent(opts) {
|
|
|
3425
3640
|
if (summarizationThreshold === void 0) {
|
|
3426
3641
|
state = clearNeedsSummarization(state);
|
|
3427
3642
|
}
|
|
3643
|
+
if (resolvedReasoning?.native) {
|
|
3644
|
+
const ctx = { ...state.ctx || {} };
|
|
3645
|
+
if (!ctx.__reasoning) {
|
|
3646
|
+
ctx.__reasoning = resolvedReasoning.native;
|
|
3647
|
+
state = { ...state, ctx };
|
|
3648
|
+
}
|
|
3649
|
+
}
|
|
3428
3650
|
const mergedLimits = {
|
|
3429
3651
|
...opts.limits || {},
|
|
3430
3652
|
...config?.limits || {}
|
|
@@ -3653,6 +3875,18 @@ function createAgent(opts) {
|
|
|
3653
3875
|
if (state.ctx?.__awaitingApproval) break;
|
|
3654
3876
|
if (checkpointIfRequested("after_tools")) break;
|
|
3655
3877
|
if (state.ctx?.__finalizedDueToStructuredOutput) break;
|
|
3878
|
+
if (reflectNode && resolvedReasoning?.reflection.enabled) {
|
|
3879
|
+
const cadence = resolvedReasoning.reflection.cadence;
|
|
3880
|
+
if (shouldRunReflection(cadence, state, true)) {
|
|
3881
|
+
try {
|
|
3882
|
+
const patch = await reflectNode(state, cadence);
|
|
3883
|
+
if (patch && Object.keys(patch).length > 0) {
|
|
3884
|
+
state = { ...state, ...patch };
|
|
3885
|
+
}
|
|
3886
|
+
} catch {
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3656
3890
|
}
|
|
3657
3891
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput) {
|
|
3658
3892
|
const lastForParse = state.messages[state.messages.length - 1];
|
|
@@ -3980,40 +4214,6 @@ function createAgentNode(opts) {
|
|
|
3980
4214
|
}
|
|
3981
4215
|
|
|
3982
4216
|
// src/smart/contextPolicy.ts
|
|
3983
|
-
function collectRecentFullToolCallIds(state, keepRecentFullCount) {
|
|
3984
|
-
if (!keepRecentFullCount || keepRecentFullCount <= 0) return /* @__PURE__ */ new Set();
|
|
3985
|
-
const history = state.toolHistory || [];
|
|
3986
|
-
const ids = [];
|
|
3987
|
-
for (let index = history.length - 1; index >= 0 && ids.length < keepRecentFullCount; index -= 1) {
|
|
3988
|
-
const entry = history[index];
|
|
3989
|
-
if (!entry || !entry.tool_call_id) continue;
|
|
3990
|
-
if (entry.status && entry.status !== "success") continue;
|
|
3991
|
-
ids.push(entry.tool_call_id);
|
|
3992
|
-
}
|
|
3993
|
-
return new Set(ids);
|
|
3994
|
-
}
|
|
3995
|
-
function applyRecentFullOverride(messages, state, config) {
|
|
3996
|
-
const keepN = config.toolResponses.keepRecentFullCount;
|
|
3997
|
-
if (!keepN || keepN <= 0) return messages;
|
|
3998
|
-
const recentIds = collectRecentFullToolCallIds(state, keepN);
|
|
3999
|
-
if (recentIds.size === 0) return messages;
|
|
4000
|
-
const history = state.toolHistory || [];
|
|
4001
|
-
const byCallId = /* @__PURE__ */ new Map();
|
|
4002
|
-
for (const entry of history) {
|
|
4003
|
-
if (entry?.tool_call_id) byCallId.set(entry.tool_call_id, entry);
|
|
4004
|
-
}
|
|
4005
|
-
return messages.map((message) => {
|
|
4006
|
-
if (message.role !== "tool" || !message.tool_call_id) return message;
|
|
4007
|
-
if (!recentIds.has(message.tool_call_id)) return message;
|
|
4008
|
-
const entry = byCallId.get(message.tool_call_id);
|
|
4009
|
-
if (!entry) return message;
|
|
4010
|
-
const raw = entry.rawOutput ?? entry.output;
|
|
4011
|
-
if (raw === void 0) return message;
|
|
4012
|
-
const fullContent = typeof raw === "string" ? raw : safeStringify(raw);
|
|
4013
|
-
if (!fullContent || fullContent === message.content) return message;
|
|
4014
|
-
return { ...message, content: fullContent };
|
|
4015
|
-
});
|
|
4016
|
-
}
|
|
4017
4217
|
function collectRecentTurns(messages, lastTurnsToKeep) {
|
|
4018
4218
|
if (lastTurnsToKeep <= 0) return [];
|
|
4019
4219
|
const systemPrefix = messages.filter((message, index) => index === 0 && message.role === "system");
|
|
@@ -4114,7 +4314,7 @@ function clampToBudget(messages, maxContextTokens) {
|
|
|
4114
4314
|
function buildModelMessages(state, config) {
|
|
4115
4315
|
const rawMessages = state.messages || [];
|
|
4116
4316
|
if (config.context.policy === "raw") {
|
|
4117
|
-
return clampToBudget(
|
|
4317
|
+
return clampToBudget(rawMessages, config.limits.maxContextTokens);
|
|
4118
4318
|
}
|
|
4119
4319
|
const recentMessages = collectRecentTurns(rawMessages, config.context.lastTurnsToKeep);
|
|
4120
4320
|
const latestSummary = state.summaryRecords?.[state.summaryRecords.length - 1];
|
|
@@ -4134,7 +4334,7 @@ function buildModelMessages(state, config) {
|
|
|
4134
4334
|
...syntheticContextMessages,
|
|
4135
4335
|
...config.context.policy === "summary_only" ? body.filter((message) => message.role === "user" || message.role === "assistant").slice(-2) : body
|
|
4136
4336
|
];
|
|
4137
|
-
return clampToBudget(
|
|
4337
|
+
return clampToBudget(assembled, config.limits.maxContextTokens);
|
|
4138
4338
|
}
|
|
4139
4339
|
|
|
4140
4340
|
// src/nodes/contextSummarize.ts
|
|
@@ -4236,24 +4436,8 @@ function extractCanonicalFacts(messages) {
|
|
|
4236
4436
|
}
|
|
4237
4437
|
return [...facts.values()];
|
|
4238
4438
|
}
|
|
4239
|
-
function flattenToolMessageContent(message) {
|
|
4240
|
-
if (typeof message.content === "string") {
|
|
4241
|
-
return message.content;
|
|
4242
|
-
}
|
|
4243
|
-
if (Array.isArray(message.content)) {
|
|
4244
|
-
return message.content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? String(part ?? "")).join(" ");
|
|
4245
|
-
}
|
|
4246
|
-
return "";
|
|
4247
|
-
}
|
|
4248
4439
|
function isSummarizedToolPlaceholder(content) {
|
|
4249
|
-
return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE"));
|
|
4250
|
-
}
|
|
4251
|
-
function summarizeToolMessagePreview(message) {
|
|
4252
|
-
const preview = flattenToolMessageContent(message).trim();
|
|
4253
|
-
if (!preview) {
|
|
4254
|
-
return "No summary available.";
|
|
4255
|
-
}
|
|
4256
|
-
return preview.length > 240 ? `${preview.slice(0, 240)}...` : preview;
|
|
4440
|
+
return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE") || content.startsWith("ARCHIVED_TOOL_RESPONSE") || content.startsWith("STRUCTURED_TOOL_RESPONSE") || content.startsWith("DROPPED_TOOL_RESPONSE"));
|
|
4257
4441
|
}
|
|
4258
4442
|
function findToolHistoryEntry(state, toolCallId, toolName) {
|
|
4259
4443
|
const entries = [
|
|
@@ -4279,29 +4463,6 @@ function findToolHistoryEntry(state, toolCallId, toolName) {
|
|
|
4279
4463
|
}
|
|
4280
4464
|
return void 0;
|
|
4281
4465
|
}
|
|
4282
|
-
function buildSummarizedToolMessage(message, state) {
|
|
4283
|
-
const toolName = message.name || "unknown_tool";
|
|
4284
|
-
const toolCallId = message.tool_call_id;
|
|
4285
|
-
const historyEntry = findToolHistoryEntry(state, toolCallId, toolName);
|
|
4286
|
-
const executionId = historyEntry?.executionId;
|
|
4287
|
-
const summary = historyEntry?.summary || summarizeToolMessagePreview(message);
|
|
4288
|
-
const references = [
|
|
4289
|
-
`toolName=${toolName}`,
|
|
4290
|
-
toolCallId ? `toolCallId=${toolCallId}` : null,
|
|
4291
|
-
executionId ? `executionId=${executionId}` : null
|
|
4292
|
-
].filter(Boolean).join("; ");
|
|
4293
|
-
let retrievalHint = "Only use get_tool_response if this summary is missing a specific field, id, snippet, or exact payload you still need.";
|
|
4294
|
-
if (executionId && toolCallId) {
|
|
4295
|
-
retrievalHint = `Only use get_tool_response with executionId "${executionId}" or tool call id "${toolCallId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
4296
|
-
} else if (executionId || toolCallId) {
|
|
4297
|
-
retrievalHint = `Only use get_tool_response with executionId "${executionId || toolCallId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
4298
|
-
}
|
|
4299
|
-
return [
|
|
4300
|
-
`SUMMARIZED_TOOL_RESPONSE [${references}]`,
|
|
4301
|
-
`Summary: ${summary}`,
|
|
4302
|
-
retrievalHint
|
|
4303
|
-
].join("\n");
|
|
4304
|
-
}
|
|
4305
4466
|
function mergeStableFacts(summary, additionalFacts) {
|
|
4306
4467
|
if (additionalFacts.length === 0) return summary;
|
|
4307
4468
|
const merged = new Map(summary.stable_facts.map((fact) => [fact.key, fact]));
|
|
@@ -4359,20 +4520,13 @@ function createContextSummarizeNode(opts) {
|
|
|
4359
4520
|
const messages = state.messages || [];
|
|
4360
4521
|
const onEvent = state.ctx?.__onEvent;
|
|
4361
4522
|
const traceSession = state.ctx?.__traceSession;
|
|
4362
|
-
const toolResponsesConfigEarly = resolved.toolResponses;
|
|
4363
|
-
const recentFullToolCallIdsEarly = collectRecentFullToolCallIds(state, toolResponsesConfigEarly.keepRecentFullCount);
|
|
4364
4523
|
const compressableMessages = messages.filter(
|
|
4365
4524
|
(m) => {
|
|
4366
4525
|
if (m.role !== "tool") return false;
|
|
4367
4526
|
if (isSummarizedToolPlaceholder(m.content)) return false;
|
|
4368
4527
|
if (isSyntheticSummaryMessage(m)) return false;
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
if (histEntry?.retentionPolicy === "keep_full") return false;
|
|
4372
|
-
if (!histEntry?.retentionPolicy) {
|
|
4373
|
-
const byTool = toolResponsesConfigEarly.toolResponseRetentionByTool?.[m.name || ""];
|
|
4374
|
-
if ((byTool || toolResponsesConfigEarly.defaultPolicy) === "keep_full") return false;
|
|
4375
|
-
}
|
|
4528
|
+
const policy = resolveSummarizationRetention(m.name || "", resolved);
|
|
4529
|
+
if (policy === "keep_full") return false;
|
|
4376
4530
|
return true;
|
|
4377
4531
|
}
|
|
4378
4532
|
);
|
|
@@ -4552,8 +4706,8 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4552
4706
|
break;
|
|
4553
4707
|
}
|
|
4554
4708
|
}
|
|
4555
|
-
const
|
|
4556
|
-
const
|
|
4709
|
+
const archivedExecutions = [...state.toolHistoryArchived || []];
|
|
4710
|
+
const archivedIds = new Set(archivedExecutions.map((entry) => entry?.executionId).filter(Boolean));
|
|
4557
4711
|
const newMessages = messages.map((m) => {
|
|
4558
4712
|
if (m.role === "tool") {
|
|
4559
4713
|
if (isSyntheticSummaryMessage(m)) {
|
|
@@ -4565,25 +4719,39 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4565
4719
|
}
|
|
4566
4720
|
if (isSummarizedToolPlaceholder(m.content)) return m;
|
|
4567
4721
|
if (toolCallId && protectedToolCallIds.has(toolCallId)) return m;
|
|
4568
|
-
if (toolCallId && recentFullToolCallIds.has(toolCallId)) return m;
|
|
4569
4722
|
const toolName = m.name || "";
|
|
4723
|
+
const policy = resolveSummarizationRetention(toolName, resolved);
|
|
4724
|
+
if (policy === "keep_full") return m;
|
|
4570
4725
|
const historyEntry = findToolHistoryEntry(state, toolCallId, toolName);
|
|
4571
|
-
const
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4726
|
+
const rawOutput = historyEntry?.rawOutput ?? historyEntry?.output ?? m.content;
|
|
4727
|
+
const executionId = historyEntry?.executionId;
|
|
4728
|
+
const prebuiltSummary = historyEntry?.summary || summarizeObject(rawOutput);
|
|
4729
|
+
if ((policy === "summarize_archive" || policy === "drop") && historyEntry && executionId && !archivedIds.has(executionId)) {
|
|
4730
|
+
archivedExecutions.push({
|
|
4731
|
+
...historyEntry,
|
|
4732
|
+
summarized: true,
|
|
4733
|
+
retentionPolicy: policy,
|
|
4734
|
+
archiveId: executionId,
|
|
4735
|
+
summary: prebuiltSummary
|
|
4736
|
+
});
|
|
4737
|
+
archivedIds.add(executionId);
|
|
4577
4738
|
}
|
|
4578
4739
|
return {
|
|
4579
4740
|
...m,
|
|
4580
|
-
content:
|
|
4741
|
+
content: renderRetainedToolMessage({
|
|
4742
|
+
policy,
|
|
4743
|
+
rawOutput,
|
|
4744
|
+
toolName,
|
|
4745
|
+
toolCallId,
|
|
4746
|
+
executionId,
|
|
4747
|
+
prebuiltSummary
|
|
4748
|
+
})
|
|
4581
4749
|
};
|
|
4582
4750
|
}
|
|
4583
4751
|
return m;
|
|
4584
4752
|
}).filter((m) => m !== null);
|
|
4585
4753
|
const actuallyCompressed = newMessages.filter(
|
|
4586
|
-
(m) => m.role === "tool" &&
|
|
4754
|
+
(m) => m.role === "tool" && isSummarizedToolPlaceholder(m.content) && !messages.some((orig) => orig.tool_call_id === m.tool_call_id && isSummarizedToolPlaceholder(orig.content))
|
|
4587
4755
|
);
|
|
4588
4756
|
if (actuallyCompressed.length === 0) {
|
|
4589
4757
|
return {};
|
|
@@ -4662,7 +4830,8 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4662
4830
|
return {
|
|
4663
4831
|
messages: finalMessages,
|
|
4664
4832
|
summaries,
|
|
4665
|
-
summaryRecords
|
|
4833
|
+
summaryRecords,
|
|
4834
|
+
toolHistoryArchived: archivedExecutions
|
|
4666
4835
|
};
|
|
4667
4836
|
};
|
|
4668
4837
|
}
|
|
@@ -5727,6 +5896,52 @@ function parseSSEBlock(block) {
|
|
|
5727
5896
|
return { event, data: dataLines.join("\n"), id, retry };
|
|
5728
5897
|
}
|
|
5729
5898
|
|
|
5899
|
+
// src/providers/utils/reasoning.ts
|
|
5900
|
+
function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
|
|
5901
|
+
if (!reasoning) return;
|
|
5902
|
+
const effort = normalizeEffort(reasoning.effort);
|
|
5903
|
+
if (mode === "responses") {
|
|
5904
|
+
const obj = {};
|
|
5905
|
+
if (effort) obj.effort = effort;
|
|
5906
|
+
if (reasoning.includeThoughts) obj.summary = "auto";
|
|
5907
|
+
if (reasoning.providerExtras) Object.assign(obj, reasoning.providerExtras);
|
|
5908
|
+
if (Object.keys(obj).length > 0) body.reasoning = obj;
|
|
5909
|
+
} else {
|
|
5910
|
+
if (effort) body.reasoning_effort = effort;
|
|
5911
|
+
if (reasoning.providerExtras) Object.assign(body, reasoning.providerExtras);
|
|
5912
|
+
}
|
|
5913
|
+
}
|
|
5914
|
+
function applyAnthropicReasoning(body, reasoning) {
|
|
5915
|
+
if (!reasoning) return;
|
|
5916
|
+
const budget = resolveBudget(reasoning, { low: 2048, medium: 8192, high: 16384, minimal: 1024 });
|
|
5917
|
+
if (!budget) return;
|
|
5918
|
+
const thinking = { type: "enabled", budget_tokens: budget };
|
|
5919
|
+
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
5920
|
+
body.thinking = thinking;
|
|
5921
|
+
}
|
|
5922
|
+
function applyGeminiReasoning(generationConfig, reasoning) {
|
|
5923
|
+
if (!reasoning) return;
|
|
5924
|
+
const budget = resolveBudget(reasoning, { low: 1024, medium: 4096, high: 12e3, minimal: 512 });
|
|
5925
|
+
if (budget == null) return;
|
|
5926
|
+
const thinkingConfig = { thinkingBudget: budget };
|
|
5927
|
+
if (reasoning.includeThoughts) thinkingConfig.includeThoughts = true;
|
|
5928
|
+
if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
|
|
5929
|
+
generationConfig.thinkingConfig = thinkingConfig;
|
|
5930
|
+
}
|
|
5931
|
+
function normalizeEffort(effort) {
|
|
5932
|
+
if (!effort) return void 0;
|
|
5933
|
+
const allowed = ["minimal", "low", "medium", "high"];
|
|
5934
|
+
return allowed.includes(effort) ? effort : void 0;
|
|
5935
|
+
}
|
|
5936
|
+
function resolveBudget(reasoning, effortBudget) {
|
|
5937
|
+
if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
|
|
5938
|
+
return Math.floor(reasoning.budgetTokens);
|
|
5939
|
+
}
|
|
5940
|
+
const effort = normalizeEffort(reasoning.effort);
|
|
5941
|
+
if (effort && effortBudget[effort]) return effortBudget[effort];
|
|
5942
|
+
return void 0;
|
|
5943
|
+
}
|
|
5944
|
+
|
|
5730
5945
|
// src/providers/openai.ts
|
|
5731
5946
|
var OpenAIProvider = class extends BaseProvider {
|
|
5732
5947
|
constructor(config) {
|
|
@@ -5842,6 +6057,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
5842
6057
|
if (request.extra) {
|
|
5843
6058
|
Object.assign(body, request.extra);
|
|
5844
6059
|
}
|
|
6060
|
+
applyOpenAIReasoning(body, request.reasoning, "legacy_effort");
|
|
5845
6061
|
return body;
|
|
5846
6062
|
}
|
|
5847
6063
|
toOpenAIMessage(m) {
|
|
@@ -6100,6 +6316,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
6100
6316
|
if (request.extra) {
|
|
6101
6317
|
Object.assign(body, request.extra);
|
|
6102
6318
|
}
|
|
6319
|
+
applyAnthropicReasoning(body, request.reasoning);
|
|
6103
6320
|
return body;
|
|
6104
6321
|
}
|
|
6105
6322
|
splitSystemMessages(messages) {
|
|
@@ -6754,6 +6971,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
6754
6971
|
}
|
|
6755
6972
|
}
|
|
6756
6973
|
}
|
|
6974
|
+
applyGeminiReasoning(generationConfig, request.reasoning);
|
|
6757
6975
|
if (Object.keys(generationConfig).length > 0) body.generationConfig = generationConfig;
|
|
6758
6976
|
if (request.tools?.length) {
|
|
6759
6977
|
body.tools = [
|
|
@@ -7092,6 +7310,13 @@ function fromNativeProvider(provider, options) {
|
|
|
7092
7310
|
if (opts?.maxTokens != null) req.maxTokens = opts.maxTokens;
|
|
7093
7311
|
if (tools?.length) req.tools = tools;
|
|
7094
7312
|
if (opts?.extra) req.extra = opts.extra;
|
|
7313
|
+
const reasoningOverride = invokeOptions?.reasoning;
|
|
7314
|
+
const reasoningCfg = reasoningOverride ?? opts?.reasoning;
|
|
7315
|
+
if (reasoningCfg) req.reasoning = reasoningCfg;
|
|
7316
|
+
const tc = invokeOptions?.tool_choice ?? invokeOptions?.toolChoice;
|
|
7317
|
+
if (tc) {
|
|
7318
|
+
req.toolChoice = tc;
|
|
7319
|
+
}
|
|
7095
7320
|
const rf = invokeOptions?.response_format;
|
|
7096
7321
|
if (rf && typeof rf === "object" && rf.type) {
|
|
7097
7322
|
if (rf.type === "json_schema" && rf.json_schema) {
|