@prestyj/agent 5.26.0 → 5.28.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/dist/index.cjs +56 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +57 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
stream,
|
|
8
8
|
EventStream,
|
|
9
9
|
EZCoderAIError,
|
|
10
|
+
environmentSecrets,
|
|
10
11
|
isHardBillingMessage,
|
|
11
12
|
redactValue,
|
|
12
13
|
sliceHead,
|
|
@@ -92,6 +93,11 @@ function clampOutputTokens(key, requested) {
|
|
|
92
93
|
// src/agent-loop.ts
|
|
93
94
|
var DEFAULT_MAX_TURNS = 300;
|
|
94
95
|
var DEFAULT_TOOL_TIMEOUT_MS = 3e5;
|
|
96
|
+
var _toolRedaction;
|
|
97
|
+
function toolRedactionOptions() {
|
|
98
|
+
_toolRedaction ??= { secrets: environmentSecrets(process.env) };
|
|
99
|
+
return _toolRedaction;
|
|
100
|
+
}
|
|
95
101
|
var _diagFn = null;
|
|
96
102
|
function setStreamDiagnostic(fn) {
|
|
97
103
|
_diagFn = fn;
|
|
@@ -427,11 +433,14 @@ async function* agentLoop(messages, options) {
|
|
|
427
433
|
const OVERLOAD_BASE_DELAY_MS = 2e3;
|
|
428
434
|
const OVERLOAD_MAX_DELAY_MS = 3e4;
|
|
429
435
|
const STREAM_IDLE_TIMEOUT_MS = 9e4;
|
|
436
|
+
const STREAM_TOOL_INPUT_IDLE_TIMEOUT_MS = 3e5;
|
|
430
437
|
const STREAM_HARD_TIMEOUT_MS = 9e4;
|
|
431
438
|
const STREAM_OUTPUT_HARD_TIMEOUT_MS = 3e5;
|
|
432
|
-
const STREAM_THINKING_IDLE_TIMEOUT_MS =
|
|
433
|
-
const STREAM_THINKING_HARD_TIMEOUT_MS =
|
|
439
|
+
const STREAM_THINKING_IDLE_TIMEOUT_MS = 6e5;
|
|
440
|
+
const STREAM_THINKING_HARD_TIMEOUT_MS = 9e5;
|
|
434
441
|
const NON_STREAMING_HARD_TIMEOUT_MS = 3e5;
|
|
442
|
+
const nonStreamingHardTimeoutMs = options.thinking != null ? STREAM_THINKING_HARD_TIMEOUT_MS : NON_STREAMING_HARD_TIMEOUT_MS;
|
|
443
|
+
const VISIBLE_STALL_AFTER_MS = 6e4;
|
|
435
444
|
const usesSilentReasoningBudget = options.provider === "sakana" || options.provider === "openai" && options.thinking != null;
|
|
436
445
|
const localBackend = isLocalBackendUrl(options.baseUrl);
|
|
437
446
|
const baseFirstEventTimeoutMs = localBackend ? Number.POSITIVE_INFINITY : usesSilentReasoningBudget ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
|
|
@@ -533,10 +542,11 @@ async function* agentLoop(messages, options) {
|
|
|
533
542
|
options.signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
534
543
|
let hasReceivedEvent = false;
|
|
535
544
|
let hasReceivedThinking = false;
|
|
545
|
+
let toolInputOpen = false;
|
|
536
546
|
const resetIdleTimer = () => {
|
|
537
547
|
if (useNonStreamingFallback) return;
|
|
538
548
|
if (idleTimer) clearTimeout(idleTimer);
|
|
539
|
-
const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : hasReceivedThinking ? STREAM_THINKING_IDLE_TIMEOUT_MS : firstEventTimeoutMs;
|
|
549
|
+
const timeoutMs = hasReceivedEvent ? toolInputOpen ? STREAM_TOOL_INPUT_IDLE_TIMEOUT_MS : STREAM_IDLE_TIMEOUT_MS : hasReceivedThinking ? STREAM_THINKING_IDLE_TIMEOUT_MS : firstEventTimeoutMs;
|
|
540
550
|
if (!Number.isFinite(timeoutMs)) return;
|
|
541
551
|
idleTimer = setTimeout(() => {
|
|
542
552
|
diag("idle_timeout_fired", {
|
|
@@ -544,14 +554,14 @@ async function* agentLoop(messages, options) {
|
|
|
544
554
|
sinceLastEventMs: Date.now() - lastEventTime,
|
|
545
555
|
lastEventType,
|
|
546
556
|
maxConsumerLagMs,
|
|
547
|
-
phase: hasReceivedEvent ? "mid_stream" : hasReceivedThinking ? "post_thinking" : "first_event",
|
|
557
|
+
phase: hasReceivedEvent ? toolInputOpen ? "mid_tool_input" : "mid_stream" : hasReceivedThinking ? "post_thinking" : "first_event",
|
|
548
558
|
eventTypes: eventTypeCounts
|
|
549
559
|
});
|
|
550
560
|
idleTimedOut = true;
|
|
551
561
|
streamController.abort();
|
|
552
562
|
}, timeoutMs);
|
|
553
563
|
};
|
|
554
|
-
let hardTimeoutMs = useNonStreamingFallback ?
|
|
564
|
+
let hardTimeoutMs = useNonStreamingFallback ? nonStreamingHardTimeoutMs : initialHardTimeoutMs;
|
|
555
565
|
hardTimer = setTimeout(() => {
|
|
556
566
|
diag("hard_timeout_fired", {
|
|
557
567
|
events: typeof streamEventCount !== "undefined" ? streamEventCount : 0,
|
|
@@ -646,6 +656,8 @@ async function* agentLoop(messages, options) {
|
|
|
646
656
|
if (firstProviderEventAt === void 0) firstProviderEventAt = pullTime;
|
|
647
657
|
eventTypeCounts[event.type] = (eventTypeCounts[event.type] ?? 0) + 1;
|
|
648
658
|
lastEventType = event.type;
|
|
659
|
+
if (event.type === "toolcall_delta") toolInputOpen = true;
|
|
660
|
+
else if (event.type === "toolcall_done") toolInputOpen = false;
|
|
649
661
|
if ((event.type === "text_delta" || event.type === "server_toolcall" || event.type === "toolcall_delta") && !hasReceivedEvent) {
|
|
650
662
|
hasReceivedEvent = true;
|
|
651
663
|
if (hardTimer && hardTimeoutMs < STREAM_OUTPUT_HARD_TIMEOUT_MS) {
|
|
@@ -980,7 +992,7 @@ async function* agentLoop(messages, options) {
|
|
|
980
992
|
attempt: stallRetries,
|
|
981
993
|
maxAttempts: MAX_STALL_RETRIES,
|
|
982
994
|
delayMs,
|
|
983
|
-
silent: stallRetries <= 2,
|
|
995
|
+
silent: stallRetries <= 2 && Date.now() - streamCallStart < VISIBLE_STALL_AFTER_MS,
|
|
984
996
|
...preservedChars > 0 ? { preservedChars } : {}
|
|
985
997
|
};
|
|
986
998
|
await abortableSleep(delayMs, options.signal);
|
|
@@ -1243,7 +1255,8 @@ async function* agentLoop(messages, options) {
|
|
|
1243
1255
|
maxTurnToolResultChars: options.maxTurnToolResultChars,
|
|
1244
1256
|
toolMap,
|
|
1245
1257
|
invalidToolArgumentCounts,
|
|
1246
|
-
markFatalToolArgumentError
|
|
1258
|
+
markFatalToolArgumentError,
|
|
1259
|
+
seenToolCalls: /* @__PURE__ */ new Set()
|
|
1247
1260
|
};
|
|
1248
1261
|
const hasSequentialToolCall = toolCalls.some(
|
|
1249
1262
|
(toolCall) => toolMap.get(toolCall.name)?.executionMode === "sequential"
|
|
@@ -1364,6 +1377,15 @@ async function* agentLoop(messages, options) {
|
|
|
1364
1377
|
totalUsage: { ...totalUsage }
|
|
1365
1378
|
};
|
|
1366
1379
|
}
|
|
1380
|
+
function canonicalToolArgs(value) {
|
|
1381
|
+
if (Array.isArray(value)) return value.map(canonicalToolArgs);
|
|
1382
|
+
if (value !== null && typeof value === "object") {
|
|
1383
|
+
return Object.fromEntries(
|
|
1384
|
+
Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, canonicalToolArgs(v)])
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
return value;
|
|
1388
|
+
}
|
|
1367
1389
|
function pushToolEvent(eventStream, state, event) {
|
|
1368
1390
|
if (!state.finalized) eventStream.push(event);
|
|
1369
1391
|
}
|
|
@@ -1380,6 +1402,21 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1380
1402
|
let isError = false;
|
|
1381
1403
|
let invalidArgAttempt;
|
|
1382
1404
|
const tool = options.toolMap.get(toolCall.name);
|
|
1405
|
+
if (tool) {
|
|
1406
|
+
const signature = JSON.stringify([toolCall.name, canonicalToolArgs(toolCall.args)]);
|
|
1407
|
+
if (options.seenToolCalls.has(signature)) {
|
|
1408
|
+
const content = "Tool call cancelled: an identical call already appeared in this response; this call was not executed.";
|
|
1409
|
+
pushEvent({
|
|
1410
|
+
type: "tool_call_end",
|
|
1411
|
+
toolCallId: toolCall.id,
|
|
1412
|
+
result: content,
|
|
1413
|
+
isError: true,
|
|
1414
|
+
durationMs: Date.now() - startTime
|
|
1415
|
+
});
|
|
1416
|
+
return { toolCallId: toolCall.id, content, isError: true };
|
|
1417
|
+
}
|
|
1418
|
+
options.seenToolCalls.add(signature);
|
|
1419
|
+
}
|
|
1383
1420
|
if (!tool) {
|
|
1384
1421
|
resultContent = `Unknown tool: ${toolCall.name}`;
|
|
1385
1422
|
isError = true;
|
|
@@ -1414,8 +1451,8 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1414
1451
|
ctx.signal
|
|
1415
1452
|
);
|
|
1416
1453
|
const normalized = normalizeToolResult(raw);
|
|
1417
|
-
resultContent = redactValue(normalized.content);
|
|
1418
|
-
details = redactValue(normalized.details);
|
|
1454
|
+
resultContent = redactValue(normalized.content, toolRedactionOptions());
|
|
1455
|
+
details = redactValue(normalized.details, toolRedactionOptions());
|
|
1419
1456
|
for (const key of options.invalidToolArgumentCounts.keys()) {
|
|
1420
1457
|
if (key.startsWith(`${toolCall.name}:`)) options.invalidToolArgumentCounts.delete(key);
|
|
1421
1458
|
}
|
|
@@ -1446,12 +1483,15 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1446
1483
|
} else if (options.signal?.aborted && isAbortError(err)) {
|
|
1447
1484
|
resultContent = indeterminateOutcomeText(toolCall.name);
|
|
1448
1485
|
} else {
|
|
1449
|
-
resultContent = redactValue(
|
|
1486
|
+
resultContent = redactValue(
|
|
1487
|
+
err instanceof Error ? err.message : String(err),
|
|
1488
|
+
toolRedactionOptions()
|
|
1489
|
+
);
|
|
1450
1490
|
}
|
|
1451
1491
|
}
|
|
1452
1492
|
}
|
|
1453
|
-
resultContent = redactValue(resultContent);
|
|
1454
|
-
details = redactValue(details);
|
|
1493
|
+
resultContent = redactValue(resultContent, toolRedactionOptions());
|
|
1494
|
+
details = redactValue(details, toolRedactionOptions());
|
|
1455
1495
|
const durationMs = Date.now() - startTime;
|
|
1456
1496
|
pushEvent({
|
|
1457
1497
|
type: "tool_call_end",
|
|
@@ -1493,6 +1533,11 @@ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
|
|
|
1493
1533
|
for (const phase of phases) {
|
|
1494
1534
|
if (options.signal?.aborted) break;
|
|
1495
1535
|
if (phase.sequential) {
|
|
1536
|
+
const signature = JSON.stringify([
|
|
1537
|
+
phase.sequential.name,
|
|
1538
|
+
canonicalToolArgs(phase.sequential.args)
|
|
1539
|
+
]);
|
|
1540
|
+
if (!options.seenToolCalls.has(signature)) options.seenToolCalls.clear();
|
|
1496
1541
|
dispatchedIds.add(phase.sequential.id);
|
|
1497
1542
|
const record = await executeSingleToolCall(
|
|
1498
1543
|
phase.sequential,
|