@tangle-network/agent-bench 0.7.0 → 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 +12 -0
- package/HARNESS.md +1 -1
- package/dist/adapters.js +2 -2
- package/dist/benchmarks/appworld.d.ts +61 -2
- package/dist/benchmarks/appworld.js +111 -40
- 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 +16 -22
- package/dist/benchmarks/finresearchbench.js.map +1 -1
- package/dist/benchmarks/finsearchcomp.js +16 -22
- package/dist/benchmarks/finsearchcomp.js.map +1 -1
- package/dist/benchmarks/frames.js +18 -20
- package/dist/benchmarks/frames.js.map +1 -1
- package/dist/benchmarks/simpleqa.js +15 -19
- package/dist/benchmarks/simpleqa.js.map +1 -1
- package/dist/benchmarks/trata-hedge.js +20 -23
- package/dist/benchmarks/trata-hedge.js.map +1 -1
- package/dist/{cadbench-BrpwOU6A.js → cadbench-BLSyxR1N.js} +21 -20
- package/dist/cadbench-BLSyxR1N.js.map +1 -0
- package/dist/{cadgenbench-DF7hYHdl.js → cadgenbench-x2OFkf8y.js} +2 -2
- package/dist/cadgenbench-x2OFkf8y.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/dist/router-turn-C2wMiDoo.js +31 -0
- package/dist/router-turn-C2wMiDoo.js.map +1 -0
- package/package.json +7 -7
- package/scripts/appworld_driver.py +1 -170
- package/scripts/run-package-tests.mjs +56 -36
- package/scripts/run-package-tests.test.mjs +33 -0
- package/scripts/trata-hedge/README.md +3 -3
- package/scripts/trata-hedge/run.sh +6 -2
- package/src/aec-gate.mts +30 -9
- package/src/agent-graphs-gen2.mts +523 -0
- package/src/agent-graphs-gen3.mts +660 -0
- package/src/agent-graphs-improve/offline-seams.mts +128 -0
- package/src/agent-graphs-improve.mts +747 -0
- package/src/atom-humaneval.mts +76 -55
- package/src/atom-mcp-e2e.mts +27 -13
- package/src/benchmarks/appworld.test.mts +119 -1
- package/src/benchmarks/appworld.ts +156 -33
- package/src/benchmarks/cadbench.ts +21 -8
- package/src/benchmarks/finresearchbench.ts +20 -16
- package/src/benchmarks/finsearchcomp.ts +20 -20
- package/src/benchmarks/frames.ts +19 -18
- package/src/benchmarks/simpleqa.ts +19 -17
- package/src/benchmarks/trata-hedge.ts +26 -18
- package/src/browser/ui-reviewer.ts +1 -1
- package/src/clbench-context-gate.mts +45 -9
- package/src/cloud-loop.mts +24 -6
- package/src/commit0-env-run.mts +6 -3
- package/src/commit0-env.ts +2 -3
- package/src/commit0-gate.mts +53 -24
- package/src/corpus.ts +3 -3
- package/src/david-attribution.mts +28 -9
- package/src/david-goliath.mts +31 -12
- package/src/egress-probe.mts +3 -3
- package/src/examples/lean-proof-gate.mts +10 -3
- package/src/examples/math-demo.mts +10 -3
- package/src/examples/strategy-demo.mts +10 -4
- package/src/fleet.mts +30 -8
- package/src/gate-cli.mts +9 -4
- package/src/gate.test.mts +7 -2
- package/src/gate.ts +23 -75
- package/src/generate-eval/certify.ts +13 -5
- package/src/hev-eval.mts +39 -10
- package/src/hev-improve.mts +28 -16
- package/src/hev-structural.mts +28 -20
- package/src/humaneval-gate.mts +24 -8
- package/src/humaneval-object-ablation.mts +52 -14
- package/src/humaneval-repair-gate.mts +53 -14
- package/src/mbpp-structural.mts +28 -20
- package/src/mcp-mount-probe.mts +23 -11
- package/src/official-optimizer-config.mts +61 -12
- package/src/official-optimizer-config.test.mts +72 -3
- package/src/quant-arena/profiles/quant-researcher.profile.json +6 -1
- package/src/quant-arena/quant-loop.mts +88 -61
- package/src/research-shot.ts +21 -11
- package/src/resolve-client.ts +6 -8
- package/src/rollout-ledger/backfill-swe-arena.test.mts +7 -2
- package/src/router-executor.ts +1 -1
- package/src/router-turn.ts +135 -0
- package/src/run-benchmarks.ts +7 -2
- package/src/sandbox-run.ts +23 -41
- package/src/search-bench/bridge.ts +66 -8
- package/src/search-bench/parametric-check.mts +19 -4
- package/src/search-bench/profiles.ts +24 -9
- package/src/search-bench/run.mts +3 -4
- package/src/smoke-structural-rollout.mts +21 -5
- package/src/supervisor-arena.mts +28 -20
- package/src/swe-arena/arms.ts +73 -15
- package/src/swe-arena/capacity.ts +44 -41
- package/src/swe-arena/diagnosis-ensemble.ts +51 -48
- package/src/swe-arena/execution.test.mts +12 -12
- package/src/swe-arena/gepa-seat.mts +12 -5
- package/src/swe-arena/gepa-seat.test.mts +45 -33
- package/src/swe-arena/outer-loop.mts +94 -70
- package/src/swe-arena/premeasured-from-cells.mts +16 -1
- package/src/swe-arena/premeasured-from-cells.test.mts +21 -1
- package/src/swe-arena/profiles/deepseek-author.profile.json +12 -0
- package/src/swe-arena/profiles/default-author.profile.json +9 -1
- package/src/swe-arena/proposer-fanout.mts +52 -99
- package/src/swe-arena/proposer-fanout.test.mts +92 -57
- package/src/swe-arena/proposer-provenance.mts +1 -1
- package/src/swe-code-improve.mts +30 -52
- package/src/swe-emit-patch.mts +26 -5
- package/src/swe-improve.mts +27 -8
- package/src/swe-jail.test.ts +128 -0
- package/src/swe-jail.ts +106 -22
- package/src/swe-local-proof.mts +27 -5
- package/src/swe-repro-calibrate.mts +5 -0
- package/src/swe-self-improve.mts +45 -10
- package/src/swe-stream.mts +68 -6
- package/src/swe-structural.mts +46 -7
- package/src/tb-container-executor.mts +38 -6
- package/src/tb-container-executor.test.mts +11 -3
- package/src/tb-supervisor-sidecar.mts +11 -27
- package/src/terminal-compare.ts +38 -18
- package/src/trata-gate.mts +26 -26
- package/src/trata-gepa.mts +25 -16
- package/src/trata-hedge-solve.mts +80 -0
- package/src/worker-blender.ts +21 -11
- package/src/worker-browser.ts +18 -5
- package/src/worker-build123d.ts +17 -8
- package/src/worker-cad.ts +31 -12
- package/src/worker.ts +1 -1
- package/tb_agents/opencode_router_agent.py +84 -42
- package/dist/cadbench-BrpwOU6A.js.map +0 -1
- package/dist/cadgenbench-DF7hYHdl.js.map +0 -1
- package/scripts/trata-hedge/solve.py +0 -83
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { readFile } from 'node:fs/promises'
|
|
15
15
|
import type { BenchScore, BenchTask, BenchmarkAdapter, LoadOptions } from './types'
|
|
16
16
|
import { renderBpy } from '../worker-blender'
|
|
17
|
+
import { runBenchRouterTurn } from '../router-turn'
|
|
17
18
|
|
|
18
19
|
interface CadBenchMeta {
|
|
19
20
|
name: string
|
|
@@ -48,14 +49,26 @@ async function judgeCriteria(
|
|
|
48
49
|
`Return ONLY a JSON array of exactly ${criteria.length} booleans (true=satisfied, false=not), in order, no prose.\n\nCRITERIA:\n${numbered}\n\nSCRIPT:\n\`\`\`python\n${script.slice(0, 6000)}\n\`\`\``
|
|
49
50
|
const content: unknown[] = [{ type: 'text', text }]
|
|
50
51
|
for (const url of renders) content.push({ type: 'image_url', image_url: { url } })
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
const turn = await runBenchRouterTurn(
|
|
53
|
+
{
|
|
54
|
+
routerBaseUrl: base,
|
|
55
|
+
routerKey: key,
|
|
56
|
+
profile: {
|
|
57
|
+
name: 'cadbench-vision-judge',
|
|
58
|
+
harness: 'cli-base',
|
|
59
|
+
model: {
|
|
60
|
+
provider: 'tangle-router',
|
|
61
|
+
default: model,
|
|
62
|
+
metadata: {
|
|
63
|
+
temperature: 0,
|
|
64
|
+
maxTokens: Number(process.env.JUDGE_MAX_TOKENS ?? 1500),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{ messages: [{ role: 'user', content }] },
|
|
70
|
+
)
|
|
71
|
+
const raw = turn.finalText
|
|
59
72
|
const m = /\[\s*(?:true|false)[\s\S]*?\]/i.exec(raw)
|
|
60
73
|
if (!m) return { passed: criteria.map(() => false), note: `judge returned no parseable verdict: ${raw.slice(0, 80)}` }
|
|
61
74
|
let arr: unknown
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { readFile, stat } from 'node:fs/promises'
|
|
11
11
|
import { join } from 'node:path'
|
|
12
|
+
import { runBenchRouterTurn } from '../router-turn'
|
|
12
13
|
import { benchRoot } from './_harness'
|
|
13
14
|
import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
|
|
14
15
|
|
|
@@ -180,22 +181,25 @@ function parseJudgeScore(content: string): { score: number; raw: unknown } {
|
|
|
180
181
|
async function runOfficialJudge(meta: FinResearchMeta, response: string): Promise<BenchScore> {
|
|
181
182
|
if (!meta.judgeSystemPrompt) throw new Error(`FinResearchBench task ${meta.id} missing judge_system_prompt`)
|
|
182
183
|
const router = routerConfig()
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
184
|
+
const turn = await runBenchRouterTurn(
|
|
185
|
+
{
|
|
186
|
+
routerBaseUrl: router.baseUrl,
|
|
187
|
+
routerKey: router.key,
|
|
188
|
+
profile: {
|
|
189
|
+
name: 'finresearchbench-judge',
|
|
190
|
+
harness: 'cli-base',
|
|
191
|
+
model: {
|
|
192
|
+
provider: 'tangle-router',
|
|
193
|
+
default: router.model,
|
|
194
|
+
metadata: { temperature: 0 },
|
|
195
|
+
},
|
|
196
|
+
prompt: { systemPrompt: meta.judgeSystemPrompt },
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
fillTemplate(meta, response),
|
|
200
|
+
)
|
|
201
|
+
const content = turn.finalText
|
|
202
|
+
if (!content) throw new Error('FinResearchBench judge returned no message content')
|
|
199
203
|
const { score, raw } = parseJudgeScore(content)
|
|
200
204
|
return {
|
|
201
205
|
resolved: score >= Number(process.env.FINRESEARCHBENCH_PASS_THRESHOLD ?? 0.8),
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
import { readFile } from 'node:fs/promises'
|
|
33
33
|
import { join } from 'node:path'
|
|
34
34
|
import { fileURLToPath } from 'node:url'
|
|
35
|
+
import { runBenchRouterTurn } from '../router-turn'
|
|
35
36
|
import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
|
|
36
37
|
|
|
37
38
|
const BENCH_ROOT = fileURLToPath(new URL('../..', import.meta.url))
|
|
@@ -206,26 +207,25 @@ function parseJudgeOutput(content: string): { resolved: boolean; score: number;
|
|
|
206
207
|
|
|
207
208
|
/** Run the record's own judge via the router. Fail loud on transport/parse errors. */
|
|
208
209
|
async function runRecordJudge(meta: FinSearchMeta, response: string, router: JudgeRouter): Promise<BenchScore> {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
210
|
+
const turn = await runBenchRouterTurn(
|
|
211
|
+
{
|
|
212
|
+
routerBaseUrl: router.baseUrl,
|
|
213
|
+
routerKey: router.key,
|
|
214
|
+
profile: {
|
|
215
|
+
name: 'finsearchcomp-judge',
|
|
216
|
+
harness: 'cli-base',
|
|
217
|
+
model: {
|
|
218
|
+
provider: 'tangle-router',
|
|
219
|
+
default: router.model,
|
|
220
|
+
metadata: { temperature: 0 },
|
|
221
|
+
},
|
|
222
|
+
prompt: { systemPrompt: meta.judgeSystemPrompt },
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
fillJudgePrompt(meta, response),
|
|
226
|
+
)
|
|
227
|
+
const content = turn.finalText
|
|
228
|
+
if (!content) throw new Error('FinSearchComp judge returned no message content')
|
|
229
229
|
const { resolved, score, raw } = parseJudgeOutput(content)
|
|
230
230
|
return {
|
|
231
231
|
resolved,
|
package/src/benchmarks/frames.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { readFile } from 'node:fs/promises'
|
|
|
25
25
|
import { join } from 'node:path'
|
|
26
26
|
import { fileURLToPath } from 'node:url'
|
|
27
27
|
import { promisify } from 'node:util'
|
|
28
|
+
import { runBenchRouterTurn } from '../router-turn'
|
|
28
29
|
import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
|
|
29
30
|
|
|
30
31
|
const execFileAsync = promisify(execFile)
|
|
@@ -322,24 +323,24 @@ async function tier2Judge(
|
|
|
322
323
|
candidate: string,
|
|
323
324
|
router: JudgeRouter,
|
|
324
325
|
): Promise<boolean> {
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
326
|
+
const turn = await runBenchRouterTurn(
|
|
327
|
+
{
|
|
328
|
+
routerBaseUrl: router.baseUrl,
|
|
329
|
+
routerKey: router.key,
|
|
330
|
+
profile: {
|
|
331
|
+
name: 'frames-equivalence-judge',
|
|
332
|
+
harness: 'cli-base',
|
|
333
|
+
model: {
|
|
334
|
+
provider: 'tangle-router',
|
|
335
|
+
default: router.model,
|
|
336
|
+
metadata: { temperature: 0, seed: 0 },
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
JUDGE_PROMPT(question, gold, candidate),
|
|
341
|
+
)
|
|
342
|
+
const content = turn.finalText
|
|
343
|
+
if (!content) throw new Error('FRAMES Tier-2 judge returned no message content')
|
|
343
344
|
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/)
|
|
344
345
|
const raw = (fenced ? fenced[1] : content)?.trim() ?? ''
|
|
345
346
|
let parsed: { verdict?: unknown }
|
|
@@ -30,6 +30,7 @@ import { readFile } from 'node:fs/promises'
|
|
|
30
30
|
import { join } from 'node:path'
|
|
31
31
|
import { fileURLToPath } from 'node:url'
|
|
32
32
|
import { promisify } from 'node:util'
|
|
33
|
+
import { runBenchRouterTurn } from '../router-turn'
|
|
33
34
|
import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
|
|
34
35
|
|
|
35
36
|
const execFileAsync = promisify(execFile)
|
|
@@ -195,23 +196,24 @@ async function gradeAnswer(
|
|
|
195
196
|
predicted: string,
|
|
196
197
|
router: GraderRouter,
|
|
197
198
|
): Promise<Grade> {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
199
|
+
const turn = await runBenchRouterTurn(
|
|
200
|
+
{
|
|
201
|
+
routerBaseUrl: router.baseUrl,
|
|
202
|
+
routerKey: router.key,
|
|
203
|
+
profile: {
|
|
204
|
+
name: 'simpleqa-grader',
|
|
205
|
+
harness: 'cli-base',
|
|
206
|
+
model: {
|
|
207
|
+
provider: 'tangle-router',
|
|
208
|
+
default: router.model,
|
|
209
|
+
metadata: { temperature: 0 },
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
GRADER_PROMPT(question, gold, predicted),
|
|
214
|
+
)
|
|
215
|
+
const content = turn.finalText
|
|
216
|
+
if (!content) throw new Error('SimpleQA grader returned no message content')
|
|
215
217
|
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/)
|
|
216
218
|
const raw = (fenced ? fenced[1] : content)?.trim() ?? ''
|
|
217
219
|
let parsed: { grade?: unknown }
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
import { readdirSync, readFileSync, statSync } from 'node:fs'
|
|
28
28
|
import { join } from 'node:path'
|
|
29
|
+
import { runBenchRouterTurn } from '../router-turn'
|
|
29
30
|
import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
|
|
30
31
|
|
|
31
32
|
const DEFAULT_BENCH_ROOT = '/tmp/trata-hedge-bench'
|
|
@@ -191,25 +192,32 @@ function parseJsonFallback(raw: string): unknown {
|
|
|
191
192
|
|
|
192
193
|
async function callJudge(router: JudgeRouter, prompt: string, maxAttempts = 2): Promise<unknown> {
|
|
193
194
|
for (let i = 0; i < maxAttempts; i++) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
195
|
+
try {
|
|
196
|
+
const turn = await runBenchRouterTurn(
|
|
197
|
+
{
|
|
198
|
+
routerBaseUrl: router.baseUrl,
|
|
199
|
+
routerKey: router.key,
|
|
200
|
+
profile: {
|
|
201
|
+
name: 'trata-hedge-judge',
|
|
202
|
+
harness: 'cli-base',
|
|
203
|
+
model: {
|
|
204
|
+
provider: 'tangle-router',
|
|
205
|
+
default: router.model,
|
|
206
|
+
metadata: {
|
|
207
|
+
temperature: 0,
|
|
208
|
+
maxTokens: Number(process.env.JUDGE_MAX_TOKENS ?? 16384),
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
prompt,
|
|
214
|
+
)
|
|
215
|
+
const content = turn.finalText
|
|
216
|
+
const parsed = parseJsonFallback(content)
|
|
217
|
+
if (parsed !== null) return parsed
|
|
218
|
+
} catch (error) {
|
|
219
|
+
if (i + 1 === maxAttempts) throw error
|
|
207
220
|
}
|
|
208
|
-
const body = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> }
|
|
209
|
-
const content = body.choices?.[0]?.message?.content
|
|
210
|
-
if (typeof content !== 'string') continue
|
|
211
|
-
const parsed = parseJsonFallback(content)
|
|
212
|
-
if (parsed !== null) return parsed
|
|
213
221
|
}
|
|
214
222
|
return null
|
|
215
223
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* browser-agent harness (./agent-adapter.ts).
|
|
4
4
|
*
|
|
5
5
|
* "More reviewers, the better": run a PANEL of UI reviewers over the same target
|
|
6
|
-
* and union their findings — #114's
|
|
6
|
+
* and union their findings — #114's runAgentRounds ui-auditor, browser-agent-driver's
|
|
7
7
|
* `bad design-audit`, a future reviewer — each a pluggable `UiReviewerAdapter`,
|
|
8
8
|
* none of them owning the verdict.
|
|
9
9
|
*
|
|
@@ -36,7 +36,12 @@ import { execFileSync } from 'node:child_process'
|
|
|
36
36
|
import { existsSync, readFileSync } from 'node:fs'
|
|
37
37
|
import { composeStrategies } from './directives'
|
|
38
38
|
import { type AttemptRecord, appendRunRecord, buildRunRecordFromAttempts } from './corpus'
|
|
39
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
benchRouterProfile,
|
|
41
|
+
type BenchRouterTarget,
|
|
42
|
+
runBenchRouterTurn,
|
|
43
|
+
withBenchProfile,
|
|
44
|
+
} from './router-turn'
|
|
40
45
|
import { selfConsistencySelect, verifierGroundedSelect } from './selector'
|
|
41
46
|
import { type PairedLift, pairedLift, pool } from './stats.mts'
|
|
42
47
|
|
|
@@ -48,7 +53,7 @@ function must(name: string): string {
|
|
|
48
53
|
return v
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
interface ChatMessage {
|
|
56
|
+
interface ChatMessage extends Readonly<Record<string, unknown>> {
|
|
52
57
|
role: string
|
|
53
58
|
content: string
|
|
54
59
|
}
|
|
@@ -154,7 +159,7 @@ function parseJudge(reply: string, rubricCount: number): RubricVerdict {
|
|
|
154
159
|
|
|
155
160
|
/** Grade one completion with the rubric judge. A judge API/parse failure is a real
|
|
156
161
|
* zero (the response could not be validated) — surfaced, never masked. */
|
|
157
|
-
async function judgeRubrics(cfg:
|
|
162
|
+
async function judgeRubrics(cfg: BenchRouterTarget, task: CtxTask, output: string): Promise<RubricVerdict> {
|
|
158
163
|
if (!output.trim()) return { fraction: 0, allPass: false, graded: 0 }
|
|
159
164
|
const rubricsText = task.rubrics.map((r, i) => `${i + 1}. ${r}`).join('\n')
|
|
160
165
|
// Fault-isolate the judge: a transient router failure (after retries) or an
|
|
@@ -162,8 +167,18 @@ async function judgeRubrics(cfg: RouterConfig, task: CtxTask, output: string): P
|
|
|
162
167
|
// NOT throw — one bad grade would otherwise crash the whole N×K×2 run. graded=0
|
|
163
168
|
// marks it as judge-failed so it's distinguishable from a real 0/N rubric pass.
|
|
164
169
|
try {
|
|
165
|
-
const res = await
|
|
166
|
-
|
|
170
|
+
const res = await runBenchRouterTurn(
|
|
171
|
+
{
|
|
172
|
+
routerBaseUrl: cfg.routerBaseUrl,
|
|
173
|
+
routerKey: cfg.routerKey,
|
|
174
|
+
profile: withBenchProfile(cfg.profile, {
|
|
175
|
+
name: 'clbench-rubric-judge',
|
|
176
|
+
temperature: 0,
|
|
177
|
+
}),
|
|
178
|
+
},
|
|
179
|
+
judgePrompt(rubricsText, output),
|
|
180
|
+
)
|
|
181
|
+
return parseJudge(res.finalText, task.rubrics.length)
|
|
167
182
|
} catch {
|
|
168
183
|
return { fraction: 0, allPass: false, graded: 0 }
|
|
169
184
|
}
|
|
@@ -190,8 +205,18 @@ async function main(): Promise<void> {
|
|
|
190
205
|
if (!Number.isInteger(n) || n < 1) throw new Error(`N must be a positive integer, got ${process.env.N}`)
|
|
191
206
|
if (!Number.isInteger(k) || k < 1) throw new Error(`K must be a positive integer, got ${process.env.K}`)
|
|
192
207
|
|
|
193
|
-
const workerCfg:
|
|
194
|
-
|
|
208
|
+
const workerCfg: BenchRouterTarget = {
|
|
209
|
+
routerBaseUrl,
|
|
210
|
+
routerKey,
|
|
211
|
+
profile: benchRouterProfile('clbench-context-worker', model, {
|
|
212
|
+
temperature: Number(process.env.TEMPERATURE ?? '0.8'),
|
|
213
|
+
}),
|
|
214
|
+
}
|
|
215
|
+
const judgeCfg: BenchRouterTarget = {
|
|
216
|
+
routerBaseUrl,
|
|
217
|
+
routerKey,
|
|
218
|
+
profile: benchRouterProfile('clbench-rubric-judge', judgeModel, { temperature: 0 }),
|
|
219
|
+
}
|
|
195
220
|
|
|
196
221
|
console.log(`=== CL-bench (Context Learning) selector gate · N=${n} K=${k} offset=${offset} ===`)
|
|
197
222
|
console.log(` worker=${model} judge=${judgeModel} (rubric-fraction verifier) router=${routerBaseUrl}`)
|
|
@@ -213,8 +238,19 @@ async function main(): Promise<void> {
|
|
|
213
238
|
}
|
|
214
239
|
console.log(`\n▶ solving ${units.length} attempts (${tasks.length} tasks × ${k} shots × 2 arms) via router, conc=${solveConcurrency}`)
|
|
215
240
|
const outputs = await pool(units, solveConcurrency, async (u) => {
|
|
216
|
-
const
|
|
217
|
-
|
|
241
|
+
const system = u.messages.find((message) => message.role === 'system')?.content
|
|
242
|
+
const res = await runBenchRouterTurn(
|
|
243
|
+
{
|
|
244
|
+
routerBaseUrl: workerCfg.routerBaseUrl,
|
|
245
|
+
routerKey: workerCfg.routerKey,
|
|
246
|
+
profile: withBenchProfile(workerCfg.profile, {
|
|
247
|
+
name: 'clbench-context-worker',
|
|
248
|
+
...(system ? { systemPrompt: system } : {}),
|
|
249
|
+
}),
|
|
250
|
+
},
|
|
251
|
+
{ messages: u.messages.filter((message) => message.role !== 'system') },
|
|
252
|
+
)
|
|
253
|
+
return res.finalText
|
|
218
254
|
})
|
|
219
255
|
|
|
220
256
|
console.log(`▶ grading ${outputs.length} completions with the rubric judge (${judgeModel}), conc=${solveConcurrency}`)
|
package/src/cloud-loop.mts
CHANGED
|
@@ -29,8 +29,11 @@
|
|
|
29
29
|
* dotenvx run -f …/.env.keys -f …/agent-state.env -- \
|
|
30
30
|
* env MODEL=gpt-4.1 ROUNDS=3 pnpm exec tsx src/cloud-loop.mts
|
|
31
31
|
*/
|
|
32
|
-
import {
|
|
33
|
-
|
|
32
|
+
import {
|
|
33
|
+
defaultAnalystInstruction,
|
|
34
|
+
observe,
|
|
35
|
+
openSandboxRun,
|
|
36
|
+
} from '@tangle-network/agent-runtime/kernel'
|
|
34
37
|
import { Sandbox } from '@tangle-network/sandbox'
|
|
35
38
|
import { answerOutput, sandboxAgentRun } from './sandbox-run'
|
|
36
39
|
|
|
@@ -68,11 +71,17 @@ function tools(events: ReadonlyArray<unknown>): string[] {
|
|
|
68
71
|
|
|
69
72
|
async function main(): Promise<void> {
|
|
70
73
|
const routerKey = env('TANGLE_API_KEY')
|
|
71
|
-
const model = env('MODEL', '
|
|
74
|
+
const model = env('MODEL', 'deepseek-v4-flash')
|
|
75
|
+
const workerProvider = env('WORKER_PROVIDER', 'openai-compat')
|
|
72
76
|
const routerBaseUrl = env('ROUTER_BASE_URL', 'https://router.tangle.tools/v1')
|
|
73
77
|
const rounds = Number(env('ROUNDS', '3'))
|
|
74
78
|
const client = new Sandbox({ baseUrl: env('SANDBOX_BASE_URL', 'https://sandbox.tangle.tools'), apiKey: routerKey })
|
|
75
|
-
const
|
|
79
|
+
const observerProfile = {
|
|
80
|
+
name: 'trace-observer',
|
|
81
|
+
harness: 'cli-base' as const,
|
|
82
|
+
model: { provider: 'tangle-router', default: model },
|
|
83
|
+
prompt: { systemPrompt: defaultAnalystInstruction },
|
|
84
|
+
}
|
|
76
85
|
|
|
77
86
|
console.error(`\n=== LIVE observe→steer loop · ${model} · real cloud worker + real observer ===\n`)
|
|
78
87
|
const steers: string[] = []
|
|
@@ -89,7 +98,13 @@ async function main(): Promise<void> {
|
|
|
89
98
|
let output = ''
|
|
90
99
|
let events: unknown[] = []
|
|
91
100
|
try {
|
|
92
|
-
const agentRun = sandboxAgentRun({
|
|
101
|
+
const agentRun = sandboxAgentRun({
|
|
102
|
+
profile: {
|
|
103
|
+
name: `worker-r${round}`,
|
|
104
|
+
harness: 'opencode',
|
|
105
|
+
model: { provider: workerProvider, default: model },
|
|
106
|
+
},
|
|
107
|
+
})
|
|
93
108
|
const run = await openSandboxRun<string>(
|
|
94
109
|
client,
|
|
95
110
|
{ agentRun, signal: controller.signal },
|
|
@@ -116,7 +131,10 @@ async function main(): Promise<void> {
|
|
|
116
131
|
// THE JOIN: a REAL observer reads the REAL trace → a finding → next round's steer.
|
|
117
132
|
const ob = await observe(
|
|
118
133
|
{ task, output, trace: events, outcome: 'failed', runId: `r${round}` },
|
|
119
|
-
{
|
|
134
|
+
{
|
|
135
|
+
profile: observerProfile,
|
|
136
|
+
executor: { backend: 'router', routerBaseUrl, routerKey },
|
|
137
|
+
},
|
|
120
138
|
)
|
|
121
139
|
const next = ob.findings.flatMap((f) => (f.recommended_action ? [f.recommended_action] : [])).slice(0, 3)
|
|
122
140
|
if (next.length === 0) {
|
package/src/commit0-env-run.mts
CHANGED
|
@@ -12,6 +12,7 @@ import { readFileSync } from 'node:fs'
|
|
|
12
12
|
import { join } from 'node:path'
|
|
13
13
|
import { adaptiveRefine, printBenchmarkReport, refine, runBenchmark, sample, type Strategy } from '@tangle-network/agent-runtime/kernel'
|
|
14
14
|
import { type Commit0Row, createCommit0Environment, rowToTask } from './commit0-env'
|
|
15
|
+
import { benchRouterProfile } from './router-turn'
|
|
15
16
|
|
|
16
17
|
function must(name: string): string {
|
|
17
18
|
const v = process.env[name]
|
|
@@ -42,9 +43,11 @@ async function main(): Promise<void> {
|
|
|
42
43
|
worker: {
|
|
43
44
|
routerBaseUrl: process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1',
|
|
44
45
|
routerKey: must('TANGLE_API_KEY'),
|
|
45
|
-
model,
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
workerProfile: benchRouterProfile('commit0-worker', model, {
|
|
47
|
+
systemPrompt: 'You are a senior Python engineer. Work through the available tools until the task is verified complete.',
|
|
48
|
+
maxTurns: Number(process.env.INNER_TURNS ?? 10),
|
|
49
|
+
temperature: 0.4,
|
|
50
|
+
}),
|
|
48
51
|
},
|
|
49
52
|
strategies,
|
|
50
53
|
budget,
|
package/src/commit0-env.ts
CHANGED
|
@@ -65,12 +65,11 @@ function parsePytest(out: string): { passed: number; failed: number } {
|
|
|
65
65
|
export function rowToTask(row: Commit0Row): AgenticTask {
|
|
66
66
|
return {
|
|
67
67
|
id: row.instance_id,
|
|
68
|
-
|
|
68
|
+
userPrompt:
|
|
69
69
|
'You are a senior Python engineer implementing a stubbed library so its existing test suite passes. ' +
|
|
70
70
|
'Workflow: list_files and read the tests + stubs to learn the required behavior, write COMPLETE implementations ' +
|
|
71
71
|
`with write_file (source under ${row.src_dir} only — the test dir is read-only), then run_tests and fix failures. ` +
|
|
72
|
-
'Iterate until the suite passes. Reply DONE only when run_tests shows no failures
|
|
73
|
-
userPrompt:
|
|
72
|
+
'Iterate until the suite passes. Reply DONE only when run_tests shows no failures.\n\n' +
|
|
74
73
|
`Implement the stubbed library "${row.repo}". The public functions/classes under \`${row.src_dir}\` have empty bodies. ` +
|
|
75
74
|
`Make the existing tests under \`${row.test.test_dir}\` pass.${row.setup.specification ? ` Spec: ${row.setup.specification}` : ''}`,
|
|
76
75
|
meta: { instanceId: row.instance_id },
|