@tangle-network/agent-eval 0.140.1 → 0.141.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/analyst/index.d.ts +74 -6
- package/dist/analyst/index.d.ts.map +1 -1
- package/dist/analyst/index.js +6 -6
- package/dist/{benchmark-command-Bo_hkhQf.js → benchmark-command-D8xXNVVh.js} +2239 -1820
- package/dist/benchmark-command-D8xXNVVh.js.map +1 -0
- package/dist/benchmarks/index.js +1 -1
- package/dist/{benchmarks-HwoBE32G.js → benchmarks-Ce8GdJbc.js} +4 -4
- package/dist/{benchmarks-HwoBE32G.js.map → benchmarks-Ce8GdJbc.js.map} +1 -1
- package/dist/campaign/index.js +3 -3
- package/dist/{campaign-BzjYNYVZ.js → campaign-COFTVy3Q.js} +3 -3
- package/dist/{campaign-BzjYNYVZ.js.map → campaign-COFTVy3Q.js.map} +1 -1
- package/dist/cli.js +1 -1
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +56 -13
- package/dist/contract/index.js.map +1 -1
- package/dist/{default-registry-BOiBXNFh.js → default-registry-BupFSXSN.js} +108 -20
- package/dist/default-registry-BupFSXSN.js.map +1 -0
- package/dist/default-registry-Ci7wAAR8.d.ts.map +1 -1
- package/dist/{dspy-rlm-engine-Bkak4nzo.js → dspy-rlm-engine-Bw8Zz9CX.js} +7 -4
- package/dist/{dspy-rlm-engine-Bkak4nzo.js.map → dspy-rlm-engine-Bw8Zz9CX.js.map} +1 -1
- package/dist/{extract-usage-C5vMw-0R.js → extract-usage-7l1Xq5ti.js} +2 -2
- package/dist/{extract-usage-C5vMw-0R.js.map → extract-usage-7l1Xq5ti.js.map} +1 -1
- package/dist/index.d.ts +68 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -46
- package/dist/index.js.map +1 -1
- package/dist/{kind-factory-DB7nIs35.js → kind-factory-Bvwe3pup.js} +11 -1
- package/dist/kind-factory-Bvwe3pup.js.map +1 -0
- package/dist/multishot/index.d.ts +29 -6
- package/dist/multishot/index.d.ts.map +1 -1
- package/dist/multishot/index.js +53 -3
- package/dist/multishot/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/replay-BqTgoioO.d.ts.map +1 -1
- package/dist/{replay-k2MsOmv5.js → replay-DjUfTrHD.js} +40 -48
- package/dist/replay-DjUfTrHD.js.map +1 -0
- package/dist/{single-run-lock-CiQThJxB.js → single-run-lock-BcvPQY57.js} +65 -15
- package/dist/single-run-lock-BcvPQY57.js.map +1 -0
- package/dist/{skill-usage-CVVnoIx-.d.ts → skill-usage-CNZTk_LT.d.ts} +8 -4
- package/dist/{skill-usage-CVVnoIx-.d.ts.map → skill-usage-CNZTk_LT.d.ts.map} +1 -1
- package/dist/{skillopt-optimization-method-CSBQ8Qma.js → skillopt-optimization-method-DV6c4ooy.js} +2 -2
- package/dist/{skillopt-optimization-method-CSBQ8Qma.js.map → skillopt-optimization-method-DV6c4ooy.js.map} +1 -1
- package/dist/{store-otlp-vRByAR6h.js → store-otlp-D4I90_vR.js} +2 -2
- package/dist/{store-otlp-vRByAR6h.js.map → store-otlp-D4I90_vR.js.map} +1 -1
- package/dist/traces.js +4 -4
- package/docs/adapters-observability.md +35 -21
- package/docs/concepts.md +1 -0
- package/docs/distributed-driver.md +7 -3
- package/docs/feature-guide.md +1 -0
- package/docs/insight-report.md +1 -1
- package/docs/trace-analysis.md +11 -0
- package/docs/wire-protocol.md +70 -2
- package/package.json +5 -3
- package/dist/benchmark-command-Bo_hkhQf.js.map +0 -1
- package/dist/default-registry-BOiBXNFh.js.map +0 -1
- package/dist/kind-factory-DB7nIs35.js.map +0 -1
- package/dist/replay-k2MsOmv5.js.map +0 -1
- package/dist/single-run-lock-CiQThJxB.js.map +0 -1
package/dist/multishot/index.js
CHANGED
|
@@ -315,6 +315,55 @@ function renderJsonFooter(dims) {
|
|
|
315
315
|
return `Respond with ONLY this JSON (no markdown, no preamble):\n{${dims.map((d) => `"${d.key}":N`).join(",")},"notes":"1-2 sentence critique"}`;
|
|
316
316
|
}
|
|
317
317
|
//#endregion
|
|
318
|
+
//#region src/multishot/shape-defaults.ts
|
|
319
|
+
/** Persona payload rendered as stable `- key: value` lines. `id` is identity,
|
|
320
|
+
* not voice, and structured values are serialized so nothing is dropped. */
|
|
321
|
+
function renderPersonaFacts(persona) {
|
|
322
|
+
const lines = [];
|
|
323
|
+
for (const [key, value] of Object.entries(persona)) {
|
|
324
|
+
if (key === "id" || value === void 0) continue;
|
|
325
|
+
const rendered = typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
|
|
326
|
+
lines.push(`- ${key}: ${rendered}`);
|
|
327
|
+
}
|
|
328
|
+
return lines.join("\n");
|
|
329
|
+
}
|
|
330
|
+
/** Default opening user message: the persona introduces itself with its whole
|
|
331
|
+
* payload and asks the agent (as described by the profile) to take over. */
|
|
332
|
+
function defaultMultishotOpener(profile, persona) {
|
|
333
|
+
const facts = renderPersonaFacts(persona);
|
|
334
|
+
return [
|
|
335
|
+
`Hi — I'm reaching out to ${profile.description ?? profile.name ?? "the agent"} for help. My situation:`,
|
|
336
|
+
facts.length > 0 ? facts : `- (no details provided beyond id: ${persona.id})`,
|
|
337
|
+
"",
|
|
338
|
+
"Tell me what you need from me, and get started on my case."
|
|
339
|
+
].join("\n");
|
|
340
|
+
}
|
|
341
|
+
/** Default driver system prompt: roleplay the persona from its payload, stay
|
|
342
|
+
* in character, push back on vague answers, and never go silent. */
|
|
343
|
+
function defaultMultishotDriverSystemPrompt(profile, persona) {
|
|
344
|
+
const facts = renderPersonaFacts(persona);
|
|
345
|
+
const agentDescription = profile.description ?? profile.name ?? "an AI agent";
|
|
346
|
+
return [
|
|
347
|
+
`You are role-playing a real person (persona "${persona.id}") talking to ${agentDescription}.`,
|
|
348
|
+
facts.length > 0 ? `Who you are:\n${facts}` : "",
|
|
349
|
+
"",
|
|
350
|
+
"How to behave:",
|
|
351
|
+
"- Stay in character: first person, realistic voice, concrete details from your situation.",
|
|
352
|
+
"- Judge every reply by whether it actually moves YOUR case forward. Push back on vague, hedged, or generic answers and demand specifics.",
|
|
353
|
+
"- Answer the agent's questions with information consistent with who you are; invent plausible details rather than stalling.",
|
|
354
|
+
"- Never go silent: always produce a substantive next message.",
|
|
355
|
+
"- Output ONLY your next message to the agent — no meta-commentary, no stage directions."
|
|
356
|
+
].filter((block) => block.length > 0).join("\n");
|
|
357
|
+
}
|
|
358
|
+
/** The fully-resolved shape for a profile: caller overrides win, the
|
|
359
|
+
* profile-derived defaults fill the rest. */
|
|
360
|
+
function defaultShapeFromProfile(profile, shape) {
|
|
361
|
+
return {
|
|
362
|
+
buildOpener: shape?.buildOpener ?? ((persona) => defaultMultishotOpener(profile, persona)),
|
|
363
|
+
buildDriverSystemPrompt: shape?.buildDriverSystemPrompt ?? ((persona) => defaultMultishotDriverSystemPrompt(profile, persona))
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
//#endregion
|
|
318
367
|
//#region src/multishot/types.ts
|
|
319
368
|
var MultishotDriverEmptyError = class extends Error {
|
|
320
369
|
turn;
|
|
@@ -357,12 +406,13 @@ async function runMultishot(opts) {
|
|
|
357
406
|
});
|
|
358
407
|
const agentTransport = opts.agentTransport ?? routerTransport;
|
|
359
408
|
const driverTransport = opts.driverTransport ?? routerTransport;
|
|
409
|
+
const shape = defaultShapeFromProfile(opts.profile, opts.shape);
|
|
360
410
|
const start = Date.now();
|
|
361
411
|
const transcript = [];
|
|
362
412
|
const artifacts = [];
|
|
363
413
|
let toolCalls = 0;
|
|
364
414
|
let totalCostUsd = 0;
|
|
365
|
-
const opener =
|
|
415
|
+
const opener = shape.buildOpener(opts.persona);
|
|
366
416
|
transcript.push({
|
|
367
417
|
role: "user",
|
|
368
418
|
content: opener
|
|
@@ -457,7 +507,7 @@ async function runMultishot(opts) {
|
|
|
457
507
|
const driver = await driverTurn({
|
|
458
508
|
transport: driverTransport,
|
|
459
509
|
persona: opts.persona,
|
|
460
|
-
shape
|
|
510
|
+
shape,
|
|
461
511
|
transcript,
|
|
462
512
|
turn,
|
|
463
513
|
models: driverModels,
|
|
@@ -723,6 +773,6 @@ function withJudgeMaxTokens(judge, maxTokens) {
|
|
|
723
773
|
};
|
|
724
774
|
}
|
|
725
775
|
//#endregion
|
|
726
|
-
export { DEFAULT_CODER_MODEL, DEFAULT_DELEGATE_CODE_TOOL, DEFAULT_DELEGATE_RESEARCH_TOOL, DEFAULT_JUDGE_MODEL, DEFAULT_RESEARCHER_MODEL, MultishotDriverEmptyError, MultishotFatalToolError, computeCellComposite, createCodeExecutor, createResearchExecutor, defaultDelegationTools, defaultRouterBaseUrl, estimateRouterCost, renderDimensions, renderJsonFooter, requireRouterApiKey, routerCompletion, runJudge, runMultishot, runMultishotMatrix };
|
|
776
|
+
export { DEFAULT_CODER_MODEL, DEFAULT_DELEGATE_CODE_TOOL, DEFAULT_DELEGATE_RESEARCH_TOOL, DEFAULT_JUDGE_MODEL, DEFAULT_RESEARCHER_MODEL, MultishotDriverEmptyError, MultishotFatalToolError, computeCellComposite, createCodeExecutor, createResearchExecutor, defaultDelegationTools, defaultMultishotDriverSystemPrompt, defaultMultishotOpener, defaultRouterBaseUrl, defaultShapeFromProfile, estimateRouterCost, renderDimensions, renderJsonFooter, renderPersonaFacts, requireRouterApiKey, routerCompletion, runJudge, runMultishot, runMultishotMatrix };
|
|
727
777
|
|
|
728
778
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/multishot/router.ts","../../src/multishot/default-tools.ts","../../src/multishot/judges.ts","../../src/multishot/types.ts","../../src/multishot/multishot.ts","../../src/multishot/matrix.ts"],"sourcesContent":["// Router fetch helper — single source of truth for OpenAI-compat calls\n// against the Tangle router. Used by the driver, agent, judges, and the\n// default tool executors.\n\nimport type { MultishotToolDefinition } from './types'\n\nexport interface RouterCompletionRequest {\n apiKey: string\n baseUrl: string\n model: string\n messages: Array<Record<string, unknown>>\n tools?: MultishotToolDefinition[]\n temperature?: number\n maxTokens?: number\n signal?: AbortSignal\n}\n\nexport interface RouterToolCall {\n id: string\n type: 'function'\n function: { name: string; arguments: string }\n}\n\nexport interface RouterCompletionResponse {\n message: { content?: string | null; tool_calls?: RouterToolCall[] }\n usage?: { prompt_tokens?: number; completion_tokens?: number }\n /** Provider-reported spend when the endpoint supplies it. */\n costUsd?: number\n /** Model echoed by the provider, falling back to the requested model. */\n model: string\n durationMs: number\n}\n\nexport async function routerCompletion(\n req: RouterCompletionRequest,\n): Promise<RouterCompletionResponse> {\n const startedAt = Date.now()\n const body: Record<string, unknown> = {\n model: req.model,\n messages: req.messages,\n temperature: req.temperature ?? 0.7,\n max_tokens: req.maxTokens ?? 2000,\n }\n if (req.tools?.length) body.tools = req.tools\n const url = `${req.baseUrl.replace(/\\/+$/, '')}/chat/completions`\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${req.apiKey}`, 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: req.signal,\n })\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`router ${res.status}: ${text.slice(0, 300)}`)\n }\n const json = (await res.json()) as {\n choices: Array<{ message: { content?: string | null; tool_calls?: RouterToolCall[] } }>\n usage?: { prompt_tokens?: number; completion_tokens?: number }\n model?: unknown\n _response_cost?: unknown\n cost_usd?: unknown\n }\n const choice = json.choices[0]\n if (!choice) throw new Error(`router returned no choices: ${JSON.stringify(json).slice(0, 200)}`)\n const rawCost = json._response_cost ?? json.cost_usd\n const costUsd =\n typeof rawCost === 'number' && Number.isFinite(rawCost) && rawCost >= 0 ? rawCost : undefined\n return {\n message: choice.message,\n usage: json.usage,\n ...(costUsd === undefined ? {} : { costUsd }),\n model: typeof json.model === 'string' && json.model ? json.model : req.model,\n durationMs: Date.now() - startedAt,\n }\n}\n\n// Rough per-model cost estimator. Used for cost-ceiling enforcement.\n// Underestimates Anthropic, overestimates oss models — fine for ceilings.\nexport function estimateRouterCost(\n model: string,\n usage?: { prompt_tokens?: number; completion_tokens?: number },\n): number {\n if (!usage) return 0\n const inputTok = usage.prompt_tokens ?? 0\n const outputTok = usage.completion_tokens ?? 0\n let inPer1k = 0.003\n let outPer1k = 0.015\n if (model.includes('gpt-4o-mini')) {\n inPer1k = 0.00015\n outPer1k = 0.0006\n } else if (model.includes('gpt-5.4') || model.includes('claude-sonnet')) {\n inPer1k = 0.003\n outPer1k = 0.015\n } else if (model.includes('kimi') || model.includes('glm') || model.includes('deepseek')) {\n inPer1k = 0.0005\n outPer1k = 0.002\n }\n return (inputTok * inPer1k + outputTok * outPer1k) / 1000\n}\n\nexport function defaultRouterBaseUrl(): string {\n return (process.env.TANGLE_ROUTER_BASE_URL ?? 'https://router.tangle.tools/v1').replace(\n /\\/+$/,\n '',\n )\n}\n\nexport function requireRouterApiKey(): string {\n const key = process.env.TANGLE_API_KEY\n if (!key) throw new Error('multishot requires TANGLE_API_KEY (router-scoped sk-tan-* key)')\n return key\n}\n","// Default delegate_research + delegate_code tools and their inline executors.\n//\n// Consumers can override either by passing their own tools + executors to\n// runMultishot. The defaults are sufficient for most domains — point the\n// researcher system prompt at your domain's citation style and the coder\n// at your preferred language.\n\nimport { estimateRouterCost, routerCompletion } from './router'\nimport type { MultishotToolDefinition, MultishotToolExecutor } from './types'\n\nexport const DEFAULT_RESEARCHER_MODEL = 'openai/gpt-4o-mini'\nexport const DEFAULT_CODER_MODEL = 'openai/gpt-4o-mini'\n\nexport interface DefaultResearcherConfig {\n /** Replace the system prompt to bias the researcher toward a domain's\n * citation style. Defaults to a generic \"cite sources by name\" prompt. */\n systemPrompt?: string\n model?: string\n}\n\nexport interface DefaultCoderConfig {\n /** Replace the system prompt to bias the coder toward a language /\n * framework / artifact style. */\n systemPrompt?: string\n model?: string\n}\n\nconst GENERIC_RESEARCHER_SYSTEM =\n '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.'\n\nconst GENERIC_CODER_SYSTEM =\n 'You are an expert engineer. Output ONE fenced code block containing the complete solution. Inline-comment non-obvious decisions. No explanation outside the block.'\n\nexport const DEFAULT_DELEGATE_RESEARCH_TOOL: MultishotToolDefinition = {\n type: 'function',\n function: {\n name: 'delegate_research',\n description:\n '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.',\n parameters: {\n type: 'object',\n properties: {\n question: { type: 'string', description: 'Specific question to research' },\n scope: {\n type: 'string',\n description: 'Optional scope: time window, geography, jurisdiction, segment',\n },\n },\n required: ['question'],\n },\n },\n}\n\nexport const DEFAULT_DELEGATE_CODE_TOOL: MultishotToolDefinition = {\n type: 'function',\n function: {\n name: 'delegate_code',\n description:\n '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.',\n parameters: {\n type: 'object',\n properties: {\n goal: { type: 'string', description: 'What the code must accomplish' },\n language: {\n type: 'string',\n description: 'Optional language preference (default: TypeScript)',\n },\n },\n required: ['goal'],\n },\n },\n}\n\nexport function createResearchExecutor(\n config: DefaultResearcherConfig = {},\n): MultishotToolExecutor {\n const systemPrompt = config.systemPrompt ?? GENERIC_RESEARCHER_SYSTEM\n const model = config.model ?? DEFAULT_RESEARCHER_MODEL\n return async (args, ctx) => {\n const question = String(args.question ?? '')\n const scope = args.scope ? String(args.scope) : undefined\n const { message, usage } = await routerCompletion({\n apiKey: ctx.apiKey,\n baseUrl: ctx.baseUrl,\n model,\n temperature: 0.3,\n maxTokens: 1800,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: `Research: ${question}${scope ? `\\nScope: ${scope}` : ''}` },\n ],\n signal: ctx.signal,\n })\n return { content: message.content ?? '', costUsd: estimateRouterCost(model, usage) }\n }\n}\n\nexport function createCodeExecutor(config: DefaultCoderConfig = {}): MultishotToolExecutor {\n const systemPrompt = config.systemPrompt ?? GENERIC_CODER_SYSTEM\n const model = config.model ?? DEFAULT_CODER_MODEL\n return async (args, ctx) => {\n const goal = String(args.goal ?? '')\n const language = args.language ? String(args.language) : 'TypeScript'\n const { message, usage } = await routerCompletion({\n apiKey: ctx.apiKey,\n baseUrl: ctx.baseUrl,\n model,\n temperature: 0.2,\n maxTokens: 2000,\n messages: [\n { role: 'system', content: `${systemPrompt}\\n\\nLanguage: ${language}` },\n { role: 'user', content: `Produce: ${goal}` },\n ],\n signal: ctx.signal,\n })\n return { content: message.content ?? '', costUsd: estimateRouterCost(model, usage) }\n }\n}\n\nexport interface DefaultToolsConfig {\n research?: DefaultResearcherConfig\n code?: DefaultCoderConfig\n /** When true (default), each tool result is recorded as a typed artifact:\n * research → type='research', code → type='code'. */\n recordArtifacts?: boolean\n}\n\nexport interface DefaultToolsBundle {\n tools: MultishotToolDefinition[]\n executors: Record<string, MultishotToolExecutor>\n artifactTypeFor: (toolName: string) => string | undefined\n}\n\nexport function defaultDelegationTools(config: DefaultToolsConfig = {}): DefaultToolsBundle {\n return {\n tools: [DEFAULT_DELEGATE_RESEARCH_TOOL, DEFAULT_DELEGATE_CODE_TOOL],\n executors: {\n delegate_research: createResearchExecutor(config.research),\n delegate_code: createCodeExecutor(config.code),\n },\n artifactTypeFor: (name) =>\n name === 'delegate_research' ? 'research' : name === 'delegate_code' ? 'code' : undefined,\n }\n}\n\nexport { defaultRouterBaseUrl } from './router'\n","// Generic judge runner — domain consumers configure dimensions + prompts.\n//\n// Three judge slots are conventional for multishot eval:\n// - conversation (scores the full transcript)\n// - codeReview (scores each code artifact)\n// - contentQuality (scores each non-code artifact)\n//\n// But the runJudge primitive is fully generic: any input maps to a score plus\n// explicit observed, estimated, or uncaptured cost.\n\nimport type { JudgeScore } from '../campaign/types'\nimport type { CostProvenance } from '../cost-ledger'\nimport type { LlmCallMetadata, LlmUsage } from '../llm-client'\nimport { estimateCost, isModelPriced } from '../metrics'\nimport {\n defaultRouterBaseUrl,\n type RouterCompletionResponse,\n requireRouterApiKey,\n routerCompletion,\n} from './router'\n\n// Canonical declaration lives in campaign/types.ts. Multishot emits the same\n// shape on its producer-defined 0-10 scale.\nexport type { JudgeScore } from '../campaign/types'\n\nexport const DEFAULT_JUDGE_MODEL = 'openai/gpt-4o-mini'\n\nexport interface JudgeDimension {\n /** JSON field name + score key. */\n key: string\n /** Description shown in the judge's user prompt. */\n description: string\n}\n\nexport interface JudgeConfig<TInput> {\n /** Display name (for trace + log). */\n name: string\n /** Model used for this judge. */\n model?: string\n /** 0-10 scored dimensions. */\n dimensions: JudgeDimension[]\n /** Judge system prompt — sets persona + JSON-only constraint. */\n systemPrompt: string\n /** Build the user prompt from the typed input. Must include \"Respond with\n * ONLY this JSON: { ... }\" listing each dimension key. */\n buildPrompt: (input: TInput) => string\n /** Optional model + api overrides. */\n apiKey?: string\n baseUrl?: string\n /** Maximum output tokens for the judge response. Defaults to 1500. */\n maxTokens?: number\n}\n\nexport interface JudgeRunResult {\n /** Semantic result; failed scores remain non-throwing so matrix aggregation can exclude them. */\n score: JudgeScore\n /** Cost of the completed call, separate from diagnostic provider metadata. */\n cost: CostProvenance\n}\n\nexport async function runJudge<TInput>(\n judge: JudgeConfig<TInput>,\n input: TInput,\n): Promise<JudgeRunResult> {\n const apiKey = judge.apiKey ?? requireRouterApiKey()\n const baseUrl = judge.baseUrl ?? defaultRouterBaseUrl()\n const model = judge.model ?? process.env.JUDGE_MODEL ?? DEFAULT_JUDGE_MODEL\n const prompt = judge.buildPrompt(input)\n let raw = ''\n let llmCall: LlmCallMetadata\n let cost: CostProvenance\n const startedAt = Date.now()\n try {\n const response = await routerCompletion({\n apiKey,\n baseUrl,\n model,\n temperature: 0,\n maxTokens: judge.maxTokens ?? 1500,\n messages: [\n { role: 'system', content: judge.systemPrompt },\n { role: 'user', content: prompt },\n ],\n })\n const call = judgeCallMetadata(response)\n llmCall = call.llmCall\n cost = call.cost\n raw = (response.message.content ?? '').trim()\n } catch (err) {\n // failed:true lets consumers reading `.composite` keep working while\n // aggregators exclude this score from means instead of averaging a zero.\n return {\n score: {\n dimensions: {},\n composite: 0,\n failed: true,\n notes: `judge ${judge.name} call failed: ${err instanceof Error ? err.message : String(err)}`,\n llmCall: unknownJudgeCall(model, Date.now() - startedAt),\n },\n cost: { kind: 'uncaptured', usd: null },\n }\n }\n\n let parsed: Record<string, unknown> | null = null\n try {\n const cleaned = raw\n .replace(/^```json\\s*/i, '')\n .replace(/```\\s*$/, '')\n .trim()\n parsed = JSON.parse(cleaned) as Record<string, unknown>\n } catch {\n return {\n score: {\n dimensions: {},\n composite: 0,\n failed: true,\n notes: `judge ${judge.name} returned non-JSON: ${raw.slice(0, 200)}`,\n llmCall,\n },\n cost,\n }\n }\n\n const dimensions: Record<string, number> = {}\n let sum = 0\n for (const dim of judge.dimensions) {\n const v = Number(parsed[dim.key] ?? 0)\n const clamped = Number.isFinite(v) ? Math.max(0, Math.min(10, v)) : 0\n dimensions[dim.key] = clamped\n sum += clamped\n }\n return {\n score: {\n dimensions,\n composite: judge.dimensions.length === 0 ? 0 : sum / judge.dimensions.length,\n notes: typeof parsed.notes === 'string' ? parsed.notes : '',\n llmCall,\n },\n cost,\n }\n}\n\nfunction judgeCallMetadata(response: RouterCompletionResponse): {\n llmCall: LlmCallMetadata\n cost: CostProvenance\n} {\n const usage = canonicalUsage(response.usage)\n return {\n llmCall: {\n usage,\n costUsd: response.costUsd ?? null,\n model: response.model,\n durationMs: response.durationMs,\n },\n cost:\n response.costUsd !== undefined\n ? { kind: 'observed', usd: response.costUsd }\n : usage.captured === false || !isModelPriced(response.model)\n ? { kind: 'uncaptured', usd: null }\n : {\n kind: 'estimated',\n usd: estimateCost(usage.promptTokens, usage.completionTokens, response.model),\n },\n }\n}\n\nfunction canonicalUsage(usage: RouterCompletionResponse['usage']): LlmUsage {\n const promptTokens = tokenCount(usage?.prompt_tokens)\n const completionTokens = tokenCount(usage?.completion_tokens)\n const captured = promptTokens !== undefined && completionTokens !== undefined\n return {\n promptTokens: promptTokens ?? 0,\n completionTokens: completionTokens ?? 0,\n totalTokens: (promptTokens ?? 0) + (completionTokens ?? 0),\n captured,\n }\n}\n\nfunction unknownJudgeCall(model: string, durationMs: number): LlmCallMetadata {\n return {\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0, captured: false },\n costUsd: null,\n model,\n durationMs,\n }\n}\n\nfunction tokenCount(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined\n}\n\n/** Convenience: stringified dimension list for inclusion in a judge prompt.\n * Returns lines like `- audience_fit: Does this match what the audience cares about? (0-10)`. */\nexport function renderDimensions(dims: readonly JudgeDimension[]): string {\n return dims.map((d) => `- ${d.key}: ${d.description}`).join('\\n')\n}\n\n/** Convenience: build the \"Respond with ONLY this JSON\" footer for a judge prompt. */\nexport function renderJsonFooter(dims: readonly JudgeDimension[]): string {\n const fields = dims.map((d) => `\"${d.key}\":N`).join(',')\n return `Respond with ONLY this JSON (no markdown, no preamble):\\n{${fields},\"notes\":\"1-2 sentence critique\"}`\n}\n","// Public types for the multishot substrate.\n\nexport interface MultishotMessage {\n role: 'user' | 'assistant' | 'tool'\n content: string\n toolCallId?: string\n toolCalls?: Array<{ id: string; name: string; args: Record<string, unknown> }>\n}\n\nexport interface MultishotArtifact {\n type: string\n turn: number\n invocation: { name: string; args: Record<string, unknown> }\n content: string\n}\n\nexport interface MultishotResult {\n transcript: MultishotMessage[]\n artifacts: MultishotArtifact[]\n toolCalls: number\n durationMs: number\n costUsd: number\n}\n\nexport interface MultishotToolDefinition {\n type: 'function'\n function: {\n name: string\n description: string\n parameters: Record<string, unknown>\n }\n}\n\n/** One chat-completion request the multishot loop issues for a single agent\n * (or driver) inference step. Mirrors the OpenAI-compat body the loop would\n * otherwise POST to the Tangle router. */\nexport interface MultishotTransportRequest {\n model: string\n messages: Array<Record<string, unknown>>\n tools?: MultishotToolDefinition[]\n temperature?: number\n maxTokens?: number\n signal?: AbortSignal\n}\n\nexport interface MultishotTransportToolCall {\n id: string\n type: 'function'\n function: { name: string; arguments: string }\n}\n\nexport interface MultishotTransportResponse {\n message: { content?: string | null; tool_calls?: MultishotTransportToolCall[] }\n usage?: { prompt_tokens?: number; completion_tokens?: number }\n /** Actual spend for this call. When omitted, the loop meters cost from\n * `usage` via the per-model router estimator (estimateRouterCost). */\n costUsd?: number\n}\n\n/** Execution seam for one leg of the multishot loop. When provided, it\n * replaces the internal router HTTP call for that leg — the loop still owns\n * turn scheduling, tool dispatch, transcript capture, and cost metering.\n * agent-eval has no dependency on agent-runtime; adapt agent-runtime's\n * resolveAgentBackend (or any sandbox/cli-bridge/router client) into this\n * signature product-side. */\nexport type MultishotTransport = (\n req: MultishotTransportRequest,\n) => Promise<MultishotTransportResponse>\n\nexport type MultishotToolExecutor = (\n args: Record<string, unknown>,\n ctx: { apiKey: string; baseUrl: string; signal?: AbortSignal },\n) => Promise<{ content: string; costUsd: number }>\n\nexport interface MultishotPersona {\n /** Stable identifier — used for per-cell artifact paths + matrix axis keys. */\n id: string\n /** Per-domain payload (income/profile/voice/etc.) shaped by the consumer. */\n [k: string]: unknown\n}\n\nexport interface MultishotShape<TPersona extends MultishotPersona> {\n /** Opening user message (turn 0) — the persona's first ask. */\n buildOpener: (persona: TPersona) => string\n /** System prompt the driver LLM uses to roleplay the persona. Should set\n * voice, goals, constraints, time-pressure, and the \"never go silent\" rule. */\n buildDriverSystemPrompt: (persona: TPersona) => string\n}\n\nexport class MultishotDriverEmptyError extends Error {\n constructor(public readonly turn: number) {\n super(`multishot: driver returned empty content twice at turn ${turn} — failing loud`)\n this.name = 'MultishotDriverEmptyError'\n }\n}\n\nexport class MultishotFatalToolError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MultishotFatalToolError'\n }\n}\n","// Multi-turn driver-agent simulation with inline tool execution.\n//\n// The driver = LLM acting as the persona (reactive, non-deterministic).\n// The agent = the product agent under test (router call by default, or an\n// injected transport — with profile's systemPrompt + the configured tools).\n// Tool calls execute inline via the configured executors and feed back\n// into the agent's message log so the agent integrates the result.\n\nimport type { AgentProfile } from '@tangle-network/agent-interface'\nimport { defaultDelegationTools } from './default-tools'\nimport {\n defaultRouterBaseUrl,\n estimateRouterCost,\n requireRouterApiKey,\n routerCompletion,\n} from './router'\nimport {\n type MultishotArtifact,\n MultishotDriverEmptyError,\n MultishotFatalToolError,\n type MultishotMessage,\n type MultishotPersona,\n type MultishotResult,\n type MultishotShape,\n type MultishotToolDefinition,\n type MultishotToolExecutor,\n type MultishotTransport,\n} from './types'\n\nexport interface RunMultishotOptions<TPersona extends MultishotPersona> {\n profile: AgentProfile\n persona: TPersona\n shape: MultishotShape<TPersona>\n /** Tool definitions advertised to the agent. Defaults to delegate_research + delegate_code. */\n tools?: MultishotToolDefinition[]\n /** Map from tool name → executor invoked inline when the agent emits a tool_call. */\n toolExecutors?: Record<string, MultishotToolExecutor>\n /** Map from tool name → artifact type label written into MultishotArtifact.type.\n * Tools without a mapping still execute, but their results aren't surfaced as\n * typed artifacts (only as tool messages in the transcript). */\n artifactTypeFor?: (toolName: string) => string | undefined\n maxTurns?: number\n agentModel?: string\n driverModel?: string\n /** Fallback driver models tried when the primary simulated-user model returns empty twice. */\n driverFallbackModels?: string[]\n /** Maximum output tokens for the first agent call in each assistant turn. */\n agentMaxTokens?: number\n /** Maximum output tokens for agent follow-up calls after tool results. */\n toolFollowupMaxTokens?: number\n /** Maximum output tokens for each simulated-user driver response. */\n driverMaxTokens?: number\n /** Maximum tool calls the agent may dispatch inside one assistant turn. */\n maxToolDispatches?: number\n /** Execution seam for the agent leg. When provided, every agent inference\n * step goes through this function instead of the router HTTP call; the\n * string levers (agentModel, apiKey, baseUrl) stop applying to that leg.\n * apiKey/baseUrl are still resolved for tool executors and any leg\n * without an injected transport. */\n agentTransport?: MultishotTransport\n /** Execution seam for the simulated-user driver leg (symmetric to\n * agentTransport). Driver model fallback rotation still applies — the\n * transport receives each candidate model in turn. */\n driverTransport?: MultishotTransport\n apiKey?: string\n baseUrl?: string\n signal?: AbortSignal\n}\n\nexport async function runMultishot<TPersona extends MultishotPersona>(\n opts: RunMultishotOptions<TPersona>,\n): Promise<MultishotResult> {\n const apiKey = opts.apiKey ?? requireRouterApiKey()\n const baseUrl = opts.baseUrl ?? defaultRouterBaseUrl()\n const maxTurns = opts.maxTurns ?? 10\n const maxToolDispatches = opts.maxToolDispatches ?? 4\n const agentModel = opts.agentModel ?? 'openai/gpt-5.4'\n const driverModel = opts.driverModel ?? 'openai/gpt-4o-mini'\n const driverModels = [driverModel, ...(opts.driverFallbackModels ?? [])]\n const agentMaxTokens = opts.agentMaxTokens ?? 2500\n const toolFollowupMaxTokens = opts.toolFollowupMaxTokens ?? 2000\n const driverMaxTokens = opts.driverMaxTokens ?? 600\n\n const bundle =\n opts.tools && opts.toolExecutors\n ? {\n tools: opts.tools,\n executors: opts.toolExecutors,\n artifactTypeFor: opts.artifactTypeFor ?? (() => undefined),\n }\n : defaultDelegationTools()\n const tools = opts.tools ?? bundle.tools\n const executors = opts.toolExecutors ?? bundle.executors\n const artifactTypeFor = opts.artifactTypeFor ?? bundle.artifactTypeFor\n\n const routerTransport: MultishotTransport = (req) => routerCompletion({ apiKey, baseUrl, ...req })\n const agentTransport = opts.agentTransport ?? routerTransport\n const driverTransport = opts.driverTransport ?? routerTransport\n\n const start = Date.now()\n const transcript: MultishotMessage[] = []\n const artifacts: MultishotArtifact[] = []\n let toolCalls = 0\n let totalCostUsd = 0\n\n const opener = opts.shape.buildOpener(opts.persona)\n transcript.push({ role: 'user', content: opener })\n\n const systemPrompt = opts.profile.prompt?.systemPrompt ?? ''\n const agentMessages: Array<Record<string, unknown>> = [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: opener },\n ]\n\n for (let turn = 0; turn < maxTurns; turn++) {\n if (opts.signal?.aborted) throw new Error('multishot aborted')\n\n let dispatchesThisTurn = 0\n while (true) {\n const {\n message: agentMsg,\n usage: agentUsage,\n costUsd: agentCostUsd,\n } = await agentTransport({\n model: agentModel,\n messages: agentMessages,\n tools,\n temperature: 0.7,\n maxTokens: dispatchesThisTurn === 0 ? agentMaxTokens : toolFollowupMaxTokens,\n signal: opts.signal,\n })\n totalCostUsd += agentCostUsd ?? estimateRouterCost(agentModel, agentUsage)\n\n const agentText = (agentMsg.content ?? '').trim()\n const agentToolCalls = (agentMsg.tool_calls ?? []).map((tc) => ({\n id: tc.id,\n name: tc.function.name,\n args: (() => {\n try {\n return JSON.parse(tc.function.arguments) as Record<string, unknown>\n } catch {\n return {} as Record<string, unknown>\n }\n })(),\n }))\n\n agentMessages.push({\n role: 'assistant',\n content: agentText || null,\n ...(agentMsg.tool_calls?.length ? { tool_calls: agentMsg.tool_calls } : {}),\n })\n transcript.push({\n role: 'assistant',\n content: agentText,\n toolCalls: agentToolCalls.length > 0 ? agentToolCalls : undefined,\n })\n\n if (agentToolCalls.length === 0) break\n dispatchesThisTurn += agentToolCalls.length\n if (dispatchesThisTurn > maxToolDispatches) {\n throw new Error(\n `multishot: tool dispatch cap exceeded (${dispatchesThisTurn}/${maxToolDispatches}) on turn ${turn}`,\n )\n }\n\n for (const tc of agentToolCalls) {\n toolCalls++\n let toolResult = ''\n try {\n const executor = executors[tc.name]\n if (!executor) {\n toolResult = JSON.stringify({ error: `unknown tool ${tc.name}` })\n } else {\n const r = await executor(tc.args, { apiKey, baseUrl, signal: opts.signal })\n toolResult = r.content\n totalCostUsd += r.costUsd\n const artifactType = artifactTypeFor(tc.name)\n if (artifactType) {\n artifacts.push({\n type: artifactType,\n turn,\n invocation: { name: tc.name, args: tc.args },\n content: toolResult,\n })\n }\n }\n } catch (err) {\n if (err instanceof MultishotFatalToolError) throw err\n toolResult = JSON.stringify({ error: err instanceof Error ? err.message : String(err) })\n }\n agentMessages.push({ role: 'tool', tool_call_id: tc.id, content: toolResult || 'done' })\n transcript.push({ role: 'tool', content: toolResult || 'done', toolCallId: tc.id })\n }\n }\n\n if (turn < maxTurns - 1) {\n const driver = await driverTurn({\n transport: driverTransport,\n persona: opts.persona,\n shape: opts.shape,\n transcript,\n turn,\n models: driverModels,\n maxTokens: driverMaxTokens,\n signal: opts.signal,\n })\n totalCostUsd += driver.costUsd\n agentMessages.push({ role: 'user', content: driver.content })\n transcript.push({ role: 'user', content: driver.content })\n }\n }\n\n return { transcript, artifacts, toolCalls, durationMs: Date.now() - start, costUsd: totalCostUsd }\n}\n\nasync function driverTurn<TPersona extends MultishotPersona>(opts: {\n transport: MultishotTransport\n persona: TPersona\n shape: MultishotShape<TPersona>\n transcript: MultishotMessage[]\n turn: number\n models: string[]\n maxTokens: number\n signal?: AbortSignal\n}): Promise<{ content: string; costUsd: number }> {\n const driverSystem = opts.shape.buildDriverSystemPrompt(opts.persona)\n\n // Translate transcript to driver POV: agent's `assistant` messages become\n // `user` (the agent talking TO the driver); the driver's prior `user`\n // messages become `assistant` (the driver's prior responses).\n const driverMessages: Array<Record<string, unknown>> = [{ role: 'system', content: driverSystem }]\n for (const msg of opts.transcript) {\n if (msg.role === 'tool') continue\n const content = driverVisibleContent(msg)\n if (!content) continue\n if (msg.role === 'assistant') driverMessages.push({ role: 'user', content })\n else if (msg.role === 'user') driverMessages.push({ role: 'assistant', content })\n }\n\n // Driver must never go silent. Retry once on empty content; then fail loud.\n for (const model of opts.models) {\n for (let attempt = 0; attempt < 2; attempt++) {\n const { message, usage, costUsd } = await opts.transport({\n model,\n messages: driverMessages,\n temperature: 0.9,\n maxTokens: opts.maxTokens,\n signal: opts.signal,\n })\n const content = (message.content ?? '').trim()\n if (content.length > 0)\n return { content, costUsd: costUsd ?? estimateRouterCost(model, usage) }\n }\n }\n throw new MultishotDriverEmptyError(opts.turn)\n}\n\nfunction driverVisibleContent(msg: MultishotMessage): string | null {\n const text = msg.content.trim()\n if (text.length > 0) return text\n if (msg.role !== 'assistant' || !msg.toolCalls?.length) return null\n\n const toolNames = msg.toolCalls.map((call) => call.name.trim()).filter(Boolean)\n if (toolNames.length === 0) return 'Agent called tools.'\n return `Agent called ${toolNames.length === 1 ? 'tool' : 'tools'}: ${toolNames.join(', ')}.`\n}\n","// Multishot matrix wrapper — sweeps profiles × personas × reps, runs\n// the driver-agent loop per cell, applies up to three configured judges,\n// persists per-cell artifacts, and aggregates by axis.\n//\n// Uses runAgentMatrix from @tangle-network/agent-eval/matrix under the\n// hood so cell scheduling + concurrency + cost ceiling are unified with\n// other matrix consumers.\n\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { AgentProfile } from '@tangle-network/agent-interface'\nimport type { CostProvenance } from '../cost-ledger'\nimport type { MatrixResult } from '../matrix'\nimport { runAgentMatrix } from '../matrix'\nimport { type JudgeConfig, type JudgeScore, runJudge } from './judges'\nimport { runMultishot } from './multishot'\nimport type {\n MultishotArtifact,\n MultishotMessage,\n MultishotPersona,\n MultishotShape,\n MultishotToolDefinition,\n MultishotToolExecutor,\n MultishotTransport,\n} from './types'\n\nexport interface ConversationJudgeInput<TPersona extends MultishotPersona> {\n transcript: MultishotMessage[]\n persona: TPersona\n}\n\nexport interface ArtifactJudgeInput<TPersona extends MultishotPersona> {\n artifact: MultishotArtifact\n persona: TPersona\n}\n\nexport interface MultishotJudges<TPersona extends MultishotPersona> {\n /** Scores the full transcript end-to-end (always runs). */\n conversation: JudgeConfig<ConversationJudgeInput<TPersona>>\n /** Scores each code-type artifact. Optional — omit when domain has no code artifacts. */\n codeReview?: JudgeConfig<ArtifactJudgeInput<TPersona>>\n /** Scores each non-code (research/content/template) artifact. Optional. */\n contentQuality?: JudgeConfig<ArtifactJudgeInput<TPersona>>\n /** Which artifact types route to codeReview. Defaults to ['code']. */\n codeArtifactTypes?: string[]\n /** Which artifact types route to contentQuality. Defaults to ['research']. */\n contentArtifactTypes?: string[]\n}\n\nexport interface CellCompositeScore {\n composite: number\n conversation: JudgeScore\n codeReview?: {\n perArtifact: Array<JudgeScore & { turn: number; type: string }>\n composite: number\n }\n contentQuality?: {\n perArtifact: Array<JudgeScore & { turn: number; type: string }>\n composite: number\n }\n}\n\nexport interface RunMultishotMatrixOptions<TPersona extends MultishotPersona> {\n /** AgentProfile axis (matrix primary). */\n profiles: Array<{ id: string; value: AgentProfile }>\n /** Persona axis. */\n personas: TPersona[]\n /** Persona-shaping callbacks. */\n shape: MultishotShape<TPersona>\n /** Judge configurations. */\n judges: MultishotJudges<TPersona>\n /** Tool definitions advertised to the agent. Defaults to delegate_research + delegate_code. */\n tools?: MultishotToolDefinition[]\n /** Map from tool name → inline executor. Must align with `tools`. */\n toolExecutors?: Record<string, MultishotToolExecutor>\n /** Tool name → artifact type label. Defaults to research/code mapping. */\n artifactTypeFor?: (toolName: string) => string | undefined\n /** Where per-cell artifacts land. Cells write to `<runDir>/<profileId>/<personaId>/rep-N/`. */\n runDir: string\n /** Replicates per (profile, persona) cell. */\n reps?: number\n /** Max conversation turns per cell. */\n maxTurns?: number\n /** Maximum tool calls the agent may dispatch inside one assistant turn. */\n maxToolDispatches?: number\n /** Max concurrent cells. */\n maxConcurrency?: number\n /** Total $ ceiling across the matrix; cells aborted past this. */\n costCeiling?: number\n /** Agent model. */\n agentModel?: string\n /** Driver model. */\n driverModel?: string\n /** Fallback driver models tried when the primary simulated-user model returns empty twice. */\n driverFallbackModels?: string[]\n /** Maximum output tokens for the first agent call in each assistant turn. */\n agentMaxTokens?: number\n /** Maximum output tokens for agent follow-up calls after tool results. */\n toolFollowupMaxTokens?: number\n /** Maximum output tokens for each simulated-user driver response. */\n driverMaxTokens?: number\n /** Maximum output tokens for each judge response. */\n judgeMaxTokens?: number\n /** Execution seam for the agent leg of every cell — replaces the router\n * HTTP call when provided (see RunMultishotOptions.agentTransport).\n * Judges are unaffected; configure those via MultishotJudges. */\n agentTransport?: MultishotTransport\n /** Execution seam for the simulated-user driver leg of every cell. */\n driverTransport?: MultishotTransport\n /** Pass-thru fields. */\n apiKey?: string\n baseUrl?: string\n}\n\ninterface CellOutput {\n turns: number\n toolCalls: number\n artifactCount: number\n}\n\ninterface ArtifactJudgeRun {\n score: JudgeScore & { turn: number; type: string }\n cost: CostProvenance\n}\n\n/** Mean composite over non-failed scores. `0` when the list is empty (a\n * configured judge with nothing to score contributes 0, matching the cell\n * composite's long-standing semantics); `null` when scores exist but every\n * one failed — no signal, so the slot must be EXCLUDED from the cell mean\n * rather than dragging it to zero. */\nfunction meanCompositeExcludingFailed(scores: ReadonlyArray<JudgeScore>): number | null {\n if (scores.length === 0) return 0\n const live = scores.filter((s) => !s.failed)\n if (live.length === 0) return null\n return live.reduce((sum, s) => sum + s.composite, 0) / live.length\n}\n\nexport interface CellCompositeInput {\n conversation: JudgeScore\n /** Present iff the codeReview judge is configured. */\n codeReviews?: ReadonlyArray<JudgeScore>\n /** Present iff the contentQuality judge is configured. */\n contentReviews?: ReadonlyArray<JudgeScore>\n}\n\n/** Cell composite = mean over configured judge slots, excluding failed\n * scores: a failed conversation judge or an all-failed artifact slot carries\n * no signal and is dropped from the mean. `composite` is 0 only when EVERY\n * configured slot failed (`allJudgesFailed` distinguishes that from a real\n * zero). Pure — exported for deterministic testing. */\nexport function computeCellComposite(input: CellCompositeInput): {\n composite: number\n codeComposite: number\n contentComposite: number\n allJudgesFailed: boolean\n} {\n const contributions: number[] = []\n if (!input.conversation.failed) contributions.push(input.conversation.composite)\n\n const codeMean = input.codeReviews ? meanCompositeExcludingFailed(input.codeReviews) : undefined\n if (typeof codeMean === 'number') contributions.push(codeMean)\n const contentMean = input.contentReviews\n ? meanCompositeExcludingFailed(input.contentReviews)\n : undefined\n if (typeof contentMean === 'number') contributions.push(contentMean)\n\n return {\n composite:\n contributions.length === 0\n ? 0\n : contributions.reduce((s, v) => s + v, 0) / contributions.length,\n codeComposite: codeMean ?? 0,\n contentComposite: contentMean ?? 0,\n allJudgesFailed: contributions.length === 0,\n }\n}\n\nexport interface RunMultishotMatrixResult {\n matrix: MatrixResult<CellOutput>\n}\n\nexport async function runMultishotMatrix<TPersona extends MultishotPersona>(\n opts: RunMultishotMatrixOptions<TPersona>,\n): Promise<RunMultishotMatrixResult> {\n const codeTypes = new Set(opts.judges.codeArtifactTypes ?? ['code'])\n const contentTypes = new Set(opts.judges.contentArtifactTypes ?? ['research'])\n mkdirSync(opts.runDir, { recursive: true })\n\n const matrix = await runAgentMatrix<CellOutput>({\n axes: [\n { name: 'profile', values: opts.profiles },\n { name: 'persona', values: opts.personas.map((p) => ({ id: p.id, value: p })) },\n ],\n reps: opts.reps ?? 1,\n maxConcurrency: opts.maxConcurrency ?? 2,\n costCeiling: opts.costCeiling,\n async runCell(cell) {\n const profile = cell.axes.profile?.value as AgentProfile\n const persona = cell.axes.persona?.value as TPersona\n const profileId = String(cell.axes.profile?.id ?? 'unknown')\n const personaId = String(cell.axes.persona?.id ?? 'unknown')\n\n const sim = await runMultishot({\n profile,\n persona,\n shape: opts.shape,\n tools: opts.tools,\n toolExecutors: opts.toolExecutors,\n artifactTypeFor: opts.artifactTypeFor,\n maxTurns: opts.maxTurns,\n maxToolDispatches: opts.maxToolDispatches,\n agentModel: opts.agentModel,\n driverModel: opts.driverModel,\n driverFallbackModels: opts.driverFallbackModels,\n agentMaxTokens: opts.agentMaxTokens,\n toolFollowupMaxTokens: opts.toolFollowupMaxTokens,\n driverMaxTokens: opts.driverMaxTokens,\n agentTransport: opts.agentTransport,\n driverTransport: opts.driverTransport,\n apiKey: opts.apiKey,\n baseUrl: opts.baseUrl,\n })\n\n const codeArtifacts = sim.artifacts.filter((a) => codeTypes.has(a.type))\n const contentArtifacts = sim.artifacts.filter((a) => contentTypes.has(a.type))\n\n const [conversationRun, codeReviewRuns, contentReviewRuns] = await Promise.all([\n runJudge(withJudgeMaxTokens(opts.judges.conversation, opts.judgeMaxTokens), {\n transcript: sim.transcript,\n persona,\n }),\n opts.judges.codeReview\n ? Promise.all(\n codeArtifacts.map((artifact) =>\n runJudge(withJudgeMaxTokens(opts.judges.codeReview!, opts.judgeMaxTokens), {\n artifact,\n persona,\n }).then((result) => ({\n score: {\n ...result.score,\n turn: artifact.turn,\n type: artifact.type,\n },\n cost: result.cost,\n })),\n ),\n )\n : Promise.resolve([] as ArtifactJudgeRun[]),\n opts.judges.contentQuality\n ? Promise.all(\n contentArtifacts.map((artifact) =>\n runJudge(withJudgeMaxTokens(opts.judges.contentQuality!, opts.judgeMaxTokens), {\n artifact,\n persona,\n }).then((result) => ({\n score: {\n ...result.score,\n turn: artifact.turn,\n type: artifact.type,\n },\n cost: result.cost,\n })),\n ),\n )\n : Promise.resolve([] as ArtifactJudgeRun[]),\n ])\n const conversation = conversationRun.score\n const codeReviews = codeReviewRuns.map((run) => run.score)\n const contentReviews = contentReviewRuns.map((run) => run.score)\n\n const { composite, codeComposite, contentComposite, allJudgesFailed } = computeCellComposite({\n conversation,\n codeReviews: opts.judges.codeReview ? codeReviews : undefined,\n contentReviews: opts.judges.contentQuality ? contentReviews : undefined,\n })\n\n const cellScore: CellCompositeScore = { composite, conversation }\n if (opts.judges.codeReview)\n cellScore.codeReview = { perArtifact: codeReviews, composite: codeComposite }\n if (opts.judges.contentQuality)\n cellScore.contentQuality = { perArtifact: contentReviews, composite: contentComposite }\n\n const cellDir = join(opts.runDir, profileId, personaId, `rep-${cell.rep}`)\n mkdirSync(cellDir, { recursive: true })\n writeFileSync(join(cellDir, 'transcript.json'), JSON.stringify(sim.transcript, null, 2))\n writeFileSync(join(cellDir, 'artifacts.json'), JSON.stringify(sim.artifacts, null, 2))\n writeFileSync(join(cellDir, 'scores.json'), JSON.stringify(cellScore, null, 2))\n\n const notes = [`convo=${conversation.composite.toFixed(1)}`]\n if (opts.judges.codeReview) notes.push(`code=${codeComposite.toFixed(1)}`)\n if (opts.judges.contentQuality) notes.push(`content=${contentComposite.toFixed(1)}`)\n if (allJudgesFailed) notes.push('all-judges-failed')\n const judgeRuns = [conversationRun, ...codeReviewRuns, ...contentReviewRuns]\n const judgeCostUsd = judgeRuns.reduce((sum, run) => sum + (run.cost.usd ?? 0), 0)\n if (judgeRuns.some((run) => run.cost.kind === 'uncaptured')) {\n notes.push('judge-cost-incomplete')\n }\n\n return {\n output: {\n turns: sim.transcript.length,\n toolCalls: sim.toolCalls,\n artifactCount: sim.artifacts.length,\n },\n verdict: { valid: composite >= 5, score: composite, notes: notes.join(' ') },\n costUsd: sim.costUsd + judgeCostUsd,\n durationMs: sim.durationMs,\n }\n },\n })\n\n // Persist top-level summary.\n const summary = {\n cells: matrix.summary.totalCells,\n passRate: matrix.summary.overallPassRate,\n meanScore: matrix.summary.overallMeanScore,\n totalCostUsd: matrix.summary.totalCostUsd,\n durationMs: matrix.summary.durationMs,\n runsExecuted: matrix.summary.runsExecuted,\n cellsSkipped: matrix.summary.cellsSkipped,\n byProfile: matrix.byAxis.profile,\n byPersona: matrix.byAxis.persona,\n }\n writeFileSync(join(opts.runDir, 'summary.json'), JSON.stringify(summary, null, 2))\n\n const md: string[] = [\n `# Multishot matrix`,\n ``,\n `**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 / 1000).toFixed(0)}s`,\n ``,\n `## By profile`,\n ``,\n '| profile | pass | mean | cost |',\n '|---|---|---|---|',\n ...Object.entries(matrix.byAxis.profile ?? {}).map(\n ([id, s]) =>\n `| ${id} | ${(s.passRate * 100).toFixed(0)}% | ${s.meanScore.toFixed(2)} | $${s.totalCostUsd.toFixed(2)} |`,\n ),\n ``,\n `## By persona`,\n ``,\n '| persona | pass | mean | cost |',\n '|---|---|---|---|',\n ...Object.entries(matrix.byAxis.persona ?? {}).map(\n ([id, s]) =>\n `| ${id} | ${(s.passRate * 100).toFixed(0)}% | ${s.meanScore.toFixed(2)} | $${s.totalCostUsd.toFixed(2)} |`,\n ),\n ``,\n ]\n writeFileSync(join(opts.runDir, 'summary.md'), md.join('\\n'))\n\n return { matrix }\n}\n\nfunction withJudgeMaxTokens<TInput>(\n judge: JudgeConfig<TInput>,\n maxTokens: number | undefined,\n): JudgeConfig<TInput> {\n if (maxTokens === undefined || judge.maxTokens !== undefined) return judge\n return { ...judge, maxTokens }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/multishot/router.ts","../../src/multishot/default-tools.ts","../../src/multishot/judges.ts","../../src/multishot/shape-defaults.ts","../../src/multishot/types.ts","../../src/multishot/multishot.ts","../../src/multishot/matrix.ts"],"sourcesContent":["// Router fetch helper — single source of truth for OpenAI-compat calls\n// against the Tangle router. Used by the driver, agent, judges, and the\n// default tool executors.\n\nimport type { MultishotToolDefinition } from './types'\n\nexport interface RouterCompletionRequest {\n apiKey: string\n baseUrl: string\n model: string\n messages: Array<Record<string, unknown>>\n tools?: MultishotToolDefinition[]\n temperature?: number\n maxTokens?: number\n signal?: AbortSignal\n}\n\nexport interface RouterToolCall {\n id: string\n type: 'function'\n function: { name: string; arguments: string }\n}\n\nexport interface RouterCompletionResponse {\n message: { content?: string | null; tool_calls?: RouterToolCall[] }\n usage?: { prompt_tokens?: number; completion_tokens?: number }\n /** Provider-reported spend when the endpoint supplies it. */\n costUsd?: number\n /** Model echoed by the provider, falling back to the requested model. */\n model: string\n durationMs: number\n}\n\nexport async function routerCompletion(\n req: RouterCompletionRequest,\n): Promise<RouterCompletionResponse> {\n const startedAt = Date.now()\n const body: Record<string, unknown> = {\n model: req.model,\n messages: req.messages,\n temperature: req.temperature ?? 0.7,\n max_tokens: req.maxTokens ?? 2000,\n }\n if (req.tools?.length) body.tools = req.tools\n const url = `${req.baseUrl.replace(/\\/+$/, '')}/chat/completions`\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${req.apiKey}`, 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: req.signal,\n })\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`router ${res.status}: ${text.slice(0, 300)}`)\n }\n const json = (await res.json()) as {\n choices: Array<{ message: { content?: string | null; tool_calls?: RouterToolCall[] } }>\n usage?: { prompt_tokens?: number; completion_tokens?: number }\n model?: unknown\n _response_cost?: unknown\n cost_usd?: unknown\n }\n const choice = json.choices[0]\n if (!choice) throw new Error(`router returned no choices: ${JSON.stringify(json).slice(0, 200)}`)\n const rawCost = json._response_cost ?? json.cost_usd\n const costUsd =\n typeof rawCost === 'number' && Number.isFinite(rawCost) && rawCost >= 0 ? rawCost : undefined\n return {\n message: choice.message,\n usage: json.usage,\n ...(costUsd === undefined ? {} : { costUsd }),\n model: typeof json.model === 'string' && json.model ? json.model : req.model,\n durationMs: Date.now() - startedAt,\n }\n}\n\n// Rough per-model cost estimator. Used for cost-ceiling enforcement.\n// Underestimates Anthropic, overestimates oss models — fine for ceilings.\nexport function estimateRouterCost(\n model: string,\n usage?: { prompt_tokens?: number; completion_tokens?: number },\n): number {\n if (!usage) return 0\n const inputTok = usage.prompt_tokens ?? 0\n const outputTok = usage.completion_tokens ?? 0\n let inPer1k = 0.003\n let outPer1k = 0.015\n if (model.includes('gpt-4o-mini')) {\n inPer1k = 0.00015\n outPer1k = 0.0006\n } else if (model.includes('gpt-5.4') || model.includes('claude-sonnet')) {\n inPer1k = 0.003\n outPer1k = 0.015\n } else if (model.includes('kimi') || model.includes('glm') || model.includes('deepseek')) {\n inPer1k = 0.0005\n outPer1k = 0.002\n }\n return (inputTok * inPer1k + outputTok * outPer1k) / 1000\n}\n\nexport function defaultRouterBaseUrl(): string {\n return (process.env.TANGLE_ROUTER_BASE_URL ?? 'https://router.tangle.tools/v1').replace(\n /\\/+$/,\n '',\n )\n}\n\nexport function requireRouterApiKey(): string {\n const key = process.env.TANGLE_API_KEY\n if (!key) throw new Error('multishot requires TANGLE_API_KEY (router-scoped sk-tan-* key)')\n return key\n}\n","// Default delegate_research + delegate_code tools and their inline executors.\n//\n// Consumers can override either by passing their own tools + executors to\n// runMultishot. The defaults are sufficient for most domains — point the\n// researcher system prompt at your domain's citation style and the coder\n// at your preferred language.\n\nimport { estimateRouterCost, routerCompletion } from './router'\nimport type { MultishotToolDefinition, MultishotToolExecutor } from './types'\n\nexport const DEFAULT_RESEARCHER_MODEL = 'openai/gpt-4o-mini'\nexport const DEFAULT_CODER_MODEL = 'openai/gpt-4o-mini'\n\nexport interface DefaultResearcherConfig {\n /** Replace the system prompt to bias the researcher toward a domain's\n * citation style. Defaults to a generic \"cite sources by name\" prompt. */\n systemPrompt?: string\n model?: string\n}\n\nexport interface DefaultCoderConfig {\n /** Replace the system prompt to bias the coder toward a language /\n * framework / artifact style. */\n systemPrompt?: string\n model?: string\n}\n\nconst GENERIC_RESEARCHER_SYSTEM =\n '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.'\n\nconst GENERIC_CODER_SYSTEM =\n 'You are an expert engineer. Output ONE fenced code block containing the complete solution. Inline-comment non-obvious decisions. No explanation outside the block.'\n\nexport const DEFAULT_DELEGATE_RESEARCH_TOOL: MultishotToolDefinition = {\n type: 'function',\n function: {\n name: 'delegate_research',\n description:\n '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.',\n parameters: {\n type: 'object',\n properties: {\n question: { type: 'string', description: 'Specific question to research' },\n scope: {\n type: 'string',\n description: 'Optional scope: time window, geography, jurisdiction, segment',\n },\n },\n required: ['question'],\n },\n },\n}\n\nexport const DEFAULT_DELEGATE_CODE_TOOL: MultishotToolDefinition = {\n type: 'function',\n function: {\n name: 'delegate_code',\n description:\n '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.',\n parameters: {\n type: 'object',\n properties: {\n goal: { type: 'string', description: 'What the code must accomplish' },\n language: {\n type: 'string',\n description: 'Optional language preference (default: TypeScript)',\n },\n },\n required: ['goal'],\n },\n },\n}\n\nexport function createResearchExecutor(\n config: DefaultResearcherConfig = {},\n): MultishotToolExecutor {\n const systemPrompt = config.systemPrompt ?? GENERIC_RESEARCHER_SYSTEM\n const model = config.model ?? DEFAULT_RESEARCHER_MODEL\n return async (args, ctx) => {\n const question = String(args.question ?? '')\n const scope = args.scope ? String(args.scope) : undefined\n const { message, usage } = await routerCompletion({\n apiKey: ctx.apiKey,\n baseUrl: ctx.baseUrl,\n model,\n temperature: 0.3,\n maxTokens: 1800,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: `Research: ${question}${scope ? `\\nScope: ${scope}` : ''}` },\n ],\n signal: ctx.signal,\n })\n return { content: message.content ?? '', costUsd: estimateRouterCost(model, usage) }\n }\n}\n\nexport function createCodeExecutor(config: DefaultCoderConfig = {}): MultishotToolExecutor {\n const systemPrompt = config.systemPrompt ?? GENERIC_CODER_SYSTEM\n const model = config.model ?? DEFAULT_CODER_MODEL\n return async (args, ctx) => {\n const goal = String(args.goal ?? '')\n const language = args.language ? String(args.language) : 'TypeScript'\n const { message, usage } = await routerCompletion({\n apiKey: ctx.apiKey,\n baseUrl: ctx.baseUrl,\n model,\n temperature: 0.2,\n maxTokens: 2000,\n messages: [\n { role: 'system', content: `${systemPrompt}\\n\\nLanguage: ${language}` },\n { role: 'user', content: `Produce: ${goal}` },\n ],\n signal: ctx.signal,\n })\n return { content: message.content ?? '', costUsd: estimateRouterCost(model, usage) }\n }\n}\n\nexport interface DefaultToolsConfig {\n research?: DefaultResearcherConfig\n code?: DefaultCoderConfig\n /** When true (default), each tool result is recorded as a typed artifact:\n * research → type='research', code → type='code'. */\n recordArtifacts?: boolean\n}\n\nexport interface DefaultToolsBundle {\n tools: MultishotToolDefinition[]\n executors: Record<string, MultishotToolExecutor>\n artifactTypeFor: (toolName: string) => string | undefined\n}\n\nexport function defaultDelegationTools(config: DefaultToolsConfig = {}): DefaultToolsBundle {\n return {\n tools: [DEFAULT_DELEGATE_RESEARCH_TOOL, DEFAULT_DELEGATE_CODE_TOOL],\n executors: {\n delegate_research: createResearchExecutor(config.research),\n delegate_code: createCodeExecutor(config.code),\n },\n artifactTypeFor: (name) =>\n name === 'delegate_research' ? 'research' : name === 'delegate_code' ? 'code' : undefined,\n }\n}\n\nexport { defaultRouterBaseUrl } from './router'\n","// Generic judge runner — domain consumers configure dimensions + prompts.\n//\n// Three judge slots are conventional for multishot eval:\n// - conversation (scores the full transcript)\n// - codeReview (scores each code artifact)\n// - contentQuality (scores each non-code artifact)\n//\n// But the runJudge primitive is fully generic: any input maps to a score plus\n// explicit observed, estimated, or uncaptured cost.\n\nimport type { JudgeScore } from '../campaign/types'\nimport type { CostProvenance } from '../cost-ledger'\nimport type { LlmCallMetadata, LlmUsage } from '../llm-client'\nimport { estimateCost, isModelPriced } from '../metrics'\nimport {\n defaultRouterBaseUrl,\n type RouterCompletionResponse,\n requireRouterApiKey,\n routerCompletion,\n} from './router'\n\n// Canonical declaration lives in campaign/types.ts. Multishot emits the same\n// shape on its producer-defined 0-10 scale.\nexport type { JudgeScore } from '../campaign/types'\n\nexport const DEFAULT_JUDGE_MODEL = 'openai/gpt-4o-mini'\n\nexport interface JudgeDimension {\n /** JSON field name + score key. */\n key: string\n /** Description shown in the judge's user prompt. */\n description: string\n}\n\nexport interface JudgeConfig<TInput> {\n /** Display name (for trace + log). */\n name: string\n /** Model used for this judge. */\n model?: string\n /** 0-10 scored dimensions. */\n dimensions: JudgeDimension[]\n /** Judge system prompt — sets persona + JSON-only constraint. */\n systemPrompt: string\n /** Build the user prompt from the typed input. Must include \"Respond with\n * ONLY this JSON: { ... }\" listing each dimension key. */\n buildPrompt: (input: TInput) => string\n /** Optional model + api overrides. */\n apiKey?: string\n baseUrl?: string\n /** Maximum output tokens for the judge response. Defaults to 1500. */\n maxTokens?: number\n}\n\nexport interface JudgeRunResult {\n /** Semantic result; failed scores remain non-throwing so matrix aggregation can exclude them. */\n score: JudgeScore\n /** Cost of the completed call, separate from diagnostic provider metadata. */\n cost: CostProvenance\n}\n\nexport async function runJudge<TInput>(\n judge: JudgeConfig<TInput>,\n input: TInput,\n): Promise<JudgeRunResult> {\n const apiKey = judge.apiKey ?? requireRouterApiKey()\n const baseUrl = judge.baseUrl ?? defaultRouterBaseUrl()\n const model = judge.model ?? process.env.JUDGE_MODEL ?? DEFAULT_JUDGE_MODEL\n const prompt = judge.buildPrompt(input)\n let raw = ''\n let llmCall: LlmCallMetadata\n let cost: CostProvenance\n const startedAt = Date.now()\n try {\n const response = await routerCompletion({\n apiKey,\n baseUrl,\n model,\n temperature: 0,\n maxTokens: judge.maxTokens ?? 1500,\n messages: [\n { role: 'system', content: judge.systemPrompt },\n { role: 'user', content: prompt },\n ],\n })\n const call = judgeCallMetadata(response)\n llmCall = call.llmCall\n cost = call.cost\n raw = (response.message.content ?? '').trim()\n } catch (err) {\n // failed:true lets consumers reading `.composite` keep working while\n // aggregators exclude this score from means instead of averaging a zero.\n return {\n score: {\n dimensions: {},\n composite: 0,\n failed: true,\n notes: `judge ${judge.name} call failed: ${err instanceof Error ? err.message : String(err)}`,\n llmCall: unknownJudgeCall(model, Date.now() - startedAt),\n },\n cost: { kind: 'uncaptured', usd: null },\n }\n }\n\n let parsed: Record<string, unknown> | null = null\n try {\n const cleaned = raw\n .replace(/^```json\\s*/i, '')\n .replace(/```\\s*$/, '')\n .trim()\n parsed = JSON.parse(cleaned) as Record<string, unknown>\n } catch {\n return {\n score: {\n dimensions: {},\n composite: 0,\n failed: true,\n notes: `judge ${judge.name} returned non-JSON: ${raw.slice(0, 200)}`,\n llmCall,\n },\n cost,\n }\n }\n\n const dimensions: Record<string, number> = {}\n let sum = 0\n for (const dim of judge.dimensions) {\n const v = Number(parsed[dim.key] ?? 0)\n const clamped = Number.isFinite(v) ? Math.max(0, Math.min(10, v)) : 0\n dimensions[dim.key] = clamped\n sum += clamped\n }\n return {\n score: {\n dimensions,\n composite: judge.dimensions.length === 0 ? 0 : sum / judge.dimensions.length,\n notes: typeof parsed.notes === 'string' ? parsed.notes : '',\n llmCall,\n },\n cost,\n }\n}\n\nfunction judgeCallMetadata(response: RouterCompletionResponse): {\n llmCall: LlmCallMetadata\n cost: CostProvenance\n} {\n const usage = canonicalUsage(response.usage)\n return {\n llmCall: {\n usage,\n costUsd: response.costUsd ?? null,\n model: response.model,\n durationMs: response.durationMs,\n },\n cost:\n response.costUsd !== undefined\n ? { kind: 'observed', usd: response.costUsd }\n : usage.captured === false || !isModelPriced(response.model)\n ? { kind: 'uncaptured', usd: null }\n : {\n kind: 'estimated',\n usd: estimateCost(usage.promptTokens, usage.completionTokens, response.model),\n },\n }\n}\n\nfunction canonicalUsage(usage: RouterCompletionResponse['usage']): LlmUsage {\n const promptTokens = tokenCount(usage?.prompt_tokens)\n const completionTokens = tokenCount(usage?.completion_tokens)\n const captured = promptTokens !== undefined && completionTokens !== undefined\n return {\n promptTokens: promptTokens ?? 0,\n completionTokens: completionTokens ?? 0,\n totalTokens: (promptTokens ?? 0) + (completionTokens ?? 0),\n captured,\n }\n}\n\nfunction unknownJudgeCall(model: string, durationMs: number): LlmCallMetadata {\n return {\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0, captured: false },\n costUsd: null,\n model,\n durationMs,\n }\n}\n\nfunction tokenCount(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined\n}\n\n/** Convenience: stringified dimension list for inclusion in a judge prompt.\n * Returns lines like `- audience_fit: Does this match what the audience cares about? (0-10)`. */\nexport function renderDimensions(dims: readonly JudgeDimension[]): string {\n return dims.map((d) => `- ${d.key}: ${d.description}`).join('\\n')\n}\n\n/** Convenience: build the \"Respond with ONLY this JSON\" footer for a judge prompt. */\nexport function renderJsonFooter(dims: readonly JudgeDimension[]): string {\n const fields = dims.map((d) => `\"${d.key}\":N`).join(',')\n return `Respond with ONLY this JSON (no markdown, no preamble):\\n{${fields},\"notes\":\"1-2 sentence critique\"}`\n}\n","// Profile-derived defaults for MultishotShape — the pure-profile path.\n//\n// `MultishotShape`'s callbacks were REQUIRED beside `profile: AgentProfile`,\n// which mixed the abstractions: the node under test was a profile, but the\n// simulated user's role could only be expressed as code. These defaults make\n// the callbacks optional — a pure-profile call works, and the derived prompts\n// are plain data (a pure function of profile + persona payload), so an\n// optimizer can sweep them (tangle-network/agent-runtime#694).\n\nimport type { AgentProfile } from '@tangle-network/agent-interface'\nimport type { MultishotPersona, MultishotShape } from './types'\n\n/** Persona payload rendered as stable `- key: value` lines. `id` is identity,\n * not voice, and structured values are serialized so nothing is dropped. */\nexport function renderPersonaFacts(persona: MultishotPersona): string {\n const lines: string[] = []\n for (const [key, value] of Object.entries(persona)) {\n if (key === 'id' || value === undefined) continue\n const rendered =\n typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean'\n ? String(value)\n : JSON.stringify(value)\n lines.push(`- ${key}: ${rendered}`)\n }\n return lines.join('\\n')\n}\n\n/** Default opening user message: the persona introduces itself with its whole\n * payload and asks the agent (as described by the profile) to take over. */\nexport function defaultMultishotOpener(profile: AgentProfile, persona: MultishotPersona): string {\n const facts = renderPersonaFacts(persona)\n const agentDescription = profile.description ?? profile.name ?? 'the agent'\n return [\n `Hi — I'm reaching out to ${agentDescription} for help. My situation:`,\n facts.length > 0 ? facts : `- (no details provided beyond id: ${persona.id})`,\n '',\n 'Tell me what you need from me, and get started on my case.',\n ].join('\\n')\n}\n\n/** Default driver system prompt: roleplay the persona from its payload, stay\n * in character, push back on vague answers, and never go silent. */\nexport function defaultMultishotDriverSystemPrompt(\n profile: AgentProfile,\n persona: MultishotPersona,\n): string {\n const facts = renderPersonaFacts(persona)\n const agentDescription = profile.description ?? profile.name ?? 'an AI agent'\n return [\n `You are role-playing a real person (persona \"${persona.id}\") talking to ${agentDescription}.`,\n facts.length > 0 ? `Who you are:\\n${facts}` : '',\n '',\n 'How to behave:',\n '- Stay in character: first person, realistic voice, concrete details from your situation.',\n '- Judge every reply by whether it actually moves YOUR case forward. Push back on vague, hedged, or generic answers and demand specifics.',\n \"- Answer the agent's questions with information consistent with who you are; invent plausible details rather than stalling.\",\n '- Never go silent: always produce a substantive next message.',\n '- Output ONLY your next message to the agent — no meta-commentary, no stage directions.',\n ]\n .filter((block) => block.length > 0)\n .join('\\n')\n}\n\n/** The fully-resolved shape for a profile: caller overrides win, the\n * profile-derived defaults fill the rest. */\nexport function defaultShapeFromProfile<TPersona extends MultishotPersona>(\n profile: AgentProfile,\n shape?: MultishotShape<TPersona>,\n): Required<MultishotShape<TPersona>> {\n return {\n buildOpener: shape?.buildOpener ?? ((persona) => defaultMultishotOpener(profile, persona)),\n buildDriverSystemPrompt:\n shape?.buildDriverSystemPrompt ??\n ((persona) => defaultMultishotDriverSystemPrompt(profile, persona)),\n }\n}\n","// Public types for the multishot substrate.\n\nexport interface MultishotMessage {\n role: 'user' | 'assistant' | 'tool'\n content: string\n toolCallId?: string\n toolCalls?: Array<{ id: string; name: string; args: Record<string, unknown> }>\n}\n\nexport interface MultishotArtifact {\n type: string\n turn: number\n invocation: { name: string; args: Record<string, unknown> }\n content: string\n}\n\nexport interface MultishotResult {\n transcript: MultishotMessage[]\n artifacts: MultishotArtifact[]\n toolCalls: number\n durationMs: number\n costUsd: number\n}\n\nexport interface MultishotToolDefinition {\n type: 'function'\n function: {\n name: string\n description: string\n parameters: Record<string, unknown>\n }\n}\n\n/** One chat-completion request the multishot loop issues for a single agent\n * (or driver) inference step. Mirrors the OpenAI-compat body the loop would\n * otherwise POST to the Tangle router. */\nexport interface MultishotTransportRequest {\n model: string\n messages: Array<Record<string, unknown>>\n tools?: MultishotToolDefinition[]\n temperature?: number\n maxTokens?: number\n signal?: AbortSignal\n}\n\nexport interface MultishotTransportToolCall {\n id: string\n type: 'function'\n function: { name: string; arguments: string }\n}\n\nexport interface MultishotTransportResponse {\n message: { content?: string | null; tool_calls?: MultishotTransportToolCall[] }\n usage?: { prompt_tokens?: number; completion_tokens?: number }\n /** Actual spend for this call. When omitted, the loop meters cost from\n * `usage` via the per-model router estimator (estimateRouterCost). */\n costUsd?: number\n}\n\n/** Execution seam for one leg of the multishot loop. When provided, it\n * replaces the internal router HTTP call for that leg — the loop still owns\n * turn scheduling, tool dispatch, transcript capture, and cost metering.\n * agent-eval has no dependency on agent-runtime; adapt agent-runtime's\n * resolveAgentBackend (or any sandbox/cli-bridge/router client) into this\n * signature product-side. */\nexport type MultishotTransport = (\n req: MultishotTransportRequest,\n) => Promise<MultishotTransportResponse>\n\nexport type MultishotToolExecutor = (\n args: Record<string, unknown>,\n ctx: { apiKey: string; baseUrl: string; signal?: AbortSignal },\n) => Promise<{ content: string; costUsd: number }>\n\nexport interface MultishotPersona {\n /** Stable identifier — used for per-cell artifact paths + matrix axis keys. */\n id: string\n /** Per-domain payload (income/profile/voice/etc.) shaped by the consumer. */\n [k: string]: unknown\n}\n\n/**\n * Persona-shaping callbacks. Both are OPTIONAL: when omitted, the loop derives\n * them from the `AgentProfile` + persona payload (see `defaultShapeFromProfile`)\n * so a pure-profile call — `runMultishot({ profile, persona })` — works with no\n * role-builder functions. Provide callbacks only to override the derived shape.\n */\nexport interface MultishotShape<TPersona extends MultishotPersona> {\n /** Opening user message (turn 0) — the persona's first ask. */\n buildOpener?: (persona: TPersona) => string\n /** System prompt the driver LLM uses to roleplay the persona. Should set\n * voice, goals, constraints, time-pressure, and the \"never go silent\" rule. */\n buildDriverSystemPrompt?: (persona: TPersona) => string\n}\n\nexport class MultishotDriverEmptyError extends Error {\n constructor(public readonly turn: number) {\n super(`multishot: driver returned empty content twice at turn ${turn} — failing loud`)\n this.name = 'MultishotDriverEmptyError'\n }\n}\n\nexport class MultishotFatalToolError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MultishotFatalToolError'\n }\n}\n","// Multi-turn driver-agent simulation with inline tool execution.\n//\n// The driver = LLM acting as the persona (reactive, non-deterministic).\n// The agent = the product agent under test (router call by default, or an\n// injected transport — with profile's systemPrompt + the configured tools).\n// Tool calls execute inline via the configured executors and feed back\n// into the agent's message log so the agent integrates the result.\n\nimport type { AgentProfile } from '@tangle-network/agent-interface'\nimport { defaultDelegationTools } from './default-tools'\nimport {\n defaultRouterBaseUrl,\n estimateRouterCost,\n requireRouterApiKey,\n routerCompletion,\n} from './router'\nimport { defaultShapeFromProfile } from './shape-defaults'\nimport {\n type MultishotArtifact,\n MultishotDriverEmptyError,\n MultishotFatalToolError,\n type MultishotMessage,\n type MultishotPersona,\n type MultishotResult,\n type MultishotShape,\n type MultishotToolDefinition,\n type MultishotToolExecutor,\n type MultishotTransport,\n} from './types'\n\nexport interface RunMultishotOptions<TPersona extends MultishotPersona> {\n profile: AgentProfile\n persona: TPersona\n /** Persona-shaping callbacks. Optional — omitted callbacks are derived from\n * the profile + persona payload, so a pure-profile call works. */\n shape?: MultishotShape<TPersona>\n /** Tool definitions advertised to the agent. Defaults to delegate_research + delegate_code. */\n tools?: MultishotToolDefinition[]\n /** Map from tool name → executor invoked inline when the agent emits a tool_call. */\n toolExecutors?: Record<string, MultishotToolExecutor>\n /** Map from tool name → artifact type label written into MultishotArtifact.type.\n * Tools without a mapping still execute, but their results aren't surfaced as\n * typed artifacts (only as tool messages in the transcript). */\n artifactTypeFor?: (toolName: string) => string | undefined\n maxTurns?: number\n agentModel?: string\n driverModel?: string\n /** Fallback driver models tried when the primary simulated-user model returns empty twice. */\n driverFallbackModels?: string[]\n /** Maximum output tokens for the first agent call in each assistant turn. */\n agentMaxTokens?: number\n /** Maximum output tokens for agent follow-up calls after tool results. */\n toolFollowupMaxTokens?: number\n /** Maximum output tokens for each simulated-user driver response. */\n driverMaxTokens?: number\n /** Maximum tool calls the agent may dispatch inside one assistant turn. */\n maxToolDispatches?: number\n /** Execution seam for the agent leg. When provided, every agent inference\n * step goes through this function instead of the router HTTP call; the\n * string levers (agentModel, apiKey, baseUrl) stop applying to that leg.\n * apiKey/baseUrl are still resolved for tool executors and any leg\n * without an injected transport. */\n agentTransport?: MultishotTransport\n /** Execution seam for the simulated-user driver leg (symmetric to\n * agentTransport). Driver model fallback rotation still applies — the\n * transport receives each candidate model in turn. */\n driverTransport?: MultishotTransport\n apiKey?: string\n baseUrl?: string\n signal?: AbortSignal\n}\n\nexport async function runMultishot<TPersona extends MultishotPersona>(\n opts: RunMultishotOptions<TPersona>,\n): Promise<MultishotResult> {\n const apiKey = opts.apiKey ?? requireRouterApiKey()\n const baseUrl = opts.baseUrl ?? defaultRouterBaseUrl()\n const maxTurns = opts.maxTurns ?? 10\n const maxToolDispatches = opts.maxToolDispatches ?? 4\n const agentModel = opts.agentModel ?? 'openai/gpt-5.4'\n const driverModel = opts.driverModel ?? 'openai/gpt-4o-mini'\n const driverModels = [driverModel, ...(opts.driverFallbackModels ?? [])]\n const agentMaxTokens = opts.agentMaxTokens ?? 2500\n const toolFollowupMaxTokens = opts.toolFollowupMaxTokens ?? 2000\n const driverMaxTokens = opts.driverMaxTokens ?? 600\n\n const bundle =\n opts.tools && opts.toolExecutors\n ? {\n tools: opts.tools,\n executors: opts.toolExecutors,\n artifactTypeFor: opts.artifactTypeFor ?? (() => undefined),\n }\n : defaultDelegationTools()\n const tools = opts.tools ?? bundle.tools\n const executors = opts.toolExecutors ?? bundle.executors\n const artifactTypeFor = opts.artifactTypeFor ?? bundle.artifactTypeFor\n\n const routerTransport: MultishotTransport = (req) => routerCompletion({ apiKey, baseUrl, ...req })\n const agentTransport = opts.agentTransport ?? routerTransport\n const driverTransport = opts.driverTransport ?? routerTransport\n\n const shape = defaultShapeFromProfile(opts.profile, opts.shape)\n\n const start = Date.now()\n const transcript: MultishotMessage[] = []\n const artifacts: MultishotArtifact[] = []\n let toolCalls = 0\n let totalCostUsd = 0\n\n const opener = shape.buildOpener(opts.persona)\n transcript.push({ role: 'user', content: opener })\n\n const systemPrompt = opts.profile.prompt?.systemPrompt ?? ''\n const agentMessages: Array<Record<string, unknown>> = [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: opener },\n ]\n\n for (let turn = 0; turn < maxTurns; turn++) {\n if (opts.signal?.aborted) throw new Error('multishot aborted')\n\n let dispatchesThisTurn = 0\n while (true) {\n const {\n message: agentMsg,\n usage: agentUsage,\n costUsd: agentCostUsd,\n } = await agentTransport({\n model: agentModel,\n messages: agentMessages,\n tools,\n temperature: 0.7,\n maxTokens: dispatchesThisTurn === 0 ? agentMaxTokens : toolFollowupMaxTokens,\n signal: opts.signal,\n })\n totalCostUsd += agentCostUsd ?? estimateRouterCost(agentModel, agentUsage)\n\n const agentText = (agentMsg.content ?? '').trim()\n const agentToolCalls = (agentMsg.tool_calls ?? []).map((tc) => ({\n id: tc.id,\n name: tc.function.name,\n args: (() => {\n try {\n return JSON.parse(tc.function.arguments) as Record<string, unknown>\n } catch {\n return {} as Record<string, unknown>\n }\n })(),\n }))\n\n agentMessages.push({\n role: 'assistant',\n content: agentText || null,\n ...(agentMsg.tool_calls?.length ? { tool_calls: agentMsg.tool_calls } : {}),\n })\n transcript.push({\n role: 'assistant',\n content: agentText,\n toolCalls: agentToolCalls.length > 0 ? agentToolCalls : undefined,\n })\n\n if (agentToolCalls.length === 0) break\n dispatchesThisTurn += agentToolCalls.length\n if (dispatchesThisTurn > maxToolDispatches) {\n throw new Error(\n `multishot: tool dispatch cap exceeded (${dispatchesThisTurn}/${maxToolDispatches}) on turn ${turn}`,\n )\n }\n\n for (const tc of agentToolCalls) {\n toolCalls++\n let toolResult = ''\n try {\n const executor = executors[tc.name]\n if (!executor) {\n toolResult = JSON.stringify({ error: `unknown tool ${tc.name}` })\n } else {\n const r = await executor(tc.args, { apiKey, baseUrl, signal: opts.signal })\n toolResult = r.content\n totalCostUsd += r.costUsd\n const artifactType = artifactTypeFor(tc.name)\n if (artifactType) {\n artifacts.push({\n type: artifactType,\n turn,\n invocation: { name: tc.name, args: tc.args },\n content: toolResult,\n })\n }\n }\n } catch (err) {\n if (err instanceof MultishotFatalToolError) throw err\n toolResult = JSON.stringify({ error: err instanceof Error ? err.message : String(err) })\n }\n agentMessages.push({ role: 'tool', tool_call_id: tc.id, content: toolResult || 'done' })\n transcript.push({ role: 'tool', content: toolResult || 'done', toolCallId: tc.id })\n }\n }\n\n if (turn < maxTurns - 1) {\n const driver = await driverTurn({\n transport: driverTransport,\n persona: opts.persona,\n shape,\n transcript,\n turn,\n models: driverModels,\n maxTokens: driverMaxTokens,\n signal: opts.signal,\n })\n totalCostUsd += driver.costUsd\n agentMessages.push({ role: 'user', content: driver.content })\n transcript.push({ role: 'user', content: driver.content })\n }\n }\n\n return { transcript, artifacts, toolCalls, durationMs: Date.now() - start, costUsd: totalCostUsd }\n}\n\nasync function driverTurn<TPersona extends MultishotPersona>(opts: {\n transport: MultishotTransport\n persona: TPersona\n shape: Required<MultishotShape<TPersona>>\n transcript: MultishotMessage[]\n turn: number\n models: string[]\n maxTokens: number\n signal?: AbortSignal\n}): Promise<{ content: string; costUsd: number }> {\n const driverSystem = opts.shape.buildDriverSystemPrompt(opts.persona)\n\n // Translate transcript to driver POV: agent's `assistant` messages become\n // `user` (the agent talking TO the driver); the driver's prior `user`\n // messages become `assistant` (the driver's prior responses).\n const driverMessages: Array<Record<string, unknown>> = [{ role: 'system', content: driverSystem }]\n for (const msg of opts.transcript) {\n if (msg.role === 'tool') continue\n const content = driverVisibleContent(msg)\n if (!content) continue\n if (msg.role === 'assistant') driverMessages.push({ role: 'user', content })\n else if (msg.role === 'user') driverMessages.push({ role: 'assistant', content })\n }\n\n // Driver must never go silent. Retry once on empty content; then fail loud.\n for (const model of opts.models) {\n for (let attempt = 0; attempt < 2; attempt++) {\n const { message, usage, costUsd } = await opts.transport({\n model,\n messages: driverMessages,\n temperature: 0.9,\n maxTokens: opts.maxTokens,\n signal: opts.signal,\n })\n const content = (message.content ?? '').trim()\n if (content.length > 0)\n return { content, costUsd: costUsd ?? estimateRouterCost(model, usage) }\n }\n }\n throw new MultishotDriverEmptyError(opts.turn)\n}\n\nfunction driverVisibleContent(msg: MultishotMessage): string | null {\n const text = msg.content.trim()\n if (text.length > 0) return text\n if (msg.role !== 'assistant' || !msg.toolCalls?.length) return null\n\n const toolNames = msg.toolCalls.map((call) => call.name.trim()).filter(Boolean)\n if (toolNames.length === 0) return 'Agent called tools.'\n return `Agent called ${toolNames.length === 1 ? 'tool' : 'tools'}: ${toolNames.join(', ')}.`\n}\n","// Multishot matrix wrapper — sweeps profiles × personas × reps, runs\n// the driver-agent loop per cell, applies up to three configured judges,\n// persists per-cell artifacts, and aggregates by axis.\n//\n// Uses runAgentMatrix from @tangle-network/agent-eval/matrix under the\n// hood so cell scheduling + concurrency + cost ceiling are unified with\n// other matrix consumers.\n\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { AgentProfile } from '@tangle-network/agent-interface'\nimport type { CostProvenance } from '../cost-ledger'\nimport type { MatrixResult } from '../matrix'\nimport { runAgentMatrix } from '../matrix'\nimport { type JudgeConfig, type JudgeScore, runJudge } from './judges'\nimport { runMultishot } from './multishot'\nimport type {\n MultishotArtifact,\n MultishotMessage,\n MultishotPersona,\n MultishotShape,\n MultishotToolDefinition,\n MultishotToolExecutor,\n MultishotTransport,\n} from './types'\n\nexport interface ConversationJudgeInput<TPersona extends MultishotPersona> {\n transcript: MultishotMessage[]\n persona: TPersona\n}\n\nexport interface ArtifactJudgeInput<TPersona extends MultishotPersona> {\n artifact: MultishotArtifact\n persona: TPersona\n}\n\nexport interface MultishotJudges<TPersona extends MultishotPersona> {\n /** Scores the full transcript end-to-end (always runs). */\n conversation: JudgeConfig<ConversationJudgeInput<TPersona>>\n /** Scores each code-type artifact. Optional — omit when domain has no code artifacts. */\n codeReview?: JudgeConfig<ArtifactJudgeInput<TPersona>>\n /** Scores each non-code (research/content/template) artifact. Optional. */\n contentQuality?: JudgeConfig<ArtifactJudgeInput<TPersona>>\n /** Which artifact types route to codeReview. Defaults to ['code']. */\n codeArtifactTypes?: string[]\n /** Which artifact types route to contentQuality. Defaults to ['research']. */\n contentArtifactTypes?: string[]\n}\n\nexport interface CellCompositeScore {\n composite: number\n conversation: JudgeScore\n codeReview?: {\n perArtifact: Array<JudgeScore & { turn: number; type: string }>\n composite: number\n }\n contentQuality?: {\n perArtifact: Array<JudgeScore & { turn: number; type: string }>\n composite: number\n }\n}\n\nexport interface RunMultishotMatrixOptions<TPersona extends MultishotPersona> {\n /** AgentProfile axis (matrix primary). */\n profiles: Array<{ id: string; value: AgentProfile }>\n /** Persona axis. */\n personas: TPersona[]\n /** Persona-shaping callbacks. Optional — omitted callbacks are derived per\n * cell from that cell's profile + persona payload (pure-profile path). */\n shape?: MultishotShape<TPersona>\n /** Judge configurations. */\n judges: MultishotJudges<TPersona>\n /** Tool definitions advertised to the agent. Defaults to delegate_research + delegate_code. */\n tools?: MultishotToolDefinition[]\n /** Map from tool name → inline executor. Must align with `tools`. */\n toolExecutors?: Record<string, MultishotToolExecutor>\n /** Tool name → artifact type label. Defaults to research/code mapping. */\n artifactTypeFor?: (toolName: string) => string | undefined\n /** Where per-cell artifacts land. Cells write to `<runDir>/<profileId>/<personaId>/rep-N/`. */\n runDir: string\n /** Replicates per (profile, persona) cell. */\n reps?: number\n /** Max conversation turns per cell. */\n maxTurns?: number\n /** Maximum tool calls the agent may dispatch inside one assistant turn. */\n maxToolDispatches?: number\n /** Max concurrent cells. */\n maxConcurrency?: number\n /** Total $ ceiling across the matrix; cells aborted past this. */\n costCeiling?: number\n /** Agent model. */\n agentModel?: string\n /** Driver model. */\n driverModel?: string\n /** Fallback driver models tried when the primary simulated-user model returns empty twice. */\n driverFallbackModels?: string[]\n /** Maximum output tokens for the first agent call in each assistant turn. */\n agentMaxTokens?: number\n /** Maximum output tokens for agent follow-up calls after tool results. */\n toolFollowupMaxTokens?: number\n /** Maximum output tokens for each simulated-user driver response. */\n driverMaxTokens?: number\n /** Maximum output tokens for each judge response. */\n judgeMaxTokens?: number\n /** Execution seam for the agent leg of every cell — replaces the router\n * HTTP call when provided (see RunMultishotOptions.agentTransport).\n * Judges are unaffected; configure those via MultishotJudges. */\n agentTransport?: MultishotTransport\n /** Execution seam for the simulated-user driver leg of every cell. */\n driverTransport?: MultishotTransport\n /** Pass-thru fields. */\n apiKey?: string\n baseUrl?: string\n}\n\ninterface CellOutput {\n turns: number\n toolCalls: number\n artifactCount: number\n}\n\ninterface ArtifactJudgeRun {\n score: JudgeScore & { turn: number; type: string }\n cost: CostProvenance\n}\n\n/** Mean composite over non-failed scores. `0` when the list is empty (a\n * configured judge with nothing to score contributes 0, matching the cell\n * composite's long-standing semantics); `null` when scores exist but every\n * one failed — no signal, so the slot must be EXCLUDED from the cell mean\n * rather than dragging it to zero. */\nfunction meanCompositeExcludingFailed(scores: ReadonlyArray<JudgeScore>): number | null {\n if (scores.length === 0) return 0\n const live = scores.filter((s) => !s.failed)\n if (live.length === 0) return null\n return live.reduce((sum, s) => sum + s.composite, 0) / live.length\n}\n\nexport interface CellCompositeInput {\n conversation: JudgeScore\n /** Present iff the codeReview judge is configured. */\n codeReviews?: ReadonlyArray<JudgeScore>\n /** Present iff the contentQuality judge is configured. */\n contentReviews?: ReadonlyArray<JudgeScore>\n}\n\n/** Cell composite = mean over configured judge slots, excluding failed\n * scores: a failed conversation judge or an all-failed artifact slot carries\n * no signal and is dropped from the mean. `composite` is 0 only when EVERY\n * configured slot failed (`allJudgesFailed` distinguishes that from a real\n * zero). Pure — exported for deterministic testing. */\nexport function computeCellComposite(input: CellCompositeInput): {\n composite: number\n codeComposite: number\n contentComposite: number\n allJudgesFailed: boolean\n} {\n const contributions: number[] = []\n if (!input.conversation.failed) contributions.push(input.conversation.composite)\n\n const codeMean = input.codeReviews ? meanCompositeExcludingFailed(input.codeReviews) : undefined\n if (typeof codeMean === 'number') contributions.push(codeMean)\n const contentMean = input.contentReviews\n ? meanCompositeExcludingFailed(input.contentReviews)\n : undefined\n if (typeof contentMean === 'number') contributions.push(contentMean)\n\n return {\n composite:\n contributions.length === 0\n ? 0\n : contributions.reduce((s, v) => s + v, 0) / contributions.length,\n codeComposite: codeMean ?? 0,\n contentComposite: contentMean ?? 0,\n allJudgesFailed: contributions.length === 0,\n }\n}\n\nexport interface RunMultishotMatrixResult {\n matrix: MatrixResult<CellOutput>\n}\n\nexport async function runMultishotMatrix<TPersona extends MultishotPersona>(\n opts: RunMultishotMatrixOptions<TPersona>,\n): Promise<RunMultishotMatrixResult> {\n const codeTypes = new Set(opts.judges.codeArtifactTypes ?? ['code'])\n const contentTypes = new Set(opts.judges.contentArtifactTypes ?? ['research'])\n mkdirSync(opts.runDir, { recursive: true })\n\n const matrix = await runAgentMatrix<CellOutput>({\n axes: [\n { name: 'profile', values: opts.profiles },\n { name: 'persona', values: opts.personas.map((p) => ({ id: p.id, value: p })) },\n ],\n reps: opts.reps ?? 1,\n maxConcurrency: opts.maxConcurrency ?? 2,\n costCeiling: opts.costCeiling,\n async runCell(cell) {\n const profile = cell.axes.profile?.value as AgentProfile\n const persona = cell.axes.persona?.value as TPersona\n const profileId = String(cell.axes.profile?.id ?? 'unknown')\n const personaId = String(cell.axes.persona?.id ?? 'unknown')\n\n const sim = await runMultishot({\n profile,\n persona,\n shape: opts.shape,\n tools: opts.tools,\n toolExecutors: opts.toolExecutors,\n artifactTypeFor: opts.artifactTypeFor,\n maxTurns: opts.maxTurns,\n maxToolDispatches: opts.maxToolDispatches,\n agentModel: opts.agentModel,\n driverModel: opts.driverModel,\n driverFallbackModels: opts.driverFallbackModels,\n agentMaxTokens: opts.agentMaxTokens,\n toolFollowupMaxTokens: opts.toolFollowupMaxTokens,\n driverMaxTokens: opts.driverMaxTokens,\n agentTransport: opts.agentTransport,\n driverTransport: opts.driverTransport,\n apiKey: opts.apiKey,\n baseUrl: opts.baseUrl,\n })\n\n const codeArtifacts = sim.artifacts.filter((a) => codeTypes.has(a.type))\n const contentArtifacts = sim.artifacts.filter((a) => contentTypes.has(a.type))\n\n const [conversationRun, codeReviewRuns, contentReviewRuns] = await Promise.all([\n runJudge(withJudgeMaxTokens(opts.judges.conversation, opts.judgeMaxTokens), {\n transcript: sim.transcript,\n persona,\n }),\n opts.judges.codeReview\n ? Promise.all(\n codeArtifacts.map((artifact) =>\n runJudge(withJudgeMaxTokens(opts.judges.codeReview!, opts.judgeMaxTokens), {\n artifact,\n persona,\n }).then((result) => ({\n score: {\n ...result.score,\n turn: artifact.turn,\n type: artifact.type,\n },\n cost: result.cost,\n })),\n ),\n )\n : Promise.resolve([] as ArtifactJudgeRun[]),\n opts.judges.contentQuality\n ? Promise.all(\n contentArtifacts.map((artifact) =>\n runJudge(withJudgeMaxTokens(opts.judges.contentQuality!, opts.judgeMaxTokens), {\n artifact,\n persona,\n }).then((result) => ({\n score: {\n ...result.score,\n turn: artifact.turn,\n type: artifact.type,\n },\n cost: result.cost,\n })),\n ),\n )\n : Promise.resolve([] as ArtifactJudgeRun[]),\n ])\n const conversation = conversationRun.score\n const codeReviews = codeReviewRuns.map((run) => run.score)\n const contentReviews = contentReviewRuns.map((run) => run.score)\n\n const { composite, codeComposite, contentComposite, allJudgesFailed } = computeCellComposite({\n conversation,\n codeReviews: opts.judges.codeReview ? codeReviews : undefined,\n contentReviews: opts.judges.contentQuality ? contentReviews : undefined,\n })\n\n const cellScore: CellCompositeScore = { composite, conversation }\n if (opts.judges.codeReview)\n cellScore.codeReview = { perArtifact: codeReviews, composite: codeComposite }\n if (opts.judges.contentQuality)\n cellScore.contentQuality = { perArtifact: contentReviews, composite: contentComposite }\n\n const cellDir = join(opts.runDir, profileId, personaId, `rep-${cell.rep}`)\n mkdirSync(cellDir, { recursive: true })\n writeFileSync(join(cellDir, 'transcript.json'), JSON.stringify(sim.transcript, null, 2))\n writeFileSync(join(cellDir, 'artifacts.json'), JSON.stringify(sim.artifacts, null, 2))\n writeFileSync(join(cellDir, 'scores.json'), JSON.stringify(cellScore, null, 2))\n\n const notes = [`convo=${conversation.composite.toFixed(1)}`]\n if (opts.judges.codeReview) notes.push(`code=${codeComposite.toFixed(1)}`)\n if (opts.judges.contentQuality) notes.push(`content=${contentComposite.toFixed(1)}`)\n if (allJudgesFailed) notes.push('all-judges-failed')\n const judgeRuns = [conversationRun, ...codeReviewRuns, ...contentReviewRuns]\n const judgeCostUsd = judgeRuns.reduce((sum, run) => sum + (run.cost.usd ?? 0), 0)\n if (judgeRuns.some((run) => run.cost.kind === 'uncaptured')) {\n notes.push('judge-cost-incomplete')\n }\n\n return {\n output: {\n turns: sim.transcript.length,\n toolCalls: sim.toolCalls,\n artifactCount: sim.artifacts.length,\n },\n verdict: { valid: composite >= 5, score: composite, notes: notes.join(' ') },\n costUsd: sim.costUsd + judgeCostUsd,\n durationMs: sim.durationMs,\n }\n },\n })\n\n // Persist top-level summary.\n const summary = {\n cells: matrix.summary.totalCells,\n passRate: matrix.summary.overallPassRate,\n meanScore: matrix.summary.overallMeanScore,\n totalCostUsd: matrix.summary.totalCostUsd,\n durationMs: matrix.summary.durationMs,\n runsExecuted: matrix.summary.runsExecuted,\n cellsSkipped: matrix.summary.cellsSkipped,\n byProfile: matrix.byAxis.profile,\n byPersona: matrix.byAxis.persona,\n }\n writeFileSync(join(opts.runDir, 'summary.json'), JSON.stringify(summary, null, 2))\n\n const md: string[] = [\n `# Multishot matrix`,\n ``,\n `**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 / 1000).toFixed(0)}s`,\n ``,\n `## By profile`,\n ``,\n '| profile | pass | mean | cost |',\n '|---|---|---|---|',\n ...Object.entries(matrix.byAxis.profile ?? {}).map(\n ([id, s]) =>\n `| ${id} | ${(s.passRate * 100).toFixed(0)}% | ${s.meanScore.toFixed(2)} | $${s.totalCostUsd.toFixed(2)} |`,\n ),\n ``,\n `## By persona`,\n ``,\n '| persona | pass | mean | cost |',\n '|---|---|---|---|',\n ...Object.entries(matrix.byAxis.persona ?? {}).map(\n ([id, s]) =>\n `| ${id} | ${(s.passRate * 100).toFixed(0)}% | ${s.meanScore.toFixed(2)} | $${s.totalCostUsd.toFixed(2)} |`,\n ),\n ``,\n ]\n writeFileSync(join(opts.runDir, 'summary.md'), md.join('\\n'))\n\n return { matrix }\n}\n\nfunction withJudgeMaxTokens<TInput>(\n judge: JudgeConfig<TInput>,\n maxTokens: number | undefined,\n): JudgeConfig<TInput> {\n if (maxTokens === undefined || judge.maxTokens !== undefined) return judge\n return { ...judge, maxTokens }\n}\n"],"mappings":"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"}
|
package/dist/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "@tangle-network/agent-eval — wire protocol",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.141.0",
|
|
6
6
|
"description": "HTTP and stdio RPC interface to agent-eval. The TypeScript runtime is the source of truth; this spec is the contract that cross-language clients (Python, Rust, Go) generate from.\n\nWire-protocol version: 1.0.0. Bumps on breaking changes to request/response schemas.",
|
|
7
7
|
"contact": {
|
|
8
8
|
"name": "Tangle Network",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replay-BqTgoioO.d.ts","names":[],"sources":["../src/trace/otel.ts","../src/trace/otlp-attributes.ts","../src/trace/otel-export.ts","../src/trace/otel-bridge.ts","../src/trace/redact.ts","../src/trace/store-to-otlp.ts","../src/trace-analyst/store-boundary.ts","../src/trace-analyst/analyst.ts","../src/trace-analyst/errors.ts","../src/trace-analyst/hook.ts","../src/trace-analyst/insights.ts","../src/trace/otlp-flat.ts","../src/trace-analyst/otlp-flatten.ts","../src/trace-analyst/otlp-span.ts","../src/trace-analyst/otlp-to-run-records.ts","../src/trace-analyst/prompts.ts","../src/trace-analyst/store-otlp.ts","../src/trace-analyst/store-tool-spans.ts","../src/replay.ts"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"replay-BqTgoioO.d.ts","names":[],"sources":["../src/trace/otel.ts","../src/trace/otlp-attributes.ts","../src/trace/otel-export.ts","../src/trace/otel-bridge.ts","../src/trace/redact.ts","../src/trace/store-to-otlp.ts","../src/trace-analyst/store-boundary.ts","../src/trace-analyst/analyst.ts","../src/trace-analyst/errors.ts","../src/trace-analyst/hook.ts","../src/trace-analyst/insights.ts","../src/trace/otlp-flat.ts","../src/trace-analyst/otlp-flatten.ts","../src/trace-analyst/otlp-span.ts","../src/trace-analyst/otlp-to-run-records.ts","../src/trace-analyst/prompts.ts","../src/trace-analyst/store-otlp.ts","../src/trace-analyst/store-tool-spans.ts","../src/replay.ts"],"mappings":"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"}
|
|
@@ -2,13 +2,14 @@ import { n as CaptureIntegrityError, s as ReplayError } from "./errors-D-LKuDhb.
|
|
|
2
2
|
import { h as hashJson, p as canonicalize } from "./agent-profile-cell-CbfBm2g6.js";
|
|
3
3
|
import { a as providerFromBaseUrl, i as defaultProviderRedactor } from "./raw-provider-sink-BQd7mzyT.js";
|
|
4
4
|
import { LLM_INPUT_TOKENS, LLM_MODEL_ATTR_KEYS, LLM_MODEL_NAME, LLM_OUTPUT_TOKENS, OPENINFERENCE_SPAN_KIND, TOOL_NAME, applyLlmSpanOtlpAttributes } from "./trace-attributes.js";
|
|
5
|
-
import { $ as spanEpochMillis, Y as firstStringAttr, Z as projectOtlpFlatLine, i as runTraceAnalyst, it as traceSpanKindToOpenInferenceKind, nt as classifyOtlpSpanRole, q as compareSpanTime, rt as isOtlpModelCall, tt as applyToolSpanOtlpAttributes } from "./kind-factory-
|
|
5
|
+
import { $ as spanEpochMillis, Y as firstStringAttr, Z as projectOtlpFlatLine, i as runTraceAnalyst, it as traceSpanKindToOpenInferenceKind, nt as classifyOtlpSpanRole, q as compareSpanTime, rt as isOtlpModelCall, tt as applyToolSpanOtlpAttributes } from "./kind-factory-Bvwe3pup.js";
|
|
6
6
|
import { s as validateRunRecord } from "./run-record-vRgqWmJw.js";
|
|
7
|
-
import { n as OtlpFileTraceStore, r as createOtlpBufferTraceStore } from "./store-otlp-
|
|
8
|
-
import { a as recordAggregateMeasurements, i as readTaskFailureLabels, o as summarizeExecutionMeasurements, r as extractUsageFromSse, s as summarizeTraceErrors, t as extractUsage } from "./extract-usage-
|
|
7
|
+
import { n as OtlpFileTraceStore, r as createOtlpBufferTraceStore } from "./store-otlp-D4I90_vR.js";
|
|
8
|
+
import { a as recordAggregateMeasurements, i as readTaskFailureLabels, o as summarizeExecutionMeasurements, r as extractUsageFromSse, s as summarizeTraceErrors, t as extractUsage } from "./extract-usage-7l1Xq5ti.js";
|
|
9
9
|
import { readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
|
+
import { deriveHexId, isW3CSpanId, isW3CTraceId } from "@tangle-network/agent-trace-contract";
|
|
12
13
|
//#region src/trace-analyst/prompts.ts
|
|
13
14
|
/** General policy for recursive, evidence-backed trace analysis. */
|
|
14
15
|
const TRACE_ANALYST_ACTOR_DESCRIPTION = `Answer the question by inspecting the OTLP trace dataset with the available tools.
|
|
@@ -1024,6 +1025,31 @@ function captureFetchToRawSink(fetch, sink, ctx, opts = {}) {
|
|
|
1024
1025
|
};
|
|
1025
1026
|
}
|
|
1026
1027
|
//#endregion
|
|
1028
|
+
//#region src/trace/wire-ids.ts
|
|
1029
|
+
/**
|
|
1030
|
+
* The ONE mapping from agent-eval's human-readable ids (run ids, span labels)
|
|
1031
|
+
* to W3C/OTLP wire ids. Every exporter in this package MUST route through
|
|
1032
|
+
* these two functions — two exporters with private paddings once produced
|
|
1033
|
+
* DIFFERENT trace ids for the same run, and one emitted invalid hex embedding
|
|
1034
|
+
* the raw run id in the wire id (tangle-network/agent-runtime#694).
|
|
1035
|
+
*
|
|
1036
|
+
* Semantics:
|
|
1037
|
+
* - an id that is ALREADY a valid W3C id passes through unchanged, so a
|
|
1038
|
+
* trace id received from an inbound `traceparent` survives the round-trip
|
|
1039
|
+
* and cross-process correlation is preserved;
|
|
1040
|
+
* - anything else is derived with the contract's `deriveHexId`, the only
|
|
1041
|
+
* legal derivation — deterministic, so every process that derives from the
|
|
1042
|
+
* same human id mints the SAME wire id.
|
|
1043
|
+
*/
|
|
1044
|
+
/** 32-hex W3C trace id for any id string. */
|
|
1045
|
+
function traceIdForWire(id) {
|
|
1046
|
+
return isW3CTraceId(id) ? id : deriveHexId(id, 16);
|
|
1047
|
+
}
|
|
1048
|
+
/** 16-hex W3C span id for any id string. */
|
|
1049
|
+
function spanIdForWire(id) {
|
|
1050
|
+
return isW3CSpanId(id) ? id : deriveHexId(id, 8);
|
|
1051
|
+
}
|
|
1052
|
+
//#endregion
|
|
1027
1053
|
//#region src/trace/otel.ts
|
|
1028
1054
|
/**
|
|
1029
1055
|
* OpenTelemetry JSON export — maps TraceSchema v1 to OTLP/JSON so
|
|
@@ -1075,8 +1101,8 @@ function spanToOtlp(span, traceId, events) {
|
|
|
1075
1101
|
const endedAt = span.endedAt ?? span.startedAt;
|
|
1076
1102
|
return {
|
|
1077
1103
|
traceId,
|
|
1078
|
-
spanId:
|
|
1079
|
-
parentSpanId: span.parentSpanId ?
|
|
1104
|
+
spanId: spanIdForWire(span.spanId),
|
|
1105
|
+
parentSpanId: span.parentSpanId ? spanIdForWire(span.parentSpanId) : void 0,
|
|
1080
1106
|
name: span.name,
|
|
1081
1107
|
kind: 1,
|
|
1082
1108
|
startTimeUnixNano: msToNs$1(span.startedAt),
|
|
@@ -1132,11 +1158,8 @@ function toAttributes$1(record) {
|
|
|
1132
1158
|
function msToNs$1(ms) {
|
|
1133
1159
|
return (BigInt(Math.floor(ms)) * 1000000n).toString();
|
|
1134
1160
|
}
|
|
1135
|
-
function padSpanId$2(id) {
|
|
1136
|
-
return id.replace(/-/g, "").slice(0, 16).padEnd(16, "0");
|
|
1137
|
-
}
|
|
1138
1161
|
function runToTraceId(run) {
|
|
1139
|
-
return run.runId
|
|
1162
|
+
return traceIdForWire(run.runId);
|
|
1140
1163
|
}
|
|
1141
1164
|
//#endregion
|
|
1142
1165
|
//#region src/trace/otel-bridge.ts
|
|
@@ -1324,9 +1347,9 @@ function toOtlpSpan(span) {
|
|
|
1324
1347
|
applyLlmSpanOtlpAttributes(attrs, span);
|
|
1325
1348
|
if (span.tool) applyToolSpanOtlpAttributes(attrs, span.tool);
|
|
1326
1349
|
return {
|
|
1327
|
-
traceId:
|
|
1328
|
-
spanId:
|
|
1329
|
-
parentSpanId: span.parentSpanId ?
|
|
1350
|
+
traceId: traceIdForWire(span.traceId),
|
|
1351
|
+
spanId: spanIdForWire(span.spanId),
|
|
1352
|
+
parentSpanId: span.parentSpanId ? spanIdForWire(span.parentSpanId) : void 0,
|
|
1330
1353
|
name: span.name,
|
|
1331
1354
|
kind: 1,
|
|
1332
1355
|
startTimeUnixNano: msToNs(span.startedAt),
|
|
@@ -1347,12 +1370,6 @@ function toAttributes(record) {
|
|
|
1347
1370
|
function msToNs(ms) {
|
|
1348
1371
|
return (BigInt(Math.floor(ms)) * 1000000n).toString();
|
|
1349
1372
|
}
|
|
1350
|
-
function padSpanId$1(id) {
|
|
1351
|
-
return id.replace(/-/g, "").slice(0, 16).padEnd(16, "0");
|
|
1352
|
-
}
|
|
1353
|
-
function padTraceId$1(id) {
|
|
1354
|
-
return id.replace(/-/g, "").slice(0, 32).padEnd(32, "0");
|
|
1355
|
-
}
|
|
1356
1373
|
//#endregion
|
|
1357
1374
|
//#region src/trace/store-to-otlp.ts
|
|
1358
1375
|
/**
|
|
@@ -1485,7 +1502,7 @@ function projectCell(args) {
|
|
|
1485
1502
|
eventsBySpanId.set(e.spanId, arr);
|
|
1486
1503
|
}
|
|
1487
1504
|
for (const run of runByRunId.values()) {
|
|
1488
|
-
const traceId =
|
|
1505
|
+
const traceId = traceIdForWire(run.runId);
|
|
1489
1506
|
const agentName = run.variantId ?? run.scenarioId;
|
|
1490
1507
|
const sharedResource = { attributes: {
|
|
1491
1508
|
"service.name": serviceName,
|
|
@@ -1494,7 +1511,7 @@ function projectCell(args) {
|
|
|
1494
1511
|
"run.status": run.status,
|
|
1495
1512
|
...resourceAttributes(run)
|
|
1496
1513
|
} };
|
|
1497
|
-
const runSpanId =
|
|
1514
|
+
const runSpanId = spanIdForWire(`run-${run.runId}`);
|
|
1498
1515
|
const runStart = msToIso(run.startedAt);
|
|
1499
1516
|
const runEnd = msToIso(run.endedAt ?? run.startedAt);
|
|
1500
1517
|
const runStatus = run.outcome?.failureClass && run.outcome.failureClass !== "success" ? "STATUS_CODE_ERROR" : "STATUS_CODE_OK";
|
|
@@ -1524,8 +1541,8 @@ function projectCell(args) {
|
|
|
1524
1541
|
const statusCode = spanStatusToOtlp(span.status, span.error, "STATUS_CODE_OK");
|
|
1525
1542
|
lines.push(JSON.stringify(toLine({
|
|
1526
1543
|
traceId,
|
|
1527
|
-
spanId:
|
|
1528
|
-
parentSpanId: span.parentSpanId ?
|
|
1544
|
+
spanId: spanIdForWire(span.spanId),
|
|
1545
|
+
parentSpanId: span.parentSpanId ? spanIdForWire(span.parentSpanId) : runSpanId,
|
|
1529
1546
|
name: span.name,
|
|
1530
1547
|
kind: spanKindToOtlpKind(span.kind),
|
|
1531
1548
|
startTime: msToIso(span.startedAt),
|
|
@@ -1650,31 +1667,6 @@ function msToIso(ms) {
|
|
|
1650
1667
|
if (ms <= 0) return (/* @__PURE__ */ new Date(0)).toISOString();
|
|
1651
1668
|
return epochMillisToIso(ms) ?? (/* @__PURE__ */ new Date(0)).toISOString();
|
|
1652
1669
|
}
|
|
1653
|
-
/** OTLP wants 16-hex span ids; eval traces use UUID-ish strings. Hex-strip +
|
|
1654
|
-
* take 16, else deterministic FNV fold. */
|
|
1655
|
-
function padSpanId(id) {
|
|
1656
|
-
const cleaned = id.replace(/[^a-f0-9]/gi, "").toLowerCase();
|
|
1657
|
-
if (cleaned.length >= 16) return cleaned.slice(0, 16);
|
|
1658
|
-
return foldTo16Hex(id);
|
|
1659
|
-
}
|
|
1660
|
-
/** OTLP wants 32-hex trace ids; fold deterministically when too short. */
|
|
1661
|
-
function padTraceId(id) {
|
|
1662
|
-
const cleaned = id.replace(/[^a-f0-9]/gi, "").toLowerCase();
|
|
1663
|
-
if (cleaned.length >= 32) return cleaned.slice(0, 32);
|
|
1664
|
-
return foldTo32Hex(id);
|
|
1665
|
-
}
|
|
1666
|
-
function foldTo16Hex(s) {
|
|
1667
|
-
let h1 = 2166136261;
|
|
1668
|
-
for (const ch of s) {
|
|
1669
|
-
h1 ^= ch.charCodeAt(0);
|
|
1670
|
-
h1 = Math.imul(h1, 16777619) >>> 0;
|
|
1671
|
-
}
|
|
1672
|
-
const part = h1.toString(16).padStart(8, "0");
|
|
1673
|
-
return (part + part).slice(0, 16);
|
|
1674
|
-
}
|
|
1675
|
-
function foldTo32Hex(s) {
|
|
1676
|
-
return foldTo16Hex(s) + foldTo16Hex(`${s}::trace`).slice(0, 16);
|
|
1677
|
-
}
|
|
1678
1670
|
//#endregion
|
|
1679
1671
|
//#region src/replay.ts
|
|
1680
1672
|
/**
|
|
@@ -1871,4 +1863,4 @@ async function keyFromBody(body) {
|
|
|
1871
1863
|
//#endregion
|
|
1872
1864
|
export { TRACE_ANALYST_ACTOR_DESCRIPTION as A, domainEvidencePattern as C, tokenizeDomainWords as D, scoreTraceInsightReadiness as E, traceAnalystOnRunComplete as O, describeTraceInsightScope as S, planTraceInsightQuestions as T, otlpToTraceRunRecords as _, convertTraceStoresToOtlp as a, buildTraceInsightPrompt as b, otelRunCompleteHook as c, captureFetchToRawSink as d, ToolTraceMissingError as f, otlpToRunRecords as g, otlpRowsToTraceRunRecords as h, iterateRawCalls as i, TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION as j, analyzeTraces as k, OTEL_AGENT_EVAL_SCOPE as l, otlpRowsToRunRecords as m, ReplayCacheMissError as n, createOtelExporter as o, toolSpansToTraceAnalysisStore as p, createReplayFetch as r, createOtelTracingStore as s, ReplayCache as t, exportRunAsOtlp as u, flattenOtlpExportToNdjson as v, inferDomainKeywords as w, defaultTraceInsightPanel as x, buildTraceInsightContext as y };
|
|
1873
1865
|
|
|
1874
|
-
//# sourceMappingURL=replay-
|
|
1866
|
+
//# sourceMappingURL=replay-DjUfTrHD.js.map
|