@tangle-network/agent-eval 0.120.1 → 0.120.2
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 +6 -0
- package/package.json +1 -1
- package/dist/analyst/index.d.ts +0 -3111
- package/dist/analyst/index.js +0 -403
- package/dist/analyst/index.js.map +0 -1
- package/dist/authenticity/index.d.ts +0 -161
- package/dist/authenticity/index.js +0 -215
- package/dist/authenticity/index.js.map +0 -1
- package/dist/belief-state/index.d.ts +0 -1301
- package/dist/belief-state/index.js +0 -2152
- package/dist/belief-state/index.js.map +0 -1
- package/dist/benchmarks/index.d.ts +0 -974
- package/dist/benchmarks/index.js +0 -60
- package/dist/benchmarks/index.js.map +0 -1
- package/dist/builder-eval/index.d.ts +0 -695
- package/dist/builder-eval/index.js +0 -366
- package/dist/builder-eval/index.js.map +0 -1
- package/dist/campaign/index.d.ts +0 -7454
- package/dist/campaign/index.js +0 -272
- package/dist/campaign/index.js.map +0 -1
- package/dist/chunk-32BZXMSO.js +0 -3878
- package/dist/chunk-32BZXMSO.js.map +0 -1
- package/dist/chunk-3A246TSA.js +0 -998
- package/dist/chunk-3A246TSA.js.map +0 -1
- package/dist/chunk-3RF76KTD.js +0 -84
- package/dist/chunk-3RF76KTD.js.map +0 -1
- package/dist/chunk-3YYRZDON.js +0 -45
- package/dist/chunk-3YYRZDON.js.map +0 -1
- package/dist/chunk-4I2E3LLO.js +0 -1030
- package/dist/chunk-4I2E3LLO.js.map +0 -1
- package/dist/chunk-ARU2PZFM.js +0 -312
- package/dist/chunk-ARU2PZFM.js.map +0 -1
- package/dist/chunk-BOD4O7OF.js +0 -40
- package/dist/chunk-BOD4O7OF.js.map +0 -1
- package/dist/chunk-DPZAEKA6.js +0 -880
- package/dist/chunk-DPZAEKA6.js.map +0 -1
- package/dist/chunk-DTJ6QUQB.js +0 -131
- package/dist/chunk-DTJ6QUQB.js.map +0 -1
- package/dist/chunk-GGE4NNQT.js +0 -65
- package/dist/chunk-GGE4NNQT.js.map +0 -1
- package/dist/chunk-H5UD2323.js +0 -286
- package/dist/chunk-H5UD2323.js.map +0 -1
- package/dist/chunk-HHWE3POT.js +0 -94
- package/dist/chunk-HHWE3POT.js.map +0 -1
- package/dist/chunk-HKUCJ437.js +0 -787
- package/dist/chunk-HKUCJ437.js.map +0 -1
- package/dist/chunk-JHCHEVET.js +0 -274
- package/dist/chunk-JHCHEVET.js.map +0 -1
- package/dist/chunk-JHOJHHU7.js +0 -867
- package/dist/chunk-JHOJHHU7.js.map +0 -1
- package/dist/chunk-JM2SKQMS.js +0 -750
- package/dist/chunk-JM2SKQMS.js.map +0 -1
- package/dist/chunk-JN2FCO5W.js +0 -7958
- package/dist/chunk-JN2FCO5W.js.map +0 -1
- package/dist/chunk-K4DBDHLK.js +0 -158
- package/dist/chunk-K4DBDHLK.js.map +0 -1
- package/dist/chunk-K6N6XJJX.js +0 -306
- package/dist/chunk-K6N6XJJX.js.map +0 -1
- package/dist/chunk-MA6HLL3S.js +0 -65
- package/dist/chunk-MA6HLL3S.js.map +0 -1
- package/dist/chunk-MAZ26DC7.js +0 -99
- package/dist/chunk-MAZ26DC7.js.map +0 -1
- package/dist/chunk-MOXWMGPC.js +0 -577
- package/dist/chunk-MOXWMGPC.js.map +0 -1
- package/dist/chunk-NJC7U437.js +0 -626
- package/dist/chunk-NJC7U437.js.map +0 -1
- package/dist/chunk-NPCTHQIO.js +0 -91
- package/dist/chunk-NPCTHQIO.js.map +0 -1
- package/dist/chunk-ONWEPEDO.js +0 -57
- package/dist/chunk-ONWEPEDO.js.map +0 -1
- package/dist/chunk-OYZAPX5G.js +0 -1526
- package/dist/chunk-OYZAPX5G.js.map +0 -1
- package/dist/chunk-PC4UYEBM.js +0 -166
- package/dist/chunk-PC4UYEBM.js.map +0 -1
- package/dist/chunk-PICTDURQ.js +0 -766
- package/dist/chunk-PICTDURQ.js.map +0 -1
- package/dist/chunk-PJQFMIOX.js +0 -1182
- package/dist/chunk-PJQFMIOX.js.map +0 -1
- package/dist/chunk-PXD6ZFNY.js +0 -1107
- package/dist/chunk-PXD6ZFNY.js.map +0 -1
- package/dist/chunk-PXE2VKMX.js +0 -140
- package/dist/chunk-PXE2VKMX.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -10
- package/dist/chunk-PZ5AY32C.js.map +0 -1
- package/dist/chunk-QBRSJK47.js +0 -622
- package/dist/chunk-QBRSJK47.js.map +0 -1
- package/dist/chunk-QWMPPZ3X.js +0 -550
- package/dist/chunk-QWMPPZ3X.js.map +0 -1
- package/dist/chunk-S3UZOQ5Y.js +0 -328
- package/dist/chunk-S3UZOQ5Y.js.map +0 -1
- package/dist/chunk-S5TT5R3L.js +0 -2668
- package/dist/chunk-S5TT5R3L.js.map +0 -1
- package/dist/chunk-T4SQEITX.js +0 -95
- package/dist/chunk-T4SQEITX.js.map +0 -1
- package/dist/chunk-TT4KNT67.js +0 -124
- package/dist/chunk-TT4KNT67.js.map +0 -1
- package/dist/chunk-U5CHZ5M3.js +0 -357
- package/dist/chunk-U5CHZ5M3.js.map +0 -1
- package/dist/chunk-ULOKLHIQ.js +0 -1937
- package/dist/chunk-ULOKLHIQ.js.map +0 -1
- package/dist/chunk-VI2UW6B6.js +0 -162
- package/dist/chunk-VI2UW6B6.js.map +0 -1
- package/dist/chunk-VQMK5FMP.js +0 -247
- package/dist/chunk-VQMK5FMP.js.map +0 -1
- package/dist/chunk-VSMTAMNK.js +0 -53
- package/dist/chunk-VSMTAMNK.js.map +0 -1
- package/dist/chunk-VZSRQ272.js +0 -149
- package/dist/chunk-VZSRQ272.js.map +0 -1
- package/dist/chunk-WW2A73HW.js +0 -159
- package/dist/chunk-WW2A73HW.js.map +0 -1
- package/dist/chunk-X4UCIOTZ.js +0 -136
- package/dist/chunk-X4UCIOTZ.js.map +0 -1
- package/dist/chunk-XDIRG3TO.js +0 -1266
- package/dist/chunk-XDIRG3TO.js.map +0 -1
- package/dist/chunk-XJYR7XFV.js +0 -317
- package/dist/chunk-XJYR7XFV.js.map +0 -1
- package/dist/chunk-ZET2UAYW.js +0 -89
- package/dist/chunk-ZET2UAYW.js.map +0 -1
- package/dist/chunk-ZZUXHH3R.js +0 -99
- package/dist/chunk-ZZUXHH3R.js.map +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -112
- package/dist/cli.js.map +0 -1
- package/dist/contract/index.d.ts +0 -4972
- package/dist/contract/index.js +0 -1654
- package/dist/contract/index.js.map +0 -1
- package/dist/control.d.ts +0 -1013
- package/dist/control.js +0 -34
- package/dist/control.js.map +0 -1
- package/dist/fuzz.d.ts +0 -759
- package/dist/fuzz.js +0 -714
- package/dist/fuzz.js.map +0 -1
- package/dist/hosted/index.d.ts +0 -730
- package/dist/hosted/index.js +0 -14
- package/dist/hosted/index.js.map +0 -1
- package/dist/index.d.ts +0 -16780
- package/dist/index.js +0 -12168
- package/dist/index.js.map +0 -1
- package/dist/matrix/index.d.ts +0 -155
- package/dist/matrix/index.js +0 -8
- package/dist/matrix/index.js.map +0 -1
- package/dist/meta-eval/index.d.ts +0 -1030
- package/dist/meta-eval/index.js +0 -417
- package/dist/meta-eval/index.js.map +0 -1
- package/dist/multishot/index.d.ts +0 -579
- package/dist/multishot/index.js +0 -589
- package/dist/multishot/index.js.map +0 -1
- package/dist/openapi.json +0 -992
- package/dist/pipelines/index.d.ts +0 -567
- package/dist/pipelines/index.js +0 -515
- package/dist/pipelines/index.js.map +0 -1
- package/dist/reporting.d.ts +0 -1277
- package/dist/reporting.js +0 -48
- package/dist/reporting.js.map +0 -1
- package/dist/rl.d.ts +0 -4092
- package/dist/rl.js +0 -1724
- package/dist/rl.js.map +0 -1
- package/dist/run-campaign-HNFPJET4.js +0 -14
- package/dist/run-campaign-HNFPJET4.js.map +0 -1
- package/dist/storyboard/index.d.ts +0 -279
- package/dist/storyboard/index.js +0 -767
- package/dist/storyboard/index.js.map +0 -1
- package/dist/trace-attributes.d.ts +0 -52
- package/dist/trace-attributes.js +0 -62
- package/dist/trace-attributes.js.map +0 -1
- package/dist/traces.d.ts +0 -2343
- package/dist/traces.js +0 -249
- package/dist/traces.js.map +0 -1
- package/dist/wire/index.d.ts +0 -1252
- package/dist/wire/index.js +0 -81
- package/dist/wire/index.js.map +0 -1
package/dist/multishot/index.js
DELETED
|
@@ -1,589 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
runAgentMatrix
|
|
3
|
-
} from "../chunk-JHCHEVET.js";
|
|
4
|
-
import "../chunk-PZ5AY32C.js";
|
|
5
|
-
|
|
6
|
-
// src/multishot/router.ts
|
|
7
|
-
async function routerCompletion(req) {
|
|
8
|
-
const body = {
|
|
9
|
-
model: req.model,
|
|
10
|
-
messages: req.messages,
|
|
11
|
-
temperature: req.temperature ?? 0.7,
|
|
12
|
-
max_tokens: req.maxTokens ?? 2e3
|
|
13
|
-
};
|
|
14
|
-
if (req.tools?.length) body.tools = req.tools;
|
|
15
|
-
const url = `${req.baseUrl.replace(/\/+$/, "")}/chat/completions`;
|
|
16
|
-
const res = await fetch(url, {
|
|
17
|
-
method: "POST",
|
|
18
|
-
headers: { Authorization: `Bearer ${req.apiKey}`, "Content-Type": "application/json" },
|
|
19
|
-
body: JSON.stringify(body),
|
|
20
|
-
signal: req.signal
|
|
21
|
-
});
|
|
22
|
-
if (!res.ok) {
|
|
23
|
-
const text = await res.text();
|
|
24
|
-
throw new Error(`router ${res.status}: ${text.slice(0, 300)}`);
|
|
25
|
-
}
|
|
26
|
-
const json = await res.json();
|
|
27
|
-
const choice = json.choices[0];
|
|
28
|
-
if (!choice) throw new Error(`router returned no choices: ${JSON.stringify(json).slice(0, 200)}`);
|
|
29
|
-
return { message: choice.message, usage: json.usage };
|
|
30
|
-
}
|
|
31
|
-
function estimateRouterCost(model, usage) {
|
|
32
|
-
if (!usage) return 0;
|
|
33
|
-
const inputTok = usage.prompt_tokens ?? 0;
|
|
34
|
-
const outputTok = usage.completion_tokens ?? 0;
|
|
35
|
-
let inPer1k = 3e-3;
|
|
36
|
-
let outPer1k = 0.015;
|
|
37
|
-
if (model.includes("gpt-4o-mini")) {
|
|
38
|
-
inPer1k = 15e-5;
|
|
39
|
-
outPer1k = 6e-4;
|
|
40
|
-
} else if (model.includes("gpt-5.4") || model.includes("claude-sonnet")) {
|
|
41
|
-
inPer1k = 3e-3;
|
|
42
|
-
outPer1k = 0.015;
|
|
43
|
-
} else if (model.includes("kimi") || model.includes("glm") || model.includes("deepseek")) {
|
|
44
|
-
inPer1k = 5e-4;
|
|
45
|
-
outPer1k = 2e-3;
|
|
46
|
-
}
|
|
47
|
-
return (inputTok * inPer1k + outputTok * outPer1k) / 1e3;
|
|
48
|
-
}
|
|
49
|
-
function defaultRouterBaseUrl() {
|
|
50
|
-
return (process.env.TANGLE_ROUTER_BASE_URL ?? "https://router.tangle.tools/v1").replace(
|
|
51
|
-
/\/+$/,
|
|
52
|
-
""
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
function requireRouterApiKey() {
|
|
56
|
-
const key = process.env.TANGLE_API_KEY;
|
|
57
|
-
if (!key) throw new Error("multishot requires TANGLE_API_KEY (router-scoped sk-tan-* key)");
|
|
58
|
-
return key;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// src/multishot/default-tools.ts
|
|
62
|
-
var DEFAULT_RESEARCHER_MODEL = "openai/gpt-4o-mini";
|
|
63
|
-
var DEFAULT_CODER_MODEL = "openai/gpt-4o-mini";
|
|
64
|
-
var GENERIC_RESEARCHER_SYSTEM = "You are a research specialist. Return a markdown brief with 3-5 findings. Each finding cites a specific source by name. Add a confidence level (high/medium/low) per finding. No fluff, no preamble.";
|
|
65
|
-
var GENERIC_CODER_SYSTEM = "You are an expert engineer. Output ONE fenced code block containing the complete solution. Inline-comment non-obvious decisions. No explanation outside the block.";
|
|
66
|
-
var DEFAULT_DELEGATE_RESEARCH_TOOL = {
|
|
67
|
-
type: "function",
|
|
68
|
-
function: {
|
|
69
|
-
name: "delegate_research",
|
|
70
|
-
description: "Research a topic deeply via specialist. Returns evidence-bearing items with citations. Use for audience research, competitive intel, regulatory landscape, market data, citation-grounded analysis.",
|
|
71
|
-
parameters: {
|
|
72
|
-
type: "object",
|
|
73
|
-
properties: {
|
|
74
|
-
question: { type: "string", description: "Specific question to research" },
|
|
75
|
-
scope: {
|
|
76
|
-
type: "string",
|
|
77
|
-
description: "Optional scope: time window, geography, jurisdiction, segment"
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
required: ["question"]
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
var DEFAULT_DELEGATE_CODE_TOOL = {
|
|
85
|
-
type: "function",
|
|
86
|
-
function: {
|
|
87
|
-
name: "delegate_code",
|
|
88
|
-
description: "Generate a runnable script, template, pipeline, or tool via specialist. Returns complete working code or structured markdown. Use for content pipelines, calc snippets, dashboards, compliance checklists, deadline trackers.",
|
|
89
|
-
parameters: {
|
|
90
|
-
type: "object",
|
|
91
|
-
properties: {
|
|
92
|
-
goal: { type: "string", description: "What the code must accomplish" },
|
|
93
|
-
language: {
|
|
94
|
-
type: "string",
|
|
95
|
-
description: "Optional language preference (default: TypeScript)"
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
required: ["goal"]
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
function createResearchExecutor(config = {}) {
|
|
103
|
-
const systemPrompt = config.systemPrompt ?? GENERIC_RESEARCHER_SYSTEM;
|
|
104
|
-
const model = config.model ?? DEFAULT_RESEARCHER_MODEL;
|
|
105
|
-
return async (args, ctx) => {
|
|
106
|
-
const question = String(args.question ?? "");
|
|
107
|
-
const scope = args.scope ? String(args.scope) : void 0;
|
|
108
|
-
const { message, usage } = await routerCompletion({
|
|
109
|
-
apiKey: ctx.apiKey,
|
|
110
|
-
baseUrl: ctx.baseUrl,
|
|
111
|
-
model,
|
|
112
|
-
temperature: 0.3,
|
|
113
|
-
maxTokens: 1800,
|
|
114
|
-
messages: [
|
|
115
|
-
{ role: "system", content: systemPrompt },
|
|
116
|
-
{ role: "user", content: `Research: ${question}${scope ? `
|
|
117
|
-
Scope: ${scope}` : ""}` }
|
|
118
|
-
],
|
|
119
|
-
signal: ctx.signal
|
|
120
|
-
});
|
|
121
|
-
return { content: message.content ?? "", costUsd: estimateRouterCost(model, usage) };
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
function createCodeExecutor(config = {}) {
|
|
125
|
-
const systemPrompt = config.systemPrompt ?? GENERIC_CODER_SYSTEM;
|
|
126
|
-
const model = config.model ?? DEFAULT_CODER_MODEL;
|
|
127
|
-
return async (args, ctx) => {
|
|
128
|
-
const goal = String(args.goal ?? "");
|
|
129
|
-
const language = args.language ? String(args.language) : "TypeScript";
|
|
130
|
-
const { message, usage } = await routerCompletion({
|
|
131
|
-
apiKey: ctx.apiKey,
|
|
132
|
-
baseUrl: ctx.baseUrl,
|
|
133
|
-
model,
|
|
134
|
-
temperature: 0.2,
|
|
135
|
-
maxTokens: 2e3,
|
|
136
|
-
messages: [
|
|
137
|
-
{ role: "system", content: `${systemPrompt}
|
|
138
|
-
|
|
139
|
-
Language: ${language}` },
|
|
140
|
-
{ role: "user", content: `Produce: ${goal}` }
|
|
141
|
-
],
|
|
142
|
-
signal: ctx.signal
|
|
143
|
-
});
|
|
144
|
-
return { content: message.content ?? "", costUsd: estimateRouterCost(model, usage) };
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
function defaultDelegationTools(config = {}) {
|
|
148
|
-
return {
|
|
149
|
-
tools: [DEFAULT_DELEGATE_RESEARCH_TOOL, DEFAULT_DELEGATE_CODE_TOOL],
|
|
150
|
-
executors: {
|
|
151
|
-
delegate_research: createResearchExecutor(config.research),
|
|
152
|
-
delegate_code: createCodeExecutor(config.code)
|
|
153
|
-
},
|
|
154
|
-
artifactTypeFor: (name) => name === "delegate_research" ? "research" : name === "delegate_code" ? "code" : void 0
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// src/multishot/judges.ts
|
|
159
|
-
var DEFAULT_JUDGE_MODEL = "openai/gpt-4o-mini";
|
|
160
|
-
async function runJudge(judge, input) {
|
|
161
|
-
const apiKey = judge.apiKey ?? requireRouterApiKey();
|
|
162
|
-
const baseUrl = judge.baseUrl ?? defaultRouterBaseUrl();
|
|
163
|
-
const model = judge.model ?? process.env.JUDGE_MODEL ?? DEFAULT_JUDGE_MODEL;
|
|
164
|
-
const prompt = judge.buildPrompt(input);
|
|
165
|
-
let raw = "";
|
|
166
|
-
try {
|
|
167
|
-
const { message } = await routerCompletion({
|
|
168
|
-
apiKey,
|
|
169
|
-
baseUrl,
|
|
170
|
-
model,
|
|
171
|
-
temperature: 0,
|
|
172
|
-
maxTokens: judge.maxTokens ?? 1500,
|
|
173
|
-
messages: [
|
|
174
|
-
{ role: "system", content: judge.systemPrompt },
|
|
175
|
-
{ role: "user", content: prompt }
|
|
176
|
-
]
|
|
177
|
-
});
|
|
178
|
-
raw = (message.content ?? "").trim();
|
|
179
|
-
} catch (err) {
|
|
180
|
-
return {
|
|
181
|
-
dimensions: {},
|
|
182
|
-
composite: 0,
|
|
183
|
-
failed: true,
|
|
184
|
-
notes: `judge ${judge.name} call failed: ${err instanceof Error ? err.message : String(err)}`
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
let parsed = null;
|
|
188
|
-
try {
|
|
189
|
-
const cleaned = raw.replace(/^```json\s*/i, "").replace(/```\s*$/, "").trim();
|
|
190
|
-
parsed = JSON.parse(cleaned);
|
|
191
|
-
} catch {
|
|
192
|
-
return {
|
|
193
|
-
dimensions: {},
|
|
194
|
-
composite: 0,
|
|
195
|
-
failed: true,
|
|
196
|
-
notes: `judge ${judge.name} returned non-JSON: ${raw.slice(0, 200)}`
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
const dimensions = {};
|
|
200
|
-
let sum = 0;
|
|
201
|
-
for (const dim of judge.dimensions) {
|
|
202
|
-
const v = Number(parsed[dim.key] ?? 0);
|
|
203
|
-
const clamped = Number.isFinite(v) ? Math.max(0, Math.min(10, v)) : 0;
|
|
204
|
-
dimensions[dim.key] = clamped;
|
|
205
|
-
sum += clamped;
|
|
206
|
-
}
|
|
207
|
-
return {
|
|
208
|
-
dimensions,
|
|
209
|
-
composite: judge.dimensions.length === 0 ? 0 : sum / judge.dimensions.length,
|
|
210
|
-
notes: typeof parsed.notes === "string" ? parsed.notes : ""
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
function renderDimensions(dims) {
|
|
214
|
-
return dims.map((d) => `- ${d.key}: ${d.description}`).join("\n");
|
|
215
|
-
}
|
|
216
|
-
function renderJsonFooter(dims) {
|
|
217
|
-
const fields = dims.map((d) => `"${d.key}":N`).join(",");
|
|
218
|
-
return `Respond with ONLY this JSON (no markdown, no preamble):
|
|
219
|
-
{${fields},"notes":"1-2 sentence critique"}`;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// src/multishot/matrix.ts
|
|
223
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
224
|
-
import { join } from "path";
|
|
225
|
-
|
|
226
|
-
// src/multishot/types.ts
|
|
227
|
-
var MultishotDriverEmptyError = class extends Error {
|
|
228
|
-
constructor(turn) {
|
|
229
|
-
super(`multishot: driver returned empty content twice at turn ${turn} \u2014 failing loud`);
|
|
230
|
-
this.turn = turn;
|
|
231
|
-
this.name = "MultishotDriverEmptyError";
|
|
232
|
-
}
|
|
233
|
-
turn;
|
|
234
|
-
};
|
|
235
|
-
var MultishotFatalToolError = class extends Error {
|
|
236
|
-
constructor(message) {
|
|
237
|
-
super(message);
|
|
238
|
-
this.name = "MultishotFatalToolError";
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
// src/multishot/multishot.ts
|
|
243
|
-
async function runMultishot(opts) {
|
|
244
|
-
const apiKey = opts.apiKey ?? requireRouterApiKey();
|
|
245
|
-
const baseUrl = opts.baseUrl ?? defaultRouterBaseUrl();
|
|
246
|
-
const maxTurns = opts.maxTurns ?? 10;
|
|
247
|
-
const maxToolDispatches = opts.maxToolDispatches ?? 4;
|
|
248
|
-
const agentModel = opts.agentModel ?? "openai/gpt-5.4";
|
|
249
|
-
const driverModel = opts.driverModel ?? "openai/gpt-4o-mini";
|
|
250
|
-
const driverModels = [driverModel, ...opts.driverFallbackModels ?? []];
|
|
251
|
-
const agentMaxTokens = opts.agentMaxTokens ?? 2500;
|
|
252
|
-
const toolFollowupMaxTokens = opts.toolFollowupMaxTokens ?? 2e3;
|
|
253
|
-
const driverMaxTokens = opts.driverMaxTokens ?? 600;
|
|
254
|
-
const bundle = opts.tools && opts.toolExecutors ? {
|
|
255
|
-
tools: opts.tools,
|
|
256
|
-
executors: opts.toolExecutors,
|
|
257
|
-
artifactTypeFor: opts.artifactTypeFor ?? (() => void 0)
|
|
258
|
-
} : defaultDelegationTools();
|
|
259
|
-
const tools = opts.tools ?? bundle.tools;
|
|
260
|
-
const executors = opts.toolExecutors ?? bundle.executors;
|
|
261
|
-
const artifactTypeFor = opts.artifactTypeFor ?? bundle.artifactTypeFor;
|
|
262
|
-
const routerTransport = (req) => routerCompletion({ apiKey, baseUrl, ...req });
|
|
263
|
-
const agentTransport = opts.agentTransport ?? routerTransport;
|
|
264
|
-
const driverTransport = opts.driverTransport ?? routerTransport;
|
|
265
|
-
const start = Date.now();
|
|
266
|
-
const transcript = [];
|
|
267
|
-
const artifacts = [];
|
|
268
|
-
let toolCalls = 0;
|
|
269
|
-
let totalCostUsd = 0;
|
|
270
|
-
const opener = opts.shape.buildOpener(opts.persona);
|
|
271
|
-
transcript.push({ role: "user", content: opener });
|
|
272
|
-
const systemPrompt = opts.profile.prompt?.systemPrompt ?? "";
|
|
273
|
-
const agentMessages = [
|
|
274
|
-
{ role: "system", content: systemPrompt },
|
|
275
|
-
{ role: "user", content: opener }
|
|
276
|
-
];
|
|
277
|
-
for (let turn = 0; turn < maxTurns; turn++) {
|
|
278
|
-
if (opts.signal?.aborted) throw new Error("multishot aborted");
|
|
279
|
-
let dispatchesThisTurn = 0;
|
|
280
|
-
while (true) {
|
|
281
|
-
const {
|
|
282
|
-
message: agentMsg,
|
|
283
|
-
usage: agentUsage,
|
|
284
|
-
costUsd: agentCostUsd
|
|
285
|
-
} = await agentTransport({
|
|
286
|
-
model: agentModel,
|
|
287
|
-
messages: agentMessages,
|
|
288
|
-
tools,
|
|
289
|
-
temperature: 0.7,
|
|
290
|
-
maxTokens: dispatchesThisTurn === 0 ? agentMaxTokens : toolFollowupMaxTokens,
|
|
291
|
-
signal: opts.signal
|
|
292
|
-
});
|
|
293
|
-
totalCostUsd += agentCostUsd ?? estimateRouterCost(agentModel, agentUsage);
|
|
294
|
-
const agentText = (agentMsg.content ?? "").trim();
|
|
295
|
-
const agentToolCalls = (agentMsg.tool_calls ?? []).map((tc) => ({
|
|
296
|
-
id: tc.id,
|
|
297
|
-
name: tc.function.name,
|
|
298
|
-
args: (() => {
|
|
299
|
-
try {
|
|
300
|
-
return JSON.parse(tc.function.arguments);
|
|
301
|
-
} catch {
|
|
302
|
-
return {};
|
|
303
|
-
}
|
|
304
|
-
})()
|
|
305
|
-
}));
|
|
306
|
-
agentMessages.push({
|
|
307
|
-
role: "assistant",
|
|
308
|
-
content: agentText || null,
|
|
309
|
-
...agentMsg.tool_calls?.length ? { tool_calls: agentMsg.tool_calls } : {}
|
|
310
|
-
});
|
|
311
|
-
transcript.push({
|
|
312
|
-
role: "assistant",
|
|
313
|
-
content: agentText,
|
|
314
|
-
toolCalls: agentToolCalls.length > 0 ? agentToolCalls : void 0
|
|
315
|
-
});
|
|
316
|
-
if (agentToolCalls.length === 0) break;
|
|
317
|
-
dispatchesThisTurn += agentToolCalls.length;
|
|
318
|
-
if (dispatchesThisTurn > maxToolDispatches) {
|
|
319
|
-
throw new Error(
|
|
320
|
-
`multishot: tool dispatch cap exceeded (${dispatchesThisTurn}/${maxToolDispatches}) on turn ${turn}`
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
for (const tc of agentToolCalls) {
|
|
324
|
-
toolCalls++;
|
|
325
|
-
let toolResult = "";
|
|
326
|
-
try {
|
|
327
|
-
const executor = executors[tc.name];
|
|
328
|
-
if (!executor) {
|
|
329
|
-
toolResult = JSON.stringify({ error: `unknown tool ${tc.name}` });
|
|
330
|
-
} else {
|
|
331
|
-
const r = await executor(tc.args, { apiKey, baseUrl, signal: opts.signal });
|
|
332
|
-
toolResult = r.content;
|
|
333
|
-
totalCostUsd += r.costUsd;
|
|
334
|
-
const artifactType = artifactTypeFor(tc.name);
|
|
335
|
-
if (artifactType) {
|
|
336
|
-
artifacts.push({
|
|
337
|
-
type: artifactType,
|
|
338
|
-
turn,
|
|
339
|
-
invocation: { name: tc.name, args: tc.args },
|
|
340
|
-
content: toolResult
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
} catch (err) {
|
|
345
|
-
if (err instanceof MultishotFatalToolError) throw err;
|
|
346
|
-
toolResult = JSON.stringify({ error: err instanceof Error ? err.message : String(err) });
|
|
347
|
-
}
|
|
348
|
-
agentMessages.push({ role: "tool", tool_call_id: tc.id, content: toolResult || "done" });
|
|
349
|
-
transcript.push({ role: "tool", content: toolResult || "done", toolCallId: tc.id });
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
if (turn < maxTurns - 1) {
|
|
353
|
-
const driver = await driverTurn({
|
|
354
|
-
transport: driverTransport,
|
|
355
|
-
persona: opts.persona,
|
|
356
|
-
shape: opts.shape,
|
|
357
|
-
transcript,
|
|
358
|
-
turn,
|
|
359
|
-
models: driverModels,
|
|
360
|
-
maxTokens: driverMaxTokens,
|
|
361
|
-
signal: opts.signal
|
|
362
|
-
});
|
|
363
|
-
totalCostUsd += driver.costUsd;
|
|
364
|
-
agentMessages.push({ role: "user", content: driver.content });
|
|
365
|
-
transcript.push({ role: "user", content: driver.content });
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
return { transcript, artifacts, toolCalls, durationMs: Date.now() - start, costUsd: totalCostUsd };
|
|
369
|
-
}
|
|
370
|
-
async function driverTurn(opts) {
|
|
371
|
-
const driverSystem = opts.shape.buildDriverSystemPrompt(opts.persona);
|
|
372
|
-
const driverMessages = [{ role: "system", content: driverSystem }];
|
|
373
|
-
for (const msg of opts.transcript) {
|
|
374
|
-
if (msg.role === "tool") continue;
|
|
375
|
-
const content = driverVisibleContent(msg);
|
|
376
|
-
if (!content) continue;
|
|
377
|
-
if (msg.role === "assistant") driverMessages.push({ role: "user", content });
|
|
378
|
-
else if (msg.role === "user") driverMessages.push({ role: "assistant", content });
|
|
379
|
-
}
|
|
380
|
-
for (const model of opts.models) {
|
|
381
|
-
for (let attempt = 0; attempt < 2; attempt++) {
|
|
382
|
-
const { message, usage, costUsd } = await opts.transport({
|
|
383
|
-
model,
|
|
384
|
-
messages: driverMessages,
|
|
385
|
-
temperature: 0.9,
|
|
386
|
-
maxTokens: opts.maxTokens,
|
|
387
|
-
signal: opts.signal
|
|
388
|
-
});
|
|
389
|
-
const content = (message.content ?? "").trim();
|
|
390
|
-
if (content.length > 0)
|
|
391
|
-
return { content, costUsd: costUsd ?? estimateRouterCost(model, usage) };
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
throw new MultishotDriverEmptyError(opts.turn);
|
|
395
|
-
}
|
|
396
|
-
function driverVisibleContent(msg) {
|
|
397
|
-
const text = msg.content.trim();
|
|
398
|
-
if (text.length > 0) return text;
|
|
399
|
-
if (msg.role !== "assistant" || !msg.toolCalls?.length) return null;
|
|
400
|
-
const toolNames = msg.toolCalls.map((call) => call.name.trim()).filter(Boolean);
|
|
401
|
-
if (toolNames.length === 0) return "Agent called tools.";
|
|
402
|
-
return `Agent called ${toolNames.length === 1 ? "tool" : "tools"}: ${toolNames.join(", ")}.`;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// src/multishot/matrix.ts
|
|
406
|
-
function meanCompositeExcludingFailed(scores) {
|
|
407
|
-
if (scores.length === 0) return 0;
|
|
408
|
-
const live = scores.filter((s) => !s.failed);
|
|
409
|
-
if (live.length === 0) return null;
|
|
410
|
-
return live.reduce((sum, s) => sum + s.composite, 0) / live.length;
|
|
411
|
-
}
|
|
412
|
-
function computeCellComposite(input) {
|
|
413
|
-
const contributions = [];
|
|
414
|
-
if (!input.conversation.failed) contributions.push(input.conversation.composite);
|
|
415
|
-
const codeMean = input.codeReviews ? meanCompositeExcludingFailed(input.codeReviews) : void 0;
|
|
416
|
-
if (typeof codeMean === "number") contributions.push(codeMean);
|
|
417
|
-
const contentMean = input.contentReviews ? meanCompositeExcludingFailed(input.contentReviews) : void 0;
|
|
418
|
-
if (typeof contentMean === "number") contributions.push(contentMean);
|
|
419
|
-
return {
|
|
420
|
-
composite: contributions.length === 0 ? 0 : contributions.reduce((s, v) => s + v, 0) / contributions.length,
|
|
421
|
-
codeComposite: codeMean ?? 0,
|
|
422
|
-
contentComposite: contentMean ?? 0,
|
|
423
|
-
allJudgesFailed: contributions.length === 0
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
async function runMultishotMatrix(opts) {
|
|
427
|
-
const codeTypes = new Set(opts.judges.codeArtifactTypes ?? ["code"]);
|
|
428
|
-
const contentTypes = new Set(opts.judges.contentArtifactTypes ?? ["research"]);
|
|
429
|
-
mkdirSync(opts.runDir, { recursive: true });
|
|
430
|
-
const matrix = await runAgentMatrix({
|
|
431
|
-
axes: [
|
|
432
|
-
{ name: "profile", values: opts.profiles },
|
|
433
|
-
{ name: "persona", values: opts.personas.map((p) => ({ id: p.id, value: p })) }
|
|
434
|
-
],
|
|
435
|
-
reps: opts.reps ?? 1,
|
|
436
|
-
maxConcurrency: opts.maxConcurrency ?? 2,
|
|
437
|
-
costCeiling: opts.costCeiling,
|
|
438
|
-
async runCell(cell) {
|
|
439
|
-
const profile = cell.axes.profile?.value;
|
|
440
|
-
const persona = cell.axes.persona?.value;
|
|
441
|
-
const profileId = String(cell.axes.profile?.id ?? "unknown");
|
|
442
|
-
const personaId = String(cell.axes.persona?.id ?? "unknown");
|
|
443
|
-
const sim = await runMultishot({
|
|
444
|
-
profile,
|
|
445
|
-
persona,
|
|
446
|
-
shape: opts.shape,
|
|
447
|
-
tools: opts.tools,
|
|
448
|
-
toolExecutors: opts.toolExecutors,
|
|
449
|
-
artifactTypeFor: opts.artifactTypeFor,
|
|
450
|
-
maxTurns: opts.maxTurns,
|
|
451
|
-
maxToolDispatches: opts.maxToolDispatches,
|
|
452
|
-
agentModel: opts.agentModel,
|
|
453
|
-
driverModel: opts.driverModel,
|
|
454
|
-
driverFallbackModels: opts.driverFallbackModels,
|
|
455
|
-
agentMaxTokens: opts.agentMaxTokens,
|
|
456
|
-
toolFollowupMaxTokens: opts.toolFollowupMaxTokens,
|
|
457
|
-
driverMaxTokens: opts.driverMaxTokens,
|
|
458
|
-
agentTransport: opts.agentTransport,
|
|
459
|
-
driverTransport: opts.driverTransport,
|
|
460
|
-
apiKey: opts.apiKey,
|
|
461
|
-
baseUrl: opts.baseUrl
|
|
462
|
-
});
|
|
463
|
-
const codeArtifacts = sim.artifacts.filter((a) => codeTypes.has(a.type));
|
|
464
|
-
const contentArtifacts = sim.artifacts.filter((a) => contentTypes.has(a.type));
|
|
465
|
-
const [conversation, codeReviews, contentReviews] = await Promise.all([
|
|
466
|
-
runJudge(withJudgeMaxTokens(opts.judges.conversation, opts.judgeMaxTokens), {
|
|
467
|
-
transcript: sim.transcript,
|
|
468
|
-
persona
|
|
469
|
-
}),
|
|
470
|
-
opts.judges.codeReview ? Promise.all(
|
|
471
|
-
codeArtifacts.map(
|
|
472
|
-
(artifact) => runJudge(withJudgeMaxTokens(opts.judges.codeReview, opts.judgeMaxTokens), {
|
|
473
|
-
artifact,
|
|
474
|
-
persona
|
|
475
|
-
}).then((s) => ({
|
|
476
|
-
...s,
|
|
477
|
-
turn: artifact.turn,
|
|
478
|
-
type: artifact.type
|
|
479
|
-
}))
|
|
480
|
-
)
|
|
481
|
-
) : Promise.resolve([]),
|
|
482
|
-
opts.judges.contentQuality ? Promise.all(
|
|
483
|
-
contentArtifacts.map(
|
|
484
|
-
(artifact) => runJudge(withJudgeMaxTokens(opts.judges.contentQuality, opts.judgeMaxTokens), {
|
|
485
|
-
artifact,
|
|
486
|
-
persona
|
|
487
|
-
}).then((s) => ({
|
|
488
|
-
...s,
|
|
489
|
-
turn: artifact.turn,
|
|
490
|
-
type: artifact.type
|
|
491
|
-
}))
|
|
492
|
-
)
|
|
493
|
-
) : Promise.resolve([])
|
|
494
|
-
]);
|
|
495
|
-
const { composite, codeComposite, contentComposite, allJudgesFailed } = computeCellComposite({
|
|
496
|
-
conversation,
|
|
497
|
-
codeReviews: opts.judges.codeReview ? codeReviews : void 0,
|
|
498
|
-
contentReviews: opts.judges.contentQuality ? contentReviews : void 0
|
|
499
|
-
});
|
|
500
|
-
const cellScore = { composite, conversation };
|
|
501
|
-
if (opts.judges.codeReview)
|
|
502
|
-
cellScore.codeReview = { perArtifact: codeReviews, composite: codeComposite };
|
|
503
|
-
if (opts.judges.contentQuality)
|
|
504
|
-
cellScore.contentQuality = { perArtifact: contentReviews, composite: contentComposite };
|
|
505
|
-
const cellDir = join(opts.runDir, profileId, personaId, `rep-${cell.rep}`);
|
|
506
|
-
mkdirSync(cellDir, { recursive: true });
|
|
507
|
-
writeFileSync(join(cellDir, "transcript.json"), JSON.stringify(sim.transcript, null, 2));
|
|
508
|
-
writeFileSync(join(cellDir, "artifacts.json"), JSON.stringify(sim.artifacts, null, 2));
|
|
509
|
-
writeFileSync(join(cellDir, "scores.json"), JSON.stringify(cellScore, null, 2));
|
|
510
|
-
const notes = [`convo=${conversation.composite.toFixed(1)}`];
|
|
511
|
-
if (opts.judges.codeReview) notes.push(`code=${codeComposite.toFixed(1)}`);
|
|
512
|
-
if (opts.judges.contentQuality) notes.push(`content=${contentComposite.toFixed(1)}`);
|
|
513
|
-
if (allJudgesFailed) notes.push("all-judges-failed");
|
|
514
|
-
return {
|
|
515
|
-
output: {
|
|
516
|
-
turns: sim.transcript.length,
|
|
517
|
-
toolCalls: sim.toolCalls,
|
|
518
|
-
artifactCount: sim.artifacts.length
|
|
519
|
-
},
|
|
520
|
-
verdict: { valid: composite >= 5, score: composite, notes: notes.join(" ") },
|
|
521
|
-
costUsd: sim.costUsd,
|
|
522
|
-
durationMs: sim.durationMs
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
const summary = {
|
|
527
|
-
cells: matrix.summary.totalCells,
|
|
528
|
-
passRate: matrix.summary.overallPassRate,
|
|
529
|
-
meanScore: matrix.summary.overallMeanScore,
|
|
530
|
-
totalCostUsd: matrix.summary.totalCostUsd,
|
|
531
|
-
durationMs: matrix.summary.durationMs,
|
|
532
|
-
runsExecuted: matrix.summary.runsExecuted,
|
|
533
|
-
cellsSkipped: matrix.summary.cellsSkipped,
|
|
534
|
-
byProfile: matrix.byAxis.profile,
|
|
535
|
-
byPersona: matrix.byAxis.persona
|
|
536
|
-
};
|
|
537
|
-
writeFileSync(join(opts.runDir, "summary.json"), JSON.stringify(summary, null, 2));
|
|
538
|
-
const md = [
|
|
539
|
-
`# Multishot matrix`,
|
|
540
|
-
``,
|
|
541
|
-
`**Cells**: ${matrix.summary.totalCells} | **Pass rate**: ${(matrix.summary.overallPassRate * 100).toFixed(0)}% | **Mean**: ${matrix.summary.overallMeanScore.toFixed(2)} | **Cost**: $${matrix.summary.totalCostUsd.toFixed(2)} | **Duration**: ${(matrix.summary.durationMs / 1e3).toFixed(0)}s`,
|
|
542
|
-
``,
|
|
543
|
-
`## By profile`,
|
|
544
|
-
``,
|
|
545
|
-
"| profile | pass | mean | cost |",
|
|
546
|
-
"|---|---|---|---|",
|
|
547
|
-
...Object.entries(matrix.byAxis.profile ?? {}).map(
|
|
548
|
-
([id, s]) => `| ${id} | ${(s.passRate * 100).toFixed(0)}% | ${s.meanScore.toFixed(2)} | $${s.totalCostUsd.toFixed(2)} |`
|
|
549
|
-
),
|
|
550
|
-
``,
|
|
551
|
-
`## By persona`,
|
|
552
|
-
``,
|
|
553
|
-
"| persona | pass | mean | cost |",
|
|
554
|
-
"|---|---|---|---|",
|
|
555
|
-
...Object.entries(matrix.byAxis.persona ?? {}).map(
|
|
556
|
-
([id, s]) => `| ${id} | ${(s.passRate * 100).toFixed(0)}% | ${s.meanScore.toFixed(2)} | $${s.totalCostUsd.toFixed(2)} |`
|
|
557
|
-
),
|
|
558
|
-
``
|
|
559
|
-
];
|
|
560
|
-
writeFileSync(join(opts.runDir, "summary.md"), md.join("\n"));
|
|
561
|
-
return { matrix };
|
|
562
|
-
}
|
|
563
|
-
function withJudgeMaxTokens(judge, maxTokens) {
|
|
564
|
-
if (maxTokens === void 0 || judge.maxTokens !== void 0) return judge;
|
|
565
|
-
return { ...judge, maxTokens };
|
|
566
|
-
}
|
|
567
|
-
export {
|
|
568
|
-
DEFAULT_CODER_MODEL,
|
|
569
|
-
DEFAULT_DELEGATE_CODE_TOOL,
|
|
570
|
-
DEFAULT_DELEGATE_RESEARCH_TOOL,
|
|
571
|
-
DEFAULT_JUDGE_MODEL,
|
|
572
|
-
DEFAULT_RESEARCHER_MODEL,
|
|
573
|
-
MultishotDriverEmptyError,
|
|
574
|
-
MultishotFatalToolError,
|
|
575
|
-
computeCellComposite,
|
|
576
|
-
createCodeExecutor,
|
|
577
|
-
createResearchExecutor,
|
|
578
|
-
defaultDelegationTools,
|
|
579
|
-
defaultRouterBaseUrl,
|
|
580
|
-
estimateRouterCost,
|
|
581
|
-
renderDimensions,
|
|
582
|
-
renderJsonFooter,
|
|
583
|
-
requireRouterApiKey,
|
|
584
|
-
routerCompletion,
|
|
585
|
-
runJudge,
|
|
586
|
-
runMultishot,
|
|
587
|
-
runMultishotMatrix
|
|
588
|
-
};
|
|
589
|
-
//# sourceMappingURL=index.js.map
|