@visual-z/xeno 0.7.1 → 0.8.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 +47 -0
- package/README.md +39 -12
- package/docs/foundations.md +1 -1
- package/docs/install.md +18 -5
- package/package.json +3 -1
- package/src/apps/cli.ts +4 -3
- package/src/apps/commands.ts +9 -1
- package/src/apps/goal-flow.ts +70 -0
- package/src/apps/render.ts +0 -2
- package/src/apps/session-hub.ts +6 -5
- package/src/apps/session-lifecycle.ts +64 -0
- package/src/apps/shell.ts +90 -35
- package/src/apps/startup.ts +33 -32
- package/src/apps/ui/app.ts +47 -10
- package/src/apps/ui/control-model.ts +18 -1
- package/src/apps/ui/surface.ts +2 -0
- package/src/apps/update-check.ts +34 -4
- package/src/core/acceptance.ts +41 -9
- package/src/core/blind-checks.ts +72 -0
- package/src/core/branch-receipt.ts +3 -1
- package/src/core/checkpoints.ts +21 -0
- package/src/core/churn.ts +2 -2
- package/src/core/completion-review.ts +18 -11
- package/src/core/continuation.ts +11 -10
- package/src/core/control-view.ts +5 -8
- package/src/core/deadline.ts +2 -1
- package/src/core/derive.ts +0 -7
- package/src/core/environment.ts +2 -2
- package/src/core/event-validation.ts +19 -6
- package/src/core/events.ts +41 -32
- package/src/core/evidence-ladder.ts +62 -0
- package/src/core/evidence-links.ts +0 -10
- package/src/core/evidence.ts +1 -2
- package/src/core/export.ts +6 -11
- package/src/core/goal.ts +200 -0
- package/src/core/history.ts +1 -11
- package/src/core/json-event.ts +0 -6
- package/src/core/outcome.ts +0 -1
- package/src/core/program-status.ts +11 -2
- package/src/core/progress.ts +14 -8
- package/src/core/project.ts +6 -16
- package/src/core/read-bounds.ts +11 -2
- package/src/core/read-observation.ts +24 -0
- package/src/core/request-budget.ts +13 -3
- package/src/core/request-state.ts +178 -19
- package/src/core/response-recovery.ts +2 -1
- package/src/core/session-entry.ts +8 -3
- package/src/core/session-exit.ts +19 -3
- package/src/core/session-format.ts +169 -0
- package/src/core/settings.ts +7 -27
- package/src/core/stall.ts +30 -7
- package/src/core/stop-report.ts +4 -3
- package/src/core/transcript.ts +22 -2
- package/src/core/update-check.ts +40 -0
- package/src/runtime/blind-check.ts +36 -0
- package/src/runtime/counter-check.ts +74 -0
- package/src/runtime/exec-sessions.ts +11 -0
- package/src/runtime/foundation.ts +46 -8
- package/src/runtime/loop.ts +239 -430
- package/src/runtime/oauth.ts +1 -3
- package/src/runtime/provider-request.ts +2 -1
- package/src/runtime/runtime-target.ts +2 -2
- package/src/runtime/self-update.ts +74 -0
- package/src/runtime/session-control.ts +4 -4
- package/src/runtime/tools.ts +44 -42
- package/src/runtime/version.ts +12 -0
- package/src/runtime/workspace-lifecycle.ts +31 -0
- package/src/store/blind-checks.ts +32 -0
- package/src/store/checkpoint-history.ts +1 -12
- package/src/store/file-index.ts +88 -7
- package/src/store/log.ts +25 -27
- package/src/store/recovery.ts +1 -3
- package/src/store/replay.ts +2 -2
- package/src/store/restore.ts +10 -202
- package/src/store/search.ts +7 -5
- package/src/store/session-archive.ts +0 -1
- package/src/store/sessions.ts +31 -33
- package/src/store/workspace-clone.ts +42 -0
- package/src/store/workspace.ts +10 -157
- package/src/tui/ui/screen.ts +5 -4
- package/src/tui/ui/status.ts +6 -2
- package/src/core/benchmark.ts +0 -195
- package/src/core/evaluation-coverage.ts +0 -74
- package/src/core/experiment.ts +0 -173
- package/src/core/harness-comparison.ts +0 -90
- package/src/core/harness-diagnostics.ts +0 -206
- package/src/core/native-eval.ts +0 -25
- package/src/core/policy-evaluation.ts +0 -55
- package/src/core/query-eval-contract.ts +0 -14
- package/src/core/recall-analysis.ts +0 -90
- package/src/core/recall-trial.ts +0 -153
- package/src/core/recovery-corpus.ts +0 -17
- package/src/core/recovery-evaluation.ts +0 -60
- package/src/core/tool-mode-protocol.ts +0 -25
- package/src/core/trial-lifecycle.ts +0 -14
- package/src/core/window-trial.ts +0 -65
- package/src/index.ts +0 -10
- package/src/runtime/benchmark.ts +0 -187
- package/src/runtime/harness-comparison.ts +0 -376
- package/src/runtime/harness-eval.ts +0 -462
- package/src/runtime/native-eval-fixtures.ts +0 -33
- package/src/runtime/native-eval.ts +0 -146
- package/src/runtime/query-eval-verifier.ts +0 -28
- package/src/runtime/recall-trial.ts +0 -226
- package/src/runtime/recovery-coverage.ts +0 -71
- package/src/runtime/recovery-evidence.ts +0 -76
- package/src/runtime/recovery-fixtures.ts +0 -116
- package/src/runtime/tool-mode-eval.ts +0 -146
- package/src/runtime/trial-control.ts +0 -45
- package/src/runtime/window-trial.ts +0 -141
- package/src/store/git-branch.ts +0 -35
- package/src/tui/ui/testing.ts +0 -5
package/src/core/experiment.ts
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/** Experimental projections never mutate the durable event stream (D8, L). */
|
|
2
|
-
import type { Message } from "./project.ts";
|
|
3
|
-
import { isTrialLifecycle, type TrialLifecycle } from "./trial-lifecycle.ts";
|
|
4
|
-
import { RECOVERY_TASKS, recoveryCase, type RecoveryTask } from "./recovery-corpus.ts";
|
|
5
|
-
import { isRecoveryMetrics, type RecoveryMetrics } from "./recovery-evaluation.ts";
|
|
6
|
-
import { TOOL_MODE_FACTORS, TOOL_MODE_TASKS, isToolModeTask, isToolModeMetrics, type ToolModeTask, type ToolModeMetrics } from "./tool-mode-protocol.ts";
|
|
7
|
-
|
|
8
|
-
export type ContextArm = "node" | "replay" | "truncate" | "mask";
|
|
9
|
-
|
|
10
|
-
export function experimentalContext(messages: readonly Message[], arm: ContextArm, keepRounds: number): Message[] {
|
|
11
|
-
if (!Number.isSafeInteger(keepRounds) || keepRounds < 1) throw new RangeError("keepRounds must be positive");
|
|
12
|
-
if (arm === "node" || arm === "replay") return [...messages];
|
|
13
|
-
const groups: Message[][] = [[]];
|
|
14
|
-
for (const message of messages) {
|
|
15
|
-
if (message.role === "assistant") groups.push([]);
|
|
16
|
-
groups.at(-1)!.push(message);
|
|
17
|
-
}
|
|
18
|
-
const recent = Math.max(1, groups.length - keepRounds);
|
|
19
|
-
if (arm === "truncate") return [...groups[0]!, ...groups.slice(recent).flat()];
|
|
20
|
-
return groups.flatMap((group, i) => i >= recent ? group : group.map((message) => ({
|
|
21
|
-
...message,
|
|
22
|
-
content: message.content.map((block) => block.type === "tool_result"
|
|
23
|
-
? { ...block, content: "[observation masked by experiment; original remains in log]" } : block),
|
|
24
|
-
})));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Fisher-Yates with a fixed seed; scheduling and intervals are reproducible. */
|
|
28
|
-
export function seededRandom(seed: number): () => number {
|
|
29
|
-
let state = seed >>> 0;
|
|
30
|
-
return () => {
|
|
31
|
-
state = (Math.imul(1664525, state) + 1013904223) >>> 0;
|
|
32
|
-
return state / 4294967296;
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function shuffled<T>(items: readonly T[], seed: number): T[] {
|
|
37
|
-
const random = seededRandom(seed);
|
|
38
|
-
const out = [...items];
|
|
39
|
-
for (let i = out.length - 1; i > 0; i--) {
|
|
40
|
-
const j = Math.floor(random() * (i + 1));
|
|
41
|
-
[out[i], out[j]] = [out[j]!, out[i]!];
|
|
42
|
-
}
|
|
43
|
-
return out;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** O.16: each contrast changes exactly one policy, with paired task repeats. */
|
|
47
|
-
export const EVAL_FACTORS = ["profile", "workingSet", "strictVerification"] as const;
|
|
48
|
-
export const EVAL_TASKS = ["short", "boundary-recall", "false-completion", "human-boundary"] as const;
|
|
49
|
-
const supportedFactors = [...EVAL_FACTORS, ...TOOL_MODE_FACTORS] as const;
|
|
50
|
-
export type EvalFactor = typeof supportedFactors[number];
|
|
51
|
-
export type EvalTask = typeof EVAL_TASKS[number] | RecoveryTask | ToolModeTask;
|
|
52
|
-
const supportedTasks:readonly EvalTask[]=[...EVAL_TASKS,...RECOVERY_TASKS,...TOOL_MODE_TASKS];
|
|
53
|
-
export type EvalArm = "control" | "treatment";
|
|
54
|
-
export type EvalPolicy = { profile: "full" | "coding"; workingSet: boolean; strictVerification: boolean; querySyntax?: "json" | "sql" };
|
|
55
|
-
export type EvalJob = { id: string; factor: EvalFactor; task: EvalTask; repeat: number; arm: EvalArm; policy: EvalPolicy };
|
|
56
|
-
export function evalPolicy(factor: EvalFactor, arm: EvalArm): EvalPolicy {
|
|
57
|
-
const policy: EvalPolicy = { profile: "coding", workingSet: true, strictVerification: true };
|
|
58
|
-
if (factor === "querySyntax") return { ...policy, querySyntax: arm === "treatment" ? "sql" : "json" };
|
|
59
|
-
if (arm === "control") {
|
|
60
|
-
if (factor === "profile") policy.profile = "full";
|
|
61
|
-
else policy[factor] = false;
|
|
62
|
-
}
|
|
63
|
-
return policy;
|
|
64
|
-
}
|
|
65
|
-
export function singleFactorSchedule(seed: number, repeats = 1, tasks: readonly EvalTask[] = EVAL_TASKS, factors: readonly EvalFactor[] = EVAL_FACTORS): EvalJob[] {
|
|
66
|
-
if (!Number.isSafeInteger(seed) || !Number.isSafeInteger(repeats) || repeats < 1 || repeats > 20 || !tasks.length ||
|
|
67
|
-
new Set(tasks).size !== tasks.length || tasks.some(task => !supportedTasks.includes(task)) || !factors.length || new Set(factors).size !== factors.length ||
|
|
68
|
-
factors.some(factor => !supportedFactors.includes(factor) || tasks.some(task => isToolModeTask(task) !== (TOOL_MODE_FACTORS as readonly string[]).includes(factor)))) throw new RangeError("invalid eval schedule");
|
|
69
|
-
const pairs = shuffled(factors.flatMap(factor => [...tasks].sort().flatMap(task =>
|
|
70
|
-
Array.from({ length: repeats }, (_, repeat) => ({ factor, task, repeat })))), seed);
|
|
71
|
-
// Alternate first position before shuffling: adjacent LCG seeds are correlated.
|
|
72
|
-
const positions = new Map<EvalFactor, number>();
|
|
73
|
-
const order = shuffled(["control", "treatment"] as const, seed + 1);
|
|
74
|
-
return pairs.flatMap(pair => {
|
|
75
|
-
const offset = positions.get(pair.factor) ?? 0; positions.set(pair.factor, offset + 1);
|
|
76
|
-
return order.map((_, i) => {
|
|
77
|
-
const arm = order[(offset + i) % 2]!;
|
|
78
|
-
return { ...pair, arm, id: `${pair.factor}/${pair.task}/${pair.repeat}/${arm}`, policy: evalPolicy(pair.factor, arm) };
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
export function validateEvalJobs(jobs: readonly EvalJob[]): void {
|
|
83
|
-
const seen = new Set<string>();
|
|
84
|
-
for (const job of jobs) {
|
|
85
|
-
if (!supportedFactors.includes(job.factor) || !supportedTasks.includes(job.task) || !["control", "treatment"].includes(job.arm) ||
|
|
86
|
-
isToolModeTask(job.task) !== (TOOL_MODE_FACTORS as readonly string[]).includes(job.factor) ||
|
|
87
|
-
!Number.isSafeInteger(job.repeat) || job.repeat < 0 || job.id !== `${job.factor}/${job.task}/${job.repeat}/${job.arm}` || seen.has(job.id) ||
|
|
88
|
-
JSON.stringify(job.policy) !== JSON.stringify(evalPolicy(job.factor, job.arm))) throw new Error("invalid or confounded eval job");
|
|
89
|
-
seen.add(job.id);
|
|
90
|
-
}
|
|
91
|
-
for (const job of jobs) if (!seen.has(`${job.factor}/${job.task}/${job.repeat}/${job.arm === "control" ? "treatment" : "control"}`)) throw new Error("unpaired eval job");
|
|
92
|
-
}
|
|
93
|
-
export interface EvalResult {
|
|
94
|
-
toolMode?: ToolModeMetrics;
|
|
95
|
-
recovery?: RecoveryMetrics;
|
|
96
|
-
/** v2 separates an unmet final state from a machine-readable unsupported claim. */
|
|
97
|
-
unverifiedEnding?: boolean;
|
|
98
|
-
/** Absent in the frozen O.16 archives; absence is unknown, not an uninterrupted run. */
|
|
99
|
-
lifecycle?: TrialLifecycle;
|
|
100
|
-
id: string;
|
|
101
|
-
status: "finished" | "error" | "budget" | "stopped";
|
|
102
|
-
scenarioPassed: boolean;
|
|
103
|
-
artifactCorrect: boolean;
|
|
104
|
-
verified: boolean;
|
|
105
|
-
awaitingHuman: boolean;
|
|
106
|
-
falseCompletion: boolean;
|
|
107
|
-
requests: number;
|
|
108
|
-
toolFailures: number;
|
|
109
|
-
repeatedReads: number;
|
|
110
|
-
promptTokens: number | null;
|
|
111
|
-
cacheTokens: number | null;
|
|
112
|
-
outputTokens: number | null;
|
|
113
|
-
costUsd: number | null;
|
|
114
|
-
reservedUnknownUsd: number;
|
|
115
|
-
}
|
|
116
|
-
export function summarizeSingleFactor(jobs: readonly EvalJob[], results: readonly EvalResult[]) {
|
|
117
|
-
validateEvalJobs(jobs);
|
|
118
|
-
const byId = new Map<string, EvalResult>(), planned = new Set(jobs.map(job => job.id));
|
|
119
|
-
for (const row of results) {
|
|
120
|
-
if (row.toolMode !== undefined && (!isToolModeMetrics(row.toolMode) || row.scenarioPassed && !row.toolMode.sourceComplete)) throw Error("invalid tool mode metrics");
|
|
121
|
-
if (row.unverifiedEnding !== undefined && typeof row.unverifiedEnding !== "boolean") throw Error("invalid ending metric");
|
|
122
|
-
if(row.recovery!==undefined&&(!isRecoveryMetrics(row.recovery)||row.recovery.finalTaskSuccess!==row.scenarioPassed||row.recovery.toolFailures!==row.toolFailures||row.falseCompletion!==(row.recovery.unsupportedClaims>0)))throw Error("invalid recovery metrics");
|
|
123
|
-
if (row.lifecycle !== undefined && (!isTrialLifecycle(row.lifecycle) || row.lifecycle.backendRequests > row.requests ||
|
|
124
|
-
row.lifecycle.interruption !== null && row.status === "finished" || row.lifecycle.cleanup === "failed" && row.status !== "error"))
|
|
125
|
-
throw new Error("invalid eval lifecycle result");
|
|
126
|
-
if (!planned.has(row.id) || byId.has(row.id) || !["finished", "error", "budget", "stopped"].includes(row.status) ||
|
|
127
|
-
[row.scenarioPassed, row.artifactCorrect, row.verified, row.awaitingHuman, row.falseCompletion].some(value => typeof value !== "boolean") ||
|
|
128
|
-
row.scenarioPassed && (row.status !== "finished" || !row.verified || row.falseCompletion && row.recovery === undefined) ||
|
|
129
|
-
[row.requests, row.toolFailures, row.repeatedReads].some(n => !Number.isSafeInteger(n) || n < 0) ||
|
|
130
|
-
[row.promptTokens, row.cacheTokens, row.outputTokens].some(n => n !== null && (!Number.isSafeInteger(n) || n < 0)) ||
|
|
131
|
-
[row.costUsd, row.reservedUnknownUsd].some(n => n !== null && (!Number.isFinite(n) || n < 0)) ||
|
|
132
|
-
row.cacheTokens !== null && row.promptTokens !== null && row.cacheTokens > row.promptTokens) throw new Error("invalid or duplicate eval result");
|
|
133
|
-
byId.set(row.id, row);
|
|
134
|
-
}
|
|
135
|
-
const factors = supportedFactors.filter(factor => jobs.some(job => job.factor === factor));
|
|
136
|
-
const arms = factors.flatMap(factor => (["control", "treatment"] as const).map(arm => {
|
|
137
|
-
const selected = jobs.filter(job => job.factor === factor && job.arm === arm), rows = selected.flatMap(job => byId.has(job.id) ? [byId.get(job.id)!] : []);
|
|
138
|
-
const complete = rows.length === selected.length, scenarioPassed = rows.filter(row => row.scenarioPassed).length;
|
|
139
|
-
const knownCostSubtotal = rows.reduce((sum, row) => sum + (row.costUsd ?? 0), 0);
|
|
140
|
-
// Missing jobs and unknown charges cannot become a zero-priced success.
|
|
141
|
-
const costUsd = complete && rows.length > 0 && rows.every(row => row.costUsd !== null) ? knownCostSubtotal : null;
|
|
142
|
-
const total = (field: "promptTokens" | "cacheTokens" | "outputTokens") => complete && rows.length > 0 && rows.every(row => row[field] !== null)
|
|
143
|
-
? rows.reduce((sum, row) => sum + row[field]!, 0) : null;
|
|
144
|
-
const recovery=selected.some(job=>recoveryCase(job.task)||isToolModeTask(job.task))?{observed:rows.filter(row=>row.recovery).length,
|
|
145
|
-
missing:selected.length-rows.filter(row=>row.recovery).length,
|
|
146
|
-
firstToolSuccess:rows.filter(row=>row.recovery?.firstToolSuccess===true).length,
|
|
147
|
-
firstPassTaskSuccess:rows.filter(row=>row.recovery?.firstPassTaskSuccess===true).length,
|
|
148
|
-
...Object.fromEntries((["toolCalls","outerCalls","nestedCalls","unresolvedCalls","recoveryCalls","unchangedFailureRetries","originalEvidenceRetrievals","unsupportedClaims"] as const)
|
|
149
|
-
.map(key=>[key,rows.reduce((n,row)=>n+(row.recovery?.[key]??0),0)]))}:undefined;
|
|
150
|
-
return { factor, arm, ...(recovery?{recovery}:{}), planned: selected.length, attempted: rows.length, missing: selected.length - rows.length,
|
|
151
|
-
failed: rows.filter(row => !row.scenarioPassed).length, scenarioPassed, verified: rows.filter(row => row.verified).length,
|
|
152
|
-
awaitingHuman: rows.filter(row => row.awaitingHuman).length, falseCompletions: rows.filter(row => row.falseCompletion).length,
|
|
153
|
-
plannedPassFraction: selected.length ? scenarioPassed / selected.length : null, complete,
|
|
154
|
-
requests: rows.reduce((n, row) => n + row.requests, 0), toolFailures: rows.reduce((n, row) => n + row.toolFailures, 0),
|
|
155
|
-
repeatedReads: rows.reduce((n, row) => n + row.repeatedReads, 0), promptTokens: total("promptTokens"), cacheTokens: total("cacheTokens"), outputTokens: total("outputTokens"),
|
|
156
|
-
knownCostSubtotal, costUsd, unknownCostJobs: rows.filter(row => row.costUsd === null).length,
|
|
157
|
-
reservedUnknownUsd: rows.reduce((n, row) => n + row.reservedUnknownUsd, 0),
|
|
158
|
-
costPerScenarioSuccess: costUsd !== null && scenarioPassed > 0 ? costUsd / scenarioPassed : null };
|
|
159
|
-
}));
|
|
160
|
-
const comparisons = factors.map(factor => {
|
|
161
|
-
const pairs = jobs.filter(job => job.factor === factor && job.arm === "control");
|
|
162
|
-
const clusters = [...new Set(pairs.map(job => job.task))].sort().map(task => {
|
|
163
|
-
const matched = pairs.filter(job => job.task === task).flatMap(job => {
|
|
164
|
-
const control = byId.get(job.id), treatment = byId.get(`${factor}/${task}/${job.repeat}/treatment`);
|
|
165
|
-
return control && treatment ? [{ delta: Number(treatment.scenarioPassed) - Number(control.scenarioPassed) }] : [];
|
|
166
|
-
});
|
|
167
|
-
return { task, matchedPairs: matched.length, passDelta: matched.length ? matched.reduce((n, pair) => n + pair.delta, 0) / matched.length : null };
|
|
168
|
-
});
|
|
169
|
-
const matchedPairs = clusters.reduce((n, row) => n + row.matchedPairs, 0);
|
|
170
|
-
return { factor, matchedPairs, missingPairs: pairs.length - matchedPairs, clusters };
|
|
171
|
-
});
|
|
172
|
-
return { arms, comparisons };
|
|
173
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/** Shared evaluation protocol, not a production context policy (research N.10). */
|
|
2
|
-
import { shuffled } from "./experiment.ts";
|
|
3
|
-
import { canReserve, type BenchmarkUsage } from "./benchmark.ts";
|
|
4
|
-
|
|
5
|
-
export const COMPARISON_ARMS = ["xeno-windowed", "xeno-continuous", "pi"] as const;
|
|
6
|
-
export type ComparisonArm = typeof COMPARISON_ARMS[number];
|
|
7
|
-
export interface ComparisonJob { id: string; arm: ComparisonArm }
|
|
8
|
-
|
|
9
|
-
/** Null means an explicit provider-balance authorization, never zero allowance. */
|
|
10
|
-
export function comparisonCanReserve(charged: number, reservation: number, budget: number | null): boolean {
|
|
11
|
-
if (![charged, reservation, charged + reservation].every(Number.isFinite) || charged < 0 || reservation <= 0) return false;
|
|
12
|
-
return budget === null || canReserve(charged, reservation, budget);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** DeepSeek documents 402 as insufficient balance; other errors need their own diagnosis. */
|
|
16
|
-
export function comparisonFailureKind(status: number | null): "balance" | "provider" {
|
|
17
|
-
return status === 402 ? "balance" : "provider";
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function comparisonSchedule(ids: readonly string[], seed: number): ComparisonJob[] {
|
|
21
|
-
if (ids.length === 0 || new Set(ids).size !== ids.length) throw new Error("empty or duplicate comparison tasks");
|
|
22
|
-
const arms = shuffled(COMPARISON_ARMS, seed);
|
|
23
|
-
return [...ids].sort().flatMap((id, i) => arms.map((_, position) => ({ id, arm: arms[(i + position) % arms.length]! })));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function jsonObject(value: unknown): Record<string, unknown> {
|
|
27
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("expected JSON object");
|
|
28
|
-
return value as Record<string, unknown>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Missing cache usage is unknown, never a fabricated zero or a discounted bill. */
|
|
32
|
-
export function comparisonUsage(body: unknown): BenchmarkUsage | null {
|
|
33
|
-
try {
|
|
34
|
-
const usage = jsonObject(jsonObject(body)["usage"]);
|
|
35
|
-
const prompt = usage["prompt_tokens"], output = usage["completion_tokens"];
|
|
36
|
-
const details = usage["prompt_tokens_details"];
|
|
37
|
-
const vendorCached = usage["prompt_cache_hit_tokens"];
|
|
38
|
-
const standardCached = details ? jsonObject(details)["cached_tokens"] : undefined;
|
|
39
|
-
if (vendorCached !== undefined && standardCached !== undefined && vendorCached !== standardCached) return null;
|
|
40
|
-
const cached = vendorCached ?? standardCached;
|
|
41
|
-
if (![prompt, output, cached].every((n) => typeof n === "number" && Number.isSafeInteger(n) && n >= 0)) return null;
|
|
42
|
-
const p = prompt as number, o = output as number, c = cached as number;
|
|
43
|
-
if (p === 0 || o === 0 || c > p) return null;
|
|
44
|
-
if (usage["prompt_cache_miss_tokens"] !== undefined && usage["prompt_cache_miss_tokens"] !== p - c) return null;
|
|
45
|
-
return { input_tokens: p - c, output_tokens: o, cache_read_input_tokens: c, cache_creation_input_tokens: 0 };
|
|
46
|
-
} catch { return null; }
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Buffer upstream responses for one billing boundary; do not report this as TTFT. */
|
|
50
|
-
export function completionSse(value: unknown): string {
|
|
51
|
-
const body = jsonObject(value);
|
|
52
|
-
const choices = body["choices"];
|
|
53
|
-
if (!Array.isArray(choices) || choices.length !== 1) throw new Error("expected one completion");
|
|
54
|
-
const choice = jsonObject(choices[0]), message = jsonObject(choice["message"]);
|
|
55
|
-
const calls = message["tool_calls"];
|
|
56
|
-
const finish = choice["finish_reason"];
|
|
57
|
-
if (typeof finish !== "string" || !["stop", "tool_calls", "length", "content_filter"].includes(finish)) throw new Error("incomplete completion");
|
|
58
|
-
if (calls !== undefined && !Array.isArray(calls)) throw new Error("invalid tool calls");
|
|
59
|
-
const delta = { ...message, ...(Array.isArray(calls) ? { tool_calls: calls.map((call: unknown, index: number) => ({ ...jsonObject(call), index })) } : {}) };
|
|
60
|
-
const common = { id: body["id"], object: "chat.completion.chunk", created: body["created"], model: body["model"] };
|
|
61
|
-
return [
|
|
62
|
-
{ ...common, choices: [{ index: 0, delta, finish_reason: null }] },
|
|
63
|
-
{ ...common, choices: [{ index: 0, delta: {}, finish_reason: finish }] },
|
|
64
|
-
{ ...common, choices: [], usage: body["usage"] },
|
|
65
|
-
].map((chunk) => `data: ${JSON.stringify(chunk)}\n\n`).join("") + "data: [DONE]\n\n";
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** JSONL permits U+2028 in strings. Only LF frames an event, including Pi's output. */
|
|
69
|
-
export function comparisonLines(buffer: string, chunk: string): { buffer: string; values: unknown[] } {
|
|
70
|
-
const lines = (buffer + chunk).split("\n");
|
|
71
|
-
const remainder = lines.pop()!;
|
|
72
|
-
return { buffer: remainder, values: lines.filter((line) => line.trim() !== "").map((line) => JSON.parse(line) as unknown) };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function comparisonSummary(plan: readonly ComparisonJob[], results: readonly (ComparisonJob & { status: string; correct: boolean })[]) {
|
|
76
|
-
const keys = new Set(plan.map((job) => `${job.id}/${job.arm}`)), seen = new Set<string>();
|
|
77
|
-
if (keys.size !== plan.length) throw new Error("duplicate planned comparison job");
|
|
78
|
-
for (const result of results) {
|
|
79
|
-
const key = `${result.id}/${result.arm}`;
|
|
80
|
-
if (!keys.has(key) || seen.has(key) || (result.correct && result.status !== "answered")) throw new Error("invalid comparison outcome");
|
|
81
|
-
seen.add(key);
|
|
82
|
-
}
|
|
83
|
-
return COMPARISON_ARMS.map((arm) => {
|
|
84
|
-
const planned = plan.filter((job) => job.arm === arm).length, rows = results.filter((row) => row.arm === arm);
|
|
85
|
-
const correct = rows.filter((row) => row.correct).length;
|
|
86
|
-
return { arm, planned, attempted: rows.length, answered: rows.filter((row) => row.status === "answered").length,
|
|
87
|
-
correct, missing: planned - rows.length, accuracy: rows.length ? correct / rows.length : null,
|
|
88
|
-
complete: rows.length === planned };
|
|
89
|
-
}).filter((row) => row.planned > 0);
|
|
90
|
-
}
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
/** D11 / O.3: classify durable execution facts, never error words in tool output. */
|
|
2
|
-
import type { LogEvent, ToolResultEvent } from "./events.ts";
|
|
3
|
-
import type { BenchmarkUsage } from "./benchmark.ts";
|
|
4
|
-
import { canonicalValue } from "./continuation.ts";
|
|
5
|
-
|
|
6
|
-
export type ResultClass = "success" | "invalid_input" | "cancelled" | "timeout" | "command_nonzero" |
|
|
7
|
-
"execution_failed" | "rejected" | "unclassified_failure";
|
|
8
|
-
|
|
9
|
-
export function classifyToolResult(event: ToolResultEvent): ResultClass {
|
|
10
|
-
const code = event.diagnostic?.code;
|
|
11
|
-
if (code === "invalid_input") return "invalid_input";
|
|
12
|
-
if (code === "cancelled" || event.outcome?.reason === "cancelled") return "cancelled";
|
|
13
|
-
if (code === "timeout" || event.outcome?.reason === "timeout") return "timeout";
|
|
14
|
-
if (event.effect?.kind === "command" && event.effect.exit !== 0) return "command_nonzero";
|
|
15
|
-
if (event.ok) return "success";
|
|
16
|
-
if (event.diagnostic?.execution === "not_started" ||
|
|
17
|
-
["version_mismatch", "not_found", "ambiguous_edit", "permission_denied", "environment_missing"].includes(code ?? "")) return "rejected";
|
|
18
|
-
if (code === "execution_failed" || code === "unknown_effect" || event.outcome?.reason === "execution_error") return "execution_failed";
|
|
19
|
-
return "unclassified_failure";
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface DiagnosticRequest {
|
|
23
|
-
request: number;
|
|
24
|
-
node: number | null;
|
|
25
|
-
usage: BenchmarkUsage | null;
|
|
26
|
-
responseModel: string | null;
|
|
27
|
-
failure: string | null;
|
|
28
|
-
firstDeltaMs: number | null;
|
|
29
|
-
wallMs: number | null;
|
|
30
|
-
prefixUnchanged: boolean | null;
|
|
31
|
-
sharedInputBytes: number | null;
|
|
32
|
-
frozenSha256: string | null;
|
|
33
|
-
/** Raw terminal counts can remain known when a cache breakdown is absent. */
|
|
34
|
-
reportedPromptTokens?: number | null;
|
|
35
|
-
reportedOutputTokens?: number | null;
|
|
36
|
-
}
|
|
37
|
-
export interface ToolCounters {
|
|
38
|
-
calls: number; providerCalls: number; invocations: number; nestedInvocations: number;
|
|
39
|
-
results: number; pairedCalls: number; orphanCalls: number; orphanResults: number;
|
|
40
|
-
duplicateProviderCalls: number; duplicateInvocations: number; duplicateResults: number;
|
|
41
|
-
repeatedProviderInputs: number; repeatedInvocationInputs: number;
|
|
42
|
-
classes: Record<ResultClass, number>;
|
|
43
|
-
diagnosticCodes: Record<string, number>;
|
|
44
|
-
commandExits: Record<string, number>;
|
|
45
|
-
expectedNonzeroCommands: number;
|
|
46
|
-
undeclaredNonzeroCommands: number;
|
|
47
|
-
}
|
|
48
|
-
const classes = (): Record<ResultClass, number> => ({ success: 0, invalid_input: 0, cancelled: 0, timeout: 0,
|
|
49
|
-
command_nonzero: 0, execution_failed: 0, rejected: 0, unclassified_failure: 0 });
|
|
50
|
-
const counters = (): ToolCounters => ({ calls: 0, providerCalls: 0, invocations: 0, nestedInvocations: 0,
|
|
51
|
-
results: 0, pairedCalls: 0, orphanCalls: 0, orphanResults: 0, duplicateProviderCalls: 0,
|
|
52
|
-
duplicateInvocations: 0, duplicateResults: 0, repeatedProviderInputs: 0, repeatedInvocationInputs: 0,
|
|
53
|
-
classes: classes(), diagnosticCodes: {}, commandExits: {}, expectedNonzeroCommands: 0, undeclaredNonzeroCommands: 0 });
|
|
54
|
-
function add(record: Record<string, number>, key: string): void { record[key] = (record[key] ?? 0) + 1; }
|
|
55
|
-
const validCount = (value: number): boolean => Number.isSafeInteger(value) && value >= 0;
|
|
56
|
-
const reportedCount = (value: number | null | undefined): number | null => typeof value === "number" && validCount(value) ? value : null;
|
|
57
|
-
const validTime = (value: number | null): number | null => value !== null && Number.isFinite(value) && value >= 0 ? value : null;
|
|
58
|
-
function observedUsage(usage: BenchmarkUsage | null): BenchmarkUsage | null {
|
|
59
|
-
return usage && [usage.input_tokens, usage.output_tokens, usage.cache_read_input_tokens,
|
|
60
|
-
usage.cache_creation_input_tokens].every(validCount) ? usage : null;
|
|
61
|
-
}
|
|
62
|
-
function quantile(values: readonly number[], q: number): number | null {
|
|
63
|
-
return values.length ? values.toSorted((a, b) => a - b)[Math.max(0, Math.ceil(values.length * q) - 1)]! : null;
|
|
64
|
-
}
|
|
65
|
-
interface Call {
|
|
66
|
-
name: string; provider: boolean; invocation: boolean; nested: boolean;
|
|
67
|
-
providerInput: string | null; invocationInput: string | null;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Inputs and outputs remain private. Equal-input counts use canonical original
|
|
72
|
-
* model arguments and immutable admitted-input hashes separately (O.3 / Pi A).
|
|
73
|
-
* Expected nonzero exits need an evaluator declaration; an exit alone cannot
|
|
74
|
-
* prove a command was accidental, and model prose cannot establish intent.
|
|
75
|
-
*/
|
|
76
|
-
export function summarizeHarnessDiagnostics(input: {
|
|
77
|
-
events: readonly LogEvent[]; requests: readonly DiagnosticRequest[];
|
|
78
|
-
expectedNonzeroCallIds?: readonly string[];
|
|
79
|
-
}) {
|
|
80
|
-
const tools: Record<string, ToolCounters> = {};
|
|
81
|
-
const tool = (name: string): ToolCounters => tools[name] ??= counters();
|
|
82
|
-
const calls = new Map<string, Call>(), results = new Map<string, ToolResultEvent[]>(), seenEvents = new Set<string>();
|
|
83
|
-
const guidance: Record<string, number> = {}, cuts: Record<string, number> = {}, cleanupProcessExits: Record<string, number> = {};
|
|
84
|
-
let duplicateEvents = 0, interruptions = 0;
|
|
85
|
-
for (const event of input.events) {
|
|
86
|
-
if (seenEvents.has(event.id)) { duplicateEvents++; continue; }
|
|
87
|
-
seenEvents.add(event.id);
|
|
88
|
-
if (event.t === "guidance") add(guidance, event.reason);
|
|
89
|
-
if (event.t === "cut") add(cuts, event.reason);
|
|
90
|
-
if (event.t === "interrupt") interruptions++;
|
|
91
|
-
if (event.t === "process_exit") add(cleanupProcessExits, String(event.exit));
|
|
92
|
-
if (event.t === "assistant") for (const block of event.blocks) {
|
|
93
|
-
if (block.type !== "tool_use") continue;
|
|
94
|
-
const existing = calls.get(block.call_id), stats = tool(block.name);
|
|
95
|
-
if (existing?.provider) stats.duplicateProviderCalls++;
|
|
96
|
-
calls.set(block.call_id, { name: existing?.name ?? block.name, provider: true,
|
|
97
|
-
invocation: existing?.invocation ?? false, nested: existing?.nested ?? false,
|
|
98
|
-
providerInput: canonicalValue(block.input), invocationInput: existing?.invocationInput ?? null });
|
|
99
|
-
}
|
|
100
|
-
if (event.t === "tool_invocation") {
|
|
101
|
-
const existing = calls.get(event.call_id), stats = tool(event.name);
|
|
102
|
-
if (existing?.invocation) stats.duplicateInvocations++;
|
|
103
|
-
calls.set(event.call_id, { name: existing?.name ?? event.name, provider: existing?.provider ?? false,
|
|
104
|
-
invocation: true, nested: event.parent_call_id !== undefined,
|
|
105
|
-
providerInput: existing?.providerInput ?? null, invocationInput: event.input_ref.sha256 });
|
|
106
|
-
}
|
|
107
|
-
if (event.t === "tool_result") {
|
|
108
|
-
const found = results.get(event.call_id) ?? [];
|
|
109
|
-
found.push(event); results.set(event.call_id, found);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
const providerInputs = new Map<string, Set<string>>(), invocationInputs = new Map<string, Set<string>>();
|
|
113
|
-
const repeat = (groups: Map<string, Set<string>>, name: string, key: string | null): boolean => {
|
|
114
|
-
if (key === null) return false;
|
|
115
|
-
const seen = groups.get(name) ?? new Set<string>(), repeated = seen.has(key);
|
|
116
|
-
seen.add(key); groups.set(name, seen); return repeated;
|
|
117
|
-
};
|
|
118
|
-
for (const [id, call] of calls) {
|
|
119
|
-
const stats = tool(call.name); stats.calls++;
|
|
120
|
-
if (call.provider) stats.providerCalls++;
|
|
121
|
-
if (call.invocation) stats.invocations++;
|
|
122
|
-
if (call.nested) stats.nestedInvocations++;
|
|
123
|
-
if (repeat(providerInputs, call.name, call.providerInput)) stats.repeatedProviderInputs++;
|
|
124
|
-
if (repeat(invocationInputs, call.name, call.invocationInput)) stats.repeatedInvocationInputs++;
|
|
125
|
-
if (results.has(id)) stats.pairedCalls++; else stats.orphanCalls++;
|
|
126
|
-
}
|
|
127
|
-
const expected = new Set(input.expectedNonzeroCallIds ?? []);
|
|
128
|
-
for (const [id, found] of results) {
|
|
129
|
-
const call = calls.get(id), stats = tool(call?.name ?? "<orphan>");
|
|
130
|
-
stats.duplicateResults += Math.max(0, found.length - 1);
|
|
131
|
-
for (const event of found) {
|
|
132
|
-
stats.results++;
|
|
133
|
-
if (!call) stats.orphanResults++;
|
|
134
|
-
stats.classes[classifyToolResult(event)]++;
|
|
135
|
-
if (event.diagnostic) add(stats.diagnosticCodes, event.diagnostic.code);
|
|
136
|
-
if (event.effect?.kind === "command") {
|
|
137
|
-
add(stats.commandExits, String(event.effect.exit));
|
|
138
|
-
if (event.effect.exit !== 0) {
|
|
139
|
-
if (expected.has(id)) stats.expectedNonzeroCommands++; else stats.undeclaredNonzeroCommands++;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
const requestIds = new Set<number>(), requests: {
|
|
145
|
-
request: number; node: number | null; usageKnown: boolean; promptTokens: number | null;
|
|
146
|
-
cachedTokens: number | null; cacheWriteTokens: number | null; outputTokens: number | null;
|
|
147
|
-
cacheHitRate: number | null; responseModel: string | null; failure: string | null;
|
|
148
|
-
firstDeltaMs: number | null; wallMs: number | null; prefixUnchanged: boolean | null; sharedInputBytes: number | null;
|
|
149
|
-
}[] = [];
|
|
150
|
-
const models: Record<string, number> = {};
|
|
151
|
-
const usage = { knownRequests: 0, unknownRequests: 0, requestsWithCacheReads: 0, promptTokens: 0, cachedTokens: 0,
|
|
152
|
-
cacheWriteTokens: 0, outputTokens: 0, promptKnownRequests: 0, promptUnknownRequests: 0,
|
|
153
|
-
cacheCoveredPromptTokens: 0, cacheCoverageRate: null as number | null,
|
|
154
|
-
observedCacheHitRate: null as number | null, cacheHitRate: null as number | null };
|
|
155
|
-
const prefix = { sameNodeComparisons: 0, sameNodeMutations: 0, boundaryComparisons: 0, boundaryMutations: 0,
|
|
156
|
-
unknownComparisons: 0, sameNodeFrozenMutations: 0, boundaryFrozenMutations: 0 };
|
|
157
|
-
let previous: DiagnosticRequest | undefined, duplicateRequests = 0;
|
|
158
|
-
for (const request of input.requests.toSorted((a, b) => a.request - b.request)) {
|
|
159
|
-
if (requestIds.has(request.request)) { duplicateRequests++; continue; }
|
|
160
|
-
requestIds.add(request.request);
|
|
161
|
-
const observed = observedUsage(request.usage);
|
|
162
|
-
const prompt = reportedCount(request.reportedPromptTokens) ?? (observed ?
|
|
163
|
-
observed.input_tokens + observed.cache_read_input_tokens + observed.cache_creation_input_tokens : null);
|
|
164
|
-
const output = reportedCount(request.reportedOutputTokens) ?? observed?.output_tokens ?? null;
|
|
165
|
-
if (prompt !== null) { usage.promptKnownRequests++; usage.promptTokens += prompt; } else usage.promptUnknownRequests++;
|
|
166
|
-
if (output !== null) usage.outputTokens += output;
|
|
167
|
-
if (observed) {
|
|
168
|
-
usage.knownRequests++; usage.cacheCoveredPromptTokens += prompt!; usage.cachedTokens += observed.cache_read_input_tokens;
|
|
169
|
-
usage.cacheWriteTokens += observed.cache_creation_input_tokens;
|
|
170
|
-
if (observed.cache_read_input_tokens > 0) usage.requestsWithCacheReads++;
|
|
171
|
-
} else usage.unknownRequests++;
|
|
172
|
-
if (request.responseModel !== null) add(models, request.responseModel);
|
|
173
|
-
if (previous) {
|
|
174
|
-
if (previous.node === null || request.node === null || request.prefixUnchanged === null) prefix.unknownComparisons++;
|
|
175
|
-
else if (previous.node === request.node) { prefix.sameNodeComparisons++; if (!request.prefixUnchanged) prefix.sameNodeMutations++; }
|
|
176
|
-
else { prefix.boundaryComparisons++; if (!request.prefixUnchanged) prefix.boundaryMutations++; }
|
|
177
|
-
if (previous.frozenSha256 !== null && request.frozenSha256 !== null && previous.frozenSha256 !== request.frozenSha256) {
|
|
178
|
-
if (previous.node === request.node && request.node !== null) prefix.sameNodeFrozenMutations++;
|
|
179
|
-
else if (previous.node !== null && request.node !== null) prefix.boundaryFrozenMutations++;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
previous = request;
|
|
183
|
-
requests.push({ request: request.request, node: request.node, usageKnown: observed !== null, promptTokens: prompt,
|
|
184
|
-
cachedTokens: observed?.cache_read_input_tokens ?? null, cacheWriteTokens: observed?.cache_creation_input_tokens ?? null,
|
|
185
|
-
outputTokens: output, cacheHitRate: observed && prompt ? observed.cache_read_input_tokens / prompt : null,
|
|
186
|
-
responseModel: request.responseModel, failure: request.failure, firstDeltaMs: validTime(request.firstDeltaMs),
|
|
187
|
-
wallMs: validTime(request.wallMs), prefixUnchanged: request.prefixUnchanged, sharedInputBytes: request.sharedInputBytes });
|
|
188
|
-
}
|
|
189
|
-
usage.observedCacheHitRate = usage.cacheCoveredPromptTokens > 0 ? usage.cachedTokens / usage.cacheCoveredPromptTokens : null;
|
|
190
|
-
usage.cacheCoverageRate = usage.promptUnknownRequests === 0 && usage.promptTokens > 0 ? usage.cacheCoveredPromptTokens / usage.promptTokens : null;
|
|
191
|
-
usage.cacheHitRate = usage.unknownRequests === 0 && usage.promptTokens > 0 ? usage.cachedTokens / usage.promptTokens : null;
|
|
192
|
-
const delta = requests.flatMap(r => r.firstDeltaMs === null ? [] : [r.firstDeltaMs]);
|
|
193
|
-
const totals = counters();
|
|
194
|
-
for (const stats of Object.values(tools)) {
|
|
195
|
-
for (const key of Object.keys(totals) as (keyof ToolCounters)[]) {
|
|
196
|
-
const value = stats[key];
|
|
197
|
-
if (typeof value === "number") (totals[key] as number) += value;
|
|
198
|
-
}
|
|
199
|
-
for (const key of Object.keys(stats.classes) as ResultClass[]) totals.classes[key] += stats.classes[key];
|
|
200
|
-
for (const key of Object.keys(stats.commandExits)) totals.commandExits[key] = (totals.commandExits[key] ?? 0) + stats.commandExits[key]!;
|
|
201
|
-
for (const key of Object.keys(stats.diagnosticCodes)) totals.diagnosticCodes[key] = (totals.diagnosticCodes[key] ?? 0) + stats.diagnosticCodes[key]!;
|
|
202
|
-
}
|
|
203
|
-
return { eventCount: seenEvents.size, duplicateEvents, tools, totals, guidance, cuts, interruptions, cleanupProcessExits,
|
|
204
|
-
requestCount: requests.length, duplicateRequests, models, usage, prefix, requests,
|
|
205
|
-
firstDeltaMs: { samples: delta.length, missing: requests.length - delta.length, p50: quantile(delta, 0.5), p95: quantile(delta, 0.95) } };
|
|
206
|
-
}
|
package/src/core/native-eval.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/** Q.20: native subscription measurements are standard API price equivalents, never invoices. */
|
|
2
|
-
import { measuredCharge, requestReservation, type BenchmarkPrice, type BenchmarkUsage } from "./benchmark.ts";
|
|
3
|
-
|
|
4
|
-
// Verified Luna short-context tier. Bound wire bytes conservatively before dispatch;
|
|
5
|
-
// crossing this tier needs a new protocol, not silent use of the cheaper price.
|
|
6
|
-
export const NATIVE_EVAL_INPUT_LIMIT = 272000;
|
|
7
|
-
export function nativeUsage(response: unknown): BenchmarkUsage | null {
|
|
8
|
-
if (!response || typeof response !== "object") return null;
|
|
9
|
-
const raw = (response as Record<string, unknown>)["usage"];
|
|
10
|
-
if (!raw || typeof raw !== "object") return null;
|
|
11
|
-
const u = raw as Record<string, unknown>, details = u["input_tokens_details"] as Record<string, unknown> | undefined;
|
|
12
|
-
const input = u["input_tokens"], output = u["output_tokens"], cached = details?.["cached_tokens"] ?? 0, created = details?.["cache_write_tokens"] ?? 0;
|
|
13
|
-
if (![input, output, cached, created].every(n => typeof n === "number" && Number.isSafeInteger(n) && n >= 0) ||
|
|
14
|
-
Number(input) <= 0 || Number(output) <= 0 || Number(input) > NATIVE_EVAL_INPUT_LIMIT || Number(cached) + Number(created) > Number(input)) return null;
|
|
15
|
-
return { input_tokens: Number(input) - Number(cached) - Number(created), output_tokens: Number(output),
|
|
16
|
-
cache_read_input_tokens: Number(cached), cache_creation_input_tokens: Number(created) };
|
|
17
|
-
}
|
|
18
|
-
export function nativeReservation(bytes: number, modelMaxOutput: number, price: BenchmarkPrice): number {
|
|
19
|
-
if (bytes + 4096 > NATIVE_EVAL_INPUT_LIMIT || price.cacheWrite === undefined) throw Error("native eval price tier or cache-write rate is not covered");
|
|
20
|
-
return requestReservation(bytes, modelMaxOutput, { ...price, input: Math.max(price.input, price.cacheWrite) });
|
|
21
|
-
}
|
|
22
|
-
export function nativeMeasured(response: unknown, price: BenchmarkPrice): number | null {
|
|
23
|
-
const usage = nativeUsage(response);
|
|
24
|
-
return usage && price.cacheWrite !== undefined ? measuredCharge(usage, price) : null;
|
|
25
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/** N.7: repetitions stay attached to their task; they are not independent questions. */
|
|
2
|
-
import { type ContextPolicy } from "./context-policy.ts";
|
|
3
|
-
import { shuffled } from "./experiment.ts";
|
|
4
|
-
|
|
5
|
-
// N.7 is a frozen three-arm protocol; new production policies cannot change it.
|
|
6
|
-
const EVALUATED_POLICIES: readonly ContextPolicy[] = ["segmented", "continuous", "adaptive"];
|
|
7
|
-
|
|
8
|
-
export interface PolicyJob { id: string; policy: ContextPolicy; repeat: number }
|
|
9
|
-
export function policyJobKey(job: PolicyJob): string { return JSON.stringify([job.id, job.policy, job.repeat]); }
|
|
10
|
-
export function policySchedule(ids: readonly string[], repetitions: number, seed: number): PolicyJob[] {
|
|
11
|
-
if (ids.length === 0 || new Set(ids).size !== ids.length || !Number.isSafeInteger(repetitions) || repetitions < 1) throw new Error("invalid policy trial design");
|
|
12
|
-
const policies = shuffled(EVALUATED_POLICIES, seed);
|
|
13
|
-
const jobs: PolicyJob[] = [];
|
|
14
|
-
let block = 0;
|
|
15
|
-
for (let repeat = 0; repeat < repetitions; repeat++) for (const id of shuffled([...ids].sort(), seed + repeat + 1)) {
|
|
16
|
-
for (let position = 0; position < policies.length; position++) jobs.push({ id, repeat, policy: policies[(block + position) % policies.length]! });
|
|
17
|
-
block++;
|
|
18
|
-
}
|
|
19
|
-
return jobs;
|
|
20
|
-
}
|
|
21
|
-
export interface PolicyObservation extends PolicyJob {
|
|
22
|
-
status: string; correct: boolean; peakRateUsd: number; reservedUnknownUsd: number;
|
|
23
|
-
requests: number; cuts: number; incompleteHandoffs: number; wallMs: number;
|
|
24
|
-
usage: { prompt_tokens: number; cache_read_input_tokens: number; output_tokens: number };
|
|
25
|
-
}
|
|
26
|
-
export function summarizePolicies(plan: readonly PolicyJob[], results: readonly PolicyObservation[]) {
|
|
27
|
-
const planned = new Set(plan.map(policyJobKey)), observed = new Set<string>();
|
|
28
|
-
if (planned.size !== plan.length) throw new Error("duplicate planned policy job");
|
|
29
|
-
for (const result of results) {
|
|
30
|
-
const key = policyJobKey(result);
|
|
31
|
-
if (!planned.has(key) || observed.has(key) || (result.correct && result.status !== "answered")) throw new Error("invalid policy result");
|
|
32
|
-
observed.add(key);
|
|
33
|
-
}
|
|
34
|
-
return [...new Set(plan.map((job) => job.policy))].sort().map((policy) => {
|
|
35
|
-
const schedule = plan.filter((job) => job.policy === policy), group = results.filter((row) => row.policy === policy);
|
|
36
|
-
const sum = (read: (row: PolicyObservation) => number) => group.reduce((n, row) => n + read(row), 0);
|
|
37
|
-
const correct = group.filter((row) => row.correct).length;
|
|
38
|
-
const peakRateUsd = sum((row) => row.peakRateUsd), reservedUnknownUsd = sum((row) => row.reservedUnknownUsd);
|
|
39
|
-
const promptTokens = sum((row) => row.usage.prompt_tokens), cachedTokens = sum((row) => row.usage.cache_read_input_tokens);
|
|
40
|
-
return { policy, planned: schedule.length, attempted: group.length, missing: schedule.length - group.length,
|
|
41
|
-
independentTasks: new Set(schedule.map((job) => job.id)).size, correct,
|
|
42
|
-
accuracy: group.length ? correct / group.length : null, complete: group.length === schedule.length,
|
|
43
|
-
plannedSolvedFraction: schedule.length ? correct / schedule.length : null,
|
|
44
|
-
peakRateUsd, reservedUnknownUsd, allAttemptCostPerSuccessUsd: correct ? (peakRateUsd + reservedUnknownUsd) / correct : null,
|
|
45
|
-
promptTokens, cachedTokens, outputTokens: sum((row) => row.usage.output_tokens),
|
|
46
|
-
cacheHitRate: promptTokens ? cachedTokens / promptTokens : null,
|
|
47
|
-
requests: sum((row) => row.requests), cuts: sum((row) => row.cuts), incompleteHandoffs: sum((row) => row.incompleteHandoffs),
|
|
48
|
-
wallMs: sum((row) => row.wallMs),
|
|
49
|
-
tasks: [...new Set(schedule.map((job) => job.id))].map((id) => ({ id,
|
|
50
|
-
planned: schedule.filter((job) => job.id === id).length,
|
|
51
|
-
attempted: group.filter((row) => row.id === id).length,
|
|
52
|
-
correct: group.filter((row) => row.id === id && row.correct).length })),
|
|
53
|
-
};
|
|
54
|
-
});
|
|
55
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/** Q.21: task-specific shape advice cannot reveal the independent numeric oracle. */
|
|
2
|
-
import type { ToolModeTask } from "./tool-mode-protocol.ts";
|
|
3
|
-
|
|
4
|
-
export function queryEvalContract(task: ToolModeTask, paths: readonly string[], answerSha256: string) {
|
|
5
|
-
const columns = task === "tool-small" ? ["amount"] : task === "tool-batch" ? ["total"] : ["team", "total"];
|
|
6
|
-
const rowCount = task === "tool-aggregate" ? 4 : 1;
|
|
7
|
-
const operation = task === "tool-small" ? "select amount; return one row with only amount" : task === "tool-batch"
|
|
8
|
-
? "sum amount across all records as total; return one row with only total per source"
|
|
9
|
-
: "keep enabled=true, group by team, sum amount as total, and sort by team ascending; return four rows with columns team,total in that order";
|
|
10
|
-
const instruction = "Use query on each of " + paths.join(", ") + " to " + operation +
|
|
11
|
-
'. Write compact JSON with a trailing newline to answer.txt: [{"path":"data-0.jsonl","rows":[...]}], one item per source in the listed order. ' +
|
|
12
|
-
"Preserve all fixture inputs and run bun run gate.";
|
|
13
|
-
return { instruction, columns, rowCount, paths: [...paths], answerSha256 };
|
|
14
|
-
}
|