@tangle-network/agent-eval 0.120.2 → 0.120.4

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 (172) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/analyst/index.d.ts +3111 -0
  3. package/dist/analyst/index.js +403 -0
  4. package/dist/analyst/index.js.map +1 -0
  5. package/dist/authenticity/index.d.ts +161 -0
  6. package/dist/authenticity/index.js +215 -0
  7. package/dist/authenticity/index.js.map +1 -0
  8. package/dist/belief-state/index.d.ts +1301 -0
  9. package/dist/belief-state/index.js +2152 -0
  10. package/dist/belief-state/index.js.map +1 -0
  11. package/dist/benchmarks/index.d.ts +974 -0
  12. package/dist/benchmarks/index.js +60 -0
  13. package/dist/benchmarks/index.js.map +1 -0
  14. package/dist/builder-eval/index.d.ts +695 -0
  15. package/dist/builder-eval/index.js +366 -0
  16. package/dist/builder-eval/index.js.map +1 -0
  17. package/dist/campaign/index.d.ts +7469 -0
  18. package/dist/campaign/index.js +272 -0
  19. package/dist/campaign/index.js.map +1 -0
  20. package/dist/chunk-3RF76KTD.js +84 -0
  21. package/dist/chunk-3RF76KTD.js.map +1 -0
  22. package/dist/chunk-3XH4Y2SS.js +750 -0
  23. package/dist/chunk-3XH4Y2SS.js.map +1 -0
  24. package/dist/chunk-3YYRZDON.js +45 -0
  25. package/dist/chunk-3YYRZDON.js.map +1 -0
  26. package/dist/chunk-5BYTIDZ7.js +550 -0
  27. package/dist/chunk-5BYTIDZ7.js.map +1 -0
  28. package/dist/chunk-5CVUPHJ4.js +2668 -0
  29. package/dist/chunk-5CVUPHJ4.js.map +1 -0
  30. package/dist/chunk-7QBFOJ3E.js +3920 -0
  31. package/dist/chunk-7QBFOJ3E.js.map +1 -0
  32. package/dist/chunk-ARU2PZFM.js +312 -0
  33. package/dist/chunk-ARU2PZFM.js.map +1 -0
  34. package/dist/chunk-BOD4O7OF.js +40 -0
  35. package/dist/chunk-BOD4O7OF.js.map +1 -0
  36. package/dist/chunk-CVJP5TMD.js +766 -0
  37. package/dist/chunk-CVJP5TMD.js.map +1 -0
  38. package/dist/chunk-DPZAEKA6.js +880 -0
  39. package/dist/chunk-DPZAEKA6.js.map +1 -0
  40. package/dist/chunk-DTJ6QUQB.js +131 -0
  41. package/dist/chunk-DTJ6QUQB.js.map +1 -0
  42. package/dist/chunk-GGE4NNQT.js +65 -0
  43. package/dist/chunk-GGE4NNQT.js.map +1 -0
  44. package/dist/chunk-H5UD2323.js +286 -0
  45. package/dist/chunk-H5UD2323.js.map +1 -0
  46. package/dist/chunk-HHWE3POT.js +94 -0
  47. package/dist/chunk-HHWE3POT.js.map +1 -0
  48. package/dist/chunk-HKUCJ437.js +787 -0
  49. package/dist/chunk-HKUCJ437.js.map +1 -0
  50. package/dist/chunk-JHCHEVET.js +274 -0
  51. package/dist/chunk-JHCHEVET.js.map +1 -0
  52. package/dist/chunk-K4DBDHLK.js +158 -0
  53. package/dist/chunk-K4DBDHLK.js.map +1 -0
  54. package/dist/chunk-K6N6XJJX.js +306 -0
  55. package/dist/chunk-K6N6XJJX.js.map +1 -0
  56. package/dist/chunk-MA6HLL3S.js +65 -0
  57. package/dist/chunk-MA6HLL3S.js.map +1 -0
  58. package/dist/chunk-MAZ26DC7.js +99 -0
  59. package/dist/chunk-MAZ26DC7.js.map +1 -0
  60. package/dist/chunk-MOXWMGPC.js +577 -0
  61. package/dist/chunk-MOXWMGPC.js.map +1 -0
  62. package/dist/chunk-NJC7U437.js +626 -0
  63. package/dist/chunk-NJC7U437.js.map +1 -0
  64. package/dist/chunk-NMN4WGSJ.js +1030 -0
  65. package/dist/chunk-NMN4WGSJ.js.map +1 -0
  66. package/dist/chunk-NPCTHQIO.js +91 -0
  67. package/dist/chunk-NPCTHQIO.js.map +1 -0
  68. package/dist/chunk-ONWEPEDO.js +57 -0
  69. package/dist/chunk-ONWEPEDO.js.map +1 -0
  70. package/dist/chunk-OYZAPX5G.js +1526 -0
  71. package/dist/chunk-OYZAPX5G.js.map +1 -0
  72. package/dist/chunk-PC4UYEBM.js +166 -0
  73. package/dist/chunk-PC4UYEBM.js.map +1 -0
  74. package/dist/chunk-PJQFMIOX.js +1182 -0
  75. package/dist/chunk-PJQFMIOX.js.map +1 -0
  76. package/dist/chunk-PXD6ZFNY.js +1107 -0
  77. package/dist/chunk-PXD6ZFNY.js.map +1 -0
  78. package/dist/chunk-PXE2VKMX.js +140 -0
  79. package/dist/chunk-PXE2VKMX.js.map +1 -0
  80. package/dist/chunk-PZ5AY32C.js +10 -0
  81. package/dist/chunk-PZ5AY32C.js.map +1 -0
  82. package/dist/chunk-QBRSJK47.js +622 -0
  83. package/dist/chunk-QBRSJK47.js.map +1 -0
  84. package/dist/chunk-S3UZOQ5Y.js +328 -0
  85. package/dist/chunk-S3UZOQ5Y.js.map +1 -0
  86. package/dist/chunk-SQQED7ZH.js +998 -0
  87. package/dist/chunk-SQQED7ZH.js.map +1 -0
  88. package/dist/chunk-SYV364BL.js +1266 -0
  89. package/dist/chunk-SYV364BL.js.map +1 -0
  90. package/dist/chunk-T4SQEITX.js +95 -0
  91. package/dist/chunk-T4SQEITX.js.map +1 -0
  92. package/dist/chunk-TT4KNT67.js +124 -0
  93. package/dist/chunk-TT4KNT67.js.map +1 -0
  94. package/dist/chunk-U5CHZ5M3.js +357 -0
  95. package/dist/chunk-U5CHZ5M3.js.map +1 -0
  96. package/dist/chunk-ULOKLHIQ.js +1937 -0
  97. package/dist/chunk-ULOKLHIQ.js.map +1 -0
  98. package/dist/chunk-VI2UW6B6.js +162 -0
  99. package/dist/chunk-VI2UW6B6.js.map +1 -0
  100. package/dist/chunk-VQMK5FMP.js +247 -0
  101. package/dist/chunk-VQMK5FMP.js.map +1 -0
  102. package/dist/chunk-VSMTAMNK.js +53 -0
  103. package/dist/chunk-VSMTAMNK.js.map +1 -0
  104. package/dist/chunk-VZSRQ272.js +149 -0
  105. package/dist/chunk-VZSRQ272.js.map +1 -0
  106. package/dist/chunk-WW2A73HW.js +159 -0
  107. package/dist/chunk-WW2A73HW.js.map +1 -0
  108. package/dist/chunk-X4UCIOTZ.js +136 -0
  109. package/dist/chunk-X4UCIOTZ.js.map +1 -0
  110. package/dist/chunk-XJYR7XFV.js +317 -0
  111. package/dist/chunk-XJYR7XFV.js.map +1 -0
  112. package/dist/chunk-ZET2UAYW.js +89 -0
  113. package/dist/chunk-ZET2UAYW.js.map +1 -0
  114. package/dist/chunk-ZMXDQ4K7.js +870 -0
  115. package/dist/chunk-ZMXDQ4K7.js.map +1 -0
  116. package/dist/chunk-ZTJPIIVI.js +7958 -0
  117. package/dist/chunk-ZTJPIIVI.js.map +1 -0
  118. package/dist/chunk-ZZUXHH3R.js +99 -0
  119. package/dist/chunk-ZZUXHH3R.js.map +1 -0
  120. package/dist/cli.d.ts +1 -0
  121. package/dist/cli.js +112 -0
  122. package/dist/cli.js.map +1 -0
  123. package/dist/contract/index.d.ts +4987 -0
  124. package/dist/contract/index.js +1654 -0
  125. package/dist/contract/index.js.map +1 -0
  126. package/dist/control.d.ts +1013 -0
  127. package/dist/control.js +34 -0
  128. package/dist/control.js.map +1 -0
  129. package/dist/fuzz.d.ts +759 -0
  130. package/dist/fuzz.js +714 -0
  131. package/dist/fuzz.js.map +1 -0
  132. package/dist/hosted/index.d.ts +730 -0
  133. package/dist/hosted/index.js +14 -0
  134. package/dist/hosted/index.js.map +1 -0
  135. package/dist/index.d.ts +16780 -0
  136. package/dist/index.js +12168 -0
  137. package/dist/index.js.map +1 -0
  138. package/dist/matrix/index.d.ts +155 -0
  139. package/dist/matrix/index.js +8 -0
  140. package/dist/matrix/index.js.map +1 -0
  141. package/dist/meta-eval/index.d.ts +1030 -0
  142. package/dist/meta-eval/index.js +417 -0
  143. package/dist/meta-eval/index.js.map +1 -0
  144. package/dist/multishot/index.d.ts +579 -0
  145. package/dist/multishot/index.js +589 -0
  146. package/dist/multishot/index.js.map +1 -0
  147. package/dist/openapi.json +992 -0
  148. package/dist/pipelines/index.d.ts +567 -0
  149. package/dist/pipelines/index.js +515 -0
  150. package/dist/pipelines/index.js.map +1 -0
  151. package/dist/reporting.d.ts +1277 -0
  152. package/dist/reporting.js +48 -0
  153. package/dist/reporting.js.map +1 -0
  154. package/dist/rl.d.ts +4092 -0
  155. package/dist/rl.js +1724 -0
  156. package/dist/rl.js.map +1 -0
  157. package/dist/run-campaign-75RTPVV5.js +14 -0
  158. package/dist/run-campaign-75RTPVV5.js.map +1 -0
  159. package/dist/storyboard/index.d.ts +279 -0
  160. package/dist/storyboard/index.js +767 -0
  161. package/dist/storyboard/index.js.map +1 -0
  162. package/dist/trace-attributes.d.ts +52 -0
  163. package/dist/trace-attributes.js +62 -0
  164. package/dist/trace-attributes.js.map +1 -0
  165. package/dist/traces.d.ts +2343 -0
  166. package/dist/traces.js +249 -0
  167. package/dist/traces.js.map +1 -0
  168. package/dist/wire/index.d.ts +1252 -0
  169. package/dist/wire/index.js +81 -0
  170. package/dist/wire/index.js.map +1 -0
  171. package/docs/eval-surface-map.md +1 -1
  172. package/package.json +1 -1
@@ -0,0 +1,589 @@
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