@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.
Files changed (42) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +14 -0
  3. package/dist/adapters.js +2 -2
  4. package/dist/benchmarks/appworld.js +1 -1
  5. package/dist/benchmarks/appworld.js.map +1 -1
  6. package/dist/benchmarks/cadbench.js +1 -1
  7. package/dist/benchmarks/cadgenbench.js +1 -1
  8. package/dist/benchmarks/finresearchbench.js +1 -1
  9. package/dist/benchmarks/finsearchcomp.js +1 -1
  10. package/dist/benchmarks/frames.js +1 -1
  11. package/dist/benchmarks/simpleqa.js +1 -1
  12. package/dist/benchmarks/trata-hedge.js +1 -1
  13. package/dist/{cadbench-BLSyxR1N.js → cadbench-BRF-59Mt.js} +2 -2
  14. package/dist/{cadbench-BLSyxR1N.js.map → cadbench-BRF-59Mt.js.map} +1 -1
  15. package/dist/{cadgenbench-x2OFkf8y.js → cadgenbench-DXtGkuW3.js} +2 -2
  16. package/dist/{cadgenbench-x2OFkf8y.js.map → cadgenbench-DXtGkuW3.js.map} +1 -1
  17. package/dist/index.js +10 -5
  18. package/dist/index.js.map +1 -1
  19. package/dist/{router-turn-C2wMiDoo.js → router-turn-uTYO6KQ1.js} +10 -8
  20. package/dist/router-turn-uTYO6KQ1.js.map +1 -0
  21. package/package.json +8 -7
  22. package/src/agent-graphs-improve.mts +1 -1
  23. package/src/atom-mcp-e2e.mts +1 -1
  24. package/src/benchmarks/appworld.ts +1 -1
  25. package/src/commit0-gate.mts +1 -1
  26. package/src/humaneval-repair-gate.mts +1 -1
  27. package/src/mcp-mount-probe.mts +1 -1
  28. package/src/quant-arena/quant-loop.mts +1 -1
  29. package/src/router-turn.ts +10 -1
  30. package/src/run-benchmarks.ts +12 -8
  31. package/src/swe-arena/arms.ts +1 -1
  32. package/dist/router-turn-C2wMiDoo.js.map +0 -1
  33. package/src/aec-gate.mts +0 -238
  34. package/src/atom-humaneval.mts +0 -218
  35. package/src/david-attribution.mts +0 -97
  36. package/src/david-goliath.mts +0 -168
  37. package/src/decoder-live.mts +0 -133
  38. package/src/diverse-gate.mjs +0 -112
  39. package/src/hev-eval.mts +0 -101
  40. package/src/hev-improve.mts +0 -245
  41. package/src/humaneval-object-ablation.mts +0 -239
  42. package/src/trata-gate.mts +0 -243
@@ -9,16 +9,18 @@ import "@tangle-network/agent-interface";
9
9
  */
10
10
  async function runBenchRouterTurn(config, input) {
11
11
  if (!config.profile.model?.default) throw new Error("runBenchRouterTurn: profile.model.default is required");
12
+ const factory = createExecutor({
13
+ backend: "router",
14
+ routerBaseUrl: config.routerBaseUrl,
15
+ routerKey: config.routerKey,
16
+ ...config.tools ? { tools: config.tools } : {}
17
+ });
18
+ const turnInput = typeof input === "string" ? { prompt: input } : { providerOptions: { messages: input.messages.map((message) => ({ ...message })) } };
12
19
  const turn = await collectAgentTurn(streamAgentTurn({
13
20
  kind: "executor",
14
- factory: createExecutor({
15
- backend: "router",
16
- routerBaseUrl: config.routerBaseUrl,
17
- routerKey: config.routerKey,
18
- ...config.tools ? { tools: config.tools } : {}
19
- }),
21
+ factory,
20
22
  profile: config.profile
21
- }, input, {
23
+ }, turnInput, {
22
24
  ...config.timeoutMs === void 0 ? {} : { timeoutMs: config.timeoutMs },
23
25
  ...config.signal ? { signal: config.signal } : {}
24
26
  }));
@@ -28,4 +30,4 @@ async function runBenchRouterTurn(config, input) {
28
30
  //#endregion
29
31
  export { runBenchRouterTurn as t };
30
32
 
31
- //# sourceMappingURL=router-turn-C2wMiDoo.js.map
33
+ //# sourceMappingURL=router-turn-uTYO6KQ1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router-turn-uTYO6KQ1.js","names":[],"sources":["../src/router-turn.ts"],"sourcesContent":["import {\n type AgentProfile,\n agentProfileSchema,\n type ReasoningEffort,\n} from '@tangle-network/agent-interface'\nimport {\n collectAgentTurn,\n createExecutor,\n streamAgentTurn,\n type AgentTurnInput,\n type CollectedAgentTurn,\n type ToolSpec,\n} from '@tangle-network/agent-runtime/kernel'\n\n/** Bench-local target shorthand; Runtime still executes only the exact profile below. */\nexport interface BenchRouterTarget {\n routerBaseUrl: string\n routerKey: string\n profile: AgentProfile\n}\n\nexport interface BenchRouterTurnConfig extends BenchRouterTarget {\n tools?: ReadonlyArray<ToolSpec>\n timeoutMs?: number\n signal?: AbortSignal\n}\n\nexport interface BenchProfileSettings {\n systemPrompt?: string\n temperature?: number\n maxTokens?: number\n retry?: {\n maxAttempts?: number\n initialBackoffMs?: number\n maxBackoffMs?: number\n jitter?: number\n retryStatuses?: ReadonlyArray<number>\n requestTimeoutMs?: number\n }\n maxTurns?: number\n seed?: number\n reasoningEffort?: ReasoningEffort\n extraBody?: Readonly<Record<string, unknown>>\n toolChoice?: 'auto' | 'required' | 'none'\n}\n\n/** Author an exact direct-Router profile for a benchmark. This is profile construction only;\n * execution still accepts no model or generation fields outside the returned AgentProfile. */\nexport function benchRouterProfile(\n name: string,\n model: string,\n settings: BenchProfileSettings = {},\n): AgentProfile {\n return withBenchProfile(\n {\n name,\n harness: 'cli-base',\n model: { provider: 'tangle-router', default: model },\n },\n settings,\n )\n}\n\n/** Derive another exact profile while preserving all untouched canonical axes. */\nexport function withBenchProfile(\n base: AgentProfile,\n settings: BenchProfileSettings & { name?: string },\n): AgentProfile {\n const metadata = {\n ...(base.model?.metadata ?? {}),\n ...(settings.temperature !== undefined ? { temperature: settings.temperature } : {}),\n ...(settings.maxTokens !== undefined ? { maxTokens: settings.maxTokens } : {}),\n ...(settings.retry !== undefined ? { retry: settings.retry } : {}),\n ...(settings.maxTurns !== undefined ? { maxTurns: settings.maxTurns } : {}),\n ...(settings.seed !== undefined ? { seed: settings.seed } : {}),\n ...(settings.extraBody !== undefined ? { extraBody: settings.extraBody } : {}),\n ...(settings.toolChoice !== undefined ? { toolChoice: settings.toolChoice } : {}),\n }\n return agentProfileSchema.parse({\n ...base,\n ...(settings.name ? { name: settings.name } : {}),\n model: {\n ...base.model,\n ...(settings.reasoningEffort !== undefined\n ? { reasoningEffort: settings.reasoningEffort }\n : {}),\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n },\n ...(settings.systemPrompt !== undefined\n ? { prompt: { ...base.prompt, systemPrompt: settings.systemPrompt } }\n : {}),\n })\n}\n\nexport function benchProfileModel(profile: AgentProfile): string {\n const model = profile.model?.default\n if (typeof model !== 'string' || model.length === 0 || model === 'runtime-selected') {\n throw new Error('benchmark AgentProfile.model.default must be concrete')\n }\n return model\n}\n\n/**\n * The benchmark-side entry to Runtime's canonical one-turn path.\n * It is only an ergonomic composition: Runtime still parses the exact profile,\n * materializes the executor, records identity/usage/result events, and refuses\n * profile axes the direct Router backend cannot carry.\n */\nexport async function runBenchRouterTurn(\n config: BenchRouterTurnConfig,\n input: string | { readonly messages: ReadonlyArray<Readonly<Record<string, unknown>>> },\n): Promise<CollectedAgentTurn> {\n if (!config.profile.model?.default) {\n throw new Error('runBenchRouterTurn: profile.model.default is required')\n }\n const factory = createExecutor({\n backend: 'router',\n routerBaseUrl: config.routerBaseUrl,\n routerKey: config.routerKey,\n ...(config.tools ? { tools: config.tools } : {}),\n })\n const turnInput: AgentTurnInput =\n typeof input === 'string'\n ? { prompt: input }\n : {\n providerOptions: {\n messages: input.messages.map((message) => ({ ...message })),\n },\n }\n const turn = await collectAgentTurn(\n streamAgentTurn(\n { kind: 'executor', factory, profile: config.profile },\n turnInput,\n {\n ...(config.timeoutMs === undefined ? {} : { timeoutMs: config.timeoutMs }),\n ...(config.signal ? { signal: config.signal } : {}),\n },\n ),\n )\n if (turn.status !== 'completed') {\n throw new Error(turn.error?.message ?? `Router turn ended with status ${turn.status}`)\n }\n return turn\n}\n"],"mappings":";;;;;;;;;AA4GA,eAAsB,mBACpB,QACA,OAC6B;CAC7B,IAAI,CAAC,OAAO,QAAQ,OAAO,SACzB,MAAM,IAAI,MAAM,uDAAuD;CAEzE,MAAM,UAAU,eAAe;EAC7B,SAAS;EACT,eAAe,OAAO;EACtB,WAAW,OAAO;EAClB,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;CAChD,CAAC;CACD,MAAM,YACJ,OAAO,UAAU,WACb,EAAE,QAAQ,MAAM,IAChB,EACE,iBAAiB,EACf,UAAU,MAAM,SAAS,KAAK,aAAa,EAAE,GAAG,QAAQ,EAAE,EAC5D,EACF;CACN,MAAM,OAAO,MAAM,iBACjB,gBACE;EAAE,MAAM;EAAY;EAAS,SAAS,OAAO;CAAQ,GACrD,WACA;EACE,GAAI,OAAO,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,OAAO,UAAU;EACxE,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;CACnD,CACF,CACF;CACA,IAAI,KAAK,WAAW,aAClB,MAAM,IAAI,MAAM,KAAK,OAAO,WAAW,iCAAiC,KAAK,QAAQ;CAEvF,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-bench",
3
- "version": "0.8.10",
3
+ "version": "0.8.15",
4
4
  "type": "module",
5
5
  "description": "Benchmark adapters and execution for agent-runtime across coding, tool-use, RAG, memory, browser, and terminal tasks.",
6
6
  "repository": {
@@ -25,11 +25,11 @@
25
25
  }
26
26
  },
27
27
  "dependencies": {
28
- "@tangle-network/agent-eval": "0.145.11",
29
- "@tangle-network/agent-interface": "0.52.0",
30
- "@tangle-network/agent-knowledge": "8.0.0",
31
- "@tangle-network/sandbox": "0.26.1",
32
- "@tangle-network/agent-runtime": "0.134.9"
28
+ "@tangle-network/agent-eval": ">=0.148.0 <0.149.0",
29
+ "@tangle-network/agent-interface": "^1.1.0",
30
+ "@tangle-network/agent-knowledge": "^8.0.9",
31
+ "@tangle-network/sandbox": ">=0.27.1 <0.28.0",
32
+ "@tangle-network/agent-runtime": "^0.141.1"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@arethetypeswrong/cli": "0.18.5",
@@ -73,7 +73,8 @@
73
73
  "typecheck:public": "tsc -p tsconfig.public.json",
74
74
  "verify:package": "pnpm run verify:package:static && node scripts/verify-packed-consumer.mjs",
75
75
  "verify:package:local-runtime": "pnpm run verify:package:static && node scripts/verify-packed-consumer.mjs --local-runtime",
76
- "verify:package:static": "pnpm run build && publint && attw --pack --profile esm-only .",
76
+ "verify:package:static": "pnpm run build && publint && attw --pack --profile esm-only . && node ../scripts/check-published-ranges.mjs bench && node ../scripts/check-api-surface.mjs bench",
77
+ "api:surface": "node ../scripts/check-api-surface.mjs --write bench",
77
78
  "wait:published-dependencies": "node scripts/wait-for-published-dependencies.mjs",
78
79
  "verify:pier": "tsx scripts/verify-pier-pair.mts"
79
80
  }
@@ -226,7 +226,7 @@ export async function callAuthor(
226
226
  const turn = await collectAgentTurn(
227
227
  streamAgentTurn(
228
228
  { kind: 'executor', factory, profile, agentRunName: profile.name ?? 'agent-graphs-author' },
229
- prompt,
229
+ { prompt },
230
230
  timeoutMs === undefined ? {} : { timeoutMs },
231
231
  ),
232
232
  )
@@ -103,7 +103,7 @@ async function bridgeChat(opts: {
103
103
  const turn = await collectAgentTurn(
104
104
  streamAgentTurn(
105
105
  { kind: 'executor', factory, profile },
106
- opts.messages.map((message) => message.content).join('\n\n'),
106
+ { prompt: opts.messages.map((message) => message.content).join('\n\n') },
107
107
  ),
108
108
  )
109
109
  if (turn.status !== 'completed') {
@@ -440,7 +440,7 @@ export function appworldToolLoopClient(cfg: {
440
440
  const loop = await collectAgentTurn(
441
441
  streamAgentTurn(
442
442
  { kind: 'executor', factory, profile },
443
- `Task: ${instruction}`,
443
+ { prompt: `Task: ${instruction}` },
444
444
  { signal },
445
445
  ),
446
446
  )
@@ -330,7 +330,7 @@ async function runShotLocal(task: BenchTask, attempt: number, cfg: ShotCfg, stee
330
330
  const turn = await collectAgentTurn(
331
331
  streamAgentTurn(
332
332
  { kind: 'executor', factory, profile: workerProfile(cfg, `commit0-local-${attempt}`) },
333
- prompt,
333
+ { prompt },
334
334
  cfg.timeoutMs > 0 ? { timeoutMs: cfg.timeoutMs } : {},
335
335
  ),
336
336
  )
@@ -89,7 +89,7 @@ async function repairAttempt(cfg: BenchRouterTarget, task: HumanEvalTask, k: num
89
89
  },
90
90
  })
91
91
  const r = await collectAgentTurn(
92
- streamAgentTurn({ kind: 'executor', factory, profile }, basePrompt(task)),
92
+ streamAgentTurn({ kind: 'executor', factory, profile }, { prompt: basePrompt(task) }),
93
93
  )
94
94
  if (r.status !== 'completed') {
95
95
  throw new Error(r.error?.message ?? `repair turn ended with status ${r.status}`)
@@ -70,7 +70,7 @@ async function bridgeChat(messages: Array<{ role: string; content: string }>, mc
70
70
  const turn = await collectAgentTurn(
71
71
  streamAgentTurn(
72
72
  { kind: 'executor', factory, profile },
73
- messages.map((message) => message.content).join('\n\n'),
73
+ { prompt: messages.map((message) => message.content).join('\n\n') },
74
74
  ),
75
75
  )
76
76
  if (turn.status !== 'completed') {
@@ -249,7 +249,7 @@ async function profileShot(opts: {
249
249
  const turn = await collectAgentTurn(
250
250
  streamAgentTurn(
251
251
  { kind: 'executor', factory, profile: opts.profile },
252
- opts.prompt,
252
+ { prompt: opts.prompt },
253
253
  { timeoutMs: opts.timeoutMs },
254
254
  ),
255
255
  )
@@ -7,6 +7,7 @@ import {
7
7
  collectAgentTurn,
8
8
  createExecutor,
9
9
  streamAgentTurn,
10
+ type AgentTurnInput,
10
11
  type CollectedAgentTurn,
11
12
  type ToolSpec,
12
13
  } from '@tangle-network/agent-runtime/kernel'
@@ -118,10 +119,18 @@ export async function runBenchRouterTurn(
118
119
  routerKey: config.routerKey,
119
120
  ...(config.tools ? { tools: config.tools } : {}),
120
121
  })
122
+ const turnInput: AgentTurnInput =
123
+ typeof input === 'string'
124
+ ? { prompt: input }
125
+ : {
126
+ providerOptions: {
127
+ messages: input.messages.map((message) => ({ ...message })),
128
+ },
129
+ }
121
130
  const turn = await collectAgentTurn(
122
131
  streamAgentTurn(
123
132
  { kind: 'executor', factory, profile: config.profile },
124
- input,
133
+ turnInput,
125
134
  {
126
135
  ...(config.timeoutMs === undefined ? {} : { timeoutMs: config.timeoutMs }),
127
136
  ...(config.signal ? { signal: config.signal } : {}),
@@ -185,13 +185,17 @@ const openSandboxShot: BenchShot = async ({ adapter, task, cell, prompt, routerB
185
185
  ...(timeoutMs ? { timeoutMs } : {}),
186
186
  })
187
187
  const harness = cell.harness ?? (cell.profile?.metadata?.backendType as string | undefined) ?? 'opencode'
188
- const profile: AgentProfile =
189
- cell.profile ?? {
190
- name: cell.label,
191
- harness: harness as AgentProfile['harness'],
192
- model: { provider: 'tangle-router', default: cell.model },
193
- metadata: { backendType: harness },
194
- }
188
+ // The cell's harness and model are the identity the box must run, so they override whatever a
189
+ // supplied profile declared rather than being dropped when one is supplied. `buildBackendOptions`
190
+ // now sends this provider/model pair on the create request and refuses a conflicting override,
191
+ // so the two must be derived from the same profile.
192
+ const profileProvider = cell.profile?.model?.provider ?? 'tangle-router'
193
+ const profile: AgentProfile = {
194
+ ...(cell.profile ?? { name: cell.label }),
195
+ harness: harness as AgentProfile['harness'],
196
+ model: { ...cell.profile?.model, provider: profileProvider, default: cell.model },
197
+ metadata: { ...cell.profile?.metadata, backendType: harness },
198
+ }
195
199
  // Unique per shot: the same (adapter, task) runs concurrently across cells and reps, so the box
196
200
  // name and runId must not collide.
197
201
  const uniq = Math.random().toString(36).slice(2, 8)
@@ -202,7 +206,7 @@ const openSandboxShot: BenchShot = async ({ adapter, task, cell, prompt, routerB
202
206
  sandboxOverrides: {
203
207
  name: `bench-${adapter.name}-${task.id}-${uniq}`.replace(/[^a-zA-Z0-9_.-]/g, '_').slice(0, 60),
204
208
  environment: 'universal',
205
- backend: { type: harness as never, model: { provider: 'openai', model: cell.model, baseUrl: routerBaseUrl } },
209
+ backend: { type: harness as never, model: { provider: profileProvider, model: cell.model, baseUrl: routerBaseUrl } },
206
210
  },
207
211
  }
208
212
  const deliverable: Deliverable<string> = {
@@ -525,7 +525,7 @@ export async function runSoloArm(spec: SoloArmSpec, ctx: ArmRunContext): Promise
525
525
  const turn = await collectAgentTurn(
526
526
  streamAgentTurn(
527
527
  { kind: 'executor', factory, profile: spec.profile },
528
- prompt,
528
+ { prompt },
529
529
  { timeoutMs, ...(ctx.signal ? { signal: ctx.signal } : {}) },
530
530
  ),
531
531
  )
@@ -1 +0,0 @@
1
- {"version":3,"file":"router-turn-C2wMiDoo.js","names":[],"sources":["../src/router-turn.ts"],"sourcesContent":["import {\n type AgentProfile,\n agentProfileSchema,\n type ReasoningEffort,\n} from '@tangle-network/agent-interface'\nimport {\n collectAgentTurn,\n createExecutor,\n streamAgentTurn,\n type CollectedAgentTurn,\n type ToolSpec,\n} from '@tangle-network/agent-runtime/kernel'\n\n/** Bench-local target shorthand; Runtime still executes only the exact profile below. */\nexport interface BenchRouterTarget {\n routerBaseUrl: string\n routerKey: string\n profile: AgentProfile\n}\n\nexport interface BenchRouterTurnConfig extends BenchRouterTarget {\n tools?: ReadonlyArray<ToolSpec>\n timeoutMs?: number\n signal?: AbortSignal\n}\n\nexport interface BenchProfileSettings {\n systemPrompt?: string\n temperature?: number\n maxTokens?: number\n retry?: {\n maxAttempts?: number\n initialBackoffMs?: number\n maxBackoffMs?: number\n jitter?: number\n retryStatuses?: ReadonlyArray<number>\n requestTimeoutMs?: number\n }\n maxTurns?: number\n seed?: number\n reasoningEffort?: ReasoningEffort\n extraBody?: Readonly<Record<string, unknown>>\n toolChoice?: 'auto' | 'required' | 'none'\n}\n\n/** Author an exact direct-Router profile for a benchmark. This is profile construction only;\n * execution still accepts no model or generation fields outside the returned AgentProfile. */\nexport function benchRouterProfile(\n name: string,\n model: string,\n settings: BenchProfileSettings = {},\n): AgentProfile {\n return withBenchProfile(\n {\n name,\n harness: 'cli-base',\n model: { provider: 'tangle-router', default: model },\n },\n settings,\n )\n}\n\n/** Derive another exact profile while preserving all untouched canonical axes. */\nexport function withBenchProfile(\n base: AgentProfile,\n settings: BenchProfileSettings & { name?: string },\n): AgentProfile {\n const metadata = {\n ...(base.model?.metadata ?? {}),\n ...(settings.temperature !== undefined ? { temperature: settings.temperature } : {}),\n ...(settings.maxTokens !== undefined ? { maxTokens: settings.maxTokens } : {}),\n ...(settings.retry !== undefined ? { retry: settings.retry } : {}),\n ...(settings.maxTurns !== undefined ? { maxTurns: settings.maxTurns } : {}),\n ...(settings.seed !== undefined ? { seed: settings.seed } : {}),\n ...(settings.extraBody !== undefined ? { extraBody: settings.extraBody } : {}),\n ...(settings.toolChoice !== undefined ? { toolChoice: settings.toolChoice } : {}),\n }\n return agentProfileSchema.parse({\n ...base,\n ...(settings.name ? { name: settings.name } : {}),\n model: {\n ...base.model,\n ...(settings.reasoningEffort !== undefined\n ? { reasoningEffort: settings.reasoningEffort }\n : {}),\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n },\n ...(settings.systemPrompt !== undefined\n ? { prompt: { ...base.prompt, systemPrompt: settings.systemPrompt } }\n : {}),\n })\n}\n\nexport function benchProfileModel(profile: AgentProfile): string {\n const model = profile.model?.default\n if (typeof model !== 'string' || model.length === 0 || model === 'runtime-selected') {\n throw new Error('benchmark AgentProfile.model.default must be concrete')\n }\n return model\n}\n\n/**\n * The benchmark-side entry to Runtime's canonical one-turn path.\n * It is only an ergonomic composition: Runtime still parses the exact profile,\n * materializes the executor, records identity/usage/result events, and refuses\n * profile axes the direct Router backend cannot carry.\n */\nexport async function runBenchRouterTurn(\n config: BenchRouterTurnConfig,\n input: string | { readonly messages: ReadonlyArray<Readonly<Record<string, unknown>>> },\n): Promise<CollectedAgentTurn> {\n if (!config.profile.model?.default) {\n throw new Error('runBenchRouterTurn: profile.model.default is required')\n }\n const factory = createExecutor({\n backend: 'router',\n routerBaseUrl: config.routerBaseUrl,\n routerKey: config.routerKey,\n ...(config.tools ? { tools: config.tools } : {}),\n })\n const turn = await collectAgentTurn(\n streamAgentTurn(\n { kind: 'executor', factory, profile: config.profile },\n input,\n {\n ...(config.timeoutMs === undefined ? {} : { timeoutMs: config.timeoutMs }),\n ...(config.signal ? { signal: config.signal } : {}),\n },\n ),\n )\n if (turn.status !== 'completed') {\n throw new Error(turn.error?.message ?? `Router turn ended with status ${turn.status}`)\n }\n return turn\n}\n"],"mappings":";;;;;;;;;AA2GA,eAAsB,mBACpB,QACA,OAC6B;CAC7B,IAAI,CAAC,OAAO,QAAQ,OAAO,SACzB,MAAM,IAAI,MAAM,uDAAuD;CAQzE,MAAM,OAAO,MAAM,iBACjB,gBACE;EAAE,MAAM;EAAY,SARR,eAAe;GAC7B,SAAS;GACT,eAAe,OAAO;GACtB,WAAW,OAAO;GAClB,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;EAChD,CAG8B;EAAG,SAAS,OAAO;CAAQ,GACrD,OACA;EACE,GAAI,OAAO,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,OAAO,UAAU;EACxE,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;CACnD,CACF,CACF;CACA,IAAI,KAAK,WAAW,aAClB,MAAM,IAAI,MAAM,KAAK,OAAO,WAAW,iCAAiC,KAAK,QAAQ;CAEvF,OAAO;AACT"}
package/src/aec-gate.mts DELETED
@@ -1,238 +0,0 @@
1
- /**
2
- * Router-based gate runner for aec-bench — the fix for the null-score sandbox path.
3
- *
4
- * aec-bench is closed-form reasoning + a deterministic local verify.py judge, so a
5
- * sandbox is unnecessary: solve each task with one direct router chat call, then
6
- * judge the raw response locally (verify.py extracts the last fenced ```json block
7
- * itself). The prior sandbox path emitted the JSON in-stream but never fed it to
8
- * the judge, so every verdict.score came out null — the bug this runner fixes by
9
- * passing the model's full response straight to adapter.judge().
10
- *
11
- * Two paired arms over the SAME task set (loadTasks once):
12
- * random@K — K identical-base-prompt shots/task (the compute control)
13
- * diverse@K — K shots, the i-th prefixed with composeStrategies(base, K)[i]
14
- *
15
- * Each attempt carries a REAL numeric verdict.score (from verify.py) + the output,
16
- * written as a corpus RunRecord (condition random@K / diverse@K) the existing
17
- * corpus-replay --selector + corpus-report consume unchanged. Fail loud on a router
18
- * error — never a fabricated score.
19
- */
20
-
21
- import { resolveAdapter } from './adapters'
22
- import type { BenchmarkAdapter, BenchTask } from './benchmarks/types'
23
- import { type AttemptRecord, appendRunRecord, buildRunRecordFromAttempts } from './corpus'
24
- import { composeStrategies } from './directives'
25
- import {
26
- benchProfileModel,
27
- benchRouterProfile,
28
- type BenchRouterTarget,
29
- runBenchRouterTurn,
30
- withBenchProfile,
31
- } from './router-turn'
32
- import { pool } from './stats.mts'
33
-
34
- function must(name: string): string {
35
- const v = process.env[name]
36
- if (!v) throw new Error(`env ${name} is required`)
37
- return v
38
- }
39
-
40
- interface ArmSpec {
41
- /** Corpus condition label the selector/report filter on (e.g. random@4). */
42
- condition: string
43
- /** Per-attempt prompt builder: the i-th of K shots for a task. */
44
- promptFor(task: BenchTask, i: number, k: number): string
45
- }
46
-
47
- interface AttemptOutcome {
48
- prompt: string
49
- output: string
50
- score: number
51
- resolved: boolean
52
- costUsd?: number
53
- tokensIn?: number
54
- tokensOut?: number
55
- wallMs: number
56
- /** the router/judge call failed after retries — EXCLUDED from stats, never scored 0. */
57
- infraError?: boolean
58
- }
59
-
60
- async function runAttempt(
61
- cfg: BenchRouterTarget,
62
- adapter: BenchmarkAdapter,
63
- task: BenchTask,
64
- prompt: string,
65
- ): Promise<AttemptOutcome> {
66
- const startedAt = Date.now()
67
- // Retry transient router/judge failures (rate limits, stream drops, 5xx) with
68
- // backoff; a genuine empty completion still scores a real 0 (verify.py fail-closes).
69
- // Only after retries are exhausted do we record an EXCLUDED infraError — never a
70
- // fabricated score, and never a throw that aborts the whole multi-model run.
71
- let lastErr: unknown
72
- for (let attempt = 0; attempt < 3; attempt += 1) {
73
- try {
74
- const res = await runBenchRouterTurn(
75
- {
76
- routerBaseUrl: cfg.routerBaseUrl,
77
- routerKey: cfg.routerKey,
78
- profile: withBenchProfile(cfg.profile, { name: 'aec-worker' }),
79
- },
80
- prompt,
81
- )
82
- const content = res.finalText
83
- const verdict = await adapter.judge(task, content)
84
- return {
85
- prompt,
86
- output: content,
87
- score: verdict.score,
88
- resolved: verdict.resolved,
89
- wallMs: Date.now() - startedAt,
90
- ...(res.usage.costUsd !== undefined ? { costUsd: res.usage.costUsd } : {}),
91
- ...(res.usage.tokensKnown === false
92
- ? {}
93
- : { tokensIn: res.usage.input, tokensOut: res.usage.output }),
94
- }
95
- } catch (err) {
96
- lastErr = err
97
- if (attempt < 2) await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt))
98
- }
99
- }
100
- console.warn(`[aec-gate] ${task.id}: infra error after 3 tries — excluded: ${(lastErr instanceof Error ? lastErr.message : String(lastErr)).slice(0, 160)}`)
101
- return { prompt, output: '', score: 0, resolved: false, wallMs: Date.now() - startedAt, infraError: true }
102
- }
103
-
104
- function toAttemptRecord(o: AttemptOutcome, round: number): AttemptRecord {
105
- return {
106
- round,
107
- prompt: o.prompt,
108
- output: o.output,
109
- // infra-errored attempts carry NO score/valid → corpus-replay skips them.
110
- ...(o.infraError ? {} : { valid: o.resolved, score: o.score }),
111
- wallMs: o.wallMs,
112
- eventCount: 1,
113
- eventTypes: o.infraError ? { 'router.error': 1 } : { 'router.chat': 1 },
114
- traceTail: o.output.slice(-600),
115
- ...(o.costUsd !== undefined ? { costUsd: o.costUsd } : {}),
116
- ...(o.tokensIn !== undefined ? { tokensIn: o.tokensIn } : {}),
117
- ...(o.tokensOut !== undefined ? { tokensOut: o.tokensOut } : {}),
118
- }
119
- }
120
-
121
- interface ArmResult {
122
- /** mean graded score across SCORED (non-infra) attempts */
123
- meanScore: number
124
- /** fraction of scored attempts at full credit (score >= 1) */
125
- fullCreditRate: number
126
- attemptCount: number
127
- /** attempts excluded as infra errors (router/judge failed after retries) */
128
- infraCount: number
129
- }
130
-
131
- async function runArm(
132
- arm: ArmSpec,
133
- cfg: BenchRouterTarget,
134
- adapter: BenchmarkAdapter,
135
- tasks: BenchTask[],
136
- k: number,
137
- concurrency: number,
138
- corpusPath: string,
139
- ): Promise<ArmResult> {
140
- // Flatten (task, shot) into one unit of work so the pool bounds TOTAL in-flight
141
- // router calls across all tasks, not per-task.
142
- const units = tasks.flatMap((task) => Array.from({ length: k }, (_, i) => ({ task, i })))
143
- const outcomes = await pool(units, concurrency, (u) => runAttempt(cfg, adapter, u.task, arm.promptFor(u.task, u.i, k)))
144
-
145
- const scored = outcomes.filter((o) => !o.infraError)
146
- let scoreSum = 0
147
- let fullCredit = 0
148
- for (const o of scored) {
149
- scoreSum += o.score
150
- if (o.score >= 1) fullCredit += 1
151
- }
152
-
153
- // Group K outcomes back per task → one RunRecord/task (the controller-run shape).
154
- for (let t = 0; t < tasks.length; t += 1) {
155
- const task = tasks[t] as BenchTask
156
- const taskOutcomes = outcomes.slice(t * k, t * k + k)
157
- const attempts = taskOutcomes.map((o, i) => toAttemptRecord(o, i))
158
- const record = buildRunRecordFromAttempts(attempts, {
159
- benchmark: adapter.name,
160
- instanceId: task.id,
161
- condition: arm.condition,
162
- model: benchProfileModel(cfg.profile),
163
- // k-attempt outcome = any usable attempt resolved (the oracle@k ceiling for
164
- // this run; the deployable selector is scored separately by corpus-replay).
165
- resolved: taskOutcomes.some((o) => o.resolved),
166
- // a task whose every attempt infra-errored is itself infra-errored.
167
- infraError: taskOutcomes.length > 0 && taskOutcomes.every((o) => o.infraError),
168
- })
169
- await appendRunRecord(corpusPath, record)
170
- }
171
-
172
- return {
173
- meanScore: scored.length > 0 ? scoreSum / scored.length : 0,
174
- fullCreditRate: scored.length > 0 ? fullCredit / scored.length : 0,
175
- infraCount: outcomes.length - scored.length,
176
- attemptCount: outcomes.length,
177
- }
178
- }
179
-
180
- async function main(): Promise<void> {
181
- const n = Number(process.env.N ?? 5)
182
- const k = Number(process.env.K ?? 4)
183
- const model = process.env.WORKER_MODEL ?? 'deepseek-v4-flash'
184
- const routerBaseUrl = process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1'
185
- const routerKey = must('TANGLE_API_KEY')
186
- const concurrency = Number(process.env.CONCURRENCY ?? 6)
187
- const randomCorpus = process.env.RANDOM_CORPUS ?? '/tmp/aec-r.jsonl'
188
- const diverseCorpus = process.env.DIVERSE_CORPUS ?? '/tmp/aec-d.jsonl'
189
-
190
- if (!Number.isFinite(n) || n < 1) throw new Error(`N must be a positive integer, got ${process.env.N}`)
191
- if (!Number.isFinite(k) || k < 1) throw new Error(`K must be a positive integer, got ${process.env.K}`)
192
-
193
- const cfg: BenchRouterTarget = {
194
- routerBaseUrl,
195
- routerKey,
196
- profile: benchRouterProfile('aec-worker', model, {
197
- retry: { maxAttempts: Number(process.env.MAX_ATTEMPTS ?? 3) },
198
- }),
199
- }
200
- const bench = process.env.BENCH ?? 'aec-bench'
201
- const adapter = resolveAdapter(bench)
202
-
203
- console.log(`=== ${bench} router gate · N=${n} K=${k} model=${model} conc=${concurrency} ===`)
204
- await adapter.preflight()
205
- const tasks = await adapter.loadTasks({ limit: n })
206
- console.log(`loaded ${tasks.length} task(s): ${tasks.map((t) => t.id).join(', ')}`)
207
-
208
- // random arm: the task prompt verbatim, K times (the compute control).
209
- const randomArm: ArmSpec = {
210
- condition: `random@${k}`,
211
- promptFor: (task) => task.prompt,
212
- }
213
- // diverse arm: the i-th shot prefixed with the i-th distinct strategy lens.
214
- const diverseArm: ArmSpec = {
215
- condition: `diverse@${k}`,
216
- promptFor: (task, i, kk) => composeStrategies(task.prompt, kk)[i] as string,
217
- }
218
-
219
- console.log(`\n▶ random@${k} (control — identical base prompt) → ${randomCorpus}`)
220
- const r = await runArm(randomArm, cfg, adapter, tasks, k, concurrency, randomCorpus)
221
- console.log(` random@${k}: mean score ${(r.meanScore * 100).toFixed(1)}% full-credit ${(r.fullCreditRate * 100).toFixed(1)}% (n=${r.attemptCount} attempts${r.infraCount ? `, ${r.infraCount} infra-excluded` : ''})`)
222
-
223
- console.log(`\n▶ diverse@${k} (K distinct strategy lenses) → ${diverseCorpus}`)
224
- const d = await runArm(diverseArm, cfg, adapter, tasks, k, concurrency, diverseCorpus)
225
- console.log(` diverse@${k}: mean score ${(d.meanScore * 100).toFixed(1)}% full-credit ${(d.fullCreditRate * 100).toFixed(1)}% (n=${d.attemptCount} attempts${d.infraCount ? `, ${d.infraCount} infra-excluded` : ''})`)
226
-
227
- console.log(
228
- `\n=== next: read the gate ===\n` +
229
- ` npx tsx src/corpus-replay.mts ${randomCorpus} --selector\n` +
230
- ` npx tsx src/corpus-replay.mts ${diverseCorpus} --selector --condition=diverse\n` +
231
- ` npx tsx src/corpus-report.mts ${randomCorpus} ${diverseCorpus}`,
232
- )
233
- }
234
-
235
- main().catch((err) => {
236
- console.error(`aec-gate: ${err instanceof Error ? err.message : String(err)}`)
237
- process.exit(1)
238
- })