@cognipeer/agent-sdk 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1237 -612
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +268 -1
- package/dist/index.d.ts +268 -1
- package/dist/index.mjs +1223 -614
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -52,7 +52,7 @@ function getTokenCounter() {
|
|
|
52
52
|
function countApproxTokens(text) {
|
|
53
53
|
return activeTokenCounter(text || "");
|
|
54
54
|
}
|
|
55
|
-
function
|
|
55
|
+
function extractMessageText(m) {
|
|
56
56
|
if (!m) return "";
|
|
57
57
|
const parts = [];
|
|
58
58
|
parts.push(m.role || "");
|
|
@@ -102,7 +102,7 @@ function extractMessageText2(m) {
|
|
|
102
102
|
}
|
|
103
103
|
function countMessagesTokens(messages) {
|
|
104
104
|
if (!Array.isArray(messages) || messages.length === 0) return 0;
|
|
105
|
-
const allText = messages.map(
|
|
105
|
+
const allText = messages.map(extractMessageText).join("\n");
|
|
106
106
|
return countApproxTokens(allText) + messages.length * 4;
|
|
107
107
|
}
|
|
108
108
|
var activeTokenCounter;
|
|
@@ -1088,7 +1088,35 @@ function buildConfigSnapshot(runtime) {
|
|
|
1088
1088
|
sink: snapshotSink(runtime)
|
|
1089
1089
|
};
|
|
1090
1090
|
}
|
|
1091
|
-
|
|
1091
|
+
var TRACE_HTTP_MAX_ATTEMPTS = 4;
|
|
1092
|
+
var TRACE_HTTP_ATTEMPT_TIMEOUT_MS = 8e3;
|
|
1093
|
+
var TRACE_HTTP_RETRYABLE_STATUS = /* @__PURE__ */ new Set([404, 408, 425, 429, 500, 502, 503, 504]);
|
|
1094
|
+
var TRACE_HTTP_RETRY_BASE_MS = 250;
|
|
1095
|
+
var TRACE_HTTP_RETRY_MAX_MS = 4e3;
|
|
1096
|
+
var RetryableHttpError = class extends Error {
|
|
1097
|
+
constructor(status, message, retryAfterMs) {
|
|
1098
|
+
super(message);
|
|
1099
|
+
this.name = "RetryableHttpError";
|
|
1100
|
+
this.status = status;
|
|
1101
|
+
this.retryAfterMs = retryAfterMs;
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
function traceSleep(ms) {
|
|
1105
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1106
|
+
}
|
|
1107
|
+
function traceBackoffDelay(attempt, baseMs, maxMs) {
|
|
1108
|
+
const exp = Math.min(maxMs, baseMs * 2 ** (attempt - 1));
|
|
1109
|
+
return Math.floor(Math.random() * exp);
|
|
1110
|
+
}
|
|
1111
|
+
function parseRetryAfterMs(headerValue) {
|
|
1112
|
+
if (!headerValue) return void 0;
|
|
1113
|
+
const seconds = Number(headerValue);
|
|
1114
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
1115
|
+
const dateMs = Date.parse(headerValue);
|
|
1116
|
+
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
|
|
1117
|
+
return void 0;
|
|
1118
|
+
}
|
|
1119
|
+
async function postJsonOnce(url, headers, body) {
|
|
1092
1120
|
const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
1093
1121
|
if (!fetchFn) {
|
|
1094
1122
|
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
@@ -1097,135 +1125,71 @@ async function postTraceSession(url, headers, payload) {
|
|
|
1097
1125
|
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
1098
1126
|
finalHeaders["content-type"] = "application/json";
|
|
1099
1127
|
}
|
|
1128
|
+
const controller = new AbortController();
|
|
1129
|
+
const timer = setTimeout(() => controller.abort(), TRACE_HTTP_ATTEMPT_TIMEOUT_MS);
|
|
1130
|
+
let response;
|
|
1100
1131
|
try {
|
|
1101
|
-
|
|
1132
|
+
response = await fetchFn(url, {
|
|
1102
1133
|
method: "POST",
|
|
1103
1134
|
headers: finalHeaders,
|
|
1104
|
-
body: JSON.stringify(
|
|
1135
|
+
body: JSON.stringify(body),
|
|
1136
|
+
signal: controller.signal
|
|
1105
1137
|
});
|
|
1106
|
-
if (!response.ok) {
|
|
1107
|
-
let responseText = "";
|
|
1108
|
-
try {
|
|
1109
|
-
responseText = await response.text();
|
|
1110
|
-
} catch {
|
|
1111
|
-
}
|
|
1112
|
-
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1113
|
-
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1114
|
-
const errorMsg = `${statusLine}${bodyPreview}`;
|
|
1115
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1116
|
-
console.error("[Tracing] Error posting to", url, ":", errorMsg);
|
|
1117
|
-
}
|
|
1118
|
-
throw new Error(errorMsg);
|
|
1119
|
-
}
|
|
1120
1138
|
} catch (err) {
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
throw err;
|
|
1139
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
1140
|
+
throw new RetryableHttpError(0, `network error - ${message2}`);
|
|
1141
|
+
} finally {
|
|
1142
|
+
clearTimeout(timer);
|
|
1126
1143
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1144
|
+
if (response.ok) return;
|
|
1145
|
+
let responseText = "";
|
|
1146
|
+
try {
|
|
1147
|
+
responseText = await response.text();
|
|
1148
|
+
} catch {
|
|
1132
1149
|
}
|
|
1133
|
-
const
|
|
1134
|
-
const
|
|
1135
|
-
|
|
1136
|
-
|
|
1150
|
+
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1151
|
+
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1152
|
+
const message = `${statusLine}${bodyPreview}`;
|
|
1153
|
+
if (TRACE_HTTP_RETRYABLE_STATUS.has(response.status)) {
|
|
1154
|
+
throw new RetryableHttpError(response.status, message, parseRetryAfterMs(response.headers.get("retry-after")));
|
|
1137
1155
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1156
|
+
throw new Error(message);
|
|
1157
|
+
}
|
|
1158
|
+
async function postJsonReliable(url, headers, body, opts = {}) {
|
|
1159
|
+
const maxAttempts = opts.retry === false ? 1 : TRACE_HTTP_MAX_ATTEMPTS;
|
|
1160
|
+
let lastError;
|
|
1161
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
1162
|
+
try {
|
|
1163
|
+
await postJsonOnce(url, headers, body);
|
|
1164
|
+
return;
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
lastError = err;
|
|
1167
|
+
if (!(err instanceof RetryableHttpError) || attempt === maxAttempts) {
|
|
1168
|
+
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1169
|
+
console.error("[Tracing] Failed to post:", err instanceof Error ? err.message : String(err));
|
|
1170
|
+
}
|
|
1171
|
+
throw err;
|
|
1149
1172
|
}
|
|
1150
|
-
const
|
|
1151
|
-
|
|
1152
|
-
throw new Error(`${statusLine}${bodyPreview}`);
|
|
1153
|
-
}
|
|
1154
|
-
} catch (err) {
|
|
1155
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1156
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1157
|
-
console.error("[Tracing] Failed to post session start:", errMsg);
|
|
1173
|
+
const wait = err.retryAfterMs ?? traceBackoffDelay(attempt, TRACE_HTTP_RETRY_BASE_MS, TRACE_HTTP_RETRY_MAX_MS);
|
|
1174
|
+
await traceSleep(Math.min(wait, TRACE_HTTP_RETRY_MAX_MS));
|
|
1158
1175
|
}
|
|
1159
|
-
throw err;
|
|
1160
1176
|
}
|
|
1177
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
1178
|
+
}
|
|
1179
|
+
async function postTraceSession(url, headers, payload) {
|
|
1180
|
+
await postJsonReliable(url, headers, payload, { retry: true });
|
|
1181
|
+
}
|
|
1182
|
+
async function postStreamingSessionStart(baseUrl, headers, payload) {
|
|
1183
|
+
const url = `${baseUrl.replace(/\/$/, "")}/stream/${payload.sessionId}/start`;
|
|
1184
|
+
await postJsonReliable(url, headers, payload, { retry: true });
|
|
1161
1185
|
}
|
|
1162
1186
|
async function postStreamingEvent(baseUrl, headers, sessionId, event) {
|
|
1163
|
-
const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
1164
|
-
if (!fetchFn) {
|
|
1165
|
-
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
1166
|
-
}
|
|
1167
1187
|
const url = `${baseUrl.replace(/\/$/, "")}/stream/${sessionId}/events`;
|
|
1168
|
-
|
|
1169
|
-
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
1170
|
-
finalHeaders["content-type"] = "application/json";
|
|
1171
|
-
}
|
|
1172
|
-
try {
|
|
1173
|
-
const response = await fetchFn(url, {
|
|
1174
|
-
method: "POST",
|
|
1175
|
-
headers: finalHeaders,
|
|
1176
|
-
body: JSON.stringify({ event })
|
|
1177
|
-
});
|
|
1178
|
-
if (!response.ok) {
|
|
1179
|
-
let responseText = "";
|
|
1180
|
-
try {
|
|
1181
|
-
responseText = await response.text();
|
|
1182
|
-
} catch {
|
|
1183
|
-
}
|
|
1184
|
-
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1185
|
-
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1186
|
-
throw new Error(`${statusLine}${bodyPreview}`);
|
|
1187
|
-
}
|
|
1188
|
-
} catch (err) {
|
|
1189
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1190
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1191
|
-
console.error("[Tracing] Failed to post streaming event:", errMsg);
|
|
1192
|
-
}
|
|
1193
|
-
throw err;
|
|
1194
|
-
}
|
|
1188
|
+
await postJsonReliable(url, headers, { event }, { retry: false });
|
|
1195
1189
|
}
|
|
1196
1190
|
async function postStreamingSessionEnd(baseUrl, headers, payload) {
|
|
1197
|
-
const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
1198
|
-
if (!fetchFn) {
|
|
1199
|
-
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
1200
|
-
}
|
|
1201
1191
|
const url = `${baseUrl.replace(/\/$/, "")}/stream/${payload.sessionId}/end`;
|
|
1202
|
-
|
|
1203
|
-
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
1204
|
-
finalHeaders["content-type"] = "application/json";
|
|
1205
|
-
}
|
|
1206
|
-
try {
|
|
1207
|
-
const response = await fetchFn(url, {
|
|
1208
|
-
method: "POST",
|
|
1209
|
-
headers: finalHeaders,
|
|
1210
|
-
body: JSON.stringify(payload)
|
|
1211
|
-
});
|
|
1212
|
-
if (!response.ok) {
|
|
1213
|
-
let responseText = "";
|
|
1214
|
-
try {
|
|
1215
|
-
responseText = await response.text();
|
|
1216
|
-
} catch {
|
|
1217
|
-
}
|
|
1218
|
-
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1219
|
-
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1220
|
-
throw new Error(`${statusLine}${bodyPreview}`);
|
|
1221
|
-
}
|
|
1222
|
-
} catch (err) {
|
|
1223
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1224
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1225
|
-
console.error("[Tracing] Failed to post session end:", errMsg);
|
|
1226
|
-
}
|
|
1227
|
-
throw err;
|
|
1228
|
-
}
|
|
1192
|
+
await postJsonReliable(url, headers, payload, { retry: true });
|
|
1229
1193
|
}
|
|
1230
1194
|
function isoToUnixNano(iso) {
|
|
1231
1195
|
const ms = new Date(iso).getTime();
|
|
@@ -1598,7 +1562,8 @@ function convertMessageListToSections(messageList) {
|
|
|
1598
1562
|
function createTraceSession(opts) {
|
|
1599
1563
|
const cfg = withDefaults(opts.tracing);
|
|
1600
1564
|
if (!cfg.enabled) return void 0;
|
|
1601
|
-
const
|
|
1565
|
+
const providedSessionId = opts.tracing?.sessionId?.trim();
|
|
1566
|
+
const sessionId = providedSessionId || generateSessionId();
|
|
1602
1567
|
const traceId = generateTraceId();
|
|
1603
1568
|
const rootSpanId = generateSpanId();
|
|
1604
1569
|
const runtime = {
|
|
@@ -1606,6 +1571,7 @@ function createTraceSession(opts) {
|
|
|
1606
1571
|
traceId,
|
|
1607
1572
|
rootSpanId,
|
|
1608
1573
|
threadId: opts.tracing?.threadId,
|
|
1574
|
+
configAgentName: opts.tracing?.agentName?.trim() || void 0,
|
|
1609
1575
|
startedAt: Date.now(),
|
|
1610
1576
|
resolvedConfig: cfg,
|
|
1611
1577
|
events: [],
|
|
@@ -1629,11 +1595,12 @@ async function startStreamingSession(session, agentRuntime) {
|
|
|
1629
1595
|
if (session.resolvedConfig.mode !== "streaming") return;
|
|
1630
1596
|
if (session.sessionStarted) return;
|
|
1631
1597
|
const sink = session.resolvedConfig.sink;
|
|
1632
|
-
const
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1598
|
+
const resolvedAgentName = session.configAgentName || agentRuntime?.name || "unknown-agent";
|
|
1599
|
+
const agentInfo = agentRuntime || session.configAgentName ? {
|
|
1600
|
+
name: resolvedAgentName,
|
|
1601
|
+
version: agentRuntime?.version,
|
|
1602
|
+
model: getModelName(agentRuntime?.model) || "unknown-model",
|
|
1603
|
+
provider: getProviderName(agentRuntime?.model)
|
|
1637
1604
|
} : void 0;
|
|
1638
1605
|
session.agentInfo = agentInfo;
|
|
1639
1606
|
const configSnapshot = buildConfigSnapshot(session);
|
|
@@ -1983,301 +1950,6 @@ function estimatePayloadBytes(value) {
|
|
|
1983
1950
|
}
|
|
1984
1951
|
}
|
|
1985
1952
|
|
|
1986
|
-
// src/nodes/agentCore.ts
|
|
1987
|
-
function createAgentCoreNode(opts) {
|
|
1988
|
-
return async (state) => {
|
|
1989
|
-
const runtime = state.agent || {
|
|
1990
|
-
name: opts.name,
|
|
1991
|
-
version: opts.version,
|
|
1992
|
-
model: opts.model,
|
|
1993
|
-
tools: opts.tools || [],
|
|
1994
|
-
guardrails: opts.guardrails,
|
|
1995
|
-
todoListPrompt: opts.todoListPrompt,
|
|
1996
|
-
limits: opts.limits,
|
|
1997
|
-
outputSchema: opts.outputSchema,
|
|
1998
|
-
tracing: opts.tracing,
|
|
1999
|
-
responseFormat: void 0
|
|
2000
|
-
};
|
|
2001
|
-
const tools = runtime.tools ?? [];
|
|
2002
|
-
const shouldUseStrictToolCalling = Boolean(
|
|
2003
|
-
runtime.responseFormat && runtime.model?.capabilities?.strictToolCalling
|
|
2004
|
-
);
|
|
2005
|
-
const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(
|
|
2006
|
-
tools,
|
|
2007
|
-
shouldUseStrictToolCalling ? { strict: true } : void 0
|
|
2008
|
-
) : runtime.model;
|
|
2009
|
-
const traceSession = state.ctx?.__traceSession;
|
|
2010
|
-
const actorName = runtime.name ?? opts.name ?? "agent";
|
|
2011
|
-
const actorVersion = runtime.version ?? opts.version;
|
|
2012
|
-
const start = Date.now();
|
|
2013
|
-
const shouldLogPrompt = !!traceSession && traceSession.resolvedConfig.logData;
|
|
2014
|
-
const promptPayload = shouldLogPrompt ? sanitizeTracePayload(state.messages) : void 0;
|
|
2015
|
-
const promptBytes = promptPayload !== void 0 ? estimatePayloadBytes(promptPayload) : void 0;
|
|
2016
|
-
const extractToolUses = (m) => {
|
|
2017
|
-
const tcs = m?.tool_calls || m?.additional_kwargs?.tool_calls;
|
|
2018
|
-
if (!Array.isArray(tcs)) return [];
|
|
2019
|
-
return tcs.map((tc) => ({ id: tc?.id, name: tc?.function?.name || tc?.name })).filter((x) => typeof x.id === "string" && x.id.length > 0);
|
|
2020
|
-
};
|
|
2021
|
-
const normalizeBedrockToolPairing = (input) => {
|
|
2022
|
-
const msgs = Array.isArray(input) ? [...input] : [];
|
|
2023
|
-
const validToolCallIds = /* @__PURE__ */ new Set();
|
|
2024
|
-
for (const m of msgs) {
|
|
2025
|
-
if (m?.role === "assistant") {
|
|
2026
|
-
for (const tu of extractToolUses(m)) {
|
|
2027
|
-
if (tu.id) validToolCallIds.add(tu.id);
|
|
2028
|
-
}
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
const filteredMsgs = msgs.filter((m) => {
|
|
2032
|
-
if (m?.role === "tool") {
|
|
2033
|
-
const toolCallId = m.tool_call_id;
|
|
2034
|
-
if (!toolCallId || !validToolCallIds.has(toolCallId)) {
|
|
2035
|
-
return false;
|
|
2036
|
-
}
|
|
2037
|
-
}
|
|
2038
|
-
return true;
|
|
2039
|
-
});
|
|
2040
|
-
for (let i = 0; i < filteredMsgs.length; i++) {
|
|
2041
|
-
const m = filteredMsgs[i];
|
|
2042
|
-
if (m?.role !== "assistant") continue;
|
|
2043
|
-
const toolUses = extractToolUses(m);
|
|
2044
|
-
if (toolUses.length === 0) continue;
|
|
2045
|
-
const next = filteredMsgs[i + 1];
|
|
2046
|
-
const firstId = toolUses[0]?.id;
|
|
2047
|
-
const nextIsToolForFirst = !!(next && next.role === "tool" && next.tool_call_id === firstId);
|
|
2048
|
-
if (nextIsToolForFirst) continue;
|
|
2049
|
-
const placeholders = toolUses.map((tu) => ({
|
|
2050
|
-
role: "tool",
|
|
2051
|
-
name: tu.name || "unknown_tool",
|
|
2052
|
-
tool_call_id: tu.id,
|
|
2053
|
-
content: "SUMMARIZED/DEFERRED: tool result missing in transcript; inserted placeholder for tool_result adjacency."
|
|
2054
|
-
}));
|
|
2055
|
-
filteredMsgs.splice(i + 1, 0, ...placeholders);
|
|
2056
|
-
i += placeholders.length;
|
|
2057
|
-
}
|
|
2058
|
-
return filteredMsgs;
|
|
2059
|
-
};
|
|
2060
|
-
const debugToolPairing = (messagesToSend) => {
|
|
2061
|
-
try {
|
|
2062
|
-
const msgs = Array.isArray(messagesToSend) ? messagesToSend : [];
|
|
2063
|
-
const toolUseIds = [];
|
|
2064
|
-
const missingResults = [];
|
|
2065
|
-
for (let i = 0; i < msgs.length; i++) {
|
|
2066
|
-
const m = msgs[i];
|
|
2067
|
-
if (m?.role === "assistant") {
|
|
2068
|
-
for (const tu of extractToolUses(m)) {
|
|
2069
|
-
toolUseIds.push(tu.id);
|
|
2070
|
-
const next = msgs[i + 1];
|
|
2071
|
-
if (!(next && next.role === "tool" && (next.tool_call_id === tu.id || next.tool_call_id === m?.tool_call_id))) {
|
|
2072
|
-
missingResults.push({ id: tu.id, atIndex: i, tool: tu.name });
|
|
2073
|
-
}
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
} catch {
|
|
2078
|
-
}
|
|
2079
|
-
};
|
|
2080
|
-
const onEvent = state.ctx?.__onEvent;
|
|
2081
|
-
const onStream = state.ctx?.__onStream;
|
|
2082
|
-
const streamingEnabled = Boolean(state.ctx?.__streaming);
|
|
2083
|
-
const cancellationToken = state.ctx?.__cancellationToken;
|
|
2084
|
-
const abortSignal = state.ctx?.__abortSignal;
|
|
2085
|
-
const responseFormat = runtime.responseFormat;
|
|
2086
|
-
const reasoningForCall = state.ctx?.__reasoning;
|
|
2087
|
-
const reasoningInvokeOpts = reasoningForCall ? { reasoning: reasoningForCall } : void 0;
|
|
2088
|
-
const extractText2 = (chunk) => {
|
|
2089
|
-
if (chunk == null) return "";
|
|
2090
|
-
if (typeof chunk === "string") return chunk;
|
|
2091
|
-
if (typeof chunk?.content === "string") return chunk.content;
|
|
2092
|
-
if (Array.isArray(chunk?.content)) {
|
|
2093
|
-
return chunk.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("");
|
|
2094
|
-
}
|
|
2095
|
-
if (typeof chunk?.text === "string") return chunk.text;
|
|
2096
|
-
if (typeof chunk?.delta?.content === "string") return chunk.delta.content;
|
|
2097
|
-
return "";
|
|
2098
|
-
};
|
|
2099
|
-
let response;
|
|
2100
|
-
try {
|
|
2101
|
-
const normalizedMessages = normalizeBedrockToolPairing([...state.messages]);
|
|
2102
|
-
debugToolPairing(normalizedMessages);
|
|
2103
|
-
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
2104
|
-
let streamedText = "";
|
|
2105
|
-
let streamedMessage;
|
|
2106
|
-
const streamOptions = { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts };
|
|
2107
|
-
for await (const chunk of modelWithTools.stream(normalizedMessages, streamOptions)) {
|
|
2108
|
-
if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
|
|
2109
|
-
break;
|
|
2110
|
-
}
|
|
2111
|
-
if (chunk && typeof chunk === "object" && chunk.role) {
|
|
2112
|
-
streamedMessage = chunk;
|
|
2113
|
-
}
|
|
2114
|
-
const text = extractText2(chunk);
|
|
2115
|
-
if (text) {
|
|
2116
|
-
streamedText += text;
|
|
2117
|
-
onStream?.({ text });
|
|
2118
|
-
onEvent?.({ type: "stream", text });
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2121
|
-
if (streamedMessage) {
|
|
2122
|
-
response = { ...streamedMessage };
|
|
2123
|
-
if (response.content == null || response.content === "") {
|
|
2124
|
-
response.content = streamedText;
|
|
2125
|
-
}
|
|
2126
|
-
} else {
|
|
2127
|
-
response = { role: "assistant", content: streamedText };
|
|
2128
|
-
}
|
|
2129
|
-
} else {
|
|
2130
|
-
response = await modelWithTools.invoke(normalizedMessages, { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts });
|
|
2131
|
-
}
|
|
2132
|
-
} catch (err) {
|
|
2133
|
-
const durationMs2 = Date.now() - start;
|
|
2134
|
-
recordTraceEvent(traceSession, {
|
|
2135
|
-
type: "ai_call",
|
|
2136
|
-
label: "Assistant Error",
|
|
2137
|
-
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
2138
|
-
status: "error",
|
|
2139
|
-
durationMs: durationMs2,
|
|
2140
|
-
requestBytes: promptBytes,
|
|
2141
|
-
model: getModelName(runtime.model || opts.model),
|
|
2142
|
-
provider: getProviderName(runtime.model || opts.model),
|
|
2143
|
-
error: { message: err?.message || String(err), stack: err?.stack },
|
|
2144
|
-
messageList: state.messages
|
|
2145
|
-
});
|
|
2146
|
-
throw err;
|
|
2147
|
-
}
|
|
2148
|
-
const messagesWithResponse = [
|
|
2149
|
-
...state.messages,
|
|
2150
|
-
response
|
|
2151
|
-
];
|
|
2152
|
-
const rawUsage = response?.usage || response?.usage_metadata || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage || response?.response_metadata?.usage_metadata || response?.response_metadata?.usageMetadata;
|
|
2153
|
-
const normalized = normalizeUsage(rawUsage);
|
|
2154
|
-
const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
|
|
2155
|
-
const durationMs = Date.now() - start;
|
|
2156
|
-
const shouldLogResponse = !!traceSession && traceSession.resolvedConfig.logData;
|
|
2157
|
-
const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
|
|
2158
|
-
const responseBytes = responsePayload !== void 0 ? estimatePayloadBytes(responsePayload) : void 0;
|
|
2159
|
-
recordTraceEvent(traceSession, {
|
|
2160
|
-
type: "ai_call",
|
|
2161
|
-
label: "Assistant Response",
|
|
2162
|
-
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
2163
|
-
durationMs,
|
|
2164
|
-
inputTokens: normalized?.prompt_tokens,
|
|
2165
|
-
outputTokens: normalized?.completion_tokens,
|
|
2166
|
-
totalTokens: normalized?.total_tokens,
|
|
2167
|
-
cachedInputTokens: normalized?.prompt_tokens_details?.cached_tokens,
|
|
2168
|
-
requestBytes: promptBytes,
|
|
2169
|
-
responseBytes,
|
|
2170
|
-
model: modelName,
|
|
2171
|
-
provider: getProviderName(runtime.model || opts.model),
|
|
2172
|
-
messageList: messagesWithResponse
|
|
2173
|
-
});
|
|
2174
|
-
if (normalized) {
|
|
2175
|
-
const usageState = state.usage || { perRequest: [], totals: {} };
|
|
2176
|
-
const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2177
|
-
const turn = usageState.perRequest.length + 1;
|
|
2178
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2179
|
-
const cachedInputTok = normalized.prompt_tokens_details?.cached_tokens;
|
|
2180
|
-
usageState.perRequest.push({ id, modelName, usage: normalized, timestamp, turn, cachedInput: cachedInputTok });
|
|
2181
|
-
const inputTok = normalized.prompt_tokens;
|
|
2182
|
-
const outputTok = normalized.completion_tokens;
|
|
2183
|
-
const totalTok = normalized.total_tokens;
|
|
2184
|
-
const key = modelName;
|
|
2185
|
-
const agg = usageState.totals[key] || { input: 0, output: 0, total: 0, cachedInput: 0 };
|
|
2186
|
-
usageState.totals[key] = {
|
|
2187
|
-
input: agg.input + (Number(inputTok) || 0),
|
|
2188
|
-
output: agg.output + (Number(outputTok) || 0),
|
|
2189
|
-
total: agg.total + (Number(totalTok) || 0),
|
|
2190
|
-
cachedInput: agg.cachedInput + (Number(cachedInputTok) || 0)
|
|
2191
|
-
};
|
|
2192
|
-
state.usage = usageState;
|
|
2193
|
-
}
|
|
2194
|
-
return { messages: messagesWithResponse, usage: state.usage };
|
|
2195
|
-
};
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
|
-
// src/utils/content.ts
|
|
2199
|
-
function contentToString(content) {
|
|
2200
|
-
try {
|
|
2201
|
-
if (content == null) return "";
|
|
2202
|
-
if (typeof content === "string") return content;
|
|
2203
|
-
if (Array.isArray(content)) {
|
|
2204
|
-
return content.map((p) => {
|
|
2205
|
-
if (!p || typeof p !== "object") return String(p);
|
|
2206
|
-
if (p.type === "text") return String(p.text ?? "");
|
|
2207
|
-
if (p.type === "image_url") {
|
|
2208
|
-
const img = p.image_url;
|
|
2209
|
-
const url = typeof img === "string" ? img : img?.url;
|
|
2210
|
-
const detail = typeof img === "string" ? void 0 : img?.detail;
|
|
2211
|
-
return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
|
|
2212
|
-
}
|
|
2213
|
-
return JSON.stringify(p);
|
|
2214
|
-
}).join("\n");
|
|
2215
|
-
}
|
|
2216
|
-
return JSON.stringify(content);
|
|
2217
|
-
} catch {
|
|
2218
|
-
return String(content);
|
|
2219
|
-
}
|
|
2220
|
-
}
|
|
2221
|
-
function mergeContentsToString(contents) {
|
|
2222
|
-
return contents.map((c) => contentToString(c)).join("\n");
|
|
2223
|
-
}
|
|
2224
|
-
function safeStringify(value, pretty = false) {
|
|
2225
|
-
if (value == null) return "";
|
|
2226
|
-
if (typeof value === "string") return value;
|
|
2227
|
-
try {
|
|
2228
|
-
return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
|
|
2229
|
-
} catch {
|
|
2230
|
-
return String(value);
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
function extractMessageText(message) {
|
|
2234
|
-
if (!message) return "";
|
|
2235
|
-
const content = message.content;
|
|
2236
|
-
if (typeof content === "string") return content;
|
|
2237
|
-
if (Array.isArray(content)) {
|
|
2238
|
-
return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
|
|
2239
|
-
}
|
|
2240
|
-
return "";
|
|
2241
|
-
}
|
|
2242
|
-
|
|
2243
|
-
// src/utils/traceSections.ts
|
|
2244
|
-
function truncate(text, max = 500) {
|
|
2245
|
-
if (!text) return "";
|
|
2246
|
-
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
2247
|
-
}
|
|
2248
|
-
function summarizeToolOutput(output) {
|
|
2249
|
-
if (output == null) return "";
|
|
2250
|
-
if (typeof output === "string") return truncate(output.trim());
|
|
2251
|
-
if (Array.isArray(output)) {
|
|
2252
|
-
const preview = output.slice(0, 3).map((item, index) => `${index + 1}. ${truncate(safeStringify(item))}`).join("\n");
|
|
2253
|
-
const suffix = output.length > 3 ? `
|
|
2254
|
-
\u2026 (+${output.length - 3} more)` : "";
|
|
2255
|
-
return `${preview}${suffix}`.trim();
|
|
2256
|
-
}
|
|
2257
|
-
if (typeof output === "object") {
|
|
2258
|
-
if (Array.isArray(output.items)) {
|
|
2259
|
-
return summarizeToolOutput(output.items);
|
|
2260
|
-
}
|
|
2261
|
-
return truncate(safeStringify(output));
|
|
2262
|
-
}
|
|
2263
|
-
return truncate(String(output));
|
|
2264
|
-
}
|
|
2265
|
-
function extractToolItems(output) {
|
|
2266
|
-
const source = Array.isArray(output) ? output : Array.isArray(output?.items) ? output.items : void 0;
|
|
2267
|
-
if (!Array.isArray(source) || source.length === 0) return void 0;
|
|
2268
|
-
return source.slice(0, 5).map((item) => {
|
|
2269
|
-
if (item && typeof item === "object") {
|
|
2270
|
-
const snippetSource = item.content ?? item.snippet ?? item.description ?? item.text ?? item.summary ?? item;
|
|
2271
|
-
return {
|
|
2272
|
-
title: typeof item.title === "string" ? item.title : void 0,
|
|
2273
|
-
url: typeof item.url === "string" ? item.url : void 0,
|
|
2274
|
-
snippet: truncate(safeStringify(snippetSource))
|
|
2275
|
-
};
|
|
2276
|
-
}
|
|
2277
|
-
return { snippet: truncate(safeStringify(item)) };
|
|
2278
|
-
});
|
|
2279
|
-
}
|
|
2280
|
-
|
|
2281
1953
|
// src/smart/runtimeConfig.ts
|
|
2282
1954
|
var DEFAULT_CRITICAL_TOOLS = ["response", "manage_todo_list", "get_tool_response"];
|
|
2283
1955
|
var BASE_DEFAULTS = {
|
|
@@ -2330,8 +2002,42 @@ var BASE_DEFAULTS = {
|
|
|
2330
2002
|
toolResponseRetentionByTool: {},
|
|
2331
2003
|
criticalTools: [...DEFAULT_CRITICAL_TOOLS],
|
|
2332
2004
|
schemaValidation: "strict"
|
|
2005
|
+
},
|
|
2006
|
+
contextPilot: {
|
|
2007
|
+
// Opt-in: ContextPilot never alters tool output unless the caller
|
|
2008
|
+
// explicitly passes `contextPilot: { enabled: true }` (or sets `enabled`
|
|
2009
|
+
// via `customProfile`/profile overrides). This preserves backward
|
|
2010
|
+
// compatibility for every existing `createSmartAgent(...)` call site.
|
|
2011
|
+
enabled: false,
|
|
2012
|
+
compression: {
|
|
2013
|
+
json: { enabled: true, targetRatio: 0.35, minItems: 20 },
|
|
2014
|
+
text: { enabled: true, targetRatio: 0.5, minChars: 1200 },
|
|
2015
|
+
diff: { enabled: true, contextLines: 3 },
|
|
2016
|
+
log: { enabled: true, maxLines: 60 },
|
|
2017
|
+
search: { enabled: true, maxMatches: 30 }
|
|
2018
|
+
},
|
|
2019
|
+
ccr: { enabled: true, ttlMs: 30 * 60 * 1e3, maxEntries: 500 },
|
|
2020
|
+
cacheAlignment: { enabled: true, warnOnVolatilePrompt: true },
|
|
2021
|
+
dedup: { enabled: true, minChars: 500 },
|
|
2022
|
+
excludeTools: []
|
|
2333
2023
|
}
|
|
2334
2024
|
};
|
|
2025
|
+
function mergeContextPilot(base, override) {
|
|
2026
|
+
return {
|
|
2027
|
+
enabled: override?.enabled ?? base.enabled,
|
|
2028
|
+
compression: {
|
|
2029
|
+
json: { ...base.compression.json, ...override?.compression?.json },
|
|
2030
|
+
text: { ...base.compression.text, ...override?.compression?.text },
|
|
2031
|
+
diff: { ...base.compression.diff, ...override?.compression?.diff },
|
|
2032
|
+
log: { ...base.compression.log, ...override?.compression?.log },
|
|
2033
|
+
search: { ...base.compression.search, ...override?.compression?.search }
|
|
2034
|
+
},
|
|
2035
|
+
ccr: { ...base.ccr, ...override?.ccr },
|
|
2036
|
+
cacheAlignment: { ...base.cacheAlignment, ...override?.cacheAlignment },
|
|
2037
|
+
dedup: { ...base.dedup, ...override?.dedup },
|
|
2038
|
+
excludeTools: override?.excludeTools ?? base.excludeTools
|
|
2039
|
+
};
|
|
2040
|
+
}
|
|
2335
2041
|
function buildProfile(overrides) {
|
|
2336
2042
|
return {
|
|
2337
2043
|
limits: { ...BASE_DEFAULTS.limits, ...overrides.limits },
|
|
@@ -2349,144 +2055,956 @@ function buildProfile(overrides) {
|
|
|
2349
2055
|
...overrides.toolResponses,
|
|
2350
2056
|
criticalTools: overrides.toolResponses?.criticalTools ?? [...DEFAULT_CRITICAL_TOOLS],
|
|
2351
2057
|
toolResponseRetentionByTool: overrides.toolResponses?.toolResponseRetentionByTool ?? {}
|
|
2058
|
+
},
|
|
2059
|
+
contextPilot: mergeContextPilot(BASE_DEFAULTS.contextPilot, overrides.contextPilot)
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
2062
|
+
var DEFAULT_PROFILE_CONFIGS = {
|
|
2063
|
+
fast: buildProfile({
|
|
2064
|
+
limits: { maxToolCalls: 8, maxParallelTools: 3, maxContextTokens: 32e3 },
|
|
2065
|
+
summarization: {
|
|
2066
|
+
maxTokens: 32e3,
|
|
2067
|
+
summaryTriggerTokens: 24e3,
|
|
2068
|
+
summaryPromptMaxTokens: 6e3,
|
|
2069
|
+
summaryCompressionRatioTarget: 0.5
|
|
2070
|
+
},
|
|
2071
|
+
context: {
|
|
2072
|
+
lastTurnsToKeep: 8,
|
|
2073
|
+
toolResponsePolicy: "keep_structured",
|
|
2074
|
+
budget: { systemReserveTokens: 1500, goalsReserveTokens: 1200, recentTurnsReserveTokens: 6e3, toolResponseReserveTokens: 3500 }
|
|
2075
|
+
},
|
|
2076
|
+
memory: { readPolicy: "recent_only" },
|
|
2077
|
+
delegation: { mode: "off", maxDelegationDepth: 1, maxChildCalls: 2, maxParallelChild: 1, childContextPolicy: "minimal" },
|
|
2078
|
+
toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 },
|
|
2079
|
+
contextPilot: {
|
|
2080
|
+
compression: {
|
|
2081
|
+
json: { targetRatio: 0.25, minItems: 12 },
|
|
2082
|
+
text: { targetRatio: 0.35, minChars: 800 }
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
}),
|
|
2086
|
+
balanced: buildProfile({}),
|
|
2087
|
+
deep: buildProfile({
|
|
2088
|
+
limits: { maxToolCalls: 40, maxParallelTools: 8, maxContextTokens: 2e5 },
|
|
2089
|
+
summarization: {
|
|
2090
|
+
maxTokens: 2e5,
|
|
2091
|
+
summaryTriggerTokens: 15e4,
|
|
2092
|
+
summaryPromptMaxTokens: 16e3,
|
|
2093
|
+
summaryCompressionRatioTarget: 0.4
|
|
2094
|
+
},
|
|
2095
|
+
context: {
|
|
2096
|
+
lastTurnsToKeep: 30,
|
|
2097
|
+
budget: { systemReserveTokens: 2500, goalsReserveTokens: 2500, recentTurnsReserveTokens: 36e3, toolResponseReserveTokens: 18e3 }
|
|
2098
|
+
},
|
|
2099
|
+
memory: { scope: "workspace" },
|
|
2100
|
+
delegation: { maxDelegationDepth: 3, maxChildCalls: 10, maxParallelChild: 4 },
|
|
2101
|
+
toolResponses: { maxToolResponseChars: 64e3, maxToolResponseTokens: 16e3 },
|
|
2102
|
+
contextPilot: {
|
|
2103
|
+
compression: {
|
|
2104
|
+
json: { targetRatio: 0.5, minItems: 30 },
|
|
2105
|
+
text: { targetRatio: 0.6, minChars: 1600 }
|
|
2106
|
+
},
|
|
2107
|
+
ccr: { ttlMs: 60 * 60 * 1e3 }
|
|
2108
|
+
}
|
|
2109
|
+
}),
|
|
2110
|
+
research: buildProfile({
|
|
2111
|
+
limits: { maxToolCalls: 80, maxParallelTools: 10, maxContextTokens: 4e5 },
|
|
2112
|
+
summarization: {
|
|
2113
|
+
maxTokens: 4e5,
|
|
2114
|
+
summaryTriggerTokens: 3e5,
|
|
2115
|
+
summaryPromptMaxTokens: 24e3,
|
|
2116
|
+
summaryCompressionRatioTarget: 0.35
|
|
2117
|
+
},
|
|
2118
|
+
context: {
|
|
2119
|
+
lastTurnsToKeep: 60,
|
|
2120
|
+
budget: { systemReserveTokens: 3e3, goalsReserveTokens: 3e3, recentTurnsReserveTokens: 72e3, toolResponseReserveTokens: 32e3 }
|
|
2121
|
+
},
|
|
2122
|
+
memory: { scope: "workspace" },
|
|
2123
|
+
delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 16, maxParallelChild: 6, childContextPolicy: "full" },
|
|
2124
|
+
toolResponses: { maxToolResponseChars: 96e3, maxToolResponseTokens: 24e3 },
|
|
2125
|
+
contextPilot: {
|
|
2126
|
+
compression: {
|
|
2127
|
+
json: { targetRatio: 0.6, minItems: 40 },
|
|
2128
|
+
text: { targetRatio: 0.65, minChars: 2e3 }
|
|
2129
|
+
},
|
|
2130
|
+
ccr: { ttlMs: 2 * 60 * 60 * 1e3, maxEntries: 1e3 }
|
|
2131
|
+
}
|
|
2132
|
+
})
|
|
2133
|
+
};
|
|
2134
|
+
function mergeLimits(base, override) {
|
|
2135
|
+
return {
|
|
2136
|
+
maxToolCalls: override?.maxToolCalls ?? base.maxToolCalls,
|
|
2137
|
+
maxParallelTools: override?.maxParallelTools ?? base.maxParallelTools,
|
|
2138
|
+
maxContextTokens: override?.maxContextTokens ?? base.maxContextTokens,
|
|
2139
|
+
maxTotalOutputTokens: override?.maxTotalOutputTokens ?? base.maxTotalOutputTokens ?? 0,
|
|
2140
|
+
maxCostUsd: override?.maxCostUsd ?? base.maxCostUsd ?? 0,
|
|
2141
|
+
maxWallClockMs: override?.maxWallClockMs ?? base.maxWallClockMs ?? 0
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
function resolveBaseProfile(opts, runtimeProfile) {
|
|
2145
|
+
if (opts.customProfile?.extends) return opts.customProfile.extends;
|
|
2146
|
+
if (runtimeProfile !== "custom") return runtimeProfile;
|
|
2147
|
+
return "balanced";
|
|
2148
|
+
}
|
|
2149
|
+
function normalizeSmartAgentOptions(opts) {
|
|
2150
|
+
const runtimeProfile = opts.runtimeProfile ?? (opts.customProfile ? "custom" : "balanced");
|
|
2151
|
+
const baseProfile = resolveBaseProfile(opts, runtimeProfile);
|
|
2152
|
+
const preset = DEFAULT_PROFILE_CONFIGS[baseProfile];
|
|
2153
|
+
const customProfile = opts.customProfile || {};
|
|
2154
|
+
const useTodoList = opts.useTodoList === true;
|
|
2155
|
+
const summarizationDisabled = opts.summarization === false;
|
|
2156
|
+
const summarizationOverride = typeof opts.summarization === "object" ? opts.summarization : {};
|
|
2157
|
+
const planningMode = opts.planning?.mode ?? customProfile.planning?.mode ?? (useTodoList ? "todo" : preset.planning.mode);
|
|
2158
|
+
const memoryStore = opts.memory?.store ?? customProfile.memory?.store;
|
|
2159
|
+
const contextToolResponsePolicy = opts.context?.toolResponsePolicy ?? customProfile.context?.toolResponsePolicy ?? preset.context.toolResponsePolicy;
|
|
2160
|
+
return {
|
|
2161
|
+
runtimeProfile,
|
|
2162
|
+
baseProfile,
|
|
2163
|
+
limits: mergeLimits(mergeLimits(preset.limits, customProfile.limits), opts.limits),
|
|
2164
|
+
summarization: {
|
|
2165
|
+
...preset.summarization,
|
|
2166
|
+
...customProfile.summarization || {},
|
|
2167
|
+
...summarizationOverride,
|
|
2168
|
+
enable: summarizationDisabled ? false : summarizationOverride.enable ?? customProfile.summarization?.enable ?? preset.summarization.enable,
|
|
2169
|
+
maxTokens: summarizationOverride.maxTokens ?? opts.limits?.maxContextTokens ?? customProfile.summarization?.maxTokens ?? preset.summarization.maxTokens,
|
|
2170
|
+
summaryTriggerTokens: summarizationOverride.summaryTriggerTokens ?? summarizationOverride.maxTokens ?? opts.limits?.maxContextTokens ?? customProfile.summarization?.summaryTriggerTokens ?? customProfile.summarization?.maxTokens ?? preset.summarization.summaryTriggerTokens,
|
|
2171
|
+
promptTemplate: summarizationOverride.promptTemplate ?? customProfile.summarization?.promptTemplate ?? preset.summarization.promptTemplate
|
|
2172
|
+
},
|
|
2173
|
+
context: {
|
|
2174
|
+
...preset.context,
|
|
2175
|
+
...customProfile.context || {},
|
|
2176
|
+
...opts.context || {},
|
|
2177
|
+
budget: {
|
|
2178
|
+
...preset.context.budget,
|
|
2179
|
+
...customProfile.context?.budget || {},
|
|
2180
|
+
...opts.context?.budget || {}
|
|
2181
|
+
},
|
|
2182
|
+
toolResponsePolicy: contextToolResponsePolicy
|
|
2183
|
+
},
|
|
2184
|
+
planning: {
|
|
2185
|
+
...preset.planning,
|
|
2186
|
+
...customProfile.planning || {},
|
|
2187
|
+
...opts.planning || {},
|
|
2188
|
+
mode: planningMode
|
|
2189
|
+
},
|
|
2190
|
+
memory: {
|
|
2191
|
+
...preset.memory,
|
|
2192
|
+
...customProfile.memory || {},
|
|
2193
|
+
...opts.memory || {},
|
|
2194
|
+
store: memoryStore
|
|
2195
|
+
},
|
|
2196
|
+
delegation: {
|
|
2197
|
+
...preset.delegation,
|
|
2198
|
+
...customProfile.delegation || {},
|
|
2199
|
+
...opts.delegation || {}
|
|
2200
|
+
},
|
|
2201
|
+
toolResponses: {
|
|
2202
|
+
...preset.toolResponses,
|
|
2203
|
+
...customProfile.toolResponses || {},
|
|
2204
|
+
...opts.toolResponses || {},
|
|
2205
|
+
defaultPolicy: opts.toolResponses?.defaultPolicy ?? customProfile.toolResponses?.defaultPolicy ?? contextToolResponsePolicy,
|
|
2206
|
+
toolResponseRetentionByTool: {
|
|
2207
|
+
...preset.toolResponses.toolResponseRetentionByTool,
|
|
2208
|
+
...customProfile.toolResponses?.toolResponseRetentionByTool || {},
|
|
2209
|
+
...opts.toolResponses?.toolResponseRetentionByTool || {}
|
|
2210
|
+
},
|
|
2211
|
+
criticalTools: opts.toolResponses?.criticalTools ?? customProfile.toolResponses?.criticalTools ?? preset.toolResponses.criticalTools
|
|
2212
|
+
},
|
|
2213
|
+
contextPilot: mergeContextPilot(mergeContextPilot(preset.contextPilot, customProfile.contextPilot), opts.contextPilot)
|
|
2214
|
+
};
|
|
2215
|
+
}
|
|
2216
|
+
function getResolvedSmartConfig(opts, runtime) {
|
|
2217
|
+
return runtime?.smart || normalizeSmartAgentOptions(opts);
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
// src/smart/contextPilot/relevance.ts
|
|
2221
|
+
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
2222
|
+
"the",
|
|
2223
|
+
"a",
|
|
2224
|
+
"an",
|
|
2225
|
+
"and",
|
|
2226
|
+
"or",
|
|
2227
|
+
"but",
|
|
2228
|
+
"if",
|
|
2229
|
+
"then",
|
|
2230
|
+
"else",
|
|
2231
|
+
"for",
|
|
2232
|
+
"of",
|
|
2233
|
+
"in",
|
|
2234
|
+
"on",
|
|
2235
|
+
"at",
|
|
2236
|
+
"to",
|
|
2237
|
+
"by",
|
|
2238
|
+
"with",
|
|
2239
|
+
"is",
|
|
2240
|
+
"are",
|
|
2241
|
+
"was",
|
|
2242
|
+
"were",
|
|
2243
|
+
"be",
|
|
2244
|
+
"been",
|
|
2245
|
+
"being",
|
|
2246
|
+
"this",
|
|
2247
|
+
"that",
|
|
2248
|
+
"these",
|
|
2249
|
+
"those",
|
|
2250
|
+
"it",
|
|
2251
|
+
"its",
|
|
2252
|
+
"as",
|
|
2253
|
+
"from"
|
|
2254
|
+
]);
|
|
2255
|
+
function tokenize(text) {
|
|
2256
|
+
if (!text) return [];
|
|
2257
|
+
const matches = text.toLowerCase().match(/[\p{L}\p{N}_]+/gu);
|
|
2258
|
+
if (!matches) return [];
|
|
2259
|
+
return matches.filter((token) => token.length > 1 && !STOPWORDS.has(token));
|
|
2260
|
+
}
|
|
2261
|
+
function scoreItemsByRelevance(docs, query, params = {}) {
|
|
2262
|
+
const k1 = params.k1 ?? 1.5;
|
|
2263
|
+
const b = params.b ?? 0.75;
|
|
2264
|
+
const queryTokens = tokenize(query);
|
|
2265
|
+
const docTokens = docs.map((doc) => tokenize(doc));
|
|
2266
|
+
if (queryTokens.length === 0) {
|
|
2267
|
+
return docs.map(() => 1);
|
|
2268
|
+
}
|
|
2269
|
+
const docLengths = docTokens.map((tokens) => tokens.length);
|
|
2270
|
+
const avgDocLen = docLengths.reduce((sum2, len) => sum2 + len, 0) / Math.max(1, docLengths.length);
|
|
2271
|
+
const uniqueQueryTerms = [...new Set(queryTokens)];
|
|
2272
|
+
const df = /* @__PURE__ */ new Map();
|
|
2273
|
+
for (const term of uniqueQueryTerms) {
|
|
2274
|
+
let count = 0;
|
|
2275
|
+
for (const tokens of docTokens) {
|
|
2276
|
+
if (tokens.includes(term)) count += 1;
|
|
2277
|
+
}
|
|
2278
|
+
df.set(term, count);
|
|
2279
|
+
}
|
|
2280
|
+
const n = docs.length;
|
|
2281
|
+
const idf = /* @__PURE__ */ new Map();
|
|
2282
|
+
for (const term of uniqueQueryTerms) {
|
|
2283
|
+
const freq = df.get(term) || 0;
|
|
2284
|
+
idf.set(term, Math.log(1 + (n - freq + 0.5) / (freq + 0.5)));
|
|
2285
|
+
}
|
|
2286
|
+
return docTokens.map((tokens, docIndex) => {
|
|
2287
|
+
if (tokens.length === 0) return 0;
|
|
2288
|
+
const termFreq = /* @__PURE__ */ new Map();
|
|
2289
|
+
for (const token of tokens) {
|
|
2290
|
+
termFreq.set(token, (termFreq.get(token) || 0) + 1);
|
|
2291
|
+
}
|
|
2292
|
+
const docLen = docLengths[docIndex];
|
|
2293
|
+
let score = 0;
|
|
2294
|
+
for (const term of uniqueQueryTerms) {
|
|
2295
|
+
const freq = termFreq.get(term) || 0;
|
|
2296
|
+
if (freq === 0) continue;
|
|
2297
|
+
const termIdf = idf.get(term) || 0;
|
|
2298
|
+
const numerator = freq * (k1 + 1);
|
|
2299
|
+
const denominator = freq + k1 * (1 - b + b * docLen / avgDocLen);
|
|
2300
|
+
score += termIdf * (numerator / denominator);
|
|
2301
|
+
}
|
|
2302
|
+
return score;
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2305
|
+
function selectTopIndicesInOrder(scores, count) {
|
|
2306
|
+
const ranked = scores.map((score, index) => ({ score, index })).sort((a, b) => b.score - a.score).slice(0, Math.max(0, count)).map((entry) => entry.index);
|
|
2307
|
+
return ranked.sort((a, b) => a - b);
|
|
2308
|
+
}
|
|
2309
|
+
var CCRStore = class _CCRStore {
|
|
2310
|
+
constructor(options = {}) {
|
|
2311
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
2312
|
+
this.defaultTtlMs = options.ttlMs ?? 30 * 60 * 1e3;
|
|
2313
|
+
this.maxEntries = options.maxEntries ?? 500;
|
|
2314
|
+
}
|
|
2315
|
+
/** Stores `value` and returns a short content hash that can be used to retrieve it later. */
|
|
2316
|
+
store(value, ttlMs) {
|
|
2317
|
+
const hash = _CCRStore.hashOf(value);
|
|
2318
|
+
this.entries.delete(hash);
|
|
2319
|
+
this.entries.set(hash, { value, storedAt: Date.now(), ttlMs: ttlMs ?? this.defaultTtlMs });
|
|
2320
|
+
this.evictIfNeeded();
|
|
2321
|
+
return hash;
|
|
2322
|
+
}
|
|
2323
|
+
/** Returns the original value for `hash`, or `undefined` if missing/expired. */
|
|
2324
|
+
retrieve(hash) {
|
|
2325
|
+
const entry = this.entries.get(hash);
|
|
2326
|
+
if (!entry) return void 0;
|
|
2327
|
+
if (Date.now() - entry.storedAt > entry.ttlMs) {
|
|
2328
|
+
this.entries.delete(hash);
|
|
2329
|
+
return void 0;
|
|
2330
|
+
}
|
|
2331
|
+
return entry.value;
|
|
2332
|
+
}
|
|
2333
|
+
has(hash) {
|
|
2334
|
+
return this.retrieve(hash) !== void 0;
|
|
2335
|
+
}
|
|
2336
|
+
get size() {
|
|
2337
|
+
return this.entries.size;
|
|
2338
|
+
}
|
|
2339
|
+
evictIfNeeded() {
|
|
2340
|
+
while (this.entries.size > this.maxEntries) {
|
|
2341
|
+
const oldestKey = this.entries.keys().next().value;
|
|
2342
|
+
if (oldestKey === void 0) break;
|
|
2343
|
+
this.entries.delete(oldestKey);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
static hashOf(value) {
|
|
2347
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
2348
|
+
return crypto.createHash("sha1").update(serialized).digest("hex").slice(0, 16);
|
|
2349
|
+
}
|
|
2350
|
+
};
|
|
2351
|
+
var DedupTracker = class {
|
|
2352
|
+
constructor() {
|
|
2353
|
+
this.seen = /* @__PURE__ */ new Map();
|
|
2354
|
+
}
|
|
2355
|
+
/**
|
|
2356
|
+
* Registers `content` under `executionId`/`toolName`. Returns the entry
|
|
2357
|
+
* that first produced this exact content, or `undefined` if this is the
|
|
2358
|
+
* first time it has been seen.
|
|
2359
|
+
*/
|
|
2360
|
+
checkAndRegister(content, executionId, toolName) {
|
|
2361
|
+
const hash = crypto.createHash("sha1").update(content).digest("hex");
|
|
2362
|
+
const existing = this.seen.get(hash);
|
|
2363
|
+
if (!existing) {
|
|
2364
|
+
this.seen.set(hash, { executionId, toolName });
|
|
2365
|
+
}
|
|
2366
|
+
return existing;
|
|
2367
|
+
}
|
|
2368
|
+
};
|
|
2369
|
+
|
|
2370
|
+
// src/smart/contextPilot/cacheAligner.ts
|
|
2371
|
+
var PATTERNS = [
|
|
2372
|
+
{ kind: "uuid", regex: /\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/g },
|
|
2373
|
+
{ kind: "iso8601", regex: /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?\b/g },
|
|
2374
|
+
{ kind: "jwt", regex: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g },
|
|
2375
|
+
{ kind: "hex_hash", regex: /\b[0-9a-fA-F]{64}\b|\b[0-9a-fA-F]{40}\b|\b[0-9a-fA-F]{32}\b/g },
|
|
2376
|
+
{ kind: "api_key", regex: /\b(?:sk|pk|ghp|gho|ghu|ghs)-[A-Za-z0-9]{10,}\b/g },
|
|
2377
|
+
{ kind: "unix_timestamp", regex: /\b1\d{12}\b(?!\d)|\b1\d{9}\b(?!\d)/g }
|
|
2378
|
+
];
|
|
2379
|
+
function detectVolatileContent(text, limit = 20) {
|
|
2380
|
+
if (!text) return [];
|
|
2381
|
+
const findings = [];
|
|
2382
|
+
for (const { kind, regex } of PATTERNS) {
|
|
2383
|
+
regex.lastIndex = 0;
|
|
2384
|
+
let match;
|
|
2385
|
+
while (findings.length < limit && (match = regex.exec(text)) !== null) {
|
|
2386
|
+
findings.push({ pattern: kind, match: match[0], index: match.index });
|
|
2387
|
+
if (regex.lastIndex === match.index) regex.lastIndex += 1;
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
return findings;
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
// src/smart/contextPilot/jsonCrusher.ts
|
|
2394
|
+
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
|
+
var CONTEXT_PILOT_JSON_MARKER_KEY = "__contextPilotDropped";
|
|
2443
|
+
function findCompressibleArray(output, minItems) {
|
|
2444
|
+
if (Array.isArray(output)) {
|
|
2445
|
+
return { array: output, wrap: (arr) => arr };
|
|
2446
|
+
}
|
|
2447
|
+
if (output && typeof output === "object") {
|
|
2448
|
+
let bestKey;
|
|
2449
|
+
let bestArray;
|
|
2450
|
+
for (const [key, value] of Object.entries(output)) {
|
|
2451
|
+
if (Array.isArray(value) && (!bestArray || value.length > bestArray.length)) {
|
|
2452
|
+
bestKey = key;
|
|
2453
|
+
bestArray = value;
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
if (bestKey && bestArray && bestArray.length >= minItems) {
|
|
2457
|
+
const key = bestKey;
|
|
2458
|
+
return {
|
|
2459
|
+
array: bestArray,
|
|
2460
|
+
wrap: (arr) => ({ ...output, [key]: arr })
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
return null;
|
|
2465
|
+
}
|
|
2466
|
+
function notApplied(output) {
|
|
2467
|
+
const tokens = countApproxTokens(safeStringify(output));
|
|
2468
|
+
return { applied: false, compressorUsed: "none", output, originalTokens: tokens, compressedTokens: tokens };
|
|
2469
|
+
}
|
|
2470
|
+
function compressJsonOutput(output, query, config, ccrStore) {
|
|
2471
|
+
if (!config.enabled) return notApplied(output);
|
|
2472
|
+
const target = findCompressibleArray(output, config.minItems);
|
|
2473
|
+
if (!target || target.array.length < config.minItems) return notApplied(output);
|
|
2474
|
+
const { array, wrap } = target;
|
|
2475
|
+
const itemTexts = array.map((item) => safeStringify(item));
|
|
2476
|
+
const scores = scoreItemsByRelevance(itemTexts, query);
|
|
2477
|
+
const keepCount = Math.max(1, Math.min(array.length, Math.ceil(array.length * config.targetRatio)));
|
|
2478
|
+
const keepIndices = new Set(selectTopIndicesInOrder(scores, keepCount));
|
|
2479
|
+
const droppedCount = array.length - keepIndices.size;
|
|
2480
|
+
if (droppedCount <= 0) return notApplied(output);
|
|
2481
|
+
const originalTokens = countApproxTokens(safeStringify(output));
|
|
2482
|
+
const ccrHash = ccrStore.store(output);
|
|
2483
|
+
const keptItems = array.filter((_item, index) => keepIndices.has(index));
|
|
2484
|
+
const marker = {
|
|
2485
|
+
[CONTEXT_PILOT_JSON_MARKER_KEY]: droppedCount,
|
|
2486
|
+
note: `${droppedCount} lower-relevance item(s) omitted by ContextPilot. Use get_tool_response with executionId="${ccrHash}" to retrieve the full original array if a dropped item is actually needed.`
|
|
2487
|
+
};
|
|
2488
|
+
const compressedOutput = wrap([...keptItems, marker]);
|
|
2489
|
+
const compressedTokens = countApproxTokens(safeStringify(compressedOutput));
|
|
2490
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied(output);
|
|
2491
|
+
return {
|
|
2492
|
+
applied: true,
|
|
2493
|
+
compressorUsed: "jsonCrusher",
|
|
2494
|
+
output: compressedOutput,
|
|
2495
|
+
originalTokens,
|
|
2496
|
+
compressedTokens,
|
|
2497
|
+
droppedItems: droppedCount,
|
|
2498
|
+
ccrHash
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
// src/smart/contextPilot/textCrusher.ts
|
|
2503
|
+
init_utilTokens();
|
|
2504
|
+
function splitIntoSentences(text) {
|
|
2505
|
+
return text.split(/(?<=[.!?。!?\n])\s*/u).map((sentence) => sentence.trim()).filter(Boolean);
|
|
2506
|
+
}
|
|
2507
|
+
function normalizeForDedup(sentence) {
|
|
2508
|
+
return sentence.toLowerCase().replace(/\s+/g, " ").trim();
|
|
2509
|
+
}
|
|
2510
|
+
function notApplied2(text) {
|
|
2511
|
+
const tokens = countApproxTokens(text);
|
|
2512
|
+
return { applied: false, compressorUsed: "none", output: text, originalTokens: tokens, compressedTokens: tokens };
|
|
2513
|
+
}
|
|
2514
|
+
function compressTextOutput(text, query, config, ccrStore) {
|
|
2515
|
+
if (!config.enabled || text.length < config.minChars) return notApplied2(text);
|
|
2516
|
+
const rawSentences = splitIntoSentences(text);
|
|
2517
|
+
if (rawSentences.length < 6) return notApplied2(text);
|
|
2518
|
+
const seenNormalized = /* @__PURE__ */ new Set();
|
|
2519
|
+
const dedupedIndices = [];
|
|
2520
|
+
rawSentences.forEach((sentence, index) => {
|
|
2521
|
+
const key = normalizeForDedup(sentence);
|
|
2522
|
+
if (seenNormalized.has(key)) return;
|
|
2523
|
+
seenNormalized.add(key);
|
|
2524
|
+
dedupedIndices.push(index);
|
|
2525
|
+
});
|
|
2526
|
+
const relevanceScores = scoreItemsByRelevance(dedupedIndices.map((i) => rawSentences[i]), query);
|
|
2527
|
+
const recencyBoost = dedupedIndices.map((_value, position) => position / Math.max(1, dedupedIndices.length - 1));
|
|
2528
|
+
const combinedScores = relevanceScores.map((score, i) => score + recencyBoost[i] * 0.25);
|
|
2529
|
+
const keepCount = Math.max(3, Math.ceil(dedupedIndices.length * config.targetRatio));
|
|
2530
|
+
const keepPositions = new Set(selectTopIndicesInOrder(combinedScores, keepCount));
|
|
2531
|
+
const keptSentences = dedupedIndices.filter((_index, position) => keepPositions.has(position)).map((i) => rawSentences[i]);
|
|
2532
|
+
const droppedCount = rawSentences.length - keptSentences.length;
|
|
2533
|
+
if (droppedCount <= 0) return notApplied2(text);
|
|
2534
|
+
const originalTokens = countApproxTokens(text);
|
|
2535
|
+
const ccrHash = ccrStore.store(text);
|
|
2536
|
+
const compressedText = `${keptSentences.join(" ")}
|
|
2537
|
+
[ContextPilot: ${droppedCount} lower-relevance sentence(s) omitted. Use get_tool_response with executionId="${ccrHash}" to retrieve the full original text.]`;
|
|
2538
|
+
const compressedTokens = countApproxTokens(compressedText);
|
|
2539
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied2(text);
|
|
2540
|
+
return {
|
|
2541
|
+
applied: true,
|
|
2542
|
+
compressorUsed: "textCrusher",
|
|
2543
|
+
output: compressedText,
|
|
2544
|
+
originalTokens,
|
|
2545
|
+
compressedTokens,
|
|
2546
|
+
droppedItems: droppedCount,
|
|
2547
|
+
ccrHash
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
// src/smart/contextPilot/formatCompressors.ts
|
|
2552
|
+
init_utilTokens();
|
|
2553
|
+
function notApplied3(text) {
|
|
2554
|
+
const tokens = countApproxTokens(text);
|
|
2555
|
+
return { applied: false, compressorUsed: "none", output: text, originalTokens: tokens, compressedTokens: tokens };
|
|
2556
|
+
}
|
|
2557
|
+
function detectTextFormat(text) {
|
|
2558
|
+
const sample = text.slice(0, 2e3);
|
|
2559
|
+
if (/^diff --git |^---\s|^\+\+\+\s|^@@ -\d+/m.test(sample)) return "diff";
|
|
2560
|
+
if (/^[\w./-]+:\d+:/m.test(sample) || /^[\w./-]+-\d+-/m.test(sample)) return "search";
|
|
2561
|
+
if (/\b(ERROR|FAIL|FAILED|WARN|PASS|PASSED)\b/.test(sample) && text.split("\n").length > 15) return "log";
|
|
2562
|
+
return "text";
|
|
2563
|
+
}
|
|
2564
|
+
function compressDiffOutput(text, config, ccrStore) {
|
|
2565
|
+
if (!config.enabled) return notApplied3(text);
|
|
2566
|
+
const lines = text.split("\n");
|
|
2567
|
+
const kept = [];
|
|
2568
|
+
let contextRun = 0;
|
|
2569
|
+
let trimmedAny = false;
|
|
2570
|
+
for (const line of lines) {
|
|
2571
|
+
const isHeader = line.startsWith("diff --git") || line.startsWith("---") || line.startsWith("+++") || line.startsWith("@@");
|
|
2572
|
+
const isChange = line.startsWith("+") || line.startsWith("-");
|
|
2573
|
+
if (isHeader || isChange) {
|
|
2574
|
+
kept.push(line);
|
|
2575
|
+
contextRun = 0;
|
|
2576
|
+
continue;
|
|
2577
|
+
}
|
|
2578
|
+
if (contextRun < config.contextLines) {
|
|
2579
|
+
kept.push(line);
|
|
2580
|
+
contextRun += 1;
|
|
2581
|
+
} else {
|
|
2582
|
+
trimmedAny = true;
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
if (!trimmedAny) return notApplied3(text);
|
|
2586
|
+
const originalTokens = countApproxTokens(text);
|
|
2587
|
+
const ccrHash = ccrStore.store(text);
|
|
2588
|
+
const compressedText = `${kept.join("\n")}
|
|
2589
|
+
[ContextPilot: unchanged context lines beyond ${config.contextLines} trimmed. Use get_tool_response with executionId="${ccrHash}" to retrieve the full diff.]`;
|
|
2590
|
+
const compressedTokens = countApproxTokens(compressedText);
|
|
2591
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied3(text);
|
|
2592
|
+
return { applied: true, compressorUsed: "diffCompressor", output: compressedText, originalTokens, compressedTokens, ccrHash };
|
|
2593
|
+
}
|
|
2594
|
+
var LOG_LEVEL_SCORE = [
|
|
2595
|
+
{ regex: /\b(FAIL|FAILED|ERROR|FATAL|EXCEPTION|TRACEBACK)\b/i, score: 1 },
|
|
2596
|
+
{ regex: /\b(WARN|WARNING)\b/i, score: 0.7 },
|
|
2597
|
+
{ regex: /\b(PASS|PASSED|OK|SUCCESS)\b/i, score: 0.4 },
|
|
2598
|
+
{ regex: /\bINFO\b/i, score: 0.3 },
|
|
2599
|
+
{ regex: /\b(DEBUG|TRACE)\b/i, score: 0.1 }
|
|
2600
|
+
];
|
|
2601
|
+
function scoreLogLine(line) {
|
|
2602
|
+
for (const { regex, score } of LOG_LEVEL_SCORE) {
|
|
2603
|
+
if (regex.test(line)) return score;
|
|
2604
|
+
}
|
|
2605
|
+
return 0.2;
|
|
2606
|
+
}
|
|
2607
|
+
function compressLogOutput(text, config, ccrStore) {
|
|
2608
|
+
if (!config.enabled) return notApplied3(text);
|
|
2609
|
+
const lines = text.split("\n").filter((line) => line.length > 0);
|
|
2610
|
+
if (lines.length <= config.maxLines) return notApplied3(text);
|
|
2611
|
+
const scored = lines.map((line, index) => ({ line, index, score: scoreLogLine(line) }));
|
|
2612
|
+
const mustKeep = /* @__PURE__ */ new Set([0, lines.length - 1]);
|
|
2613
|
+
const ranked = scored.filter((entry) => !mustKeep.has(entry.index)).sort((a, b) => b.score - a.score).slice(0, Math.max(0, config.maxLines - mustKeep.size)).map((entry) => entry.index);
|
|
2614
|
+
const keepIndices = /* @__PURE__ */ new Set([...mustKeep, ...ranked]);
|
|
2615
|
+
const droppedCount = lines.length - keepIndices.size;
|
|
2616
|
+
if (droppedCount <= 0) return notApplied3(text);
|
|
2617
|
+
const originalTokens = countApproxTokens(text);
|
|
2618
|
+
const ccrHash = ccrStore.store(text);
|
|
2619
|
+
const keptLines = lines.filter((_line, index) => keepIndices.has(index));
|
|
2620
|
+
const compressedText = `${keptLines.join("\n")}
|
|
2621
|
+
[ContextPilot: ${droppedCount} lower-priority log line(s) omitted (errors/warnings preserved). Use get_tool_response with executionId="${ccrHash}" to retrieve the full log.]`;
|
|
2622
|
+
const compressedTokens = countApproxTokens(compressedText);
|
|
2623
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied3(text);
|
|
2624
|
+
return { applied: true, compressorUsed: "logCompressor", output: compressedText, originalTokens, compressedTokens, droppedItems: droppedCount, ccrHash };
|
|
2625
|
+
}
|
|
2626
|
+
function compressSearchOutput(text, config, ccrStore) {
|
|
2627
|
+
if (!config.enabled) return notApplied3(text);
|
|
2628
|
+
const lines = text.split("\n").filter((line) => line.length > 0);
|
|
2629
|
+
if (lines.length <= config.maxMatches) return notApplied3(text);
|
|
2630
|
+
const perFileCount = /* @__PURE__ */ new Map();
|
|
2631
|
+
const perFileCap = Math.max(3, Math.ceil(config.maxMatches / 4));
|
|
2632
|
+
const kept = [];
|
|
2633
|
+
for (const line of lines) {
|
|
2634
|
+
if (kept.length >= config.maxMatches) break;
|
|
2635
|
+
const fileKey = line.split(/[:-]/)[0] || "unknown";
|
|
2636
|
+
const count = perFileCount.get(fileKey) || 0;
|
|
2637
|
+
if (count >= perFileCap) continue;
|
|
2638
|
+
perFileCount.set(fileKey, count + 1);
|
|
2639
|
+
kept.push(line);
|
|
2640
|
+
}
|
|
2641
|
+
const droppedCount = lines.length - kept.length;
|
|
2642
|
+
if (droppedCount <= 0) return notApplied3(text);
|
|
2643
|
+
const originalTokens = countApproxTokens(text);
|
|
2644
|
+
const ccrHash = ccrStore.store(text);
|
|
2645
|
+
const compressedText = `${kept.join("\n")}
|
|
2646
|
+
[ContextPilot: ${droppedCount} additional match(es) omitted. Use get_tool_response with executionId="${ccrHash}" to retrieve all matches.]`;
|
|
2647
|
+
const compressedTokens = countApproxTokens(compressedText);
|
|
2648
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied3(text);
|
|
2649
|
+
return { applied: true, compressorUsed: "searchCompressor", output: compressedText, originalTokens, compressedTokens, droppedItems: droppedCount, ccrHash };
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2652
|
+
// src/smart/contextPilot/pipeline.ts
|
|
2653
|
+
init_utilTokens();
|
|
2654
|
+
function createContextPilotRuntime(config) {
|
|
2655
|
+
return {
|
|
2656
|
+
ccrStore: new CCRStore({ ttlMs: config.ccr.ttlMs, maxEntries: config.ccr.maxEntries }),
|
|
2657
|
+
dedupTracker: new DedupTracker()
|
|
2658
|
+
};
|
|
2659
|
+
}
|
|
2660
|
+
function extractLatestUserQuery(messages) {
|
|
2661
|
+
if (!Array.isArray(messages)) return "";
|
|
2662
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
2663
|
+
const message = messages[i];
|
|
2664
|
+
if (message?.role !== "user") continue;
|
|
2665
|
+
if (typeof message.content === "string") return message.content;
|
|
2666
|
+
if (Array.isArray(message.content)) {
|
|
2667
|
+
return message.content.map((part) => typeof part?.text === "string" ? part.text : "").filter(Boolean).join(" ");
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
return "";
|
|
2671
|
+
}
|
|
2672
|
+
function notApplied4(output) {
|
|
2673
|
+
const tokens = countApproxTokens(safeStringify(output));
|
|
2674
|
+
return { applied: false, compressorUsed: "none", output, originalTokens: tokens, compressedTokens: tokens };
|
|
2675
|
+
}
|
|
2676
|
+
function compressToolOutput(params) {
|
|
2677
|
+
const { toolName, output, query, executionId, config, runtime } = params;
|
|
2678
|
+
if (!config.enabled || config.excludeTools.includes(toolName)) return notApplied4(output);
|
|
2679
|
+
const ccrAvailable = config.ccr.enabled && config.ccr.maxEntries > 0;
|
|
2680
|
+
if (config.dedup.enabled) {
|
|
2681
|
+
const serialized = typeof output === "string" ? output : safeStringify(output);
|
|
2682
|
+
if (serialized.length >= config.dedup.minChars) {
|
|
2683
|
+
const duplicate = runtime.dedupTracker.checkAndRegister(serialized, executionId, toolName);
|
|
2684
|
+
if (duplicate) {
|
|
2685
|
+
const originalTokens = countApproxTokens(serialized);
|
|
2686
|
+
const pointer = `DUPLICATE_TOOL_RESPONSE [toolName=${toolName}]
|
|
2687
|
+
Identical to an earlier ${duplicate.toolName} result. Use get_tool_response with executionId="${duplicate.executionId}" to view it.`;
|
|
2688
|
+
return {
|
|
2689
|
+
applied: true,
|
|
2690
|
+
compressorUsed: "none",
|
|
2691
|
+
output: pointer,
|
|
2692
|
+
originalTokens,
|
|
2693
|
+
compressedTokens: countApproxTokens(pointer),
|
|
2694
|
+
duplicateOf: duplicate.executionId
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
if (typeof output !== "string") {
|
|
2700
|
+
if (ccrAvailable && config.compression.json.enabled) {
|
|
2701
|
+
const result = compressJsonOutput(output, query, config.compression.json, runtime.ccrStore);
|
|
2702
|
+
if (result.applied) return result;
|
|
2703
|
+
}
|
|
2704
|
+
return notApplied4(output);
|
|
2705
|
+
}
|
|
2706
|
+
const format = detectTextFormat(output);
|
|
2707
|
+
if (ccrAvailable && format === "diff" && config.compression.diff.enabled) {
|
|
2708
|
+
const result = compressDiffOutput(output, config.compression.diff, runtime.ccrStore);
|
|
2709
|
+
if (result.applied) return result;
|
|
2710
|
+
} else if (ccrAvailable && format === "log" && config.compression.log.enabled) {
|
|
2711
|
+
const result = compressLogOutput(output, config.compression.log, runtime.ccrStore);
|
|
2712
|
+
if (result.applied) return result;
|
|
2713
|
+
} else if (ccrAvailable && format === "search" && config.compression.search.enabled) {
|
|
2714
|
+
const result = compressSearchOutput(output, config.compression.search, runtime.ccrStore);
|
|
2715
|
+
if (result.applied) return result;
|
|
2716
|
+
}
|
|
2717
|
+
if (ccrAvailable && config.compression.text.enabled) {
|
|
2718
|
+
const result = compressTextOutput(output, query, config.compression.text, runtime.ccrStore);
|
|
2719
|
+
if (result.applied) return result;
|
|
2720
|
+
}
|
|
2721
|
+
return notApplied4(output);
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// src/nodes/agentCore.ts
|
|
2725
|
+
function createAgentCoreNode(opts) {
|
|
2726
|
+
return async (state) => {
|
|
2727
|
+
const runtime = state.agent || {
|
|
2728
|
+
name: opts.name,
|
|
2729
|
+
version: opts.version,
|
|
2730
|
+
model: opts.model,
|
|
2731
|
+
tools: opts.tools || [],
|
|
2732
|
+
guardrails: opts.guardrails,
|
|
2733
|
+
todoListPrompt: opts.todoListPrompt,
|
|
2734
|
+
limits: opts.limits,
|
|
2735
|
+
outputSchema: opts.outputSchema,
|
|
2736
|
+
tracing: opts.tracing,
|
|
2737
|
+
responseFormat: void 0
|
|
2738
|
+
};
|
|
2739
|
+
const tools = runtime.tools ?? [];
|
|
2740
|
+
const shouldUseStrictToolCalling = Boolean(
|
|
2741
|
+
runtime.responseFormat && runtime.model?.capabilities?.strictToolCalling
|
|
2742
|
+
);
|
|
2743
|
+
const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(
|
|
2744
|
+
tools,
|
|
2745
|
+
shouldUseStrictToolCalling ? { strict: true } : void 0
|
|
2746
|
+
) : runtime.model;
|
|
2747
|
+
const traceSession = state.ctx?.__traceSession;
|
|
2748
|
+
const actorName = runtime.name ?? opts.name ?? "agent";
|
|
2749
|
+
const actorVersion = runtime.version ?? opts.version;
|
|
2750
|
+
const start = Date.now();
|
|
2751
|
+
const shouldLogPrompt = !!traceSession && traceSession.resolvedConfig.logData;
|
|
2752
|
+
const promptPayload = shouldLogPrompt ? sanitizeTracePayload(state.messages) : void 0;
|
|
2753
|
+
const promptBytes = promptPayload !== void 0 ? estimatePayloadBytes(promptPayload) : void 0;
|
|
2754
|
+
const extractToolUses = (m) => {
|
|
2755
|
+
const tcs = m?.tool_calls || m?.additional_kwargs?.tool_calls;
|
|
2756
|
+
if (!Array.isArray(tcs)) return [];
|
|
2757
|
+
return tcs.map((tc) => ({ id: tc?.id, name: tc?.function?.name || tc?.name })).filter((x) => typeof x.id === "string" && x.id.length > 0);
|
|
2758
|
+
};
|
|
2759
|
+
const normalizeBedrockToolPairing = (input) => {
|
|
2760
|
+
const msgs = Array.isArray(input) ? [...input] : [];
|
|
2761
|
+
const validToolCallIds = /* @__PURE__ */ new Set();
|
|
2762
|
+
for (const m of msgs) {
|
|
2763
|
+
if (m?.role === "assistant") {
|
|
2764
|
+
for (const tu of extractToolUses(m)) {
|
|
2765
|
+
if (tu.id) validToolCallIds.add(tu.id);
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
const filteredMsgs = msgs.filter((m) => {
|
|
2770
|
+
if (m?.role === "tool") {
|
|
2771
|
+
const toolCallId = m.tool_call_id;
|
|
2772
|
+
if (!toolCallId || !validToolCallIds.has(toolCallId)) {
|
|
2773
|
+
return false;
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
return true;
|
|
2777
|
+
});
|
|
2778
|
+
for (let i = 0; i < filteredMsgs.length; i++) {
|
|
2779
|
+
const m = filteredMsgs[i];
|
|
2780
|
+
if (m?.role !== "assistant") continue;
|
|
2781
|
+
const toolUses = extractToolUses(m);
|
|
2782
|
+
if (toolUses.length === 0) continue;
|
|
2783
|
+
const next = filteredMsgs[i + 1];
|
|
2784
|
+
const firstId = toolUses[0]?.id;
|
|
2785
|
+
const nextIsToolForFirst = !!(next && next.role === "tool" && next.tool_call_id === firstId);
|
|
2786
|
+
if (nextIsToolForFirst) continue;
|
|
2787
|
+
const placeholders = toolUses.map((tu) => ({
|
|
2788
|
+
role: "tool",
|
|
2789
|
+
name: tu.name || "unknown_tool",
|
|
2790
|
+
tool_call_id: tu.id,
|
|
2791
|
+
content: "SUMMARIZED/DEFERRED: tool result missing in transcript; inserted placeholder for tool_result adjacency."
|
|
2792
|
+
}));
|
|
2793
|
+
filteredMsgs.splice(i + 1, 0, ...placeholders);
|
|
2794
|
+
i += placeholders.length;
|
|
2795
|
+
}
|
|
2796
|
+
return filteredMsgs;
|
|
2797
|
+
};
|
|
2798
|
+
const debugToolPairing = (messagesToSend) => {
|
|
2799
|
+
try {
|
|
2800
|
+
const msgs = Array.isArray(messagesToSend) ? messagesToSend : [];
|
|
2801
|
+
const toolUseIds = [];
|
|
2802
|
+
const missingResults = [];
|
|
2803
|
+
for (let i = 0; i < msgs.length; i++) {
|
|
2804
|
+
const m = msgs[i];
|
|
2805
|
+
if (m?.role === "assistant") {
|
|
2806
|
+
for (const tu of extractToolUses(m)) {
|
|
2807
|
+
toolUseIds.push(tu.id);
|
|
2808
|
+
const next = msgs[i + 1];
|
|
2809
|
+
if (!(next && next.role === "tool" && (next.tool_call_id === tu.id || next.tool_call_id === m?.tool_call_id))) {
|
|
2810
|
+
missingResults.push({ id: tu.id, atIndex: i, tool: tu.name });
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
} catch {
|
|
2816
|
+
}
|
|
2817
|
+
};
|
|
2818
|
+
const onEvent = state.ctx?.__onEvent;
|
|
2819
|
+
const onStream = state.ctx?.__onStream;
|
|
2820
|
+
const streamingEnabled = Boolean(state.ctx?.__streaming);
|
|
2821
|
+
const cancellationToken = state.ctx?.__cancellationToken;
|
|
2822
|
+
const abortSignal = state.ctx?.__abortSignal;
|
|
2823
|
+
const resolvedForCachePilot = getResolvedSmartConfig(opts, runtime);
|
|
2824
|
+
if (resolvedForCachePilot.contextPilot.enabled && resolvedForCachePilot.contextPilot.cacheAlignment.enabled) {
|
|
2825
|
+
const ctxForCacheWarning = state.ctx = state.ctx || {};
|
|
2826
|
+
if (!ctxForCacheWarning.__contextPilotCacheWarned) {
|
|
2827
|
+
const systemMessages = (state.messages || []).filter((m) => m?.role === "system");
|
|
2828
|
+
const systemText = systemMessages.map((m) => typeof m.content === "string" ? m.content : "").join("\n");
|
|
2829
|
+
const findings = detectVolatileContent(systemText);
|
|
2830
|
+
if (findings.length > 0) {
|
|
2831
|
+
ctxForCacheWarning.__contextPilotCacheWarned = true;
|
|
2832
|
+
if (resolvedForCachePilot.contextPilot.cacheAlignment.warnOnVolatilePrompt) {
|
|
2833
|
+
const patternCounts = findings.reduce((acc, finding) => {
|
|
2834
|
+
acc[finding.pattern] = (acc[finding.pattern] || 0) + 1;
|
|
2835
|
+
return acc;
|
|
2836
|
+
}, {});
|
|
2837
|
+
onEvent?.({
|
|
2838
|
+
type: "metadata",
|
|
2839
|
+
reason: "context_pilot_cache_alignment",
|
|
2840
|
+
message: "Volatile content detected in system prompt; this may defeat provider-side prompt caching.",
|
|
2841
|
+
patternCounts
|
|
2842
|
+
});
|
|
2843
|
+
recordTraceEvent(traceSession, {
|
|
2844
|
+
type: "metadata",
|
|
2845
|
+
label: "ContextPilot: volatile system prompt content",
|
|
2846
|
+
actor: { scope: "agent", name: actorName, role: "agent" },
|
|
2847
|
+
sections: [
|
|
2848
|
+
{
|
|
2849
|
+
kind: "metadata",
|
|
2850
|
+
label: "Volatile content findings",
|
|
2851
|
+
data: { patternCounts, totalFindings: findings.length }
|
|
2852
|
+
}
|
|
2853
|
+
]
|
|
2854
|
+
});
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
const responseFormat = runtime.responseFormat;
|
|
2860
|
+
const reasoningForCall = state.ctx?.__reasoning;
|
|
2861
|
+
const reasoningInvokeOpts = reasoningForCall ? { reasoning: reasoningForCall } : void 0;
|
|
2862
|
+
const extractText2 = (chunk) => {
|
|
2863
|
+
if (chunk == null) return "";
|
|
2864
|
+
if (typeof chunk === "string") return chunk;
|
|
2865
|
+
if (typeof chunk?.content === "string") return chunk.content;
|
|
2866
|
+
if (Array.isArray(chunk?.content)) {
|
|
2867
|
+
return chunk.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("");
|
|
2868
|
+
}
|
|
2869
|
+
if (typeof chunk?.text === "string") return chunk.text;
|
|
2870
|
+
if (typeof chunk?.delta?.content === "string") return chunk.delta.content;
|
|
2871
|
+
return "";
|
|
2872
|
+
};
|
|
2873
|
+
let response;
|
|
2874
|
+
try {
|
|
2875
|
+
const normalizedMessages = normalizeBedrockToolPairing([...state.messages]);
|
|
2876
|
+
debugToolPairing(normalizedMessages);
|
|
2877
|
+
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
2878
|
+
let streamedText = "";
|
|
2879
|
+
let streamedMessage;
|
|
2880
|
+
const streamOptions = { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts };
|
|
2881
|
+
for await (const chunk of modelWithTools.stream(normalizedMessages, streamOptions)) {
|
|
2882
|
+
if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
|
|
2883
|
+
break;
|
|
2884
|
+
}
|
|
2885
|
+
if (chunk && typeof chunk === "object" && chunk.role) {
|
|
2886
|
+
streamedMessage = chunk;
|
|
2887
|
+
}
|
|
2888
|
+
const text = extractText2(chunk);
|
|
2889
|
+
if (text) {
|
|
2890
|
+
streamedText += text;
|
|
2891
|
+
onStream?.({ text });
|
|
2892
|
+
onEvent?.({ type: "stream", text });
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
if (streamedMessage) {
|
|
2896
|
+
response = { ...streamedMessage };
|
|
2897
|
+
if (response.content == null || response.content === "") {
|
|
2898
|
+
response.content = streamedText;
|
|
2899
|
+
}
|
|
2900
|
+
} else {
|
|
2901
|
+
response = { role: "assistant", content: streamedText };
|
|
2902
|
+
}
|
|
2903
|
+
} else {
|
|
2904
|
+
response = await modelWithTools.invoke(normalizedMessages, { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts });
|
|
2905
|
+
}
|
|
2906
|
+
} catch (err) {
|
|
2907
|
+
const durationMs2 = Date.now() - start;
|
|
2908
|
+
recordTraceEvent(traceSession, {
|
|
2909
|
+
type: "ai_call",
|
|
2910
|
+
label: "Assistant Error",
|
|
2911
|
+
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
2912
|
+
status: "error",
|
|
2913
|
+
durationMs: durationMs2,
|
|
2914
|
+
requestBytes: promptBytes,
|
|
2915
|
+
model: getModelName(runtime.model || opts.model),
|
|
2916
|
+
provider: getProviderName(runtime.model || opts.model),
|
|
2917
|
+
error: { message: err?.message || String(err), stack: err?.stack },
|
|
2918
|
+
messageList: state.messages
|
|
2919
|
+
});
|
|
2920
|
+
throw err;
|
|
2921
|
+
}
|
|
2922
|
+
const messagesWithResponse = [
|
|
2923
|
+
...state.messages,
|
|
2924
|
+
response
|
|
2925
|
+
];
|
|
2926
|
+
const rawUsage = response?.usage || response?.usage_metadata || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage || response?.response_metadata?.usage_metadata || response?.response_metadata?.usageMetadata;
|
|
2927
|
+
const normalized = normalizeUsage(rawUsage);
|
|
2928
|
+
const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
|
|
2929
|
+
const durationMs = Date.now() - start;
|
|
2930
|
+
const shouldLogResponse = !!traceSession && traceSession.resolvedConfig.logData;
|
|
2931
|
+
const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
|
|
2932
|
+
const responseBytes = responsePayload !== void 0 ? estimatePayloadBytes(responsePayload) : void 0;
|
|
2933
|
+
recordTraceEvent(traceSession, {
|
|
2934
|
+
type: "ai_call",
|
|
2935
|
+
label: "Assistant Response",
|
|
2936
|
+
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
2937
|
+
durationMs,
|
|
2938
|
+
inputTokens: normalized?.prompt_tokens,
|
|
2939
|
+
outputTokens: normalized?.completion_tokens,
|
|
2940
|
+
totalTokens: normalized?.total_tokens,
|
|
2941
|
+
cachedInputTokens: normalized?.prompt_tokens_details?.cached_tokens,
|
|
2942
|
+
requestBytes: promptBytes,
|
|
2943
|
+
responseBytes,
|
|
2944
|
+
model: modelName,
|
|
2945
|
+
provider: getProviderName(runtime.model || opts.model),
|
|
2946
|
+
messageList: messagesWithResponse
|
|
2947
|
+
});
|
|
2948
|
+
if (normalized) {
|
|
2949
|
+
const usageState = state.usage || { perRequest: [], totals: {} };
|
|
2950
|
+
const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2951
|
+
const turn = usageState.perRequest.length + 1;
|
|
2952
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2953
|
+
const cachedInputTok = normalized.prompt_tokens_details?.cached_tokens;
|
|
2954
|
+
usageState.perRequest.push({ id, modelName, usage: normalized, timestamp, turn, cachedInput: cachedInputTok });
|
|
2955
|
+
const inputTok = normalized.prompt_tokens;
|
|
2956
|
+
const outputTok = normalized.completion_tokens;
|
|
2957
|
+
const totalTok = normalized.total_tokens;
|
|
2958
|
+
const key = modelName;
|
|
2959
|
+
const agg = usageState.totals[key] || { input: 0, output: 0, total: 0, cachedInput: 0 };
|
|
2960
|
+
usageState.totals[key] = {
|
|
2961
|
+
input: agg.input + (Number(inputTok) || 0),
|
|
2962
|
+
output: agg.output + (Number(outputTok) || 0),
|
|
2963
|
+
total: agg.total + (Number(totalTok) || 0),
|
|
2964
|
+
cachedInput: agg.cachedInput + (Number(cachedInputTok) || 0)
|
|
2965
|
+
};
|
|
2966
|
+
state.usage = usageState;
|
|
2352
2967
|
}
|
|
2968
|
+
return { messages: messagesWithResponse, usage: state.usage };
|
|
2353
2969
|
};
|
|
2354
2970
|
}
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
summaryTriggerTokens: 24e3,
|
|
2361
|
-
summaryPromptMaxTokens: 6e3,
|
|
2362
|
-
summaryCompressionRatioTarget: 0.5
|
|
2363
|
-
},
|
|
2364
|
-
context: {
|
|
2365
|
-
lastTurnsToKeep: 8,
|
|
2366
|
-
toolResponsePolicy: "keep_structured",
|
|
2367
|
-
budget: { systemReserveTokens: 1500, goalsReserveTokens: 1200, recentTurnsReserveTokens: 6e3, toolResponseReserveTokens: 3500 }
|
|
2368
|
-
},
|
|
2369
|
-
memory: { readPolicy: "recent_only" },
|
|
2370
|
-
delegation: { mode: "off", maxDelegationDepth: 1, maxChildCalls: 2, maxParallelChild: 1, childContextPolicy: "minimal" },
|
|
2371
|
-
toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 }
|
|
2372
|
-
}),
|
|
2373
|
-
balanced: buildProfile({}),
|
|
2374
|
-
deep: buildProfile({
|
|
2375
|
-
limits: { maxToolCalls: 40, maxParallelTools: 8, maxContextTokens: 2e5 },
|
|
2376
|
-
summarization: {
|
|
2377
|
-
maxTokens: 2e5,
|
|
2378
|
-
summaryTriggerTokens: 15e4,
|
|
2379
|
-
summaryPromptMaxTokens: 16e3,
|
|
2380
|
-
summaryCompressionRatioTarget: 0.4
|
|
2381
|
-
},
|
|
2382
|
-
context: {
|
|
2383
|
-
lastTurnsToKeep: 30,
|
|
2384
|
-
budget: { systemReserveTokens: 2500, goalsReserveTokens: 2500, recentTurnsReserveTokens: 36e3, toolResponseReserveTokens: 18e3 }
|
|
2385
|
-
},
|
|
2386
|
-
memory: { scope: "workspace" },
|
|
2387
|
-
delegation: { maxDelegationDepth: 3, maxChildCalls: 10, maxParallelChild: 4 },
|
|
2388
|
-
toolResponses: { maxToolResponseChars: 64e3, maxToolResponseTokens: 16e3 }
|
|
2389
|
-
}),
|
|
2390
|
-
research: buildProfile({
|
|
2391
|
-
limits: { maxToolCalls: 80, maxParallelTools: 10, maxContextTokens: 4e5 },
|
|
2392
|
-
summarization: {
|
|
2393
|
-
maxTokens: 4e5,
|
|
2394
|
-
summaryTriggerTokens: 3e5,
|
|
2395
|
-
summaryPromptMaxTokens: 24e3,
|
|
2396
|
-
summaryCompressionRatioTarget: 0.35
|
|
2397
|
-
},
|
|
2398
|
-
context: {
|
|
2399
|
-
lastTurnsToKeep: 60,
|
|
2400
|
-
budget: { systemReserveTokens: 3e3, goalsReserveTokens: 3e3, recentTurnsReserveTokens: 72e3, toolResponseReserveTokens: 32e3 }
|
|
2401
|
-
},
|
|
2402
|
-
memory: { scope: "workspace" },
|
|
2403
|
-
delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 16, maxParallelChild: 6, childContextPolicy: "full" },
|
|
2404
|
-
toolResponses: { maxToolResponseChars: 96e3, maxToolResponseTokens: 24e3 }
|
|
2405
|
-
})
|
|
2406
|
-
};
|
|
2407
|
-
function mergeLimits(base, override) {
|
|
2408
|
-
return {
|
|
2409
|
-
maxToolCalls: override?.maxToolCalls ?? base.maxToolCalls,
|
|
2410
|
-
maxParallelTools: override?.maxParallelTools ?? base.maxParallelTools,
|
|
2411
|
-
maxContextTokens: override?.maxContextTokens ?? base.maxContextTokens,
|
|
2412
|
-
maxTotalOutputTokens: override?.maxTotalOutputTokens ?? base.maxTotalOutputTokens ?? 0,
|
|
2413
|
-
maxCostUsd: override?.maxCostUsd ?? base.maxCostUsd ?? 0,
|
|
2414
|
-
maxWallClockMs: override?.maxWallClockMs ?? base.maxWallClockMs ?? 0
|
|
2415
|
-
};
|
|
2416
|
-
}
|
|
2417
|
-
function resolveBaseProfile(opts, runtimeProfile) {
|
|
2418
|
-
if (opts.customProfile?.extends) return opts.customProfile.extends;
|
|
2419
|
-
if (runtimeProfile !== "custom") return runtimeProfile;
|
|
2420
|
-
return "balanced";
|
|
2971
|
+
|
|
2972
|
+
// src/utils/traceSections.ts
|
|
2973
|
+
function truncate(text, max = 500) {
|
|
2974
|
+
if (!text) return "";
|
|
2975
|
+
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
2421
2976
|
}
|
|
2422
|
-
function
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
runtimeProfile,
|
|
2435
|
-
baseProfile,
|
|
2436
|
-
limits: mergeLimits(mergeLimits(preset.limits, customProfile.limits), opts.limits),
|
|
2437
|
-
summarization: {
|
|
2438
|
-
...preset.summarization,
|
|
2439
|
-
...customProfile.summarization || {},
|
|
2440
|
-
...summarizationOverride,
|
|
2441
|
-
enable: summarizationDisabled ? false : summarizationOverride.enable ?? customProfile.summarization?.enable ?? preset.summarization.enable,
|
|
2442
|
-
maxTokens: summarizationOverride.maxTokens ?? opts.limits?.maxContextTokens ?? customProfile.summarization?.maxTokens ?? preset.summarization.maxTokens,
|
|
2443
|
-
summaryTriggerTokens: summarizationOverride.summaryTriggerTokens ?? summarizationOverride.maxTokens ?? opts.limits?.maxContextTokens ?? customProfile.summarization?.summaryTriggerTokens ?? customProfile.summarization?.maxTokens ?? preset.summarization.summaryTriggerTokens,
|
|
2444
|
-
promptTemplate: summarizationOverride.promptTemplate ?? customProfile.summarization?.promptTemplate ?? preset.summarization.promptTemplate
|
|
2445
|
-
},
|
|
2446
|
-
context: {
|
|
2447
|
-
...preset.context,
|
|
2448
|
-
...customProfile.context || {},
|
|
2449
|
-
...opts.context || {},
|
|
2450
|
-
budget: {
|
|
2451
|
-
...preset.context.budget,
|
|
2452
|
-
...customProfile.context?.budget || {},
|
|
2453
|
-
...opts.context?.budget || {}
|
|
2454
|
-
},
|
|
2455
|
-
toolResponsePolicy: contextToolResponsePolicy
|
|
2456
|
-
},
|
|
2457
|
-
planning: {
|
|
2458
|
-
...preset.planning,
|
|
2459
|
-
...customProfile.planning || {},
|
|
2460
|
-
...opts.planning || {},
|
|
2461
|
-
mode: planningMode
|
|
2462
|
-
},
|
|
2463
|
-
memory: {
|
|
2464
|
-
...preset.memory,
|
|
2465
|
-
...customProfile.memory || {},
|
|
2466
|
-
...opts.memory || {},
|
|
2467
|
-
store: memoryStore
|
|
2468
|
-
},
|
|
2469
|
-
delegation: {
|
|
2470
|
-
...preset.delegation,
|
|
2471
|
-
...customProfile.delegation || {},
|
|
2472
|
-
...opts.delegation || {}
|
|
2473
|
-
},
|
|
2474
|
-
toolResponses: {
|
|
2475
|
-
...preset.toolResponses,
|
|
2476
|
-
...customProfile.toolResponses || {},
|
|
2477
|
-
...opts.toolResponses || {},
|
|
2478
|
-
defaultPolicy: opts.toolResponses?.defaultPolicy ?? customProfile.toolResponses?.defaultPolicy ?? contextToolResponsePolicy,
|
|
2479
|
-
toolResponseRetentionByTool: {
|
|
2480
|
-
...preset.toolResponses.toolResponseRetentionByTool,
|
|
2481
|
-
...customProfile.toolResponses?.toolResponseRetentionByTool || {},
|
|
2482
|
-
...opts.toolResponses?.toolResponseRetentionByTool || {}
|
|
2483
|
-
},
|
|
2484
|
-
criticalTools: opts.toolResponses?.criticalTools ?? customProfile.toolResponses?.criticalTools ?? preset.toolResponses.criticalTools
|
|
2977
|
+
function summarizeToolOutput(output) {
|
|
2978
|
+
if (output == null) return "";
|
|
2979
|
+
if (typeof output === "string") return truncate(output.trim());
|
|
2980
|
+
if (Array.isArray(output)) {
|
|
2981
|
+
const preview = output.slice(0, 3).map((item, index) => `${index + 1}. ${truncate(safeStringify(item))}`).join("\n");
|
|
2982
|
+
const suffix = output.length > 3 ? `
|
|
2983
|
+
\u2026 (+${output.length - 3} more)` : "";
|
|
2984
|
+
return `${preview}${suffix}`.trim();
|
|
2985
|
+
}
|
|
2986
|
+
if (typeof output === "object") {
|
|
2987
|
+
if (Array.isArray(output.items)) {
|
|
2988
|
+
return summarizeToolOutput(output.items);
|
|
2485
2989
|
}
|
|
2486
|
-
|
|
2990
|
+
return truncate(safeStringify(output));
|
|
2991
|
+
}
|
|
2992
|
+
return truncate(String(output));
|
|
2487
2993
|
}
|
|
2488
|
-
function
|
|
2489
|
-
|
|
2994
|
+
function extractToolItems(output) {
|
|
2995
|
+
const source = Array.isArray(output) ? output : Array.isArray(output?.items) ? output.items : void 0;
|
|
2996
|
+
if (!Array.isArray(source) || source.length === 0) return void 0;
|
|
2997
|
+
return source.slice(0, 5).map((item) => {
|
|
2998
|
+
if (item && typeof item === "object") {
|
|
2999
|
+
const snippetSource = item.content ?? item.snippet ?? item.description ?? item.text ?? item.summary ?? item;
|
|
3000
|
+
return {
|
|
3001
|
+
title: typeof item.title === "string" ? item.title : void 0,
|
|
3002
|
+
url: typeof item.url === "string" ? item.url : void 0,
|
|
3003
|
+
snippet: truncate(safeStringify(snippetSource))
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
return { snippet: truncate(safeStringify(item)) };
|
|
3007
|
+
});
|
|
2490
3008
|
}
|
|
2491
3009
|
|
|
2492
3010
|
// src/smart/toolResponses.ts
|
|
@@ -2730,6 +3248,23 @@ function createToolsNode(initialTools, opts) {
|
|
|
2730
3248
|
outputSchema: opts?.outputSchema
|
|
2731
3249
|
};
|
|
2732
3250
|
const resolved = getResolvedSmartConfig(opts || {}, runtime);
|
|
3251
|
+
const contextPilotRuntime = state.ctx?.__contextPilot;
|
|
3252
|
+
const contextPilotQuery = contextPilotRuntime ? extractLatestUserQuery(state.messages) : "";
|
|
3253
|
+
const maybeCompressToolOutput = (toolNameForCompression, rawValue, executionIdForCompression) => {
|
|
3254
|
+
if (!contextPilotRuntime || !resolved.contextPilot.enabled) return { output: rawValue };
|
|
3255
|
+
if (resolved.toolResponses.criticalTools.includes(toolNameForCompression)) return { output: rawValue };
|
|
3256
|
+
const result = compressToolOutput({
|
|
3257
|
+
toolName: toolNameForCompression,
|
|
3258
|
+
output: rawValue,
|
|
3259
|
+
query: contextPilotQuery,
|
|
3260
|
+
executionId: executionIdForCompression,
|
|
3261
|
+
config: resolved.contextPilot,
|
|
3262
|
+
runtime: contextPilotRuntime
|
|
3263
|
+
});
|
|
3264
|
+
if (!result.applied) return { output: rawValue };
|
|
3265
|
+
const { output: compressedValue, ...stats } = result;
|
|
3266
|
+
return { output: compressedValue, stats };
|
|
3267
|
+
};
|
|
2733
3268
|
const activeTools = runtime.tools;
|
|
2734
3269
|
const toolByName = /* @__PURE__ */ new Map();
|
|
2735
3270
|
for (const tool of activeTools) toolByName.set(tool.name, tool);
|
|
@@ -2967,12 +3502,13 @@ function createToolsNode(initialTools, opts) {
|
|
|
2967
3502
|
try {
|
|
2968
3503
|
if (cachedHit !== void 0) {
|
|
2969
3504
|
const executionId2 = nanoid.nanoid();
|
|
2970
|
-
const
|
|
3505
|
+
const { output: compressedCachedHit, stats: cachedContextPilotStats } = maybeCompressToolOutput(toolName, cachedHit, executionId2);
|
|
3506
|
+
const responsePolicy2 = applyToolResponseHardCap(toolName, compressedCachedHit, executionId2, resolved);
|
|
2971
3507
|
toolHistory.push({
|
|
2972
3508
|
executionId: executionId2,
|
|
2973
3509
|
toolName,
|
|
2974
3510
|
args,
|
|
2975
|
-
output:
|
|
3511
|
+
output: compressedCachedHit,
|
|
2976
3512
|
rawOutput: cachedHit,
|
|
2977
3513
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2978
3514
|
tool_call_id: tc.id,
|
|
@@ -2981,7 +3517,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
2981
3517
|
classification: responsePolicy2.classification,
|
|
2982
3518
|
retentionPolicy: "keep_full",
|
|
2983
3519
|
fromCache: true,
|
|
2984
|
-
status: "success"
|
|
3520
|
+
status: "success",
|
|
3521
|
+
contextPilot: cachedContextPilotStats
|
|
2985
3522
|
});
|
|
2986
3523
|
push({ role: "tool", content: responsePolicy2.content, tool_call_id: tc.id || `${tc.name}_${toolCount}`, name: tc.name });
|
|
2987
3524
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: cachedHit, durationMs: 0 });
|
|
@@ -3014,7 +3551,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
3014
3551
|
retentionPolicy: "keep_full",
|
|
3015
3552
|
originalTokenCount: responsePolicy2.tokenCount,
|
|
3016
3553
|
truncated: responsePolicy2.truncated,
|
|
3017
|
-
fromCache: true
|
|
3554
|
+
fromCache: true,
|
|
3555
|
+
contextPilot: cachedContextPilotStats
|
|
3018
3556
|
}
|
|
3019
3557
|
});
|
|
3020
3558
|
toolCount += 1;
|
|
@@ -3119,13 +3657,14 @@ function createToolsNode(initialTools, opts) {
|
|
|
3119
3657
|
state.ctx.__structuredOutputParsed = output.data;
|
|
3120
3658
|
state.ctx.__finalizedDueToStructuredOutput = true;
|
|
3121
3659
|
}
|
|
3122
|
-
const
|
|
3660
|
+
const { output: compressedOutput, stats: contextPilotStats } = maybeCompressToolOutput(toolName, output, executionId);
|
|
3661
|
+
const responsePolicy = applyToolResponseHardCap(toolName, compressedOutput, executionId, resolved);
|
|
3123
3662
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3124
3663
|
toolHistory.push({
|
|
3125
3664
|
executionId,
|
|
3126
3665
|
toolName,
|
|
3127
3666
|
args,
|
|
3128
|
-
output,
|
|
3667
|
+
output: compressedOutput,
|
|
3129
3668
|
rawOutput: output,
|
|
3130
3669
|
timestamp,
|
|
3131
3670
|
tool_call_id: tc.id,
|
|
@@ -3135,7 +3674,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
3135
3674
|
retentionPolicy: "keep_full",
|
|
3136
3675
|
summary: void 0,
|
|
3137
3676
|
archiveId: void 0,
|
|
3138
|
-
status: "success"
|
|
3677
|
+
status: "success",
|
|
3678
|
+
contextPilot: contextPilotStats
|
|
3139
3679
|
});
|
|
3140
3680
|
push({ role: "tool", content: responsePolicy.content, tool_call_id: tc.id || `${tc.name}_${toolCount}`, name: tc.name });
|
|
3141
3681
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: output, durationMs });
|
|
@@ -3173,7 +3713,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
3173
3713
|
classification: responsePolicy.classification,
|
|
3174
3714
|
retentionPolicy: "keep_full",
|
|
3175
3715
|
originalTokenCount: responsePolicy.tokenCount,
|
|
3176
|
-
truncated: responsePolicy.truncated
|
|
3716
|
+
truncated: responsePolicy.truncated,
|
|
3717
|
+
contextPilot: contextPilotStats
|
|
3177
3718
|
}
|
|
3178
3719
|
});
|
|
3179
3720
|
toolCount += 1;
|
|
@@ -3812,7 +4353,8 @@ var DISALLOWED_CTX_KEYS = /* @__PURE__ */ new Set([
|
|
|
3812
4353
|
"__traceSession",
|
|
3813
4354
|
"__paused",
|
|
3814
4355
|
"__cancellationToken",
|
|
3815
|
-
"__abortSignal"
|
|
4356
|
+
"__abortSignal",
|
|
4357
|
+
"__contextPilot"
|
|
3816
4358
|
]);
|
|
3817
4359
|
var clone = (value) => {
|
|
3818
4360
|
if (typeof globalThis.structuredClone === "function") {
|
|
@@ -4763,7 +5305,7 @@ function createAgent(opts) {
|
|
|
4763
5305
|
if (toolCalls.length === 0) {
|
|
4764
5306
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize) {
|
|
4765
5307
|
if (soManager.strategy.kind === "native") {
|
|
4766
|
-
const assistantText =
|
|
5308
|
+
const assistantText = extractMessageText2(lastMsg);
|
|
4767
5309
|
if (assistantText) {
|
|
4768
5310
|
const parsed = soManager.parseFromContent(assistantText);
|
|
4769
5311
|
if (parsed.success) {
|
|
@@ -4816,7 +5358,7 @@ function createAgent(opts) {
|
|
|
4816
5358
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput) {
|
|
4817
5359
|
const lastForParse = state.messages[state.messages.length - 1];
|
|
4818
5360
|
if (lastForParse?.role === "assistant") {
|
|
4819
|
-
const assistantText =
|
|
5361
|
+
const assistantText = extractMessageText2(lastForParse);
|
|
4820
5362
|
if (assistantText) {
|
|
4821
5363
|
const parsed = soManager.parseFromContent(assistantText);
|
|
4822
5364
|
if (parsed.success) {
|
|
@@ -4925,6 +5467,10 @@ function createAgent(opts) {
|
|
|
4925
5467
|
if (config?.timeoutMs && config.timeoutMs > 0) {
|
|
4926
5468
|
ctx.__deadline = Date.now() + config.timeoutMs;
|
|
4927
5469
|
}
|
|
5470
|
+
if (!ctx.__contextPilot) {
|
|
5471
|
+
const resolvedForContextPilot = getResolvedSmartConfig(opts, runtime);
|
|
5472
|
+
ctx.__contextPilot = createContextPilotRuntime(resolvedForContextPilot.contextPilot);
|
|
5473
|
+
}
|
|
4928
5474
|
const runtimeWithInvokeLimits = config?.limits ? { ...runtime, limits: { ...runtime.limits || {}, ...config.limits } } : runtime;
|
|
4929
5475
|
const initial = {
|
|
4930
5476
|
messages: input.messages || [],
|
|
@@ -4969,7 +5515,7 @@ function createAgent(opts) {
|
|
|
4969
5515
|
const isTransientSummarizationExit = !!res.ctx?.__needsSummarization;
|
|
4970
5516
|
const finalAssistantMsg = isTransientSummarizationExit ? void 0 : getLastAssistantMessage(res.messages);
|
|
4971
5517
|
const finalIsSyntheticSummary = !isTransientSummarizationExit && finalAssistantMsg && isSyntheticSummaryMessage(finalAssistantMsg);
|
|
4972
|
-
const content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" :
|
|
5518
|
+
const content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText2(finalAssistantMsg);
|
|
4973
5519
|
let parsed = void 0;
|
|
4974
5520
|
let outputError = void 0;
|
|
4975
5521
|
if (soManager) {
|
|
@@ -5278,7 +5824,7 @@ function renderMemoryBlock(facts) {
|
|
|
5278
5824
|
function clampToBudget(messages, maxContextTokens) {
|
|
5279
5825
|
let working = [...messages];
|
|
5280
5826
|
while (working.length > 2) {
|
|
5281
|
-
const tokenCount = countApproxTokens(working.map(
|
|
5827
|
+
const tokenCount = countApproxTokens(working.map(extractMessageText2).join("\n"));
|
|
5282
5828
|
if (tokenCount <= maxContextTokens) return working;
|
|
5283
5829
|
const firstNonSystem = working.findIndex((message, index) => !(index === 0 && message.role === "system"));
|
|
5284
5830
|
if (firstNonSystem < 0) break;
|
|
@@ -6151,6 +6697,13 @@ function createGetToolResponseTool(stateRef) {
|
|
|
6151
6697
|
if (execution) {
|
|
6152
6698
|
return execution.rawOutput || execution.output;
|
|
6153
6699
|
}
|
|
6700
|
+
const ccrStore = stateRef.ctx?.__contextPilot?.ccrStore;
|
|
6701
|
+
if (ccrStore && typeof ccrStore.retrieve === "function") {
|
|
6702
|
+
const recovered = ccrStore.retrieve(executionId);
|
|
6703
|
+
if (recovered !== void 0) {
|
|
6704
|
+
return recovered;
|
|
6705
|
+
}
|
|
6706
|
+
}
|
|
6154
6707
|
return "Execution not found. Please check the executionId.";
|
|
6155
6708
|
}
|
|
6156
6709
|
});
|
|
@@ -7082,7 +7635,7 @@ function createSmartAgent(opts) {
|
|
|
7082
7635
|
].join("\n");
|
|
7083
7636
|
function latestUserPrompt(messages) {
|
|
7084
7637
|
const latest = [...messages].reverse().find((message) => message.role === "user");
|
|
7085
|
-
return latest ?
|
|
7638
|
+
return latest ? extractMessageText2(latest) : "";
|
|
7086
7639
|
}
|
|
7087
7640
|
async function syncMemory(state) {
|
|
7088
7641
|
const query = latestUserPrompt(state.messages || []);
|
|
@@ -8614,7 +9167,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
8614
9167
|
const { system, messages } = this.splitSystemMessages(request.messages);
|
|
8615
9168
|
const body = {
|
|
8616
9169
|
model: request.model || this.defaultModel,
|
|
8617
|
-
messages:
|
|
9170
|
+
messages: this.toAnthropicMessages(messages),
|
|
8618
9171
|
max_tokens: request.maxTokens ?? 4096,
|
|
8619
9172
|
stream
|
|
8620
9173
|
};
|
|
@@ -8670,20 +9223,44 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
8670
9223
|
messages: rest
|
|
8671
9224
|
};
|
|
8672
9225
|
}
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
9226
|
+
/**
|
|
9227
|
+
* Converts unified messages to Anthropic format, coalescing consecutive
|
|
9228
|
+
* tool-result messages into a single `user` turn.
|
|
9229
|
+
*
|
|
9230
|
+
* The unified message list carries one `role: "tool"` entry per tool call
|
|
9231
|
+
* (mirroring OpenAI's shape). Anthropic's Messages API expects every
|
|
9232
|
+
* `tool_result` block answering a single assistant turn's `tool_use`
|
|
9233
|
+
* block(s) to be batched into ONE `user` message rather than sent as
|
|
9234
|
+
* separate consecutive `user` messages.
|
|
9235
|
+
*/
|
|
9236
|
+
toAnthropicMessages(messages) {
|
|
9237
|
+
const result = [];
|
|
9238
|
+
let mergingToolResults = false;
|
|
9239
|
+
for (const m of messages) {
|
|
9240
|
+
if (m.role === "tool" && m.toolCallId) {
|
|
9241
|
+
const toolResult = this.toAnthropicToolResult(m);
|
|
9242
|
+
if (mergingToolResults) {
|
|
9243
|
+
result[result.length - 1].content.push(toolResult);
|
|
9244
|
+
} else {
|
|
9245
|
+
result.push({ role: "user", content: [toolResult] });
|
|
9246
|
+
mergingToolResults = true;
|
|
9247
|
+
}
|
|
9248
|
+
continue;
|
|
9249
|
+
}
|
|
9250
|
+
mergingToolResults = false;
|
|
9251
|
+
result.push(this.toAnthropicMessage(m));
|
|
8686
9252
|
}
|
|
9253
|
+
return result;
|
|
9254
|
+
}
|
|
9255
|
+
toAnthropicToolResult(m) {
|
|
9256
|
+
const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
9257
|
+
return {
|
|
9258
|
+
type: "tool_result",
|
|
9259
|
+
tool_use_id: m.toolCallId,
|
|
9260
|
+
content
|
|
9261
|
+
};
|
|
9262
|
+
}
|
|
9263
|
+
toAnthropicMessage(m) {
|
|
8687
9264
|
if (m.role === "assistant" && m.toolCalls?.length) {
|
|
8688
9265
|
const content = [];
|
|
8689
9266
|
appendReasoningBlocks(content, m.reasoning?.blocks);
|
|
@@ -9068,7 +9645,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
9068
9645
|
buildConverseBody(request) {
|
|
9069
9646
|
const { system, messages } = this.splitSystemMessages(request.messages);
|
|
9070
9647
|
const body = {
|
|
9071
|
-
messages:
|
|
9648
|
+
messages: this.toBedrockMessages(messages)
|
|
9072
9649
|
};
|
|
9073
9650
|
if (system.length > 0) {
|
|
9074
9651
|
const systemBlocks = system.map((s) => ({ text: s }));
|
|
@@ -9118,22 +9695,47 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
9118
9695
|
}
|
|
9119
9696
|
return { system, messages: rest };
|
|
9120
9697
|
}
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9135
|
-
|
|
9698
|
+
/**
|
|
9699
|
+
* Converts unified messages to Bedrock Converse format, coalescing
|
|
9700
|
+
* consecutive tool-result messages into a single `user` turn.
|
|
9701
|
+
*
|
|
9702
|
+
* The unified message list carries one `role: "tool"` entry per tool call
|
|
9703
|
+
* (mirroring OpenAI's shape). Bedrock's Converse API requires every
|
|
9704
|
+
* `toolResult` block answering a single assistant turn's `toolUse`
|
|
9705
|
+
* block(s) to be batched into ONE `user` message — sending them as
|
|
9706
|
+
* separate consecutive `user` messages triggers: "Expected toolResult
|
|
9707
|
+
* blocks at messages.N.content for the following Ids: ...".
|
|
9708
|
+
*/
|
|
9709
|
+
toBedrockMessages(messages) {
|
|
9710
|
+
const result = [];
|
|
9711
|
+
let mergingToolResults = false;
|
|
9712
|
+
for (const m of messages) {
|
|
9713
|
+
if (m.role === "tool" && m.toolCallId) {
|
|
9714
|
+
const toolResult = this.toBedrockToolResult(m);
|
|
9715
|
+
if (mergingToolResults) {
|
|
9716
|
+
result[result.length - 1].content.push(toolResult);
|
|
9717
|
+
} else {
|
|
9718
|
+
result.push({ role: "user", content: [toolResult] });
|
|
9719
|
+
mergingToolResults = true;
|
|
9720
|
+
}
|
|
9721
|
+
continue;
|
|
9722
|
+
}
|
|
9723
|
+
mergingToolResults = false;
|
|
9724
|
+
result.push(this.toBedrockMessage(m));
|
|
9136
9725
|
}
|
|
9726
|
+
return result;
|
|
9727
|
+
}
|
|
9728
|
+
toBedrockToolResult(m) {
|
|
9729
|
+
const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
9730
|
+
return {
|
|
9731
|
+
toolResult: {
|
|
9732
|
+
toolUseId: m.toolCallId,
|
|
9733
|
+
content: [{ text }],
|
|
9734
|
+
status: "success"
|
|
9735
|
+
}
|
|
9736
|
+
};
|
|
9737
|
+
}
|
|
9738
|
+
toBedrockMessage(m) {
|
|
9137
9739
|
if (m.role === "assistant" && m.toolCalls?.length) {
|
|
9138
9740
|
const content2 = [];
|
|
9139
9741
|
appendBedrockReasoning(content2, m.reasoning?.blocks);
|
|
@@ -9439,12 +10041,24 @@ var VertexProvider = class extends BaseProvider {
|
|
|
9439
10041
|
buildContents(messages) {
|
|
9440
10042
|
const systemParts = [];
|
|
9441
10043
|
const contents = [];
|
|
10044
|
+
let mergingToolResults = false;
|
|
9442
10045
|
for (const m of messages) {
|
|
9443
10046
|
if (m.role === "system") {
|
|
9444
10047
|
const text = typeof m.content === "string" ? m.content : m.content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
9445
10048
|
if (text) systemParts.push(text);
|
|
9446
10049
|
continue;
|
|
9447
10050
|
}
|
|
10051
|
+
if (m.role === "tool" && m.toolCallId) {
|
|
10052
|
+
const part = this.toGeminiFunctionResponsePart(m);
|
|
10053
|
+
if (mergingToolResults) {
|
|
10054
|
+
contents[contents.length - 1].parts.push(part);
|
|
10055
|
+
} else {
|
|
10056
|
+
contents.push({ role: "user", parts: [part] });
|
|
10057
|
+
mergingToolResults = true;
|
|
10058
|
+
}
|
|
10059
|
+
continue;
|
|
10060
|
+
}
|
|
10061
|
+
mergingToolResults = false;
|
|
9448
10062
|
contents.push(this.toGeminiContent(m));
|
|
9449
10063
|
}
|
|
9450
10064
|
return {
|
|
@@ -9452,27 +10066,22 @@ var VertexProvider = class extends BaseProvider {
|
|
|
9452
10066
|
contents
|
|
9453
10067
|
};
|
|
9454
10068
|
}
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
response = { result: text };
|
|
9463
|
-
}
|
|
9464
|
-
return {
|
|
9465
|
-
role: "user",
|
|
9466
|
-
parts: [
|
|
9467
|
-
{
|
|
9468
|
-
functionResponse: {
|
|
9469
|
-
name: m.name ?? m.toolCallId,
|
|
9470
|
-
response
|
|
9471
|
-
}
|
|
9472
|
-
}
|
|
9473
|
-
]
|
|
9474
|
-
};
|
|
10069
|
+
toGeminiFunctionResponsePart(m) {
|
|
10070
|
+
const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
10071
|
+
let response;
|
|
10072
|
+
try {
|
|
10073
|
+
response = JSON.parse(text);
|
|
10074
|
+
} catch {
|
|
10075
|
+
response = { result: text };
|
|
9475
10076
|
}
|
|
10077
|
+
return {
|
|
10078
|
+
functionResponse: {
|
|
10079
|
+
name: m.name ?? m.toolCallId,
|
|
10080
|
+
response
|
|
10081
|
+
}
|
|
10082
|
+
};
|
|
10083
|
+
}
|
|
10084
|
+
toGeminiContent(m) {
|
|
9476
10085
|
if (m.role === "assistant" && m.toolCalls?.length) {
|
|
9477
10086
|
const parts2 = [];
|
|
9478
10087
|
if (typeof m.content === "string" && m.content) {
|
|
@@ -10133,10 +10742,13 @@ exports.AnthropicProvider = AnthropicProvider;
|
|
|
10133
10742
|
exports.AzureProvider = AzureProvider;
|
|
10134
10743
|
exports.BaseProvider = BaseProvider;
|
|
10135
10744
|
exports.BedrockProvider = BedrockProvider;
|
|
10745
|
+
exports.CCRStore = CCRStore;
|
|
10746
|
+
exports.CONTEXT_PILOT_JSON_MARKER_KEY = CONTEXT_PILOT_JSON_MARKER_KEY;
|
|
10136
10747
|
exports.DEFAULT_PROFILE_CONFIGS = DEFAULT_PROFILE_CONFIGS;
|
|
10137
10748
|
exports.DEFAULT_SKILL_POLICY = DEFAULT_SKILL_POLICY;
|
|
10138
10749
|
exports.DEFAULT_SUBAGENT_POLICY = DEFAULT_SUBAGENT_POLICY;
|
|
10139
10750
|
exports.DEFAULT_SUBAGENT_TOOL_NAMES = DEFAULT_SUBAGENT_TOOL_NAMES;
|
|
10751
|
+
exports.DedupTracker = DedupTracker;
|
|
10140
10752
|
exports.GuardrailPhase = GuardrailPhase;
|
|
10141
10753
|
exports.InMemoryMemoryStore = InMemoryMemoryStore;
|
|
10142
10754
|
exports.NativeJsonSchemaStrategy = NativeJsonSchemaStrategy;
|
|
@@ -10158,6 +10770,12 @@ exports.captureSnapshot = captureSnapshot;
|
|
|
10158
10770
|
exports.codePresenceRule = codePresenceRule;
|
|
10159
10771
|
exports.cognipeerSink = cognipeerSink;
|
|
10160
10772
|
exports.composeToolSets = composeToolSets;
|
|
10773
|
+
exports.compressDiffOutput = compressDiffOutput;
|
|
10774
|
+
exports.compressJsonOutput = compressJsonOutput;
|
|
10775
|
+
exports.compressLogOutput = compressLogOutput;
|
|
10776
|
+
exports.compressSearchOutput = compressSearchOutput;
|
|
10777
|
+
exports.compressTextOutput = compressTextOutput;
|
|
10778
|
+
exports.compressToolOutput = compressToolOutput;
|
|
10161
10779
|
exports.countApproxTokens = countApproxTokens;
|
|
10162
10780
|
exports.countMessagesTokens = countMessagesTokens;
|
|
10163
10781
|
exports.createAgent = createAgent;
|
|
@@ -10165,6 +10783,7 @@ exports.createAgentNode = createAgentNode;
|
|
|
10165
10783
|
exports.createAskUserQuestionTool = createAskUserQuestionTool;
|
|
10166
10784
|
exports.createBindSkillToolsTool = createBindSkillToolsTool;
|
|
10167
10785
|
exports.createCodeGuardrail = createCodeGuardrail;
|
|
10786
|
+
exports.createContextPilotRuntime = createContextPilotRuntime;
|
|
10168
10787
|
exports.createContextSummarizeNode = createContextSummarizeNode;
|
|
10169
10788
|
exports.createContextTools = createContextTools;
|
|
10170
10789
|
exports.createDelegateTool = createDelegateTool;
|
|
@@ -10190,8 +10809,11 @@ exports.customCallbackRule = customCallbackRule;
|
|
|
10190
10809
|
exports.customSink = customSink;
|
|
10191
10810
|
exports.dedupeToolsByName = dedupeToolsByName;
|
|
10192
10811
|
exports.defaultTokenCounter = defaultTokenCounter;
|
|
10812
|
+
exports.detectTextFormat = detectTextFormat;
|
|
10813
|
+
exports.detectVolatileContent = detectVolatileContent;
|
|
10193
10814
|
exports.emptyUsage = emptyUsage;
|
|
10194
10815
|
exports.evaluateGuardrails = evaluateGuardrails;
|
|
10816
|
+
exports.extractLatestUserQuery = extractLatestUserQuery;
|
|
10195
10817
|
exports.fileSink = fileSink;
|
|
10196
10818
|
exports.findSubagent = findSubagent;
|
|
10197
10819
|
exports.formatZodError = formatZodError;
|
|
@@ -10224,9 +10846,12 @@ exports.resolveToolApprovalState = resolveToolApprovalState;
|
|
|
10224
10846
|
exports.resolveUserQuestionState = resolveUserQuestionState;
|
|
10225
10847
|
exports.restoreSnapshot = restoreSnapshot;
|
|
10226
10848
|
exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
|
|
10849
|
+
exports.scoreItemsByRelevance = scoreItemsByRelevance;
|
|
10227
10850
|
exports.seedChildMessages = seedChildMessages;
|
|
10851
|
+
exports.selectTopIndicesInOrder = selectTopIndicesInOrder;
|
|
10228
10852
|
exports.setTokenCounter = setTokenCounter;
|
|
10229
10853
|
exports.startStreamingSession = startStreamingSession;
|
|
10854
|
+
exports.tokenize = tokenize;
|
|
10230
10855
|
exports.traceSessionToOtlp = traceSessionToOtlp;
|
|
10231
10856
|
exports.validateReasoningConfig = validateReasoningConfig;
|
|
10232
10857
|
exports.withTools = withTools;
|