@cognipeer/agent-sdk 0.8.1 → 0.8.3
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 +1341 -563
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +282 -2
- package/dist/index.d.ts +282 -2
- package/dist/index.mjs +1327 -565
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import fs from 'fs';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { Buffer as Buffer$1 } from 'buffer';
|
|
7
7
|
import { nanoid } from 'nanoid';
|
|
8
|
-
import crypto, {
|
|
8
|
+
import crypto, { createHash, randomUUID, createHmac } from 'crypto';
|
|
9
9
|
import AjvModule from 'ajv';
|
|
10
10
|
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
@@ -42,7 +42,7 @@ function getTokenCounter() {
|
|
|
42
42
|
function countApproxTokens(text) {
|
|
43
43
|
return activeTokenCounter(text || "");
|
|
44
44
|
}
|
|
45
|
-
function
|
|
45
|
+
function extractMessageText(m) {
|
|
46
46
|
if (!m) return "";
|
|
47
47
|
const parts = [];
|
|
48
48
|
parts.push(m.role || "");
|
|
@@ -92,7 +92,7 @@ function extractMessageText2(m) {
|
|
|
92
92
|
}
|
|
93
93
|
function countMessagesTokens(messages) {
|
|
94
94
|
if (!Array.isArray(messages) || messages.length === 0) return 0;
|
|
95
|
-
const allText = messages.map(
|
|
95
|
+
const allText = messages.map(extractMessageText).join("\n");
|
|
96
96
|
return countApproxTokens(allText) + messages.length * 4;
|
|
97
97
|
}
|
|
98
98
|
var activeTokenCounter;
|
|
@@ -1078,7 +1078,35 @@ function buildConfigSnapshot(runtime) {
|
|
|
1078
1078
|
sink: snapshotSink(runtime)
|
|
1079
1079
|
};
|
|
1080
1080
|
}
|
|
1081
|
-
|
|
1081
|
+
var TRACE_HTTP_MAX_ATTEMPTS = 4;
|
|
1082
|
+
var TRACE_HTTP_ATTEMPT_TIMEOUT_MS = 8e3;
|
|
1083
|
+
var TRACE_HTTP_RETRYABLE_STATUS = /* @__PURE__ */ new Set([404, 408, 425, 429, 500, 502, 503, 504]);
|
|
1084
|
+
var TRACE_HTTP_RETRY_BASE_MS = 250;
|
|
1085
|
+
var TRACE_HTTP_RETRY_MAX_MS = 4e3;
|
|
1086
|
+
var RetryableHttpError = class extends Error {
|
|
1087
|
+
constructor(status, message, retryAfterMs) {
|
|
1088
|
+
super(message);
|
|
1089
|
+
this.name = "RetryableHttpError";
|
|
1090
|
+
this.status = status;
|
|
1091
|
+
this.retryAfterMs = retryAfterMs;
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
function traceSleep(ms) {
|
|
1095
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1096
|
+
}
|
|
1097
|
+
function traceBackoffDelay(attempt, baseMs, maxMs) {
|
|
1098
|
+
const exp = Math.min(maxMs, baseMs * 2 ** (attempt - 1));
|
|
1099
|
+
return Math.floor(Math.random() * exp);
|
|
1100
|
+
}
|
|
1101
|
+
function parseRetryAfterMs(headerValue) {
|
|
1102
|
+
if (!headerValue) return void 0;
|
|
1103
|
+
const seconds = Number(headerValue);
|
|
1104
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
1105
|
+
const dateMs = Date.parse(headerValue);
|
|
1106
|
+
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
|
|
1107
|
+
return void 0;
|
|
1108
|
+
}
|
|
1109
|
+
async function postJsonOnce(url, headers, body) {
|
|
1082
1110
|
const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
1083
1111
|
if (!fetchFn) {
|
|
1084
1112
|
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
@@ -1087,135 +1115,71 @@ async function postTraceSession(url, headers, payload) {
|
|
|
1087
1115
|
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
1088
1116
|
finalHeaders["content-type"] = "application/json";
|
|
1089
1117
|
}
|
|
1118
|
+
const controller = new AbortController();
|
|
1119
|
+
const timer = setTimeout(() => controller.abort(), TRACE_HTTP_ATTEMPT_TIMEOUT_MS);
|
|
1120
|
+
let response;
|
|
1090
1121
|
try {
|
|
1091
|
-
|
|
1122
|
+
response = await fetchFn(url, {
|
|
1092
1123
|
method: "POST",
|
|
1093
1124
|
headers: finalHeaders,
|
|
1094
|
-
body: JSON.stringify(
|
|
1125
|
+
body: JSON.stringify(body),
|
|
1126
|
+
signal: controller.signal
|
|
1095
1127
|
});
|
|
1096
|
-
if (!response.ok) {
|
|
1097
|
-
let responseText = "";
|
|
1098
|
-
try {
|
|
1099
|
-
responseText = await response.text();
|
|
1100
|
-
} catch {
|
|
1101
|
-
}
|
|
1102
|
-
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1103
|
-
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1104
|
-
const errorMsg = `${statusLine}${bodyPreview}`;
|
|
1105
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1106
|
-
console.error("[Tracing] Error posting to", url, ":", errorMsg);
|
|
1107
|
-
}
|
|
1108
|
-
throw new Error(errorMsg);
|
|
1109
|
-
}
|
|
1110
1128
|
} catch (err) {
|
|
1111
|
-
const
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
throw err;
|
|
1129
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
1130
|
+
throw new RetryableHttpError(0, `network error - ${message2}`);
|
|
1131
|
+
} finally {
|
|
1132
|
+
clearTimeout(timer);
|
|
1116
1133
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1134
|
+
if (response.ok) return;
|
|
1135
|
+
let responseText = "";
|
|
1136
|
+
try {
|
|
1137
|
+
responseText = await response.text();
|
|
1138
|
+
} catch {
|
|
1122
1139
|
}
|
|
1123
|
-
const
|
|
1124
|
-
const
|
|
1125
|
-
|
|
1126
|
-
|
|
1140
|
+
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1141
|
+
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1142
|
+
const message = `${statusLine}${bodyPreview}`;
|
|
1143
|
+
if (TRACE_HTTP_RETRYABLE_STATUS.has(response.status)) {
|
|
1144
|
+
throw new RetryableHttpError(response.status, message, parseRetryAfterMs(response.headers.get("retry-after")));
|
|
1127
1145
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1146
|
+
throw new Error(message);
|
|
1147
|
+
}
|
|
1148
|
+
async function postJsonReliable(url, headers, body, opts = {}) {
|
|
1149
|
+
const maxAttempts = opts.retry === false ? 1 : TRACE_HTTP_MAX_ATTEMPTS;
|
|
1150
|
+
let lastError;
|
|
1151
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
1152
|
+
try {
|
|
1153
|
+
await postJsonOnce(url, headers, body);
|
|
1154
|
+
return;
|
|
1155
|
+
} catch (err) {
|
|
1156
|
+
lastError = err;
|
|
1157
|
+
if (!(err instanceof RetryableHttpError) || attempt === maxAttempts) {
|
|
1158
|
+
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1159
|
+
console.error("[Tracing] Failed to post:", err instanceof Error ? err.message : String(err));
|
|
1160
|
+
}
|
|
1161
|
+
throw err;
|
|
1139
1162
|
}
|
|
1140
|
-
const
|
|
1141
|
-
|
|
1142
|
-
throw new Error(`${statusLine}${bodyPreview}`);
|
|
1143
|
-
}
|
|
1144
|
-
} catch (err) {
|
|
1145
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1146
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1147
|
-
console.error("[Tracing] Failed to post session start:", errMsg);
|
|
1163
|
+
const wait = err.retryAfterMs ?? traceBackoffDelay(attempt, TRACE_HTTP_RETRY_BASE_MS, TRACE_HTTP_RETRY_MAX_MS);
|
|
1164
|
+
await traceSleep(Math.min(wait, TRACE_HTTP_RETRY_MAX_MS));
|
|
1148
1165
|
}
|
|
1149
|
-
throw err;
|
|
1150
1166
|
}
|
|
1167
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
1168
|
+
}
|
|
1169
|
+
async function postTraceSession(url, headers, payload) {
|
|
1170
|
+
await postJsonReliable(url, headers, payload, { retry: true });
|
|
1171
|
+
}
|
|
1172
|
+
async function postStreamingSessionStart(baseUrl, headers, payload) {
|
|
1173
|
+
const url = `${baseUrl.replace(/\/$/, "")}/stream/${payload.sessionId}/start`;
|
|
1174
|
+
await postJsonReliable(url, headers, payload, { retry: true });
|
|
1151
1175
|
}
|
|
1152
1176
|
async function postStreamingEvent(baseUrl, headers, sessionId, event) {
|
|
1153
|
-
const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
1154
|
-
if (!fetchFn) {
|
|
1155
|
-
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
1156
|
-
}
|
|
1157
1177
|
const url = `${baseUrl.replace(/\/$/, "")}/stream/${sessionId}/events`;
|
|
1158
|
-
|
|
1159
|
-
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
1160
|
-
finalHeaders["content-type"] = "application/json";
|
|
1161
|
-
}
|
|
1162
|
-
try {
|
|
1163
|
-
const response = await fetchFn(url, {
|
|
1164
|
-
method: "POST",
|
|
1165
|
-
headers: finalHeaders,
|
|
1166
|
-
body: JSON.stringify({ event })
|
|
1167
|
-
});
|
|
1168
|
-
if (!response.ok) {
|
|
1169
|
-
let responseText = "";
|
|
1170
|
-
try {
|
|
1171
|
-
responseText = await response.text();
|
|
1172
|
-
} catch {
|
|
1173
|
-
}
|
|
1174
|
-
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1175
|
-
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1176
|
-
throw new Error(`${statusLine}${bodyPreview}`);
|
|
1177
|
-
}
|
|
1178
|
-
} catch (err) {
|
|
1179
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1180
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1181
|
-
console.error("[Tracing] Failed to post streaming event:", errMsg);
|
|
1182
|
-
}
|
|
1183
|
-
throw err;
|
|
1184
|
-
}
|
|
1178
|
+
await postJsonReliable(url, headers, { event }, { retry: false });
|
|
1185
1179
|
}
|
|
1186
1180
|
async function postStreamingSessionEnd(baseUrl, headers, payload) {
|
|
1187
|
-
const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
1188
|
-
if (!fetchFn) {
|
|
1189
|
-
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
1190
|
-
}
|
|
1191
1181
|
const url = `${baseUrl.replace(/\/$/, "")}/stream/${payload.sessionId}/end`;
|
|
1192
|
-
|
|
1193
|
-
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
1194
|
-
finalHeaders["content-type"] = "application/json";
|
|
1195
|
-
}
|
|
1196
|
-
try {
|
|
1197
|
-
const response = await fetchFn(url, {
|
|
1198
|
-
method: "POST",
|
|
1199
|
-
headers: finalHeaders,
|
|
1200
|
-
body: JSON.stringify(payload)
|
|
1201
|
-
});
|
|
1202
|
-
if (!response.ok) {
|
|
1203
|
-
let responseText = "";
|
|
1204
|
-
try {
|
|
1205
|
-
responseText = await response.text();
|
|
1206
|
-
} catch {
|
|
1207
|
-
}
|
|
1208
|
-
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1209
|
-
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1210
|
-
throw new Error(`${statusLine}${bodyPreview}`);
|
|
1211
|
-
}
|
|
1212
|
-
} catch (err) {
|
|
1213
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1214
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1215
|
-
console.error("[Tracing] Failed to post session end:", errMsg);
|
|
1216
|
-
}
|
|
1217
|
-
throw err;
|
|
1218
|
-
}
|
|
1182
|
+
await postJsonReliable(url, headers, payload, { retry: true });
|
|
1219
1183
|
}
|
|
1220
1184
|
function isoToUnixNano(iso) {
|
|
1221
1185
|
const ms = new Date(iso).getTime();
|
|
@@ -1588,7 +1552,8 @@ function convertMessageListToSections(messageList) {
|
|
|
1588
1552
|
function createTraceSession(opts) {
|
|
1589
1553
|
const cfg = withDefaults(opts.tracing);
|
|
1590
1554
|
if (!cfg.enabled) return void 0;
|
|
1591
|
-
const
|
|
1555
|
+
const providedSessionId = opts.tracing?.sessionId?.trim();
|
|
1556
|
+
const sessionId = providedSessionId || generateSessionId();
|
|
1592
1557
|
const traceId = generateTraceId();
|
|
1593
1558
|
const rootSpanId = generateSpanId();
|
|
1594
1559
|
const runtime = {
|
|
@@ -1596,6 +1561,7 @@ function createTraceSession(opts) {
|
|
|
1596
1561
|
traceId,
|
|
1597
1562
|
rootSpanId,
|
|
1598
1563
|
threadId: opts.tracing?.threadId,
|
|
1564
|
+
configAgentName: opts.tracing?.agentName?.trim() || void 0,
|
|
1599
1565
|
startedAt: Date.now(),
|
|
1600
1566
|
resolvedConfig: cfg,
|
|
1601
1567
|
events: [],
|
|
@@ -1619,11 +1585,12 @@ async function startStreamingSession(session, agentRuntime) {
|
|
|
1619
1585
|
if (session.resolvedConfig.mode !== "streaming") return;
|
|
1620
1586
|
if (session.sessionStarted) return;
|
|
1621
1587
|
const sink = session.resolvedConfig.sink;
|
|
1622
|
-
const
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1588
|
+
const resolvedAgentName = session.configAgentName || agentRuntime?.name || "unknown-agent";
|
|
1589
|
+
const agentInfo = agentRuntime || session.configAgentName ? {
|
|
1590
|
+
name: resolvedAgentName,
|
|
1591
|
+
version: agentRuntime?.version,
|
|
1592
|
+
model: getModelName(agentRuntime?.model) || "unknown-model",
|
|
1593
|
+
provider: getProviderName(agentRuntime?.model)
|
|
1627
1594
|
} : void 0;
|
|
1628
1595
|
session.agentInfo = agentInfo;
|
|
1629
1596
|
const configSnapshot = buildConfigSnapshot(session);
|
|
@@ -1973,301 +1940,6 @@ function estimatePayloadBytes(value) {
|
|
|
1973
1940
|
}
|
|
1974
1941
|
}
|
|
1975
1942
|
|
|
1976
|
-
// src/nodes/agentCore.ts
|
|
1977
|
-
function createAgentCoreNode(opts) {
|
|
1978
|
-
return async (state) => {
|
|
1979
|
-
const runtime = state.agent || {
|
|
1980
|
-
name: opts.name,
|
|
1981
|
-
version: opts.version,
|
|
1982
|
-
model: opts.model,
|
|
1983
|
-
tools: opts.tools || [],
|
|
1984
|
-
guardrails: opts.guardrails,
|
|
1985
|
-
todoListPrompt: opts.todoListPrompt,
|
|
1986
|
-
limits: opts.limits,
|
|
1987
|
-
outputSchema: opts.outputSchema,
|
|
1988
|
-
tracing: opts.tracing,
|
|
1989
|
-
responseFormat: void 0
|
|
1990
|
-
};
|
|
1991
|
-
const tools = runtime.tools ?? [];
|
|
1992
|
-
const shouldUseStrictToolCalling = Boolean(
|
|
1993
|
-
runtime.responseFormat && runtime.model?.capabilities?.strictToolCalling
|
|
1994
|
-
);
|
|
1995
|
-
const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(
|
|
1996
|
-
tools,
|
|
1997
|
-
shouldUseStrictToolCalling ? { strict: true } : void 0
|
|
1998
|
-
) : runtime.model;
|
|
1999
|
-
const traceSession = state.ctx?.__traceSession;
|
|
2000
|
-
const actorName = runtime.name ?? opts.name ?? "agent";
|
|
2001
|
-
const actorVersion = runtime.version ?? opts.version;
|
|
2002
|
-
const start = Date.now();
|
|
2003
|
-
const shouldLogPrompt = !!traceSession && traceSession.resolvedConfig.logData;
|
|
2004
|
-
const promptPayload = shouldLogPrompt ? sanitizeTracePayload(state.messages) : void 0;
|
|
2005
|
-
const promptBytes = promptPayload !== void 0 ? estimatePayloadBytes(promptPayload) : void 0;
|
|
2006
|
-
const extractToolUses = (m) => {
|
|
2007
|
-
const tcs = m?.tool_calls || m?.additional_kwargs?.tool_calls;
|
|
2008
|
-
if (!Array.isArray(tcs)) return [];
|
|
2009
|
-
return tcs.map((tc) => ({ id: tc?.id, name: tc?.function?.name || tc?.name })).filter((x) => typeof x.id === "string" && x.id.length > 0);
|
|
2010
|
-
};
|
|
2011
|
-
const normalizeBedrockToolPairing = (input) => {
|
|
2012
|
-
const msgs = Array.isArray(input) ? [...input] : [];
|
|
2013
|
-
const validToolCallIds = /* @__PURE__ */ new Set();
|
|
2014
|
-
for (const m of msgs) {
|
|
2015
|
-
if (m?.role === "assistant") {
|
|
2016
|
-
for (const tu of extractToolUses(m)) {
|
|
2017
|
-
if (tu.id) validToolCallIds.add(tu.id);
|
|
2018
|
-
}
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
const filteredMsgs = msgs.filter((m) => {
|
|
2022
|
-
if (m?.role === "tool") {
|
|
2023
|
-
const toolCallId = m.tool_call_id;
|
|
2024
|
-
if (!toolCallId || !validToolCallIds.has(toolCallId)) {
|
|
2025
|
-
return false;
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
return true;
|
|
2029
|
-
});
|
|
2030
|
-
for (let i = 0; i < filteredMsgs.length; i++) {
|
|
2031
|
-
const m = filteredMsgs[i];
|
|
2032
|
-
if (m?.role !== "assistant") continue;
|
|
2033
|
-
const toolUses = extractToolUses(m);
|
|
2034
|
-
if (toolUses.length === 0) continue;
|
|
2035
|
-
const next = filteredMsgs[i + 1];
|
|
2036
|
-
const firstId = toolUses[0]?.id;
|
|
2037
|
-
const nextIsToolForFirst = !!(next && next.role === "tool" && next.tool_call_id === firstId);
|
|
2038
|
-
if (nextIsToolForFirst) continue;
|
|
2039
|
-
const placeholders = toolUses.map((tu) => ({
|
|
2040
|
-
role: "tool",
|
|
2041
|
-
name: tu.name || "unknown_tool",
|
|
2042
|
-
tool_call_id: tu.id,
|
|
2043
|
-
content: "SUMMARIZED/DEFERRED: tool result missing in transcript; inserted placeholder for tool_result adjacency."
|
|
2044
|
-
}));
|
|
2045
|
-
filteredMsgs.splice(i + 1, 0, ...placeholders);
|
|
2046
|
-
i += placeholders.length;
|
|
2047
|
-
}
|
|
2048
|
-
return filteredMsgs;
|
|
2049
|
-
};
|
|
2050
|
-
const debugToolPairing = (messagesToSend) => {
|
|
2051
|
-
try {
|
|
2052
|
-
const msgs = Array.isArray(messagesToSend) ? messagesToSend : [];
|
|
2053
|
-
const toolUseIds = [];
|
|
2054
|
-
const missingResults = [];
|
|
2055
|
-
for (let i = 0; i < msgs.length; i++) {
|
|
2056
|
-
const m = msgs[i];
|
|
2057
|
-
if (m?.role === "assistant") {
|
|
2058
|
-
for (const tu of extractToolUses(m)) {
|
|
2059
|
-
toolUseIds.push(tu.id);
|
|
2060
|
-
const next = msgs[i + 1];
|
|
2061
|
-
if (!(next && next.role === "tool" && (next.tool_call_id === tu.id || next.tool_call_id === m?.tool_call_id))) {
|
|
2062
|
-
missingResults.push({ id: tu.id, atIndex: i, tool: tu.name });
|
|
2063
|
-
}
|
|
2064
|
-
}
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
} catch {
|
|
2068
|
-
}
|
|
2069
|
-
};
|
|
2070
|
-
const onEvent = state.ctx?.__onEvent;
|
|
2071
|
-
const onStream = state.ctx?.__onStream;
|
|
2072
|
-
const streamingEnabled = Boolean(state.ctx?.__streaming);
|
|
2073
|
-
const cancellationToken = state.ctx?.__cancellationToken;
|
|
2074
|
-
const abortSignal = state.ctx?.__abortSignal;
|
|
2075
|
-
const responseFormat = runtime.responseFormat;
|
|
2076
|
-
const reasoningForCall = state.ctx?.__reasoning;
|
|
2077
|
-
const reasoningInvokeOpts = reasoningForCall ? { reasoning: reasoningForCall } : void 0;
|
|
2078
|
-
const extractText2 = (chunk) => {
|
|
2079
|
-
if (chunk == null) return "";
|
|
2080
|
-
if (typeof chunk === "string") return chunk;
|
|
2081
|
-
if (typeof chunk?.content === "string") return chunk.content;
|
|
2082
|
-
if (Array.isArray(chunk?.content)) {
|
|
2083
|
-
return chunk.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("");
|
|
2084
|
-
}
|
|
2085
|
-
if (typeof chunk?.text === "string") return chunk.text;
|
|
2086
|
-
if (typeof chunk?.delta?.content === "string") return chunk.delta.content;
|
|
2087
|
-
return "";
|
|
2088
|
-
};
|
|
2089
|
-
let response;
|
|
2090
|
-
try {
|
|
2091
|
-
const normalizedMessages = normalizeBedrockToolPairing([...state.messages]);
|
|
2092
|
-
debugToolPairing(normalizedMessages);
|
|
2093
|
-
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
2094
|
-
let streamedText = "";
|
|
2095
|
-
let streamedMessage;
|
|
2096
|
-
const streamOptions = { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts };
|
|
2097
|
-
for await (const chunk of modelWithTools.stream(normalizedMessages, streamOptions)) {
|
|
2098
|
-
if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
|
|
2099
|
-
break;
|
|
2100
|
-
}
|
|
2101
|
-
if (chunk && typeof chunk === "object" && chunk.role) {
|
|
2102
|
-
streamedMessage = chunk;
|
|
2103
|
-
}
|
|
2104
|
-
const text = extractText2(chunk);
|
|
2105
|
-
if (text) {
|
|
2106
|
-
streamedText += text;
|
|
2107
|
-
onStream?.({ text });
|
|
2108
|
-
onEvent?.({ type: "stream", text });
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
if (streamedMessage) {
|
|
2112
|
-
response = { ...streamedMessage };
|
|
2113
|
-
if (response.content == null || response.content === "") {
|
|
2114
|
-
response.content = streamedText;
|
|
2115
|
-
}
|
|
2116
|
-
} else {
|
|
2117
|
-
response = { role: "assistant", content: streamedText };
|
|
2118
|
-
}
|
|
2119
|
-
} else {
|
|
2120
|
-
response = await modelWithTools.invoke(normalizedMessages, { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts });
|
|
2121
|
-
}
|
|
2122
|
-
} catch (err) {
|
|
2123
|
-
const durationMs2 = Date.now() - start;
|
|
2124
|
-
recordTraceEvent(traceSession, {
|
|
2125
|
-
type: "ai_call",
|
|
2126
|
-
label: "Assistant Error",
|
|
2127
|
-
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
2128
|
-
status: "error",
|
|
2129
|
-
durationMs: durationMs2,
|
|
2130
|
-
requestBytes: promptBytes,
|
|
2131
|
-
model: getModelName(runtime.model || opts.model),
|
|
2132
|
-
provider: getProviderName(runtime.model || opts.model),
|
|
2133
|
-
error: { message: err?.message || String(err), stack: err?.stack },
|
|
2134
|
-
messageList: state.messages
|
|
2135
|
-
});
|
|
2136
|
-
throw err;
|
|
2137
|
-
}
|
|
2138
|
-
const messagesWithResponse = [
|
|
2139
|
-
...state.messages,
|
|
2140
|
-
response
|
|
2141
|
-
];
|
|
2142
|
-
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;
|
|
2143
|
-
const normalized = normalizeUsage(rawUsage);
|
|
2144
|
-
const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
|
|
2145
|
-
const durationMs = Date.now() - start;
|
|
2146
|
-
const shouldLogResponse = !!traceSession && traceSession.resolvedConfig.logData;
|
|
2147
|
-
const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
|
|
2148
|
-
const responseBytes = responsePayload !== void 0 ? estimatePayloadBytes(responsePayload) : void 0;
|
|
2149
|
-
recordTraceEvent(traceSession, {
|
|
2150
|
-
type: "ai_call",
|
|
2151
|
-
label: "Assistant Response",
|
|
2152
|
-
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
2153
|
-
durationMs,
|
|
2154
|
-
inputTokens: normalized?.prompt_tokens,
|
|
2155
|
-
outputTokens: normalized?.completion_tokens,
|
|
2156
|
-
totalTokens: normalized?.total_tokens,
|
|
2157
|
-
cachedInputTokens: normalized?.prompt_tokens_details?.cached_tokens,
|
|
2158
|
-
requestBytes: promptBytes,
|
|
2159
|
-
responseBytes,
|
|
2160
|
-
model: modelName,
|
|
2161
|
-
provider: getProviderName(runtime.model || opts.model),
|
|
2162
|
-
messageList: messagesWithResponse
|
|
2163
|
-
});
|
|
2164
|
-
if (normalized) {
|
|
2165
|
-
const usageState = state.usage || { perRequest: [], totals: {} };
|
|
2166
|
-
const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2167
|
-
const turn = usageState.perRequest.length + 1;
|
|
2168
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2169
|
-
const cachedInputTok = normalized.prompt_tokens_details?.cached_tokens;
|
|
2170
|
-
usageState.perRequest.push({ id, modelName, usage: normalized, timestamp, turn, cachedInput: cachedInputTok });
|
|
2171
|
-
const inputTok = normalized.prompt_tokens;
|
|
2172
|
-
const outputTok = normalized.completion_tokens;
|
|
2173
|
-
const totalTok = normalized.total_tokens;
|
|
2174
|
-
const key = modelName;
|
|
2175
|
-
const agg = usageState.totals[key] || { input: 0, output: 0, total: 0, cachedInput: 0 };
|
|
2176
|
-
usageState.totals[key] = {
|
|
2177
|
-
input: agg.input + (Number(inputTok) || 0),
|
|
2178
|
-
output: agg.output + (Number(outputTok) || 0),
|
|
2179
|
-
total: agg.total + (Number(totalTok) || 0),
|
|
2180
|
-
cachedInput: agg.cachedInput + (Number(cachedInputTok) || 0)
|
|
2181
|
-
};
|
|
2182
|
-
state.usage = usageState;
|
|
2183
|
-
}
|
|
2184
|
-
return { messages: messagesWithResponse, usage: state.usage };
|
|
2185
|
-
};
|
|
2186
|
-
}
|
|
2187
|
-
|
|
2188
|
-
// src/utils/content.ts
|
|
2189
|
-
function contentToString(content) {
|
|
2190
|
-
try {
|
|
2191
|
-
if (content == null) return "";
|
|
2192
|
-
if (typeof content === "string") return content;
|
|
2193
|
-
if (Array.isArray(content)) {
|
|
2194
|
-
return content.map((p) => {
|
|
2195
|
-
if (!p || typeof p !== "object") return String(p);
|
|
2196
|
-
if (p.type === "text") return String(p.text ?? "");
|
|
2197
|
-
if (p.type === "image_url") {
|
|
2198
|
-
const img = p.image_url;
|
|
2199
|
-
const url = typeof img === "string" ? img : img?.url;
|
|
2200
|
-
const detail = typeof img === "string" ? void 0 : img?.detail;
|
|
2201
|
-
return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
|
|
2202
|
-
}
|
|
2203
|
-
return JSON.stringify(p);
|
|
2204
|
-
}).join("\n");
|
|
2205
|
-
}
|
|
2206
|
-
return JSON.stringify(content);
|
|
2207
|
-
} catch {
|
|
2208
|
-
return String(content);
|
|
2209
|
-
}
|
|
2210
|
-
}
|
|
2211
|
-
function mergeContentsToString(contents) {
|
|
2212
|
-
return contents.map((c) => contentToString(c)).join("\n");
|
|
2213
|
-
}
|
|
2214
|
-
function safeStringify(value, pretty = false) {
|
|
2215
|
-
if (value == null) return "";
|
|
2216
|
-
if (typeof value === "string") return value;
|
|
2217
|
-
try {
|
|
2218
|
-
return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
|
|
2219
|
-
} catch {
|
|
2220
|
-
return String(value);
|
|
2221
|
-
}
|
|
2222
|
-
}
|
|
2223
|
-
function extractMessageText(message) {
|
|
2224
|
-
if (!message) return "";
|
|
2225
|
-
const content = message.content;
|
|
2226
|
-
if (typeof content === "string") return content;
|
|
2227
|
-
if (Array.isArray(content)) {
|
|
2228
|
-
return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
|
|
2229
|
-
}
|
|
2230
|
-
return "";
|
|
2231
|
-
}
|
|
2232
|
-
|
|
2233
|
-
// src/utils/traceSections.ts
|
|
2234
|
-
function truncate(text, max = 500) {
|
|
2235
|
-
if (!text) return "";
|
|
2236
|
-
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
2237
|
-
}
|
|
2238
|
-
function summarizeToolOutput(output) {
|
|
2239
|
-
if (output == null) return "";
|
|
2240
|
-
if (typeof output === "string") return truncate(output.trim());
|
|
2241
|
-
if (Array.isArray(output)) {
|
|
2242
|
-
const preview = output.slice(0, 3).map((item, index) => `${index + 1}. ${truncate(safeStringify(item))}`).join("\n");
|
|
2243
|
-
const suffix = output.length > 3 ? `
|
|
2244
|
-
\u2026 (+${output.length - 3} more)` : "";
|
|
2245
|
-
return `${preview}${suffix}`.trim();
|
|
2246
|
-
}
|
|
2247
|
-
if (typeof output === "object") {
|
|
2248
|
-
if (Array.isArray(output.items)) {
|
|
2249
|
-
return summarizeToolOutput(output.items);
|
|
2250
|
-
}
|
|
2251
|
-
return truncate(safeStringify(output));
|
|
2252
|
-
}
|
|
2253
|
-
return truncate(String(output));
|
|
2254
|
-
}
|
|
2255
|
-
function extractToolItems(output) {
|
|
2256
|
-
const source = Array.isArray(output) ? output : Array.isArray(output?.items) ? output.items : void 0;
|
|
2257
|
-
if (!Array.isArray(source) || source.length === 0) return void 0;
|
|
2258
|
-
return source.slice(0, 5).map((item) => {
|
|
2259
|
-
if (item && typeof item === "object") {
|
|
2260
|
-
const snippetSource = item.content ?? item.snippet ?? item.description ?? item.text ?? item.summary ?? item;
|
|
2261
|
-
return {
|
|
2262
|
-
title: typeof item.title === "string" ? item.title : void 0,
|
|
2263
|
-
url: typeof item.url === "string" ? item.url : void 0,
|
|
2264
|
-
snippet: truncate(safeStringify(snippetSource))
|
|
2265
|
-
};
|
|
2266
|
-
}
|
|
2267
|
-
return { snippet: truncate(safeStringify(item)) };
|
|
2268
|
-
});
|
|
2269
|
-
}
|
|
2270
|
-
|
|
2271
1943
|
// src/smart/runtimeConfig.ts
|
|
2272
1944
|
var DEFAULT_CRITICAL_TOOLS = ["response", "manage_todo_list", "get_tool_response"];
|
|
2273
1945
|
var BASE_DEFAULTS = {
|
|
@@ -2320,8 +1992,42 @@ var BASE_DEFAULTS = {
|
|
|
2320
1992
|
toolResponseRetentionByTool: {},
|
|
2321
1993
|
criticalTools: [...DEFAULT_CRITICAL_TOOLS],
|
|
2322
1994
|
schemaValidation: "strict"
|
|
1995
|
+
},
|
|
1996
|
+
contextPilot: {
|
|
1997
|
+
// Opt-in: ContextPilot never alters tool output unless the caller
|
|
1998
|
+
// explicitly passes `contextPilot: { enabled: true }` (or sets `enabled`
|
|
1999
|
+
// via `customProfile`/profile overrides). This preserves backward
|
|
2000
|
+
// compatibility for every existing `createSmartAgent(...)` call site.
|
|
2001
|
+
enabled: false,
|
|
2002
|
+
compression: {
|
|
2003
|
+
json: { enabled: true, targetRatio: 0.35, minItems: 20 },
|
|
2004
|
+
text: { enabled: true, targetRatio: 0.5, minChars: 1200 },
|
|
2005
|
+
diff: { enabled: true, contextLines: 3 },
|
|
2006
|
+
log: { enabled: true, maxLines: 60 },
|
|
2007
|
+
search: { enabled: true, maxMatches: 30 }
|
|
2008
|
+
},
|
|
2009
|
+
ccr: { enabled: true, ttlMs: 30 * 60 * 1e3, maxEntries: 500 },
|
|
2010
|
+
cacheAlignment: { enabled: true, warnOnVolatilePrompt: true },
|
|
2011
|
+
dedup: { enabled: true, minChars: 500 },
|
|
2012
|
+
excludeTools: []
|
|
2323
2013
|
}
|
|
2324
2014
|
};
|
|
2015
|
+
function mergeContextPilot(base, override) {
|
|
2016
|
+
return {
|
|
2017
|
+
enabled: override?.enabled ?? base.enabled,
|
|
2018
|
+
compression: {
|
|
2019
|
+
json: { ...base.compression.json, ...override?.compression?.json },
|
|
2020
|
+
text: { ...base.compression.text, ...override?.compression?.text },
|
|
2021
|
+
diff: { ...base.compression.diff, ...override?.compression?.diff },
|
|
2022
|
+
log: { ...base.compression.log, ...override?.compression?.log },
|
|
2023
|
+
search: { ...base.compression.search, ...override?.compression?.search }
|
|
2024
|
+
},
|
|
2025
|
+
ccr: { ...base.ccr, ...override?.ccr },
|
|
2026
|
+
cacheAlignment: { ...base.cacheAlignment, ...override?.cacheAlignment },
|
|
2027
|
+
dedup: { ...base.dedup, ...override?.dedup },
|
|
2028
|
+
excludeTools: override?.excludeTools ?? base.excludeTools
|
|
2029
|
+
};
|
|
2030
|
+
}
|
|
2325
2031
|
function buildProfile(overrides) {
|
|
2326
2032
|
return {
|
|
2327
2033
|
limits: { ...BASE_DEFAULTS.limits, ...overrides.limits },
|
|
@@ -2339,144 +2045,956 @@ function buildProfile(overrides) {
|
|
|
2339
2045
|
...overrides.toolResponses,
|
|
2340
2046
|
criticalTools: overrides.toolResponses?.criticalTools ?? [...DEFAULT_CRITICAL_TOOLS],
|
|
2341
2047
|
toolResponseRetentionByTool: overrides.toolResponses?.toolResponseRetentionByTool ?? {}
|
|
2048
|
+
},
|
|
2049
|
+
contextPilot: mergeContextPilot(BASE_DEFAULTS.contextPilot, overrides.contextPilot)
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2052
|
+
var DEFAULT_PROFILE_CONFIGS = {
|
|
2053
|
+
fast: buildProfile({
|
|
2054
|
+
limits: { maxToolCalls: 8, maxParallelTools: 3, maxContextTokens: 32e3 },
|
|
2055
|
+
summarization: {
|
|
2056
|
+
maxTokens: 32e3,
|
|
2057
|
+
summaryTriggerTokens: 24e3,
|
|
2058
|
+
summaryPromptMaxTokens: 6e3,
|
|
2059
|
+
summaryCompressionRatioTarget: 0.5
|
|
2060
|
+
},
|
|
2061
|
+
context: {
|
|
2062
|
+
lastTurnsToKeep: 8,
|
|
2063
|
+
toolResponsePolicy: "keep_structured",
|
|
2064
|
+
budget: { systemReserveTokens: 1500, goalsReserveTokens: 1200, recentTurnsReserveTokens: 6e3, toolResponseReserveTokens: 3500 }
|
|
2065
|
+
},
|
|
2066
|
+
memory: { readPolicy: "recent_only" },
|
|
2067
|
+
delegation: { mode: "off", maxDelegationDepth: 1, maxChildCalls: 2, maxParallelChild: 1, childContextPolicy: "minimal" },
|
|
2068
|
+
toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 },
|
|
2069
|
+
contextPilot: {
|
|
2070
|
+
compression: {
|
|
2071
|
+
json: { targetRatio: 0.25, minItems: 12 },
|
|
2072
|
+
text: { targetRatio: 0.35, minChars: 800 }
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
}),
|
|
2076
|
+
balanced: buildProfile({}),
|
|
2077
|
+
deep: buildProfile({
|
|
2078
|
+
limits: { maxToolCalls: 40, maxParallelTools: 8, maxContextTokens: 2e5 },
|
|
2079
|
+
summarization: {
|
|
2080
|
+
maxTokens: 2e5,
|
|
2081
|
+
summaryTriggerTokens: 15e4,
|
|
2082
|
+
summaryPromptMaxTokens: 16e3,
|
|
2083
|
+
summaryCompressionRatioTarget: 0.4
|
|
2084
|
+
},
|
|
2085
|
+
context: {
|
|
2086
|
+
lastTurnsToKeep: 30,
|
|
2087
|
+
budget: { systemReserveTokens: 2500, goalsReserveTokens: 2500, recentTurnsReserveTokens: 36e3, toolResponseReserveTokens: 18e3 }
|
|
2088
|
+
},
|
|
2089
|
+
memory: { scope: "workspace" },
|
|
2090
|
+
delegation: { maxDelegationDepth: 3, maxChildCalls: 10, maxParallelChild: 4 },
|
|
2091
|
+
toolResponses: { maxToolResponseChars: 64e3, maxToolResponseTokens: 16e3 },
|
|
2092
|
+
contextPilot: {
|
|
2093
|
+
compression: {
|
|
2094
|
+
json: { targetRatio: 0.5, minItems: 30 },
|
|
2095
|
+
text: { targetRatio: 0.6, minChars: 1600 }
|
|
2096
|
+
},
|
|
2097
|
+
ccr: { ttlMs: 60 * 60 * 1e3 }
|
|
2098
|
+
}
|
|
2099
|
+
}),
|
|
2100
|
+
research: buildProfile({
|
|
2101
|
+
limits: { maxToolCalls: 80, maxParallelTools: 10, maxContextTokens: 4e5 },
|
|
2102
|
+
summarization: {
|
|
2103
|
+
maxTokens: 4e5,
|
|
2104
|
+
summaryTriggerTokens: 3e5,
|
|
2105
|
+
summaryPromptMaxTokens: 24e3,
|
|
2106
|
+
summaryCompressionRatioTarget: 0.35
|
|
2107
|
+
},
|
|
2108
|
+
context: {
|
|
2109
|
+
lastTurnsToKeep: 60,
|
|
2110
|
+
budget: { systemReserveTokens: 3e3, goalsReserveTokens: 3e3, recentTurnsReserveTokens: 72e3, toolResponseReserveTokens: 32e3 }
|
|
2111
|
+
},
|
|
2112
|
+
memory: { scope: "workspace" },
|
|
2113
|
+
delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 16, maxParallelChild: 6, childContextPolicy: "full" },
|
|
2114
|
+
toolResponses: { maxToolResponseChars: 96e3, maxToolResponseTokens: 24e3 },
|
|
2115
|
+
contextPilot: {
|
|
2116
|
+
compression: {
|
|
2117
|
+
json: { targetRatio: 0.6, minItems: 40 },
|
|
2118
|
+
text: { targetRatio: 0.65, minChars: 2e3 }
|
|
2119
|
+
},
|
|
2120
|
+
ccr: { ttlMs: 2 * 60 * 60 * 1e3, maxEntries: 1e3 }
|
|
2121
|
+
}
|
|
2122
|
+
})
|
|
2123
|
+
};
|
|
2124
|
+
function mergeLimits(base, override) {
|
|
2125
|
+
return {
|
|
2126
|
+
maxToolCalls: override?.maxToolCalls ?? base.maxToolCalls,
|
|
2127
|
+
maxParallelTools: override?.maxParallelTools ?? base.maxParallelTools,
|
|
2128
|
+
maxContextTokens: override?.maxContextTokens ?? base.maxContextTokens,
|
|
2129
|
+
maxTotalOutputTokens: override?.maxTotalOutputTokens ?? base.maxTotalOutputTokens ?? 0,
|
|
2130
|
+
maxCostUsd: override?.maxCostUsd ?? base.maxCostUsd ?? 0,
|
|
2131
|
+
maxWallClockMs: override?.maxWallClockMs ?? base.maxWallClockMs ?? 0
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
function resolveBaseProfile(opts, runtimeProfile) {
|
|
2135
|
+
if (opts.customProfile?.extends) return opts.customProfile.extends;
|
|
2136
|
+
if (runtimeProfile !== "custom") return runtimeProfile;
|
|
2137
|
+
return "balanced";
|
|
2138
|
+
}
|
|
2139
|
+
function normalizeSmartAgentOptions(opts) {
|
|
2140
|
+
const runtimeProfile = opts.runtimeProfile ?? (opts.customProfile ? "custom" : "balanced");
|
|
2141
|
+
const baseProfile = resolveBaseProfile(opts, runtimeProfile);
|
|
2142
|
+
const preset = DEFAULT_PROFILE_CONFIGS[baseProfile];
|
|
2143
|
+
const customProfile = opts.customProfile || {};
|
|
2144
|
+
const useTodoList = opts.useTodoList === true;
|
|
2145
|
+
const summarizationDisabled = opts.summarization === false;
|
|
2146
|
+
const summarizationOverride = typeof opts.summarization === "object" ? opts.summarization : {};
|
|
2147
|
+
const planningMode = opts.planning?.mode ?? customProfile.planning?.mode ?? (useTodoList ? "todo" : preset.planning.mode);
|
|
2148
|
+
const memoryStore = opts.memory?.store ?? customProfile.memory?.store;
|
|
2149
|
+
const contextToolResponsePolicy = opts.context?.toolResponsePolicy ?? customProfile.context?.toolResponsePolicy ?? preset.context.toolResponsePolicy;
|
|
2150
|
+
return {
|
|
2151
|
+
runtimeProfile,
|
|
2152
|
+
baseProfile,
|
|
2153
|
+
limits: mergeLimits(mergeLimits(preset.limits, customProfile.limits), opts.limits),
|
|
2154
|
+
summarization: {
|
|
2155
|
+
...preset.summarization,
|
|
2156
|
+
...customProfile.summarization || {},
|
|
2157
|
+
...summarizationOverride,
|
|
2158
|
+
enable: summarizationDisabled ? false : summarizationOverride.enable ?? customProfile.summarization?.enable ?? preset.summarization.enable,
|
|
2159
|
+
maxTokens: summarizationOverride.maxTokens ?? opts.limits?.maxContextTokens ?? customProfile.summarization?.maxTokens ?? preset.summarization.maxTokens,
|
|
2160
|
+
summaryTriggerTokens: summarizationOverride.summaryTriggerTokens ?? summarizationOverride.maxTokens ?? opts.limits?.maxContextTokens ?? customProfile.summarization?.summaryTriggerTokens ?? customProfile.summarization?.maxTokens ?? preset.summarization.summaryTriggerTokens,
|
|
2161
|
+
promptTemplate: summarizationOverride.promptTemplate ?? customProfile.summarization?.promptTemplate ?? preset.summarization.promptTemplate
|
|
2162
|
+
},
|
|
2163
|
+
context: {
|
|
2164
|
+
...preset.context,
|
|
2165
|
+
...customProfile.context || {},
|
|
2166
|
+
...opts.context || {},
|
|
2167
|
+
budget: {
|
|
2168
|
+
...preset.context.budget,
|
|
2169
|
+
...customProfile.context?.budget || {},
|
|
2170
|
+
...opts.context?.budget || {}
|
|
2171
|
+
},
|
|
2172
|
+
toolResponsePolicy: contextToolResponsePolicy
|
|
2173
|
+
},
|
|
2174
|
+
planning: {
|
|
2175
|
+
...preset.planning,
|
|
2176
|
+
...customProfile.planning || {},
|
|
2177
|
+
...opts.planning || {},
|
|
2178
|
+
mode: planningMode
|
|
2179
|
+
},
|
|
2180
|
+
memory: {
|
|
2181
|
+
...preset.memory,
|
|
2182
|
+
...customProfile.memory || {},
|
|
2183
|
+
...opts.memory || {},
|
|
2184
|
+
store: memoryStore
|
|
2185
|
+
},
|
|
2186
|
+
delegation: {
|
|
2187
|
+
...preset.delegation,
|
|
2188
|
+
...customProfile.delegation || {},
|
|
2189
|
+
...opts.delegation || {}
|
|
2190
|
+
},
|
|
2191
|
+
toolResponses: {
|
|
2192
|
+
...preset.toolResponses,
|
|
2193
|
+
...customProfile.toolResponses || {},
|
|
2194
|
+
...opts.toolResponses || {},
|
|
2195
|
+
defaultPolicy: opts.toolResponses?.defaultPolicy ?? customProfile.toolResponses?.defaultPolicy ?? contextToolResponsePolicy,
|
|
2196
|
+
toolResponseRetentionByTool: {
|
|
2197
|
+
...preset.toolResponses.toolResponseRetentionByTool,
|
|
2198
|
+
...customProfile.toolResponses?.toolResponseRetentionByTool || {},
|
|
2199
|
+
...opts.toolResponses?.toolResponseRetentionByTool || {}
|
|
2200
|
+
},
|
|
2201
|
+
criticalTools: opts.toolResponses?.criticalTools ?? customProfile.toolResponses?.criticalTools ?? preset.toolResponses.criticalTools
|
|
2202
|
+
},
|
|
2203
|
+
contextPilot: mergeContextPilot(mergeContextPilot(preset.contextPilot, customProfile.contextPilot), opts.contextPilot)
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
function getResolvedSmartConfig(opts, runtime) {
|
|
2207
|
+
return runtime?.smart || normalizeSmartAgentOptions(opts);
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
// src/smart/contextPilot/relevance.ts
|
|
2211
|
+
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
2212
|
+
"the",
|
|
2213
|
+
"a",
|
|
2214
|
+
"an",
|
|
2215
|
+
"and",
|
|
2216
|
+
"or",
|
|
2217
|
+
"but",
|
|
2218
|
+
"if",
|
|
2219
|
+
"then",
|
|
2220
|
+
"else",
|
|
2221
|
+
"for",
|
|
2222
|
+
"of",
|
|
2223
|
+
"in",
|
|
2224
|
+
"on",
|
|
2225
|
+
"at",
|
|
2226
|
+
"to",
|
|
2227
|
+
"by",
|
|
2228
|
+
"with",
|
|
2229
|
+
"is",
|
|
2230
|
+
"are",
|
|
2231
|
+
"was",
|
|
2232
|
+
"were",
|
|
2233
|
+
"be",
|
|
2234
|
+
"been",
|
|
2235
|
+
"being",
|
|
2236
|
+
"this",
|
|
2237
|
+
"that",
|
|
2238
|
+
"these",
|
|
2239
|
+
"those",
|
|
2240
|
+
"it",
|
|
2241
|
+
"its",
|
|
2242
|
+
"as",
|
|
2243
|
+
"from"
|
|
2244
|
+
]);
|
|
2245
|
+
function tokenize(text) {
|
|
2246
|
+
if (!text) return [];
|
|
2247
|
+
const matches = text.toLowerCase().match(/[\p{L}\p{N}_]+/gu);
|
|
2248
|
+
if (!matches) return [];
|
|
2249
|
+
return matches.filter((token) => token.length > 1 && !STOPWORDS.has(token));
|
|
2250
|
+
}
|
|
2251
|
+
function scoreItemsByRelevance(docs, query, params = {}) {
|
|
2252
|
+
const k1 = params.k1 ?? 1.5;
|
|
2253
|
+
const b = params.b ?? 0.75;
|
|
2254
|
+
const queryTokens = tokenize(query);
|
|
2255
|
+
const docTokens = docs.map((doc) => tokenize(doc));
|
|
2256
|
+
if (queryTokens.length === 0) {
|
|
2257
|
+
return docs.map(() => 1);
|
|
2258
|
+
}
|
|
2259
|
+
const docLengths = docTokens.map((tokens) => tokens.length);
|
|
2260
|
+
const avgDocLen = docLengths.reduce((sum2, len) => sum2 + len, 0) / Math.max(1, docLengths.length);
|
|
2261
|
+
const uniqueQueryTerms = [...new Set(queryTokens)];
|
|
2262
|
+
const df = /* @__PURE__ */ new Map();
|
|
2263
|
+
for (const term of uniqueQueryTerms) {
|
|
2264
|
+
let count = 0;
|
|
2265
|
+
for (const tokens of docTokens) {
|
|
2266
|
+
if (tokens.includes(term)) count += 1;
|
|
2267
|
+
}
|
|
2268
|
+
df.set(term, count);
|
|
2269
|
+
}
|
|
2270
|
+
const n = docs.length;
|
|
2271
|
+
const idf = /* @__PURE__ */ new Map();
|
|
2272
|
+
for (const term of uniqueQueryTerms) {
|
|
2273
|
+
const freq = df.get(term) || 0;
|
|
2274
|
+
idf.set(term, Math.log(1 + (n - freq + 0.5) / (freq + 0.5)));
|
|
2275
|
+
}
|
|
2276
|
+
return docTokens.map((tokens, docIndex) => {
|
|
2277
|
+
if (tokens.length === 0) return 0;
|
|
2278
|
+
const termFreq = /* @__PURE__ */ new Map();
|
|
2279
|
+
for (const token of tokens) {
|
|
2280
|
+
termFreq.set(token, (termFreq.get(token) || 0) + 1);
|
|
2281
|
+
}
|
|
2282
|
+
const docLen = docLengths[docIndex];
|
|
2283
|
+
let score = 0;
|
|
2284
|
+
for (const term of uniqueQueryTerms) {
|
|
2285
|
+
const freq = termFreq.get(term) || 0;
|
|
2286
|
+
if (freq === 0) continue;
|
|
2287
|
+
const termIdf = idf.get(term) || 0;
|
|
2288
|
+
const numerator = freq * (k1 + 1);
|
|
2289
|
+
const denominator = freq + k1 * (1 - b + b * docLen / avgDocLen);
|
|
2290
|
+
score += termIdf * (numerator / denominator);
|
|
2291
|
+
}
|
|
2292
|
+
return score;
|
|
2293
|
+
});
|
|
2294
|
+
}
|
|
2295
|
+
function selectTopIndicesInOrder(scores, count) {
|
|
2296
|
+
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);
|
|
2297
|
+
return ranked.sort((a, b) => a - b);
|
|
2298
|
+
}
|
|
2299
|
+
var CCRStore = class _CCRStore {
|
|
2300
|
+
constructor(options = {}) {
|
|
2301
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
2302
|
+
this.defaultTtlMs = options.ttlMs ?? 30 * 60 * 1e3;
|
|
2303
|
+
this.maxEntries = options.maxEntries ?? 500;
|
|
2304
|
+
}
|
|
2305
|
+
/** Stores `value` and returns a short content hash that can be used to retrieve it later. */
|
|
2306
|
+
store(value, ttlMs) {
|
|
2307
|
+
const hash = _CCRStore.hashOf(value);
|
|
2308
|
+
this.entries.delete(hash);
|
|
2309
|
+
this.entries.set(hash, { value, storedAt: Date.now(), ttlMs: ttlMs ?? this.defaultTtlMs });
|
|
2310
|
+
this.evictIfNeeded();
|
|
2311
|
+
return hash;
|
|
2312
|
+
}
|
|
2313
|
+
/** Returns the original value for `hash`, or `undefined` if missing/expired. */
|
|
2314
|
+
retrieve(hash) {
|
|
2315
|
+
const entry = this.entries.get(hash);
|
|
2316
|
+
if (!entry) return void 0;
|
|
2317
|
+
if (Date.now() - entry.storedAt > entry.ttlMs) {
|
|
2318
|
+
this.entries.delete(hash);
|
|
2319
|
+
return void 0;
|
|
2320
|
+
}
|
|
2321
|
+
return entry.value;
|
|
2322
|
+
}
|
|
2323
|
+
has(hash) {
|
|
2324
|
+
return this.retrieve(hash) !== void 0;
|
|
2325
|
+
}
|
|
2326
|
+
get size() {
|
|
2327
|
+
return this.entries.size;
|
|
2328
|
+
}
|
|
2329
|
+
evictIfNeeded() {
|
|
2330
|
+
while (this.entries.size > this.maxEntries) {
|
|
2331
|
+
const oldestKey = this.entries.keys().next().value;
|
|
2332
|
+
if (oldestKey === void 0) break;
|
|
2333
|
+
this.entries.delete(oldestKey);
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
static hashOf(value) {
|
|
2337
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
2338
|
+
return createHash("sha1").update(serialized).digest("hex").slice(0, 16);
|
|
2339
|
+
}
|
|
2340
|
+
};
|
|
2341
|
+
var DedupTracker = class {
|
|
2342
|
+
constructor() {
|
|
2343
|
+
this.seen = /* @__PURE__ */ new Map();
|
|
2344
|
+
}
|
|
2345
|
+
/**
|
|
2346
|
+
* Registers `content` under `executionId`/`toolName`. Returns the entry
|
|
2347
|
+
* that first produced this exact content, or `undefined` if this is the
|
|
2348
|
+
* first time it has been seen.
|
|
2349
|
+
*/
|
|
2350
|
+
checkAndRegister(content, executionId, toolName) {
|
|
2351
|
+
const hash = createHash("sha1").update(content).digest("hex");
|
|
2352
|
+
const existing = this.seen.get(hash);
|
|
2353
|
+
if (!existing) {
|
|
2354
|
+
this.seen.set(hash, { executionId, toolName });
|
|
2355
|
+
}
|
|
2356
|
+
return existing;
|
|
2357
|
+
}
|
|
2358
|
+
};
|
|
2359
|
+
|
|
2360
|
+
// src/smart/contextPilot/cacheAligner.ts
|
|
2361
|
+
var PATTERNS = [
|
|
2362
|
+
{ 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 },
|
|
2363
|
+
{ 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 },
|
|
2364
|
+
{ kind: "jwt", regex: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g },
|
|
2365
|
+
{ 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 },
|
|
2366
|
+
{ kind: "api_key", regex: /\b(?:sk|pk|ghp|gho|ghu|ghs)-[A-Za-z0-9]{10,}\b/g },
|
|
2367
|
+
{ kind: "unix_timestamp", regex: /\b1\d{12}\b(?!\d)|\b1\d{9}\b(?!\d)/g }
|
|
2368
|
+
];
|
|
2369
|
+
function detectVolatileContent(text, limit = 20) {
|
|
2370
|
+
if (!text) return [];
|
|
2371
|
+
const findings = [];
|
|
2372
|
+
for (const { kind, regex } of PATTERNS) {
|
|
2373
|
+
regex.lastIndex = 0;
|
|
2374
|
+
let match;
|
|
2375
|
+
while (findings.length < limit && (match = regex.exec(text)) !== null) {
|
|
2376
|
+
findings.push({ pattern: kind, match: match[0], index: match.index });
|
|
2377
|
+
if (regex.lastIndex === match.index) regex.lastIndex += 1;
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
return findings;
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
// src/smart/contextPilot/jsonCrusher.ts
|
|
2384
|
+
init_utilTokens();
|
|
2385
|
+
|
|
2386
|
+
// src/utils/content.ts
|
|
2387
|
+
function contentToString(content) {
|
|
2388
|
+
try {
|
|
2389
|
+
if (content == null) return "";
|
|
2390
|
+
if (typeof content === "string") return content;
|
|
2391
|
+
if (Array.isArray(content)) {
|
|
2392
|
+
return content.map((p) => {
|
|
2393
|
+
if (!p || typeof p !== "object") return String(p);
|
|
2394
|
+
if (p.type === "text") return String(p.text ?? "");
|
|
2395
|
+
if (p.type === "image_url") {
|
|
2396
|
+
const img = p.image_url;
|
|
2397
|
+
const url = typeof img === "string" ? img : img?.url;
|
|
2398
|
+
const detail = typeof img === "string" ? void 0 : img?.detail;
|
|
2399
|
+
return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
|
|
2400
|
+
}
|
|
2401
|
+
return JSON.stringify(p);
|
|
2402
|
+
}).join("\n");
|
|
2403
|
+
}
|
|
2404
|
+
return JSON.stringify(content);
|
|
2405
|
+
} catch {
|
|
2406
|
+
return String(content);
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
function mergeContentsToString(contents) {
|
|
2410
|
+
return contents.map((c) => contentToString(c)).join("\n");
|
|
2411
|
+
}
|
|
2412
|
+
function safeStringify(value, pretty = false) {
|
|
2413
|
+
if (value == null) return "";
|
|
2414
|
+
if (typeof value === "string") return value;
|
|
2415
|
+
try {
|
|
2416
|
+
return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
|
|
2417
|
+
} catch {
|
|
2418
|
+
return String(value);
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
function extractMessageText2(message) {
|
|
2422
|
+
if (!message) return "";
|
|
2423
|
+
const content = message.content;
|
|
2424
|
+
if (typeof content === "string") return content;
|
|
2425
|
+
if (Array.isArray(content)) {
|
|
2426
|
+
return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
|
|
2427
|
+
}
|
|
2428
|
+
return "";
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
// src/smart/contextPilot/jsonCrusher.ts
|
|
2432
|
+
var CONTEXT_PILOT_JSON_MARKER_KEY = "__contextPilotDropped";
|
|
2433
|
+
function findCompressibleArray(output, minItems) {
|
|
2434
|
+
if (Array.isArray(output)) {
|
|
2435
|
+
return { array: output, wrap: (arr) => arr };
|
|
2436
|
+
}
|
|
2437
|
+
if (output && typeof output === "object") {
|
|
2438
|
+
let bestKey;
|
|
2439
|
+
let bestArray;
|
|
2440
|
+
for (const [key, value] of Object.entries(output)) {
|
|
2441
|
+
if (Array.isArray(value) && (!bestArray || value.length > bestArray.length)) {
|
|
2442
|
+
bestKey = key;
|
|
2443
|
+
bestArray = value;
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
if (bestKey && bestArray && bestArray.length >= minItems) {
|
|
2447
|
+
const key = bestKey;
|
|
2448
|
+
return {
|
|
2449
|
+
array: bestArray,
|
|
2450
|
+
wrap: (arr) => ({ ...output, [key]: arr })
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
return null;
|
|
2455
|
+
}
|
|
2456
|
+
function notApplied(output) {
|
|
2457
|
+
const tokens = countApproxTokens(safeStringify(output));
|
|
2458
|
+
return { applied: false, compressorUsed: "none", output, originalTokens: tokens, compressedTokens: tokens };
|
|
2459
|
+
}
|
|
2460
|
+
function compressJsonOutput(output, query, config, ccrStore) {
|
|
2461
|
+
if (!config.enabled) return notApplied(output);
|
|
2462
|
+
const target = findCompressibleArray(output, config.minItems);
|
|
2463
|
+
if (!target || target.array.length < config.minItems) return notApplied(output);
|
|
2464
|
+
const { array, wrap } = target;
|
|
2465
|
+
const itemTexts = array.map((item) => safeStringify(item));
|
|
2466
|
+
const scores = scoreItemsByRelevance(itemTexts, query);
|
|
2467
|
+
const keepCount = Math.max(1, Math.min(array.length, Math.ceil(array.length * config.targetRatio)));
|
|
2468
|
+
const keepIndices = new Set(selectTopIndicesInOrder(scores, keepCount));
|
|
2469
|
+
const droppedCount = array.length - keepIndices.size;
|
|
2470
|
+
if (droppedCount <= 0) return notApplied(output);
|
|
2471
|
+
const originalTokens = countApproxTokens(safeStringify(output));
|
|
2472
|
+
const ccrHash = ccrStore.store(output);
|
|
2473
|
+
const keptItems = array.filter((_item, index) => keepIndices.has(index));
|
|
2474
|
+
const marker = {
|
|
2475
|
+
[CONTEXT_PILOT_JSON_MARKER_KEY]: droppedCount,
|
|
2476
|
+
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.`
|
|
2477
|
+
};
|
|
2478
|
+
const compressedOutput = wrap([...keptItems, marker]);
|
|
2479
|
+
const compressedTokens = countApproxTokens(safeStringify(compressedOutput));
|
|
2480
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied(output);
|
|
2481
|
+
return {
|
|
2482
|
+
applied: true,
|
|
2483
|
+
compressorUsed: "jsonCrusher",
|
|
2484
|
+
output: compressedOutput,
|
|
2485
|
+
originalTokens,
|
|
2486
|
+
compressedTokens,
|
|
2487
|
+
droppedItems: droppedCount,
|
|
2488
|
+
ccrHash
|
|
2489
|
+
};
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
// src/smart/contextPilot/textCrusher.ts
|
|
2493
|
+
init_utilTokens();
|
|
2494
|
+
function splitIntoSentences(text) {
|
|
2495
|
+
return text.split(/(?<=[.!?。!?\n])\s*/u).map((sentence) => sentence.trim()).filter(Boolean);
|
|
2496
|
+
}
|
|
2497
|
+
function normalizeForDedup(sentence) {
|
|
2498
|
+
return sentence.toLowerCase().replace(/\s+/g, " ").trim();
|
|
2499
|
+
}
|
|
2500
|
+
function notApplied2(text) {
|
|
2501
|
+
const tokens = countApproxTokens(text);
|
|
2502
|
+
return { applied: false, compressorUsed: "none", output: text, originalTokens: tokens, compressedTokens: tokens };
|
|
2503
|
+
}
|
|
2504
|
+
function compressTextOutput(text, query, config, ccrStore) {
|
|
2505
|
+
if (!config.enabled || text.length < config.minChars) return notApplied2(text);
|
|
2506
|
+
const rawSentences = splitIntoSentences(text);
|
|
2507
|
+
if (rawSentences.length < 6) return notApplied2(text);
|
|
2508
|
+
const seenNormalized = /* @__PURE__ */ new Set();
|
|
2509
|
+
const dedupedIndices = [];
|
|
2510
|
+
rawSentences.forEach((sentence, index) => {
|
|
2511
|
+
const key = normalizeForDedup(sentence);
|
|
2512
|
+
if (seenNormalized.has(key)) return;
|
|
2513
|
+
seenNormalized.add(key);
|
|
2514
|
+
dedupedIndices.push(index);
|
|
2515
|
+
});
|
|
2516
|
+
const relevanceScores = scoreItemsByRelevance(dedupedIndices.map((i) => rawSentences[i]), query);
|
|
2517
|
+
const recencyBoost = dedupedIndices.map((_value, position) => position / Math.max(1, dedupedIndices.length - 1));
|
|
2518
|
+
const combinedScores = relevanceScores.map((score, i) => score + recencyBoost[i] * 0.25);
|
|
2519
|
+
const keepCount = Math.max(3, Math.ceil(dedupedIndices.length * config.targetRatio));
|
|
2520
|
+
const keepPositions = new Set(selectTopIndicesInOrder(combinedScores, keepCount));
|
|
2521
|
+
const keptSentences = dedupedIndices.filter((_index, position) => keepPositions.has(position)).map((i) => rawSentences[i]);
|
|
2522
|
+
const droppedCount = rawSentences.length - keptSentences.length;
|
|
2523
|
+
if (droppedCount <= 0) return notApplied2(text);
|
|
2524
|
+
const originalTokens = countApproxTokens(text);
|
|
2525
|
+
const ccrHash = ccrStore.store(text);
|
|
2526
|
+
const compressedText = `${keptSentences.join(" ")}
|
|
2527
|
+
[ContextPilot: ${droppedCount} lower-relevance sentence(s) omitted. Use get_tool_response with executionId="${ccrHash}" to retrieve the full original text.]`;
|
|
2528
|
+
const compressedTokens = countApproxTokens(compressedText);
|
|
2529
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied2(text);
|
|
2530
|
+
return {
|
|
2531
|
+
applied: true,
|
|
2532
|
+
compressorUsed: "textCrusher",
|
|
2533
|
+
output: compressedText,
|
|
2534
|
+
originalTokens,
|
|
2535
|
+
compressedTokens,
|
|
2536
|
+
droppedItems: droppedCount,
|
|
2537
|
+
ccrHash
|
|
2538
|
+
};
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
// src/smart/contextPilot/formatCompressors.ts
|
|
2542
|
+
init_utilTokens();
|
|
2543
|
+
function notApplied3(text) {
|
|
2544
|
+
const tokens = countApproxTokens(text);
|
|
2545
|
+
return { applied: false, compressorUsed: "none", output: text, originalTokens: tokens, compressedTokens: tokens };
|
|
2546
|
+
}
|
|
2547
|
+
function detectTextFormat(text) {
|
|
2548
|
+
const sample = text.slice(0, 2e3);
|
|
2549
|
+
if (/^diff --git |^---\s|^\+\+\+\s|^@@ -\d+/m.test(sample)) return "diff";
|
|
2550
|
+
if (/^[\w./-]+:\d+:/m.test(sample) || /^[\w./-]+-\d+-/m.test(sample)) return "search";
|
|
2551
|
+
if (/\b(ERROR|FAIL|FAILED|WARN|PASS|PASSED)\b/.test(sample) && text.split("\n").length > 15) return "log";
|
|
2552
|
+
return "text";
|
|
2553
|
+
}
|
|
2554
|
+
function compressDiffOutput(text, config, ccrStore) {
|
|
2555
|
+
if (!config.enabled) return notApplied3(text);
|
|
2556
|
+
const lines = text.split("\n");
|
|
2557
|
+
const kept = [];
|
|
2558
|
+
let contextRun = 0;
|
|
2559
|
+
let trimmedAny = false;
|
|
2560
|
+
for (const line of lines) {
|
|
2561
|
+
const isHeader = line.startsWith("diff --git") || line.startsWith("---") || line.startsWith("+++") || line.startsWith("@@");
|
|
2562
|
+
const isChange = line.startsWith("+") || line.startsWith("-");
|
|
2563
|
+
if (isHeader || isChange) {
|
|
2564
|
+
kept.push(line);
|
|
2565
|
+
contextRun = 0;
|
|
2566
|
+
continue;
|
|
2567
|
+
}
|
|
2568
|
+
if (contextRun < config.contextLines) {
|
|
2569
|
+
kept.push(line);
|
|
2570
|
+
contextRun += 1;
|
|
2571
|
+
} else {
|
|
2572
|
+
trimmedAny = true;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
if (!trimmedAny) return notApplied3(text);
|
|
2576
|
+
const originalTokens = countApproxTokens(text);
|
|
2577
|
+
const ccrHash = ccrStore.store(text);
|
|
2578
|
+
const compressedText = `${kept.join("\n")}
|
|
2579
|
+
[ContextPilot: unchanged context lines beyond ${config.contextLines} trimmed. Use get_tool_response with executionId="${ccrHash}" to retrieve the full diff.]`;
|
|
2580
|
+
const compressedTokens = countApproxTokens(compressedText);
|
|
2581
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied3(text);
|
|
2582
|
+
return { applied: true, compressorUsed: "diffCompressor", output: compressedText, originalTokens, compressedTokens, ccrHash };
|
|
2583
|
+
}
|
|
2584
|
+
var LOG_LEVEL_SCORE = [
|
|
2585
|
+
{ regex: /\b(FAIL|FAILED|ERROR|FATAL|EXCEPTION|TRACEBACK)\b/i, score: 1 },
|
|
2586
|
+
{ regex: /\b(WARN|WARNING)\b/i, score: 0.7 },
|
|
2587
|
+
{ regex: /\b(PASS|PASSED|OK|SUCCESS)\b/i, score: 0.4 },
|
|
2588
|
+
{ regex: /\bINFO\b/i, score: 0.3 },
|
|
2589
|
+
{ regex: /\b(DEBUG|TRACE)\b/i, score: 0.1 }
|
|
2590
|
+
];
|
|
2591
|
+
function scoreLogLine(line) {
|
|
2592
|
+
for (const { regex, score } of LOG_LEVEL_SCORE) {
|
|
2593
|
+
if (regex.test(line)) return score;
|
|
2594
|
+
}
|
|
2595
|
+
return 0.2;
|
|
2596
|
+
}
|
|
2597
|
+
function compressLogOutput(text, config, ccrStore) {
|
|
2598
|
+
if (!config.enabled) return notApplied3(text);
|
|
2599
|
+
const lines = text.split("\n").filter((line) => line.length > 0);
|
|
2600
|
+
if (lines.length <= config.maxLines) return notApplied3(text);
|
|
2601
|
+
const scored = lines.map((line, index) => ({ line, index, score: scoreLogLine(line) }));
|
|
2602
|
+
const mustKeep = /* @__PURE__ */ new Set([0, lines.length - 1]);
|
|
2603
|
+
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);
|
|
2604
|
+
const keepIndices = /* @__PURE__ */ new Set([...mustKeep, ...ranked]);
|
|
2605
|
+
const droppedCount = lines.length - keepIndices.size;
|
|
2606
|
+
if (droppedCount <= 0) return notApplied3(text);
|
|
2607
|
+
const originalTokens = countApproxTokens(text);
|
|
2608
|
+
const ccrHash = ccrStore.store(text);
|
|
2609
|
+
const keptLines = lines.filter((_line, index) => keepIndices.has(index));
|
|
2610
|
+
const compressedText = `${keptLines.join("\n")}
|
|
2611
|
+
[ContextPilot: ${droppedCount} lower-priority log line(s) omitted (errors/warnings preserved). Use get_tool_response with executionId="${ccrHash}" to retrieve the full log.]`;
|
|
2612
|
+
const compressedTokens = countApproxTokens(compressedText);
|
|
2613
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied3(text);
|
|
2614
|
+
return { applied: true, compressorUsed: "logCompressor", output: compressedText, originalTokens, compressedTokens, droppedItems: droppedCount, ccrHash };
|
|
2615
|
+
}
|
|
2616
|
+
function compressSearchOutput(text, config, ccrStore) {
|
|
2617
|
+
if (!config.enabled) return notApplied3(text);
|
|
2618
|
+
const lines = text.split("\n").filter((line) => line.length > 0);
|
|
2619
|
+
if (lines.length <= config.maxMatches) return notApplied3(text);
|
|
2620
|
+
const perFileCount = /* @__PURE__ */ new Map();
|
|
2621
|
+
const perFileCap = Math.max(3, Math.ceil(config.maxMatches / 4));
|
|
2622
|
+
const kept = [];
|
|
2623
|
+
for (const line of lines) {
|
|
2624
|
+
if (kept.length >= config.maxMatches) break;
|
|
2625
|
+
const fileKey = line.split(/[:-]/)[0] || "unknown";
|
|
2626
|
+
const count = perFileCount.get(fileKey) || 0;
|
|
2627
|
+
if (count >= perFileCap) continue;
|
|
2628
|
+
perFileCount.set(fileKey, count + 1);
|
|
2629
|
+
kept.push(line);
|
|
2630
|
+
}
|
|
2631
|
+
const droppedCount = lines.length - kept.length;
|
|
2632
|
+
if (droppedCount <= 0) return notApplied3(text);
|
|
2633
|
+
const originalTokens = countApproxTokens(text);
|
|
2634
|
+
const ccrHash = ccrStore.store(text);
|
|
2635
|
+
const compressedText = `${kept.join("\n")}
|
|
2636
|
+
[ContextPilot: ${droppedCount} additional match(es) omitted. Use get_tool_response with executionId="${ccrHash}" to retrieve all matches.]`;
|
|
2637
|
+
const compressedTokens = countApproxTokens(compressedText);
|
|
2638
|
+
if (compressedTokens >= originalTokens * 0.9) return notApplied3(text);
|
|
2639
|
+
return { applied: true, compressorUsed: "searchCompressor", output: compressedText, originalTokens, compressedTokens, droppedItems: droppedCount, ccrHash };
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
// src/smart/contextPilot/pipeline.ts
|
|
2643
|
+
init_utilTokens();
|
|
2644
|
+
function createContextPilotRuntime(config) {
|
|
2645
|
+
return {
|
|
2646
|
+
ccrStore: new CCRStore({ ttlMs: config.ccr.ttlMs, maxEntries: config.ccr.maxEntries }),
|
|
2647
|
+
dedupTracker: new DedupTracker()
|
|
2648
|
+
};
|
|
2649
|
+
}
|
|
2650
|
+
function extractLatestUserQuery(messages) {
|
|
2651
|
+
if (!Array.isArray(messages)) return "";
|
|
2652
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
2653
|
+
const message = messages[i];
|
|
2654
|
+
if (message?.role !== "user") continue;
|
|
2655
|
+
if (typeof message.content === "string") return message.content;
|
|
2656
|
+
if (Array.isArray(message.content)) {
|
|
2657
|
+
return message.content.map((part) => typeof part?.text === "string" ? part.text : "").filter(Boolean).join(" ");
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
return "";
|
|
2661
|
+
}
|
|
2662
|
+
function notApplied4(output) {
|
|
2663
|
+
const tokens = countApproxTokens(safeStringify(output));
|
|
2664
|
+
return { applied: false, compressorUsed: "none", output, originalTokens: tokens, compressedTokens: tokens };
|
|
2665
|
+
}
|
|
2666
|
+
function compressToolOutput(params) {
|
|
2667
|
+
const { toolName, output, query, executionId, config, runtime } = params;
|
|
2668
|
+
if (!config.enabled || config.excludeTools.includes(toolName)) return notApplied4(output);
|
|
2669
|
+
const ccrAvailable = config.ccr.enabled && config.ccr.maxEntries > 0;
|
|
2670
|
+
if (config.dedup.enabled) {
|
|
2671
|
+
const serialized = typeof output === "string" ? output : safeStringify(output);
|
|
2672
|
+
if (serialized.length >= config.dedup.minChars) {
|
|
2673
|
+
const duplicate = runtime.dedupTracker.checkAndRegister(serialized, executionId, toolName);
|
|
2674
|
+
if (duplicate) {
|
|
2675
|
+
const originalTokens = countApproxTokens(serialized);
|
|
2676
|
+
const pointer = `DUPLICATE_TOOL_RESPONSE [toolName=${toolName}]
|
|
2677
|
+
Identical to an earlier ${duplicate.toolName} result. Use get_tool_response with executionId="${duplicate.executionId}" to view it.`;
|
|
2678
|
+
return {
|
|
2679
|
+
applied: true,
|
|
2680
|
+
compressorUsed: "none",
|
|
2681
|
+
output: pointer,
|
|
2682
|
+
originalTokens,
|
|
2683
|
+
compressedTokens: countApproxTokens(pointer),
|
|
2684
|
+
duplicateOf: duplicate.executionId
|
|
2685
|
+
};
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
if (typeof output !== "string") {
|
|
2690
|
+
if (ccrAvailable && config.compression.json.enabled) {
|
|
2691
|
+
const result = compressJsonOutput(output, query, config.compression.json, runtime.ccrStore);
|
|
2692
|
+
if (result.applied) return result;
|
|
2693
|
+
}
|
|
2694
|
+
return notApplied4(output);
|
|
2695
|
+
}
|
|
2696
|
+
const format = detectTextFormat(output);
|
|
2697
|
+
if (ccrAvailable && format === "diff" && config.compression.diff.enabled) {
|
|
2698
|
+
const result = compressDiffOutput(output, config.compression.diff, runtime.ccrStore);
|
|
2699
|
+
if (result.applied) return result;
|
|
2700
|
+
} else if (ccrAvailable && format === "log" && config.compression.log.enabled) {
|
|
2701
|
+
const result = compressLogOutput(output, config.compression.log, runtime.ccrStore);
|
|
2702
|
+
if (result.applied) return result;
|
|
2703
|
+
} else if (ccrAvailable && format === "search" && config.compression.search.enabled) {
|
|
2704
|
+
const result = compressSearchOutput(output, config.compression.search, runtime.ccrStore);
|
|
2705
|
+
if (result.applied) return result;
|
|
2706
|
+
}
|
|
2707
|
+
if (ccrAvailable && config.compression.text.enabled) {
|
|
2708
|
+
const result = compressTextOutput(output, query, config.compression.text, runtime.ccrStore);
|
|
2709
|
+
if (result.applied) return result;
|
|
2710
|
+
}
|
|
2711
|
+
return notApplied4(output);
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
// src/nodes/agentCore.ts
|
|
2715
|
+
function createAgentCoreNode(opts) {
|
|
2716
|
+
return async (state) => {
|
|
2717
|
+
const runtime = state.agent || {
|
|
2718
|
+
name: opts.name,
|
|
2719
|
+
version: opts.version,
|
|
2720
|
+
model: opts.model,
|
|
2721
|
+
tools: opts.tools || [],
|
|
2722
|
+
guardrails: opts.guardrails,
|
|
2723
|
+
todoListPrompt: opts.todoListPrompt,
|
|
2724
|
+
limits: opts.limits,
|
|
2725
|
+
outputSchema: opts.outputSchema,
|
|
2726
|
+
tracing: opts.tracing,
|
|
2727
|
+
responseFormat: void 0
|
|
2728
|
+
};
|
|
2729
|
+
const tools = runtime.tools ?? [];
|
|
2730
|
+
const shouldUseStrictToolCalling = Boolean(
|
|
2731
|
+
runtime.responseFormat && runtime.model?.capabilities?.strictToolCalling
|
|
2732
|
+
);
|
|
2733
|
+
const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(
|
|
2734
|
+
tools,
|
|
2735
|
+
shouldUseStrictToolCalling ? { strict: true } : void 0
|
|
2736
|
+
) : runtime.model;
|
|
2737
|
+
const traceSession = state.ctx?.__traceSession;
|
|
2738
|
+
const actorName = runtime.name ?? opts.name ?? "agent";
|
|
2739
|
+
const actorVersion = runtime.version ?? opts.version;
|
|
2740
|
+
const start = Date.now();
|
|
2741
|
+
const shouldLogPrompt = !!traceSession && traceSession.resolvedConfig.logData;
|
|
2742
|
+
const promptPayload = shouldLogPrompt ? sanitizeTracePayload(state.messages) : void 0;
|
|
2743
|
+
const promptBytes = promptPayload !== void 0 ? estimatePayloadBytes(promptPayload) : void 0;
|
|
2744
|
+
const extractToolUses = (m) => {
|
|
2745
|
+
const tcs = m?.tool_calls || m?.additional_kwargs?.tool_calls;
|
|
2746
|
+
if (!Array.isArray(tcs)) return [];
|
|
2747
|
+
return tcs.map((tc) => ({ id: tc?.id, name: tc?.function?.name || tc?.name })).filter((x) => typeof x.id === "string" && x.id.length > 0);
|
|
2748
|
+
};
|
|
2749
|
+
const normalizeBedrockToolPairing = (input) => {
|
|
2750
|
+
const msgs = Array.isArray(input) ? [...input] : [];
|
|
2751
|
+
const validToolCallIds = /* @__PURE__ */ new Set();
|
|
2752
|
+
for (const m of msgs) {
|
|
2753
|
+
if (m?.role === "assistant") {
|
|
2754
|
+
for (const tu of extractToolUses(m)) {
|
|
2755
|
+
if (tu.id) validToolCallIds.add(tu.id);
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
const filteredMsgs = msgs.filter((m) => {
|
|
2760
|
+
if (m?.role === "tool") {
|
|
2761
|
+
const toolCallId = m.tool_call_id;
|
|
2762
|
+
if (!toolCallId || !validToolCallIds.has(toolCallId)) {
|
|
2763
|
+
return false;
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
return true;
|
|
2767
|
+
});
|
|
2768
|
+
for (let i = 0; i < filteredMsgs.length; i++) {
|
|
2769
|
+
const m = filteredMsgs[i];
|
|
2770
|
+
if (m?.role !== "assistant") continue;
|
|
2771
|
+
const toolUses = extractToolUses(m);
|
|
2772
|
+
if (toolUses.length === 0) continue;
|
|
2773
|
+
const next = filteredMsgs[i + 1];
|
|
2774
|
+
const firstId = toolUses[0]?.id;
|
|
2775
|
+
const nextIsToolForFirst = !!(next && next.role === "tool" && next.tool_call_id === firstId);
|
|
2776
|
+
if (nextIsToolForFirst) continue;
|
|
2777
|
+
const placeholders = toolUses.map((tu) => ({
|
|
2778
|
+
role: "tool",
|
|
2779
|
+
name: tu.name || "unknown_tool",
|
|
2780
|
+
tool_call_id: tu.id,
|
|
2781
|
+
content: "SUMMARIZED/DEFERRED: tool result missing in transcript; inserted placeholder for tool_result adjacency."
|
|
2782
|
+
}));
|
|
2783
|
+
filteredMsgs.splice(i + 1, 0, ...placeholders);
|
|
2784
|
+
i += placeholders.length;
|
|
2785
|
+
}
|
|
2786
|
+
return filteredMsgs;
|
|
2787
|
+
};
|
|
2788
|
+
const debugToolPairing = (messagesToSend) => {
|
|
2789
|
+
try {
|
|
2790
|
+
const msgs = Array.isArray(messagesToSend) ? messagesToSend : [];
|
|
2791
|
+
const toolUseIds = [];
|
|
2792
|
+
const missingResults = [];
|
|
2793
|
+
for (let i = 0; i < msgs.length; i++) {
|
|
2794
|
+
const m = msgs[i];
|
|
2795
|
+
if (m?.role === "assistant") {
|
|
2796
|
+
for (const tu of extractToolUses(m)) {
|
|
2797
|
+
toolUseIds.push(tu.id);
|
|
2798
|
+
const next = msgs[i + 1];
|
|
2799
|
+
if (!(next && next.role === "tool" && (next.tool_call_id === tu.id || next.tool_call_id === m?.tool_call_id))) {
|
|
2800
|
+
missingResults.push({ id: tu.id, atIndex: i, tool: tu.name });
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
} catch {
|
|
2806
|
+
}
|
|
2807
|
+
};
|
|
2808
|
+
const onEvent = state.ctx?.__onEvent;
|
|
2809
|
+
const onStream = state.ctx?.__onStream;
|
|
2810
|
+
const streamingEnabled = Boolean(state.ctx?.__streaming);
|
|
2811
|
+
const cancellationToken = state.ctx?.__cancellationToken;
|
|
2812
|
+
const abortSignal = state.ctx?.__abortSignal;
|
|
2813
|
+
const resolvedForCachePilot = getResolvedSmartConfig(opts, runtime);
|
|
2814
|
+
if (resolvedForCachePilot.contextPilot.enabled && resolvedForCachePilot.contextPilot.cacheAlignment.enabled) {
|
|
2815
|
+
const ctxForCacheWarning = state.ctx = state.ctx || {};
|
|
2816
|
+
if (!ctxForCacheWarning.__contextPilotCacheWarned) {
|
|
2817
|
+
const systemMessages = (state.messages || []).filter((m) => m?.role === "system");
|
|
2818
|
+
const systemText = systemMessages.map((m) => typeof m.content === "string" ? m.content : "").join("\n");
|
|
2819
|
+
const findings = detectVolatileContent(systemText);
|
|
2820
|
+
if (findings.length > 0) {
|
|
2821
|
+
ctxForCacheWarning.__contextPilotCacheWarned = true;
|
|
2822
|
+
if (resolvedForCachePilot.contextPilot.cacheAlignment.warnOnVolatilePrompt) {
|
|
2823
|
+
const patternCounts = findings.reduce((acc, finding) => {
|
|
2824
|
+
acc[finding.pattern] = (acc[finding.pattern] || 0) + 1;
|
|
2825
|
+
return acc;
|
|
2826
|
+
}, {});
|
|
2827
|
+
onEvent?.({
|
|
2828
|
+
type: "metadata",
|
|
2829
|
+
reason: "context_pilot_cache_alignment",
|
|
2830
|
+
message: "Volatile content detected in system prompt; this may defeat provider-side prompt caching.",
|
|
2831
|
+
patternCounts
|
|
2832
|
+
});
|
|
2833
|
+
recordTraceEvent(traceSession, {
|
|
2834
|
+
type: "metadata",
|
|
2835
|
+
label: "ContextPilot: volatile system prompt content",
|
|
2836
|
+
actor: { scope: "agent", name: actorName, role: "agent" },
|
|
2837
|
+
sections: [
|
|
2838
|
+
{
|
|
2839
|
+
kind: "metadata",
|
|
2840
|
+
label: "Volatile content findings",
|
|
2841
|
+
data: { patternCounts, totalFindings: findings.length }
|
|
2842
|
+
}
|
|
2843
|
+
]
|
|
2844
|
+
});
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
const responseFormat = runtime.responseFormat;
|
|
2850
|
+
const reasoningForCall = state.ctx?.__reasoning;
|
|
2851
|
+
const reasoningInvokeOpts = reasoningForCall ? { reasoning: reasoningForCall } : void 0;
|
|
2852
|
+
const extractText2 = (chunk) => {
|
|
2853
|
+
if (chunk == null) return "";
|
|
2854
|
+
if (typeof chunk === "string") return chunk;
|
|
2855
|
+
if (typeof chunk?.content === "string") return chunk.content;
|
|
2856
|
+
if (Array.isArray(chunk?.content)) {
|
|
2857
|
+
return chunk.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("");
|
|
2858
|
+
}
|
|
2859
|
+
if (typeof chunk?.text === "string") return chunk.text;
|
|
2860
|
+
if (typeof chunk?.delta?.content === "string") return chunk.delta.content;
|
|
2861
|
+
return "";
|
|
2862
|
+
};
|
|
2863
|
+
let response;
|
|
2864
|
+
try {
|
|
2865
|
+
const normalizedMessages = normalizeBedrockToolPairing([...state.messages]);
|
|
2866
|
+
debugToolPairing(normalizedMessages);
|
|
2867
|
+
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
2868
|
+
let streamedText = "";
|
|
2869
|
+
let streamedMessage;
|
|
2870
|
+
const streamOptions = { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts };
|
|
2871
|
+
for await (const chunk of modelWithTools.stream(normalizedMessages, streamOptions)) {
|
|
2872
|
+
if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
|
|
2873
|
+
break;
|
|
2874
|
+
}
|
|
2875
|
+
if (chunk && typeof chunk === "object" && chunk.role) {
|
|
2876
|
+
streamedMessage = chunk;
|
|
2877
|
+
}
|
|
2878
|
+
const text = extractText2(chunk);
|
|
2879
|
+
if (text) {
|
|
2880
|
+
streamedText += text;
|
|
2881
|
+
onStream?.({ text });
|
|
2882
|
+
onEvent?.({ type: "stream", text });
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
if (streamedMessage) {
|
|
2886
|
+
response = { ...streamedMessage };
|
|
2887
|
+
if (response.content == null || response.content === "") {
|
|
2888
|
+
response.content = streamedText;
|
|
2889
|
+
}
|
|
2890
|
+
} else {
|
|
2891
|
+
response = { role: "assistant", content: streamedText };
|
|
2892
|
+
}
|
|
2893
|
+
} else {
|
|
2894
|
+
response = await modelWithTools.invoke(normalizedMessages, { signal: abortSignal, cancellationToken, ...responseFormat, ...reasoningInvokeOpts });
|
|
2895
|
+
}
|
|
2896
|
+
} catch (err) {
|
|
2897
|
+
const durationMs2 = Date.now() - start;
|
|
2898
|
+
recordTraceEvent(traceSession, {
|
|
2899
|
+
type: "ai_call",
|
|
2900
|
+
label: "Assistant Error",
|
|
2901
|
+
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
2902
|
+
status: "error",
|
|
2903
|
+
durationMs: durationMs2,
|
|
2904
|
+
requestBytes: promptBytes,
|
|
2905
|
+
model: getModelName(runtime.model || opts.model),
|
|
2906
|
+
provider: getProviderName(runtime.model || opts.model),
|
|
2907
|
+
error: { message: err?.message || String(err), stack: err?.stack },
|
|
2908
|
+
messageList: state.messages
|
|
2909
|
+
});
|
|
2910
|
+
throw err;
|
|
2911
|
+
}
|
|
2912
|
+
const messagesWithResponse = [
|
|
2913
|
+
...state.messages,
|
|
2914
|
+
response
|
|
2915
|
+
];
|
|
2916
|
+
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;
|
|
2917
|
+
const normalized = normalizeUsage(rawUsage);
|
|
2918
|
+
const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
|
|
2919
|
+
const durationMs = Date.now() - start;
|
|
2920
|
+
const shouldLogResponse = !!traceSession && traceSession.resolvedConfig.logData;
|
|
2921
|
+
const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
|
|
2922
|
+
const responseBytes = responsePayload !== void 0 ? estimatePayloadBytes(responsePayload) : void 0;
|
|
2923
|
+
recordTraceEvent(traceSession, {
|
|
2924
|
+
type: "ai_call",
|
|
2925
|
+
label: "Assistant Response",
|
|
2926
|
+
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
2927
|
+
durationMs,
|
|
2928
|
+
inputTokens: normalized?.prompt_tokens,
|
|
2929
|
+
outputTokens: normalized?.completion_tokens,
|
|
2930
|
+
totalTokens: normalized?.total_tokens,
|
|
2931
|
+
cachedInputTokens: normalized?.prompt_tokens_details?.cached_tokens,
|
|
2932
|
+
requestBytes: promptBytes,
|
|
2933
|
+
responseBytes,
|
|
2934
|
+
model: modelName,
|
|
2935
|
+
provider: getProviderName(runtime.model || opts.model),
|
|
2936
|
+
messageList: messagesWithResponse
|
|
2937
|
+
});
|
|
2938
|
+
if (normalized) {
|
|
2939
|
+
const usageState = state.usage || { perRequest: [], totals: {} };
|
|
2940
|
+
const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2941
|
+
const turn = usageState.perRequest.length + 1;
|
|
2942
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2943
|
+
const cachedInputTok = normalized.prompt_tokens_details?.cached_tokens;
|
|
2944
|
+
usageState.perRequest.push({ id, modelName, usage: normalized, timestamp, turn, cachedInput: cachedInputTok });
|
|
2945
|
+
const inputTok = normalized.prompt_tokens;
|
|
2946
|
+
const outputTok = normalized.completion_tokens;
|
|
2947
|
+
const totalTok = normalized.total_tokens;
|
|
2948
|
+
const key = modelName;
|
|
2949
|
+
const agg = usageState.totals[key] || { input: 0, output: 0, total: 0, cachedInput: 0 };
|
|
2950
|
+
usageState.totals[key] = {
|
|
2951
|
+
input: agg.input + (Number(inputTok) || 0),
|
|
2952
|
+
output: agg.output + (Number(outputTok) || 0),
|
|
2953
|
+
total: agg.total + (Number(totalTok) || 0),
|
|
2954
|
+
cachedInput: agg.cachedInput + (Number(cachedInputTok) || 0)
|
|
2955
|
+
};
|
|
2956
|
+
state.usage = usageState;
|
|
2342
2957
|
}
|
|
2958
|
+
return { messages: messagesWithResponse, usage: state.usage };
|
|
2343
2959
|
};
|
|
2344
2960
|
}
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
summaryTriggerTokens: 24e3,
|
|
2351
|
-
summaryPromptMaxTokens: 6e3,
|
|
2352
|
-
summaryCompressionRatioTarget: 0.5
|
|
2353
|
-
},
|
|
2354
|
-
context: {
|
|
2355
|
-
lastTurnsToKeep: 8,
|
|
2356
|
-
toolResponsePolicy: "keep_structured",
|
|
2357
|
-
budget: { systemReserveTokens: 1500, goalsReserveTokens: 1200, recentTurnsReserveTokens: 6e3, toolResponseReserveTokens: 3500 }
|
|
2358
|
-
},
|
|
2359
|
-
memory: { readPolicy: "recent_only" },
|
|
2360
|
-
delegation: { mode: "off", maxDelegationDepth: 1, maxChildCalls: 2, maxParallelChild: 1, childContextPolicy: "minimal" },
|
|
2361
|
-
toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 }
|
|
2362
|
-
}),
|
|
2363
|
-
balanced: buildProfile({}),
|
|
2364
|
-
deep: buildProfile({
|
|
2365
|
-
limits: { maxToolCalls: 40, maxParallelTools: 8, maxContextTokens: 2e5 },
|
|
2366
|
-
summarization: {
|
|
2367
|
-
maxTokens: 2e5,
|
|
2368
|
-
summaryTriggerTokens: 15e4,
|
|
2369
|
-
summaryPromptMaxTokens: 16e3,
|
|
2370
|
-
summaryCompressionRatioTarget: 0.4
|
|
2371
|
-
},
|
|
2372
|
-
context: {
|
|
2373
|
-
lastTurnsToKeep: 30,
|
|
2374
|
-
budget: { systemReserveTokens: 2500, goalsReserveTokens: 2500, recentTurnsReserveTokens: 36e3, toolResponseReserveTokens: 18e3 }
|
|
2375
|
-
},
|
|
2376
|
-
memory: { scope: "workspace" },
|
|
2377
|
-
delegation: { maxDelegationDepth: 3, maxChildCalls: 10, maxParallelChild: 4 },
|
|
2378
|
-
toolResponses: { maxToolResponseChars: 64e3, maxToolResponseTokens: 16e3 }
|
|
2379
|
-
}),
|
|
2380
|
-
research: buildProfile({
|
|
2381
|
-
limits: { maxToolCalls: 80, maxParallelTools: 10, maxContextTokens: 4e5 },
|
|
2382
|
-
summarization: {
|
|
2383
|
-
maxTokens: 4e5,
|
|
2384
|
-
summaryTriggerTokens: 3e5,
|
|
2385
|
-
summaryPromptMaxTokens: 24e3,
|
|
2386
|
-
summaryCompressionRatioTarget: 0.35
|
|
2387
|
-
},
|
|
2388
|
-
context: {
|
|
2389
|
-
lastTurnsToKeep: 60,
|
|
2390
|
-
budget: { systemReserveTokens: 3e3, goalsReserveTokens: 3e3, recentTurnsReserveTokens: 72e3, toolResponseReserveTokens: 32e3 }
|
|
2391
|
-
},
|
|
2392
|
-
memory: { scope: "workspace" },
|
|
2393
|
-
delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 16, maxParallelChild: 6, childContextPolicy: "full" },
|
|
2394
|
-
toolResponses: { maxToolResponseChars: 96e3, maxToolResponseTokens: 24e3 }
|
|
2395
|
-
})
|
|
2396
|
-
};
|
|
2397
|
-
function mergeLimits(base, override) {
|
|
2398
|
-
return {
|
|
2399
|
-
maxToolCalls: override?.maxToolCalls ?? base.maxToolCalls,
|
|
2400
|
-
maxParallelTools: override?.maxParallelTools ?? base.maxParallelTools,
|
|
2401
|
-
maxContextTokens: override?.maxContextTokens ?? base.maxContextTokens,
|
|
2402
|
-
maxTotalOutputTokens: override?.maxTotalOutputTokens ?? base.maxTotalOutputTokens ?? 0,
|
|
2403
|
-
maxCostUsd: override?.maxCostUsd ?? base.maxCostUsd ?? 0,
|
|
2404
|
-
maxWallClockMs: override?.maxWallClockMs ?? base.maxWallClockMs ?? 0
|
|
2405
|
-
};
|
|
2406
|
-
}
|
|
2407
|
-
function resolveBaseProfile(opts, runtimeProfile) {
|
|
2408
|
-
if (opts.customProfile?.extends) return opts.customProfile.extends;
|
|
2409
|
-
if (runtimeProfile !== "custom") return runtimeProfile;
|
|
2410
|
-
return "balanced";
|
|
2961
|
+
|
|
2962
|
+
// src/utils/traceSections.ts
|
|
2963
|
+
function truncate(text, max = 500) {
|
|
2964
|
+
if (!text) return "";
|
|
2965
|
+
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
2411
2966
|
}
|
|
2412
|
-
function
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
runtimeProfile,
|
|
2425
|
-
baseProfile,
|
|
2426
|
-
limits: mergeLimits(mergeLimits(preset.limits, customProfile.limits), opts.limits),
|
|
2427
|
-
summarization: {
|
|
2428
|
-
...preset.summarization,
|
|
2429
|
-
...customProfile.summarization || {},
|
|
2430
|
-
...summarizationOverride,
|
|
2431
|
-
enable: summarizationDisabled ? false : summarizationOverride.enable ?? customProfile.summarization?.enable ?? preset.summarization.enable,
|
|
2432
|
-
maxTokens: summarizationOverride.maxTokens ?? opts.limits?.maxContextTokens ?? customProfile.summarization?.maxTokens ?? preset.summarization.maxTokens,
|
|
2433
|
-
summaryTriggerTokens: summarizationOverride.summaryTriggerTokens ?? summarizationOverride.maxTokens ?? opts.limits?.maxContextTokens ?? customProfile.summarization?.summaryTriggerTokens ?? customProfile.summarization?.maxTokens ?? preset.summarization.summaryTriggerTokens,
|
|
2434
|
-
promptTemplate: summarizationOverride.promptTemplate ?? customProfile.summarization?.promptTemplate ?? preset.summarization.promptTemplate
|
|
2435
|
-
},
|
|
2436
|
-
context: {
|
|
2437
|
-
...preset.context,
|
|
2438
|
-
...customProfile.context || {},
|
|
2439
|
-
...opts.context || {},
|
|
2440
|
-
budget: {
|
|
2441
|
-
...preset.context.budget,
|
|
2442
|
-
...customProfile.context?.budget || {},
|
|
2443
|
-
...opts.context?.budget || {}
|
|
2444
|
-
},
|
|
2445
|
-
toolResponsePolicy: contextToolResponsePolicy
|
|
2446
|
-
},
|
|
2447
|
-
planning: {
|
|
2448
|
-
...preset.planning,
|
|
2449
|
-
...customProfile.planning || {},
|
|
2450
|
-
...opts.planning || {},
|
|
2451
|
-
mode: planningMode
|
|
2452
|
-
},
|
|
2453
|
-
memory: {
|
|
2454
|
-
...preset.memory,
|
|
2455
|
-
...customProfile.memory || {},
|
|
2456
|
-
...opts.memory || {},
|
|
2457
|
-
store: memoryStore
|
|
2458
|
-
},
|
|
2459
|
-
delegation: {
|
|
2460
|
-
...preset.delegation,
|
|
2461
|
-
...customProfile.delegation || {},
|
|
2462
|
-
...opts.delegation || {}
|
|
2463
|
-
},
|
|
2464
|
-
toolResponses: {
|
|
2465
|
-
...preset.toolResponses,
|
|
2466
|
-
...customProfile.toolResponses || {},
|
|
2467
|
-
...opts.toolResponses || {},
|
|
2468
|
-
defaultPolicy: opts.toolResponses?.defaultPolicy ?? customProfile.toolResponses?.defaultPolicy ?? contextToolResponsePolicy,
|
|
2469
|
-
toolResponseRetentionByTool: {
|
|
2470
|
-
...preset.toolResponses.toolResponseRetentionByTool,
|
|
2471
|
-
...customProfile.toolResponses?.toolResponseRetentionByTool || {},
|
|
2472
|
-
...opts.toolResponses?.toolResponseRetentionByTool || {}
|
|
2473
|
-
},
|
|
2474
|
-
criticalTools: opts.toolResponses?.criticalTools ?? customProfile.toolResponses?.criticalTools ?? preset.toolResponses.criticalTools
|
|
2967
|
+
function summarizeToolOutput(output) {
|
|
2968
|
+
if (output == null) return "";
|
|
2969
|
+
if (typeof output === "string") return truncate(output.trim());
|
|
2970
|
+
if (Array.isArray(output)) {
|
|
2971
|
+
const preview = output.slice(0, 3).map((item, index) => `${index + 1}. ${truncate(safeStringify(item))}`).join("\n");
|
|
2972
|
+
const suffix = output.length > 3 ? `
|
|
2973
|
+
\u2026 (+${output.length - 3} more)` : "";
|
|
2974
|
+
return `${preview}${suffix}`.trim();
|
|
2975
|
+
}
|
|
2976
|
+
if (typeof output === "object") {
|
|
2977
|
+
if (Array.isArray(output.items)) {
|
|
2978
|
+
return summarizeToolOutput(output.items);
|
|
2475
2979
|
}
|
|
2476
|
-
|
|
2980
|
+
return truncate(safeStringify(output));
|
|
2981
|
+
}
|
|
2982
|
+
return truncate(String(output));
|
|
2477
2983
|
}
|
|
2478
|
-
function
|
|
2479
|
-
|
|
2984
|
+
function extractToolItems(output) {
|
|
2985
|
+
const source = Array.isArray(output) ? output : Array.isArray(output?.items) ? output.items : void 0;
|
|
2986
|
+
if (!Array.isArray(source) || source.length === 0) return void 0;
|
|
2987
|
+
return source.slice(0, 5).map((item) => {
|
|
2988
|
+
if (item && typeof item === "object") {
|
|
2989
|
+
const snippetSource = item.content ?? item.snippet ?? item.description ?? item.text ?? item.summary ?? item;
|
|
2990
|
+
return {
|
|
2991
|
+
title: typeof item.title === "string" ? item.title : void 0,
|
|
2992
|
+
url: typeof item.url === "string" ? item.url : void 0,
|
|
2993
|
+
snippet: truncate(safeStringify(snippetSource))
|
|
2994
|
+
};
|
|
2995
|
+
}
|
|
2996
|
+
return { snippet: truncate(safeStringify(item)) };
|
|
2997
|
+
});
|
|
2480
2998
|
}
|
|
2481
2999
|
|
|
2482
3000
|
// src/smart/toolResponses.ts
|
|
@@ -2720,6 +3238,23 @@ function createToolsNode(initialTools, opts) {
|
|
|
2720
3238
|
outputSchema: opts?.outputSchema
|
|
2721
3239
|
};
|
|
2722
3240
|
const resolved = getResolvedSmartConfig(opts || {}, runtime);
|
|
3241
|
+
const contextPilotRuntime = state.ctx?.__contextPilot;
|
|
3242
|
+
const contextPilotQuery = contextPilotRuntime ? extractLatestUserQuery(state.messages) : "";
|
|
3243
|
+
const maybeCompressToolOutput = (toolNameForCompression, rawValue, executionIdForCompression) => {
|
|
3244
|
+
if (!contextPilotRuntime || !resolved.contextPilot.enabled) return { output: rawValue };
|
|
3245
|
+
if (resolved.toolResponses.criticalTools.includes(toolNameForCompression)) return { output: rawValue };
|
|
3246
|
+
const result = compressToolOutput({
|
|
3247
|
+
toolName: toolNameForCompression,
|
|
3248
|
+
output: rawValue,
|
|
3249
|
+
query: contextPilotQuery,
|
|
3250
|
+
executionId: executionIdForCompression,
|
|
3251
|
+
config: resolved.contextPilot,
|
|
3252
|
+
runtime: contextPilotRuntime
|
|
3253
|
+
});
|
|
3254
|
+
if (!result.applied) return { output: rawValue };
|
|
3255
|
+
const { output: compressedValue, ...stats } = result;
|
|
3256
|
+
return { output: compressedValue, stats };
|
|
3257
|
+
};
|
|
2723
3258
|
const activeTools = runtime.tools;
|
|
2724
3259
|
const toolByName = /* @__PURE__ */ new Map();
|
|
2725
3260
|
for (const tool of activeTools) toolByName.set(tool.name, tool);
|
|
@@ -2957,12 +3492,13 @@ function createToolsNode(initialTools, opts) {
|
|
|
2957
3492
|
try {
|
|
2958
3493
|
if (cachedHit !== void 0) {
|
|
2959
3494
|
const executionId2 = nanoid();
|
|
2960
|
-
const
|
|
3495
|
+
const { output: compressedCachedHit, stats: cachedContextPilotStats } = maybeCompressToolOutput(toolName, cachedHit, executionId2);
|
|
3496
|
+
const responsePolicy2 = applyToolResponseHardCap(toolName, compressedCachedHit, executionId2, resolved);
|
|
2961
3497
|
toolHistory.push({
|
|
2962
3498
|
executionId: executionId2,
|
|
2963
3499
|
toolName,
|
|
2964
3500
|
args,
|
|
2965
|
-
output:
|
|
3501
|
+
output: compressedCachedHit,
|
|
2966
3502
|
rawOutput: cachedHit,
|
|
2967
3503
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2968
3504
|
tool_call_id: tc.id,
|
|
@@ -2971,7 +3507,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
2971
3507
|
classification: responsePolicy2.classification,
|
|
2972
3508
|
retentionPolicy: "keep_full",
|
|
2973
3509
|
fromCache: true,
|
|
2974
|
-
status: "success"
|
|
3510
|
+
status: "success",
|
|
3511
|
+
contextPilot: cachedContextPilotStats
|
|
2975
3512
|
});
|
|
2976
3513
|
push({ role: "tool", content: responsePolicy2.content, tool_call_id: tc.id || `${tc.name}_${toolCount}`, name: tc.name });
|
|
2977
3514
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: cachedHit, durationMs: 0 });
|
|
@@ -3004,7 +3541,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
3004
3541
|
retentionPolicy: "keep_full",
|
|
3005
3542
|
originalTokenCount: responsePolicy2.tokenCount,
|
|
3006
3543
|
truncated: responsePolicy2.truncated,
|
|
3007
|
-
fromCache: true
|
|
3544
|
+
fromCache: true,
|
|
3545
|
+
contextPilot: cachedContextPilotStats
|
|
3008
3546
|
}
|
|
3009
3547
|
});
|
|
3010
3548
|
toolCount += 1;
|
|
@@ -3109,13 +3647,14 @@ function createToolsNode(initialTools, opts) {
|
|
|
3109
3647
|
state.ctx.__structuredOutputParsed = output.data;
|
|
3110
3648
|
state.ctx.__finalizedDueToStructuredOutput = true;
|
|
3111
3649
|
}
|
|
3112
|
-
const
|
|
3650
|
+
const { output: compressedOutput, stats: contextPilotStats } = maybeCompressToolOutput(toolName, output, executionId);
|
|
3651
|
+
const responsePolicy = applyToolResponseHardCap(toolName, compressedOutput, executionId, resolved);
|
|
3113
3652
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3114
3653
|
toolHistory.push({
|
|
3115
3654
|
executionId,
|
|
3116
3655
|
toolName,
|
|
3117
3656
|
args,
|
|
3118
|
-
output,
|
|
3657
|
+
output: compressedOutput,
|
|
3119
3658
|
rawOutput: output,
|
|
3120
3659
|
timestamp,
|
|
3121
3660
|
tool_call_id: tc.id,
|
|
@@ -3125,7 +3664,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
3125
3664
|
retentionPolicy: "keep_full",
|
|
3126
3665
|
summary: void 0,
|
|
3127
3666
|
archiveId: void 0,
|
|
3128
|
-
status: "success"
|
|
3667
|
+
status: "success",
|
|
3668
|
+
contextPilot: contextPilotStats
|
|
3129
3669
|
});
|
|
3130
3670
|
push({ role: "tool", content: responsePolicy.content, tool_call_id: tc.id || `${tc.name}_${toolCount}`, name: tc.name });
|
|
3131
3671
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: output, durationMs });
|
|
@@ -3163,7 +3703,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
3163
3703
|
classification: responsePolicy.classification,
|
|
3164
3704
|
retentionPolicy: "keep_full",
|
|
3165
3705
|
originalTokenCount: responsePolicy.tokenCount,
|
|
3166
|
-
truncated: responsePolicy.truncated
|
|
3706
|
+
truncated: responsePolicy.truncated,
|
|
3707
|
+
contextPilot: contextPilotStats
|
|
3167
3708
|
}
|
|
3168
3709
|
});
|
|
3169
3710
|
toolCount += 1;
|
|
@@ -3802,7 +4343,8 @@ var DISALLOWED_CTX_KEYS = /* @__PURE__ */ new Set([
|
|
|
3802
4343
|
"__traceSession",
|
|
3803
4344
|
"__paused",
|
|
3804
4345
|
"__cancellationToken",
|
|
3805
|
-
"__abortSignal"
|
|
4346
|
+
"__abortSignal",
|
|
4347
|
+
"__contextPilot"
|
|
3806
4348
|
]);
|
|
3807
4349
|
var clone = (value) => {
|
|
3808
4350
|
if (typeof globalThis.structuredClone === "function") {
|
|
@@ -4753,7 +5295,7 @@ function createAgent(opts) {
|
|
|
4753
5295
|
if (toolCalls.length === 0) {
|
|
4754
5296
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize) {
|
|
4755
5297
|
if (soManager.strategy.kind === "native") {
|
|
4756
|
-
const assistantText =
|
|
5298
|
+
const assistantText = extractMessageText2(lastMsg);
|
|
4757
5299
|
if (assistantText) {
|
|
4758
5300
|
const parsed = soManager.parseFromContent(assistantText);
|
|
4759
5301
|
if (parsed.success) {
|
|
@@ -4806,7 +5348,7 @@ function createAgent(opts) {
|
|
|
4806
5348
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput) {
|
|
4807
5349
|
const lastForParse = state.messages[state.messages.length - 1];
|
|
4808
5350
|
if (lastForParse?.role === "assistant") {
|
|
4809
|
-
const assistantText =
|
|
5351
|
+
const assistantText = extractMessageText2(lastForParse);
|
|
4810
5352
|
if (assistantText) {
|
|
4811
5353
|
const parsed = soManager.parseFromContent(assistantText);
|
|
4812
5354
|
if (parsed.success) {
|
|
@@ -4915,6 +5457,10 @@ function createAgent(opts) {
|
|
|
4915
5457
|
if (config?.timeoutMs && config.timeoutMs > 0) {
|
|
4916
5458
|
ctx.__deadline = Date.now() + config.timeoutMs;
|
|
4917
5459
|
}
|
|
5460
|
+
if (!ctx.__contextPilot) {
|
|
5461
|
+
const resolvedForContextPilot = getResolvedSmartConfig(opts, runtime);
|
|
5462
|
+
ctx.__contextPilot = createContextPilotRuntime(resolvedForContextPilot.contextPilot);
|
|
5463
|
+
}
|
|
4918
5464
|
const runtimeWithInvokeLimits = config?.limits ? { ...runtime, limits: { ...runtime.limits || {}, ...config.limits } } : runtime;
|
|
4919
5465
|
const initial = {
|
|
4920
5466
|
messages: input.messages || [],
|
|
@@ -4959,7 +5505,7 @@ function createAgent(opts) {
|
|
|
4959
5505
|
const isTransientSummarizationExit = !!res.ctx?.__needsSummarization;
|
|
4960
5506
|
const finalAssistantMsg = isTransientSummarizationExit ? void 0 : getLastAssistantMessage(res.messages);
|
|
4961
5507
|
const finalIsSyntheticSummary = !isTransientSummarizationExit && finalAssistantMsg && isSyntheticSummaryMessage(finalAssistantMsg);
|
|
4962
|
-
const content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" :
|
|
5508
|
+
const content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText2(finalAssistantMsg);
|
|
4963
5509
|
let parsed = void 0;
|
|
4964
5510
|
let outputError = void 0;
|
|
4965
5511
|
if (soManager) {
|
|
@@ -5268,7 +5814,7 @@ function renderMemoryBlock(facts) {
|
|
|
5268
5814
|
function clampToBudget(messages, maxContextTokens) {
|
|
5269
5815
|
let working = [...messages];
|
|
5270
5816
|
while (working.length > 2) {
|
|
5271
|
-
const tokenCount = countApproxTokens(working.map(
|
|
5817
|
+
const tokenCount = countApproxTokens(working.map(extractMessageText2).join("\n"));
|
|
5272
5818
|
if (tokenCount <= maxContextTokens) return working;
|
|
5273
5819
|
const firstNonSystem = working.findIndex((message, index) => !(index === 0 && message.role === "system"));
|
|
5274
5820
|
if (firstNonSystem < 0) break;
|
|
@@ -6141,6 +6687,13 @@ function createGetToolResponseTool(stateRef) {
|
|
|
6141
6687
|
if (execution) {
|
|
6142
6688
|
return execution.rawOutput || execution.output;
|
|
6143
6689
|
}
|
|
6690
|
+
const ccrStore = stateRef.ctx?.__contextPilot?.ccrStore;
|
|
6691
|
+
if (ccrStore && typeof ccrStore.retrieve === "function") {
|
|
6692
|
+
const recovered = ccrStore.retrieve(executionId);
|
|
6693
|
+
if (recovered !== void 0) {
|
|
6694
|
+
return recovered;
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6144
6697
|
return "Execution not found. Please check the executionId.";
|
|
6145
6698
|
}
|
|
6146
6699
|
});
|
|
@@ -7072,7 +7625,7 @@ function createSmartAgent(opts) {
|
|
|
7072
7625
|
].join("\n");
|
|
7073
7626
|
function latestUserPrompt(messages) {
|
|
7074
7627
|
const latest = [...messages].reverse().find((message) => message.role === "user");
|
|
7075
|
-
return latest ?
|
|
7628
|
+
return latest ? extractMessageText2(latest) : "";
|
|
7076
7629
|
}
|
|
7077
7630
|
async function syncMemory(state) {
|
|
7078
7631
|
const query = latestUserPrompt(state.messages || []);
|
|
@@ -8037,6 +8590,78 @@ function resolveBudget(reasoning, effortBudget) {
|
|
|
8037
8590
|
return void 0;
|
|
8038
8591
|
}
|
|
8039
8592
|
|
|
8593
|
+
// src/providers/utils/media.ts
|
|
8594
|
+
var EXTENSION_MIME = {
|
|
8595
|
+
jpg: "image/jpeg",
|
|
8596
|
+
jpeg: "image/jpeg",
|
|
8597
|
+
png: "image/png",
|
|
8598
|
+
gif: "image/gif",
|
|
8599
|
+
webp: "image/webp",
|
|
8600
|
+
svg: "image/svg+xml",
|
|
8601
|
+
bmp: "image/bmp",
|
|
8602
|
+
tif: "image/tiff",
|
|
8603
|
+
tiff: "image/tiff",
|
|
8604
|
+
heic: "image/heic",
|
|
8605
|
+
heif: "image/heif",
|
|
8606
|
+
pdf: "application/pdf",
|
|
8607
|
+
csv: "text/csv",
|
|
8608
|
+
txt: "text/plain",
|
|
8609
|
+
md: "text/markdown",
|
|
8610
|
+
html: "text/html",
|
|
8611
|
+
doc: "application/msword",
|
|
8612
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
8613
|
+
xls: "application/vnd.ms-excel",
|
|
8614
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
8615
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
8616
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
8617
|
+
mp3: "audio/mpeg",
|
|
8618
|
+
mpga: "audio/mpeg",
|
|
8619
|
+
wav: "audio/wav",
|
|
8620
|
+
ogg: "audio/ogg",
|
|
8621
|
+
flac: "audio/flac",
|
|
8622
|
+
aac: "audio/aac",
|
|
8623
|
+
m4a: "audio/mp4",
|
|
8624
|
+
webm: "audio/webm",
|
|
8625
|
+
mp4: "video/mp4",
|
|
8626
|
+
mov: "video/quicktime",
|
|
8627
|
+
avi: "video/x-msvideo"
|
|
8628
|
+
};
|
|
8629
|
+
function inferMediaTypeFromUrl(urlOrName) {
|
|
8630
|
+
if (!urlOrName) return void 0;
|
|
8631
|
+
const cleaned = urlOrName.split("?")[0].split("#")[0];
|
|
8632
|
+
const ext = cleaned.split(".").pop()?.toLowerCase();
|
|
8633
|
+
if (!ext || ext === cleaned.toLowerCase()) return void 0;
|
|
8634
|
+
return EXTENSION_MIME[ext];
|
|
8635
|
+
}
|
|
8636
|
+
function audioMimeToOpenAIFormat(mediaType) {
|
|
8637
|
+
const m = (mediaType ?? "").toLowerCase();
|
|
8638
|
+
if (m.includes("wav")) return "wav";
|
|
8639
|
+
return "mp3";
|
|
8640
|
+
}
|
|
8641
|
+
var BEDROCK_DOC_FORMATS = {
|
|
8642
|
+
"application/pdf": "pdf",
|
|
8643
|
+
"text/csv": "csv",
|
|
8644
|
+
"application/msword": "doc",
|
|
8645
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
|
|
8646
|
+
"application/vnd.ms-excel": "xls",
|
|
8647
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
|
|
8648
|
+
"text/html": "html",
|
|
8649
|
+
"text/plain": "txt",
|
|
8650
|
+
"text/markdown": "md"
|
|
8651
|
+
};
|
|
8652
|
+
function documentMimeToBedrockFormat(mediaType, fileName) {
|
|
8653
|
+
if (mediaType && BEDROCK_DOC_FORMATS[mediaType.toLowerCase()]) {
|
|
8654
|
+
return BEDROCK_DOC_FORMATS[mediaType.toLowerCase()];
|
|
8655
|
+
}
|
|
8656
|
+
const inferred = inferMediaTypeFromUrl(fileName);
|
|
8657
|
+
if (inferred && BEDROCK_DOC_FORMATS[inferred]) return BEDROCK_DOC_FORMATS[inferred];
|
|
8658
|
+
return void 0;
|
|
8659
|
+
}
|
|
8660
|
+
function sanitizeBedrockDocName(name, fallback = "document") {
|
|
8661
|
+
const cleaned = (name ?? "").replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9\s\-()[\]]/g, " ").replace(/\s+/g, " ").trim();
|
|
8662
|
+
return cleaned || fallback;
|
|
8663
|
+
}
|
|
8664
|
+
|
|
8040
8665
|
// src/providers/openai.ts
|
|
8041
8666
|
var OpenAIProvider = class extends BaseProvider {
|
|
8042
8667
|
constructor(config) {
|
|
@@ -8259,6 +8884,27 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
8259
8884
|
const url = src.type === "url" ? src.url : `data:${src.mediaType};base64,${src.data}`;
|
|
8260
8885
|
return { type: "input_image", image_url: url };
|
|
8261
8886
|
}
|
|
8887
|
+
if (part.type === "file") {
|
|
8888
|
+
const src = part.source;
|
|
8889
|
+
if (src.type === "base64") {
|
|
8890
|
+
return {
|
|
8891
|
+
type: "input_file",
|
|
8892
|
+
filename: part.fileName ?? "file",
|
|
8893
|
+
file_data: `data:${src.mediaType};base64,${src.data}`
|
|
8894
|
+
};
|
|
8895
|
+
}
|
|
8896
|
+
return { type: "input_file", file_url: src.url };
|
|
8897
|
+
}
|
|
8898
|
+
if (part.type === "audio") {
|
|
8899
|
+
const src = part.source;
|
|
8900
|
+
if (src.type === "base64") {
|
|
8901
|
+
return {
|
|
8902
|
+
type: "input_audio",
|
|
8903
|
+
input_audio: { data: src.data, format: audioMimeToOpenAIFormat(src.mediaType) }
|
|
8904
|
+
};
|
|
8905
|
+
}
|
|
8906
|
+
return { type: textType, text: `[audio: ${src.url}]` };
|
|
8907
|
+
}
|
|
8262
8908
|
return { type: textType, text: "" };
|
|
8263
8909
|
});
|
|
8264
8910
|
return { role, content };
|
|
@@ -8343,6 +8989,29 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
8343
8989
|
const url = src.type === "url" ? src.url : `data:${src.mediaType};base64,${src.data}`;
|
|
8344
8990
|
return { type: "image_url", image_url: { url } };
|
|
8345
8991
|
}
|
|
8992
|
+
if (part.type === "file") {
|
|
8993
|
+
const src = part.source;
|
|
8994
|
+
if (src.type === "base64") {
|
|
8995
|
+
return {
|
|
8996
|
+
type: "file",
|
|
8997
|
+
file: {
|
|
8998
|
+
filename: part.fileName ?? "file",
|
|
8999
|
+
file_data: `data:${src.mediaType};base64,${src.data}`
|
|
9000
|
+
}
|
|
9001
|
+
};
|
|
9002
|
+
}
|
|
9003
|
+
return { type: "text", text: `[file: ${src.url}]` };
|
|
9004
|
+
}
|
|
9005
|
+
if (part.type === "audio") {
|
|
9006
|
+
const src = part.source;
|
|
9007
|
+
if (src.type === "base64") {
|
|
9008
|
+
return {
|
|
9009
|
+
type: "input_audio",
|
|
9010
|
+
input_audio: { data: src.data, format: audioMimeToOpenAIFormat(src.mediaType) }
|
|
9011
|
+
};
|
|
9012
|
+
}
|
|
9013
|
+
return { type: "text", text: `[audio: ${src.url}]` };
|
|
9014
|
+
}
|
|
8346
9015
|
return part;
|
|
8347
9016
|
});
|
|
8348
9017
|
}
|
|
@@ -8740,6 +9409,22 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
8740
9409
|
source: { type: "url", url: src.url }
|
|
8741
9410
|
};
|
|
8742
9411
|
}
|
|
9412
|
+
if (part.type === "file") {
|
|
9413
|
+
const src = part.source;
|
|
9414
|
+
const title = part.fileName ? { title: part.fileName } : {};
|
|
9415
|
+
if (src.type === "base64") {
|
|
9416
|
+
return {
|
|
9417
|
+
type: "document",
|
|
9418
|
+
source: { type: "base64", media_type: src.mediaType, data: src.data },
|
|
9419
|
+
...title
|
|
9420
|
+
};
|
|
9421
|
+
}
|
|
9422
|
+
return { type: "document", source: { type: "url", url: src.url }, ...title };
|
|
9423
|
+
}
|
|
9424
|
+
if (part.type === "audio") {
|
|
9425
|
+
const src = part.source;
|
|
9426
|
+
return { type: "text", text: src.type === "url" ? `[audio: ${src.url}]` : "[audio attachment omitted: not supported by this model]" };
|
|
9427
|
+
}
|
|
8743
9428
|
return part;
|
|
8744
9429
|
});
|
|
8745
9430
|
}
|
|
@@ -9207,6 +9892,24 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
9207
9892
|
}
|
|
9208
9893
|
});
|
|
9209
9894
|
}
|
|
9895
|
+
} else if (part.type === "file") {
|
|
9896
|
+
const src = part.source;
|
|
9897
|
+
const format = documentMimeToBedrockFormat(src.mediaType, part.fileName);
|
|
9898
|
+
if (src.type === "base64" && format) {
|
|
9899
|
+
content.push({
|
|
9900
|
+
document: {
|
|
9901
|
+
format,
|
|
9902
|
+
name: sanitizeBedrockDocName(part.fileName),
|
|
9903
|
+
source: { bytes: src.data }
|
|
9904
|
+
}
|
|
9905
|
+
});
|
|
9906
|
+
} else {
|
|
9907
|
+
const ref = src.type === "url" ? src.url : part.fileName ?? "attachment";
|
|
9908
|
+
content.push({ text: `[file: ${ref}]` });
|
|
9909
|
+
}
|
|
9910
|
+
} else if (part.type === "audio") {
|
|
9911
|
+
const src = part.source;
|
|
9912
|
+
content.push({ text: src.type === "url" ? `[audio: ${src.url}]` : "[audio attachment omitted: not supported by this model]" });
|
|
9210
9913
|
}
|
|
9211
9914
|
}
|
|
9212
9915
|
}
|
|
@@ -9550,7 +10253,25 @@ var VertexProvider = class extends BaseProvider {
|
|
|
9550
10253
|
});
|
|
9551
10254
|
} else {
|
|
9552
10255
|
parts.push({
|
|
9553
|
-
fileData: {
|
|
10256
|
+
fileData: {
|
|
10257
|
+
mimeType: src.mediaType ?? inferMediaTypeFromUrl(src.url) ?? "image/jpeg",
|
|
10258
|
+
fileUri: src.url
|
|
10259
|
+
}
|
|
10260
|
+
});
|
|
10261
|
+
}
|
|
10262
|
+
} else if (part.type === "file" || part.type === "audio") {
|
|
10263
|
+
const src = part.source;
|
|
10264
|
+
const fallbackMime = part.type === "audio" ? "audio/mpeg" : "application/pdf";
|
|
10265
|
+
if (src.type === "base64") {
|
|
10266
|
+
parts.push({
|
|
10267
|
+
inlineData: { mimeType: src.mediaType ?? fallbackMime, data: src.data }
|
|
10268
|
+
});
|
|
10269
|
+
} else {
|
|
10270
|
+
parts.push({
|
|
10271
|
+
fileData: {
|
|
10272
|
+
mimeType: src.mediaType ?? inferMediaTypeFromUrl(src.url) ?? inferMediaTypeFromUrl(part.fileName) ?? fallbackMime,
|
|
10273
|
+
fileUri: src.url
|
|
10274
|
+
}
|
|
9554
10275
|
});
|
|
9555
10276
|
}
|
|
9556
10277
|
}
|
|
@@ -9895,9 +10616,50 @@ function convertContent(content) {
|
|
|
9895
10616
|
}
|
|
9896
10617
|
}
|
|
9897
10618
|
}
|
|
10619
|
+
if (part.type === "file" || part.type === "document") {
|
|
10620
|
+
const source = extractBinarySource(part);
|
|
10621
|
+
if (source) {
|
|
10622
|
+
const fileName = part.metadata?.filename ?? part.metadata?.fileName ?? part.fileName ?? part.filename ?? part.name ?? part.file?.filename;
|
|
10623
|
+
return { type: "file", source, ...fileName ? { fileName } : {} };
|
|
10624
|
+
}
|
|
10625
|
+
}
|
|
10626
|
+
if (part.type === "audio" || part.type === "input_audio") {
|
|
10627
|
+
const ia = part.input_audio;
|
|
10628
|
+
if (ia?.data) {
|
|
10629
|
+
const mediaType = ia.format === "wav" ? "audio/wav" : "audio/mpeg";
|
|
10630
|
+
return { type: "audio", source: { type: "base64", mediaType, data: ia.data } };
|
|
10631
|
+
}
|
|
10632
|
+
const source = extractBinarySource(part);
|
|
10633
|
+
if (source) return { type: "audio", source };
|
|
10634
|
+
}
|
|
9898
10635
|
return { type: "text", text: part.text ?? part.content ?? JSON.stringify(part) };
|
|
9899
10636
|
});
|
|
9900
10637
|
}
|
|
10638
|
+
function extractBinarySource(part) {
|
|
10639
|
+
const src = part.source;
|
|
10640
|
+
if (src?.type === "base64" && src.data) {
|
|
10641
|
+
return { type: "base64", mediaType: src.mediaType ?? src.media_type ?? src.mime_type ?? "application/octet-stream", data: src.data };
|
|
10642
|
+
}
|
|
10643
|
+
if (src?.type === "url" && src.url) {
|
|
10644
|
+
const mediaType2 = src.mediaType ?? src.media_type ?? src.mime_type;
|
|
10645
|
+
return { type: "url", url: src.url, ...mediaType2 ? { mediaType: mediaType2 } : {} };
|
|
10646
|
+
}
|
|
10647
|
+
const mediaType = part.mime_type ?? part.mimeType ?? part.media_type ?? part.mediaType;
|
|
10648
|
+
if (part.source_type === "base64" && part.data) {
|
|
10649
|
+
return { type: "base64", mediaType: mediaType ?? "application/octet-stream", data: part.data };
|
|
10650
|
+
}
|
|
10651
|
+
if (part.source_type === "url" && part.url) {
|
|
10652
|
+
return { type: "url", url: part.url, ...mediaType ? { mediaType } : {} };
|
|
10653
|
+
}
|
|
10654
|
+
const value = part.data ?? part.url ?? part.file?.file_data;
|
|
10655
|
+
if (typeof value === "string" && value) {
|
|
10656
|
+
const match = value.match(/^data:([^;]+);base64,(.+)$/);
|
|
10657
|
+
if (match) return { type: "base64", mediaType: mediaType ?? match[1], data: match[2] };
|
|
10658
|
+
if (/^https?:\/\//.test(value)) return { type: "url", url: value, ...mediaType ? { mediaType } : {} };
|
|
10659
|
+
if (mediaType) return { type: "base64", mediaType, data: value };
|
|
10660
|
+
}
|
|
10661
|
+
return void 0;
|
|
10662
|
+
}
|
|
9901
10663
|
function isZodSchema(obj) {
|
|
9902
10664
|
return obj != null && typeof obj === "object" && typeof obj.safeParse === "function" && "_def" in obj;
|
|
9903
10665
|
}
|
|
@@ -10175,6 +10937,6 @@ function createProvider(config) {
|
|
|
10175
10937
|
}
|
|
10176
10938
|
}
|
|
10177
10939
|
|
|
10178
|
-
export { AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, GuardrailPhase, InMemoryMemoryStore, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, ToolBasedStrategy, VertexProvider, agentVerdictRule, appendBoundTools, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, canOpenSkill, canSpawn, captureSnapshot, codePresenceRule, cognipeerSink, composeToolSets, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createJsonGuardrail, createManageTodoTool, createOpenSkillTool, createParallelTool, createProvider, createRegexGuardrail, createResolverNode, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customSink, dedupeToolsByName, defaultTokenCounter, emptyUsage, evaluateGuardrails, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasToolResponseRecoveryReference, httpSink, isSmartModel, jsonSchemaRule, loadSkillsFromDisk, normalizeSmartAgentOptions, otlpSink, parseSkillFrontmatter, readMemoryFacts, regexRule, resolveAvailableSkills, resolveAvailableSubagents, resolveMemoryStore, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveToolApprovalState, resolveUserQuestionState, restoreSnapshot, runSmartAgentEvalHarness, seedChildMessages, setTokenCounter, startStreamingSession, traceSessionToOtlp, validateReasoningConfig, withTools, withinDepth, writeSummaryFactsToMemory };
|
|
10940
|
+
export { AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONTEXT_PILOT_JSON_MARKER_KEY, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DedupTracker, GuardrailPhase, InMemoryMemoryStore, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, ToolBasedStrategy, VertexProvider, agentVerdictRule, appendBoundTools, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, canOpenSkill, canSpawn, captureSnapshot, codePresenceRule, cognipeerSink, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createJsonGuardrail, createManageTodoTool, createOpenSkillTool, createParallelTool, createProvider, createRegexGuardrail, createResolverNode, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customSink, dedupeToolsByName, defaultTokenCounter, detectTextFormat, detectVolatileContent, emptyUsage, evaluateGuardrails, extractLatestUserQuery, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasToolResponseRecoveryReference, httpSink, isSmartModel, jsonSchemaRule, loadSkillsFromDisk, normalizeSmartAgentOptions, otlpSink, parseSkillFrontmatter, readMemoryFacts, regexRule, resolveAvailableSkills, resolveAvailableSubagents, resolveMemoryStore, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveToolApprovalState, resolveUserQuestionState, restoreSnapshot, runSmartAgentEvalHarness, scoreItemsByRelevance, seedChildMessages, selectTopIndicesInOrder, setTokenCounter, startStreamingSession, tokenize, traceSessionToOtlp, validateReasoningConfig, withTools, withinDepth, writeSummaryFactsToMemory };
|
|
10179
10941
|
//# sourceMappingURL=index.mjs.map
|
|
10180
10942
|
//# sourceMappingURL=index.mjs.map
|