@tangle-network/agent-bench 0.3.8 → 0.4.1
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 +13 -0
- package/README.md +7 -0
- package/dist/adapters.js +23 -23
- package/dist/benchmarks/_harness.d.ts +4 -1
- package/dist/benchmarks/_harness.js +3 -1
- package/dist/benchmarks/aec-bench.js +2 -2
- package/dist/benchmarks/agentbench.js +2 -2
- package/dist/benchmarks/appworld.js +2 -2
- package/dist/benchmarks/bfcl.js +2 -2
- package/dist/benchmarks/commit0.js +2 -2
- package/dist/benchmarks/crag.js +2 -2
- package/dist/benchmarks/dabstep.js +2 -2
- package/dist/benchmarks/enterpriseops-gym.js +2 -2
- package/dist/benchmarks/finresearchbench.js +2 -2
- package/dist/benchmarks/nomiracl.js +2 -2
- package/dist/benchmarks/open-rag-bench.js +2 -2
- package/dist/benchmarks/programbench.js +2 -2
- package/dist/benchmarks/ragbench.js +2 -2
- package/dist/benchmarks/swe-bench.js +2 -2
- package/dist/benchmarks/t2-ragbench.js +2 -2
- package/dist/benchmarks/tau-bench-shared.js +2 -2
- package/dist/benchmarks/tau2-bench.js +3 -3
- package/dist/benchmarks/tau3-banking.js +3 -3
- package/dist/benchmarks/terminal-bench.js +2 -2
- package/dist/benchmarks/toollm.js +2 -2
- package/dist/benchmarks/webarena-verified.js +2 -2
- package/dist/{chunk-YSMEKBTD.js → chunk-5FEQDSCT.js} +2 -2
- package/dist/{chunk-PB64GYIG.js → chunk-67ACKDCX.js} +2 -2
- package/dist/{chunk-NQG5XDSB.js → chunk-7FKBWOQT.js} +2 -2
- package/dist/{chunk-K3BQGZCT.js → chunk-BEN6IF2X.js} +2 -2
- package/dist/{chunk-SHYIRB7I.js → chunk-BZY5QARD.js} +2 -2
- package/dist/{chunk-KP5KD6EN.js → chunk-CLIKAXKH.js} +2 -2
- package/dist/{chunk-XKEFIFIC.js → chunk-CWIOBFSP.js} +2 -2
- package/dist/{chunk-IA2FBTWC.js → chunk-CXDUTWQE.js} +2 -2
- package/dist/{chunk-RH5F53JT.js → chunk-DWALFME7.js} +2 -2
- package/dist/{chunk-V7AEBY6U.js → chunk-EEOC6QPJ.js} +21 -21
- package/dist/{chunk-WSKWVEQB.js → chunk-EIETHPD5.js} +7 -3
- package/dist/chunk-EIETHPD5.js.map +1 -0
- package/dist/{chunk-SHM6MRRF.js → chunk-GC2EPS6L.js} +2 -2
- package/dist/{chunk-IZ5M6OAC.js → chunk-GCHL6XPM.js} +2 -2
- package/dist/{chunk-IFVINJ4B.js → chunk-HQ5HCCKF.js} +2 -2
- package/dist/{chunk-7GRVHU22.js → chunk-HVW25KSX.js} +2 -2
- package/dist/{chunk-3U5TXJZS.js → chunk-J6BU3NTM.js} +2 -2
- package/dist/{chunk-XYA4XSNU.js → chunk-JSQOUKXS.js} +4 -3
- package/dist/chunk-JSQOUKXS.js.map +1 -0
- package/dist/{chunk-SVR2LKYI.js → chunk-NRMGT25X.js} +2 -2
- package/dist/{chunk-MQMRLGOG.js → chunk-QZZEAHWJ.js} +2 -2
- package/dist/{chunk-RCYQEFNX.js → chunk-WG7TM7UV.js} +3 -3
- package/dist/{chunk-HWST3SED.js → chunk-XXFF3RRD.js} +2 -2
- package/dist/{chunk-SFLA7OH3.js → chunk-ZFNOM7WR.js} +3 -3
- package/dist/{chunk-Z4TZ76N7.js → chunk-ZNCCYTFG.js} +2 -2
- package/dist/index.js +23 -23
- package/package.json +4 -4
- package/pier_agents/candidate_contract.py +238 -24
- package/pier_agents/tangle_candidate.py +75 -5
- package/scripts/trata-hedge/README.md +6 -5
- package/scripts/verify-packed-consumer.mjs +65 -1
- package/scripts/verify-pier-agent.mts +6 -4
- package/src/benchmarks/_harness.test.mts +16 -1
- package/src/benchmarks/_harness.ts +9 -2
- package/src/benchmarks/terminal-bench.ts +2 -1
- package/src/gate.ts +1 -1
- package/src/hev-eval.mts +5 -2
- package/src/hev-improve.mts +118 -73
- package/src/official-optimizer-config.mts +89 -0
- package/src/official-optimizer-config.test.mts +88 -0
- package/src/profiles.ts +2 -2
- package/src/rollout-ledger/backfill-swe-arena.test.mts +28 -24
- package/src/smoke-structural-rollout.mts +15 -9
- package/src/swe-arena/activation.mts +1 -4
- package/src/swe-arena/activation.test.mts +10 -13
- package/src/swe-arena/gepa-seat.mts +425 -131
- package/src/swe-arena/gepa-seat.test.mts +524 -100
- package/src/swe-arena/implementation-ref.test.mts +64 -0
- package/src/swe-arena/implementation-ref.ts +62 -0
- package/src/swe-arena/outer-loop.mts +103 -76
- package/src/swe-arena/proposer-fanout.mts +51 -36
- package/src/swe-arena/proposer-fanout.test.mts +0 -1
- package/src/swe-arena/proposer-provenance.mts +11 -16
- package/src/swe-arena/scratch-worktree.test.mts +55 -0
- package/src/swe-arena/scratch-worktree.ts +34 -0
- package/src/swe-code-improve.mts +24 -25
- package/src/swe-improve.mts +129 -96
- package/src/swe-local-proof.mts +6 -1
- package/src/swe-stream.mts +4 -2
- package/src/tb-container-executor.test.mts +30 -6
- package/src/tb-supervisor-sidecar.mts +2 -1
- package/src/trata-gepa.mts +182 -245
- package/dist/chunk-WSKWVEQB.js.map +0 -1
- package/dist/chunk-XYA4XSNU.js.map +0 -1
- package/src/live-improve-campaign-mbpp.mts +0 -641
- package/src/live-improve-campaign.mts +0 -500
- package/src/swe-arena/lineage-record.mts +0 -164
- package/src/swe-arena/lineage-record.test.mts +0 -115
- /package/dist/{chunk-YSMEKBTD.js.map → chunk-5FEQDSCT.js.map} +0 -0
- /package/dist/{chunk-PB64GYIG.js.map → chunk-67ACKDCX.js.map} +0 -0
- /package/dist/{chunk-NQG5XDSB.js.map → chunk-7FKBWOQT.js.map} +0 -0
- /package/dist/{chunk-K3BQGZCT.js.map → chunk-BEN6IF2X.js.map} +0 -0
- /package/dist/{chunk-SHYIRB7I.js.map → chunk-BZY5QARD.js.map} +0 -0
- /package/dist/{chunk-KP5KD6EN.js.map → chunk-CLIKAXKH.js.map} +0 -0
- /package/dist/{chunk-XKEFIFIC.js.map → chunk-CWIOBFSP.js.map} +0 -0
- /package/dist/{chunk-IA2FBTWC.js.map → chunk-CXDUTWQE.js.map} +0 -0
- /package/dist/{chunk-RH5F53JT.js.map → chunk-DWALFME7.js.map} +0 -0
- /package/dist/{chunk-V7AEBY6U.js.map → chunk-EEOC6QPJ.js.map} +0 -0
- /package/dist/{chunk-SHM6MRRF.js.map → chunk-GC2EPS6L.js.map} +0 -0
- /package/dist/{chunk-IZ5M6OAC.js.map → chunk-GCHL6XPM.js.map} +0 -0
- /package/dist/{chunk-IFVINJ4B.js.map → chunk-HQ5HCCKF.js.map} +0 -0
- /package/dist/{chunk-7GRVHU22.js.map → chunk-HVW25KSX.js.map} +0 -0
- /package/dist/{chunk-3U5TXJZS.js.map → chunk-J6BU3NTM.js.map} +0 -0
- /package/dist/{chunk-SVR2LKYI.js.map → chunk-NRMGT25X.js.map} +0 -0
- /package/dist/{chunk-MQMRLGOG.js.map → chunk-QZZEAHWJ.js.map} +0 -0
- /package/dist/{chunk-RCYQEFNX.js.map → chunk-WG7TM7UV.js.map} +0 -0
- /package/dist/{chunk-HWST3SED.js.map → chunk-XXFF3RRD.js.map} +0 -0
- /package/dist/{chunk-SFLA7OH3.js.map → chunk-ZFNOM7WR.js.map} +0 -0
- /package/dist/{chunk-Z4TZ76N7.js.map → chunk-ZNCCYTFG.js.map} +0 -0
|
@@ -27,21 +27,19 @@ import { join } from 'node:path'
|
|
|
27
27
|
import {
|
|
28
28
|
DEFAULT_GEPA_PYTHON,
|
|
29
29
|
isGepaSeat,
|
|
30
|
-
loadGepaMethodFactory,
|
|
31
30
|
probeGepaRuntime,
|
|
32
|
-
type CampaignModuleImport,
|
|
33
31
|
} from './gepa-seat.mts'
|
|
34
32
|
import { run } from './proc.ts'
|
|
35
33
|
import type { ProposerSpec } from './proposer-fanout.mts'
|
|
36
34
|
|
|
37
35
|
export interface ProposerModelProvenance {
|
|
38
36
|
name: string
|
|
39
|
-
/** Absent on
|
|
37
|
+
/** Absent on an engine seat (see `engine`). */
|
|
40
38
|
harness: ProposerSpec['harness']
|
|
41
39
|
/** Explicit model pin from the spec (threaded as `-m`), or null when the
|
|
42
40
|
* seat runs the CLI's own resolved default. */
|
|
43
41
|
pinnedModel: string | null
|
|
44
|
-
/** `<harness> --version` stdout (trimmed). For a
|
|
42
|
+
/** `<harness> --version` stdout (trimmed). For a GEPA seat this is
|
|
45
43
|
* the bridge python's `--version` output — the runtime that authors. */
|
|
46
44
|
harnessVersion: string
|
|
47
45
|
/** claude seats only: the settings default model the logged-in CLI resolves
|
|
@@ -51,13 +49,13 @@ export interface ProposerModelProvenance {
|
|
|
51
49
|
/** codex seats only: `codex login status` stdout (trimmed). */
|
|
52
50
|
authStatus: string | null
|
|
53
51
|
merge: boolean
|
|
54
|
-
/**
|
|
52
|
+
/** GEPA seat: the engine name from the spec. */
|
|
55
53
|
engine?: 'gepa' | 'omni'
|
|
56
|
-
/**
|
|
54
|
+
/** GEPA seat: the one change-space file GEPA optimizes. */
|
|
57
55
|
surface?: string
|
|
58
|
-
/**
|
|
56
|
+
/** GEPA seat: installed GEPA version ('source' for a source pin). */
|
|
59
57
|
gepaVersion?: string
|
|
60
|
-
/**
|
|
58
|
+
/** GEPA seat: the Python bridge module the seat runs. */
|
|
61
59
|
bridge?: string
|
|
62
60
|
}
|
|
63
61
|
|
|
@@ -92,17 +90,16 @@ export function claudeSettingsModel(
|
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
/** Capture per-proposer model provenance. Throws when any configured harness
|
|
95
|
-
* binary is missing/broken, when a codex seat is not logged in, or
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
93
|
+
* binary is missing/broken, when a codex seat is not logged in, or when
|
|
94
|
+
* a GEPA seat's Python bridge or engine cannot import
|
|
95
|
+
* (`probeGepaRuntime` carries the exact install instructions). A dead seat
|
|
96
|
+
* fails the launch at t=0, never a mid-run candidate slot. The TypeScript
|
|
97
|
+
* adapter is a pinned package dependency and therefore checked at install. */
|
|
100
98
|
export async function captureProposerProvenance(
|
|
101
99
|
proposers: ProposerSpec[],
|
|
102
100
|
deps: {
|
|
103
101
|
exec?: VersionExec
|
|
104
102
|
readSettingsModel?: () => string | null
|
|
105
|
-
importCampaign?: CampaignModuleImport
|
|
106
103
|
} = {},
|
|
107
104
|
): Promise<ProvenanceCaptureRecord> {
|
|
108
105
|
const exec = deps.exec ?? defaultExec
|
|
@@ -112,8 +109,6 @@ export async function captureProposerProvenance(
|
|
|
112
109
|
const gepaBySeat = new Map<string, { pythonVersion: string; gepaVersion: string }>()
|
|
113
110
|
const gepaSeats = proposers.filter(isGepaSeat)
|
|
114
111
|
if (gepaSeats.length > 0) {
|
|
115
|
-
// Node side first: the adapter export (fails loud with upgrade hint).
|
|
116
|
-
await loadGepaMethodFactory(...(deps.importCampaign ? [deps.importCampaign] : []))
|
|
117
112
|
for (const seat of gepaSeats) {
|
|
118
113
|
gepaBySeat.set(seat.name, await probeGepaRuntime(seat.python ?? DEFAULT_GEPA_PYTHON, exec, seat.name))
|
|
119
114
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
5
|
+
import { runOk } from './proc.ts'
|
|
6
|
+
import {
|
|
7
|
+
createDetachedWorktree,
|
|
8
|
+
pruneDetachedWorktrees,
|
|
9
|
+
removeDetachedWorktree,
|
|
10
|
+
} from './scratch-worktree.ts'
|
|
11
|
+
|
|
12
|
+
describe('scratch worktrees', () => {
|
|
13
|
+
const roots: string[] = []
|
|
14
|
+
|
|
15
|
+
afterEach(async () => {
|
|
16
|
+
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })))
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('creates and removes a parallel batch without pruning live metadata', async () => {
|
|
20
|
+
const repository = await mkdtemp(join(tmpdir(), 'scratch-worktree-repo-'))
|
|
21
|
+
const output = await mkdtemp(join(tmpdir(), 'scratch-worktree-out-'))
|
|
22
|
+
roots.push(repository, output)
|
|
23
|
+
await runOk('git', ['init', '-q', '-b', 'main', repository])
|
|
24
|
+
await runOk('git', ['-C', repository, 'config', 'user.email', 'test@example.com'])
|
|
25
|
+
await runOk('git', ['-C', repository, 'config', 'user.name', 'Test'])
|
|
26
|
+
await writeFile(join(repository, 'seed.txt'), 'seed\n')
|
|
27
|
+
await runOk('git', ['-C', repository, 'add', 'seed.txt'])
|
|
28
|
+
await runOk('git', ['-C', repository, 'commit', '-q', '-m', 'seed'])
|
|
29
|
+
const commit = (
|
|
30
|
+
await runOk('git', ['-C', repository, 'rev-parse', 'HEAD'])
|
|
31
|
+
).stdout.trim()
|
|
32
|
+
for (let batch = 0; batch < 5; batch += 1) {
|
|
33
|
+
const worktrees = Array.from(
|
|
34
|
+
{ length: 8 },
|
|
35
|
+
(_, index) => join(output, `batch-${batch}-candidate-${index}`),
|
|
36
|
+
)
|
|
37
|
+
await pruneDetachedWorktrees(repository)
|
|
38
|
+
await Promise.all(
|
|
39
|
+
worktrees.map((worktree) => createDetachedWorktree(repository, commit, worktree)),
|
|
40
|
+
)
|
|
41
|
+
expect(
|
|
42
|
+
await Promise.all(
|
|
43
|
+
worktrees.map((worktree) => readFile(join(worktree, 'seed.txt'), 'utf8')),
|
|
44
|
+
),
|
|
45
|
+
).toEqual(Array.from({ length: 8 }, () => 'seed\n'))
|
|
46
|
+
await Promise.all(
|
|
47
|
+
worktrees.map((worktree) => removeDetachedWorktree(repository, worktree)),
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
const listed = (
|
|
51
|
+
await runOk('git', ['-C', repository, 'worktree', 'list', '--porcelain'])
|
|
52
|
+
).stdout
|
|
53
|
+
expect(listed.match(/^worktree /gmu)).toHaveLength(1)
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { rm } from 'node:fs/promises'
|
|
2
|
+
import { run, runOk } from './proc'
|
|
3
|
+
|
|
4
|
+
export async function createDetachedWorktree(
|
|
5
|
+
repository: string,
|
|
6
|
+
commit: string,
|
|
7
|
+
destination: string,
|
|
8
|
+
): Promise<void> {
|
|
9
|
+
await run('git', ['-C', repository, 'worktree', 'remove', '--force', '--', destination])
|
|
10
|
+
await rm(destination, { recursive: true, force: true })
|
|
11
|
+
await runOk('git', ['-C', repository, 'worktree', 'add', '--detach', destination, commit])
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function pruneDetachedWorktrees(repository: string): Promise<void> {
|
|
15
|
+
await runOk('git', ['-C', repository, 'worktree', 'prune'])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function removeDetachedWorktree(
|
|
19
|
+
repository: string,
|
|
20
|
+
destination: string,
|
|
21
|
+
): Promise<void> {
|
|
22
|
+
const result = await run('git', [
|
|
23
|
+
'-C',
|
|
24
|
+
repository,
|
|
25
|
+
'worktree',
|
|
26
|
+
'remove',
|
|
27
|
+
'--force',
|
|
28
|
+
'--',
|
|
29
|
+
destination,
|
|
30
|
+
])
|
|
31
|
+
if (result.code !== 0) {
|
|
32
|
+
await rm(destination, { recursive: true, force: true })
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/swe-code-improve.mts
CHANGED
|
@@ -33,7 +33,6 @@ import { spawn, spawnSync } from 'node:child_process'
|
|
|
33
33
|
import { existsSync, mkdirSync, symlinkSync } from 'node:fs'
|
|
34
34
|
import { join } from 'node:path'
|
|
35
35
|
import { improve, agenticGenerator } from '@tangle-network/agent-runtime'
|
|
36
|
-
import type { AgentProfile } from '@tangle-network/agent-interface'
|
|
37
36
|
import type { DispatchContext, JudgeConfig, Scenario } from '@tangle-network/agent-eval/contract'
|
|
38
37
|
import { createSweBenchAdapter } from './benchmarks/swe-bench'
|
|
39
38
|
import type { BenchTask } from './benchmarks/types'
|
|
@@ -108,7 +107,6 @@ async function main(): Promise<void> {
|
|
|
108
107
|
if (!routerKey) throw new Error('TANGLE_API_KEY required (worker calls the router)')
|
|
109
108
|
const routerBaseUrl = process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1'
|
|
110
109
|
const workerModel = process.env.WORKER_MODEL ?? 'glm-4.6'
|
|
111
|
-
const reflectModel = process.env.REFLECT_MODEL ?? 'glm-4.6'
|
|
112
110
|
const trainIds = (process.env.TRAIN_IDS ?? 'psf__requests-2931,pallets__flask-5014').split(',').map((s) => s.trim()).filter(Boolean)
|
|
113
111
|
const holdoutIds = (process.env.HOLDOUT_IDS ?? 'psf__requests-1142,psf__requests-1921').split(',').map((s) => s.trim()).filter(Boolean)
|
|
114
112
|
const generations = Number(process.env.GENERATIONS ?? 1)
|
|
@@ -127,7 +125,7 @@ async function main(): Promise<void> {
|
|
|
127
125
|
const allIds = [...new Set([...trainIds, ...holdoutIds])]
|
|
128
126
|
|
|
129
127
|
console.log('=== META-HARNESS on the SWE scaffold — improve(surface:code) ===')
|
|
130
|
-
console.log(`worker=${workerModel}
|
|
128
|
+
console.log(`worker=${workerModel} router=${routerBaseUrl} runTool=${enableRun}`)
|
|
131
129
|
console.log(`train=[${trainIds.join(', ')}] holdout=[${holdoutIds.join(', ')}]`)
|
|
132
130
|
console.log(`generations=${generations} population=${population} innerTurns=${innerTurns} maxTokens=${maxTokens}`)
|
|
133
131
|
console.log(`repoRoot=${REPO_ROOT} baseRef=${baseRef}`)
|
|
@@ -156,15 +154,25 @@ async function main(): Promise<void> {
|
|
|
156
154
|
const worktreeRef = isCode ? String((surface as { worktreeRef?: string }).worktreeRef ?? '') : ''
|
|
157
155
|
const rootDir = isCode && worktreeRef && existsSync(worktreeRef) ? worktreeRef : SWE_MAIN_ROOT
|
|
158
156
|
const t0 = Date.now()
|
|
159
|
-
const
|
|
157
|
+
const paid = await ctx.cost.runPaidCall({
|
|
158
|
+
channel: 'agent',
|
|
159
|
+
actor: 'swe-scaffold-worker',
|
|
160
|
+
model: workerModel,
|
|
161
|
+
execute: () => runEmit(rootDir, scenario.id, workerEnv, emitTimeoutMs),
|
|
162
|
+
receipt: (result) => {
|
|
163
|
+
const usageUnknown = result.tokIn === 0 && result.tokOut === 0
|
|
164
|
+
return {
|
|
165
|
+
model: workerModel,
|
|
166
|
+
inputTokens: result.tokIn,
|
|
167
|
+
outputTokens: result.tokOut,
|
|
168
|
+
...(result.usd > 0 ? { actualCostUsd: result.usd } : {}),
|
|
169
|
+
...(usageUnknown ? { usageUnknown: true, costUnknown: result.usd <= 0 } : {}),
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
})
|
|
173
|
+
if (!paid.succeeded) throw paid.error
|
|
174
|
+
const r = paid.value
|
|
160
175
|
const hasPatch = r.patch.trim().length > 0
|
|
161
|
-
// Report real usage; floor a patch-bearing zero-usage cell so the stub-guard cannot abort on a
|
|
162
|
-
// router telemetry gap (lift is judge-derived, so this only affects cost accounting).
|
|
163
|
-
const zeroUsage = r.tokIn === 0 && r.tokOut === 0
|
|
164
|
-
ctx.cost.observe(zeroUsage && hasPatch ? Math.max(r.usd, 0.0001) : r.usd, workerModel)
|
|
165
|
-
ctx.cost.observeTokens(
|
|
166
|
-
zeroUsage && hasPatch ? { input: Math.max(r.tokIn, 1), output: Math.max(r.tokOut, 1) } : { input: r.tokIn, output: r.tokOut },
|
|
167
|
-
)
|
|
168
176
|
const files = hasPatch ? [...r.patch.matchAll(/^diff --git a\/(\S+)/gm)].map((m) => m[1]) : []
|
|
169
177
|
console.log(
|
|
170
178
|
` [measure] ${isCode ? 'cand' : 'base'} ${scenario.id} patch=${r.patch.length}b files=[${files.join(', ') || 'none'}] ` +
|
|
@@ -173,7 +181,7 @@ async function main(): Promise<void> {
|
|
|
173
181
|
return hasPatch ? r.patch : null
|
|
174
182
|
}
|
|
175
183
|
|
|
176
|
-
const judge: JudgeConfig<string, Scenario> = {
|
|
184
|
+
const judge: JudgeConfig<string | null, Scenario> = {
|
|
177
185
|
name: 'swebench-docker',
|
|
178
186
|
dimensions: [{ key: 'resolved', description: 'FAIL_TO_PASS + PASS_TO_PASS resolved by the official swebench Docker harness' }],
|
|
179
187
|
async score({ artifact, scenario }) {
|
|
@@ -286,11 +294,10 @@ async function main(): Promise<void> {
|
|
|
286
294
|
runHarness: runHarness as any,
|
|
287
295
|
})
|
|
288
296
|
|
|
289
|
-
const profile: AgentProfile = { name: 'swe-scaffold', prompt: { systemPrompt: '' } }
|
|
290
297
|
const scenarios: Scenario[] = allIds.map((id) => ({ id, kind: 'swe-bench-verified' }))
|
|
291
298
|
const holdoutScenarios: Scenario[] = holdoutIds.map((id) => ({ id, kind: 'swe-bench-verified' }))
|
|
292
299
|
|
|
293
|
-
const out = await improve(
|
|
300
|
+
const out = await improve({
|
|
294
301
|
surface: 'code',
|
|
295
302
|
gate: 'holdout',
|
|
296
303
|
code: { repoRoot: REPO_ROOT, baseRef, worktreeDir, generator },
|
|
@@ -301,25 +308,17 @@ async function main(): Promise<void> {
|
|
|
301
308
|
agent,
|
|
302
309
|
expectUsage: 'warn',
|
|
303
310
|
budget: { generations, populationSize: population, holdoutScenarios, maxConcurrency: 1, reps: 1 },
|
|
304
|
-
llm: { baseUrl: routerBaseUrl, apiKey: routerKey, model: reflectModel },
|
|
305
311
|
})
|
|
306
312
|
|
|
307
313
|
console.log('\n=== RESULT ===')
|
|
308
|
-
console.log(`
|
|
314
|
+
console.log(`decision=${out.decision} lift=${out.lift}`)
|
|
309
315
|
console.log(`baseline holdout composite = ${out.raw.baseline.compositeMean}`)
|
|
310
316
|
console.log(`winner holdout composite = ${out.raw.winner.compositeMean}`)
|
|
311
317
|
console.log(`baseline per-scenario: ${JSON.stringify(out.raw.baseline.perScenario)}`)
|
|
312
318
|
console.log(`winner per-scenario: ${JSON.stringify(out.raw.winner.perScenario)}`)
|
|
313
319
|
if (out.raw.winner.label) console.log(`winner label: ${out.raw.winner.label}`)
|
|
314
|
-
if (out.raw.winner.
|
|
315
|
-
|
|
316
|
-
console.log(`\n-- generation ${gen.record.generationIndex} candidates --`)
|
|
317
|
-
for (const c of gen.record.candidates) {
|
|
318
|
-
const perScenario = (c as { scenarios?: Array<{ scenarioId: string; composite: number }> }).scenarios ?? []
|
|
319
|
-
const detail = perScenario.map((s) => `${s.scenarioId}=${s.composite}`).join(' ')
|
|
320
|
-
console.log(` candidate ${c.surfaceHash.slice(0, 8)} composite=${c.composite}${c.label ? ` "${c.label}"` : ''} [${detail}]`)
|
|
321
|
-
}
|
|
322
|
-
}
|
|
320
|
+
if (out.raw.winner.rationale) console.log(`winner rationale: ${out.raw.winner.rationale}`)
|
|
321
|
+
console.log(`generations explored: ${out.generationsExplored ?? 0}`)
|
|
323
322
|
}
|
|
324
323
|
|
|
325
324
|
main().catch((e) => {
|
package/src/swe-improve.mts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Official GEPA prompt optimization on the local SWE-bench path.
|
|
3
3
|
*
|
|
4
|
-
* Composes
|
|
5
|
-
* 1. `improve({
|
|
6
|
-
*
|
|
7
|
-
* candidate prompt on real instances and gates the winner on a held-out split.
|
|
4
|
+
* Composes three pieces:
|
|
5
|
+
* 1. `improve({ method: officialGepa(...) })` runs GEPA's upstream
|
|
6
|
+
* Optimize Anything engine on explicit train and selection partitions.
|
|
8
7
|
* 2. Per candidate + scenario, the `agent` fn runs the LOCAL SWE env
|
|
9
8
|
* (`createSweBenchEnvironment` + `runAgentic`): clone the instance repo to a
|
|
10
9
|
* host tmpdir, run the jailed list/read/edit tool loop with the CANDIDATE
|
|
@@ -16,23 +15,33 @@
|
|
|
16
15
|
* IN-LOOP score is a cheap patch-exists proxy (NOT the Docker judge) so the ONLY
|
|
17
16
|
* Docker run per cell is the improve judge — one deterministic verdict per cell.
|
|
18
17
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* GENERATIONS=1 POPULATION=1 WORKER_MODEL=glm-4.6 REFLECT_MODEL=glm-4.6 \
|
|
18
|
+
* TANGLE_API_KEY=... dotenvx run -f .../agent-state.env -- \
|
|
19
|
+
* TRAIN_IDS=psf__requests-2931 SELECTION_IDS=pallets__flask-5014 \
|
|
20
|
+
* TEST_IDS=psf__requests-1142,psf__requests-1921 \
|
|
21
|
+
* MAX_EVALUATIONS=4 MAX_PROPOSER_COST_USD=2 \
|
|
24
22
|
* node_modules/.bin/tsx bench/src/swe-improve.mts
|
|
25
23
|
*/
|
|
26
24
|
import { execFile } from 'node:child_process'
|
|
27
25
|
import { promisify } from 'node:util'
|
|
28
|
-
import {
|
|
29
|
-
|
|
26
|
+
import {
|
|
27
|
+
improve,
|
|
28
|
+
officialGepa,
|
|
29
|
+
type ReadonlyAgentProfile,
|
|
30
|
+
} from '@tangle-network/agent-runtime'
|
|
31
|
+
import {
|
|
32
|
+
canonicalCandidateDigest,
|
|
33
|
+
type AgentProfile,
|
|
34
|
+
} from '@tangle-network/agent-interface'
|
|
30
35
|
import type { AgenticSurface, ArtifactHandle, SurfaceScore } from '@tangle-network/agent-runtime/loops'
|
|
31
36
|
import { refine, runAgentic } from '@tangle-network/agent-runtime/loops'
|
|
32
37
|
import type { DispatchContext, JudgeConfig, Scenario } from '@tangle-network/agent-eval/contract'
|
|
33
|
-
import { gepaProposer } from '@tangle-network/agent-eval/campaign'
|
|
34
38
|
import { createSweBenchAdapter } from './benchmarks/swe-bench'
|
|
35
39
|
import type { BenchTask } from './benchmarks/types'
|
|
40
|
+
import {
|
|
41
|
+
assertCompleteCost,
|
|
42
|
+
officialOptimizerModel,
|
|
43
|
+
requiredTokenPricing,
|
|
44
|
+
} from './official-optimizer-config.mjs'
|
|
36
45
|
import { createSweBenchEnvironment, SWE_SEED_PROMPT, SWE_SEED_PROMPT_WITH_RUN } from './swe-bench-env'
|
|
37
46
|
|
|
38
47
|
const exec = promisify(execFile)
|
|
@@ -42,36 +51,47 @@ async function main(): Promise<void> {
|
|
|
42
51
|
if (!routerKey) throw new Error('TANGLE_API_KEY required (the worker + reflection call the router)')
|
|
43
52
|
const routerBaseUrl = process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1'
|
|
44
53
|
const workerModel = process.env.WORKER_MODEL ?? 'glm-4.6'
|
|
54
|
+
const reflectBase = process.env.REFLECT_BASE ?? routerBaseUrl
|
|
55
|
+
const reflectKey = process.env.REFLECT_KEY ?? routerKey
|
|
45
56
|
const reflectModel = process.env.REFLECT_MODEL ?? 'glm-4.6'
|
|
46
57
|
const trainIds = (process.env.TRAIN_IDS ?? 'psf__requests-2931').split(',').map((s) => s.trim()).filter(Boolean)
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
58
|
+
const selectionIds = (process.env.SELECTION_IDS ?? 'pallets__flask-5014').split(',').map((s) => s.trim()).filter(Boolean)
|
|
59
|
+
const testIds = (process.env.TEST_IDS ?? 'psf__requests-1142,psf__requests-1921').split(',').map((s) => s.trim()).filter(Boolean)
|
|
60
|
+
const maxEvaluations = Number(process.env.MAX_EVALUATIONS ?? 4)
|
|
61
|
+
const maxProposerCostUsd = Number(process.env.MAX_PROPOSER_COST_USD ?? 2)
|
|
50
62
|
const innerTurns = Number(process.env.INNER_TURNS ?? 40)
|
|
51
63
|
const workerMaxTokens = Number(process.env.MAX_TOKENS ?? 8000)
|
|
52
64
|
const reflectMaxTokens = Number(process.env.REFLECT_MAX_TOKENS ?? 12000)
|
|
53
65
|
const maxConcurrency = Number(process.env.MAX_CONCURRENCY ?? 1)
|
|
54
66
|
const budgetShots = Number(process.env.BUDGET ?? 1)
|
|
67
|
+
const runDir = process.env.RUN_DIR ?? '.runs/swe-official-gepa'
|
|
55
68
|
// WITH-TOOLS arm: RUN_TOOL=1 exposes the jailed `run` tool AND swaps the seed to the run-aware prompt.
|
|
56
69
|
// Default OFF ⇒ reproduces the read/edit-only baseline denominator unchanged.
|
|
57
70
|
const enableRun = ['1', 'true', 'yes'].includes((process.env.RUN_TOOL ?? '').toLowerCase())
|
|
58
71
|
const SEED_PROMPT = enableRun ? SWE_SEED_PROMPT_WITH_RUN : SWE_SEED_PROMPT
|
|
72
|
+
const allIds = [...new Set([...trainIds, ...selectionIds, ...testIds])]
|
|
59
73
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
console.log(
|
|
64
|
-
console.log(`
|
|
65
|
-
console.log(`train=[${trainIds.join(', ')}] holdout=[${holdoutIds.join(', ')}]`)
|
|
66
|
-
console.log(`generations=${generations} population=${population} innerTurns=${innerTurns} workerMaxTokens=${workerMaxTokens} reflectMaxTokens=${reflectMaxTokens} runTool=${enableRun}`)
|
|
67
|
-
console.log(`≈ ${cellsMax} cells max (each = 1 clone + 1 runAgentic + 1 Docker judge)\n`)
|
|
74
|
+
console.log('=== SWE-bench prompt optimization with official GEPA ===')
|
|
75
|
+
console.log(`worker=${workerModel} reflect=${reflectModel} router=${routerBaseUrl}`)
|
|
76
|
+
console.log(`train=[${trainIds.join(', ')}] selection=[${selectionIds.join(', ')}] test=[${testIds.join(', ')}]`)
|
|
77
|
+
console.log(`maxEvaluations=${maxEvaluations} maxProposerCostUsd=${maxProposerCostUsd} innerTurns=${innerTurns} workerMaxTokens=${workerMaxTokens} runTool=${enableRun}`)
|
|
78
|
+
console.log(`runDir=${runDir}\n`)
|
|
68
79
|
|
|
69
80
|
if (process.env.DRYRUN) {
|
|
70
81
|
// Import + wiring smoke: prove every module resolves and the plan is well-formed
|
|
71
82
|
// WITHOUT paying for a clone / model call / Docker judge.
|
|
72
|
-
console.log(`DRYRUN: imports OK (improve=${typeof improve},
|
|
83
|
+
console.log(`DRYRUN: imports OK (improve=${typeof improve}, officialGepa=${typeof officialGepa}, runAgentic=${typeof runAgentic}, refine=${typeof refine})`)
|
|
73
84
|
return
|
|
74
85
|
}
|
|
86
|
+
const workerPricing = requiredTokenPricing(process.env, 'WORKER')
|
|
87
|
+
const optimizer = officialOptimizerModel({
|
|
88
|
+
env: process.env,
|
|
89
|
+
model: reflectModel,
|
|
90
|
+
baseUrl: reflectBase,
|
|
91
|
+
apiKey: reflectKey,
|
|
92
|
+
maxCostUsd: maxProposerCostUsd,
|
|
93
|
+
maxOutputTokensPerRequest: reflectMaxTokens,
|
|
94
|
+
})
|
|
75
95
|
|
|
76
96
|
const { environment, adapter } = await createSweBenchEnvironment(allIds.length, { ids: allIds, enableRun })
|
|
77
97
|
const pool = await adapter.loadTasks({ ids: allIds, split: 'test' })
|
|
@@ -82,8 +102,9 @@ async function main(): Promise<void> {
|
|
|
82
102
|
// one instance, return the git-diff patch. A per-call proxy captures the patch in
|
|
83
103
|
// score() BEFORE runAgentic closes (rm) the workspace; its score is a cheap
|
|
84
104
|
// patch-exists proxy so the ONLY Docker run per cell is the improve judge.
|
|
85
|
-
const agent = async (
|
|
86
|
-
const promptText =
|
|
105
|
+
const agent = async (candidate: ReadonlyAgentProfile, scenario: Scenario, ctx: DispatchContext): Promise<string | null> => {
|
|
106
|
+
const promptText = candidate.prompt?.systemPrompt
|
|
107
|
+
if (promptText === undefined) throw new Error('agent: candidate profile has no system prompt')
|
|
87
108
|
const bt = byId.get(scenario.id)
|
|
88
109
|
if (!bt) throw new Error(`agent: unknown scenario ${scenario.id}`)
|
|
89
110
|
const task = { id: bt.id, systemPrompt: promptText, userPrompt: bt.prompt, meta: { instanceId: bt.id } }
|
|
@@ -111,40 +132,44 @@ async function main(): Promise<void> {
|
|
|
111
132
|
},
|
|
112
133
|
}
|
|
113
134
|
const t0 = Date.now()
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
strategy: refine,
|
|
118
|
-
routerBaseUrl,
|
|
119
|
-
routerKey,
|
|
135
|
+
const paid = await ctx.cost.runPaidCall({
|
|
136
|
+
channel: 'agent',
|
|
137
|
+
actor: 'swe-worker',
|
|
120
138
|
model: workerModel,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
139
|
+
execute: () =>
|
|
140
|
+
runAgentic({
|
|
141
|
+
surface: proxy,
|
|
142
|
+
task,
|
|
143
|
+
strategy: refine,
|
|
144
|
+
routerBaseUrl,
|
|
145
|
+
routerKey,
|
|
146
|
+
model: workerModel,
|
|
147
|
+
maxTokens: workerMaxTokens,
|
|
148
|
+
innerTurns,
|
|
149
|
+
budget: budgetShots,
|
|
150
|
+
}),
|
|
151
|
+
receipt: (result) => {
|
|
152
|
+
const inputTokens = result.tokens.input ?? 0
|
|
153
|
+
const outputTokens = result.tokens.output ?? 0
|
|
154
|
+
const usageUnknown = inputTokens === 0 && outputTokens === 0
|
|
155
|
+
return {
|
|
156
|
+
model: workerModel,
|
|
157
|
+
inputTokens,
|
|
158
|
+
outputTokens,
|
|
159
|
+
customTokenPricing: workerPricing,
|
|
160
|
+
...(usageUnknown ? { usageUnknown: true } : {}),
|
|
161
|
+
}
|
|
162
|
+
},
|
|
124
163
|
})
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
// patch with an UNPOPULATED usage block (a router telemetry gap on some
|
|
128
|
-
// reasoning-model responses — NOT a stub: the cell made real tool calls and
|
|
129
|
-
// produced a patch). In that gap case report a nominal floor so the stub-guard
|
|
130
|
-
// (artifact + zero usage) cannot abort the whole campaign on a telemetry gap.
|
|
131
|
-
// The lift metric is judge-derived, so a floored count does not distort it; only
|
|
132
|
-
// cost accounting undercounts those few cells (disclosed). No-patch cells return
|
|
133
|
-
// null below and are skipped by the guard's own contract, so this floor only
|
|
134
|
-
// ever applies to a cell that genuinely produced a patch.
|
|
164
|
+
if (!paid.succeeded) throw paid.error
|
|
165
|
+
const r = paid.value
|
|
135
166
|
const zeroUsage = (r.tokens.input ?? 0) === 0 && (r.tokens.output ?? 0) === 0
|
|
136
167
|
const hasPatch = capturedPatch.trim().length > 0
|
|
137
|
-
ctx.cost.observe(zeroUsage && hasPatch ? Math.max(r.usd ?? 0, 0.0001) : r.usd ?? 0, workerModel)
|
|
138
|
-
ctx.cost.observeTokens(
|
|
139
|
-
zeroUsage && hasPatch
|
|
140
|
-
? { input: Math.max(r.tokens.input ?? 0, 1), output: Math.max(r.tokens.output ?? 0, 1) }
|
|
141
|
-
: { input: r.tokens.input, output: r.tokens.output },
|
|
142
|
-
)
|
|
143
168
|
const files = capturedPatch ? [...capturedPatch.matchAll(/^diff --git a\/(\S+)/gm)].map((m) => m[1]) : []
|
|
144
169
|
console.log(
|
|
145
170
|
` [agent] ${scenario.id} prompt=${promptText.length}c tools(l/r/e+/e-/run/run!)=${stats.list}/${stats.read}/${stats.edit_ok}/${stats.edit_fail}/${stats.run}/${stats.run_err} ` +
|
|
146
|
-
`patch=${capturedPatch.length}b files=[${files.join(', ') || 'none'}] tok=in:${r.tokens.input}/out:${r.tokens.output}
|
|
147
|
-
`${zeroUsage ?
|
|
171
|
+
`patch=${capturedPatch.length}b files=[${files.join(', ') || 'none'}] tok=in:${r.tokens.input}/out:${r.tokens.output} ${Math.round((Date.now() - t0) / 1000)}s` +
|
|
172
|
+
`${zeroUsage ? ' [provider usage unavailable]' : ''}`,
|
|
148
173
|
)
|
|
149
174
|
// A cell with no patch produced NO artifact. Return null (not '') so the
|
|
150
175
|
// backend-integrity guard's own contract (`artifact == null → skip`) applies:
|
|
@@ -156,7 +181,7 @@ async function main(): Promise<void> {
|
|
|
156
181
|
|
|
157
182
|
// The judge: the OFFICIAL swebench Docker harness. Deterministic FAIL_TO_PASS +
|
|
158
183
|
// PASS_TO_PASS → resolved 0/1. This is the held-out gate's scoring axis.
|
|
159
|
-
const judge: JudgeConfig<string, Scenario> = {
|
|
184
|
+
const judge: JudgeConfig<string | null, Scenario> = {
|
|
160
185
|
name: 'swebench-docker',
|
|
161
186
|
dimensions: [{ key: 'resolved', description: 'FAIL_TO_PASS + PASS_TO_PASS resolved by the official swebench Docker harness' }],
|
|
162
187
|
async score({ artifact, scenario }) {
|
|
@@ -177,53 +202,61 @@ async function main(): Promise<void> {
|
|
|
177
202
|
}
|
|
178
203
|
|
|
179
204
|
const profile: AgentProfile = { name: 'swe-agent-glm46', prompt: { systemPrompt: SEED_PROMPT } }
|
|
180
|
-
const
|
|
181
|
-
llm: { baseUrl: routerBaseUrl, apiKey: routerKey },
|
|
182
|
-
model: reflectModel,
|
|
183
|
-
target: 'the system prompt of a coding agent that fixes real GitHub bugs via list_files/read_file/edit_file tools',
|
|
184
|
-
maxTokens: reflectMaxTokens,
|
|
185
|
-
temperature: 0.7,
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
const scenarios: Scenario[] = allIds.map((id) => ({ id, kind: 'swe-bench-verified' }))
|
|
189
|
-
const holdoutScenarios: Scenario[] = holdoutIds.map((id) => ({ id, kind: 'swe-bench-verified' }))
|
|
205
|
+
const scenario = (id: string): Scenario => ({ id, kind: 'swe-bench-verified' })
|
|
190
206
|
|
|
191
|
-
const out = await improve(profile,
|
|
207
|
+
const out = await improve(profile, {
|
|
192
208
|
surface: 'prompt',
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
209
|
+
executionRef: canonicalCandidateDigest({
|
|
210
|
+
callback: 'bench/swe-improve',
|
|
211
|
+
model: workerModel,
|
|
212
|
+
endpoint: new URL(routerBaseUrl).origin,
|
|
213
|
+
innerTurns,
|
|
214
|
+
maxTokens: workerMaxTokens,
|
|
215
|
+
budgetShots,
|
|
216
|
+
enableRun,
|
|
217
|
+
}),
|
|
218
|
+
method: officialGepa<Scenario, string | null>({
|
|
219
|
+
objective:
|
|
220
|
+
'Improve the system prompt of a coding agent that fixes real GitHub bugs with list_files, read_file, edit_file, and optional run tools.',
|
|
221
|
+
background:
|
|
222
|
+
'Return the complete system prompt. Preserve tool names and require evidence from repository files and tests.',
|
|
223
|
+
recipe: {
|
|
224
|
+
kind: 'engine',
|
|
225
|
+
run: {
|
|
226
|
+
engine: 'gepa',
|
|
227
|
+
maxEvaluations,
|
|
228
|
+
maxProposerCostUsd,
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
optimizer,
|
|
232
|
+
resume: 'if-compatible',
|
|
233
|
+
trustResumeState: true,
|
|
234
|
+
describeScenario: (item) => ({ prompt: byId.get(item.id)?.prompt ?? item.id }),
|
|
235
|
+
}),
|
|
236
|
+
trainScenarios: trainIds.map(scenario),
|
|
237
|
+
selectionScenarios: selectionIds.map(scenario),
|
|
238
|
+
testScenarios: testIds.map(scenario),
|
|
239
|
+
judges: [judge],
|
|
197
240
|
agent,
|
|
198
|
-
// glm-5.2 occasionally returns a real patch with an unpopulated usage block
|
|
199
|
-
// (a router telemetry gap on some reasoning-model responses — NOT a stub: the
|
|
200
|
-
// cell made real tool calls and produced a patch). 'assert' would abort the
|
|
201
|
-
// whole campaign on such a cell; 'warn' logs it and continues. The lift metric
|
|
202
|
-
// (resolved) is judge-derived, so a missing token count does not distort it —
|
|
203
|
-
// only the cost accounting undercounts those cells, which is disclosed.
|
|
204
241
|
expectUsage: 'warn',
|
|
205
|
-
|
|
206
|
-
|
|
242
|
+
maxConcurrency,
|
|
243
|
+
reps: 1,
|
|
244
|
+
runDir,
|
|
245
|
+
optimizationRunOptions: {
|
|
246
|
+
expectUsage: 'warn',
|
|
247
|
+
maxConcurrency,
|
|
248
|
+
reps: 1,
|
|
249
|
+
},
|
|
207
250
|
})
|
|
208
251
|
|
|
209
|
-
|
|
210
|
-
console.log(
|
|
211
|
-
console.log(`
|
|
212
|
-
console.log(`
|
|
213
|
-
console.log(`
|
|
214
|
-
console.log(`
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
// Per-candidate verdicts on the train set (the "real swebench verdict per candidate").
|
|
219
|
-
for (const gen of out.raw.generations ?? []) {
|
|
220
|
-
console.log(`\n── generation ${gen.record.generationIndex} candidates ──`)
|
|
221
|
-
for (const c of gen.record.candidates) {
|
|
222
|
-
const perScenario = (c as { scenarios?: Array<{ scenarioId: string; composite: number }> }).scenarios ?? []
|
|
223
|
-
const detail = perScenario.map((s) => `${s.scenarioId}=${s.composite}`).join(' ')
|
|
224
|
-
console.log(` candidate ${c.surfaceHash.slice(0, 8)} composite=${c.composite}${c.label ? ` "${c.label}"` : ''} [${detail}]`)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
252
|
+
assertCompleteCost('SWE-bench official GEPA run', out.cost)
|
|
253
|
+
console.log('\n=== RESULT ===')
|
|
254
|
+
console.log(`decision=${out.decision} lift=${out.lift} interval=[${out.liftInterval.low}, ${out.liftInterval.high}]`)
|
|
255
|
+
console.log(`baseline test composite=${out.raw.best.baselineComposite}`)
|
|
256
|
+
console.log(`winner test composite=${out.raw.best.winnerComposite}`)
|
|
257
|
+
console.log(`test scenarios=${JSON.stringify(out.raw.best.scenarioScores)}`)
|
|
258
|
+
console.log(`cost=${JSON.stringify(out.cost)}`)
|
|
259
|
+
console.log(`candidate prompt:\n${String(out.candidate.value).slice(0, 2000)}`)
|
|
227
260
|
}
|
|
228
261
|
|
|
229
262
|
main().catch((e) => {
|
package/src/swe-local-proof.mts
CHANGED
|
@@ -46,6 +46,9 @@ async function main(): Promise<void> {
|
|
|
46
46
|
|
|
47
47
|
const { environment, tasks, adapter } = await createSweBenchEnvironment(ids.length, { ids, enableRun })
|
|
48
48
|
const taskList = await tasks(0, ids.length)
|
|
49
|
+
const benchTaskById = new Map(
|
|
50
|
+
(await adapter.loadTasks({ ids, split: 'test' })).map((task) => [task.id, task]),
|
|
51
|
+
)
|
|
49
52
|
|
|
50
53
|
// One shot per pinned id: proxy score() to capture the exact judged bytes + a NON-DESTRUCTIVE
|
|
51
54
|
// apply-coherence check, then delegate the verdict to the real Docker judge.
|
|
@@ -123,7 +126,9 @@ async function main(): Promise<void> {
|
|
|
123
126
|
// Cached judge: identical patch ⇒ identical verdict; don't pay for a second Docker run.
|
|
124
127
|
let s = judged.get(effPatch)
|
|
125
128
|
if (!s) {
|
|
126
|
-
|
|
129
|
+
const benchTask = benchTaskById.get(task.id)
|
|
130
|
+
if (!benchTask) throw new Error(`swe-local-proof: unknown benchmark task ${task.id}`)
|
|
131
|
+
s = await adapter.judge(benchTask, effPatch)
|
|
127
132
|
judged.set(effPatch, s)
|
|
128
133
|
}
|
|
129
134
|
rec.score = s
|
package/src/swe-stream.mts
CHANGED
|
@@ -700,6 +700,8 @@ async function acquireRepro(
|
|
|
700
700
|
// hands the worker a no-code plan. Primitives replicated from supervisor-arena.mts (that file runs
|
|
701
701
|
// main() on import, so it cannot be imported) — evidence from execution-verified inputs only. ----------
|
|
702
702
|
|
|
703
|
+
type RepairFailureKind = 'wrong-fix' | 'apply-failed' | 'empty-diff'
|
|
704
|
+
|
|
703
705
|
/** Evidence for the supervisor: the issue, the worker's own candidate diff, and the tail of the
|
|
704
706
|
* gold-verified reproduction's output on that diff. Execution-verified / model-visible ONLY — never
|
|
705
707
|
* FAIL_TO_PASS, never the gold patch, never any worker self-report. Bounded to maxChars. */
|
|
@@ -709,7 +711,7 @@ function renderRepairEvidence(
|
|
|
709
711
|
reproTail: string,
|
|
710
712
|
reproExit: number | null,
|
|
711
713
|
maxChars: number,
|
|
712
|
-
failureKind:
|
|
714
|
+
failureKind: RepairFailureKind = 'wrong-fix',
|
|
713
715
|
): string {
|
|
714
716
|
const header =
|
|
715
717
|
failureKind === 'apply-failed'
|
|
@@ -789,7 +791,7 @@ async function superviseRepair(
|
|
|
789
791
|
reproExit: number | null,
|
|
790
792
|
marks: readonly string[],
|
|
791
793
|
deadlineAt: number,
|
|
792
|
-
failureKind:
|
|
794
|
+
failureKind: RepairFailureKind = 'wrong-fix',
|
|
793
795
|
): Promise<SupervisorPlanReceipt> {
|
|
794
796
|
const md = bt.metadata as Record<string, string>
|
|
795
797
|
const evidence = renderRepairEvidence(String(md.problem_statement ?? ''), candidateDiff, reproTail, reproExit, 14_000, failureKind)
|