@monotykamary/pi-retry 0.6.8 → 0.6.10
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/package.json +9 -3
- package/retry.ts +40 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monotykamary/pi-retry",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.10",
|
|
4
4
|
"description": "Extension suite for pi coding agent that handles 400/413 errors and connection errors with automatic retry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Tom X Nguyen",
|
|
@@ -32,9 +32,15 @@
|
|
|
32
32
|
"src/",
|
|
33
33
|
"README.md"
|
|
34
34
|
],
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@earendil-works/pi-agent-core": "*",
|
|
37
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
38
|
+
"@earendil-works/pi-tui": "*"
|
|
39
|
+
},
|
|
35
40
|
"devDependencies": {
|
|
36
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
37
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
41
|
+
"@earendil-works/pi-agent-core": "^0.84.0",
|
|
42
|
+
"@earendil-works/pi-coding-agent": "^0.84.0",
|
|
43
|
+
"@earendil-works/pi-tui": "^0.84.0",
|
|
38
44
|
"@types/node": "25.9.1",
|
|
39
45
|
"@vitest/coverage-v8": "4.1.7",
|
|
40
46
|
"knip": "6.14.1",
|
package/retry.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { matchesKey } from "@earendil-works/pi-tui";
|
|
2
3
|
import { Agent } from "@earendil-works/pi-agent-core";
|
|
3
4
|
import { AgentSession } from "@earendil-works/pi-coding-agent";
|
|
4
5
|
import {
|
|
@@ -102,9 +103,10 @@ const stateOther = new RetryState();
|
|
|
102
103
|
// Max_tokens continuation state (indefinite — no cap needed)
|
|
103
104
|
const stateContinuation = new ContinuationState();
|
|
104
105
|
|
|
105
|
-
// Abort flag: set when
|
|
106
|
-
// session_start and
|
|
107
|
-
// from starting a hidden retry turn after
|
|
106
|
+
// Abort flag: set when Pi's active signal is aborted or turn_end reports
|
|
107
|
+
// stopReason "aborted", cleared on session_start and fresh user activity.
|
|
108
|
+
// Prevents triggerInvisibleContinue() from starting a hidden retry turn after
|
|
109
|
+
// the user explicitly cancelled, even if a tool/provider reports an error.
|
|
108
110
|
let _userAborted = false;
|
|
109
111
|
|
|
110
112
|
// Mutex: only one triggerInvisibleContinue may be in-flight at a time.
|
|
@@ -186,25 +188,32 @@ export default function (pi: ExtensionAPI) {
|
|
|
186
188
|
|
|
187
189
|
pi.on("input", () => {
|
|
188
190
|
_inputGeneration++;
|
|
191
|
+
// The generation change cancels any older loop; the new user request gets
|
|
192
|
+
// its own retry eligibility even if the previous request was aborted.
|
|
193
|
+
_userAborted = false;
|
|
189
194
|
});
|
|
190
195
|
|
|
191
196
|
// Reset retry counters on successful completion (not max_tokens, not error)
|
|
192
197
|
pi.on("turn_end", async (event, ctx) => {
|
|
193
198
|
const msg = event.message as any;
|
|
199
|
+
if (
|
|
200
|
+
ctx.signal?.aborted ||
|
|
201
|
+
(msg.role === "assistant" && msg.stopReason === "aborted")
|
|
202
|
+
) {
|
|
203
|
+
// User cancelled — reset retry state so it doesn't leak into other
|
|
204
|
+
// branches of the session tree. The signal check matters for tool calls:
|
|
205
|
+
// some tools/providers finish with an error-shaped result after abort.
|
|
206
|
+
state400.reset();
|
|
207
|
+
stateCredit.reset();
|
|
208
|
+
stateConnection.reset();
|
|
209
|
+
stateOther.reset();
|
|
210
|
+
stateContinuation.endContinuation();
|
|
211
|
+
// Signal to any in-flight triggerInvisibleContinue or pending retry
|
|
212
|
+
// that the user has cancelled — do not queue another retry turn.
|
|
213
|
+
_userAborted = true;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
194
216
|
if (msg.role === "assistant" && msg.stopReason !== "error") {
|
|
195
|
-
if (msg.stopReason === "aborted") {
|
|
196
|
-
// User cancelled — reset retry state so it doesn't leak into other
|
|
197
|
-
// branches of the session tree.
|
|
198
|
-
state400.reset();
|
|
199
|
-
stateCredit.reset();
|
|
200
|
-
stateConnection.reset();
|
|
201
|
-
stateOther.reset();
|
|
202
|
-
stateContinuation.endContinuation();
|
|
203
|
-
// Signal to any in-flight triggerInvisibleContinue or pending retry
|
|
204
|
-
// that the user has cancelled — do not queue another retry turn.
|
|
205
|
-
_userAborted = true;
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
217
|
if (msg.stopReason !== "length") {
|
|
209
218
|
// Normal completion — reset everything including continuation count
|
|
210
219
|
state400.succeed();
|
|
@@ -230,6 +239,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
230
239
|
// triggerInvisibleContinue(), which owns the retry loop with backoff
|
|
231
240
|
// sleeps that happen AFTER processEvents returns (outside the agent run).
|
|
232
241
|
pi.on("agent_end", async (event, ctx) => {
|
|
242
|
+
// Prefer Pi's run signal over provider-specific stop-reason mapping. An
|
|
243
|
+
// Escape during a Fabric/core tool may settle as an error-shaped result,
|
|
244
|
+
// but it is still a user cancellation and must never schedule a retry.
|
|
245
|
+
if (ctx.signal?.aborted) {
|
|
246
|
+
_userAborted = true;
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
233
250
|
const entries = ctx.sessionManager.getEntries();
|
|
234
251
|
const lastAssistant = getLastAssistantMessage(entries);
|
|
235
252
|
|
|
@@ -480,16 +497,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
480
497
|
if (ctx.mode === "tui") {
|
|
481
498
|
_terminalInputUnsubscribe = ctx.ui.onTerminalInput(data => {
|
|
482
499
|
if (
|
|
483
|
-
data
|
|
500
|
+
!matchesKey(data, "escape") ||
|
|
484
501
|
!_continueInProgress ||
|
|
485
502
|
_continueGeneration !== _sessionGeneration
|
|
486
503
|
) {
|
|
487
504
|
return undefined;
|
|
488
505
|
}
|
|
489
506
|
|
|
507
|
+
// Cancel pi-retry's out-of-band loop, but let Pi's native interrupt
|
|
508
|
+
// handler receive the same key. Pi owns the active turn and queue: its
|
|
509
|
+
// handler aborts the current tool/model call and clears any queued
|
|
510
|
+
// steer/follow-up messages. Consuming Escape here bypasses that cleanup
|
|
511
|
+
// and can let AgentSession continue after the user asked it to stop.
|
|
490
512
|
_userAborted = true;
|
|
491
|
-
|
|
492
|
-
return { consume: true };
|
|
513
|
+
return undefined;
|
|
493
514
|
});
|
|
494
515
|
}
|
|
495
516
|
});
|