@monotykamary/pi-retry 0.3.8 → 0.3.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/retry.ts +35 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monotykamary/pi-retry",
3
- "version": "0.3.8",
3
+ "version": "0.3.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",
package/retry.ts CHANGED
@@ -58,8 +58,18 @@ Agent.prototype.subscribe = function (this: Agent, ...args: any[]) {
58
58
  };
59
59
 
60
60
  // Monkey-patch continue() so the session's built-in retry loop cooperates
61
- // with our _continueInProgress mutex instead of throwing "Agent is already
62
- // processing" when we beat it to the punch.
61
+ // with our _continueInProgress mutex AND can convert the "Cannot continue
62
+ // from assistant" error into a prompt([]) call when the agent was mid-task.
63
+ //
64
+ // When continue() throws "Cannot continue from message role: assistant":
65
+ // - stopReason "stop" → agent finished cleanly, don't continue
66
+ // - stopReason "aborted" → user cancelled, don't continue
67
+ // - stopReason "error" → pi-retry IS the error handler, fall back to prompt([])
68
+ // so the retry actually happens (rather than swallowing and stalling)
69
+ // - stopReason "toolUse" or "length" → mid-task, fall back to prompt([])
70
+ //
71
+ // This ensures the agent loop actually continues after compaction instead
72
+ // of swallowing the error and letting the while-loop die.
63
73
  const _origContinue = Agent.prototype.continue as (this: Agent) => Promise<unknown>;
64
74
  Agent.prototype.continue = function (this: Agent) {
65
75
  const self = this;
@@ -71,14 +81,30 @@ Agent.prototype.continue = function (this: Agent) {
71
81
  try {
72
82
  return await _origContinue.call(self);
73
83
  } catch (e: any) {
74
- // After pi-retry finishes, the transcript ends with a fresh
75
- // assistant message. The session's continue() sees this and
76
- // would throw "Cannot continue from an assistant message".
77
- // Catch it — the while-loop will poll _handlePostAgentRun()
78
- // again, find no error, and exit cleanly.
79
84
  const msg = e?.message ?? '';
80
- if (msg.includes('Cannot continue from an assistant message') ||
81
- msg.includes('Agent is already processing')) {
85
+ if (msg.includes('Cannot continue from message role') ||
86
+ msg.includes('Cannot continue from an assistant message')) {
87
+ // Check stopReason — only continue if the agent was mid-task
88
+ const lastMsg = self.state.messages[self.state.messages.length - 1];
89
+ if (lastMsg?.role === 'assistant' &&
90
+ lastMsg.stopReason !== 'stop' &&
91
+ lastMsg.stopReason !== 'aborted') {
92
+ // Agent was mid-task (toolUse, length, or error) — fall back to prompt([])
93
+ if (!_continueInProgress) {
94
+ _continueInProgress = true;
95
+ try {
96
+ await self.prompt([]);
97
+ } catch {
98
+ // Agent already processing or other transient error
99
+ } finally {
100
+ _continueInProgress = false;
101
+ }
102
+ }
103
+ }
104
+ // For stop/aborted: return void, the session loop exits naturally
105
+ return;
106
+ }
107
+ if (msg.includes('Agent is already processing')) {
82
108
  return;
83
109
  }
84
110
  throw e;