bareloop 0.40.0 → 0.42.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 +96 -1
- package/README.md +13 -21
- package/bareloop.context.md +141 -128
- package/package.json +5 -4
- package/src/authorflow.js +346 -38
- package/src/authoring.js +92 -7
- package/src/authorjob.js +82 -20
- package/src/authorreadout.js +89 -5
- package/src/authorrun.js +39 -30
- package/src/authorscout.js +112 -4
- package/src/bundle.js +7 -4
- package/src/bundlerun.js +4 -1
- package/src/cli.js +1 -1
- package/src/config.js +129 -29
- package/src/declaredclose.js +23 -12
- package/src/draftspend.js +4 -4
- package/src/facts.js +317 -0
- package/src/factwords.js +129 -0
- package/src/index.js +2 -4
- package/src/inputlook.js +301 -0
- package/src/interviewrun.js +17 -25
- package/src/job.js +15 -8
- package/src/jobblock.js +7 -2
- package/src/judged.js +11 -43
- package/src/keysfile.js +15 -7
- package/src/kinds.js +86 -5
- package/src/labelscan.js +170 -0
- package/src/modellist.js +84 -0
- package/src/monthly.js +23 -43
- package/src/pagefetch.js +125 -0
- package/src/panel/authorroutes.js +34 -16
- package/src/panel/authorsession.js +161 -80
- package/src/panel/index.html +553 -152
- package/src/panel/jobplan.js +34 -11
- package/src/panel/runroutes.js +3 -0
- package/src/panel/server.js +54 -18
- package/src/panel/settingsroutes.js +232 -173
- package/src/planrun.js +5 -4
- package/src/providerrows.js +226 -141
- package/src/providers.js +58 -332
- package/src/providershapes.js +18 -0
- package/src/replay.js +1 -1
- package/src/rubricstep.js +804 -0
- package/src/source.js +166 -1
- package/src/thinking.js +130 -0
- package/src/u-readout.js +1 -1
- package/src/userrun.js +64 -75
- package/types/authorflow.d.ts +272 -18
- package/types/authoring.d.ts +29 -1
- package/types/authorjob.d.ts +9 -7
- package/types/authorreadout.d.ts +27 -2
- package/types/authorscout.d.ts +72 -2
- package/types/config.d.ts +23 -6
- package/types/declaredclose.d.ts +4 -2
- package/types/draftspend.d.ts +8 -8
- package/types/facts.d.ts +71 -0
- package/types/factwords.d.ts +42 -0
- package/types/index.d.ts +1 -1
- package/types/inputlook.d.ts +238 -0
- package/types/job.d.ts +5 -5
- package/types/jobblock.d.ts +8 -1
- package/types/judged.d.ts +5 -36
- package/types/keysfile.d.ts +15 -4
- package/types/labelscan.d.ts +38 -0
- package/types/modellist.d.ts +50 -0
- package/types/monthly.d.ts +4 -3
- package/types/pagefetch.d.ts +71 -0
- package/types/panel/authorsession.d.ts +20 -11
- package/types/panel/jobplan.d.ts +12 -4
- package/types/panel/server.d.ts +18 -6
- package/types/providerrows.d.ts +192 -99
- package/types/providers.d.ts +34 -159
- package/types/providershapes.d.ts +10 -0
- package/types/rubricstep.d.ts +286 -0
- package/types/source.d.ts +94 -0
- package/types/thinking.d.ts +90 -0
- package/types/userrun.d.ts +17 -1
package/src/userrun.js
CHANGED
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
// authored is preserved from the spine as a reusable artifact, and the next run of
|
|
26
26
|
// this shape reuses and fine-tunes it rather than starting cold.
|
|
27
27
|
import { readFileSync, writeFileSync, appendFileSync, mkdirSync, existsSync, rmSync, readdirSync, openSync, readSync, closeSync, fstatSync, unlinkSync } from 'node:fs';
|
|
28
|
-
import { createRequire } from 'node:module';
|
|
29
28
|
import { fileURLToPath } from 'node:url';
|
|
30
29
|
import { execFileSync, spawn } from 'node:child_process';
|
|
31
30
|
import { join, resolve, dirname, basename } from 'node:path';
|
|
@@ -43,7 +42,7 @@ import { makeSpine } from './spine.js';
|
|
|
43
42
|
// signed into the job spec — a job is a repeatable SHAPE, the source/
|
|
44
43
|
// destination a per-run value, exactly like `bareloop run <bundle> --repo
|
|
45
44
|
// <path>` varies the repo without touching the bundle's signature).
|
|
46
|
-
import { readSourceManifest, frontDoorFromManifest, proveDestination, copyOut } from './source.js';
|
|
45
|
+
import { readSourceManifest, frontDoorFromManifest, proveDestination, copyOut, refreezeUrlInputs } from './source.js';
|
|
47
46
|
import { scanSecrets, redactSecrets } from './validate.js';
|
|
48
47
|
import { runBehaviour, formatBehaviour } from './behaviour.js';
|
|
49
48
|
// the three doors' SEMANTICS live in the library; this script surfaces them
|
|
@@ -83,14 +82,11 @@ import { parseJsonl } from './replayio.js';
|
|
|
83
82
|
import { claimRun, monthlyRefusalText, legSpend, chainSpend } from './monthly.js';
|
|
84
83
|
import { ConfigError } from './config.js';
|
|
85
84
|
import { commandFor } from './invoke.js';
|
|
86
|
-
import {
|
|
85
|
+
import { judgeRatesFor, keyNameFor, keyValueOf, priceReadout, ratesFor, ratesOfLine, resolveWorker, judgeRowFor, rowsForHome, REFUSE_NAME_MODEL } from './providerrows.js';
|
|
87
86
|
// the banner's wall arithmetic, extracted so it is reachable by a test (F83): the
|
|
88
87
|
// end-of-run readout sits past the approval gate, so nothing could ever drive it here
|
|
89
88
|
import { wallLine, doomedResume, deathAtOf, evidencePackage, doorLines, resumeAtLines, reviewDoorPackage, runDoorLines, tokensLine, doorTimingRedLines } from './u-readout.js';
|
|
90
89
|
|
|
91
|
-
const require = createRequire(import.meta.url);
|
|
92
|
-
const { AnthropicProvider } = require('bare-agent/providers');
|
|
93
|
-
|
|
94
90
|
const JOBS = {
|
|
95
91
|
'aurora-spawner': {
|
|
96
92
|
spec: 'aurora-u-spawner-types.json',
|
|
@@ -174,10 +170,10 @@ const JOBS = {
|
|
|
174
170
|
},
|
|
175
171
|
// PRD item 28 / 30.9 — the openai-api probe through THIS runner (the shipped
|
|
176
172
|
// one), not poc-run-param.mjs. Same job shape, same seed, its own patient copy.
|
|
177
|
-
'bareguard-types-
|
|
178
|
-
spec: 'bareguard-u-types-
|
|
179
|
-
workdir: '/home/hamr/PycharmProjects/bareloop-patients/bareguard-u-
|
|
180
|
-
spine: 'bareguard-u-
|
|
173
|
+
'bareguard-types-gateway': {
|
|
174
|
+
spec: 'bareguard-u-types-gateway.json',
|
|
175
|
+
workdir: '/home/hamr/PycharmProjects/bareloop-patients/bareguard-u-gateway',
|
|
176
|
+
spine: 'bareguard-u-gateway-bareloop',
|
|
181
177
|
seed: '2ae8fcd37041c186524a6eb5e953b9752cd602fa',
|
|
182
178
|
},
|
|
183
179
|
// N4's hitl PROVING job (build plan §Proving; hamr's ruling, 2026-08-13). The job
|
|
@@ -239,6 +235,7 @@ class ExitSignal extends Error {
|
|
|
239
235
|
* @property {any} [provider] the TEST SEAM: supplying this skips the real-key
|
|
240
236
|
* check entirely, the same shape `src/cli.js`'s `main(argv, deps)` uses.
|
|
241
237
|
* @property {(tier: string) => any} [providerFor]
|
|
238
|
+
* @property {(url: string) => Promise<{ok: true, text: string, url: string}|{ok: false, error: string}>} [fetchUrl] PART 1c - a test seam: how a web input is read at run start (production: barebrowse)
|
|
242
239
|
* @property {any} [judgeProvider]
|
|
243
240
|
* @property {string} [runlistHome] F196 — a test seam for `appendRun`'s
|
|
244
241
|
* (src/runlist.js) `home` override, the same shape `deps.provider` already
|
|
@@ -273,7 +270,8 @@ class ExitSignal extends Error {
|
|
|
273
270
|
* @property {string} [into] the source door's own directory (`source.json`, and the spine directory beside it).
|
|
274
271
|
* Default `dirname(workdir)` — the copied-tree layout, where the tree is `<into>/tree`. A repo job on a WORKTREE
|
|
275
272
|
* (P6 item 1) has its tree inside the person's repo, so its `into` is passed explicitly.
|
|
276
|
-
* @property {string|null} [model] the raw `--model
|
|
273
|
+
* @property {string|null} [model] the raw `--model <id>` (a model id of a ticked Settings line), or null
|
|
274
|
+
* @property {string|null} [providerKey] the raw `--provider <KEY>` (a key's env name), or null
|
|
277
275
|
* @property {string|null} [readShim] the raw `--read-shim` arm name, or null for the default
|
|
278
276
|
* @property {string|null} [scout] the raw `--scout` value (`on`/`off`), or null for the default
|
|
279
277
|
* @property {string|null} [draftSpentUsd] the raw `--draft-spent-usd` value (hamr's
|
|
@@ -306,6 +304,7 @@ class ExitSignal extends Error {
|
|
|
306
304
|
* @property {string} spineName
|
|
307
305
|
* @property {string} [into] see `RunOpts.into`
|
|
308
306
|
* @property {string|null} model
|
|
307
|
+
* @property {string|null} providerKey
|
|
309
308
|
* @property {string|null} readShim
|
|
310
309
|
* @property {string|null} scout
|
|
311
310
|
* @property {string|null} draftSpentUsd
|
|
@@ -389,25 +388,13 @@ async function execute(ctx) {
|
|
|
389
388
|
/** @type {{workdir: string, seed: string, spine: string}} */
|
|
390
389
|
const target = { workdir: ctx.workdir, seed: ctx.seed, spine: ctx.spineName };
|
|
391
390
|
|
|
392
|
-
// --model
|
|
393
|
-
//
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
// (provider-gated, battery rule) — nothing to gate yet since neither tier sets effort.
|
|
398
|
-
// PRD v1.36 floor: the drafter/default tier is sonnet MINIMUM — measured, a haiku
|
|
399
|
-
// drafter died plan-red twice on the same rejection (ms7gne7s). `--model haiku` runs
|
|
400
|
-
// BELOW the floor: an explicit operator probe whose rows are probes, never battery
|
|
401
|
-
// evidence.
|
|
402
|
-
const DEFAULT_TIER_MODELS = { sonnet: 'claude-sonnet-5', haiku: 'claude-haiku-4-5-20251001' };
|
|
403
|
-
// `modelFlagArg` is null when --model was never passed at all — distinct from a
|
|
404
|
-
// flag that happens to resolve to the default tier's own id, because the SPEC
|
|
405
|
-
// (below, once loaded) needs to know whether a flag was actually given, not just
|
|
406
|
-
// what it resolved to (build-list #3: spec wins, a mismatched flag is refused).
|
|
391
|
+
// --model <id> names the Settings line a run works on when the SPEC names no model (an older spec, signed before a job carried its
|
|
392
|
+
// own); a spec's own `model` still wins and a different --model is refused. --provider <KEY> narrows to one key when two keys tick the
|
|
393
|
+
// same id. Runner territory: the spec names neither, so the signed hash is unaffected. There are no tier aliases and no built-in model.
|
|
394
|
+
// `modelFlagArg` is null when --model was never passed — distinct from a flag that happens to equal the spec's model, because the SPEC
|
|
395
|
+
// (below, once loaded) needs to know whether a flag was actually given (build-list #3: spec wins, a mismatched flag is refused).
|
|
407
396
|
const modelFlagArg = ctx.model ?? null;
|
|
408
|
-
const
|
|
409
|
-
const FLAG_TIER_MODEL = DEFAULT_TIER_MODELS[/** @type {keyof typeof DEFAULT_TIER_MODELS} */ (tierArg)];
|
|
410
|
-
if (!FLAG_TIER_MODEL) { err(`unknown --model "${tierArg}" — one of: ${Object.keys(DEFAULT_TIER_MODELS).join(', ')}`); throw new ExitSignal(2); }
|
|
397
|
+
const providerFlagArg = ctx.providerKey ?? null;
|
|
411
398
|
// --read-shim picks the READ SHIM's ARM (src/readshim.js, Phase 2 A0/A1/A2/A3). Runner
|
|
412
399
|
// territory exactly like --model: the spec names no shim, so the signed hash is
|
|
413
400
|
// unaffected. Phase 2 itself never flipped this default — its own "what this
|
|
@@ -545,11 +532,12 @@ async function execute(ctx) {
|
|
|
545
532
|
try {
|
|
546
533
|
modelResolution = resolveWorkerModel({
|
|
547
534
|
specModel: spec.model,
|
|
548
|
-
flagModel: modelFlagArg === null ? undefined :
|
|
549
|
-
|
|
535
|
+
flagModel: modelFlagArg === null ? undefined : modelFlagArg,
|
|
536
|
+
// a scripted provider handed in by a test IS the run: it names its own model; a real run has no default
|
|
537
|
+
suppliedModel: deps.provider ? String(/** @type {any} */ (deps.provider).model ?? 'scripted') : undefined,
|
|
550
538
|
});
|
|
551
539
|
} catch (e) {
|
|
552
|
-
die(/** @type {Error} */ (e).message);
|
|
540
|
+
die(spec.model === undefined && modelFlagArg === null ? REFUSE_NAME_MODEL : /** @type {Error} */ (e).message);
|
|
553
541
|
}
|
|
554
542
|
const MODEL = modelResolution.model;
|
|
555
543
|
const MODEL_LABEL = modelResolution.source === 'spec' ? `${MODEL} (spec)` : MODEL;
|
|
@@ -1022,16 +1010,20 @@ async function execute(ctx) {
|
|
|
1022
1010
|
// spine, then handed down as data (`runJob`'s `rates`) — nothing deep in the run re-reads config. A bad
|
|
1023
1011
|
// price refuses here; it never falls back to the built-in guess. No price set = `null` = no `rates` key
|
|
1024
1012
|
// passed anywhere, byte-identical to before. The judge's own row is resolved below, beside its key.
|
|
1025
|
-
const keyCfg = cfgOn ? rowsForHome(cfgHome) : [];
|
|
1013
|
+
const keyCfg = cfgOn ? rowsForHome(cfgHome, env) : [];
|
|
1026
1014
|
/** @type {ReturnType<typeof ratesFor>} */
|
|
1027
1015
|
let workerPrice = null;
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1016
|
+
// WHICH SETTINGS LINE THIS RUN WORKS ON (P8): the row is the key, the Base URL and the old-max_tokens tick; the line is the model
|
|
1017
|
+
// and its price. A scripted provider handed in by a test IS the run (no row). A refusal here is $0, before anything else.
|
|
1018
|
+
const W = deps.provider ? null : resolveWorker(keyCfg, spec, { model: modelFlagArg, provider: providerFlagArg });
|
|
1019
|
+
const refuseWorker = () => { if (W && !W.ok) { err(W.say.includes('Nothing was spent') ? W.say : `${W.say} Nothing was spent.`); throw new ExitSignal(2); } };
|
|
1020
|
+
// the preview cannot name its key without a line: refuse it here. A SIGNED run meets its other gates first (pause door, wall) and
|
|
1021
|
+
// is refused at the key check below — still before anything is spent
|
|
1022
|
+
if ((ctx.approve ?? null) === null) refuseWorker();
|
|
1023
|
+
/** the endpoint the worker talks to: the chosen row's own Base URL (a spec signed before addresses were required carries none) */
|
|
1024
|
+
const baseUrl = W && W.ok ? W.baseUrl : (typeof spec.baseUrl === 'string' ? spec.baseUrl : undefined);
|
|
1025
|
+
const wLine = W && W.ok ? ratesOfLine(W.line) : null;
|
|
1026
|
+
workerPrice = W ? (wLine && W.ok ? { ...wLine, envName: W.row.envName } : null) : ratesFor(spec.provider, spec.baseUrl, keyCfg, spec.model);
|
|
1035
1027
|
|
|
1036
1028
|
if ((ctx.approve ?? null) !== specHash) {
|
|
1037
1029
|
out(dead ? 'U — RESUME, continuing a halted run, REAL dollars' : 'U — user-mode e2e, ONE run, REAL dollars');
|
|
@@ -1192,7 +1184,7 @@ async function execute(ctx) {
|
|
|
1192
1184
|
// right key only by accident of the runner's own generic error message,
|
|
1193
1185
|
// never from this hint. `keyNameFor` is the same resolved name
|
|
1194
1186
|
// the real key check at launch reads (the person's row variable, else the provider's built-in one).
|
|
1195
|
-
const invoke = (/** @type {string} */ tail) => ` ${keyNameFor(spec.provider, spec.baseUrl, keyCfg, spec.model).name}=... ${INVOKE}${dead ? ` --resume ${RESUME}` : ''}${SHIM_TAIL}${SCOUT_TAIL}${DRAFT_TAIL}${REGISTRY_TAIL}${tail} --approve ${PRINT_APPROVE}`;
|
|
1187
|
+
const invoke = (/** @type {string} */ tail) => ` ${(W && W.ok ? W.row.envName : null) ?? keyNameFor(spec.provider, spec.baseUrl, keyCfg, spec.model).name ?? '<KEY>'}=... ${INVOKE}${dead ? ` --resume ${RESUME}` : ''}${SHIM_TAIL}${SCOUT_TAIL}${DRAFT_TAIL}${REGISTRY_TAIL}${tail} --approve ${PRINT_APPROVE}`;
|
|
1196
1188
|
/** the door the operator has already picked, as flags — hoisted out of the else
|
|
1197
1189
|
* below so the inhibitor line at the bottom can print the WHOLE command rather
|
|
1198
1190
|
* than a shape the operator has to assemble. Empty on an ordinary run and on the
|
|
@@ -1446,13 +1438,15 @@ async function execute(ctx) {
|
|
|
1446
1438
|
let judgePrice = null;
|
|
1447
1439
|
if (JUDGES) {
|
|
1448
1440
|
try {
|
|
1449
|
-
judgePrice = judgeRatesFor(judge, spec.provider,
|
|
1441
|
+
judgePrice = judgeRatesFor(judge, spec.provider, baseUrl, workerPrice, keyCfg);
|
|
1450
1442
|
} catch (e) {
|
|
1451
1443
|
if (!(e instanceof ConfigError)) throw e;
|
|
1452
1444
|
err(`${e.message} — refusing to start rather than guess a price. Nothing spent.`);
|
|
1453
1445
|
throw new ExitSignal(2);
|
|
1454
1446
|
}
|
|
1455
1447
|
}
|
|
1448
|
+
/** the row the judge's key (and endpoint) comes from: the worker's own row when the judge shares its provider, else the judge provider's row */
|
|
1449
|
+
const judgeRow = judgeRowFor(keyCfg, judge, spec.provider, W && W.ok ? W.row : null);
|
|
1456
1450
|
// undefined, not null: both come straight off `env[...]` lookups below, which
|
|
1457
1451
|
// (like process.env) never produce null for a missing key.
|
|
1458
1452
|
/** @type {string|undefined} */
|
|
@@ -1468,13 +1462,10 @@ async function execute(ctx) {
|
|
|
1468
1462
|
// row = the built-in. Names only — values come from the
|
|
1469
1463
|
// env / keys file. The judge follows the worker's choice when it is the same provider
|
|
1470
1464
|
// (the same rule that gives it the worker's baseUrl below).
|
|
1471
|
-
|
|
1472
|
-
const
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
// A green anthropic-api job's behaviour is byte-identical to before: its
|
|
1476
|
-
// worker key IS `ANTHROPIC_API_KEY`, demanded as ever.
|
|
1477
|
-
workerApiKey = workerEnv[providerEntry.envKey];
|
|
1465
|
+
refuseWorker();
|
|
1466
|
+
const workerKeyName = /** @type {NonNullable<typeof W> & {ok: true}} */ (W).row.envName;
|
|
1467
|
+
// A job's worker key is its Settings row's own variable — there is no built-in name.
|
|
1468
|
+
workerApiKey = keyValueOf(env, workerKeyName);
|
|
1478
1469
|
if (!workerApiKey) { err(`${workerKeyName} not set (secrets load from the environment — never the tree)`); throw new ExitSignal(2); }
|
|
1479
1470
|
// F181 — a key that reads as "set" above can still carry a line break/
|
|
1480
1471
|
// control char/stray whitespace (a two-line secret-store entry, e.g.) and
|
|
@@ -1487,10 +1478,10 @@ async function execute(ctx) {
|
|
|
1487
1478
|
// override matters most in the case this item exists for: a job whose worker and
|
|
1488
1479
|
// judge are the SAME provider but different accounts, and the anthropic case
|
|
1489
1480
|
// where one variable used to do two jobs.
|
|
1490
|
-
judgeApiKey = env.JUDGE_API_KEY ??
|
|
1481
|
+
judgeApiKey = env.JUDGE_API_KEY ?? keyValueOf(env, judgeRow?.envName);
|
|
1491
1482
|
if (JUDGES && !judgeApiKey) {
|
|
1492
1483
|
err(`This job's close JUDGES (${judgedStages(spec.closeDecl).length} judged stage(s)) and its judge is ${judge.model} on ${judge.provider}${spec.judge ? ' (signed override)' : " (this job's own worker model — no `judge` override signed)"}.`);
|
|
1493
|
-
err(`Neither JUDGE_API_KEY nor ${
|
|
1484
|
+
err(`Neither JUDGE_API_KEY nor ${judgeRow?.envName ?? `a key row for ${judge.provider}`} is set — secrets load from the environment, never the tree.`);
|
|
1494
1485
|
err('Refused at $0, BEFORE the worker spends anything: a judged run that discovers this at the close has paid for a verdict it cannot render.');
|
|
1495
1486
|
throw new ExitSignal(2);
|
|
1496
1487
|
}
|
|
@@ -1500,7 +1491,7 @@ async function execute(ctx) {
|
|
|
1500
1491
|
if (JUDGES) {
|
|
1501
1492
|
const judgeKeyProblem = apiKeyProblem(/** @type {string} */ (judgeApiKey));
|
|
1502
1493
|
if (judgeKeyProblem) {
|
|
1503
|
-
const judgeEnvName = env.JUDGE_API_KEY ? 'JUDGE_API_KEY' :
|
|
1494
|
+
const judgeEnvName = env.JUDGE_API_KEY ? 'JUDGE_API_KEY' : (judgeRow?.envName ?? judge.provider);
|
|
1504
1495
|
err(`${judgeEnvName} ${judgeKeyProblem} — refusing rather than crashing mid-call (never trimmed or repaired; fix the value at its source)`);
|
|
1505
1496
|
throw new ExitSignal(2);
|
|
1506
1497
|
}
|
|
@@ -1640,7 +1631,7 @@ async function execute(ctx) {
|
|
|
1640
1631
|
// OpenAI-compatible gateway/endpoint. Undefined for anthropic-api jobs and
|
|
1641
1632
|
// for an openai-api job that names none (bare-agent's OpenAIProvider then
|
|
1642
1633
|
// defaults to api.openai.com/v1 on its own).
|
|
1643
|
-
|
|
1634
|
+
// (`baseUrl` — the worker row's Base URL — was resolved above with the Settings line)
|
|
1644
1635
|
// TEST SEAM — same shape as the bundle door (src/bundlerun.js): a caller that supplies
|
|
1645
1636
|
// `deps.provider` skips the real-key check above entirely and this
|
|
1646
1637
|
// construction never runs (a scripted provider IS the run).
|
|
@@ -1648,26 +1639,11 @@ async function execute(ctx) {
|
|
|
1648
1639
|
let providerFor = deps.providerFor;
|
|
1649
1640
|
let judgeProvider = deps.judgeProvider ?? null;
|
|
1650
1641
|
if (!provider) {
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
//
|
|
1654
|
-
//
|
|
1655
|
-
|
|
1656
|
-
// battery rule) - nothing to gate yet since neither tier sets effort params.
|
|
1657
|
-
// `sonnet` maps to the RESOLVED worker model (MODEL — spec/flag/default), not the
|
|
1658
|
-
// bare provider-table id, so a spec-named model reaches every plan step's own
|
|
1659
|
-
// provider (STEP_MODELS is sonnet-only), not just the top-level `provider` above.
|
|
1660
|
-
// ONLY when the SPEC named it: a `--model haiku` probe keeps its old reach (the
|
|
1661
|
-
// top-level provider), never silently widening into every step's tier. The tier
|
|
1662
|
-
// table itself comes from `providerEntry` (src/providers.js) — for openai-api
|
|
1663
|
-
// today that means BOTH tiers resolve to the same `deepseek-flash` id (hamr's
|
|
1664
|
-
// ruling, PRD 30.7: one secondary provider, not a menu; swapped from the
|
|
1665
|
-
// retired `deepseek-chat`, F171), so a `--model haiku` probe against an
|
|
1666
|
-
// openai-api job harmlessly re-resolves to the same model.
|
|
1667
|
-
const TIER_MODELS = modelResolution.source === 'spec' ? { ...providerEntry.tiers, sonnet: MODEL } : providerEntry.tiers;
|
|
1668
|
-
/** @type {Record<string, any>} */
|
|
1669
|
-
const tierCache = {};
|
|
1670
|
-
providerFor = (/** @type {string} */ tier) => (tierCache[tier] ??= TIER_MODELS[/** @type {keyof typeof TIER_MODELS} */ (tier)] === MODEL ? provider : makeProvider(spec.provider, { apiKey: /** @type {string} */ (workerApiKey), model: TIER_MODELS[/** @type {keyof typeof TIER_MODELS} */ (tier)], baseUrl }));
|
|
1642
|
+
const legacyMaxTokens = W && W.ok ? W.row.legacyMaxTokens : false;
|
|
1643
|
+
provider = makeProvider(spec.provider, { apiKey: /** @type {string} */ (workerApiKey), model: MODEL, baseUrl, legacyMaxTokens });
|
|
1644
|
+
// P: the per-step model factory. The ONLY tier a plan may name is the schema token `sonnet` (STEP_MODELS, src/plan.js — a
|
|
1645
|
+
// documented schema token, not a model id); it means THIS job's worker model, so every step's provider is the one above.
|
|
1646
|
+
providerFor = () => provider;
|
|
1671
1647
|
// SOFTGREEN — the JUDGED stage's own provider. Since PRD item 32.1 its identity is
|
|
1672
1648
|
// RESOLVED (`judge` above), not pinned: the spec's signed `judge` override, else this
|
|
1673
1649
|
// job's own worker model. It is still never a step knob and never agent-selectable —
|
|
@@ -1684,7 +1660,7 @@ async function execute(ctx) {
|
|
|
1684
1660
|
// every live softgreen run would have done: run-author wired this seam and this
|
|
1685
1661
|
// runner never did.
|
|
1686
1662
|
judgeProvider = judgeApiKey
|
|
1687
|
-
? makeProvider(judge.provider, { apiKey: /** @type {string} */ (judgeApiKey), model: judge.model, baseUrl: judge.provider === spec.provider ? baseUrl : undefined })
|
|
1663
|
+
? makeProvider(judge.provider, { apiKey: /** @type {string} */ (judgeApiKey), model: judge.model, baseUrl: judge.provider === spec.provider ? baseUrl : (judgeRow && judgeRow.baseUrl.trim() !== '' ? judgeRow.baseUrl.trim() : undefined), legacyMaxTokens: judgeRow ? judgeRow.legacyMaxTokens : false })
|
|
1688
1664
|
: null;
|
|
1689
1665
|
}
|
|
1690
1666
|
|
|
@@ -2433,6 +2409,7 @@ function buildCtx(mode, opts) {
|
|
|
2433
2409
|
spineName: /** @type {string} */ (opts.spineName),
|
|
2434
2410
|
...(opts.into === undefined ? {} : { into: opts.into }),
|
|
2435
2411
|
model: opts.model ?? null,
|
|
2412
|
+
providerKey: opts.providerKey ?? null,
|
|
2436
2413
|
readShim: opts.readShim ?? null,
|
|
2437
2414
|
scout: opts.scout ?? null,
|
|
2438
2415
|
draftSpentUsd: opts.draftSpentUsd ?? null,
|
|
@@ -2616,13 +2593,24 @@ export async function main(argv, deps = {}) {
|
|
|
2616
2593
|
+ 'with exactly one source-*/ sibling.');
|
|
2617
2594
|
}
|
|
2618
2595
|
const into = candidates[0];
|
|
2619
|
-
|
|
2596
|
+
let manifestRead = await readSourceManifest(into);
|
|
2620
2597
|
if (manifestRead.stop !== null) {
|
|
2621
2598
|
die(`--spec ${specPath}: ${manifestRead.code} — ${manifestRead.stop}`);
|
|
2622
2599
|
}
|
|
2623
2600
|
if (!manifestRead.present || !manifestRead.manifest) {
|
|
2624
2601
|
die(`--spec ${specPath}: ${into} carries no source.json — not a prepared copy this runner can trust`);
|
|
2625
2602
|
}
|
|
2603
|
+
// PART 1c (RF22): a FRESH run of a rubric job with web inputs fetches each address again and makes that text the run's frozen
|
|
2604
|
+
// input BEFORE the worker starts (the drafting copy was only for the look). A resume / door / decision keeps the copy its
|
|
2605
|
+
// first start froze. A refusal is plain words, $0.
|
|
2606
|
+
if (argFlag('resume') === null && argFlag('door') === null && argFlag('decide') === null) {
|
|
2607
|
+
const fresh = await refreezeUrlInputs({ into, ...(deps.fetchUrl ? { fetchUrl: deps.fetchUrl } : {}) });
|
|
2608
|
+
if (!fresh.ok) die(`--spec ${specPath}: ${fresh.error}`);
|
|
2609
|
+
if (fresh.refreshed.length > 0) {
|
|
2610
|
+
manifestRead = await readSourceManifest(into);
|
|
2611
|
+
if (manifestRead.stop !== null || !manifestRead.manifest) die(`--spec ${specPath}: the run copy's record could not be read after the fresh fetch`);
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2626
2614
|
const seed = manifestRead.manifest.seed;
|
|
2627
2615
|
if (typeof seed !== 'string' || !seed) {
|
|
2628
2616
|
die(`--spec ${specPath}: ${into}/source.json carries no seed commit — not a prepared copy this runner can trust`);
|
|
@@ -2661,6 +2649,7 @@ export async function main(argv, deps = {}) {
|
|
|
2661
2649
|
spineName: target.spine,
|
|
2662
2650
|
...(target.into === undefined ? {} : { into: target.into }),
|
|
2663
2651
|
model: argFlag('model'),
|
|
2652
|
+
providerKey: argFlag('provider'),
|
|
2664
2653
|
readShim: argFlag('read-shim'),
|
|
2665
2654
|
scout: argFlag('scout'),
|
|
2666
2655
|
draftSpentUsd: argFlag('draft-spent-usd'),
|