@tangle-network/agent-eval 0.196.0 → 0.197.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 +18 -0
- package/dist/adapters/http.d.ts +1 -1
- package/dist/analyst/index.d.ts +1 -1
- package/dist/analyst/index.js +1 -1
- package/dist/{benchmark-command-Bw1he2JM.js → benchmark-command-DB7pxlks.js} +2 -2
- package/dist/{benchmark-command-Bw1he2JM.js.map → benchmark-command-DB7pxlks.js.map} +1 -1
- package/dist/benchmarks/index.d.ts +1 -1
- package/dist/benchmarks/index.js +2 -2
- package/dist/campaign/index.d.ts +2 -2
- package/dist/campaign/index.js +4 -4
- package/dist/{campaign-qe1WC3Sz.js → campaign-BUFSOI36.js} +4 -4
- package/dist/{campaign-qe1WC3Sz.js.map → campaign-BUFSOI36.js.map} +1 -1
- package/dist/cli.js +1 -1
- package/dist/contract/index.d.ts +3 -3
- package/dist/contract/index.js +3 -3
- package/dist/{define-agent-eval-h2qYe0xY.js → define-agent-eval-4J02MdF7.js} +2 -2
- package/dist/{define-agent-eval-h2qYe0xY.js.map → define-agent-eval-4J02MdF7.js.map} +1 -1
- package/dist/{define-agent-eval-DwAaPvvH.d.ts → define-agent-eval-ulRlLvse.d.ts} +2 -2
- package/dist/{define-agent-eval-DwAaPvvH.d.ts.map → define-agent-eval-ulRlLvse.d.ts.map} +1 -1
- package/dist/{index-CpCIXObe.d.ts → index-CRsmcAGl.d.ts} +3 -3
- package/dist/{index-CpCIXObe.d.ts.map → index-CRsmcAGl.d.ts.map} +1 -1
- package/dist/{index-CigojbNH.d.ts → index-DJKZEldg.d.ts} +32 -4
- package/dist/index-DJKZEldg.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/jev-protocol.d.ts +17 -9
- package/dist/jev-protocol.d.ts.map +1 -1
- package/dist/jev-protocol.js +22 -14
- package/dist/jev-protocol.js.map +1 -1
- package/dist/jev.d.ts +2 -2
- package/dist/jev.js +3 -7
- package/dist/jev.js.map +1 -1
- package/dist/{llm-judge-CxfoYqdk.js → llm-judge-fhkFQL1N.js} +138 -122
- package/dist/llm-judge-fhkFQL1N.js.map +1 -0
- package/dist/openapi.json +1 -1
- package/dist/{produced-state-B0QMdiLh.js → produced-state-1RnbLrSa.js} +2 -2
- package/dist/{produced-state-B0QMdiLh.js.map → produced-state-1RnbLrSa.js.map} +1 -1
- package/dist/{skillopt-optimization-method-IbEhlA1V.js → skillopt-optimization-method-CHUcZ8w6.js} +40 -28
- package/dist/{skillopt-optimization-method-IbEhlA1V.js.map → skillopt-optimization-method-CHUcZ8w6.js.map} +1 -1
- package/docs/jev.md +3 -2
- package/docs/search-ledger.md +2 -0
- package/package.json +1 -1
- package/dist/index-CigojbNH.d.ts.map +0 -1
- package/dist/llm-judge-CxfoYqdk.js.map +0 -1
package/dist/jev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jev.js","names":[],"sources":["../src/jev-review.ts","../src/jev.ts"],"sourcesContent":["import { z } from 'zod'\nimport {\n ANALYST_SEVERITIES,\n type AnalystFinding,\n type EvidenceRef,\n makeFinding,\n} from './analyst/types'\nimport type { JevQuestions, JevRequest, JevResult } from './jev-protocol'\nimport { parseJevRequest, parseJevResult } from './jev-protocol'\nimport { canonicalString, hashCanonical, jsonDocument } from './ledger-core/canonical'\nimport { deepFreezeCanonicalJson } from './ledger-core/deep-freeze'\n\nconst name = z.string().trim().min(1)\nconst probability = z.number().finite().gt(0).max(1)\nconst checkSchema = z\n .object({\n claim: name,\n area: name,\n subject: name,\n severity: z.enum(ANALYST_SEVERITIES),\n /** Choice labels or score-level keys, never scores invented from category order. */\n supports: z.array(z.string()).min(1),\n refutes: z.array(z.string()).min(1),\n supportAtLeast: probability,\n refuteAtLeast: probability,\n /** Host-supplied coverage of the question's required evidence, not model self-assessment. */\n coverage: z.enum(['complete', 'partial', 'missing']),\n evidence: z.array(\n z\n .object({\n kind: z.enum(['span', 'event', 'artifact', 'finding', 'metric']),\n uri: name,\n excerpt: z.string().optional(),\n })\n .strict(),\n ),\n })\n .strict()\n .refine((value) => value.supportAtLeast + value.refuteAtLeast > 1, {\n message: 'Support and refutation thresholds must not overlap',\n })\n\n/** Optional interpretation of native choices/scores. Policy and evidence belong to the caller. */\nexport type JevReviewCheck = z.infer<typeof checkSchema>\nexport interface JevReviewInput<Q extends JevQuestions = JevQuestions> {\n version: string\n request: JevRequest<Q>\n checks: { [K in keyof Q]: JevReviewCheck }\n}\n\nexport interface PreparedJevReview<Q extends JevQuestions = JevQuestions>\n extends JevReviewInput<Q> {\n /** Binds questions, option order, context, evidence, thresholds and definition version. */\n digest: string\n}\n\nexport interface JevReviewAssessment {\n question: string\n status: 'supported' | 'refuted' | 'unresolved'\n reason:\n | 'support-threshold'\n | 'refutation-threshold'\n | 'missing-evidence'\n | 'partial-negative-evidence'\n | 'below-threshold'\n | 'ambiguous-thresholds'\n /** Unnormalized marginal mass of caller-designated native alternatives. Not calibrated risk. */\n supportProbability: number\n refutationProbability: number\n unresolvedProbability: number\n modelConfidence: number | null\n check: JevReviewCheck\n}\n\nexport interface JevReviewReport {\n reviewDigest: string\n requestedModel: string\n servedModel: string\n assessments: JevReviewAssessment[]\n}\n\nfunction alternatives(question: JevQuestions[string]): string[] {\n if (question.type === 'noul') return ['true', 'false']\n return question.type === 'choice'\n ? Object.keys(question.criteria)\n : question.criteria.map((_, index) => String(index))\n}\n\n/** Validate before paid admission; make a detached, frozen snapshot without rewriting native JSON. */\nexport function prepareJevReview<const Q extends JevQuestions>(\n input: JevReviewInput<Q>,\n): PreparedJevReview<Q> {\n if (!input.version?.trim()) throw new TypeError('Review version is required')\n parseJevRequest(input.request)\n // Document form drops only optional undefined object fields; canonicalization rejects loss.\n const document = jsonDocument(input)\n canonicalString(document)\n // Canonical bytes are for hashing, not dispatch: option order can affect a classifier.\n const snapshot = structuredClone(document) as JevReviewInput<Q>\n const keys = Object.keys(snapshot.request.questions)\n if (\n !snapshot.checks ||\n Object.keys(snapshot.checks).length !== keys.length ||\n keys.some((key) => !Object.hasOwn(snapshot.checks, key))\n ) {\n throw new TypeError('Review checks must match the exact question names')\n }\n for (const key of keys) {\n const check = checkSchema.parse(snapshot.checks[key])\n const labels = [...check.supports, ...check.refutes]\n const allowed = alternatives(snapshot.request.questions[key]!)\n if (\n new Set(labels).size !== labels.length ||\n labels.some((label) => !allowed.includes(label))\n ) {\n throw new TypeError('Review alternatives must exist and be disjoint')\n }\n if (check.coverage !== 'missing' && check.evidence.length === 0) {\n throw new TypeError('Review evidence references are required for non-missing coverage')\n }\n // Validation must not normalize a label into a different native option.\n if (canonicalString(jsonDocument(check)) !== canonicalString(snapshot.checks[key])) {\n throw new TypeError('Review metadata must not require normalization')\n }\n }\n const order = keys.map((key) => [key, alternatives(snapshot.request.questions[key]!)])\n return deepFreezeCanonicalJson({ ...snapshot, digest: hashCanonical({ snapshot, order }) })\n}\n\n/** Re-score the same retained distribution without new inference or any authorization effect. */\nexport function assessJevReview<Q extends JevQuestions>(\n review: PreparedJevReview<Q>,\n raw: unknown,\n): JevReviewReport {\n const { digest, ...input } = review\n const prepared = prepareJevReview(input)\n if (prepared.digest !== digest) throw new TypeError('Review definition changed after preparation')\n const result = parseJevResult(raw, prepared.request)\n const assessments = Object.entries(prepared.checks).map(([question, check]) => {\n const answer = result.answers[question]!\n const probabilities: Record<string, number> =\n answer.type === 'noul' ? { true: answer.noul, false: 1 - answer.noul } : answer.probabilities\n const sum = (labels: string[]) =>\n labels.reduce((total, label) => total + probabilities[label]!, 0)\n const supportProbability = sum(check.supports)\n const refutationProbability = sum(check.refutes)\n const used = new Set([...check.supports, ...check.refutes])\n const unresolvedProbability = sum(\n Object.keys(probabilities).filter((label) => !used.has(label)),\n )\n let status: JevReviewAssessment['status'] = 'unresolved'\n let reason: JevReviewAssessment['reason'] = 'below-threshold'\n if (supportProbability > 1 || refutationProbability > 1 || unresolvedProbability > 1) {\n throw new TypeError('Review probability mass exceeds one; do not silently normalize it')\n }\n if (check.coverage === 'missing') reason = 'missing-evidence'\n else if (\n supportProbability >= check.supportAtLeast &&\n refutationProbability >= check.refuteAtLeast\n ) {\n reason = 'ambiguous-thresholds'\n } else if (supportProbability >= check.supportAtLeast) {\n status = 'supported'\n reason = 'support-threshold'\n } else if (refutationProbability >= check.refuteAtLeast) {\n if (check.coverage === 'complete') {\n status = 'refuted'\n reason = 'refutation-threshold'\n } else reason = 'partial-negative-evidence'\n }\n return {\n question,\n status,\n reason,\n supportProbability,\n refutationProbability,\n unresolvedProbability,\n modelConfidence: answer.type === 'noul' ? null : answer.confidence,\n check: structuredClone(check),\n }\n })\n return {\n reviewDigest: digest,\n requestedModel: review.request.model,\n servedModel: result.model,\n assessments,\n }\n}\n\n/** Ordinary analyst findings; a negative review is not a global safety certificate. */\nexport function jevReviewFindings<Q extends JevQuestions>(\n review: PreparedJevReview<Q>,\n result: JevResult<Q>,\n options: { analystId: string; producedAt?: string },\n): AnalystFinding[] {\n if (!options.analystId.trim()) throw new TypeError('Analyst id is required')\n const report = assessJevReview(review, result)\n return report.assessments\n .filter((item) => item.status !== 'refuted')\n .map((item) =>\n makeFinding({\n analyst_id: options.analystId,\n ...(options.producedAt === undefined ? {} : { produced_at: options.producedAt }),\n subject: item.check.subject,\n area: item.status === 'unresolved' ? 'assessment-coverage' : item.check.area,\n severity: item.status === 'unresolved' ? 'info' : item.check.severity,\n claim:\n item.status === 'supported'\n ? `Model-supported hypothesis: ${item.check.claim}`\n : `Unresolved review: ${item.check.claim}`,\n evidence_refs: structuredClone(item.check.evidence) as EvidenceRef[],\n // For unresolved findings, confidence describes the deterministic unresolved status only.\n confidence: item.status === 'supported' ? item.supportProbability : 1,\n derived_from_judge: true,\n id_basis: hashCanonical([item.question, item.status, review.version, item.check.claim]),\n metadata: {\n review_digest: report.reviewDigest,\n question: item.question,\n requested_model: report.requestedModel,\n served_model: report.servedModel,\n assessment: item.status,\n assessment_reason: item.reason,\n evidence_coverage: item.check.coverage,\n support_probability: item.supportProbability,\n refutation_probability: item.refutationProbability,\n unresolved_probability: item.unresolvedProbability,\n model_confidence: item.modelConfidence,\n calibration: 'not-established',\n confidence_basis:\n item.status === 'supported' ? 'model-support-mass' : 'deterministic-status',\n native_answer: structuredClone(result.answers[item.question]),\n },\n }),\n )\n}\n","import type { Analyst, AnalystContext, AnalystFinding } from './analyst/types'\nimport type { JudgeConfig, JudgeScore, Scenario } from './campaign/types'\nimport type { CostReceiptInput, CustomTokenPricing } from './cost-ledger'\nimport type { EvaluationContext, EvaluationResult, EvaluatorOptions } from './evaluation'\nimport { asAnalyst, asJudge, createEvaluator } from './evaluation'\nimport type { JevQuestions, JevRequest, JevResult, JevState } from './jev-protocol'\nimport { jevUsage, parseJevRequest, parseJevResult } from './jev-protocol'\nimport { jsonDocument } from './ledger-core/canonical'\nimport { weightedComposite } from './statistics'\nimport { contentHash } from './verdict-cache'\n\nexport * from './evaluation'\nexport * from './jev-protocol'\nexport * from './jev-review'\n\nexport type JevEvaluate = EvaluatorOptions<JevRequest, unknown>['execute']\nexport interface JevEvaluatorOptions {\n evaluate: JevEvaluate\n costLedger?: EvaluatorOptions<JevRequest, unknown>['costLedger']\n maximumCharge?: EvaluatorOptions<JevRequest, unknown>['maximumCharge']\n pricing?: CustomTokenPricing\n receipt?: (response: unknown) => CostReceiptInput\n receiptFromError?: (error: Error) => CostReceiptInput | undefined\n /** Optional deployment policy; the protocol adapter does not hardcode model aliases. */\n acceptModel?: (requested: string, served: string) => boolean\n}\n\n/** Configure transport once; supply native state, questions, and model on every invocation. */\nexport function jevEvaluator(options: JevEvaluatorOptions) {\n const config = { ...options, pricing: options.pricing && { ...options.pricing } }\n const run = createEvaluator<JevRequest, unknown>({\n execute: (request, context) => config.evaluate(structuredClone(request), context),\n model: (request) => request.model,\n costLedger: config.costLedger,\n maximumCharge: config.maximumCharge,\n receiptFromError: config.receiptFromError,\n receipt:\n config.receipt ??\n ((raw) => {\n const usage = jevUsage(raw)\n const { model } = raw as JevResult\n return {\n model,\n inputTokens: usage.input_tokens,\n outputTokens: usage.output_tokens,\n customTokenPricing: config.pricing,\n }\n }),\n validate: (raw, request) => {\n const result = parseJevResult(raw, request)\n if (config.acceptModel && !config.acceptModel(request.model, result.model)) {\n throw new Error('Evaluation served a model rejected by the caller policy')\n }\n },\n })\n return async <const Q extends JevQuestions>(\n request: JevRequest<Q>,\n context?: EvaluationContext,\n ): Promise<EvaluationResult<JevResult<Q>>> => {\n context?.signal?.throwIfAborted()\n parseJevRequest(request)\n const snapshot = structuredClone(request)\n const result = await run(snapshot, context)\n // The validator checked these exact questions after recording the paid work.\n return { ...result, value: result.value as JevResult<Q> }\n }\n}\n\ntype Input<A, S extends Scenario> = { artifact: A; scenario: S }\ntype QuestionSource<I, Q extends JevQuestions> = Q | ((input: I) => Q | Promise<Q>)\nexport interface JevOptions extends JevEvaluatorOptions {\n model: string\n version: string\n questions: JevQuestions\n}\nexport interface JevJudgeOptions<\n A,\n S extends Scenario = Scenario,\n Q extends JevQuestions = JevQuestions,\n> extends JevEvaluatorOptions {\n model: string\n version: string\n questions: QuestionSource<Input<A, S>, Q>\n renderState: (input: Input<A, S>, context: EvaluationContext) => JevState | Promise<JevState>\n dimensions?: JudgeConfig<A, S>['dimensions']\n weights?: Record<string, number>\n map?: (value: JevResult<Q>, input: Input<A, S>) => JudgeScore | Promise<JudgeScore>\n record?: (result: EvaluationResult<JevResult<Q>>, input: Input<A, S>) => void | Promise<void>\n appliesTo?: (scenario: S) => boolean\n}\n\n/** Canonical identity also retains native question/alternative order; dispatch stays untouched. */\nfunction questionIdentity(questions: JevQuestions) {\n return {\n document: jsonDocument(questions),\n order: Object.entries(questions).map(([name, question]) => [\n name,\n question.type === 'choice' ? Object.keys(question.criteria) : null,\n ]),\n }\n}\n\nfunction validateWeights(weights: Record<string, number>, keys: string[]): void {\n if (\n Object.entries(weights).some(\n ([key, weight]) => !keys.includes(key) || !Number.isFinite(weight) || weight < 0,\n ) ||\n Object.values(weights).reduce((sum, weight) => sum + weight, 0) <= 0\n ) {\n throw new TypeError('Invalid judge weights')\n }\n}\n\n/** Optional convention. Choice utilities and non-uniform scales belong in an explicit map. */\nexport function normalizedJevScore(\n result: JevResult,\n weights?: Record<string, number>,\n): JudgeScore {\n const dimensions: Record<string, number> = Object.create(null)\n const distribution: NonNullable<JudgeScore['distribution']> = Object.create(null)\n for (const [key, answer] of Object.entries(result.answers)) {\n if (answer.type === 'choice') throw new TypeError('Choice scoring requires an explicit map')\n if (answer.type === 'noul') {\n dimensions[key] = answer.noul\n distribution[key] = [\n { score: 0, probability: 1 - answer.noul },\n { score: 1, probability: answer.noul },\n ]\n } else {\n const scale = Object.keys(answer.legend).length - 1\n dimensions[key] = answer.score / scale\n distribution[key] = Object.entries(answer.probabilities).map(([level, probability]) => ({\n score: Number(level) / scale,\n probability,\n }))\n }\n }\n const effective = weights ?? Object.fromEntries(Object.keys(dimensions).map((key) => [key, 1]))\n validateWeights(effective, Object.keys(dimensions))\n return {\n dimensions,\n composite: weightedComposite({ dims: dimensions, weights: effective }).composite,\n notes: '',\n scoringMethod: 'expectation',\n distribution,\n }\n}\n\n/** Convenience around the public evaluator. No domain questions, thresholds, or prose. */\nexport function jevJudge<A, S extends Scenario = Scenario, Q extends JevQuestions = JevQuestions>(\n name: string,\n options: JevJudgeOptions<A, S, Q>,\n): JudgeConfig<A, S> {\n const config = { ...options }\n const source =\n typeof options.questions === 'function' ? options.questions : structuredClone(options.questions)\n const weights = options.weights && { ...options.weights }\n if (!name.trim() || !options.version.trim()) {\n throw new TypeError('Judge name and version are required')\n }\n if ((typeof source === 'function' || config.map) && !config.dimensions) {\n throw new TypeError('Dynamic questions and custom mappings require stable judge dimensions')\n }\n if (!config.map && typeof source !== 'function') {\n parseJevRequest({ model: config.model, state: null, questions: source })\n if (Object.values(source).some((question) => question.type === 'choice')) {\n throw new TypeError(\n 'Choice scoring requires an explicit map; labels have no numeric ordering',\n )\n }\n if (weights) validateWeights(weights, Object.keys(source))\n }\n const dimensions =\n config.dimensions ??\n Object.entries(source).map(([key, question]) => ({\n key,\n description: typeof question.instructions === 'string' ? question.instructions : key,\n }))\n const evaluate = jevEvaluator(config)\n return asJudge<A, S, JevResult<Q>>({\n name,\n version: contentHash({\n model: config.model,\n version: config.version,\n questions: typeof source === 'function' ? 'dynamic' : questionIdentity(source),\n dimensions,\n // Hash the JSON document: optional undefined fields are absent on the wire.\n ...(weights ? { weights } : {}),\n }),\n dimensions,\n appliesTo: config.appliesTo,\n evaluate: async (input, context = {}) =>\n evaluate(\n {\n model: config.model,\n state: await config.renderState(input, context),\n questions: typeof source === 'function' ? await source(input) : source,\n },\n context,\n ),\n map: config.map ?? ((value) => normalizedJevScore(value, weights)),\n record: config.record,\n })\n}\n\nexport interface JevAnalystOptions<I, Q extends JevQuestions = JevQuestions>\n extends JevEvaluatorOptions {\n id: string\n description: string\n inputKind: Analyst<I>['inputKind']\n model: string\n version: string\n questions: Q | ((input: I, context: AnalystContext) => Q | Promise<Q>)\n renderState: (input: I, context: AnalystContext) => JevState | Promise<JevState>\n findings: (\n value: JevResult<Q>,\n input: I,\n context: AnalystContext,\n ) => AnalystFinding[] | Promise<AnalystFinding[]>\n record?: (\n result: EvaluationResult<JevResult<Q>>,\n input: I,\n context: AnalystContext,\n ) => void | Promise<void>\n}\n\nexport function jevAnalyst<I, Q extends JevQuestions = JevQuestions>(\n options: JevAnalystOptions<I, Q>,\n): Analyst<I> {\n const config = { ...options }\n const source =\n typeof options.questions === 'function' ? options.questions : structuredClone(options.questions)\n if (!config.id.trim() || !config.version.trim() || !config.description.trim()) {\n throw new TypeError('Analyst id, version, and description are required')\n }\n const evaluate = jevEvaluator(config)\n return asAnalyst<I, JevResult<Q>>({\n id: config.id,\n description: config.description,\n inputKind: config.inputKind,\n version: contentHash({\n model: config.model,\n version: config.version,\n questions: typeof source === 'function' ? 'dynamic' : questionIdentity(source),\n }),\n cost: { kind: 'llm', models: [config.model] },\n evaluate: async (input, context, analystContext) =>\n evaluate(\n {\n model: config.model,\n state: await config.renderState(input, analystContext),\n questions: typeof source === 'function' ? await source(input, analystContext) : source,\n },\n context,\n ),\n map: config.findings,\n record: config.record,\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"jev.js","names":[],"sources":["../src/jev-review.ts","../src/jev.ts"],"sourcesContent":["import { z } from 'zod'\nimport {\n ANALYST_SEVERITIES,\n type AnalystFinding,\n type EvidenceRef,\n makeFinding,\n} from './analyst/types'\nimport type { JevQuestions, JevRequest, JevResult } from './jev-protocol'\nimport { parseJevRequest, parseJevResult } from './jev-protocol'\nimport { canonicalString, hashCanonical, jsonDocument } from './ledger-core/canonical'\nimport { deepFreezeCanonicalJson } from './ledger-core/deep-freeze'\n\nconst name = z.string().trim().min(1)\nconst probability = z.number().finite().gt(0).max(1)\nconst checkSchema = z\n .object({\n claim: name,\n area: name,\n subject: name,\n severity: z.enum(ANALYST_SEVERITIES),\n /** Choice labels or score-level keys, never scores invented from category order. */\n supports: z.array(z.string()).min(1),\n refutes: z.array(z.string()).min(1),\n supportAtLeast: probability,\n refuteAtLeast: probability,\n /** Host-supplied coverage of the question's required evidence, not model self-assessment. */\n coverage: z.enum(['complete', 'partial', 'missing']),\n evidence: z.array(\n z\n .object({\n kind: z.enum(['span', 'event', 'artifact', 'finding', 'metric']),\n uri: name,\n excerpt: z.string().optional(),\n })\n .strict(),\n ),\n })\n .strict()\n .refine((value) => value.supportAtLeast + value.refuteAtLeast > 1, {\n message: 'Support and refutation thresholds must not overlap',\n })\n\n/** Optional interpretation of native choices/scores. Policy and evidence belong to the caller. */\nexport type JevReviewCheck = z.infer<typeof checkSchema>\nexport interface JevReviewInput<Q extends JevQuestions = JevQuestions> {\n version: string\n request: JevRequest<Q>\n checks: { [K in keyof Q]: JevReviewCheck }\n}\n\nexport interface PreparedJevReview<Q extends JevQuestions = JevQuestions>\n extends JevReviewInput<Q> {\n /** Binds questions, option order, context, evidence, thresholds and definition version. */\n digest: string\n}\n\nexport interface JevReviewAssessment {\n question: string\n status: 'supported' | 'refuted' | 'unresolved'\n reason:\n | 'support-threshold'\n | 'refutation-threshold'\n | 'missing-evidence'\n | 'partial-negative-evidence'\n | 'below-threshold'\n | 'ambiguous-thresholds'\n /** Unnormalized marginal mass of caller-designated native alternatives. Not calibrated risk. */\n supportProbability: number\n refutationProbability: number\n unresolvedProbability: number\n modelConfidence: number | null\n check: JevReviewCheck\n}\n\nexport interface JevReviewReport {\n reviewDigest: string\n requestedModel: string\n servedModel: string\n assessments: JevReviewAssessment[]\n}\n\nfunction alternatives(question: JevQuestions[string]): string[] {\n if (question.type === 'noul') return ['true', 'false']\n return question.type === 'choice'\n ? Object.keys(question.criteria)\n : question.criteria.map((_, index) => String(index))\n}\n\n/** Validate before paid admission; make a detached, frozen snapshot without rewriting native JSON. */\nexport function prepareJevReview<const Q extends JevQuestions>(\n input: JevReviewInput<Q>,\n): PreparedJevReview<Q> {\n if (!input.version?.trim()) throw new TypeError('Review version is required')\n parseJevRequest(input.request)\n // Document form drops only optional undefined object fields; canonicalization rejects loss.\n const document = jsonDocument(input)\n canonicalString(document)\n // Canonical bytes are for hashing, not dispatch: option order can affect a classifier.\n const snapshot = structuredClone(document) as JevReviewInput<Q>\n const keys = Object.keys(snapshot.request.questions)\n if (\n !snapshot.checks ||\n Object.keys(snapshot.checks).length !== keys.length ||\n keys.some((key) => !Object.hasOwn(snapshot.checks, key))\n ) {\n throw new TypeError('Review checks must match the exact question names')\n }\n for (const key of keys) {\n const check = checkSchema.parse(snapshot.checks[key])\n const labels = [...check.supports, ...check.refutes]\n const allowed = alternatives(snapshot.request.questions[key]!)\n if (\n new Set(labels).size !== labels.length ||\n labels.some((label) => !allowed.includes(label))\n ) {\n throw new TypeError('Review alternatives must exist and be disjoint')\n }\n if (check.coverage !== 'missing' && check.evidence.length === 0) {\n throw new TypeError('Review evidence references are required for non-missing coverage')\n }\n // Validation must not normalize a label into a different native option.\n if (canonicalString(jsonDocument(check)) !== canonicalString(snapshot.checks[key])) {\n throw new TypeError('Review metadata must not require normalization')\n }\n }\n const order = keys.map((key) => [key, alternatives(snapshot.request.questions[key]!)])\n return deepFreezeCanonicalJson({ ...snapshot, digest: hashCanonical({ snapshot, order }) })\n}\n\n/** Re-score the same retained distribution without new inference or any authorization effect. */\nexport function assessJevReview<Q extends JevQuestions>(\n review: PreparedJevReview<Q>,\n raw: unknown,\n): JevReviewReport {\n const { digest, ...input } = review\n const prepared = prepareJevReview(input)\n if (prepared.digest !== digest) throw new TypeError('Review definition changed after preparation')\n const result = parseJevResult(raw, prepared.request)\n const assessments = Object.entries(prepared.checks).map(([question, check]) => {\n const answer = result.answers[question]!\n const probabilities: Record<string, number> =\n answer.type === 'noul' ? { true: answer.noul, false: 1 - answer.noul } : answer.probabilities\n const sum = (labels: string[]) =>\n labels.reduce((total, label) => total + probabilities[label]!, 0)\n const supportProbability = sum(check.supports)\n const refutationProbability = sum(check.refutes)\n const used = new Set([...check.supports, ...check.refutes])\n const unresolvedProbability = sum(\n Object.keys(probabilities).filter((label) => !used.has(label)),\n )\n let status: JevReviewAssessment['status'] = 'unresolved'\n let reason: JevReviewAssessment['reason'] = 'below-threshold'\n if (supportProbability > 1 || refutationProbability > 1 || unresolvedProbability > 1) {\n throw new TypeError('Review probability mass exceeds one; do not silently normalize it')\n }\n if (check.coverage === 'missing') reason = 'missing-evidence'\n else if (\n supportProbability >= check.supportAtLeast &&\n refutationProbability >= check.refuteAtLeast\n ) {\n reason = 'ambiguous-thresholds'\n } else if (supportProbability >= check.supportAtLeast) {\n status = 'supported'\n reason = 'support-threshold'\n } else if (refutationProbability >= check.refuteAtLeast) {\n if (check.coverage === 'complete') {\n status = 'refuted'\n reason = 'refutation-threshold'\n } else reason = 'partial-negative-evidence'\n }\n return {\n question,\n status,\n reason,\n supportProbability,\n refutationProbability,\n unresolvedProbability,\n modelConfidence: answer.type === 'noul' ? null : answer.confidence,\n check: structuredClone(check),\n }\n })\n return {\n reviewDigest: digest,\n requestedModel: review.request.model,\n servedModel: result.model,\n assessments,\n }\n}\n\n/** Ordinary analyst findings; a negative review is not a global safety certificate. */\nexport function jevReviewFindings<Q extends JevQuestions>(\n review: PreparedJevReview<Q>,\n result: JevResult<Q>,\n options: { analystId: string; producedAt?: string },\n): AnalystFinding[] {\n if (!options.analystId.trim()) throw new TypeError('Analyst id is required')\n const report = assessJevReview(review, result)\n return report.assessments\n .filter((item) => item.status !== 'refuted')\n .map((item) =>\n makeFinding({\n analyst_id: options.analystId,\n ...(options.producedAt === undefined ? {} : { produced_at: options.producedAt }),\n subject: item.check.subject,\n area: item.status === 'unresolved' ? 'assessment-coverage' : item.check.area,\n severity: item.status === 'unresolved' ? 'info' : item.check.severity,\n claim:\n item.status === 'supported'\n ? `Model-supported hypothesis: ${item.check.claim}`\n : `Unresolved review: ${item.check.claim}`,\n evidence_refs: structuredClone(item.check.evidence) as EvidenceRef[],\n // For unresolved findings, confidence describes the deterministic unresolved status only.\n confidence: item.status === 'supported' ? item.supportProbability : 1,\n derived_from_judge: true,\n id_basis: hashCanonical([item.question, item.status, review.version, item.check.claim]),\n metadata: {\n review_digest: report.reviewDigest,\n question: item.question,\n requested_model: report.requestedModel,\n served_model: report.servedModel,\n assessment: item.status,\n assessment_reason: item.reason,\n evidence_coverage: item.check.coverage,\n support_probability: item.supportProbability,\n refutation_probability: item.refutationProbability,\n unresolved_probability: item.unresolvedProbability,\n model_confidence: item.modelConfidence,\n calibration: 'not-established',\n confidence_basis:\n item.status === 'supported' ? 'model-support-mass' : 'deterministic-status',\n native_answer: structuredClone(result.answers[item.question]),\n },\n }),\n )\n}\n","import type { Analyst, AnalystContext, AnalystFinding } from './analyst/types'\nimport type { JudgeConfig, JudgeScore, Scenario } from './campaign/types'\nimport type { CostReceiptInput, CustomTokenPricing } from './cost-ledger'\nimport type { EvaluationContext, EvaluationResult, EvaluatorOptions } from './evaluation'\nimport { asAnalyst, asJudge, createEvaluator } from './evaluation'\nimport type { JevQuestions, JevRequest, JevResult, JevState } from './jev-protocol'\nimport { jevUsage, parseJevQuestions, parseJevRequest, parseJevResult } from './jev-protocol'\nimport { jsonDocument } from './ledger-core/canonical'\nimport { weightedComposite } from './statistics'\nimport { contentHash } from './verdict-cache'\n\nexport * from './evaluation'\nexport * from './jev-protocol'\nexport * from './jev-review'\n\nexport type JevEvaluate = EvaluatorOptions<JevRequest, unknown>['execute']\nexport interface JevEvaluatorOptions {\n evaluate: JevEvaluate\n costLedger?: EvaluatorOptions<JevRequest, unknown>['costLedger']\n maximumCharge?: EvaluatorOptions<JevRequest, unknown>['maximumCharge']\n pricing?: CustomTokenPricing\n receipt?: (response: unknown) => CostReceiptInput\n receiptFromError?: (error: Error) => CostReceiptInput | undefined\n /** Optional deployment policy; the protocol adapter does not hardcode model aliases. */\n acceptModel?: (requested: string, served: string) => boolean\n}\n\n/** Configure transport once; supply native state, questions, and model on every invocation. */\nexport function jevEvaluator(options: JevEvaluatorOptions) {\n const config = { ...options, pricing: options.pricing && { ...options.pricing } }\n const run = createEvaluator<JevRequest, unknown>({\n execute: (request, context) => config.evaluate(structuredClone(request), context),\n model: (request) => request.model,\n costLedger: config.costLedger,\n maximumCharge: config.maximumCharge,\n receiptFromError: config.receiptFromError,\n receipt:\n config.receipt ??\n ((raw) => {\n const usage = jevUsage(raw)\n const { model } = raw as JevResult\n return {\n model,\n inputTokens: usage.input_tokens,\n outputTokens: usage.output_tokens,\n customTokenPricing: config.pricing,\n }\n }),\n validate: (raw, request) => {\n const result = parseJevResult(raw, request)\n if (config.acceptModel && !config.acceptModel(request.model, result.model)) {\n throw new Error('Evaluation served a model rejected by the caller policy')\n }\n },\n })\n return async <const Q extends JevQuestions>(\n request: JevRequest<Q>,\n context?: EvaluationContext,\n ): Promise<EvaluationResult<JevResult<Q>>> => {\n context?.signal?.throwIfAborted()\n parseJevRequest(request)\n const snapshot = structuredClone(request)\n const result = await run(snapshot, context)\n // The validator checked these exact questions after recording the paid work.\n return { ...result, value: result.value as JevResult<Q> }\n }\n}\n\ntype Input<A, S extends Scenario> = { artifact: A; scenario: S }\ntype QuestionSource<I, Q extends JevQuestions> = Q | ((input: I) => Q | Promise<Q>)\nexport interface JevOptions extends JevEvaluatorOptions {\n model: string\n version: string\n questions: JevQuestions\n}\nexport interface JevJudgeOptions<\n A,\n S extends Scenario = Scenario,\n Q extends JevQuestions = JevQuestions,\n> extends JevEvaluatorOptions {\n model: string\n version: string\n questions: QuestionSource<Input<A, S>, Q>\n renderState: (input: Input<A, S>, context: EvaluationContext) => JevState | Promise<JevState>\n dimensions?: JudgeConfig<A, S>['dimensions']\n weights?: Record<string, number>\n map?: (value: JevResult<Q>, input: Input<A, S>) => JudgeScore | Promise<JudgeScore>\n record?: (result: EvaluationResult<JevResult<Q>>, input: Input<A, S>) => void | Promise<void>\n appliesTo?: (scenario: S) => boolean\n}\n\n/** Canonical identity also retains native question/alternative order; dispatch stays untouched. */\nfunction questionIdentity(questions: JevQuestions) {\n return {\n document: jsonDocument(questions),\n order: Object.entries(questions).map(([name, question]) => [\n name,\n question.type === 'choice' ? Object.keys(question.criteria) : null,\n ]),\n }\n}\n\nfunction validateWeights(weights: Record<string, number>, keys: string[]): void {\n if (\n Object.entries(weights).some(\n ([key, weight]) => !keys.includes(key) || !Number.isFinite(weight) || weight < 0,\n ) ||\n Object.values(weights).reduce((sum, weight) => sum + weight, 0) <= 0\n ) {\n throw new TypeError('Invalid judge weights')\n }\n}\n\n/** Optional convention. Choice utilities and non-uniform scales belong in an explicit map. */\nexport function normalizedJevScore(\n result: JevResult,\n weights?: Record<string, number>,\n): JudgeScore {\n const dimensions: Record<string, number> = Object.create(null)\n const distribution: NonNullable<JudgeScore['distribution']> = Object.create(null)\n for (const [key, answer] of Object.entries(result.answers)) {\n if (answer.type === 'choice') throw new TypeError('Choice scoring requires an explicit map')\n if (answer.type === 'noul') {\n dimensions[key] = answer.noul\n distribution[key] = [\n { score: 0, probability: 1 - answer.noul },\n { score: 1, probability: answer.noul },\n ]\n } else {\n const scale = Object.keys(answer.legend).length - 1\n dimensions[key] = answer.score / scale\n distribution[key] = Object.entries(answer.probabilities).map(([level, probability]) => ({\n score: Number(level) / scale,\n probability,\n }))\n }\n }\n const effective = weights ?? Object.fromEntries(Object.keys(dimensions).map((key) => [key, 1]))\n validateWeights(effective, Object.keys(dimensions))\n return {\n dimensions,\n composite: weightedComposite({ dims: dimensions, weights: effective }).composite,\n notes: '',\n scoringMethod: 'expectation',\n distribution,\n }\n}\n\n/** Convenience around the public evaluator. No domain questions, thresholds, or prose. */\nexport function jevJudge<A, S extends Scenario = Scenario, Q extends JevQuestions = JevQuestions>(\n name: string,\n options: JevJudgeOptions<A, S, Q>,\n): JudgeConfig<A, S> {\n const config = { ...options }\n const source =\n typeof options.questions === 'function' ? options.questions : structuredClone(options.questions)\n const weights = options.weights && { ...options.weights }\n if (!name.trim() || !options.version.trim()) {\n throw new TypeError('Judge name and version are required')\n }\n if ((typeof source === 'function' || config.map) && !config.dimensions) {\n throw new TypeError('Dynamic questions and custom mappings require stable judge dimensions')\n }\n if (!config.map && typeof source !== 'function') {\n parseJevQuestions(source)\n if (Object.values(source).some((question) => question.type === 'choice')) {\n throw new TypeError(\n 'Choice scoring requires an explicit map; labels have no numeric ordering',\n )\n }\n if (weights) validateWeights(weights, Object.keys(source))\n }\n const dimensions =\n config.dimensions ??\n Object.entries(source).map(([key, question]) => ({\n key,\n description: typeof question.instructions === 'string' ? question.instructions : key,\n }))\n const evaluate = jevEvaluator(config)\n return asJudge<A, S, JevResult<Q>>({\n name,\n version: contentHash({\n model: config.model,\n version: config.version,\n questions: typeof source === 'function' ? 'dynamic' : questionIdentity(source),\n dimensions,\n // Hash the JSON document: optional undefined fields are absent on the wire.\n ...(weights ? { weights } : {}),\n }),\n dimensions,\n appliesTo: config.appliesTo,\n evaluate: async (input, context = {}) =>\n evaluate(\n {\n model: config.model,\n state: await config.renderState(input, context),\n questions: typeof source === 'function' ? await source(input) : source,\n },\n context,\n ),\n map: config.map ?? ((value) => normalizedJevScore(value, weights)),\n record: config.record,\n })\n}\n\nexport interface JevAnalystOptions<I, Q extends JevQuestions = JevQuestions>\n extends JevEvaluatorOptions {\n id: string\n description: string\n inputKind: Analyst<I>['inputKind']\n model: string\n version: string\n questions: Q | ((input: I, context: AnalystContext) => Q | Promise<Q>)\n renderState: (input: I, context: AnalystContext) => JevState | Promise<JevState>\n findings: (\n value: JevResult<Q>,\n input: I,\n context: AnalystContext,\n ) => AnalystFinding[] | Promise<AnalystFinding[]>\n record?: (\n result: EvaluationResult<JevResult<Q>>,\n input: I,\n context: AnalystContext,\n ) => void | Promise<void>\n}\n\nexport function jevAnalyst<I, Q extends JevQuestions = JevQuestions>(\n options: JevAnalystOptions<I, Q>,\n): Analyst<I> {\n const config = { ...options }\n const source =\n typeof options.questions === 'function' ? options.questions : structuredClone(options.questions)\n if (!config.id.trim() || !config.version.trim() || !config.description.trim()) {\n throw new TypeError('Analyst id, version, and description are required')\n }\n const evaluate = jevEvaluator(config)\n return asAnalyst<I, JevResult<Q>>({\n id: config.id,\n description: config.description,\n inputKind: config.inputKind,\n version: contentHash({\n model: config.model,\n version: config.version,\n questions: typeof source === 'function' ? 'dynamic' : questionIdentity(source),\n }),\n cost: { kind: 'llm', models: [config.model] },\n evaluate: async (input, context, analystContext) =>\n evaluate(\n {\n model: config.model,\n state: await config.renderState(input, analystContext),\n questions: typeof source === 'function' ? await source(input, analystContext) : source,\n },\n context,\n ),\n map: config.findings,\n record: config.record,\n })\n}\n"],"mappings":"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"}
|
|
@@ -2849,6 +2849,136 @@ function round$1(value) {
|
|
|
2849
2849
|
return Math.round(value * 1e4) / 1e4;
|
|
2850
2850
|
}
|
|
2851
2851
|
//#endregion
|
|
2852
|
+
//#region src/campaign/search-campaign-cell.ts
|
|
2853
|
+
/**
|
|
2854
|
+
* What `cell-settled` records for one campaign cell: `passed` with the
|
|
2855
|
+
* composite (and each judge's) when every judge scored it, else `errored`,
|
|
2856
|
+
* never retryable, because `runCampaign` already applied its own retry policy;
|
|
2857
|
+
* its tokens and cost, with an uncaptured cost kept as a lower bound; the
|
|
2858
|
+
* model the cell resolved, else the declared one.
|
|
2859
|
+
*/
|
|
2860
|
+
function campaignCellSearchResult(cell, input) {
|
|
2861
|
+
return {
|
|
2862
|
+
outcome: campaignCellOutcome(cell),
|
|
2863
|
+
accounting: campaignCellAccounting(cell),
|
|
2864
|
+
identity: {
|
|
2865
|
+
...input.execution,
|
|
2866
|
+
model: cell.resolvedModel === void 0 ? input.execution.model : searchModelIdentity(cell.resolvedModel, input.execution.model.provider)
|
|
2867
|
+
},
|
|
2868
|
+
wallMs: cell.durationMs,
|
|
2869
|
+
placement: {
|
|
2870
|
+
lane: input.lane,
|
|
2871
|
+
boxId: null
|
|
2872
|
+
},
|
|
2873
|
+
traceRef: { unknown: "runCampaign reports no trace id per cell" }
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2876
|
+
/** A provider-reported model: a snapshot when its name pins one, else a moving alias. */
|
|
2877
|
+
function searchModelIdentity(model, provider) {
|
|
2878
|
+
return modelHasSnapshot(model) ? {
|
|
2879
|
+
provider,
|
|
2880
|
+
snapshot: model
|
|
2881
|
+
} : {
|
|
2882
|
+
provider,
|
|
2883
|
+
alias: model,
|
|
2884
|
+
unknown: "the provider reported a moving alias, not a snapshot"
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
function campaignCellOutcome(cell) {
|
|
2888
|
+
const quality = projectCampaignCellQuality(cell);
|
|
2889
|
+
if (quality.score === void 0) return {
|
|
2890
|
+
status: "errored",
|
|
2891
|
+
metrics: {},
|
|
2892
|
+
error: {
|
|
2893
|
+
code: cell.errorStage ?? "unscored",
|
|
2894
|
+
message: cell.error ?? "the cell produced no complete judge score",
|
|
2895
|
+
retryable: false
|
|
2896
|
+
}
|
|
2897
|
+
};
|
|
2898
|
+
const metrics = { composite: quality.score };
|
|
2899
|
+
for (const [judge, score] of Object.entries(quality.successfulJudgeScores)) metrics[`judge.${judge}`] = score.composite;
|
|
2900
|
+
return {
|
|
2901
|
+
status: "passed",
|
|
2902
|
+
score: quality.score,
|
|
2903
|
+
metrics
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
function campaignCellAccounting(cell) {
|
|
2907
|
+
const usage = cell.tokenUsage;
|
|
2908
|
+
return {
|
|
2909
|
+
tokens: usage.tokensKnown === false ? {
|
|
2910
|
+
status: "unknown",
|
|
2911
|
+
reason: "a paid call in this cell reported no token usage"
|
|
2912
|
+
} : {
|
|
2913
|
+
status: "known",
|
|
2914
|
+
inputTokens: usage.input,
|
|
2915
|
+
outputTokens: usage.output,
|
|
2916
|
+
cachedTokens: 0
|
|
2917
|
+
},
|
|
2918
|
+
cost: cell.costProvenance.kind === "uncaptured" ? {
|
|
2919
|
+
status: "unknown",
|
|
2920
|
+
knownLowerBoundUsd: cell.costUsd,
|
|
2921
|
+
reason: "the cell recorded spend without a provider receipt"
|
|
2922
|
+
} : {
|
|
2923
|
+
status: "known",
|
|
2924
|
+
usd: cell.costUsd,
|
|
2925
|
+
source: cell.costProvenance.kind === "observed" ? "provider" : "pricing-table"
|
|
2926
|
+
}
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
/** The accounting of a proposal's cost receipts: token and dollar sums, each
|
|
2930
|
+
* unknown (with the known dollars as a lower bound) when a receipt lacks it. */
|
|
2931
|
+
function searchReceiptAccounting(receipts) {
|
|
2932
|
+
let inputTokens = 0;
|
|
2933
|
+
let outputTokens = 0;
|
|
2934
|
+
let cachedTokens = 0;
|
|
2935
|
+
let usd = 0;
|
|
2936
|
+
let tokensKnown = true;
|
|
2937
|
+
let costKnown = true;
|
|
2938
|
+
for (const receipt of receipts) {
|
|
2939
|
+
if (receipt.usageUnknown === true) tokensKnown = false;
|
|
2940
|
+
inputTokens += receipt.inputTokens;
|
|
2941
|
+
outputTokens += receipt.outputTokens;
|
|
2942
|
+
cachedTokens += receipt.cachedTokens ?? 0;
|
|
2943
|
+
if (receipt.costUnknown) costKnown = false;
|
|
2944
|
+
else usd += receipt.costUsd;
|
|
2945
|
+
}
|
|
2946
|
+
return {
|
|
2947
|
+
tokens: tokensKnown ? {
|
|
2948
|
+
status: "known",
|
|
2949
|
+
inputTokens,
|
|
2950
|
+
outputTokens,
|
|
2951
|
+
cachedTokens
|
|
2952
|
+
} : {
|
|
2953
|
+
status: "unknown",
|
|
2954
|
+
reason: "a candidate-generation call reported no token usage"
|
|
2955
|
+
},
|
|
2956
|
+
cost: costKnown ? {
|
|
2957
|
+
status: "known",
|
|
2958
|
+
usd,
|
|
2959
|
+
source: usd === 0 ? "free" : "provider"
|
|
2960
|
+
} : {
|
|
2961
|
+
status: "unknown",
|
|
2962
|
+
knownLowerBoundUsd: usd,
|
|
2963
|
+
reason: "a candidate-generation call recorded no provider cost"
|
|
2964
|
+
}
|
|
2965
|
+
};
|
|
2966
|
+
}
|
|
2967
|
+
/** What ran a proposal: a model when it made a paid call other than a judge's,
|
|
2968
|
+
* else deterministic code. */
|
|
2969
|
+
function searchProposalExecution(receipts, provider, source) {
|
|
2970
|
+
const model = receipts.find((receipt) => receipt.channel !== "judge")?.model;
|
|
2971
|
+
if (model === void 0) return {
|
|
2972
|
+
kind: "deterministic",
|
|
2973
|
+
source
|
|
2974
|
+
};
|
|
2975
|
+
return {
|
|
2976
|
+
kind: "model",
|
|
2977
|
+
model: searchModelIdentity(model, provider),
|
|
2978
|
+
source
|
|
2979
|
+
};
|
|
2980
|
+
}
|
|
2981
|
+
//#endregion
|
|
2852
2982
|
//#region src/paired-promotion-power.ts
|
|
2853
2983
|
/**
|
|
2854
2984
|
* @module
|
|
@@ -5603,8 +5733,8 @@ async function runOptimization(opts) {
|
|
|
5603
5733
|
const accounting = () => {
|
|
5604
5734
|
const fresh = phases.flatMap((phase) => costLedger.list({ phase })).filter((receipt) => !before.has(receiptKey(receipt)));
|
|
5605
5735
|
return {
|
|
5606
|
-
accounting:
|
|
5607
|
-
execution: opts.searchLedger ? identity.proposer :
|
|
5736
|
+
accounting: searchReceiptAccounting(fresh),
|
|
5737
|
+
execution: opts.searchLedger ? identity.proposer : searchProposalExecution(fresh, identity.model.provider, proposerSource)
|
|
5608
5738
|
};
|
|
5609
5739
|
};
|
|
5610
5740
|
const earlier = await recorder.state();
|
|
@@ -6010,20 +6140,10 @@ var SurfaceNodes = class {
|
|
|
6010
6140
|
this.cells.set(nodeId, cells);
|
|
6011
6141
|
}
|
|
6012
6142
|
cellResult(cell, work) {
|
|
6013
|
-
return {
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
...this.execution,
|
|
6018
|
-
model: cellModel(cell, this.execution.model)
|
|
6019
|
-
},
|
|
6020
|
-
wallMs: cell.durationMs,
|
|
6021
|
-
placement: {
|
|
6022
|
-
lane: work.lane,
|
|
6023
|
-
boxId: null
|
|
6024
|
-
},
|
|
6025
|
-
traceRef: { unknown: "runCampaign reports no trace id per cell" }
|
|
6026
|
-
};
|
|
6143
|
+
return campaignCellSearchResult(cell, {
|
|
6144
|
+
execution: this.execution,
|
|
6145
|
+
lane: work.lane
|
|
6146
|
+
});
|
|
6027
6147
|
}
|
|
6028
6148
|
};
|
|
6029
6149
|
/** The default ledger and identities when the caller binds none. Revisions are
|
|
@@ -6074,110 +6194,6 @@ function artifactKindOf(surface) {
|
|
|
6074
6194
|
function receiptKey(receipt) {
|
|
6075
6195
|
return receipt.callId;
|
|
6076
6196
|
}
|
|
6077
|
-
/** A proposal that made a paid call ran a model; one that made none ran code. */
|
|
6078
|
-
function proposalExecution(receipts, provider, source) {
|
|
6079
|
-
const model = receipts.find((receipt) => receipt.channel !== "judge")?.model;
|
|
6080
|
-
if (model === void 0) return {
|
|
6081
|
-
kind: "deterministic",
|
|
6082
|
-
source
|
|
6083
|
-
};
|
|
6084
|
-
return {
|
|
6085
|
-
kind: "model",
|
|
6086
|
-
model: modelIdentity(model, provider),
|
|
6087
|
-
source
|
|
6088
|
-
};
|
|
6089
|
-
}
|
|
6090
|
-
function modelIdentity(model, provider) {
|
|
6091
|
-
return modelHasSnapshot(model) ? {
|
|
6092
|
-
provider,
|
|
6093
|
-
snapshot: model
|
|
6094
|
-
} : {
|
|
6095
|
-
provider,
|
|
6096
|
-
alias: model,
|
|
6097
|
-
unknown: "the provider reported a moving alias, not a snapshot"
|
|
6098
|
-
};
|
|
6099
|
-
}
|
|
6100
|
-
function cellModel(cell, fallback) {
|
|
6101
|
-
return cell.resolvedModel === void 0 ? fallback : modelIdentity(cell.resolvedModel, fallback.provider);
|
|
6102
|
-
}
|
|
6103
|
-
function cellOutcome(cell) {
|
|
6104
|
-
const quality = projectCampaignCellQuality(cell);
|
|
6105
|
-
if (quality.score === void 0) return {
|
|
6106
|
-
status: "errored",
|
|
6107
|
-
metrics: {},
|
|
6108
|
-
error: {
|
|
6109
|
-
code: cell.errorStage ?? "unscored",
|
|
6110
|
-
message: cell.error ?? "the cell produced no complete judge score",
|
|
6111
|
-
retryable: false
|
|
6112
|
-
}
|
|
6113
|
-
};
|
|
6114
|
-
const metrics = { composite: quality.score };
|
|
6115
|
-
for (const [judge, score] of Object.entries(quality.successfulJudgeScores)) metrics[`judge.${judge}`] = score.composite;
|
|
6116
|
-
return {
|
|
6117
|
-
status: "passed",
|
|
6118
|
-
score: quality.score,
|
|
6119
|
-
metrics
|
|
6120
|
-
};
|
|
6121
|
-
}
|
|
6122
|
-
function cellAccounting(cell) {
|
|
6123
|
-
const usage = cell.tokenUsage;
|
|
6124
|
-
return {
|
|
6125
|
-
tokens: usage.tokensKnown === false ? {
|
|
6126
|
-
status: "unknown",
|
|
6127
|
-
reason: "a paid call in this cell reported no token usage"
|
|
6128
|
-
} : {
|
|
6129
|
-
status: "known",
|
|
6130
|
-
inputTokens: usage.input,
|
|
6131
|
-
outputTokens: usage.output,
|
|
6132
|
-
cachedTokens: 0
|
|
6133
|
-
},
|
|
6134
|
-
cost: cell.costProvenance.kind === "uncaptured" ? {
|
|
6135
|
-
status: "unknown",
|
|
6136
|
-
knownLowerBoundUsd: cell.costUsd,
|
|
6137
|
-
reason: "the cell recorded spend without a provider receipt"
|
|
6138
|
-
} : {
|
|
6139
|
-
status: "known",
|
|
6140
|
-
usd: cell.costUsd,
|
|
6141
|
-
source: cell.costProvenance.kind === "observed" ? "provider" : "pricing-table"
|
|
6142
|
-
}
|
|
6143
|
-
};
|
|
6144
|
-
}
|
|
6145
|
-
function receiptAccounting(receipts) {
|
|
6146
|
-
let inputTokens = 0;
|
|
6147
|
-
let outputTokens = 0;
|
|
6148
|
-
let cachedTokens = 0;
|
|
6149
|
-
let usd = 0;
|
|
6150
|
-
let tokensKnown = true;
|
|
6151
|
-
let costKnown = true;
|
|
6152
|
-
for (const receipt of receipts) {
|
|
6153
|
-
if (receipt.usageUnknown === true) tokensKnown = false;
|
|
6154
|
-
inputTokens += receipt.inputTokens;
|
|
6155
|
-
outputTokens += receipt.outputTokens;
|
|
6156
|
-
cachedTokens += receipt.cachedTokens ?? 0;
|
|
6157
|
-
if (receipt.costUnknown) costKnown = false;
|
|
6158
|
-
else usd += receipt.costUsd;
|
|
6159
|
-
}
|
|
6160
|
-
return {
|
|
6161
|
-
tokens: tokensKnown ? {
|
|
6162
|
-
status: "known",
|
|
6163
|
-
inputTokens,
|
|
6164
|
-
outputTokens,
|
|
6165
|
-
cachedTokens
|
|
6166
|
-
} : {
|
|
6167
|
-
status: "unknown",
|
|
6168
|
-
reason: "a candidate-generation call reported no token usage"
|
|
6169
|
-
},
|
|
6170
|
-
cost: costKnown ? {
|
|
6171
|
-
status: "known",
|
|
6172
|
-
usd,
|
|
6173
|
-
source: usd === 0 ? "free" : "provider"
|
|
6174
|
-
} : {
|
|
6175
|
-
status: "unknown",
|
|
6176
|
-
knownLowerBoundUsd: usd,
|
|
6177
|
-
reason: "a candidate-generation call recorded no provider cost"
|
|
6178
|
-
}
|
|
6179
|
-
};
|
|
6180
|
-
}
|
|
6181
6197
|
function immutableProposalSnapshot(value, label) {
|
|
6182
6198
|
try {
|
|
6183
6199
|
return deepFreeze(structuredClone(value));
|
|
@@ -7666,6 +7682,6 @@ function firstString(value) {
|
|
|
7666
7682
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
7667
7683
|
}
|
|
7668
7684
|
//#endregion
|
|
7669
|
-
export {
|
|
7685
|
+
export { paretoFrontier as $, createSearchHistoryReceipt as A, decideSearchClaim as B, searchEdgeId as C, assertCompleteSearchHistory as D, SearchHistoryRequiredError as E, runSearch as F, requiredPairsForPairedPromotion as G, searchClaimReserveUsd as H, searchDivergence as I, searchProposalExecution as J, campaignCellSearchResult as K, searchExpansionIndex as L, verifySearchHistoryArtifact as M, verifySearchHistoryReceipt as N, assertSearchHistoryAdmissionOptions as O, SEARCH_KERNEL_SOURCE as P, dominates as Q, searchPolicyView as R, developmentClaim as S, surfaceNode as T, verifySearchClaim as U, planSearchClaim as V, pairedPromotionPower as W, asha as X, searchReceiptAccounting as Y, uniform as Z, isProposedCandidate as _, tangleTracesRoot as _t, transientDispatchFailure as a, redTeamDataset as at, incumbent as b, cellCachePath as bt, compareOptimizationMethods as c, runCanaries as ct, combineComparisonCosts as d, evaluationUnitMap as dt, runFinalComparison as et, costFromLedgerSummary as f, reserveFinalEvidence as ft, runOptimization as g, resolveRunDir as gt, runImprovementLoop as h, planCampaignRun as ht, quotaExhaustedUntil as i, DEFAULT_RED_TEAM_CORPUS as it, searchHistoryCoverageRow as j, assertSearchHistoryMatchesState as k, optimizationTokenUsageFromSummary as l, assertIndependentEvaluationSplit as lt, readGepaCandidatePopulationArtifact as m, runCampaign as mt, JudgeParseError as n, captureJudge as nt, aggregateRunScore as o, redTeamReport as ot, assertGepaCandidatePopulationSummary as p, runEval as pt, searchModelIdentity as q, isTransientTransportFailure as r, defaultProductionGate as rt, clamp01 as s, scoreRedTeamOutput as st, llmJudge as t, openAutoPr as tt, executeOptimizationMethod as u, captureFinalEvidencePolicy as ut, labelTrustRank as v, readCachedCell as vt, surfaceDiff as w, SearchRecorder as x, computeManifestHash as xt, crowdedFrontierParent as y, buildCellSchedule as yt, SEARCH_CLAIM_RULE as z };
|
|
7670
7686
|
|
|
7671
|
-
//# sourceMappingURL=llm-judge-
|
|
7687
|
+
//# sourceMappingURL=llm-judge-fhkFQL1N.js.map
|