@prestyj/agent 5.27.0 → 5.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +43 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +43 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -460,11 +460,14 @@ async function* agentLoop(messages, options) {
|
|
|
460
460
|
const OVERLOAD_BASE_DELAY_MS = 2e3;
|
|
461
461
|
const OVERLOAD_MAX_DELAY_MS = 3e4;
|
|
462
462
|
const STREAM_IDLE_TIMEOUT_MS = 9e4;
|
|
463
|
+
const STREAM_TOOL_INPUT_IDLE_TIMEOUT_MS = 3e5;
|
|
463
464
|
const STREAM_HARD_TIMEOUT_MS = 9e4;
|
|
464
465
|
const STREAM_OUTPUT_HARD_TIMEOUT_MS = 3e5;
|
|
465
|
-
const STREAM_THINKING_IDLE_TIMEOUT_MS =
|
|
466
|
-
const STREAM_THINKING_HARD_TIMEOUT_MS =
|
|
466
|
+
const STREAM_THINKING_IDLE_TIMEOUT_MS = 6e5;
|
|
467
|
+
const STREAM_THINKING_HARD_TIMEOUT_MS = 9e5;
|
|
467
468
|
const NON_STREAMING_HARD_TIMEOUT_MS = 3e5;
|
|
469
|
+
const nonStreamingHardTimeoutMs = options.thinking != null ? STREAM_THINKING_HARD_TIMEOUT_MS : NON_STREAMING_HARD_TIMEOUT_MS;
|
|
470
|
+
const VISIBLE_STALL_AFTER_MS = 6e4;
|
|
468
471
|
const usesSilentReasoningBudget = options.provider === "sakana" || options.provider === "openai" && options.thinking != null;
|
|
469
472
|
const localBackend = isLocalBackendUrl(options.baseUrl);
|
|
470
473
|
const baseFirstEventTimeoutMs = localBackend ? Number.POSITIVE_INFINITY : usesSilentReasoningBudget ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
|
|
@@ -566,10 +569,11 @@ async function* agentLoop(messages, options) {
|
|
|
566
569
|
options.signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
567
570
|
let hasReceivedEvent = false;
|
|
568
571
|
let hasReceivedThinking = false;
|
|
572
|
+
let toolInputOpen = false;
|
|
569
573
|
const resetIdleTimer = () => {
|
|
570
574
|
if (useNonStreamingFallback) return;
|
|
571
575
|
if (idleTimer) clearTimeout(idleTimer);
|
|
572
|
-
const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : hasReceivedThinking ? STREAM_THINKING_IDLE_TIMEOUT_MS : firstEventTimeoutMs;
|
|
576
|
+
const timeoutMs = hasReceivedEvent ? toolInputOpen ? STREAM_TOOL_INPUT_IDLE_TIMEOUT_MS : STREAM_IDLE_TIMEOUT_MS : hasReceivedThinking ? STREAM_THINKING_IDLE_TIMEOUT_MS : firstEventTimeoutMs;
|
|
573
577
|
if (!Number.isFinite(timeoutMs)) return;
|
|
574
578
|
idleTimer = setTimeout(() => {
|
|
575
579
|
diag("idle_timeout_fired", {
|
|
@@ -577,14 +581,14 @@ async function* agentLoop(messages, options) {
|
|
|
577
581
|
sinceLastEventMs: Date.now() - lastEventTime,
|
|
578
582
|
lastEventType,
|
|
579
583
|
maxConsumerLagMs,
|
|
580
|
-
phase: hasReceivedEvent ? "mid_stream" : hasReceivedThinking ? "post_thinking" : "first_event",
|
|
584
|
+
phase: hasReceivedEvent ? toolInputOpen ? "mid_tool_input" : "mid_stream" : hasReceivedThinking ? "post_thinking" : "first_event",
|
|
581
585
|
eventTypes: eventTypeCounts
|
|
582
586
|
});
|
|
583
587
|
idleTimedOut = true;
|
|
584
588
|
streamController.abort();
|
|
585
589
|
}, timeoutMs);
|
|
586
590
|
};
|
|
587
|
-
let hardTimeoutMs = useNonStreamingFallback ?
|
|
591
|
+
let hardTimeoutMs = useNonStreamingFallback ? nonStreamingHardTimeoutMs : initialHardTimeoutMs;
|
|
588
592
|
hardTimer = setTimeout(() => {
|
|
589
593
|
diag("hard_timeout_fired", {
|
|
590
594
|
events: typeof streamEventCount !== "undefined" ? streamEventCount : 0,
|
|
@@ -679,6 +683,8 @@ async function* agentLoop(messages, options) {
|
|
|
679
683
|
if (firstProviderEventAt === void 0) firstProviderEventAt = pullTime;
|
|
680
684
|
eventTypeCounts[event.type] = (eventTypeCounts[event.type] ?? 0) + 1;
|
|
681
685
|
lastEventType = event.type;
|
|
686
|
+
if (event.type === "toolcall_delta") toolInputOpen = true;
|
|
687
|
+
else if (event.type === "toolcall_done") toolInputOpen = false;
|
|
682
688
|
if ((event.type === "text_delta" || event.type === "server_toolcall" || event.type === "toolcall_delta") && !hasReceivedEvent) {
|
|
683
689
|
hasReceivedEvent = true;
|
|
684
690
|
if (hardTimer && hardTimeoutMs < STREAM_OUTPUT_HARD_TIMEOUT_MS) {
|
|
@@ -1013,7 +1019,7 @@ async function* agentLoop(messages, options) {
|
|
|
1013
1019
|
attempt: stallRetries,
|
|
1014
1020
|
maxAttempts: MAX_STALL_RETRIES,
|
|
1015
1021
|
delayMs,
|
|
1016
|
-
silent: stallRetries <= 2,
|
|
1022
|
+
silent: stallRetries <= 2 && Date.now() - streamCallStart < VISIBLE_STALL_AFTER_MS,
|
|
1017
1023
|
...preservedChars > 0 ? { preservedChars } : {}
|
|
1018
1024
|
};
|
|
1019
1025
|
await abortableSleep(delayMs, options.signal);
|
|
@@ -1276,7 +1282,8 @@ async function* agentLoop(messages, options) {
|
|
|
1276
1282
|
maxTurnToolResultChars: options.maxTurnToolResultChars,
|
|
1277
1283
|
toolMap,
|
|
1278
1284
|
invalidToolArgumentCounts,
|
|
1279
|
-
markFatalToolArgumentError
|
|
1285
|
+
markFatalToolArgumentError,
|
|
1286
|
+
seenToolCalls: /* @__PURE__ */ new Set()
|
|
1280
1287
|
};
|
|
1281
1288
|
const hasSequentialToolCall = toolCalls.some(
|
|
1282
1289
|
(toolCall) => toolMap.get(toolCall.name)?.executionMode === "sequential"
|
|
@@ -1397,6 +1404,15 @@ async function* agentLoop(messages, options) {
|
|
|
1397
1404
|
totalUsage: { ...totalUsage }
|
|
1398
1405
|
};
|
|
1399
1406
|
}
|
|
1407
|
+
function canonicalToolArgs(value) {
|
|
1408
|
+
if (Array.isArray(value)) return value.map(canonicalToolArgs);
|
|
1409
|
+
if (value !== null && typeof value === "object") {
|
|
1410
|
+
return Object.fromEntries(
|
|
1411
|
+
Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, canonicalToolArgs(v)])
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
return value;
|
|
1415
|
+
}
|
|
1400
1416
|
function pushToolEvent(eventStream, state, event) {
|
|
1401
1417
|
if (!state.finalized) eventStream.push(event);
|
|
1402
1418
|
}
|
|
@@ -1413,6 +1429,21 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1413
1429
|
let isError = false;
|
|
1414
1430
|
let invalidArgAttempt;
|
|
1415
1431
|
const tool = options.toolMap.get(toolCall.name);
|
|
1432
|
+
if (tool) {
|
|
1433
|
+
const signature = JSON.stringify([toolCall.name, canonicalToolArgs(toolCall.args)]);
|
|
1434
|
+
if (options.seenToolCalls.has(signature)) {
|
|
1435
|
+
const content = "Tool call cancelled: an identical call already appeared in this response; this call was not executed.";
|
|
1436
|
+
pushEvent({
|
|
1437
|
+
type: "tool_call_end",
|
|
1438
|
+
toolCallId: toolCall.id,
|
|
1439
|
+
result: content,
|
|
1440
|
+
isError: true,
|
|
1441
|
+
durationMs: Date.now() - startTime
|
|
1442
|
+
});
|
|
1443
|
+
return { toolCallId: toolCall.id, content, isError: true };
|
|
1444
|
+
}
|
|
1445
|
+
options.seenToolCalls.add(signature);
|
|
1446
|
+
}
|
|
1416
1447
|
if (!tool) {
|
|
1417
1448
|
resultContent = `Unknown tool: ${toolCall.name}`;
|
|
1418
1449
|
isError = true;
|
|
@@ -1529,6 +1560,11 @@ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
|
|
|
1529
1560
|
for (const phase of phases) {
|
|
1530
1561
|
if (options.signal?.aborted) break;
|
|
1531
1562
|
if (phase.sequential) {
|
|
1563
|
+
const signature = JSON.stringify([
|
|
1564
|
+
phase.sequential.name,
|
|
1565
|
+
canonicalToolArgs(phase.sequential.args)
|
|
1566
|
+
]);
|
|
1567
|
+
if (!options.seenToolCalls.has(signature)) options.seenToolCalls.clear();
|
|
1532
1568
|
dispatchedIds.add(phase.sequential.id);
|
|
1533
1569
|
const record = await executeSingleToolCall(
|
|
1534
1570
|
phase.sequential,
|