@prestyj/agent 5.8.0 → 5.9.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 +70 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +70 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -215,7 +215,11 @@ function createAbortError() {
|
|
|
215
215
|
}
|
|
216
216
|
function abortablePromise(promise, signal) {
|
|
217
217
|
if (!signal) return promise;
|
|
218
|
-
if (signal.aborted)
|
|
218
|
+
if (signal.aborted) {
|
|
219
|
+
promise.catch(() => {
|
|
220
|
+
});
|
|
221
|
+
return Promise.reject(createAbortError());
|
|
222
|
+
}
|
|
219
223
|
return new Promise((resolve, reject) => {
|
|
220
224
|
let settled = false;
|
|
221
225
|
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
@@ -271,6 +275,7 @@ async function* agentLoop(messages, options) {
|
|
|
271
275
|
let overloadRetries = 0;
|
|
272
276
|
let emptyResponseRetries = 0;
|
|
273
277
|
let stallRetries = 0;
|
|
278
|
+
let runawayToolcallRetries = 0;
|
|
274
279
|
let overflowCompactionAttempts = 0;
|
|
275
280
|
let toolResultTruncationAttempted = false;
|
|
276
281
|
const invalidToolArgumentCounts = /* @__PURE__ */ new Map();
|
|
@@ -279,11 +284,16 @@ async function* agentLoop(messages, options) {
|
|
|
279
284
|
const MAX_OVERLOAD_RETRIES = 10;
|
|
280
285
|
const MAX_EMPTY_RESPONSE_RETRIES = 2;
|
|
281
286
|
const MAX_STALL_RETRIES = 10;
|
|
287
|
+
const MAX_RUNAWAY_TOOLCALL_RETRIES = 2;
|
|
288
|
+
const RUNAWAY_TOOLCALL_RETRY_DELAY_MS = 1e3;
|
|
282
289
|
const MAX_OVERFLOW_COMPACTIONS = 2;
|
|
283
290
|
const STALL_RETRIES_BEFORE_NON_STREAMING = 2;
|
|
284
291
|
const STALL_DELAY_MS = 1e3;
|
|
285
292
|
const MIN_PARTIAL_PRESERVE_CHARS = 200;
|
|
286
293
|
const PARTIAL_CONTINUATION_PROMPT = "[Your previous response was cut off by a connection failure. The text above is what was already delivered to the user. Continue exactly from where it stopped \u2014 do not repeat or restart it.]";
|
|
294
|
+
const MAX_OUTPUT_CONTINUATIONS = 2;
|
|
295
|
+
const MAX_TOKENS_CONTINUATION_PROMPT = "[Your previous response hit the output-token limit and was cut off. The text above is what was already delivered to the user. Continue exactly from where it stopped \u2014 do not repeat or restart it.]";
|
|
296
|
+
let maxTokensContinuations = 0;
|
|
287
297
|
const OVERLOAD_BASE_DELAY_MS = 2e3;
|
|
288
298
|
const OVERLOAD_MAX_DELAY_MS = 3e4;
|
|
289
299
|
const STREAM_FIRST_EVENT_TIMEOUT_MS = 45e3;
|
|
@@ -686,11 +696,33 @@ async function* agentLoop(messages, options) {
|
|
|
686
696
|
provider: options.provider,
|
|
687
697
|
model: options.model
|
|
688
698
|
});
|
|
699
|
+
if (runawayToolcallRetries < MAX_RUNAWAY_TOOLCALL_RETRIES) {
|
|
700
|
+
runawayToolcallRetries++;
|
|
701
|
+
const delayMs = RUNAWAY_TOOLCALL_RETRY_DELAY_MS * runawayToolcallRetries;
|
|
702
|
+
diag("retry", {
|
|
703
|
+
reason: "runaway_toolcall",
|
|
704
|
+
attempt: runawayToolcallRetries,
|
|
705
|
+
maxAttempts: MAX_RUNAWAY_TOOLCALL_RETRIES,
|
|
706
|
+
delayMs,
|
|
707
|
+
...runawayDetected
|
|
708
|
+
});
|
|
709
|
+
yield {
|
|
710
|
+
type: "retry",
|
|
711
|
+
reason: "runaway_toolcall",
|
|
712
|
+
attempt: runawayToolcallRetries,
|
|
713
|
+
maxAttempts: MAX_RUNAWAY_TOOLCALL_RETRIES,
|
|
714
|
+
delayMs,
|
|
715
|
+
silent: true
|
|
716
|
+
};
|
|
717
|
+
await abortableSleep(delayMs, options.signal);
|
|
718
|
+
turn--;
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
689
721
|
const detail = runawayDetected.kind === "chars" ? `${(runawayDetected.chars / 1024).toFixed(0)} KB of tool-call arguments` : `${runawayDetected.events} tool-call delta events`;
|
|
690
722
|
yield {
|
|
691
723
|
type: "error",
|
|
692
724
|
error: new Error(
|
|
693
|
-
`The model
|
|
725
|
+
`The model repeatedly failed to close a tool call after ${MAX_RUNAWAY_TOOLCALL_RETRIES} automatic retries (${detail}). Switch models and retry; your conversation is preserved.`
|
|
694
726
|
)
|
|
695
727
|
};
|
|
696
728
|
break;
|
|
@@ -791,6 +823,7 @@ async function* agentLoop(messages, options) {
|
|
|
791
823
|
}
|
|
792
824
|
overloadRetries = 0;
|
|
793
825
|
stallRetries = 0;
|
|
826
|
+
runawayToolcallRetries = 0;
|
|
794
827
|
const contentArr = Array.isArray(response.message.content) ? response.message.content : null;
|
|
795
828
|
const hasActionableContent = response.message.content !== "" && contentArr !== null && contentArr.some(
|
|
796
829
|
(p) => p.type === "text" || p.type === "tool_call" || p.type === "server_tool_call"
|
|
@@ -862,6 +895,27 @@ async function* agentLoop(messages, options) {
|
|
|
862
895
|
consecutivePauses = 0;
|
|
863
896
|
const allToolCalls = extractToolCalls(response.message.content);
|
|
864
897
|
if (response.stopReason !== "tool_use" && allToolCalls.length === 0) {
|
|
898
|
+
if (response.stopReason === "max_tokens") {
|
|
899
|
+
if (maxTokensContinuations < MAX_OUTPUT_CONTINUATIONS) {
|
|
900
|
+
maxTokensContinuations++;
|
|
901
|
+
diag("max_tokens_continuation", {
|
|
902
|
+
attempt: maxTokensContinuations,
|
|
903
|
+
maxAttempts: MAX_OUTPUT_CONTINUATIONS,
|
|
904
|
+
provider: options.provider,
|
|
905
|
+
model: options.model
|
|
906
|
+
});
|
|
907
|
+
yield { type: "truncated", reason: "max_tokens", continued: true };
|
|
908
|
+
messages.push({ role: "user", content: MAX_TOKENS_CONTINUATION_PROMPT });
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
yield { type: "truncated", reason: "max_tokens", continued: false };
|
|
912
|
+
} else if (response.stopReason === "refusal" || response.stopReason === "error") {
|
|
913
|
+
yield {
|
|
914
|
+
type: "truncated",
|
|
915
|
+
reason: response.stopReason === "refusal" ? "refusal" : "provider_error",
|
|
916
|
+
continued: false
|
|
917
|
+
};
|
|
918
|
+
}
|
|
865
919
|
if (options.getSteeringMessages) {
|
|
866
920
|
const steering = await options.getSteeringMessages();
|
|
867
921
|
if (steering && steering.length > 0) {
|
|
@@ -1228,16 +1282,22 @@ function capToolResults(toolResults, maxToolResultChars) {
|
|
|
1228
1282
|
const max = Math.min(maxToolResultChars, hardMax);
|
|
1229
1283
|
for (const toolResult of toolResults) {
|
|
1230
1284
|
if (typeof toolResult.content !== "string" || toolResult.content.length <= max) continue;
|
|
1285
|
+
const originalChars = toolResult.content.length;
|
|
1231
1286
|
const headChars = Math.floor(max * 0.7);
|
|
1232
1287
|
const tailChars = max - headChars;
|
|
1233
1288
|
const head = toolResult.content.slice(0, headChars);
|
|
1234
1289
|
const tail = toolResult.content.slice(-tailChars);
|
|
1235
|
-
const omitted =
|
|
1290
|
+
const omitted = originalChars - headChars - tailChars;
|
|
1236
1291
|
toolResult.content = head + `
|
|
1237
1292
|
|
|
1238
1293
|
[... ${omitted} characters omitted ...]
|
|
1239
1294
|
|
|
1240
1295
|
` + tail;
|
|
1296
|
+
toolResult.capped = {
|
|
1297
|
+
originalChars,
|
|
1298
|
+
keptChars: toolResult.content.length,
|
|
1299
|
+
scope: "per-result"
|
|
1300
|
+
};
|
|
1241
1301
|
}
|
|
1242
1302
|
}
|
|
1243
1303
|
function capTurnToolResults(toolResults, maxTurnToolResultChars) {
|
|
@@ -1258,14 +1318,20 @@ function capTurnToolResults(toolResults, maxTurnToolResultChars) {
|
|
|
1258
1318
|
continue;
|
|
1259
1319
|
}
|
|
1260
1320
|
remaining -= fairShare;
|
|
1321
|
+
const originalChars = toolResult.content.length;
|
|
1261
1322
|
const headChars = Math.floor(fairShare * 0.7);
|
|
1262
1323
|
const tailChars = fairShare - headChars;
|
|
1263
|
-
const omitted =
|
|
1324
|
+
const omitted = originalChars - fairShare;
|
|
1264
1325
|
toolResult.content = toolResult.content.slice(0, headChars) + `
|
|
1265
1326
|
|
|
1266
1327
|
[... ${omitted} characters trimmed: this turn's combined tool results exceeded the per-turn budget. Re-run this call alone with narrower filters or offset/limit if you need the omitted content ...]
|
|
1267
1328
|
|
|
1268
1329
|
` + (tailChars > 0 ? toolResult.content.slice(-tailChars) : "");
|
|
1330
|
+
toolResult.capped = {
|
|
1331
|
+
originalChars: toolResult.capped?.originalChars ?? originalChars,
|
|
1332
|
+
keptChars: toolResult.content.length,
|
|
1333
|
+
scope: "per-turn"
|
|
1334
|
+
};
|
|
1269
1335
|
}
|
|
1270
1336
|
}
|
|
1271
1337
|
function normalizeToolResult(raw) {
|