@tangle-network/agent-eval 0.120.1 → 0.120.2
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 +6 -0
- package/package.json +1 -1
- package/dist/analyst/index.d.ts +0 -3111
- package/dist/analyst/index.js +0 -403
- package/dist/analyst/index.js.map +0 -1
- package/dist/authenticity/index.d.ts +0 -161
- package/dist/authenticity/index.js +0 -215
- package/dist/authenticity/index.js.map +0 -1
- package/dist/belief-state/index.d.ts +0 -1301
- package/dist/belief-state/index.js +0 -2152
- package/dist/belief-state/index.js.map +0 -1
- package/dist/benchmarks/index.d.ts +0 -974
- package/dist/benchmarks/index.js +0 -60
- package/dist/benchmarks/index.js.map +0 -1
- package/dist/builder-eval/index.d.ts +0 -695
- package/dist/builder-eval/index.js +0 -366
- package/dist/builder-eval/index.js.map +0 -1
- package/dist/campaign/index.d.ts +0 -7454
- package/dist/campaign/index.js +0 -272
- package/dist/campaign/index.js.map +0 -1
- package/dist/chunk-32BZXMSO.js +0 -3878
- package/dist/chunk-32BZXMSO.js.map +0 -1
- package/dist/chunk-3A246TSA.js +0 -998
- package/dist/chunk-3A246TSA.js.map +0 -1
- package/dist/chunk-3RF76KTD.js +0 -84
- package/dist/chunk-3RF76KTD.js.map +0 -1
- package/dist/chunk-3YYRZDON.js +0 -45
- package/dist/chunk-3YYRZDON.js.map +0 -1
- package/dist/chunk-4I2E3LLO.js +0 -1030
- package/dist/chunk-4I2E3LLO.js.map +0 -1
- package/dist/chunk-ARU2PZFM.js +0 -312
- package/dist/chunk-ARU2PZFM.js.map +0 -1
- package/dist/chunk-BOD4O7OF.js +0 -40
- package/dist/chunk-BOD4O7OF.js.map +0 -1
- package/dist/chunk-DPZAEKA6.js +0 -880
- package/dist/chunk-DPZAEKA6.js.map +0 -1
- package/dist/chunk-DTJ6QUQB.js +0 -131
- package/dist/chunk-DTJ6QUQB.js.map +0 -1
- package/dist/chunk-GGE4NNQT.js +0 -65
- package/dist/chunk-GGE4NNQT.js.map +0 -1
- package/dist/chunk-H5UD2323.js +0 -286
- package/dist/chunk-H5UD2323.js.map +0 -1
- package/dist/chunk-HHWE3POT.js +0 -94
- package/dist/chunk-HHWE3POT.js.map +0 -1
- package/dist/chunk-HKUCJ437.js +0 -787
- package/dist/chunk-HKUCJ437.js.map +0 -1
- package/dist/chunk-JHCHEVET.js +0 -274
- package/dist/chunk-JHCHEVET.js.map +0 -1
- package/dist/chunk-JHOJHHU7.js +0 -867
- package/dist/chunk-JHOJHHU7.js.map +0 -1
- package/dist/chunk-JM2SKQMS.js +0 -750
- package/dist/chunk-JM2SKQMS.js.map +0 -1
- package/dist/chunk-JN2FCO5W.js +0 -7958
- package/dist/chunk-JN2FCO5W.js.map +0 -1
- package/dist/chunk-K4DBDHLK.js +0 -158
- package/dist/chunk-K4DBDHLK.js.map +0 -1
- package/dist/chunk-K6N6XJJX.js +0 -306
- package/dist/chunk-K6N6XJJX.js.map +0 -1
- package/dist/chunk-MA6HLL3S.js +0 -65
- package/dist/chunk-MA6HLL3S.js.map +0 -1
- package/dist/chunk-MAZ26DC7.js +0 -99
- package/dist/chunk-MAZ26DC7.js.map +0 -1
- package/dist/chunk-MOXWMGPC.js +0 -577
- package/dist/chunk-MOXWMGPC.js.map +0 -1
- package/dist/chunk-NJC7U437.js +0 -626
- package/dist/chunk-NJC7U437.js.map +0 -1
- package/dist/chunk-NPCTHQIO.js +0 -91
- package/dist/chunk-NPCTHQIO.js.map +0 -1
- package/dist/chunk-ONWEPEDO.js +0 -57
- package/dist/chunk-ONWEPEDO.js.map +0 -1
- package/dist/chunk-OYZAPX5G.js +0 -1526
- package/dist/chunk-OYZAPX5G.js.map +0 -1
- package/dist/chunk-PC4UYEBM.js +0 -166
- package/dist/chunk-PC4UYEBM.js.map +0 -1
- package/dist/chunk-PICTDURQ.js +0 -766
- package/dist/chunk-PICTDURQ.js.map +0 -1
- package/dist/chunk-PJQFMIOX.js +0 -1182
- package/dist/chunk-PJQFMIOX.js.map +0 -1
- package/dist/chunk-PXD6ZFNY.js +0 -1107
- package/dist/chunk-PXD6ZFNY.js.map +0 -1
- package/dist/chunk-PXE2VKMX.js +0 -140
- package/dist/chunk-PXE2VKMX.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -10
- package/dist/chunk-PZ5AY32C.js.map +0 -1
- package/dist/chunk-QBRSJK47.js +0 -622
- package/dist/chunk-QBRSJK47.js.map +0 -1
- package/dist/chunk-QWMPPZ3X.js +0 -550
- package/dist/chunk-QWMPPZ3X.js.map +0 -1
- package/dist/chunk-S3UZOQ5Y.js +0 -328
- package/dist/chunk-S3UZOQ5Y.js.map +0 -1
- package/dist/chunk-S5TT5R3L.js +0 -2668
- package/dist/chunk-S5TT5R3L.js.map +0 -1
- package/dist/chunk-T4SQEITX.js +0 -95
- package/dist/chunk-T4SQEITX.js.map +0 -1
- package/dist/chunk-TT4KNT67.js +0 -124
- package/dist/chunk-TT4KNT67.js.map +0 -1
- package/dist/chunk-U5CHZ5M3.js +0 -357
- package/dist/chunk-U5CHZ5M3.js.map +0 -1
- package/dist/chunk-ULOKLHIQ.js +0 -1937
- package/dist/chunk-ULOKLHIQ.js.map +0 -1
- package/dist/chunk-VI2UW6B6.js +0 -162
- package/dist/chunk-VI2UW6B6.js.map +0 -1
- package/dist/chunk-VQMK5FMP.js +0 -247
- package/dist/chunk-VQMK5FMP.js.map +0 -1
- package/dist/chunk-VSMTAMNK.js +0 -53
- package/dist/chunk-VSMTAMNK.js.map +0 -1
- package/dist/chunk-VZSRQ272.js +0 -149
- package/dist/chunk-VZSRQ272.js.map +0 -1
- package/dist/chunk-WW2A73HW.js +0 -159
- package/dist/chunk-WW2A73HW.js.map +0 -1
- package/dist/chunk-X4UCIOTZ.js +0 -136
- package/dist/chunk-X4UCIOTZ.js.map +0 -1
- package/dist/chunk-XDIRG3TO.js +0 -1266
- package/dist/chunk-XDIRG3TO.js.map +0 -1
- package/dist/chunk-XJYR7XFV.js +0 -317
- package/dist/chunk-XJYR7XFV.js.map +0 -1
- package/dist/chunk-ZET2UAYW.js +0 -89
- package/dist/chunk-ZET2UAYW.js.map +0 -1
- package/dist/chunk-ZZUXHH3R.js +0 -99
- package/dist/chunk-ZZUXHH3R.js.map +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -112
- package/dist/cli.js.map +0 -1
- package/dist/contract/index.d.ts +0 -4972
- package/dist/contract/index.js +0 -1654
- package/dist/contract/index.js.map +0 -1
- package/dist/control.d.ts +0 -1013
- package/dist/control.js +0 -34
- package/dist/control.js.map +0 -1
- package/dist/fuzz.d.ts +0 -759
- package/dist/fuzz.js +0 -714
- package/dist/fuzz.js.map +0 -1
- package/dist/hosted/index.d.ts +0 -730
- package/dist/hosted/index.js +0 -14
- package/dist/hosted/index.js.map +0 -1
- package/dist/index.d.ts +0 -16780
- package/dist/index.js +0 -12168
- package/dist/index.js.map +0 -1
- package/dist/matrix/index.d.ts +0 -155
- package/dist/matrix/index.js +0 -8
- package/dist/matrix/index.js.map +0 -1
- package/dist/meta-eval/index.d.ts +0 -1030
- package/dist/meta-eval/index.js +0 -417
- package/dist/meta-eval/index.js.map +0 -1
- package/dist/multishot/index.d.ts +0 -579
- package/dist/multishot/index.js +0 -589
- package/dist/multishot/index.js.map +0 -1
- package/dist/openapi.json +0 -992
- package/dist/pipelines/index.d.ts +0 -567
- package/dist/pipelines/index.js +0 -515
- package/dist/pipelines/index.js.map +0 -1
- package/dist/reporting.d.ts +0 -1277
- package/dist/reporting.js +0 -48
- package/dist/reporting.js.map +0 -1
- package/dist/rl.d.ts +0 -4092
- package/dist/rl.js +0 -1724
- package/dist/rl.js.map +0 -1
- package/dist/run-campaign-HNFPJET4.js +0 -14
- package/dist/run-campaign-HNFPJET4.js.map +0 -1
- package/dist/storyboard/index.d.ts +0 -279
- package/dist/storyboard/index.js +0 -767
- package/dist/storyboard/index.js.map +0 -1
- package/dist/trace-attributes.d.ts +0 -52
- package/dist/trace-attributes.js +0 -62
- package/dist/trace-attributes.js.map +0 -1
- package/dist/traces.d.ts +0 -2343
- package/dist/traces.js +0 -249
- package/dist/traces.js.map +0 -1
- package/dist/wire/index.d.ts +0 -1252
- package/dist/wire/index.js +0 -81
- package/dist/wire/index.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/wire/schemas.ts","../src/wire/rubrics.ts","../src/wire/handlers.ts","../src/wire/openapi.ts","../src/wire/rpc.ts","../src/wire/server.ts"],"sourcesContent":["/**\n * Wire-protocol schemas.\n *\n * These Zod schemas are the contract between the agent-eval runtime and\n * any non-TypeScript client (Python, Rust, Go, …). They get rendered to\n * OpenAPI by `wire/openapi.ts` and code-generators consume that spec to\n * produce typed clients in other languages.\n *\n * Rule: if it's not in this file, it isn't on the wire. Keep names and\n * shapes self-explanatory — every field has a `.describe()` so the\n * generated docs are useful without reading the source.\n */\nimport { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi'\nimport { z } from 'zod'\n\nextendZodWithOpenApi(z)\n\n// ── Building blocks ─────────────────────────────────────────────────\n\nexport const RubricDimensionSchema = z\n .object({\n id: z\n .string()\n .min(1)\n .describe('Short stable id like \"buyer_quality\" — used as the key in scoring output.'),\n description: z\n .string()\n .min(1)\n .describe('One-line plain-English meaning. Read by humans reviewing low scores.'),\n weight: z\n .number()\n .min(0)\n .default(1)\n .describe('Relative weight in the composite score. Default 1; 0 disables.'),\n min: z.number().default(0).describe('Lower bound of valid score for this dimension.'),\n max: z.number().default(1).describe('Upper bound of valid score for this dimension.'),\n })\n .openapi('RubricDimension')\n\nexport const FailureModeSchema = z\n .object({\n id: z.string().min(1).describe('Short stable id like \"ai-cadence\" — used in detection lists.'),\n description: z.string().min(1).describe('Plain-English description of the failure pattern.'),\n })\n .openapi('FailureMode')\n\n// ── Rubric ──────────────────────────────────────────────────────────\n\nexport const RubricSchema = z\n .object({\n name: z\n .string()\n .min(1)\n .describe('Stable name like \"anti-slop\" — used by clients to invoke this rubric.'),\n description: z\n .string()\n .min(1)\n .describe('What this rubric measures. Shown in /v1/rubrics listing.'),\n systemPrompt: z\n .string()\n .min(1)\n .describe(\n 'Instructs the judging LLM. Should explain the persona (e.g. \"senior engineer reviewing voice\"), what to score on, and what to return.',\n ),\n dimensions: z\n .array(RubricDimensionSchema)\n .min(1)\n .describe('Scoring axes. The composite score is a weighted sum of these.'),\n failureModes: z\n .array(FailureModeSchema)\n .default([])\n .describe('Patterns to detect; each detected mode appears in the result.failureModes list.'),\n wins: z\n .array(FailureModeSchema)\n .default([])\n .describe('Positive patterns; each detected one appears in the result.wins list.'),\n })\n .openapi('Rubric')\n\n// ── Judge call ──────────────────────────────────────────────────────\n\nexport const JudgeRequestSchema = z\n .object({\n rubricName: z\n .string()\n .optional()\n .describe('Use a built-in rubric by name. Mutually exclusive with `rubric`.'),\n rubric: RubricSchema.optional().describe(\n 'Inline rubric definition. Mutually exclusive with `rubricName`.',\n ),\n content: z\n .string()\n .min(1)\n .describe('The text being judged — a tweet, a blog post, a code snippet, anything stringly.'),\n context: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n 'Free-form metadata for the rubric to use — analytics, source URL, author, etc. Surfaced to the LLM.',\n ),\n model: z\n .string()\n .optional()\n .describe('Override the judge model (default routes via tcloud). e.g. \"claude-opus-4-7\".'),\n })\n .refine((v) => Boolean(v.rubricName) !== Boolean(v.rubric), {\n message: 'Provide exactly one of `rubricName` or `rubric`.',\n })\n .openapi('JudgeRequest')\n\nexport const JudgeResultSchema = z\n .object({\n composite: z\n .number()\n .min(0)\n .max(1)\n .describe('Weighted combination of dimension scores in 0..1. The single number to gate on.'),\n dimensions: z\n .record(z.string(), z.number())\n .describe('Per-dimension score, keyed by RubricDimension.id.'),\n failureModes: z\n .array(z.string())\n .default([])\n .describe('Failure-mode ids detected in the content (subset of rubric.failureModes ids).'),\n wins: z\n .array(z.string())\n .default([])\n .describe('Win ids detected in the content (subset of rubric.wins ids).'),\n rationale: z\n .string()\n .describe('Plain-English explanation of the score. Surfaced to the human reviewer.'),\n rubricVersion: z\n .string()\n .describe(\n 'Stable hash of the rubric used. Scores are only comparable across runs when this matches.',\n ),\n model: z.string().describe('Model that produced the judgement, for reproducibility.'),\n durationMs: z.number().int().nonnegative().describe('End-to-end wall time for this call.'),\n })\n .openapi('JudgeResult')\n\n// ── Rubric listing ──────────────────────────────────────────────────\n\nexport const RubricInfoSchema = z\n .object({\n name: z.string().describe('Pass this to /v1/judge as `rubricName`.'),\n description: z.string().describe('What this rubric measures.'),\n dimensions: z\n .array(z.object({ id: z.string(), description: z.string(), weight: z.number() }))\n .describe('The scoring axes this rubric uses, with weights.'),\n failureModes: z.array(z.string()).default([]).describe('Failure-mode ids this rubric detects.'),\n rubricVersion: z.string().describe('Stable hash — match this to compare scores across runs.'),\n })\n .openapi('RubricInfo')\n\nexport const ListRubricsResponseSchema = z\n .object({\n rubrics: z.array(RubricInfoSchema),\n })\n .openapi('ListRubricsResponse')\n\n// ── Version / health ────────────────────────────────────────────────\n\nexport const VersionResponseSchema = z\n .object({\n package: z.string().describe('Package name (always \"@tangle-network/agent-eval\").'),\n version: z.string().describe('Semver of the running server. Match your client to this.'),\n wireVersion: z\n .string()\n .describe(\n 'Wire-protocol semver. Bumps separately from package version when the schema changes.',\n ),\n apiSurface: z.array(z.string()).describe('List of supported method names.'),\n })\n .openapi('VersionResponse')\n\nexport const HealthResponseSchema = z\n .object({\n status: z.literal('ok'),\n uptimeSec: z.number(),\n })\n .openapi('HealthResponse')\n\n// ── Ingestion: production traces + user feedback ────────────────────\n\n/**\n * Minimal `TraceEvent` shape that the production runtime emits.\n * Matches `trace/schema.ts` `TraceEvent` but is duplicated here as a\n * wire schema so non-TypeScript clients can validate without depending\n * on internal types.\n */\nexport const TraceEventSchema = z\n .object({\n eventId: z.string().min(1).describe('Stable id for the event. Use ULID or UUID.'),\n runId: z.string().min(1).describe('Run this event belongs to.'),\n spanId: z.string().optional().describe('Span that emitted the event, if any.'),\n kind: z\n .enum([\n 'log',\n 'error',\n 'budget_decrement',\n 'budget_breach',\n 'state_mutation',\n 'policy_violation',\n 'redaction_applied',\n 'custom',\n ])\n .describe('Coarse event category — matches the TraceSchema v1 EventKind enum.'),\n timestamp: z\n .number()\n .int()\n .nonnegative()\n .describe('Unix millis. Must be monotonically non-decreasing within a span.'),\n payload: z\n .record(z.string(), z.unknown())\n .describe('Free-form payload — the runtime owns the shape.'),\n })\n .openapi('TraceEvent')\n\nexport const TracesIngestRequestSchema = z\n .object({\n events: z\n .array(TraceEventSchema)\n .min(1)\n .max(10_000)\n .describe('Batch of events. Max 10k per call — bigger streams should be chunked.'),\n })\n .openapi('TracesIngestRequest')\n\nexport const TracesIngestResponseSchema = z\n .object({\n accepted: z.number().int().nonnegative().describe('Number of events persisted.'),\n rejected: z\n .number()\n .int()\n .nonnegative()\n .describe('Number of events the store refused — see `errors[]` for reasons.'),\n errors: z\n .array(\n z.object({\n eventId: z.string().describe('Event id this error applies to.'),\n message: z.string().describe('Why the event was rejected.'),\n }),\n )\n .default([]),\n })\n .openapi('TracesIngestResponse')\n\nexport const FeedbackLabelSchema = z\n .object({\n id: z.string().optional(),\n source: z.enum(['user', 'judge', 'environment', 'metric', 'policy', 'system']),\n kind: z.enum([\n 'approve',\n 'reject',\n 'select',\n 'edit',\n 'rank',\n 'rate',\n 'comment',\n 'metric_outcome',\n 'policy_block',\n 'revision_request',\n ]),\n value: z.unknown(),\n reason: z.string().optional(),\n severity: z.enum(['info', 'warning', 'error', 'critical']).optional(),\n createdAt: z.string().describe('ISO-8601 UTC.'),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .openapi('FeedbackLabel')\n\nexport const FeedbackAttemptSchema = z\n .object({\n id: z.string().min(1),\n stepIndex: z.number().int().nonnegative(),\n artifactType: z.enum([\n 'text',\n 'code',\n 'plan',\n 'research',\n 'action',\n 'ui',\n 'decision',\n 'data',\n 'other',\n ]),\n artifact: z.unknown(),\n options: z.array(z.unknown()).optional(),\n proposedAction: z\n .object({\n type: z.string(),\n risk: z.enum(['low', 'medium', 'high']).optional(),\n costUsd: z.number().optional(),\n externalSideEffect: z.boolean().optional(),\n requiresApproval: z.boolean().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .optional(),\n feedback: z.array(FeedbackLabelSchema).optional(),\n createdAt: z.string(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .openapi('FeedbackAttempt')\n\nexport const FeedbackTrajectorySchema = z\n .object({\n id: z.string().min(1).describe('Stable id; idempotency key for the trajectory.'),\n projectId: z.string().optional(),\n scenarioId: z.string().optional(),\n task: z.object({\n intent: z.string().min(1),\n context: z.unknown().optional(),\n }),\n attempts: z.array(FeedbackAttemptSchema).default([]),\n labels: z.array(FeedbackLabelSchema).default([]),\n outcome: z\n .object({\n success: z.boolean().optional(),\n score: z.number().optional(),\n metrics: z.record(z.string(), z.number()).optional(),\n costUsd: z.number().optional(),\n detail: z.string().optional(),\n observedAt: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .optional(),\n split: z.enum(['train', 'dev', 'test', 'holdout']).optional(),\n tags: z.record(z.string(), z.string()).optional(),\n createdAt: z.string().describe('ISO-8601 UTC.'),\n updatedAt: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .openapi('FeedbackTrajectory')\n\nexport const FeedbackIngestResponseSchema = z\n .object({\n id: z.string().describe('Trajectory id that was persisted.'),\n persisted: z.boolean().describe('True when the trajectory was saved (idempotent on id).'),\n })\n .openapi('FeedbackIngestResponse')\n\nexport type TraceEvent = z.infer<typeof TraceEventSchema>\nexport type TracesIngestRequest = z.infer<typeof TracesIngestRequestSchema>\nexport type TracesIngestResponse = z.infer<typeof TracesIngestResponseSchema>\nexport type FeedbackTrajectory = z.infer<typeof FeedbackTrajectorySchema>\nexport type FeedbackIngestResponse = z.infer<typeof FeedbackIngestResponseSchema>\n\n// ── Errors ──────────────────────────────────────────────────────────\n\nexport const ErrorResponseSchema = z\n .object({\n error: z\n .object({\n code: z\n .string()\n .describe(\n 'Machine-readable code: \"validation_error\", \"rubric_not_found\", \"judge_error\".',\n ),\n message: z.string().describe('Human-readable message.'),\n details: z.unknown().optional().describe('Optional structured detail.'),\n })\n .describe('Errors are always wrapped in this shape across all endpoints.'),\n })\n .openapi('ErrorResponse')\n\n// ── Type exports for callers in the same package ────────────────────\n\nexport type RubricDimension = z.infer<typeof RubricDimensionSchema>\nexport type FailureMode = z.infer<typeof FailureModeSchema>\nexport type Rubric = z.infer<typeof RubricSchema>\nexport type JudgeRequest = z.infer<typeof JudgeRequestSchema>\nexport type JudgeResult = z.infer<typeof JudgeResultSchema>\nexport type RubricInfo = z.infer<typeof RubricInfoSchema>\nexport type ListRubricsResponse = z.infer<typeof ListRubricsResponseSchema>\nexport type VersionResponse = z.infer<typeof VersionResponseSchema>\nexport type ErrorResponse = z.infer<typeof ErrorResponseSchema>\n\n// ── Wire-protocol version ───────────────────────────────────────────\n\n/**\n * Bump on any breaking change to a request/response schema.\n * Non-breaking (additive) changes don't require a bump.\n */\nexport const WIRE_VERSION = '1.0.0'\n\n/**\n * Stable hash of a rubric. Used to make scores comparable across runs:\n * if the rubricVersion matches, the rubric was identical.\n */\nexport function hashRubric(rubric: Rubric): string {\n const stable = stableStringify(rubric)\n let h = 5381\n for (let i = 0; i < stable.length; i++) {\n h = (h * 33) ^ stable.charCodeAt(i)\n }\n // Unsigned 32-bit hex, prefixed with rubric name + version slot\n return `${rubric.name}@${(h >>> 0).toString(16).padStart(8, '0')}`\n}\n\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(',')}]`\n if (value && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`)\n return `{${entries.join(',')}}`\n }\n return JSON.stringify(value)\n}\n","/**\n * Built-in rubrics shipped with agent-eval.\n *\n * A rubric is a set of scoring axes plus a system prompt that tells the\n * judging LLM how to grade against those axes. Built-in rubrics are\n * curated for use cases that recur across Tangle projects — call them\n * by name from any client.\n *\n * Adding a rubric:\n * 1. Define the Rubric object below with a clear `description` and\n * named `dimensions`.\n * 2. Register it in `BUILTIN_RUBRICS` at the bottom.\n * 3. Add a test in `tests/wire/rubrics.test.ts`.\n *\n * Custom rubrics: callers pass `rubric` inline to /v1/judge instead of\n * `rubricName` — see schemas.ts.\n */\nimport type { Rubric } from './schemas'\nimport { hashRubric } from './schemas'\n\n// ── anti-slop ───────────────────────────────────────────────────────\n// Voice/style judge tuned for technical-buyer audiences. Used by the\n// Postiz autoresearch loop and any content-quality gate.\n\nconst ANTI_SLOP: Rubric = {\n name: 'anti-slop',\n description:\n 'Voice and signal quality for content aimed at senior engineers. Catches AI cadence, marketing tone, and engagement-bait shapes.',\n systemPrompt: `You are evaluating a piece of content written for senior engineers and technical founders.\n\nYou score three things:\n- buyer_quality (0..1): would a senior engineer in the target ICP find this worth their attention? High = specific, earned, technically interesting. Low = generic, hyped, off-target.\n- voice (0..1): does it read like a person who built the thing, or like AI/marketing copy?\n- signal (0..1): does it contain a non-obvious detail, constraint, or claim a reader couldn't get from the public docs?\n\nDetect failure modes (return ids matching):\n- ai-cadence: rule-of-three openings, em-dash flourish, \"Let me explain\", \"Here's the thing\", AI rhythm\n- marketing-tone: \"We're excited to announce\", \"thrilled\", \"delighted\", \"game-changer\", buzzword stack\n- vague-claim: technical claim without a specific component, file, or measurement\n- no-hook: opening doesn't earn attention from the target reader\n- engagement-bait: \"agree?\", \"thoughts?\", listicles, controversy-fishing, hook-detail-pitch\n- off-icp: content shape would attract motivational/grift/hype audiences instead of buyers\n- stale-claim: repeats a positioning line we've used many times this month\n\nDetect wins (return ids matching):\n- specific-component: names a real file, component, or measurement\n- earned-detail: shares a non-obvious detail not derivable from public docs\n- constraint-articulated: names a real tradeoff and the side chosen\n- honest-failure: describes a real failure mode and what was done about it\n\nReturn ONLY JSON matching the response schema. Be conservative — most content has 0-1 wins and 1-2 failure modes, not many of each.`,\n dimensions: [\n {\n id: 'buyer_quality',\n description: 'Would the target buyer find this worth attention?',\n weight: 0.5,\n min: 0,\n max: 1,\n },\n {\n id: 'voice',\n description: 'Does it sound like a builder, not AI or marketing?',\n weight: 0.3,\n min: 0,\n max: 1,\n },\n {\n id: 'signal',\n description: 'Non-obvious detail, constraint, or claim?',\n weight: 0.2,\n min: 0,\n max: 1,\n },\n ],\n failureModes: [\n { id: 'ai-cadence', description: 'AI-rhythm openings and transitions' },\n { id: 'marketing-tone', description: 'Buzzwords, hype, corporate-PR voice' },\n { id: 'vague-claim', description: 'Technical claim without specifics' },\n { id: 'no-hook', description: 'Opening fails to earn attention' },\n { id: 'engagement-bait', description: 'Listicle/controversy/agree-pattern' },\n { id: 'off-icp', description: 'Voice attracts the wrong audience' },\n { id: 'stale-claim', description: 'Reuses an over-used positioning line' },\n ],\n wins: [\n { id: 'specific-component', description: 'Names a real file/component/number' },\n { id: 'earned-detail', description: 'Detail not in public docs' },\n { id: 'constraint-articulated', description: 'Names a real tradeoff' },\n { id: 'honest-failure', description: 'Describes a real failure honestly' },\n ],\n}\n\n// ── Registry ────────────────────────────────────────────────────────\n\nexport const BUILTIN_RUBRICS: Record<string, Rubric> = {\n 'anti-slop': ANTI_SLOP,\n}\n\n/** Get a built-in rubric by name, or undefined. */\nexport function getBuiltinRubric(name: string): Rubric | undefined {\n return BUILTIN_RUBRICS[name]\n}\n\n/** List built-in rubrics with their stable versions. */\nexport function listBuiltinRubrics() {\n return Object.values(BUILTIN_RUBRICS).map((r) => ({\n name: r.name,\n description: r.description,\n dimensions: r.dimensions.map((d) => ({\n id: d.id,\n description: d.description,\n weight: d.weight,\n })),\n failureModes: r.failureModes.map((f) => f.id),\n rubricVersion: hashRubric(r),\n }))\n}\n","/**\n * Pure handler functions — the \"business logic\" behind every wire-protocol\n * method. The HTTP server (`server.ts`) and the stdio RPC (`rpc.ts`) both\n * call these. Tests call these directly without spinning a server.\n *\n * Each handler:\n * - Takes a parsed request (already Zod-validated by the transport).\n * - Returns a result that matches the response schema.\n * - Throws `WireError` for caller-fixable errors (404, 400, 422).\n * - Lets unexpected errors bubble — the transport maps them to 500.\n */\n\nimport { CostLedger, type CostLedgerHandle } from '../cost-ledger'\nimport type { FeedbackTrajectoryStore } from '../feedback-trajectory'\nimport {\n callLlmJson,\n costReceiptFromLlm,\n costReceiptFromLlmError,\n type LlmCallRequest,\n type LlmClientOptions,\n maximumChargeForLlmRequest,\n} from '../llm-client'\nimport type { TraceEvent as InternalTraceEvent } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\nimport { getBuiltinRubric, listBuiltinRubrics } from './rubrics'\nimport {\n type FeedbackIngestResponse,\n hashRubric,\n type JudgeRequest,\n type JudgeResult,\n type ListRubricsResponse,\n type Rubric,\n type TracesIngestRequest,\n type TracesIngestResponse,\n type VersionResponse,\n WIRE_VERSION,\n type FeedbackTrajectory as WireFeedbackTrajectory,\n} from './schemas'\n\n/** Caller-fixable error. The transport renders this to 4xx + ErrorResponse. */\nexport class WireError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number = 400,\n public readonly details?: unknown,\n ) {\n super(message)\n this.name = 'WireError'\n }\n}\n\n// ── judge ───────────────────────────────────────────────────────────\n\n/** The JSON schema we ask the judging LLM to fill in. */\nfunction judgeOutputSchema(rubric: Rubric) {\n return {\n name: 'JudgeOutput',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n dimensions: {\n type: 'object',\n additionalProperties: false,\n properties: Object.fromEntries(\n rubric.dimensions.map((d) => [\n d.id,\n { type: 'number', minimum: d.min, maximum: d.max },\n ]),\n ),\n required: rubric.dimensions.map((d) => d.id),\n },\n failureModes: {\n type: 'array',\n items: { type: 'string', enum: rubric.failureModes.map((f) => f.id) },\n },\n wins: {\n type: 'array',\n items: { type: 'string', enum: rubric.wins.map((w) => w.id) },\n },\n rationale: { type: 'string' },\n },\n required: ['dimensions', 'rationale'],\n } as Record<string, unknown>,\n }\n}\n\ninterface JudgeOutput {\n dimensions: Record<string, number>\n failureModes?: string[]\n wins?: string[]\n rationale: string\n}\n\nfunction validateJudgeOutput(value: unknown, rubric: Rubric): JudgeOutput {\n if (!value || typeof value !== 'object') {\n throw new WireError('judge_error', 'Judge returned malformed output.', 500, value)\n }\n const raw = value as Record<string, unknown>\n const rawDimensions = raw.dimensions\n if (!rawDimensions || typeof rawDimensions !== 'object' || Array.isArray(rawDimensions)) {\n throw new WireError('judge_error', 'Judge returned malformed dimensions.', 500, value)\n }\n\n const dimensions: Record<string, number> = {}\n const dimensionRecord = rawDimensions as Record<string, unknown>\n for (const dim of rubric.dimensions) {\n const score = dimensionRecord[dim.id]\n if (\n typeof score !== 'number' ||\n !Number.isFinite(score) ||\n score < dim.min ||\n score > dim.max\n ) {\n throw new WireError(\n 'judge_error',\n `Judge returned invalid score for dimension \"${dim.id}\".`,\n 500,\n value,\n )\n }\n dimensions[dim.id] = score\n }\n\n const allowedFailures = new Set(rubric.failureModes.map((mode) => mode.id))\n const allowedWins = new Set(rubric.wins.map((win) => win.id))\n const failureModes = validateIdArray(raw.failureModes, allowedFailures, 'failureModes', value)\n const wins = validateIdArray(raw.wins, allowedWins, 'wins', value)\n if (typeof raw.rationale !== 'string' || raw.rationale.trim().length === 0) {\n throw new WireError('judge_error', 'Judge returned missing rationale.', 500, value)\n }\n\n return { dimensions, failureModes, wins, rationale: raw.rationale }\n}\n\nfunction validateIdArray(\n raw: unknown,\n allowed: Set<string>,\n field: 'failureModes' | 'wins',\n original: unknown,\n): string[] {\n if (raw === undefined) return []\n if (!Array.isArray(raw)) {\n throw new WireError('judge_error', `Judge returned non-array ${field}.`, 500, original)\n }\n const out: string[] = []\n for (const item of raw) {\n if (typeof item !== 'string' || !allowed.has(item)) {\n throw new WireError(\n 'judge_error',\n `Judge returned unknown ${field} id \"${String(item)}\".`,\n 500,\n original,\n )\n }\n out.push(item)\n }\n return out\n}\n\nfunction compositeScore(dimensions: Record<string, number>, rubric: Rubric): number {\n let weighted = 0\n let totalWeight = 0\n for (const dim of rubric.dimensions) {\n const raw = dimensions[dim.id] ?? 0\n const range = dim.max - dim.min || 1\n const normalized = Math.max(0, Math.min(1, (raw - dim.min) / range))\n weighted += normalized * dim.weight\n totalWeight += dim.weight\n }\n return totalWeight > 0 ? weighted / totalWeight : 0\n}\n\nfunction buildJudgePrompt(content: string, context: unknown): string {\n const ctx = context && Object.keys(context as object).length ? JSON.stringify(context) : ''\n return [\n `CONTENT TO JUDGE:`,\n content,\n '',\n ctx ? `CONTEXT (metadata, analytics, etc.):` : '',\n ctx ? ctx : '',\n ]\n .filter(Boolean)\n .join('\\n')\n}\n\nconst DEFAULT_JUDGE_MODEL = 'claude-sonnet-4-6'\n\nexport interface HandleJudgeOptions {\n costLedger?: CostLedgerHandle\n costPhase?: string\n llm?: LlmClientOptions\n signal?: AbortSignal\n}\n\nexport async function handleJudge(\n req: JudgeRequest,\n options: HandleJudgeOptions = {},\n): Promise<JudgeResult> {\n // Resolve rubric\n let rubric: Rubric\n if (req.rubricName) {\n const found = getBuiltinRubric(req.rubricName)\n if (!found) {\n throw new WireError('rubric_not_found', `No built-in rubric named \"${req.rubricName}\".`, 404)\n }\n rubric = found\n } else if (req.rubric) {\n rubric = req.rubric\n } else {\n // refine() in the schema should already have caught this — defense in depth\n throw new WireError('validation_error', 'Provide either `rubricName` or `rubric`.', 422)\n }\n\n const startedAt = Date.now()\n const model = req.model ?? DEFAULT_JUDGE_MODEL\n\n const request = {\n model,\n messages: [\n { role: 'system', content: rubric.systemPrompt },\n { role: 'user', content: buildJudgePrompt(req.content, req.context) },\n ],\n jsonSchema: judgeOutputSchema(rubric),\n temperature: 0.0,\n maxTokens: 4_000,\n timeoutMs: 60_000,\n } satisfies LlmCallRequest\n const ledger = options.costLedger ?? new CostLedger()\n const paid = await ledger.runPaidCall({\n channel: 'judge',\n phase: options.costPhase ?? 'wire.judge',\n actor: `wire.${req.rubricName ?? 'inline'}`,\n model,\n maximumCharge: maximumChargeForLlmRequest(request, options.llm),\n signal: options.signal,\n execute: (signal, callId) =>\n callLlmJson<JudgeOutput>(request, {\n ...options.llm,\n signal,\n idempotencyKey: callId,\n }),\n receipt: ({ result }) => costReceiptFromLlm(result),\n receiptFromError: costReceiptFromLlmError,\n })\n if (!paid.succeeded) throw paid.error\n const { value, result } = paid.value\n\n const output = validateJudgeOutput(value, rubric)\n\n const composite = compositeScore(output.dimensions, rubric)\n const durationMs = Date.now() - startedAt\n\n return {\n composite,\n dimensions: output.dimensions,\n failureModes: output.failureModes ?? [],\n wins: output.wins ?? [],\n rationale: output.rationale,\n rubricVersion: hashRubric(rubric),\n model: result.model,\n durationMs,\n }\n}\n\n// ── listRubrics ─────────────────────────────────────────────────────\n\nexport function handleListRubrics(): ListRubricsResponse {\n return { rubrics: listBuiltinRubrics() }\n}\n\n// ── version ─────────────────────────────────────────────────────────\n\nimport { readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nlet CACHED_VERSION: string | undefined\n\nfunction readPackageVersion(): string {\n if (CACHED_VERSION) return CACHED_VERSION\n // Walk up from this file looking for the nearest package.json.\n // In dist/ this is dist/.., in src/wire/ this is ../../package.json.\n const here = dirname(fileURLToPath(import.meta.url))\n const candidates = [\n resolve(here, '..', '..', 'package.json'), // src/wire → repo root\n resolve(here, '..', 'package.json'), // dist → repo root\n ]\n for (const path of candidates) {\n try {\n const pkg = JSON.parse(readFileSync(path, 'utf-8')) as { version?: string }\n if (pkg.version) {\n CACHED_VERSION = pkg.version\n return pkg.version\n }\n } catch {\n // try next\n }\n }\n return '0.0.0-unknown'\n}\n\nexport function handleVersion(): VersionResponse {\n return {\n package: '@tangle-network/agent-eval',\n version: readPackageVersion(),\n wireVersion: WIRE_VERSION,\n apiSurface: ['judge', 'listRubrics', 'version', 'feedback.ingest', 'traces.ingest'],\n }\n}\n\n// ── Ingestion handlers ───────────────────────────────────────────────\n\n/**\n * Pluggable stores the wire layer routes ingestion writes into. Both\n * are optional — when omitted, the corresponding endpoint returns 503.\n *\n * Production deployments wire a `FileSystemTraceStore` and\n * `FileSystemFeedbackTrajectoryStore` here. Tests substitute in-memory\n * stores.\n */\nexport interface IngestionStores {\n traceStore?: TraceStore\n feedbackStore?: FeedbackTrajectoryStore\n}\n\n/**\n * `POST /v1/traces/ingest` — accept a batch of `TraceEvent`s from the\n * production runtime. Best-effort: each event is appended independently;\n * one bad event does not poison the batch.\n *\n * Idempotency: the underlying store is append-only; consumers retrying\n * the same payload will get duplicate events. Consumers should\n * de-duplicate by `eventId` downstream — production traces frequently\n * land via at-least-once buses (Kafka, SQS) where dedup is unavoidable.\n */\nexport async function handleTracesIngest(\n req: TracesIngestRequest,\n stores: IngestionStores,\n): Promise<TracesIngestResponse> {\n if (!stores.traceStore) {\n throw new WireError(\n 'service_unavailable',\n 'No trace store configured on this server. Pass `traceStore` to `createApp`.',\n 503,\n )\n }\n const errors: Array<{ eventId: string; message: string }> = []\n let accepted = 0\n for (const event of req.events) {\n try {\n // The wire `TraceEvent` is structurally identical to the internal one.\n await stores.traceStore.appendEvent(event as InternalTraceEvent)\n accepted++\n } catch (err) {\n errors.push({\n eventId: event.eventId,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n return { accepted, rejected: errors.length, errors }\n}\n\n/**\n * `POST /v1/feedback` — accept a single `FeedbackTrajectory` from the\n * production runtime. Idempotent on `id`: re-posting the same trajectory\n * replaces the prior record.\n */\nexport async function handleFeedbackIngest(\n req: WireFeedbackTrajectory,\n stores: IngestionStores,\n): Promise<FeedbackIngestResponse> {\n if (!stores.feedbackStore) {\n throw new WireError(\n 'service_unavailable',\n 'No feedback store configured on this server. Pass `feedbackStore` to `createApp`.',\n 503,\n )\n }\n // The wire `FeedbackTrajectory` aligns 1:1 with the internal type;\n // cast through `unknown` since the wire schema is a Zod-inferred\n // structural type with optional fields the internal store consumes.\n await stores.feedbackStore.save(req as unknown as Parameters<FeedbackTrajectoryStore['save']>[0])\n return { id: req.id, persisted: true }\n}\n","/**\n * Build an OpenAPI spec from the wire schemas.\n *\n * The spec is the contract that other-language clients (Python, Rust,\n * Go, …) generate from. There is no hand-written client — clients are\n * derived artifacts of this file plus `schemas.ts`.\n *\n * Run `pnpm openapi` (defined in package.json) to write the spec to\n * `dist/openapi.json`. CI uses that file to regenerate the Python\n * client and gate the dual-publish workflow.\n */\nimport { OpenAPIRegistry, OpenApiGeneratorV31 } from '@asteasolutions/zod-to-openapi'\nimport type { OpenAPIObject } from 'openapi3-ts/oas31'\n\nimport {\n ErrorResponseSchema,\n FeedbackIngestResponseSchema,\n FeedbackTrajectorySchema,\n HealthResponseSchema,\n JudgeRequestSchema,\n JudgeResultSchema,\n ListRubricsResponseSchema,\n TracesIngestRequestSchema,\n TracesIngestResponseSchema,\n VersionResponseSchema,\n WIRE_VERSION,\n} from './schemas'\n\nexport function buildOpenApi(packageVersion: string): OpenAPIObject {\n const registry = new OpenAPIRegistry()\n\n // Components — each schema becomes a $ref-able component\n registry.register('JudgeRequest', JudgeRequestSchema)\n registry.register('JudgeResult', JudgeResultSchema)\n registry.register('ListRubricsResponse', ListRubricsResponseSchema)\n registry.register('VersionResponse', VersionResponseSchema)\n registry.register('HealthResponse', HealthResponseSchema)\n registry.register('ErrorResponse', ErrorResponseSchema)\n registry.register('TracesIngestRequest', TracesIngestRequestSchema)\n registry.register('TracesIngestResponse', TracesIngestResponseSchema)\n registry.register('FeedbackTrajectory', FeedbackTrajectorySchema)\n registry.register('FeedbackIngestResponse', FeedbackIngestResponseSchema)\n\n // Routes\n registry.registerPath({\n method: 'post',\n path: '/v1/judge',\n summary: 'Score a piece of content against a rubric',\n description:\n 'Runs the judging LLM with the named (or inline) rubric and returns dimension scores, detected failure modes, wins, and a composite score in 0..1.',\n request: {\n body: {\n content: {\n 'application/json': { schema: JudgeRequestSchema },\n },\n },\n },\n responses: {\n 200: {\n description: 'Successful judgement',\n content: { 'application/json': { schema: JudgeResultSchema } },\n },\n 400: {\n description: 'Validation error',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 404: {\n description: 'Rubric not found',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 500: {\n description: 'Judge error',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'get',\n path: '/v1/rubrics',\n summary: 'List built-in rubrics',\n description:\n 'Returns every rubric registered server-side, with their dimensions and stable rubricVersion hash.',\n responses: {\n 200: {\n description: 'Listing',\n content: { 'application/json': { schema: ListRubricsResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'get',\n path: '/v1/version',\n summary: 'Server and wire-protocol version',\n description: 'Match your client version to `version`; check `wireVersion` for compatibility.',\n responses: {\n 200: {\n description: 'Version info',\n content: { 'application/json': { schema: VersionResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'get',\n path: '/healthz',\n summary: 'Liveness check',\n responses: {\n 200: {\n description: 'OK',\n content: { 'application/json': { schema: HealthResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'post',\n path: '/v1/traces/ingest',\n summary: 'Ingest a batch of production TraceEvents',\n description:\n 'Append a batch of TraceEvents to the configured TraceStore. Accepts application/json ({events:[...]}) or application/x-ndjson (one event per line). Returns counts of accepted + rejected events.',\n request: {\n body: {\n content: {\n 'application/json': { schema: TracesIngestRequestSchema },\n 'application/x-ndjson': { schema: TracesIngestRequestSchema },\n },\n },\n },\n responses: {\n 200: {\n description: 'Ingestion summary',\n content: { 'application/json': { schema: TracesIngestResponseSchema } },\n },\n 400: {\n description: 'Validation error',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 401: {\n description: 'Unauthorized (when bearer auth is configured)',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 503: {\n description: 'No trace store configured',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'post',\n path: '/v1/feedback',\n summary: 'Ingest a FeedbackTrajectory from production',\n description:\n 'Persist a single FeedbackTrajectory. Idempotent on trajectory.id — re-posting replaces the prior record. Used by production runtimes to forward user 👍/👎/edits into the eval substrate.',\n request: {\n body: {\n content: {\n 'application/json': { schema: FeedbackTrajectorySchema },\n },\n },\n },\n responses: {\n 200: {\n description: 'Persisted',\n content: { 'application/json': { schema: FeedbackIngestResponseSchema } },\n },\n 400: {\n description: 'Validation error',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 401: {\n description: 'Unauthorized (when bearer auth is configured)',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 503: {\n description: 'No feedback store configured',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n },\n })\n\n const generator = new OpenApiGeneratorV31(registry.definitions)\n const doc = generator.generateDocument({\n openapi: '3.1.0',\n info: {\n title: '@tangle-network/agent-eval — wire protocol',\n version: packageVersion,\n description: `HTTP and stdio RPC interface to agent-eval. The TypeScript runtime is the source of truth; this spec is the contract that cross-language clients (Python, Rust, Go) generate from.\n\nWire-protocol version: ${WIRE_VERSION}. Bumps on breaking changes to request/response schemas.`,\n contact: { name: 'Tangle Network', url: 'https://github.com/tangle-network/agent-eval' },\n license: { name: 'MIT' },\n },\n servers: [{ url: 'http://localhost:5005', description: 'Local agent-eval serve' }],\n })\n const rubricRef = { $ref: '#/components/schemas/Rubric' } as const\n const commonJudgeFields = {\n content: { type: 'string', minLength: 1 },\n context: { type: 'object', additionalProperties: true },\n model: { type: 'string' },\n } as const\n doc.components ??= {}\n doc.components.schemas ??= {}\n doc.components.schemas.JudgeRequest = {\n oneOf: [\n {\n type: 'object',\n additionalProperties: false,\n required: ['rubricName', 'content'],\n properties: {\n rubricName: { type: 'string', minLength: 1 },\n ...commonJudgeFields,\n },\n },\n {\n type: 'object',\n additionalProperties: false,\n required: ['rubric', 'content'],\n properties: {\n rubric: rubricRef,\n ...commonJudgeFields,\n },\n },\n ],\n description: 'Judge request. Provide exactly one of rubricName or rubric.',\n }\n return doc\n}\n","/**\n * stdio RPC transport.\n *\n * For batch / cron use without a running server. The Python client falls\n * back to this when no server is reachable.\n *\n * Protocol (line-delimited JSON over stdin/stdout):\n * IN: one JSON object on stdin: {\"method\":\"judge\",\"params\":{...}}\n * OUT: one JSON object on stdout: {\"result\":{...}} or {\"error\":{...}}\n *\n * One request per process invocation. To pipeline many calls, the client\n * writes JSONL to stdin and reads JSONL from stdout — see batch mode below.\n */\nimport { handleJudge, handleListRubrics, handleVersion, WireError } from './handlers'\nimport { JudgeRequestSchema } from './schemas'\n\ninterface RpcRequest {\n method: 'judge' | 'listRubrics' | 'version'\n params?: unknown\n}\n\ninterface RpcSuccess {\n result: unknown\n}\n\ninterface RpcError {\n error: { code: string; message: string; details?: unknown }\n}\n\nexport async function dispatchRpc(req: RpcRequest): Promise<RpcSuccess | RpcError> {\n try {\n switch (req.method) {\n case 'judge': {\n const parsed = JudgeRequestSchema.safeParse(req.params)\n if (!parsed.success) {\n return {\n error: {\n code: 'validation_error',\n message: 'params did not match JudgeRequest schema.',\n details: parsed.error.issues,\n },\n }\n }\n return { result: await handleJudge(parsed.data) }\n }\n case 'listRubrics':\n return { result: handleListRubrics() }\n case 'version':\n return { result: handleVersion() }\n default:\n return {\n error: {\n code: 'unknown_method',\n message: `No such method: ${(req as { method: string }).method}`,\n },\n }\n }\n } catch (err) {\n if (err instanceof WireError) {\n return { error: { code: err.code, message: err.message, details: err.details } }\n }\n const message = err instanceof Error ? err.message : String(err)\n return { error: { code: 'internal_error', message } }\n }\n}\n\n// ── stdin/stdout driver ─────────────────────────────────────────────\n\nasync function readAll(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = []\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as string))\n }\n return Buffer.concat(chunks).toString('utf-8')\n}\n\n/** Read one JSON request from stdin, write one JSON response to stdout. */\nexport async function runRpcOnce(method?: string): Promise<number> {\n const raw = await readAll(process.stdin)\n let req: RpcRequest\n try {\n const body = JSON.parse(raw)\n req = method ? { method: method as RpcRequest['method'], params: body } : (body as RpcRequest)\n } catch (err) {\n process.stdout.write(\n `${JSON.stringify({\n error: {\n code: 'parse_error',\n message: `stdin was not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n },\n })}\\n`,\n )\n return 1\n }\n const out = await dispatchRpc(req)\n process.stdout.write(`${JSON.stringify(out)}\\n`)\n return 'error' in out ? 1 : 0\n}\n\n/** Read JSONL requests from stdin, write JSONL responses to stdout. */\nexport async function runRpcBatch(method?: string): Promise<number> {\n const raw = await readAll(process.stdin)\n const lines = raw.split('\\n').filter((l) => l.trim().length > 0)\n let exitCode = 0\n for (const line of lines) {\n let req: RpcRequest\n try {\n const body = JSON.parse(line)\n req = method ? { method: method as RpcRequest['method'], params: body } : (body as RpcRequest)\n } catch (err) {\n process.stdout.write(\n `${JSON.stringify({\n error: {\n code: 'parse_error',\n message: `line was not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n },\n })}\\n`,\n )\n exitCode = 1\n continue\n }\n const out = await dispatchRpc(req)\n process.stdout.write(`${JSON.stringify(out)}\\n`)\n if ('error' in out) exitCode = 1\n }\n return exitCode\n}\n","/**\n * HTTP transport for the wire protocol.\n *\n * Hono + @hono/node-server. Every endpoint:\n * 1. Validates the request against its Zod schema.\n * 2. Calls the matching handler in `handlers.ts`.\n * 3. Renders 4xx for `WireError` with structured body, 500 for unexpected.\n *\n * The server holds optional `IngestionStores` (passed to `createApp`)\n * to receive production traces and user feedback. With no stores wired,\n * the ingestion endpoints return 503 — read endpoints (`/v1/judge`,\n * `/v1/rubrics`, `/v1/version`) remain fully functional.\n *\n * Run via `agent-eval serve --port 5005`.\n */\nimport { type ServerType, serve } from '@hono/node-server'\nimport { Hono } from 'hono'\nimport { cors } from 'hono/cors'\n\nimport {\n handleFeedbackIngest,\n handleJudge,\n handleListRubrics,\n handleTracesIngest,\n handleVersion,\n type IngestionStores,\n WireError,\n} from './handlers'\nimport { buildOpenApi } from './openapi'\nimport { FeedbackTrajectorySchema, JudgeRequestSchema, TracesIngestRequestSchema } from './schemas'\n\nconst STARTED_AT = Date.now()\n\nexport interface CreateAppOptions {\n /** Stores wired to the ingestion endpoints. */\n stores?: IngestionStores\n /**\n * Bearer-token auth. When provided, every endpoint EXCEPT `/healthz`\n * and `/v1/version` requires `Authorization: Bearer <token>`. The\n * token may be a static string OR a function for time-bounded /\n * rotating tokens.\n *\n * Recommended for any server that accepts ingestion writes from the\n * public internet. Read-only deployments may omit it.\n */\n auth?: {\n bearer: string | ((token: string) => boolean | Promise<boolean>)\n }\n}\n\nconst AUTH_EXEMPT_PATHS = new Set(['/healthz', '/v1/version', '/openapi.json'])\n\nexport function createApp(opts: CreateAppOptions = {}) {\n const app = new Hono()\n\n app.use('*', cors())\n\n // Bearer-token middleware (only attached when configured).\n if (opts.auth) {\n const verify = opts.auth.bearer\n app.use('*', async (c, next) => {\n const path = new URL(c.req.url).pathname\n if (AUTH_EXEMPT_PATHS.has(path)) return next()\n const raw = c.req.header('authorization') ?? ''\n const match = raw.match(/^Bearer\\s+(.+)$/i)\n if (!match) {\n throw new WireError('unauthorized', 'Missing or malformed Authorization header.', 401)\n }\n const token = match[1] as string\n const ok = typeof verify === 'string' ? token === verify : await verify(token)\n if (!ok) {\n throw new WireError('unauthorized', 'Invalid bearer token.', 401)\n }\n return next()\n })\n }\n\n app.onError((err, c) => {\n if (err instanceof WireError) {\n const status = err.status as 400 | 401 | 404 | 422 | 500 | 503\n return c.json(\n { error: { code: err.code, message: err.message, details: err.details } },\n status,\n )\n }\n // Unexpected — log and return generic 500 without leaking internals.\n console.error('[agent-eval] unhandled error:', err)\n return c.json({ error: { code: 'internal_error', message: 'Internal server error.' } }, 500)\n })\n\n // ── Health ──\n app.get('/healthz', (c) =>\n c.json({ status: 'ok' as const, uptimeSec: (Date.now() - STARTED_AT) / 1000 }),\n )\n\n // ── Version ──\n app.get('/v1/version', (c) => c.json(handleVersion()))\n\n // ── Rubrics ──\n app.get('/v1/rubrics', (c) => c.json(handleListRubrics()))\n\n // ── Judge ──\n app.post('/v1/judge', async (c) => {\n const raw = await c.req.json().catch(() => null)\n if (raw == null) {\n throw new WireError('validation_error', 'Request body must be JSON.', 400)\n }\n const parsed = JudgeRequestSchema.safeParse(raw)\n if (!parsed.success) {\n throw new WireError(\n 'validation_error',\n 'Request did not match JudgeRequest schema.',\n 400,\n parsed.error.issues,\n )\n }\n const result = await handleJudge(parsed.data)\n return c.json(result)\n })\n\n // ── Traces ingest (NDJSON-friendly: accepts either {events:[...]} or NDJSON) ──\n app.post('/v1/traces/ingest', async (c) => {\n const contentType = c.req.header('content-type') ?? ''\n let payload: unknown\n if (contentType.includes('application/x-ndjson')) {\n const text = await c.req.text()\n const events = text\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n try {\n return JSON.parse(line)\n } catch {\n throw new WireError(\n 'validation_error',\n 'NDJSON line did not parse as JSON.',\n 400,\n line.slice(0, 200),\n )\n }\n })\n payload = { events }\n } else {\n payload = await c.req.json().catch(() => null)\n }\n if (payload == null) {\n throw new WireError('validation_error', 'Request body must be JSON or NDJSON.', 400)\n }\n const parsed = TracesIngestRequestSchema.safeParse(payload)\n if (!parsed.success) {\n throw new WireError(\n 'validation_error',\n 'Request did not match TracesIngestRequest schema.',\n 400,\n parsed.error.issues,\n )\n }\n const result = await handleTracesIngest(parsed.data, opts.stores ?? {})\n return c.json(result)\n })\n\n // ── Feedback ingest ──\n app.post('/v1/feedback', async (c) => {\n const raw = await c.req.json().catch(() => null)\n if (raw == null) {\n throw new WireError('validation_error', 'Request body must be JSON.', 400)\n }\n const parsed = FeedbackTrajectorySchema.safeParse(raw)\n if (!parsed.success) {\n throw new WireError(\n 'validation_error',\n 'Request did not match FeedbackTrajectory schema.',\n 400,\n parsed.error.issues,\n )\n }\n const result = await handleFeedbackIngest(parsed.data, opts.stores ?? {})\n return c.json(result)\n })\n\n // ── OpenAPI spec ──\n app.get('/openapi.json', (c) => c.json(buildOpenApi(handleVersion().version)))\n\n return app\n}\n\nexport interface ServeOptions extends CreateAppOptions {\n /** Default 5005. */\n port?: number\n /** Default '127.0.0.1'. Set to '0.0.0.0' to listen on all interfaces. */\n host?: string\n}\n\nexport function startServer(opts: ServeOptions = {}): ServerType {\n const app = createApp(opts)\n const port = opts.port ?? 5005\n const host = opts.host ?? '127.0.0.1'\n return serve({ fetch: app.fetch, port, hostname: host }, ({ address, port: actualPort }) => {\n // eslint-disable-next-line no-console\n console.log(`[agent-eval] serving on http://${address}:${actualPort}`)\n })\n}\n\nexport interface StartedServer {\n server: ServerType\n /** The OS-assigned port. When opts.port was 0, this is the actual port the\n * kernel bound — callers that need to dial back (smoke tests, sidecars\n * registering with a parent) read this rather than guessing a free port. */\n port: number\n /** Resolved host the server bound to (defaults to 127.0.0.1). */\n host: string\n /** Close the server. Resolves once active connections have drained. */\n close(): Promise<void>\n}\n\n/**\n * Promise-returning variant of `startServer` that resolves once the server is\n * listening and surfaces the resolved bound port. Use this from smoke tests\n * (`startServerAsync({ port: 0 })`) and any caller that needs to dial back.\n */\nexport function startServerAsync(opts: ServeOptions = {}): Promise<StartedServer> {\n const app = createApp(opts)\n const port = opts.port ?? 5005\n const host = opts.host ?? '127.0.0.1'\n return new Promise((resolve, reject) => {\n let settled = false\n let server: ServerType | undefined\n server = serve({ fetch: app.fetch, port, hostname: host }, ({ address, port: actualPort }) => {\n if (settled) return\n settled = true\n // eslint-disable-next-line no-console\n console.log(`[agent-eval] serving on http://${address}:${actualPort}`)\n resolve({\n server: server!,\n port: actualPort,\n host: address,\n close: () =>\n new Promise<void>((res, rej) => {\n server!.close((err) => (err ? rej(err) : res()))\n }),\n })\n })\n server.on('error', (err) => {\n if (settled) return\n settled = true\n reject(err)\n })\n })\n}\n"],"mappings":"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","names":["result","resolve"]}
|
package/dist/chunk-ARU2PZFM.js
DELETED
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
pearsonR
|
|
3
|
-
} from "./chunk-PJQFMIOX.js";
|
|
4
|
-
|
|
5
|
-
// src/rl/verifiable-reward.ts
|
|
6
|
-
var DEFAULT_DETERMINISTIC_LAYERS = /* @__PURE__ */ new Set([
|
|
7
|
-
"install",
|
|
8
|
-
"typecheck",
|
|
9
|
-
"build",
|
|
10
|
-
"lint",
|
|
11
|
-
"test",
|
|
12
|
-
"compile",
|
|
13
|
-
"schema",
|
|
14
|
-
"sandbox",
|
|
15
|
-
"unit_tests",
|
|
16
|
-
"integration_tests"
|
|
17
|
-
]);
|
|
18
|
-
var DEFAULT_SOURCE_FOR = (name) => {
|
|
19
|
-
const lower = name.toLowerCase();
|
|
20
|
-
if (lower.includes("test")) return "test";
|
|
21
|
-
if (lower.includes("compile") || lower.includes("build") || lower.includes("typecheck") || lower.includes("lint"))
|
|
22
|
-
return "compile";
|
|
23
|
-
if (lower.includes("schema")) return "schema";
|
|
24
|
-
if (lower.includes("sandbox")) return "sandbox";
|
|
25
|
-
if (lower.includes("judge") || lower.includes("semantic")) return "judge";
|
|
26
|
-
return "composite";
|
|
27
|
-
};
|
|
28
|
-
function extractVerifiableReward(report, opts = {}) {
|
|
29
|
-
const deterministicSet = new Set(opts.deterministicLayers ?? [...DEFAULT_DETERMINISTIC_LAYERS]);
|
|
30
|
-
const sourceFor = opts.sourceFor ?? DEFAULT_SOURCE_FOR;
|
|
31
|
-
const fallbackToJudge = opts.fallbackToJudge ?? true;
|
|
32
|
-
const judgeFloor = opts.judgeConfidenceFloor ?? 0.7;
|
|
33
|
-
const deterministic = report.layers.filter(
|
|
34
|
-
(l) => deterministicSet.has(l.layer) && typeof l.score === "number" && Number.isFinite(l.score)
|
|
35
|
-
);
|
|
36
|
-
if (deterministic.length === 1) {
|
|
37
|
-
const layer = deterministic[0];
|
|
38
|
-
const value = clamp01(layer.score);
|
|
39
|
-
return {
|
|
40
|
-
value,
|
|
41
|
-
source: sourceFor(layer.layer),
|
|
42
|
-
determinism: "deterministic",
|
|
43
|
-
confidence: 1,
|
|
44
|
-
origin: layer.layer,
|
|
45
|
-
components: { [layer.layer]: value },
|
|
46
|
-
breakdown: layerBreakdown(layer)
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
if (deterministic.length > 1) {
|
|
50
|
-
let num = 0;
|
|
51
|
-
let denom = 0;
|
|
52
|
-
const components = {};
|
|
53
|
-
for (const l of deterministic) {
|
|
54
|
-
const w = l.detail?.weight ?? 1;
|
|
55
|
-
num += w * (l.score ?? 0);
|
|
56
|
-
denom += w;
|
|
57
|
-
components[l.layer] = l.score;
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
value: denom === 0 ? 0 : clamp01(num / denom),
|
|
61
|
-
source: "composite",
|
|
62
|
-
determinism: "deterministic",
|
|
63
|
-
confidence: 1,
|
|
64
|
-
origin: deterministic.map((l) => l.layer).join("+"),
|
|
65
|
-
components,
|
|
66
|
-
breakdown: { ...components }
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
if (!fallbackToJudge) return null;
|
|
70
|
-
const judge = report.layers.find(
|
|
71
|
-
(l) => typeof l.score === "number" && Number.isFinite(l.score) && sourceFor(l.layer) === "judge"
|
|
72
|
-
) ?? report.layers.find((l) => typeof l.score === "number" && Number.isFinite(l.score));
|
|
73
|
-
if (!judge) return null;
|
|
74
|
-
const confFromDetail = judge.detail?.confidence;
|
|
75
|
-
const judgeValue = clamp01(judge.score);
|
|
76
|
-
return {
|
|
77
|
-
value: judgeValue,
|
|
78
|
-
source: "judge",
|
|
79
|
-
determinism: "probabilistic",
|
|
80
|
-
confidence: typeof confFromDetail === "number" ? confFromDetail : judgeFloor,
|
|
81
|
-
origin: judge.layer,
|
|
82
|
-
components: { [judge.layer]: judgeValue },
|
|
83
|
-
breakdown: layerBreakdown(judge)
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function extractVerifiableRewardsFromRecords(runs, opts = {}) {
|
|
87
|
-
const sourceFor = opts.sourceFor ?? DEFAULT_SOURCE_FOR;
|
|
88
|
-
const deterministicSet = new Set(opts.deterministicLayers ?? [...DEFAULT_DETERMINISTIC_LAYERS]);
|
|
89
|
-
const fallbackToJudge = opts.fallbackToJudge ?? true;
|
|
90
|
-
const judgeFloor = opts.judgeConfidenceFloor ?? 0.7;
|
|
91
|
-
return runs.map((run) => {
|
|
92
|
-
const layerScores = [];
|
|
93
|
-
for (const [k, v] of Object.entries(run.outcome.raw)) {
|
|
94
|
-
if (k.startsWith("layer.") && !k.includes(".", 6) && typeof v === "number" && Number.isFinite(v)) {
|
|
95
|
-
layerScores.push({ name: k.slice("layer.".length), score: v });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
const det = layerScores.filter((l) => deterministicSet.has(l.name));
|
|
99
|
-
if (det.length === 1) {
|
|
100
|
-
const layer = det[0];
|
|
101
|
-
const value = clamp01(layer.score);
|
|
102
|
-
return {
|
|
103
|
-
runId: run.runId,
|
|
104
|
-
reward: {
|
|
105
|
-
value,
|
|
106
|
-
source: sourceFor(layer.name),
|
|
107
|
-
determinism: "deterministic",
|
|
108
|
-
confidence: 1,
|
|
109
|
-
origin: layer.name,
|
|
110
|
-
components: { [layer.name]: value }
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
if (det.length > 1) {
|
|
115
|
-
const value = det.reduce((s, l) => s + l.score, 0) / det.length;
|
|
116
|
-
const components = Object.fromEntries(
|
|
117
|
-
det.map((l) => [l.name, l.score])
|
|
118
|
-
);
|
|
119
|
-
return {
|
|
120
|
-
runId: run.runId,
|
|
121
|
-
reward: {
|
|
122
|
-
value: clamp01(value),
|
|
123
|
-
source: "composite",
|
|
124
|
-
determinism: "deterministic",
|
|
125
|
-
confidence: 1,
|
|
126
|
-
origin: det.map((l) => l.name).join("+"),
|
|
127
|
-
components,
|
|
128
|
-
breakdown: { ...components }
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
if (!fallbackToJudge) return { runId: run.runId, reward: null };
|
|
133
|
-
const primary = run.outcome.holdoutScore ?? run.outcome.searchScore;
|
|
134
|
-
if (typeof primary !== "number" || !Number.isFinite(primary)) {
|
|
135
|
-
return { runId: run.runId, reward: null };
|
|
136
|
-
}
|
|
137
|
-
const primaryValue = clamp01(primary);
|
|
138
|
-
return {
|
|
139
|
-
runId: run.runId,
|
|
140
|
-
reward: {
|
|
141
|
-
value: primaryValue,
|
|
142
|
-
source: "judge",
|
|
143
|
-
determinism: "probabilistic",
|
|
144
|
-
confidence: judgeFloor,
|
|
145
|
-
origin: "run.outcome.score",
|
|
146
|
-
components: { "run.outcome.score": primaryValue }
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
function filterDeterministicallyRewarded(runs, opts = {}) {
|
|
152
|
-
const rewarded = extractVerifiableRewardsFromRecords(runs, { ...opts, fallbackToJudge: false });
|
|
153
|
-
const out = [];
|
|
154
|
-
for (let i = 0; i < runs.length; i++) {
|
|
155
|
-
const r = rewarded[i];
|
|
156
|
-
if (r.reward && r.reward.determinism === "deterministic") {
|
|
157
|
-
out.push({ run: runs[i], reward: r.reward });
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return out;
|
|
161
|
-
}
|
|
162
|
-
function clamp01(x) {
|
|
163
|
-
if (!Number.isFinite(x)) return 0;
|
|
164
|
-
return Math.max(0, Math.min(1, x));
|
|
165
|
-
}
|
|
166
|
-
function layerBreakdown(l) {
|
|
167
|
-
const out = {};
|
|
168
|
-
if (l.diagnostics) {
|
|
169
|
-
for (const [k, v] of Object.entries(l.diagnostics)) {
|
|
170
|
-
if (typeof v === "number" && Number.isFinite(v)) out[k] = v;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return out;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// src/rl/reward-hacking.ts
|
|
177
|
-
var DEFAULT_PROXY = (r) => {
|
|
178
|
-
const v = r.outcome.holdoutScore ?? r.outcome.searchScore;
|
|
179
|
-
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
180
|
-
};
|
|
181
|
-
function detectRewardHacking(input) {
|
|
182
|
-
const proxyOf = input.proxyOf ?? DEFAULT_PROXY;
|
|
183
|
-
const truthOf = input.truthOf;
|
|
184
|
-
const sus = input.thresholds?.suspect ?? 0.3;
|
|
185
|
-
const gam = input.thresholds?.gaming ?? 0.6;
|
|
186
|
-
const runs = input.runs.filter((r) => proxyOf(r) !== null);
|
|
187
|
-
const n = runs.length;
|
|
188
|
-
if (n < 4) {
|
|
189
|
-
return {
|
|
190
|
-
findings: [],
|
|
191
|
-
verdict: "clean",
|
|
192
|
-
n,
|
|
193
|
-
rationale: [`fewer than 4 runs with proxy reward (n=${n}); insufficient evidence`]
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
const windowSize = Math.max(1, input.windowSize ?? Math.min(50, Math.floor(n / 2)));
|
|
197
|
-
const before = runs.slice(0, n - windowSize);
|
|
198
|
-
const after = runs.slice(n - windowSize);
|
|
199
|
-
const findings = [];
|
|
200
|
-
if (truthOf) {
|
|
201
|
-
const beforeProxy = before.map(proxyOf).filter((v) => typeof v === "number");
|
|
202
|
-
const afterProxy = after.map(proxyOf).filter((v) => typeof v === "number");
|
|
203
|
-
const beforeTruth = before.map(truthOf).filter((v) => typeof v === "number");
|
|
204
|
-
const afterTruth = after.map(truthOf).filter((v) => typeof v === "number");
|
|
205
|
-
if (beforeProxy.length >= 2 && afterProxy.length >= 2 && beforeTruth.length >= 2 && afterTruth.length >= 2) {
|
|
206
|
-
const proxyDelta = mean(afterProxy) - mean(beforeProxy);
|
|
207
|
-
const truthDelta = mean(afterTruth) - mean(beforeTruth);
|
|
208
|
-
const gap = Math.max(0, proxyDelta - truthDelta);
|
|
209
|
-
const severity = clamp012(gap * 5);
|
|
210
|
-
findings.push({
|
|
211
|
-
signal: "reward_divergence",
|
|
212
|
-
severity,
|
|
213
|
-
message: severity >= sus ? `proxy reward rose by ${proxyDelta.toFixed(3)} while truth changed by ${truthDelta.toFixed(3)} \u2014 potential Goodhart` : `proxy and truth moved together (proxy ${proxyDelta.toFixed(3)}, truth ${truthDelta.toFixed(3)})`,
|
|
214
|
-
detail: {
|
|
215
|
-
proxyDelta,
|
|
216
|
-
truthDelta,
|
|
217
|
-
gap,
|
|
218
|
-
beforeN: beforeProxy.length,
|
|
219
|
-
afterN: afterProxy.length
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
{
|
|
225
|
-
const beforeP = before.map(proxyOf).filter((v) => typeof v === "number");
|
|
226
|
-
const afterP = after.map(proxyOf).filter((v) => typeof v === "number");
|
|
227
|
-
if (beforeP.length >= 4 && afterP.length >= 4) {
|
|
228
|
-
const ks = ksStatistic(beforeP, afterP);
|
|
229
|
-
const severity = clamp012(ks - 0.2);
|
|
230
|
-
findings.push({
|
|
231
|
-
signal: "distribution_shift",
|
|
232
|
-
severity,
|
|
233
|
-
message: severity >= sus ? `KS=${ks.toFixed(3)} between before/after windows \u2014 distributional shift large` : `KS=${ks.toFixed(3)} between before/after windows \u2014 within-distribution drift`,
|
|
234
|
-
detail: { ks, beforeN: beforeP.length, afterN: afterP.length }
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
{
|
|
239
|
-
const secondaryOf = input.secondaryRewardOf ?? defaultSecondary(input.verifiableRewardOptions);
|
|
240
|
-
const aligned = runs.map((r) => ({ p: proxyOf(r), s: secondaryOf(r) })).filter(
|
|
241
|
-
(x) => typeof x.p === "number" && typeof x.s === "number"
|
|
242
|
-
);
|
|
243
|
-
if (aligned.length >= 4) {
|
|
244
|
-
const ps = aligned.map((x) => x.p);
|
|
245
|
-
const ss = aligned.map((x) => x.s);
|
|
246
|
-
const r = pearsonR(ps, ss);
|
|
247
|
-
const severity = clamp012(0.5 - Math.max(0, r));
|
|
248
|
-
findings.push({
|
|
249
|
-
signal: "reward_disagreement",
|
|
250
|
-
severity,
|
|
251
|
-
message: severity >= sus ? `proxy and independent secondary reward correlate \u03C1=${r.toFixed(3)} \u2014 possibly hacking proxy` : `proxy and secondary reward correlate \u03C1=${r.toFixed(3)}`,
|
|
252
|
-
detail: { pearson: r, n: aligned.length }
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
{
|
|
257
|
-
const detRuns = filterDeterministicallyRewarded(runs, input.verifiableRewardOptions ?? {});
|
|
258
|
-
if (detRuns.length >= 4) {
|
|
259
|
-
const detBefore = detRuns.slice(0, Math.floor(detRuns.length / 2));
|
|
260
|
-
const detAfter = detRuns.slice(Math.floor(detRuns.length / 2));
|
|
261
|
-
const detDelta = mean(detAfter.map((r) => r.reward.value)) - mean(detBefore.map((r) => r.reward.value));
|
|
262
|
-
const proxyDelta = mean(after.map(proxyOf).filter((v) => typeof v === "number")) - mean(before.map(proxyOf).filter((v) => typeof v === "number"));
|
|
263
|
-
const driftGap = Math.max(0, proxyDelta - detDelta);
|
|
264
|
-
const severity = clamp012(driftGap * 5);
|
|
265
|
-
findings.push({
|
|
266
|
-
signal: "judge_drift",
|
|
267
|
-
severity,
|
|
268
|
-
message: severity >= sus ? `judge proxy +${proxyDelta.toFixed(3)} while deterministic reward +${detDelta.toFixed(3)} \u2014 judge drifting up without verifiable backing` : `judge and deterministic rewards move in step (judge ${proxyDelta.toFixed(3)}, det ${detDelta.toFixed(3)})`,
|
|
269
|
-
detail: { proxyDelta, detDelta, driftGap, n: detRuns.length }
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
const maxSev = findings.reduce((m, f) => Math.max(m, f.severity), 0);
|
|
274
|
-
const verdict = maxSev >= gam ? "gaming" : maxSev >= sus ? "suspect" : "clean";
|
|
275
|
-
const rationale = findings.filter((f) => f.severity >= sus).map((f) => `${f.signal}: severity ${f.severity.toFixed(2)} \u2014 ${f.message}`);
|
|
276
|
-
if (rationale.length === 0) rationale.push("no signals fired above suspect threshold");
|
|
277
|
-
return { findings, verdict, rationale, n };
|
|
278
|
-
}
|
|
279
|
-
function mean(xs) {
|
|
280
|
-
if (xs.length === 0) return 0;
|
|
281
|
-
return xs.reduce((s, x) => s + x, 0) / xs.length;
|
|
282
|
-
}
|
|
283
|
-
function clamp012(x) {
|
|
284
|
-
if (!Number.isFinite(x)) return 0;
|
|
285
|
-
return Math.max(0, Math.min(1, x));
|
|
286
|
-
}
|
|
287
|
-
function ksStatistic(a, b) {
|
|
288
|
-
const sortedA = [...a].sort((x, y) => x - y);
|
|
289
|
-
const sortedB = [...b].sort((x, y) => x - y);
|
|
290
|
-
const all = [.../* @__PURE__ */ new Set([...sortedA, ...sortedB])].sort((x, y) => x - y);
|
|
291
|
-
let max = 0;
|
|
292
|
-
for (const v of all) {
|
|
293
|
-
const fa = sortedA.filter((x) => x <= v).length / sortedA.length;
|
|
294
|
-
const fb = sortedB.filter((x) => x <= v).length / sortedB.length;
|
|
295
|
-
max = Math.max(max, Math.abs(fa - fb));
|
|
296
|
-
}
|
|
297
|
-
return max;
|
|
298
|
-
}
|
|
299
|
-
function defaultSecondary(verifiableOpts) {
|
|
300
|
-
return (run) => {
|
|
301
|
-
const filtered = filterDeterministicallyRewarded([run], verifiableOpts ?? {});
|
|
302
|
-
return filtered.length === 1 ? filtered[0].reward.value : null;
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
export {
|
|
307
|
-
extractVerifiableReward,
|
|
308
|
-
extractVerifiableRewardsFromRecords,
|
|
309
|
-
filterDeterministicallyRewarded,
|
|
310
|
-
detectRewardHacking
|
|
311
|
-
};
|
|
312
|
-
//# sourceMappingURL=chunk-ARU2PZFM.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rl/verifiable-reward.ts","../src/rl/reward-hacking.ts"],"sourcesContent":["/**\n * Verifiable reward channel.\n *\n * For RL on coding / math / theorem-proving / structured-output tasks, the\n * reward signal is *decidable* — a test passes or fails, a proof checks or\n * doesn't, an output validates against a schema or doesn't. These rewards\n * are dramatically more useful for RL training than LLM-judge scores\n * because they don't drift, can't be Goodhart-gamed by the policy in the\n * same way, and don't require a separate calibration loop.\n *\n * The `MultiLayerVerifier` already produces this signal — it just doesn't\n * surface it in a shape that's clean enough for RL training. This module\n * wraps the verifier output so consumers can:\n *\n * 1. Extract a clean `VerifiableReward` from a `VerificationReport`\n * 2. Distinguish *deterministic* rewards (compile, test, schema) from\n * *probabilistic* rewards (judge) so they can be weighted differently\n * in the RL training step\n * 3. Filter `RunRecord[]` to only those with a verifiable reward,\n * producing the clean training set that DeepSeek-R1-style GRPO and\n * AlphaProof-style search both depend on\n *\n * Why this matters: every credible 2025-2026 frontier RL result on coding\n * agents leans on verifiable reward (DeepSeek-R1 GRPO on test pass-rate,\n * o-series RL on math/code, AlphaProof on Lean kernel checking). Mixing\n * judge scores into the reward signal poisons the gradient. This module\n * is the seam.\n */\n\nimport type { LayerResult, VerificationReport } from '../multi-layer-verifier'\nimport type { RunRecord } from '../run-record'\n\nexport type VerifiableRewardSource =\n | 'compile' // typecheck / build / lint passed\n | 'test' // unit / integration test pass-rate\n | 'schema' // structured output validates\n | 'sandbox' // sandbox exec exit code\n | 'judge' // LLM judge — probabilistic, included for completeness\n | 'composite' // weighted blend across multiple of the above\n\nexport interface VerifiableReward {\n /** Scalar in [0, 1]. The RL training signal. */\n value: number\n /** What produced the reward — different sources have different determinism. */\n source: VerifiableRewardSource\n /**\n * Determinism class. `'deterministic'` rewards are repeatable byte-for-byte\n * given the same inputs (compile, test, schema validation, sandbox exit code).\n * `'probabilistic'` rewards depend on a stochastic component (LLM judge).\n * Mixing these in the same training batch without separation is a known\n * footgun in production RLHF pipelines.\n */\n determinism: 'deterministic' | 'probabilistic'\n /**\n * Confidence in the reward value. For deterministic sources this is 1.0\n * (the bit either flipped or didn't). For judge sources this is the\n * judge-reported confidence or — when missing — a calibrated prior.\n */\n confidence: number\n /** The layer / judge id that produced the signal, for provenance. */\n origin: string\n /**\n * Per-source contribution to `value`, keyed by layer/judge id. Single-source\n * rewards carry one entry (`{ [origin]: value }`); composite rewards carry\n * every contributing layer's score — the anti-scalar-collapse surface RL\n * consumers weight per-source instead of trusting one blended number.\n */\n components: Record<string, number>\n /**\n * @deprecated Read `components` for per-source reward values. Kept for\n * published-API compatibility: single-source rewards carry the layer's\n * diagnostics here (e.g. `{ tests_passed: 7 }`); composite rewards carry\n * the same per-layer scores `components` now holds.\n */\n breakdown?: Record<string, number>\n}\n\nexport interface VerifiableRewardExtractionOptions {\n /**\n * Which layers count as deterministic-reward sources. The verifier doesn't\n * tag layers as \"this is verifiable\"; the caller declares it via this list\n * (or via the layer name → source mapping). Default treats common names\n * (`install`, `typecheck`, `build`, `lint`, `test`, `compile`, `schema`,\n * `sandbox`) as deterministic.\n */\n deterministicLayers?: string[]\n /**\n * Map layer name → reward source. Defaults to a sensible string-match.\n */\n sourceFor?: (layerName: string) => VerifiableRewardSource\n /**\n * Whether to fall back to a probabilistic (judge) reward when no\n * deterministic layer produced a numeric score. Default `true`. Set to\n * `false` for \"deterministic-only\" training pipelines that should\n * discard runs without a verifiable signal.\n */\n fallbackToJudge?: boolean\n /**\n * Default confidence for probabilistic (judge) rewards when the judge\n * doesn't report one. Default `0.7`.\n */\n judgeConfidenceFloor?: number\n}\n\nconst DEFAULT_DETERMINISTIC_LAYERS = new Set([\n 'install',\n 'typecheck',\n 'build',\n 'lint',\n 'test',\n 'compile',\n 'schema',\n 'sandbox',\n 'unit_tests',\n 'integration_tests',\n])\n\nconst DEFAULT_SOURCE_FOR = (name: string): VerifiableRewardSource => {\n const lower = name.toLowerCase()\n if (lower.includes('test')) return 'test'\n if (\n lower.includes('compile') ||\n lower.includes('build') ||\n lower.includes('typecheck') ||\n lower.includes('lint')\n )\n return 'compile'\n if (lower.includes('schema')) return 'schema'\n if (lower.includes('sandbox')) return 'sandbox'\n if (lower.includes('judge') || lower.includes('semantic')) return 'judge'\n return 'composite'\n}\n\n/**\n * Extract a `VerifiableReward` from a `VerificationReport`.\n *\n * Strategy: prefer the deterministic layers (in order: test → compile →\n * schema → sandbox), fall back to the judge layer if `fallbackToJudge` is\n * true, return `null` if no signal qualifies. When multiple deterministic\n * layers contribute, return a `'composite'` source with a weighted blend.\n */\nexport function extractVerifiableReward(\n report: VerificationReport,\n opts: VerifiableRewardExtractionOptions = {},\n): VerifiableReward | null {\n const deterministicSet = new Set(opts.deterministicLayers ?? [...DEFAULT_DETERMINISTIC_LAYERS])\n const sourceFor = opts.sourceFor ?? DEFAULT_SOURCE_FOR\n const fallbackToJudge = opts.fallbackToJudge ?? true\n const judgeFloor = opts.judgeConfidenceFloor ?? 0.7\n\n const deterministic = report.layers.filter(\n (l) => deterministicSet.has(l.layer) && typeof l.score === 'number' && Number.isFinite(l.score),\n )\n\n if (deterministic.length === 1) {\n const layer = deterministic[0]!\n const value = clamp01(layer.score!)\n return {\n value,\n source: sourceFor(layer.layer),\n determinism: 'deterministic',\n confidence: 1,\n origin: layer.layer,\n components: { [layer.layer]: value },\n breakdown: layerBreakdown(layer),\n }\n }\n\n if (deterministic.length > 1) {\n // Composite: weighted blend by `Layer.weight` if present, else equal.\n let num = 0\n let denom = 0\n const components: Record<string, number> = {}\n for (const l of deterministic) {\n const w = (l.detail?.weight as number | undefined) ?? 1\n num += w * (l.score ?? 0)\n denom += w\n components[l.layer] = l.score!\n }\n return {\n value: denom === 0 ? 0 : clamp01(num / denom),\n source: 'composite',\n determinism: 'deterministic',\n confidence: 1,\n origin: deterministic.map((l) => l.layer).join('+'),\n components,\n breakdown: { ...components },\n }\n }\n\n if (!fallbackToJudge) return null\n\n const judge =\n report.layers.find(\n (l) =>\n typeof l.score === 'number' && Number.isFinite(l.score) && sourceFor(l.layer) === 'judge',\n ) ?? report.layers.find((l) => typeof l.score === 'number' && Number.isFinite(l.score))\n\n if (!judge) return null\n\n const confFromDetail = judge.detail?.confidence as number | undefined\n const judgeValue = clamp01(judge.score!)\n return {\n value: judgeValue,\n source: 'judge',\n determinism: 'probabilistic',\n confidence: typeof confFromDetail === 'number' ? confFromDetail : judgeFloor,\n origin: judge.layer,\n components: { [judge.layer]: judgeValue },\n breakdown: layerBreakdown(judge),\n }\n}\n\n/**\n * Extract verifiable rewards from `RunRecord[]` produced via the\n * `verificationReportToRunRecord` adapter (which encodes per-layer scores\n * in `outcome.raw['layer.<name>']`). For records that don't carry layer\n * scores, returns `null` for that record.\n *\n * This is the canonical bridge from \"campaign-shaped artifacts\" to\n * \"RL-training-ready reward signals\": every record that has a clean\n * verifiable reward becomes a training datum, every record that doesn't\n * gets filtered out (or kept with `'probabilistic'` determinism for\n * separate downstream handling).\n */\nexport function extractVerifiableRewardsFromRecords(\n runs: RunRecord[],\n opts: VerifiableRewardExtractionOptions = {},\n): Array<{ runId: string; reward: VerifiableReward | null }> {\n const sourceFor = opts.sourceFor ?? DEFAULT_SOURCE_FOR\n const deterministicSet = new Set(opts.deterministicLayers ?? [...DEFAULT_DETERMINISTIC_LAYERS])\n const fallbackToJudge = opts.fallbackToJudge ?? true\n const judgeFloor = opts.judgeConfidenceFloor ?? 0.7\n\n return runs.map((run) => {\n // Recover per-layer scores from outcome.raw['layer.<name>']\n const layerScores: Array<{ name: string; score: number }> = []\n for (const [k, v] of Object.entries(run.outcome.raw)) {\n if (\n k.startsWith('layer.') &&\n !k.includes('.', 6) &&\n typeof v === 'number' &&\n Number.isFinite(v)\n ) {\n layerScores.push({ name: k.slice('layer.'.length), score: v })\n }\n }\n const det = layerScores.filter((l) => deterministicSet.has(l.name))\n\n if (det.length === 1) {\n const layer = det[0]!\n const value = clamp01(layer.score)\n return {\n runId: run.runId,\n reward: {\n value,\n source: sourceFor(layer.name),\n determinism: 'deterministic',\n confidence: 1,\n origin: layer.name,\n components: { [layer.name]: value },\n },\n }\n }\n if (det.length > 1) {\n const value = det.reduce((s, l) => s + l.score, 0) / det.length\n const components: Record<string, number> = Object.fromEntries(\n det.map((l) => [l.name, l.score]),\n )\n return {\n runId: run.runId,\n reward: {\n value: clamp01(value),\n source: 'composite',\n determinism: 'deterministic',\n confidence: 1,\n origin: det.map((l) => l.name).join('+'),\n components,\n breakdown: { ...components },\n },\n }\n }\n if (!fallbackToJudge) return { runId: run.runId, reward: null }\n\n // Probabilistic fallback: use the run's primary score.\n const primary = run.outcome.holdoutScore ?? run.outcome.searchScore\n if (typeof primary !== 'number' || !Number.isFinite(primary)) {\n return { runId: run.runId, reward: null }\n }\n const primaryValue = clamp01(primary)\n return {\n runId: run.runId,\n reward: {\n value: primaryValue,\n source: 'judge',\n determinism: 'probabilistic',\n confidence: judgeFloor,\n origin: 'run.outcome.score',\n components: { 'run.outcome.score': primaryValue },\n },\n }\n })\n}\n\n/** Filter `RunRecord[]` to those with deterministic verifiable rewards. */\nexport function filterDeterministicallyRewarded(\n runs: RunRecord[],\n opts: VerifiableRewardExtractionOptions = {},\n): Array<{ run: RunRecord; reward: VerifiableReward }> {\n const rewarded = extractVerifiableRewardsFromRecords(runs, { ...opts, fallbackToJudge: false })\n const out: Array<{ run: RunRecord; reward: VerifiableReward }> = []\n for (let i = 0; i < runs.length; i++) {\n const r = rewarded[i]!\n if (r.reward && r.reward.determinism === 'deterministic') {\n out.push({ run: runs[i]!, reward: r.reward })\n }\n }\n return out\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction clamp01(x: number): number {\n if (!Number.isFinite(x)) return 0\n return Math.max(0, Math.min(1, x))\n}\n\nfunction layerBreakdown(l: LayerResult): Record<string, number> {\n const out: Record<string, number> = {}\n if (l.diagnostics) {\n for (const [k, v] of Object.entries(l.diagnostics)) {\n if (typeof v === 'number' && Number.isFinite(v)) out[k] = v\n }\n }\n return out\n}\n","/**\n * Reward hacking / Goodhart detection.\n *\n * Goodhart's Law says: when a measure becomes a target, it ceases to be\n * a good measure. In RLHF and agentic-RL settings this is the dominant\n * failure mode — the policy learns to produce outputs that score well on\n * the proxy reward (judge, rubric, test pass-rate) without producing\n * the underlying capability the proxy was meant to track.\n *\n * Krakovna et al. (2020, \"Specification Gaming Examples in AI\") and the\n * subsequent RLHF reward-hacking literature (Skalse et al. 2022, Kim et al.\n * 2023) converge on a few diagnostic signatures:\n *\n * 1. **Reward divergence:** the proxy reward grows while the held-out\n * ground-truth signal stagnates or drops. Predictive validity over\n * time captures this.\n * 2. **Distributional shift in outputs:** after RL, the policy produces\n * outputs that no longer match the reference distribution — usually\n * because it found a high-reward attractor that's degenerate (e.g.\n * one-token responses, repetition, formatting tricks).\n * 3. **Disagreement between independent rewards:** if you train on\n * reward A and a held-out independent reward B drops sharply, you're\n * probably hacking A.\n * 4. **Calibration drift:** the verifiable / deterministic component of\n * the reward is stable; the probabilistic / judge component drifts up\n * while the deterministic component doesn't. The judge is being\n * gamed.\n *\n * This module ships explicit detectors for all four signatures, plus a\n * combined verdict. The output is diagnostic — actionable signals,\n * not autoreject — because each signature has known false positives\n * (e.g., a policy that genuinely improves can show distributional shift).\n *\n * Differs from `rubricPredictiveValidity` (which is a *standing* check on\n * whether rubrics correlate with deployment outcomes) — this is a\n * *temporal* check on whether the reward-vs-truth gap is *widening over\n * time during a training run*.\n */\n\nimport type { RunRecord } from '../run-record'\nimport { pearsonR } from '../statistics'\nimport {\n filterDeterministicallyRewarded,\n type VerifiableRewardExtractionOptions,\n} from './verifiable-reward'\n\nexport type RewardHackingSignal =\n | 'reward_divergence'\n | 'distribution_shift'\n | 'reward_disagreement'\n | 'judge_drift'\n\nexport interface RewardHackingFinding {\n signal: RewardHackingSignal\n /** Severity in [0, 1]. >0.5 = strong signal. */\n severity: number\n message: string\n /** Numeric evidence the consumer can render. */\n detail: Record<string, number>\n}\n\nexport interface RewardHackingReport {\n findings: RewardHackingFinding[]\n /**\n * Composite verdict. `'clean'` if every signal severity < 0.3;\n * `'suspect'` if at least one ≥ 0.3 but none ≥ 0.6; `'gaming'` if any ≥ 0.6.\n */\n verdict: 'clean' | 'suspect' | 'gaming'\n /** Rationale for the verdict, ready to paste into an audit log. */\n rationale: string[]\n /** Number of paired (proxy, truth) data points the report saw. */\n n: number\n}\n\nexport interface DetectRewardHackingInput {\n /**\n * Run records ordered by recency (oldest first). The detector segments\n * them into prefix/suffix windows to compute \"did the gap widen.\"\n */\n runs: RunRecord[]\n /**\n * The metric the policy was trained to optimize. Should be present on\n * `outcome.raw` or `outcome.holdoutScore`. Default reads `outcome.holdoutScore`.\n */\n proxyOf?: (run: RunRecord) => number | null\n /**\n * The held-out ground-truth metric. For RL on coding, this is typically\n * test pass-rate. For RLHF, it's downstream task performance or human\n * preference. For knowledge tasks, it's an independently-graded score.\n */\n truthOf?: (run: RunRecord) => number | null\n /**\n * Independent secondary reward. Used for the `reward_disagreement`\n * signal. Default uses the verifiable reward extractor (deterministic\n * sources only).\n */\n secondaryRewardOf?: (run: RunRecord) => number | null\n /**\n * Window size — how many of the most recent runs count as the \"after\"\n * cohort. Default min(50, half the runs).\n */\n windowSize?: number\n /**\n * Severity threshold to flag a signal. Default 0.3 (suspect) and 0.6\n * (gaming).\n */\n thresholds?: { suspect?: number; gaming?: number }\n /**\n * Verifiable-reward options used for the secondary-reward fallback.\n */\n verifiableRewardOptions?: VerifiableRewardExtractionOptions\n}\n\nconst DEFAULT_PROXY = (r: RunRecord): number | null => {\n const v = r.outcome.holdoutScore ?? r.outcome.searchScore\n return typeof v === 'number' && Number.isFinite(v) ? v : null\n}\n\nexport function detectRewardHacking(input: DetectRewardHackingInput): RewardHackingReport {\n const proxyOf = input.proxyOf ?? DEFAULT_PROXY\n const truthOf = input.truthOf\n const sus = input.thresholds?.suspect ?? 0.3\n const gam = input.thresholds?.gaming ?? 0.6\n\n const runs = input.runs.filter((r) => proxyOf(r) !== null)\n const n = runs.length\n if (n < 4) {\n return {\n findings: [],\n verdict: 'clean',\n n,\n rationale: [`fewer than 4 runs with proxy reward (n=${n}); insufficient evidence`],\n }\n }\n const windowSize = Math.max(1, input.windowSize ?? Math.min(50, Math.floor(n / 2)))\n const before = runs.slice(0, n - windowSize)\n const after = runs.slice(n - windowSize)\n\n const findings: RewardHackingFinding[] = []\n\n // ── Signal 1: reward divergence (proxy ↑ while truth flat or ↓) ──────\n if (truthOf) {\n const beforeProxy = before.map(proxyOf).filter((v): v is number => typeof v === 'number')\n const afterProxy = after.map(proxyOf).filter((v): v is number => typeof v === 'number')\n const beforeTruth = before.map(truthOf).filter((v): v is number => typeof v === 'number')\n const afterTruth = after.map(truthOf).filter((v): v is number => typeof v === 'number')\n if (\n beforeProxy.length >= 2 &&\n afterProxy.length >= 2 &&\n beforeTruth.length >= 2 &&\n afterTruth.length >= 2\n ) {\n const proxyDelta = mean(afterProxy) - mean(beforeProxy)\n const truthDelta = mean(afterTruth) - mean(beforeTruth)\n // Divergence: proxy goes up while truth goes flat or down.\n // Severity = max(0, (proxyDelta - truthDelta)) — bigger gap = bigger signal.\n const gap = Math.max(0, proxyDelta - truthDelta)\n const severity = clamp01(gap * 5) // scale: 0.2 absolute gap → severity 1.0\n findings.push({\n signal: 'reward_divergence',\n severity,\n message:\n severity >= sus\n ? `proxy reward rose by ${proxyDelta.toFixed(3)} while truth changed by ${truthDelta.toFixed(3)} — potential Goodhart`\n : `proxy and truth moved together (proxy ${proxyDelta.toFixed(3)}, truth ${truthDelta.toFixed(3)})`,\n detail: {\n proxyDelta,\n truthDelta,\n gap,\n beforeN: beforeProxy.length,\n afterN: afterProxy.length,\n },\n })\n }\n }\n\n // ── Signal 2: distributional shift in outputs (KS on score distributions) ──\n {\n const beforeP = before.map(proxyOf).filter((v): v is number => typeof v === 'number')\n const afterP = after.map(proxyOf).filter((v): v is number => typeof v === 'number')\n if (beforeP.length >= 4 && afterP.length >= 4) {\n const ks = ksStatistic(beforeP, afterP)\n // KS statistic: bigger = more shift. We're agnostic about direction;\n // genuine improvement ALSO produces shift, so this signal is\n // contributory rather than load-bearing.\n const severity = clamp01(ks - 0.2)\n findings.push({\n signal: 'distribution_shift',\n severity,\n message:\n severity >= sus\n ? `KS=${ks.toFixed(3)} between before/after windows — distributional shift large`\n : `KS=${ks.toFixed(3)} between before/after windows — within-distribution drift`,\n detail: { ks, beforeN: beforeP.length, afterN: afterP.length },\n })\n }\n }\n\n // ── Signal 3: reward disagreement (proxy vs independent secondary) ────\n {\n const secondaryOf = input.secondaryRewardOf ?? defaultSecondary(input.verifiableRewardOptions)\n const aligned = runs\n .map((r) => ({ p: proxyOf(r), s: secondaryOf(r) }))\n .filter(\n (x): x is { p: number; s: number } => typeof x.p === 'number' && typeof x.s === 'number',\n )\n if (aligned.length >= 4) {\n const ps = aligned.map((x) => x.p)\n const ss = aligned.map((x) => x.s)\n const r = pearsonR(ps, ss)\n // Disagreement: low or negative correlation between primary proxy\n // reward and an independent secondary signal.\n const severity = clamp01(0.5 - Math.max(0, r))\n findings.push({\n signal: 'reward_disagreement',\n severity,\n message:\n severity >= sus\n ? `proxy and independent secondary reward correlate ρ=${r.toFixed(3)} — possibly hacking proxy`\n : `proxy and secondary reward correlate ρ=${r.toFixed(3)}`,\n detail: { pearson: r, n: aligned.length },\n })\n }\n }\n\n // ── Signal 4: judge drift (probabilistic up while deterministic flat) ─\n {\n const detRuns = filterDeterministicallyRewarded(runs, input.verifiableRewardOptions ?? {})\n if (detRuns.length >= 4) {\n const detBefore = detRuns.slice(0, Math.floor(detRuns.length / 2))\n const detAfter = detRuns.slice(Math.floor(detRuns.length / 2))\n const detDelta =\n mean(detAfter.map((r) => r.reward.value)) - mean(detBefore.map((r) => r.reward.value))\n const proxyDelta =\n mean(after.map(proxyOf).filter((v): v is number => typeof v === 'number')) -\n mean(before.map(proxyOf).filter((v): v is number => typeof v === 'number'))\n const driftGap = Math.max(0, proxyDelta - detDelta)\n const severity = clamp01(driftGap * 5)\n findings.push({\n signal: 'judge_drift',\n severity,\n message:\n severity >= sus\n ? `judge proxy +${proxyDelta.toFixed(3)} while deterministic reward +${detDelta.toFixed(3)} — judge drifting up without verifiable backing`\n : `judge and deterministic rewards move in step (judge ${proxyDelta.toFixed(3)}, det ${detDelta.toFixed(3)})`,\n detail: { proxyDelta, detDelta, driftGap, n: detRuns.length },\n })\n }\n }\n\n const maxSev = findings.reduce((m, f) => Math.max(m, f.severity), 0)\n const verdict: RewardHackingReport['verdict'] =\n maxSev >= gam ? 'gaming' : maxSev >= sus ? 'suspect' : 'clean'\n const rationale = findings\n .filter((f) => f.severity >= sus)\n .map((f) => `${f.signal}: severity ${f.severity.toFixed(2)} — ${f.message}`)\n if (rationale.length === 0) rationale.push('no signals fired above suspect threshold')\n\n return { findings, verdict, rationale, n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction mean(xs: number[]): number {\n if (xs.length === 0) return 0\n return xs.reduce((s, x) => s + x, 0) / xs.length\n}\n\nfunction clamp01(x: number): number {\n if (!Number.isFinite(x)) return 0\n return Math.max(0, Math.min(1, x))\n}\n\nfunction ksStatistic(a: number[], b: number[]): number {\n // Two-sample Kolmogorov-Smirnov statistic.\n const sortedA = [...a].sort((x, y) => x - y)\n const sortedB = [...b].sort((x, y) => x - y)\n const all = [...new Set([...sortedA, ...sortedB])].sort((x, y) => x - y)\n let max = 0\n for (const v of all) {\n const fa = sortedA.filter((x) => x <= v).length / sortedA.length\n const fb = sortedB.filter((x) => x <= v).length / sortedB.length\n max = Math.max(max, Math.abs(fa - fb))\n }\n return max\n}\n\nfunction defaultSecondary(\n verifiableOpts?: VerifiableRewardExtractionOptions,\n): (run: RunRecord) => number | null {\n return (run: RunRecord) => {\n const filtered = filterDeterministicallyRewarded([run], verifiableOpts ?? {})\n return filtered.length === 1 ? filtered[0]!.reward.value : null\n }\n}\n"],"mappings":"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","names":["clamp01"]}
|
package/dist/chunk-BOD4O7OF.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// src/series-convergence.ts
|
|
2
|
-
function analyzeSeries(values, options = {}) {
|
|
3
|
-
const window = options.window ?? 5;
|
|
4
|
-
const stableCv = options.stableCv ?? 0.05;
|
|
5
|
-
const driftRun = options.driftRun ?? 3;
|
|
6
|
-
if (values.length < Math.max(2, Math.min(window, 3))) {
|
|
7
|
-
return { state: "insufficient-data", windowMean: 0, windowCv: 0, tailRun: 0, stable: false };
|
|
8
|
-
}
|
|
9
|
-
const tail = values.slice(-window);
|
|
10
|
-
const mean = tail.reduce((a, b) => a + b, 0) / tail.length;
|
|
11
|
-
const variance = tail.reduce((acc, v) => acc + (v - mean) ** 2, 0) / tail.length;
|
|
12
|
-
const stdDev = Math.sqrt(variance);
|
|
13
|
-
const refMean = Math.abs(mean) > 1e-9 ? Math.abs(mean) : 1;
|
|
14
|
-
const cv = stdDev / refMean;
|
|
15
|
-
const stable = tail.length >= window && cv <= stableCv;
|
|
16
|
-
let tailRun = 0;
|
|
17
|
-
let direction = 0;
|
|
18
|
-
for (let i = values.length - 1; i > 0; i--) {
|
|
19
|
-
const delta = values[i] - values[i - 1];
|
|
20
|
-
if (delta === 0) break;
|
|
21
|
-
const dir = delta > 0 ? 1 : -1;
|
|
22
|
-
if (direction === 0) direction = dir;
|
|
23
|
-
if (dir !== direction) break;
|
|
24
|
-
tailRun += dir;
|
|
25
|
-
}
|
|
26
|
-
let state;
|
|
27
|
-
if (stable) {
|
|
28
|
-
state = "stabilized";
|
|
29
|
-
} else if (Math.abs(tailRun) >= driftRun) {
|
|
30
|
-
state = tailRun > 0 ? "drifting-up" : "drifting-down";
|
|
31
|
-
} else {
|
|
32
|
-
state = "noisy";
|
|
33
|
-
}
|
|
34
|
-
return { state, windowMean: mean, windowCv: cv, tailRun, stable };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export {
|
|
38
|
-
analyzeSeries
|
|
39
|
-
};
|
|
40
|
-
//# sourceMappingURL=chunk-BOD4O7OF.js.map
|