@parall/claude-agent 1.65.0 → 1.66.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/dispatch.d.ts +10 -10
- package/dist/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +20 -24
- package/dist/input-lifecycle.d.ts.map +1 -1
- package/dist/input-lifecycle.js +5 -1
- package/dist/turn-outcome.d.ts.map +1 -1
- package/dist/turn-outcome.js +28 -5
- package/package.json +4 -4
- package/src/dispatch.ts +20 -27
- package/src/input-lifecycle.ts +5 -1
- package/src/turn-outcome.ts +25 -5
package/dist/dispatch.d.ts
CHANGED
|
@@ -89,19 +89,19 @@ export declare class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
89
89
|
abortDispatch(sessionKey: string): void;
|
|
90
90
|
hasPendingInjections(sessionKey: string): boolean;
|
|
91
91
|
hasUnsettledInjections(sessionKey: string): boolean;
|
|
92
|
+
isInjectionLive(sessionKey: string, deliveryKey: string): boolean;
|
|
92
93
|
/**
|
|
93
94
|
* The gateway discarded the buffered copy of an injection without a
|
|
94
|
-
* dispatch(). A settled injection only owes bookkeeping.
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* and let the gateway run it as a real turn.
|
|
95
|
+
* dispatch(). A settled injection only owes bookkeeping. A live one never
|
|
96
|
+
* reaches here (the gateway attaches to it via isInjectionLive); if one
|
|
97
|
+
* does, it is left registered — byCommand must keep routing its lifecycle
|
|
98
|
+
* frames and its terminal state drops it (see apply/fail) — and the
|
|
99
|
+
* anomaly is logged. Killing it is not an option: Claude Code starts a
|
|
100
|
+
* queued input on its own once the turn it was steered into ends, and the
|
|
101
|
+
* server, having recorded that `started` as delivered, would never re-run
|
|
102
|
+
* it (2026-09-17 prod loss).
|
|
103
103
|
*/
|
|
104
|
-
acknowledgeDiscardedInjection(sessionKey: string, deliveryKey: string):
|
|
104
|
+
acknowledgeDiscardedInjection(sessionKey: string, deliveryKey: string): DiscardedInjectionOutcome;
|
|
105
105
|
dispatch({ event, bodyForAgent, sessionKey, context, inputLifecycle, noteActivity, }: DispatchOpts): AsyncIterable<RuntimeEvent>;
|
|
106
106
|
getBranchPoint(_sessionKey: string): string | undefined;
|
|
107
107
|
getSessionHistoryPath(sessionKey: string): string | undefined;
|
package/dist/dispatch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
|
package/dist/dispatch.js
CHANGED
|
@@ -170,38 +170,34 @@ export class ClaudeCodeAdapter {
|
|
|
170
170
|
return false;
|
|
171
171
|
return state.inputs.hasUnsettledInjections();
|
|
172
172
|
}
|
|
173
|
+
isInjectionLive(sessionKey, deliveryKey) {
|
|
174
|
+
const state = this.processes.get(sessionKey);
|
|
175
|
+
if (!state || state.done)
|
|
176
|
+
return false;
|
|
177
|
+
const delivery = state.inputs.getByKey(deliveryKey);
|
|
178
|
+
if (!delivery || delivery.terminal)
|
|
179
|
+
return false;
|
|
180
|
+
const { proc } = state.handle;
|
|
181
|
+
return proc.exitCode === null && proc.signalCode === null;
|
|
182
|
+
}
|
|
173
183
|
/**
|
|
174
184
|
* The gateway discarded the buffered copy of an injection without a
|
|
175
|
-
* dispatch(). A settled injection only owes bookkeeping.
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* and let the gateway run it as a real turn.
|
|
185
|
+
* dispatch(). A settled injection only owes bookkeeping. A live one never
|
|
186
|
+
* reaches here (the gateway attaches to it via isInjectionLive); if one
|
|
187
|
+
* does, it is left registered — byCommand must keep routing its lifecycle
|
|
188
|
+
* frames and its terminal state drops it (see apply/fail) — and the
|
|
189
|
+
* anomaly is logged. Killing it is not an option: Claude Code starts a
|
|
190
|
+
* queued input on its own once the turn it was steered into ends, and the
|
|
191
|
+
* server, having recorded that `started` as delivered, would never re-run
|
|
192
|
+
* it (2026-09-17 prod loss).
|
|
184
193
|
*/
|
|
185
|
-
|
|
194
|
+
acknowledgeDiscardedInjection(sessionKey, deliveryKey) {
|
|
186
195
|
const state = this.processes.get(sessionKey);
|
|
187
196
|
if (!state)
|
|
188
197
|
return 'discarded';
|
|
189
198
|
const delivery = state.inputs.getByKey(deliveryKey);
|
|
190
199
|
if (delivery && !delivery.terminal) {
|
|
191
|
-
state.log?.warn?.(`
|
|
192
|
-
await this.killProcess(sessionKey, state);
|
|
193
|
-
state.inputs.discardBookkeeping(deliveryKey);
|
|
194
|
-
// 'cancelled' only when the server confirmed the failed receipt: the
|
|
195
|
-
// member is released and un-folded, so the gateway can re-fold and run
|
|
196
|
-
// it locally. A lost receipt (reportedState never reached 'failed') or
|
|
197
|
-
// a 'settled' answer (a reply effect already resolved the member)
|
|
198
|
-
// leaves nothing to re-run here — the lane complete releases an unread
|
|
199
|
-
// member for re-drive instead.
|
|
200
|
-
const confirmed = delivery.reportedState === 'failed' && delivery.terminal === 'failed';
|
|
201
|
-
if (!confirmed) {
|
|
202
|
-
state.log?.warn?.(`withdrawal of Claude input ${delivery.commandUuid} was not confirmed by the server (${delivery.terminal}); leaving the member to the lane complete`);
|
|
203
|
-
}
|
|
204
|
-
return confirmed ? 'cancelled' : 'discarded';
|
|
200
|
+
state.log?.warn?.(`buffered copy of Claude input ${delivery.commandUuid} (${delivery.reportedState ?? 'queued'}) on ${sessionKey} discarded while still live — keeping its registration; the runtime runs it as its own turn`);
|
|
205
201
|
}
|
|
206
202
|
state.inputs.discardBookkeeping(deliveryKey);
|
|
207
203
|
// The discarded copy may have been the last thing a lazy restart was
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-lifecycle.d.ts","sourceRoot":"","sources":["../src/input-lifecycle.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEnG,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC9C,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,YAAY,EAAE,OAAO,CAAC;IACtB,kFAAkF;IAClF,IAAI,EAAE,cAAc,CAAC;IACrB,uEAAuE;IACvE,QAAQ,EAAE,YAAY,CAAC;IACvB,6FAA6F;IAC7F,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,8DAA8D;IAC9D,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0C;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;IAEpE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAI9D,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIlE,eAAe,CAAC,gBAAgB,EAAE,MAAM,EAAE,GAAG,mBAAmB,GAAG,SAAS;IAU5E,MAAM,IAAI,gBAAgB,CAAC,mBAAmB,CAAC;IAI/C,oBAAoB,IAAI,OAAO;IAI/B;;;;;;;;;OASG;IACH,sBAAsB,IAAI,OAAO;IAIjC,QAAQ,CACN,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,sBAAsB,GAAG,SAAS,EAC7C,QAAQ,EAAE,OAAO,EACjB,YAAY,CAAC,EAAE,MAAM,IAAI,EACzB,GAAG,CAAC,EAAE,aAAa,GAClB,mBAAmB;IAsBtB,MAAM,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAY3C;;;;;;;;OAQG;IACH,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAOvC,KAAK,CACT,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACpE,OAAO,CAAC,IAAI,CAAC;IA0BV,IAAI,CAAC,QAAQ,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"input-lifecycle.d.ts","sourceRoot":"","sources":["../src/input-lifecycle.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEnG,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC9C,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,YAAY,EAAE,OAAO,CAAC;IACtB,kFAAkF;IAClF,IAAI,EAAE,cAAc,CAAC;IACrB,uEAAuE;IACvE,QAAQ,EAAE,YAAY,CAAC;IACvB,6FAA6F;IAC7F,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,8DAA8D;IAC9D,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0C;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;IAEpE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAI9D,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIlE,eAAe,CAAC,gBAAgB,EAAE,MAAM,EAAE,GAAG,mBAAmB,GAAG,SAAS;IAU5E,MAAM,IAAI,gBAAgB,CAAC,mBAAmB,CAAC;IAI/C,oBAAoB,IAAI,OAAO;IAI/B;;;;;;;;;OASG;IACH,sBAAsB,IAAI,OAAO;IAIjC,QAAQ,CACN,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,sBAAsB,GAAG,SAAS,EAC7C,QAAQ,EAAE,OAAO,EACjB,YAAY,CAAC,EAAE,MAAM,IAAI,EACzB,GAAG,CAAC,EAAE,aAAa,GAClB,mBAAmB;IAsBtB,MAAM,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAY3C;;;;;;;;OAQG;IACH,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAOvC,KAAK,CACT,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACpE,OAAO,CAAC,IAAI,CAAC;IA0BV,IAAI,CAAC,QAAQ,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiCnE,cAAc,CAClB,QAAQ,EAAE,mBAAmB,EAC7B,GAAG,CAAC,EAAE,aAAa,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAUV,iBAAiB,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAO7E"}
|
package/dist/input-lifecycle.js
CHANGED
|
@@ -136,7 +136,11 @@ export class ClaudeInputRegistry {
|
|
|
136
136
|
detail: detail ?? classified.detail ?? 'Claude input failed',
|
|
137
137
|
});
|
|
138
138
|
delivery.reportedState = 'failed';
|
|
139
|
-
|
|
139
|
+
// 'settled' only when the server answered and released nothing (a
|
|
140
|
+
// delivered or reply-resolved member); an unconfirmed receipt is not
|
|
141
|
+
// a settlement.
|
|
142
|
+
delivery.terminal =
|
|
143
|
+
result && !result.pending && result.retry === false ? 'settled' : 'failed';
|
|
140
144
|
}
|
|
141
145
|
}
|
|
142
146
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-outcome.d.ts","sourceRoot":"","sources":["../src/turn-outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"turn-outcome.d.ts","sourceRoot":"","sources":["../src/turn-outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAgD3D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CA8ChF;AAcD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAClC,WAAW,EAAE,MAAM,EAAE,EACrB,GAAG,GAAE,IAAiB,GACrB,gBAAgB,CA8ElB"}
|
package/dist/turn-outcome.js
CHANGED
|
@@ -5,13 +5,20 @@
|
|
|
5
5
|
* (api_error_status / terminal_reason / is_error), behavioral heuristics
|
|
6
6
|
* second (zero-usage synthetic turns), message regex last — and regex only
|
|
7
7
|
* ever refines a classification, so a CLI wording change degrades to the
|
|
8
|
-
* generic `
|
|
8
|
+
* generic `transient`, never to a wrong `ok` or a wrong deferral.
|
|
9
9
|
* Classification uncertainty must never defer: deferring a real message is
|
|
10
10
|
* costlier than losing one automatic recovery.
|
|
11
11
|
*/
|
|
12
12
|
const LIMIT_TEXT = /you'?ve (hit|reached) your .*limit|usage limit reached|weekly limit/i;
|
|
13
|
-
const AUTH_TEXT = /not logged in|please run \/login|authentication_error|invalid api key|oauth token (has )?expired|\[action required\]/i;
|
|
13
|
+
const AUTH_TEXT = /not logged in|please run \/login|authentication_error|authentication_failed|failed to authenticate|invalid api key|oauth (token|session) (has )?expired|\[action required\]/i;
|
|
14
14
|
const CONTEXT_TEXT = /prompt is too long|context (window|length) exceeded|request too large/i;
|
|
15
|
+
// A positively identified per-minute rate limit (agent-runtime-state-model-
|
|
16
|
+
// design.md §7.1): the API's own error type, never a plan / subscription
|
|
17
|
+
// limit notice. Only this wording moves a 429 off the deferred path.
|
|
18
|
+
const RATE_LIMIT_ERROR_TEXT = /rate_limit_error/i;
|
|
19
|
+
// Exhausted balance / quota (402): the sender must top up — an error, not a
|
|
20
|
+
// wait, so it takes the same path as auth.
|
|
21
|
+
const QUOTA_TEXT = /credit balance is too low|insufficient credits|insufficient_quota|payment required/i;
|
|
15
22
|
const DETAIL_MAX = 500;
|
|
16
23
|
/**
|
|
17
24
|
* Parse the reset time out of a limit notice like
|
|
@@ -136,9 +143,23 @@ export function classifyClaudeTurn(meta, noticeTexts, now = new Date()) {
|
|
|
136
143
|
// 1) Structured HTTP status.
|
|
137
144
|
if (meta.apiErrorStatus === 401 || meta.apiErrorStatus === 403)
|
|
138
145
|
return withDetail('auth');
|
|
146
|
+
if (meta.apiErrorStatus === 402)
|
|
147
|
+
return withDetail('quota_exhausted');
|
|
139
148
|
if (meta.apiErrorStatus === 413)
|
|
140
149
|
return withDetail('context_overflow');
|
|
141
150
|
if (meta.apiErrorStatus === 429) {
|
|
151
|
+
// A provider that answers an exhausted balance with 429 (OpenAI-style
|
|
152
|
+
// `insufficient_quota`) is a top-up problem, never a wait: quota
|
|
153
|
+
// evidence outranks both 429 readings below.
|
|
154
|
+
if (QUOTA_TEXT.test(evidence))
|
|
155
|
+
return withDetail('quota_exhausted');
|
|
156
|
+
// The CLI exposes only the status: a 429 that positively names the
|
|
157
|
+
// API's rate_limit_error is a short-backoff transient; every other 429
|
|
158
|
+
// (plan limits, no discernible text) stays a deferral — a wrong
|
|
159
|
+
// deferral costs a wait, a wrong "transient" on a real plan limit costs
|
|
160
|
+
// three fast retries and a dead letter.
|
|
161
|
+
if (RATE_LIMIT_ERROR_TEXT.test(evidence))
|
|
162
|
+
return withDetail('transient');
|
|
142
163
|
return withDetail('usage_limit', evidence ? parseClaudeResetTime(evidence, now) : undefined);
|
|
143
164
|
}
|
|
144
165
|
// 2) Text families — refine only; they can never turn a failure into ok.
|
|
@@ -158,6 +179,8 @@ export function classifyClaudeTurn(meta, noticeTexts, now = new Date()) {
|
|
|
158
179
|
if (failed || syntheticQuiet || noticeTexts.length > 0) {
|
|
159
180
|
if (CONTEXT_TEXT.test(evidence))
|
|
160
181
|
return withDetail('context_overflow');
|
|
182
|
+
if (QUOTA_TEXT.test(evidence))
|
|
183
|
+
return withDetail('quota_exhausted');
|
|
161
184
|
if (LIMIT_TEXT.test(evidence)) {
|
|
162
185
|
return withDetail('usage_limit', parseClaudeResetTime(evidence, now));
|
|
163
186
|
}
|
|
@@ -165,9 +188,9 @@ export function classifyClaudeTurn(meta, noticeTexts, now = new Date()) {
|
|
|
165
188
|
return withDetail('auth');
|
|
166
189
|
// Reached only when this block was entered (failed / syntheticQuiet /
|
|
167
190
|
// a captured synthetic notice) but no text family matched. A CLI wording
|
|
168
|
-
// change must degrade to
|
|
169
|
-
// a refused turn as success (the read-no-reply class
|
|
170
|
-
return withDetail('
|
|
191
|
+
// change must degrade to transient — never fall through to `ok` and
|
|
192
|
+
// settle a refused turn as success (the read-no-reply class).
|
|
193
|
+
return withDetail('transient');
|
|
171
194
|
}
|
|
172
195
|
return { ...base, outcome: 'ok' };
|
|
173
196
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/claude-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.66.0",
|
|
4
4
|
"description": "Claude Code bridge runtime for self-hosted Parall agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"src"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@parall/agent-core": "1.
|
|
29
|
-
"@parall/cli": "1.
|
|
30
|
-
"@parall/sdk": "1.
|
|
28
|
+
"@parall/agent-core": "1.66.0",
|
|
29
|
+
"@parall/cli": "1.66.0",
|
|
30
|
+
"@parall/sdk": "1.66.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.0.0",
|
package/src/dispatch.ts
CHANGED
|
@@ -262,44 +262,37 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
262
262
|
return state.inputs.hasUnsettledInjections();
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
isInjectionLive(sessionKey: string, deliveryKey: string): boolean {
|
|
266
|
+
const state = this.processes.get(sessionKey);
|
|
267
|
+
if (!state || state.done) return false;
|
|
268
|
+
const delivery = state.inputs.getByKey(deliveryKey);
|
|
269
|
+
if (!delivery || delivery.terminal) return false;
|
|
270
|
+
const { proc } = state.handle;
|
|
271
|
+
return proc.exitCode === null && proc.signalCode === null;
|
|
272
|
+
}
|
|
273
|
+
|
|
265
274
|
/**
|
|
266
275
|
* The gateway discarded the buffered copy of an injection without a
|
|
267
|
-
* dispatch(). A settled injection only owes bookkeeping.
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
* and let the gateway run it as a real turn.
|
|
276
|
+
* dispatch(). A settled injection only owes bookkeeping. A live one never
|
|
277
|
+
* reaches here (the gateway attaches to it via isInjectionLive); if one
|
|
278
|
+
* does, it is left registered — byCommand must keep routing its lifecycle
|
|
279
|
+
* frames and its terminal state drops it (see apply/fail) — and the
|
|
280
|
+
* anomaly is logged. Killing it is not an option: Claude Code starts a
|
|
281
|
+
* queued input on its own once the turn it was steered into ends, and the
|
|
282
|
+
* server, having recorded that `started` as delivered, would never re-run
|
|
283
|
+
* it (2026-09-17 prod loss).
|
|
276
284
|
*/
|
|
277
|
-
|
|
285
|
+
acknowledgeDiscardedInjection(
|
|
278
286
|
sessionKey: string,
|
|
279
287
|
deliveryKey: string,
|
|
280
|
-
):
|
|
288
|
+
): DiscardedInjectionOutcome {
|
|
281
289
|
const state = this.processes.get(sessionKey);
|
|
282
290
|
if (!state) return 'discarded';
|
|
283
291
|
const delivery = state.inputs.getByKey(deliveryKey);
|
|
284
292
|
if (delivery && !delivery.terminal) {
|
|
285
293
|
state.log?.warn?.(
|
|
286
|
-
`
|
|
294
|
+
`buffered copy of Claude input ${delivery.commandUuid} (${delivery.reportedState ?? 'queued'}) on ${sessionKey} discarded while still live — keeping its registration; the runtime runs it as its own turn`,
|
|
287
295
|
);
|
|
288
|
-
await this.killProcess(sessionKey, state);
|
|
289
|
-
state.inputs.discardBookkeeping(deliveryKey);
|
|
290
|
-
// 'cancelled' only when the server confirmed the failed receipt: the
|
|
291
|
-
// member is released and un-folded, so the gateway can re-fold and run
|
|
292
|
-
// it locally. A lost receipt (reportedState never reached 'failed') or
|
|
293
|
-
// a 'settled' answer (a reply effect already resolved the member)
|
|
294
|
-
// leaves nothing to re-run here — the lane complete releases an unread
|
|
295
|
-
// member for re-drive instead.
|
|
296
|
-
const confirmed = delivery.reportedState === 'failed' && delivery.terminal === 'failed';
|
|
297
|
-
if (!confirmed) {
|
|
298
|
-
state.log?.warn?.(
|
|
299
|
-
`withdrawal of Claude input ${delivery.commandUuid} was not confirmed by the server (${delivery.terminal}); leaving the member to the lane complete`,
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
return confirmed ? 'cancelled' : 'discarded';
|
|
303
296
|
}
|
|
304
297
|
state.inputs.discardBookkeeping(deliveryKey);
|
|
305
298
|
// The discarded copy may have been the last thing a lazy restart was
|
package/src/input-lifecycle.ts
CHANGED
|
@@ -190,7 +190,11 @@ export class ClaudeInputRegistry {
|
|
|
190
190
|
detail: detail ?? classified.detail ?? 'Claude input failed',
|
|
191
191
|
});
|
|
192
192
|
delivery.reportedState = 'failed';
|
|
193
|
-
|
|
193
|
+
// 'settled' only when the server answered and released nothing (a
|
|
194
|
+
// delivered or reply-resolved member); an unconfirmed receipt is not
|
|
195
|
+
// a settlement.
|
|
196
|
+
delivery.terminal =
|
|
197
|
+
result && !result.pending && result.retry === false ? 'settled' : 'failed';
|
|
194
198
|
}
|
|
195
199
|
} finally {
|
|
196
200
|
delivery.terminal ??= 'failed';
|
package/src/turn-outcome.ts
CHANGED
|
@@ -8,15 +8,23 @@ import type { ClaudeResultMeta } from './output-parser.js';
|
|
|
8
8
|
* (api_error_status / terminal_reason / is_error), behavioral heuristics
|
|
9
9
|
* second (zero-usage synthetic turns), message regex last — and regex only
|
|
10
10
|
* ever refines a classification, so a CLI wording change degrades to the
|
|
11
|
-
* generic `
|
|
11
|
+
* generic `transient`, never to a wrong `ok` or a wrong deferral.
|
|
12
12
|
* Classification uncertainty must never defer: deferring a real message is
|
|
13
13
|
* costlier than losing one automatic recovery.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
const LIMIT_TEXT = /you'?ve (hit|reached) your .*limit|usage limit reached|weekly limit/i;
|
|
17
17
|
const AUTH_TEXT =
|
|
18
|
-
/not logged in|please run \/login|authentication_error|invalid api key|oauth token (has )?expired|\[action required\]/i;
|
|
18
|
+
/not logged in|please run \/login|authentication_error|authentication_failed|failed to authenticate|invalid api key|oauth (token|session) (has )?expired|\[action required\]/i;
|
|
19
19
|
const CONTEXT_TEXT = /prompt is too long|context (window|length) exceeded|request too large/i;
|
|
20
|
+
// A positively identified per-minute rate limit (agent-runtime-state-model-
|
|
21
|
+
// design.md §7.1): the API's own error type, never a plan / subscription
|
|
22
|
+
// limit notice. Only this wording moves a 429 off the deferred path.
|
|
23
|
+
const RATE_LIMIT_ERROR_TEXT = /rate_limit_error/i;
|
|
24
|
+
// Exhausted balance / quota (402): the sender must top up — an error, not a
|
|
25
|
+
// wait, so it takes the same path as auth.
|
|
26
|
+
const QUOTA_TEXT =
|
|
27
|
+
/credit balance is too low|insufficient credits|insufficient_quota|payment required/i;
|
|
20
28
|
|
|
21
29
|
const DETAIL_MAX = 500;
|
|
22
30
|
|
|
@@ -139,8 +147,19 @@ export function classifyClaudeTurn(
|
|
|
139
147
|
|
|
140
148
|
// 1) Structured HTTP status.
|
|
141
149
|
if (meta.apiErrorStatus === 401 || meta.apiErrorStatus === 403) return withDetail('auth');
|
|
150
|
+
if (meta.apiErrorStatus === 402) return withDetail('quota_exhausted');
|
|
142
151
|
if (meta.apiErrorStatus === 413) return withDetail('context_overflow');
|
|
143
152
|
if (meta.apiErrorStatus === 429) {
|
|
153
|
+
// A provider that answers an exhausted balance with 429 (OpenAI-style
|
|
154
|
+
// `insufficient_quota`) is a top-up problem, never a wait: quota
|
|
155
|
+
// evidence outranks both 429 readings below.
|
|
156
|
+
if (QUOTA_TEXT.test(evidence)) return withDetail('quota_exhausted');
|
|
157
|
+
// The CLI exposes only the status: a 429 that positively names the
|
|
158
|
+
// API's rate_limit_error is a short-backoff transient; every other 429
|
|
159
|
+
// (plan limits, no discernible text) stays a deferral — a wrong
|
|
160
|
+
// deferral costs a wait, a wrong "transient" on a real plan limit costs
|
|
161
|
+
// three fast retries and a dead letter.
|
|
162
|
+
if (RATE_LIMIT_ERROR_TEXT.test(evidence)) return withDetail('transient');
|
|
144
163
|
return withDetail('usage_limit', evidence ? parseClaudeResetTime(evidence, now) : undefined);
|
|
145
164
|
}
|
|
146
165
|
|
|
@@ -162,15 +181,16 @@ export function classifyClaudeTurn(
|
|
|
162
181
|
(meta.durationApiMs ?? 0) === 0;
|
|
163
182
|
if (failed || syntheticQuiet || noticeTexts.length > 0) {
|
|
164
183
|
if (CONTEXT_TEXT.test(evidence)) return withDetail('context_overflow');
|
|
184
|
+
if (QUOTA_TEXT.test(evidence)) return withDetail('quota_exhausted');
|
|
165
185
|
if (LIMIT_TEXT.test(evidence)) {
|
|
166
186
|
return withDetail('usage_limit', parseClaudeResetTime(evidence, now));
|
|
167
187
|
}
|
|
168
188
|
if (AUTH_TEXT.test(evidence)) return withDetail('auth');
|
|
169
189
|
// Reached only when this block was entered (failed / syntheticQuiet /
|
|
170
190
|
// a captured synthetic notice) but no text family matched. A CLI wording
|
|
171
|
-
// change must degrade to
|
|
172
|
-
// a refused turn as success (the read-no-reply class
|
|
173
|
-
return withDetail('
|
|
191
|
+
// change must degrade to transient — never fall through to `ok` and
|
|
192
|
+
// settle a refused turn as success (the read-no-reply class).
|
|
193
|
+
return withDetail('transient');
|
|
174
194
|
}
|
|
175
195
|
|
|
176
196
|
return { ...base, outcome: 'ok' };
|