@prestyj/agent 5.3.0 → 5.4.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.d.ts CHANGED
@@ -84,6 +84,13 @@ interface AgentRetryEvent {
84
84
  observedLimit?: number;
85
85
  /** When true, the retry should not be shown to the user (hidden retry). */
86
86
  silent?: boolean;
87
+ /**
88
+ * Chars of streamed text preserved in message history across this retry
89
+ * (transport failures only). When > 0 the retry CONTINUES from the partial
90
+ * instead of replaying — UIs must keep the streamed text on screen rather
91
+ * than rolling it back.
92
+ */
93
+ preservedChars?: number;
87
94
  }
88
95
  interface AgentToolCallDeltaEvent {
89
96
  type: "toolcall_delta";
package/dist/index.js CHANGED
@@ -230,7 +230,7 @@ function closeIterator(iterator) {
230
230
  async function* agentLoop(messages, options) {
231
231
  const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;
232
232
  const maxContinuations = options.maxContinuations ?? 5;
233
- const toolMap = new Map((options.tools ?? []).map((t) => [t.name, t]));
233
+ let toolMap = new Map((options.tools ?? []).map((t) => [t.name, t]));
234
234
  const totalUsage = { inputTokens: 0, outputTokens: 0 };
235
235
  let turn = 0;
236
236
  let hitMaxTurns = false;
@@ -252,6 +252,8 @@ async function* agentLoop(messages, options) {
252
252
  const MAX_OVERFLOW_COMPACTIONS = 2;
253
253
  const STALL_RETRIES_BEFORE_NON_STREAMING = 2;
254
254
  const STALL_DELAY_MS = 1e3;
255
+ const MIN_PARTIAL_PRESERVE_CHARS = 200;
256
+ 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.]";
255
257
  const OVERLOAD_BASE_DELAY_MS = 2e3;
256
258
  const OVERLOAD_MAX_DELAY_MS = 3e4;
257
259
  const STREAM_FIRST_EVENT_TIMEOUT_MS = 45e3;
@@ -270,6 +272,7 @@ async function* agentLoop(messages, options) {
270
272
  while (turn < maxTurns) {
271
273
  options.signal?.throwIfAborted();
272
274
  turn++;
275
+ toolMap = new Map((options.tools ?? []).map((t) => [t.name, t]));
273
276
  if (_diagFn) {
274
277
  let msgChars = 0;
275
278
  for (const m of messages) {
@@ -326,6 +329,7 @@ async function* agentLoop(messages, options) {
326
329
  let toolcallDeltaChars = 0;
327
330
  let toolcallDeltaCount = 0;
328
331
  let runawayDetected = null;
332
+ let attemptText = "";
329
333
  let lastYieldEndTime = Date.now();
330
334
  let maxConsumerLagMs = 0;
331
335
  const forwardAbort = () => streamController.abort();
@@ -451,6 +455,7 @@ async function* agentLoop(messages, options) {
451
455
  idleTimer = null;
452
456
  }
453
457
  if (event.type === "text_delta") {
458
+ attemptText += event.text;
454
459
  yield { type: "text_delta", text: event.text };
455
460
  } else if (event.type === "thinking_delta") {
456
461
  yield { type: "thinking_delta", text: event.text };
@@ -653,13 +658,23 @@ async function* agentLoop(messages, options) {
653
658
  });
654
659
  }
655
660
  const delayMs = Math.min(STALL_DELAY_MS * 2 ** (stallRetries - 1), 8e3);
661
+ let preservedChars = 0;
662
+ if (attemptText.length >= MIN_PARTIAL_PRESERVE_CHARS && toolcallDeltaCount === 0) {
663
+ messages.push({
664
+ role: "assistant",
665
+ content: [{ type: "text", text: attemptText }]
666
+ });
667
+ messages.push({ role: "user", content: PARTIAL_CONTINUATION_PROMPT });
668
+ preservedChars = attemptText.length;
669
+ }
656
670
  diag("retry", {
657
671
  reason: cause,
658
672
  attempt: stallRetries,
659
673
  maxAttempts: MAX_STALL_RETRIES,
660
674
  delayMs,
661
675
  events: streamEventCount,
662
- nonStreaming: useNonStreamingFallback
676
+ nonStreaming: useNonStreamingFallback,
677
+ preservedChars
663
678
  });
664
679
  yield {
665
680
  type: "retry",
@@ -667,7 +682,8 @@ async function* agentLoop(messages, options) {
667
682
  attempt: stallRetries,
668
683
  maxAttempts: MAX_STALL_RETRIES,
669
684
  delayMs,
670
- silent: stallRetries <= 2
685
+ silent: stallRetries <= 2,
686
+ ...preservedChars > 0 ? { preservedChars } : {}
671
687
  };
672
688
  await abortableSleep(delayMs, options.signal);
673
689
  turn--;