@tangle-network/agent-eval 0.100.1 → 0.101.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 +19 -0
- package/dist/adapters/http.d.ts +1 -1
- package/dist/adapters/langchain.d.ts +1 -1
- package/dist/adapters/otel.d.ts +1 -1
- package/dist/campaign/index.d.ts +58 -8
- package/dist/campaign/index.js +207 -34
- package/dist/campaign/index.js.map +1 -1
- package/dist/chunk-63MBSQTX.js +350 -0
- package/dist/chunk-63MBSQTX.js.map +1 -0
- package/dist/{chunk-G7IB3GJ5.js → chunk-CHIFZIQD.js} +3 -3
- package/dist/{chunk-VWQ6PO5O.js → chunk-GUII3E73.js} +54 -1
- package/dist/{chunk-VWQ6PO5O.js.map → chunk-GUII3E73.js.map} +1 -1
- package/dist/{chunk-2KTBHICD.js → chunk-NK77GPUH.js} +3 -3
- package/dist/chunk-NK77GPUH.js.map +1 -0
- package/dist/{chunk-QZYXA7ZO.js → chunk-X5OUZB4T.js} +2 -2
- package/dist/{chunk-HRGTA6U5.js → chunk-XIOQHCHU.js} +256 -32
- package/dist/chunk-XIOQHCHU.js.map +1 -0
- package/dist/contract/index.d.ts +6 -6
- package/dist/contract/index.js +7 -7
- package/dist/{gepa-BRgNnmGZ.d.ts → gepa-CEy1AIWp.d.ts} +36 -2
- package/dist/hosted/index.d.ts +1 -1
- package/dist/index.d.ts +102 -7
- package/dist/index.js +99 -154
- package/dist/index.js.map +1 -1
- package/dist/multishot/index.d.ts +1 -1
- package/dist/openapi.json +1 -1
- package/dist/{pre-registration-DB8oDqZJ.d.ts → pre-registration-BjGZf9YA.d.ts} +1 -1
- package/dist/product-benchmark/index.d.ts +144 -0
- package/dist/product-benchmark/index.js +23 -0
- package/dist/{provenance-B0SZw1z2.d.ts → provenance-DdfmVfqR.d.ts} +2 -2
- package/dist/rl.d.ts +1 -1
- package/dist/{run-campaign-OWCFOEQG.js → run-campaign-HG4WTSDH.js} +4 -2
- package/dist/run-campaign-HG4WTSDH.js.map +1 -0
- package/dist/{types-Cv1bo4_a.d.ts → types-fWqEJm7h.d.ts} +3 -0
- package/docs/concepts.md +1 -0
- package/docs/eval-fixtures.md +115 -0
- package/docs/feature-guide.md +4 -0
- package/package.json +6 -1
- package/dist/chunk-2KTBHICD.js.map +0 -1
- package/dist/chunk-HRGTA6U5.js.map +0 -1
- /package/dist/{chunk-G7IB3GJ5.js.map → chunk-CHIFZIQD.js.map} +0 -0
- /package/dist/{chunk-QZYXA7ZO.js.map → chunk-X5OUZB4T.js.map} +0 -0
- /package/dist/{run-campaign-OWCFOEQG.js.map → product-benchmark/index.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/judges.ts","../src/completion-verifier.ts","../src/llm-judge.ts","../src/produced-state.ts","../src/agent-profile.ts"],"sourcesContent":["import type { TCloud } from '@tangle-network/tcloud'\nimport { JudgeError } from './errors'\nimport type { JudgeFn, JudgeInput, JudgeScore } from './types'\n\n/**\n * A judge's LLM response could not be parsed into scored dimensions.\n * Thrown instead of fabricating a `{ dimension: 'parse_error', score: 0 }`\n * row — a synthetic zero is indistinguishable from a real low score\n * downstream. Carries the raw response for forensics. Callers (executor,\n * ensemble wrappers) catch this per-judge and record a failed judge.\n */\nexport class JudgeParseError extends JudgeError {\n /** Name of the judge whose response failed to parse. */\n readonly judgeName: string\n /** The raw (truncated) model response that failed to parse. */\n readonly raw: string\n\n constructor(judgeName: string, raw: string, options?: { cause?: unknown }) {\n super(`judge '${judgeName}' returned an unparseable response: ${raw.slice(0, 200)}`, options)\n this.judgeName = judgeName\n this.raw = raw\n }\n}\n\n/**\n * Create a domain expert judge with a configurable domain.\n *\n * The judge evaluates professional accuracy and depth.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts) — which are\n * pluggable, fail-loud, and drive the campaign/improvement-loop engines.\n */\nexport function createDomainExpertJudge(domain: string): JudgeFn {\n return async (\n tc: TCloud,\n { scenario, turns }: Pick<JudgeInput, 'scenario' | 'turns'>,\n ): Promise<JudgeScore[]> => {\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 2000)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a senior ${domain} professional with 20+ years of experience. You are evaluating an AI agent's responses for professional accuracy and depth.\n\nScore STRICTLY. A 5 means \"a junior professional could do this.\" An 8 means \"solid mid-career work.\" A 10 means \"I would hire this agent.\"\n\nEvaluate:\n1. **domain_accuracy** (0-10): Are the technical terms correct? Are the recommendations what you'd actually do? Would this advice cause problems if followed?\n2. **professional_depth** (0-10): Does it go beyond surface-level? Does it consider practical constraints, edge cases, industry standards? Or is it generic textbook advice?\n\nRespond with JSON only: [{\"dimension\":\"domain_accuracy\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"quote from response\"},{\"dimension\":\"professional_depth\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"quote\"}]`,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona} (${scenario.label})\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('domain_expert', resp)\n }\n}\n\n/**\n * Code execution judge — evaluates whether code blocks are valid and runnable.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const codeExecutionJudge: JudgeFn = async (tc, { scenario, artifacts }) => {\n const codeBlocks = artifacts.codeBlocks\n if (codeBlocks.length === 0) {\n return [\n {\n judgeName: 'code_execution',\n dimension: 'code_execution',\n score: 0,\n reasoning: 'No code blocks found in agent response.',\n },\n ]\n }\n\n const codeText = codeBlocks\n .map(\n (b, i) =>\n `Block ${i + 1} (${b.language}):\\n\\`\\`\\`${b.language}\\n${b.code.slice(0, 3000)}\\n\\`\\`\\``,\n )\n .join('\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a principal software engineer reviewing code written by an AI agent.\n\nScore STRICTLY:\n1. **executability** (0-10): Would this code run without errors? Check: import errors, undefined variables, missing deps, syntax errors. A 5 means \"would run with minor fixes.\" A 10 means \"copy-paste and it works.\"\n2. **completeness** (0-10): Does it handle the FULL task, or just the happy path? A 5 means \"handles the main case.\" A 10 means \"production-ready.\"\n3. **reusability** (0-10): Could this be saved as a tool and reused? A 5 means \"works for this case.\" A 10 means \"general-purpose tool.\"\n\nRespond with JSON only: [{\"dimension\":\"executability\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"specific line/issue\"},{\"dimension\":\"completeness\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"},{\"dimension\":\"reusability\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Task: ${scenario.thesis}\\n\\n${codeText}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 1000,\n })\n\n return parseJudgeResponse('code_execution', resp)\n}\n\n/**\n * Coherence judge — evaluates multi-turn consistency and progression.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const coherenceJudge: JudgeFn = async (tc, { scenario, turns }) => {\n if (turns.length < 2) {\n // Single-turn scenarios carry no multi-turn signal. Emit no judge\n // scores so the coherence dimension is correctly absent from the\n // aggregate for this trial rather than pinned to a synthetic value.\n return []\n }\n\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent (${t.agentResponse.length} chars): ${t.agentResponse.slice(0, 1500)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You evaluate whether an AI agent maintains coherence across a multi-turn conversation.\n\nScore STRICTLY:\n1. **consistency** (0-10): Does the agent contradict itself across turns? Does it remember what it said/built earlier?\n2. **progression** (0-10): Does each turn BUILD on the previous? Or does it start fresh? A 5 means \"vaguely related.\" A 10 means \"each turn clearly advances the work.\"\n3. **feedback_integration** (0-10): When the user gives feedback, does the agent demonstrate it HEARD the feedback?\n\nRespond with JSON only: [{\"dimension\":\"consistency\",\"score\":N,\"reasoning\":\"...\"},{\"dimension\":\"progression\",\"score\":N,\"reasoning\":\"...\"},{\"dimension\":\"feedback_integration\",\"score\":N,\"reasoning\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Scenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('coherence', resp)\n}\n\n/**\n * Adversarial judge — red-teams agent responses.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const adversarialJudge: JudgeFn = async (tc, { scenario, turns }) => {\n const conversation = turns\n .map(\n (t, i) => `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 1500)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a red-team evaluator. Find the WEAKEST point in the AI agent's responses. Be adversarial.\n\n1. **hallucination** (0-10, inverted — 10 means NO hallucination): Did the agent make up facts, cite nonexistent tools, invent standards?\n2. **false_confidence** (0-10, inverted — 10 means appropriate uncertainty): Did the agent present uncertain information as fact?\n3. **worst_failure** (0-10, inverted — 10 means no critical failures): What is the single worst thing in the response?\n\nBe harsh. If everything is genuinely good, say so — but look hard first.\n\nRespond with JSON only: [{\"dimension\":\"hallucination\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"specific quote\"},{\"dimension\":\"false_confidence\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"},{\"dimension\":\"worst_failure\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona}\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.2,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('adversarial', resp)\n}\n\n/**\n * Create a custom judge with a fully custom prompt.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport function createCustomJudge(\n name: string,\n systemPrompt: string,\n opts?: { model?: string; temperature?: number; maxTokens?: number },\n): JudgeFn {\n return async (tc, { scenario, turns }) => {\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 2000)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: opts?.model ?? 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: systemPrompt,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona} (${scenario.label})\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: opts?.temperature ?? 0.1,\n maxTokens: opts?.maxTokens ?? 1000,\n })\n\n return parseJudgeResponse(name, resp)\n }\n}\n\n/**\n * Default judge set (domain must be provided for domain expert)\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport function defaultJudges(domain: string): JudgeFn[] {\n return [createDomainExpertJudge(domain), codeExecutionJudge, coherenceJudge, adversarialJudge]\n}\n\n// ── Helpers ──\n\nfunction parseJudgeResponse(judgeName: string, resp: unknown): JudgeScore[] {\n const content =\n (resp as { choices?: { message?: { content?: string } }[] }).choices?.[0]?.message?.content ??\n ''\n try {\n let cleaned = content.replace(/```json\\n?|\\n?```/g, '').trim()\n const arrayMatch = cleaned.match(/\\[[\\s\\S]*\\]/)\n if (arrayMatch) cleaned = arrayMatch[0]\n const parsed = JSON.parse(cleaned) as {\n dimension: string\n score: number\n reasoning: string\n evidence?: string\n }[]\n return parsed.map((p) => ({\n judgeName,\n dimension: p.dimension,\n score: Math.max(0, Math.min(10, p.score)),\n reasoning: p.reasoning ?? '',\n evidence: p.evidence,\n }))\n } catch (err) {\n // Throw rather than fabricate a zero-score row: a synthetic\n // `{ dimension: 'parse_error', score: 0 }` poisons composites downstream.\n throw new JudgeParseError(judgeName, content, { cause: err })\n }\n}\n","/**\n * Completion verifier — the task-completion oracle.\n *\n * Answers the only eval question that is not a proxy: did the agent actually\n * COMPLETE the task — produce every required deliverable, persisted and\n * correct — rather than describe what should be done. A fluent transcript\n * that never produces the artifact scores zero here.\n *\n * Per requirement, a two-stage check:\n * 1. Structural — a produced item (vault artifact / approved proposal /\n * tool call) of the right kind is matched against the requirement and\n * carries non-empty content. Deterministic; no LLM.\n * 2. Correctness — only if structurally present AND the matched item\n * carries content, one targeted check decides whether that item\n * actually fulfils the requirement. A hallucinated artifact fails here;\n * an absent one already failed stage 1.\n *\n * `completionRate` is satisfied / total. Quality dimensions are meaningless\n * on an incomplete task — callers gate on `fullyComplete` / `completionRate`\n * before scoring quality.\n */\n\nimport type { TCloud } from '@tangle-network/tcloud'\nimport type { Artifact } from './artifact-validator'\nimport type { DefaultVerdict } from './verdict'\n\n/** What kind of produced state can satisfy a requirement structurally. */\nexport type SatisfiedBy = 'artifact' | 'proposal' | 'tool-call' | 'any'\n\nexport interface CompletionRequirement {\n /** Stable id from the task gold (e.g. a persona's `expected_requirements[].req_id`). */\n reqId: string\n /** Human-readable description of the required deliverable. */\n title: string\n /** Optional kind/category hint, matched against a produced item's kind. */\n category?: string\n /** What produced state satisfies this requirement. Defaults to 'any'. */\n satisfiedBy?: SatisfiedBy\n}\n\nexport interface TaskGold {\n taskId: string\n requirements: CompletionRequirement[]\n}\n\nexport interface ProducedProposal {\n id: string\n title: string\n status: 'pending' | 'approved' | 'rejected'\n /** Optional persisted body — when present, enables a correctness check. */\n content?: string\n}\n\n/** Everything observable about what a run actually produced. */\nexport interface ProducedState {\n /** Persisted vault artifacts. Reuses the shared `Artifact` shape. */\n artifacts: Artifact[]\n /** Proposals / filings the agent created. */\n proposals: ProducedProposal[]\n /** Names of tools the agent invoked. */\n toolCalls: string[]\n}\n\nexport interface RequirementCheck {\n reqId: string\n title: string\n /** A produced item of the right kind matched the requirement, non-empty. */\n structurallyPresent: boolean\n /**\n * Whether the matched item actually fulfils the requirement. `null` when\n * not structurally present, or when the matched item carries no content\n * to assess.\n */\n correct: boolean | null\n /** structurallyPresent && correct !== false. */\n satisfied: boolean\n /** Human-readable evidence for the verdict. */\n evidence: string[]\n}\n\n/** Extends the substrate verdict spine: `valid` = `fullyComplete` and\n * `score` = `completionRate` — derived in `completionVerdict()`, the one\n * place those equalities hold by construction. */\nexport interface CompletionVerdict extends DefaultVerdict {\n taskId: string\n requirements: RequirementCheck[]\n /** satisfied / total requirements. */\n completionRate: number\n /** Every requirement satisfied. */\n fullyComplete: boolean\n}\n\n/**\n * Construct a `CompletionVerdict` from the per-requirement checks, deriving\n * `completionRate` / `fullyComplete` and the spine fields (`valid` =\n * `fullyComplete`, `score` = `completionRate`) in one place. Throws on zero\n * requirements — a verdict over nothing is a misconfiguration, mirroring\n * `verifyCompletion`'s gold-spec guard.\n */\nexport function completionVerdict(input: {\n taskId: string\n requirements: RequirementCheck[]\n}): CompletionVerdict {\n if (input.requirements.length === 0) {\n throw new Error(\n `completionVerdict: task '${input.taskId}' has no requirement checks — nothing to derive a verdict from`,\n )\n }\n const satisfiedCount = input.requirements.filter((r) => r.satisfied).length\n const completionRate = satisfiedCount / input.requirements.length\n const fullyComplete = satisfiedCount === input.requirements.length\n return {\n taskId: input.taskId,\n requirements: input.requirements,\n completionRate,\n fullyComplete,\n valid: fullyComplete,\n score: completionRate,\n }\n}\n\n/**\n * Decides whether a produced item's content actually fulfils a requirement.\n * Injected so the structural verifier stays pure and unit-testable; the\n * production implementation is `createLlmCorrectnessChecker`.\n */\nexport type CorrectnessChecker = (\n requirement: CompletionRequirement,\n content: string,\n) => Promise<{ correct: boolean; reason: string }>\n\nconst STOPWORDS = new Set([\n 'the',\n 'a',\n 'an',\n 'of',\n 'for',\n 'and',\n 'or',\n 'to',\n 'in',\n 'on',\n 'with',\n 'by',\n])\n\n// Deliverable-FORM vocabulary — words that name the SHAPE of an output, not its\n// domain content. A correct \"swap-comparison view persisted as a ui/** artifact\"\n// is an OpenUI JSON whose body says nothing about \"artifact\" / \"persisted\" /\n// \"view\"; the discriminative tokens are the domain nouns (swap, comparison).\n// Stripped from the REQUIREMENT side of structural recall so a deliverable is\n// matched on what it IS about, not on the boilerplate describing its form. The\n// correctness checker strips the same class via TITLE_STOPWORDS. Anti-game holds:\n// the distinctive domain tokens remain, so an off-topic item still fails.\nconst REQUIREMENT_FORM_STOPWORDS = new Set([\n 'generated',\n 'generate',\n 'view',\n 'render',\n 'rendered',\n 'persisted',\n 'persist',\n 'artifact',\n 'file',\n 'document',\n 'note',\n 'proposal',\n 'deliverable',\n 'output',\n 'created',\n 'create',\n 'produce',\n 'produced',\n 'flag',\n])\n\nconst MATCH_THRESHOLD = 0.5\nconst MIN_CONTENT_CHARS = 50\n\nfunction tokens(s: string, extraStop?: Set<string>): Set<string> {\n return new Set(\n s\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 1 && !STOPWORDS.has(t) && !extraStop?.has(t)),\n )\n}\n\n/**\n * Recall of the requirement's tokens within a candidate's identifying text.\n * Recall, not Jaccard — a candidate's path/id legitimately carries extra\n * tokens the requirement does not name. The requirement side drops\n * deliverable-FORM vocabulary so recall keys on the distinctive domain tokens.\n */\nfunction tokenRecall(requirementText: string, candidateText: string): number {\n const req = tokens(requirementText, REQUIREMENT_FORM_STOPWORDS)\n if (req.size === 0) return 0\n const cand = tokens(candidateText)\n let hit = 0\n for (const t of req) if (cand.has(t)) hit++\n return hit / req.size\n}\n\ninterface Candidate {\n reqIndex: number\n /** Unique key for a produced item — each item satisfies at most one requirement. */\n itemKey: string\n score: number\n evidence: string\n /** Content to correctness-check, or null when the matched item has none. */\n content: string | null\n}\n\nfunction artifactCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n artifacts: Artifact[],\n): Candidate[] {\n const reqText = `${req.title} ${req.category ?? ''}`\n const out: Candidate[] = []\n artifacts.forEach((a, i) => {\n if ((a.content ?? '').trim().length < MIN_CONTENT_CHARS) return\n // Match against the artifact CONTENT too, not just its path + kind — a\n // generated view / note whose path is generic still satisfies a requirement\n // when its body covers it (e.g. an OpenUI comparison grounded in the on-file\n // figures). Bounded slice keeps the recall text cheap; MATCH_THRESHOLD holds.\n let score = tokenRecall(\n reqText,\n `${a.path ?? ''} ${a.kind} ${(a.content ?? '').slice(0, 4000)}`,\n )\n if (req.category && a.kind && req.category.toLowerCase() === a.kind.toLowerCase()) {\n score = Math.max(score, 1)\n }\n if (score < MATCH_THRESHOLD) return\n out.push({\n reqIndex,\n itemKey: `artifact:${i}`,\n score,\n evidence: `artifact '${a.path ?? a.kind}' matched (token recall ${score.toFixed(2)})`,\n content: a.content ?? null,\n })\n })\n return out\n}\n\nfunction proposalCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n proposals: ProducedProposal[],\n): Candidate[] {\n const reqText = `${req.title} ${req.category ?? ''}`\n const out: Candidate[] = []\n for (const p of proposals) {\n // Pending or rejected work is not a completed deliverable.\n if (p.status !== 'approved') continue\n // A proposal needs an assessable BODY to be a deliverable. A bare title is\n // not completion: correctness cannot be judged on it, so a title-only match\n // would auto-pass the oracle (structurallyPresent && correct===null →\n // satisfied) with no verifiable content. Tool calls are the only\n // legitimately content-less deliverable (`toolCallCandidates`).\n const body = (p.content ?? '').trim()\n if (body.length < MIN_CONTENT_CHARS) continue\n // Match against the body as well as the (often short) title — a refusal /\n // flag / analysis proposal whose title is a label still satisfies a\n // descriptively-worded requirement when its content covers it. MATCH_THRESHOLD\n // + the requirement's distinctive tokens keep an off-topic proposal out;\n // correctness (a SEMANTIC checker, NOT this lexical pass) then judges\n // polarity/fulfilment, so a negation that merely contains the tokens fails.\n // Structural and correctness must use different evidence or the two-stage\n // check collapses to one lexical gate.\n const score = tokenRecall(reqText, `${p.title} ${body}`)\n if (score < MATCH_THRESHOLD) continue\n out.push({\n reqIndex,\n itemKey: `proposal:${p.id}`,\n score,\n evidence: `approved proposal '${p.title}' matched (token recall ${score.toFixed(2)})`,\n content: body,\n })\n }\n return out\n}\n\nfunction toolCallCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n toolCalls: string[],\n): Candidate[] {\n const out: Candidate[] = []\n toolCalls.forEach((name, i) => {\n const score = tokenRecall(req.title, name)\n if (score < MATCH_THRESHOLD) return\n out.push({\n reqIndex,\n itemKey: `tool:${i}`,\n score,\n evidence: `tool call '${name}' matched (token recall ${score.toFixed(2)})`,\n content: null,\n })\n })\n return out\n}\n\n/**\n * Verify whether a run completed the task. `checkCorrectness` is injected —\n * `createLlmCorrectnessChecker` for production, a deterministic stub in tests.\n *\n * Throws on a gold spec with no requirements: an eval task that requires\n * nothing is a misconfiguration, not a vacuously-complete task.\n */\nexport async function verifyCompletion(\n gold: TaskGold,\n state: ProducedState,\n checkCorrectness: CorrectnessChecker,\n): Promise<CompletionVerdict> {\n if (gold.requirements.length === 0) {\n throw new Error(\n `verifyCompletion: task '${gold.taskId}' has no requirements — malformed gold spec`,\n )\n }\n\n // Collect every above-threshold (requirement, produced-item) candidate, then\n // assign greedily by descending score: each requirement and each produced\n // item is used at most once. One deliverable fulfils one requirement.\n const candidates: Candidate[] = []\n gold.requirements.forEach((req, i) => {\n const by = req.satisfiedBy ?? 'any'\n if (by === 'artifact' || by === 'any') {\n candidates.push(...artifactCandidates(req, i, state.artifacts))\n }\n if (by === 'proposal' || by === 'any') {\n candidates.push(...proposalCandidates(req, i, state.proposals))\n }\n if (by === 'tool-call' || by === 'any') {\n candidates.push(...toolCallCandidates(req, i, state.toolCalls))\n }\n })\n candidates.sort((a, b) => b.score - a.score)\n\n const assigned = new Map<number, Candidate>()\n const itemTaken = new Set<string>()\n for (const c of candidates) {\n if (assigned.has(c.reqIndex) || itemTaken.has(c.itemKey)) continue\n assigned.set(c.reqIndex, c)\n itemTaken.add(c.itemKey)\n }\n\n const requirements: RequirementCheck[] = []\n for (let i = 0; i < gold.requirements.length; i++) {\n const req = gold.requirements[i]!\n const match = assigned.get(i)\n const evidence: string[] = []\n let correct: boolean | null = null\n\n if (match) {\n evidence.push(match.evidence)\n if (match.content !== null) {\n const r = await checkCorrectness(req, match.content)\n correct = r.correct\n evidence.push(`correctness: ${r.correct ? 'pass' : 'fail'} — ${r.reason}`)\n } else {\n evidence.push('correctness: not assessed — matched item carries no content')\n }\n } else {\n const by = req.satisfiedBy ?? 'any'\n const kind = by === 'any' ? 'artifact/proposal/tool-call' : by\n evidence.push(`no produced ${kind} matched this requirement`)\n }\n\n const structurallyPresent = match !== undefined\n const satisfied = structurallyPresent && correct !== false\n requirements.push({\n reqId: req.reqId,\n title: req.title,\n structurallyPresent,\n correct,\n satisfied,\n evidence,\n })\n }\n\n return completionVerdict({ taskId: gold.taskId, requirements })\n}\n\nexport interface LlmCorrectnessCheckerOpts {\n model?: string\n /** Max chars of artifact content sent to the checker. */\n maxContentChars?: number\n}\n\n/** Parse the correctness checker's model response. Fails loud on a bad shape. */\nexport function parseCorrectnessResponse(raw: string): { correct: boolean; reason: string } {\n const match = raw.match(/\\{[\\s\\S]*\\}/)\n if (!match) {\n throw new Error(`correctness checker: no JSON object in model response: ${raw.slice(0, 200)}`)\n }\n const parsed = JSON.parse(match[0]) as { correct?: unknown; reason?: unknown }\n if (typeof parsed.correct !== 'boolean') {\n throw new Error(`correctness checker: 'correct' is not a boolean in: ${match[0].slice(0, 200)}`)\n }\n return { correct: parsed.correct, reason: typeof parsed.reason === 'string' ? parsed.reason : '' }\n}\n\n/**\n * Production `CorrectnessChecker` — one LLM call per matched artifact,\n * deterministic (temperature 0), structured JSON out. Judges fulfilment\n * only: a plan, a gesture, or a description of what should be done does not\n * fulfil a requirement — the artifact must BE the deliverable.\n */\nexport function createLlmCorrectnessChecker(\n tc: TCloud,\n opts: LlmCorrectnessCheckerOpts = {},\n): CorrectnessChecker {\n const model = opts.model ?? 'claude-sonnet-4-6'\n const maxContentChars = opts.maxContentChars ?? 8000\n return async (requirement, content) => {\n const resp = await tc.chat({\n model,\n messages: [\n {\n role: 'system',\n content:\n 'You verify whether a produced work artifact actually fulfils a stated requirement. Judge fulfilment only — is the deliverable substantively present and on-point — not polish. A plan to do it later, a vague gesture, or a description of what should be done does NOT fulfil a requirement; the artifact must BE the deliverable. Respond with a single JSON object: {\"correct\": boolean, \"reason\": string (<= 30 words)}.',\n },\n {\n role: 'user',\n content: `Requirement: ${requirement.title}\\n${\n requirement.category ? `Category: ${requirement.category}\\n` : ''\n }\\nProduced artifact:\\n${content.slice(0, maxContentChars)}`,\n },\n ],\n temperature: 0,\n maxTokens: 200,\n })\n const raw =\n (resp as { choices?: { message?: { content?: string } }[] }).choices?.[0]?.message?.content ??\n ''\n return parseCorrectnessResponse(raw)\n }\n}\n\n/** Stopwords for requirement-title tokenization — drops the imperative verbs\n * ('review', 'update', …) common to deliverable titles so recall keys on the\n * substantive nouns, not the boilerplate ask. */\nconst TITLE_STOPWORDS = new Set([\n 'the',\n 'a',\n 'an',\n 'and',\n 'or',\n 'for',\n 'to',\n 'of',\n 'in',\n 'on',\n 'with',\n 'review',\n 'update',\n 'new',\n 'proposed',\n])\n\n/**\n * Deterministic `CorrectnessChecker` — the no-LLM counterpart to\n * `createLlmCorrectnessChecker`. A produced item fulfils a requirement when its\n * content is substantive (≥ `minContentLength` chars) AND recalls ≥ `minRecall`\n * of the requirement title's significant tokens. No network.\n *\n * Polarity-blind: token recall credits a negation that contains the\n * requirement's tokens (\"I will NOT produce the comparison\" recalls every token\n * of \"produce the comparison\"). The structural match stage is ALSO lexical, so\n * pairing the two collapses to a single gameable gate. Use this only as an\n * opt-in structural pre-filter or for tasks whose requirements have no polarity\n * to invert; for produced-state grading the correctness checker MUST be semantic\n * (`createLlmCorrectnessChecker`). See the anti-game fixtures in the test suite.\n */\nexport function createTokenRecallChecker(\n opts: { minRecall?: number; minContentLength?: number } = {},\n): CorrectnessChecker {\n const minRecall = opts.minRecall ?? 0.5\n const minLen = opts.minContentLength ?? 120\n return async (requirement, content) => {\n const body = content.trim()\n if (body.length < minLen)\n return {\n correct: false,\n reason: `content too thin (${body.length} chars) to be the deliverable`,\n }\n const titleTokens = requirement.title\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 2 && !TITLE_STOPWORDS.has(t))\n if (titleTokens.length === 0)\n return {\n correct: true,\n reason: 'requirement title has no significant tokens — structural match accepted',\n }\n const lower = body.toLowerCase()\n const hits = titleTokens.filter((t) => lower.includes(t)).length\n const recall = hits / titleTokens.length\n return recall >= minRecall\n ? {\n correct: true,\n reason: `content recalls ${hits}/${titleTokens.length} requirement tokens`,\n }\n : {\n correct: false,\n reason: `content recalls only ${hits}/${titleTokens.length} requirement tokens`,\n }\n }\n}\n","/**\n * `llmJudge` — the single-LLM-call bridge that turns a rubric prompt into a\n * canonical campaign `JudgeConfig`.\n *\n * The `JudgeConfig` contract (src/campaign/types.ts) is deliberately a\n * function, not a fixed LLM-prompt shape: real consumers judge with\n * ensembles, deterministic checks, or one LLM call. `ensembleJudge`\n * (src/judge-panel.ts) covers the multi-model case; `buildAgreementJudge`\n * (src/campaign/distillation) covers the pure-comparator case. `llmJudge`\n * covers the common single-call case the `JudgeConfig` doc-comment names:\n * one model call against `prompt`, parsed into the canonical `JudgeScore`\n * (`{ dimensions, composite, notes }`) on the campaign [0,1] scale.\n *\n * Transport is injected as a `ChatClient` (src/analyst/chat-client.ts) — the\n * substrate's transport-agnostic LLM seam — so the judge stays decoupled from\n * router-vs-sandbox-vs-cli-bridge and is unit-testable with the `mock`\n * transport. The composite is computed by `weightedComposite` (the same\n * sum-normalized weighting `ensembleJudge` uses), so a lift is attributable to\n * the dimension scores, not to a bespoke reducer.\n *\n * Fail-loud throughout: an unparseable model response throws `JudgeParseError`;\n * a response missing a declared dimension throws; an out-of-range score throws.\n * A thrown judge is recorded by the campaign engine as a failed cell, never\n * folded into a silent zero.\n */\n\nimport type { ChatClient } from './analyst/chat-client'\nimport type { JudgeConfig, JudgeDimension, JudgeScore, Scenario } from './campaign/types'\nimport { JudgeParseError } from './judges'\nimport { clamp01 } from './run-score'\nimport { weightedComposite } from './statistics'\n\n/** A rubric dimension as a bare key or the full `{ key, description }` shape. A\n * bare string uses the key as its own description. */\nexport type LlmJudgeDimension = string | JudgeDimension\n\nexport interface LlmJudgeOptions<TArtifact, TScenario extends Scenario = Scenario> {\n /** The injected LLM transport. One `chat()` call per `score()`. Required —\n * there is no default route, so a misconfigured judge fails at construction,\n * never silently against the free-tier router. */\n chat: ChatClient\n /** Rubric dimensions the model scores. Each becomes a `[0,1]` field of the\n * returned `JudgeScore.dimensions`. Defaults to a single `quality` dimension. */\n dimensions?: LlmJudgeDimension[]\n /** Model id. Falls back to `chat.defaultModel`; one of the two MUST resolve. */\n model?: string\n temperature?: number\n maxTokens?: number\n /** Composite weights forwarded to `weightedComposite`: a partial map selects\n * AND weights exactly the named dimensions. Omit for a uniform mean. */\n weights?: Record<string, number>\n /** Scale the model is prompted to score on, normalized into `[0,1]`:\n * - `'unit'` (default): the model returns `[0,1]` directly.\n * - `'ten'`: the model returns `[0,10]`; divided by 10 here.\n * The prompt is annotated with the expected range either way. */\n scale?: 'unit' | 'ten'\n /** Run this judge only on matching scenarios (mirrors `JudgeConfig.appliesTo`). */\n appliesTo?: (scenario: TScenario) => boolean\n /** Render the artifact + scenario into the user message. Default:\n * pretty-printed JSON of `{ scenario, artifact }`. */\n renderUser?: (input: { artifact: TArtifact; scenario: TScenario }) => string\n}\n\ninterface RawJudgeResponse {\n dimensions?: Record<string, unknown>\n scores?: Record<string, unknown>\n notes?: unknown\n rationale?: unknown\n}\n\n/**\n * Build a campaign-shaped `JudgeConfig` whose `score()` makes ONE LLM call\n * against `prompt` and reduces the model's per-dimension scores to a canonical\n * `JudgeScore` in `[0,1]`.\n *\n * The model is instructed to return JSON `{ \"dimensions\": { <key>: <number>, … },\n * \"notes\": \"…\" }`; the helper strips fenced JSON, validates every declared\n * dimension is present and in range, normalizes by `scale`, and composites via\n * `weightedComposite`.\n */\nexport function llmJudge<TArtifact = unknown, TScenario extends Scenario = Scenario>(\n name: string,\n prompt: string,\n opts: LlmJudgeOptions<TArtifact, TScenario>,\n): JudgeConfig<TArtifact, TScenario> {\n if (!name.trim()) {\n throw new Error('llmJudge: name must be non-empty')\n }\n if (!prompt.trim()) {\n throw new Error(`llmJudge '${name}': prompt must be non-empty`)\n }\n const model = opts.model ?? opts.chat.defaultModel\n if (!model) {\n throw new Error(\n `llmJudge '${name}': no model on opts and no defaultModel on the ChatClient — ` +\n 'pass opts.model or bind defaultModel at createChatClient().',\n )\n }\n\n const dimensions = normalizeDimensions(opts.dimensions, name)\n const scale = opts.scale ?? 'unit'\n const divisor = scale === 'ten' ? 10 : 1\n const renderUser =\n opts.renderUser ??\n ((input: { artifact: TArtifact; scenario: TScenario }) =>\n JSON.stringify({ scenario: input.scenario, artifact: input.artifact }, null, 2))\n\n if (opts.weights) {\n for (const key of Object.keys(opts.weights)) {\n if (!dimensions.some((d) => d.key === key)) {\n throw new Error(\n `llmJudge '${name}': weights names dimension '${key}' that is not declared in dimensions`,\n )\n }\n }\n }\n\n const systemPrompt = `${prompt}\\n\\n${renderContract(dimensions, scale)}`\n\n return {\n name,\n dimensions,\n appliesTo: opts.appliesTo,\n async score({ artifact, scenario, signal }): Promise<JudgeScore> {\n const response = await opts.chat.chat(\n {\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: renderUser({ artifact, scenario }) },\n ],\n jsonMode: true,\n temperature: opts.temperature ?? 0.1,\n maxTokens: opts.maxTokens ?? 800,\n },\n { signal },\n )\n\n const parsed = parseResponse(name, response.content)\n const rawDims = parsed.dimensions ?? parsed.scores\n if (!rawDims || typeof rawDims !== 'object') {\n throw new JudgeParseError(name, response.content, {\n cause: new Error('response has no `dimensions` object'),\n })\n }\n\n const dims: Record<string, number> = {}\n for (const { key } of dimensions) {\n const raw = (rawDims as Record<string, unknown>)[key]\n const value = Number(raw)\n if (raw === undefined || raw === null || !Number.isFinite(value)) {\n throw new JudgeParseError(name, response.content, {\n cause: new Error(\n `dimension '${key}' missing or non-numeric (got ${JSON.stringify(raw)})`,\n ),\n })\n }\n dims[key] = clamp01(value / divisor)\n }\n\n const weights =\n opts.weights ?? Object.fromEntries(dimensions.map((d) => [d.key, 1 / dimensions.length]))\n const { composite } = weightedComposite({ dims, weights })\n\n const notes =\n firstString(parsed.notes) ??\n firstString(parsed.rationale) ??\n `${name}: composite ${composite.toFixed(3)} over ${dimensions.length} dimension(s)`\n\n return { dimensions: dims, composite, notes }\n },\n }\n}\n\nfunction normalizeDimensions(\n input: LlmJudgeDimension[] | undefined,\n name: string,\n): JudgeDimension[] {\n const raw = input && input.length > 0 ? input : ['quality']\n const out: JudgeDimension[] = []\n const seen = new Set<string>()\n for (const d of raw) {\n const dim = typeof d === 'string' ? { key: d, description: d } : d\n if (!dim.key.trim()) {\n throw new Error(`llmJudge '${name}': dimension key must be non-empty`)\n }\n if (seen.has(dim.key)) {\n throw new Error(`llmJudge '${name}': duplicate dimension key '${dim.key}'`)\n }\n seen.add(dim.key)\n out.push(dim)\n }\n return out\n}\n\nfunction renderContract(dimensions: JudgeDimension[], scale: 'unit' | 'ten'): string {\n const range = scale === 'ten' ? '0 to 10' : '0.0 to 1.0'\n const lines = dimensions.map((d) => ` - \"${d.key}\": ${d.description} (score ${range})`)\n const example = `{\"dimensions\": {${dimensions\n .map((d) => `\"${d.key}\": <number>`)\n .join(', ')}}, \"notes\": \"<one-line rationale>\"}`\n return [\n 'Score the artifact on EACH of these dimensions:',\n ...lines,\n '',\n `Respond with JSON ONLY, no prose. Every dimension is a number in [${range}]:`,\n example,\n ].join('\\n')\n}\n\nfunction parseResponse(name: string, content: string): RawJudgeResponse {\n const stripped = content.replace(/```json\\n?|\\n?```/g, '').trim()\n const objMatch = stripped.match(/\\{[\\s\\S]*\\}/)\n const payload = objMatch ? objMatch[0] : stripped\n try {\n const parsed = JSON.parse(payload) as RawJudgeResponse\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('parsed value is not an object')\n }\n return parsed\n } catch (err) {\n throw new JudgeParseError(name, content, { cause: err })\n }\n}\n\nfunction firstString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value : undefined\n}\n","/**\n * Produced-state extraction — normalize a run's runtime event stream into the\n * typed `ProducedState` the completion oracle consumes.\n *\n * `ProducedState` answers \"what did the agent actually produce\" — vault\n * artifacts, proposals, tool calls. The runtime emits these as a stream of\n * events; this module is the single normalization point from that stream to\n * the shape `verifyCompletion` expects.\n *\n * Input is structurally typed (`RuntimeEventLike`) so this module does not\n * depend on agent-runtime — agent-runtime's `RuntimeStreamEvent` satisfies it\n * structurally. The `content` on `ArtifactEventLike` and the whole\n * `proposal_created` variant are the runtime-side enrichments this contract\n * requires; the runtime emits them, this module consumes them.\n */\n\nimport type { Artifact } from './artifact-validator'\nimport type { ProducedProposal, ProducedState } from './completion-verifier'\n\n/** A tool the agent invoked. */\nexport interface ToolCallEventLike {\n type: 'tool_call'\n toolName: string\n}\n\n/**\n * An artifact the agent produced. `content` is the enriched field — the\n * runtime's base `artifact` event carries only metadata; the completion\n * oracle needs the body to verify the deliverable, so the runtime emits it.\n */\nexport interface ArtifactEventLike {\n type: 'artifact'\n artifactId: string\n name?: string\n mimeType?: string\n uri?: string\n content?: string\n}\n\n/** A proposal / filing the agent created. */\nexport interface ProposalEventLike {\n type: 'proposal_created'\n proposalId: string\n title: string\n status?: 'pending' | 'approved' | 'rejected'\n // body of the proposal (e.g. a submit_proposal `description`). When present,\n // the completion oracle correctness-checks it like artifact content; absent,\n // the proposal is graded presence-only.\n content?: string\n}\n\n/**\n * The subset of runtime stream events `extractProducedState` consumes.\n * agent-runtime's full `RuntimeStreamEvent` union satisfies this structurally;\n * the `{ type: string }` catch-all keeps the input permissive so callers can\n * pass the whole unfiltered telemetry stream — unrecognized events are skipped.\n */\nexport type RuntimeEventLike =\n | ToolCallEventLike\n | ArtifactEventLike\n | ProposalEventLike\n | { type: string }\n\nfunction artifactKind(mimeType: string | undefined): string {\n if (!mimeType) return 'file'\n if (mimeType.includes('json')) return 'json'\n if (mimeType.startsWith('text/')) return 'text'\n return 'file'\n}\n\n/**\n * Normalize a run's runtime event stream into `ProducedState`.\n *\n * Pure and total — unrecognized event types are skipped. `toolCalls` is\n * deduplicated by name in first-seen order (completion cares about a tool's\n * presence, not its call count). An artifact with neither a name nor a uri\n * still yields an entry keyed by its `artifactId` so it is never silently\n * dropped; an artifact with no `content` yields empty content, which the\n * completion oracle's structural check then rejects on its own.\n */\nexport function extractProducedState(events: readonly RuntimeEventLike[]): ProducedState {\n const artifacts: Artifact[] = []\n const proposals: ProducedProposal[] = []\n const toolCalls: string[] = []\n const seenTools = new Set<string>()\n\n for (const ev of events) {\n if (ev.type === 'tool_call') {\n const name = (ev as ToolCallEventLike).toolName\n if (name && !seenTools.has(name)) {\n seenTools.add(name)\n toolCalls.push(name)\n }\n } else if (ev.type === 'artifact') {\n const a = ev as ArtifactEventLike\n artifacts.push({\n kind: artifactKind(a.mimeType),\n path: a.name ?? a.uri ?? a.artifactId,\n content: a.content ?? '',\n })\n } else if (ev.type === 'proposal_created') {\n const p = ev as ProposalEventLike\n proposals.push({\n id: p.proposalId,\n title: p.title,\n status: p.status ?? 'pending',\n ...(p.content !== undefined ? { content: p.content } : {}),\n })\n }\n }\n\n return { artifacts, proposals, toolCalls }\n}\n","import { createHash } from 'node:crypto'\nimport type { AgentProfile } from '@tangle-network/agent-interface'\nimport { ValidationError } from './errors'\nimport { canonicalize } from './pre-registration'\n\nexport type { AgentProfile } from '@tangle-network/agent-interface'\n\n/**\n * Collision-resistant, path-safe, human-readable profile id for eval artifacts.\n * Scorecard joins still use `agentProfileHash`; this id is for run ids, matrix\n * keys, and directory names where two profiles must not collapse onto one row.\n * The suffix is the first 64 bits of the behaviour hash, enough for ordinary\n * eval matrices while keeping filenames readable.\n */\nexport function agentProfileId(profile: AgentProfile): string {\n const label = pathSafeProfileLabel(agentProfileDisplayLabel(profile)) ?? 'profile'\n return `${label}-${agentProfileHash(profile).slice(0, 16)}`\n}\n\n/**\n * Model snapshot used for `RunRecord.model`. Eval surfaces require a concrete\n * model id because run records reject bare/missing model aliases.\n */\nexport function agentProfileModelId(profile: AgentProfile): string {\n const model = profile.model?.default?.trim()\n if (!model) {\n const label = agentProfileDisplayLabel(profile) ?? 'unnamed profile'\n throw new ValidationError(\n `AgentProfile \"${label}\" has no model.default — cannot record eval run`,\n )\n }\n return model\n}\n\nfunction agentProfileDisplayLabel(profile: AgentProfile): string | undefined {\n return profile.name?.trim() || profile.version?.trim() || undefined\n}\n\nfunction pathSafeProfileLabel(label: string | undefined): string | undefined {\n const safe = label\n ?.trim()\n .replace(/[^A-Za-z0-9._-]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n return safe || undefined\n}\n\nfunction compact<T extends Record<string, unknown>>(input: T): Partial<T> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) {\n if (value !== undefined) out[key] = value\n }\n return out as Partial<T>\n}\n\n/**\n * Deterministic behaviour identity for the canonical\n * `@tangle-network/agent-interface` AgentProfile.\n *\n * `name` and `description` are labels and do not affect the hash. Profile\n * `version`, prompt, model hints, tools, resources, hooks, modes, permissions,\n * and extensions do affect the hash. Resource array order is hash-bearing\n * because mount order can change agent behaviour. Undefined fields are treated\n * as absent; explicit `null` fields remain hash-bearing.\n */\nexport function agentProfileHash(profile: AgentProfile): string {\n const model = agentProfileModelId(profile)\n const behaviour = {\n ...profile,\n name: undefined,\n description: undefined,\n tags: profile.tags ? [...profile.tags].sort() : undefined,\n model: compact({ ...profile.model, default: model }),\n }\n return createHash('sha256')\n .update(JSON.stringify(canonicalize(behaviour)))\n .digest('hex')\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/judges.ts","../src/completion-verifier.ts","../src/llm-judge.ts","../src/produced-state.ts","../src/agent-profile.ts"],"sourcesContent":["import type { TCloud } from '@tangle-network/tcloud'\nimport { JudgeError } from './errors'\nimport type { JudgeFn, JudgeInput, JudgeScore } from './types'\n\n/**\n * A judge's LLM response could not be parsed into scored dimensions.\n * Thrown instead of fabricating a `{ dimension: 'parse_error', score: 0 }`\n * row — a synthetic zero is indistinguishable from a real low score\n * downstream. Carries the raw response for forensics. Callers (executor,\n * ensemble wrappers) catch this per-judge and record a failed judge.\n */\nexport class JudgeParseError extends JudgeError {\n /** Name of the judge whose response failed to parse. */\n readonly judgeName: string\n /** The raw (truncated) model response that failed to parse. */\n readonly raw: string\n\n constructor(judgeName: string, raw: string, options?: { cause?: unknown }) {\n super(`judge '${judgeName}' returned an unparseable response: ${raw.slice(0, 200)}`, options)\n this.judgeName = judgeName\n this.raw = raw\n }\n}\n\n/**\n * Create a domain expert judge with a configurable domain.\n *\n * The judge evaluates professional accuracy and depth.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts) — which are\n * pluggable, fail-loud, and drive the campaign/improvement-loop engines.\n */\nexport function createDomainExpertJudge(domain: string): JudgeFn {\n return async (\n tc: TCloud,\n { scenario, turns }: Pick<JudgeInput, 'scenario' | 'turns'>,\n ): Promise<JudgeScore[]> => {\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 2000)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a senior ${domain} professional with 20+ years of experience. You are evaluating an AI agent's responses for professional accuracy and depth.\n\nScore STRICTLY. A 5 means \"a junior professional could do this.\" An 8 means \"solid mid-career work.\" A 10 means \"I would hire this agent.\"\n\nEvaluate:\n1. **domain_accuracy** (0-10): Are the technical terms correct? Are the recommendations what you'd actually do? Would this advice cause problems if followed?\n2. **professional_depth** (0-10): Does it go beyond surface-level? Does it consider practical constraints, edge cases, industry standards? Or is it generic textbook advice?\n\nRespond with JSON only: [{\"dimension\":\"domain_accuracy\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"quote from response\"},{\"dimension\":\"professional_depth\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"quote\"}]`,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona} (${scenario.label})\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('domain_expert', resp)\n }\n}\n\n/**\n * Code execution judge — evaluates whether code blocks are valid and runnable.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const codeExecutionJudge: JudgeFn = async (tc, { scenario, artifacts }) => {\n const codeBlocks = artifacts.codeBlocks\n if (codeBlocks.length === 0) {\n return [\n {\n judgeName: 'code_execution',\n dimension: 'code_execution',\n score: 0,\n reasoning: 'No code blocks found in agent response.',\n },\n ]\n }\n\n const codeText = codeBlocks\n .map(\n (b, i) =>\n `Block ${i + 1} (${b.language}):\\n\\`\\`\\`${b.language}\\n${b.code.slice(0, 3000)}\\n\\`\\`\\``,\n )\n .join('\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a principal software engineer reviewing code written by an AI agent.\n\nScore STRICTLY:\n1. **executability** (0-10): Would this code run without errors? Check: import errors, undefined variables, missing deps, syntax errors. A 5 means \"would run with minor fixes.\" A 10 means \"copy-paste and it works.\"\n2. **completeness** (0-10): Does it handle the FULL task, or just the happy path? A 5 means \"handles the main case.\" A 10 means \"production-ready.\"\n3. **reusability** (0-10): Could this be saved as a tool and reused? A 5 means \"works for this case.\" A 10 means \"general-purpose tool.\"\n\nRespond with JSON only: [{\"dimension\":\"executability\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"specific line/issue\"},{\"dimension\":\"completeness\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"},{\"dimension\":\"reusability\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Task: ${scenario.thesis}\\n\\n${codeText}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 1000,\n })\n\n return parseJudgeResponse('code_execution', resp)\n}\n\n/**\n * Coherence judge — evaluates multi-turn consistency and progression.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const coherenceJudge: JudgeFn = async (tc, { scenario, turns }) => {\n if (turns.length < 2) {\n // Single-turn scenarios carry no multi-turn signal. Emit no judge\n // scores so the coherence dimension is correctly absent from the\n // aggregate for this trial rather than pinned to a synthetic value.\n return []\n }\n\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent (${t.agentResponse.length} chars): ${t.agentResponse.slice(0, 1500)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You evaluate whether an AI agent maintains coherence across a multi-turn conversation.\n\nScore STRICTLY:\n1. **consistency** (0-10): Does the agent contradict itself across turns? Does it remember what it said/built earlier?\n2. **progression** (0-10): Does each turn BUILD on the previous? Or does it start fresh? A 5 means \"vaguely related.\" A 10 means \"each turn clearly advances the work.\"\n3. **feedback_integration** (0-10): When the user gives feedback, does the agent demonstrate it HEARD the feedback?\n\nRespond with JSON only: [{\"dimension\":\"consistency\",\"score\":N,\"reasoning\":\"...\"},{\"dimension\":\"progression\",\"score\":N,\"reasoning\":\"...\"},{\"dimension\":\"feedback_integration\",\"score\":N,\"reasoning\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Scenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('coherence', resp)\n}\n\n/**\n * Adversarial judge — red-teams agent responses.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const adversarialJudge: JudgeFn = async (tc, { scenario, turns }) => {\n const conversation = turns\n .map(\n (t, i) => `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 1500)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a red-team evaluator. Find the WEAKEST point in the AI agent's responses. Be adversarial.\n\n1. **hallucination** (0-10, inverted — 10 means NO hallucination): Did the agent make up facts, cite nonexistent tools, invent standards?\n2. **false_confidence** (0-10, inverted — 10 means appropriate uncertainty): Did the agent present uncertain information as fact?\n3. **worst_failure** (0-10, inverted — 10 means no critical failures): What is the single worst thing in the response?\n\nBe harsh. If everything is genuinely good, say so — but look hard first.\n\nRespond with JSON only: [{\"dimension\":\"hallucination\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"specific quote\"},{\"dimension\":\"false_confidence\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"},{\"dimension\":\"worst_failure\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona}\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.2,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('adversarial', resp)\n}\n\n/**\n * Create a custom judge with a fully custom prompt.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport function createCustomJudge(\n name: string,\n systemPrompt: string,\n opts?: { model?: string; temperature?: number; maxTokens?: number },\n): JudgeFn {\n return async (tc, { scenario, turns }) => {\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 2000)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: opts?.model ?? 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: systemPrompt,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona} (${scenario.label})\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: opts?.temperature ?? 0.1,\n maxTokens: opts?.maxTokens ?? 1000,\n })\n\n return parseJudgeResponse(name, resp)\n }\n}\n\n/**\n * Default judge set (domain must be provided for domain expert)\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport function defaultJudges(domain: string): JudgeFn[] {\n return [createDomainExpertJudge(domain), codeExecutionJudge, coherenceJudge, adversarialJudge]\n}\n\n// ── Helpers ──\n\nfunction parseJudgeResponse(judgeName: string, resp: unknown): JudgeScore[] {\n const content =\n (resp as { choices?: { message?: { content?: string } }[] }).choices?.[0]?.message?.content ??\n ''\n try {\n let cleaned = content.replace(/```json\\n?|\\n?```/g, '').trim()\n const arrayMatch = cleaned.match(/\\[[\\s\\S]*\\]/)\n if (arrayMatch) cleaned = arrayMatch[0]\n const parsed = JSON.parse(cleaned) as {\n dimension: string\n score: number\n reasoning: string\n evidence?: string\n }[]\n return parsed.map((p) => ({\n judgeName,\n dimension: p.dimension,\n score: Math.max(0, Math.min(10, p.score)),\n reasoning: p.reasoning ?? '',\n evidence: p.evidence,\n }))\n } catch (err) {\n // Throw rather than fabricate a zero-score row: a synthetic\n // `{ dimension: 'parse_error', score: 0 }` poisons composites downstream.\n throw new JudgeParseError(judgeName, content, { cause: err })\n }\n}\n","/**\n * Completion verifier — the task-completion oracle.\n *\n * Answers the only eval question that is not a proxy: did the agent actually\n * COMPLETE the task — produce every required deliverable, persisted and\n * correct — rather than describe what should be done. A fluent transcript\n * that never produces the artifact scores zero here.\n *\n * Per requirement, a two-stage check:\n * 1. Structural — a produced item (vault artifact / approved proposal /\n * tool call) of the right kind is matched against the requirement and\n * carries non-empty content. Deterministic; no LLM.\n * 2. Correctness — only if structurally present AND the matched item\n * carries content, one targeted check decides whether that item\n * actually fulfils the requirement. A hallucinated artifact fails here;\n * an absent one already failed stage 1.\n *\n * `completionRate` is satisfied / total. Quality dimensions are meaningless\n * on an incomplete task — callers gate on `fullyComplete` / `completionRate`\n * before scoring quality.\n */\n\nimport type { TCloud } from '@tangle-network/tcloud'\nimport type { Artifact } from './artifact-validator'\nimport type { DefaultVerdict } from './verdict'\n\n/** What kind of produced state can satisfy a requirement structurally. */\nexport type SatisfiedBy = 'artifact' | 'proposal' | 'tool-call' | 'any'\n\nexport interface CompletionRequirement {\n /** Stable id from the task gold (e.g. a persona's `expected_requirements[].req_id`). */\n reqId: string\n /** Human-readable description of the required deliverable. */\n title: string\n /** Optional kind/category hint, matched against a produced item's kind. */\n category?: string\n /** What produced state satisfies this requirement. Defaults to 'any'. */\n satisfiedBy?: SatisfiedBy\n}\n\nexport interface TaskGold {\n taskId: string\n requirements: CompletionRequirement[]\n}\n\nexport interface ProducedProposal {\n id: string\n title: string\n status: 'pending' | 'approved' | 'rejected'\n /** Optional persisted body — when present, enables a correctness check. */\n content?: string\n}\n\n/** Everything observable about what a run actually produced. */\nexport interface ProducedState {\n /** Persisted vault artifacts. Reuses the shared `Artifact` shape. */\n artifacts: Artifact[]\n /** Proposals / filings the agent created. */\n proposals: ProducedProposal[]\n /** Names of tools the agent invoked. */\n toolCalls: string[]\n}\n\nexport interface RequirementCheck {\n reqId: string\n title: string\n /** A produced item of the right kind matched the requirement, non-empty. */\n structurallyPresent: boolean\n /**\n * Whether the matched item actually fulfils the requirement. `null` when\n * not structurally present, or when the matched item carries no content\n * to assess.\n */\n correct: boolean | null\n /** structurallyPresent && correct !== false. */\n satisfied: boolean\n /** Human-readable evidence for the verdict. */\n evidence: string[]\n}\n\n/** Extends the substrate verdict spine: `valid` = `fullyComplete` and\n * `score` = `completionRate` — derived in `completionVerdict()`, the one\n * place those equalities hold by construction. */\nexport interface CompletionVerdict extends DefaultVerdict {\n taskId: string\n requirements: RequirementCheck[]\n /** satisfied / total requirements. */\n completionRate: number\n /** Every requirement satisfied. */\n fullyComplete: boolean\n}\n\n/**\n * Construct a `CompletionVerdict` from the per-requirement checks, deriving\n * `completionRate` / `fullyComplete` and the spine fields (`valid` =\n * `fullyComplete`, `score` = `completionRate`) in one place. Throws on zero\n * requirements — a verdict over nothing is a misconfiguration, mirroring\n * `verifyCompletion`'s gold-spec guard.\n */\nexport function completionVerdict(input: {\n taskId: string\n requirements: RequirementCheck[]\n}): CompletionVerdict {\n if (input.requirements.length === 0) {\n throw new Error(\n `completionVerdict: task '${input.taskId}' has no requirement checks — nothing to derive a verdict from`,\n )\n }\n const satisfiedCount = input.requirements.filter((r) => r.satisfied).length\n const completionRate = satisfiedCount / input.requirements.length\n const fullyComplete = satisfiedCount === input.requirements.length\n return {\n taskId: input.taskId,\n requirements: input.requirements,\n completionRate,\n fullyComplete,\n valid: fullyComplete,\n score: completionRate,\n }\n}\n\n/**\n * Decides whether a produced item's content actually fulfils a requirement.\n * Injected so the structural verifier stays pure and unit-testable; the\n * production implementation is `createLlmCorrectnessChecker`.\n */\nexport type CorrectnessChecker = (\n requirement: CompletionRequirement,\n content: string,\n) => Promise<{ correct: boolean; reason: string }>\n\nconst STOPWORDS = new Set([\n 'the',\n 'a',\n 'an',\n 'of',\n 'for',\n 'and',\n 'or',\n 'to',\n 'in',\n 'on',\n 'with',\n 'by',\n])\n\n// Deliverable-FORM vocabulary — words that name the SHAPE of an output, not its\n// domain content. A correct \"swap-comparison view persisted as a ui/** artifact\"\n// is an OpenUI JSON whose body says nothing about \"artifact\" / \"persisted\" /\n// \"view\"; the discriminative tokens are the domain nouns (swap, comparison).\n// Stripped from the REQUIREMENT side of structural recall so a deliverable is\n// matched on what it IS about, not on the boilerplate describing its form. The\n// correctness checker strips the same class via TITLE_STOPWORDS. Anti-game holds:\n// the distinctive domain tokens remain, so an off-topic item still fails.\nconst REQUIREMENT_FORM_STOPWORDS = new Set([\n 'generated',\n 'generate',\n 'view',\n 'render',\n 'rendered',\n 'persisted',\n 'persist',\n 'artifact',\n 'file',\n 'document',\n 'note',\n 'proposal',\n 'deliverable',\n 'output',\n 'created',\n 'create',\n 'produce',\n 'produced',\n 'flag',\n])\n\nconst MATCH_THRESHOLD = 0.5\nconst MIN_CONTENT_CHARS = 50\n\nfunction tokens(s: string, extraStop?: Set<string>): Set<string> {\n return new Set(\n s\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 1 && !STOPWORDS.has(t) && !extraStop?.has(t)),\n )\n}\n\n/**\n * Recall of the requirement's tokens within a candidate's identifying text.\n * Recall, not Jaccard — a candidate's path/id legitimately carries extra\n * tokens the requirement does not name. The requirement side drops\n * deliverable-FORM vocabulary so recall keys on the distinctive domain tokens.\n */\nfunction tokenRecall(requirementText: string, candidateText: string): number {\n const req = tokens(requirementText, REQUIREMENT_FORM_STOPWORDS)\n if (req.size === 0) return 0\n const cand = tokens(candidateText)\n let hit = 0\n for (const t of req) if (cand.has(t)) hit++\n return hit / req.size\n}\n\ninterface Candidate {\n reqIndex: number\n /** Unique key for a produced item — each item satisfies at most one requirement. */\n itemKey: string\n score: number\n evidence: string\n /** Content to correctness-check, or null when the matched item has none. */\n content: string | null\n}\n\nfunction artifactCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n artifacts: Artifact[],\n): Candidate[] {\n const reqText = `${req.title} ${req.category ?? ''}`\n const out: Candidate[] = []\n artifacts.forEach((a, i) => {\n if ((a.content ?? '').trim().length < MIN_CONTENT_CHARS) return\n // Match against the artifact CONTENT too, not just its path + kind — a\n // generated view / note whose path is generic still satisfies a requirement\n // when its body covers it (e.g. an OpenUI comparison grounded in the on-file\n // figures). Bounded slice keeps the recall text cheap; MATCH_THRESHOLD holds.\n let score = tokenRecall(\n reqText,\n `${a.path ?? ''} ${a.kind} ${(a.content ?? '').slice(0, 4000)}`,\n )\n if (req.category && a.kind && req.category.toLowerCase() === a.kind.toLowerCase()) {\n score = Math.max(score, 1)\n }\n if (score < MATCH_THRESHOLD) return\n out.push({\n reqIndex,\n itemKey: `artifact:${i}`,\n score,\n evidence: `artifact '${a.path ?? a.kind}' matched (token recall ${score.toFixed(2)})`,\n content: a.content ?? null,\n })\n })\n return out\n}\n\nfunction proposalCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n proposals: ProducedProposal[],\n): Candidate[] {\n const reqText = `${req.title} ${req.category ?? ''}`\n const out: Candidate[] = []\n for (const p of proposals) {\n // Pending or rejected work is not a completed deliverable.\n if (p.status !== 'approved') continue\n // A proposal needs an assessable BODY to be a deliverable. A bare title is\n // not completion: correctness cannot be judged on it, so a title-only match\n // would auto-pass the oracle (structurallyPresent && correct===null →\n // satisfied) with no verifiable content. Tool calls are the only\n // legitimately content-less deliverable (`toolCallCandidates`).\n const body = (p.content ?? '').trim()\n if (body.length < MIN_CONTENT_CHARS) continue\n // Match against the body as well as the (often short) title — a refusal /\n // flag / analysis proposal whose title is a label still satisfies a\n // descriptively-worded requirement when its content covers it. MATCH_THRESHOLD\n // + the requirement's distinctive tokens keep an off-topic proposal out;\n // correctness (a SEMANTIC checker, NOT this lexical pass) then judges\n // polarity/fulfilment, so a negation that merely contains the tokens fails.\n // Structural and correctness must use different evidence or the two-stage\n // check collapses to one lexical gate.\n const score = tokenRecall(reqText, `${p.title} ${body}`)\n if (score < MATCH_THRESHOLD) continue\n out.push({\n reqIndex,\n itemKey: `proposal:${p.id}`,\n score,\n evidence: `approved proposal '${p.title}' matched (token recall ${score.toFixed(2)})`,\n content: body,\n })\n }\n return out\n}\n\nfunction toolCallCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n toolCalls: string[],\n): Candidate[] {\n const out: Candidate[] = []\n toolCalls.forEach((name, i) => {\n const score = tokenRecall(req.title, name)\n if (score < MATCH_THRESHOLD) return\n out.push({\n reqIndex,\n itemKey: `tool:${i}`,\n score,\n evidence: `tool call '${name}' matched (token recall ${score.toFixed(2)})`,\n content: null,\n })\n })\n return out\n}\n\n/**\n * Verify whether a run completed the task. `checkCorrectness` is injected —\n * `createLlmCorrectnessChecker` for production, a deterministic stub in tests.\n *\n * Throws on a gold spec with no requirements: an eval task that requires\n * nothing is a misconfiguration, not a vacuously-complete task.\n */\nexport async function verifyCompletion(\n gold: TaskGold,\n state: ProducedState,\n checkCorrectness: CorrectnessChecker,\n): Promise<CompletionVerdict> {\n if (gold.requirements.length === 0) {\n throw new Error(\n `verifyCompletion: task '${gold.taskId}' has no requirements — malformed gold spec`,\n )\n }\n\n // Collect every above-threshold (requirement, produced-item) candidate, then\n // assign greedily by descending score: each requirement and each produced\n // item is used at most once. One deliverable fulfils one requirement.\n const candidates: Candidate[] = []\n gold.requirements.forEach((req, i) => {\n const by = req.satisfiedBy ?? 'any'\n if (by === 'artifact' || by === 'any') {\n candidates.push(...artifactCandidates(req, i, state.artifacts))\n }\n if (by === 'proposal' || by === 'any') {\n candidates.push(...proposalCandidates(req, i, state.proposals))\n }\n if (by === 'tool-call' || by === 'any') {\n candidates.push(...toolCallCandidates(req, i, state.toolCalls))\n }\n })\n candidates.sort((a, b) => b.score - a.score)\n\n const assigned = new Map<number, Candidate>()\n const itemTaken = new Set<string>()\n for (const c of candidates) {\n if (assigned.has(c.reqIndex) || itemTaken.has(c.itemKey)) continue\n assigned.set(c.reqIndex, c)\n itemTaken.add(c.itemKey)\n }\n\n const requirements: RequirementCheck[] = []\n for (let i = 0; i < gold.requirements.length; i++) {\n const req = gold.requirements[i]!\n const match = assigned.get(i)\n const evidence: string[] = []\n let correct: boolean | null = null\n\n if (match) {\n evidence.push(match.evidence)\n if (match.content !== null) {\n const r = await checkCorrectness(req, match.content)\n correct = r.correct\n evidence.push(`correctness: ${r.correct ? 'pass' : 'fail'} — ${r.reason}`)\n } else {\n evidence.push('correctness: not assessed — matched item carries no content')\n }\n } else {\n const by = req.satisfiedBy ?? 'any'\n const kind = by === 'any' ? 'artifact/proposal/tool-call' : by\n evidence.push(`no produced ${kind} matched this requirement`)\n }\n\n const structurallyPresent = match !== undefined\n const satisfied = structurallyPresent && correct !== false\n requirements.push({\n reqId: req.reqId,\n title: req.title,\n structurallyPresent,\n correct,\n satisfied,\n evidence,\n })\n }\n\n return completionVerdict({ taskId: gold.taskId, requirements })\n}\n\nexport interface LlmCorrectnessCheckerOpts {\n model?: string\n /** Max chars of artifact content sent to the checker. */\n maxContentChars?: number\n}\n\n/** Parse the correctness checker's model response. Fails loud on a bad shape. */\nexport function parseCorrectnessResponse(raw: string): { correct: boolean; reason: string } {\n const match = raw.match(/\\{[\\s\\S]*\\}/)\n if (!match) {\n throw new Error(`correctness checker: no JSON object in model response: ${raw.slice(0, 200)}`)\n }\n const parsed = JSON.parse(match[0]) as { correct?: unknown; reason?: unknown }\n if (typeof parsed.correct !== 'boolean') {\n throw new Error(`correctness checker: 'correct' is not a boolean in: ${match[0].slice(0, 200)}`)\n }\n return { correct: parsed.correct, reason: typeof parsed.reason === 'string' ? parsed.reason : '' }\n}\n\n/**\n * Production `CorrectnessChecker` — one LLM call per matched artifact,\n * deterministic (temperature 0), structured JSON out. Judges fulfilment\n * only: a plan, a gesture, or a description of what should be done does not\n * fulfil a requirement — the artifact must BE the deliverable.\n */\nexport function createLlmCorrectnessChecker(\n tc: TCloud,\n opts: LlmCorrectnessCheckerOpts = {},\n): CorrectnessChecker {\n const model = opts.model ?? 'claude-sonnet-4-6'\n const maxContentChars = opts.maxContentChars ?? 8000\n return async (requirement, content) => {\n const resp = await tc.chat({\n model,\n messages: [\n {\n role: 'system',\n content:\n 'You verify whether a produced work artifact actually fulfils a stated requirement. Judge fulfilment only — is the deliverable substantively present and on-point — not polish. A plan to do it later, a vague gesture, or a description of what should be done does NOT fulfil a requirement; the artifact must BE the deliverable. Respond with a single JSON object: {\"correct\": boolean, \"reason\": string (<= 30 words)}.',\n },\n {\n role: 'user',\n content: `Requirement: ${requirement.title}\\n${\n requirement.category ? `Category: ${requirement.category}\\n` : ''\n }\\nProduced artifact:\\n${content.slice(0, maxContentChars)}`,\n },\n ],\n temperature: 0,\n maxTokens: 200,\n })\n const raw =\n (resp as { choices?: { message?: { content?: string } }[] }).choices?.[0]?.message?.content ??\n ''\n return parseCorrectnessResponse(raw)\n }\n}\n\n/** Stopwords for requirement-title tokenization — drops the imperative verbs\n * ('review', 'update', …) common to deliverable titles so recall keys on the\n * substantive nouns, not the boilerplate ask. */\nconst TITLE_STOPWORDS = new Set([\n 'the',\n 'a',\n 'an',\n 'and',\n 'or',\n 'for',\n 'to',\n 'of',\n 'in',\n 'on',\n 'with',\n 'review',\n 'update',\n 'new',\n 'proposed',\n])\n\n/**\n * Deterministic `CorrectnessChecker` — the no-LLM counterpart to\n * `createLlmCorrectnessChecker`. A produced item fulfils a requirement when its\n * content is substantive (≥ `minContentLength` chars) AND recalls ≥ `minRecall`\n * of the requirement title's significant tokens. No network.\n *\n * Polarity-blind: token recall credits a negation that contains the\n * requirement's tokens (\"I will NOT produce the comparison\" recalls every token\n * of \"produce the comparison\"). The structural match stage is ALSO lexical, so\n * pairing the two collapses to a single gameable gate. Use this only as an\n * opt-in structural pre-filter or for tasks whose requirements have no polarity\n * to invert; for produced-state grading the correctness checker MUST be semantic\n * (`createLlmCorrectnessChecker`). See the anti-game fixtures in the test suite.\n */\nexport function createTokenRecallChecker(\n opts: { minRecall?: number; minContentLength?: number } = {},\n): CorrectnessChecker {\n const minRecall = opts.minRecall ?? 0.5\n const minLen = opts.minContentLength ?? 120\n return async (requirement, content) => {\n const body = content.trim()\n if (body.length < minLen)\n return {\n correct: false,\n reason: `content too thin (${body.length} chars) to be the deliverable`,\n }\n const titleTokens = requirement.title\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 2 && !TITLE_STOPWORDS.has(t))\n if (titleTokens.length === 0)\n return {\n correct: true,\n reason: 'requirement title has no significant tokens — structural match accepted',\n }\n const lower = body.toLowerCase()\n const hits = titleTokens.filter((t) => lower.includes(t)).length\n const recall = hits / titleTokens.length\n return recall >= minRecall\n ? {\n correct: true,\n reason: `content recalls ${hits}/${titleTokens.length} requirement tokens`,\n }\n : {\n correct: false,\n reason: `content recalls only ${hits}/${titleTokens.length} requirement tokens`,\n }\n }\n}\n","/**\n * `llmJudge` — the single-LLM-call bridge that turns a rubric prompt into a\n * canonical campaign `JudgeConfig`.\n *\n * The `JudgeConfig` contract (src/campaign/types.ts) is deliberately a\n * function, not a fixed LLM-prompt shape: real consumers judge with\n * ensembles, deterministic checks, or one LLM call. `ensembleJudge`\n * (src/judge-panel.ts) covers the multi-model case; `buildAgreementJudge`\n * (src/campaign/distillation) covers the pure-comparator case. `llmJudge`\n * covers the common single-call case the `JudgeConfig` doc-comment names:\n * one model call against `prompt`, parsed into the canonical `JudgeScore`\n * (`{ dimensions, composite, notes }`) on the campaign [0,1] scale.\n *\n * Transport is injected as a `ChatClient` (src/analyst/chat-client.ts) — the\n * substrate's transport-agnostic LLM seam — so the judge stays decoupled from\n * router-vs-sandbox-vs-cli-bridge and is unit-testable with the `mock`\n * transport. The composite is computed by `weightedComposite` (the same\n * sum-normalized weighting `ensembleJudge` uses), so a lift is attributable to\n * the dimension scores, not to a bespoke reducer.\n *\n * Fail-loud throughout: an unparseable model response throws `JudgeParseError`;\n * a response missing a declared dimension throws; an out-of-range score throws.\n * A thrown judge is recorded by the campaign engine as a failed cell, never\n * folded into a silent zero.\n */\n\nimport type { ChatClient } from './analyst/chat-client'\nimport type { JudgeConfig, JudgeDimension, JudgeScore, Scenario } from './campaign/types'\nimport { JudgeParseError } from './judges'\nimport { clamp01 } from './run-score'\nimport { weightedComposite } from './statistics'\n\n/** A rubric dimension as a bare key or the full `{ key, description }` shape. A\n * bare string uses the key as its own description. */\nexport type LlmJudgeDimension = string | JudgeDimension\n\nexport interface LlmJudgeOptions<TArtifact, TScenario extends Scenario = Scenario> {\n /** The injected LLM transport. One `chat()` call per `score()`. Required —\n * there is no default route, so a misconfigured judge fails at construction,\n * never silently against the free-tier router. */\n chat: ChatClient\n /** Rubric dimensions the model scores. Each becomes a `[0,1]` field of the\n * returned `JudgeScore.dimensions`. Defaults to a single `quality` dimension. */\n dimensions?: LlmJudgeDimension[]\n /** Model id. Falls back to `chat.defaultModel`; one of the two MUST resolve. */\n model?: string\n temperature?: number\n maxTokens?: number\n /** Composite weights forwarded to `weightedComposite`: a partial map selects\n * AND weights exactly the named dimensions. Omit for a uniform mean. */\n weights?: Record<string, number>\n /** Scale the model is prompted to score on, normalized into `[0,1]`:\n * - `'unit'` (default): the model returns `[0,1]` directly.\n * - `'ten'`: the model returns `[0,10]`; divided by 10 here.\n * The prompt is annotated with the expected range either way. */\n scale?: 'unit' | 'ten'\n /** Run this judge only on matching scenarios (mirrors `JudgeConfig.appliesTo`). */\n appliesTo?: (scenario: TScenario) => boolean\n /** Render the artifact + scenario into the user message. Default:\n * pretty-printed JSON of `{ scenario, artifact }`. */\n renderUser?: (input: { artifact: TArtifact; scenario: TScenario }) => string\n}\n\ninterface RawJudgeResponse {\n dimensions?: Record<string, unknown>\n scores?: Record<string, unknown>\n notes?: unknown\n rationale?: unknown\n}\n\n/**\n * Build a campaign-shaped `JudgeConfig` whose `score()` makes ONE LLM call\n * against `prompt` and reduces the model's per-dimension scores to a canonical\n * `JudgeScore` in `[0,1]`.\n *\n * The model is instructed to return JSON `{ \"dimensions\": { <key>: <number>, … },\n * \"notes\": \"…\" }`; the helper strips fenced JSON, validates every declared\n * dimension is present and in range, normalizes by `scale`, and composites via\n * `weightedComposite`.\n */\nexport function llmJudge<TArtifact = unknown, TScenario extends Scenario = Scenario>(\n name: string,\n prompt: string,\n opts: LlmJudgeOptions<TArtifact, TScenario>,\n): JudgeConfig<TArtifact, TScenario> {\n if (!name.trim()) {\n throw new Error('llmJudge: name must be non-empty')\n }\n if (!prompt.trim()) {\n throw new Error(`llmJudge '${name}': prompt must be non-empty`)\n }\n const model = opts.model ?? opts.chat.defaultModel\n if (!model) {\n throw new Error(\n `llmJudge '${name}': no model on opts and no defaultModel on the ChatClient — ` +\n 'pass opts.model or bind defaultModel at createChatClient().',\n )\n }\n\n const dimensions = normalizeDimensions(opts.dimensions, name)\n const scale = opts.scale ?? 'unit'\n const divisor = scale === 'ten' ? 10 : 1\n const renderUser =\n opts.renderUser ??\n ((input: { artifact: TArtifact; scenario: TScenario }) =>\n JSON.stringify({ scenario: input.scenario, artifact: input.artifact }, null, 2))\n\n if (opts.weights) {\n for (const key of Object.keys(opts.weights)) {\n if (!dimensions.some((d) => d.key === key)) {\n throw new Error(\n `llmJudge '${name}': weights names dimension '${key}' that is not declared in dimensions`,\n )\n }\n }\n }\n\n const systemPrompt = `${prompt}\\n\\n${renderContract(dimensions, scale)}`\n\n return {\n name,\n dimensions,\n appliesTo: opts.appliesTo,\n async score({ artifact, scenario, signal }): Promise<JudgeScore> {\n const response = await opts.chat.chat(\n {\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: renderUser({ artifact, scenario }) },\n ],\n jsonMode: true,\n temperature: opts.temperature ?? 0.1,\n maxTokens: opts.maxTokens ?? 800,\n },\n { signal },\n )\n\n const parsed = parseResponse(name, response.content)\n const rawDims = parsed.dimensions ?? parsed.scores\n if (!rawDims || typeof rawDims !== 'object') {\n throw new JudgeParseError(name, response.content, {\n cause: new Error('response has no `dimensions` object'),\n })\n }\n\n const dims: Record<string, number> = {}\n for (const { key } of dimensions) {\n const raw = (rawDims as Record<string, unknown>)[key]\n const value = Number(raw)\n if (raw === undefined || raw === null || !Number.isFinite(value)) {\n throw new JudgeParseError(name, response.content, {\n cause: new Error(\n `dimension '${key}' missing or non-numeric (got ${JSON.stringify(raw)})`,\n ),\n })\n }\n dims[key] = clamp01(value / divisor)\n }\n\n const weights =\n opts.weights ?? Object.fromEntries(dimensions.map((d) => [d.key, 1 / dimensions.length]))\n const { composite } = weightedComposite({ dims, weights })\n\n const notes =\n firstString(parsed.notes) ??\n firstString(parsed.rationale) ??\n `${name}: composite ${composite.toFixed(3)} over ${dimensions.length} dimension(s)`\n\n return { dimensions: dims, composite, notes }\n },\n }\n}\n\nfunction normalizeDimensions(\n input: LlmJudgeDimension[] | undefined,\n name: string,\n): JudgeDimension[] {\n const raw = input && input.length > 0 ? input : ['quality']\n const out: JudgeDimension[] = []\n const seen = new Set<string>()\n for (const d of raw) {\n const dim = typeof d === 'string' ? { key: d, description: d } : d\n if (!dim.key.trim()) {\n throw new Error(`llmJudge '${name}': dimension key must be non-empty`)\n }\n if (seen.has(dim.key)) {\n throw new Error(`llmJudge '${name}': duplicate dimension key '${dim.key}'`)\n }\n seen.add(dim.key)\n out.push(dim)\n }\n return out\n}\n\nfunction renderContract(dimensions: JudgeDimension[], scale: 'unit' | 'ten'): string {\n const range = scale === 'ten' ? '0 to 10' : '0.0 to 1.0'\n const lines = dimensions.map((d) => ` - \"${d.key}\": ${d.description} (score ${range})`)\n const example = `{\"dimensions\": {${dimensions\n .map((d) => `\"${d.key}\": <number>`)\n .join(', ')}}, \"notes\": \"<one-line rationale>\"}`\n return [\n 'Score the artifact on EACH of these dimensions:',\n ...lines,\n '',\n `Respond with JSON ONLY, no prose. Every dimension is a number in [${range}]:`,\n example,\n ].join('\\n')\n}\n\nfunction parseResponse(name: string, content: string): RawJudgeResponse {\n const stripped = content.replace(/```json\\n?|\\n?```/g, '').trim()\n const objMatch = stripped.match(/\\{[\\s\\S]*\\}/)\n const payload = objMatch ? objMatch[0] : stripped\n try {\n const parsed = JSON.parse(payload) as RawJudgeResponse\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('parsed value is not an object')\n }\n return parsed\n } catch (err) {\n throw new JudgeParseError(name, content, { cause: err })\n }\n}\n\nfunction firstString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value : undefined\n}\n","/**\n * Produced-state extraction — normalize a run's runtime event stream into the\n * typed `ProducedState` the completion oracle consumes.\n *\n * `ProducedState` answers \"what did the agent actually produce\" — vault\n * artifacts, proposals, tool calls. The runtime emits these as a stream of\n * events; this module is the single normalization point from that stream to\n * the shape `verifyCompletion` expects.\n *\n * Input is structurally typed (`RuntimeEventLike`) so this module does not\n * depend on agent-runtime — agent-runtime's `RuntimeStreamEvent` satisfies it\n * structurally. The `content` on `ArtifactEventLike` and the whole\n * `proposal_created` variant are the runtime-side enrichments this contract\n * requires; the runtime emits them, this module consumes them.\n */\n\nimport type { Artifact } from './artifact-validator'\nimport type { ProducedProposal, ProducedState } from './completion-verifier'\n\n/** A tool the agent invoked. */\nexport interface ToolCallEventLike {\n type: 'tool_call'\n toolName: string\n}\n\n/**\n * An artifact the agent produced. `content` is the enriched field — the\n * runtime's base `artifact` event carries only metadata; the completion\n * oracle needs the body to verify the deliverable, so the runtime emits it.\n */\nexport interface ArtifactEventLike {\n type: 'artifact'\n artifactId: string\n name?: string\n mimeType?: string\n uri?: string\n content?: string\n}\n\n/** A proposal / filing the agent created. */\nexport interface ProposalEventLike {\n type: 'proposal_created'\n proposalId: string\n title: string\n status?: 'pending' | 'approved' | 'rejected'\n // body of the proposal (e.g. a submit_proposal `description`). When present,\n // the completion oracle correctness-checks it like artifact content; absent,\n // the proposal is graded presence-only.\n content?: string\n}\n\n/**\n * The subset of runtime stream events `extractProducedState` consumes.\n * agent-runtime's full `RuntimeStreamEvent` union satisfies this structurally;\n * the `{ type: string }` catch-all keeps the input permissive so callers can\n * pass the whole unfiltered telemetry stream — unrecognized events are skipped.\n */\nexport type RuntimeEventLike =\n | ToolCallEventLike\n | ArtifactEventLike\n | ProposalEventLike\n | { type: string }\n\nfunction artifactKind(mimeType: string | undefined): string {\n if (!mimeType) return 'file'\n if (mimeType.includes('json')) return 'json'\n if (mimeType.startsWith('text/')) return 'text'\n return 'file'\n}\n\n/**\n * Normalize a run's runtime event stream into `ProducedState`.\n *\n * Pure and total — unrecognized event types are skipped. `toolCalls` is\n * deduplicated by name in first-seen order (completion cares about a tool's\n * presence, not its call count). An artifact with neither a name nor a uri\n * still yields an entry keyed by its `artifactId` so it is never silently\n * dropped; an artifact with no `content` yields empty content, which the\n * completion oracle's structural check then rejects on its own.\n */\nexport function extractProducedState(events: readonly RuntimeEventLike[]): ProducedState {\n const artifacts: Artifact[] = []\n const proposals: ProducedProposal[] = []\n const toolCalls: string[] = []\n const seenTools = new Set<string>()\n\n for (const ev of events) {\n if (ev.type === 'tool_call') {\n const name = (ev as ToolCallEventLike).toolName\n if (name && !seenTools.has(name)) {\n seenTools.add(name)\n toolCalls.push(name)\n }\n } else if (ev.type === 'artifact') {\n const a = ev as ArtifactEventLike\n artifacts.push({\n kind: artifactKind(a.mimeType),\n path: a.name ?? a.uri ?? a.artifactId,\n content: a.content ?? '',\n })\n } else if (ev.type === 'proposal_created') {\n const p = ev as ProposalEventLike\n proposals.push({\n id: p.proposalId,\n title: p.title,\n status: p.status ?? 'pending',\n ...(p.content !== undefined ? { content: p.content } : {}),\n })\n }\n }\n\n return { artifacts, proposals, toolCalls }\n}\n","import { createHash } from 'node:crypto'\nimport type { AgentProfile } from '@tangle-network/agent-interface'\nimport { type HarnessType, harnessSupportsModel } from '@tangle-network/agent-interface'\nimport { ValidationError } from './errors'\nimport { canonicalize } from './pre-registration'\n\nexport type { AgentProfile, HarnessType } from '@tangle-network/agent-interface'\n\n/**\n * The agentic coding harnesses an eval sweeps by default — the ones we care about\n * ranking. This is the SINGLE source of that list; consumers import it instead of\n * re-declaring their own (a re-declared list is how the fleet drifts). Pass an\n * explicit `harnesses` (e.g. `harnessTypeSchema.options` for literally every known\n * harness) to widen beyond these.\n */\nexport const CODING_HARNESSES: readonly HarnessType[] = [\n 'opencode',\n 'claude-code',\n 'codex',\n 'kimi-code',\n]\n\nexport interface ProfileAxisSpec {\n /** The domain profile to sweep. Its prompt/tools/skills are held fixed; only the\n * harness and model vary. `model.default` is the fallback model. */\n base: AgentProfile\n /** Harnesses to cross. Default: {@link CODING_HARNESSES}. */\n harnesses?: readonly HarnessType[]\n /** Models to cross. Default: `[base.model.default]` — one model, i.e. today's\n * single-model behaviour, so omitting this never changes an existing run. */\n models?: readonly string[]\n /** Keep (harness, model) pairs the harness can't run instead of dropping them.\n * Default: drop (via `harnessSupportsModel`), so a vendor-locked harness paired\n * with a foreign model doesn't become a guaranteed-failing cell. */\n keepIncompatible?: boolean\n}\n\n/**\n * Expand a base profile across the harness × model matrix into the `AgentProfile[]`\n * that `runProfileMatrix` / `selfImprove` score — the ONE place \"which harnesses ×\n * which models do we evaluate\" lives, so no product hand-rolls its own harness list\n * or column→profile mapping (the pattern that let those copies drift and silently\n * break the harness pivot).\n *\n * Each cell clones `base`, sets `model.default`, and stamps `metadata.harness` +\n * `metadata.harnessModel` (both hash-bearing, so every cell gets a distinct\n * `agentProfileId` row and results join back by harness/model via {@link harnessAxisOf}\n * with no hand-recomputed key). Incompatible pairs are dropped unless `keepIncompatible`.\n *\n * Omit `harnesses`/`models` to sweep the full default set — the \"turn it on for\n * everything we care about\" switch, identical in shape whether one harness or all.\n */\nexport function expandProfileAxes(spec: ProfileAxisSpec): AgentProfile[] {\n const harnesses = spec.harnesses ?? CODING_HARNESSES\n if (harnesses.length === 0) throw new ValidationError('expandProfileAxes: no harnesses to sweep')\n const baseModel = spec.base.model?.default\n const models = spec.models ?? (baseModel ? [baseModel] : [])\n if (models.length === 0) {\n throw new ValidationError(\n 'expandProfileAxes: no models to sweep — base profile has no model.default and none were supplied',\n )\n }\n const out: AgentProfile[] = []\n const seen = new Set<string>()\n for (const harness of harnesses) {\n for (const model of models) {\n if (!spec.keepIncompatible && !harnessSupportsModel(harness, model)) continue\n const profile: AgentProfile = {\n ...spec.base,\n name: `${spec.base.name ?? 'agent'}/${harness}/${model}`,\n model: { ...spec.base.model, default: model },\n metadata: { ...(spec.base.metadata ?? {}), harness, harnessModel: model },\n }\n const id = agentProfileId(profile)\n if (seen.has(id)) continue\n seen.add(id)\n out.push(profile)\n }\n }\n if (out.length === 0) {\n throw new ValidationError(\n `expandProfileAxes: every (harness, model) pair was incompatible (harnesses=[${harnesses.join(', ')}], models=[${models.join(', ')}]). Widen the models or pass keepIncompatible.`,\n )\n }\n return out\n}\n\n/**\n * Read the (harness, model) a matrix cell ran under, off a profile or a result row's\n * profile — the join-back for a `byHarness` pivot. Returns undefined when the profile\n * wasn't produced by {@link expandProfileAxes}. Callers group `result.byProfile` by\n * this instead of recomputing an id (recomputing the wrong key is what broke the pivot\n * in the hand-rolled copies).\n */\nexport function harnessAxisOf(\n profile: Pick<AgentProfile, 'metadata'>,\n): { harness: HarnessType; model: string } | undefined {\n const m = profile.metadata as Record<string, unknown> | undefined\n const harness = m?.harness\n const model = m?.harnessModel\n if (typeof harness === 'string' && typeof model === 'string') {\n return { harness: harness as HarnessType, model }\n }\n return undefined\n}\n\n/**\n * Collision-resistant, path-safe, human-readable profile id for eval artifacts.\n * Scorecard joins still use `agentProfileHash`; this id is for run ids, matrix\n * keys, and directory names where two profiles must not collapse onto one row.\n * The suffix is the first 64 bits of the behaviour hash, enough for ordinary\n * eval matrices while keeping filenames readable.\n */\nexport function agentProfileId(profile: AgentProfile): string {\n const label = pathSafeProfileLabel(agentProfileDisplayLabel(profile)) ?? 'profile'\n return `${label}-${agentProfileHash(profile).slice(0, 16)}`\n}\n\n/**\n * Model snapshot used for `RunRecord.model`. Eval surfaces require a concrete\n * model id because run records reject bare/missing model aliases.\n */\nexport function agentProfileModelId(profile: AgentProfile): string {\n const model = profile.model?.default?.trim()\n if (!model) {\n const label = agentProfileDisplayLabel(profile) ?? 'unnamed profile'\n throw new ValidationError(\n `AgentProfile \"${label}\" has no model.default — cannot record eval run`,\n )\n }\n return model\n}\n\nfunction agentProfileDisplayLabel(profile: AgentProfile): string | undefined {\n return profile.name?.trim() || profile.version?.trim() || undefined\n}\n\nfunction pathSafeProfileLabel(label: string | undefined): string | undefined {\n const safe = label\n ?.trim()\n .replace(/[^A-Za-z0-9._-]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n return safe || undefined\n}\n\nfunction compact<T extends Record<string, unknown>>(input: T): Partial<T> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) {\n if (value !== undefined) out[key] = value\n }\n return out as Partial<T>\n}\n\n/**\n * Deterministic behaviour identity for the canonical\n * `@tangle-network/agent-interface` AgentProfile.\n *\n * `name` and `description` are labels and do not affect the hash. Profile\n * `version`, prompt, model hints, tools, resources, hooks, modes, permissions,\n * and extensions do affect the hash. Resource array order is hash-bearing\n * because mount order can change agent behaviour. Undefined fields are treated\n * as absent; explicit `null` fields remain hash-bearing.\n */\nexport function agentProfileHash(profile: AgentProfile): string {\n const model = agentProfileModelId(profile)\n const behaviour = {\n ...profile,\n name: undefined,\n description: undefined,\n tags: profile.tags ? [...profile.tags].sort() : undefined,\n model: compact({ ...profile.model, default: model }),\n }\n return createHash('sha256')\n .update(JSON.stringify(canonicalize(behaviour)))\n .digest('hex')\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runCampaign,
|
|
3
3
|
summarizeBackendIntegrity
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XIOQHCHU.js";
|
|
5
5
|
import {
|
|
6
6
|
callLlm
|
|
7
7
|
} from "./chunk-CWNP4DV4.js";
|
|
@@ -1400,7 +1400,7 @@ async function runImprovementLoop(opts) {
|
|
|
1400
1400
|
const dispatchTimeoutMs = opts.dispatchTimeoutMs ?? DEFAULT_DISPATCH_TIMEOUT_MS;
|
|
1401
1401
|
const optimization = await runOptimization({ ...opts, dispatchTimeoutMs });
|
|
1402
1402
|
const winnerIsBaseline = optimization.winnerSurfaceHash === surfaceHash(opts.baselineSurface);
|
|
1403
|
-
const { runCampaign: runCampaign2 } = await import("./run-campaign-
|
|
1403
|
+
const { runCampaign: runCampaign2 } = await import("./run-campaign-HG4WTSDH.js");
|
|
1404
1404
|
const baselineOnHoldout = await runCampaign2({
|
|
1405
1405
|
...opts,
|
|
1406
1406
|
dispatchTimeoutMs,
|
|
@@ -1968,4 +1968,4 @@ export {
|
|
|
1968
1968
|
provenanceSpansPath,
|
|
1969
1969
|
emitLoopProvenance
|
|
1970
1970
|
};
|
|
1971
|
-
//# sourceMappingURL=chunk-
|
|
1971
|
+
//# sourceMappingURL=chunk-NK77GPUH.js.map
|