@crewhaus/recovery-engine 0.1.7 → 0.2.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 +14 -1
- package/dist/index.js +21 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
* user-aborted → fail("user_aborted") — orchestrator handles abort separately
|
|
13
13
|
* anything else → fail(message)
|
|
14
14
|
*
|
|
15
|
+
* Item 23 — `switch-model` is an OPT-IN `failure_taxonomy` recovery action
|
|
16
|
+
* (never a built-in `classify()` verdict, so default runs are byte-for-byte
|
|
17
|
+
* unchanged). It tells the orchestrator to route the same turn onto the
|
|
18
|
+
* next provider-failover candidate (open the active breaker so the chain
|
|
19
|
+
* reroutes) instead of exhausting backoff retries against a dead provider.
|
|
20
|
+
* Budgeted per turn like the others; a run without a failover chain treats
|
|
21
|
+
* it as a retry-shaped no-op re-issue (documented in runtime-core).
|
|
22
|
+
*
|
|
15
23
|
* References: claude-code/query.ts recovery branches; agent-framework
|
|
16
24
|
* _runner.py retry; AI-Harness-Systems §recovery.
|
|
17
25
|
*/
|
|
@@ -27,6 +35,8 @@ export type RecoveryAction = {
|
|
|
27
35
|
} | {
|
|
28
36
|
readonly kind: "tombstone";
|
|
29
37
|
readonly messageId?: string;
|
|
38
|
+
} | {
|
|
39
|
+
readonly kind: "switch-model";
|
|
30
40
|
} | {
|
|
31
41
|
readonly kind: "fail";
|
|
32
42
|
readonly reason: string;
|
|
@@ -41,6 +51,8 @@ export type RecoveryState = {
|
|
|
41
51
|
readonly continueCount: number;
|
|
42
52
|
/** Number of `tombstone` actions already chosen in this turn. */
|
|
43
53
|
readonly tombstoneCount: number;
|
|
54
|
+
/** Item 23 — number of `switch-model` actions already chosen this turn. */
|
|
55
|
+
readonly switchModelCount: number;
|
|
44
56
|
};
|
|
45
57
|
export declare const initialRecoveryState: RecoveryState;
|
|
46
58
|
export declare class RecoveryEngineError extends CrewhausError {
|
|
@@ -71,7 +83,7 @@ export declare function classify(error: unknown): RecoveryErrorClass;
|
|
|
71
83
|
export type NamedFailureClass = {
|
|
72
84
|
readonly class: string;
|
|
73
85
|
readonly pattern: string;
|
|
74
|
-
readonly recovery: "retry" | "compact" | "continue" | "tombstone" | "fail";
|
|
86
|
+
readonly recovery: "retry" | "compact" | "continue" | "tombstone" | "switch-model" | "fail";
|
|
75
87
|
readonly hint?: string;
|
|
76
88
|
};
|
|
77
89
|
/**
|
|
@@ -101,6 +113,7 @@ export declare const BUDGETS: {
|
|
|
101
113
|
readonly MAX_COMPACTS: 1;
|
|
102
114
|
readonly MAX_CONTINUES: 3;
|
|
103
115
|
readonly MAX_TOMBSTONES: 1;
|
|
116
|
+
readonly MAX_SWITCH_MODELS: 3;
|
|
104
117
|
readonly BASE_BACKOFF_MS: 1000;
|
|
105
118
|
readonly MAX_BACKOFF_MS: 30000;
|
|
106
119
|
readonly MAX_JITTER_MS: 250;
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
* user-aborted → fail("user_aborted") — orchestrator handles abort separately
|
|
13
13
|
* anything else → fail(message)
|
|
14
14
|
*
|
|
15
|
+
* Item 23 — `switch-model` is an OPT-IN `failure_taxonomy` recovery action
|
|
16
|
+
* (never a built-in `classify()` verdict, so default runs are byte-for-byte
|
|
17
|
+
* unchanged). It tells the orchestrator to route the same turn onto the
|
|
18
|
+
* next provider-failover candidate (open the active breaker so the chain
|
|
19
|
+
* reroutes) instead of exhausting backoff retries against a dead provider.
|
|
20
|
+
* Budgeted per turn like the others; a run without a failover chain treats
|
|
21
|
+
* it as a retry-shaped no-op re-issue (documented in runtime-core).
|
|
22
|
+
*
|
|
15
23
|
* References: claude-code/query.ts recovery branches; agent-framework
|
|
16
24
|
* _runner.py retry; AI-Harness-Systems §recovery.
|
|
17
25
|
*/
|
|
@@ -21,6 +29,7 @@ export const initialRecoveryState = {
|
|
|
21
29
|
compactCount: 0,
|
|
22
30
|
continueCount: 0,
|
|
23
31
|
tombstoneCount: 0,
|
|
32
|
+
switchModelCount: 0,
|
|
24
33
|
};
|
|
25
34
|
export class RecoveryEngineError extends CrewhausError {
|
|
26
35
|
name = "RecoveryEngineError";
|
|
@@ -32,6 +41,10 @@ const MAX_RETRIES = 5;
|
|
|
32
41
|
const MAX_COMPACTS = 1;
|
|
33
42
|
const MAX_CONTINUES = 3;
|
|
34
43
|
const MAX_TOMBSTONES = 1;
|
|
44
|
+
// Item 23 — cap `switch-model` hops per turn. Generous enough to walk a
|
|
45
|
+
// short failover chain (primary → fallback → fallback), low enough that a
|
|
46
|
+
// mutually-degraded chain fails the turn instead of looping forever.
|
|
47
|
+
const MAX_SWITCH_MODELS = 3;
|
|
35
48
|
const BASE_BACKOFF_MS = 1_000;
|
|
36
49
|
const MAX_BACKOFF_MS = 30_000;
|
|
37
50
|
const MAX_JITTER_MS = 250;
|
|
@@ -202,6 +215,11 @@ function recoverNamed(named, state) {
|
|
|
202
215
|
return { kind: "fail", reason: `tombstone budget exhausted: ${reason}` };
|
|
203
216
|
}
|
|
204
217
|
return { kind: "tombstone" };
|
|
218
|
+
case "switch-model":
|
|
219
|
+
if (state.switchModelCount >= MAX_SWITCH_MODELS) {
|
|
220
|
+
return { kind: "fail", reason: `switch-model budget exhausted: ${reason}` };
|
|
221
|
+
}
|
|
222
|
+
return { kind: "switch-model" };
|
|
205
223
|
case "fail":
|
|
206
224
|
return { kind: "fail", reason };
|
|
207
225
|
}
|
|
@@ -220,6 +238,8 @@ export function advanceState(state, action) {
|
|
|
220
238
|
return { ...state, continueCount: state.continueCount + 1 };
|
|
221
239
|
case "tombstone":
|
|
222
240
|
return { ...state, tombstoneCount: state.tombstoneCount + 1 };
|
|
241
|
+
case "switch-model":
|
|
242
|
+
return { ...state, switchModelCount: state.switchModelCount + 1 };
|
|
223
243
|
case "fail":
|
|
224
244
|
return state;
|
|
225
245
|
}
|
|
@@ -230,6 +250,7 @@ export const BUDGETS = {
|
|
|
230
250
|
MAX_COMPACTS,
|
|
231
251
|
MAX_CONTINUES,
|
|
232
252
|
MAX_TOMBSTONES,
|
|
253
|
+
MAX_SWITCH_MODELS,
|
|
233
254
|
BASE_BACKOFF_MS,
|
|
234
255
|
MAX_BACKOFF_MS,
|
|
235
256
|
MAX_JITTER_MS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewhaus/recovery-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pure recovery taxonomy: classify Anthropic API errors into a RecoveryAction (compact/retry/continue/tombstone/fail)",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"test": "bun test src"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@crewhaus/errors": "0.
|
|
18
|
+
"@crewhaus/errors": "0.2.0"
|
|
19
19
|
},
|
|
20
20
|
"license": "Apache-2.0",
|
|
21
21
|
"author": {
|