@tangle-network/agent-bench 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/HARNESS.md +1 -1
- package/dist/adapters.js +2 -2
- package/dist/benchmarks/appworld.d.ts +61 -2
- package/dist/benchmarks/appworld.js +111 -40
- package/dist/benchmarks/appworld.js.map +1 -1
- package/dist/benchmarks/cadbench.js +1 -1
- package/dist/benchmarks/cadgenbench.js +1 -1
- package/dist/benchmarks/finresearchbench.js +16 -22
- package/dist/benchmarks/finresearchbench.js.map +1 -1
- package/dist/benchmarks/finsearchcomp.js +16 -22
- package/dist/benchmarks/finsearchcomp.js.map +1 -1
- package/dist/benchmarks/frames.js +18 -20
- package/dist/benchmarks/frames.js.map +1 -1
- package/dist/benchmarks/simpleqa.js +15 -19
- package/dist/benchmarks/simpleqa.js.map +1 -1
- package/dist/benchmarks/trata-hedge.js +20 -23
- package/dist/benchmarks/trata-hedge.js.map +1 -1
- package/dist/{cadbench-BrpwOU6A.js → cadbench-BLSyxR1N.js} +21 -20
- package/dist/cadbench-BLSyxR1N.js.map +1 -0
- package/dist/{cadgenbench-DF7hYHdl.js → cadgenbench-x2OFkf8y.js} +2 -2
- package/dist/cadgenbench-x2OFkf8y.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/dist/router-turn-C2wMiDoo.js +31 -0
- package/dist/router-turn-C2wMiDoo.js.map +1 -0
- package/package.json +7 -7
- package/scripts/appworld_driver.py +1 -170
- package/scripts/run-package-tests.mjs +56 -36
- package/scripts/run-package-tests.test.mjs +33 -0
- package/scripts/trata-hedge/README.md +3 -3
- package/scripts/trata-hedge/run.sh +6 -2
- package/src/aec-gate.mts +30 -9
- package/src/agent-graphs-gen2.mts +523 -0
- package/src/agent-graphs-gen3.mts +660 -0
- package/src/agent-graphs-improve/offline-seams.mts +128 -0
- package/src/agent-graphs-improve.mts +747 -0
- package/src/atom-humaneval.mts +76 -55
- package/src/atom-mcp-e2e.mts +27 -13
- package/src/benchmarks/appworld.test.mts +119 -1
- package/src/benchmarks/appworld.ts +156 -33
- package/src/benchmarks/cadbench.ts +21 -8
- package/src/benchmarks/finresearchbench.ts +20 -16
- package/src/benchmarks/finsearchcomp.ts +20 -20
- package/src/benchmarks/frames.ts +19 -18
- package/src/benchmarks/simpleqa.ts +19 -17
- package/src/benchmarks/trata-hedge.ts +26 -18
- package/src/browser/ui-reviewer.ts +1 -1
- package/src/clbench-context-gate.mts +45 -9
- package/src/cloud-loop.mts +24 -6
- package/src/commit0-env-run.mts +6 -3
- package/src/commit0-env.ts +2 -3
- package/src/commit0-gate.mts +53 -24
- package/src/corpus.ts +3 -3
- package/src/david-attribution.mts +28 -9
- package/src/david-goliath.mts +31 -12
- package/src/egress-probe.mts +3 -3
- package/src/examples/lean-proof-gate.mts +10 -3
- package/src/examples/math-demo.mts +10 -3
- package/src/examples/strategy-demo.mts +10 -4
- package/src/fleet.mts +30 -8
- package/src/gate-cli.mts +9 -4
- package/src/gate.test.mts +7 -2
- package/src/gate.ts +23 -75
- package/src/generate-eval/certify.ts +13 -5
- package/src/hev-eval.mts +39 -10
- package/src/hev-improve.mts +28 -16
- package/src/hev-structural.mts +28 -20
- package/src/humaneval-gate.mts +24 -8
- package/src/humaneval-object-ablation.mts +52 -14
- package/src/humaneval-repair-gate.mts +53 -14
- package/src/mbpp-structural.mts +28 -20
- package/src/mcp-mount-probe.mts +23 -11
- package/src/official-optimizer-config.mts +61 -12
- package/src/official-optimizer-config.test.mts +72 -3
- package/src/quant-arena/profiles/quant-researcher.profile.json +6 -1
- package/src/quant-arena/quant-loop.mts +88 -61
- package/src/research-shot.ts +21 -11
- package/src/resolve-client.ts +6 -8
- package/src/rollout-ledger/backfill-swe-arena.test.mts +7 -2
- package/src/router-executor.ts +1 -1
- package/src/router-turn.ts +135 -0
- package/src/run-benchmarks.ts +7 -2
- package/src/sandbox-run.ts +23 -41
- package/src/search-bench/bridge.ts +66 -8
- package/src/search-bench/parametric-check.mts +19 -4
- package/src/search-bench/profiles.ts +24 -9
- package/src/search-bench/run.mts +3 -4
- package/src/smoke-structural-rollout.mts +21 -5
- package/src/supervisor-arena.mts +28 -20
- package/src/swe-arena/arms.ts +73 -15
- package/src/swe-arena/capacity.ts +44 -41
- package/src/swe-arena/diagnosis-ensemble.ts +51 -48
- package/src/swe-arena/execution.test.mts +12 -12
- package/src/swe-arena/gepa-seat.mts +12 -5
- package/src/swe-arena/gepa-seat.test.mts +45 -33
- package/src/swe-arena/outer-loop.mts +94 -70
- package/src/swe-arena/premeasured-from-cells.mts +16 -1
- package/src/swe-arena/premeasured-from-cells.test.mts +21 -1
- package/src/swe-arena/profiles/deepseek-author.profile.json +12 -0
- package/src/swe-arena/profiles/default-author.profile.json +9 -1
- package/src/swe-arena/proposer-fanout.mts +52 -99
- package/src/swe-arena/proposer-fanout.test.mts +92 -57
- package/src/swe-arena/proposer-provenance.mts +1 -1
- package/src/swe-code-improve.mts +30 -52
- package/src/swe-emit-patch.mts +26 -5
- package/src/swe-improve.mts +27 -8
- package/src/swe-jail.test.ts +128 -0
- package/src/swe-jail.ts +106 -22
- package/src/swe-local-proof.mts +27 -5
- package/src/swe-repro-calibrate.mts +5 -0
- package/src/swe-self-improve.mts +45 -10
- package/src/swe-stream.mts +68 -6
- package/src/swe-structural.mts +46 -7
- package/src/tb-container-executor.mts +38 -6
- package/src/tb-container-executor.test.mts +11 -3
- package/src/tb-supervisor-sidecar.mts +11 -27
- package/src/terminal-compare.ts +38 -18
- package/src/trata-gate.mts +26 -26
- package/src/trata-gepa.mts +25 -16
- package/src/trata-hedge-solve.mts +80 -0
- package/src/worker-blender.ts +21 -11
- package/src/worker-browser.ts +18 -5
- package/src/worker-build123d.ts +17 -8
- package/src/worker-cad.ts +31 -12
- package/src/worker.ts +1 -1
- package/tb_agents/opencode_router_agent.py +84 -42
- package/dist/cadbench-BrpwOU6A.js.map +0 -1
- package/dist/cadgenbench-DF7hYHdl.js.map +0 -1
- package/scripts/trata-hedge/solve.py +0 -83
|
@@ -20,9 +20,20 @@
|
|
|
20
20
|
* tsx src/humaneval-repair-gate.mts
|
|
21
21
|
*/
|
|
22
22
|
import { type HumanEvalTask, basePrompt, extractCode, loadHumanEval, runChecker } from './benchmarks/humaneval'
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
collectAgentTurn,
|
|
25
|
+
createExecutor,
|
|
26
|
+
streamAgentTurn,
|
|
27
|
+
type ToolSpec,
|
|
28
|
+
} from '@tangle-network/agent-runtime/kernel'
|
|
24
29
|
import { verifierGroundedSelect } from './selector'
|
|
25
30
|
import { type PairedLift, pairedLift, pool } from './stats.mts'
|
|
31
|
+
import {
|
|
32
|
+
benchRouterProfile,
|
|
33
|
+
type BenchRouterTarget,
|
|
34
|
+
runBenchRouterTurn,
|
|
35
|
+
withBenchProfile,
|
|
36
|
+
} from './router-turn'
|
|
26
37
|
|
|
27
38
|
function must(name: string): string {
|
|
28
39
|
const v = process.env[name]
|
|
@@ -51,14 +62,23 @@ const repairSystem = [
|
|
|
51
62
|
].join(' ')
|
|
52
63
|
|
|
53
64
|
/** repair@K: one worker, up to K inference turns, steering on real test failures. */
|
|
54
|
-
async function repairAttempt(cfg:
|
|
65
|
+
async function repairAttempt(cfg: BenchRouterTarget, task: HumanEvalTask, k: number): Promise<number> {
|
|
55
66
|
let lastTested = ''
|
|
56
|
-
const
|
|
57
|
-
cfg,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
const profile = {
|
|
68
|
+
...withBenchProfile(cfg.profile, {
|
|
69
|
+
name: 'humaneval-repair-worker',
|
|
70
|
+
systemPrompt: repairSystem,
|
|
71
|
+
maxTurns: k,
|
|
72
|
+
temperature: 0.3,
|
|
73
|
+
}),
|
|
74
|
+
tools: { run_tests: true },
|
|
75
|
+
}
|
|
76
|
+
const factory = createExecutor({
|
|
77
|
+
backend: 'router-tools',
|
|
78
|
+
routerBaseUrl: cfg.routerBaseUrl,
|
|
79
|
+
routerKey: cfg.routerKey,
|
|
80
|
+
tools: [runTestsTool],
|
|
81
|
+
executeToolCall: async (name, args) => {
|
|
62
82
|
if (name !== 'run_tests') return `error: unknown tool ${name}`
|
|
63
83
|
const code = extractCode(String(args.code ?? ''))
|
|
64
84
|
lastTested = code
|
|
@@ -67,22 +87,37 @@ async function repairAttempt(cfg: RouterConfig, task: HumanEvalTask, k: number):
|
|
|
67
87
|
? 'ALL TESTS PASSED. Reply with the final function now; do not call run_tests again.'
|
|
68
88
|
: `TESTS FAILED:\n${res.detail ?? 'no output'}\n\nFix the function and call run_tests again.`
|
|
69
89
|
},
|
|
70
|
-
|
|
90
|
+
})
|
|
91
|
+
const r = await collectAgentTurn(
|
|
92
|
+
streamAgentTurn({ kind: 'executor', factory, profile }, basePrompt(task)),
|
|
71
93
|
)
|
|
94
|
+
if (r.status !== 'completed') {
|
|
95
|
+
throw new Error(r.error?.message ?? `repair turn ended with status ${r.status}`)
|
|
96
|
+
}
|
|
72
97
|
// Judge the model's final answer; fall back to the last code it tested (it may
|
|
73
98
|
// report "done" without re-pasting the passing function).
|
|
74
|
-
const finalCode = extractCode(r.
|
|
99
|
+
const finalCode = extractCode(r.finalText) || lastTested
|
|
75
100
|
if (!finalCode) return 0
|
|
76
101
|
return (await runChecker(task, finalCode)).pass
|
|
77
102
|
}
|
|
78
103
|
|
|
79
104
|
/** blind@K: K independent completions, verifier-grounded pick (the resample control). */
|
|
80
|
-
async function blindAttempts(cfg:
|
|
105
|
+
async function blindAttempts(cfg: BenchRouterTarget, task: HumanEvalTask, k: number): Promise<number[]> {
|
|
81
106
|
const base = basePrompt(task)
|
|
82
107
|
const passes: number[] = []
|
|
83
108
|
for (let i = 0; i < k; i += 1) {
|
|
84
|
-
const res = await
|
|
85
|
-
|
|
109
|
+
const res = await runBenchRouterTurn(
|
|
110
|
+
{
|
|
111
|
+
routerBaseUrl: cfg.routerBaseUrl,
|
|
112
|
+
routerKey: cfg.routerKey,
|
|
113
|
+
profile: withBenchProfile(cfg.profile, {
|
|
114
|
+
name: 'humaneval-blind-worker',
|
|
115
|
+
temperature: 0.8,
|
|
116
|
+
}),
|
|
117
|
+
},
|
|
118
|
+
base,
|
|
119
|
+
)
|
|
120
|
+
passes.push((await runChecker(task, extractCode(res.finalText))).pass)
|
|
86
121
|
}
|
|
87
122
|
return passes
|
|
88
123
|
}
|
|
@@ -95,7 +130,11 @@ async function main(): Promise<void> {
|
|
|
95
130
|
const k = Number(process.env.K ?? 3)
|
|
96
131
|
const offset = Number(process.env.OFFSET ?? 82)
|
|
97
132
|
const model = process.env.WORKER_MODEL ?? 'deepseek-v4-flash'
|
|
98
|
-
const cfg:
|
|
133
|
+
const cfg: BenchRouterTarget = {
|
|
134
|
+
routerBaseUrl: process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1',
|
|
135
|
+
routerKey: must('TANGLE_API_KEY'),
|
|
136
|
+
profile: benchRouterProfile('humaneval-worker', model),
|
|
137
|
+
}
|
|
99
138
|
const concurrency = Number(process.env.CONCURRENCY ?? 6)
|
|
100
139
|
if (k < 2) throw new Error('K must be >= 2 (repair needs at least write + one fix)')
|
|
101
140
|
|
package/src/mbpp-structural.mts
CHANGED
|
@@ -32,6 +32,7 @@ import { tmpdir } from 'node:os'
|
|
|
32
32
|
import { join, resolve } from 'node:path'
|
|
33
33
|
import { fileURLToPath } from 'node:url'
|
|
34
34
|
import { extractCode } from './benchmarks/humaneval'
|
|
35
|
+
import { runBenchRouterTurn } from './router-turn'
|
|
35
36
|
import { type PairedLift, pairedLift, pool } from './stats.mts'
|
|
36
37
|
|
|
37
38
|
const dockerImage = 'python:3.12-slim'
|
|
@@ -326,33 +327,40 @@ async function complete(cfg: ClientCfg, messages: Array<{ role: string; content:
|
|
|
326
327
|
let lastErr = ''
|
|
327
328
|
for (let attempt = 1; attempt <= 4; attempt += 1) {
|
|
328
329
|
if (attempt > 1) await new Promise((r) => setTimeout(r, 2000 * 2 ** attempt))
|
|
329
|
-
const ctl = new AbortController()
|
|
330
|
-
const timer = setTimeout(() => ctl.abort(), 240_000)
|
|
331
330
|
try {
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
331
|
+
const system = messages.find((message) => message.role === 'system')?.content
|
|
332
|
+
const result = await runBenchRouterTurn(
|
|
333
|
+
{
|
|
334
|
+
routerBaseUrl: cfg.base,
|
|
335
|
+
routerKey: cfg.key,
|
|
336
|
+
profile: {
|
|
337
|
+
name: 'mbpp-structural-worker',
|
|
338
|
+
harness: 'cli-base',
|
|
339
|
+
model: {
|
|
340
|
+
provider: 'tangle-router',
|
|
341
|
+
default: cfg.model,
|
|
342
|
+
metadata: { temperature: cfg.temperature, maxTokens: cfg.maxTokens },
|
|
343
|
+
},
|
|
344
|
+
...(system ? { prompt: { systemPrompt: system } } : {}),
|
|
345
|
+
},
|
|
346
|
+
timeoutMs: Number(process.env.LLM_TIMEOUT_MS ?? 240_000),
|
|
347
|
+
},
|
|
348
|
+
{ messages: messages.filter((message) => message.role !== 'system') },
|
|
349
|
+
)
|
|
350
|
+
if (result.usage.tokensKnown === false) throw new Error('provider omitted token usage')
|
|
351
|
+
const content = result.finalText
|
|
347
352
|
if (content.trim() === '') {
|
|
348
353
|
lastErr = 'empty content'
|
|
349
354
|
continue
|
|
350
355
|
}
|
|
351
|
-
return {
|
|
356
|
+
return {
|
|
357
|
+
content,
|
|
358
|
+
attempts: attempt,
|
|
359
|
+
tokensIn: result.usage.input,
|
|
360
|
+
tokensOut: result.usage.output,
|
|
361
|
+
}
|
|
352
362
|
} catch (e) {
|
|
353
363
|
lastErr = e instanceof Error ? e.message : String(e)
|
|
354
|
-
} finally {
|
|
355
|
-
clearTimeout(timer)
|
|
356
364
|
}
|
|
357
365
|
}
|
|
358
366
|
throw new Error(`completion failed after retries: ${lastErr}`)
|
package/src/mcp-mount-probe.mts
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
type Agent,
|
|
15
15
|
type AgentProfile,
|
|
16
16
|
type AgentSpec,
|
|
17
|
+
collectAgentTurn,
|
|
18
|
+
createExecutor,
|
|
17
19
|
createExecutorRegistry,
|
|
18
20
|
createSupervisor,
|
|
19
21
|
type Executor,
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
InMemoryResultBlobStore,
|
|
22
24
|
InMemorySpawnJournal,
|
|
23
25
|
type Scope,
|
|
26
|
+
streamAgentTurn,
|
|
24
27
|
type UsageEvent,
|
|
25
28
|
} from '../../src/runtime/index'
|
|
26
29
|
import { serveCoordinationMcp } from '../../src/runtime/supervise/coordination-mcp'
|
|
@@ -53,18 +56,27 @@ function deliveringLeaf(name: string, out: unknown): Agent<unknown, unknown> {
|
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
async function bridgeChat(messages: Array<{ role: string; content: string }>, mcpUrl: string): Promise<string> {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
if (!BEARER) throw new Error('TANGLE_API_KEY is required')
|
|
60
|
+
const profile: AgentProfile = {
|
|
61
|
+
name: 'mcp-mount-probe-supervisor',
|
|
62
|
+
model: { default: MODEL },
|
|
63
|
+
mcp: { coordination: { transport: 'http', url: mcpUrl } },
|
|
64
|
+
}
|
|
65
|
+
const factory = createExecutor({
|
|
66
|
+
backend: 'bridge',
|
|
67
|
+
bridgeUrl: BRIDGE.replace(/\/v1\/?$/u, ''),
|
|
68
|
+
bridgeBearer: BEARER,
|
|
64
69
|
})
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
const turn = await collectAgentTurn(
|
|
71
|
+
streamAgentTurn(
|
|
72
|
+
{ kind: 'executor', factory, profile },
|
|
73
|
+
messages.map((message) => message.content).join('\n\n'),
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
if (turn.status !== 'completed') {
|
|
77
|
+
throw new Error(turn.error?.message ?? `bridge turn ended with ${turn.status}`)
|
|
78
|
+
}
|
|
79
|
+
return turn.finalText
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
async function main(): Promise<void> {
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
OpenAICompatibleOptimizerModel,
|
|
3
|
+
OptimizerModelBudget,
|
|
4
|
+
} from '@tangle-network/agent-eval/campaign'
|
|
5
|
+
import {
|
|
6
|
+
type AgentProfile,
|
|
7
|
+
canonicalAgentProfileDigest,
|
|
8
|
+
canonicalCandidateDigest,
|
|
9
|
+
} from '@tangle-network/agent-interface'
|
|
10
|
+
import { profileOptimizerModelCall } from '../../src/runtime/profile-chat-client'
|
|
11
|
+
import type { RouterSeam } from '../../src/runtime/supervise/runtime'
|
|
12
|
+
|
|
1
13
|
function requiredNonNegativeNumber(
|
|
2
14
|
env: NodeJS.ProcessEnv,
|
|
3
15
|
name: string,
|
|
@@ -57,22 +69,59 @@ export function officialOptimizerModel(options: {
|
|
|
57
69
|
maxCostUsd: number
|
|
58
70
|
maxOutputTokensPerRequest: number
|
|
59
71
|
envPrefix?: string
|
|
60
|
-
|
|
72
|
+
provider?: string
|
|
73
|
+
temperature?: number
|
|
74
|
+
reasoningEffort?: NonNullable<AgentProfile['model']>['reasoningEffort']
|
|
75
|
+
callRef?: string
|
|
76
|
+
complete?: RouterSeam['complete']
|
|
77
|
+
}): OpenAICompatibleOptimizerModel {
|
|
61
78
|
const { env } = options
|
|
62
79
|
const envPrefix = options.envPrefix ?? 'REFLECT'
|
|
80
|
+
const budget: OptimizerModelBudget = {
|
|
81
|
+
maxCostUsd: options.maxCostUsd,
|
|
82
|
+
maxRequests: positiveInteger(env, `${envPrefix}_MAX_REQUESTS`, 100),
|
|
83
|
+
maxRequestBytes: positiveInteger(env, `${envPrefix}_MAX_REQUEST_BYTES`, 2_000_000),
|
|
84
|
+
maxResponseBytes: positiveInteger(env, `${envPrefix}_MAX_RESPONSE_BYTES`, 2_000_000),
|
|
85
|
+
maxOutputTokensPerRequest: options.maxOutputTokensPerRequest,
|
|
86
|
+
requestTimeoutMs: positiveInteger(env, `${envPrefix}_REQUEST_TIMEOUT_MS`, 300_000),
|
|
87
|
+
pricing: requiredTokenPricing(env, envPrefix),
|
|
88
|
+
}
|
|
89
|
+
const profile: AgentProfile = {
|
|
90
|
+
name: 'official-optimizer-model',
|
|
91
|
+
harness: 'cli-base',
|
|
92
|
+
model: {
|
|
93
|
+
provider: options.provider ?? new URL(options.baseUrl).hostname,
|
|
94
|
+
default: options.model,
|
|
95
|
+
...(options.reasoningEffort ? { reasoningEffort: options.reasoningEffort } : {}),
|
|
96
|
+
metadata: {
|
|
97
|
+
maxTokens: options.maxOutputTokensPerRequest,
|
|
98
|
+
...(options.temperature !== undefined ? { temperature: options.temperature } : {}),
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
const profileDigest = canonicalAgentProfileDigest(profile)
|
|
103
|
+
const executor: RouterSeam & { backend: 'router' } = {
|
|
104
|
+
backend: 'router',
|
|
105
|
+
routerBaseUrl: options.baseUrl,
|
|
106
|
+
routerKey: options.apiKey,
|
|
107
|
+
...(options.complete ? { complete: options.complete } : {}),
|
|
108
|
+
}
|
|
109
|
+
const call = profileOptimizerModelCall({
|
|
110
|
+
profile,
|
|
111
|
+
context: 'official optimizer model',
|
|
112
|
+
executor,
|
|
113
|
+
pricing: budget.pricing,
|
|
114
|
+
})
|
|
63
115
|
return {
|
|
64
116
|
model: options.model,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
requestTimeoutMs: positiveInteger(env, `${envPrefix}_REQUEST_TIMEOUT_MS`, 300_000),
|
|
74
|
-
pricing: requiredTokenPricing(env, envPrefix),
|
|
75
|
-
},
|
|
117
|
+
callRef:
|
|
118
|
+
options.callRef ??
|
|
119
|
+
`agent-runtime:${canonicalCandidateDigest({
|
|
120
|
+
profileDigest,
|
|
121
|
+
endpoint: new URL(options.baseUrl).origin,
|
|
122
|
+
})}`,
|
|
123
|
+
call,
|
|
124
|
+
budget,
|
|
76
125
|
}
|
|
77
126
|
}
|
|
78
127
|
|
|
@@ -30,10 +30,8 @@ describe('official optimizer configuration', () => {
|
|
|
30
30
|
maxOutputTokensPerRequest: 4000,
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
-
expect(model).
|
|
33
|
+
expect(model).toMatchObject({
|
|
34
34
|
model: 'test-model',
|
|
35
|
-
baseUrl: 'http://127.0.0.1:8080/v1',
|
|
36
|
-
apiKey: 'test-key',
|
|
37
35
|
budget: {
|
|
38
36
|
maxCostUsd: 2,
|
|
39
37
|
maxRequests: 7,
|
|
@@ -49,6 +47,77 @@ describe('official optimizer configuration', () => {
|
|
|
49
47
|
},
|
|
50
48
|
},
|
|
51
49
|
})
|
|
50
|
+
expect(model.call).toEqual(expect.any(Function))
|
|
51
|
+
expect(model.callRef).toMatch(/^agent-runtime:sha256:/)
|
|
52
|
+
expect(model).not.toHaveProperty('baseUrl')
|
|
53
|
+
expect(model).not.toHaveProperty('apiKey')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('executes the published optimizer callback through the exact Runtime profile', async () => {
|
|
57
|
+
const requests: unknown[] = []
|
|
58
|
+
const model = officialOptimizerModel({
|
|
59
|
+
env: pricingEnv,
|
|
60
|
+
envPrefix: 'OPT',
|
|
61
|
+
model: 'test-model',
|
|
62
|
+
baseUrl: 'http://127.0.0.1:8080/v1',
|
|
63
|
+
apiKey: 'test-key',
|
|
64
|
+
maxCostUsd: 2,
|
|
65
|
+
maxOutputTokensPerRequest: 4000,
|
|
66
|
+
complete: async (request) => {
|
|
67
|
+
requests.push(request)
|
|
68
|
+
return {
|
|
69
|
+
model: 'test-model',
|
|
70
|
+
choices: [{ message: { content: 'ok' }, finish_reason: 'stop' }],
|
|
71
|
+
usage: {
|
|
72
|
+
prompt_tokens: 3,
|
|
73
|
+
completion_tokens: 2,
|
|
74
|
+
cost: 0.001,
|
|
75
|
+
prompt_tokens_details: { cached_tokens: 1 },
|
|
76
|
+
completion_tokens_details: { reasoning_tokens: 1 },
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const result = await model.call({
|
|
83
|
+
callId: 'optimizer-call-1',
|
|
84
|
+
request: {
|
|
85
|
+
model: 'test-model',
|
|
86
|
+
messages: [{ role: 'user', content: 'hi' }],
|
|
87
|
+
maxTokens: 4000,
|
|
88
|
+
},
|
|
89
|
+
endpointFormat: 'chat-completions',
|
|
90
|
+
signal: new AbortController().signal,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
expect(result.succeeded).toBe(true)
|
|
94
|
+
if (!result.succeeded) throw new Error(result.error)
|
|
95
|
+
expect(result.response).toMatchObject({
|
|
96
|
+
model: 'test-model',
|
|
97
|
+
content: 'ok',
|
|
98
|
+
usage: { promptTokens: 3, completionTokens: 2, totalTokens: 5 },
|
|
99
|
+
})
|
|
100
|
+
expect(result.receipt).toMatchObject({
|
|
101
|
+
model: 'test-model',
|
|
102
|
+
inputTokens: 2,
|
|
103
|
+
cachedTokens: 1,
|
|
104
|
+
outputTokens: 2,
|
|
105
|
+
reasoningTokens: 1,
|
|
106
|
+
actualCostUsd: 0.001,
|
|
107
|
+
})
|
|
108
|
+
expect(result.execution).toMatchObject({
|
|
109
|
+
kind: 'agent-runtime-profile-model-call',
|
|
110
|
+
executed: true,
|
|
111
|
+
succeeded: true,
|
|
112
|
+
model: 'test-model',
|
|
113
|
+
callId: 'optimizer-call-1',
|
|
114
|
+
endpointFormat: 'chat-completions',
|
|
115
|
+
})
|
|
116
|
+
expect(requests).toHaveLength(1)
|
|
117
|
+
expect(requests[0]).toMatchObject({
|
|
118
|
+
model: 'test-model',
|
|
119
|
+
max_tokens: 4000,
|
|
120
|
+
})
|
|
52
121
|
})
|
|
53
122
|
|
|
54
123
|
it('requires every token price instead of inventing cost data', () => {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quant-researcher",
|
|
3
|
-
"description": "
|
|
3
|
+
"description": "Pi strategy-author lens that speaks quant language: regimes, turnover, capacity, transaction costs. The model and harness match the default author; only the system prompt differs.",
|
|
4
|
+
"harness": "pi",
|
|
5
|
+
"model": {
|
|
6
|
+
"provider": "tangle-router",
|
|
7
|
+
"default": "glm-5.2"
|
|
8
|
+
},
|
|
4
9
|
"prompt": {
|
|
5
10
|
"systemPrompt": "You are a systematic-trading researcher at a mid-frequency equity desk. You think in regimes (trend vs chop, calm vs stress), you treat turnover as a cost center (every rebalance pays spread + impact), you size positions for capacity, and you are allergic to backtest overfitting — you prefer one robust effect over five fitted parameters. When you write a strategy you state, in comments, the economic rationale the rule is harvesting and why it should survive out-of-sample."
|
|
6
11
|
}
|