@cognipeer/agent-sdk 0.6.5 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/dist/index.cjs +630 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +149 -2
- package/dist/index.d.ts +149 -2
- package/dist/index.mjs +629 -176
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -52,7 +52,7 @@ function getTokenCounter() {
|
|
|
52
52
|
function countApproxTokens(text) {
|
|
53
53
|
return activeTokenCounter(text || "");
|
|
54
54
|
}
|
|
55
|
-
function
|
|
55
|
+
function extractMessageText2(m) {
|
|
56
56
|
if (!m) return "";
|
|
57
57
|
const parts = [];
|
|
58
58
|
parts.push(m.role || "");
|
|
@@ -102,7 +102,7 @@ function extractMessageText(m) {
|
|
|
102
102
|
}
|
|
103
103
|
function countMessagesTokens(messages) {
|
|
104
104
|
if (!Array.isArray(messages) || messages.length === 0) return 0;
|
|
105
|
-
const allText = messages.map(
|
|
105
|
+
const allText = messages.map(extractMessageText2).join("\n");
|
|
106
106
|
return countApproxTokens(allText) + messages.length * 4;
|
|
107
107
|
}
|
|
108
108
|
var activeTokenCounter;
|
|
@@ -753,6 +753,7 @@ function createResolverNode() {
|
|
|
753
753
|
toolHistory: state.toolHistory || [],
|
|
754
754
|
toolHistoryArchived: state.toolHistoryArchived || [],
|
|
755
755
|
pendingApprovals: state.pendingApprovals || [],
|
|
756
|
+
pendingUserQuestions: state.pendingUserQuestions || [],
|
|
756
757
|
plan: state.plan || null,
|
|
757
758
|
planVersion: state.planVersion || 0
|
|
758
759
|
};
|
|
@@ -1271,6 +1272,7 @@ function eventToOtlpSpan(event) {
|
|
|
1271
1272
|
stringAttr("cognipeer.actor.role", event.actor?.role),
|
|
1272
1273
|
stringAttr("cognipeer.model", event.model),
|
|
1273
1274
|
stringAttr("cognipeer.provider", event.provider),
|
|
1275
|
+
stringAttr("cognipeer.tool.details", event.toolDetails ? JSON.stringify(event.toolDetails) : void 0),
|
|
1274
1276
|
intAttr("cognipeer.tokens.input", event.inputTokens),
|
|
1275
1277
|
intAttr("cognipeer.tokens.output", event.outputTokens),
|
|
1276
1278
|
intAttr("cognipeer.tokens.total", event.totalTokens),
|
|
@@ -1742,6 +1744,7 @@ function recordTraceEvent(session, event) {
|
|
|
1742
1744
|
responseBytes,
|
|
1743
1745
|
model: resolvedModel,
|
|
1744
1746
|
provider: resolvedProvider,
|
|
1747
|
+
toolDetails: session.resolvedConfig.logData ? sanitizeTracePayload(event.toolDetails) : void 0,
|
|
1745
1748
|
toolExecutionId: event.toolExecutionId,
|
|
1746
1749
|
retryOf: event.retryOf,
|
|
1747
1750
|
error: event.error ?? (status === "error" ? { message: "Unknown error" } : void 0) ?? void 0,
|
|
@@ -2192,16 +2195,99 @@ function createAgentCoreNode(opts) {
|
|
|
2192
2195
|
};
|
|
2193
2196
|
}
|
|
2194
2197
|
|
|
2198
|
+
// src/utils/content.ts
|
|
2199
|
+
function contentToString(content) {
|
|
2200
|
+
try {
|
|
2201
|
+
if (content == null) return "";
|
|
2202
|
+
if (typeof content === "string") return content;
|
|
2203
|
+
if (Array.isArray(content)) {
|
|
2204
|
+
return content.map((p) => {
|
|
2205
|
+
if (!p || typeof p !== "object") return String(p);
|
|
2206
|
+
if (p.type === "text") return String(p.text ?? "");
|
|
2207
|
+
if (p.type === "image_url") {
|
|
2208
|
+
const img = p.image_url;
|
|
2209
|
+
const url = typeof img === "string" ? img : img?.url;
|
|
2210
|
+
const detail = typeof img === "string" ? void 0 : img?.detail;
|
|
2211
|
+
return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
|
|
2212
|
+
}
|
|
2213
|
+
return JSON.stringify(p);
|
|
2214
|
+
}).join("\n");
|
|
2215
|
+
}
|
|
2216
|
+
return JSON.stringify(content);
|
|
2217
|
+
} catch {
|
|
2218
|
+
return String(content);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
function mergeContentsToString(contents) {
|
|
2222
|
+
return contents.map((c) => contentToString(c)).join("\n");
|
|
2223
|
+
}
|
|
2224
|
+
function safeStringify(value, pretty = false) {
|
|
2225
|
+
if (value == null) return "";
|
|
2226
|
+
if (typeof value === "string") return value;
|
|
2227
|
+
try {
|
|
2228
|
+
return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
|
|
2229
|
+
} catch {
|
|
2230
|
+
return String(value);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
function extractMessageText(message) {
|
|
2234
|
+
if (!message) return "";
|
|
2235
|
+
const content = message.content;
|
|
2236
|
+
if (typeof content === "string") return content;
|
|
2237
|
+
if (Array.isArray(content)) {
|
|
2238
|
+
return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
|
|
2239
|
+
}
|
|
2240
|
+
return "";
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
// src/utils/traceSections.ts
|
|
2244
|
+
function truncate(text, max = 500) {
|
|
2245
|
+
if (!text) return "";
|
|
2246
|
+
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
2247
|
+
}
|
|
2248
|
+
function summarizeToolOutput(output) {
|
|
2249
|
+
if (output == null) return "";
|
|
2250
|
+
if (typeof output === "string") return truncate(output.trim());
|
|
2251
|
+
if (Array.isArray(output)) {
|
|
2252
|
+
const preview = output.slice(0, 3).map((item, index) => `${index + 1}. ${truncate(safeStringify(item))}`).join("\n");
|
|
2253
|
+
const suffix = output.length > 3 ? `
|
|
2254
|
+
\u2026 (+${output.length - 3} more)` : "";
|
|
2255
|
+
return `${preview}${suffix}`.trim();
|
|
2256
|
+
}
|
|
2257
|
+
if (typeof output === "object") {
|
|
2258
|
+
if (Array.isArray(output.items)) {
|
|
2259
|
+
return summarizeToolOutput(output.items);
|
|
2260
|
+
}
|
|
2261
|
+
return truncate(safeStringify(output));
|
|
2262
|
+
}
|
|
2263
|
+
return truncate(String(output));
|
|
2264
|
+
}
|
|
2265
|
+
function extractToolItems(output) {
|
|
2266
|
+
const source = Array.isArray(output) ? output : Array.isArray(output?.items) ? output.items : void 0;
|
|
2267
|
+
if (!Array.isArray(source) || source.length === 0) return void 0;
|
|
2268
|
+
return source.slice(0, 5).map((item) => {
|
|
2269
|
+
if (item && typeof item === "object") {
|
|
2270
|
+
const snippetSource = item.content ?? item.snippet ?? item.description ?? item.text ?? item.summary ?? item;
|
|
2271
|
+
return {
|
|
2272
|
+
title: typeof item.title === "string" ? item.title : void 0,
|
|
2273
|
+
url: typeof item.url === "string" ? item.url : void 0,
|
|
2274
|
+
snippet: truncate(safeStringify(snippetSource))
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
2277
|
+
return { snippet: truncate(safeStringify(item)) };
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2195
2281
|
// src/smart/runtimeConfig.ts
|
|
2196
2282
|
var DEFAULT_CRITICAL_TOOLS = ["response", "manage_todo_list", "get_tool_response"];
|
|
2197
2283
|
var BASE_DEFAULTS = {
|
|
2198
|
-
limits: { maxToolCalls:
|
|
2284
|
+
limits: { maxToolCalls: 20, maxParallelTools: 5, maxContextTokens: 96e3, maxTotalOutputTokens: 0, maxCostUsd: 0, maxWallClockMs: 0 },
|
|
2199
2285
|
summarization: {
|
|
2200
2286
|
enable: true,
|
|
2201
|
-
maxTokens:
|
|
2202
|
-
summaryTriggerTokens:
|
|
2203
|
-
summaryPromptMaxTokens:
|
|
2204
|
-
summaryCompressionRatioTarget: 0.
|
|
2287
|
+
maxTokens: 96e3,
|
|
2288
|
+
summaryTriggerTokens: 72e3,
|
|
2289
|
+
summaryPromptMaxTokens: 12e3,
|
|
2290
|
+
summaryCompressionRatioTarget: 0.45,
|
|
2205
2291
|
summaryMode: "incremental",
|
|
2206
2292
|
promptTemplate: "",
|
|
2207
2293
|
toolFreeCall: true,
|
|
@@ -2209,13 +2295,13 @@ var BASE_DEFAULTS = {
|
|
|
2209
2295
|
},
|
|
2210
2296
|
context: {
|
|
2211
2297
|
policy: "hybrid",
|
|
2212
|
-
lastTurnsToKeep:
|
|
2298
|
+
lastTurnsToKeep: 16,
|
|
2213
2299
|
toolResponsePolicy: "summarize_archive",
|
|
2214
2300
|
budget: {
|
|
2215
|
-
systemReserveTokens:
|
|
2216
|
-
goalsReserveTokens:
|
|
2217
|
-
recentTurnsReserveTokens:
|
|
2218
|
-
toolResponseReserveTokens:
|
|
2301
|
+
systemReserveTokens: 2e3,
|
|
2302
|
+
goalsReserveTokens: 2e3,
|
|
2303
|
+
recentTurnsReserveTokens: 18e3,
|
|
2304
|
+
toolResponseReserveTokens: 9e3
|
|
2219
2305
|
}
|
|
2220
2306
|
},
|
|
2221
2307
|
planning: {
|
|
@@ -2232,14 +2318,14 @@ var BASE_DEFAULTS = {
|
|
|
2232
2318
|
delegation: {
|
|
2233
2319
|
mode: "role_based",
|
|
2234
2320
|
maxDelegationDepth: 2,
|
|
2235
|
-
maxChildCalls:
|
|
2236
|
-
maxParallelChild:
|
|
2321
|
+
maxChildCalls: 6,
|
|
2322
|
+
maxParallelChild: 3,
|
|
2237
2323
|
childContextPolicy: "scoped",
|
|
2238
2324
|
requireJsonOutputContract: true
|
|
2239
2325
|
},
|
|
2240
2326
|
toolResponses: {
|
|
2241
|
-
maxToolResponseChars:
|
|
2242
|
-
maxToolResponseTokens:
|
|
2327
|
+
maxToolResponseChars: 32e3,
|
|
2328
|
+
maxToolResponseTokens: 8e3,
|
|
2243
2329
|
defaultPolicy: "summarize_archive",
|
|
2244
2330
|
toolResponseRetentionByTool: {},
|
|
2245
2331
|
criticalTools: [...DEFAULT_CRITICAL_TOOLS],
|
|
@@ -2268,54 +2354,54 @@ function buildProfile(overrides) {
|
|
|
2268
2354
|
}
|
|
2269
2355
|
var DEFAULT_PROFILE_CONFIGS = {
|
|
2270
2356
|
fast: buildProfile({
|
|
2271
|
-
limits: { maxToolCalls:
|
|
2357
|
+
limits: { maxToolCalls: 8, maxParallelTools: 3, maxContextTokens: 32e3 },
|
|
2272
2358
|
summarization: {
|
|
2273
|
-
maxTokens:
|
|
2274
|
-
summaryTriggerTokens:
|
|
2275
|
-
summaryPromptMaxTokens:
|
|
2276
|
-
summaryCompressionRatioTarget: 0.
|
|
2359
|
+
maxTokens: 32e3,
|
|
2360
|
+
summaryTriggerTokens: 24e3,
|
|
2361
|
+
summaryPromptMaxTokens: 6e3,
|
|
2362
|
+
summaryCompressionRatioTarget: 0.5
|
|
2277
2363
|
},
|
|
2278
2364
|
context: {
|
|
2279
|
-
lastTurnsToKeep:
|
|
2365
|
+
lastTurnsToKeep: 8,
|
|
2280
2366
|
toolResponsePolicy: "keep_structured",
|
|
2281
|
-
budget: { systemReserveTokens:
|
|
2367
|
+
budget: { systemReserveTokens: 1500, goalsReserveTokens: 1200, recentTurnsReserveTokens: 6e3, toolResponseReserveTokens: 3500 }
|
|
2282
2368
|
},
|
|
2283
2369
|
memory: { readPolicy: "recent_only" },
|
|
2284
2370
|
delegation: { mode: "off", maxDelegationDepth: 1, maxChildCalls: 2, maxParallelChild: 1, childContextPolicy: "minimal" },
|
|
2285
|
-
toolResponses: { maxToolResponseChars:
|
|
2371
|
+
toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 }
|
|
2286
2372
|
}),
|
|
2287
2373
|
balanced: buildProfile({}),
|
|
2288
2374
|
deep: buildProfile({
|
|
2289
|
-
limits: { maxToolCalls:
|
|
2375
|
+
limits: { maxToolCalls: 40, maxParallelTools: 8, maxContextTokens: 2e5 },
|
|
2290
2376
|
summarization: {
|
|
2291
|
-
maxTokens:
|
|
2292
|
-
summaryTriggerTokens:
|
|
2293
|
-
summaryPromptMaxTokens:
|
|
2294
|
-
summaryCompressionRatioTarget: 0.
|
|
2377
|
+
maxTokens: 2e5,
|
|
2378
|
+
summaryTriggerTokens: 15e4,
|
|
2379
|
+
summaryPromptMaxTokens: 16e3,
|
|
2380
|
+
summaryCompressionRatioTarget: 0.4
|
|
2295
2381
|
},
|
|
2296
2382
|
context: {
|
|
2297
|
-
lastTurnsToKeep:
|
|
2298
|
-
budget: { systemReserveTokens:
|
|
2383
|
+
lastTurnsToKeep: 30,
|
|
2384
|
+
budget: { systemReserveTokens: 2500, goalsReserveTokens: 2500, recentTurnsReserveTokens: 36e3, toolResponseReserveTokens: 18e3 }
|
|
2299
2385
|
},
|
|
2300
2386
|
memory: { scope: "workspace" },
|
|
2301
|
-
delegation: { maxDelegationDepth: 3, maxChildCalls:
|
|
2302
|
-
toolResponses: { maxToolResponseChars:
|
|
2387
|
+
delegation: { maxDelegationDepth: 3, maxChildCalls: 10, maxParallelChild: 4 },
|
|
2388
|
+
toolResponses: { maxToolResponseChars: 64e3, maxToolResponseTokens: 16e3 }
|
|
2303
2389
|
}),
|
|
2304
2390
|
research: buildProfile({
|
|
2305
|
-
limits: { maxToolCalls:
|
|
2391
|
+
limits: { maxToolCalls: 80, maxParallelTools: 10, maxContextTokens: 4e5 },
|
|
2306
2392
|
summarization: {
|
|
2307
|
-
maxTokens:
|
|
2308
|
-
summaryTriggerTokens:
|
|
2309
|
-
summaryPromptMaxTokens:
|
|
2310
|
-
summaryCompressionRatioTarget: 0.
|
|
2393
|
+
maxTokens: 4e5,
|
|
2394
|
+
summaryTriggerTokens: 3e5,
|
|
2395
|
+
summaryPromptMaxTokens: 24e3,
|
|
2396
|
+
summaryCompressionRatioTarget: 0.35
|
|
2311
2397
|
},
|
|
2312
2398
|
context: {
|
|
2313
|
-
lastTurnsToKeep:
|
|
2314
|
-
budget: { systemReserveTokens:
|
|
2399
|
+
lastTurnsToKeep: 60,
|
|
2400
|
+
budget: { systemReserveTokens: 3e3, goalsReserveTokens: 3e3, recentTurnsReserveTokens: 72e3, toolResponseReserveTokens: 32e3 }
|
|
2315
2401
|
},
|
|
2316
2402
|
memory: { scope: "workspace" },
|
|
2317
|
-
delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls:
|
|
2318
|
-
toolResponses: { maxToolResponseChars:
|
|
2403
|
+
delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 16, maxParallelChild: 6, childContextPolicy: "full" },
|
|
2404
|
+
toolResponses: { maxToolResponseChars: 96e3, maxToolResponseTokens: 24e3 }
|
|
2319
2405
|
})
|
|
2320
2406
|
};
|
|
2321
2407
|
function mergeLimits(base, override) {
|
|
@@ -2405,53 +2491,6 @@ function getResolvedSmartConfig(opts, runtime) {
|
|
|
2405
2491
|
|
|
2406
2492
|
// src/smart/toolResponses.ts
|
|
2407
2493
|
init_utilTokens();
|
|
2408
|
-
|
|
2409
|
-
// src/utils/content.ts
|
|
2410
|
-
function contentToString(content) {
|
|
2411
|
-
try {
|
|
2412
|
-
if (content == null) return "";
|
|
2413
|
-
if (typeof content === "string") return content;
|
|
2414
|
-
if (Array.isArray(content)) {
|
|
2415
|
-
return content.map((p) => {
|
|
2416
|
-
if (!p || typeof p !== "object") return String(p);
|
|
2417
|
-
if (p.type === "text") return String(p.text ?? "");
|
|
2418
|
-
if (p.type === "image_url") {
|
|
2419
|
-
const img = p.image_url;
|
|
2420
|
-
const url = typeof img === "string" ? img : img?.url;
|
|
2421
|
-
const detail = typeof img === "string" ? void 0 : img?.detail;
|
|
2422
|
-
return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
|
|
2423
|
-
}
|
|
2424
|
-
return JSON.stringify(p);
|
|
2425
|
-
}).join("\n");
|
|
2426
|
-
}
|
|
2427
|
-
return JSON.stringify(content);
|
|
2428
|
-
} catch {
|
|
2429
|
-
return String(content);
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
function mergeContentsToString(contents) {
|
|
2433
|
-
return contents.map((c) => contentToString(c)).join("\n");
|
|
2434
|
-
}
|
|
2435
|
-
function safeStringify(value, pretty = false) {
|
|
2436
|
-
if (value == null) return "";
|
|
2437
|
-
if (typeof value === "string") return value;
|
|
2438
|
-
try {
|
|
2439
|
-
return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
|
|
2440
|
-
} catch {
|
|
2441
|
-
return String(value);
|
|
2442
|
-
}
|
|
2443
|
-
}
|
|
2444
|
-
function extractMessageText2(message) {
|
|
2445
|
-
if (!message) return "";
|
|
2446
|
-
const content = message.content;
|
|
2447
|
-
if (typeof content === "string") return content;
|
|
2448
|
-
if (Array.isArray(content)) {
|
|
2449
|
-
return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
|
|
2450
|
-
}
|
|
2451
|
-
return "";
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
|
-
// src/smart/toolResponses.ts
|
|
2455
2494
|
function summarizeObject(value) {
|
|
2456
2495
|
if (value == null) return "null";
|
|
2457
2496
|
if (typeof value === "string") {
|
|
@@ -2566,6 +2605,97 @@ function normalizeToolCall(call) {
|
|
|
2566
2605
|
args: call.args ?? call.arguments ?? call.input ?? call.function?.arguments ?? call.function_call?.arguments
|
|
2567
2606
|
};
|
|
2568
2607
|
}
|
|
2608
|
+
function normalizeToolSchema(tool, toolName) {
|
|
2609
|
+
const schema = tool.schema;
|
|
2610
|
+
if (!schema) return void 0;
|
|
2611
|
+
if (typeof schema === "object" && schema._def) {
|
|
2612
|
+
try {
|
|
2613
|
+
return sanitizeTracePayload(zodToJsonSchema.zodToJsonSchema(schema, { name: toolName }));
|
|
2614
|
+
} catch {
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
if (schema && typeof schema === "object" && typeof schema.toJSON === "function") {
|
|
2618
|
+
try {
|
|
2619
|
+
return sanitizeTracePayload(schema.toJSON());
|
|
2620
|
+
} catch {
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
return sanitizeTracePayload(schema);
|
|
2624
|
+
}
|
|
2625
|
+
function buildToolDetails(tool, toolName) {
|
|
2626
|
+
if (!tool) return void 0;
|
|
2627
|
+
const details = { name: toolName };
|
|
2628
|
+
if (typeof tool.description === "string" && tool.description.trim().length > 0) {
|
|
2629
|
+
details.description = tool.description;
|
|
2630
|
+
}
|
|
2631
|
+
const inputSchema = normalizeToolSchema(tool, toolName);
|
|
2632
|
+
if (inputSchema !== void 0) details.inputSchema = inputSchema;
|
|
2633
|
+
const needsApproval = typeof tool.needsApproval === "boolean" ? tool.needsApproval : void 0;
|
|
2634
|
+
if (needsApproval !== void 0 || tool.approvalPrompt !== void 0 || tool.approvalDefaults !== void 0) {
|
|
2635
|
+
details.approval = {
|
|
2636
|
+
required: needsApproval,
|
|
2637
|
+
prompt: typeof tool.approvalPrompt === "string" ? tool.approvalPrompt : void 0,
|
|
2638
|
+
defaults: tool.approvalDefaults !== void 0 ? sanitizeTracePayload(tool.approvalDefaults) : void 0
|
|
2639
|
+
};
|
|
2640
|
+
}
|
|
2641
|
+
const cache = tool.cache;
|
|
2642
|
+
if (cache !== void 0) {
|
|
2643
|
+
details.cache = {
|
|
2644
|
+
enabled: Boolean(cache),
|
|
2645
|
+
scope: cache && typeof cache === "object" && typeof cache.scope === "string" ? cache.scope : void 0,
|
|
2646
|
+
ttlMs: cache && typeof cache === "object" && typeof cache.ttlMs === "number" ? cache.ttlMs : void 0,
|
|
2647
|
+
hasKeyFn: Boolean(cache && typeof cache === "object" && typeof cache.keyFn === "function")
|
|
2648
|
+
};
|
|
2649
|
+
}
|
|
2650
|
+
const retry = tool.retry;
|
|
2651
|
+
if (retry && typeof retry === "object") {
|
|
2652
|
+
details.retry = {
|
|
2653
|
+
maxRetries: typeof retry.maxRetries === "number" ? retry.maxRetries : void 0,
|
|
2654
|
+
backoffMs: typeof retry.backoffMs === "number" ? retry.backoffMs : void 0,
|
|
2655
|
+
circuitBreakerThreshold: typeof retry.circuitBreakerThreshold === "number" ? retry.circuitBreakerThreshold : void 0,
|
|
2656
|
+
hasShouldRetry: typeof retry.shouldRetry === "function"
|
|
2657
|
+
};
|
|
2658
|
+
}
|
|
2659
|
+
if (tool.maxExecutionsPerRun !== void 0) {
|
|
2660
|
+
details.limits = { maxExecutionsPerRun: tool.maxExecutionsPerRun };
|
|
2661
|
+
}
|
|
2662
|
+
if (typeof tool.__source === "string") {
|
|
2663
|
+
details.source = tool.__source;
|
|
2664
|
+
}
|
|
2665
|
+
return details;
|
|
2666
|
+
}
|
|
2667
|
+
function buildToolTraceSections(params) {
|
|
2668
|
+
const sanitizedArgs = sanitizeTracePayload(params.args ?? {});
|
|
2669
|
+
const sanitizedOutput = sanitizeTracePayload(params.output);
|
|
2670
|
+
const summary = params.summary ?? summarizeToolOutput(sanitizedOutput);
|
|
2671
|
+
const items = extractToolItems(sanitizedOutput);
|
|
2672
|
+
return [
|
|
2673
|
+
{
|
|
2674
|
+
kind: "tool_call",
|
|
2675
|
+
label: `Tool Call: ${params.toolName}`,
|
|
2676
|
+
tool: params.toolName,
|
|
2677
|
+
arguments: sanitizedArgs,
|
|
2678
|
+
toolDetails: params.toolDetails
|
|
2679
|
+
},
|
|
2680
|
+
{
|
|
2681
|
+
kind: "tool_result",
|
|
2682
|
+
label: `Tool Result: ${params.toolName}`,
|
|
2683
|
+
tool: params.toolName,
|
|
2684
|
+
summary,
|
|
2685
|
+
items,
|
|
2686
|
+
output: sanitizedOutput,
|
|
2687
|
+
toolDetails: params.toolDetails,
|
|
2688
|
+
execution: {
|
|
2689
|
+
id: params.executionId,
|
|
2690
|
+
status: params.status,
|
|
2691
|
+
durationMs: params.durationMs,
|
|
2692
|
+
fromCache: params.fromCache
|
|
2693
|
+
},
|
|
2694
|
+
classification: params.classification,
|
|
2695
|
+
retentionPolicy: params.retentionPolicy
|
|
2696
|
+
}
|
|
2697
|
+
];
|
|
2698
|
+
}
|
|
2569
2699
|
function createToolsNode(initialTools, opts) {
|
|
2570
2700
|
return async (state) => {
|
|
2571
2701
|
const runtime = state.agent || {
|
|
@@ -2594,13 +2724,16 @@ function createToolsNode(initialTools, opts) {
|
|
|
2594
2724
|
const traceSession = state.ctx?.__traceSession;
|
|
2595
2725
|
const pendingApprovals = Array.isArray(state.pendingApprovals) ? state.pendingApprovals.map((entry) => ({ ...entry })) : [];
|
|
2596
2726
|
const pendingByCallId = new Map(pendingApprovals.map((entry) => [entry.toolCallId, entry]));
|
|
2727
|
+
const pendingUserQuestions = Array.isArray(state.pendingUserQuestions) ? state.pendingUserQuestions.map((entry) => ({ ...entry })) : [];
|
|
2597
2728
|
let awaitingApproval = false;
|
|
2729
|
+
let awaitingUserQuestion = false;
|
|
2598
2730
|
for (const tool of toolByName.values()) {
|
|
2599
2731
|
const anyTool = tool;
|
|
2600
2732
|
if (anyTool._stateRef && typeof anyTool._stateRef === "object") {
|
|
2601
2733
|
anyTool._stateRef.toolHistory = state.toolHistory;
|
|
2602
2734
|
anyTool._stateRef.toolHistoryArchived = state.toolHistoryArchived;
|
|
2603
2735
|
anyTool._stateRef.pendingApprovals = pendingApprovals;
|
|
2736
|
+
anyTool._stateRef.pendingUserQuestions = pendingUserQuestions;
|
|
2604
2737
|
anyTool._stateRef.messages = state.messages;
|
|
2605
2738
|
anyTool._stateRef.ctx = state.ctx || (state.ctx = {});
|
|
2606
2739
|
anyTool._stateRef.__onEvent = onEvent;
|
|
@@ -2671,9 +2804,11 @@ function createToolsNode(initialTools, opts) {
|
|
|
2671
2804
|
args = validatedArgs.value;
|
|
2672
2805
|
}
|
|
2673
2806
|
const toolName = tool.name || tc.name;
|
|
2807
|
+
const toolDetails = buildToolDetails(tool, toolName);
|
|
2674
2808
|
const toolStateRef = tool._stateRef && typeof tool._stateRef === "object" ? tool._stateRef : null;
|
|
2675
2809
|
if (toolStateRef) {
|
|
2676
2810
|
toolStateRef.pendingApprovals = pendingApprovals;
|
|
2811
|
+
toolStateRef.pendingUserQuestions = pendingUserQuestions;
|
|
2677
2812
|
toolStateRef.ctx = state.ctx || (state.ctx = {});
|
|
2678
2813
|
toolStateRef.__currentToolCallId = toolCallId;
|
|
2679
2814
|
delete toolStateRef.__awaitingApproval;
|
|
@@ -2690,21 +2825,17 @@ function createToolsNode(initialTools, opts) {
|
|
|
2690
2825
|
label: `Tool Skipped - ${toolName}`,
|
|
2691
2826
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
2692
2827
|
status: "skipped",
|
|
2828
|
+
toolDetails,
|
|
2693
2829
|
toolExecutionId: tc.id,
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
function: { name: toolName, arguments: sanitizeTracePayload(args) }
|
|
2704
|
-
}
|
|
2705
|
-
]
|
|
2706
|
-
}
|
|
2707
|
-
]
|
|
2830
|
+
sections: buildToolTraceSections({
|
|
2831
|
+
args,
|
|
2832
|
+
executionId: tc.id,
|
|
2833
|
+
output: limitMessage,
|
|
2834
|
+
status: "skipped",
|
|
2835
|
+
summary: limitMessage,
|
|
2836
|
+
toolDetails,
|
|
2837
|
+
toolName
|
|
2838
|
+
})
|
|
2708
2839
|
});
|
|
2709
2840
|
toolCount += 1;
|
|
2710
2841
|
return { status: "error" };
|
|
@@ -2791,6 +2922,25 @@ function createToolsNode(initialTools, opts) {
|
|
|
2791
2922
|
push({ role: "tool", content: breakerMsg, tool_call_id: toolCallId, name: tc.name });
|
|
2792
2923
|
markToolFailure(breakerMsg, toolName, toolCallId);
|
|
2793
2924
|
onEvent?.({ type: "tool_call", phase: "error", name: toolName, id: tc.id, args, error: { message: breakerMsg } });
|
|
2925
|
+
recordTraceEvent(traceSession, {
|
|
2926
|
+
type: "tool_call",
|
|
2927
|
+
label: `Tool Error - ${toolName}`,
|
|
2928
|
+
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
2929
|
+
status: "error",
|
|
2930
|
+
requestBytes: inputBytes,
|
|
2931
|
+
toolDetails,
|
|
2932
|
+
toolExecutionId: toolCallId,
|
|
2933
|
+
error: { message: breakerMsg },
|
|
2934
|
+
sections: buildToolTraceSections({
|
|
2935
|
+
args,
|
|
2936
|
+
executionId: toolCallId,
|
|
2937
|
+
output: { message: breakerMsg },
|
|
2938
|
+
status: "error",
|
|
2939
|
+
summary: breakerMsg,
|
|
2940
|
+
toolDetails,
|
|
2941
|
+
toolName
|
|
2942
|
+
})
|
|
2943
|
+
});
|
|
2794
2944
|
toolCount += 1;
|
|
2795
2945
|
return { status: "error" };
|
|
2796
2946
|
}
|
|
@@ -2815,6 +2965,38 @@ function createToolsNode(initialTools, opts) {
|
|
|
2815
2965
|
});
|
|
2816
2966
|
push({ role: "tool", content: responsePolicy2.content, tool_call_id: tc.id || `${tc.name}_${toolCount}`, name: tc.name });
|
|
2817
2967
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: cachedHit, durationMs: 0 });
|
|
2968
|
+
const sanitizedCachedHit = sanitizeTracePayload(cachedHit);
|
|
2969
|
+
const outputBytes2 = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedCachedHit) : void 0;
|
|
2970
|
+
recordTraceEvent(traceSession, {
|
|
2971
|
+
type: "tool_call",
|
|
2972
|
+
label: `Tool Execution - ${toolName}`,
|
|
2973
|
+
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
2974
|
+
durationMs: 0,
|
|
2975
|
+
requestBytes: inputBytes,
|
|
2976
|
+
responseBytes: outputBytes2,
|
|
2977
|
+
toolDetails,
|
|
2978
|
+
toolExecutionId: executionId2,
|
|
2979
|
+
sections: buildToolTraceSections({
|
|
2980
|
+
args,
|
|
2981
|
+
classification: responsePolicy2.classification,
|
|
2982
|
+
durationMs: 0,
|
|
2983
|
+
executionId: executionId2,
|
|
2984
|
+
fromCache: true,
|
|
2985
|
+
output: sanitizedCachedHit,
|
|
2986
|
+
retentionPolicy: "keep_full",
|
|
2987
|
+
status: "cached",
|
|
2988
|
+
summary: responsePolicy2.content,
|
|
2989
|
+
toolDetails,
|
|
2990
|
+
toolName
|
|
2991
|
+
}),
|
|
2992
|
+
debug: {
|
|
2993
|
+
classification: responsePolicy2.classification,
|
|
2994
|
+
retentionPolicy: "keep_full",
|
|
2995
|
+
originalTokenCount: responsePolicy2.tokenCount,
|
|
2996
|
+
truncated: responsePolicy2.truncated,
|
|
2997
|
+
fromCache: true
|
|
2998
|
+
}
|
|
2999
|
+
});
|
|
2818
3000
|
toolCount += 1;
|
|
2819
3001
|
return { status: "success" };
|
|
2820
3002
|
}
|
|
@@ -2885,6 +3067,22 @@ function createToolsNode(initialTools, opts) {
|
|
|
2885
3067
|
approval: pendingApproval
|
|
2886
3068
|
};
|
|
2887
3069
|
}
|
|
3070
|
+
if (output && typeof output === "object" && output.__awaitingUserQuestion) {
|
|
3071
|
+
if (toolStateRef?.ctx && typeof toolStateRef.ctx === "object") {
|
|
3072
|
+
state.ctx = toolStateRef.ctx;
|
|
3073
|
+
}
|
|
3074
|
+
const pendingQuestion = pendingUserQuestions.find(
|
|
3075
|
+
(entry) => entry.toolCallId === output.toolCallId || entry.id === output.id
|
|
3076
|
+
);
|
|
3077
|
+
if (!pendingQuestion) {
|
|
3078
|
+
throw new Error(`Tool ${toolName} requested a user question but no pending question entry was recorded.`);
|
|
3079
|
+
}
|
|
3080
|
+
awaitingUserQuestion = true;
|
|
3081
|
+
return {
|
|
3082
|
+
status: "awaiting_user_question",
|
|
3083
|
+
userQuestion: pendingQuestion
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
2888
3086
|
if (output && typeof output === "object" && output.__finalStructuredOutput) {
|
|
2889
3087
|
if (!state.ctx) state.ctx = {};
|
|
2890
3088
|
state.ctx.__structuredOutputParsed = output.data;
|
|
@@ -2919,28 +3117,6 @@ function createToolsNode(initialTools, opts) {
|
|
|
2919
3117
|
}
|
|
2920
3118
|
const sanitizedOutput = sanitizeTracePayload(output);
|
|
2921
3119
|
const outputBytes = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedOutput) : void 0;
|
|
2922
|
-
const messageList = [
|
|
2923
|
-
{
|
|
2924
|
-
role: "assistant",
|
|
2925
|
-
name: toolName,
|
|
2926
|
-
content: "",
|
|
2927
|
-
tool_calls: [
|
|
2928
|
-
{
|
|
2929
|
-
id: tc.id || executionId,
|
|
2930
|
-
type: "function",
|
|
2931
|
-
function: {
|
|
2932
|
-
name: toolName,
|
|
2933
|
-
arguments: sanitizedArgs
|
|
2934
|
-
}
|
|
2935
|
-
}
|
|
2936
|
-
]
|
|
2937
|
-
},
|
|
2938
|
-
{
|
|
2939
|
-
role: "tool",
|
|
2940
|
-
name: toolName,
|
|
2941
|
-
content: responsePolicy.content
|
|
2942
|
-
}
|
|
2943
|
-
];
|
|
2944
3120
|
recordTraceEvent(traceSession, {
|
|
2945
3121
|
type: "tool_call",
|
|
2946
3122
|
label: `Tool Execution - ${toolName}`,
|
|
@@ -2948,8 +3124,20 @@ function createToolsNode(initialTools, opts) {
|
|
|
2948
3124
|
durationMs,
|
|
2949
3125
|
requestBytes: inputBytes,
|
|
2950
3126
|
responseBytes: outputBytes,
|
|
3127
|
+
toolDetails,
|
|
2951
3128
|
toolExecutionId: executionId,
|
|
2952
|
-
|
|
3129
|
+
sections: buildToolTraceSections({
|
|
3130
|
+
args: sanitizedArgs,
|
|
3131
|
+
classification: responsePolicy.classification,
|
|
3132
|
+
durationMs,
|
|
3133
|
+
executionId,
|
|
3134
|
+
output: sanitizedOutput,
|
|
3135
|
+
retentionPolicy: "keep_full",
|
|
3136
|
+
status: "success",
|
|
3137
|
+
summary: responsePolicy.content,
|
|
3138
|
+
toolDetails,
|
|
3139
|
+
toolName
|
|
3140
|
+
}),
|
|
2953
3141
|
debug: {
|
|
2954
3142
|
classification: responsePolicy.classification,
|
|
2955
3143
|
retentionPolicy: "keep_full",
|
|
@@ -2968,6 +3156,7 @@ function createToolsNode(initialTools, opts) {
|
|
|
2968
3156
|
markToolFailure(message, toolName, toolCallId);
|
|
2969
3157
|
onEvent?.({ type: "tool_call", phase: "error", name: toolName, id: tc.id, args, error: { message } });
|
|
2970
3158
|
onProgress?.({ stage: "tools", message: `Tool ${tc.name} failed`, detail: { error: message } });
|
|
3159
|
+
const errorOutput = { message, stack: error?.stack };
|
|
2971
3160
|
recordTraceEvent(traceSession, {
|
|
2972
3161
|
type: "tool_call",
|
|
2973
3162
|
label: `Tool Error - ${toolName}`,
|
|
@@ -2975,27 +3164,20 @@ function createToolsNode(initialTools, opts) {
|
|
|
2975
3164
|
status: "error",
|
|
2976
3165
|
durationMs,
|
|
2977
3166
|
requestBytes: inputBytes,
|
|
3167
|
+
responseBytes: traceSession?.resolvedConfig.logData ? estimatePayloadBytes(errorOutput) : void 0,
|
|
3168
|
+
toolDetails,
|
|
2978
3169
|
toolExecutionId: executionId,
|
|
2979
3170
|
error: { message, stack: error?.stack },
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
}
|
|
2991
|
-
]
|
|
2992
|
-
},
|
|
2993
|
-
{
|
|
2994
|
-
role: "tool",
|
|
2995
|
-
name: toolName,
|
|
2996
|
-
content: `Error executing tool: ${message}`
|
|
2997
|
-
}
|
|
2998
|
-
]
|
|
3171
|
+
sections: buildToolTraceSections({
|
|
3172
|
+
args: sanitizedArgs,
|
|
3173
|
+
durationMs,
|
|
3174
|
+
executionId,
|
|
3175
|
+
output: errorOutput,
|
|
3176
|
+
status: "error",
|
|
3177
|
+
summary: `Error executing tool: ${message}`,
|
|
3178
|
+
toolDetails,
|
|
3179
|
+
toolName
|
|
3180
|
+
})
|
|
2999
3181
|
});
|
|
3000
3182
|
toolCount += 1;
|
|
3001
3183
|
return { status: "error", approval: approvalEntry };
|
|
@@ -3022,15 +3204,19 @@ function createToolsNode(initialTools, opts) {
|
|
|
3022
3204
|
return false;
|
|
3023
3205
|
};
|
|
3024
3206
|
for (const idx of approvalIndices) {
|
|
3025
|
-
if (awaitingApproval || shouldStop) break;
|
|
3207
|
+
if (awaitingApproval || awaitingUserQuestion || shouldStop) break;
|
|
3026
3208
|
if (checkCancellationStop()) break;
|
|
3027
3209
|
const result = await runOne(planned[idx], orderedSlots[idx]);
|
|
3028
3210
|
if (result.status === "awaiting_approval") {
|
|
3029
3211
|
awaitingApproval = true;
|
|
3030
3212
|
break;
|
|
3031
3213
|
}
|
|
3214
|
+
if (result.status === "awaiting_user_question") {
|
|
3215
|
+
awaitingUserQuestion = true;
|
|
3216
|
+
break;
|
|
3217
|
+
}
|
|
3032
3218
|
}
|
|
3033
|
-
if (!awaitingApproval && !shouldStop && parallelIndices.length > 0) {
|
|
3219
|
+
if (!awaitingApproval && !awaitingUserQuestion && !shouldStop && parallelIndices.length > 0) {
|
|
3034
3220
|
const concurrency = Math.max(1, Math.min(limits.maxParallelTools, parallelIndices.length));
|
|
3035
3221
|
let cursor = 0;
|
|
3036
3222
|
const workerError = {};
|
|
@@ -3038,7 +3224,7 @@ function createToolsNode(initialTools, opts) {
|
|
|
3038
3224
|
for (let w = 0; w < concurrency; w++) {
|
|
3039
3225
|
workers.push((async () => {
|
|
3040
3226
|
while (true) {
|
|
3041
|
-
if (workerError.err || shouldStop || awaitingApproval) return;
|
|
3227
|
+
if (workerError.err || shouldStop || awaitingApproval || awaitingUserQuestion) return;
|
|
3042
3228
|
const i = cursor++;
|
|
3043
3229
|
if (i >= parallelIndices.length) return;
|
|
3044
3230
|
if (checkCancellationStop()) return;
|
|
@@ -3049,6 +3235,10 @@ function createToolsNode(initialTools, opts) {
|
|
|
3049
3235
|
awaitingApproval = true;
|
|
3050
3236
|
return;
|
|
3051
3237
|
}
|
|
3238
|
+
if (result.status === "awaiting_user_question") {
|
|
3239
|
+
awaitingUserQuestion = true;
|
|
3240
|
+
return;
|
|
3241
|
+
}
|
|
3052
3242
|
} catch (err) {
|
|
3053
3243
|
workerError.err = err;
|
|
3054
3244
|
return;
|
|
@@ -3064,29 +3254,26 @@ function createToolsNode(initialTools, opts) {
|
|
|
3064
3254
|
}
|
|
3065
3255
|
for (const tc of skipped) {
|
|
3066
3256
|
onEvent?.({ type: "tool_call", phase: "skipped", name: tc.name, id: tc.id, args: tc.args });
|
|
3067
|
-
const
|
|
3257
|
+
const toolDetails = buildToolDetails(toolByName.get(tc.name), tc.name);
|
|
3258
|
+
const skipMessage = `Skipped tool due to tool-call limit: ${tc.name}`;
|
|
3068
3259
|
recordTraceEvent(traceSession, {
|
|
3069
3260
|
type: "tool_call",
|
|
3070
3261
|
label: `Tool Skipped - ${tc.name}`,
|
|
3071
3262
|
actor: { scope: "tool", name: tc.name, role: "tool" },
|
|
3072
3263
|
status: "skipped",
|
|
3264
|
+
toolDetails,
|
|
3073
3265
|
toolExecutionId: tc.id,
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
function: { name: tc.name, arguments: sanitizedArgs }
|
|
3084
|
-
}
|
|
3085
|
-
]
|
|
3086
|
-
}
|
|
3087
|
-
]
|
|
3266
|
+
sections: buildToolTraceSections({
|
|
3267
|
+
args: tc.args,
|
|
3268
|
+
executionId: tc.id,
|
|
3269
|
+
output: skipMessage,
|
|
3270
|
+
status: "skipped",
|
|
3271
|
+
summary: skipMessage,
|
|
3272
|
+
toolDetails,
|
|
3273
|
+
toolName: tc.name
|
|
3274
|
+
})
|
|
3088
3275
|
});
|
|
3089
|
-
appended.push({ role: "tool", content:
|
|
3276
|
+
appended.push({ role: "tool", content: skipMessage, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
|
|
3090
3277
|
toolCount += 1;
|
|
3091
3278
|
}
|
|
3092
3279
|
if (!awaitingApproval && state.ctx?.__awaitingApproval) {
|
|
@@ -3111,11 +3298,12 @@ function createToolsNode(initialTools, opts) {
|
|
|
3111
3298
|
toolCache: state.toolCache,
|
|
3112
3299
|
// Explicitly propagate ctx so callers using `{ ...state, ...delta }`
|
|
3113
3300
|
// do not silently capture a stale ctx reference. Mutations to
|
|
3114
|
-
// __summarizationExhausted / __awaitingApproval /
|
|
3115
|
-
// are made on this object during execution.
|
|
3301
|
+
// __summarizationExhausted / __awaitingApproval / __awaitingUserQuestion /
|
|
3302
|
+
// __structuredOutputParsed are made on this object during execution.
|
|
3116
3303
|
ctx: state.ctx,
|
|
3117
3304
|
agent: state.agent,
|
|
3118
|
-
pendingApprovals
|
|
3305
|
+
pendingApprovals,
|
|
3306
|
+
pendingUserQuestions
|
|
3119
3307
|
};
|
|
3120
3308
|
};
|
|
3121
3309
|
}
|
|
@@ -3581,6 +3769,226 @@ function resolveToolApprovalState(state, resolution) {
|
|
|
3581
3769
|
};
|
|
3582
3770
|
}
|
|
3583
3771
|
|
|
3772
|
+
// src/utils/userQuestions.ts
|
|
3773
|
+
var cloneQuestions = (questions) => Array.isArray(questions) ? questions.map((entry) => ({ ...entry })) : [];
|
|
3774
|
+
function validateAnswers(entry, answers, cancelled) {
|
|
3775
|
+
if (cancelled) {
|
|
3776
|
+
return answers || {};
|
|
3777
|
+
}
|
|
3778
|
+
const allowFreeText = entry.allowFreeText !== false;
|
|
3779
|
+
const out = {};
|
|
3780
|
+
const provided = answers || {};
|
|
3781
|
+
for (const question of entry.questions) {
|
|
3782
|
+
const required = question.required !== false;
|
|
3783
|
+
const key = question.question;
|
|
3784
|
+
const answer = provided[key] ?? provided[question.header || ""];
|
|
3785
|
+
if (!answer) {
|
|
3786
|
+
if (required) {
|
|
3787
|
+
throw new Error(`Missing answer for required question: "${key}".`);
|
|
3788
|
+
}
|
|
3789
|
+
continue;
|
|
3790
|
+
}
|
|
3791
|
+
const values = Array.isArray(answer.values) ? answer.values.filter((v) => typeof v === "string") : [];
|
|
3792
|
+
const freeText = typeof answer.freeText === "string" ? answer.freeText.trim() : "";
|
|
3793
|
+
const notes = typeof answer.notes === "string" ? answer.notes : void 0;
|
|
3794
|
+
if (freeText && !allowFreeText) {
|
|
3795
|
+
throw new Error(
|
|
3796
|
+
`Free-text answers are disabled for this agent (question: "${key}"). Pick one of the provided options.`
|
|
3797
|
+
);
|
|
3798
|
+
}
|
|
3799
|
+
if (values.length === 0 && !freeText) {
|
|
3800
|
+
if (required) {
|
|
3801
|
+
throw new Error(`Question "${key}" requires either a selected option or free-text answer.`);
|
|
3802
|
+
}
|
|
3803
|
+
continue;
|
|
3804
|
+
}
|
|
3805
|
+
if (values.length > 1 && !question.multiSelect) {
|
|
3806
|
+
throw new Error(`Question "${key}" is single-select but received multiple values.`);
|
|
3807
|
+
}
|
|
3808
|
+
if (Array.isArray(question.options) && question.options.length > 0 && values.length > 0) {
|
|
3809
|
+
const allowedValues = new Set(
|
|
3810
|
+
question.options.map((option) => option.value ?? option.label)
|
|
3811
|
+
);
|
|
3812
|
+
for (const value of values) {
|
|
3813
|
+
if (!allowedValues.has(value)) {
|
|
3814
|
+
if (!allowFreeText) {
|
|
3815
|
+
throw new Error(
|
|
3816
|
+
`Value "${value}" is not one of the allowed options for question "${key}".`
|
|
3817
|
+
);
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
out[key] = { values, ...freeText ? { freeText } : {}, ...notes ? { notes } : {} };
|
|
3823
|
+
}
|
|
3824
|
+
return out;
|
|
3825
|
+
}
|
|
3826
|
+
function buildToolResponseContent(entry, answers, cancelled, notes) {
|
|
3827
|
+
if (cancelled) {
|
|
3828
|
+
return JSON.stringify({
|
|
3829
|
+
status: "cancelled",
|
|
3830
|
+
message: notes || "User dismissed the question without answering."
|
|
3831
|
+
});
|
|
3832
|
+
}
|
|
3833
|
+
const payload = {
|
|
3834
|
+
status: "answered",
|
|
3835
|
+
answers: entry.questions.map((question) => {
|
|
3836
|
+
const key = question.question;
|
|
3837
|
+
const ans = answers[key];
|
|
3838
|
+
return {
|
|
3839
|
+
question: key,
|
|
3840
|
+
header: question.header,
|
|
3841
|
+
values: ans?.values ?? [],
|
|
3842
|
+
freeText: ans?.freeText,
|
|
3843
|
+
notes: ans?.notes
|
|
3844
|
+
};
|
|
3845
|
+
}),
|
|
3846
|
+
...notes ? { reviewerNotes: notes } : {}
|
|
3847
|
+
};
|
|
3848
|
+
return JSON.stringify(payload);
|
|
3849
|
+
}
|
|
3850
|
+
function resolveUserQuestionState(state, resolution) {
|
|
3851
|
+
const pending = cloneQuestions(state.pendingUserQuestions);
|
|
3852
|
+
const matchIndex = pending.findIndex(
|
|
3853
|
+
(entry2) => entry2.id === resolution.id || entry2.toolCallId === resolution.id
|
|
3854
|
+
);
|
|
3855
|
+
if (matchIndex === -1) {
|
|
3856
|
+
throw new Error(`Pending user question not found for id: ${resolution.id}`);
|
|
3857
|
+
}
|
|
3858
|
+
const entry = { ...pending[matchIndex] };
|
|
3859
|
+
if (entry.status === "answered" || entry.status === "executed" || entry.status === "cancelled") {
|
|
3860
|
+
throw new Error(`User question ${entry.id} already resolved (status: ${entry.status}).`);
|
|
3861
|
+
}
|
|
3862
|
+
const cancelled = resolution.cancelled === true;
|
|
3863
|
+
const validated = validateAnswers(entry, resolution.answers, cancelled);
|
|
3864
|
+
entry.status = cancelled ? "cancelled" : "answered";
|
|
3865
|
+
entry.answers = validated;
|
|
3866
|
+
entry.cancelled = cancelled || void 0;
|
|
3867
|
+
entry.answeredBy = resolution.answeredBy;
|
|
3868
|
+
entry.notes = resolution.notes;
|
|
3869
|
+
entry.answeredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3870
|
+
pending[matchIndex] = entry;
|
|
3871
|
+
const ctx = { ...state.ctx || {} };
|
|
3872
|
+
delete ctx.__awaitingUserQuestion;
|
|
3873
|
+
if (ctx.__resumeStage === "tools") {
|
|
3874
|
+
delete ctx.__resumeStage;
|
|
3875
|
+
}
|
|
3876
|
+
ctx.__userQuestionResolved = { id: entry.id, status: entry.status };
|
|
3877
|
+
const toolMessage = {
|
|
3878
|
+
role: "tool",
|
|
3879
|
+
name: "ask_user_question",
|
|
3880
|
+
tool_call_id: entry.toolCallId,
|
|
3881
|
+
content: buildToolResponseContent(entry, validated, cancelled, resolution.notes)
|
|
3882
|
+
};
|
|
3883
|
+
return {
|
|
3884
|
+
...state,
|
|
3885
|
+
pendingUserQuestions: pending,
|
|
3886
|
+
messages: [...state.messages || [], toolMessage],
|
|
3887
|
+
ctx
|
|
3888
|
+
};
|
|
3889
|
+
}
|
|
3890
|
+
var DEFAULT_DESCRIPTION_WITH_FREETEXT = "Pause the agent and surface a structured prompt to the human user when you genuinely cannot proceed without their input. Group up to 4 closely related questions into a single call. Prefer concrete options the user can pick over open-ended free-text \u2014 list `options` whenever you can anticipate the choices. The user may type a custom answer for any question. Do not use this tool for things you can deduce from the conversation, the system prompt, or another tool. After the user answers, their selections come back as the tool result.";
|
|
3891
|
+
var DEFAULT_DESCRIPTION_NO_FREETEXT = "Pause the agent and surface a structured multi-choice prompt to the human user when you genuinely cannot proceed without their input. Group up to 4 closely related questions into a single call. Every question MUST include at least two `options` \u2014 free-text answers are disabled for this agent. Do not use this tool for things you can deduce from the conversation, the system prompt, or another tool. After the user picks, their selections come back as the tool result.";
|
|
3892
|
+
function buildOptionSchema() {
|
|
3893
|
+
return zod.z.object({
|
|
3894
|
+
label: zod.z.string().min(1).describe("Display text the user sees"),
|
|
3895
|
+
value: zod.z.string().min(1).optional().describe("Value returned in the answer; defaults to label"),
|
|
3896
|
+
description: zod.z.string().optional(),
|
|
3897
|
+
preview: zod.z.string().optional().describe("Optional code / ASCII preview rendered when this option is focused")
|
|
3898
|
+
}).strict();
|
|
3899
|
+
}
|
|
3900
|
+
function buildQuestionSchema(allowFreeText) {
|
|
3901
|
+
const optionSchema = buildOptionSchema();
|
|
3902
|
+
const baseShape = {
|
|
3903
|
+
question: zod.z.string().min(1).describe("Full question shown to the user"),
|
|
3904
|
+
header: zod.z.string().max(40).optional().describe("Short chip / tag rendered next to the question (max ~12 chars recommended)"),
|
|
3905
|
+
multiSelect: zod.z.boolean().optional().describe("Allow multiple selections. Default: false"),
|
|
3906
|
+
placeholder: zod.z.string().optional(),
|
|
3907
|
+
required: zod.z.boolean().optional().describe("Default: true")
|
|
3908
|
+
};
|
|
3909
|
+
if (allowFreeText) {
|
|
3910
|
+
return zod.z.object({
|
|
3911
|
+
...baseShape,
|
|
3912
|
+
options: zod.z.array(optionSchema).min(2).max(12).optional()
|
|
3913
|
+
}).strict();
|
|
3914
|
+
}
|
|
3915
|
+
return zod.z.object({
|
|
3916
|
+
...baseShape,
|
|
3917
|
+
options: zod.z.array(optionSchema).min(2).max(12).describe("Required: free-text answers are disabled for this agent")
|
|
3918
|
+
}).strict();
|
|
3919
|
+
}
|
|
3920
|
+
function createAskUserQuestionTool(stateRef, config) {
|
|
3921
|
+
const allowFreeText = config.allowFreeText !== false;
|
|
3922
|
+
const description = config.promptOverride ?? (allowFreeText ? DEFAULT_DESCRIPTION_WITH_FREETEXT : DEFAULT_DESCRIPTION_NO_FREETEXT);
|
|
3923
|
+
const questionSchema = buildQuestionSchema(allowFreeText);
|
|
3924
|
+
const askUser = createTool({
|
|
3925
|
+
name: "ask_user_question",
|
|
3926
|
+
description,
|
|
3927
|
+
schema: zod.z.object({
|
|
3928
|
+
questions: zod.z.array(questionSchema).min(1).max(4).describe("1-4 related questions to ask in a single pause.")
|
|
3929
|
+
}).strict(),
|
|
3930
|
+
func: async ({ questions }) => {
|
|
3931
|
+
const ref = askUser._stateRef || (askUser._stateRef = {});
|
|
3932
|
+
const onEvent = ref.__onEvent;
|
|
3933
|
+
if (!ref.ctx) ref.ctx = {};
|
|
3934
|
+
const ctx = ref.ctx;
|
|
3935
|
+
const toolCallId = ref.__currentToolCallId || `ask_user_${nanoid.nanoid(6)}`;
|
|
3936
|
+
if (!ref.pendingUserQuestions) ref.pendingUserQuestions = [];
|
|
3937
|
+
const pendingList = ref.pendingUserQuestions;
|
|
3938
|
+
const entry = {
|
|
3939
|
+
id: nanoid.nanoid(),
|
|
3940
|
+
toolCallId,
|
|
3941
|
+
toolName: "ask_user_question",
|
|
3942
|
+
questions,
|
|
3943
|
+
status: "pending",
|
|
3944
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3945
|
+
allowFreeText
|
|
3946
|
+
};
|
|
3947
|
+
pendingList.push(entry);
|
|
3948
|
+
ctx.__awaitingUserQuestion = {
|
|
3949
|
+
id: entry.id,
|
|
3950
|
+
toolCallId: entry.toolCallId,
|
|
3951
|
+
requestedAt: entry.requestedAt
|
|
3952
|
+
};
|
|
3953
|
+
ctx.__resumeStage = "tools";
|
|
3954
|
+
onEvent?.({
|
|
3955
|
+
type: "user_question",
|
|
3956
|
+
status: "pending",
|
|
3957
|
+
id: entry.id,
|
|
3958
|
+
toolCallId: entry.toolCallId,
|
|
3959
|
+
questions: entry.questions,
|
|
3960
|
+
allowFreeText
|
|
3961
|
+
});
|
|
3962
|
+
recordTraceEvent(ctx.__traceSession, {
|
|
3963
|
+
type: "user_question",
|
|
3964
|
+
label: "Ask User",
|
|
3965
|
+
actor: { scope: "agent", name: "ask_user_question", role: "user_interaction" },
|
|
3966
|
+
status: "success",
|
|
3967
|
+
sections: [
|
|
3968
|
+
{
|
|
3969
|
+
kind: "metadata",
|
|
3970
|
+
label: "Pending Question",
|
|
3971
|
+
data: {
|
|
3972
|
+
id: entry.id,
|
|
3973
|
+
toolCallId: entry.toolCallId,
|
|
3974
|
+
questions: entry.questions,
|
|
3975
|
+
allowFreeText
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
]
|
|
3979
|
+
});
|
|
3980
|
+
return {
|
|
3981
|
+
__awaitingUserQuestion: true,
|
|
3982
|
+
id: entry.id,
|
|
3983
|
+
toolCallId: entry.toolCallId
|
|
3984
|
+
};
|
|
3985
|
+
}
|
|
3986
|
+
});
|
|
3987
|
+
askUser._stateRef = stateRef;
|
|
3988
|
+
askUser.__source = "human-in-the-loop";
|
|
3989
|
+
return askUser;
|
|
3990
|
+
}
|
|
3991
|
+
|
|
3584
3992
|
// src/agent.ts
|
|
3585
3993
|
init_utilTokens();
|
|
3586
3994
|
|
|
@@ -3792,6 +4200,21 @@ function createAgent(opts) {
|
|
|
3792
4200
|
const resolver = createResolverNode();
|
|
3793
4201
|
const agentCore = createAgentCoreNode(opts);
|
|
3794
4202
|
const toolsBase = [...opts.tools ?? []];
|
|
4203
|
+
const askUserConfig = (() => {
|
|
4204
|
+
const raw = opts.humanInTheLoop?.askUser;
|
|
4205
|
+
if (!raw) return void 0;
|
|
4206
|
+
if (raw === true) return { enabled: true, allowFreeText: true };
|
|
4207
|
+
return {
|
|
4208
|
+
enabled: true,
|
|
4209
|
+
allowFreeText: raw.allowFreeText !== false,
|
|
4210
|
+
promptOverride: raw.promptOverride
|
|
4211
|
+
};
|
|
4212
|
+
})();
|
|
4213
|
+
const askUserOnQuestion = typeof opts.humanInTheLoop?.askUser === "object" ? opts.humanInTheLoop?.askUser?.onQuestion : void 0;
|
|
4214
|
+
const askUserStateRef = askUserConfig ? { pendingUserQuestions: void 0, ctx: void 0, __onEvent: void 0, __currentToolCallId: void 0 } : void 0;
|
|
4215
|
+
if (askUserConfig && askUserStateRef) {
|
|
4216
|
+
toolsBase.push(createAskUserQuestionTool(askUserStateRef, askUserConfig));
|
|
4217
|
+
}
|
|
3795
4218
|
const soManager = opts.outputSchema ? new StructuredOutputManager(opts.outputSchema, resolveStrategy(opts.model)) : void 0;
|
|
3796
4219
|
if (soManager) {
|
|
3797
4220
|
const modelCapabilities = getModelCapabilities(opts.model);
|
|
@@ -3836,7 +4259,8 @@ function createAgent(opts) {
|
|
|
3836
4259
|
useTodoList: void 0,
|
|
3837
4260
|
outputSchema: opts.outputSchema,
|
|
3838
4261
|
responseFormat: soManager?.getResponseFormat(),
|
|
3839
|
-
tracing: opts.tracing
|
|
4262
|
+
tracing: opts.tracing,
|
|
4263
|
+
humanInTheLoop: askUserConfig ? { askUser: askUserConfig } : void 0
|
|
3840
4264
|
};
|
|
3841
4265
|
const summarizationThreshold = getActiveSummarizationThreshold(opts);
|
|
3842
4266
|
async function runLoop(initial, config, emit) {
|
|
@@ -4100,7 +4524,7 @@ function createAgent(opts) {
|
|
|
4100
4524
|
if (toolCalls.length === 0) {
|
|
4101
4525
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize) {
|
|
4102
4526
|
if (soManager.strategy.kind === "native") {
|
|
4103
|
-
const assistantText =
|
|
4527
|
+
const assistantText = extractMessageText(lastMsg);
|
|
4104
4528
|
if (assistantText) {
|
|
4105
4529
|
const parsed = soManager.parseFromContent(assistantText);
|
|
4106
4530
|
if (parsed.success) {
|
|
@@ -4126,6 +4550,7 @@ function createAgent(opts) {
|
|
|
4126
4550
|
state = { ...state, ...await toolsNode(state) };
|
|
4127
4551
|
onProgress?.({ stage: "tools", message: "Tools finished" });
|
|
4128
4552
|
if (state.ctx?.__awaitingApproval) break;
|
|
4553
|
+
if (state.ctx?.__awaitingUserQuestion) break;
|
|
4129
4554
|
if (checkpointIfRequested("after_tools")) break;
|
|
4130
4555
|
if (state.ctx?.__finalizedDueToStructuredOutput) break;
|
|
4131
4556
|
if (reflectNode && resolvedReasoning?.reflection.enabled) {
|
|
@@ -4150,7 +4575,7 @@ function createAgent(opts) {
|
|
|
4150
4575
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput) {
|
|
4151
4576
|
const lastForParse = state.messages[state.messages.length - 1];
|
|
4152
4577
|
if (lastForParse?.role === "assistant") {
|
|
4153
|
-
const assistantText =
|
|
4578
|
+
const assistantText = extractMessageText(lastForParse);
|
|
4154
4579
|
if (assistantText) {
|
|
4155
4580
|
const parsed = soManager.parseFromContent(assistantText);
|
|
4156
4581
|
if (parsed.success) {
|
|
@@ -4196,7 +4621,7 @@ function createAgent(opts) {
|
|
|
4196
4621
|
}
|
|
4197
4622
|
const lastAfterLoop = state.messages[state.messages.length - 1];
|
|
4198
4623
|
if (lastAfterLoop?.role === "tool" && !pausedStage) {
|
|
4199
|
-
const isExpectedExit = state.ctx?.__awaitingApproval || state.ctx?.__cancelled || state.ctx?.__finalizedDueToStructuredOutput || state.ctx?.__finalizedDueToToolLimit || state.ctx?.__needsSummarization || state.ctx?.__limitBreached;
|
|
4624
|
+
const isExpectedExit = state.ctx?.__awaitingApproval || state.ctx?.__awaitingUserQuestion || state.ctx?.__cancelled || state.ctx?.__finalizedDueToStructuredOutput || state.ctx?.__finalizedDueToToolLimit || state.ctx?.__needsSummarization || state.ctx?.__limitBreached;
|
|
4200
4625
|
if (!isExpectedExit) {
|
|
4201
4626
|
throw new Error(
|
|
4202
4627
|
"Agent loop terminated with a pending tool response but no subsequent model invocation. This usually indicates a model provider error or exhausted iteration budget."
|
|
@@ -4214,7 +4639,17 @@ function createAgent(opts) {
|
|
|
4214
4639
|
const { setTokenCounter: setTokenCounter2 } = await Promise.resolve().then(() => (init_utilTokens(), utilTokens_exports));
|
|
4215
4640
|
setTokenCounter2(userTokenCounter);
|
|
4216
4641
|
}
|
|
4217
|
-
const
|
|
4642
|
+
const callerOnEvent = config?.onEvent;
|
|
4643
|
+
const onEvent = askUserOnQuestion ? (event) => {
|
|
4644
|
+
if (event && event.type === "user_question") {
|
|
4645
|
+
try {
|
|
4646
|
+
askUserOnQuestion(event);
|
|
4647
|
+
} catch (err) {
|
|
4648
|
+
console.warn("[agent-sdk] humanInTheLoop.askUser.onQuestion error:", err);
|
|
4649
|
+
}
|
|
4650
|
+
}
|
|
4651
|
+
callerOnEvent?.(event);
|
|
4652
|
+
} : callerOnEvent;
|
|
4218
4653
|
const onProgress = config?.onProgress;
|
|
4219
4654
|
const onStream = config?.onStream;
|
|
4220
4655
|
const streamEnabled = config?.stream === true;
|
|
@@ -4258,6 +4693,7 @@ function createAgent(opts) {
|
|
|
4258
4693
|
metadata: input.metadata,
|
|
4259
4694
|
ctx,
|
|
4260
4695
|
pendingApprovals: input.pendingApprovals || [],
|
|
4696
|
+
pendingUserQuestions: input.pendingUserQuestions || [],
|
|
4261
4697
|
agent: input.agent || runtimeWithInvokeLimits,
|
|
4262
4698
|
usage: input.usage || { perRequest: [], totals: {} }
|
|
4263
4699
|
};
|
|
@@ -4292,7 +4728,7 @@ function createAgent(opts) {
|
|
|
4292
4728
|
const isTransientSummarizationExit = !!res.ctx?.__needsSummarization;
|
|
4293
4729
|
const finalAssistantMsg = isTransientSummarizationExit ? void 0 : getLastAssistantMessage(res.messages);
|
|
4294
4730
|
const finalIsSyntheticSummary = !isTransientSummarizationExit && finalAssistantMsg && isSyntheticSummaryMessage(finalAssistantMsg);
|
|
4295
|
-
const content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" :
|
|
4731
|
+
const content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText(finalAssistantMsg);
|
|
4296
4732
|
let parsed = void 0;
|
|
4297
4733
|
let outputError = void 0;
|
|
4298
4734
|
if (soManager) {
|
|
@@ -4334,11 +4770,13 @@ function createAgent(opts) {
|
|
|
4334
4770
|
return invokeAgent(restoredState, config);
|
|
4335
4771
|
};
|
|
4336
4772
|
const resolveToolApproval = (state, resolution) => resolveToolApprovalState(state, resolution);
|
|
4773
|
+
const resolveUserQuestion = (state, resolution) => resolveUserQuestionState(state, resolution);
|
|
4337
4774
|
const instance = {
|
|
4338
4775
|
invoke: invokeAgent,
|
|
4339
4776
|
snapshot: snapshotState,
|
|
4340
4777
|
resume: resumeAgent,
|
|
4341
4778
|
resolveToolApproval,
|
|
4779
|
+
resolveUserQuestion,
|
|
4342
4780
|
asTool: ({ toolName, description, inputDescription }) => {
|
|
4343
4781
|
const schema = zod.z.object({ input: zod.z.string().describe(inputDescription || "Input for delegated agent") });
|
|
4344
4782
|
const delegatedTool = createTool({
|
|
@@ -4598,7 +5036,7 @@ function renderMemoryBlock(facts) {
|
|
|
4598
5036
|
function clampToBudget(messages, maxContextTokens) {
|
|
4599
5037
|
let working = [...messages];
|
|
4600
5038
|
while (working.length > 2) {
|
|
4601
|
-
const tokenCount = countApproxTokens(working.map(
|
|
5039
|
+
const tokenCount = countApproxTokens(working.map(extractMessageText).join("\n"));
|
|
4602
5040
|
if (tokenCount <= maxContextTokens) return working;
|
|
4603
5041
|
const firstNonSystem = working.findIndex((message, index) => !(index === 0 && message.role === "system"));
|
|
4604
5042
|
if (firstNonSystem < 0) break;
|
|
@@ -5655,7 +6093,20 @@ function createSmartAgent(opts) {
|
|
|
5655
6093
|
const userTools = opts.tools ?? [];
|
|
5656
6094
|
const factoryStateRef = { toolHistory: void 0, toolHistoryArchived: void 0, todoList: void 0, planVersion: 0, adherenceScore: 0 };
|
|
5657
6095
|
const factoryContextTools = createContextTools(factoryStateRef, { planningEnabled, includeGetToolResponse: false });
|
|
6096
|
+
const askUserConfig = (() => {
|
|
6097
|
+
const raw = opts.humanInTheLoop?.askUser;
|
|
6098
|
+
if (!raw) return void 0;
|
|
6099
|
+
if (raw === true) return { enabled: true, allowFreeText: true };
|
|
6100
|
+
return {
|
|
6101
|
+
enabled: true,
|
|
6102
|
+
allowFreeText: raw.allowFreeText !== false,
|
|
6103
|
+
promptOverride: raw.promptOverride
|
|
6104
|
+
};
|
|
6105
|
+
})();
|
|
5658
6106
|
const factoryToolsWithoutRecovery = [...userTools, ...factoryContextTools];
|
|
6107
|
+
if (askUserConfig) {
|
|
6108
|
+
factoryToolsWithoutRecovery.push(createAskUserQuestionTool(factoryStateRef, askUserConfig));
|
|
6109
|
+
}
|
|
5659
6110
|
const soManagerFactory = opts.outputSchema ? new StructuredOutputManager(opts.outputSchema, resolveStrategy(opts.model)) : void 0;
|
|
5660
6111
|
const modelCapabilities = opts.outputSchema ? getModelCapabilities(opts.model) : void 0;
|
|
5661
6112
|
const responseFinalizeTool = soManagerFactory && modelCapabilities?.structuredOutput !== "native" ? soManagerFactory.getResponseTool() : void 0;
|
|
@@ -5665,6 +6116,7 @@ function createSmartAgent(opts) {
|
|
|
5665
6116
|
const recoveryTool = createGetToolResponseTool(ref);
|
|
5666
6117
|
const base2 = [...userTools, ...ctxTools];
|
|
5667
6118
|
if (responseFinalizeTool) base2.push(responseFinalizeTool);
|
|
6119
|
+
if (askUserConfig) base2.push(createAskUserQuestionTool(ref, askUserConfig));
|
|
5668
6120
|
const without = base2;
|
|
5669
6121
|
const withRec = [...without, recoveryTool];
|
|
5670
6122
|
return { stateRef: ref, toolsWithoutRecovery: without, toolsWithRecovery: withRec };
|
|
@@ -5687,7 +6139,7 @@ function createSmartAgent(opts) {
|
|
|
5687
6139
|
].join("\n");
|
|
5688
6140
|
function latestUserPrompt(messages) {
|
|
5689
6141
|
const latest = [...messages].reverse().find((message) => message.role === "user");
|
|
5690
|
-
return latest ?
|
|
6142
|
+
return latest ? extractMessageText(latest) : "";
|
|
5691
6143
|
}
|
|
5692
6144
|
async function syncMemory(state) {
|
|
5693
6145
|
const query = latestUserPrompt(state.messages || []);
|
|
@@ -5849,6 +6301,7 @@ function createSmartAgent(opts) {
|
|
|
5849
6301
|
snapshot: base.snapshot,
|
|
5850
6302
|
resume: base.resume,
|
|
5851
6303
|
resolveToolApproval: base.resolveToolApproval,
|
|
6304
|
+
resolveUserQuestion: base.resolveUserQuestion,
|
|
5852
6305
|
asTool: base.asTool,
|
|
5853
6306
|
asHandoff: base.asHandoff,
|
|
5854
6307
|
__runtime: base.__runtime
|
|
@@ -8174,6 +8627,7 @@ exports.countApproxTokens = countApproxTokens;
|
|
|
8174
8627
|
exports.countMessagesTokens = countMessagesTokens;
|
|
8175
8628
|
exports.createAgent = createAgent;
|
|
8176
8629
|
exports.createAgentNode = createAgentNode;
|
|
8630
|
+
exports.createAskUserQuestionTool = createAskUserQuestionTool;
|
|
8177
8631
|
exports.createCodeGuardrail = createCodeGuardrail;
|
|
8178
8632
|
exports.createContextSummarizeNode = createContextSummarizeNode;
|
|
8179
8633
|
exports.createContextTools = createContextTools;
|
|
@@ -8215,6 +8669,7 @@ exports.regexRule = regexRule;
|
|
|
8215
8669
|
exports.resolveMemoryStore = resolveMemoryStore;
|
|
8216
8670
|
exports.resolveStrategy = resolveStrategy;
|
|
8217
8671
|
exports.resolveToolApprovalState = resolveToolApprovalState;
|
|
8672
|
+
exports.resolveUserQuestionState = resolveUserQuestionState;
|
|
8218
8673
|
exports.restoreSnapshot = restoreSnapshot;
|
|
8219
8674
|
exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
|
|
8220
8675
|
exports.setTokenCounter = setTokenCounter;
|