@tangle-network/agent-eval 0.221.3 → 0.221.6
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 +159 -0
- package/README.md +0 -1
- package/dist/adapters/http.d.ts +2 -2
- package/dist/{agent-profile-Bc7ADJY4.d.ts → agent-profile-CNmwfaqq.d.ts} +3 -3
- package/dist/{agent-profile-Bc7ADJY4.d.ts.map → agent-profile-CNmwfaqq.d.ts.map} +1 -1
- package/dist/analyst/index.d.ts +14 -14
- package/dist/analyst/index.js +11 -11
- package/dist/analyst/index.js.map +1 -1
- package/dist/{analyze-runs-D7In4c3z.d.ts → analyze-runs-DfX6dHP0.d.ts} +2 -2
- package/dist/{analyze-runs-D7In4c3z.d.ts.map → analyze-runs-DfX6dHP0.d.ts.map} +1 -1
- package/dist/{benchmark-command-BDq0VgoP.js → benchmark-command-Cnjfo0Zh.js} +6 -6
- package/dist/{benchmark-command-BDq0VgoP.js.map → benchmark-command-Cnjfo0Zh.js.map} +1 -1
- package/dist/benchmarks/index.d.ts +4 -4
- package/dist/benchmarks/index.js +3 -3
- package/dist/campaign/index.d.ts +6 -6
- package/dist/campaign/index.js +4 -4
- package/dist/{campaign-Bt6rbWIU.js → campaign-uddTlFg5.js} +6 -6
- package/dist/{campaign-Bt6rbWIU.js.map → campaign-uddTlFg5.js.map} +1 -1
- package/dist/{chat-client-CMQ8_h4J.js → chat-client-BNATB3rJ.js} +2 -2
- package/dist/{chat-client-CMQ8_h4J.js.map → chat-client-BNATB3rJ.js.map} +1 -1
- package/dist/{chat-json-call-BrZKn0L3.js → chat-json-call-BzWYp18J.js} +2 -2
- package/dist/{chat-json-call-BrZKn0L3.js.map → chat-json-call-BzWYp18J.js.map} +1 -1
- package/dist/cli.js +3 -3
- package/dist/{completion-verifier-YwoeujPl.js → completion-verifier-asaV1nSj.js} +3 -3
- package/dist/{completion-verifier-YwoeujPl.js.map → completion-verifier-asaV1nSj.js.map} +1 -1
- package/dist/contract/index.d.ts +10 -10
- package/dist/contract/index.js +6 -6
- package/dist/{default-registry-BZ5FyYl9.js → default-registry-BBTDgkDM.js} +2 -2
- package/dist/{default-registry-BZ5FyYl9.js.map → default-registry-BBTDgkDM.js.map} +1 -1
- package/dist/{default-registry-BMHqNR6_.d.ts → default-registry-CLG5YqGS.d.ts} +7 -7
- package/dist/{default-registry-BMHqNR6_.d.ts.map → default-registry-CLG5YqGS.d.ts.map} +1 -1
- package/dist/{define-agent-eval-CJhECJNL.js → define-agent-eval-CCbT7Kfr.js} +3 -3
- package/dist/{define-agent-eval-CJhECJNL.js.map → define-agent-eval-CCbT7Kfr.js.map} +1 -1
- package/dist/{define-agent-eval-Bsoi2GUV.d.ts → define-agent-eval-JKt3gMQr.d.ts} +7 -7
- package/dist/{define-agent-eval-Bsoi2GUV.d.ts.map → define-agent-eval-JKt3gMQr.d.ts.map} +1 -1
- package/dist/diagnosis/index.d.ts +2 -2
- package/dist/{dspy-rlm-engine-BTy7u0jQ.js → dspy-rlm-engine-DN1p_5jx.js} +2 -2
- package/dist/{dspy-rlm-engine-BTy7u0jQ.js.map → dspy-rlm-engine-DN1p_5jx.js.map} +1 -1
- package/dist/{engine-BF95CWzH.d.ts → engine-dtRVeuQs.d.ts} +2 -2
- package/dist/{engine-BF95CWzH.d.ts.map → engine-dtRVeuQs.d.ts.map} +1 -1
- package/dist/{evaluation-D1PGzkPR.d.ts → evaluation-DblGquCB.d.ts} +3 -3
- package/dist/{evaluation-D1PGzkPR.d.ts.map → evaluation-DblGquCB.d.ts.map} +1 -1
- package/dist/evaluation.d.ts +1 -1
- package/dist/{exact-types-CVn1QxFO.d.ts → exact-types-Do63KoKn.d.ts} +2 -2
- package/dist/{exact-types-CVn1QxFO.d.ts.map → exact-types-Do63KoKn.d.ts.map} +1 -1
- package/dist/experiment/index.d.ts +1 -1
- package/dist/{external-optimizer-process-E5yY2SYS.js → external-optimizer-process-DEzJ2CGX.js} +2 -2
- package/dist/{external-optimizer-process-E5yY2SYS.js.map → external-optimizer-process-DEzJ2CGX.js.map} +1 -1
- package/dist/{external-optimizer-subprocess-DA02c_L6.js → external-optimizer-subprocess-B_ukPtRD.js} +2 -2
- package/dist/{external-optimizer-subprocess-DA02c_L6.js.map → external-optimizer-subprocess-B_ukPtRD.js.map} +1 -1
- package/dist/{feedback-trajectory-BZhVCWuz.d.ts → feedback-trajectory-CYVJXolG.d.ts} +3 -3
- package/dist/{feedback-trajectory-BZhVCWuz.d.ts.map → feedback-trajectory-CYVJXolG.d.ts.map} +1 -1
- package/dist/{findings-store-DRiFdoid.js → findings-store-Bg4sdS-e.js} +4 -4
- package/dist/{findings-store-DRiFdoid.js.map → findings-store-Bg4sdS-e.js.map} +1 -1
- package/dist/{index-BJZ7s-sv.d.ts → index-CTIRz-AB.d.ts} +7 -7
- package/dist/{index-BJZ7s-sv.d.ts.map → index-CTIRz-AB.d.ts.map} +1 -1
- package/dist/{index-BvX3CFNS.d.ts → index-CdEVr8-O.d.ts} +7 -7
- package/dist/{index-BvX3CFNS.d.ts.map → index-CdEVr8-O.d.ts.map} +1 -1
- package/dist/{index-DWd1gUwR.d.ts → index-CfJULcW5.d.ts} +116 -3
- package/dist/index-CfJULcW5.d.ts.map +1 -0
- package/dist/{index-y7i8l6Y_.d.ts → index-jnuFLxOs.d.ts} +8 -8
- package/dist/{index-y7i8l6Y_.d.ts.map → index-jnuFLxOs.d.ts.map} +1 -1
- package/dist/index.d.ts +21 -21
- package/dist/index.js +11 -90
- package/dist/index.js.map +1 -1
- package/dist/{integrity-CCwvezWS.d.ts → integrity-D9lBnv_K.d.ts} +2 -2
- package/dist/{integrity-CCwvezWS.d.ts.map → integrity-D9lBnv_K.d.ts.map} +1 -1
- package/dist/{judge-gate-Co5tuh57.js → judge-gate-BVvmP00P.js} +82 -2
- package/dist/judge-gate-BVvmP00P.js.map +1 -0
- package/dist/{llm-client-DXuOTseU.js → llm-client-b1ysZVIU.js} +7 -6
- package/dist/llm-client-b1ysZVIU.js.map +1 -0
- package/dist/{llm-judge-3uAeRawE.js → llm-judge-Cybq29bL.js} +4 -4
- package/dist/{llm-judge-3uAeRawE.js.map → llm-judge-Cybq29bL.js.map} +1 -1
- package/dist/{matrix-BXo3PSqM.d.ts → matrix-DtkZLD_3.d.ts} +2 -2
- package/dist/{matrix-BXo3PSqM.d.ts.map → matrix-DtkZLD_3.d.ts.map} +1 -1
- package/dist/meta-eval/index.d.ts +2 -2
- package/dist/meta-eval/index.js +217 -2
- package/dist/meta-eval/index.js.map +1 -1
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/index.d.ts +47 -3
- package/dist/multishot/index.d.ts.map +1 -1
- package/dist/multishot/index.js +257 -216
- package/dist/multishot/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/{prime-protocol-BEaqBoQE.d.ts → prime-protocol-BGxjfhM4.d.ts} +2 -2
- package/dist/{prime-protocol-BEaqBoQE.d.ts.map → prime-protocol-BGxjfhM4.d.ts.map} +1 -1
- package/dist/{proposal-findings-D0_zkQ2l.js → proposal-findings-DqLUWsAG.js} +2 -2
- package/dist/{proposal-findings-D0_zkQ2l.js.map → proposal-findings-DqLUWsAG.js.map} +1 -1
- package/dist/{registry-DDKaUrmM.d.ts → registry-BcdJmyoU.d.ts} +4 -4
- package/dist/{registry-DDKaUrmM.d.ts.map → registry-BcdJmyoU.d.ts.map} +1 -1
- package/dist/{researcher-H0p44OYC.d.ts → researcher-DKWtoMWk.d.ts} +3 -3
- package/dist/{researcher-H0p44OYC.d.ts.map → researcher-DKWtoMWk.d.ts.map} +1 -1
- package/dist/rl.d.ts +4 -4
- package/dist/search/index.d.ts +2 -2
- package/dist/{search-kernel-C6__V0IS.d.ts → search-kernel-CctpiDd2.d.ts} +2 -2
- package/dist/{search-kernel-C6__V0IS.d.ts.map → search-kernel-CctpiDd2.d.ts.map} +1 -1
- package/dist/{server-8TS8XCvg.js → server-ChhXPCgX.js} +2 -2
- package/dist/{server-8TS8XCvg.js.map → server-ChhXPCgX.js.map} +1 -1
- package/dist/{skillopt-optimization-method-D21dH_Bh.js → skillopt-optimization-method-sB_-yi1G.js} +5 -5
- package/dist/{skillopt-optimization-method-D21dH_Bh.js.map → skillopt-optimization-method-sB_-yi1G.js.map} +1 -1
- package/dist/{statistical-heldout-pD1Yah-0.d.ts → statistical-heldout-BjzSOmLH.d.ts} +3 -3
- package/dist/{statistical-heldout-pD1Yah-0.d.ts.map → statistical-heldout-BjzSOmLH.d.ts.map} +1 -1
- package/dist/{store-tool-spans-Bf9OVKs6.d.ts → store-tool-spans-DxsFwtdr.d.ts} +5 -5
- package/dist/{store-tool-spans-Bf9OVKs6.d.ts.map → store-tool-spans-DxsFwtdr.d.ts.map} +1 -1
- package/dist/{systemone-D3MrW63C.d.ts → systemone-CHnqwmYg.d.ts} +6 -6
- package/dist/{systemone-D3MrW63C.d.ts.map → systemone-CHnqwmYg.d.ts.map} +1 -1
- package/dist/{systemone-review-C8DRiT_-.d.ts → systemone-review-cQ9acAsb.d.ts} +2 -2
- package/dist/{systemone-review-C8DRiT_-.d.ts.map → systemone-review-cQ9acAsb.d.ts.map} +1 -1
- package/dist/systemone.d.ts +3 -3
- package/dist/{tool-groups-DK1bu5TD.d.ts → tool-groups-b3oU_D88.d.ts} +3 -3
- package/dist/tool-groups-b3oU_D88.d.ts.map +1 -0
- package/dist/{trace-questions-D_OKYZ6u.d.ts → trace-questions-BmT8M6UQ.d.ts} +3 -3
- package/dist/{trace-questions-D_OKYZ6u.d.ts.map → trace-questions-BmT8M6UQ.d.ts.map} +1 -1
- package/dist/trace-repair/index.d.ts +1 -1
- package/dist/traces.d.ts +5 -5
- package/dist/{types-DGImvHIr.d.ts → types-6Lfdlshp.d.ts} +2 -2
- package/dist/{types-DGImvHIr.d.ts.map → types-6Lfdlshp.d.ts.map} +1 -1
- package/dist/{types-eMhdacVp.d.ts → types-B_IFcKp5.d.ts} +12 -2
- package/dist/types-B_IFcKp5.d.ts.map +1 -0
- package/dist/{types-IERw_HxR.d.ts → types-DZ0mYVw9.d.ts} +2 -2
- package/dist/{types-IERw_HxR.d.ts.map → types-DZ0mYVw9.d.ts.map} +1 -1
- package/dist/{types-DDKfH-N6.d.ts → types-M6eF9m-r.d.ts} +3 -3
- package/dist/{types-DDKfH-N6.d.ts.map → types-M6eF9m-r.d.ts.map} +1 -1
- package/dist/wire/index.d.ts +2 -2
- package/dist/wire/index.js +1 -1
- package/docs/finding-layers.md +3 -1
- package/docs/multishot-golden-records.md +1 -0
- package/package.json +1 -1
- package/dist/index-DWd1gUwR.d.ts.map +0 -1
- package/dist/judge-gate-Co5tuh57.js.map +0 -1
- package/dist/llm-client-DXuOTseU.js.map +0 -1
- package/dist/tool-groups-DK1bu5TD.d.ts.map +0 -1
- package/dist/types-eMhdacVp.d.ts.map +0 -1
package/dist/multishot/index.js
CHANGED
|
@@ -138,140 +138,6 @@ function defaultDelegationTools(config = {}) {
|
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
//#endregion
|
|
141
|
-
//#region src/multishot/judges.ts
|
|
142
|
-
const DEFAULT_JUDGE_MODEL = "openai/gpt-4o-mini";
|
|
143
|
-
async function runJudge(judge, input) {
|
|
144
|
-
const model = judge.model ?? "openai/gpt-4o-mini";
|
|
145
|
-
const prompt = judge.buildPrompt(input);
|
|
146
|
-
let raw = "";
|
|
147
|
-
let llmCall;
|
|
148
|
-
let cost;
|
|
149
|
-
const startedAt = Date.now();
|
|
150
|
-
try {
|
|
151
|
-
const response = await judge.transport({
|
|
152
|
-
model,
|
|
153
|
-
temperature: 0,
|
|
154
|
-
maxTokens: judge.maxTokens ?? 1500,
|
|
155
|
-
messages: [{
|
|
156
|
-
role: "system",
|
|
157
|
-
content: judge.systemPrompt
|
|
158
|
-
}, {
|
|
159
|
-
role: "user",
|
|
160
|
-
content: prompt
|
|
161
|
-
}]
|
|
162
|
-
});
|
|
163
|
-
const call = judgeCallMetadata(response, model, Date.now() - startedAt);
|
|
164
|
-
llmCall = call.llmCall;
|
|
165
|
-
cost = call.cost;
|
|
166
|
-
raw = (response.message.content ?? "").trim();
|
|
167
|
-
} catch (err) {
|
|
168
|
-
return {
|
|
169
|
-
score: {
|
|
170
|
-
dimensions: {},
|
|
171
|
-
composite: 0,
|
|
172
|
-
failed: true,
|
|
173
|
-
notes: `judge ${judge.name} call failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
174
|
-
llmCall: unknownJudgeCall(model, Date.now() - startedAt)
|
|
175
|
-
},
|
|
176
|
-
cost: {
|
|
177
|
-
kind: "uncaptured",
|
|
178
|
-
usd: null
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
let parsed = null;
|
|
183
|
-
try {
|
|
184
|
-
const cleaned = raw.replace(/^```json\s*/i, "").replace(/```\s*$/, "").trim();
|
|
185
|
-
parsed = JSON.parse(cleaned);
|
|
186
|
-
} catch {
|
|
187
|
-
return {
|
|
188
|
-
score: {
|
|
189
|
-
dimensions: {},
|
|
190
|
-
composite: 0,
|
|
191
|
-
failed: true,
|
|
192
|
-
notes: `judge ${judge.name} returned non-JSON: ${raw.slice(0, 200)}`,
|
|
193
|
-
llmCall
|
|
194
|
-
},
|
|
195
|
-
cost
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
const dimensions = {};
|
|
199
|
-
let sum = 0;
|
|
200
|
-
for (const dim of judge.dimensions) {
|
|
201
|
-
const v = Number(parsed[dim.key] ?? 0);
|
|
202
|
-
const clamped = Number.isFinite(v) ? Math.max(0, Math.min(10, v)) : 0;
|
|
203
|
-
dimensions[dim.key] = clamped;
|
|
204
|
-
sum += clamped;
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
score: {
|
|
208
|
-
dimensions,
|
|
209
|
-
composite: judge.dimensions.length === 0 ? 0 : sum / judge.dimensions.length,
|
|
210
|
-
notes: typeof parsed.notes === "string" ? parsed.notes : "",
|
|
211
|
-
llmCall
|
|
212
|
-
},
|
|
213
|
-
cost
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
function judgeCallMetadata(response, requestedModel, durationMs) {
|
|
217
|
-
const usage = canonicalUsage(response.usage);
|
|
218
|
-
const model = response.model ?? requestedModel;
|
|
219
|
-
return {
|
|
220
|
-
llmCall: {
|
|
221
|
-
usage,
|
|
222
|
-
costUsd: response.costUsd ?? null,
|
|
223
|
-
model,
|
|
224
|
-
durationMs
|
|
225
|
-
},
|
|
226
|
-
cost: response.costUsd !== void 0 ? {
|
|
227
|
-
kind: "observed",
|
|
228
|
-
usd: response.costUsd
|
|
229
|
-
} : usage.captured === false || !isModelPriced(model) ? {
|
|
230
|
-
kind: "uncaptured",
|
|
231
|
-
usd: null
|
|
232
|
-
} : {
|
|
233
|
-
kind: "estimated",
|
|
234
|
-
usd: estimateCost(usage.promptTokens, usage.completionTokens, model)
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
function canonicalUsage(usage) {
|
|
239
|
-
const promptTokens = tokenCount(usage?.prompt_tokens);
|
|
240
|
-
const completionTokens = tokenCount(usage?.completion_tokens);
|
|
241
|
-
const captured = promptTokens !== void 0 && completionTokens !== void 0;
|
|
242
|
-
return {
|
|
243
|
-
promptTokens: promptTokens ?? 0,
|
|
244
|
-
completionTokens: completionTokens ?? 0,
|
|
245
|
-
totalTokens: (promptTokens ?? 0) + (completionTokens ?? 0),
|
|
246
|
-
captured
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
function unknownJudgeCall(model, durationMs) {
|
|
250
|
-
return {
|
|
251
|
-
usage: {
|
|
252
|
-
promptTokens: 0,
|
|
253
|
-
completionTokens: 0,
|
|
254
|
-
totalTokens: 0,
|
|
255
|
-
captured: false
|
|
256
|
-
},
|
|
257
|
-
costUsd: null,
|
|
258
|
-
model,
|
|
259
|
-
durationMs
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
function tokenCount(value) {
|
|
263
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
264
|
-
}
|
|
265
|
-
/** Convenience: stringified dimension list for inclusion in a judge prompt.
|
|
266
|
-
* Returns lines like `- audience_fit: Does this match what the audience cares about? (0-10)`. */
|
|
267
|
-
function renderDimensions(dims) {
|
|
268
|
-
return dims.map((d) => `- ${d.key}: ${d.description}`).join("\n");
|
|
269
|
-
}
|
|
270
|
-
/** Convenience: build the "Respond with ONLY this JSON" footer for a judge prompt. */
|
|
271
|
-
function renderJsonFooter(dims) {
|
|
272
|
-
return `Respond with ONLY this JSON (no markdown, no preamble):\n{${dims.map((d) => `"${d.key}":N`).join(",")},"notes":"1-2 sentence critique"}`;
|
|
273
|
-
}
|
|
274
|
-
//#endregion
|
|
275
141
|
//#region src/multishot/shape-defaults.ts
|
|
276
142
|
/** Persona payload rendered as stable `- key: value` lines. `id` is identity,
|
|
277
143
|
* not voice, and structured values are serialized so nothing is dropped. */
|
|
@@ -321,31 +187,37 @@ function defaultShapeFromProfile(profile, shape) {
|
|
|
321
187
|
};
|
|
322
188
|
}
|
|
323
189
|
//#endregion
|
|
324
|
-
//#region src/multishot/
|
|
325
|
-
/**
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
* 1. `runMultishotMatrix` runs it as the per-cell engine when the caller names
|
|
329
|
-
* no `runShot`, so the matrix always has an engine to run.
|
|
330
|
-
* 2. `golden.test.ts` proves the frozen records against it on every run, and
|
|
331
|
-
* perturbs it to prove the records detect a change. Records checked only
|
|
332
|
-
* against a replay of themselves prove nothing.
|
|
333
|
-
* 3. The repo's recording command names it as `--engine`. The script defaults
|
|
334
|
-
* no engine, so a version records whichever one the caller names — and a
|
|
335
|
-
* record set minted from a consumer's engine would let a product's wiring
|
|
336
|
-
* define this package's frozen contract.
|
|
190
|
+
//#region src/multishot/conversation.ts
|
|
191
|
+
/**
|
|
192
|
+
* Run one multishot conversation whose leg order `drive` decides.
|
|
337
193
|
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
|
|
194
|
+
* Returns the conversation's `MultishotResult`. When any leg or `drive` throws,
|
|
195
|
+
* the error is rethrown carrying the spend so far (`withCellSpend`), so a
|
|
196
|
+
* matrix bills the failed cell for the turns it already paid for.
|
|
197
|
+
*/
|
|
198
|
+
async function runMultishotConversation(opts, drive) {
|
|
342
199
|
const meter = {
|
|
343
200
|
costUsd: 0,
|
|
344
201
|
startedAt: Date.now(),
|
|
345
202
|
uncaptured: false
|
|
346
203
|
};
|
|
347
204
|
try {
|
|
348
|
-
|
|
205
|
+
const state = openConversation(opts, meter);
|
|
206
|
+
await drive(state.conversation);
|
|
207
|
+
return {
|
|
208
|
+
transcript: state.transcript,
|
|
209
|
+
artifacts: state.artifacts,
|
|
210
|
+
toolCalls: state.toolCalls(),
|
|
211
|
+
durationMs: Date.now() - meter.startedAt,
|
|
212
|
+
costUsd: meter.costUsd,
|
|
213
|
+
costProvenance: meter.uncaptured ? {
|
|
214
|
+
kind: "uncaptured",
|
|
215
|
+
usd: null
|
|
216
|
+
} : {
|
|
217
|
+
kind: "estimated",
|
|
218
|
+
usd: meter.costUsd
|
|
219
|
+
}
|
|
220
|
+
};
|
|
349
221
|
} catch (err) {
|
|
350
222
|
throw withCellSpend(err, {
|
|
351
223
|
costUsd: meter.costUsd,
|
|
@@ -354,11 +226,12 @@ async function runMultishot(opts) {
|
|
|
354
226
|
});
|
|
355
227
|
}
|
|
356
228
|
}
|
|
357
|
-
|
|
229
|
+
function openConversation(opts, meter) {
|
|
358
230
|
const maxTurns = opts.maxTurns ?? 10;
|
|
359
231
|
const maxToolDispatches = opts.maxToolDispatches ?? 4;
|
|
360
232
|
const agentModel = opts.agentModel ?? "openai/gpt-5.4";
|
|
361
|
-
const
|
|
233
|
+
const driverModel = opts.driverModel ?? "openai/gpt-4o-mini";
|
|
234
|
+
const driverModels = [driverModel, ...opts.driverFallbackModels ?? []];
|
|
362
235
|
const agentMaxTokens = opts.agentMaxTokens ?? 2500;
|
|
363
236
|
const toolFollowupMaxTokens = opts.toolFollowupMaxTokens ?? 2e3;
|
|
364
237
|
const driverMaxTokens = opts.driverMaxTokens ?? 600;
|
|
@@ -389,8 +262,13 @@ async function runShotTurns(opts, meter) {
|
|
|
389
262
|
role: "user",
|
|
390
263
|
content: opener
|
|
391
264
|
}];
|
|
392
|
-
|
|
265
|
+
const driverSystemPrompt = shape.buildDriverSystemPrompt(opts.persona);
|
|
266
|
+
async function agentTurn(turn) {
|
|
393
267
|
if (opts.signal?.aborted) throw new Error("multishot aborted");
|
|
268
|
+
const tokens = {
|
|
269
|
+
input: 0,
|
|
270
|
+
output: 0
|
|
271
|
+
};
|
|
394
272
|
let dispatchesThisTurn = 0;
|
|
395
273
|
while (true) {
|
|
396
274
|
const { message: agentMsg, usage: agentUsage, costUsd: agentCostUsd } = await agentTransport({
|
|
@@ -403,6 +281,8 @@ async function runShotTurns(opts, meter) {
|
|
|
403
281
|
});
|
|
404
282
|
meter.costUsd += agentCostUsd ?? estimateMultishotCost(agentModel, agentUsage);
|
|
405
283
|
if (agentCostUsd === void 0 && agentUsage === void 0) meter.uncaptured = true;
|
|
284
|
+
tokens.input += agentUsage?.prompt_tokens ?? 0;
|
|
285
|
+
tokens.output += agentUsage?.completion_tokens ?? 0;
|
|
406
286
|
const agentText = (agentMsg.content ?? "").trim();
|
|
407
287
|
const agentToolCalls = (agentMsg.tool_calls ?? []).map((tc) => ({
|
|
408
288
|
id: tc.id,
|
|
@@ -468,76 +348,77 @@ async function runShotTurns(opts, meter) {
|
|
|
468
348
|
});
|
|
469
349
|
}
|
|
470
350
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
agentMessages.push({
|
|
351
|
+
return { tokens };
|
|
352
|
+
}
|
|
353
|
+
async function driverTurn(turn) {
|
|
354
|
+
const driverMessages = [{
|
|
355
|
+
role: "system",
|
|
356
|
+
content: driverSystemPrompt
|
|
357
|
+
}];
|
|
358
|
+
for (const msg of transcript) {
|
|
359
|
+
if (msg.role === "tool") continue;
|
|
360
|
+
const content = driverVisibleContent(msg);
|
|
361
|
+
if (!content) continue;
|
|
362
|
+
if (msg.role === "assistant") driverMessages.push({
|
|
484
363
|
role: "user",
|
|
485
|
-
content
|
|
364
|
+
content
|
|
486
365
|
});
|
|
487
|
-
|
|
488
|
-
role: "
|
|
489
|
-
content
|
|
366
|
+
else if (msg.role === "user") driverMessages.push({
|
|
367
|
+
role: "assistant",
|
|
368
|
+
content
|
|
490
369
|
});
|
|
491
370
|
}
|
|
371
|
+
const tokens = {
|
|
372
|
+
input: 0,
|
|
373
|
+
output: 0
|
|
374
|
+
};
|
|
375
|
+
for (const model of driverModels) for (let attempt = 0; attempt < 2; attempt++) {
|
|
376
|
+
const { message, usage, costUsd } = await driverTransport({
|
|
377
|
+
model,
|
|
378
|
+
messages: driverMessages,
|
|
379
|
+
temperature: .9,
|
|
380
|
+
maxTokens: driverMaxTokens,
|
|
381
|
+
signal: opts.signal
|
|
382
|
+
});
|
|
383
|
+
meter.costUsd += costUsd ?? estimateMultishotCost(model, usage);
|
|
384
|
+
if (costUsd === void 0 && usage === void 0) meter.uncaptured = true;
|
|
385
|
+
tokens.input += usage?.prompt_tokens ?? 0;
|
|
386
|
+
tokens.output += usage?.completion_tokens ?? 0;
|
|
387
|
+
const content = (message.content ?? "").trim();
|
|
388
|
+
if (content.length > 0) {
|
|
389
|
+
agentMessages.push({
|
|
390
|
+
role: "user",
|
|
391
|
+
content
|
|
392
|
+
});
|
|
393
|
+
transcript.push({
|
|
394
|
+
role: "user",
|
|
395
|
+
content
|
|
396
|
+
});
|
|
397
|
+
return {
|
|
398
|
+
content,
|
|
399
|
+
tokens
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
throw new MultishotDriverEmptyError(turn);
|
|
492
404
|
}
|
|
493
405
|
return {
|
|
406
|
+
conversation: {
|
|
407
|
+
maxTurns,
|
|
408
|
+
agentModel,
|
|
409
|
+
driverModel,
|
|
410
|
+
opener,
|
|
411
|
+
driverSystemPrompt,
|
|
412
|
+
agentTurn,
|
|
413
|
+
driverTurn
|
|
414
|
+
},
|
|
494
415
|
transcript,
|
|
495
416
|
artifacts,
|
|
496
|
-
toolCalls
|
|
497
|
-
durationMs: Date.now() - meter.startedAt,
|
|
498
|
-
costUsd: meter.costUsd,
|
|
499
|
-
costProvenance: meter.uncaptured ? {
|
|
500
|
-
kind: "uncaptured",
|
|
501
|
-
usd: null
|
|
502
|
-
} : {
|
|
503
|
-
kind: "estimated",
|
|
504
|
-
usd: meter.costUsd
|
|
505
|
-
}
|
|
417
|
+
toolCalls: () => toolCalls
|
|
506
418
|
};
|
|
507
419
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
role: "system",
|
|
511
|
-
content: opts.shape.buildDriverSystemPrompt(opts.persona)
|
|
512
|
-
}];
|
|
513
|
-
for (const msg of opts.transcript) {
|
|
514
|
-
if (msg.role === "tool") continue;
|
|
515
|
-
const content = driverVisibleContent(msg);
|
|
516
|
-
if (!content) continue;
|
|
517
|
-
if (msg.role === "assistant") driverMessages.push({
|
|
518
|
-
role: "user",
|
|
519
|
-
content
|
|
520
|
-
});
|
|
521
|
-
else if (msg.role === "user") driverMessages.push({
|
|
522
|
-
role: "assistant",
|
|
523
|
-
content
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
for (const model of opts.models) for (let attempt = 0; attempt < 2; attempt++) {
|
|
527
|
-
const { message, usage, costUsd } = await opts.transport({
|
|
528
|
-
model,
|
|
529
|
-
messages: driverMessages,
|
|
530
|
-
temperature: .9,
|
|
531
|
-
maxTokens: opts.maxTokens,
|
|
532
|
-
signal: opts.signal
|
|
533
|
-
});
|
|
534
|
-
opts.meter.costUsd += costUsd ?? estimateMultishotCost(model, usage);
|
|
535
|
-
if (costUsd === void 0 && usage === void 0) opts.meter.uncaptured = true;
|
|
536
|
-
const content = (message.content ?? "").trim();
|
|
537
|
-
if (content.length > 0) return { content };
|
|
538
|
-
}
|
|
539
|
-
throw new MultishotDriverEmptyError(opts.turn);
|
|
540
|
-
}
|
|
420
|
+
/** Silent tool-calling agent turns surface to the driver as
|
|
421
|
+
* "Agent called tools: …" so the simulated user can react to them. */
|
|
541
422
|
function driverVisibleContent(msg) {
|
|
542
423
|
const text = msg.content.trim();
|
|
543
424
|
if (text.length > 0) return text;
|
|
@@ -547,6 +428,166 @@ function driverVisibleContent(msg) {
|
|
|
547
428
|
return `Agent called ${toolNames.length === 1 ? "tool" : "tools"}: ${toolNames.join(", ")}.`;
|
|
548
429
|
}
|
|
549
430
|
//#endregion
|
|
431
|
+
//#region src/multishot/judges.ts
|
|
432
|
+
const DEFAULT_JUDGE_MODEL = "openai/gpt-4o-mini";
|
|
433
|
+
async function runJudge(judge, input) {
|
|
434
|
+
const model = judge.model ?? "openai/gpt-4o-mini";
|
|
435
|
+
const prompt = judge.buildPrompt(input);
|
|
436
|
+
let raw = "";
|
|
437
|
+
let llmCall;
|
|
438
|
+
let cost;
|
|
439
|
+
const startedAt = Date.now();
|
|
440
|
+
try {
|
|
441
|
+
const response = await judge.transport({
|
|
442
|
+
model,
|
|
443
|
+
temperature: 0,
|
|
444
|
+
maxTokens: judge.maxTokens ?? 1500,
|
|
445
|
+
messages: [{
|
|
446
|
+
role: "system",
|
|
447
|
+
content: judge.systemPrompt
|
|
448
|
+
}, {
|
|
449
|
+
role: "user",
|
|
450
|
+
content: prompt
|
|
451
|
+
}]
|
|
452
|
+
});
|
|
453
|
+
const call = judgeCallMetadata(response, model, Date.now() - startedAt);
|
|
454
|
+
llmCall = call.llmCall;
|
|
455
|
+
cost = call.cost;
|
|
456
|
+
raw = (response.message.content ?? "").trim();
|
|
457
|
+
} catch (err) {
|
|
458
|
+
return {
|
|
459
|
+
score: {
|
|
460
|
+
dimensions: {},
|
|
461
|
+
composite: 0,
|
|
462
|
+
failed: true,
|
|
463
|
+
notes: `judge ${judge.name} call failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
464
|
+
llmCall: unknownJudgeCall(model, Date.now() - startedAt)
|
|
465
|
+
},
|
|
466
|
+
cost: {
|
|
467
|
+
kind: "uncaptured",
|
|
468
|
+
usd: null
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
let parsed = null;
|
|
473
|
+
try {
|
|
474
|
+
const cleaned = raw.replace(/^```json\s*/i, "").replace(/```\s*$/, "").trim();
|
|
475
|
+
parsed = JSON.parse(cleaned);
|
|
476
|
+
} catch {
|
|
477
|
+
return {
|
|
478
|
+
score: {
|
|
479
|
+
dimensions: {},
|
|
480
|
+
composite: 0,
|
|
481
|
+
failed: true,
|
|
482
|
+
notes: `judge ${judge.name} returned non-JSON: ${raw.slice(0, 200)}`,
|
|
483
|
+
llmCall
|
|
484
|
+
},
|
|
485
|
+
cost
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
const dimensions = {};
|
|
489
|
+
let sum = 0;
|
|
490
|
+
for (const dim of judge.dimensions) {
|
|
491
|
+
const v = Number(parsed[dim.key] ?? 0);
|
|
492
|
+
const clamped = Number.isFinite(v) ? Math.max(0, Math.min(10, v)) : 0;
|
|
493
|
+
dimensions[dim.key] = clamped;
|
|
494
|
+
sum += clamped;
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
score: {
|
|
498
|
+
dimensions,
|
|
499
|
+
composite: judge.dimensions.length === 0 ? 0 : sum / judge.dimensions.length,
|
|
500
|
+
notes: typeof parsed.notes === "string" ? parsed.notes : "",
|
|
501
|
+
llmCall
|
|
502
|
+
},
|
|
503
|
+
cost
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
function judgeCallMetadata(response, requestedModel, durationMs) {
|
|
507
|
+
const usage = canonicalUsage(response.usage);
|
|
508
|
+
const model = response.model ?? requestedModel;
|
|
509
|
+
return {
|
|
510
|
+
llmCall: {
|
|
511
|
+
usage,
|
|
512
|
+
costUsd: response.costUsd ?? null,
|
|
513
|
+
model,
|
|
514
|
+
durationMs
|
|
515
|
+
},
|
|
516
|
+
cost: response.costUsd !== void 0 ? {
|
|
517
|
+
kind: "observed",
|
|
518
|
+
usd: response.costUsd
|
|
519
|
+
} : usage.captured === false || !isModelPriced(model) ? {
|
|
520
|
+
kind: "uncaptured",
|
|
521
|
+
usd: null
|
|
522
|
+
} : {
|
|
523
|
+
kind: "estimated",
|
|
524
|
+
usd: estimateCost(usage.promptTokens, usage.completionTokens, model)
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
function canonicalUsage(usage) {
|
|
529
|
+
const promptTokens = tokenCount(usage?.prompt_tokens);
|
|
530
|
+
const completionTokens = tokenCount(usage?.completion_tokens);
|
|
531
|
+
const captured = promptTokens !== void 0 && completionTokens !== void 0;
|
|
532
|
+
return {
|
|
533
|
+
promptTokens: promptTokens ?? 0,
|
|
534
|
+
completionTokens: completionTokens ?? 0,
|
|
535
|
+
totalTokens: (promptTokens ?? 0) + (completionTokens ?? 0),
|
|
536
|
+
captured
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
function unknownJudgeCall(model, durationMs) {
|
|
540
|
+
return {
|
|
541
|
+
usage: {
|
|
542
|
+
promptTokens: 0,
|
|
543
|
+
completionTokens: 0,
|
|
544
|
+
totalTokens: 0,
|
|
545
|
+
captured: false
|
|
546
|
+
},
|
|
547
|
+
costUsd: null,
|
|
548
|
+
model,
|
|
549
|
+
durationMs
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function tokenCount(value) {
|
|
553
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
554
|
+
}
|
|
555
|
+
/** Convenience: stringified dimension list for inclusion in a judge prompt.
|
|
556
|
+
* Returns lines like `- audience_fit: Does this match what the audience cares about? (0-10)`. */
|
|
557
|
+
function renderDimensions(dims) {
|
|
558
|
+
return dims.map((d) => `- ${d.key}: ${d.description}`).join("\n");
|
|
559
|
+
}
|
|
560
|
+
/** Convenience: build the "Respond with ONLY this JSON" footer for a judge prompt. */
|
|
561
|
+
function renderJsonFooter(dims) {
|
|
562
|
+
return `Respond with ONLY this JSON (no markdown, no preamble):\n{${dims.map((d) => `"${d.key}":N`).join(",")},"notes":"1-2 sentence critique"}`;
|
|
563
|
+
}
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/multishot/multishot.ts
|
|
566
|
+
/** The package's reference conversation engine, and the referent of three
|
|
567
|
+
* things that stop working without it.
|
|
568
|
+
*
|
|
569
|
+
* 1. `runMultishotMatrix` runs it as the per-cell engine when the caller names
|
|
570
|
+
* no `runShot`, so the matrix always has an engine to run.
|
|
571
|
+
* 2. `golden.test.ts` proves the frozen records against it on every run, and
|
|
572
|
+
* perturbs it to prove the records detect a change. Records checked only
|
|
573
|
+
* against a replay of themselves prove nothing.
|
|
574
|
+
* 3. The repo's recording command names it as `--engine`. The script defaults
|
|
575
|
+
* no engine, so a version records whichever one the caller names — and a
|
|
576
|
+
* record set minted from a consumer's engine would let a product's wiring
|
|
577
|
+
* define this package's frozen contract.
|
|
578
|
+
*
|
|
579
|
+
* An alternative engine reaches the matrix through `runShot` and reaches the
|
|
580
|
+
* records through `assertMultishotGoldenScenario`. Neither seam removes the
|
|
581
|
+
* three roles above. */
|
|
582
|
+
async function runMultishot(opts) {
|
|
583
|
+
return runMultishotConversation(opts, async (conversation) => {
|
|
584
|
+
for (let turn = 0; turn < conversation.maxTurns; turn++) {
|
|
585
|
+
await conversation.agentTurn(turn);
|
|
586
|
+
if (turn < conversation.maxTurns - 1) await conversation.driverTurn(turn);
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
//#endregion
|
|
550
591
|
//#region src/multishot/matrix.ts
|
|
551
592
|
/** Mean composite over non-failed scores. `0` when the list is empty (a
|
|
552
593
|
* configured judge with nothing to score contributes 0, matching the cell
|
|
@@ -784,6 +825,6 @@ function withJudgeMaxTokens(judge, maxTokens) {
|
|
|
784
825
|
};
|
|
785
826
|
}
|
|
786
827
|
//#endregion
|
|
787
|
-
export { DEFAULT_CODER_MODEL, DEFAULT_JUDGE_MODEL, MultishotDriverEmptyError, MultishotFatalToolError, assertMultishotShotResult, computeCellComposite, defaultDelegationTools, defaultShapeFromProfile, estimateMultishotCost, renderDimensions, renderJsonFooter, runJudge, runMultishot, runMultishotMatrix };
|
|
828
|
+
export { DEFAULT_CODER_MODEL, DEFAULT_JUDGE_MODEL, MultishotDriverEmptyError, MultishotFatalToolError, assertMultishotShotResult, computeCellComposite, defaultDelegationTools, defaultShapeFromProfile, estimateMultishotCost, renderDimensions, renderJsonFooter, runJudge, runMultishot, runMultishotConversation, runMultishotMatrix };
|
|
788
829
|
|
|
789
830
|
//# sourceMappingURL=index.js.map
|