@openprose/reactor-cradle 0.1.0-rc.1

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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +270 -0
  3. package/dist/assert/index.d.ts +35 -0
  4. package/dist/assert/index.d.ts.map +1 -0
  5. package/dist/assert/index.js +398 -0
  6. package/dist/baselines/cost-thesis/index.d.ts +103 -0
  7. package/dist/baselines/cost-thesis/index.d.ts.map +1 -0
  8. package/dist/baselines/cost-thesis/index.js +337 -0
  9. package/dist/baselines/naive-loop/index.d.ts +46 -0
  10. package/dist/baselines/naive-loop/index.d.ts.map +1 -0
  11. package/dist/baselines/naive-loop/index.js +188 -0
  12. package/dist/baselines/no-memo/index.d.ts +84 -0
  13. package/dist/baselines/no-memo/index.d.ts.map +1 -0
  14. package/dist/baselines/no-memo/index.js +226 -0
  15. package/dist/doubles/clock.d.ts +9 -0
  16. package/dist/doubles/clock.d.ts.map +1 -0
  17. package/dist/doubles/clock.js +42 -0
  18. package/dist/doubles/storage.d.ts +24 -0
  19. package/dist/doubles/storage.d.ts.map +1 -0
  20. package/dist/doubles/storage.js +191 -0
  21. package/dist/eval/index.d.ts +204 -0
  22. package/dist/eval/index.d.ts.map +1 -0
  23. package/dist/eval/index.js +596 -0
  24. package/dist/index.d.ts +24 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +39 -0
  27. package/dist/policy-author/index.d.ts +103 -0
  28. package/dist/policy-author/index.d.ts.map +1 -0
  29. package/dist/policy-author/index.js +358 -0
  30. package/dist/policy-drift/index.d.ts +64 -0
  31. package/dist/policy-drift/index.d.ts.map +1 -0
  32. package/dist/policy-drift/index.js +495 -0
  33. package/dist/policy-replay/index.d.ts +106 -0
  34. package/dist/policy-replay/index.d.ts.map +1 -0
  35. package/dist/policy-replay/index.js +361 -0
  36. package/dist/provider-parity/index.d.ts +91 -0
  37. package/dist/provider-parity/index.d.ts.map +1 -0
  38. package/dist/provider-parity/index.js +439 -0
  39. package/dist/recompile/index.d.ts +161 -0
  40. package/dist/recompile/index.d.ts.map +1 -0
  41. package/dist/recompile/index.js +690 -0
  42. package/dist/release-candidate/index.d.ts +139 -0
  43. package/dist/release-candidate/index.d.ts.map +1 -0
  44. package/dist/release-candidate/index.js +553 -0
  45. package/dist/release-parity/index.d.ts +80 -0
  46. package/dist/release-parity/index.d.ts.map +1 -0
  47. package/dist/release-parity/index.js +1035 -0
  48. package/dist/replay/model-gateway.d.ts +25 -0
  49. package/dist/replay/model-gateway.d.ts.map +1 -0
  50. package/dist/replay/model-gateway.js +166 -0
  51. package/dist/replay/parity.d.ts +110 -0
  52. package/dist/replay/parity.d.ts.map +1 -0
  53. package/dist/replay/parity.js +232 -0
  54. package/dist/rollback/index.d.ts +106 -0
  55. package/dist/rollback/index.d.ts.map +1 -0
  56. package/dist/rollback/index.js +694 -0
  57. package/dist/scenario/parser.d.ts +11 -0
  58. package/dist/scenario/parser.d.ts.map +1 -0
  59. package/dist/scenario/parser.js +490 -0
  60. package/dist/scenario/runner.d.ts +12 -0
  61. package/dist/scenario/runner.d.ts.map +1 -0
  62. package/dist/scenario/runner.js +345 -0
  63. package/dist/scenario/synthetic-world-adapter.d.ts +4 -0
  64. package/dist/scenario/synthetic-world-adapter.d.ts.map +1 -0
  65. package/dist/scenario/synthetic-world-adapter.js +82 -0
  66. package/dist/scenario/time.d.ts +4 -0
  67. package/dist/scenario/time.d.ts.map +1 -0
  68. package/dist/scenario/time.js +45 -0
  69. package/dist/scenario/types.d.ts +149 -0
  70. package/dist/scenario/types.d.ts.map +1 -0
  71. package/dist/scenario/types.js +5 -0
  72. package/dist/spikes/index.d.ts +10 -0
  73. package/dist/spikes/index.d.ts.map +1 -0
  74. package/dist/spikes/index.js +29 -0
  75. package/dist/spikes/k1-ensemble-spread.d.ts +88 -0
  76. package/dist/spikes/k1-ensemble-spread.d.ts.map +1 -0
  77. package/dist/spikes/k1-ensemble-spread.js +396 -0
  78. package/dist/spikes/k2-policy-author.d.ts +25 -0
  79. package/dist/spikes/k2-policy-author.d.ts.map +1 -0
  80. package/dist/spikes/k2-policy-author.js +503 -0
  81. package/dist/spikes/live-refresh.d.ts +150 -0
  82. package/dist/spikes/live-refresh.d.ts.map +1 -0
  83. package/dist/spikes/live-refresh.js +511 -0
  84. package/dist/world/index.d.ts +2 -0
  85. package/dist/world/index.d.ts.map +1 -0
  86. package/dist/world/index.js +17 -0
  87. package/dist/world/synthetic-world.d.ts +104 -0
  88. package/dist/world/synthetic-world.d.ts.map +1 -0
  89. package/dist/world/synthetic-world.js +449 -0
  90. package/package.json +139 -0
@@ -0,0 +1,511 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OPENROUTER_K1_LIVE_RECORDING_MODELS_V0 = exports.OPENROUTER_K1_LIVE_CHAT_COMPLETIONS_URL_V0 = exports.OPENROUTER_K1_LIVE_RECORDING_VERSION_V0 = exports.OPENROUTER_K1_LIVE_RECORDING_SCHEMA_V0 = exports.OPENROUTER_LIVE_REFRESH_GUARD_VERSION_V0 = exports.OPENROUTER_LIVE_REFRESH_GUARD_SCHEMA_V0 = exports.OPENROUTER_LIVE_REFRESH_STANDING_CAP_USD_V0 = exports.OPENROUTER_LIVE_REFRESH_DEFAULT_MODEL_V0 = exports.OPENROUTER_LIVE_REFRESH_PROVIDER_V0 = exports.OPENROUTER_API_KEY_ENV_NAME_V0 = exports.OPENPROSE_DOTENV_PATH_V0 = void 0;
4
+ exports.prepareOpenRouterLiveRefreshV0 = prepareOpenRouterLiveRefreshV0;
5
+ exports.runOpenRouterLiveRefreshV0 = runOpenRouterLiveRefreshV0;
6
+ exports.recordOpenRouterK1LiveFixtureV0 = recordOpenRouterK1LiveFixtureV0;
7
+ exports.hasOpenRouterApiKeyInDotenvV0 = hasOpenRouterApiKeyInDotenvV0;
8
+ const node_fs_1 = require("node:fs");
9
+ const k1_ensemble_spread_1 = require("./k1-ensemble-spread");
10
+ exports.OPENPROSE_DOTENV_PATH_V0 = ".env";
11
+ exports.OPENROUTER_API_KEY_ENV_NAME_V0 = "OPENROUTER_API_KEY";
12
+ exports.OPENROUTER_LIVE_REFRESH_PROVIDER_V0 = "openrouter";
13
+ exports.OPENROUTER_LIVE_REFRESH_DEFAULT_MODEL_V0 = "google/gemini-3.1-flash-lite-preview";
14
+ exports.OPENROUTER_LIVE_REFRESH_STANDING_CAP_USD_V0 = 200;
15
+ exports.OPENROUTER_LIVE_REFRESH_GUARD_SCHEMA_V0 = "openprose.reactor-cradle.openrouter-live-refresh-guard";
16
+ exports.OPENROUTER_LIVE_REFRESH_GUARD_VERSION_V0 = 0;
17
+ exports.OPENROUTER_K1_LIVE_RECORDING_SCHEMA_V0 = "openprose.reactor-cradle.k1-live-recording";
18
+ exports.OPENROUTER_K1_LIVE_RECORDING_VERSION_V0 = 0;
19
+ exports.OPENROUTER_K1_LIVE_CHAT_COMPLETIONS_URL_V0 = "https://openrouter.ai/api/v1/chat/completions";
20
+ exports.OPENROUTER_K1_LIVE_RECORDING_MODELS_V0 = Object.freeze([
21
+ {
22
+ provider: "google",
23
+ model: exports.OPENROUTER_LIVE_REFRESH_DEFAULT_MODEL_V0,
24
+ family: "gemini",
25
+ size_class: "small",
26
+ prompt_cost_per_token_usd: 0.00000025,
27
+ completion_cost_per_token_usd: 0.0000015,
28
+ max_output_tokens: 180,
29
+ request_cap_usd: 0.25,
30
+ },
31
+ {
32
+ provider: "mistralai",
33
+ model: "mistralai/mistral-small-3.2-24b-instruct",
34
+ family: "mistral",
35
+ size_class: "small",
36
+ prompt_cost_per_token_usd: 0.000000075,
37
+ completion_cost_per_token_usd: 0.0000002,
38
+ max_output_tokens: 180,
39
+ request_cap_usd: 0.25,
40
+ },
41
+ {
42
+ provider: "qwen",
43
+ model: "qwen/qwen-2.5-72b-instruct",
44
+ family: "qwen",
45
+ size_class: "large",
46
+ prompt_cost_per_token_usd: 0.00000036,
47
+ completion_cost_per_token_usd: 0.0000004,
48
+ max_output_tokens: 180,
49
+ request_cap_usd: 0.25,
50
+ },
51
+ ]);
52
+ function prepareOpenRouterLiveRefreshV0(input = {}) {
53
+ if (input.allow_live !== true) {
54
+ return {
55
+ schema: exports.OPENROUTER_LIVE_REFRESH_GUARD_SCHEMA_V0,
56
+ v: exports.OPENROUTER_LIVE_REFRESH_GUARD_VERSION_V0,
57
+ status: "disabled",
58
+ provider: exports.OPENROUTER_LIVE_REFRESH_PROVIDER_V0,
59
+ reason: "live-opt-in-required",
60
+ };
61
+ }
62
+ const accounting = validateAccounting(input.accounting);
63
+ const model = validateModel(input.model);
64
+ const envPath = normalizeEnvPath(input.env_path);
65
+ const envText = readDotenvText(envPath, input.readEnvFile);
66
+ if (!hasOpenRouterApiKeyInDotenvV0(envText)) {
67
+ throw new Error(`live refresh requires ${exports.OPENROUTER_API_KEY_ENV_NAME_V0} in ${envPath}`);
68
+ }
69
+ return {
70
+ schema: exports.OPENROUTER_LIVE_REFRESH_GUARD_SCHEMA_V0,
71
+ v: exports.OPENROUTER_LIVE_REFRESH_GUARD_VERSION_V0,
72
+ status: "ready",
73
+ provider: exports.OPENROUTER_LIVE_REFRESH_PROVIDER_V0,
74
+ env_path: envPath,
75
+ env_key_name: exports.OPENROUTER_API_KEY_ENV_NAME_V0,
76
+ api_key_present: true,
77
+ model,
78
+ accounting,
79
+ };
80
+ }
81
+ function runOpenRouterLiveRefreshV0(input, invokeLiveRefresh) {
82
+ const guard = prepareOpenRouterLiveRefreshV0(input);
83
+ if (guard.status === "disabled") {
84
+ return {
85
+ status: "disabled",
86
+ invoked: false,
87
+ guard,
88
+ };
89
+ }
90
+ return {
91
+ status: "ready",
92
+ invoked: true,
93
+ guard,
94
+ result: invokeLiveRefresh(guard),
95
+ };
96
+ }
97
+ async function recordOpenRouterK1LiveFixtureV0(input) {
98
+ const guard = prepareOpenRouterLiveRefreshV0(input);
99
+ if (guard.status !== "ready") {
100
+ throw new Error("K1 live recording requires explicit live opt-in");
101
+ }
102
+ const models = Object.freeze([
103
+ ...(input.models ?? exports.OPENROUTER_K1_LIVE_RECORDING_MODELS_V0),
104
+ ]);
105
+ validateK1LiveModelSet(models);
106
+ const prompt = buildK1LivePrompt();
107
+ const costPlan = planK1LiveRequestCosts(models, prompt, guard.accounting);
108
+ const apiKey = readOpenRouterApiKey(input.env_path, input.readEnvFile);
109
+ const liveFetch = input.fetch ?? fetch;
110
+ const startedAt = (input.now?.() ?? new Date()).toISOString();
111
+ const outputs = [];
112
+ const outputRecordings = [];
113
+ for (const [index, model] of models.entries()) {
114
+ const requestStartedAt = Date.now();
115
+ const response = await liveFetch(exports.OPENROUTER_K1_LIVE_CHAT_COMPLETIONS_URL_V0, {
116
+ method: "POST",
117
+ headers: {
118
+ authorization: `Bearer ${apiKey}`,
119
+ "content-type": "application/json",
120
+ "http-referer": "https://github.com/openprose/prose",
121
+ "x-title": "OpenProse Reactor Cradle K1 Live Recording",
122
+ },
123
+ body: JSON.stringify({
124
+ model: model.model,
125
+ messages: [
126
+ {
127
+ role: "system",
128
+ content: "You are a calibration judge. Return only compact JSON. Do not include markdown fences.",
129
+ },
130
+ {
131
+ role: "user",
132
+ content: prompt,
133
+ },
134
+ ],
135
+ temperature: 0,
136
+ max_tokens: model.max_output_tokens,
137
+ usage: { include: true },
138
+ }),
139
+ });
140
+ const latencyMs = Math.max(0, Date.now() - requestStartedAt);
141
+ const requestId = response.headers.get("x-request-id") ??
142
+ response.headers.get("x-openrouter-request-id") ??
143
+ response.headers.get("cf-ray") ??
144
+ "";
145
+ if (!response.ok) {
146
+ const body = await safeResponseText(response);
147
+ throw new Error(`OpenRouter K1 live recording failed for ${model.model}: HTTP ${response.status} ${body}`);
148
+ }
149
+ const body = (await response.json());
150
+ const parsed = parseOpenRouterChatCompletion(body, model, index);
151
+ const usage = parsed.usage;
152
+ const spend = usageCostUsd(usage) ?? estimateUsageCostUsd(model, usage);
153
+ if (spend > model.request_cap_usd) {
154
+ throw new Error(`OpenRouter K1 live recording spend for ${model.model} exceeded per-call cap`);
155
+ }
156
+ const outputId = `${sanitizeOutputId(model.model)}-${parsed.response_id}`;
157
+ outputs.push({
158
+ output_id: outputId,
159
+ provider: model.provider,
160
+ model: model.model,
161
+ family: model.family,
162
+ size_class: model.size_class,
163
+ verdict: parsed.verdict,
164
+ score: parsed.score,
165
+ confidence: parsed.confidence,
166
+ text: parsed.text,
167
+ });
168
+ outputRecordings.push({
169
+ output_id: outputId,
170
+ provider: model.provider,
171
+ model: model.model,
172
+ request_id: requestId.length === 0 ? parsed.response_id : requestId,
173
+ response_id: parsed.response_id,
174
+ latency_ms: latencyMs,
175
+ finish_reason: parsed.finish_reason,
176
+ usage,
177
+ spend_usd: roundLiveSpendUsd(spend),
178
+ spend_source: usageCostUsd(usage) === undefined
179
+ ? "pricing-estimate-from-token-usage"
180
+ : "openrouter-usage-cost",
181
+ });
182
+ }
183
+ const spendUsd = roundLiveSpendUsd(outputRecordings.reduce((total, output) => total + output.spend_usd, 0));
184
+ if (spendUsd > costPlan.total_request_cap_usd) {
185
+ throw new Error("OpenRouter K1 live recording exceeded total request cap");
186
+ }
187
+ const completedAt = (input.now?.() ?? new Date()).toISOString();
188
+ return {
189
+ schema: k1_ensemble_spread_1.K1_ENSEMBLE_SPREAD_SCHEMA_V0,
190
+ v: k1_ensemble_spread_1.K1_ENSEMBLE_SPREAD_VERSION_V0,
191
+ fixture_id: `k1-live-recorded-openrouter-${startedAt.slice(0, 10)}`,
192
+ responsibility_id: "incident-briefing",
193
+ recorded_at: completedAt,
194
+ anchor: K1_LIVE_ANCHOR_V0,
195
+ calibration_bar: K1_LIVE_CALIBRATION_BAR_V0,
196
+ outputs,
197
+ recording: {
198
+ schema: exports.OPENROUTER_K1_LIVE_RECORDING_SCHEMA_V0,
199
+ v: exports.OPENROUTER_K1_LIVE_RECORDING_VERSION_V0,
200
+ provider: exports.OPENROUTER_LIVE_REFRESH_PROVIDER_V0,
201
+ chat_completions_url: exports.OPENROUTER_K1_LIVE_CHAT_COMPLETIONS_URL_V0,
202
+ started_at: startedAt,
203
+ completed_at: completedAt,
204
+ cap_usd: guard.accounting.cap_usd,
205
+ request_cap_usd: costPlan.total_request_cap_usd,
206
+ spend_usd: spendUsd,
207
+ currency: "USD",
208
+ model_count: models.length,
209
+ request_count: outputRecordings.length,
210
+ model_specs: models,
211
+ outputs: outputRecordings,
212
+ },
213
+ };
214
+ }
215
+ function hasOpenRouterApiKeyInDotenvV0(dotenvText) {
216
+ for (const line of dotenvText.split(/\r?\n/)) {
217
+ const match = /^(?:export\s+)?OPENROUTER_API_KEY\s*=\s*(.*)$/.exec(line.trim());
218
+ if (match === null) {
219
+ continue;
220
+ }
221
+ const rawValue = match[1];
222
+ if (rawValue === undefined) {
223
+ return false;
224
+ }
225
+ return normalizeDotenvValue(rawValue).length > 0;
226
+ }
227
+ return false;
228
+ }
229
+ const K1_LIVE_ANCHOR_V0 = Object.freeze({
230
+ label_source: "authored-incident-oracle-live-refresh",
231
+ calibration_grade: "authored",
232
+ verdict: "up",
233
+ score: 1,
234
+ });
235
+ const K1_LIVE_CALIBRATION_BAR_V0 = Object.freeze({
236
+ max_mean_error: 0.18,
237
+ max_spread_error_gap: 0.12,
238
+ low_spread_threshold: 0.15,
239
+ max_error_when_low_spread: 0.18,
240
+ });
241
+ function validateK1LiveModelSet(models) {
242
+ if (models.length < 2) {
243
+ throw new Error("K1 live recording requires at least two models");
244
+ }
245
+ const families = new Set(models.map((model) => model.family));
246
+ const providers = new Set(models.map((model) => model.provider));
247
+ const sizes = new Set(models.map((model) => model.size_class));
248
+ if (families.size < 2 || providers.size < 2 || sizes.size < 2) {
249
+ throw new Error("K1 live recording requires >=2 model families, >=2 providers, and cross-size models");
250
+ }
251
+ for (const model of models) {
252
+ assertNonEmpty(model.provider, "model.provider");
253
+ assertNonEmpty(model.model, "model.model");
254
+ assertNonEmpty(model.family, "model.family");
255
+ assertFiniteUsd(model.prompt_cost_per_token_usd, "prompt_cost_per_token_usd");
256
+ assertFiniteUsd(model.completion_cost_per_token_usd, "completion_cost_per_token_usd");
257
+ assertFiniteUsd(model.request_cap_usd, "request_cap_usd");
258
+ if (!Number.isSafeInteger(model.max_output_tokens) || model.max_output_tokens <= 0) {
259
+ throw new Error("K1 live recording max_output_tokens must be a positive safe integer");
260
+ }
261
+ }
262
+ }
263
+ function buildK1LivePrompt() {
264
+ return [
265
+ "Judge this static incident-briefing responsibility against the correctness anchor.",
266
+ "Anchor verdict: up. Anchor score: 1.0.",
267
+ "Current evidence: the incident mitigation is acknowledged, no new source contradicts it, the status page remains green, and no customer-impact update has arrived since the last briefing.",
268
+ "Return JSON with keys: verdict, score, confidence, text.",
269
+ "verdict must be one of up, drifting, down, blocked.",
270
+ "score and confidence must be numbers between 0 and 1.",
271
+ "The text should be one concise sentence explaining the judgment.",
272
+ ].join("\n");
273
+ }
274
+ function planK1LiveRequestCosts(models, prompt, accounting) {
275
+ let total = 0;
276
+ const promptTokenEstimate = Math.ceil(prompt.length / 4);
277
+ for (const model of models) {
278
+ const estimatedMax = roundUsd(promptTokenEstimate * model.prompt_cost_per_token_usd +
279
+ model.max_output_tokens * model.completion_cost_per_token_usd);
280
+ if (estimatedMax > model.request_cap_usd) {
281
+ throw new Error(`K1 live recording estimated request cost for ${model.model} exceeds per-call cap`);
282
+ }
283
+ if (model.request_cap_usd > accounting.request_cap_usd) {
284
+ throw new Error(`K1 live recording per-model cap for ${model.model} exceeds live refresh request_cap_usd`);
285
+ }
286
+ total += model.request_cap_usd;
287
+ }
288
+ const totalCap = roundUsd(total);
289
+ if (totalCap > accounting.remaining_usd) {
290
+ throw new Error("K1 live recording total request cap would exceed remaining cap");
291
+ }
292
+ return { total_request_cap_usd: totalCap };
293
+ }
294
+ function readOpenRouterApiKey(envPath, readEnvFile) {
295
+ const normalizedPath = normalizeEnvPath(envPath);
296
+ const envText = readDotenvText(normalizedPath, readEnvFile);
297
+ for (const line of envText.split(/\r?\n/)) {
298
+ const match = /^(?:export\s+)?OPENROUTER_API_KEY\s*=\s*(.*)$/.exec(line.trim());
299
+ if (match?.[1] === undefined) {
300
+ continue;
301
+ }
302
+ const value = normalizeDotenvValue(match[1]);
303
+ if (value.length > 0) {
304
+ return value;
305
+ }
306
+ }
307
+ throw new Error(`live refresh requires ${exports.OPENROUTER_API_KEY_ENV_NAME_V0} in ${normalizedPath}`);
308
+ }
309
+ async function safeResponseText(response) {
310
+ try {
311
+ return (await response.text()).slice(0, 500);
312
+ }
313
+ catch {
314
+ return "";
315
+ }
316
+ }
317
+ function parseOpenRouterChatCompletion(body, model, index) {
318
+ if (!isRecord(body)) {
319
+ throw new Error(`OpenRouter response for ${model.model} was not an object`);
320
+ }
321
+ const responseId = typeof body["id"] === "string" && body["id"].length > 0
322
+ ? body["id"]
323
+ : `response-${index + 1}`;
324
+ const choices = body["choices"];
325
+ if (!Array.isArray(choices) || !isRecord(choices[0])) {
326
+ throw new Error(`OpenRouter response for ${model.model} had no choice`);
327
+ }
328
+ const choice = choices[0];
329
+ const finishReason = typeof choice["finish_reason"] === "string" && choice["finish_reason"].length > 0
330
+ ? choice["finish_reason"]
331
+ : "unknown";
332
+ const message = choice["message"];
333
+ const content = isRecord(message) && typeof message["content"] === "string"
334
+ ? message["content"]
335
+ : "";
336
+ const parsed = parseK1JudgeJson(content, model.model);
337
+ const usage = isRecord(body["usage"]) ? body["usage"] : {};
338
+ return {
339
+ response_id: responseId,
340
+ finish_reason: finishReason,
341
+ usage,
342
+ ...parsed,
343
+ };
344
+ }
345
+ function parseK1JudgeJson(content, model) {
346
+ const trimmed = content.trim();
347
+ const jsonText = trimmed.startsWith("{")
348
+ ? trimmed
349
+ : (trimmed.match(/\{[\s\S]*\}/)?.[0] ?? "");
350
+ let parsed;
351
+ try {
352
+ parsed = JSON.parse(jsonText);
353
+ }
354
+ catch {
355
+ throw new Error(`OpenRouter K1 output for ${model} was not JSON`);
356
+ }
357
+ if (!isRecord(parsed)) {
358
+ throw new Error(`OpenRouter K1 output for ${model} was not a JSON object`);
359
+ }
360
+ const verdict = parsed["verdict"];
361
+ const score = parsed["score"];
362
+ const confidence = parsed["confidence"];
363
+ const text = parsed["text"];
364
+ if (verdict !== "up" &&
365
+ verdict !== "drifting" &&
366
+ verdict !== "down" &&
367
+ verdict !== "blocked") {
368
+ throw new Error(`OpenRouter K1 output for ${model} had invalid verdict`);
369
+ }
370
+ if (!isUnitInterval(score)) {
371
+ throw new Error(`OpenRouter K1 output for ${model} had invalid score`);
372
+ }
373
+ if (!isUnitInterval(confidence)) {
374
+ throw new Error(`OpenRouter K1 output for ${model} had invalid confidence`);
375
+ }
376
+ if (typeof text !== "string" || text.trim().length === 0) {
377
+ throw new Error(`OpenRouter K1 output for ${model} had invalid text`);
378
+ }
379
+ return {
380
+ verdict,
381
+ score,
382
+ confidence,
383
+ text: text.trim(),
384
+ };
385
+ }
386
+ function usageCostUsd(usage) {
387
+ const direct = usage["cost"];
388
+ if (typeof direct === "number" && Number.isFinite(direct) && direct >= 0) {
389
+ return direct;
390
+ }
391
+ const nested = usage["cost_usd"];
392
+ if (typeof nested === "number" && Number.isFinite(nested) && nested >= 0) {
393
+ return nested;
394
+ }
395
+ return undefined;
396
+ }
397
+ function estimateUsageCostUsd(model, usage) {
398
+ const promptTokens = readTokenCount(usage, "prompt_tokens");
399
+ const completionTokens = readTokenCount(usage, "completion_tokens");
400
+ return roundLiveSpendUsd(promptTokens * model.prompt_cost_per_token_usd +
401
+ completionTokens * model.completion_cost_per_token_usd);
402
+ }
403
+ function readTokenCount(usage, key) {
404
+ const value = usage[key];
405
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0
406
+ ? value
407
+ : 0;
408
+ }
409
+ function sanitizeOutputId(value) {
410
+ return value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
411
+ }
412
+ function roundLiveSpendUsd(value) {
413
+ return Number(value.toFixed(8));
414
+ }
415
+ function isUnitInterval(value) {
416
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
417
+ }
418
+ function isRecord(value) {
419
+ return typeof value === "object" && value !== null && !Array.isArray(value);
420
+ }
421
+ function validateAccounting(accounting) {
422
+ if (accounting === undefined) {
423
+ throw new Error("live refresh requires explicit cap and accounting input");
424
+ }
425
+ if (accounting.currency !== "USD") {
426
+ throw new Error("live refresh accounting currency must be USD");
427
+ }
428
+ assertFiniteUsd(accounting.cap_usd, "cap_usd");
429
+ assertFiniteUsd(accounting.spent_usd, "spent_usd");
430
+ assertFiniteUsd(accounting.request_cap_usd, "request_cap_usd");
431
+ if (accounting.cap_usd <= 0) {
432
+ throw new Error("live refresh cap_usd must be greater than zero");
433
+ }
434
+ if (accounting.cap_usd > exports.OPENROUTER_LIVE_REFRESH_STANDING_CAP_USD_V0) {
435
+ throw new Error(`live refresh cap_usd must not exceed standing cap ${exports.OPENROUTER_LIVE_REFRESH_STANDING_CAP_USD_V0} USD`);
436
+ }
437
+ if (accounting.spent_usd < 0) {
438
+ throw new Error("live refresh spent_usd must be non-negative");
439
+ }
440
+ if (accounting.request_cap_usd <= 0) {
441
+ throw new Error("live refresh request_cap_usd must be greater than zero");
442
+ }
443
+ if (accounting.spent_usd > accounting.cap_usd) {
444
+ throw new Error("live refresh spent_usd must not exceed cap_usd");
445
+ }
446
+ const remainingUsd = roundUsd(accounting.cap_usd - accounting.spent_usd);
447
+ if (accounting.request_cap_usd > remainingUsd) {
448
+ throw new Error("live refresh request_cap_usd would exceed explicit cap");
449
+ }
450
+ return {
451
+ currency: "USD",
452
+ cap_usd: roundUsd(accounting.cap_usd),
453
+ spent_usd: roundUsd(accounting.spent_usd),
454
+ request_cap_usd: roundUsd(accounting.request_cap_usd),
455
+ remaining_usd: remainingUsd,
456
+ remaining_after_request_usd: roundUsd(remainingUsd - accounting.request_cap_usd),
457
+ account_ref: assertNonEmpty(accounting.account_ref, "account_ref"),
458
+ ledger_ref: assertNonEmpty(accounting.ledger_ref, "ledger_ref"),
459
+ standing_cap_usd: exports.OPENROUTER_LIVE_REFRESH_STANDING_CAP_USD_V0,
460
+ };
461
+ }
462
+ function validateModel(model) {
463
+ if (model === undefined) {
464
+ return exports.OPENROUTER_LIVE_REFRESH_DEFAULT_MODEL_V0;
465
+ }
466
+ if (model !== exports.OPENROUTER_LIVE_REFRESH_DEFAULT_MODEL_V0) {
467
+ throw new Error(`live refresh model must be ${exports.OPENROUTER_LIVE_REFRESH_DEFAULT_MODEL_V0}`);
468
+ }
469
+ return model;
470
+ }
471
+ function normalizeEnvPath(envPath) {
472
+ const path = envPath ?? exports.OPENPROSE_DOTENV_PATH_V0;
473
+ if (path.trim().length === 0) {
474
+ throw new Error("live refresh env_path must be non-empty");
475
+ }
476
+ return path;
477
+ }
478
+ function readDotenvText(envPath, readEnvFile) {
479
+ try {
480
+ return readEnvFile?.(envPath) ?? (0, node_fs_1.readFileSync)(envPath, "utf8");
481
+ }
482
+ catch {
483
+ throw new Error(`live refresh requires readable ${exports.OPENROUTER_API_KEY_ENV_NAME_V0} source at ${envPath}`);
484
+ }
485
+ }
486
+ function normalizeDotenvValue(rawValue) {
487
+ const value = rawValue.trim();
488
+ if (value.length < 2) {
489
+ return value;
490
+ }
491
+ const first = value[0];
492
+ const last = value[value.length - 1];
493
+ if ((first === `"` && last === `"`) || (first === `'` && last === `'`)) {
494
+ return value.slice(1, -1).trim();
495
+ }
496
+ return value;
497
+ }
498
+ function assertFiniteUsd(value, label) {
499
+ if (!Number.isFinite(value)) {
500
+ throw new Error(`live refresh ${label} must be finite`);
501
+ }
502
+ }
503
+ function assertNonEmpty(value, label) {
504
+ if (value.trim().length === 0) {
505
+ throw new Error(`live refresh ${label} must be non-empty`);
506
+ }
507
+ return value;
508
+ }
509
+ function roundUsd(value) {
510
+ return Math.round(value * 100) / 100;
511
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./synthetic-world";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/world/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./synthetic-world"), exports);
@@ -0,0 +1,104 @@
1
+ import type { ReactorConnectorAdapterV0, ReactorConnectorRequestV0, ReactorConnectorResponseV0 } from "@openprose/reactor/sdk";
2
+ export declare const SYNTHETIC_WORLD_SCHEMA_V0: "openprose.reactor.synthetic-world";
3
+ export declare const SYNTHETIC_WORLD_VERSION_V0: 0;
4
+ export type SyntheticWorldSurpriseProfileKindV0 = "static" | "periodic-surprise" | "adversarial-silent";
5
+ export type SyntheticWorldJsonValueV0 = null | boolean | number | string | readonly SyntheticWorldJsonValueV0[] | {
6
+ readonly [key: string]: SyntheticWorldJsonValueV0;
7
+ };
8
+ export interface StaticSurpriseProfileV0 {
9
+ readonly kind: "static";
10
+ }
11
+ export interface PeriodicSurpriseProfileV0 {
12
+ readonly kind: "periodic-surprise";
13
+ readonly every_events: number;
14
+ }
15
+ export interface AdversarialSilentSurpriseProfileV0 {
16
+ readonly kind: "adversarial-silent";
17
+ readonly silent_after_events: readonly number[];
18
+ }
19
+ export type SyntheticWorldSurpriseProfileV0 = StaticSurpriseProfileV0 | PeriodicSurpriseProfileV0 | AdversarialSilentSurpriseProfileV0;
20
+ export declare const STATIC_SURPRISE_PROFILE_V0: StaticSurpriseProfileV0;
21
+ export interface SyntheticWorldSourceSeedV0 {
22
+ readonly source_id: string;
23
+ readonly payload: SyntheticWorldJsonValueV0;
24
+ readonly payload_hash?: string;
25
+ readonly materialized_at?: string;
26
+ }
27
+ export interface SyntheticWorldConnectorInputV0 {
28
+ readonly initial_as_of: string;
29
+ readonly profile: SyntheticWorldSurpriseProfileV0;
30
+ readonly sources: readonly SyntheticWorldSourceSeedV0[];
31
+ }
32
+ export type SyntheticWorldProfileInputV0 = SyntheticWorldSurpriseProfileKindV0 | SyntheticWorldSurpriseProfileV0;
33
+ export interface SyntheticWorldCreateSourceInputV0 {
34
+ readonly id: string;
35
+ readonly payload: SyntheticWorldJsonValueV0;
36
+ readonly payload_hash?: string;
37
+ readonly materialized_at?: string;
38
+ }
39
+ export interface SyntheticWorldCreateInputV0 {
40
+ readonly initial_instant: string;
41
+ readonly profile: SyntheticWorldProfileInputV0;
42
+ readonly sources: readonly SyntheticWorldCreateSourceInputV0[];
43
+ }
44
+ export type SyntheticWorldAdvanceInputV0 = SyntheticWorldTimeAdvanceInputV0 | SyntheticWorldSourceEventInputV0;
45
+ export interface SyntheticWorldTimeAdvanceInputV0 {
46
+ readonly kind: "time";
47
+ readonly as_of: string;
48
+ readonly event_id?: string;
49
+ }
50
+ export interface SyntheticWorldSourceEventInputV0 {
51
+ readonly kind: "source-event";
52
+ readonly as_of: string;
53
+ readonly source_id: string;
54
+ readonly event_id?: string;
55
+ readonly payload?: SyntheticWorldJsonValueV0;
56
+ }
57
+ export type SyntheticWorldAdvanceKindV0 = SyntheticWorldAdvanceInputV0["kind"];
58
+ export interface SyntheticWorldSurpriseEventV0 {
59
+ readonly kind: "material-change" | "missing-event";
60
+ readonly source_id: string;
61
+ readonly as_of: string;
62
+ readonly event_id: string;
63
+ readonly profile: SyntheticWorldSurpriseProfileKindV0;
64
+ }
65
+ export interface SyntheticWorldSurpriseReportV0 {
66
+ readonly profile: SyntheticWorldSurpriseProfileKindV0;
67
+ readonly as_of: string;
68
+ readonly event_index: number;
69
+ readonly surprise_count: number;
70
+ readonly material_change: boolean;
71
+ readonly surprise_events: readonly SyntheticWorldSurpriseEventV0[];
72
+ }
73
+ export interface SyntheticWorldAdvanceRecordV0 {
74
+ readonly kind: SyntheticWorldAdvanceKindV0;
75
+ readonly event_id: string;
76
+ readonly event_index: number;
77
+ readonly as_of: string;
78
+ readonly source_id?: string;
79
+ readonly surprise: SyntheticWorldSurpriseReportV0;
80
+ }
81
+ export interface SyntheticWorldReadPayloadV0 {
82
+ readonly schema: typeof SYNTHETIC_WORLD_SCHEMA_V0;
83
+ readonly v: typeof SYNTHETIC_WORLD_VERSION_V0;
84
+ readonly profile: SyntheticWorldSurpriseProfileKindV0;
85
+ readonly source_id: string;
86
+ readonly as_of: string;
87
+ readonly materialized_at: string;
88
+ readonly material_version: number;
89
+ readonly payload_hash?: string;
90
+ readonly state: SyntheticWorldJsonValueV0;
91
+ readonly surprise: SyntheticWorldSurpriseReportV0;
92
+ }
93
+ export declare class SyntheticWorldConnectorV0 implements ReactorConnectorAdapterV0 {
94
+ #private;
95
+ constructor(input: SyntheticWorldConnectorInputV0);
96
+ read(request: ReactorConnectorRequestV0): ReactorConnectorResponseV0;
97
+ advance(input: SyntheticWorldAdvanceInputV0): SyntheticWorldAdvanceRecordV0;
98
+ currentAsOf(): string;
99
+ history(): readonly SyntheticWorldAdvanceRecordV0[];
100
+ }
101
+ export declare function createSyntheticWorldV0(input: SyntheticWorldCreateInputV0): SyntheticWorldConnectorV0;
102
+ export declare function createSyntheticWorldConnectorV0(input: SyntheticWorldConnectorInputV0): SyntheticWorldConnectorV0;
103
+ export declare function createSyntheticWorldConnectorV0(world: SyntheticWorldConnectorV0): SyntheticWorldConnectorV0;
104
+ //# sourceMappingURL=synthetic-world.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthetic-world.d.ts","sourceRoot":"","sources":["../../src/world/synthetic-world.ts"],"names":[],"mappings":"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"}