@tangle-network/agent-bench 0.8.10 → 0.8.15
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 +10 -0
- package/README.md +14 -0
- package/dist/adapters.js +2 -2
- package/dist/benchmarks/appworld.js +1 -1
- package/dist/benchmarks/appworld.js.map +1 -1
- package/dist/benchmarks/cadbench.js +1 -1
- package/dist/benchmarks/cadgenbench.js +1 -1
- package/dist/benchmarks/finresearchbench.js +1 -1
- package/dist/benchmarks/finsearchcomp.js +1 -1
- package/dist/benchmarks/frames.js +1 -1
- package/dist/benchmarks/simpleqa.js +1 -1
- package/dist/benchmarks/trata-hedge.js +1 -1
- package/dist/{cadbench-BLSyxR1N.js → cadbench-BRF-59Mt.js} +2 -2
- package/dist/{cadbench-BLSyxR1N.js.map → cadbench-BRF-59Mt.js.map} +1 -1
- package/dist/{cadgenbench-x2OFkf8y.js → cadgenbench-DXtGkuW3.js} +2 -2
- package/dist/{cadgenbench-x2OFkf8y.js.map → cadgenbench-DXtGkuW3.js.map} +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/{router-turn-C2wMiDoo.js → router-turn-uTYO6KQ1.js} +10 -8
- package/dist/router-turn-uTYO6KQ1.js.map +1 -0
- package/package.json +8 -7
- package/src/agent-graphs-improve.mts +1 -1
- package/src/atom-mcp-e2e.mts +1 -1
- package/src/benchmarks/appworld.ts +1 -1
- package/src/commit0-gate.mts +1 -1
- package/src/humaneval-repair-gate.mts +1 -1
- package/src/mcp-mount-probe.mts +1 -1
- package/src/quant-arena/quant-loop.mts +1 -1
- package/src/router-turn.ts +10 -1
- package/src/run-benchmarks.ts +12 -8
- package/src/swe-arena/arms.ts +1 -1
- package/dist/router-turn-C2wMiDoo.js.map +0 -1
- package/src/aec-gate.mts +0 -238
- package/src/atom-humaneval.mts +0 -218
- package/src/david-attribution.mts +0 -97
- package/src/david-goliath.mts +0 -168
- package/src/decoder-live.mts +0 -133
- package/src/diverse-gate.mjs +0 -112
- package/src/hev-eval.mts +0 -101
- package/src/hev-improve.mts +0 -245
- package/src/humaneval-object-ablation.mts +0 -239
- package/src/trata-gate.mts +0 -243
package/src/atom-humaneval.mts
DELETED
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The "useful or BS" verdict: agents-driving-agents on a REAL deployable-checked domain.
|
|
3
|
-
*
|
|
4
|
-
* A `driverAgent` with a REAL router-LLM brain drives, per HumanEval task: it spawns
|
|
5
|
-
* worker agents (each a router LLM that writes the function), every worker GATED by the
|
|
6
|
-
* deterministic local Docker checker (the deliverable — a worker settles `valid` ⟺ its tests
|
|
7
|
-
* pass), and the completion-oracle keeps-best a DELIVERED worker. The supervisor returns a winner
|
|
8
|
-
* ONLY when a worker actually passed the tests (no self-declared done). We measure the driver's
|
|
9
|
-
* delivered rate against a BLIND best-of-K baseline (K independent workers, no orchestration) at
|
|
10
|
-
* the same K — the honest "does the recursion+oracle beat blind compute, or is it BS" question.
|
|
11
|
-
*
|
|
12
|
-
* Run (creds via dotenvx; Docker daemon must be up):
|
|
13
|
-
* DOTENV_PRIVATE_KEY_FILE=~/company/devops/secrets/.env.keys \
|
|
14
|
-
* dotenvx run -f ~/company/devops/secrets/agent-state.env -- \
|
|
15
|
-
* N=5 K=3 WORKER_MODEL=deepseek-v4-flash DRIVER_MODEL=deepseek-v4-flash \
|
|
16
|
-
* npx tsx bench/src/atom-humaneval.mts
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
type Agent,
|
|
21
|
-
type AgentProfile,
|
|
22
|
-
type AgentSpec,
|
|
23
|
-
contentAddress,
|
|
24
|
-
createExecutor,
|
|
25
|
-
createExecutorRegistry,
|
|
26
|
-
createSupervisor,
|
|
27
|
-
gateOnDeliverable,
|
|
28
|
-
InMemoryResultBlobStore,
|
|
29
|
-
InMemorySpawnJournal,
|
|
30
|
-
mapExecutorResult,
|
|
31
|
-
supervisorAgent,
|
|
32
|
-
} from '../../src/runtime/index'
|
|
33
|
-
import { basePrompt, extractCode, type HumanEvalTask, loadHumanEval, runChecker } from './benchmarks/humaneval'
|
|
34
|
-
import {
|
|
35
|
-
benchProfileModel,
|
|
36
|
-
benchRouterProfile,
|
|
37
|
-
type BenchRouterTarget,
|
|
38
|
-
runBenchRouterTurn,
|
|
39
|
-
withBenchProfile,
|
|
40
|
-
} from './router-turn'
|
|
41
|
-
|
|
42
|
-
function must(k: string): string {
|
|
43
|
-
const v = process.env[k]
|
|
44
|
-
if (!v) throw new Error(`missing required env ${k}`)
|
|
45
|
-
return v
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const N = Number(process.env.N ?? 5)
|
|
49
|
-
const K = Number(process.env.K ?? 3)
|
|
50
|
-
const OFFSET = Number(process.env.OFFSET ?? 0)
|
|
51
|
-
const WORKER_TEMP = Number(process.env.WORKER_TEMP ?? 0.7)
|
|
52
|
-
|
|
53
|
-
const cfg: BenchRouterTarget = {
|
|
54
|
-
routerBaseUrl: process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1',
|
|
55
|
-
routerKey: must('TANGLE_API_KEY'),
|
|
56
|
-
profile: benchRouterProfile(
|
|
57
|
-
'humaneval-worker',
|
|
58
|
-
process.env.WORKER_MODEL ?? 'deepseek-v4-flash',
|
|
59
|
-
{ temperature: WORKER_TEMP },
|
|
60
|
-
),
|
|
61
|
-
}
|
|
62
|
-
const driverCfg: BenchRouterTarget = {
|
|
63
|
-
...cfg,
|
|
64
|
-
profile: benchRouterProfile(
|
|
65
|
-
'humaneval-driver',
|
|
66
|
-
process.env.DRIVER_MODEL ?? benchProfileModel(cfg.profile),
|
|
67
|
-
{ maxTurns: K + 4 },
|
|
68
|
-
),
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ── A gated router worker: one router call → candidate code, settled valid ⟺ the tests pass ──
|
|
72
|
-
function humanEvalWorker(task: HumanEvalTask, label: string): Agent<unknown, unknown> {
|
|
73
|
-
const profile: AgentProfile = withBenchProfile(cfg.profile, {
|
|
74
|
-
name: label,
|
|
75
|
-
systemPrompt: basePrompt(task),
|
|
76
|
-
})
|
|
77
|
-
const routerFactory = createExecutor({
|
|
78
|
-
backend: 'router',
|
|
79
|
-
routerBaseUrl: cfg.routerBaseUrl,
|
|
80
|
-
routerKey: cfg.routerKey,
|
|
81
|
-
})
|
|
82
|
-
const executorFactory = (spec: AgentSpec, ctx: Parameters<typeof routerFactory>[1]) => {
|
|
83
|
-
const inner = routerFactory(spec, ctx)
|
|
84
|
-
const mapped = mapExecutorResult(inner, (result) => {
|
|
85
|
-
const raw = result.out as { content?: unknown }
|
|
86
|
-
const code = extractCode(typeof raw?.content === 'string' ? raw.content : '')
|
|
87
|
-
return { outRef: contentAddress(code), out: code }
|
|
88
|
-
})
|
|
89
|
-
return gateOnDeliverable(mapped, {
|
|
90
|
-
check: async (out) => (await runChecker(task, String(out))).pass === 1,
|
|
91
|
-
describe: `${task.taskId}: the provided test suite passes`,
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
const spec: AgentSpec = { profile, harness: null, executorFactory }
|
|
95
|
-
return { name: label, act: async () => '', executorSpec: spec } as Agent<unknown, unknown> & {
|
|
96
|
-
executorSpec: AgentSpec
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const driverSystem = `You are an orchestrator driving worker agents to solve a Python coding task. You do NOT write code yourself. Each worker independently attempts the task and is graded by a deterministic, hidden test suite. Tools: spawn_worker (dispatch one attempt; the "profile" argument may be {} and "task" a short note), await_event (collect the next settled worker — its result tells you valid:true if its tests PASSED, valid:false if they failed), and stopping (reply with NO tool call) once a worker has DELIVERED. Spawn one worker, await it; if it delivered, stop; if not, spawn another, up to ${K} workers total. You cannot declare success yourself — only a delivered (valid:true) worker counts.`
|
|
101
|
-
|
|
102
|
-
interface TaskOutcome {
|
|
103
|
-
taskId: string
|
|
104
|
-
driverDelivered: boolean
|
|
105
|
-
blindDelivered: boolean
|
|
106
|
-
driverSpawns: number
|
|
107
|
-
driverWorkerTokens: number
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ── Driver arm: the orchestrated atom ────────────────────────────────────────────────────────
|
|
111
|
-
async function driveTask(
|
|
112
|
-
task: HumanEvalTask,
|
|
113
|
-
): Promise<{ delivered: boolean; spawns: number; tokens: number }> {
|
|
114
|
-
const blobs = new InMemoryResultBlobStore()
|
|
115
|
-
const journal = new InMemorySpawnJournal()
|
|
116
|
-
let spawns = 0
|
|
117
|
-
const makeWorker = (): Agent<unknown, unknown> => {
|
|
118
|
-
const w = humanEvalWorker(task, `w-${spawns}`)
|
|
119
|
-
spawns += 1
|
|
120
|
-
return w
|
|
121
|
-
}
|
|
122
|
-
const root = supervisorAgent(
|
|
123
|
-
withBenchProfile(driverCfg.profile, {
|
|
124
|
-
name: `drv-${task.taskId}`,
|
|
125
|
-
systemPrompt: driverSystem,
|
|
126
|
-
}),
|
|
127
|
-
{
|
|
128
|
-
router: {
|
|
129
|
-
routerBaseUrl: driverCfg.routerBaseUrl,
|
|
130
|
-
routerKey: driverCfg.routerKey,
|
|
131
|
-
},
|
|
132
|
-
blobs,
|
|
133
|
-
makeWorkerAgent: makeWorker,
|
|
134
|
-
perWorker: { maxIterations: 2, maxTokens: 4000 },
|
|
135
|
-
},
|
|
136
|
-
)
|
|
137
|
-
const runId = `he-${task.taskId.replace('/', '-')}`
|
|
138
|
-
const result = await createSupervisor<unknown, unknown>().run(root, basePrompt(task), {
|
|
139
|
-
budget: { maxIterations: 100, maxTokens: 400_000 },
|
|
140
|
-
runId,
|
|
141
|
-
journal,
|
|
142
|
-
blobs,
|
|
143
|
-
executors: createExecutorRegistry(),
|
|
144
|
-
maxDepth: 4,
|
|
145
|
-
now: () => Date.now(),
|
|
146
|
-
})
|
|
147
|
-
const tree = await journal.loadTree(runId)
|
|
148
|
-
const tokens = (tree ?? [])
|
|
149
|
-
.filter((e): e is Extract<NonNullable<typeof tree>[number], { kind: 'settled' }> => e.kind === 'settled')
|
|
150
|
-
.reduce((s, e) => s + e.spent.tokens.input + e.spent.tokens.output, 0)
|
|
151
|
-
return { delivered: result.kind === 'winner', spawns, tokens }
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// ── Blind arm: K independent workers, best-of-K by the checker (no orchestration) ─────────────
|
|
155
|
-
async function blindTask(task: HumanEvalTask): Promise<boolean> {
|
|
156
|
-
for (let i = 0; i < K; i += 1) {
|
|
157
|
-
// A transient router error is a FAILED attempt, not a crash — the driver arm already types
|
|
158
|
-
// an executor throw into a `down` settlement, so the blind arm must match (fair comparison).
|
|
159
|
-
let content = ''
|
|
160
|
-
try {
|
|
161
|
-
const res = await runBenchRouterTurn(
|
|
162
|
-
{
|
|
163
|
-
routerBaseUrl: cfg.routerBaseUrl,
|
|
164
|
-
routerKey: cfg.routerKey,
|
|
165
|
-
profile: withBenchProfile(cfg.profile, {
|
|
166
|
-
name: 'humaneval-blind-atom-worker',
|
|
167
|
-
}),
|
|
168
|
-
},
|
|
169
|
-
basePrompt(task),
|
|
170
|
-
)
|
|
171
|
-
content = res.finalText
|
|
172
|
-
} catch {
|
|
173
|
-
continue
|
|
174
|
-
}
|
|
175
|
-
if ((await runChecker(task, extractCode(content))).pass === 1) return true
|
|
176
|
-
}
|
|
177
|
-
return false
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async function main(): Promise<void> {
|
|
181
|
-
console.log(
|
|
182
|
-
`atom-humaneval: N=${N} K=${K} offset=${OFFSET} worker=${benchProfileModel(cfg.profile)} driver=${benchProfileModel(driverCfg.profile)}`,
|
|
183
|
-
)
|
|
184
|
-
const tasks = await loadHumanEval(N, OFFSET)
|
|
185
|
-
const outcomes: TaskOutcome[] = []
|
|
186
|
-
for (const task of tasks) {
|
|
187
|
-
const drv = await driveTask(task)
|
|
188
|
-
const blind = await blindTask(task)
|
|
189
|
-
outcomes.push({
|
|
190
|
-
taskId: task.taskId,
|
|
191
|
-
driverDelivered: drv.delivered,
|
|
192
|
-
blindDelivered: blind,
|
|
193
|
-
driverSpawns: drv.spawns,
|
|
194
|
-
driverWorkerTokens: drv.tokens,
|
|
195
|
-
})
|
|
196
|
-
console.log(
|
|
197
|
-
` ${task.taskId.padEnd(14)} driver=${drv.delivered ? 'PASS' : 'fail'} (spawns=${drv.spawns}, tok=${drv.tokens}) blind@${K}=${blind ? 'PASS' : 'fail'}`,
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
const driverPass = outcomes.filter((o) => o.driverDelivered).length
|
|
201
|
-
const blindPass = outcomes.filter((o) => o.blindDelivered).length
|
|
202
|
-
const avgSpawns = outcomes.reduce((s, o) => s + o.driverSpawns, 0) / Math.max(1, outcomes.length)
|
|
203
|
-
console.log('\n── verdict ──')
|
|
204
|
-
console.log(`driver-orchestrated delivered: ${driverPass}/${outcomes.length} (avg spawns ${avgSpawns.toFixed(1)} of ${K} allowed)`)
|
|
205
|
-
console.log(`blind best-of-${K} delivered: ${blindPass}/${outcomes.length}`)
|
|
206
|
-
console.log(
|
|
207
|
-
driverPass > blindPass
|
|
208
|
-
? `→ orchestration BEAT blind by +${driverPass - blindPass} tasks`
|
|
209
|
-
: driverPass === blindPass
|
|
210
|
-
? `→ orchestration TIED blind (the atom delivers, but adds no lift here at this N)`
|
|
211
|
-
: `→ orchestration LOST to blind by ${blindPass - driverPass} tasks`,
|
|
212
|
-
)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
main().catch((e) => {
|
|
216
|
-
console.error(e)
|
|
217
|
-
process.exit(1)
|
|
218
|
-
})
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DAVID mechanism attribution — decompose the cheap-model harness's held-out
|
|
3
|
-
* accuracy into what SAMPLING buys vs what VERIFICATION-SELECTION buys, so a
|
|
4
|
-
* David-Goliath win is credited to the right lever (not just best-of-N luck).
|
|
5
|
-
*
|
|
6
|
-
* For each task, generate N candidate solutions + the model's own tests, then
|
|
7
|
-
* report four numbers on the HIDDEN test:
|
|
8
|
-
* pass@1 — first candidate (no harness).
|
|
9
|
-
* mean-cand — expected accuracy of a RANDOM candidate (sampling floor).
|
|
10
|
-
* oracle@N — a correct candidate exists among the N (ceiling of selection).
|
|
11
|
-
* verify-select — the candidate the self-tests picked (the actual David).
|
|
12
|
-
* verify-select − mean-cand = what VERIFICATION adds over blind sampling;
|
|
13
|
-
* oracle@N − verify-select = the selection gap left on the table.
|
|
14
|
-
*
|
|
15
|
-
* Run from cwd=bench: env DAVID=groq/llama-3.1-8b-instant N=8 T=5 NTASKS=60 \
|
|
16
|
-
* node_modules/.bin/tsx src/david-attribution.mts
|
|
17
|
-
*/
|
|
18
|
-
import { execFile } from 'node:child_process'
|
|
19
|
-
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs'
|
|
20
|
-
import { tmpdir } from 'node:os'
|
|
21
|
-
import { join } from 'node:path'
|
|
22
|
-
import { loadHumanEval, extractCode, type HumanEvalTask } from './benchmarks/humaneval'
|
|
23
|
-
import { benchRouterProfile, runBenchRouterTurn } from './router-turn'
|
|
24
|
-
|
|
25
|
-
function requiredEnv(name: string): string {
|
|
26
|
-
const value = process.env[name]
|
|
27
|
-
if (!value) throw new Error(`${name} required`)
|
|
28
|
-
return value
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const KEY = requiredEnv('TANGLE_API_KEY')
|
|
32
|
-
const ROUTER = process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1'
|
|
33
|
-
const DAVID = process.env.DAVID ?? 'groq/llama-3.1-8b-instant'
|
|
34
|
-
const N = Number(process.env.N ?? 8)
|
|
35
|
-
const T = Number(process.env.T ?? 5)
|
|
36
|
-
const NTASKS = Number(process.env.NTASKS ?? 60)
|
|
37
|
-
const CONC = Number(process.env.CONCURRENCY ?? 6)
|
|
38
|
-
const MAX_TOKENS = Number(process.env.MAX_TOKENS ?? 1000)
|
|
39
|
-
const LLM_TIMEOUT_MS = Number(process.env.LLM_TIMEOUT_MS ?? 60_000)
|
|
40
|
-
|
|
41
|
-
async function chat(messages: { role: string; content: string }[], temp: number): Promise<string> {
|
|
42
|
-
try {
|
|
43
|
-
const system = messages.find((message) => message.role === 'system')?.content
|
|
44
|
-
const turn = await runBenchRouterTurn(
|
|
45
|
-
{
|
|
46
|
-
routerBaseUrl: ROUTER,
|
|
47
|
-
routerKey: KEY,
|
|
48
|
-
profile: benchRouterProfile('david-attribution-worker', DAVID, {
|
|
49
|
-
...(system ? { systemPrompt: system } : {}),
|
|
50
|
-
temperature: temp,
|
|
51
|
-
maxTokens: MAX_TOKENS,
|
|
52
|
-
}),
|
|
53
|
-
timeoutMs: LLM_TIMEOUT_MS,
|
|
54
|
-
},
|
|
55
|
-
{ messages: messages.filter((message) => message.role !== 'system') },
|
|
56
|
-
)
|
|
57
|
-
return turn.finalText
|
|
58
|
-
} catch {
|
|
59
|
-
return ''
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
const exec = (f: string, a: string[], o: object) => new Promise<number>((res) => execFile(f, a, { ...o, maxBuffer: 8e6 }, (e) => res((e as { code?: number } | null)?.code ?? (e ? 1 : 0))))
|
|
63
|
-
async function runPy(p: string): Promise<boolean> { const d = mkdtempSync(join(tmpdir(), 'da-')); try { writeFileSync(join(d, 'p.py'), p); return (await exec('python3', [join(d, 'p.py')], { cwd: d, timeout: 6000 })) === 0 } finally { rmSync(d, { recursive: true, force: true }) } }
|
|
64
|
-
const SOLVE = 'Expert Python. Output the COMPLETE function in one ```python block, no prose, no tests.'
|
|
65
|
-
const genSol = async (t: HumanEvalTask, temp: number) => extractCode(await chat([{ role: 'system', content: SOLVE }, { role: 'user', content: `Complete:\n\n\`\`\`python\n${t.prompt}\`\`\`` }], temp))
|
|
66
|
-
async function genTests(t: HumanEvalTask): Promise<string[]> {
|
|
67
|
-
const b = extractCode(await chat([{ role: 'system', content: 'Write Python assert unit tests. Output ONLY a ```python block of `assert <entry>(...) == ...` lines. No function, no prose.' }, { role: 'user', content: `entry: ${t.entryPoint}\n\n\`\`\`python\n${t.prompt}\`\`\`` }], 0.4))
|
|
68
|
-
return b.split('\n').map((l) => l.trim()).filter((l) => l.startsWith('assert ') && l.includes(t.entryPoint)).slice(0, T + 3)
|
|
69
|
-
}
|
|
70
|
-
const judge = async (t: HumanEvalTask, code: string) => code.trim() ? runPy(`${code}\n\n${t.test}\n\ncheck(${t.entryPoint})\n`) : false
|
|
71
|
-
async function scoreTests(code: string, tests: string[]): Promise<number> { if (!code.trim() || !tests.length) return 0; let p = 0; for (const a of tests) if (await runPy(`${code}\n\n${a}\n`)) p++; return p }
|
|
72
|
-
async function pool<T2, R>(xs: T2[], n: number, fn: (x: T2) => Promise<R>): Promise<R[]> { const o = new Array<R>(xs.length); let i = 0; await Promise.all(Array.from({ length: n }, async () => { while (i < xs.length) { const k = i++; o[k] = await fn(xs[k]!) } })); return o }
|
|
73
|
-
|
|
74
|
-
async function main(): Promise<void> {
|
|
75
|
-
const tasks = await loadHumanEval(NTASKS, 0)
|
|
76
|
-
console.error(`=== ATTRIBUTION · ${DAVID} · N=${N} sols + ${T} tests · n=${tasks.length} ===`)
|
|
77
|
-
let done = 0
|
|
78
|
-
const rows = await pool(tasks, CONC, async (t) => {
|
|
79
|
-
const cands = (await Promise.all(Array.from({ length: N }, () => genSol(t, 0.7)))).filter((c) => c.trim())
|
|
80
|
-
if (!cands.length) return { p1: 0, mean: 0, oracle: 0, sel: 0 }
|
|
81
|
-
const tests = await genTests(t)
|
|
82
|
-
const hidden = await Promise.all(cands.map((c) => judge(t, c))) // hidden-test pass per candidate (for attribution only)
|
|
83
|
-
const selScores = tests.length ? await Promise.all(cands.map((c) => scoreTests(c, tests))) : cands.map(() => 0)
|
|
84
|
-
let bi = 0; for (let i = 1; i < cands.length; i++) if (selScores[i]! > selScores[bi]! || (selScores[i]! === selScores[bi]! && cands[i]!.length > cands[bi]!.length)) bi = i
|
|
85
|
-
if (++done % 15 === 0) console.error(` ${done}/${tasks.length}`)
|
|
86
|
-
return { p1: hidden[0] ? 1 : 0, mean: hidden.filter(Boolean).length / cands.length, oracle: hidden.some(Boolean) ? 1 : 0, sel: hidden[bi] ? 1 : 0 }
|
|
87
|
-
})
|
|
88
|
-
const n = rows.length, avg = (f: (r: typeof rows[number]) => number) => (rows.reduce((s, r) => s + f(r), 0) / n) * 100
|
|
89
|
-
console.log('\n=== ATTRIBUTION (held-out) ===')
|
|
90
|
-
console.log(` pass@1 (no harness) : ${avg((r) => r.p1).toFixed(1)}%`)
|
|
91
|
-
console.log(` mean random candidate : ${avg((r) => r.mean).toFixed(1)}% (sampling floor)`)
|
|
92
|
-
console.log(` verify-select (DAVID) : ${avg((r) => r.sel).toFixed(1)}%`)
|
|
93
|
-
console.log(` oracle@N (a correct exists): ${avg((r) => r.oracle).toFixed(1)}% (selection ceiling)`)
|
|
94
|
-
console.log(` --> verification adds over random sampling: +${(avg((r) => r.sel) - avg((r) => r.mean)).toFixed(1)}pp`)
|
|
95
|
-
console.log(` --> selection gap still on table (oracle-select): ${(avg((r) => r.oracle) - avg((r) => r.sel)).toFixed(1)}pp`)
|
|
96
|
-
}
|
|
97
|
-
main().catch((e) => { console.error('MAIN:', e instanceof Error ? e.stack : e); process.exit(1) })
|
package/src/david-goliath.mts
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DAVID vs GOLIATH — the program's northstar, tested head-on: does a CHEAP model
|
|
3
|
-
* with a self-verification harness beat a FRONTIER model running solo, at EQUAL OR
|
|
4
|
-
* LOWER dollar cost, on held-out code?
|
|
5
|
-
*
|
|
6
|
-
* GOLIATH — a strong model, ONE shot. The "just use the big model" baseline.
|
|
7
|
-
* DAVID — a cheap/weak model + test-time compute: generate N candidate
|
|
8
|
-
* solutions AND M of its own unit tests, EXECUTE every candidate
|
|
9
|
-
* against the generated tests, and submit the candidate that passes
|
|
10
|
-
* the most (CodeT-style execution self-selection). No ground-truth
|
|
11
|
-
* test is ever used to select — only the model's own generated tests.
|
|
12
|
-
*
|
|
13
|
-
* Both are graded by the HIDDEN HumanEval test (never shown). Cost is the real
|
|
14
|
-
* token spend × the router-reported/priced rate per arm. The win condition is a
|
|
15
|
-
* Pareto beat: David's held-out pass rate >= Goliath's AND David's $ <= Goliath's.
|
|
16
|
-
* Mechanism under test: EXECUTION-BASED VERIFICATION is the lever that lets a weak
|
|
17
|
-
* generator punch above its solo weight — the standing "verification is live" claim
|
|
18
|
-
* at its most dramatic. Paired McNemar on per-task discordant pairs for significance.
|
|
19
|
-
*
|
|
20
|
-
* Run from cwd=bench: env DAVID=glm-5.2 GOLIATH=deepseek-v4-flash \
|
|
21
|
-
* N=8 T=5 NTASKS=164 REPS=2 node_modules/.bin/tsx src/david-goliath.mts
|
|
22
|
-
*/
|
|
23
|
-
import { execFile } from 'node:child_process'
|
|
24
|
-
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs'
|
|
25
|
-
import { tmpdir } from 'node:os'
|
|
26
|
-
import { join } from 'node:path'
|
|
27
|
-
import { loadHumanEval, extractCode, type HumanEvalTask } from './benchmarks/humaneval'
|
|
28
|
-
import { runBenchRouterTurn } from './router-turn'
|
|
29
|
-
|
|
30
|
-
const KEY = process.env.TANGLE_API_KEY
|
|
31
|
-
if (!KEY) throw new Error('TANGLE_API_KEY required')
|
|
32
|
-
const ROUTER_KEY = KEY
|
|
33
|
-
const ROUTER = process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1'
|
|
34
|
-
const DAVID = process.env.DAVID ?? 'groq/llama-3.1-8b-instant'
|
|
35
|
-
const GOLIATH = process.env.GOLIATH ?? 'deepseek-v4-flash'
|
|
36
|
-
const N = Number(process.env.N ?? 8) // David candidate solutions
|
|
37
|
-
const T = Number(process.env.T ?? 5) // David generated tests
|
|
38
|
-
const NTASKS = Number(process.env.NTASKS ?? 164)
|
|
39
|
-
const REPS = Number(process.env.REPS ?? 2)
|
|
40
|
-
const CONC = Number(process.env.CONCURRENCY ?? 6)
|
|
41
|
-
const EXEC_TIMEOUT = Number(process.env.EXEC_TIMEOUT_MS ?? 6000)
|
|
42
|
-
const LLM_TIMEOUT = Number(process.env.LLM_TIMEOUT_MS ?? 60_000)
|
|
43
|
-
const MAX_TOKENS = Number(process.env.MAX_TOKENS ?? 1000)
|
|
44
|
-
|
|
45
|
-
// Approx $/1M tokens (in,out) for cost accounting — the router does not price
|
|
46
|
-
// every model inline, so use public rates; a cheap/frontier gap of ~20-30x is the
|
|
47
|
-
// point, and the ratio is robust to small rate errors. Override via PRICES env.
|
|
48
|
-
const PRICES: Record<string, [number, number]> = {
|
|
49
|
-
'groq/llama-3.1-8b-instant': [0.05, 0.08],
|
|
50
|
-
'google/gemini-2.5-flash-lite': [0.10, 0.40],
|
|
51
|
-
'openai/gpt-4o-mini': [0.15, 0.60],
|
|
52
|
-
'anthropic/claude-haiku-4-5-20251001': [1.0, 5.0],
|
|
53
|
-
'glm-5.2': [0.60, 2.20],
|
|
54
|
-
}
|
|
55
|
-
const priceOf = (m: string) => PRICES[m] ?? [0.5, 1.5]
|
|
56
|
-
|
|
57
|
-
interface Usage { in: number; out: number }
|
|
58
|
-
const zero = (): Usage => ({ in: 0, out: 0 })
|
|
59
|
-
const addU = (a: Usage, b: Usage) => { a.in += b.in; a.out += b.out }
|
|
60
|
-
const usd = (m: string, u: Usage) => { const [pi, po] = priceOf(m); return (u.in * pi + u.out * po) / 1e6 }
|
|
61
|
-
|
|
62
|
-
async function chat(model: string, messages: { role: string; content: string }[], temperature: number, usage: Usage): Promise<string> {
|
|
63
|
-
try {
|
|
64
|
-
const system = messages.find((message) => message.role === 'system')?.content
|
|
65
|
-
const result = await runBenchRouterTurn(
|
|
66
|
-
{
|
|
67
|
-
routerBaseUrl: ROUTER,
|
|
68
|
-
routerKey: ROUTER_KEY,
|
|
69
|
-
profile: {
|
|
70
|
-
name: 'david-goliath-worker',
|
|
71
|
-
harness: 'cli-base',
|
|
72
|
-
model: {
|
|
73
|
-
provider: 'tangle-router',
|
|
74
|
-
default: model,
|
|
75
|
-
metadata: { temperature, maxTokens: MAX_TOKENS },
|
|
76
|
-
},
|
|
77
|
-
...(system ? { prompt: { systemPrompt: system } } : {}),
|
|
78
|
-
},
|
|
79
|
-
timeoutMs: LLM_TIMEOUT,
|
|
80
|
-
},
|
|
81
|
-
{ messages: messages.filter((message) => message.role !== 'system') },
|
|
82
|
-
)
|
|
83
|
-
if (result.usage.tokensKnown === false) throw new Error('provider omitted token usage')
|
|
84
|
-
addU(usage, { in: result.usage.input, out: result.usage.output })
|
|
85
|
-
return result.finalText
|
|
86
|
-
} catch {
|
|
87
|
-
return ''
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const exec = (file: string, args: string[], o: object) => new Promise<{ code: number; stdout: string }>((res) => execFile(file, args, { ...o, maxBuffer: 8 * 1024 * 1024 }, (e, stdout) => res({ code: (e as { code?: number } | null)?.code ?? (e ? 1 : 0), stdout: String(stdout) })))
|
|
91
|
-
async function runPy(program: string): Promise<{ ok: boolean }> {
|
|
92
|
-
const d = mkdtempSync(join(tmpdir(), 'dg-'))
|
|
93
|
-
try { writeFileSync(join(d, 'p.py'), program); const r = await exec('python3', [join(d, 'p.py')], { cwd: d, timeout: EXEC_TIMEOUT }); return { ok: r.code === 0 } } finally { rmSync(d, { recursive: true, force: true }) }
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const SOLVE = 'You are an expert Python programmer. Output the COMPLETE function (signature + body + imports) in a single ```python block. No prose, no tests.'
|
|
97
|
-
async function genSolution(model: string, t: HumanEvalTask, temp: number, u: Usage): Promise<string> {
|
|
98
|
-
return extractCode(await chat(model, [{ role: 'system', content: SOLVE }, { role: 'user', content: `Complete:\n\n\`\`\`python\n${t.prompt}\`\`\`` }], temp, u))
|
|
99
|
-
}
|
|
100
|
-
// David writes its OWN tests (never sees the hidden test). Parse assert lines.
|
|
101
|
-
async function genTests(model: string, t: HumanEvalTask, u: Usage): Promise<string[]> {
|
|
102
|
-
const reply = await chat(model, [
|
|
103
|
-
{ role: 'system', content: 'Write Python assert-based unit tests for the described function. Output ONLY a ```python block of standalone `assert <entry>(...) == ...` lines (at least a few, covering normal + edge cases). No function definition, no prose.' },
|
|
104
|
-
{ role: 'user', content: `Function to test (entry point: ${t.entryPoint}):\n\n\`\`\`python\n${t.prompt}\`\`\`` },
|
|
105
|
-
], 0.4, u)
|
|
106
|
-
const block = extractCode(reply) || reply
|
|
107
|
-
return block.split('\n').map((l) => l.trim()).filter((l) => l.startsWith('assert ') && l.includes(t.entryPoint)).slice(0, T + 3)
|
|
108
|
-
}
|
|
109
|
-
// Hidden held-out judge — the truth. Never used for selection.
|
|
110
|
-
async function judge(t: HumanEvalTask, code: string): Promise<boolean> {
|
|
111
|
-
if (!code.trim()) return false
|
|
112
|
-
return (await runPy(`${code}\n\n${t.test}\n\ncheck(${t.entryPoint})\n`)).ok
|
|
113
|
-
}
|
|
114
|
-
// David's self-selection: score each candidate by how many of ITS OWN tests it passes.
|
|
115
|
-
async function scoreOnTests(code: string, tests: string[]): Promise<number> {
|
|
116
|
-
if (!code.trim() || tests.length === 0) return 0
|
|
117
|
-
let pass = 0
|
|
118
|
-
// one program per test keeps a crash on one test from voiding the rest
|
|
119
|
-
for (const a of tests) if ((await runPy(`${code}\n\n${a}\n`)).ok) pass++
|
|
120
|
-
return pass
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async function davidArm(t: HumanEvalTask, u: Usage): Promise<string> {
|
|
124
|
-
const cands = (await Promise.all(Array.from({ length: N }, () => genSolution(DAVID, t, 0.7, u)))).filter((c) => c.trim())
|
|
125
|
-
if (cands.length === 0) return ''
|
|
126
|
-
const tests = await genTests(DAVID, t, u)
|
|
127
|
-
if (tests.length === 0) return cands[0]! // no verifier signal → first sample
|
|
128
|
-
const scored = await Promise.all(cands.map(async (c) => ({ c, s: await scoreOnTests(c, tests) })))
|
|
129
|
-
scored.sort((a, b) => b.s - a.s || b.c.length - a.c.length)
|
|
130
|
-
return scored[0]!.c
|
|
131
|
-
}
|
|
132
|
-
const goliathArm = (t: HumanEvalTask, u: Usage) => genSolution(GOLIATH, t, 0.2, u)
|
|
133
|
-
|
|
134
|
-
async function pool<T2, R>(xs: T2[], n: number, fn: (x: T2, i: number) => Promise<R>): Promise<R[]> {
|
|
135
|
-
const o = new Array<R>(xs.length); let i = 0
|
|
136
|
-
await Promise.all(Array.from({ length: Math.min(n, xs.length) }, async () => { while (i < xs.length) { const k = i++; o[k] = await fn(xs[k]!, k) } }))
|
|
137
|
-
return o
|
|
138
|
-
}
|
|
139
|
-
function mcnemar(b: number, c: number): number { const n = b + c; if (n === 0) return 1; const k = Math.min(b, c); const lf = (x: number) => { let s = 0; for (let i = 2; i <= x; i++) s += Math.log(i); return s }; let tl = 0; for (let i = 0; i <= k; i++) tl += Math.exp(lf(n) - lf(i) - lf(n - i) - n * Math.log(2)); return Math.min(1, 2 * tl) }
|
|
140
|
-
|
|
141
|
-
async function main(): Promise<void> {
|
|
142
|
-
if (['1', 'true'].includes((process.env.SMOKE ?? '').toLowerCase())) { console.error('SMOKE ok: david-goliath loaded'); return }
|
|
143
|
-
const tasks = await loadHumanEval(NTASKS, 0)
|
|
144
|
-
console.error(`=== DAVID(${DAVID}, N=${N} sols + ${T} self-tests) vs GOLIATH(${GOLIATH}, 1 shot) · HumanEval n=${tasks.length} · reps=${REPS} ===`)
|
|
145
|
-
const dU = zero(), gU = zero()
|
|
146
|
-
const units = tasks.flatMap((task) => Array.from({ length: REPS }, () => task))
|
|
147
|
-
let done = 0
|
|
148
|
-
const res = await pool(units, CONC, async (task) => {
|
|
149
|
-
const safe = async (fn: () => Promise<string>) => { try { return await fn() } catch { return '' } }
|
|
150
|
-
const [dCode, gCode] = await Promise.all([safe(() => davidArm(task, dU)), safe(() => goliathArm(task, gU))])
|
|
151
|
-
const [d, g] = await Promise.all([judge(task, dCode), judge(task, gCode)])
|
|
152
|
-
if (++done % 20 === 0) console.error(` ${done}/${units.length} units`)
|
|
153
|
-
return { d, g }
|
|
154
|
-
})
|
|
155
|
-
const n = res.length, dPass = res.filter((r) => r.d).length, gPass = res.filter((r) => r.g).length
|
|
156
|
-
const b = res.filter((r) => r.d && !r.g).length, c = res.filter((r) => !r.d && r.g).length
|
|
157
|
-
const p = mcnemar(b, c)
|
|
158
|
-
const dCost = usd(DAVID, dU), gCost = usd(GOLIATH, gU)
|
|
159
|
-
console.log('\n=== RESULT (held-out HumanEval) ===')
|
|
160
|
-
console.log(` GOLIATH ${GOLIATH} solo : ${gPass}/${n} = ${(gPass / n * 100).toFixed(1)}% $${gCost.toFixed(4)}`)
|
|
161
|
-
console.log(` DAVID ${DAVID} + verify: ${dPass}/${n} = ${(dPass / n * 100).toFixed(1)}% $${dCost.toFixed(4)}`)
|
|
162
|
-
console.log(` accuracy: David ${dPass >= gPass ? '>=' : '<'} Goliath (${(dPass / n * 100).toFixed(1)} vs ${(gPass / n * 100).toFixed(1)}); paired McNemar David-only=${b} Goliath-only=${c} p=${p.toFixed(4)}`)
|
|
163
|
-
console.log(` cost: David is ${(gCost / Math.max(dCost, 1e-9)).toFixed(1)}x CHEAPER ($${dCost.toFixed(4)} vs $${gCost.toFixed(4)})`)
|
|
164
|
-
const paretoBeat = dPass >= gPass && dCost <= gCost
|
|
165
|
-
const sigBeat = dPass > gPass && p < 0.05
|
|
166
|
-
console.log(` VERDICT: ${sigBeat ? 'DAVID SIGNIFICANTLY BEATS GOLIATH' : paretoBeat ? 'DAVID PARETO-DOMINATES (>= accuracy, <= cost)' : dPass >= gPass ? 'David matches accuracy (check cost)' : 'Goliath wins accuracy'}`)
|
|
167
|
-
}
|
|
168
|
-
main().catch((e) => { console.error('MAIN:', e instanceof Error ? (e.stack ?? e.message) : e); process.exit(1) })
|
package/src/decoder-live.mts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LIVE validation of the per-harness tool-part decoders against a REAL sandbox box.
|
|
3
|
-
*
|
|
4
|
-
* Spin a real box for HARNESS, make the harness call tools, capture the actual session part shapes,
|
|
5
|
-
* and prove the harness's decoder extracts the tool calls (with error status where the harness carries
|
|
6
|
-
* it). No mock. Exits non-zero on a decode miss so it can gate CI. The box is ALWAYS deleted.
|
|
7
|
-
*
|
|
8
|
-
* Run: HARNESS=opencode dotenvx run -f ~/company/devops/secrets/agent-state.env -- \
|
|
9
|
-
* pnpm exec tsx bench/src/decoder-live.mts (also: claude-code, codex, kimi-code, …)
|
|
10
|
-
*/
|
|
11
|
-
import { Sandbox } from '@tangle-network/sandbox'
|
|
12
|
-
import { decodeToolPart } from '../../src/runtime/supervise/trace-source'
|
|
13
|
-
|
|
14
|
-
function must(k: string): string {
|
|
15
|
-
const v = process.env[k]
|
|
16
|
-
if (!v) throw new Error(`missing env ${k}`)
|
|
17
|
-
return v
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function* candidateParts(node: unknown, depth = 0): Generator<unknown> {
|
|
21
|
-
if (!node || typeof node !== 'object' || depth > 6) return
|
|
22
|
-
const o = node as Record<string, unknown>
|
|
23
|
-
yield o
|
|
24
|
-
if (o.part) yield o.part
|
|
25
|
-
if (Array.isArray(o.parts)) for (const p of o.parts) yield p
|
|
26
|
-
if (o.data) yield* candidateParts(o.data, depth + 1)
|
|
27
|
-
if (o.message) yield* candidateParts(o.message, depth + 1)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const HARNESS = process.env.HARNESS ?? 'opencode'
|
|
31
|
-
|
|
32
|
-
async function main(): Promise<number> {
|
|
33
|
-
const client = new Sandbox({
|
|
34
|
-
baseUrl: process.env.SANDBOX_BASE_URL ?? 'https://sandbox.tangle.tools',
|
|
35
|
-
apiKey: must('TANGLE_API_KEY'),
|
|
36
|
-
timeoutMs: 600_000,
|
|
37
|
-
} as never)
|
|
38
|
-
|
|
39
|
-
console.error(`[live] creating ${HARNESS} box (${process.env.WORKER_MODEL ?? 'deepseek-v4-flash'})…`)
|
|
40
|
-
const box = (await client.create({
|
|
41
|
-
backend: {
|
|
42
|
-
type: HARNESS,
|
|
43
|
-
model: {
|
|
44
|
-
provider: process.env.WORKER_PROVIDER ?? 'openai',
|
|
45
|
-
model: process.env.WORKER_MODEL ?? 'deepseek-v4-flash',
|
|
46
|
-
baseUrl: process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1',
|
|
47
|
-
},
|
|
48
|
-
profile: { name: 'decoder-live' },
|
|
49
|
-
},
|
|
50
|
-
} as never)) as unknown as Record<string, (...a: never[]) => unknown> & { id?: string }
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
console.error('[live] box', box.id, '— waiting for running…')
|
|
54
|
-
await box.waitFor('running' as never, { timeoutMs: 180_000 } as never)
|
|
55
|
-
|
|
56
|
-
// Force several distinct tool calls AND at least one tool error (to exercise error-status decode).
|
|
57
|
-
const prompt =
|
|
58
|
-
'Use your tools, one tool call at a time: (1) list the files in the current directory; ' +
|
|
59
|
-
'(2) run `echo hello-from-tool`; (3) run `false` (this command fails on purpose); ' +
|
|
60
|
-
'(4) create notes.txt containing "hi". A separate tool call for each. Then reply "done".'
|
|
61
|
-
|
|
62
|
-
const rawEvents: unknown[] = []
|
|
63
|
-
const ac = new AbortController()
|
|
64
|
-
const timer = setTimeout(() => ac.abort(), 240_000)
|
|
65
|
-
try {
|
|
66
|
-
for await (const ev of box.streamPrompt(prompt as never, {
|
|
67
|
-
signal: ac.signal,
|
|
68
|
-
} as never) as AsyncGenerator<unknown>) {
|
|
69
|
-
rawEvents.push(ev)
|
|
70
|
-
}
|
|
71
|
-
} finally {
|
|
72
|
-
clearTimeout(timer)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Vocabulary: every distinct part `type` the harness emitted (so we learn its real schema).
|
|
76
|
-
const types = new Map<string, number>()
|
|
77
|
-
for (const ev of rawEvents)
|
|
78
|
-
for (const part of candidateParts(ev)) {
|
|
79
|
-
const t = (part as Record<string, unknown>)?.type
|
|
80
|
-
if (typeof t === 'string') types.set(t, (types.get(t) ?? 0) + 1)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Decode tool calls via the HARNESS adapter + de-dup by callId.
|
|
84
|
-
const decoded: Array<{ toolName: string; status?: string; callId?: string }> = []
|
|
85
|
-
const seen = new Set<string>()
|
|
86
|
-
for (const ev of rawEvents)
|
|
87
|
-
for (const part of candidateParts(ev)) {
|
|
88
|
-
const step = decodeToolPart(part, HARNESS)
|
|
89
|
-
if (!step) continue
|
|
90
|
-
if (step.callId && seen.has(step.callId)) continue
|
|
91
|
-
if (step.callId) seen.add(step.callId)
|
|
92
|
-
decoded.push({ toolName: step.toolName, ...(step.status ? { status: step.status } : {}), ...(step.callId ? { callId: step.callId } : {}) })
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Surface any harness/model error events (so a no-tools run isn't mistaken for a decoder miss).
|
|
96
|
-
const errs = rawEvents.filter((e) => JSON.stringify(e).match(/"error"/i)).slice(0, 2)
|
|
97
|
-
if (errs.length) console.error(`[live] harness error events:`, errs.map((e) => JSON.stringify(e).slice(0, 300)))
|
|
98
|
-
|
|
99
|
-
console.error(`\n========== LIVE DECODER RESULT — harness=${HARNESS} ==========`)
|
|
100
|
-
console.error(`raw stream events: ${rawEvents.length}`)
|
|
101
|
-
console.error(`part-type vocabulary:`, JSON.stringify(Object.fromEntries(types)))
|
|
102
|
-
console.error(`decoded ${decoded.length} tool calls:`, JSON.stringify(decoded))
|
|
103
|
-
console.error(`with error status: ${decoded.filter((d) => d.status === 'error').length}`)
|
|
104
|
-
// Sample raw shapes the decoder did NOT match but that mention a tool (the schema to learn from).
|
|
105
|
-
console.error(`\n--- raw toolish parts NOT decoded (first 4) ---`)
|
|
106
|
-
let shown = 0
|
|
107
|
-
for (const ev of rawEvents) {
|
|
108
|
-
if (shown >= 4) break
|
|
109
|
-
for (const part of candidateParts(ev)) {
|
|
110
|
-
if (shown >= 4) break
|
|
111
|
-
const s = JSON.stringify(part)
|
|
112
|
-
if (s.match(/tool/i) && !decodeToolPart(part, HARNESS)) {
|
|
113
|
-
console.error(s.slice(0, 380))
|
|
114
|
-
shown++
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return decoded.length > 0 ? 0 : 2
|
|
119
|
-
} finally {
|
|
120
|
-
await (box.delete as (...a: never[]) => Promise<void>)().catch(() => {})
|
|
121
|
-
console.error('[live] box deleted.')
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
main()
|
|
126
|
-
.then((code) => {
|
|
127
|
-
console.error(code === 0 ? `\n✅ ${HARNESS}: decoder extracts real tool calls.` : `\n❌ ${HARNESS}: decoder extracted ZERO — see raw shapes above.`)
|
|
128
|
-
process.exit(code)
|
|
129
|
-
})
|
|
130
|
-
.catch((e) => {
|
|
131
|
-
console.error('[live] FAILED:', e)
|
|
132
|
-
process.exit(1)
|
|
133
|
-
})
|