@tangle-network/agent-eval 0.221.5 → 0.221.7
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 +114 -0
- 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 +12 -12
- package/dist/analyst/index.js +7 -7
- 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 +51 -3
- package/dist/multishot/index.d.ts.map +1 -1
- package/dist/multishot/index.js +263 -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/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,14 @@ 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 usdBefore = meter.costUsd;
|
|
269
|
+
const tokens = {
|
|
270
|
+
input: 0,
|
|
271
|
+
output: 0
|
|
272
|
+
};
|
|
394
273
|
let dispatchesThisTurn = 0;
|
|
395
274
|
while (true) {
|
|
396
275
|
const { message: agentMsg, usage: agentUsage, costUsd: agentCostUsd } = await agentTransport({
|
|
@@ -403,6 +282,8 @@ async function runShotTurns(opts, meter) {
|
|
|
403
282
|
});
|
|
404
283
|
meter.costUsd += agentCostUsd ?? estimateMultishotCost(agentModel, agentUsage);
|
|
405
284
|
if (agentCostUsd === void 0 && agentUsage === void 0) meter.uncaptured = true;
|
|
285
|
+
tokens.input += agentUsage?.prompt_tokens ?? 0;
|
|
286
|
+
tokens.output += agentUsage?.completion_tokens ?? 0;
|
|
406
287
|
const agentText = (agentMsg.content ?? "").trim();
|
|
407
288
|
const agentToolCalls = (agentMsg.tool_calls ?? []).map((tc) => ({
|
|
408
289
|
id: tc.id,
|
|
@@ -468,76 +349,82 @@ async function runShotTurns(opts, meter) {
|
|
|
468
349
|
});
|
|
469
350
|
}
|
|
470
351
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
352
|
+
return {
|
|
353
|
+
tokens,
|
|
354
|
+
usd: meter.costUsd - usdBefore
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
async function driverTurn(turn) {
|
|
358
|
+
const usdBefore = meter.costUsd;
|
|
359
|
+
const driverMessages = [{
|
|
360
|
+
role: "system",
|
|
361
|
+
content: driverSystemPrompt
|
|
362
|
+
}];
|
|
363
|
+
for (const msg of transcript) {
|
|
364
|
+
if (msg.role === "tool") continue;
|
|
365
|
+
const content = driverVisibleContent(msg);
|
|
366
|
+
if (!content) continue;
|
|
367
|
+
if (msg.role === "assistant") driverMessages.push({
|
|
484
368
|
role: "user",
|
|
485
|
-
content
|
|
369
|
+
content
|
|
486
370
|
});
|
|
487
|
-
|
|
488
|
-
role: "
|
|
489
|
-
content
|
|
371
|
+
else if (msg.role === "user") driverMessages.push({
|
|
372
|
+
role: "assistant",
|
|
373
|
+
content
|
|
490
374
|
});
|
|
491
375
|
}
|
|
376
|
+
const tokens = {
|
|
377
|
+
input: 0,
|
|
378
|
+
output: 0
|
|
379
|
+
};
|
|
380
|
+
for (const model of driverModels) for (let attempt = 0; attempt < 2; attempt++) {
|
|
381
|
+
const { message, usage, costUsd } = await driverTransport({
|
|
382
|
+
model,
|
|
383
|
+
messages: driverMessages,
|
|
384
|
+
temperature: .9,
|
|
385
|
+
maxTokens: driverMaxTokens,
|
|
386
|
+
signal: opts.signal
|
|
387
|
+
});
|
|
388
|
+
meter.costUsd += costUsd ?? estimateMultishotCost(model, usage);
|
|
389
|
+
if (costUsd === void 0 && usage === void 0) meter.uncaptured = true;
|
|
390
|
+
tokens.input += usage?.prompt_tokens ?? 0;
|
|
391
|
+
tokens.output += usage?.completion_tokens ?? 0;
|
|
392
|
+
const content = (message.content ?? "").trim();
|
|
393
|
+
if (content.length > 0) {
|
|
394
|
+
agentMessages.push({
|
|
395
|
+
role: "user",
|
|
396
|
+
content
|
|
397
|
+
});
|
|
398
|
+
transcript.push({
|
|
399
|
+
role: "user",
|
|
400
|
+
content
|
|
401
|
+
});
|
|
402
|
+
return {
|
|
403
|
+
content,
|
|
404
|
+
tokens,
|
|
405
|
+
usd: meter.costUsd - usdBefore
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
throw new MultishotDriverEmptyError(turn);
|
|
492
410
|
}
|
|
493
411
|
return {
|
|
412
|
+
conversation: {
|
|
413
|
+
maxTurns,
|
|
414
|
+
agentModel,
|
|
415
|
+
driverModel,
|
|
416
|
+
opener,
|
|
417
|
+
driverSystemPrompt,
|
|
418
|
+
agentTurn,
|
|
419
|
+
driverTurn
|
|
420
|
+
},
|
|
494
421
|
transcript,
|
|
495
422
|
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
|
-
}
|
|
423
|
+
toolCalls: () => toolCalls
|
|
506
424
|
};
|
|
507
425
|
}
|
|
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
|
-
}
|
|
426
|
+
/** Silent tool-calling agent turns surface to the driver as
|
|
427
|
+
* "Agent called tools: …" so the simulated user can react to them. */
|
|
541
428
|
function driverVisibleContent(msg) {
|
|
542
429
|
const text = msg.content.trim();
|
|
543
430
|
if (text.length > 0) return text;
|
|
@@ -547,6 +434,166 @@ function driverVisibleContent(msg) {
|
|
|
547
434
|
return `Agent called ${toolNames.length === 1 ? "tool" : "tools"}: ${toolNames.join(", ")}.`;
|
|
548
435
|
}
|
|
549
436
|
//#endregion
|
|
437
|
+
//#region src/multishot/judges.ts
|
|
438
|
+
const DEFAULT_JUDGE_MODEL = "openai/gpt-4o-mini";
|
|
439
|
+
async function runJudge(judge, input) {
|
|
440
|
+
const model = judge.model ?? "openai/gpt-4o-mini";
|
|
441
|
+
const prompt = judge.buildPrompt(input);
|
|
442
|
+
let raw = "";
|
|
443
|
+
let llmCall;
|
|
444
|
+
let cost;
|
|
445
|
+
const startedAt = Date.now();
|
|
446
|
+
try {
|
|
447
|
+
const response = await judge.transport({
|
|
448
|
+
model,
|
|
449
|
+
temperature: 0,
|
|
450
|
+
maxTokens: judge.maxTokens ?? 1500,
|
|
451
|
+
messages: [{
|
|
452
|
+
role: "system",
|
|
453
|
+
content: judge.systemPrompt
|
|
454
|
+
}, {
|
|
455
|
+
role: "user",
|
|
456
|
+
content: prompt
|
|
457
|
+
}]
|
|
458
|
+
});
|
|
459
|
+
const call = judgeCallMetadata(response, model, Date.now() - startedAt);
|
|
460
|
+
llmCall = call.llmCall;
|
|
461
|
+
cost = call.cost;
|
|
462
|
+
raw = (response.message.content ?? "").trim();
|
|
463
|
+
} catch (err) {
|
|
464
|
+
return {
|
|
465
|
+
score: {
|
|
466
|
+
dimensions: {},
|
|
467
|
+
composite: 0,
|
|
468
|
+
failed: true,
|
|
469
|
+
notes: `judge ${judge.name} call failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
470
|
+
llmCall: unknownJudgeCall(model, Date.now() - startedAt)
|
|
471
|
+
},
|
|
472
|
+
cost: {
|
|
473
|
+
kind: "uncaptured",
|
|
474
|
+
usd: null
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
let parsed = null;
|
|
479
|
+
try {
|
|
480
|
+
const cleaned = raw.replace(/^```json\s*/i, "").replace(/```\s*$/, "").trim();
|
|
481
|
+
parsed = JSON.parse(cleaned);
|
|
482
|
+
} catch {
|
|
483
|
+
return {
|
|
484
|
+
score: {
|
|
485
|
+
dimensions: {},
|
|
486
|
+
composite: 0,
|
|
487
|
+
failed: true,
|
|
488
|
+
notes: `judge ${judge.name} returned non-JSON: ${raw.slice(0, 200)}`,
|
|
489
|
+
llmCall
|
|
490
|
+
},
|
|
491
|
+
cost
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
const dimensions = {};
|
|
495
|
+
let sum = 0;
|
|
496
|
+
for (const dim of judge.dimensions) {
|
|
497
|
+
const v = Number(parsed[dim.key] ?? 0);
|
|
498
|
+
const clamped = Number.isFinite(v) ? Math.max(0, Math.min(10, v)) : 0;
|
|
499
|
+
dimensions[dim.key] = clamped;
|
|
500
|
+
sum += clamped;
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
score: {
|
|
504
|
+
dimensions,
|
|
505
|
+
composite: judge.dimensions.length === 0 ? 0 : sum / judge.dimensions.length,
|
|
506
|
+
notes: typeof parsed.notes === "string" ? parsed.notes : "",
|
|
507
|
+
llmCall
|
|
508
|
+
},
|
|
509
|
+
cost
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
function judgeCallMetadata(response, requestedModel, durationMs) {
|
|
513
|
+
const usage = canonicalUsage(response.usage);
|
|
514
|
+
const model = response.model ?? requestedModel;
|
|
515
|
+
return {
|
|
516
|
+
llmCall: {
|
|
517
|
+
usage,
|
|
518
|
+
costUsd: response.costUsd ?? null,
|
|
519
|
+
model,
|
|
520
|
+
durationMs
|
|
521
|
+
},
|
|
522
|
+
cost: response.costUsd !== void 0 ? {
|
|
523
|
+
kind: "observed",
|
|
524
|
+
usd: response.costUsd
|
|
525
|
+
} : usage.captured === false || !isModelPriced(model) ? {
|
|
526
|
+
kind: "uncaptured",
|
|
527
|
+
usd: null
|
|
528
|
+
} : {
|
|
529
|
+
kind: "estimated",
|
|
530
|
+
usd: estimateCost(usage.promptTokens, usage.completionTokens, model)
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
function canonicalUsage(usage) {
|
|
535
|
+
const promptTokens = tokenCount(usage?.prompt_tokens);
|
|
536
|
+
const completionTokens = tokenCount(usage?.completion_tokens);
|
|
537
|
+
const captured = promptTokens !== void 0 && completionTokens !== void 0;
|
|
538
|
+
return {
|
|
539
|
+
promptTokens: promptTokens ?? 0,
|
|
540
|
+
completionTokens: completionTokens ?? 0,
|
|
541
|
+
totalTokens: (promptTokens ?? 0) + (completionTokens ?? 0),
|
|
542
|
+
captured
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function unknownJudgeCall(model, durationMs) {
|
|
546
|
+
return {
|
|
547
|
+
usage: {
|
|
548
|
+
promptTokens: 0,
|
|
549
|
+
completionTokens: 0,
|
|
550
|
+
totalTokens: 0,
|
|
551
|
+
captured: false
|
|
552
|
+
},
|
|
553
|
+
costUsd: null,
|
|
554
|
+
model,
|
|
555
|
+
durationMs
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function tokenCount(value) {
|
|
559
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
560
|
+
}
|
|
561
|
+
/** Convenience: stringified dimension list for inclusion in a judge prompt.
|
|
562
|
+
* Returns lines like `- audience_fit: Does this match what the audience cares about? (0-10)`. */
|
|
563
|
+
function renderDimensions(dims) {
|
|
564
|
+
return dims.map((d) => `- ${d.key}: ${d.description}`).join("\n");
|
|
565
|
+
}
|
|
566
|
+
/** Convenience: build the "Respond with ONLY this JSON" footer for a judge prompt. */
|
|
567
|
+
function renderJsonFooter(dims) {
|
|
568
|
+
return `Respond with ONLY this JSON (no markdown, no preamble):\n{${dims.map((d) => `"${d.key}":N`).join(",")},"notes":"1-2 sentence critique"}`;
|
|
569
|
+
}
|
|
570
|
+
//#endregion
|
|
571
|
+
//#region src/multishot/multishot.ts
|
|
572
|
+
/** The package's reference conversation engine, and the referent of three
|
|
573
|
+
* things that stop working without it.
|
|
574
|
+
*
|
|
575
|
+
* 1. `runMultishotMatrix` runs it as the per-cell engine when the caller names
|
|
576
|
+
* no `runShot`, so the matrix always has an engine to run.
|
|
577
|
+
* 2. `golden.test.ts` proves the frozen records against it on every run, and
|
|
578
|
+
* perturbs it to prove the records detect a change. Records checked only
|
|
579
|
+
* against a replay of themselves prove nothing.
|
|
580
|
+
* 3. The repo's recording command names it as `--engine`. The script defaults
|
|
581
|
+
* no engine, so a version records whichever one the caller names — and a
|
|
582
|
+
* record set minted from a consumer's engine would let a product's wiring
|
|
583
|
+
* define this package's frozen contract.
|
|
584
|
+
*
|
|
585
|
+
* An alternative engine reaches the matrix through `runShot` and reaches the
|
|
586
|
+
* records through `assertMultishotGoldenScenario`. Neither seam removes the
|
|
587
|
+
* three roles above. */
|
|
588
|
+
async function runMultishot(opts) {
|
|
589
|
+
return runMultishotConversation(opts, async (conversation) => {
|
|
590
|
+
for (let turn = 0; turn < conversation.maxTurns; turn++) {
|
|
591
|
+
await conversation.agentTurn(turn);
|
|
592
|
+
if (turn < conversation.maxTurns - 1) await conversation.driverTurn(turn);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
//#endregion
|
|
550
597
|
//#region src/multishot/matrix.ts
|
|
551
598
|
/** Mean composite over non-failed scores. `0` when the list is empty (a
|
|
552
599
|
* configured judge with nothing to score contributes 0, matching the cell
|
|
@@ -784,6 +831,6 @@ function withJudgeMaxTokens(judge, maxTokens) {
|
|
|
784
831
|
};
|
|
785
832
|
}
|
|
786
833
|
//#endregion
|
|
787
|
-
export { DEFAULT_CODER_MODEL, DEFAULT_JUDGE_MODEL, MultishotDriverEmptyError, MultishotFatalToolError, assertMultishotShotResult, computeCellComposite, defaultDelegationTools, defaultShapeFromProfile, estimateMultishotCost, renderDimensions, renderJsonFooter, runJudge, runMultishot, runMultishotMatrix };
|
|
834
|
+
export { DEFAULT_CODER_MODEL, DEFAULT_JUDGE_MODEL, MultishotDriverEmptyError, MultishotFatalToolError, assertMultishotShotResult, computeCellComposite, defaultDelegationTools, defaultShapeFromProfile, estimateMultishotCost, renderDimensions, renderJsonFooter, runJudge, runMultishot, runMultishotConversation, runMultishotMatrix };
|
|
788
835
|
|
|
789
836
|
//# sourceMappingURL=index.js.map
|