bareloop 0.21.0 → 0.23.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/CHANGELOG.md +292 -0
- package/README.md +1 -1
- package/bareloop.context.md +177 -24
- package/package.json +3 -3
- package/src/authorflow.js +7 -2
- package/src/authorjob.js +15 -1
- package/src/authorscout.js +83 -9
- package/src/bundle.js +40 -46
- package/src/calibrate.js +10 -0
- package/src/cli.js +52 -19
- package/src/close-integrity.js +325 -0
- package/src/closetimeout.js +165 -0
- package/src/declaredclose.js +9 -2
- package/src/index.js +14 -0
- package/src/job.js +84 -5
- package/src/judged.js +108 -5
- package/src/kinds.js +12 -0
- package/src/plan.js +5 -1
- package/src/planrun.js +392 -46
- package/src/providers.js +176 -0
- package/src/ralph.js +40 -7
- package/src/ratelimit.js +116 -0
- package/src/reuse.js +12 -2
- package/src/reviewdoor.js +26 -6
- package/src/run.js +83 -8
- package/src/transport.js +29 -12
- package/src/validate.js +59 -0
- package/types/authorscout.d.ts +27 -2
- package/types/close-integrity.d.ts +196 -0
- package/types/closetimeout.d.ts +126 -0
- package/types/declaredclose.d.ts +6 -1
- package/types/index.d.ts +1 -0
- package/types/job.d.ts +4 -0
- package/types/judged.d.ts +7 -2
- package/types/kinds.d.ts +9 -0
- package/types/planrun.d.ts +17 -2
- package/types/providers.d.ts +104 -0
- package/types/ralph.d.ts +19 -5
- package/types/ratelimit.d.ts +59 -0
- package/types/reuse.d.ts +2 -0
- package/types/reviewdoor.d.ts +3 -1
- package/types/run.d.ts +33 -2
- package/types/transport.d.ts +10 -4
- package/types/validate.d.ts +48 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The $0 timing preflight (PRD item 27, M3 §2): run every close STAGE once,
|
|
3
|
+
* ignoring verdicts — first-red-wins stays for the real verdict precheck
|
|
4
|
+
* (`src/planrun.js`'s `check-preflight`); this is a separate, sequential pass
|
|
5
|
+
* (F131/F68: never two closes in flight against one tree) whose only purpose
|
|
6
|
+
* is TIMING. A declared-close stage (no `.cmd`, a kind executor) has nothing
|
|
7
|
+
* a command runner can spawn and is skipped — it contributes no reading, not
|
|
8
|
+
* a zero one (a silent zero would understate the real close's later cost).
|
|
9
|
+
*
|
|
10
|
+
* @param {any[]} stages a close stage chain (`runStages`'s own shape)
|
|
11
|
+
* @param {{cwd?: string, redact?: (s: string) => string, ceilingMs?: number}} [opts]
|
|
12
|
+
* `ceilingMs` (test seam only — never wired to any spec/runner surface):
|
|
13
|
+
* overrides `TIMING_PREFLIGHT_CEILING_MS` so a hang-detection test does not
|
|
14
|
+
* have to wait 10 real minutes. Production callers never pass it.
|
|
15
|
+
* @returns {Promise<{
|
|
16
|
+
* perStage: {name: string, ms: number, exitCode: number|null, timedOut: boolean}[],
|
|
17
|
+
* slowestMs: number, slowestName: string|null, anyTimedOut: boolean,
|
|
18
|
+
* }>}
|
|
19
|
+
*/
|
|
20
|
+
export function timeCloseStages(stages: any[], { cwd, redact, ceilingMs }?: {
|
|
21
|
+
cwd?: string;
|
|
22
|
+
redact?: (s: string) => string;
|
|
23
|
+
ceilingMs?: number;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
perStage: {
|
|
26
|
+
name: string;
|
|
27
|
+
ms: number;
|
|
28
|
+
exitCode: number | null;
|
|
29
|
+
timedOut: boolean;
|
|
30
|
+
}[];
|
|
31
|
+
slowestMs: number;
|
|
32
|
+
slowestName: string | null;
|
|
33
|
+
anyTimedOut: boolean;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* The ceiling formula (PRD item 27, M3): `max(FLOOR, K × slowest measured
|
|
37
|
+
* stage)`, unless an explicit override is given — the override is the
|
|
38
|
+
* OPERATOR'S number (the rates-passthrough shape, F113: guesstimate + loud
|
|
39
|
+
* sign + customer override), so it may legally sit ABOVE or BELOW the
|
|
40
|
+
* autoset estimate; this is not tighten-only.
|
|
41
|
+
* @param {{slowestMs: number, overrideMs?: number|null}} args
|
|
42
|
+
* @returns {{ ceilingMs: number, source: 'estimated'|'override' }}
|
|
43
|
+
*/
|
|
44
|
+
export function computeCloseTimeoutCeiling({ slowestMs, overrideMs }: {
|
|
45
|
+
slowestMs: number;
|
|
46
|
+
overrideMs?: number | null;
|
|
47
|
+
}): {
|
|
48
|
+
ceilingMs: number;
|
|
49
|
+
source: "estimated" | "override";
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* ONE resolver for "what per-stage close timeout does this job get", shared
|
|
53
|
+
* by `src/planrun.js` (the in-run path) and `scripts/run-u.mjs` (which must
|
|
54
|
+
* know the answer BEFORE it spawns the outside watchdog — F67 — so the
|
|
55
|
+
* watchdog's own stale/grace windows are sized off the real ceiling rather
|
|
56
|
+
* than a hardcoded guess). Two callers computing this independently is
|
|
57
|
+
* exactly the class of drift this whole rung exists to close (F129's own
|
|
58
|
+
* lesson, one level up): this function is the only place the precedence is
|
|
59
|
+
* spelled out.
|
|
60
|
+
*
|
|
61
|
+
* Precedence: a signed spec override (`job.closeTimeoutMs`) wins outright,
|
|
62
|
+
* with NO timing pass run (the pass would waste real machine time and, on a
|
|
63
|
+
* deliberately slow/hung stage, block for up to `TIMING_PREFLIGHT_CEILING_MS`
|
|
64
|
+
* for no purpose). Absent that, every stage is timed once (F131's autoset
|
|
65
|
+
* design) and the ceiling is `max(FLOOR, K × slowest)`.
|
|
66
|
+
* @param {{job: any, stages: any[], cwd: string, redact?: (s: string) => string, ceilingMs?: number}} args
|
|
67
|
+
* `ceilingMs` — see `timeCloseStages`; test seam only.
|
|
68
|
+
* @returns {Promise<{
|
|
69
|
+
* closeTimeoutMs: number|null, source: 'estimated'|'override',
|
|
70
|
+
* timing: Awaited<ReturnType<typeof timeCloseStages>>|null, timedOut: boolean,
|
|
71
|
+
* }>} `closeTimeoutMs: null, timedOut: true` means a stage never finished the
|
|
72
|
+
* timing pass — the caller reds `close-timing-red` rather than trusting any
|
|
73
|
+
* number here.
|
|
74
|
+
*/
|
|
75
|
+
export function resolveCloseTimeoutMs({ job, stages, cwd, redact, ceilingMs }: {
|
|
76
|
+
job: any;
|
|
77
|
+
stages: any[];
|
|
78
|
+
cwd: string;
|
|
79
|
+
redact?: (s: string) => string;
|
|
80
|
+
ceilingMs?: number;
|
|
81
|
+
}): Promise<{
|
|
82
|
+
closeTimeoutMs: number | null;
|
|
83
|
+
source: "estimated" | "override";
|
|
84
|
+
timing: Awaited<ReturnType<typeof timeCloseStages>> | null;
|
|
85
|
+
timedOut: boolean;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* The printed banner (build spec M3 §2's exact wording) — ONE spelling, so
|
|
89
|
+
* the run-u tail and the bundle CLI can never drift into two announcements of
|
|
90
|
+
* the same number. `source` accepts 'explicit' too: a caller-passed
|
|
91
|
+
* `closeTimeoutMs` runtime option (the pre-M3 shell/test knob, kept for
|
|
92
|
+
* backward compatibility and test control — never the signed spec field) is
|
|
93
|
+
* a real override but not a SIGNED one, so it earns its own honest word
|
|
94
|
+
* rather than being folded into 'signed override'.
|
|
95
|
+
* @param {{ceilingMs: number, source: 'estimated'|'override'|'explicit', slowestMs?: number, slowestName?: string|null}} args
|
|
96
|
+
* @returns {string}
|
|
97
|
+
*/
|
|
98
|
+
export function closeTimeoutBanner({ ceilingMs, source, slowestMs, slowestName }: {
|
|
99
|
+
ceilingMs: number;
|
|
100
|
+
source: "estimated" | "override" | "explicit";
|
|
101
|
+
slowestMs?: number;
|
|
102
|
+
slowestName?: string | null;
|
|
103
|
+
}): string;
|
|
104
|
+
/** hamr, 2026-09-07: the floor, verbatim. Also the value `runClose`'s own
|
|
105
|
+
* un-autoset default has always used — kept as its own named constant here
|
|
106
|
+
* (not re-exported from ralph.js) because the two are different CLAIMS: one is
|
|
107
|
+
* "what runClose does if nobody says otherwise", the other is "the arbiter's
|
|
108
|
+
* chosen floor for autoset" — they happen to be the same number today, and a
|
|
109
|
+
* future change to either must not silently move the other. */
|
|
110
|
+
export const CLOSE_TIMEOUT_FLOOR_MS: 120000;
|
|
111
|
+
/** hamr, 2026-09-07, verbatim: "K = 5 ('2 and 5 are fine')." */
|
|
112
|
+
export const CLOSE_TIMEOUT_K: 5;
|
|
113
|
+
/** `runClose`'s own shipped default when nobody passes a timeout at all
|
|
114
|
+
* (`src/ralph.js:221`) — the ceiling the $0 timing PASS ITSELF runs each
|
|
115
|
+
* stage under is a multiple of this, never of the floor above (the two are
|
|
116
|
+
* the same number today; named separately on purpose, see the constant
|
|
117
|
+
* above). */
|
|
118
|
+
export const LIBRARY_DEFAULT_CLOSE_TIMEOUT_MS: 120000;
|
|
119
|
+
/**
|
|
120
|
+
* The generous PROVISIONAL ceiling the timing preflight runs every stage
|
|
121
|
+
* under, so "a genuinely hung stage still ends" (build spec, M3 §2) rather
|
|
122
|
+
* than blocking the timing pass forever. Deliberately the library default × K
|
|
123
|
+
* (600s) — NOT the autoset/override ceiling this module computes, which is
|
|
124
|
+
* only known after the pass completes.
|
|
125
|
+
*/
|
|
126
|
+
export const TIMING_PREFLIGHT_CEILING_MS: number;
|
package/types/declaredclose.d.ts
CHANGED
|
@@ -110,7 +110,8 @@ export function guardNames(closeDecl: any, verdictType: string): string[];
|
|
|
110
110
|
* seedTrees?: any, gapCap?: number, maxBuffer?: number, baselineMode?: 'auto'|'worktree',
|
|
111
111
|
* humanRuling?: {decision: string, text?: string|null}|null,
|
|
112
112
|
* judgeLoop?: ((o: {system: string}) => any)|null,
|
|
113
|
-
* onJudgeCost?: ((c: any) => void)|null
|
|
113
|
+
* onJudgeCost?: ((c: any) => void)|null,
|
|
114
|
+
* callBounds?: (() => {timeoutMs?: number, deadlineMs?: number})|null}} [opts]
|
|
114
115
|
* @returns {Promise<any>}
|
|
115
116
|
*/
|
|
116
117
|
export function runDeclaredStages(stages: any[], redact?: (s: string) => string, opts?: {
|
|
@@ -129,6 +130,10 @@ export function runDeclaredStages(stages: any[], redact?: (s: string) => string,
|
|
|
129
130
|
system: string;
|
|
130
131
|
}) => any) | null;
|
|
131
132
|
onJudgeCost?: ((c: any) => void) | null;
|
|
133
|
+
callBounds?: (() => {
|
|
134
|
+
timeoutMs?: number;
|
|
135
|
+
deadlineMs?: number;
|
|
136
|
+
}) | null;
|
|
132
137
|
}): Promise<any>;
|
|
133
138
|
/**
|
|
134
139
|
* The trend reader's input for ONE close verdict, whichever executor produced
|
package/types/index.d.ts
CHANGED
|
@@ -28,3 +28,4 @@ export { replayRun, formatReplay } from "./replay.js";
|
|
|
28
28
|
export { runInterview, authorCloseForJob, assembleSpec, prepareSigning, refusalEvents, refuseLockedKind, GENRE, REFUSAL_LIB, REFUSAL_CATEGORY, AUTHORED_SPEC_FIELDS } from "./authorjob.js";
|
|
29
29
|
export { PROMPT_REGISTERS, isPromptFile } from "./promptregisters.js";
|
|
30
30
|
export { exportBundle, bundleHash, readBundle, resolveBundleSpec, checkEnvelope, bless, verifyBlessing, appendHistory, checkBundleDeps } from "./bundle.js";
|
|
31
|
+
export { readCloseScripts, checkCloseAbsolutePaths, absolutePathLiteralsOf, hashCloseScriptBytes, checkCloseByteSignature, checkStageByteSignature, signCloseScripts } from "./close-integrity.js";
|
package/types/job.d.ts
CHANGED
|
@@ -207,6 +207,10 @@ export const CADENCE_UNITS: readonly string[];
|
|
|
207
207
|
* subscription — its costUsd axis is NOTIONAL (API-equivalent value, not
|
|
208
208
|
* billed), so it is a DISTINCT condition: rows never pool with anthropic-api
|
|
209
209
|
* rows on the cost axis, and budgets sized for one do not transfer. */
|
|
210
|
+
/** PRD item 28 (2026-09-06/09-09): `openai-api` — an OpenAI-shaped provider,
|
|
211
|
+
* constructed via `src/providers.js`'s factory. hamr's ruling (PRD 30.7):
|
|
212
|
+
* `deepseek-chat` is THE secondary provider (one, not a menu of half-tested
|
|
213
|
+
* models); the factory's tier table is where that lives, not this menu. */
|
|
210
214
|
export const PROVIDERS: readonly string[];
|
|
211
215
|
/** V3 environment label: declared keys only — every field is a lineage-key
|
|
212
216
|
* candidate at N3. `provider` is part of the key by definition (top-level,
|
package/types/judged.d.ts
CHANGED
|
@@ -130,12 +130,13 @@ export function locatePrompt(card: any): string;
|
|
|
130
130
|
* On every route out, red or clean, `onCost` fires exactly once with the honest
|
|
131
131
|
* read: a paid call that leaves no meter record is F12 wearing a judge's coat.
|
|
132
132
|
* @param {{artifactText: string, card: any, loopFactory: (o: {provider?: any, system: string}) => any,
|
|
133
|
-
* maxTokens?: number, attempt?: number, onCost?: (c: {costUsd: number|null, unpricedRounds: number}) => void
|
|
133
|
+
* maxTokens?: number, attempt?: number, onCost?: (c: {costUsd: number|null, unpricedRounds: number}) => void,
|
|
134
|
+
* callBounds?: {timeoutMs?: number, deadlineMs?: number}}} o
|
|
134
135
|
* @returns {Promise<{ok: boolean, facts: any|null, red: {axis: string, detail: string}|null,
|
|
135
136
|
* costUsd: number|null, unpricedRounds: number, truncated: boolean, parseError: boolean,
|
|
136
137
|
* raw: ReturnType<typeof scrubRaw>}>}
|
|
137
138
|
*/
|
|
138
|
-
export function runLocate({ artifactText, card, loopFactory, maxTokens, attempt, onCost }: {
|
|
139
|
+
export function runLocate({ artifactText, card, loopFactory, maxTokens, attempt, onCost, callBounds, }: {
|
|
139
140
|
artifactText: string;
|
|
140
141
|
card: any;
|
|
141
142
|
loopFactory: (o: {
|
|
@@ -148,6 +149,10 @@ export function runLocate({ artifactText, card, loopFactory, maxTokens, attempt,
|
|
|
148
149
|
costUsd: number | null;
|
|
149
150
|
unpricedRounds: number;
|
|
150
151
|
}) => void;
|
|
152
|
+
callBounds?: {
|
|
153
|
+
timeoutMs?: number;
|
|
154
|
+
deadlineMs?: number;
|
|
155
|
+
};
|
|
151
156
|
}): Promise<{
|
|
152
157
|
ok: boolean;
|
|
153
158
|
facts: any | null;
|
package/types/kinds.d.ts
CHANGED
|
@@ -539,6 +539,11 @@ export type Red = {
|
|
|
539
539
|
* funded honestly: this executor cannot reach the run's ledger, so every locate
|
|
540
540
|
* call's cost is reported OUT through it, once per call, on every route including
|
|
541
541
|
* the red ones — a paid call that leaves no meter record is F12 in a judge's coat.
|
|
542
|
+
* `callBounds` is F152/PRD 30.4's per-call TIME bound, read fresh before every
|
|
543
|
+
* locate attempt — the same derivation the run's own worker rounds carry
|
|
544
|
+
* (`callBounds()`, src/planrun.js). Absent is the honest unbounded default:
|
|
545
|
+
* an adopter or test that wires no clock through behaves exactly as before
|
|
546
|
+
* this field existed.
|
|
542
547
|
* `onStage` is a REPORTING seam and nothing else: the seed read spawns a real
|
|
543
548
|
* toolchain per stage (a suite is the slow one) and a whole read is one opaque
|
|
544
549
|
* await, so the shell gets told as each stage lands. It decides nothing, it is
|
|
@@ -571,6 +576,10 @@ export type Ctx = {
|
|
|
571
576
|
costUsd: number | null;
|
|
572
577
|
unpricedRounds: number;
|
|
573
578
|
}) => void;
|
|
579
|
+
callBounds?: () => {
|
|
580
|
+
timeoutMs?: number;
|
|
581
|
+
deadlineMs?: number;
|
|
582
|
+
};
|
|
574
583
|
onStage?: (row: {
|
|
575
584
|
stage: string | null;
|
|
576
585
|
kind: string | null;
|
package/types/planrun.d.ts
CHANGED
|
@@ -221,7 +221,14 @@ export function planPrompt(job: any, scoutBlob: string, reds: any[] | null, maxS
|
|
|
221
221
|
* ladder (src/ladder.js). Arbiter territory exactly as the count it replaced was —
|
|
222
222
|
* the runner sets it, the plan cannot express it, and no step may tighten or raise
|
|
223
223
|
* it.
|
|
224
|
-
* @param {number} [opts.closeTimeoutMs] close/check wall-clock cap (shell territory)
|
|
224
|
+
* @param {number} [opts.closeTimeoutMs] close/check wall-clock cap (shell territory).
|
|
225
|
+
* OPTIONAL as of PRD item 27/M3: absent, this run autosets it from a $0 seed
|
|
226
|
+
* timing pass (or the spec's own signed `closeTimeoutMs` override) — an
|
|
227
|
+
* explicit value here still wins outright (backward compatibility/test
|
|
228
|
+
* control only, F133: `scripts/run-u.mjs`/`src/cli.js` never pass this).
|
|
229
|
+
* @param {string|null} [opts.closeDir] the close's own books directory (PRD
|
|
230
|
+
* item 27/M3 Part B), forwarded to every close invocation as
|
|
231
|
+
* `BARELOOP_CLOSE_DIR`
|
|
225
232
|
* @param {number} [opts.maxStepRounds] the shell's per-step rounds ceiling (validatePlan's bound)
|
|
226
233
|
* @param {boolean} [opts.scout=true] operator-only switch (docs/product/SCOUT-CONTRAST.md):
|
|
227
234
|
* `false` on a FRESH run (no `resumeSeed`) skips the survey entirely — `scoutBlob`
|
|
@@ -392,12 +399,18 @@ export function planPrompt(job: any, scoutBlob: string, reds: any[] | null, maxS
|
|
|
392
399
|
* precisely the state the person rejected), and the words reach the PLANNER as new
|
|
393
400
|
* authoring. It is never a `humanRuling` — that answers a close's human STAGE, and
|
|
394
401
|
* a green-class job has none. Empty words are refused at the same seam every door is.
|
|
402
|
+
* @param {boolean} [opts.resumable=true] PRD item 27(c)/F130 — does THIS runner
|
|
403
|
+
* support `--resume`? Forwarded verbatim from `runJob`; `run-u.mjs` leaves it at
|
|
404
|
+
* the default (byte-identical to before this param existed), the bundle CLI
|
|
405
|
+
* passes `false` so the three `--resume`-naming readouts below (`MONEY_OPTIONS`,
|
|
406
|
+
* the resume-plan-red option, the fix-loop terminal) say "resume is `run-u`-only
|
|
407
|
+
* in v1" instead of naming a flag that would fail if typed.
|
|
395
408
|
* @returns {Promise<string>} 'green' | 'already-green' | 'escalated' | 'plan-red' |
|
|
396
409
|
* 'check-red' | 'close-red' | 'close-unsupported' | 'recipe-stale' | 'pricing-red' |
|
|
397
410
|
* 'branch-red' | 'cap-halt' | 'wall-halt' | 'provider-red' | 'interpreter-red' |
|
|
398
411
|
* 'step-stalled' | 'hitl-pause' | 'hitl-decision-red' | `step-red:<id>`
|
|
399
412
|
*/
|
|
400
|
-
export function runPlan(job: any, { workdir, provider, nativeProvider, providerFor, judgeProvider, emit, remainingUsd, isUnpriced, spendComplete, capRuns, strikeLimit, closeTimeoutMs, maxStepRounds, layerRoot, readShim, scout, scoutRounds, bridge, now, priorWallMs, resumeSeed, resumeGrades, resumeReplans, resumeBranch, humanRuling, heldRuling, priorSpentUsd, reviewDoor, doorRerun }: {
|
|
413
|
+
export function runPlan(job: any, { workdir, provider, nativeProvider, providerFor, judgeProvider, emit, remainingUsd, isUnpriced, spendComplete, capRuns, strikeLimit, closeTimeoutMs, closeDir, maxStepRounds, layerRoot, readShim, scout, scoutRounds, bridge, now, priorWallMs, resumeSeed, resumeGrades, resumeReplans, resumeBranch, humanRuling, heldRuling, priorSpentUsd, reviewDoor, doorRerun, resumable }: {
|
|
401
414
|
workdir: string;
|
|
402
415
|
provider: any;
|
|
403
416
|
nativeProvider?: ((o: {
|
|
@@ -414,6 +427,7 @@ export function runPlan(job: any, { workdir, provider, nativeProvider, providerF
|
|
|
414
427
|
capRuns?: number | undefined;
|
|
415
428
|
strikeLimit?: number | undefined;
|
|
416
429
|
closeTimeoutMs?: number | undefined;
|
|
430
|
+
closeDir?: string | null | undefined;
|
|
417
431
|
maxStepRounds?: number | undefined;
|
|
418
432
|
scout?: boolean | undefined;
|
|
419
433
|
scoutRounds?: number | undefined;
|
|
@@ -449,6 +463,7 @@ export function runPlan(job: any, { workdir, provider, nativeProvider, providerF
|
|
|
449
463
|
fromRunid?: string | null;
|
|
450
464
|
receivedAt?: string | null;
|
|
451
465
|
} | null | undefined;
|
|
466
|
+
resumable?: boolean | undefined;
|
|
452
467
|
}): Promise<string>;
|
|
453
468
|
/**
|
|
454
469
|
* The recorded bound-reason's ceiling in the WORKER-facing note. The reason is a
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Look up a provider's table entry. Throws a NAMED error on an unrecognized
|
|
3
|
+
* provider — never a silent default (the `resolveRates`-style-substring-
|
|
4
|
+
* match lesson: a forward hazard even at zero observed rounds, MEMORY.md).
|
|
5
|
+
* `src/job.js`'s `PROVIDERS` menu is the one place a spec's `provider`
|
|
6
|
+
* field is validated; this is the runtime construction seam it feeds.
|
|
7
|
+
* @param {string} providerName
|
|
8
|
+
* @returns {ProviderTableEntry}
|
|
9
|
+
*/
|
|
10
|
+
export function resolveProvider(providerName: string): ProviderTableEntry;
|
|
11
|
+
/**
|
|
12
|
+
* Construct ONE provider instance for `providerName`/`model`, applying
|
|
13
|
+
* `exposeErrorBody: true` (F153 — every constructed provider, unconditionally)
|
|
14
|
+
* and the model's own request-key gating (`paramsFor`). `baseUrl` (PRD item
|
|
15
|
+
* 28, ruling (d), 2026-09-09: admitted in v1) is forwarded only when given —
|
|
16
|
+
* every provider constructor here defaults it on its own when absent.
|
|
17
|
+
* @param {string} providerName
|
|
18
|
+
* @param {{apiKey?: string, model?: string, baseUrl?: string}} [options]
|
|
19
|
+
*/
|
|
20
|
+
export function makeProvider(providerName: string, { apiKey, model, baseUrl }?: {
|
|
21
|
+
apiKey?: string;
|
|
22
|
+
model?: string;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
}): any;
|
|
25
|
+
/**
|
|
26
|
+
* Build the `{provider, providerFor, judgeProvider}` triple both runners
|
|
27
|
+
* need (`src/cli.js`'s `buildProviders`, `scripts/run-u.mjs`'s top-level
|
|
28
|
+
* wiring) — ONE seam instead of two copies of the same construction and
|
|
29
|
+
* tier-memoization logic. `model`/`tierModels` are already-RESOLVED inputs
|
|
30
|
+
* (the caller runs `resolveWorkerModel` itself, exactly as both runners did
|
|
31
|
+
* before this factory existed — that decision stays where each runner's own
|
|
32
|
+
* `--model` flag/spec precedence lives, not duplicated in here).
|
|
33
|
+
*
|
|
34
|
+
* The JUDGE stays pinned to `anthropic-api`/`judgeModel` regardless of
|
|
35
|
+
* `providerName` — arbiter territory (PRD item 28: "the judge stays PINNED
|
|
36
|
+
* … regardless of the job's worker provider"). A signed `judge:{provider,
|
|
37
|
+
* model}` field with its own calibration record is PRD item 28 part (2),
|
|
38
|
+
* NOT built here; until it lands, the judge always needs its own
|
|
39
|
+
* `judgeApiKey` (today, always `ANTHROPIC_API_KEY`), independent of which
|
|
40
|
+
* key the worker used.
|
|
41
|
+
* @param {object} args
|
|
42
|
+
* @param {string} args.providerName spec.provider (or the anthropic-api default)
|
|
43
|
+
* @param {string|undefined} args.apiKey the WORKER's key, read from the provider's own `envKey`
|
|
44
|
+
* @param {string} args.model the already-resolved worker model id
|
|
45
|
+
* @param {Readonly<Record<string, string>>} args.tierModels the already-resolved tier -> model map (spec override folded in by the caller)
|
|
46
|
+
* @param {string|undefined} [args.baseUrl] spec.baseUrl, if any
|
|
47
|
+
* @param {string|undefined} args.judgeApiKey the judge's own key (today: `ANTHROPIC_API_KEY`)
|
|
48
|
+
* @param {string} args.judgeModel `JUDGE_MODEL`
|
|
49
|
+
*/
|
|
50
|
+
export function buildRunnerProviders({ providerName, apiKey, model, tierModels, baseUrl, judgeApiKey, judgeModel, }: {
|
|
51
|
+
providerName: string;
|
|
52
|
+
apiKey: string | undefined;
|
|
53
|
+
model: string;
|
|
54
|
+
tierModels: Readonly<Record<string, string>>;
|
|
55
|
+
baseUrl?: string | undefined;
|
|
56
|
+
judgeApiKey: string | undefined;
|
|
57
|
+
judgeModel: string;
|
|
58
|
+
}): {
|
|
59
|
+
provider: any;
|
|
60
|
+
providerFor: (tier: string) => any;
|
|
61
|
+
judgeProvider: any;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Today's anthropic-api tier table — EXACTLY the `DEFAULT_TIER_MODELS` both
|
|
65
|
+
* runners hardcoded before this factory existed. Any change to these two
|
|
66
|
+
* values is a change to shipped anthropic-api behaviour, not a refactor.
|
|
67
|
+
*/
|
|
68
|
+
export const ANTHROPIC_TIER_MODELS: Readonly<{
|
|
69
|
+
sonnet: "claude-sonnet-5";
|
|
70
|
+
haiku: "claude-haiku-4-5-20251001";
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* DeepSeek (F149/F150) is a SINGLE model, not a tiered family — hamr's
|
|
74
|
+
* ruling above: one secondary provider, not a menu. Both tiers map to the
|
|
75
|
+
* same model id ON PURPOSE: `resolveWorkerModel`/a runner's `providerFor
|
|
76
|
+
* (tier)` only ever LOOK UP a tier's model id (src/job.js:818-827,
|
|
77
|
+
* scripts/run-u.mjs's `providerFor`) — neither assumes the tiers name
|
|
78
|
+
* different models — so repeating the one id is the honest representation
|
|
79
|
+
* of a single-model provider, not a second model masquerading as `haiku`.
|
|
80
|
+
* If DeepSeek (or a future openai-api entrant) ever ships a genuinely
|
|
81
|
+
* cheaper tier model, this is where it would earn its own `haiku` id.
|
|
82
|
+
*/
|
|
83
|
+
export const OPENAI_TIER_MODELS: Readonly<{
|
|
84
|
+
sonnet: "deepseek-chat";
|
|
85
|
+
haiku: "deepseek-chat";
|
|
86
|
+
}>;
|
|
87
|
+
export type ProviderTableEntry = {
|
|
88
|
+
/**
|
|
89
|
+
* the bare-agent provider class
|
|
90
|
+
*/
|
|
91
|
+
ctor: new (options: any) => any;
|
|
92
|
+
/**
|
|
93
|
+
* the environment variable this provider reads its key from
|
|
94
|
+
*/
|
|
95
|
+
envKey: string;
|
|
96
|
+
/**
|
|
97
|
+
* tier name -> model id
|
|
98
|
+
*/
|
|
99
|
+
tiers: Readonly<Record<string, string>>;
|
|
100
|
+
/**
|
|
101
|
+
* per-model request-key/param gating, applied on TOP of {exposeErrorBody:true, apiKey, model, baseUrl?}
|
|
102
|
+
*/
|
|
103
|
+
paramsFor: (model: string | undefined) => Record<string, any>;
|
|
104
|
+
};
|
package/types/ralph.d.ts
CHANGED
|
@@ -54,17 +54,24 @@
|
|
|
54
54
|
*
|
|
55
55
|
* @param {string[]} close argv, e.g. ['node', '--test', 'close/']
|
|
56
56
|
* @param {(s: string) => string} [redact] source scrubber; identity by default
|
|
57
|
-
* @param {{ timeoutMs?: number, cwd?: string, expect?: number, judged?: {pattern: string, min: number}, gapKeep?: string }} [opts]
|
|
57
|
+
* @param {{ timeoutMs?: number, cwd?: string, expect?: number, judged?: {pattern: string, min: number}, gapKeep?: string, closeDir?: string|null }} [opts]
|
|
58
58
|
* close wall-clock cap (operator-set via the runner, never the config's — the
|
|
59
59
|
* agent must not author its arbiter's clock), the directory the close runs in
|
|
60
60
|
* (the workdir — the tree it is judging), the exit code the SIGNED spec calls
|
|
61
61
|
* success, the judgment-rendered signal, and the kept-failures pattern. All
|
|
62
62
|
* five are arbiter territory: the drafted workflow config cannot express any.
|
|
63
|
+
* `closeDir` (PRD item 27/M3 Part B) is the close's OWN books directory —
|
|
64
|
+
* pristine copies, calibration thresholds, logs — deliberately outside the
|
|
65
|
+
* patient tree (the worker must never read the arbiter's books). Handed to
|
|
66
|
+
* the child as `BARELOOP_CLOSE_DIR` (`CLOSE_DIR_ENV_VAR`,
|
|
67
|
+
* src/close-integrity.js); a close script that needs one and gets none
|
|
68
|
+
* instrument-stops itself, by the script's own contract — this seam only
|
|
69
|
+
* ever THREADS the value, it never invents one.
|
|
63
70
|
* @returns {Promise<{verdict: 'satisfied'|'needs_revision'|'failed'|'timed-out'|'killed'|'crashed',
|
|
64
71
|
* gap?: string, exitCode?: number, signal?: string, detail?: string,
|
|
65
72
|
* judgedCount?: number|null, unaudited?: boolean}>}
|
|
66
73
|
*/
|
|
67
|
-
export function runClose(close: string[], redact?: (s: string) => string, { timeoutMs, cwd, expect, judged, gapKeep }?: {
|
|
74
|
+
export function runClose(close: string[], redact?: (s: string) => string, { timeoutMs, cwd, expect, judged, gapKeep, closeDir }?: {
|
|
68
75
|
timeoutMs?: number;
|
|
69
76
|
cwd?: string;
|
|
70
77
|
expect?: number;
|
|
@@ -73,6 +80,7 @@ export function runClose(close: string[], redact?: (s: string) => string, { time
|
|
|
73
80
|
min: number;
|
|
74
81
|
};
|
|
75
82
|
gapKeep?: string;
|
|
83
|
+
closeDir?: string | null;
|
|
76
84
|
}): Promise<{
|
|
77
85
|
verdict: "satisfied" | "needs_revision" | "failed" | "timed-out" | "killed" | "crashed";
|
|
78
86
|
gap?: string;
|
|
@@ -104,12 +112,13 @@ export function runClose(close: string[], redact?: (s: string) => string, { time
|
|
|
104
112
|
*
|
|
105
113
|
* @param {any[]} stages the stage list (already validated by validateJob)
|
|
106
114
|
* @param {(s: string) => string} [redact] scrub, applied at capture on EVERY stage
|
|
107
|
-
* @param {{timeoutMs?: number, cwd?: string}} [opts]
|
|
115
|
+
* @param {{timeoutMs?: number, cwd?: string, closeDir?: string|null}} [opts]
|
|
108
116
|
* @returns {Promise<any>} runClose's verdict shape, plus `stage` and `stages`
|
|
109
117
|
*/
|
|
110
|
-
export function runStages(stages: any[], redact?: (s: string) => string, { timeoutMs, cwd }?: {
|
|
118
|
+
export function runStages(stages: any[], redact?: (s: string) => string, { timeoutMs, cwd, closeDir }?: {
|
|
111
119
|
timeoutMs?: number;
|
|
112
120
|
cwd?: string;
|
|
121
|
+
closeDir?: string | null;
|
|
113
122
|
}): Promise<any>;
|
|
114
123
|
/**
|
|
115
124
|
* Bound an over-long close stream to a head sample + elided middle + tail. When
|
|
@@ -210,9 +219,13 @@ export function boundGap(s: string, keepPattern?: string): string;
|
|
|
210
219
|
* it to the gate audit's allow-decision writes. Injected like `redact` so the shell
|
|
211
220
|
* stays stdlib-only and dumb; consulted ONLY at a crashed verdict. With no seam, or
|
|
212
221
|
* with zero writes, a crash stays what it always was: an instrument stop.
|
|
222
|
+
* @param {string|null} [opts.closeDir] the close's own books directory
|
|
223
|
+
* (PRD item 27/M3 Part B), forwarded to the raw `close` path's `runClose`
|
|
224
|
+
* call unchanged; a caller supplying `judge` instead already closed over
|
|
225
|
+
* its own `closeDir` and this param does nothing for it.
|
|
213
226
|
* @returns {Promise<'green'|'escalated'>}
|
|
214
227
|
*/
|
|
215
|
-
export function ralph({ middle, close, judge, capRuns, ladder, emit, redact, closeTimeoutMs, cwd, expect, judged, gapKeep, workerWrites }: {
|
|
228
|
+
export function ralph({ middle, close, judge, capRuns, ladder, emit, redact, closeTimeoutMs, cwd, expect, judged, gapKeep, workerWrites, closeDir }: {
|
|
216
229
|
middle: (iteration: number, gap?: string) => void | Promise<void>;
|
|
217
230
|
close?: string[] | undefined;
|
|
218
231
|
judge?: (() => Promise<{
|
|
@@ -237,6 +250,7 @@ export function ralph({ middle, close, judge, capRuns, ladder, emit, redact, clo
|
|
|
237
250
|
} | undefined;
|
|
238
251
|
gapKeep?: string | undefined;
|
|
239
252
|
workerWrites?: (() => string[]) | undefined;
|
|
253
|
+
closeDir?: string | null | undefined;
|
|
240
254
|
}): Promise<"green" | "escalated">;
|
|
241
255
|
/**
|
|
242
256
|
* What the close child must NOT be able to read (operator ruling, 2026-07-31:
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is `err` an HTTP 429 (rate-limited) response? True ONLY for an explicit
|
|
3
|
+
* status of 429 on the error itself. Nothing else qualifies — not message
|
|
4
|
+
* text (a message merely containing "429" is not this), not `retryable`,
|
|
5
|
+
* not any other status. Symmetric with `isTransportFailure`'s own status
|
|
6
|
+
* check (src/transport.js), just reading the opposite branch of it.
|
|
7
|
+
* @param {any} err
|
|
8
|
+
* @returns {boolean}
|
|
9
|
+
*/
|
|
10
|
+
export function isRateLimited(err: any): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The vendor's RAW stated wait, in milliseconds, parsed straight from the
|
|
13
|
+
* error message — no default, no margin, no cap. `null` when nothing in the
|
|
14
|
+
* message matches a known shape. Exported separately from `rateLimitWaitMs`
|
|
15
|
+
* so a caller that wants to report the vendor's own number on the spine
|
|
16
|
+
* (`statedMs`) never has to re-derive it from the margin-adjusted figure.
|
|
17
|
+
*
|
|
18
|
+
* bare-agent does not expose the vendor's `retry-after` /
|
|
19
|
+
* `x-ratelimit-reset-*` response headers on the thrown error (BA-26) — the
|
|
20
|
+
* delay exists only in the vendor's English message text, so this parses
|
|
21
|
+
* that text. Verified real shape (OpenAI, run `8ev2sdkn`, 2026-09-08):
|
|
22
|
+
* "Please try again in 11.996s." This also supports "try again in 1.5
|
|
23
|
+
* seconds", "try again in 20ms", "retry after 30s", and "retry after 30
|
|
24
|
+
* seconds" — case-insensitive.
|
|
25
|
+
* @param {any} err
|
|
26
|
+
* @returns {number|null}
|
|
27
|
+
*/
|
|
28
|
+
export function statedWaitMs(err: any): number | null;
|
|
29
|
+
/**
|
|
30
|
+
* How long to wait before retrying a 429, in milliseconds — or `null`
|
|
31
|
+
* meaning "do not retry at all" (either the parsed wait exceeds
|
|
32
|
+
* `RATE_LIMIT_MAX_WAIT_MS`, in which case waiting that long is the
|
|
33
|
+
* operator's decision, not ours).
|
|
34
|
+
*
|
|
35
|
+
* A parsed value gets `PARSED_DELAY_MARGIN_MS` added (the vendor's stated
|
|
36
|
+
* number is the earliest moment its window resets, not a safe one to fire
|
|
37
|
+
* on), capped so the margin itself can never push a parsed value over
|
|
38
|
+
* `RATE_LIMIT_MAX_WAIT_MS`. When nothing parses, `RATE_LIMIT_DEFAULT_WAIT_MS`
|
|
39
|
+
* is returned as-is, with no margin added (there is nothing to add margin
|
|
40
|
+
* to — it is already a conservative guess, not an earliest-moment reading).
|
|
41
|
+
* @param {any} err
|
|
42
|
+
* @returns {number|null}
|
|
43
|
+
*/
|
|
44
|
+
export function rateLimitWaitMs(err: any): number | null;
|
|
45
|
+
/** The fixed retry budget: ONE extra attempt after a 429. Never read from a
|
|
46
|
+
* job spec or CLI flag — raising it is arbiter territory, mirroring
|
|
47
|
+
* transport.js's TRANSPORT_RETRIES exactly (tighten-only doctrine). */
|
|
48
|
+
export const RATE_LIMIT_RETRIES: 1;
|
|
49
|
+
/** bare-agent's `Retry.call` (if ever used) counts ATTEMPTS, not retries;
|
|
50
|
+
* this module's own hand-rolled ladder (src/planrun.js) does the same for
|
|
51
|
+
* symmetry with TRANSPORT_MAX_ATTEMPTS. */
|
|
52
|
+
export const RATE_LIMIT_MAX_ATTEMPTS: number;
|
|
53
|
+
/** The hard cap on how long we will ever wait for a vendor-stated 429 delay.
|
|
54
|
+
* A vendor asking for longer than this is not honoured — we do not retry at
|
|
55
|
+
* all in that case. Waiting that long is the operator's decision, not ours
|
|
56
|
+
* (arbiter territory: nothing here escalates the wait past what hamr set). */
|
|
57
|
+
export const RATE_LIMIT_MAX_WAIT_MS: 60000;
|
|
58
|
+
/** Used only when the vendor's message carries no parseable delay at all. */
|
|
59
|
+
export const RATE_LIMIT_DEFAULT_WAIT_MS: 5000;
|
package/types/reuse.d.ts
CHANGED
|
@@ -377,6 +377,7 @@ export function resumeTreeGate({ head, seed, dirty }: {
|
|
|
377
377
|
* @param {number} [opts.capRuns] forwarded
|
|
378
378
|
* @param {number} [opts.strikeLimit] forwarded (a plan step's strike ceiling)
|
|
379
379
|
* @param {number} [opts.closeTimeoutMs] forwarded
|
|
380
|
+
* @param {string} [opts.closeDir] forwarded (PRD item 27/M3 Part B)
|
|
380
381
|
* @param {boolean} [opts.layerRoot] forwarded
|
|
381
382
|
* @param {boolean|'cap'|'diff'} [opts.readShim] the read shim's ARM (A0/A1/A2/A3), forwarded verbatim
|
|
382
383
|
* @param {any} [opts.resume] RESUME (module C) — a `readResume` reading of the KILLED
|
|
@@ -411,6 +412,7 @@ export function runReuse(opts: {
|
|
|
411
412
|
capRuns?: number | undefined;
|
|
412
413
|
strikeLimit?: number | undefined;
|
|
413
414
|
closeTimeoutMs?: number | undefined;
|
|
415
|
+
closeDir?: string | undefined;
|
|
414
416
|
layerRoot?: boolean | undefined;
|
|
415
417
|
readShim?: boolean | "cap" | "diff" | undefined;
|
|
416
418
|
resume?: any;
|
package/types/reviewdoor.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export function doorAgeGate(door: any, { now, ttlMs }?: {
|
|
|
40
40
|
* @param {string} opts.decision one of the three doors
|
|
41
41
|
* @param {string|null} [opts.text] the rerun's words — the gap, and refused when empty
|
|
42
42
|
* @param {number} [opts.closeTimeoutMs] the per-stage bound for the accept's re-run
|
|
43
|
+
* @param {string|null} [opts.closeDir] the close's own books directory (PRD item 27/M3 Part B), forwarded to the accept's re-run
|
|
43
44
|
* @param {string|null} [opts.registryDir] the workflow registry, when the runner keeps one
|
|
44
45
|
* @param {string|null} [opts.name] the workflow this run wrote its row against
|
|
45
46
|
* @param {string|null} [opts.runid] the RUN's id, exactly as the bridge row records it
|
|
@@ -51,13 +52,14 @@ export function doorAgeGate(door: any, { now, ttlMs }?: {
|
|
|
51
52
|
* doorRecorded: boolean, reds: any[], mechanical: any, door: any, text: string|null,
|
|
52
53
|
* options: string[], ttlMs: number, note: string|null}>}
|
|
53
54
|
*/
|
|
54
|
-
export function answerReviewDoor({ job, workdir, events, decision, text, closeTimeoutMs, registryDir, name, runid, at, now, ttlMs, emit, }: {
|
|
55
|
+
export function answerReviewDoor({ job, workdir, events, decision, text, closeTimeoutMs, closeDir, registryDir, name, runid, at, now, ttlMs, emit, }: {
|
|
55
56
|
job: any;
|
|
56
57
|
workdir: string;
|
|
57
58
|
events: any[];
|
|
58
59
|
decision: string;
|
|
59
60
|
text?: string | null | undefined;
|
|
60
61
|
closeTimeoutMs?: number | undefined;
|
|
62
|
+
closeDir?: string | null | undefined;
|
|
61
63
|
registryDir?: string | null | undefined;
|
|
62
64
|
name?: string | null | undefined;
|
|
63
65
|
runid?: string | null | undefined;
|
package/types/run.d.ts
CHANGED
|
@@ -45,7 +45,22 @@
|
|
|
45
45
|
* CLOSE-FIX loop (a plan STEP runs under the strike ladder instead)
|
|
46
46
|
* @param {number} [opts.strikeLimit] shell-owned strike ceiling for a plan step's ladder
|
|
47
47
|
* @param {number} [opts.shellCapUsd] the shell's hard USD ceiling
|
|
48
|
-
* @param {number} [opts.closeTimeoutMs] close wall-clock cap (shell territory)
|
|
48
|
+
* @param {number} [opts.closeTimeoutMs] close wall-clock cap (shell territory).
|
|
49
|
+
* OPTIONAL as of PRD item 27/M3: absent, the plan flow autosets it from a $0
|
|
50
|
+
* seed timing pass (or reads the spec's own signed `closeTimeoutMs`
|
|
51
|
+
* override) — a caller passing an explicit value here still wins outright
|
|
52
|
+
* (backward compatibility / test control), but production callers
|
|
53
|
+
* (`src/cli.js`, `scripts/run-u.mjs`) pass nothing (F133, run mtqwmb9l: a
|
|
54
|
+
* runner that resolves this itself for its own purposes — e.g. `run-u.mjs`
|
|
55
|
+
* sizing its outside watchdog, F67 — must never feed the number back in
|
|
56
|
+
* here too, or this call's own autoset/override banner prints a SECOND,
|
|
57
|
+
* mislabelled "explicit runner override" line on top of the runner's own
|
|
58
|
+
* correctly-labelled one).
|
|
59
|
+
* @param {string|null} [opts.closeDir] the close's own books directory (PRD item
|
|
60
|
+
* 27/M3 Part B) — pristine copies, calibration thresholds, logs — outside
|
|
61
|
+
* the patient tree. Forwarded to every close invocation as
|
|
62
|
+
* `BARELOOP_CLOSE_DIR`; a close script that needs one and gets none
|
|
63
|
+
* instrument-stops itself (`checkCloseDirRequired`, src/close-integrity.js).
|
|
49
64
|
* @param {unknown} [opts.bridge] Layer 3 — a bridge-v1 entry to reuse as the drafter's
|
|
50
65
|
* STARTING DRAFT (design record 2026-08-01, D4), forwarded to the plan flow. Omitted is
|
|
51
66
|
* the cold path and is byte-identical to a pre-Layer-3 run. WHICH entry (the listing, an
|
|
@@ -141,13 +156,27 @@
|
|
|
141
156
|
* @param {{text: string, fromRunid?: string|null, receivedAt?: string|null}|null} [opts.doorRerun]
|
|
142
157
|
* MODULE 8 — this leg IS the fresh engagement a signer commissioned at a previous
|
|
143
158
|
* run's review door, carrying their words. Forwarded verbatim.
|
|
159
|
+
* @param {boolean} [opts.resumable=true] PRD item 27(c)/F130 — does THIS runner
|
|
160
|
+
* support `--resume` at all? `run-u.mjs` does (the default, `true`, byte-identical
|
|
161
|
+
* to before this param existed); the exported bundle CLI does not (F130) and
|
|
162
|
+
* passes `false` so the escalation tail's option strings say "resume is
|
|
163
|
+
* `run-u`-only in v1" instead of naming a flag that would fail if typed. Forwarded
|
|
164
|
+
* verbatim to the plan flow, which owns the three `--resume`-naming readouts.
|
|
144
165
|
* @returns {Promise<string>} outcome: 'green' | 'already-green' | 'escalated' |
|
|
145
166
|
* 'unapproved-spec' | 'job-red' | 'smoke-red' | 'plan-red' | 'check-red' |
|
|
146
167
|
* 'close-red' | 'close-unsupported' | 'recipe-stale' | 'branch-red' | 'pricing-red' | 'provider-red' |
|
|
147
168
|
* 'interpreter-red' | 'cap-halt' | 'wall-halt' | 'step-stalled' |
|
|
148
169
|
* 'hitl-pause' | 'hitl-decision-red' | `step-red:<id>`
|
|
170
|
+
* NOTE: `job-end` can ALSO land with outcome 'runner-drained' (F140/PRD item
|
|
171
|
+
* 28(c)) — the `beforeExit` backstop's own terminal, emitted from OUTSIDE this
|
|
172
|
+
* function's normal control flow when the process drains with no `job-end` at
|
|
173
|
+
* all (a provider promise that never settled). It never appears as this
|
|
174
|
+
* function's own RETURN value (nothing is left to receive it), only as the
|
|
175
|
+
* spine's terminal record. Non-zero exit, `spendComplete:false` always, and
|
|
176
|
+
* deliberately NOT in the resumable/checkpoint set (`src/reuse.js`) — an
|
|
177
|
+
* unknown in-flight state is not a known-safe resume point.
|
|
149
178
|
*/
|
|
150
|
-
export function runJob(rawSpec: object | string, { approvals, workdir, provider, nativeProvider, providerFor, judgeProvider, emit, capRuns, strikeLimit, shellCapUsd, closeTimeoutMs, layerRoot, readShim, scout, bridge, priorSpentUsd, priorSpendComplete, priorWallMs, resumeSeed, resumeGrades, resumeReplans, resumeBranch, humanRuling, heldRuling, reviewDoor, doorRerun }: {
|
|
179
|
+
export function runJob(rawSpec: object | string, { approvals, workdir, provider, nativeProvider, providerFor, judgeProvider, emit, capRuns, strikeLimit, shellCapUsd, closeTimeoutMs, closeDir, layerRoot, readShim, scout, bridge, priorSpentUsd, priorSpendComplete, priorWallMs, resumeSeed, resumeGrades, resumeReplans, resumeBranch, humanRuling, heldRuling, reviewDoor, doorRerun, resumable }: {
|
|
151
180
|
approvals: unknown;
|
|
152
181
|
workdir: string;
|
|
153
182
|
provider: any;
|
|
@@ -164,6 +193,7 @@ export function runJob(rawSpec: object | string, { approvals, workdir, provider,
|
|
|
164
193
|
strikeLimit?: number | undefined;
|
|
165
194
|
shellCapUsd?: number | undefined;
|
|
166
195
|
closeTimeoutMs?: number | undefined;
|
|
196
|
+
closeDir?: string | null | undefined;
|
|
167
197
|
bridge?: unknown;
|
|
168
198
|
priorSpentUsd?: number | undefined;
|
|
169
199
|
priorSpendComplete?: boolean | undefined;
|
|
@@ -196,6 +226,7 @@ export function runJob(rawSpec: object | string, { approvals, workdir, provider,
|
|
|
196
226
|
fromRunid?: string | null;
|
|
197
227
|
receivedAt?: string | null;
|
|
198
228
|
} | null | undefined;
|
|
229
|
+
resumable?: boolean | undefined;
|
|
199
230
|
}): Promise<string>;
|
|
200
231
|
/** @typedef {{code: string, path: string, detail?: string}} Red */
|
|
201
232
|
/**
|
package/types/transport.d.ts
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
* Is `err` a transport-class failure — the request never produced an HTTP
|
|
3
3
|
* response? True for: a TLS fault mid-record ("bad record mac" and kin), a
|
|
4
4
|
* reset/broken/timed-out socket (ECONNRESET, EPIPE, ETIMEDOUT, ECONNREFUSED,
|
|
5
|
-
* ENETUNREACH — by code on the error itself or on `err.cause`),
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* ENETUNREACH — by code on the error itself or on `err.cause`), `fetch
|
|
6
|
+
* failed` wrapping a network `cause`, and — as of bare-agent 0.42.0 (BA-25)
|
|
7
|
+
* — a `ProviderError` whose `err.context.bound === 'transport'`: the
|
|
8
|
+
* response stream ended (`'aborted'`/`'error'`/premature `'close'`) after
|
|
9
|
+
* headers but before the body completed, which bare-agent itself rejects as
|
|
10
|
+
* retryable with no HTTP status. False for anything carrying an HTTP status
|
|
11
|
+
* (`err.status`/`err.statusCode`, 4xx/5xx/429) or an explicit
|
|
8
12
|
* `err.retryable === false` — those are provider RESPONSES, not transport
|
|
9
|
-
* casualties, and bare-agent's own policy governs them unchanged
|
|
13
|
+
* casualties, and bare-agent's own policy governs them unchanged; both
|
|
14
|
+
* guards run BEFORE the `context.bound` check, so a status or an explicit
|
|
15
|
+
* `retryable:false` wins even if `bound` says 'transport'.
|
|
10
16
|
* @param {any} err
|
|
11
17
|
* @returns {boolean}
|
|
12
18
|
*/
|