bareloop 0.40.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 +33 -0
- package/bareloop.context.md +97 -124
- package/package.json +2 -2
- package/src/authorflow.js +9 -9
- package/src/authorjob.js +4 -4
- package/src/authorrun.js +25 -25
- package/src/authorscout.js +4 -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/draftspend.js +4 -4
- package/src/index.js +2 -4
- package/src/interviewrun.js +17 -25
- package/src/job.js +13 -7
- package/src/judged.js +11 -43
- package/src/keysfile.js +15 -7
- package/src/kinds.js +2 -2
- package/src/modellist.js +84 -0
- package/src/monthly.js +23 -43
- package/src/panel/authorroutes.js +19 -14
- package/src/panel/authorsession.js +62 -58
- package/src/panel/index.html +520 -145
- package/src/panel/runroutes.js +3 -0
- package/src/panel/server.js +35 -15
- package/src/panel/settingsroutes.js +232 -173
- package/src/planrun.js +2 -2
- 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/thinking.js +130 -0
- package/src/userrun.js +50 -73
- package/types/authorflow.d.ts +5 -5
- package/types/authorjob.d.ts +2 -2
- package/types/authorscout.d.ts +2 -2
- package/types/config.d.ts +23 -6
- package/types/draftspend.d.ts +8 -8
- package/types/index.d.ts +1 -1
- package/types/job.d.ts +5 -5
- 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 +2 -9
- package/types/panel/server.d.ts +14 -4
- package/types/providerrows.d.ts +192 -99
- package/types/providers.d.ts +34 -159
- package/types/providershapes.d.ts +10 -0
- package/types/thinking.d.ts +90 -0
- package/types/userrun.d.ts +6 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The key goes only in a header, in the form each shape expects.
|
|
3
|
+
* @param {string} shape an API shape id (src/providershapes.js)
|
|
4
|
+
* @param {string} key
|
|
5
|
+
* @returns {Record<string, string>}
|
|
6
|
+
*/
|
|
7
|
+
export function authHeaders(shape: string, key: string): Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* The model ids a provider's list answer holds, per API shape (`data[].id` for two shapes;
|
|
10
|
+
* `models[].name` minus its `models/` prefix for the third). Sorted, de-duplicated.
|
|
11
|
+
* @param {string} shape
|
|
12
|
+
* @param {any} body
|
|
13
|
+
* @returns {string[]}
|
|
14
|
+
*/
|
|
15
|
+
export function idsOf(shape: string, body: any): string[];
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {{ ok: true, models: string[], ms: number }
|
|
18
|
+
* | { ok: false, why: string, status: string, detail?: string }} ListResult
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* One free GET of `<baseUrl>/models` with the key in the header only and a deadline.
|
|
22
|
+
* Failure is data, never a throw: `why` is a plain sentence, `status` a short machine word
|
|
23
|
+
* (`no-base-url`, `redirect`, `HTTP <n>`, `timeout`, `unreachable`) for callers that need it.
|
|
24
|
+
* @param {object} o
|
|
25
|
+
* @param {string} o.shape an API shape id
|
|
26
|
+
* @param {string} o.baseUrl the row's Base URL ('' = no call)
|
|
27
|
+
* @param {string} o.key the key value (header only)
|
|
28
|
+
* @param {typeof fetch} [o.fetchImpl] test seam; defaults to the global `fetch`
|
|
29
|
+
* @param {number} [o.timeoutMs]
|
|
30
|
+
* @returns {Promise<ListResult>}
|
|
31
|
+
*/
|
|
32
|
+
export function listModels({ shape, baseUrl, key, fetchImpl, timeoutMs }: {
|
|
33
|
+
shape: string;
|
|
34
|
+
baseUrl: string;
|
|
35
|
+
key: string;
|
|
36
|
+
fetchImpl?: typeof fetch | undefined;
|
|
37
|
+
timeoutMs?: number | undefined;
|
|
38
|
+
}): Promise<ListResult>;
|
|
39
|
+
/** The default deadline for the one GET. */
|
|
40
|
+
export const LIST_TIMEOUT_MS: 4000;
|
|
41
|
+
export type ListResult = {
|
|
42
|
+
ok: true;
|
|
43
|
+
models: string[];
|
|
44
|
+
ms: number;
|
|
45
|
+
} | {
|
|
46
|
+
ok: false;
|
|
47
|
+
why: string;
|
|
48
|
+
status: string;
|
|
49
|
+
detail?: string;
|
|
50
|
+
};
|
package/types/monthly.d.ts
CHANGED
|
@@ -48,11 +48,11 @@ export function monthSpend(opts?: {
|
|
|
48
48
|
};
|
|
49
49
|
/**
|
|
50
50
|
* The Money tab's figures: all-time and this-month spend, and per-provider breakdown
|
|
51
|
-
* (
|
|
52
|
-
* pooled into another row). Any leg with unknown spend makes the figure it belongs to
|
|
51
|
+
* (grouped by the matched Providers row's key variable name; a run on no row lands under its
|
|
52
|
+
* own provider name, never pooled into another row). Any leg with unknown spend makes the figure it belongs to
|
|
53
53
|
* an "at least".
|
|
54
54
|
* @param {{ home?: string, sessionsRoot?: string, now?: () => number, rows?: readonly import('./providerrows.js').KeyRow[] }} [opts] `rows` = the Providers rows: when given, `tokensByRow` sums each row's tokens
|
|
55
|
-
* @returns {{ tokensByRow: Record<string, number>, total: {usd: number, atLeast: boolean, tokens: number}, month: {usd: number, atLeast: boolean, tokens: number},
|
|
55
|
+
* @returns {{ tokensByRow: Record<string, number>, tokensByModel: Record<string, Record<string, number>>, total: {usd: number, atLeast: boolean, tokens: number}, month: {usd: number, atLeast: boolean, tokens: number},
|
|
56
56
|
* byProvider: Record<string, {label: string, monthUsd: number, monthAtLeast: boolean, totalUsd: number, totalAtLeast: boolean, tokens: number, vouchedRounds: number, otherRounds: number, monthWallMs: number|null, monthWallAtLeast: boolean, totalWallMs: number|null, totalWallAtLeast: boolean}> }}
|
|
57
57
|
*/
|
|
58
58
|
export function spendSummary(opts?: {
|
|
@@ -62,6 +62,7 @@ export function spendSummary(opts?: {
|
|
|
62
62
|
rows?: readonly import("./providerrows.js").KeyRow[];
|
|
63
63
|
}): {
|
|
64
64
|
tokensByRow: Record<string, number>;
|
|
65
|
+
tokensByModel: Record<string, Record<string, number>>;
|
|
65
66
|
total: {
|
|
66
67
|
usd: number;
|
|
67
68
|
atLeast: boolean;
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The first drafting row's words (hamr 2026-10-11) — code-owned, one owner, ALWAYS starting "thinking on" or "thinking off".
|
|
3
|
-
* `sent` is what the drafting calls carry (`draftThinkingFor`); `thoughtAnyway` = a call reported `thinkingApplied === false`
|
|
4
|
-
* after 'off' was sent (bare-agent saw reasoning in the reply).
|
|
5
|
-
* @param {'on'|'off'|'not-switchable'|'unverified'} sent @param {boolean} [thoughtAnyway]
|
|
6
|
-
* @returns {string}
|
|
7
|
-
*/
|
|
8
|
-
export function thinkingRowText(sent: "on" | "off" | "not-switchable" | "unverified", thoughtAnyway?: boolean): string;
|
|
9
1
|
/** @typedef {{id: string, label: string, status: 'running'|'done'|'failed', detail: string}} StepLine */
|
|
10
2
|
/** @param {StepLine[]} steps @param {string} id the LATEST line carrying this id (the list is a time-ordered log; an id can repeat) */
|
|
11
3
|
export function latestStep(steps: StepLine[], id: string): StepLine | undefined;
|
|
@@ -195,7 +187,6 @@ export const CARD_FIELDS: readonly string[];
|
|
|
195
187
|
export const REUSE_OPEN_FIELDS: readonly string[];
|
|
196
188
|
/** every card field that is NOT open on a reuse card, in card order */
|
|
197
189
|
export const REUSE_LOCKED_FIELDS: readonly string[];
|
|
198
|
-
export { nonRepoSourceMessage };
|
|
199
190
|
export type StepLine = {
|
|
200
191
|
id: string;
|
|
201
192
|
label: string;
|
|
@@ -203,4 +194,6 @@ export type StepLine = {
|
|
|
203
194
|
detail: string;
|
|
204
195
|
};
|
|
205
196
|
import { planFromConfirm } from './jobplan.js';
|
|
197
|
+
import { thinkingRowText } from '../thinking.js';
|
|
206
198
|
import { nonRepoSourceMessage } from '../source.js';
|
|
199
|
+
export { thinkingRowText, nonRepoSourceMessage };
|
package/types/panel/server.d.ts
CHANGED
|
@@ -400,15 +400,17 @@ export function reuseLine(record: {
|
|
|
400
400
|
* $ cap and the Time cap — start at what the run had. `ok:false` when the run's signed job is not on disk (nothing
|
|
401
401
|
* to copy: change the job: Clear the card). `null` when the runid is not listed.
|
|
402
402
|
* @param {string} runid
|
|
403
|
-
* @param {{ home?: string, model?: string }} [opts] `model` = the Model box's current Name (the estimate counts only runs on that worker); absent = the card's own Model
|
|
403
|
+
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` = the Model box's current Name (the estimate counts only runs on that worker); absent = the card's own Model
|
|
404
404
|
* @returns {{ok: true, origin: {runid: string, job: string}, outcome: string|null, card: Record<string, any>, from: 'signed job',
|
|
405
405
|
* locked: readonly string[], open: readonly string[], note: string|null,
|
|
406
|
-
* specHash: string, workflowKey: string, spec: any, specPath: string,
|
|
406
|
+
* specHash: string, workflowKey: string, spec: any, specPath: string, specNamesModel: boolean,
|
|
407
|
+
* specWorker: {provider: string, endpoint: string, label: string},
|
|
407
408
|
* trackRecord: ReturnType<typeof trackRecordFor>, line: string}|{ok: false, error: string}|null}
|
|
408
409
|
*/
|
|
409
410
|
export function getStartFrom(runid: string, opts?: {
|
|
410
411
|
home?: string;
|
|
411
412
|
model?: string;
|
|
413
|
+
provider?: string;
|
|
412
414
|
}): {
|
|
413
415
|
ok: true;
|
|
414
416
|
origin: {
|
|
@@ -425,6 +427,12 @@ export function getStartFrom(runid: string, opts?: {
|
|
|
425
427
|
workflowKey: string;
|
|
426
428
|
spec: any;
|
|
427
429
|
specPath: string;
|
|
430
|
+
specNamesModel: boolean;
|
|
431
|
+
specWorker: {
|
|
432
|
+
provider: string;
|
|
433
|
+
endpoint: string;
|
|
434
|
+
label: string;
|
|
435
|
+
};
|
|
428
436
|
trackRecord: ReturnType<typeof trackRecordFor>;
|
|
429
437
|
line: string;
|
|
430
438
|
} | {
|
|
@@ -436,12 +444,13 @@ export function getStartFrom(runid: string, opts?: {
|
|
|
436
444
|
* that has at least one GREEN local run, newest green first. `runid` = that job's newest green run, so the page hands
|
|
437
445
|
* it to the existing start-from flow unchanged; `line` is `getStartFrom`'s own estimate line (never a second
|
|
438
446
|
* spelling). Local runs only — an imported job keeps its Reuse button in the Import view. $0, read-only.
|
|
439
|
-
* @param {{ home?: string, model?: string }} [opts] `model` passes through to the estimate line, as start-from's does
|
|
447
|
+
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` passes through to the estimate line, as start-from's does
|
|
440
448
|
* @returns {{job: string, runid: string, checkType: 'deterministic'|'rubric', line: string}[]}
|
|
441
449
|
*/
|
|
442
450
|
export function listReuseJobs(opts?: {
|
|
443
451
|
home?: string;
|
|
444
452
|
model?: string;
|
|
453
|
+
provider?: string;
|
|
445
454
|
}): {
|
|
446
455
|
job: string;
|
|
447
456
|
runid: string;
|
|
@@ -458,7 +467,7 @@ export function listReuseJobs(opts?: {
|
|
|
458
467
|
* signs it on this machine at [Sign & run]. Same card, same locked/open boxes as a run's reuse. `null` when no such
|
|
459
468
|
* imported job.
|
|
460
469
|
* @param {string} id
|
|
461
|
-
* @param {{ home?: string, model?: string }} [opts] `model` as for {@link getStartFrom}
|
|
470
|
+
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` as for {@link getStartFrom}
|
|
462
471
|
* @returns {{ok: true, origin: {runid: null, job: string, importId: string}, card: Record<string, any>, from: 'imported job',
|
|
463
472
|
* locked: readonly string[], open: readonly string[], note: string|null, specHash: string, workflowKey: string, spec: any,
|
|
464
473
|
* specPath: null, trackRecord: ReturnType<typeof trackRecordFor>, line: string}|{ok: false, error: string}|null}
|
|
@@ -466,6 +475,7 @@ export function listReuseJobs(opts?: {
|
|
|
466
475
|
export function getStartFromImport(id: string, opts?: {
|
|
467
476
|
home?: string;
|
|
468
477
|
model?: string;
|
|
478
|
+
provider?: string;
|
|
469
479
|
}): {
|
|
470
480
|
ok: true;
|
|
471
481
|
origin: {
|
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';
|