faberun 0.10.0 → 0.12.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/README.md +6 -0
- package/integrations/claude-code/statusline.sh +31 -2
- package/package.json +2 -2
- package/skills/faberun/references/spec-format.md +9 -0
- package/src/campaign/chain.mjs +2 -1
- package/src/campaign/index.mjs +102 -1
- package/src/campaign/metrics.mjs +2 -2
- package/src/cli/brand.mjs +2 -0
- package/src/cli/campaign-contract.mjs +55 -0
- package/src/cli/campaign.mjs +48 -13
- package/src/cli/init.mjs +8 -2
- package/src/cli/launch.mjs +2 -1
- package/src/cli/plan.mjs +3 -2
- package/src/cli/project.mjs +150 -0
- package/src/cli/skills.mjs +2 -3
- package/src/cli/update.mjs +7 -10
- package/src/cli.mjs +30 -4
- package/src/contract/index.mjs +44 -0
- package/src/contract/task-packet.mjs +12 -3
- package/src/engine/cancel.mjs +13 -0
- package/src/engine/dispatch.mjs +20 -2
- package/src/engine/lifecycle.mjs +38 -61
- package/src/engine/live-preflight.mjs +2 -1
- package/src/engine/notify-queue.mjs +9 -1
- package/src/engine/pricing-seed.json +543 -0
- package/src/engine/pricing-seed.mjs +54 -0
- package/src/engine/process.mjs +8 -1
- package/src/engine/result-file.mjs +2 -1
- package/src/engine/resume.mjs +6 -2
- package/src/engine/run-identity.mjs +9 -2
- package/src/engine/scheduler.mjs +40 -6
- package/src/engine/settle-judge.mjs +141 -0
- package/src/engine/settle.mjs +1 -1
- package/src/harnesses/protocol.mjs +46 -10
- package/src/harnesses/replay/bin.mjs +10 -1
- package/src/host/home.mjs +10 -3
- package/src/host/platform.mjs +111 -0
- package/src/host/preflight.mjs +43 -21
- package/src/host/projects.mjs +155 -0
- package/src/notify/index.mjs +88 -10
- package/src/plan/pipeline.mjs +32 -9
- package/src/plan/repo-facts.mjs +80 -2
- package/src/plan/spec.mjs +2 -1
- package/src/repo/declared-paths.mjs +7 -1
- package/src/repo/integrate.mjs +1 -1
- package/src/repo/scope-closure.mjs +2 -1
- package/src/repo/signal.mjs +24 -7
- package/src/repo/source-identity.mjs +7 -0
- package/src/repo/workspace.mjs +12 -2
- package/src/repo/worktree.mjs +89 -22
- package/src/report/next.mjs +66 -6
- package/src/report/progress.mjs +724 -0
- package/src/report/render.mjs +3 -3
- package/src/run/migrate.mjs +278 -0
- package/src/run/paths.mjs +189 -0
- package/src/seat/index.mjs +2 -1
- package/src/web/app.css +170 -0
- package/src/web/app.mjs +690 -0
- package/src/web/index.html +38 -283
- package/src/web/server.mjs +197 -182
|
@@ -24,6 +24,7 @@ import { tmpdir } from "node:os";
|
|
|
24
24
|
import { validateContract } from "../contract/index.mjs";
|
|
25
25
|
import { validateNodeSnapshot } from "../contract/snapshot.mjs";
|
|
26
26
|
import { compactCost as formatCost } from "../util.mjs";
|
|
27
|
+
import { runsRoot } from "../run/paths.mjs";
|
|
27
28
|
|
|
28
29
|
/** @typedef {import("../harnesses/index.mjs").ProbeResult} ProbeResult */
|
|
29
30
|
/** @typedef {import("../harnesses/index.mjs").ProviderEnvelope} ProviderEnvelope */
|
|
@@ -263,7 +264,7 @@ function redactProviderText(value) {
|
|
|
263
264
|
export function reusedDoneWarnings(contract) {
|
|
264
265
|
/** @type {string[]} */
|
|
265
266
|
const warnings = [];
|
|
266
|
-
const runsDir =
|
|
267
|
+
const runsDir = runsRoot(contract.cwd);
|
|
267
268
|
if (!existsSync(runsDir)) return warnings;
|
|
268
269
|
const ownRunDir = join(runsDir, contract.id);
|
|
269
270
|
for (const name of readdirSync(runsDir)) {
|
|
@@ -222,6 +222,12 @@ export function attentionDedupeKey(runId, anchor, slot) {
|
|
|
222
222
|
* already announced. A receipt is the durable record, so a restarted
|
|
223
223
|
* supervisor reads the same slot as already sent.
|
|
224
224
|
*
|
|
225
|
+
* The message is rendered exactly once, with `runDir` set, and that one
|
|
226
|
+
* string is handed to both the inbox entry and the notify queue: `enqueue`
|
|
227
|
+
* never re-renders a `summary` it is given. Rendering it twice -- once for
|
|
228
|
+
* the inbox with no `runDir` and once inside `enqueue` with `runDir` filled
|
|
229
|
+
* in -- is what let the inbox and the transport disagree before.
|
|
230
|
+
*
|
|
225
231
|
* @param {string} runDir
|
|
226
232
|
* @param {{anchor: string, code?: string|null, campaignId?: string|null, now?: number}} options
|
|
227
233
|
* @returns {Promise<number|null>} the emitted slot, or null when none was due
|
|
@@ -234,10 +240,11 @@ export async function emitScheduledAttention(runDir, options) {
|
|
|
234
240
|
const runId = basename(runDir);
|
|
235
241
|
const dedupeKey = attentionDedupeKey(runId, options.anchor, slot);
|
|
236
242
|
if (alreadyNotified(runDir, dedupeKey)) return null;
|
|
237
|
-
const summary = renderNotification({
|
|
243
|
+
const summary = await renderNotification({
|
|
238
244
|
type: "attention",
|
|
239
245
|
runId,
|
|
240
246
|
errorCode: options.code ?? null,
|
|
247
|
+
runDir,
|
|
241
248
|
});
|
|
242
249
|
// The run-level attention also lands in the campaign-level inbox, which is
|
|
243
250
|
// the append-only record the managed signal block summarises.
|
|
@@ -255,6 +262,7 @@ export async function emitScheduledAttention(runDir, options) {
|
|
|
255
262
|
runId,
|
|
256
263
|
errorCode: options.code ?? null,
|
|
257
264
|
dedupeKey,
|
|
265
|
+
summary,
|
|
258
266
|
});
|
|
259
267
|
return slot;
|
|
260
268
|
}
|
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
{
|
|
2
|
+
"fetchedAt": "2026-09-19",
|
|
3
|
+
"source": "https://models.dev/api.json",
|
|
4
|
+
"providers": [
|
|
5
|
+
"anthropic",
|
|
6
|
+
"deepseek",
|
|
7
|
+
"google",
|
|
8
|
+
"openai",
|
|
9
|
+
"zhipuai"
|
|
10
|
+
],
|
|
11
|
+
"models": {
|
|
12
|
+
"claude-fable-5": {
|
|
13
|
+
"inputPerMTok": 10,
|
|
14
|
+
"cachedInputPerMTok": 1,
|
|
15
|
+
"outputPerMTok": 50
|
|
16
|
+
},
|
|
17
|
+
"claude-fable-5-1": {
|
|
18
|
+
"inputPerMTok": 10,
|
|
19
|
+
"cachedInputPerMTok": 0.25,
|
|
20
|
+
"outputPerMTok": 50
|
|
21
|
+
},
|
|
22
|
+
"claude-haiku-4-5": {
|
|
23
|
+
"inputPerMTok": 1,
|
|
24
|
+
"cachedInputPerMTok": 0.1,
|
|
25
|
+
"outputPerMTok": 5
|
|
26
|
+
},
|
|
27
|
+
"claude-haiku-4-5-20251001": {
|
|
28
|
+
"inputPerMTok": 1,
|
|
29
|
+
"cachedInputPerMTok": 0.1,
|
|
30
|
+
"outputPerMTok": 5
|
|
31
|
+
},
|
|
32
|
+
"claude-opus-4-5": {
|
|
33
|
+
"inputPerMTok": 5,
|
|
34
|
+
"cachedInputPerMTok": 0.5,
|
|
35
|
+
"outputPerMTok": 25
|
|
36
|
+
},
|
|
37
|
+
"claude-opus-4-5-20251101": {
|
|
38
|
+
"inputPerMTok": 5,
|
|
39
|
+
"cachedInputPerMTok": 0.5,
|
|
40
|
+
"outputPerMTok": 25
|
|
41
|
+
},
|
|
42
|
+
"claude-opus-4-6": {
|
|
43
|
+
"inputPerMTok": 5,
|
|
44
|
+
"cachedInputPerMTok": 0.5,
|
|
45
|
+
"outputPerMTok": 25
|
|
46
|
+
},
|
|
47
|
+
"claude-opus-4-7": {
|
|
48
|
+
"inputPerMTok": 5,
|
|
49
|
+
"cachedInputPerMTok": 0.5,
|
|
50
|
+
"outputPerMTok": 25
|
|
51
|
+
},
|
|
52
|
+
"claude-opus-4-8": {
|
|
53
|
+
"inputPerMTok": 5,
|
|
54
|
+
"cachedInputPerMTok": 0.5,
|
|
55
|
+
"outputPerMTok": 25
|
|
56
|
+
},
|
|
57
|
+
"claude-opus-5": {
|
|
58
|
+
"inputPerMTok": 5,
|
|
59
|
+
"cachedInputPerMTok": 0.5,
|
|
60
|
+
"outputPerMTok": 25
|
|
61
|
+
},
|
|
62
|
+
"claude-sonnet-4-5": {
|
|
63
|
+
"inputPerMTok": 3,
|
|
64
|
+
"cachedInputPerMTok": 0.3,
|
|
65
|
+
"outputPerMTok": 15
|
|
66
|
+
},
|
|
67
|
+
"claude-sonnet-4-5-20250929": {
|
|
68
|
+
"inputPerMTok": 3,
|
|
69
|
+
"cachedInputPerMTok": 0.3,
|
|
70
|
+
"outputPerMTok": 15
|
|
71
|
+
},
|
|
72
|
+
"claude-sonnet-4-6": {
|
|
73
|
+
"inputPerMTok": 3,
|
|
74
|
+
"cachedInputPerMTok": 0.3,
|
|
75
|
+
"outputPerMTok": 15
|
|
76
|
+
},
|
|
77
|
+
"claude-sonnet-5": {
|
|
78
|
+
"inputPerMTok": 2,
|
|
79
|
+
"cachedInputPerMTok": 0.2,
|
|
80
|
+
"outputPerMTok": 10
|
|
81
|
+
},
|
|
82
|
+
"deep-research-max-preview-04-2026": {
|
|
83
|
+
"inputPerMTok": 2,
|
|
84
|
+
"cachedInputPerMTok": 0.2,
|
|
85
|
+
"outputPerMTok": 12
|
|
86
|
+
},
|
|
87
|
+
"deep-research-preview-04-2026": {
|
|
88
|
+
"inputPerMTok": 2,
|
|
89
|
+
"cachedInputPerMTok": 0.2,
|
|
90
|
+
"outputPerMTok": 12
|
|
91
|
+
},
|
|
92
|
+
"deepseek-flash": {
|
|
93
|
+
"inputPerMTok": 0.15,
|
|
94
|
+
"cachedInputPerMTok": 0.003,
|
|
95
|
+
"outputPerMTok": 0.6
|
|
96
|
+
},
|
|
97
|
+
"deepseek-v4-flash": {
|
|
98
|
+
"inputPerMTok": 0.15,
|
|
99
|
+
"cachedInputPerMTok": 0.003,
|
|
100
|
+
"outputPerMTok": 0.6
|
|
101
|
+
},
|
|
102
|
+
"deepseek-v4-flash-vision-exp": {
|
|
103
|
+
"inputPerMTok": 0.15,
|
|
104
|
+
"cachedInputPerMTok": 0.003,
|
|
105
|
+
"outputPerMTok": 0.6
|
|
106
|
+
},
|
|
107
|
+
"deepseek-v4-pro": {
|
|
108
|
+
"inputPerMTok": 0.435,
|
|
109
|
+
"cachedInputPerMTok": 0.003625,
|
|
110
|
+
"outputPerMTok": 0.87
|
|
111
|
+
},
|
|
112
|
+
"gemini-2.5-computer-use-preview-10-2025": {
|
|
113
|
+
"inputPerMTok": 1.25,
|
|
114
|
+
"outputPerMTok": 10
|
|
115
|
+
},
|
|
116
|
+
"gemini-2.5-flash": {
|
|
117
|
+
"inputPerMTok": 0.3,
|
|
118
|
+
"cachedInputPerMTok": 0.03,
|
|
119
|
+
"outputPerMTok": 2.5
|
|
120
|
+
},
|
|
121
|
+
"gemini-2.5-flash-image": {
|
|
122
|
+
"inputPerMTok": 0.3,
|
|
123
|
+
"cachedInputPerMTok": 0.075,
|
|
124
|
+
"outputPerMTok": 30
|
|
125
|
+
},
|
|
126
|
+
"gemini-2.5-flash-lite": {
|
|
127
|
+
"inputPerMTok": 0.1,
|
|
128
|
+
"cachedInputPerMTok": 0.01,
|
|
129
|
+
"outputPerMTok": 0.4
|
|
130
|
+
},
|
|
131
|
+
"gemini-2.5-flash-preview-tts": {
|
|
132
|
+
"inputPerMTok": 0.5,
|
|
133
|
+
"outputPerMTok": 10
|
|
134
|
+
},
|
|
135
|
+
"gemini-2.5-pro": {
|
|
136
|
+
"inputPerMTok": 1.25,
|
|
137
|
+
"cachedInputPerMTok": 0.125,
|
|
138
|
+
"outputPerMTok": 10
|
|
139
|
+
},
|
|
140
|
+
"gemini-2.5-pro-preview-tts": {
|
|
141
|
+
"inputPerMTok": 1,
|
|
142
|
+
"outputPerMTok": 20
|
|
143
|
+
},
|
|
144
|
+
"gemini-3-flash-preview": {
|
|
145
|
+
"inputPerMTok": 0.5,
|
|
146
|
+
"cachedInputPerMTok": 0.05,
|
|
147
|
+
"outputPerMTok": 3
|
|
148
|
+
},
|
|
149
|
+
"gemini-3-pro-image": {
|
|
150
|
+
"inputPerMTok": 2,
|
|
151
|
+
"outputPerMTok": 120
|
|
152
|
+
},
|
|
153
|
+
"gemini-3-pro-image-preview": {
|
|
154
|
+
"inputPerMTok": 2,
|
|
155
|
+
"outputPerMTok": 120
|
|
156
|
+
},
|
|
157
|
+
"gemini-3.1-flash-image": {
|
|
158
|
+
"inputPerMTok": 0.5,
|
|
159
|
+
"outputPerMTok": 60
|
|
160
|
+
},
|
|
161
|
+
"gemini-3.1-flash-image-preview": {
|
|
162
|
+
"inputPerMTok": 0.5,
|
|
163
|
+
"outputPerMTok": 60
|
|
164
|
+
},
|
|
165
|
+
"gemini-3.1-flash-lite": {
|
|
166
|
+
"inputPerMTok": 0.25,
|
|
167
|
+
"cachedInputPerMTok": 0.025,
|
|
168
|
+
"outputPerMTok": 1.5
|
|
169
|
+
},
|
|
170
|
+
"gemini-3.1-flash-lite-image": {
|
|
171
|
+
"inputPerMTok": 0.25,
|
|
172
|
+
"outputPerMTok": 30
|
|
173
|
+
},
|
|
174
|
+
"gemini-3.1-flash-lite-preview": {
|
|
175
|
+
"inputPerMTok": 0.25,
|
|
176
|
+
"cachedInputPerMTok": 0.025,
|
|
177
|
+
"outputPerMTok": 1.5
|
|
178
|
+
},
|
|
179
|
+
"gemini-3.1-flash-live-preview": {
|
|
180
|
+
"inputPerMTok": 0.75,
|
|
181
|
+
"outputPerMTok": 4.5
|
|
182
|
+
},
|
|
183
|
+
"gemini-3.1-flash-tts-preview": {
|
|
184
|
+
"inputPerMTok": 1,
|
|
185
|
+
"outputPerMTok": 20
|
|
186
|
+
},
|
|
187
|
+
"gemini-3.1-pro-preview": {
|
|
188
|
+
"inputPerMTok": 2,
|
|
189
|
+
"cachedInputPerMTok": 0.2,
|
|
190
|
+
"outputPerMTok": 12
|
|
191
|
+
},
|
|
192
|
+
"gemini-3.1-pro-preview-customtools": {
|
|
193
|
+
"inputPerMTok": 2,
|
|
194
|
+
"cachedInputPerMTok": 0.2,
|
|
195
|
+
"outputPerMTok": 12
|
|
196
|
+
},
|
|
197
|
+
"gemini-3.5-flash": {
|
|
198
|
+
"inputPerMTok": 1.5,
|
|
199
|
+
"cachedInputPerMTok": 0.15,
|
|
200
|
+
"outputPerMTok": 9
|
|
201
|
+
},
|
|
202
|
+
"gemini-3.5-flash-lite": {
|
|
203
|
+
"inputPerMTok": 0.3,
|
|
204
|
+
"cachedInputPerMTok": 0.03,
|
|
205
|
+
"outputPerMTok": 2.5
|
|
206
|
+
},
|
|
207
|
+
"gemini-3.5-live-translate-preview": {
|
|
208
|
+
"inputPerMTok": 3.5,
|
|
209
|
+
"outputPerMTok": 21
|
|
210
|
+
},
|
|
211
|
+
"gemini-3.6-flash": {
|
|
212
|
+
"inputPerMTok": 0.75,
|
|
213
|
+
"cachedInputPerMTok": 0.075,
|
|
214
|
+
"outputPerMTok": 3.75
|
|
215
|
+
},
|
|
216
|
+
"gemini-3.7-flash": {
|
|
217
|
+
"inputPerMTok": 0.75,
|
|
218
|
+
"cachedInputPerMTok": 0.075,
|
|
219
|
+
"outputPerMTok": 3.75
|
|
220
|
+
},
|
|
221
|
+
"gemini-3.8-flash": {
|
|
222
|
+
"inputPerMTok": 0.75,
|
|
223
|
+
"cachedInputPerMTok": 0.075,
|
|
224
|
+
"outputPerMTok": 3.75
|
|
225
|
+
},
|
|
226
|
+
"gemini-embedding-001": {
|
|
227
|
+
"inputPerMTok": 0.15,
|
|
228
|
+
"outputPerMTok": 0
|
|
229
|
+
},
|
|
230
|
+
"gemini-embedding-2": {
|
|
231
|
+
"inputPerMTok": 0.2,
|
|
232
|
+
"outputPerMTok": 0
|
|
233
|
+
},
|
|
234
|
+
"gemini-flash-latest": {
|
|
235
|
+
"inputPerMTok": 0.75,
|
|
236
|
+
"cachedInputPerMTok": 0.075,
|
|
237
|
+
"outputPerMTok": 3.75
|
|
238
|
+
},
|
|
239
|
+
"gemini-flash-lite-latest": {
|
|
240
|
+
"inputPerMTok": 0.3,
|
|
241
|
+
"cachedInputPerMTok": 0.03,
|
|
242
|
+
"outputPerMTok": 2.5
|
|
243
|
+
},
|
|
244
|
+
"gemini-omni-flash-preview": {
|
|
245
|
+
"inputPerMTok": 1.5,
|
|
246
|
+
"outputPerMTok": 17.5
|
|
247
|
+
},
|
|
248
|
+
"glm-4.5": {
|
|
249
|
+
"inputPerMTok": 0.6,
|
|
250
|
+
"cachedInputPerMTok": 0.11,
|
|
251
|
+
"outputPerMTok": 2.2
|
|
252
|
+
},
|
|
253
|
+
"glm-4.5-air": {
|
|
254
|
+
"inputPerMTok": 0.2,
|
|
255
|
+
"cachedInputPerMTok": 0.03,
|
|
256
|
+
"outputPerMTok": 1.1
|
|
257
|
+
},
|
|
258
|
+
"glm-4.5-flash": {
|
|
259
|
+
"inputPerMTok": 0,
|
|
260
|
+
"cachedInputPerMTok": 0,
|
|
261
|
+
"outputPerMTok": 0
|
|
262
|
+
},
|
|
263
|
+
"glm-4.5v": {
|
|
264
|
+
"inputPerMTok": 0.6,
|
|
265
|
+
"outputPerMTok": 1.8
|
|
266
|
+
},
|
|
267
|
+
"glm-4.6": {
|
|
268
|
+
"inputPerMTok": 0.6,
|
|
269
|
+
"cachedInputPerMTok": 0.11,
|
|
270
|
+
"outputPerMTok": 2.2
|
|
271
|
+
},
|
|
272
|
+
"glm-4.6v": {
|
|
273
|
+
"inputPerMTok": 0.3,
|
|
274
|
+
"outputPerMTok": 0.9
|
|
275
|
+
},
|
|
276
|
+
"glm-4.7": {
|
|
277
|
+
"inputPerMTok": 0.6,
|
|
278
|
+
"cachedInputPerMTok": 0.11,
|
|
279
|
+
"outputPerMTok": 2.2
|
|
280
|
+
},
|
|
281
|
+
"glm-4.7-flash": {
|
|
282
|
+
"inputPerMTok": 0,
|
|
283
|
+
"cachedInputPerMTok": 0,
|
|
284
|
+
"outputPerMTok": 0
|
|
285
|
+
},
|
|
286
|
+
"glm-4.7-flashx": {
|
|
287
|
+
"inputPerMTok": 0.07,
|
|
288
|
+
"cachedInputPerMTok": 0.01,
|
|
289
|
+
"outputPerMTok": 0.4
|
|
290
|
+
},
|
|
291
|
+
"glm-5": {
|
|
292
|
+
"inputPerMTok": 1,
|
|
293
|
+
"cachedInputPerMTok": 0.2,
|
|
294
|
+
"outputPerMTok": 3.2
|
|
295
|
+
},
|
|
296
|
+
"glm-5.1": {
|
|
297
|
+
"inputPerMTok": 1.4,
|
|
298
|
+
"cachedInputPerMTok": 0.26,
|
|
299
|
+
"outputPerMTok": 4.4
|
|
300
|
+
},
|
|
301
|
+
"glm-5.2": {
|
|
302
|
+
"inputPerMTok": 1.4,
|
|
303
|
+
"cachedInputPerMTok": 0.26,
|
|
304
|
+
"outputPerMTok": 4.4
|
|
305
|
+
},
|
|
306
|
+
"glm-5.3": {
|
|
307
|
+
"inputPerMTok": 1.4,
|
|
308
|
+
"cachedInputPerMTok": 0.26,
|
|
309
|
+
"outputPerMTok": 4.4
|
|
310
|
+
},
|
|
311
|
+
"glm-5.3-flash": {
|
|
312
|
+
"inputPerMTok": 0.15,
|
|
313
|
+
"cachedInputPerMTok": 0.03,
|
|
314
|
+
"outputPerMTok": 0.5
|
|
315
|
+
},
|
|
316
|
+
"glm-5.3-flashx": {
|
|
317
|
+
"inputPerMTok": 0.37,
|
|
318
|
+
"cachedInputPerMTok": 0.075,
|
|
319
|
+
"outputPerMTok": 1.25
|
|
320
|
+
},
|
|
321
|
+
"glm-5v-turbo": {
|
|
322
|
+
"inputPerMTok": 5,
|
|
323
|
+
"cachedInputPerMTok": 1.2,
|
|
324
|
+
"outputPerMTok": 22
|
|
325
|
+
},
|
|
326
|
+
"gpt-3.5-turbo": {
|
|
327
|
+
"inputPerMTok": 0.5,
|
|
328
|
+
"cachedInputPerMTok": 0,
|
|
329
|
+
"outputPerMTok": 1.5
|
|
330
|
+
},
|
|
331
|
+
"gpt-4": {
|
|
332
|
+
"inputPerMTok": 30,
|
|
333
|
+
"outputPerMTok": 60
|
|
334
|
+
},
|
|
335
|
+
"gpt-4-turbo": {
|
|
336
|
+
"inputPerMTok": 10,
|
|
337
|
+
"outputPerMTok": 30
|
|
338
|
+
},
|
|
339
|
+
"gpt-4.1": {
|
|
340
|
+
"inputPerMTok": 2,
|
|
341
|
+
"cachedInputPerMTok": 0.5,
|
|
342
|
+
"outputPerMTok": 8
|
|
343
|
+
},
|
|
344
|
+
"gpt-4.1-mini": {
|
|
345
|
+
"inputPerMTok": 0.4,
|
|
346
|
+
"cachedInputPerMTok": 0.1,
|
|
347
|
+
"outputPerMTok": 1.6
|
|
348
|
+
},
|
|
349
|
+
"gpt-4.1-nano": {
|
|
350
|
+
"inputPerMTok": 0.1,
|
|
351
|
+
"cachedInputPerMTok": 0.025,
|
|
352
|
+
"outputPerMTok": 0.4
|
|
353
|
+
},
|
|
354
|
+
"gpt-4o": {
|
|
355
|
+
"inputPerMTok": 2.5,
|
|
356
|
+
"cachedInputPerMTok": 1.25,
|
|
357
|
+
"outputPerMTok": 10
|
|
358
|
+
},
|
|
359
|
+
"gpt-4o-2024-05-13": {
|
|
360
|
+
"inputPerMTok": 5,
|
|
361
|
+
"outputPerMTok": 15
|
|
362
|
+
},
|
|
363
|
+
"gpt-4o-2024-08-06": {
|
|
364
|
+
"inputPerMTok": 2.5,
|
|
365
|
+
"cachedInputPerMTok": 1.25,
|
|
366
|
+
"outputPerMTok": 10
|
|
367
|
+
},
|
|
368
|
+
"gpt-4o-2024-11-20": {
|
|
369
|
+
"inputPerMTok": 2.5,
|
|
370
|
+
"cachedInputPerMTok": 1.25,
|
|
371
|
+
"outputPerMTok": 10
|
|
372
|
+
},
|
|
373
|
+
"gpt-4o-mini": {
|
|
374
|
+
"inputPerMTok": 0.15,
|
|
375
|
+
"cachedInputPerMTok": 0.075,
|
|
376
|
+
"outputPerMTok": 0.6
|
|
377
|
+
},
|
|
378
|
+
"gpt-5": {
|
|
379
|
+
"inputPerMTok": 1.25,
|
|
380
|
+
"cachedInputPerMTok": 0.125,
|
|
381
|
+
"outputPerMTok": 10
|
|
382
|
+
},
|
|
383
|
+
"gpt-5-mini": {
|
|
384
|
+
"inputPerMTok": 0.25,
|
|
385
|
+
"cachedInputPerMTok": 0.025,
|
|
386
|
+
"outputPerMTok": 2
|
|
387
|
+
},
|
|
388
|
+
"gpt-5-nano": {
|
|
389
|
+
"inputPerMTok": 0.05,
|
|
390
|
+
"cachedInputPerMTok": 0.005,
|
|
391
|
+
"outputPerMTok": 0.4
|
|
392
|
+
},
|
|
393
|
+
"gpt-5-pro": {
|
|
394
|
+
"inputPerMTok": 15,
|
|
395
|
+
"outputPerMTok": 120
|
|
396
|
+
},
|
|
397
|
+
"gpt-5.1": {
|
|
398
|
+
"inputPerMTok": 1.25,
|
|
399
|
+
"cachedInputPerMTok": 0.125,
|
|
400
|
+
"outputPerMTok": 10
|
|
401
|
+
},
|
|
402
|
+
"gpt-5.2": {
|
|
403
|
+
"inputPerMTok": 1.75,
|
|
404
|
+
"cachedInputPerMTok": 0.175,
|
|
405
|
+
"outputPerMTok": 14
|
|
406
|
+
},
|
|
407
|
+
"gpt-5.2-chat-latest": {
|
|
408
|
+
"inputPerMTok": 1.75,
|
|
409
|
+
"cachedInputPerMTok": 0.175,
|
|
410
|
+
"outputPerMTok": 14
|
|
411
|
+
},
|
|
412
|
+
"gpt-5.2-pro": {
|
|
413
|
+
"inputPerMTok": 21,
|
|
414
|
+
"outputPerMTok": 168
|
|
415
|
+
},
|
|
416
|
+
"gpt-5.3-chat-latest": {
|
|
417
|
+
"inputPerMTok": 1.75,
|
|
418
|
+
"cachedInputPerMTok": 0.175,
|
|
419
|
+
"outputPerMTok": 14
|
|
420
|
+
},
|
|
421
|
+
"gpt-5.3-codex": {
|
|
422
|
+
"inputPerMTok": 1.75,
|
|
423
|
+
"cachedInputPerMTok": 0.175,
|
|
424
|
+
"outputPerMTok": 14
|
|
425
|
+
},
|
|
426
|
+
"gpt-5.3-codex-spark": {
|
|
427
|
+
"inputPerMTok": 1.75,
|
|
428
|
+
"cachedInputPerMTok": 0.175,
|
|
429
|
+
"outputPerMTok": 14
|
|
430
|
+
},
|
|
431
|
+
"gpt-5.4": {
|
|
432
|
+
"inputPerMTok": 2.5,
|
|
433
|
+
"cachedInputPerMTok": 0.25,
|
|
434
|
+
"outputPerMTok": 15
|
|
435
|
+
},
|
|
436
|
+
"gpt-5.4-mini": {
|
|
437
|
+
"inputPerMTok": 0.75,
|
|
438
|
+
"cachedInputPerMTok": 0.075,
|
|
439
|
+
"outputPerMTok": 4.5
|
|
440
|
+
},
|
|
441
|
+
"gpt-5.4-nano": {
|
|
442
|
+
"inputPerMTok": 0.2,
|
|
443
|
+
"cachedInputPerMTok": 0.02,
|
|
444
|
+
"outputPerMTok": 1.25
|
|
445
|
+
},
|
|
446
|
+
"gpt-5.4-pro": {
|
|
447
|
+
"inputPerMTok": 30,
|
|
448
|
+
"outputPerMTok": 180
|
|
449
|
+
},
|
|
450
|
+
"gpt-5.5": {
|
|
451
|
+
"inputPerMTok": 5,
|
|
452
|
+
"cachedInputPerMTok": 0.5,
|
|
453
|
+
"outputPerMTok": 30
|
|
454
|
+
},
|
|
455
|
+
"gpt-5.5-pro": {
|
|
456
|
+
"inputPerMTok": 30,
|
|
457
|
+
"outputPerMTok": 180
|
|
458
|
+
},
|
|
459
|
+
"gpt-5.6": {
|
|
460
|
+
"inputPerMTok": 4,
|
|
461
|
+
"cachedInputPerMTok": 0.4,
|
|
462
|
+
"outputPerMTok": 20
|
|
463
|
+
},
|
|
464
|
+
"gpt-5.6-luna": {
|
|
465
|
+
"inputPerMTok": 0.2,
|
|
466
|
+
"cachedInputPerMTok": 0.02,
|
|
467
|
+
"outputPerMTok": 1.2
|
|
468
|
+
},
|
|
469
|
+
"gpt-5.6-sol": {
|
|
470
|
+
"inputPerMTok": 4,
|
|
471
|
+
"cachedInputPerMTok": 0.4,
|
|
472
|
+
"outputPerMTok": 20
|
|
473
|
+
},
|
|
474
|
+
"gpt-5.6-terra": {
|
|
475
|
+
"inputPerMTok": 2,
|
|
476
|
+
"cachedInputPerMTok": 0.2,
|
|
477
|
+
"outputPerMTok": 12
|
|
478
|
+
},
|
|
479
|
+
"gpt-6-astra": {
|
|
480
|
+
"inputPerMTok": 10,
|
|
481
|
+
"cachedInputPerMTok": 1,
|
|
482
|
+
"outputPerMTok": 50
|
|
483
|
+
},
|
|
484
|
+
"gpt-image-2": {
|
|
485
|
+
"inputPerMTok": 5,
|
|
486
|
+
"cachedInputPerMTok": 1.25,
|
|
487
|
+
"outputPerMTok": 30
|
|
488
|
+
},
|
|
489
|
+
"gpt-realtime-2.1": {
|
|
490
|
+
"inputPerMTok": 4,
|
|
491
|
+
"cachedInputPerMTok": 0.4,
|
|
492
|
+
"outputPerMTok": 24
|
|
493
|
+
},
|
|
494
|
+
"lyria-3-clip-preview": {
|
|
495
|
+
"inputPerMTok": 0,
|
|
496
|
+
"outputPerMTok": 0
|
|
497
|
+
},
|
|
498
|
+
"lyria-3-pro-preview": {
|
|
499
|
+
"inputPerMTok": 0,
|
|
500
|
+
"outputPerMTok": 0
|
|
501
|
+
},
|
|
502
|
+
"o1": {
|
|
503
|
+
"inputPerMTok": 15,
|
|
504
|
+
"cachedInputPerMTok": 7.5,
|
|
505
|
+
"outputPerMTok": 60
|
|
506
|
+
},
|
|
507
|
+
"o1-pro": {
|
|
508
|
+
"inputPerMTok": 150,
|
|
509
|
+
"outputPerMTok": 600
|
|
510
|
+
},
|
|
511
|
+
"o3": {
|
|
512
|
+
"inputPerMTok": 2,
|
|
513
|
+
"cachedInputPerMTok": 0.5,
|
|
514
|
+
"outputPerMTok": 8
|
|
515
|
+
},
|
|
516
|
+
"o3-mini": {
|
|
517
|
+
"inputPerMTok": 1.1,
|
|
518
|
+
"cachedInputPerMTok": 0.55,
|
|
519
|
+
"outputPerMTok": 4.4
|
|
520
|
+
},
|
|
521
|
+
"o3-pro": {
|
|
522
|
+
"inputPerMTok": 20,
|
|
523
|
+
"outputPerMTok": 80
|
|
524
|
+
},
|
|
525
|
+
"o4-mini": {
|
|
526
|
+
"inputPerMTok": 1.1,
|
|
527
|
+
"cachedInputPerMTok": 0.275,
|
|
528
|
+
"outputPerMTok": 4.4
|
|
529
|
+
},
|
|
530
|
+
"text-embedding-3-large": {
|
|
531
|
+
"inputPerMTok": 0.13,
|
|
532
|
+
"outputPerMTok": 0
|
|
533
|
+
},
|
|
534
|
+
"text-embedding-3-small": {
|
|
535
|
+
"inputPerMTok": 0.02,
|
|
536
|
+
"outputPerMTok": 0
|
|
537
|
+
},
|
|
538
|
+
"text-embedding-ada-002": {
|
|
539
|
+
"inputPerMTok": 0.1,
|
|
540
|
+
"outputPerMTok": 0
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vendored price snapshot every invocation is priced against when its
|
|
3
|
+
* runtime declares no rates of its own: models.dev's published first-party
|
|
4
|
+
* rates for the five vendors this product's harnesses talk to (anthropic,
|
|
5
|
+
* deepseek, google, openai, zhipuai), filtered at vendor time.
|
|
6
|
+
*
|
|
7
|
+
* A dated snapshot, not a live query, by design: the live per-invocation spend
|
|
8
|
+
* surfaces that motivated the idea were investigated and closed (DeepSeek
|
|
9
|
+
* exposes only an account-wide balance scalar, Zhipu publishes no billing
|
|
10
|
+
* endpoint at all, Google Cloud Billing exposes a budget cap without a
|
|
11
|
+
* pre-configured BigQuery export), so the owner's decision was to vendor
|
|
12
|
+
* models.dev and always compute cost from these rates and the token counts.
|
|
13
|
+
* Update it only by re-vendoring, never by fetching at run time.
|
|
14
|
+
*
|
|
15
|
+
* The lookup keys by model id alone: at vendor time (2026-09-19) these five
|
|
16
|
+
* providers carried zero colliding model ids, so no vendor or harness
|
|
17
|
+
* disambiguation is needed for exactly this set. A model with a documented
|
|
18
|
+
* higher-context tier (e.g. openai's gpt-5.6-sol above 200k tokens) is
|
|
19
|
+
* recorded at its base-tier rate only -- a known, unmeasured simplification,
|
|
20
|
+
* not a bug; tiers are deliberately not modelled.
|
|
21
|
+
*/
|
|
22
|
+
import { readFileSync } from "node:fs";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
|
|
25
|
+
/** @typedef {import("./process.mjs").RuntimePricing} RuntimePricing */
|
|
26
|
+
|
|
27
|
+
/** @type {{fetchedAt: string, source: string, providers: string[], models: Record<string, RuntimePricing>}} */
|
|
28
|
+
const SEED = JSON.parse(readFileSync(fileURLToPath(new URL("./pricing-seed.json", import.meta.url)), "utf8"));
|
|
29
|
+
|
|
30
|
+
const DAY_MS = 86_400_000;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The vendored rate for one model id, or undefined when the seed does not
|
|
34
|
+
* know it -- an unknown model keeps its cost unknown rather than unpriced.
|
|
35
|
+
*
|
|
36
|
+
* @param {string|null|undefined} model
|
|
37
|
+
* @returns {RuntimePricing|undefined}
|
|
38
|
+
*/
|
|
39
|
+
export function seedPricing(model) {
|
|
40
|
+
if (typeof model !== "string") return undefined;
|
|
41
|
+
return SEED.models[model];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* How old the vendored snapshot is, in whole days, and whether it is stale.
|
|
46
|
+
*
|
|
47
|
+
* @param {Date} [now]
|
|
48
|
+
* @returns {{fetchedAt: string, ageDays: number, stale: boolean}}
|
|
49
|
+
*/
|
|
50
|
+
export function pricingSeedAge(now = new Date()) {
|
|
51
|
+
const ageDays = Math.floor((now.getTime() - Date.parse(SEED.fetchedAt)) / DAY_MS);
|
|
52
|
+
// The 90-day staleness threshold is a first guess, not a measurement (2026-09-19).
|
|
53
|
+
return { fetchedAt: SEED.fetchedAt, ageDays, stale: ageDays > 90 };
|
|
54
|
+
}
|
package/src/engine/process.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { errorCode, errorMessage } from "../util.mjs";
|
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
import { harnessCapabilities, normalizeProviderResult, providerCommand } from "../harnesses/index.mjs";
|
|
16
16
|
import { latestTimeoutSec } from "./backoff.mjs";
|
|
17
|
+
import { seedPricing } from "./pricing-seed.mjs";
|
|
17
18
|
import { attemptWorkspace, sealAttempt } from "../repo/worktree.mjs";
|
|
18
19
|
|
|
19
20
|
import { invocationOwned, processGroupAlive, processStartTokenMatches } from "./process-identity.mjs";
|
|
@@ -550,6 +551,11 @@ export function invocationResult(invocation, runtime, options = {}) {
|
|
|
550
551
|
* missing measurement, not a zero contribution, so it keeps the whole record
|
|
551
552
|
* `unknown` (`costUsd: null`) rather than understating it.
|
|
552
553
|
*
|
|
554
|
+
* When the runtime declares no pricing of its own, the rates fall back to the
|
|
555
|
+
* vendored models.dev snapshot (`pricing-seed.mjs`) keyed by the runtime's
|
|
556
|
+
* model, and a seed-priced invocation is exactly as `priced` as an
|
|
557
|
+
* operator-declared one; a model the seed does not know stays unknown.
|
|
558
|
+
*
|
|
553
559
|
* It lives beside `invocationResult`, the second source point, rather than in
|
|
554
560
|
* `run/usage.mjs`, which re-exports it: that module already imports this one,
|
|
555
561
|
* so defining it here is what keeps the two source points acyclic.
|
|
@@ -561,7 +567,8 @@ export function invocationResult(invocation, runtime, options = {}) {
|
|
|
561
567
|
*/
|
|
562
568
|
export function priceUsage(runtime, usage, reportedCostUsd) {
|
|
563
569
|
if (typeof reportedCostUsd === "number") return { costUsd: reportedCostUsd, costProvenance: undefined };
|
|
564
|
-
const
|
|
570
|
+
const declaredRuntime = /** @type {{pricing?: RuntimePricing, model?: string}|null|undefined} */ (runtime);
|
|
571
|
+
const pricing = declaredRuntime?.pricing ?? seedPricing(declaredRuntime?.model);
|
|
565
572
|
if (!pricing) return { costUsd: null, costProvenance: undefined };
|
|
566
573
|
/** @type {[number|null|undefined, number|undefined][]} */
|
|
567
574
|
const terms = [
|
|
@@ -22,6 +22,7 @@ import { parseJudge } from "./prompts.mjs";
|
|
|
22
22
|
import { discoveryOutput, parseWorkerResult } from "../contract/worker-result.mjs";
|
|
23
23
|
import { readJson, writeJsonAtomic, writeTextAtomic } from "../run/store.mjs";
|
|
24
24
|
import { routeRuntimeForState, runtimeSnapshot } from "./failover.mjs";
|
|
25
|
+
import { RUNS_DIR_NAME } from "../run/paths.mjs";
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Thrown by `resolveWorkerResult` when an execution result declares `output`.
|
|
@@ -47,7 +48,7 @@ export function workerResultPath(runDir, nodeId) {
|
|
|
47
48
|
}
|
|
48
49
|
/** @param {string} runDir @param {string} nodeId @param {string} workspace @returns {string} */
|
|
49
50
|
export function attemptWorkerResultPath(runDir, nodeId, workspace) {
|
|
50
|
-
return join(workspace,
|
|
51
|
+
return join(workspace, RUNS_DIR_NAME, "results", `${nodeId}.json`);
|
|
51
52
|
}
|
|
52
53
|
/** @param {string} workspace @param {string} nodeId */
|
|
53
54
|
export function clearAttemptWorkerResult(workspace, nodeId) {
|