bareloop 0.39.0 → 0.41.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 +60 -0
- package/bareloop.context.md +137 -112
- package/package.json +2 -2
- package/src/authorflow.js +333 -58
- package/src/authoring.js +65 -2
- package/src/authorjob.js +57 -9
- package/src/authorreadout.js +50 -2
- package/src/authorrun.js +30 -27
- package/src/authorscout.js +9 -6
- package/src/bridges.js +1 -1
- package/src/bundle.js +7 -4
- package/src/bundlerun.js +4 -1
- package/src/calibrate.js +1 -1
- package/src/cardauthor.js +4 -1
- package/src/cli.js +1 -1
- package/src/config.js +129 -29
- package/src/declaredclose.js +4 -3
- package/src/draftspend.js +6 -1
- package/src/index.js +2 -4
- package/src/interviewrun.js +73 -52
- package/src/job.js +50 -11
- package/src/jobblock.js +140 -0
- package/src/judged.js +12 -44
- package/src/keysfile.js +15 -7
- package/src/kinds.js +2 -2
- package/src/ledger.js +1 -1
- package/src/modellist.js +84 -0
- package/src/monthly.js +23 -43
- package/src/panel/authorroutes.js +34 -19
- package/src/panel/authorsession.js +187 -72
- package/src/panel/index.html +699 -215
- package/src/panel/jobplan.js +107 -0
- package/src/panel/runroutes.js +3 -0
- package/src/panel/server.js +102 -28
- package/src/panel/settingsroutes.js +232 -173
- package/src/planrun.js +6 -6
- package/src/promptregisters.js +1 -1
- package/src/providerrows.js +226 -141
- package/src/providers.js +58 -250
- package/src/providershapes.js +18 -0
- package/src/replay.js +1 -1
- package/src/reuse.js +1 -1
- package/src/root.js +1 -1
- package/src/run.js +3 -3
- package/src/selection.js +1 -1
- package/src/source.js +64 -1
- package/src/text.js +13 -0
- package/src/thinking.js +130 -0
- package/src/transport.js +1 -1
- package/src/userrun.js +53 -76
- package/types/authorflow.d.ts +258 -39
- package/types/authoring.d.ts +7 -1
- package/types/authorjob.d.ts +35 -3
- package/types/authorreadout.d.ts +17 -1
- package/types/authorscout.d.ts +5 -3
- package/types/config.d.ts +23 -6
- package/types/declaredclose.d.ts +4 -1
- package/types/draftspend.d.ts +8 -2
- package/types/index.d.ts +1 -1
- package/types/job.d.ts +6 -6
- package/types/jobblock.d.ts +102 -0
- package/types/judged.d.ts +5 -36
- package/types/keysfile.d.ts +15 -4
- package/types/modellist.d.ts +50 -0
- package/types/monthly.d.ts +4 -3
- package/types/panel/authorsession.d.ts +44 -15
- package/types/panel/jobplan.d.ts +58 -0
- package/types/panel/server.d.ts +34 -4
- package/types/planrun.d.ts +1 -1
- package/types/providerrows.d.ts +192 -99
- package/types/providers.d.ts +35 -116
- package/types/providershapes.d.ts +10 -0
- package/types/run.d.ts +1 -1
- package/types/source.d.ts +26 -0
- package/types/thinking.d.ts +90 -0
- package/types/userrun.d.ts +6 -1
package/types/providerrows.d.ts
CHANGED
|
@@ -7,26 +7,26 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export function usableKey<T extends string | undefined>(raw: T): T | string;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* The model lines of a row, pure (no I/O, no rewrite of the file). A row WITH `models.<ENV>` uses
|
|
11
|
+
* that list and ignores `keys.<ENV>.{name,priceInPerM,priceOutPerM}`. A row WITHOUT it whose
|
|
12
|
+
* `keys.<ENV>.name` is a non-empty saved string reads as ONE line: ticked when BOTH older prices
|
|
13
|
+
* are finite numbers >= 0 (the line carries them), else UNTICKED with no price (a ticked line
|
|
14
|
+
* needs both prices). A row with no saved name reads as no lines — nothing is carried from a
|
|
15
|
+
* built-in table.
|
|
12
16
|
* @param {string} envName
|
|
13
|
-
* @
|
|
17
|
+
* @param {Record<string, any>} config
|
|
18
|
+
* @returns {ModelLine[]}
|
|
14
19
|
*/
|
|
15
|
-
export function
|
|
16
|
-
name: string;
|
|
17
|
-
shape: string;
|
|
18
|
-
baseUrl: string;
|
|
19
|
-
};
|
|
20
|
+
export function effectiveModels(envName: string, config: Record<string, any>): ModelLine[];
|
|
20
21
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @
|
|
23
|
-
* @
|
|
24
|
-
* @property {string} provider the `src/providers.js` table entry (the API shape's id)
|
|
25
|
-
* @property {string} baseUrl the saved Base URL ('' = the shape's default host)
|
|
26
|
-
* @property {unknown} [priceInPerM] the customer's own price, USD per 1M input tokens — carried RAW
|
|
27
|
-
* (present only when the config row names it); {@link ratesFor} is the one place that validates it
|
|
28
|
-
* @property {unknown} [priceOutPerM] the same, for output tokens
|
|
22
|
+
* Every ticked-and-priced line of the rows, in keys-file order.
|
|
23
|
+
* @param {readonly KeyRow[]} rows
|
|
24
|
+
* @returns {{ row: KeyRow, line: ModelLine }[]}
|
|
29
25
|
*/
|
|
26
|
+
export function tickedLines(rows: readonly KeyRow[]): {
|
|
27
|
+
row: KeyRow;
|
|
28
|
+
line: ModelLine;
|
|
29
|
+
}[];
|
|
30
30
|
/**
|
|
31
31
|
* The rows: one per name in `filled`, saved entry over defaults.
|
|
32
32
|
* @param {{ filled: readonly string[], config: Record<string, any> }} src
|
|
@@ -37,20 +37,33 @@ export function keyRows({ filled, config }: {
|
|
|
37
37
|
config: Record<string, any>;
|
|
38
38
|
}): KeyRow[];
|
|
39
39
|
/**
|
|
40
|
-
* The rows
|
|
41
|
-
*
|
|
40
|
+
* The key names that make rows: every key in the keys file with a value (file order), plus — when `env` is given — a key only the
|
|
41
|
+
* SHELL holds that config already names (`keys.<ENV>` or `models.<ENV>`), sorted after them. The page shows such a row as
|
|
42
|
+
* "found in shell"; the run path must resolve it the same way.
|
|
43
|
+
* @param {readonly string[]} filled the keys file's filled names
|
|
44
|
+
* @param {Record<string, any>} config
|
|
45
|
+
* @param {Record<string, string|undefined>} [env] the shell side
|
|
46
|
+
* @returns {string[]}
|
|
47
|
+
*/
|
|
48
|
+
export function rowNamesOf(filled: readonly string[], config: Record<string, any>, env?: Record<string, string | undefined>): string[];
|
|
49
|
+
/**
|
|
50
|
+
* The rows for a keys home. `undefined` home (a door that skipped the keys file) = no rows. With `env`, a shell-only key that
|
|
51
|
+
* config names is a row too ({@link rowNamesOf}).
|
|
42
52
|
* @param {string|undefined} home
|
|
53
|
+
* @param {Record<string, string|undefined>} [env]
|
|
43
54
|
* @returns {KeyRow[]}
|
|
44
55
|
*/
|
|
45
|
-
export function rowsForHome(home: string | undefined): KeyRow[];
|
|
56
|
+
export function rowsForHome(home: string | undefined, env?: Record<string, string | undefined>): KeyRow[];
|
|
46
57
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
58
|
+
* EVERY row a config home names, keyed or not: the keys file's filled names plus every name `keys.<ENV>` / `models.<ENV>` carries. For
|
|
59
|
+
* a readout that must say which variable a model line WOULD read ("KEY is not set in this shell") before any key exists. Never for a run.
|
|
60
|
+
* @param {string|undefined} home
|
|
61
|
+
* @returns {KeyRow[]}
|
|
49
62
|
*/
|
|
50
|
-
export function
|
|
63
|
+
export function namedRowsForHome(home: string | undefined): KeyRow[];
|
|
51
64
|
/**
|
|
52
|
-
* An endpoint in comparable form:
|
|
53
|
-
*
|
|
65
|
+
* An endpoint in comparable form: scheme + host lower-cased, trailing slashes dropped. A blank
|
|
66
|
+
* Base URL is blank — there is no default host.
|
|
54
67
|
* @param {string} provider
|
|
55
68
|
* @param {string|null|undefined} baseUrl
|
|
56
69
|
* @returns {string}
|
|
@@ -58,8 +71,7 @@ export function defaultUrlOf(provider: string): string;
|
|
|
58
71
|
export function endpointOf(provider: string, baseUrl: string | null | undefined): string;
|
|
59
72
|
/**
|
|
60
73
|
* A job's provider in plain words for a refusal line: the host its Base URL points at (else the
|
|
61
|
-
* shape's
|
|
62
|
-
* Never a key, a path or a status code.
|
|
74
|
+
* shape's label), plus the model when the spec names one. Never a key, a path or a status code.
|
|
63
75
|
* @param {{provider?: string, baseUrl?: string|null, model?: string|null}} spec
|
|
64
76
|
* @returns {string}
|
|
65
77
|
*/
|
|
@@ -68,15 +80,10 @@ export function providerInWords(spec: {
|
|
|
68
80
|
baseUrl?: string | null;
|
|
69
81
|
model?: string | null;
|
|
70
82
|
}): string;
|
|
71
|
-
/**
|
|
72
|
-
* The URL a row talks to, for display ('' = the vendor's own host, which has no URL to show).
|
|
73
|
-
* @param {KeyRow} row
|
|
74
|
-
* @returns {string}
|
|
75
|
-
*/
|
|
76
|
-
export function shownUrl(row: KeyRow): string;
|
|
77
83
|
/**
|
|
78
84
|
* Which row a `(provider, baseUrl[, model])` identity belongs to: the rows on that shape and
|
|
79
|
-
* endpoint; when several share it, the one
|
|
85
|
+
* endpoint; when several share it, the one that HAS a ticked-and-priced line for `model`, else
|
|
86
|
+
* the first.
|
|
80
87
|
* @param {readonly KeyRow[]} rows
|
|
81
88
|
* @param {{ provider?: string|null, baseUrl?: string|null, model?: string|null }} id
|
|
82
89
|
* @returns {KeyRow|null}
|
|
@@ -87,56 +94,97 @@ export function findRow(rows: readonly KeyRow[], { provider, baseUrl, model }: {
|
|
|
87
94
|
model?: string | null;
|
|
88
95
|
}): KeyRow | null;
|
|
89
96
|
/**
|
|
90
|
-
*
|
|
91
|
-
* (
|
|
97
|
+
* How a Model-menu pick resolves: the row named by `provider` (its key's env name) with a ticked-and-priced line for `model`.
|
|
98
|
+
* With no `provider` (an older caller) the first row ticking the model. `baseUrl` is absent when blank, exactly as a spec omits it.
|
|
99
|
+
* A model no row ticks, or a row that does not tick it, is `null` — never offered, never run.
|
|
92
100
|
* @param {readonly KeyRow[]} rows
|
|
93
|
-
* @param {string}
|
|
94
|
-
* @returns {{ provider: string, baseUrl?: string, envName: string, name: string }|null}
|
|
101
|
+
* @param {{ provider?: string|null, model?: string|null }} pick `provider` is the KEY's env name
|
|
102
|
+
* @returns {{ provider: string, baseUrl?: string, envName: string, name: string, legacyMaxTokens: boolean }|null}
|
|
95
103
|
*/
|
|
96
|
-
export function modelChoiceFor(rows: readonly KeyRow[], model
|
|
104
|
+
export function modelChoiceFor(rows: readonly KeyRow[], { provider, model }: {
|
|
105
|
+
provider?: string | null;
|
|
106
|
+
model?: string | null;
|
|
107
|
+
}): {
|
|
97
108
|
provider: string;
|
|
98
109
|
baseUrl?: string;
|
|
99
110
|
envName: string;
|
|
100
111
|
name: string;
|
|
112
|
+
legacyMaxTokens: boolean;
|
|
101
113
|
} | null;
|
|
102
114
|
/**
|
|
103
|
-
* The
|
|
115
|
+
* The lines Chat's Model menu offers: every ticked-and-priced line of the rows, in keys-file order, labelled `<KEY> · <model>`.
|
|
104
116
|
* @param {readonly KeyRow[]} rows
|
|
105
|
-
* @returns {{
|
|
117
|
+
* @returns {{ slot: string, model: string, label: string }[]}
|
|
106
118
|
*/
|
|
107
|
-
export function
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
export function chatLines(rows: readonly KeyRow[]): {
|
|
120
|
+
slot: string;
|
|
121
|
+
model: string;
|
|
122
|
+
label: string;
|
|
111
123
|
}[];
|
|
112
124
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
125
|
+
* Judge a Model-menu pick `{provider, model}` against the rows, for the doors that start a session. `ok:true` carries the choice;
|
|
126
|
+
* otherwise the plain refusal (one of the three sentences).
|
|
127
|
+
* @param {readonly KeyRow[]} rows
|
|
128
|
+
* @param {{ provider?: string|null, model?: string|null }} pick
|
|
129
|
+
* @returns {{ ok: true, choice: NonNullable<ReturnType<typeof modelChoiceFor>> } | { ok: false, say: string }}
|
|
130
|
+
*/
|
|
131
|
+
export function judgePick(rows: readonly KeyRow[], pick: {
|
|
132
|
+
provider?: string | null;
|
|
133
|
+
model?: string | null;
|
|
134
|
+
}): {
|
|
135
|
+
ok: true;
|
|
136
|
+
choice: NonNullable<ReturnType<typeof modelChoiceFor>>;
|
|
137
|
+
} | {
|
|
138
|
+
ok: false;
|
|
139
|
+
say: string;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Which Settings line a RUN works on. A spec's own `model` wins; a spec that names none (signed before models were required)
|
|
143
|
+
* takes `--model <id>`; a spec with no `baseUrl` (the same era) matches a row on any endpoint of its shape. `--provider <KEY>`
|
|
144
|
+
* narrows to one key when two keys tick the same id. Pure; the signed spec is never changed, so its hash is untouched.
|
|
145
|
+
* @param {readonly KeyRow[]} rows
|
|
146
|
+
* @param {{ provider?: string|null, baseUrl?: string|null, model?: string|null }} spec the signed spec's worker fields
|
|
147
|
+
* @param {{ model?: string|null, provider?: string|null }} [flags] the operator's `--model` / `--provider`
|
|
148
|
+
* @returns {{ ok: true, row: KeyRow, line: ModelLine, model: string, baseUrl: string|undefined } | { ok: false, say: string }}
|
|
149
|
+
*/
|
|
150
|
+
export function resolveWorker(rows: readonly KeyRow[], spec: {
|
|
151
|
+
provider?: string | null;
|
|
152
|
+
baseUrl?: string | null;
|
|
153
|
+
model?: string | null;
|
|
154
|
+
}, flags?: {
|
|
155
|
+
model?: string | null;
|
|
156
|
+
provider?: string | null;
|
|
157
|
+
}): {
|
|
158
|
+
ok: true;
|
|
159
|
+
row: KeyRow;
|
|
160
|
+
line: ModelLine;
|
|
161
|
+
model: string;
|
|
162
|
+
baseUrl: string | undefined;
|
|
163
|
+
} | {
|
|
164
|
+
ok: false;
|
|
165
|
+
say: string;
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* The key variable NAME a job on `(provider, baseUrl[, model])` reads: the matching row's own env name. There is NO built-in
|
|
169
|
+
* name: no matching row = no key (`name: null`).
|
|
116
170
|
* @param {string|null|undefined} provider
|
|
117
171
|
* @param {string|null|undefined} baseUrl
|
|
118
172
|
* @param {readonly KeyRow[]} rows
|
|
119
173
|
* @param {string|null|undefined} [model]
|
|
120
|
-
* @returns {{ name: string,
|
|
174
|
+
* @returns {{ name: string|null, chosen: boolean }}
|
|
121
175
|
*/
|
|
122
176
|
export function keyNameFor(provider: string | null | undefined, baseUrl: string | null | undefined, rows: readonly KeyRow[], model?: string | null | undefined): {
|
|
123
|
-
name: string;
|
|
124
|
-
builtIn: string;
|
|
177
|
+
name: string | null;
|
|
125
178
|
chosen: boolean;
|
|
126
179
|
};
|
|
127
180
|
/**
|
|
128
|
-
* The
|
|
129
|
-
*
|
|
130
|
-
* no-key marker becomes {@link NO_KEY_PLACEHOLDER}). A copy — never mutates the input.
|
|
131
|
-
* No matching row and no marker = the env unchanged.
|
|
181
|
+
* The key VALUE for a row's env name out of an env (the `null` no-key marker becomes {@link NO_KEY_PLACEHOLDER}); `undefined`
|
|
182
|
+
* when the row's variable is unset or empty.
|
|
132
183
|
* @param {Record<string,string|undefined>} env
|
|
133
|
-
* @param {string|null|undefined}
|
|
134
|
-
* @
|
|
135
|
-
* @param {readonly KeyRow[]} rows
|
|
136
|
-
* @param {string|null|undefined} [model]
|
|
137
|
-
* @returns {Record<string,string|undefined>}
|
|
184
|
+
* @param {string|null|undefined} envName
|
|
185
|
+
* @returns {string|undefined}
|
|
138
186
|
*/
|
|
139
|
-
export function
|
|
187
|
+
export function keyValueOf(env: Record<string, string | undefined>, envName: string | null | undefined): string | undefined;
|
|
140
188
|
/**
|
|
141
189
|
* The one readout line for a resolved customer price, preview and run tail alike:
|
|
142
190
|
* `yours: in $0.006 / out $1.20 per 1M tokens (DEEPSEEK_API_KEY row)`. A 0 / 0 price is accepted (the price
|
|
@@ -150,12 +198,12 @@ export function priceReadout(price: {
|
|
|
150
198
|
envName: string;
|
|
151
199
|
}): string;
|
|
152
200
|
/**
|
|
153
|
-
* The customer's own price for the row a `(provider, baseUrl[, model])` identity
|
|
154
|
-
* the SAME row match {@link keyNameFor} uses (`findRow`), so the price and the key
|
|
155
|
-
* from one row.
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
201
|
+
* The customer's own price for the model LINE of the row a `(provider, baseUrl[, model])` identity
|
|
202
|
+
* belongs to — the SAME row match {@link keyNameFor} uses (`findRow`), so the price and the key
|
|
203
|
+
* always come from one row. With a `model`, the row's line of that name; without one, the row's
|
|
204
|
+
* first ticked line. `null` = no price set (the run keeps bare-agent's built-in guess). A line's
|
|
205
|
+
* price is a pair or nothing ({@link modelsProblem} guards the file), so a half price never
|
|
206
|
+
* reaches here. `rates` is bare-agent's `Loop({ rates })` shape (USD per 1K); `inPerM`/`outPerM`
|
|
159
207
|
* are what a readout prints.
|
|
160
208
|
* @param {string|null|undefined} provider
|
|
161
209
|
* @param {string|null|undefined} baseUrl
|
|
@@ -173,13 +221,38 @@ export function ratesFor(provider: string | null | undefined, baseUrl: string |
|
|
|
173
221
|
envName: string;
|
|
174
222
|
} | null;
|
|
175
223
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
224
|
+
* A model line's own price in bare-agent's shape, or `null` when the line carries none (a price is a pair or nothing).
|
|
225
|
+
* @param {ModelLine} line
|
|
226
|
+
* @returns {{ rates: { in: number, out: number }, inPerM: number, outPerM: number }|null}
|
|
227
|
+
*/
|
|
228
|
+
export function ratesOfLine(line: ModelLine): {
|
|
229
|
+
rates: {
|
|
230
|
+
in: number;
|
|
231
|
+
out: number;
|
|
232
|
+
};
|
|
233
|
+
inPerM: number;
|
|
234
|
+
outPerM: number;
|
|
235
|
+
} | null;
|
|
236
|
+
/**
|
|
237
|
+
* The row a judge's key and endpoint come from: the worker's own row when the judge shares the worker's API shape, else the judge
|
|
238
|
+
* shape's row that ticks the judge's model (else the first row of that shape). `null` when no row is on that shape.
|
|
239
|
+
* @param {readonly KeyRow[]} rows
|
|
240
|
+
* @param {{ provider: string, model?: string|null }} judge
|
|
241
|
+
* @param {string|null|undefined} workerProvider
|
|
242
|
+
* @param {KeyRow|null} workerRow
|
|
243
|
+
* @returns {KeyRow|null}
|
|
244
|
+
*/
|
|
245
|
+
export function judgeRowFor(rows: readonly KeyRow[], judge: {
|
|
246
|
+
provider: string;
|
|
247
|
+
model?: string | null;
|
|
248
|
+
}, workerProvider: string | null | undefined, workerRow: KeyRow | null): KeyRow | null;
|
|
249
|
+
/**
|
|
250
|
+
* The price a judge's rounds are booked at. A price belongs to the MODEL's line: when the judge is
|
|
251
|
+
* the worker's own provider it calls the worker's endpoint, so a row on that endpoint with a line
|
|
252
|
+
* NAMED for the judge's model prices it ({@link ratesFor}); a judge model that is absent or names
|
|
253
|
+
* no line there keeps the worker's price (the worker's row, or none = the guess). A different
|
|
254
|
+
* provider resolves with no endpoint. The judge's KEY is chosen elsewhere (`applyConfiguredKey`,
|
|
255
|
+
* by the worker's model), so the two can come from different rows.
|
|
183
256
|
* @param {{ provider: string, model?: string|null }} judge
|
|
184
257
|
* @param {string|null|undefined} workerProvider
|
|
185
258
|
* @param {string|null|undefined} workerBaseUrl
|
|
@@ -191,52 +264,72 @@ export function judgeRatesFor(judge: {
|
|
|
191
264
|
provider: string;
|
|
192
265
|
model?: string | null;
|
|
193
266
|
}, workerProvider: string | null | undefined, workerBaseUrl: string | null | undefined, workerPrice: ReturnType<typeof ratesFor>, rows: readonly KeyRow[]): ReturnType<typeof ratesFor>;
|
|
194
|
-
|
|
195
|
-
export const DEEPSEEK_BASE_URL: "https://api.deepseek.com/v1";
|
|
196
|
-
/**
|
|
197
|
-
* The API shapes the dropdown offers. `id` is the `src/providers.js` table name;
|
|
198
|
-
* `defaultUrl` is the host a blank Base URL means ('' = the vendor's own, unshown).
|
|
199
|
-
* @type {readonly {id: string, label: string, defaultUrl: string}[]}
|
|
200
|
-
*/
|
|
201
|
-
export const SHAPES: readonly {
|
|
202
|
-
id: string;
|
|
203
|
-
label: string;
|
|
204
|
-
defaultUrl: string;
|
|
205
|
-
}[];
|
|
206
|
-
/** The five empty lines a fresh keys file is created with, in this order. */
|
|
207
|
-
export const PRESET_KEY_NAMES: readonly string[];
|
|
208
|
-
/** A local server's default endpoint: Ollama's OpenAI-compatible host (LM Studio / llama.cpp: change the URL). */
|
|
209
|
-
export const LOCAL_BASE_URL: "http://127.0.0.1:11434/v1";
|
|
267
|
+
export { SHAPES };
|
|
210
268
|
/**
|
|
211
269
|
* A key line whose value is the word `null` is SET and means "no real key": the row exists and
|
|
212
270
|
* the provider is handed this harmless stand-in (local servers ignore auth). It is not a
|
|
213
271
|
* secret and is never shown or logged as a key.
|
|
214
272
|
*/
|
|
215
273
|
export const NO_KEY_PLACEHOLDER: "no-key-needed";
|
|
216
|
-
export
|
|
274
|
+
export function isTickedLine(l: ModelLine): boolean;
|
|
275
|
+
/** The plain sentence when a stale Chat pick names a key and a model no row ticks (fwd's wording, bareloop's seam). */
|
|
276
|
+
export const REFUSE_NO_TICK: "Tick a model in Settings > Providers. Nothing was spent.";
|
|
277
|
+
export const REFUSE_NO_PICK: "Pick a model. Nothing was spent.";
|
|
278
|
+
export function refuseNotSetUp(key: string): string;
|
|
279
|
+
/**
|
|
280
|
+
* The CLI sentence when a run names no model and the spec carries none (fwd's `pickTicked` sentence).
|
|
281
|
+
*/
|
|
282
|
+
export const REFUSE_NAME_MODEL: "Name the model with --model <id>: one ticked in Settings > Providers with both prices.";
|
|
283
|
+
/**
|
|
284
|
+
* one model line of a row (`models.<ENV>` in config.json)
|
|
285
|
+
*/
|
|
286
|
+
export type ModelLine = {
|
|
217
287
|
/**
|
|
218
|
-
* the
|
|
288
|
+
* the model id
|
|
289
|
+
*/
|
|
290
|
+
model: string;
|
|
291
|
+
/**
|
|
292
|
+
* ticked = offered in Chat (needs both prices)
|
|
219
293
|
*/
|
|
294
|
+
use: boolean;
|
|
295
|
+
/**
|
|
296
|
+
* the customer's own price, USD per 1M input tokens
|
|
297
|
+
*/
|
|
298
|
+
inPerM?: number | undefined;
|
|
299
|
+
/**
|
|
300
|
+
* the same, for output tokens
|
|
301
|
+
*/
|
|
302
|
+
outPerM?: number | undefined;
|
|
303
|
+
};
|
|
304
|
+
export type PriceResult = {
|
|
305
|
+
rates: {
|
|
306
|
+
in: number;
|
|
307
|
+
out: number;
|
|
308
|
+
};
|
|
309
|
+
inPerM: number;
|
|
310
|
+
outPerM: number;
|
|
220
311
|
envName: string;
|
|
312
|
+
} | null;
|
|
313
|
+
export type KeyRow = {
|
|
221
314
|
/**
|
|
222
|
-
* the
|
|
315
|
+
* the key variable NAME (read-only label; never a value)
|
|
223
316
|
*/
|
|
224
|
-
|
|
317
|
+
envName: string;
|
|
225
318
|
/**
|
|
226
319
|
* the `src/providers.js` table entry (the API shape's id)
|
|
227
320
|
*/
|
|
228
321
|
provider: string;
|
|
229
322
|
/**
|
|
230
|
-
* the saved Base URL ('' =
|
|
323
|
+
* the saved Base URL ('' = none typed yet)
|
|
231
324
|
*/
|
|
232
325
|
baseUrl: string;
|
|
233
326
|
/**
|
|
234
|
-
* the
|
|
235
|
-
* (present only when the config row names it); {@link ratesFor} is the one place that validates it
|
|
327
|
+
* the "old max_tokens" tick (only meaningful on `openai-api`)
|
|
236
328
|
*/
|
|
237
|
-
|
|
329
|
+
legacyMaxTokens: boolean;
|
|
238
330
|
/**
|
|
239
|
-
* the
|
|
331
|
+
* the row's model lines
|
|
240
332
|
*/
|
|
241
|
-
|
|
333
|
+
models: ModelLine[];
|
|
242
334
|
};
|
|
335
|
+
import { SHAPES } from './providershapes.js';
|
package/types/providers.d.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The per-call options the rubric JUDGE's model calls carry for this provider
|
|
3
|
-
* instance, from the allow-list above. Empty for any provider/model not listed.
|
|
4
|
-
* @param {any} provider a constructed bare-agent provider
|
|
5
|
-
* @returns {Record<string, any>}
|
|
6
|
-
*/
|
|
7
|
-
export function judgeCallOptions(provider: any): Record<string, any>;
|
|
8
1
|
/**
|
|
9
2
|
* Look up a provider's table entry. Throws a NAMED error on an unrecognized
|
|
10
3
|
* provider — never a silent default (the `resolveRates`-style-substring-
|
|
@@ -18,7 +11,7 @@ export function resolveProvider(providerName: string): ProviderTableEntry;
|
|
|
18
11
|
/**
|
|
19
12
|
* Report whether a resolved API key VALUE (not its presence — every call
|
|
20
13
|
* site already presence-checks separately) carries a shape an HTTP header
|
|
21
|
-
* value cannot: F181 (`docs/
|
|
14
|
+
* value cannot: F181 (`docs/wiki/FINDINGS.md`) — a two-line secret-store
|
|
22
15
|
* entry put the key plus a trailing metadata line into `OPENAI_API_KEY`
|
|
23
16
|
* (`"<key>\nmeta"`), the presence-only check at every door passed, and Node
|
|
24
17
|
* crashed `TypeError [ERR_INVALID_CHAR]` inside its own header-encode at the
|
|
@@ -44,80 +37,67 @@ export function resolveProvider(providerName: string): ProviderTableEntry;
|
|
|
44
37
|
*/
|
|
45
38
|
export function apiKeyProblem(value: string): string | null;
|
|
46
39
|
/**
|
|
47
|
-
* Construct ONE provider instance for `providerName`/`model`, applying
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
40
|
+
* Construct ONE provider instance for `providerName`/`model`, applying `exposeErrorBody: true` (F153 — every constructed
|
|
41
|
+
* provider, unconditionally). `baseUrl` (PRD item 28, ruling (d), 2026-09-09: admitted in v1) is forwarded only when given.
|
|
42
|
+
* `legacyMaxTokens` is the Settings ROW's "old max_tokens" tick: a server that ignores `max_completion_tokens` (F149) does not
|
|
43
|
+
* bind the output cap until it is on. It is forwarded only for `openai-api` and only when `true` — nothing here sniffs a host
|
|
44
|
+
* or a model id to decide it.
|
|
52
45
|
* @param {string} providerName
|
|
53
|
-
* @param {{apiKey?: string, model?: string, baseUrl?: string}} [options]
|
|
46
|
+
* @param {{apiKey?: string, model?: string, baseUrl?: string, legacyMaxTokens?: boolean}} [options]
|
|
54
47
|
*/
|
|
55
|
-
export function makeProvider(providerName: string, { apiKey, model, baseUrl }?: {
|
|
48
|
+
export function makeProvider(providerName: string, { apiKey, model, baseUrl, legacyMaxTokens }?: {
|
|
56
49
|
apiKey?: string;
|
|
57
50
|
model?: string;
|
|
58
51
|
baseUrl?: string;
|
|
52
|
+
legacyMaxTokens?: boolean;
|
|
59
53
|
}): any;
|
|
60
54
|
/**
|
|
61
|
-
* Build the `{provider, providerFor, judgeProvider}` triple both runners
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* (the caller runs `resolveWorkerModel` itself, exactly as both runners did
|
|
65
|
-
* before this factory existed — that decision stays where each runner's own
|
|
66
|
-
* `--model` flag/spec precedence lives, not duplicated in here).
|
|
67
|
-
*
|
|
68
|
-
* THE JUDGE IS NO LONGER PINNED TO ANTHROPIC (PRD item 32.2, hamr 2026-09-10:
|
|
69
|
-
* *"what i care about is that judge becomes llm agnostic and not set to one
|
|
70
|
-
* model or provider"*). It is constructed through this same factory, from a
|
|
71
|
-
* `judgeProviderName`/`judgeModel` pair the CALLER resolved (`resolveJudge`,
|
|
72
|
-
* src/judged.js — the spec's signed `judge` override, else the job's own worker
|
|
73
|
-
* provider and model). Item 28's pin, and item 28 part (2)'s deferral of a
|
|
74
|
-
* signed `judge:{provider,model}` field, both close here.
|
|
55
|
+
* Build the `{provider, providerFor, judgeProvider}` triple both authoring runners need (`src/authorrun.js` and
|
|
56
|
+
* `src/panel/authorsession.js` call it) — ONE seam instead of two copies of the same construction. `model` is the
|
|
57
|
+
* already-RESOLVED worker model id (the caller picked the Settings line).
|
|
75
58
|
*
|
|
76
|
-
*
|
|
77
|
-
* may
|
|
78
|
-
*
|
|
79
|
-
* have exactly one. The caller reads the resolved judge provider's own `envKey`
|
|
80
|
-
* and hands the key in — the same contract the worker key already has here.
|
|
59
|
+
* THE JUDGE IS NOT PINNED (PRD item 32.2): it is constructed through this same factory from a `judgeProviderName`/`judgeModel`
|
|
60
|
+
* pair the CALLER resolved. `judgeApiKey` stays a SEPARATE argument: the judge may be a different provider from the worker,
|
|
61
|
+
* and each key is read by the caller from its own row.
|
|
81
62
|
* @param {object} args
|
|
82
|
-
* @param {string} args.providerName
|
|
83
|
-
* @param {string|undefined} args.apiKey the WORKER's key, read from
|
|
63
|
+
* @param {string} args.providerName the worker's API shape id
|
|
64
|
+
* @param {string|undefined} args.apiKey the WORKER's key, read from its row's env name
|
|
84
65
|
* @param {string} args.model the already-resolved worker model id
|
|
85
|
-
* @param {
|
|
86
|
-
* @param {
|
|
87
|
-
* @param {string|undefined} args.judgeApiKey the judge's own key
|
|
66
|
+
* @param {string|undefined} [args.baseUrl] the worker row's Base URL
|
|
67
|
+
* @param {boolean} [args.legacyMaxTokens] the worker row's old max_tokens tick
|
|
68
|
+
* @param {string|undefined} args.judgeApiKey the judge's own key
|
|
88
69
|
* @param {string} args.judgeModel the resolved judge model id
|
|
89
|
-
* @param {string} [args.judgeProviderName] the resolved judge
|
|
90
|
-
* @param {string|undefined} [args.judgeBaseUrl] the judge
|
|
70
|
+
* @param {string} [args.judgeProviderName] the resolved judge shape; defaults to `providerName`
|
|
71
|
+
* @param {string|undefined} [args.judgeBaseUrl] the judge row's endpoint
|
|
72
|
+
* @param {boolean} [args.judgeLegacyMaxTokens] the judge row's old max_tokens tick (defaults to the worker's when the judge shares its provider)
|
|
91
73
|
*/
|
|
92
|
-
export function buildRunnerProviders({ providerName, apiKey, model,
|
|
74
|
+
export function buildRunnerProviders({ providerName, apiKey, model, baseUrl, legacyMaxTokens, judgeApiKey, judgeModel, judgeProviderName, judgeBaseUrl, judgeLegacyMaxTokens, }: {
|
|
93
75
|
providerName: string;
|
|
94
76
|
apiKey: string | undefined;
|
|
95
77
|
model: string;
|
|
96
|
-
tierModels: Readonly<Record<string, string>>;
|
|
97
78
|
baseUrl?: string | undefined;
|
|
79
|
+
legacyMaxTokens?: boolean | undefined;
|
|
98
80
|
judgeApiKey: string | undefined;
|
|
99
81
|
judgeModel: string;
|
|
100
82
|
judgeProviderName?: string | undefined;
|
|
101
83
|
judgeBaseUrl?: string | undefined;
|
|
84
|
+
judgeLegacyMaxTokens?: boolean | undefined;
|
|
102
85
|
}): {
|
|
103
86
|
provider: any;
|
|
104
|
-
providerFor: (
|
|
87
|
+
providerFor: (_tier: string) => any;
|
|
105
88
|
judgeProvider: any;
|
|
106
89
|
};
|
|
107
90
|
/**
|
|
108
|
-
* $0 reachability check:
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* (`src/panel/authorroutes.js`) and by the future Settings providers
|
|
114
|
-
* table's own "test" column (PANEL-BUILD.md P4) — ONE function, not two
|
|
115
|
-
* hand-typed copies of the same probe.
|
|
91
|
+
* $0 reachability check: ONE GET of the provider's models list (`src/modellist.js`, the one owner of
|
|
92
|
+
* that call), server-side, with the key in a header — NEVER a completion request, so it never spends
|
|
93
|
+
* a token (PANEL-BUILD.md P3 build item 7: "the person must get feedback BEFORE drafting if the
|
|
94
|
+
* chosen model can't work"). Used by the panel's model-readiness route (`src/panel/authorroutes.js`);
|
|
95
|
+
* Settings > Providers' Test and Refresh call `listModels` directly. A blank `baseUrl` makes no call.
|
|
116
96
|
*
|
|
117
|
-
* NEVER returns the key, never logs it — the key only ever appears in a
|
|
118
|
-
*
|
|
97
|
+
* NEVER returns the key, never logs it — the key only ever appears in a request header sent
|
|
98
|
+
* straight to the provider's own host.
|
|
119
99
|
* @param {object} o
|
|
120
|
-
* @param {string} o.providerName
|
|
100
|
+
* @param {string} o.providerName an API shape id
|
|
121
101
|
* @param {string} o.apiKey
|
|
122
102
|
* @param {string} [o.model] when given, the response is also checked for this model id
|
|
123
103
|
* @param {string} [o.baseUrl]
|
|
@@ -157,55 +137,6 @@ export function checkProviderReachable({ providerName, apiKey, model, baseUrl, f
|
|
|
157
137
|
* @returns {string[]|null} lines to print, in order, or null when there is nothing to say
|
|
158
138
|
*/
|
|
159
139
|
export function probeWarningLines(providerName: string): string[] | null;
|
|
160
|
-
/**
|
|
161
|
-
* Today's anthropic-api tier table — EXACTLY the `DEFAULT_TIER_MODELS` both
|
|
162
|
-
* runners hardcoded before this factory existed. Any change to these two
|
|
163
|
-
* values is a change to shipped anthropic-api behaviour, not a refactor.
|
|
164
|
-
*/
|
|
165
|
-
export const ANTHROPIC_TIER_MODELS: Readonly<{
|
|
166
|
-
sonnet: "claude-sonnet-5";
|
|
167
|
-
haiku: "claude-haiku-4-5-20251001";
|
|
168
|
-
}>;
|
|
169
|
-
/**
|
|
170
|
-
* DeepSeek (F149/F150) is a SINGLE model, not a tiered family — hamr's
|
|
171
|
-
* ruling above: one secondary provider, not a menu. Both tiers map to the
|
|
172
|
-
* same model id ON PURPOSE: `resolveWorkerModel`/a runner's `providerFor
|
|
173
|
-
* (tier)` only ever LOOK UP a tier's model id (src/job.js:818-827,
|
|
174
|
-
* scripts/run-u.mjs's `providerFor`) — neither assumes the tiers name
|
|
175
|
-
* different models — so repeating the one id is the honest representation
|
|
176
|
-
* of a single-model provider, not a second model masquerading as `haiku`.
|
|
177
|
-
* If DeepSeek (or a future openai-api entrant) ever ships a genuinely
|
|
178
|
-
* cheaper tier model, this is where it would earn its own `haiku` id.
|
|
179
|
-
*
|
|
180
|
-
* MODEL SWAP (F171, item 34 L16, hamr 2026-09-13): `deepseek-chat` is no
|
|
181
|
-
* longer served — a live `/models` call returned only `deepseek-flash` and
|
|
182
|
-
* `deepseek-v4-pro`. Switched to `deepseek-flash` (DeepSeek V4.1). F149's
|
|
183
|
-
* `legacyMaxTokens` measurement (asked 64 output tokens, got 665/608) was
|
|
184
|
-
* taken on `deepseek-chat` and is UNVERIFIED on `deepseek-flash` — kept on
|
|
185
|
-
* below as the fail-safe (over-capping direction is safe; see F171).
|
|
186
|
-
*/
|
|
187
|
-
export const OPENAI_TIER_MODELS: Readonly<{
|
|
188
|
-
sonnet: "deepseek-flash";
|
|
189
|
-
haiku: "deepseek-flash";
|
|
190
|
-
}>;
|
|
191
|
-
/**
|
|
192
|
-
* Gemini (PRD item 31.3, hamr 2026-09-09: "anthropic, openai, gemini drop
|
|
193
|
-
* ollama for now"). Two real tiers, unlike DeepSeek's single model: `flash` is
|
|
194
|
-
* the cheap tier by design, so `haiku` maps to it honestly rather than
|
|
195
|
-
* repeating one id.
|
|
196
|
-
*
|
|
197
|
-
* ADMITTED-PENDING-PROBE. The probe rule stands (PRD item 28 ruling (d),
|
|
198
|
-
* 2026-09-09): no endpoint is in the menu without its own clean paid probe,
|
|
199
|
-
* and `gemini-api` has ZERO runs. `anthropic-api` is the original (~167
|
|
200
|
-
* archived runs) and `openai-api` was probed green through the shipped runner
|
|
201
|
-
* (run mtu12vks, $1.64/$4, F157); gemini owes that fire and has not paid it.
|
|
202
|
-
* `PROBE_STATUS` below is the machine-readable form of that debt — nothing in
|
|
203
|
-
* here silently pretends the provider is proven.
|
|
204
|
-
*/
|
|
205
|
-
export const GEMINI_TIER_MODELS: Readonly<{
|
|
206
|
-
sonnet: "gemini-2.5-pro";
|
|
207
|
-
haiku: "gemini-2.5-flash";
|
|
208
|
-
}>;
|
|
209
140
|
/**
|
|
210
141
|
* Which admitted providers have paid for their own end-to-end probe, and which
|
|
211
142
|
* have not. Read by the runner to print a loud marker; never read to REFUSE —
|
|
@@ -222,20 +153,8 @@ export type ProviderTableEntry = {
|
|
|
222
153
|
* the bare-agent provider class
|
|
223
154
|
*/
|
|
224
155
|
ctor: new (options: any) => any;
|
|
225
|
-
/**
|
|
226
|
-
* the environment variable this provider reads its key from
|
|
227
|
-
*/
|
|
228
|
-
envKey: string;
|
|
229
|
-
/**
|
|
230
|
-
* tier name -> model id
|
|
231
|
-
*/
|
|
232
|
-
tiers: Readonly<Record<string, string>>;
|
|
233
156
|
/**
|
|
234
157
|
* the CONSTRUCTOR OPTION NAME this provider reads its endpoint from — NOT assumed to be `baseUrl` (see below)
|
|
235
158
|
*/
|
|
236
159
|
endpointKey: string;
|
|
237
|
-
/**
|
|
238
|
-
* per-model request-key/param gating, applied on TOP of {exposeErrorBody:true, apiKey, model, <endpointKey>?}
|
|
239
|
-
*/
|
|
240
|
-
paramsFor: (model: string | undefined) => Record<string, any>;
|
|
241
160
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `id` is the value saved in config.json (and the signed spec's `provider`).
|
|
3
|
+
* @type {readonly {id: string, label: string}[]}
|
|
4
|
+
*/
|
|
5
|
+
export const SHAPES: readonly {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
}[];
|
|
9
|
+
/** @type {readonly string[]} */
|
|
10
|
+
export const SHAPE_IDS: readonly string[];
|
package/types/run.d.ts
CHANGED
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
* frozen A0 baseline arm has to be exactly today, so a guard firing under a disabled
|
|
159
159
|
* shim would make the baseline a treatment arm. The default-flip belongs to a
|
|
160
160
|
* paid contrast nobody has approved yet (the `layerRoot` precedent, F41).
|
|
161
|
-
* @param {boolean} [opts.scout=true] operator-only switch (docs/
|
|
161
|
+
* @param {boolean} [opts.scout=true] operator-only switch (docs/logs/SCOUT-CONTRAST.md),
|
|
162
162
|
* forwarded verbatim to the plan flow: `false` on a fresh run (no `resumeSeed`) skips the
|
|
163
163
|
* read-only survey and records `scout-skipped {reason:'operator-off'}` instead — the
|
|
164
164
|
* planner drafts from `(no scout notes)`. Runner territory exactly like `readShim`: the
|