@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/diverse-gate.mjs
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
// The beat-blind gate, as ONE command — the experiment that decides whether the
|
|
2
|
-
// diversification/selection surface (the one PR #145 defers to as "tracked separately")
|
|
3
|
-
// actually beats compute-matched best-of-N. Composes only LANDED pieces:
|
|
4
|
-
// 1. random@k corpus — k identical-directive shots/instance (the compute control)
|
|
5
|
-
// 2. diverse@k corpus — k DIFFERENT strategy lenses/instance (DIVERSE=1; the bet)
|
|
6
|
-
// 3. selector replay — selfConsistencySelect@k over each (corpus-replay --selector)
|
|
7
|
-
// 4. paired report — bootstrap CI + Benjamini-Hochberg over both (corpus-report)
|
|
8
|
-
//
|
|
9
|
-
// The decomposition it yields:
|
|
10
|
-
// random@k = more-compute, no picking (control)
|
|
11
|
-
// selector@k (homog) = picking over IDENTICAL attempts (#143: −8.2pp on the committed corpus)
|
|
12
|
-
// diverse-selector@k = picking over DIVERSE attempts (THE bet: does approach-diversity
|
|
13
|
-
// give self-consistency the signal identical attempts don't?)
|
|
14
|
-
// Beat-blind iff diverse-selector@k > random@k at significant n.
|
|
15
|
-
//
|
|
16
|
-
// node diverse-gate.mjs run it (generates corpora — a real worker run)
|
|
17
|
-
// node diverse-gate.mjs --dry print the plan only (no run; safe while another
|
|
18
|
-
// sandbox run is live — zero router/sandbox contention)
|
|
19
|
-
//
|
|
20
|
-
// Knobs (env): BENCH (default hotpotqa) · N (default 30) · K (default 4) ·
|
|
21
|
-
// RESEARCH=1 (local opencode, default) | SANDBOX=1 (prod sandbox web worker) · MODELS ·
|
|
22
|
-
// DIVERSE_BASE (compose #145's GEPA-learned directive as the lens base — follow-on).
|
|
23
|
-
|
|
24
|
-
import { spawn } from 'node:child_process'
|
|
25
|
-
|
|
26
|
-
const DRY = process.argv.includes('--dry')
|
|
27
|
-
const BENCH = process.env.BENCH ?? 'hotpotqa'
|
|
28
|
-
const N = process.env.N ?? '30'
|
|
29
|
-
const K = process.env.K ?? '4'
|
|
30
|
-
const RANDOM_CORPUS = process.env.RANDOM_CORPUS ?? '/tmp/dg-random.jsonl'
|
|
31
|
-
const DIVERSE_CORPUS = process.env.DIVERSE_CORPUS ?? '/tmp/dg-diverse.jsonl'
|
|
32
|
-
// Worker-mode env passes through to batch-oracle unchanged (RESEARCH=1 / SANDBOX=1 / MODELS / TANGLE_API_KEY).
|
|
33
|
-
const passEnv = { ...process.env, BENCH, N, K }
|
|
34
|
-
|
|
35
|
-
const steps = [
|
|
36
|
-
{
|
|
37
|
-
label: 'random@k corpus (control — identical directive)',
|
|
38
|
-
cmd: 'npx',
|
|
39
|
-
args: ['tsx', 'src/run.ts', 'batch-oracle', N],
|
|
40
|
-
env: { ...passEnv, CORPUS: RANDOM_CORPUS },
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
label: 'diverse@k corpus (the bet — k distinct strategy lenses)',
|
|
44
|
-
cmd: 'npx',
|
|
45
|
-
args: ['tsx', 'src/run.ts', 'batch-oracle', N],
|
|
46
|
-
env: { ...passEnv, CORPUS: DIVERSE_CORPUS, DIVERSE: '1' },
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
label: 'selector@k over the CONTROL corpus (homogeneous)',
|
|
50
|
-
cmd: 'npx',
|
|
51
|
-
args: ['tsx', 'src/corpus-replay.mts', RANDOM_CORPUS, '--selector'],
|
|
52
|
-
env: passEnv,
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
label: 'selector@k over the DIVERSE corpus (the beat-blind number)',
|
|
56
|
-
cmd: 'npx',
|
|
57
|
-
// The diverse corpus records carry condition="diverse@4"; corpus-replay's
|
|
58
|
-
// selector filter defaults to "random", so match the diverse condition here.
|
|
59
|
-
args: ['tsx', 'src/corpus-replay.mts', DIVERSE_CORPUS, '--selector', '--condition=diverse'],
|
|
60
|
-
env: passEnv,
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
label: 'paired bootstrap CI + Benjamini-Hochberg over both corpora',
|
|
64
|
-
cmd: 'npx',
|
|
65
|
-
args: ['tsx', 'src/corpus-report.mts', RANDOM_CORPUS, DIVERSE_CORPUS],
|
|
66
|
-
env: passEnv,
|
|
67
|
-
},
|
|
68
|
-
]
|
|
69
|
-
|
|
70
|
-
const shellPreview = (s) => {
|
|
71
|
-
const envStr = Object.entries(s.env)
|
|
72
|
-
.filter(([k]) => ['BENCH', 'N', 'K', 'CORPUS', 'DIVERSE', 'RESEARCH', 'SANDBOX', 'MODELS'].includes(k))
|
|
73
|
-
.map(([k, v]) => `${k}=${v}`)
|
|
74
|
-
.join(' ')
|
|
75
|
-
return ` ${envStr} ${s.cmd} ${s.args.join(' ')}`.replace(/\s+/g, ' ')
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function runStep(s) {
|
|
79
|
-
return new Promise((resolve, reject) => {
|
|
80
|
-
console.log(`\n▶ ${s.label}`)
|
|
81
|
-
const child = spawn(s.cmd, s.args, { cwd: process.cwd(), env: s.env, stdio: 'inherit' })
|
|
82
|
-
child.on('error', reject)
|
|
83
|
-
// Fail loud: a non-zero step aborts the gate (no silent partial result).
|
|
84
|
-
child.on('exit', (code) => (code === 0 ? resolve() : reject(new Error(`${s.label} exited ${code}`))))
|
|
85
|
-
})
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function main() {
|
|
89
|
-
console.log(`=== beat-blind gate · BENCH=${BENCH} N=${N} K=${K} ${DRY ? '(DRY — plan only)' : ''} ===`)
|
|
90
|
-
if (DRY) {
|
|
91
|
-
console.log('plan (no run — zero sandbox/router contention):')
|
|
92
|
-
for (const s of steps) console.log(shellPreview(s))
|
|
93
|
-
console.log(
|
|
94
|
-
'\nbeat-blind iff diverse-selector@k > random@k at significant n.' +
|
|
95
|
-
'\nDIVERSE_BASE=<file> composes #145\'s GEPA-learned directive as the lens base (follow-on).',
|
|
96
|
-
)
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
for (const s of steps) await runStep(s)
|
|
100
|
-
console.log(
|
|
101
|
-
'\n=== read the gate ===\n' +
|
|
102
|
-
` random@k (control) — from ${RANDOM_CORPUS} replay\n` +
|
|
103
|
-
` selector@k (homogeneous) — same corpus, the pick (#143: −8.2pp on committed finsearch)\n` +
|
|
104
|
-
` diverse-selector@k — ${DIVERSE_CORPUS} replay: THE bet\n` +
|
|
105
|
-
' beat-blind iff diverse-selector@k > random@k, significant per the BH report above.',
|
|
106
|
-
)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
main().catch((err) => {
|
|
110
|
-
console.error(`diverse-gate: ${err instanceof Error ? err.message : String(err)}`)
|
|
111
|
-
process.exit(1)
|
|
112
|
-
})
|
package/src/hev-eval.mts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal HumanEval evaluator: given an INSTRUCTION (env) + a fixed task set, run the
|
|
3
|
-
* worker model on each task and print the pass rate + the per-task result. Used to
|
|
4
|
-
* measure a baseline instruction vs a proposer-supplied instruction on the SAME
|
|
5
|
-
* held-out set (the proposer proposes; this grades — kept separate for honesty).
|
|
6
|
-
*
|
|
7
|
-
* INSTRUCTION="..." IDS=HumanEval/55,... WORKER_MODEL=... ROUTER_BASE=... TANGLE_API_KEY=... \
|
|
8
|
-
* HUMANEVAL_GZ=/abs/HumanEval.jsonl.gz tsx src/hev-eval.mts
|
|
9
|
-
*/
|
|
10
|
-
import { readFileSync } from 'node:fs'
|
|
11
|
-
import { extractCode, loadHumanEval, runChecker, type HumanEvalTask } from './benchmarks/humaneval'
|
|
12
|
-
import { runBenchRouterTurn } from './router-turn'
|
|
13
|
-
|
|
14
|
-
const SEED_INSTRUCTION =
|
|
15
|
-
'Complete the following Python function. Output the COMPLETE function definition (signature, docstring optional, body) inside a single ```python code block. Include any imports the function needs. Do not write tests or example calls.'
|
|
16
|
-
|
|
17
|
-
async function complete(
|
|
18
|
-
base: string,
|
|
19
|
-
key: string,
|
|
20
|
-
model: string,
|
|
21
|
-
instruction: string,
|
|
22
|
-
prompt: string,
|
|
23
|
-
maxTokens: number,
|
|
24
|
-
): Promise<string> {
|
|
25
|
-
try {
|
|
26
|
-
const turn = await runBenchRouterTurn(
|
|
27
|
-
{
|
|
28
|
-
routerBaseUrl: base,
|
|
29
|
-
routerKey: key,
|
|
30
|
-
profile: {
|
|
31
|
-
name: 'humaneval-worker',
|
|
32
|
-
harness: 'cli-base',
|
|
33
|
-
model: {
|
|
34
|
-
provider: 'tangle-router',
|
|
35
|
-
default: model,
|
|
36
|
-
metadata: { temperature: 0.2, maxTokens },
|
|
37
|
-
},
|
|
38
|
-
prompt: { systemPrompt: instruction },
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
prompt,
|
|
42
|
-
)
|
|
43
|
-
return turn.finalText
|
|
44
|
-
} catch {
|
|
45
|
-
return ''
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function main(): Promise<void> {
|
|
50
|
-
const key = process.env.TANGLE_API_KEY
|
|
51
|
-
if (!key) throw new Error('TANGLE_API_KEY required')
|
|
52
|
-
const apiKey: string = key
|
|
53
|
-
const base = process.env.ROUTER_BASE ?? 'https://api.together.xyz/v1'
|
|
54
|
-
const model = process.env.WORKER_MODEL ?? 'meta-llama/Meta-Llama-3-8B-Instruct-Lite'
|
|
55
|
-
const instruction = process.env.INSTRUCTION_FILE
|
|
56
|
-
? readFileSync(process.env.INSTRUCTION_FILE, 'utf8')
|
|
57
|
-
: (process.env.INSTRUCTION ?? SEED_INSTRUCTION)
|
|
58
|
-
const maxTokens = Number(process.env.MAX_TOKENS ?? 2500)
|
|
59
|
-
const conc = Number(process.env.CONC ?? 6)
|
|
60
|
-
const offset = Number(process.env.OFFSET ?? 55)
|
|
61
|
-
const n = Number(process.env.N ?? 40)
|
|
62
|
-
const idsEnv = (process.env.IDS ?? '').split(',').map((s) => s.trim()).filter(Boolean)
|
|
63
|
-
|
|
64
|
-
const all = await loadHumanEval(164, 0)
|
|
65
|
-
const byId = new Map(all.map((t) => [t.taskId, t]))
|
|
66
|
-
const tasks: HumanEvalTask[] = idsEnv.length
|
|
67
|
-
? idsEnv.map((id) => byId.get(id)).filter((t): t is HumanEvalTask => !!t)
|
|
68
|
-
: all.slice(offset, offset + n)
|
|
69
|
-
|
|
70
|
-
console.log(`eval model=${model} n=${tasks.length} instr_len=${instruction.length}`)
|
|
71
|
-
let pass = 0
|
|
72
|
-
const fails: string[] = []
|
|
73
|
-
// simple concurrency pool
|
|
74
|
-
let i = 0
|
|
75
|
-
async function worker(): Promise<void> {
|
|
76
|
-
while (i < tasks.length) {
|
|
77
|
-
const t = tasks[i]
|
|
78
|
-
i += 1
|
|
79
|
-
if (!t) continue
|
|
80
|
-
const reply = await complete(
|
|
81
|
-
base,
|
|
82
|
-
apiKey,
|
|
83
|
-
model,
|
|
84
|
-
instruction,
|
|
85
|
-
`\`\`\`python\n${t.prompt}\`\`\``,
|
|
86
|
-
maxTokens,
|
|
87
|
-
)
|
|
88
|
-
const { pass: p } = await runChecker(t, extractCode(reply))
|
|
89
|
-
if (p === 1) pass += 1
|
|
90
|
-
else fails.push(t.taskId)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
await Promise.all(Array.from({ length: conc }, () => worker()))
|
|
94
|
-
console.log(`PASS ${pass}/${tasks.length} = ${((100 * pass) / tasks.length).toFixed(1)}%`)
|
|
95
|
-
console.log(`FAILED: ${fails.sort().join(', ')}`)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
main().catch((e) => {
|
|
99
|
-
console.error(e instanceof Error ? (e.stack ?? e.message) : String(e))
|
|
100
|
-
process.exit(1)
|
|
101
|
-
})
|
package/src/hev-improve.mts
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Official GEPA prompt optimization on HumanEval. The worker is a single chat
|
|
3
|
-
* completion and the judge is the deterministic Docker checker.
|
|
4
|
-
*
|
|
5
|
-
* WHY this exists: on SWE-bench the same GEPA loop was NULL because the grading test
|
|
6
|
-
* is withheld — the worker cannot verify, so prompt wording cannot move resolve.
|
|
7
|
-
* HumanEval hands the worker a well-specified function to complete and grades by
|
|
8
|
-
* running tests, so the instruction prompt DOES move pass-rate. This run measures
|
|
9
|
-
* whether self-improvement lifts a CHEAP model when the task is prompt-sensitive.
|
|
10
|
-
*
|
|
11
|
-
* Worker + reflect models call the zai coding endpoint directly (no tangle router,
|
|
12
|
-
* no WAF, no 503): TANGLE_API_KEY=$ZAI_API_KEY ROUTER_BASE=https://api.z.ai/api/coding/paas/v4
|
|
13
|
-
*/
|
|
14
|
-
import {
|
|
15
|
-
improve,
|
|
16
|
-
officialGepa,
|
|
17
|
-
type ReadonlyAgentProfile,
|
|
18
|
-
} from '@tangle-network/agent-runtime'
|
|
19
|
-
import {
|
|
20
|
-
canonicalCandidateDigest,
|
|
21
|
-
type AgentProfile,
|
|
22
|
-
agentProfileSchema,
|
|
23
|
-
} from '@tangle-network/agent-interface'
|
|
24
|
-
import type { DispatchContext, JudgeConfig, Scenario } from '@tangle-network/agent-eval/contract'
|
|
25
|
-
import { extractCode, loadHumanEval, runChecker, type HumanEvalTask } from './benchmarks/humaneval'
|
|
26
|
-
import {
|
|
27
|
-
assertCompleteCost,
|
|
28
|
-
officialOptimizerModel,
|
|
29
|
-
requiredTokenPricing,
|
|
30
|
-
} from './official-optimizer-config.mjs'
|
|
31
|
-
import { runBenchRouterTurn, withBenchProfile } from './router-turn'
|
|
32
|
-
|
|
33
|
-
// The SEED instruction GEPA evolves. Byte-identical to humaneval.ts basePrompt's
|
|
34
|
-
// solveInstruction so the baseline arm reproduces the plain-prompt denominator.
|
|
35
|
-
const SEED_INSTRUCTION =
|
|
36
|
-
'Complete the following Python function. Output the COMPLETE function definition (signature, docstring optional, body) inside a single ```python code block. Include any imports the function needs. Do not write tests or example calls.'
|
|
37
|
-
|
|
38
|
-
interface Completion {
|
|
39
|
-
text: string
|
|
40
|
-
tokIn: number
|
|
41
|
-
tokOut: number
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async function complete(
|
|
45
|
-
base: string,
|
|
46
|
-
key: string,
|
|
47
|
-
profile: AgentProfile,
|
|
48
|
-
prompt: string,
|
|
49
|
-
maxTokens: number,
|
|
50
|
-
): Promise<Completion> {
|
|
51
|
-
const result = await runBenchRouterTurn(
|
|
52
|
-
{
|
|
53
|
-
routerBaseUrl: base,
|
|
54
|
-
routerKey: key,
|
|
55
|
-
profile: withBenchProfile(profile, { temperature: 0.2, maxTokens }),
|
|
56
|
-
},
|
|
57
|
-
prompt,
|
|
58
|
-
)
|
|
59
|
-
return {
|
|
60
|
-
text: result.finalText,
|
|
61
|
-
tokIn: result.usage.input,
|
|
62
|
-
tokOut: result.usage.output,
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function main(): Promise<void> {
|
|
67
|
-
const key = process.env.TANGLE_API_KEY
|
|
68
|
-
if (!key) throw new Error('TANGLE_API_KEY required (worker + reflect completions)')
|
|
69
|
-
const base = process.env.ROUTER_BASE ?? 'https://api.z.ai/api/coding/paas/v4'
|
|
70
|
-
const workerModel = process.env.WORKER_MODEL ?? 'glm-4.5-air'
|
|
71
|
-
const reflectModel = process.env.REFLECT_MODEL ?? 'glm-4.6'
|
|
72
|
-
// The GEPA reflector may live on a DIFFERENT endpoint than the (cheap) worker —
|
|
73
|
-
// e.g. a small worker on Together + a strong optimizer on zai. Defaults to the
|
|
74
|
-
// worker endpoint when unset.
|
|
75
|
-
const reflectBase = process.env.REFLECT_BASE ?? base
|
|
76
|
-
const reflectKey = process.env.REFLECT_KEY ?? key
|
|
77
|
-
const trainN = Number(process.env.TRAIN_N ?? 12)
|
|
78
|
-
const selectionN = Number(process.env.SELECTION_N ?? 12)
|
|
79
|
-
const testN = Number(process.env.TEST_N ?? 12)
|
|
80
|
-
const offset = Number(process.env.OFFSET ?? 80)
|
|
81
|
-
const maxEvaluations = Number(process.env.MAX_EVALUATIONS ?? 24)
|
|
82
|
-
const maxProposerCostUsd = Number(process.env.MAX_PROPOSER_COST_USD ?? 5)
|
|
83
|
-
const workerMaxTokens = Number(process.env.MAX_TOKENS ?? 6000)
|
|
84
|
-
const reflectMaxTokens = Number(process.env.REFLECT_MAX_TOKENS ?? 8000)
|
|
85
|
-
const maxConcurrency = Number(process.env.MAX_CONCURRENCY ?? 4)
|
|
86
|
-
const runDir = process.env.RUN_DIR ?? '.runs/humaneval-official-gepa'
|
|
87
|
-
if (process.env.DRYRUN) {
|
|
88
|
-
console.log(
|
|
89
|
-
`DRYRUN: imports OK (improve=${typeof improve}, officialGepa=${typeof officialGepa})`,
|
|
90
|
-
)
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
const workerPricing = requiredTokenPricing(process.env, 'WORKER')
|
|
94
|
-
const optimizer = officialOptimizerModel({
|
|
95
|
-
env: process.env,
|
|
96
|
-
model: reflectModel,
|
|
97
|
-
baseUrl: reflectBase,
|
|
98
|
-
apiKey: reflectKey,
|
|
99
|
-
maxCostUsd: maxProposerCostUsd,
|
|
100
|
-
maxOutputTokensPerRequest: reflectMaxTokens,
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
// All three partitions are disjoint slices of the harder middle band.
|
|
104
|
-
const train = await loadHumanEval(trainN, offset)
|
|
105
|
-
const selection = await loadHumanEval(selectionN, offset + trainN)
|
|
106
|
-
const testCases = await loadHumanEval(testN, offset + trainN + selectionN)
|
|
107
|
-
const byId = new Map<string, HumanEvalTask>(
|
|
108
|
-
[...train, ...selection, ...testCases].map((t) => [t.taskId, t]),
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
console.log('=== HumanEval prompt optimization with official GEPA ===')
|
|
112
|
-
console.log(`worker=${workerModel} reflect=${reflectModel} base=${base}`)
|
|
113
|
-
console.log(`train=[${train.map((t) => t.taskId).join(', ')}]`)
|
|
114
|
-
console.log(`selection=[${selection.map((t) => t.taskId).join(', ')}]`)
|
|
115
|
-
console.log(`test=[${testCases.map((t) => t.taskId).join(', ')}]`)
|
|
116
|
-
console.log(`maxEvaluations=${maxEvaluations} maxProposerCostUsd=${maxProposerCostUsd} offset=${offset} maxTokens=${workerMaxTokens}`)
|
|
117
|
-
console.log(`runDir=${runDir}\n`)
|
|
118
|
-
|
|
119
|
-
const stats = { n: 0 }
|
|
120
|
-
const agent = async (candidate: ReadonlyAgentProfile, scenario: Scenario, ctx: DispatchContext): Promise<string | null> => {
|
|
121
|
-
const instr = candidate.prompt?.systemPrompt
|
|
122
|
-
if (instr === undefined) throw new Error('agent: candidate profile has no system prompt')
|
|
123
|
-
const t = byId.get(scenario.id)
|
|
124
|
-
if (!t) throw new Error(`agent: unknown scenario ${scenario.id}`)
|
|
125
|
-
const prompt = `\`\`\`python\n${t.prompt}\`\`\``
|
|
126
|
-
const executionProfile: AgentProfile = agentProfileSchema.parse({
|
|
127
|
-
...candidate,
|
|
128
|
-
name: candidate.name ?? 'humaneval-improvement-worker',
|
|
129
|
-
model: { ...candidate.model, provider: 'tangle-router', default: workerModel },
|
|
130
|
-
})
|
|
131
|
-
const t0 = Date.now()
|
|
132
|
-
const paid = await ctx.cost.runPaidCall({
|
|
133
|
-
channel: 'agent',
|
|
134
|
-
actor: 'humaneval-worker',
|
|
135
|
-
model: workerModel,
|
|
136
|
-
execute: () => complete(base, key, executionProfile, prompt, workerMaxTokens),
|
|
137
|
-
receipt: (result) => {
|
|
138
|
-
const usageUnknown = result.tokIn === 0 && result.tokOut === 0
|
|
139
|
-
return {
|
|
140
|
-
model: workerModel,
|
|
141
|
-
inputTokens: result.tokIn,
|
|
142
|
-
outputTokens: result.tokOut,
|
|
143
|
-
customTokenPricing: workerPricing,
|
|
144
|
-
...(usageUnknown ? { usageUnknown: true } : {}),
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
})
|
|
148
|
-
if (!paid.succeeded) throw paid.error
|
|
149
|
-
const r = paid.value
|
|
150
|
-
const hasText = r.text.trim().length > 0
|
|
151
|
-
stats.n += 1
|
|
152
|
-
const codeLen = extractCode(r.text).length
|
|
153
|
-
console.log(` [agent] ${scenario.id} instr=${instr.length}c code=${codeLen}b tok=in:${r.tokIn}/out:${r.tokOut} ${Math.round((Date.now() - t0) / 1000)}s`)
|
|
154
|
-
return hasText ? r.text : null
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const judge: JudgeConfig<string | null, Scenario> = {
|
|
158
|
-
name: 'humaneval-docker',
|
|
159
|
-
dimensions: [{ key: 'pass', description: 'the completed function passes its hidden unit tests (deterministic Docker checker)' }],
|
|
160
|
-
async score({ artifact, scenario }) {
|
|
161
|
-
const t = byId.get(scenario.id)
|
|
162
|
-
if (!t) throw new Error(`judge: unknown scenario ${scenario.id}`)
|
|
163
|
-
const code = extractCode(String(artifact ?? ''))
|
|
164
|
-
if (!code.trim()) {
|
|
165
|
-
console.log(` [judge] ${scenario.id} pass=0 (empty)`)
|
|
166
|
-
return { dimensions: { pass: 0 }, composite: 0, notes: 'empty' }
|
|
167
|
-
}
|
|
168
|
-
const { pass, detail } = await runChecker(t, code)
|
|
169
|
-
console.log(` [judge] ${scenario.id} pass=${pass}`)
|
|
170
|
-
if (pass === 1) return { dimensions: { pass }, composite: pass, notes: 'passed' }
|
|
171
|
-
// Trajectory-grounded failure note: the checker's traceback/assertion tail
|
|
172
|
-
// plus the model's own emitted code, so GEPA reflection sees WHAT failed and
|
|
173
|
-
// WHAT the model wrote — not just the word 'failed'. The candidate's full
|
|
174
|
-
// raw reply additionally reaches the proposer via the campaign breakdown's
|
|
175
|
-
// `emitted` field (carried automatically from the string artifact).
|
|
176
|
-
const traceback = (detail ?? 'checker produced no output (timeout or silent non-zero exit)').slice(-800)
|
|
177
|
-
const excerpt = code.slice(0, 700)
|
|
178
|
-
return {
|
|
179
|
-
dimensions: { pass },
|
|
180
|
-
composite: pass,
|
|
181
|
-
notes: `${traceback}\n--- emitted code (first 700 chars) ---\n${excerpt}`,
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const profile: AgentProfile = { name: 'hev-solver', prompt: { systemPrompt: SEED_INSTRUCTION } }
|
|
187
|
-
const scenario = (task: HumanEvalTask): Scenario => ({ id: task.taskId, kind: 'humaneval' })
|
|
188
|
-
|
|
189
|
-
const out = await improve(profile, {
|
|
190
|
-
surface: 'prompt',
|
|
191
|
-
executionRef: canonicalCandidateDigest({
|
|
192
|
-
callback: 'bench/hev-improve',
|
|
193
|
-
model: workerModel,
|
|
194
|
-
endpoint: new URL(base).origin,
|
|
195
|
-
maxTokens: workerMaxTokens,
|
|
196
|
-
checker: 'local-python',
|
|
197
|
-
}),
|
|
198
|
-
method: officialGepa<Scenario, string | null>({
|
|
199
|
-
objective:
|
|
200
|
-
'Improve the complete instruction for a small model that writes Python functions which pass hidden unit tests.',
|
|
201
|
-
background:
|
|
202
|
-
'Prefer behavioral strategies over wording changes. Address algorithm choice, edge cases, boundary values, type behavior, and self-checking. Return only the complete instruction.',
|
|
203
|
-
recipe: {
|
|
204
|
-
kind: 'engine',
|
|
205
|
-
run: {
|
|
206
|
-
engine: 'gepa',
|
|
207
|
-
maxEvaluations,
|
|
208
|
-
maxProposerCostUsd,
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
optimizer,
|
|
212
|
-
resume: 'if-compatible',
|
|
213
|
-
trustResumeState: true,
|
|
214
|
-
describeScenario: (item) => ({ prompt: byId.get(item.id)?.prompt ?? item.id }),
|
|
215
|
-
}),
|
|
216
|
-
trainScenarios: train.map(scenario),
|
|
217
|
-
selectionScenarios: selection.map(scenario),
|
|
218
|
-
testScenarios: testCases.map(scenario),
|
|
219
|
-
judges: [judge],
|
|
220
|
-
agent,
|
|
221
|
-
expectUsage: 'warn',
|
|
222
|
-
maxConcurrency,
|
|
223
|
-
reps: 1,
|
|
224
|
-
runDir,
|
|
225
|
-
optimizationRunOptions: {
|
|
226
|
-
expectUsage: 'warn',
|
|
227
|
-
maxConcurrency,
|
|
228
|
-
reps: 1,
|
|
229
|
-
},
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
assertCompleteCost('humaneval official GEPA run', out.cost)
|
|
233
|
-
console.log('\n=== RESULT ===')
|
|
234
|
-
console.log(`decision=${out.decision} lift=${out.lift} interval=[${out.liftInterval.low}, ${out.liftInterval.high}]`)
|
|
235
|
-
console.log(`baseline test pass-rate=${out.raw.best.baselineComposite}`)
|
|
236
|
-
console.log(`winner test pass-rate=${out.raw.best.winnerComposite}`)
|
|
237
|
-
console.log(`test scenarios=${JSON.stringify(out.raw.best.scenarioScores)}`)
|
|
238
|
-
console.log(`cost=${JSON.stringify(out.cost)}`)
|
|
239
|
-
console.log(`winner instruction:\n${String(out.candidate.value).slice(0, 2000)}`)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
main().catch((e) => {
|
|
243
|
-
console.error(e instanceof Error ? (e.stack ?? e.message) : String(e))
|
|
244
|
-
process.exit(1)
|
|
245
|
-
})
|