@sensigo/realm-cli 0.38.0 → 0.40.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/agent/drive-failure.d.ts +62 -0
- package/dist/agent/drive-failure.d.ts.map +1 -0
- package/dist/agent/drive-failure.js +241 -0
- package/dist/agent/drive-failure.js.map +1 -0
- package/dist/agent/providers/agent-utils.d.ts +132 -0
- package/dist/agent/providers/agent-utils.d.ts.map +1 -1
- package/dist/agent/providers/agent-utils.js +348 -1
- package/dist/agent/providers/agent-utils.js.map +1 -1
- package/dist/agent/providers/anthropic-provider.d.ts +51 -1
- package/dist/agent/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/agent/providers/anthropic-provider.js +109 -30
- package/dist/agent/providers/anthropic-provider.js.map +1 -1
- package/dist/agent/providers/llm-provider.d.ts +13 -1
- package/dist/agent/providers/llm-provider.d.ts.map +1 -1
- package/dist/agent/providers/llm-provider.js +8 -4
- package/dist/agent/providers/llm-provider.js.map +1 -1
- package/dist/agent/providers/openai-provider.d.ts +6 -1
- package/dist/agent/providers/openai-provider.d.ts.map +1 -1
- package/dist/agent/providers/openai-provider.js +75 -20
- package/dist/agent/providers/openai-provider.js.map +1 -1
- package/dist/agent/providers/openai-reasoning-provider.d.ts +4 -1
- package/dist/agent/providers/openai-reasoning-provider.d.ts.map +1 -1
- package/dist/agent/providers/openai-reasoning-provider.js +21 -6
- package/dist/agent/providers/openai-reasoning-provider.js.map +1 -1
- package/dist/agent/run-agent.d.ts +9 -0
- package/dist/agent/run-agent.d.ts.map +1 -1
- package/dist/agent/run-agent.js +775 -680
- package/dist/agent/run-agent.js.map +1 -1
- package/dist/agent/run-attach.d.ts.map +1 -1
- package/dist/agent/run-attach.js +58 -11
- package/dist/agent/run-attach.js.map +1 -1
- package/dist/agent/test-support/anthropic-stub.d.ts +45 -0
- package/dist/agent/test-support/anthropic-stub.d.ts.map +1 -0
- package/dist/agent/test-support/anthropic-stub.js +146 -0
- package/dist/agent/test-support/anthropic-stub.js.map +1 -0
- package/dist/agent/test-support/composed-journey.d.ts +40 -0
- package/dist/agent/test-support/composed-journey.d.ts.map +1 -0
- package/dist/agent/test-support/composed-journey.js +104 -0
- package/dist/agent/test-support/composed-journey.js.map +1 -0
- package/dist/agent/test-support/mcp-server-entry.d.ts +20 -0
- package/dist/agent/test-support/mcp-server-entry.d.ts.map +1 -0
- package/dist/agent/test-support/mcp-server-entry.js +39 -0
- package/dist/agent/test-support/mcp-server-entry.js.map +1 -0
- package/dist/agent/test-support/openai-stub.d.ts +47 -0
- package/dist/agent/test-support/openai-stub.d.ts.map +1 -0
- package/dist/agent/test-support/openai-stub.js +115 -0
- package/dist/agent/test-support/openai-stub.js.map +1 -0
- package/dist/commands/abandon.d.ts.map +1 -1
- package/dist/commands/abandon.js +8 -1
- package/dist/commands/abandon.js.map +1 -1
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +17 -0
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/cleanup.d.ts.map +1 -1
- package/dist/commands/cleanup.js +21 -9
- package/dist/commands/cleanup.js.map +1 -1
- package/dist/commands/export.d.ts +5 -2
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +1 -1
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/gc.d.ts +1 -1
- package/dist/commands/gc.d.ts.map +1 -1
- package/dist/commands/gc.js +29 -4
- package/dist/commands/gc.js.map +1 -1
- package/dist/commands/inspect.d.ts.map +1 -1
- package/dist/commands/inspect.js +86 -1
- package/dist/commands/inspect.js.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +35 -0
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/listen.d.ts.map +1 -1
- package/dist/commands/listen.js +9 -5
- package/dist/commands/listen.js.map +1 -1
- package/dist/commands/purge.d.ts +22 -1
- package/dist/commands/purge.d.ts.map +1 -1
- package/dist/commands/purge.js +70 -42
- package/dist/commands/purge.js.map +1 -1
- package/dist/commands/register.d.ts.map +1 -1
- package/dist/commands/register.js +3 -1
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/run-migrate.d.ts +83 -0
- package/dist/commands/run-migrate.d.ts.map +1 -0
- package/dist/commands/run-migrate.js +303 -0
- package/dist/commands/run-migrate.js.map +1 -0
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +7 -5
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +6 -4
- package/dist/commands/watch.js.map +1 -1
- package/dist/commands-registry.d.ts.map +1 -1
- package/dist/commands-registry.js +4 -0
- package/dist/commands-registry.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/loader-warnings.d.ts +22 -1
- package/dist/lib/loader-warnings.d.ts.map +1 -1
- package/dist/lib/loader-warnings.js +42 -2
- package/dist/lib/loader-warnings.js.map +1 -1
- package/package.json +5 -4
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type DriveFailureRecord, type RunStore } from '@sensigo/realm';
|
|
2
|
+
/**
|
|
3
|
+
* Messages are capped so one enormous provider error cannot dominate a run record. Exported so
|
|
4
|
+
* run-agent's own validation mint uses THIS number rather than a second literal that could drift.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MESSAGE_CAP = 500;
|
|
7
|
+
/**
|
|
8
|
+
* What a provider attaches to an error it throws, when it knows more than the error itself says.
|
|
9
|
+
* A plain property on the SAME object, which is what survives every wrap point in the providers.
|
|
10
|
+
*/
|
|
11
|
+
export interface DriveCallPayload {
|
|
12
|
+
error_class?: DriveFailureRecord['error_class'];
|
|
13
|
+
attempts_sdk?: number;
|
|
14
|
+
elapsed_ms?: number;
|
|
15
|
+
last_observed_status?: number;
|
|
16
|
+
retry_after_observed_ms?: number;
|
|
17
|
+
declared_per_attempt_ms?: number;
|
|
18
|
+
derived_ceiling_ms?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Walks the cause chain looking for an attached payload, PAYLOAD-FIRST and depth-bounded.
|
|
22
|
+
*
|
|
23
|
+
* The walk is the point: a provider's retry ladder wraps the original error in another one, so the
|
|
24
|
+
* payload that knows what actually happened is a `cause` or two down. Reading only the outermost
|
|
25
|
+
* error would classify every wrapped failure as `other`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function findDriveCall(err: unknown): DriveCallPayload | undefined;
|
|
28
|
+
export declare function classifyDriveError(err: unknown): DriveCallPayload & {
|
|
29
|
+
error_class: DriveFailureRecord['error_class'];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Builds the record for one failed attempt.
|
|
33
|
+
*
|
|
34
|
+
* TOTAL BY CONSTRUCTION, and this is not defensive habit — it closes a real hole. `buildEntry`
|
|
35
|
+
* runs OUTSIDE the fence's try at every chokepoint, and every step of it touches the thrown value:
|
|
36
|
+
* `classifyDriveError` reads `err.name` (a throwing getter throws here), `findDriveCall` does
|
|
37
|
+
* `'driveCall' in e` (a proxy with a `has` trap throws), and `sanitizeError` calls `String(err)`
|
|
38
|
+
* (a poisoned `toString` throws). A hostile thrown object would therefore make the MINT throw
|
|
39
|
+
* from inside a catch — replacing the operator's actual error with a secondary one, and at
|
|
40
|
+
* chokepoints (1)/(2) escalating it to (3), which would then re-mint against the WRONG error.
|
|
41
|
+
*
|
|
42
|
+
* So: the mint must never out-throw the failure it records. When the value cannot be rendered,
|
|
43
|
+
* the degraded entry below carries all six required fields and says plainly that it could not.
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildEntry(err: unknown, step: string, provider: string, attemptStartedAt: number): DriveFailureRecord;
|
|
46
|
+
/** The one loud line printed when a failure could not be recorded — never replaces the original. */
|
|
47
|
+
export declare function lostLine(runId: string, entry: DriveFailureRecord): string;
|
|
48
|
+
/**
|
|
49
|
+
* THE FENCE. Appends one entry to the run's drive-failure ring, and never lets its own failure
|
|
50
|
+
* become the operator's problem.
|
|
51
|
+
*
|
|
52
|
+
* Everything here is subordinate to one rule: this must never replace, hide, or crash on top of
|
|
53
|
+
* the operator's actual error. So a terminal run is a silent skip (the seal is already the
|
|
54
|
+
* visibility), a vanished run is a silent skip (disposal is the visibility), contention is
|
|
55
|
+
* retried, and anything else prints ONE line naming exactly what was lost.
|
|
56
|
+
*
|
|
57
|
+
* That line lands BESIDE the original, not always after it: chokepoints (1), (2) and (4) print
|
|
58
|
+
* their error first, so the lost line follows — but chokepoint (3) mints BEFORE its re-throw
|
|
59
|
+
* reaches the CLI's printer, so there the lost line comes first. Either way the operator has both.
|
|
60
|
+
*/
|
|
61
|
+
export declare function recordDriveFailure(store: Pick<RunStore, 'get' | 'update'>, runId: string, entry: DriveFailureRecord): Promise<void>;
|
|
62
|
+
//# sourceMappingURL=drive-failure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive-failure.d.ts","sourceRoot":"","sources":["../../src/agent/drive-failure.ts"],"names":[],"mappings":"AAaA,OAAO,EAEL,KAAK,kBAAkB,EAEvB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAKxB;;;GAGG;AACH,eAAO,MAAM,WAAW,MAAM,CAAC;AAM/B;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CASxE;AAoDD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG;IACnE,WAAW,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC;CAChD,CA4BA;AAqBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GACvB,kBAAkB,CAapB;AAuBD,oGAAoG;AACpG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAEzE;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC,EACvC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,IAAI,CAAC,CAmCf"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// drive-failure.ts — recording a failed drive attempt on the run (issue #401).
|
|
2
|
+
//
|
|
3
|
+
// THE PROBLEM. Any failure while `realm agent` drives a step — a connection error, a timeout, an
|
|
4
|
+
// MCP discovery failure, a missing SDK, an engine throw mid-loop, a schema-rejection wedge — used
|
|
5
|
+
// to write NOTHING to the store. The console said what happened and the process exited; the run
|
|
6
|
+
// read healthy on every operator surface until `never_claimed_idle` noticed 24 hours later.
|
|
7
|
+
//
|
|
8
|
+
// THE INVARIANT this module serves: a failed drive attempt on an EXISTING run, whose process
|
|
9
|
+
// survives to a catch inside `runAgent`, is visible on every operator surface within one minute.
|
|
10
|
+
//
|
|
11
|
+
// The write itself is what makes that true twice over: it records the failure AND, because
|
|
12
|
+
// `update()` bumps `version`/`updated_at`, it resets the idle clock — so the run stops looking
|
|
13
|
+
// untouched at exactly the moment it stopped being driven.
|
|
14
|
+
import { WorkflowError, } from '@sensigo/realm';
|
|
15
|
+
import { sanitizeError, extractHttpStatus } from './providers/agent-utils.js';
|
|
16
|
+
/** At most this many entries are retained, most-recent-last. */
|
|
17
|
+
const RING_CAP = 5;
|
|
18
|
+
/**
|
|
19
|
+
* Messages are capped so one enormous provider error cannot dominate a run record. Exported so
|
|
20
|
+
* run-agent's own validation mint uses THIS number rather than a second literal that could drift.
|
|
21
|
+
*/
|
|
22
|
+
export const MESSAGE_CAP = 500;
|
|
23
|
+
/** How deep the cause chain is walked looking for a payload. */
|
|
24
|
+
const CAUSE_DEPTH = 8;
|
|
25
|
+
/** How many times the fence re-reads and re-applies before giving up loudly. */
|
|
26
|
+
const WRITE_ATTEMPTS = 3;
|
|
27
|
+
/**
|
|
28
|
+
* Walks the cause chain looking for an attached payload, PAYLOAD-FIRST and depth-bounded.
|
|
29
|
+
*
|
|
30
|
+
* The walk is the point: a provider's retry ladder wraps the original error in another one, so the
|
|
31
|
+
* payload that knows what actually happened is a `cause` or two down. Reading only the outermost
|
|
32
|
+
* error would classify every wrapped failure as `other`.
|
|
33
|
+
*/
|
|
34
|
+
export function findDriveCall(err) {
|
|
35
|
+
let e = err;
|
|
36
|
+
for (let depth = 0; e != null && depth < CAUSE_DEPTH; depth++) {
|
|
37
|
+
if (typeof e === 'object' && 'driveCall' in e) {
|
|
38
|
+
return e.driveCall;
|
|
39
|
+
}
|
|
40
|
+
e = e.cause;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Classifies a thrown error, in strict precedence order.
|
|
46
|
+
*
|
|
47
|
+
* 1. an attached payload — the producer knew more than the error's shape says, so it wins;
|
|
48
|
+
* 2. the SDK's own error names — `APIConnectionTimeoutError` is a timeout even if a status is also
|
|
49
|
+
* somehow present, which is why the name is checked before the status;
|
|
50
|
+
* 3. an HTTP status, which also carries the status VALUE forward as a discriminator;
|
|
51
|
+
* 4. `other`.
|
|
52
|
+
*/
|
|
53
|
+
const ERROR_CLASSES = new Set([
|
|
54
|
+
'connection_timeout',
|
|
55
|
+
'connection_error',
|
|
56
|
+
'api_status',
|
|
57
|
+
'sdk_missing',
|
|
58
|
+
'validation_rejected',
|
|
59
|
+
'aborted_by_budget',
|
|
60
|
+
'other',
|
|
61
|
+
]);
|
|
62
|
+
const NUMERIC_PAYLOAD_FIELDS = [
|
|
63
|
+
'attempts_sdk',
|
|
64
|
+
'elapsed_ms',
|
|
65
|
+
'last_observed_status',
|
|
66
|
+
'retry_after_observed_ms',
|
|
67
|
+
'declared_per_attempt_ms',
|
|
68
|
+
'derived_ceiling_ms',
|
|
69
|
+
];
|
|
70
|
+
/**
|
|
71
|
+
* Picks the known fields out of an attached payload, key-filtered and typeof-checked.
|
|
72
|
+
*
|
|
73
|
+
* The payload is an UNTYPED boundary into a record realm persists, so a raw spread would let any
|
|
74
|
+
* key a provider happened to attach land in the store forever. Filtering is per FIELD, not
|
|
75
|
+
* whole-payload: the numbers are measurements and are kept when they are numbers, while the class
|
|
76
|
+
* is a CLAIM — an out-of-union value is dropped and shape classification decides instead.
|
|
77
|
+
*/
|
|
78
|
+
function pickPayload(payload) {
|
|
79
|
+
const out = {};
|
|
80
|
+
for (const field of NUMERIC_PAYLOAD_FIELDS) {
|
|
81
|
+
const value = payload[field];
|
|
82
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
83
|
+
out[field] = value;
|
|
84
|
+
}
|
|
85
|
+
const cls = payload['error_class'];
|
|
86
|
+
if (typeof cls === 'string' && ERROR_CLASSES.has(cls))
|
|
87
|
+
out['error_class'] = cls;
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
export function classifyDriveError(err) {
|
|
91
|
+
const payload = findDriveCall(err);
|
|
92
|
+
if (payload !== undefined) {
|
|
93
|
+
const picked = pickPayload(payload);
|
|
94
|
+
// A payload whose class did not survive the pick falls through to shape classification —
|
|
95
|
+
// the measurements it carried are still kept.
|
|
96
|
+
return { error_class: picked.error_class ?? shapeClassify(err), ...picked };
|
|
97
|
+
}
|
|
98
|
+
// `constructor.name`, not just `.name`: neither installed SDK sets `.name` on its error
|
|
99
|
+
// classes, so a real connection failure or request timeout reports `name === 'Error'` and was
|
|
100
|
+
// recorded as `other` — the two classes an operator most needs told apart from a hang, silently
|
|
101
|
+
// collapsed. `.name` is kept for wrappers that re-throw with a copied name. Deliberately NOT
|
|
102
|
+
// wrapped in try/catch: `buildEntry`'s own catch is this path's totality, and a hostile value
|
|
103
|
+
// that throws here is meant to reach it.
|
|
104
|
+
const name = err?.name;
|
|
105
|
+
const ctor = err?.constructor?.name;
|
|
106
|
+
if (name === 'APIConnectionTimeoutError' || ctor === 'APIConnectionTimeoutError') {
|
|
107
|
+
return { error_class: 'connection_timeout' };
|
|
108
|
+
}
|
|
109
|
+
if (name === 'APIConnectionError' || ctor === 'APIConnectionError') {
|
|
110
|
+
return { error_class: 'connection_error' };
|
|
111
|
+
}
|
|
112
|
+
const status = extractHttpStatus(err);
|
|
113
|
+
if (status !== undefined)
|
|
114
|
+
return { error_class: 'api_status', last_observed_status: status };
|
|
115
|
+
return { error_class: 'other' };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The class an error's SHAPE implies, for a payload whose own claim did not survive the pick.
|
|
119
|
+
*
|
|
120
|
+
* The same constructor check as the arm above, and the easiest of the three to overlook: a
|
|
121
|
+
* payload carrying measurements but no usable class lands here, so leaving it on `.name` would
|
|
122
|
+
* have kept the whole defect alive on that one path. Same totality boundary — `buildEntry`'s
|
|
123
|
+
* catch, not a guard here.
|
|
124
|
+
*/
|
|
125
|
+
function shapeClassify(err) {
|
|
126
|
+
const name = err?.name;
|
|
127
|
+
const ctor = err?.constructor?.name;
|
|
128
|
+
if (name === 'APIConnectionTimeoutError' || ctor === 'APIConnectionTimeoutError') {
|
|
129
|
+
return 'connection_timeout';
|
|
130
|
+
}
|
|
131
|
+
if (name === 'APIConnectionError' || ctor === 'APIConnectionError')
|
|
132
|
+
return 'connection_error';
|
|
133
|
+
if (extractHttpStatus(err) !== undefined)
|
|
134
|
+
return 'api_status';
|
|
135
|
+
return 'other';
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Builds the record for one failed attempt.
|
|
139
|
+
*
|
|
140
|
+
* TOTAL BY CONSTRUCTION, and this is not defensive habit — it closes a real hole. `buildEntry`
|
|
141
|
+
* runs OUTSIDE the fence's try at every chokepoint, and every step of it touches the thrown value:
|
|
142
|
+
* `classifyDriveError` reads `err.name` (a throwing getter throws here), `findDriveCall` does
|
|
143
|
+
* `'driveCall' in e` (a proxy with a `has` trap throws), and `sanitizeError` calls `String(err)`
|
|
144
|
+
* (a poisoned `toString` throws). A hostile thrown object would therefore make the MINT throw
|
|
145
|
+
* from inside a catch — replacing the operator's actual error with a secondary one, and at
|
|
146
|
+
* chokepoints (1)/(2) escalating it to (3), which would then re-mint against the WRONG error.
|
|
147
|
+
*
|
|
148
|
+
* So: the mint must never out-throw the failure it records. When the value cannot be rendered,
|
|
149
|
+
* the degraded entry below carries all six required fields and says plainly that it could not.
|
|
150
|
+
*/
|
|
151
|
+
export function buildEntry(err, step, provider, attemptStartedAt) {
|
|
152
|
+
try {
|
|
153
|
+
return buildEntryUnsafe(err, step, provider, attemptStartedAt);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return {
|
|
157
|
+
at: new Date().toISOString(),
|
|
158
|
+
step,
|
|
159
|
+
provider,
|
|
160
|
+
error_class: 'other',
|
|
161
|
+
message: 'unrenderable thrown value',
|
|
162
|
+
elapsed_ms: Date.now() - attemptStartedAt,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function buildEntryUnsafe(err, step, provider, attemptStartedAt) {
|
|
167
|
+
const classified = classifyDriveError(err);
|
|
168
|
+
return {
|
|
169
|
+
at: new Date().toISOString(),
|
|
170
|
+
step,
|
|
171
|
+
provider,
|
|
172
|
+
message: sanitizeError(err).slice(0, MESSAGE_CAP),
|
|
173
|
+
// The spread goes ABOVE the computed span deliberately (issue #401): a payload key that is
|
|
174
|
+
// PRESENT but undefined-valued would otherwise clobber a real measurement with nothing. With
|
|
175
|
+
// this order the `??` below is the live protector of a payload's genuine 0ms span, which also
|
|
176
|
+
// makes an `||` there a caught mutant rather than an equivalent one.
|
|
177
|
+
...classified,
|
|
178
|
+
elapsed_ms: classified.elapsed_ms ?? Date.now() - attemptStartedAt,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/** The one loud line printed when a failure could not be recorded — never replaces the original. */
|
|
182
|
+
export function lostLine(runId, entry) {
|
|
183
|
+
return `⚠ drive-failure record LOST for run ${runId} (${entry.error_class} at ${entry.at}, step '${entry.step}'): ${entry.message}`;
|
|
184
|
+
}
|
|
185
|
+
function workflowErrorCode(err) {
|
|
186
|
+
return err instanceof WorkflowError ? err.code : undefined;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* THE FENCE. Appends one entry to the run's drive-failure ring, and never lets its own failure
|
|
190
|
+
* become the operator's problem.
|
|
191
|
+
*
|
|
192
|
+
* Everything here is subordinate to one rule: this must never replace, hide, or crash on top of
|
|
193
|
+
* the operator's actual error. So a terminal run is a silent skip (the seal is already the
|
|
194
|
+
* visibility), a vanished run is a silent skip (disposal is the visibility), contention is
|
|
195
|
+
* retried, and anything else prints ONE line naming exactly what was lost.
|
|
196
|
+
*
|
|
197
|
+
* That line lands BESIDE the original, not always after it: chokepoints (1), (2) and (4) print
|
|
198
|
+
* their error first, so the lost line follows — but chokepoint (3) mints BEFORE its re-throw
|
|
199
|
+
* reaches the CLI's printer, so there the lost line comes first. Either way the operator has both.
|
|
200
|
+
*/
|
|
201
|
+
export async function recordDriveFailure(store, runId, entry) {
|
|
202
|
+
try {
|
|
203
|
+
for (let i = 0; i < WRITE_ATTEMPTS; i++) {
|
|
204
|
+
const run = await store.get(runId);
|
|
205
|
+
// A sealed run already tells its story; adding to it would be noise, and writing to it
|
|
206
|
+
// would reopen a settled record.
|
|
207
|
+
if (run.terminal_state)
|
|
208
|
+
return;
|
|
209
|
+
const prev = run.drive_failures;
|
|
210
|
+
const field = {
|
|
211
|
+
first_failed_at: prev?.first_failed_at ?? entry.at,
|
|
212
|
+
// Monotonic and OUTSIDE the ring: a run that failed forty times must not read as five.
|
|
213
|
+
total: (prev?.total ?? 0) + 1,
|
|
214
|
+
entries: [...(prev?.entries ?? []), entry].slice(-RING_CAP),
|
|
215
|
+
};
|
|
216
|
+
try {
|
|
217
|
+
// The record carries its own CAS version, read a few lines above. `update()` bumps
|
|
218
|
+
// version and updated_at — the latter is what resets the idle clock.
|
|
219
|
+
await store.update({ ...run, drive_failures: field });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
const code = workflowErrorCode(err);
|
|
224
|
+
// Contention, either flavour: re-read and re-apply against the newer record.
|
|
225
|
+
if (code === 'STATE_SNAPSHOT_MISMATCH' || code === 'STATE_RUN_BUSY')
|
|
226
|
+
continue;
|
|
227
|
+
if (code === 'STATE_RUN_NOT_FOUND')
|
|
228
|
+
return; // concurrently purged — disposal is visibility
|
|
229
|
+
throw err;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Lost to contention after every retry.
|
|
233
|
+
console.error(lostLine(runId, entry));
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
if (workflowErrorCode(err) === 'STATE_RUN_NOT_FOUND')
|
|
237
|
+
return;
|
|
238
|
+
console.error(lostLine(runId, entry));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=drive-failure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive-failure.js","sourceRoot":"","sources":["../../src/agent/drive-failure.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,20 @@ export declare function setAdditionalRedactionValues(values: readonly string[]):
|
|
|
16
16
|
* (manifest-secret) values. All literal values are redacted in ONE combined pass,
|
|
17
17
|
* deduped and applied LONGEST-FIRST — a short value contained in a longer one can no
|
|
18
18
|
* longer leave fragments of the longer value behind.
|
|
19
|
+
*
|
|
20
|
+
* EXCLUDED from the env sweep (issue #407): npm's own manifest metadata —
|
|
21
|
+
* `npm_package_*` (except `npm_package_config_*`) and `npm_lifecycle_*`. These are values npm
|
|
22
|
+
* copies OUT OF package.json, so treating them as secrets meant realm redacted its own name and
|
|
23
|
+
* version from its own error messages: under npm, `npm_package_name` is `"realm"`, and a message
|
|
24
|
+
* reading "realm agent requires…" shipped as "[REDACTED] agent requires…". Harmless while it was
|
|
25
|
+
* console-only; issue #401 persists these messages in the run record, which made the mangling
|
|
26
|
+
* durable evidence.
|
|
27
|
+
*
|
|
28
|
+
* `npm_package_config_*` deliberately STAYS redacted, and the lookahead that keeps it in is
|
|
29
|
+
* load-bearing: a package.json `config` block holds values the AUTHOR wrote, and npm exports them
|
|
30
|
+
* verbatim — a probe on this repo produced `npm_package_config_apitoken=SUPERSECRETVALUE123`.
|
|
31
|
+
* `npm_config_*` stays for the same reason. Widening this exclusion to all `npm_*` would leak
|
|
32
|
+
* exactly the values most likely to be secrets.
|
|
19
33
|
*/
|
|
20
34
|
export declare function sanitizeError(err: unknown): string;
|
|
21
35
|
/**
|
|
@@ -23,6 +37,32 @@ export declare function sanitizeError(err: unknown): string;
|
|
|
23
37
|
* as sanitizeError to strip any tokens that upstream services may have echoed.
|
|
24
38
|
*/
|
|
25
39
|
export declare function serializeToolResult(result: unknown): string;
|
|
40
|
+
/** The `error` text for a Class-B result whose content carries no readable text at all. */
|
|
41
|
+
export declare const CLASS_B_NO_TEXT_MARKER = "tool returned isError with no text content";
|
|
42
|
+
/**
|
|
43
|
+
* Extracts the failure text from a POLITELY FAILED tool call — issue #345.
|
|
44
|
+
*
|
|
45
|
+
* MCP defines two ways a tool call fails. The transport can reject (Class A: an exception, which
|
|
46
|
+
* the providers' catch branch already records honestly), or the call can RETURN normally with
|
|
47
|
+
* `isError: true` inside the result (Class B: the polite failure the spec defines for a tool
|
|
48
|
+
* reporting its own error to the model). Class B used to be minted as a success — no `error`
|
|
49
|
+
* field, the failure text buried inside `result` — which made the record type's own doc contract
|
|
50
|
+
* false and made every tool-reliability count read failures as successes.
|
|
51
|
+
*
|
|
52
|
+
* Returns the sanitized failure text for a Class-B result, or `undefined` for anything else — so
|
|
53
|
+
* a caller writes `const err = classBError(raw)` and branches on presence.
|
|
54
|
+
*
|
|
55
|
+
* WHY `=== true` AND NOT TRUTHINESS. The SDK zod-validates every `callTool` response against
|
|
56
|
+
* `CallToolResultSchema`, where `isError` is `z.boolean().optional()`. A non-boolean `isError`
|
|
57
|
+
* fails that parse, the promise REJECTS, and the call lands in the catch branch as Class A —
|
|
58
|
+
* recorded WITH an `error` either way. So the spec-illegal world cannot reach this mint through
|
|
59
|
+
* the real transport, and a strict check cannot silently swallow a failure. (The fixture in the
|
|
60
|
+
* strict-boolean cell models a wire state that cannot occur; it exists to pin the choice, not a
|
|
61
|
+
* reachable case.) This premise breaks only if realm switches to
|
|
62
|
+
* `CompatibilityCallToolResultSchema` or talks to a raw transport that skips validation — if that
|
|
63
|
+
* ever happens, revisit this line first.
|
|
64
|
+
*/
|
|
65
|
+
export declare function classBError(rawResult: unknown): string | undefined;
|
|
26
66
|
/** Splits "server_id:tool_name" into its components. Throws if the format is invalid. */
|
|
27
67
|
export declare function parseNamespacedId(id: string): {
|
|
28
68
|
serverId: string;
|
|
@@ -101,4 +141,96 @@ export declare function extractApiErrorFields(err: unknown): {
|
|
|
101
141
|
api_param?: string | null;
|
|
102
142
|
api_code?: string | null;
|
|
103
143
|
};
|
|
144
|
+
/** Realm's own retry count, passed EXPLICITLY to every SDK client. */
|
|
145
|
+
export declare const MAX_RETRIES = 2;
|
|
146
|
+
/** What a provider attaches to an error it throws, so a chokepoint can classify it precisely. */
|
|
147
|
+
export interface DriveCallPayload {
|
|
148
|
+
error_class?: string;
|
|
149
|
+
/**
|
|
150
|
+
* Attempts the wrapper SAW COMPLETE. An attempt still in flight when the ceiling fired is not
|
|
151
|
+
* counted — so a pre-header hang records 0, truthfully: nothing came back.
|
|
152
|
+
*/
|
|
153
|
+
attempts_sdk?: number;
|
|
154
|
+
elapsed_ms?: number;
|
|
155
|
+
last_observed_status?: number;
|
|
156
|
+
retry_after_observed_ms?: number;
|
|
157
|
+
declared_per_attempt_ms?: number;
|
|
158
|
+
derived_ceiling_ms?: number;
|
|
159
|
+
}
|
|
160
|
+
/** What one client's fetch wrapper has seen. Per-invocation, minted beside the client. */
|
|
161
|
+
export interface WireCounters {
|
|
162
|
+
attempts: number;
|
|
163
|
+
lastStatus?: number;
|
|
164
|
+
lastRetryAfterMs?: number;
|
|
165
|
+
}
|
|
166
|
+
/** The clock one step drives under. */
|
|
167
|
+
export interface LlmClock {
|
|
168
|
+
ceilingMs: number;
|
|
169
|
+
declaredPerAttemptMs?: number;
|
|
170
|
+
/**
|
|
171
|
+
* WHERE the per-attempt value came from. Set once, at run-agent's clock construction, and read
|
|
172
|
+
* only by the disclosure: it decides whether `declared_per_attempt_ms` is recorded at all (a
|
|
173
|
+
* default nobody chose is not a declaration) and which lever the abort message names.
|
|
174
|
+
*
|
|
175
|
+
* Absent on a hand-built clock — a unit cell, a caller that constructed one directly — and the
|
|
176
|
+
* message then names BOTH levers, because with no provenance either could be the live one.
|
|
177
|
+
*/
|
|
178
|
+
perAttemptSource?: 'step' | 'flag' | 'default';
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Derives the whole-create ceiling from a per-attempt value.
|
|
182
|
+
*
|
|
183
|
+
* `perAttempt × (MAX_RETRIES + 1)` covers every attempt the SDK will make, plus the backoff it
|
|
184
|
+
* sleeps between them, plus a download allowance so a large-but-progressing response is never
|
|
185
|
+
* killed for being large. The backoff term is the SDK's OWN schedule summed as an UPPER bound —
|
|
186
|
+
* its jitter only ever reduces the wait, so budgeting the un-jittered sum cannot cut short a
|
|
187
|
+
* retry the SDK scheduled for itself.
|
|
188
|
+
*
|
|
189
|
+
* A SERVER-DIRECTED wait is a different thing and is deliberately NOT budgeted. A `Retry-After`
|
|
190
|
+
* can ask for hours; the ceiling outranks it on purpose, which is the point of the bound rather
|
|
191
|
+
* than a gap in it.
|
|
192
|
+
*/
|
|
193
|
+
export declare function deriveLlmClock(perAttemptMs: number): LlmClock;
|
|
194
|
+
/**
|
|
195
|
+
* Wraps `fetch` so realm can SEE what the SDK's retry ladder did — how many attempts it made, the
|
|
196
|
+
* last status, and any Retry-After the server asked for, in all three of its legal forms
|
|
197
|
+
* (`retry-after-ms`, a numeric `Retry-After`, an HTTP-date `Retry-After`).
|
|
198
|
+
*
|
|
199
|
+
* Observation only. Realm never honors a Retry-After: acting on it would be a scheduling decision
|
|
200
|
+
* this layer does not make, and recording it is what lets an operator tell a rate limit apart from
|
|
201
|
+
* a hang. The inner fetch is injectable so the wrapper is unit-testable without a socket.
|
|
202
|
+
*/
|
|
203
|
+
export declare function makeCountingFetch(counters: WireCounters, innerFetch?: typeof fetch): typeof fetch;
|
|
204
|
+
/**
|
|
205
|
+
* Attaches a payload to an error, WITHOUT overwriting one that is already there.
|
|
206
|
+
*
|
|
207
|
+
* TOTAL. Both the probe and the assignment can throw on a value realm did not create — `in` runs
|
|
208
|
+
* a proxy's `has` trap, and assigning to a frozen object throws in strict mode. Either one would
|
|
209
|
+
* hand the caller the attacher's own TypeError in place of the failure it was trying to describe,
|
|
210
|
+
* which is the whole attribution chain defeated by the last link in it. An error that cannot be
|
|
211
|
+
* enriched still propagates, intact and unenriched; shape classification never needed the payload.
|
|
212
|
+
*/
|
|
213
|
+
export declare function attachDriveCall(err: unknown, payload: DriveCallPayload): void;
|
|
214
|
+
/**
|
|
215
|
+
* Converts any thrown value to display text, TOTALLY.
|
|
216
|
+
*
|
|
217
|
+
* The chokepoints interpolate the thrown value into their console line BEFORE recording it, so a
|
|
218
|
+
* poisoned `toString` used to out-throw at the print — replacing the operator's error with a
|
|
219
|
+
* secondary one before the (already hardened) mint could run.
|
|
220
|
+
*/
|
|
221
|
+
export declare function safeErrorText(err: unknown): string;
|
|
222
|
+
/**
|
|
223
|
+
* Runs ONE model create under realm's ceiling.
|
|
224
|
+
*
|
|
225
|
+
* Two mechanisms, because one is not enough. The timer is what bounds the wall clock; the abort is
|
|
226
|
+
* what actually stops work — but only as far as the SDK will let it. The SDK's sleep primitive is
|
|
227
|
+
* signal-aware, yet its retry site passes no signal, so a raced-out backoff sleep runs to
|
|
228
|
+
* completion in the worker. That is the ceiling's known reach, not a bug in it: an SDK bump that
|
|
229
|
+
* threads the signal there would make the race leg partially redundant, and it would still be
|
|
230
|
+
* earning its keep on the post-header body hang.
|
|
231
|
+
*
|
|
232
|
+
* Wraps the CREATE only. Client construction stays outside — that is where a missing SDK attaches
|
|
233
|
+
* its own payload, and this must never re-attribute it.
|
|
234
|
+
*/
|
|
235
|
+
export declare function driveCreate<T>(rawCreate: (body: Record<string, unknown>, opts: Record<string, unknown>) => Promise<T>, body: Record<string, unknown>, clock: LlmClock, counters: WireCounters): Promise<T>;
|
|
104
236
|
//# sourceMappingURL=agent-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-utils.d.ts","sourceRoot":"","sources":["../../../src/agent/providers/agent-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AActF;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,wBAAwB,CAAC,EAAE,MAAM,EACjC,qBAAqB,CAAC,EAAE,OAAO,GAC9B,MAAM,CASR;AAUD,6EAA6E;AAC7E,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAE5E;
|
|
1
|
+
{"version":3,"file":"agent-utils.d.ts","sourceRoot":"","sources":["../../../src/agent/providers/agent-utils.ts"],"names":[],"mappings":"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"}
|