Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
305fea5
fix(bench): SWE-bench scores from repo STATE, not the model printed text
drewstone Jul 8, 2026
92a8c17
feat(improvement): raw-trace filesystem context for the code-surface …
drewstone Jul 8, 2026
6bf0e54
feat(improvement): wire profile stack through runtime primitives
drewstone Jul 8, 2026
8c78eaa
Merge remote-tracking branch 'origin/main' into feat/raw-trace-context
drewstone Jul 8, 2026
137822f
feat(swe): judge-free patch emitter + code-surface meta-harness entry…
Jul 9, 2026
c9dd6e5
feat(bench): honest-oracle structural-lever rig for HumanEval (best-o…
drewstone Jul 9, 2026
f305193
feat(bench): CodeT-style generated-assert oracle (TESTGEN) for the st…
drewstone Jul 9, 2026
1adcbd6
feat(bench): DIVERSE mode — per-slot strategy prefixes to attack the …
drewstone Jul 9, 2026
415a033
feat(bench): MBPP structural-lever rig — visible=shown assert (+TESTG…
drewstone Jul 9, 2026
9da237f
docs(design): structural-rollout integration map — CheckSource is the…
drewstone Jul 9, 2026
0a40753
feat(runtime): structuralRollout strategy — k-sample + visible-check …
drewstone Jul 9, 2026
e8f2687
chore(bench): track the prompt-evolution rigs behind the documented n…
drewstone Jul 9, 2026
8e5d3a9
feat(improvement): rollout-policy surface — improve() tunes structura…
drewstone Jul 9, 2026
f726b36
fix(runtime): carry the stopping content-only assistant reply in the …
drewstone Jul 9, 2026
dff5c07
fix(runtime): fuse instruction+task into one user message for traject…
drewstone Jul 9, 2026
7073681
feat(bench): structuralRollout runtime smoke — real model, real Human…
drewstone Jul 9, 2026
d694ffe
feat(bench): supervisor-arena — pre-registered supervisor showdown ri…
drewstone Jul 10, 2026
43fc7bd
fix(bench): arena client timeout env-configurable (LLM_TIMEOUT_MS) — …
drewstone Jul 10, 2026
3c2e92c
feat(bench): swe-repro-calibrate — Stage 0 reproduction-oracle calibr…
drewstone Jul 10, 2026
dd55cd3
fix(bench): repro calibrator — READ requests wrapped in a python fenc…
drewstone Jul 10, 2026
f7660ce
feat(bench): repro calibrator REPRO_EXEC=image substrate — run agains…
drewstone Jul 10, 2026
48af450
fix(bench): repro calibrator — 429-aware retry ladder (30s..240s, 6 a…
drewstone Jul 10, 2026
345497b
fix(bench): repro calibrator — collapse doubled fence openers before …
drewstone Jul 10, 2026
5102c43
feat(bench): repro calibrator — per-instance execution canary decides…
drewstone Jul 10, 2026
393ee50
feat(bench): Stage-1 structural pilot — k-candidate repro-argmax sele…
drewstone Jul 10, 2026
3b93916
feat(bench): live self-improvement campaign — improve() tunes structu…
drewstone Jul 12, 2026
6b55c23
feat(bench): MBPP live self-improvement campaign — the kill-flow foll…
drewstone Jul 12, 2026
978778e
fix(bench): MBPP campaign fails fast on a dead worker instead of an e…
drewstone Jul 12, 2026
8ae5054
feat(bench): swe-stream day 1 — two-arm (frozen vs learning) stream d…
drewstone Jul 12, 2026
bbf6933
fix(bench): swe-jail captures docker stderr + retries transient exit-…
drewstone Jul 12, 2026
7ad7fe2
fix(bench): sampling temp reads SAMPLE_TEMP, not TEMP — Node os.tmpdi…
drewstone Jul 12, 2026
64baaea
feat(bench): swe-stream — glm-4.5-air worker + symmetric thinking budget
drewstone Jul 13, 2026
62b3020
feat(bench): swe-stream — supervisor-steered repair (arm L, verified-…
drewstone Jul 13, 2026
897b206
fix(bench): author the shared repro instrument on REPRO_MODEL (strong…
drewstone Jul 13, 2026
f9ace85
fix(bench): supervisor fires on apply-failed too, not just wrong-fix …
drewstone Jul 13, 2026
21fcfc8
fix(bench): supervisor also fires on empty-diff (sev 4) — worker prod…
drewstone Jul 13, 2026
6feed84
feat(bench): stream-observe — autogenerate a run topology+telemetry d…
drewstone Jul 13, 2026
bb98288
fix(bench): stream-observe diagram — time-ordered execution sequence …
drewstone Jul 13, 2026
16f98ae
feat(lifecycle): sweEvalRunner closes the self-improve loop over the …
drewstone Jul 13, 2026
7132f9a
feat(improvement): senior scientific-method optimizer prompt + driver…
drewstone Jul 13, 2026
24cfced
feat(runtime): same-host stdio MCP sandbox client + wire buildable MC…
drewstone Jul 13, 2026
aee7d69
feat(improvement): typed trace ingestion + spans->OTLP so trace propo…
drewstone Jul 13, 2026
13cb802
feat(lifecycle): memory as a first-class profile surface, served live…
drewstone Jul 13, 2026
32a3116
feat(lifecycle): external-MCP connection surface + key provisioning f…
drewstone Jul 13, 2026
fb636d7
fix(bench): canonical self-improve invocation resolves local src
drewstone Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bench/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.venv/
.venv
.venv-*/
node_modules/
*.log
Expand Down
6 changes: 4 additions & 2 deletions bench/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@tangle-network/agent-bench",
"version": "0.1.0",
"type": "module",
"description": "The unified benchmark suite for agent-runtime agents: 31 adapters (commit0, enterpriseops-gym, ragbench, crag, nomiracl, open-rag-bench, t2-ragbench, tau3-banking, bfcl, finresearchbench, ) behind one resolveAdapter registry, each with a real judge or fail-loud unsupported scorer. Score any profile/skill/prompt change against them. Map: bench/HARNESS.md.",
"description": "The unified benchmark suite for agent-runtime agents: 31 adapters (commit0, enterpriseops-gym, ragbench, crag, nomiracl, open-rag-bench, t2-ragbench, tau3-banking, bfcl, finresearchbench, \u2026) behind one resolveAdapter registry, each with a real judge or fail-loud unsupported scorer. Score any profile/skill/prompt change against them. Map: bench/HARNESS.md.",
"main": "src/index.ts",
"types": "src/index.ts",
"exports": {
Expand All @@ -15,10 +15,12 @@
"gate-cli": "tsx src/gate-cli.mts",
"run-benchmarks": "tsx src/run-benchmarks-cli.mts",
"gate-report": "tsx src/corpus-report.mts corpus/finsearch.jsonl",
"terminal-compare": "tsx src/terminal-compare.ts"
"terminal-compare": "tsx src/terminal-compare.ts",
"self-improve": "tsx src/self-improve-swe.mts"
},
"dependencies": {
"@tangle-network/agent-eval": "^0.106.3",
"@tangle-network/agent-knowledge": "^1.11.1",
"@tangle-network/agent-runtime": "^0.89.0",
"@tangle-network/sandbox": "^0.9.7"
},
Expand Down
57 changes: 54 additions & 3 deletions bench/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions bench/src/benchmarks/humaneval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/

import { execFile } from 'node:child_process'
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { gunzipSync } from 'node:zlib'
Expand All @@ -41,9 +41,17 @@ export interface HumanEvalTask {
* selects a deeper slice (the later tasks are harder) so the worker has a
* correctable middle band rather than a saturated easy prefix. */
export async function loadHumanEval(limit: number, offset = 0): Promise<HumanEvalTask[]> {
const res = await fetch(humanevalUrl)
if (!res.ok) throw new Error(`HumanEval fetch HTTP ${res.status}: ${humanevalUrl}`)
const gz = Buffer.from(await res.arrayBuffer())
// Prefer a locally-cached .jsonl.gz (HUMANEVAL_GZ) — the GitHub raw URL rate-limits
// (429) under repeated runs. Fall back to the network fetch when unset.
const localGz = process.env.HUMANEVAL_GZ
let gz: Buffer
if (localGz) {
gz = readFileSync(localGz)
} else {
const res = await fetch(humanevalUrl)
if (!res.ok) throw new Error(`HumanEval fetch HTTP ${res.status}: ${humanevalUrl}`)
gz = Buffer.from(await res.arrayBuffer())
}
const text = gunzipSync(gz).toString('utf8')
const tasks: HumanEvalTask[] = []
for (const line of text.split('\n')) {
Expand Down
40 changes: 35 additions & 5 deletions bench/src/benchmarks/swe-bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,38 @@ export const swePatchOutput: OutputAdapter<string> = {
}

const DATASET = 'princeton-nlp/SWE-bench_Verified'
const TEST_FILE_EXCLUDES = [
"':(exclude,glob)**/tests/**'",
"':(exclude,glob)**/test/**'",
"':(exclude,glob)test_*.py'",
"':(exclude,glob)**/test_*.py'",
"':(exclude,glob)*_test.py'",
"':(exclude,glob)**/*_test.py'",
"':(exclude,glob)conftest.py'",
"':(exclude,glob)**/conftest.py'",
].join(' ')

interface SweReport {
resolved_instances?: number
resolved_ids?: string[]
}

function shellQuote(value: string): string {
return `'${value.replace(/'/g, `'\\''`)}'`
}

function sweMetadata(task: BenchTask): { repo: string; base: string } {
const repo = String(task.metadata?.repo ?? '')
const base = String(task.metadata?.base_commit ?? '')
if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repo)) {
throw new Error(`swe-bench: invalid repo metadata for ${task.id}: ${repo}`)
}
if (!/^[0-9a-f]{7,40}$/i.test(base)) {
throw new Error(`swe-bench: invalid base_commit metadata for ${task.id}: ${base}`)
}
return { repo, base }
}

export function createSweBenchAdapter(): BenchmarkAdapter {
return {
name: 'swe-bench-verified',
Expand All @@ -79,15 +105,14 @@ export function createSweBenchAdapter(): BenchmarkAdapter {
// agent only edits (the harness owns the checkout — a stochastic model can't be
// trusted to clone to an exact path). `--quiet` keeps the exec output small.
boxSetup(task) {
const repo = String(task.metadata?.repo ?? '')
const base = String(task.metadata?.base_commit ?? '')
const { repo, base } = sweMetadata(task)
return {
command: `rm -rf ${SWE_REPO_DIR} && git clone --quiet https://github.com/${repo} ${SWE_REPO_DIR} && git -C ${SWE_REPO_DIR} checkout --quiet ${base}`,
command: `rm -rf ${shellQuote(SWE_REPO_DIR)} && git clone --quiet ${shellQuote(`https://github.com/${repo}`)} ${shellQuote(SWE_REPO_DIR)} && git -C ${shellQuote(SWE_REPO_DIR)} checkout --quiet ${shellQuote(base)}`,
}
},
boxExtract() {
return {
command: `git -C ${SWE_REPO_DIR} add -A && git -C ${SWE_REPO_DIR} diff --cached -- . ':(exclude)*/test*'`,
command: `git -C ${shellQuote(SWE_REPO_DIR)} add -A && git -C ${shellQuote(SWE_REPO_DIR)} diff --cached -- . ${TEST_FILE_EXCLUDES}`,
}
},

Expand Down Expand Up @@ -175,7 +200,12 @@ print(json.dumps(out))
'--run_id', runId,
'--instance_ids', task.id,
'--max_workers', '1',
'--cache_level', 'env',
// 'env' (the default) REMOVES the per-instance image after each run — measured: it
// silently pruned the 23-image fingerprint cache between sessions, and it forces a
// re-pull between back-to-back judges of the same instance (the stream judges F then L).
// Drivers that manage image rotation themselves set SWEBENCH_CACHE_LEVEL=instance and
// delete images explicitly.
'--cache_level', process.env.SWEBENCH_CACHE_LEVEL ?? 'env',
],
async parseReport(dir) {
// Report file: agent-runtime-bench.<run_id>.json
Expand Down
69 changes: 69 additions & 0 deletions bench/src/hev-eval.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Minimal HumanEval evaluator: given an INSTRUCTION (env) + a fixed task set, run the
* worker model on each task and print the pass rate + the per-task result. Used to
* measure a baseline instruction vs a proposer-supplied instruction on the SAME
* held-out set (the proposer proposes; this grades — kept separate for honesty).
*
* INSTRUCTION="..." IDS=HumanEval/55,... WORKER_MODEL=... ROUTER_BASE=... TANGLE_API_KEY=... \
* HUMANEVAL_GZ=/abs/HumanEval.jsonl.gz tsx src/hev-eval.mts
*/
import { readFileSync } from 'node:fs'
import { extractCode, loadHumanEval, runChecker, type HumanEvalTask } from './benchmarks/humaneval'

const SEED_INSTRUCTION =
'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.'

async function complete(base: string, key: string, model: string, prompt: string, maxTokens: number): Promise<string> {
const res = await fetch(`${base}/chat/completions`, {
method: 'POST',
headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ model, max_tokens: maxTokens, temperature: 0.2, messages: [{ role: 'user', content: prompt }] }),
})
if (!res.ok) return ''
const d = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> }
return d.choices?.[0]?.message?.content ?? ''
}

async function main(): Promise<void> {
const key = process.env.TANGLE_API_KEY
if (!key) throw new Error('TANGLE_API_KEY required')
const base = process.env.ROUTER_BASE ?? 'https://api.together.xyz/v1'
const model = process.env.WORKER_MODEL ?? 'meta-llama/Meta-Llama-3-8B-Instruct-Lite'
const instruction = process.env.INSTRUCTION_FILE
? readFileSync(process.env.INSTRUCTION_FILE, 'utf8')
: (process.env.INSTRUCTION ?? SEED_INSTRUCTION)
const maxTokens = Number(process.env.MAX_TOKENS ?? 2500)
const conc = Number(process.env.CONC ?? 6)
const offset = Number(process.env.OFFSET ?? 55)
const n = Number(process.env.N ?? 40)
const idsEnv = (process.env.IDS ?? '').split(',').map((s) => s.trim()).filter(Boolean)

const all = await loadHumanEval(164, 0)
const byId = new Map(all.map((t) => [t.taskId, t]))
const tasks: HumanEvalTask[] = idsEnv.length
? idsEnv.map((id) => byId.get(id)).filter((t): t is HumanEvalTask => !!t)
: all.slice(offset, offset + n)

console.log(`eval model=${model} n=${tasks.length} instr_len=${instruction.length}`)
let pass = 0
const fails: string[] = []
// simple concurrency pool
let i = 0
async function worker(): Promise<void> {
while (i < tasks.length) {
const t = tasks[i++]
const reply = await complete(base, key, model, `${instruction}\n\n\`\`\`python\n${t.prompt}\`\`\``, maxTokens)
const { pass: p } = await runChecker(t, extractCode(reply))
if (p === 1) pass += 1
else fails.push(t.taskId)
}
}
await Promise.all(Array.from({ length: conc }, () => worker()))
console.log(`PASS ${pass}/${tasks.length} = ${((100 * pass) / tasks.length).toFixed(1)}%`)
console.log(`FAILED: ${fails.sort().join(', ')}`)
}

main().catch((e) => {
console.error(e instanceof Error ? (e.stack ?? e.message) : String(e))
process.exit(1)
})
Loading