@tangle-network/agent-eval 0.133.1 → 0.133.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 +9 -0
- package/dist/{analyze-runs-DZr7JW-m.d.ts → analyze-runs-BmX-h_yn.d.ts} +3 -3
- package/dist/{analyze-runs-DZr7JW-m.d.ts.map → analyze-runs-BmX-h_yn.d.ts.map} +1 -1
- package/dist/benchmarks/index.d.ts +1 -1
- package/dist/benchmarks/index.js +1 -1
- package/dist/{benchmarks-BU7P6PCW.js → benchmarks-CJr1H1_a.js} +3 -3
- package/dist/{benchmarks-BU7P6PCW.js.map → benchmarks-CJr1H1_a.js.map} +1 -1
- package/dist/campaign/index.d.ts +2 -2
- package/dist/campaign/index.js +2 -2
- package/dist/{campaign-CnzHQndg.js → campaign-BJjn1rhw.js} +2 -2
- package/dist/{campaign-CnzHQndg.js.map → campaign-BJjn1rhw.js.map} +1 -1
- package/dist/{client-D4F9hdzR.d.ts → client-COvaLoQG.d.ts} +2 -2
- package/dist/{client-D4F9hdzR.d.ts.map → client-COvaLoQG.d.ts.map} +1 -1
- package/dist/contract/index.d.ts +3 -3
- package/dist/contract/index.js +1 -1
- package/dist/hosted/index.d.ts +1 -1
- package/dist/index-3cdlURSk.d.ts.map +1 -1
- package/dist/{index-Wek5mU0y.d.ts → index-BREtv3ZZ.d.ts} +3 -3
- package/dist/{index-Wek5mU0y.d.ts.map → index-BREtv3ZZ.d.ts.map} +1 -1
- package/dist/{index-Ba636PKl.d.ts → index-C7Wue8R6.d.ts} +2 -2
- package/dist/{index-Ba636PKl.d.ts.map → index-C7Wue8R6.d.ts.map} +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/{opencode-sqlite-BGrHeDu3.js → opencode-sqlite-8r6WUfHc.js} +2 -3
- package/dist/opencode-sqlite-8r6WUfHc.js.map +1 -0
- package/dist/{release-report-DfmKSIEE.d.ts → release-report-CjHWa8Ia.d.ts} +2 -2
- package/dist/{release-report-DfmKSIEE.d.ts.map → release-report-CjHWa8Ia.d.ts.map} +1 -1
- package/dist/reporting.d.ts +2 -2
- package/dist/{researcher-DMimgHtN.d.ts → researcher-CbSKhK8z.d.ts} +2 -2
- package/dist/{researcher-DMimgHtN.d.ts.map → researcher-CbSKhK8z.d.ts.map} +1 -1
- package/dist/rl.d.ts +1 -1
- package/dist/rollout/index.js +2 -2
- package/dist/{rollout-CeTlDrf6.js → rollout-CreDz__7.js} +2 -2
- package/dist/{rollout-CeTlDrf6.js.map → rollout-CreDz__7.js.map} +1 -1
- package/dist/{skillopt-optimization-method-BoIzh7Dl.js → skillopt-optimization-method-CF6a327Q.js} +5 -1
- package/dist/{skillopt-optimization-method-BoIzh7Dl.js.map → skillopt-optimization-method-CF6a327Q.js.map} +1 -1
- package/dist/{skillopt-optimization-method-CAASpcS3.d.ts → skillopt-optimization-method-wHF5xsUv.d.ts} +2 -2
- package/dist/{skillopt-optimization-method-CAASpcS3.d.ts.map → skillopt-optimization-method-wHF5xsUv.d.ts.map} +1 -1
- package/dist/{summary-report-DnUcjVpV.d.ts → summary-report-CFnQgNfg.d.ts} +2 -2
- package/dist/{summary-report-DnUcjVpV.d.ts.map → summary-report-CFnQgNfg.d.ts.map} +1 -1
- package/dist/supervisor-run/index.js +1 -1
- package/dist/{supervisor-run-_lnTLM3z.js → supervisor-run-B7lUGoyZ.js} +2 -2
- package/dist/{supervisor-run-_lnTLM3z.js.map → supervisor-run-B7lUGoyZ.js.map} +1 -1
- package/package.json +1 -1
- package/dist/opencode-sqlite-BGrHeDu3.js.map +0 -1
package/dist/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "@tangle-network/agent-eval — wire protocol",
|
|
5
|
-
"version": "0.133.
|
|
5
|
+
"version": "0.133.2",
|
|
6
6
|
"description": "HTTP and stdio RPC interface to agent-eval. The TypeScript runtime is the source of truth; this spec is the contract that cross-language clients (Python, Rust, Go) generate from.\n\nWire-protocol version: 1.0.0. Bumps on breaking changes to request/response schemas.",
|
|
7
7
|
"contact": {
|
|
8
8
|
"name": "Tangle Network",
|
|
@@ -187,11 +187,10 @@ function transcriptFromEntries(entries, options = {}) {
|
|
|
187
187
|
* throwing — callers record a gap line, never crash the backfill.
|
|
188
188
|
*/
|
|
189
189
|
const DEFAULT_OPENCODE_DB = join(homedir(), ".local", "share", "opencode", "opencode.db");
|
|
190
|
-
const nodeRequire = createRequire(import.meta.url);
|
|
191
190
|
/** Open the store read-only; null = unavailable/corrupt (caller records a gap). */
|
|
192
191
|
async function openOpencodeDb(path = DEFAULT_OPENCODE_DB) {
|
|
193
192
|
try {
|
|
194
|
-
const { DatabaseSync } =
|
|
193
|
+
const { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
|
|
195
194
|
const db = new DatabaseSync(path, { readOnly: true });
|
|
196
195
|
db.prepare("SELECT id FROM session LIMIT 1").get();
|
|
197
196
|
return db;
|
|
@@ -315,4 +314,4 @@ function readOpencodeSessionMessages(db, sessionId) {
|
|
|
315
314
|
//#endregion
|
|
316
315
|
export { readOpencodeSessionMessages as a, findClaudeTranscripts as c, transcriptFromEntries as d, openOpencodeDb as i, parseClaudeEntries as l, findOpencodeSessionById as n, DEFAULT_CLAUDE_PROJECTS_DIR as o, findOpencodeSessionsByDirectory as r, claudeProjectSlug as s, DEFAULT_OPENCODE_DB as t, readClaudeTranscript as u };
|
|
317
316
|
|
|
318
|
-
//# sourceMappingURL=opencode-sqlite-
|
|
317
|
+
//# sourceMappingURL=opencode-sqlite-8r6WUfHc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-sqlite-8r6WUfHc.js","names":["isRecord"],"sources":["../src/rollout/readers/claude-jsonl.ts","../src/rollout/readers/opencode-sqlite.ts"],"sourcesContent":["/**\n * Backfill reader over Claude Code project transcripts\n * (~/.claude/projects/<cwd-slug>/<sessionId>.jsonl) → canonical\n * chat-with-tools messages plus per-session token usage.\n *\n * Transcript lines consumed: type:\"user\" (string content or content blocks —\n * text + tool_result) and type:\"assistant\" (content blocks — thinking, text,\n * tool_use; message.usage carries tokens). Sidechain lines (isSidechain=true,\n * subagent threads) are separate invocations and are excluded from the main\n * transcript. Everything else (queue-operation, attachment, last-prompt…) is\n * transport metadata, not conversation.\n */\n\nimport { readdir, readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type { ChatMessage, ChatToolCall } from '../schema'\n\nexport const DEFAULT_CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects')\n\n/** Claude Code's project-directory slug for a working directory. */\nexport function claudeProjectSlug(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9-]/g, '-')\n}\n\nexport interface ClaudeTranscriptRef {\n sessionId: string\n path: string\n}\n\n/** Transcript files recorded for sessions launched from `cwd`. */\nexport async function findClaudeTranscripts(\n cwd: string,\n projectsDir: string = DEFAULT_CLAUDE_PROJECTS_DIR,\n): Promise<ClaudeTranscriptRef[]> {\n const dir = join(projectsDir, claudeProjectSlug(cwd))\n const names = await readdir(dir).catch(() => [])\n return names\n .filter((n) => n.endsWith('.jsonl'))\n .sort()\n .map((n) => ({ sessionId: n.replace(/\\.jsonl$/, ''), path: join(dir, n) }))\n}\n\nexport interface ClaudeUsageTotals {\n tokensIn: number\n tokensOut: number\n cacheRead: number\n cacheWrite: number\n}\n\nexport interface ClaudeTranscript {\n messages: ChatMessage[]\n usage: ClaudeUsageTotals\n /** Timestamp of the first conversation line; null = empty transcript. */\n startedAt: string | null\n endedAt: string | null\n model: string | null\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v)\n\n/**\n * One conversation line of a transcript, still in Claude Code's own shape.\n *\n * This is the single line-level parse of the format. `readClaudeTranscript`\n * projects it to canonical messages + usage; the supervision-tree reader\n * (`src/supervisor-run/claude-code-reader.ts`) projects the SAME entries to\n * spawn/settle/steer instants. Two projections, one parser — a second\n * transcript parser is how the two views silently disagree.\n */\nexport interface ClaudeEntry {\n readonly type: 'user' | 'assistant'\n /** ISO instant of the line; null when the line carried none. */\n readonly timestamp: string | null\n /** The Anthropic message body (`role`, `content`, `model`, `usage`). */\n readonly message: Record<string, unknown>\n /** Claude Code's structured tool result, when the line carries one. */\n readonly toolUseResult: unknown\n /** True on subagent threads — a separate invocation, not this transcript's turn. */\n readonly isSidechain: boolean\n /** Subagent id Claude Code stamps on sidechain lines; null on main-thread lines. */\n readonly agentId: string | null\n}\n\n/** Parse transcript jsonl text into conversation lines. Non-conversation lines are dropped. */\nexport function parseClaudeEntries(raw: string): ClaudeEntry[] {\n const out: ClaudeEntry[] = []\n for (const line of raw.split('\\n')) {\n if (!line.trim()) continue\n let entry: Record<string, unknown>\n try {\n const parsed: unknown = JSON.parse(line)\n if (!isRecord(parsed)) continue\n entry = parsed\n } catch {\n continue\n }\n if (entry.type !== 'user' && entry.type !== 'assistant') continue\n const message = entry.message\n if (!isRecord(message)) continue\n out.push({\n type: entry.type,\n timestamp: typeof entry.timestamp === 'string' ? entry.timestamp : null,\n message,\n toolUseResult: entry.toolUseResult,\n isSidechain: entry.isSidechain === true,\n agentId: typeof entry.agentId === 'string' ? entry.agentId : null,\n })\n }\n return out\n}\n\nexport interface ReadClaudeTranscriptOptions {\n /**\n * Read the sidechain (subagent) thread instead of skipping it. Subagent\n * transcripts under `<session>/subagents/agent-<id>.jsonl` are sidechain\n * lines end to end, so their usage is invisible without this.\n */\n readonly includeSidechain?: boolean\n}\n\nfunction blockText(content: unknown): string {\n if (typeof content === 'string') return content\n if (!Array.isArray(content)) return ''\n return content\n .filter(\n (b): b is Record<string, unknown> =>\n isRecord(b) && b.type === 'text' && typeof b.text === 'string',\n )\n .map((b) => b.text as string)\n .join('\\n')\n}\n\n/** Parse one transcript jsonl into canonical messages + usage totals. */\nexport async function readClaudeTranscript(\n path: string,\n options: ReadClaudeTranscriptOptions = {},\n): Promise<ClaudeTranscript> {\n return transcriptFromEntries(parseClaudeEntries(await readFile(path, 'utf8')), options)\n}\n\n/** The messages+usage projection of already-parsed entries. */\nexport function transcriptFromEntries(\n entries: readonly ClaudeEntry[],\n options: ReadClaudeTranscriptOptions = {},\n): ClaudeTranscript {\n const wantSidechain = options.includeSidechain === true\n const messages: ChatMessage[] = []\n const usage: ClaudeUsageTotals = { tokensIn: 0, tokensOut: 0, cacheRead: 0, cacheWrite: 0 }\n let startedAt: string | null = null\n let endedAt: string | null = null\n let model: string | null = null\n // Claude Code writes one jsonl line PER CONTENT BLOCK of an API message,\n // repeating message.id and usage on each — merge blocks into one canonical\n // assistant turn and count usage once per API message id.\n let lastAssistantApiId: string | null = null\n let lastAssistantIndex = -1\n\n for (const entry of entries) {\n if (entry.isSidechain !== wantSidechain) continue\n const message = entry.message\n if (entry.timestamp !== null) {\n if (startedAt === null) startedAt = entry.timestamp\n endedAt = entry.timestamp\n }\n\n if (entry.type === 'user') {\n lastAssistantApiId = null\n lastAssistantIndex = -1\n const content = message.content\n if (typeof content === 'string') {\n messages.push({ role: 'user', content })\n continue\n }\n if (!Array.isArray(content)) continue\n // A user line may interleave tool_result blocks (answers to the prior\n // assistant tool_use) with plain text; preserve order.\n let userText = ''\n for (const block of content) {\n if (!isRecord(block)) continue\n if (block.type === 'tool_result' && typeof block.tool_use_id === 'string') {\n messages.push({\n role: 'tool',\n tool_call_id: block.tool_use_id,\n content:\n blockText(block.content) || (typeof block.content === 'string' ? block.content : ''),\n })\n } else if (block.type === 'text' && typeof block.text === 'string') {\n userText += (userText.length > 0 ? '\\n' : '') + block.text\n }\n }\n if (userText.length > 0) messages.push({ role: 'user', content: userText })\n continue\n }\n\n // assistant\n if (typeof message.model === 'string') model = message.model\n const apiId = typeof message.id === 'string' ? message.id : null\n const continuesTurn = apiId !== null && apiId === lastAssistantApiId && lastAssistantIndex >= 0\n const msgUsage = message.usage\n if (isRecord(msgUsage) && !continuesTurn) {\n usage.tokensIn += typeof msgUsage.input_tokens === 'number' ? msgUsage.input_tokens : 0\n usage.tokensOut += typeof msgUsage.output_tokens === 'number' ? msgUsage.output_tokens : 0\n usage.cacheRead +=\n typeof msgUsage.cache_read_input_tokens === 'number' ? msgUsage.cache_read_input_tokens : 0\n usage.cacheWrite +=\n typeof msgUsage.cache_creation_input_tokens === 'number'\n ? msgUsage.cache_creation_input_tokens\n : 0\n }\n const content = message.content\n if (!Array.isArray(content)) continue\n let reasoning = ''\n let text = ''\n const toolCalls: ChatToolCall[] = []\n for (const block of content) {\n if (!isRecord(block)) continue\n if (\n block.type === 'thinking' &&\n typeof block.thinking === 'string' &&\n block.thinking.length > 0\n ) {\n reasoning += (reasoning.length > 0 ? '\\n' : '') + block.thinking\n } else if (block.type === 'text' && typeof block.text === 'string') {\n text += (text.length > 0 ? '\\n' : '') + block.text\n } else if (block.type === 'tool_use' && typeof block.id === 'string') {\n toolCalls.push({\n id: block.id,\n type: 'function',\n function: {\n name: typeof block.name === 'string' ? block.name : 'unknown',\n arguments: JSON.stringify(block.input ?? {}),\n },\n })\n }\n }\n if (reasoning.length === 0 && text.length === 0 && toolCalls.length === 0) continue\n if (continuesTurn) {\n const prev = messages[lastAssistantIndex]!\n if (text.length > 0) prev.content = prev.content === null ? text : `${prev.content}\\n${text}`\n if (reasoning.length > 0) {\n prev.reasoning_content =\n prev.reasoning_content === undefined\n ? reasoning\n : `${prev.reasoning_content}\\n${reasoning}`\n }\n if (toolCalls.length > 0) prev.tool_calls = [...(prev.tool_calls ?? []), ...toolCalls]\n continue\n }\n messages.push({\n role: 'assistant',\n content: text.length > 0 ? text : null,\n ...(reasoning.length > 0 ? { reasoning_content: reasoning } : {}),\n ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),\n })\n lastAssistantApiId = apiId\n lastAssistantIndex = messages.length - 1\n }\n\n return { messages, usage, startedAt, endedAt, model }\n}\n","/**\n * Read-only backfill reader over the opencode sqlite store\n * (~/.local/share/opencode/opencode.db) → canonical chat-with-tools messages.\n *\n * Schema consumed (observed, 2026-07): `session` rows carry directory /\n * parent_id / agent / model / cost / tokens_*; `message` rows carry a JSON\n * `data` blob ({role, modelID, providerID, tokens, cost, finish}); `part`\n * rows carry the actual content ({type: text|reasoning|tool|step-start|\n * step-finish|snapshot…}). Tool parts hold {callID, state:{input, output,\n * status}} — both the call and its result, which we split into an assistant\n * tool_call plus a role:\"tool\" result message.\n *\n * The store is mutable and can be corrupt (a `.corrupt-bak` sibling ships\n * next to it in the wild), so `openOpencodeDb` returns null instead of\n * throwing — callers record a gap line, never crash the backfill.\n */\n\nimport { createRequire } from 'node:module'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type { DatabaseSync } from 'node:sqlite'\nimport type { ChatMessage, ChatToolCall } from '../schema'\n\nexport const DEFAULT_OPENCODE_DB = join(homedir(), '.local', 'share', 'opencode', 'opencode.db')\n\nexport interface OpencodeSessionRow {\n id: string\n parentId: string | null\n directory: string\n agent: string | null\n /** Raw session.model JSON: {id, providerID, variant} where present. */\n model: { id?: string; providerID?: string } | null\n costUsd: number\n tokensInput: number\n tokensOutput: number\n tokensReasoning: number\n tokensCacheRead: number\n tokensCacheWrite: number\n timeCreated: number\n timeUpdated: number\n}\n\n// `node:sqlite` is loaded through CommonJS `require`, not `import()`. esbuild\n// (bundling) and Vite (tests) both rewrite a dynamic import and strip the\n// `node:` prefix under an es20xx target, turning this builtin into a bogus\n// \"sqlite\" package lookup; composing the specifier at runtime does not reliably\n// defeat that (it still resolved through Vite's transform in some workers, so\n// the failure moved around as test files were added). A require obtained from\n// `createRequire` is not an analyzable module reference in either tool, so\n// neither can rewrite it.\n/** Open the store read-only; null = unavailable/corrupt (caller records a gap). */\nexport async function openOpencodeDb(\n path: string = DEFAULT_OPENCODE_DB,\n): Promise<DatabaseSync | null> {\n try {\n // Keep Node-only module initialization inside the Node-only operation.\n // Root imports are shared with edge consumers that do not define import.meta.url.\n const nodeRequire = createRequire(import.meta.url)\n const { DatabaseSync } = nodeRequire('node:sqlite') as typeof import('node:sqlite')\n const db = new DatabaseSync(path, { readOnly: true })\n // Probe: a corrupt store can open() fine and fail on first page read.\n db.prepare('SELECT id FROM session LIMIT 1').get()\n return db\n } catch {\n return null\n }\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v)\n\nfunction parseSessionRow(row: Record<string, unknown>): OpencodeSessionRow {\n let model: OpencodeSessionRow['model'] = null\n if (typeof row.model === 'string' && row.model.length > 0) {\n try {\n const parsed: unknown = JSON.parse(row.model)\n if (isRecord(parsed)) model = parsed as { id?: string; providerID?: string }\n } catch {\n model = null\n }\n }\n return {\n id: String(row.id),\n parentId: row.parent_id === null || row.parent_id === undefined ? null : String(row.parent_id),\n directory: String(row.directory),\n agent: row.agent === null || row.agent === undefined ? null : String(row.agent),\n model,\n costUsd: Number(row.cost ?? 0),\n tokensInput: Number(row.tokens_input ?? 0),\n tokensOutput: Number(row.tokens_output ?? 0),\n tokensReasoning: Number(row.tokens_reasoning ?? 0),\n tokensCacheRead: Number(row.tokens_cache_read ?? 0),\n tokensCacheWrite: Number(row.tokens_cache_write ?? 0),\n timeCreated: Number(row.time_created ?? 0),\n timeUpdated: Number(row.time_updated ?? 0),\n }\n}\n\nconst SESSION_COLUMNS =\n 'id, parent_id, directory, agent, model, cost, tokens_input, tokens_output, tokens_reasoning, tokens_cache_read, tokens_cache_write, time_created, time_updated'\n\n/** Sessions whose cwd is `directory` (the worker-clone join key). */\nexport function findOpencodeSessionsByDirectory(\n db: DatabaseSync,\n directory: string,\n): OpencodeSessionRow[] {\n const rows = db\n .prepare(`SELECT ${SESSION_COLUMNS} FROM session WHERE directory = ? ORDER BY time_created`)\n .all(directory) as Array<Record<string, unknown>>\n return rows.map(parseSessionRow)\n}\n\nexport function findOpencodeSessionById(\n db: DatabaseSync,\n sessionId: string,\n): OpencodeSessionRow | null {\n const row = db.prepare(`SELECT ${SESSION_COLUMNS} FROM session WHERE id = ?`).get(sessionId) as\n | Record<string, unknown>\n | undefined\n return row === undefined ? null : parseSessionRow(row)\n}\n\ninterface OpencodePart {\n type?: string\n text?: string\n tool?: string\n callID?: string\n state?: { status?: string; input?: unknown; output?: unknown }\n}\n\nfunction toolResultContent(output: unknown): string {\n if (typeof output === 'string') return output\n if (output === null || output === undefined) return ''\n return JSON.stringify(output)\n}\n\n/**\n * Convert one session's message+part rows into canonical messages.\n * An opencode assistant message row spans several model steps; each step's\n * parts (reasoning → text → tool …) become one assistant message followed by\n * the role:\"tool\" results of its calls, preserving order.\n */\nexport function readOpencodeSessionMessages(db: DatabaseSync, sessionId: string): ChatMessage[] {\n const messageRows = db\n .prepare('SELECT id, data FROM message WHERE session_id = ? ORDER BY time_created, id')\n .all(sessionId) as Array<{ id: string; data: string }>\n const partsStmt = db.prepare('SELECT data FROM part WHERE message_id = ? ORDER BY id')\n\n const messages: ChatMessage[] = []\n for (const messageRow of messageRows) {\n let data: Record<string, unknown>\n try {\n const parsed: unknown = JSON.parse(messageRow.data)\n if (!isRecord(parsed)) continue\n data = parsed\n } catch {\n continue\n }\n const parts: OpencodePart[] = []\n for (const row of partsStmt.all(messageRow.id) as Array<{ data: string }>) {\n try {\n const parsed: unknown = JSON.parse(row.data)\n if (isRecord(parsed)) parts.push(parsed as OpencodePart)\n } catch {\n // Malformed part payload: skip the part, keep the message.\n }\n }\n\n if (data.role === 'user') {\n const text = parts\n .filter((p) => p.type === 'text' && typeof p.text === 'string')\n .map((p) => p.text as string)\n .join('\\n')\n messages.push({ role: 'user', content: text })\n continue\n }\n if (data.role !== 'assistant') continue\n\n // Split the row into steps at step-start boundaries; parts before the\n // first step-start (none observed, but tolerated) form an implicit step.\n const steps: OpencodePart[][] = []\n let current: OpencodePart[] = []\n for (const part of parts) {\n if (part.type === 'step-start') {\n if (current.length > 0) steps.push(current)\n current = []\n continue\n }\n if (part.type === 'step-finish' || part.type === 'snapshot' || part.type === 'patch') continue\n current.push(part)\n }\n if (current.length > 0) steps.push(current)\n\n for (const step of steps) {\n const reasoning = step\n .filter((p) => p.type === 'reasoning' && typeof p.text === 'string' && p.text.length > 0)\n .map((p) => p.text as string)\n .join('\\n')\n const text = step\n .filter((p) => p.type === 'text' && typeof p.text === 'string')\n .map((p) => p.text as string)\n .join('\\n')\n const toolParts = step.filter((p) => p.type === 'tool' && typeof p.callID === 'string')\n const toolCalls: ChatToolCall[] = toolParts.map((p) => ({\n id: p.callID as string,\n type: 'function',\n function: {\n name: p.tool ?? 'unknown',\n arguments: JSON.stringify(p.state?.input ?? {}),\n },\n }))\n if (reasoning.length === 0 && text.length === 0 && toolCalls.length === 0) continue\n messages.push({\n role: 'assistant',\n content: text.length > 0 ? text : null,\n ...(reasoning.length > 0 ? { reasoning_content: reasoning } : {}),\n ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),\n })\n for (const p of toolParts) {\n messages.push({\n role: 'tool',\n tool_call_id: p.callID as string,\n name: p.tool ?? 'unknown',\n content: toolResultContent(p.state?.output),\n })\n }\n }\n }\n return messages\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,MAAa,8BAA8B,KAAK,QAAQ,GAAG,WAAW,UAAU;;AAGhF,SAAgB,kBAAkB,KAAqB;CACrD,OAAO,IAAI,QAAQ,kBAAkB,GAAG;AAC1C;;AAQA,eAAsB,sBACpB,KACA,cAAsB,6BACU;CAChC,MAAM,MAAM,KAAK,aAAa,kBAAkB,GAAG,CAAC;CAEpD,QAAO,MADa,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,EAAA,CAE5C,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC,CAAC,CACnC,KAAK,CAAC,CACN,KAAK,OAAO;EAAE,WAAW,EAAE,QAAQ,YAAY,EAAE;EAAG,MAAM,KAAK,KAAK,CAAC;CAAE,EAAE;AAC9E;AAkBA,MAAMA,cAAY,MAChB,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;;AA0BzD,SAAgB,mBAAmB,KAA4B;CAC7D,MAAM,MAAqB,CAAC;CAC5B,KAAK,MAAM,QAAQ,IAAI,MAAM,IAAI,GAAG;EAClC,IAAI,CAAC,KAAK,KAAK,GAAG;EAClB,IAAI;EACJ,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,IAAI;GACvC,IAAI,CAACA,WAAS,MAAM,GAAG;GACvB,QAAQ;EACV,QAAQ;GACN;EACF;EACA,IAAI,MAAM,SAAS,UAAU,MAAM,SAAS,aAAa;EACzD,MAAM,UAAU,MAAM;EACtB,IAAI,CAACA,WAAS,OAAO,GAAG;EACxB,IAAI,KAAK;GACP,MAAM,MAAM;GACZ,WAAW,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY;GACnE;GACA,eAAe,MAAM;GACrB,aAAa,MAAM,gBAAgB;GACnC,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;EAC/D,CAAC;CACH;CACA,OAAO;AACT;AAWA,SAAS,UAAU,SAA0B;CAC3C,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,OAAO;CACpC,OAAO,QACJ,QACE,MACCA,WAAS,CAAC,KAAK,EAAE,SAAS,UAAU,OAAO,EAAE,SAAS,QAC1D,CAAC,CACA,KAAK,MAAM,EAAE,IAAc,CAAC,CAC5B,KAAK,IAAI;AACd;;AAGA,eAAsB,qBACpB,MACA,UAAuC,CAAC,GACb;CAC3B,OAAO,sBAAsB,mBAAmB,MAAM,SAAS,MAAM,MAAM,CAAC,GAAG,OAAO;AACxF;;AAGA,SAAgB,sBACd,SACA,UAAuC,CAAC,GACtB;CAClB,MAAM,gBAAgB,QAAQ,qBAAqB;CACnD,MAAM,WAA0B,CAAC;CACjC,MAAM,QAA2B;EAAE,UAAU;EAAG,WAAW;EAAG,WAAW;EAAG,YAAY;CAAE;CAC1F,IAAI,YAA2B;CAC/B,IAAI,UAAyB;CAC7B,IAAI,QAAuB;CAI3B,IAAI,qBAAoC;CACxC,IAAI,qBAAqB;CAEzB,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,MAAM,gBAAgB,eAAe;EACzC,MAAM,UAAU,MAAM;EACtB,IAAI,MAAM,cAAc,MAAM;GAC5B,IAAI,cAAc,MAAM,YAAY,MAAM;GAC1C,UAAU,MAAM;EAClB;EAEA,IAAI,MAAM,SAAS,QAAQ;GACzB,qBAAqB;GACrB,qBAAqB;GACrB,MAAM,UAAU,QAAQ;GACxB,IAAI,OAAO,YAAY,UAAU;IAC/B,SAAS,KAAK;KAAE,MAAM;KAAQ;IAAQ,CAAC;IACvC;GACF;GACA,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;GAG7B,IAAI,WAAW;GACf,KAAK,MAAM,SAAS,SAAS;IAC3B,IAAI,CAACA,WAAS,KAAK,GAAG;IACtB,IAAI,MAAM,SAAS,iBAAiB,OAAO,MAAM,gBAAgB,UAC/D,SAAS,KAAK;KACZ,MAAM;KACN,cAAc,MAAM;KACpB,SACE,UAAU,MAAM,OAAO,MAAM,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;IACrF,CAAC;SACI,IAAI,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,UACxD,aAAa,SAAS,SAAS,IAAI,OAAO,MAAM,MAAM;GAE1D;GACA,IAAI,SAAS,SAAS,GAAG,SAAS,KAAK;IAAE,MAAM;IAAQ,SAAS;GAAS,CAAC;GAC1E;EACF;EAGA,IAAI,OAAO,QAAQ,UAAU,UAAU,QAAQ,QAAQ;EACvD,MAAM,QAAQ,OAAO,QAAQ,OAAO,WAAW,QAAQ,KAAK;EAC5D,MAAM,gBAAgB,UAAU,QAAQ,UAAU,sBAAsB,sBAAsB;EAC9F,MAAM,WAAW,QAAQ;EACzB,IAAIA,WAAS,QAAQ,KAAK,CAAC,eAAe;GACxC,MAAM,YAAY,OAAO,SAAS,iBAAiB,WAAW,SAAS,eAAe;GACtF,MAAM,aAAa,OAAO,SAAS,kBAAkB,WAAW,SAAS,gBAAgB;GACzF,MAAM,aACJ,OAAO,SAAS,4BAA4B,WAAW,SAAS,0BAA0B;GAC5F,MAAM,cACJ,OAAO,SAAS,gCAAgC,WAC5C,SAAS,8BACT;EACR;EACA,MAAM,UAAU,QAAQ;EACxB,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;EAC7B,IAAI,YAAY;EAChB,IAAI,OAAO;EACX,MAAM,YAA4B,CAAC;EACnC,KAAK,MAAM,SAAS,SAAS;GAC3B,IAAI,CAACA,WAAS,KAAK,GAAG;GACtB,IACE,MAAM,SAAS,cACf,OAAO,MAAM,aAAa,YAC1B,MAAM,SAAS,SAAS,GAExB,cAAc,UAAU,SAAS,IAAI,OAAO,MAAM,MAAM;QACnD,IAAI,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,UACxD,SAAS,KAAK,SAAS,IAAI,OAAO,MAAM,MAAM;QACzC,IAAI,MAAM,SAAS,cAAc,OAAO,MAAM,OAAO,UAC1D,UAAU,KAAK;IACb,IAAI,MAAM;IACV,MAAM;IACN,UAAU;KACR,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;KACpD,WAAW,KAAK,UAAU,MAAM,SAAS,CAAC,CAAC;IAC7C;GACF,CAAC;EAEL;EACA,IAAI,UAAU,WAAW,KAAK,KAAK,WAAW,KAAK,UAAU,WAAW,GAAG;EAC3E,IAAI,eAAe;GACjB,MAAM,OAAO,SAAS;GACtB,IAAI,KAAK,SAAS,GAAG,KAAK,UAAU,KAAK,YAAY,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI;GACvF,IAAI,UAAU,SAAS,GACrB,KAAK,oBACH,KAAK,sBAAsB,KAAA,IACvB,YACA,GAAG,KAAK,kBAAkB,IAAI;GAEtC,IAAI,UAAU,SAAS,GAAG,KAAK,aAAa,CAAC,GAAI,KAAK,cAAc,CAAC,GAAI,GAAG,SAAS;GACrF;EACF;EACA,SAAS,KAAK;GACZ,MAAM;GACN,SAAS,KAAK,SAAS,IAAI,OAAO;GAClC,GAAI,UAAU,SAAS,IAAI,EAAE,mBAAmB,UAAU,IAAI,CAAC;GAC/D,GAAI,UAAU,SAAS,IAAI,EAAE,YAAY,UAAU,IAAI,CAAC;EAC1D,CAAC;EACD,qBAAqB;EACrB,qBAAqB,SAAS,SAAS;CACzC;CAEA,OAAO;EAAE;EAAU;EAAO;EAAW;EAAS;CAAM;AACtD;;;;;;;;;;;;;;;;;;;AC9OA,MAAa,sBAAsB,KAAK,QAAQ,GAAG,UAAU,SAAS,YAAY,aAAa;;AA4B/F,eAAsB,eACpB,OAAe,qBACe;CAC9B,IAAI;EAIF,MAAM,EAAE,iBADY,cAAc,OAAO,KAAK,GACX,CAAC,CAAC,aAAa;EAClD,MAAM,KAAK,IAAI,aAAa,MAAM,EAAE,UAAU,KAAK,CAAC;EAEpD,GAAG,QAAQ,gCAAgC,CAAC,CAAC,IAAI;EACjD,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAM,YAAY,MAChB,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAEzD,SAAS,gBAAgB,KAAkD;CACzE,IAAI,QAAqC;CACzC,IAAI,OAAO,IAAI,UAAU,YAAY,IAAI,MAAM,SAAS,GACtD,IAAI;EACF,MAAM,SAAkB,KAAK,MAAM,IAAI,KAAK;EAC5C,IAAI,SAAS,MAAM,GAAG,QAAQ;CAChC,QAAQ;EACN,QAAQ;CACV;CAEF,OAAO;EACL,IAAI,OAAO,IAAI,EAAE;EACjB,UAAU,IAAI,cAAc,QAAQ,IAAI,cAAc,KAAA,IAAY,OAAO,OAAO,IAAI,SAAS;EAC7F,WAAW,OAAO,IAAI,SAAS;EAC/B,OAAO,IAAI,UAAU,QAAQ,IAAI,UAAU,KAAA,IAAY,OAAO,OAAO,IAAI,KAAK;EAC9E;EACA,SAAS,OAAO,IAAI,QAAQ,CAAC;EAC7B,aAAa,OAAO,IAAI,gBAAgB,CAAC;EACzC,cAAc,OAAO,IAAI,iBAAiB,CAAC;EAC3C,iBAAiB,OAAO,IAAI,oBAAoB,CAAC;EACjD,iBAAiB,OAAO,IAAI,qBAAqB,CAAC;EAClD,kBAAkB,OAAO,IAAI,sBAAsB,CAAC;EACpD,aAAa,OAAO,IAAI,gBAAgB,CAAC;EACzC,aAAa,OAAO,IAAI,gBAAgB,CAAC;CAC3C;AACF;AAEA,MAAM,kBACJ;;AAGF,SAAgB,gCACd,IACA,WACsB;CAItB,OAHa,GACV,QAAQ,UAAU,gBAAgB,wDAAwD,CAAC,CAC3F,IAAI,SACG,CAAC,CAAC,IAAI,eAAe;AACjC;AAEA,SAAgB,wBACd,IACA,WAC2B;CAC3B,MAAM,MAAM,GAAG,QAAQ,UAAU,gBAAgB,2BAA2B,CAAC,CAAC,IAAI,SAAS;CAG3F,OAAO,QAAQ,KAAA,IAAY,OAAO,gBAAgB,GAAG;AACvD;AAUA,SAAS,kBAAkB,QAAyB;CAClD,IAAI,OAAO,WAAW,UAAU,OAAO;CACvC,IAAI,WAAW,QAAQ,WAAW,KAAA,GAAW,OAAO;CACpD,OAAO,KAAK,UAAU,MAAM;AAC9B;;;;;;;AAQA,SAAgB,4BAA4B,IAAkB,WAAkC;CAC9F,MAAM,cAAc,GACjB,QAAQ,6EAA6E,CAAC,CACtF,IAAI,SAAS;CAChB,MAAM,YAAY,GAAG,QAAQ,wDAAwD;CAErF,MAAM,WAA0B,CAAC;CACjC,KAAK,MAAM,cAAc,aAAa;EACpC,IAAI;EACJ,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,WAAW,IAAI;GAClD,IAAI,CAAC,SAAS,MAAM,GAAG;GACvB,OAAO;EACT,QAAQ;GACN;EACF;EACA,MAAM,QAAwB,CAAC;EAC/B,KAAK,MAAM,OAAO,UAAU,IAAI,WAAW,EAAE,GAC3C,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,IAAI,IAAI;GAC3C,IAAI,SAAS,MAAM,GAAG,MAAM,KAAK,MAAsB;EACzD,QAAQ,CAER;EAGF,IAAI,KAAK,SAAS,QAAQ;GACxB,MAAM,OAAO,MACV,QAAQ,MAAM,EAAE,SAAS,UAAU,OAAO,EAAE,SAAS,QAAQ,CAAC,CAC9D,KAAK,MAAM,EAAE,IAAc,CAAC,CAC5B,KAAK,IAAI;GACZ,SAAS,KAAK;IAAE,MAAM;IAAQ,SAAS;GAAK,CAAC;GAC7C;EACF;EACA,IAAI,KAAK,SAAS,aAAa;EAI/B,MAAM,QAA0B,CAAC;EACjC,IAAI,UAA0B,CAAC;EAC/B,KAAK,MAAM,QAAQ,OAAO;GACxB,IAAI,KAAK,SAAS,cAAc;IAC9B,IAAI,QAAQ,SAAS,GAAG,MAAM,KAAK,OAAO;IAC1C,UAAU,CAAC;IACX;GACF;GACA,IAAI,KAAK,SAAS,iBAAiB,KAAK,SAAS,cAAc,KAAK,SAAS,SAAS;GACtF,QAAQ,KAAK,IAAI;EACnB;EACA,IAAI,QAAQ,SAAS,GAAG,MAAM,KAAK,OAAO;EAE1C,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,YAAY,KACf,QAAQ,MAAM,EAAE,SAAS,eAAe,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,SAAS,CAAC,CAAC,CACxF,KAAK,MAAM,EAAE,IAAc,CAAC,CAC5B,KAAK,IAAI;GACZ,MAAM,OAAO,KACV,QAAQ,MAAM,EAAE,SAAS,UAAU,OAAO,EAAE,SAAS,QAAQ,CAAC,CAC9D,KAAK,MAAM,EAAE,IAAc,CAAC,CAC5B,KAAK,IAAI;GACZ,MAAM,YAAY,KAAK,QAAQ,MAAM,EAAE,SAAS,UAAU,OAAO,EAAE,WAAW,QAAQ;GACtF,MAAM,YAA4B,UAAU,KAAK,OAAO;IACtD,IAAI,EAAE;IACN,MAAM;IACN,UAAU;KACR,MAAM,EAAE,QAAQ;KAChB,WAAW,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC,CAAC;IAChD;GACF,EAAE;GACF,IAAI,UAAU,WAAW,KAAK,KAAK,WAAW,KAAK,UAAU,WAAW,GAAG;GAC3E,SAAS,KAAK;IACZ,MAAM;IACN,SAAS,KAAK,SAAS,IAAI,OAAO;IAClC,GAAI,UAAU,SAAS,IAAI,EAAE,mBAAmB,UAAU,IAAI,CAAC;IAC/D,GAAI,UAAU,SAAS,IAAI,EAAE,YAAY,UAAU,IAAI,CAAC;GAC1D,CAAC;GACD,KAAK,MAAM,KAAK,WACd,SAAS,KAAK;IACZ,MAAM;IACN,cAAc,EAAE;IAChB,MAAM,EAAE,QAAQ;IAChB,SAAS,kBAAkB,EAAE,OAAO,MAAM;GAC5C,CAAC;EAEL;CACF;CACA,OAAO;AACT"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { o as FailureClass } from "./schema-BtVldJ3T.js";
|
|
2
2
|
import { a as RunRecord, s as RunSplitTag } from "./run-record-DcObtIGh.js";
|
|
3
3
|
import { a as DatasetScenario, o as DatasetSplit, r as DatasetManifest } from "./dataset-BvtnC8Dc.js";
|
|
4
|
-
import { b as GateDecision } from "./summary-report-
|
|
4
|
+
import { b as GateDecision } from "./summary-report-CFnQgNfg.js";
|
|
5
5
|
//#region src/release-confidence.d.ts
|
|
6
6
|
/** Severity of an actionable finding attached to a run/trace. */
|
|
7
7
|
type AsiSeverity = 'info' | 'warning' | 'error' | 'critical';
|
|
@@ -241,4 +241,4 @@ interface RenderReleaseReportOptions {
|
|
|
241
241
|
declare function renderReleaseReport(scorecard: ReleaseConfidenceScorecard, options?: RenderReleaseReportOptions): string;
|
|
242
242
|
//#endregion
|
|
243
243
|
export { ReleaseConfidenceStatus as _, JudgeReplayGateArgs as a, assertReleaseConfidence as b, judgeReplayGate as c, ReleaseConfidenceAxis as d, ReleaseConfidenceAxisName as f, ReleaseConfidenceScorecard as g, ReleaseConfidenceMetrics as h, BootstrapResult as i, ActionableSideInfo as l, ReleaseConfidenceIssue as m, renderReleaseReport as n, Verdict as o, ReleaseConfidenceInput as p, BootstrapOptions as r, bootstrapCi as s, RenderReleaseReportOptions as t, AsiSeverity as u, ReleaseConfidenceThresholds as v, evaluateReleaseConfidence as x, ReleaseTraceEvidence as y };
|
|
244
|
-
//# sourceMappingURL=release-report-
|
|
244
|
+
//# sourceMappingURL=release-report-CjHWa8Ia.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-report-
|
|
1
|
+
{"version":3,"file":"release-report-CjHWa8Ia.d.ts","names":[],"sources":["../src/release-confidence.ts","../src/promotion-gate.ts","../src/release-report.ts"],"mappings":";;;;;;KAsBY;;UAGK;;EAEf;;EAEA;EACA,WAAW;;EAEX;;EAEA;;EAEA;;EAEA;EACA,WAAW;;KAGD;KACA;UAQK;EACf;EACA;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;;EAEA,eAAe;EACf,MAAM;EACN,WAAW;;UAGI;;EAEf;EACA;EACA;EACA;;EAEA;EACA;EACA;;EAEA;EACA;EACA;;EAEA;;EAEA;;UAGe;EACf;EACA;EACA;EACA,UAAU;EACV,qBAAqB;EACrB,gBAAgB;EAChB,kBAAkB;EAClB,eAAe;EACf,aAAa;;UAGE;EACf,MAAM;EACN,QAAQ;EACR;EACA;;UAGe;EACf,MAAM;EACN;EACA;EACA;;UAGe;EACf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,aAAa,OAAO;EACpB,cAAc;EACd,oBAAoB,QAAQ,OAAO;EACnC,0BAA0B;;;;;;;EAO1B;;UAGe;EACf;EACA;EACA;EACA,QAAQ;EACR;EACA,MAAM;EACN,QAAQ;EACR,SAAS;EACT,SAAS;EACT,cAAc;EACd;;iBAkBc,0BACd,OAAO,yBACN;iBA4Ha,wBAAwB,OAAO,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;KCxR5D;UAEK;EACf;EACA;;EAEA;;EAEA;;EAEA;;EAEA;EACA;EACA,SAAS;;UAGM;;EAEf;;EAEA;;;;;;EAMA;;EAEA;;;;;;;;;iBAUc,YACd,oBACA,qBACA,UAAS,mBACR;;;;;;;;;;;;;;;;UA+Gc,oBAAoB;EACnC,iBAAiB;EACjB,kBAAkB;;EAElB,QAAQ,QAAQ,YAAY;EAC5B;EACA;;EAEA;;EAEA;;;;;iBAMoB,gBAAgB,SACpC,MAAM,oBAAoB,WACzB,QAAQ;EAAoB;EAAyB;;;;UCjMvC;EACf;EACA,gBAAgB;EAChB;EACA;EACA;;iBAGc,oBACd,WAAW,4BACX,UAAS"}
|
package/dist/reporting.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { I as pairedBootstrap, Z as wilcoxonSignedRank, d as PairedBootstrapOptions, f as PairedBootstrapResult, y as benjaminiHochberg } from "./statistics-DbvkkDPa.js";
|
|
2
|
-
import { _ as paretoChart, a as ParetoPoint, c as ResearchReportCandidate, d as ResearchReportOptions, f as ResearchReportRecommendation, g as gainHistogram, h as SummaryTableRow, i as ParetoFigureSpec, l as ResearchReportDecision, m as SummaryTableOptions, n as GainDistributionFigureSpec, o as RESEARCH_REPORT_HARD_PAIR_FLOOR, p as SummaryTable, r as GainDistributionOptions, s as ResearchReport, t as GainDistributionBin, u as ResearchReportMethodology, v as researchReport, y as summaryTable } from "./summary-report-
|
|
3
|
-
import { _ as ReleaseConfidenceStatus, a as JudgeReplayGateArgs, b as assertReleaseConfidence, c as judgeReplayGate, d as ReleaseConfidenceAxis, f as ReleaseConfidenceAxisName, g as ReleaseConfidenceScorecard, h as ReleaseConfidenceMetrics, i as BootstrapResult, m as ReleaseConfidenceIssue, n as renderReleaseReport, o as Verdict, p as ReleaseConfidenceInput, r as BootstrapOptions, s as bootstrapCi, t as RenderReleaseReportOptions, v as ReleaseConfidenceThresholds, x as evaluateReleaseConfidence, y as ReleaseTraceEvidence } from "./release-report-
|
|
2
|
+
import { _ as paretoChart, a as ParetoPoint, c as ResearchReportCandidate, d as ResearchReportOptions, f as ResearchReportRecommendation, g as gainHistogram, h as SummaryTableRow, i as ParetoFigureSpec, l as ResearchReportDecision, m as SummaryTableOptions, n as GainDistributionFigureSpec, o as RESEARCH_REPORT_HARD_PAIR_FLOOR, p as SummaryTable, r as GainDistributionOptions, s as ResearchReport, t as GainDistributionBin, u as ResearchReportMethodology, v as researchReport, y as summaryTable } from "./summary-report-CFnQgNfg.js";
|
|
3
|
+
import { _ as ReleaseConfidenceStatus, a as JudgeReplayGateArgs, b as assertReleaseConfidence, c as judgeReplayGate, d as ReleaseConfidenceAxis, f as ReleaseConfidenceAxisName, g as ReleaseConfidenceScorecard, h as ReleaseConfidenceMetrics, i as BootstrapResult, m as ReleaseConfidenceIssue, n as renderReleaseReport, o as Verdict, p as ReleaseConfidenceInput, r as BootstrapOptions, s as bootstrapCi, t as RenderReleaseReportOptions, v as ReleaseConfidenceThresholds, x as evaluateReleaseConfidence, y as ReleaseTraceEvidence } from "./release-report-CjHWa8Ia.js";
|
|
4
4
|
import { a as PairedEvalueStep, c as pairedEvalueSequence, i as PairedEvalueSequence, n as InterimReleaseConfidenceInput, o as SequentialDecision, r as PairedEvalueOptions, s as evaluateInterimReleaseConfidence, t as InterimReleaseConfidence } from "./sequential-CYwq6Ff_.js";
|
|
5
5
|
import { a as rubricPredictiveValidity, i as RubricRanking, n as RubricPredictiveValidityInput, r as RubricPredictiveValidityReport, t as RubricOutcomePair } from "./rubric-predictive-validity-C1dCLcvb.js";
|
|
6
6
|
export { type BootstrapOptions, type BootstrapResult, type GainDistributionBin, type GainDistributionFigureSpec, type GainDistributionOptions, type InterimReleaseConfidence, type InterimReleaseConfidenceInput, type JudgeReplayGateArgs, type PairedBootstrapOptions, type PairedBootstrapResult, type PairedEvalueOptions, type PairedEvalueSequence, type PairedEvalueStep, type ParetoFigureSpec, type ParetoPoint, RESEARCH_REPORT_HARD_PAIR_FLOOR, type ReleaseConfidenceAxis, type ReleaseConfidenceAxisName, type ReleaseConfidenceInput, type ReleaseConfidenceIssue, type ReleaseConfidenceMetrics, type ReleaseConfidenceScorecard, type ReleaseConfidenceStatus, type ReleaseConfidenceThresholds, type ReleaseTraceEvidence, type RenderReleaseReportOptions, type ResearchReport, type ResearchReportCandidate, type ResearchReportDecision, type ResearchReportMethodology, type ResearchReportOptions, type ResearchReportRecommendation, type RubricOutcomePair, type RubricPredictiveValidityInput, type RubricPredictiveValidityReport, type RubricRanking, type SequentialDecision, type SummaryTable, type SummaryTableOptions, type SummaryTableRow, type Verdict, assertReleaseConfidence, benjaminiHochberg, bootstrapCi, evaluateInterimReleaseConfidence, evaluateReleaseConfidence, gainHistogram, judgeReplayGate, pairedBootstrap, pairedEvalueSequence, paretoChart, renderReleaseReport, researchReport, rubricPredictiveValidity, summaryTable, wilcoxonSignedRank };
|
|
@@ -5,7 +5,7 @@ import { s as TraceStore } from "./store-CT9YIIve.js";
|
|
|
5
5
|
import { i as TraceEmitter, t as RunCompleteHook } from "./emitter-DGQGoLyj.js";
|
|
6
6
|
import { a as RunIntegrityReport, n as RunIntegrityExpectations } from "./integrity-rmVhXWA7.js";
|
|
7
7
|
import { o as LlmClientOptions, u as LlmRouteRequirements } from "./llm-client-BiK4HW0u.js";
|
|
8
|
-
import { b as GateDecision, d as ResearchReportOptions, s as ResearchReport } from "./summary-report-
|
|
8
|
+
import { b as GateDecision, d as ResearchReportOptions, s as ResearchReport } from "./summary-report-CFnQgNfg.js";
|
|
9
9
|
//#region src/eval-campaign.d.ts
|
|
10
10
|
interface CampaignVariant<V> {
|
|
11
11
|
id: string;
|
|
@@ -312,4 +312,4 @@ declare class NoopResearcher implements Researcher {
|
|
|
312
312
|
}
|
|
313
313
|
//#endregion
|
|
314
314
|
export { EvalCampaignResult as _, FailureMode as a, SteeringChange as c, CampaignRunContext as d, CampaignRunOutcome as f, EvalCampaignOptions as g, CampaignVariant as h, ExperimentResult as i, CampaignFactoryParams as l, CampaignScenario as m, CallbackResearcherOptions as n, NoopResearcher as o, CampaignRunner as p, ExperimentPlan as r, Researcher as s, CallbackResearcher as t, CampaignIntegrityPolicy as u, FailedRun as v, runEvalCampaign as y };
|
|
315
|
-
//# sourceMappingURL=researcher-
|
|
315
|
+
//# sourceMappingURL=researcher-CbSKhK8z.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"researcher-
|
|
1
|
+
{"version":3,"file":"researcher-CbSKhK8z.d.ts","names":[],"sources":["../src/eval-campaign.ts","../src/researcher.ts"],"mappings":";;;;;;;;;UAyEiB,gBAAgB;EAC/B;EACA,SAAS;;UAGM;EACf;;EAEA,OAAO;;UAGQ,mBAAmB;;EAElC;;EAEA;EACA,SAAS;EACT;EACA;EACA,cAAc;EACd;EACA,UAAU;;;;;;;EAOV,SAAS;EACT,OAAO;EACP,SAAS;;;;;;EAMT,SAAS;;UAGD;;EAER;;EAEA;;EAEA;;EAEA,gBAAgB;EAChB,YAAY;;EAEZ;;EAEA;;EAEA;;EAEA,MAAM;;EAEN,gBAAgB;;;;;;EAMhB,cAAc;;;;;;EAMd,eAAe,mBAAmB;;;KAIxB,qBAAqB,2BAA2B;KAEhD,eAAe,MAAM,KAAK,mBAAmB,OAAO,QAAQ;KAE5D;UAEK,oBAAoB;;;;;EAKnC;EACA,UAAU,gBAAgB;EAC1B,WAAW;;EAEX;;EAEA,WAAW;;EAEX;;;;;;EAMA,SAAS;;;;;;EAMT,oBAAoB;;;;;;EAMpB,eAAe,QAAQ,0BAA0B;;;;;;;EAOjD,kBAAkB,QAAQ,0BAA0B;;;;;EAKpD;;;;;EAKA,gBAAgB;;;;;;EAMhB,YAAY;;EAEZ,qBAAqB;;;;;EAKrB,QAAQ,eAAe;;;;;EAKvB;IAAW;MAAwB,KACjC;;;;;EAOF;;EAEA;;;;EAIA;;EAEA,SAAS,QAAQ;;;;;;;EAOjB,eACI,mBACA,0BAEE,QAAQ;IACN,SAAS;IACT,cAAc;QAGd,mBACA,wBACA,QAAQ,mBAAmB;;UAGpB;EACf;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;;EAEA;EACA;;EAEA,MAAM;;EAEN,kBAAkB;EAClB,YAAY;;EAEZ,SAAS;EACT;EACA;;iBAgBoB,gBAAgB,GACpC,MAAM,oBAAoB,KACzB,QAAQ;;;;UC5QM;;;EAGf;;EAEA;EACA;;;IAGE;;IAEA;;;;UAKa;EACf;;;;EAIA;;;EAGA;;EAEA;;;UAIe;EACf;EACA;EACA,SAAS;;;EAGT;;EAEA;IAAU;IAAkB;;;;UAIb;EACf,MAAM;EACN,MAAM;EACN,cAAc;;;;;;;;;;;;;;;;;;;UAoBC;EACf,gBAAgB,MAAM,cAAc,QAAQ;EAC5C,cAAc,UAAU,gBAAgB,QAAQ;EAChD,YAAY,SAAS,kBAAkB,UAAU,iBAAiB,QAAQ;EAC1E,eAAe,MAAM,iBAAiB,QAAQ;;UAG/B;EACf,iBAAiB;EACjB,eAAe;EACf,aAAa;EACb,gBAAgB;;;;;;cAOL,8BAA8B;mBACZ;EAA7B,YAA6B,WAAW;EAExC,gBAAgB,MAAM,cAAc,QAAQ;EAI5C,cAAc,UAAU,gBAAgB,QAAQ;EAIhD,YAAY,SAAS,kBAAkB,UAAU,iBAAiB,QAAQ;EAI1E,eAAe,MAAM,iBAAiB,QAAQ;;;;;;;;;cAYnC,0BAA0B;mBACpB;EAEjB,YAAY;EAIN,gBAAgB,OAAO,cAAc,QAAQ;EAI7C,cAAc,WAAW,gBAAgB,QAAQ;EAIjD,YACJ,UAAU,kBACV,WAAW,iBACV,QAAQ;EAIL,eAAe,OAAO,iBAAiB,QAAQ"}
|
package/dist/rl.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { a as detectRewardHacking, c as VerifiableRewardSource, d as filterDeter
|
|
|
7
7
|
import { i as InMemoryOutcomeStore, n as FileSystemOutcomeStore, o as OutcomeStore, r as FileSystemOutcomeStoreOptions, t as DeploymentOutcome } from "./outcome-store-BYHIuO0e.js";
|
|
8
8
|
import { t as AdversarialMutation } from "./adversarial-smnADNFS.js";
|
|
9
9
|
import { b as RolloutSplit, o as MintedRolloutLine } from "./schema-Cef2cFmb.js";
|
|
10
|
-
import { _ as EvalCampaignResult, a as FailureMode, c as SteeringChange, g as EvalCampaignOptions, i as ExperimentResult, r as ExperimentPlan, s as Researcher, y as runEvalCampaign } from "./researcher-
|
|
10
|
+
import { _ as EvalCampaignResult, a as FailureMode, c as SteeringChange, g as EvalCampaignOptions, i as ExperimentResult, r as ExperimentPlan, s as Researcher, y as runEvalCampaign } from "./researcher-CbSKhK8z.js";
|
|
11
11
|
import { t as InterimReleaseConfidence } from "./sequential-CYwq6Ff_.js";
|
|
12
12
|
import { r as RubricPredictiveValidityReport } from "./rubric-predictive-validity-C1dCLcvb.js";
|
|
13
13
|
//#region src/rl/active-curriculum.d.ts
|
package/dist/rollout/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as scoreOrigin, n as observedScore, o as trainingReward, r as observedSplitScore, s as trainingScore, t as isRealnessGated } from "../reward-nw2xZGZG.js";
|
|
2
2
|
import { _ as GATE_POLICIES, a as ROLLOUT_SPLITS, c as assertMintedLines, d as gateGamedOutcome, f as isRolloutLine, g as GATE_CHECK_IDS, h as GATE_CHECKS, i as ROLLOUT_SCHEMA, m as validateRolloutLine, n as ROLLOUT_CAPTURES, o as TRAINABLE_SPLITS, p as isTrainableSplit, r as ROLLOUT_ROLES, s as assertMinted, t as CHAT_ROLES, u as assertRolloutLine, v as gateErrors, y as gatedEvidenceOf } from "../schema-C6DW4ZHR.js";
|
|
3
3
|
import { a as toRftItem, c as toVerifiersRolloutOutput, i as toRewardRows, l as toVerifiersRolloutOutputs, n as realnessLabels, o as toRftItems, r as toJsonl, s as toSftRows } from "../exporters-q9iL-2Jf.js";
|
|
4
|
-
import { a as toHarborTrajectories, i as relabelImportedSplit, n as HARBOR_IMPORT_GAP, o as toHarborTrajectory, r as fromHarborTrajectory, t as ATIF_SCHEMA_VERSION } from "../rollout-
|
|
4
|
+
import { a as toHarborTrajectories, i as relabelImportedSplit, n as HARBOR_IMPORT_GAP, o as toHarborTrajectory, r as fromHarborTrajectory, t as ATIF_SCHEMA_VERSION } from "../rollout-CreDz__7.js";
|
|
5
5
|
import { C as readRolloutJournal, S as appendRolloutLines, T as writeRolloutLedger, _ as FORMAT_GATE_DISPOSITION, a as pushDataset, b as measureFormatGate, c as addScrubCounts, d as scrubLines, f as scrubRolloutLine, g as buildDatasetCard, h as RELEASE_FORMATS, i as planPushCommand, l as defaultRolloutScrubber, m as FORMAT_FILES, n as buildHfDataset, o as runRolloutReleaseCli, p as scrubText, r as parseRolloutReleaseArgs, s as SCRUB_RULES, t as ROLLOUT_RELEASE_USAGE, u as emptyScrubCounts, v as assertGateReport, w as readRolloutLedger, x as releaseRowRefs, y as gatedRolloutIds } from "../hf-dataset-DBJXXoY1.js";
|
|
6
6
|
import { t as mintRolloutRows } from "../mint-BvkwcYZU.js";
|
|
7
|
-
import { a as readOpencodeSessionMessages, c as findClaudeTranscripts, i as openOpencodeDb, n as findOpencodeSessionById, o as DEFAULT_CLAUDE_PROJECTS_DIR, r as findOpencodeSessionsByDirectory, s as claudeProjectSlug, t as DEFAULT_OPENCODE_DB, u as readClaudeTranscript } from "../opencode-sqlite-
|
|
7
|
+
import { a as readOpencodeSessionMessages, c as findClaudeTranscripts, i as openOpencodeDb, n as findOpencodeSessionById, o as DEFAULT_CLAUDE_PROJECTS_DIR, r as findOpencodeSessionsByDirectory, s as claudeProjectSlug, t as DEFAULT_OPENCODE_DB, u as readClaudeTranscript } from "../opencode-sqlite-8r6WUfHc.js";
|
|
8
8
|
export { ATIF_SCHEMA_VERSION, CHAT_ROLES, DEFAULT_CLAUDE_PROJECTS_DIR, DEFAULT_OPENCODE_DB, FORMAT_FILES, FORMAT_GATE_DISPOSITION, GATE_CHECKS, GATE_CHECK_IDS, GATE_POLICIES, HARBOR_IMPORT_GAP, RELEASE_FORMATS, ROLLOUT_CAPTURES, ROLLOUT_RELEASE_USAGE, ROLLOUT_ROLES, ROLLOUT_SCHEMA, ROLLOUT_SPLITS, SCRUB_RULES, TRAINABLE_SPLITS, addScrubCounts, appendRolloutLines, assertGateReport, assertMinted, assertMintedLines, assertRolloutLine, buildDatasetCard, buildHfDataset, claudeProjectSlug, defaultRolloutScrubber, emptyScrubCounts, findClaudeTranscripts, findOpencodeSessionById, findOpencodeSessionsByDirectory, fromHarborTrajectory, gateErrors, gateGamedOutcome, gatedEvidenceOf, gatedRolloutIds, isRealnessGated, isRolloutLine, isTrainableSplit, measureFormatGate, mintRolloutRows, observedScore, observedSplitScore, openOpencodeDb, parseRolloutReleaseArgs, planPushCommand, pushDataset, readClaudeTranscript, readOpencodeSessionMessages, readRolloutJournal, readRolloutLedger, realnessLabels, relabelImportedSplit, releaseRowRefs, runRolloutReleaseCli, scoreOrigin, scrubLines, scrubRolloutLine, scrubText, toHarborTrajectories, toHarborTrajectory, toJsonl, toRewardRows, toRftItem, toRftItems, toSftRows, toVerifiersRolloutOutput, toVerifiersRolloutOutputs, trainingReward, trainingScore, validateRolloutLine, writeRolloutLedger };
|
|
@@ -2,7 +2,7 @@ import { a as ROLLOUT_SPLITS, i as ROLLOUT_SCHEMA, n as ROLLOUT_CAPTURES, r as R
|
|
|
2
2
|
import "./exporters-q9iL-2Jf.js";
|
|
3
3
|
import "./hf-dataset-DBJXXoY1.js";
|
|
4
4
|
import "./mint-BvkwcYZU.js";
|
|
5
|
-
import "./opencode-sqlite-
|
|
5
|
+
import "./opencode-sqlite-8r6WUfHc.js";
|
|
6
6
|
//#region src/rollout/interchange/harbor.ts
|
|
7
7
|
/**
|
|
8
8
|
* Harbor ATIF-v1.7 interchange — `tangle.rollout.v1` ⇄ Agent Trajectory
|
|
@@ -621,4 +621,4 @@ function relabelImportedSplit(lines, split) {
|
|
|
621
621
|
//#endregion
|
|
622
622
|
export { toHarborTrajectories as a, relabelImportedSplit as i, HARBOR_IMPORT_GAP as n, toHarborTrajectory as o, fromHarborTrajectory as r, ATIF_SCHEMA_VERSION as t };
|
|
623
623
|
|
|
624
|
-
//# sourceMappingURL=rollout-
|
|
624
|
+
//# sourceMappingURL=rollout-CreDz__7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rollout-CeTlDrf6.js","names":[],"sources":["../src/rollout/interchange/harbor.ts"],"sourcesContent":["/**\n * Harbor ATIF-v1.7 interchange — `tangle.rollout.v1` ⇄ Agent Trajectory\n * Interchange Format.\n *\n * ATIF is the portability format (spec:\n * https://www.harborframework.com/docs/agents/trajectory-format, normative\n * RFC: harbor-framework/harbor `rfcs/0001-trajectory-format.md`). It sits\n * BELOW the waist of the rollout hourglass in both directions — export reads\n * `RolloutLine[]`, import writes `RolloutLine[]` — and it is never a source\n * of training labels:\n *\n * ATIF models NO reward, NO judge verdict, NO task/split coordinates.\n *\n * Consequences, both deliberate:\n * - EXPORT drops `outcome.reward`, `outcome.reward_source` and\n * `outcome.verdict` entirely. They are not smuggled into `extra`: a\n * third-party reading our ATIF file must not be able to mistake an\n * agent-eval judge score for something ATIF sanctioned.\n * - IMPORT therefore mints UNLABELED lines: `reward: null` (the existing\n * \"null reward is a labeled gap, never 0\" semantics), `verdict: null`,\n * and a `provenance.gap` naming the missing label. An imported\n * trajectory is not a training example until a judge scores it.\n *\n * Everything else we own that ATIF has no field for travels in a namespaced\n * escrow at `extra.tangle.*`, so our own round-trip is exact while a foreign\n * reader can ignore it. Fields that neither ATIF nor the escrow can carry\n * come back explicitly null / fail-closed, never invented.\n *\n * THE ESCROW IS NAMESPACED, NOT AUTHENTICATED. Anyone can write\n * `extra.tangle.*` into a file. So the escrow may restore what a value IS, but\n * never what a line is ALLOWED to do: `task.split` is forced to `holdout` on\n * every import regardless of what the document claims, and promoting an\n * imported trajectory to a trainable split is an explicit, greppable act\n * (`relabelImportedSplit`) rather than a property of the file. The document\n * keeps its claim — the claim just is not authority.\n *\n * Multi-agent shape differs on purpose. ATIF EMBEDS children in\n * `subagent_trajectories`; we keep a flat ledger with a normalized\n * `parent_rollout_id` edge. Export assembles the tree, import flattens it.\n * `session_id` is RUN-scoped in ATIF, so it carries `run_id` — the coordinate\n * that is shared by every invocation of one run — not `rollout_id`, which\n * identifies a single invocation and would split one run across session ids.\n *\n * ROUND-TRIPPING IS IDEMPOTENT: `import(export(import(export(x))))` is\n * byte-identical to `import(export(x))`. Import composes `provenance.gap` as a\n * de-duplicated ordered set rather than appending, and it emits every\n * `ChatMessage` with keys in the canonical schema order (role, content,\n * reasoning_content, tool_calls, tool_call_id, name, is_copied_context), so a\n * ledger hashed on serialized bytes sees no diff across further passes. The\n * FIRST import may re-order a producer's keys — that is the canonicalization.\n *\n * NOT building a Letta converter. Letta's trajectory-v1 is a strict subset of\n * what we need from ATIF here — no per-step or aggregate cost, no\n * multi-agent/subagent structure, no token-id or logprob channel — so a Letta\n * sink would carry less than this one and add a second format to keep\n * correct. Decision recorded in docs/rollout.md; do not re-litigate without a\n * concrete consumer that reads Letta and cannot read ATIF.\n */\n\nimport {\n assertRolloutLine,\n type ChatMessage,\n type ChatRole,\n type ChatToolCall,\n type GatedEvidence,\n ROLLOUT_CAPTURES,\n ROLLOUT_ROLES,\n ROLLOUT_SCHEMA,\n ROLLOUT_SPLITS,\n type RolloutArtifacts,\n type RolloutCapture,\n type RolloutCostBlock,\n type RolloutLine,\n type RolloutPolicy,\n type RolloutRole,\n type RolloutSplit,\n type RolloutStep,\n type RolloutTask,\n type ToolDef,\n} from '../schema'\n\nexport const ATIF_SCHEMA_VERSION = 'ATIF-v1.7'\n\n/** Gap note on every imported line — ATIF carries no verdict, so nothing is scored. */\nexport const HARBOR_IMPORT_GAP = 'imported from Harbor ATIF; no verdict'\n\n/** Namespaced escrow key for everything ATIF does not model but we must not lose. */\nconst ESCROW = 'tangle'\n\n/**\n * Marks a step we synthesized purely to hold tool results that answered no\n * assistant turn IN THIS DOCUMENT. ATIF has no `tool` source, so such results\n * need a carrier step; the marker lets import drop the carrier instead of\n * inventing a turn.\n *\n * A carrier's results carry NO `source_call_id`. RFC 0001 rule 2 requires every\n * `source_call_id` to match a `tool_call_id` in the same step's `tool_calls`,\n * and a carrier declares no calls (a `system` step cannot legally make one), so\n * emitting the id there would produce an invalid document. The id is escrowed\n * instead and restored verbatim on import — the link survives without the\n * document lying about who made the call.\n */\nconst TOOL_RESULTS_ONLY = 'tool-results-only'\n\n// ---------------------------------------------------------------------------\n// ATIF-v1.7 wire types (RFC 0001). Optional fields are optional here too.\n// ---------------------------------------------------------------------------\n\nexport type HarborStepSource = 'system' | 'user' | 'agent'\n\nexport interface HarborImageSource {\n media_type: string\n path: string\n}\n\nexport interface HarborContentPart {\n type: 'text' | 'image'\n text?: string\n source?: HarborImageSource\n}\n\nexport interface HarborToolCall {\n tool_call_id: string\n function_name: string\n /** ATIF requires a decoded JSON object here, unlike our raw argument string. */\n arguments: Record<string, unknown>\n extra?: Record<string, unknown>\n}\n\nexport interface HarborSubagentTrajectoryRef {\n trajectory_id?: string\n trajectory_path?: string\n /** Informational only since v1.7 — never a resolution key. */\n session_id?: string\n extra?: Record<string, unknown>\n}\n\nexport interface HarborObservationResult {\n source_call_id?: string\n content?: string | HarborContentPart[]\n subagent_trajectory_ref?: HarborSubagentTrajectoryRef[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborObservation {\n results: HarborObservationResult[]\n}\n\nexport interface HarborMetrics {\n prompt_tokens?: number\n completion_tokens?: number\n cached_tokens?: number\n cost_usd?: number\n prompt_token_ids?: number[]\n completion_token_ids?: number[]\n logprobs?: number[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborStep {\n /** Ordinal, sequential from 1. */\n step_id: number\n timestamp?: string\n source: HarborStepSource\n model_name?: string\n reasoning_effort?: string | number\n message: string | HarborContentPart[]\n reasoning_content?: string\n tool_calls?: HarborToolCall[]\n observation?: HarborObservation\n metrics?: HarborMetrics\n llm_call_count?: number\n is_copied_context?: boolean\n extra?: Record<string, unknown>\n}\n\nexport interface HarborAgent {\n name: string\n version: string\n model_name?: string\n /** OpenAI function-calling schema — byte-identical to our `ToolDef`. */\n tool_definitions?: ToolDef[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborFinalMetrics {\n total_prompt_tokens?: number\n total_completion_tokens?: number\n total_cached_tokens?: number\n total_cost_usd?: number\n total_steps?: number\n extra?: Record<string, unknown>\n}\n\nexport interface HarborTrajectory {\n schema_version: string\n session_id?: string\n /** Required on embedded subagents; we always set it so lines stay joinable. */\n trajectory_id?: string\n agent: HarborAgent\n steps: HarborStep[]\n notes?: string\n final_metrics?: HarborFinalMetrics\n continued_trajectory_ref?: string\n subagent_trajectories?: HarborTrajectory[]\n extra?: Record<string, unknown>\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v)\n\nconst asString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined)\n\nconst asNumberOrNull = (v: unknown): number | null =>\n typeof v === 'number' && Number.isFinite(v) ? v : null\n\nconst asIntegerOrUndefined = (v: unknown): number | undefined =>\n Number.isInteger(v) ? (v as number) : undefined\n\nconst asNumberArray = (v: unknown): number[] | undefined =>\n Array.isArray(v) && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n ? (v as number[])\n : undefined\n\nconst asIntegerArray = (v: unknown): number[] | undefined =>\n Array.isArray(v) && v.every((n) => Number.isInteger(n)) ? (v as number[]) : undefined\n\n/**\n * Builds a `ChatMessage` with keys in the schema's declaration order.\n *\n * Object key order is insertion order in JS, so a message assembled\n * conditionally field-by-field serializes differently depending on which\n * optional fields were present — which makes a byte-hashed ledger see a diff\n * across an import that changed nothing. One builder, one order, stable bytes.\n */\nfunction canonicalChatMessage(parts: {\n role: ChatRole\n content: string | null\n reasoning_content?: string\n tool_calls?: ChatToolCall[]\n tool_call_id?: string\n name?: string\n is_copied_context?: boolean\n}): ChatMessage {\n const message: ChatMessage = { role: parts.role, content: parts.content }\n if (parts.reasoning_content !== undefined) message.reasoning_content = parts.reasoning_content\n if (parts.tool_calls !== undefined) message.tool_calls = parts.tool_calls\n if (parts.tool_call_id !== undefined) message.tool_call_id = parts.tool_call_id\n if (parts.name !== undefined) message.name = parts.name\n if (parts.is_copied_context === true) message.is_copied_context = true\n return message\n}\n\n/** Reads the `extra.tangle` escrow, tolerating a foreign file that has none. */\nfunction escrowOf(extra: Record<string, unknown> | undefined): Record<string, unknown> | undefined {\n if (!isRecord(extra)) return undefined\n const value = extra[ESCROW]\n return isRecord(value) ? value : undefined\n}\n\nfunction escrowSection(\n escrow: Record<string, unknown> | undefined,\n key: string,\n): Record<string, unknown> | undefined {\n if (escrow === undefined) return undefined\n const value = escrow[key]\n return isRecord(value) ? value : undefined\n}\n\n// ---------------------------------------------------------------------------\n// Export: RolloutLine[] → ATIF trajectory tree\n// ---------------------------------------------------------------------------\n\nfunction toHarborToolCall(call: ChatToolCall): HarborToolCall {\n // ATIF requires `arguments` to be a JSON object; ours is the raw\n // JSON-encoded string the model emitted, and models really do emit\n // malformed ones. Keep the exact bytes in `extra` so import restores the\n // string verbatim instead of re-serializing a normalized parse.\n let parsed: Record<string, unknown> | undefined\n try {\n const decoded: unknown = JSON.parse(call.function.arguments)\n if (isRecord(decoded)) parsed = decoded\n } catch {\n parsed = undefined\n }\n return {\n tool_call_id: call.id,\n function_name: call.function.name,\n arguments: parsed ?? {},\n extra: { [ESCROW]: { arguments_raw: call.function.arguments } },\n }\n}\n\n/**\n * `linked` = this result is attached to the step that actually declared the\n * call, so `source_call_id` is legal (RFC 0001 rule 2). When it is not, the id\n * goes to escrow instead of onto the wire.\n */\nfunction toObservationResult(message: ChatMessage, linked: boolean): HarborObservationResult {\n const result: HarborObservationResult = {}\n if (linked && message.tool_call_id !== undefined) result.source_call_id = message.tool_call_id\n if (message.content !== null) result.content = message.content\n const escrow: Record<string, unknown> = {}\n if (!linked && message.tool_call_id !== undefined) escrow.source_call_id = message.tool_call_id\n if (message.name !== undefined) escrow.name = message.name\n // `content: null` on a tool turn is meaningful (a tool that returned\n // nothing) and is not the same as the empty string ATIF would round-trip it to.\n if (message.content === null) escrow.content_null = true\n if (message.reasoning_content !== undefined) escrow.reasoning_content = message.reasoning_content\n if (message.is_copied_context === true) escrow.is_copied_context = true\n if (Object.keys(escrow).length > 0) result.extra = { [ESCROW]: escrow }\n return result\n}\n\n/** True when `step` is the agent turn that declared `callId` — the rule-2 test. */\nfunction declaresCall(step: HarborStep, callId: string | undefined): boolean {\n if (callId === undefined) return false\n return step.tool_calls?.some((call) => call.tool_call_id === callId) === true\n}\n\n/**\n * Attaches the four RL fields lifted from ATIF onto the agent step the span\n * describes. They are ALSO escrowed with the whole span under `extra.tangle`,\n * on purpose: the escrow is how our own round-trip stays exact, and these\n * native fields are how a foreign consumer — which never reads our escrow —\n * gets the logprobs and token ids at all. A field carried only in the escrow is\n * not an interchange field.\n */\nfunction applySpanMetrics(step: HarborStep, span: RolloutStep | undefined): void {\n if (span === undefined) return\n if (span.llm_call_count !== undefined) step.llm_call_count = span.llm_call_count\n const metrics: HarborMetrics = {}\n if (span.prompt_token_ids !== undefined) metrics.prompt_token_ids = span.prompt_token_ids\n if (span.completion_token_ids !== undefined) {\n metrics.completion_token_ids = span.completion_token_ids\n }\n if (span.logprobs !== undefined) metrics.logprobs = span.logprobs\n if (Object.keys(metrics).length > 0) step.metrics = metrics\n}\n\n/**\n * Coalescing fold, not a 1:1 map: ATIF has no `tool` source, so a tool result\n * becomes an `observation.results[]` entry on the agent step THAT DECLARED ITS\n * `tool_call_id`.\n *\n * Linking by id, not by adjacency. Adjacency emitted invalid documents in three\n * shapes the RFC forbids — an assistant turn with no `tool_calls` swallowing the\n * results that followed it, a result whose id matched none of the preceding\n * step's calls, and an unanswered result riding a `system` step that carried a\n * `source_call_id` it could never declare. Attaching only to the step that owns\n * the id also preserves message order exactly: a result either joins the step\n * immediately before it or becomes its own carrier at its own position.\n *\n * `line.steps` span projections are matched to agent steps in order (k-th llm\n * span → k-th agent step) purely to fill ATIF's native per-step `metrics`;\n * extra spans on either side are simply not matched, never invented.\n */\nfunction messagesToSteps(line: RolloutLine): HarborStep[] {\n const steps: HarborStep[] = []\n const llmSpans = (line.steps ?? []).filter((span) => span.kind === 'llm')\n let nextSpan = 0\n for (const message of line.messages) {\n if (message.role === 'tool') {\n const previous = steps[steps.length - 1]\n if (previous !== undefined && declaresCall(previous, message.tool_call_id)) {\n if (previous.observation === undefined) previous.observation = { results: [] }\n previous.observation.results.push(toObservationResult(message, true))\n continue\n }\n // A tool result answering no assistant turn in this document (truncated or\n // reconstructed transcript). It still has to survive, so it rides a marked\n // carrier step whose observation states no call id.\n const carrier: HarborStep = {\n step_id: steps.length + 1,\n source: 'system',\n message: '',\n observation: { results: [toObservationResult(message, false)] },\n extra: { [ESCROW]: { synthetic: TOOL_RESULTS_ONLY } },\n }\n if (message.is_copied_context === true) carrier.is_copied_context = true\n steps.push(carrier)\n continue\n }\n const step: HarborStep = {\n step_id: steps.length + 1,\n source: message.role === 'assistant' ? 'agent' : message.role,\n message: message.content ?? '',\n }\n const escrow: Record<string, unknown> = {}\n if (message.content === null) escrow.content_null = true\n if (message.name !== undefined) escrow.name = message.name\n if (message.role === 'assistant') {\n if (line.policy.model !== null) step.model_name = line.policy.model\n if (message.reasoning_content !== undefined) {\n step.reasoning_content = message.reasoning_content\n }\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n step.tool_calls = message.tool_calls.map(toHarborToolCall)\n }\n applySpanMetrics(step, llmSpans[nextSpan])\n nextSpan += 1\n } else if (message.reasoning_content !== undefined) {\n // ATIF confines `reasoning_content` to agent steps; ours is not confined.\n escrow.reasoning_content = message.reasoning_content\n }\n // RFC 0001 rule 7: a copied-context turn was not authored by this agent, and\n // an SFT pipeline MUST exclude it. Native ATIF field, both directions.\n if (message.is_copied_context === true) step.is_copied_context = true\n if (Object.keys(escrow).length > 0) step.extra = { [ESCROW]: escrow }\n steps.push(step)\n }\n return steps\n}\n\nfunction finalMetricsOf(line: RolloutLine, stepCount: number): HarborFinalMetrics {\n const metrics: HarborFinalMetrics = {}\n if (line.cost.tokens_in !== null) metrics.total_prompt_tokens = line.cost.tokens_in\n if (line.cost.tokens_out !== null) metrics.total_completion_tokens = line.cost.tokens_out\n if (line.cost.cache_read !== null) metrics.total_cached_tokens = line.cost.cache_read\n // Omitted, never 0, when cost was not captured — a fake 0 is a lie about spend.\n if (line.cost.usd !== null) metrics.total_cost_usd = line.cost.usd\n metrics.total_steps = stepCount\n // ATIF has no aggregate field for these three; `reasoning_tokens` under\n // `extra` is the key the RFC's own worked example uses.\n const extra: Record<string, unknown> = {}\n if (line.cost.tokens_reasoning !== null) extra.reasoning_tokens = line.cost.tokens_reasoning\n if (line.cost.cache_write !== null) extra.cache_write_tokens = line.cost.cache_write\n if (line.cost.wall_s !== null) extra.wall_s = line.cost.wall_s\n if (line.cost.llm_call_count !== undefined && line.cost.llm_call_count !== null) {\n extra.llm_call_count = line.cost.llm_call_count\n }\n if (Object.keys(extra).length > 0) metrics.extra = extra\n return metrics\n}\n\nfunction notesOf(line: RolloutLine): string | undefined {\n const parts: string[] = []\n if (line.provenance.gap !== undefined) parts.push(line.provenance.gap)\n if (line.outcome.realness_gated === true) {\n // ATIF has no gate field. A third-party consumer that ignores `extra`\n // would otherwise see a gamed trajectory with nothing marking it, so the\n // flag is stated in prose as well. This export carries no reward at all,\n // so it is not a training-data door — but it is an audit record.\n parts.push('realness-gated: this run faked its success signal (anti-Goodhart gate fired)')\n }\n return parts.length > 0 ? parts.join(' | ') : undefined\n}\n\nfunction toTrajectoryNode(line: RolloutLine): HarborTrajectory {\n const steps = messagesToSteps(line)\n const trajectory: HarborTrajectory = {\n schema_version: ATIF_SCHEMA_VERSION,\n // RUN-scoped, per the spec — so it is `run_id`, the coordinate every\n // invocation of one run shares. `rollout_id` identifies a single\n // invocation: using it gave two roots of the same run different session\n // ids, and foreign tooling that groups by session_id would split the run.\n session_id: line.run_id,\n trajectory_id: line.rollout_id,\n agent: {\n // ATIF requires both; ours are nullable, so a null is substituted here\n // and restored on import from the escrowed policy — never guessed back.\n name: line.policy.harness ?? 'unknown',\n version: line.policy.harness_version ?? '0.0.0',\n ...(line.policy.model !== null ? { model_name: line.policy.model } : {}),\n ...(line.tool_defs.length > 0 ? { tool_definitions: line.tool_defs } : {}),\n },\n steps,\n final_metrics: finalMetricsOf(line, steps.length),\n extra: {\n [ESCROW]: {\n schema: line.schema,\n rollout_id: line.rollout_id,\n parent_rollout_id: line.parent_rollout_id,\n run_id: line.run_id,\n ...(line.experiment_id !== undefined ? { experiment_id: line.experiment_id } : {}),\n ...(line.candidate_id !== undefined ? { candidate_id: line.candidate_id } : {}),\n generation: line.generation,\n candidate_index: line.candidate_index,\n role: line.role,\n task: line.task,\n policy: line.policy,\n // Span projections overlap the same turns as `steps[]`; folding them\n // into ATIF steps would double-count the run, so they stay escrowed.\n ...(line.steps !== undefined ? { spans: line.steps } : {}),\n outcome: {\n // reward / reward_source / verdict are deliberately absent — see the\n // module header. Only the non-scalar outcome fields travel.\n metrics: line.outcome.metrics,\n is_completed: line.outcome.is_completed,\n is_truncated: line.outcome.is_truncated,\n error: line.outcome.error,\n ...(line.outcome.realness_gated !== undefined\n ? { realness_gated: line.outcome.realness_gated }\n : {}),\n },\n artifacts: line.artifacts,\n provenance: line.provenance,\n },\n },\n }\n const notes = notesOf(line)\n if (notes !== undefined) trajectory.notes = notes\n return trajectory\n}\n\ninterface Forest {\n roots: RolloutLine[]\n childrenOf: Map<string, RolloutLine[]>\n}\n\nfunction buildForest(lines: RolloutLine[]): Forest {\n const byId = new Map<string, RolloutLine>()\n for (const line of lines) {\n if (byId.has(line.rollout_id)) {\n throw new Error(`duplicate rollout_id in input: ${line.rollout_id}`)\n }\n byId.set(line.rollout_id, line)\n }\n const roots: RolloutLine[] = []\n const childrenOf = new Map<string, RolloutLine[]>()\n for (const line of lines) {\n const parent = line.parent_rollout_id\n // A parent outside this set is a root OF WHAT WE HAVE: the edge is kept in\n // escrow so a later import restores the dangling pointer instead of nulling it.\n if (parent === null || !byId.has(parent)) {\n roots.push(line)\n continue\n }\n const siblings = childrenOf.get(parent)\n if (siblings === undefined) childrenOf.set(parent, [line])\n else siblings.push(line)\n }\n // Every line has a parent inside the set: the edges form a cycle with no\n // root. Returning zero documents would drop the whole episode silently.\n if (lines.length > 0 && roots.length === 0) {\n throw new Error(\n `parent_rollout_id cycle: no root among ${lines.length} lines (${lines.map((l) => l.rollout_id).join(', ')})`,\n )\n }\n return { roots, childrenOf }\n}\n\nfunction assemble(line: RolloutLine, forest: Forest, onPath: Set<string>): HarborTrajectory {\n if (onPath.has(line.rollout_id)) {\n throw new Error(`parent_rollout_id cycle through rollout_id ${line.rollout_id}`)\n }\n onPath.add(line.rollout_id)\n const node = toTrajectoryNode(line)\n const children = forest.childrenOf.get(line.rollout_id)\n if (children !== undefined && children.length > 0) {\n node.subagent_trajectories = children.map((child) => assemble(child, forest, onPath))\n }\n onPath.delete(line.rollout_id)\n return node\n}\n\n/**\n * Assemble one episode's flat lines into a single ATIF trajectory tree,\n * linked by `parent_rollout_id`.\n *\n * Reward, verdict and split are NOT emitted (ATIF models none of them); the\n * split and the rest of the task coordinates survive only in `extra.tangle`.\n *\n * We deliberately do NOT synthesize an `observation.subagent_trajectory_ref`\n * pointing at each child: our ledger records WHICH invocation spawned a\n * worker, not which STEP did, and attaching the ref to a guessed step would\n * fabricate a causal claim. Children are embedded in `subagent_trajectories`\n * (each with the `trajectory_id` the spec requires) and the edge is stated in\n * the child's escrowed `parent_rollout_id`.\n *\n * Throws when the lines are not one tree — use `toHarborTrajectories` for a forest.\n */\nexport function toHarborTrajectory(lines: RolloutLine[]): HarborTrajectory {\n const trees = toHarborTrajectories(lines)\n if (trees.length === 0) throw new Error('toHarborTrajectory: no lines')\n if (trees.length > 1) {\n const ids = trees.map((t) => t.trajectory_id ?? '?').join(', ')\n throw new Error(\n `toHarborTrajectory: ${trees.length} roots (${ids}) — ATIF is one tree per document; use toHarborTrajectories`,\n )\n }\n return trees[0]!\n}\n\n/** Every independent tree in the input, one ATIF document each. */\nexport function toHarborTrajectories(lines: RolloutLine[]): HarborTrajectory[] {\n const forest = buildForest(lines)\n return forest.roots.map((root) => assemble(root, forest, new Set()))\n}\n\n// ---------------------------------------------------------------------------\n// Import: ATIF trajectory tree → RolloutLine[]\n// ---------------------------------------------------------------------------\n\nfunction contentToString(message: string | HarborContentPart[]): string {\n if (typeof message === 'string') return message\n return message\n .map((part) =>\n part.type === 'image'\n ? // Our chat content is text-only. Describing the image is honest about\n // what the source held; dropping it silently would not be.\n `[image ${part.source?.media_type ?? 'unknown'} ${part.source?.path ?? ''}]`.trim()\n : (part.text ?? ''),\n )\n .join('\\n')\n}\n\nfunction fromHarborToolCall(call: HarborToolCall): ChatToolCall {\n const raw = asString(escrowOf(call.extra)?.arguments_raw)\n return {\n id: call.tool_call_id,\n type: 'function',\n function: { name: call.function_name, arguments: raw ?? JSON.stringify(call.arguments ?? {}) },\n }\n}\n\nfunction fromObservationResult(\n result: HarborObservationResult,\n callId: string | undefined,\n): ChatMessage {\n const escrow = escrowOf(result.extra)\n return canonicalChatMessage({\n role: 'tool',\n content:\n escrow?.content_null === true\n ? null\n : result.content === undefined\n ? ''\n : contentToString(result.content),\n reasoning_content: asString(escrow?.reasoning_content),\n tool_call_id: callId,\n name: asString(escrow?.name),\n is_copied_context: escrow?.is_copied_context === true,\n })\n}\n\nfunction stepsToMessages(steps: HarborStep[]): ChatMessage[] {\n const messages: ChatMessage[] = []\n for (const step of steps) {\n const escrow = escrowOf(step.extra)\n const carrierOnly = escrow?.synthetic === TOOL_RESULTS_ONLY\n if (!carrierOnly) {\n messages.push(\n canonicalChatMessage({\n role: step.source === 'agent' ? 'assistant' : step.source,\n content: escrow?.content_null === true ? null : contentToString(step.message),\n reasoning_content: step.reasoning_content ?? asString(escrow?.reasoning_content),\n tool_calls:\n step.tool_calls !== undefined && step.tool_calls.length > 0\n ? step.tool_calls.map(fromHarborToolCall)\n : undefined,\n name: asString(escrow?.name),\n is_copied_context: step.is_copied_context === true,\n }),\n )\n }\n for (const result of step.observation?.results ?? []) {\n const resultEscrow = escrowOf(result.extra)\n const callId = result.source_call_id ?? asString(resultEscrow?.source_call_id)\n if (carrierOnly) {\n // Our own carrier: every result on it was a tool turn, and its call id\n // (if the transcript had one) is in escrow, not on the wire.\n messages.push(fromObservationResult(result, callId))\n continue\n }\n if (typeof callId === 'string') {\n messages.push(fromObservationResult(result, callId))\n continue\n }\n // ATIF allows a result from a non-tool-calling action. Our chat schema\n // requires `tool_call_id` on a tool turn, so inventing one would forge a\n // link; the text is preserved as a system observation instead.\n if (result.content !== undefined) {\n messages.push(\n canonicalChatMessage({ role: 'system', content: contentToString(result.content) }),\n )\n }\n }\n }\n return messages\n}\n\nfunction taskFrom(escrow: Record<string, unknown> | undefined, fallbackId: string): RolloutTask {\n const task = escrowSection(escrow, 'task')\n return {\n suite: asString(task?.suite) ?? 'harbor-atif-import',\n instance_id: asString(task?.instance_id) ?? fallbackId,\n // ALWAYS holdout — the escrowed claim is read for nothing here.\n //\n // `extra.tangle.task.split` is a namespaced key, not an authenticated one:\n // a hand-written or third-party document can set `split: 'search'` as\n // easily as our own exporter can, and honouring it made \"this file says so\"\n // sufficient to walk into a training export. Trainability is a decision\n // about a file, so it is made by an operator through\n // `relabelImportedSplit`, never by the file about itself. The claim is not\n // destroyed — it stays readable in the source document.\n split: 'holdout',\n seed: asNumberOrNull(task?.seed),\n rep: asIntegerOrUndefined(task?.rep) ?? 0,\n }\n}\n\nfunction policyFrom(\n escrow: Record<string, unknown> | undefined,\n agent: HarborAgent,\n): RolloutPolicy {\n const escrowed = escrowSection(escrow, 'policy')\n if (escrowed !== undefined) {\n // Our own export: restore verbatim, including the nulls ATIF forced us to\n // substitute placeholders for in `agent.name` / `agent.version`.\n return {\n harness: asString(escrowed.harness) ?? null,\n harness_version: asString(escrowed.harness_version) ?? null,\n model: asString(escrowed.model) ?? null,\n provider: asString(escrowed.provider) ?? null,\n profile_commit: asString(escrowed.profile_commit) ?? null,\n ...(escrowed.prompt_hash !== undefined\n ? { prompt_hash: asString(escrowed.prompt_hash) ?? null }\n : {}),\n ...(escrowed.config_hash !== undefined\n ? { config_hash: asString(escrowed.config_hash) ?? null }\n : {}),\n ...(escrowed.agent_profile_cell_id !== undefined\n ? { agent_profile_cell_id: asString(escrowed.agent_profile_cell_id) ?? null }\n : {}),\n sampling: isRecord(escrowed.sampling) ? escrowed.sampling : null,\n }\n }\n return {\n harness: agent.name,\n harness_version: agent.version,\n model: agent.model_name ?? null,\n provider: null,\n profile_commit: null,\n sampling: null,\n }\n}\n\nfunction artifactsFrom(escrow: Record<string, unknown> | undefined): RolloutArtifacts {\n const artifacts = escrowSection(escrow, 'artifacts')\n return {\n patch_path: asString(artifacts?.patch_path) ?? null,\n run_dir: asString(artifacts?.run_dir) ?? null,\n transcript_ref: asString(artifacts?.transcript_ref) ?? null,\n }\n}\n\nfunction costFrom(final: HarborFinalMetrics | undefined): RolloutCostBlock {\n const rawExtra = final?.extra\n const extra = isRecord(rawExtra) ? rawExtra : undefined\n const calls = asIntegerOrUndefined(extra?.llm_call_count)\n return {\n usd: asNumberOrNull(final?.total_cost_usd),\n tokens_in: asNumberOrNull(final?.total_prompt_tokens),\n tokens_out: asNumberOrNull(final?.total_completion_tokens),\n tokens_reasoning: asNumberOrNull(extra?.reasoning_tokens),\n cache_read: asNumberOrNull(final?.total_cached_tokens),\n cache_write: asNumberOrNull(extra?.cache_write_tokens),\n wall_s: asNumberOrNull(extra?.wall_s),\n ...(calls !== undefined ? { llm_call_count: calls } : {}),\n }\n}\n\n/**\n * Recovers span projections from ATIF's NATIVE per-step channel, for documents\n * with no `extra.tangle.spans` escrow — i.e. everything a foreign producer\n * writes. Without this the logprobs and token ids a Harbor-native trainer\n * records would be read, validated, and then dropped on the floor.\n *\n * Only steps that actually carry one of the four fields produce a span: an\n * agent step with no metrics means \"not captured\", and inventing an empty span\n * for it would claim the run had a shape we did not observe.\n */\nfunction spansFromSteps(steps: HarborStep[]): RolloutStep[] {\n const spans: RolloutStep[] = []\n for (const step of steps) {\n if (step.source !== 'agent') continue\n const calls = asIntegerOrUndefined(step.llm_call_count)\n const promptIds = asIntegerArray(step.metrics?.prompt_token_ids)\n const completionIds = asIntegerArray(step.metrics?.completion_token_ids)\n const logprobs = asNumberArray(step.metrics?.logprobs)\n if (\n calls === undefined &&\n promptIds === undefined &&\n completionIds === undefined &&\n logprobs === undefined\n ) {\n continue\n }\n spans.push({\n kind: 'llm',\n name: step.model_name ?? 'chat',\n ...(calls !== undefined ? { llm_call_count: calls } : {}),\n ...(promptIds !== undefined ? { prompt_token_ids: promptIds } : {}),\n ...(completionIds !== undefined ? { completion_token_ids: completionIds } : {}),\n ...(logprobs !== undefined ? { logprobs } : {}),\n })\n }\n return spans\n}\n\n/**\n * Composes `provenance.gap` as an ordered SET of reasons.\n *\n * Appending made the note accrete on every pass (\"…no verdict | …no verdict\"),\n * which both grows without bound and breaks byte-level idempotency for a ledger\n * hashed on its serialized lines.\n */\nfunction composeGap(escrowedGap: string | undefined, added: readonly string[]): string {\n const parts: string[] = []\n const seen = new Set<string>()\n for (const raw of [...(escrowedGap?.split(' | ') ?? []), ...added]) {\n const reason = raw.trim()\n if (reason.length === 0 || seen.has(reason)) continue\n seen.add(reason)\n parts.push(reason)\n }\n return parts.join(' | ')\n}\n\nexport interface FromHarborOptions {\n /** Injected clock for deterministic output when the source carries no capture time. */\n now?: () => Date\n}\n\nfunction nodeToLine(\n trajectory: HarborTrajectory,\n parentId: string | null,\n capturedAt: string,\n): RolloutLine {\n const escrow = escrowOf(trajectory.extra)\n const rolloutId =\n asString(escrow?.rollout_id) ?? trajectory.trajectory_id ?? trajectory.session_id\n if (rolloutId === undefined || rolloutId.length === 0) {\n throw new Error(\n 'fromHarborTrajectory: trajectory has no trajectory_id or session_id — cannot mint a joinable rollout_id without inventing one',\n )\n }\n const outcome = escrowSection(escrow, 'outcome')\n const provenance = escrowSection(escrow, 'provenance')\n const capture = provenance?.capture\n const escrowedGap = asString(provenance?.gap)\n const role = escrow?.role\n const escrowedSpans = escrow?.spans\n // The escrow wins when it exists (our own export: exact, including an empty\n // array, which claims \"captured, none\" rather than \"not captured\"), and the\n // native per-step channel is the fallback (a foreign export: still signal).\n const nativeSpans = spansFromSteps(trajectory.steps)\n const spans: RolloutStep[] | undefined = Array.isArray(escrowedSpans)\n ? (escrowedSpans as RolloutStep[])\n : nativeSpans.length > 0\n ? nativeSpans\n : undefined\n const messages = stepsToMessages(trajectory.steps)\n const line: RolloutLine = {\n schema: ROLLOUT_SCHEMA,\n rollout_id: rolloutId,\n // The tree edge wins for embedded children; for a root, the escrowed\n // pointer may reference a line outside this document and is preserved.\n parent_rollout_id: parentId ?? asString(escrow?.parent_rollout_id) ?? null,\n run_id: asString(escrow?.run_id) ?? trajectory.session_id ?? rolloutId,\n // Required keys on the wire (0.127.0): a foreign document that never\n // stated them imports as explicit `null`, not as an absent field.\n experiment_id: asString(escrow?.experiment_id) ?? null,\n candidate_id: asString(escrow?.candidate_id) ?? null,\n generation: asIntegerOrUndefined(escrow?.generation) ?? null,\n candidate_index: asIntegerOrUndefined(escrow?.candidate_index) ?? null,\n role: ROLLOUT_ROLES.includes(role as RolloutRole) ? (role as RolloutRole) : 'agent',\n task: taskFrom(escrow, rolloutId),\n policy: policyFrom(escrow, trajectory.agent),\n messages,\n tool_defs: trajectory.agent.tool_definitions ?? [],\n ...(spans !== undefined ? { steps: spans } : {}),\n outcome: {\n // ATIF carries no label. Null is the labeled gap; a 0 here would be a\n // fabricated failure and a 1 a fabricated success.\n reward: null,\n reward_source: null,\n verdict: null,\n metrics: isRecord(outcome?.metrics) ? outcome.metrics : {},\n is_completed: typeof outcome?.is_completed === 'boolean' ? outcome.is_completed : true,\n is_truncated:\n typeof outcome?.is_truncated === 'boolean'\n ? outcome.is_truncated\n : trajectory.continued_trajectory_ref !== undefined,\n error: asString(outcome?.error) ?? null,\n // The anti-Goodhart flag is restored when the source document stated\n // it; the wire schema requires the field, so a document that never did\n // imports as `false`. That is safe here because the reward is already\n // forced to `null` (not trainable) and `realness_screened` stays\n // absent = unknown rather than claiming a screen ran.\n realness_gated: outcome?.realness_gated === true,\n },\n cost: costFrom(trajectory.final_metrics),\n artifacts: artifactsFrom(escrow),\n provenance: {\n captured_at: asString(provenance?.captured_at) ?? capturedAt,\n capture: ROLLOUT_CAPTURES.includes(capture as RolloutCapture)\n ? (capture as RolloutCapture)\n : 'backfill',\n gap: composeGap(escrowedGap, [HARBOR_IMPORT_GAP]),\n // Restored for the same reason `realness_gated` is, and with the opposite\n // risk profile from the reward: this is the gated run's own measurement\n // bag, moved off `outcome` by `gateGamedOutcome` so no exporter reads it\n // as training input. Dropping it here would silently destroy the audit\n // trail that says WHY the run was flagged and what it claimed, on the one\n // population an auditor most wants to inspect. It cannot be fail-open —\n // nothing projects `provenance` into a training row.\n ...(isRecord(provenance?.gated_evidence)\n ? { gated_evidence: provenance.gated_evidence as GatedEvidence }\n : {}),\n },\n }\n assertRolloutLine(line, `rollout line imported from ATIF trajectory ${rolloutId}`)\n return line\n}\n\n/**\n * Flatten an ATIF trajectory tree back into `tangle.rollout.v1` lines, parent\n * first, each child carrying `parent_rollout_id`.\n *\n * Every line comes back UNLABELED: `reward`, `reward_source` and `verdict` are\n * null and `provenance.gap` says why. ATIF models no verdict, so scoring an\n * imported trajectory is a judge's job, not this function's. Every line lands\n * on `holdout` whatever the document claims — see `relabelImportedSplit`.\n */\nexport function fromHarborTrajectory(\n trajectory: HarborTrajectory,\n options: FromHarborOptions = {},\n): RolloutLine[] {\n const capturedAt = (options.now?.() ?? new Date()).toISOString()\n const lines: RolloutLine[] = []\n const walk = (node: HarborTrajectory, parentId: string | null, onPath: Set<string>): void => {\n const line = nodeToLine(node, parentId, capturedAt)\n if (onPath.has(line.rollout_id)) {\n throw new Error(`subagent_trajectories cycle through trajectory_id ${line.rollout_id}`)\n }\n onPath.add(line.rollout_id)\n lines.push(line)\n for (const child of node.subagent_trajectories ?? []) {\n walk(child, line.rollout_id, onPath)\n }\n onPath.delete(line.rollout_id)\n }\n walk(trajectory, null, new Set())\n return lines\n}\n\n/**\n * THE explicit door out of `holdout` for imported lines.\n *\n * Import forces `holdout` because a document's own claim about its split is not\n * evidence — anyone can write `extra.tangle.task.split`. Promoting a file to a\n * trainable split is an operator's decision about provenance they verified, so\n * it is a separate, greppable call: `grep relabelImportedSplit` enumerates\n * every place foreign data was declared trainable, which is exactly the audit\n * the trusted-escrow version made impossible.\n *\n * Returns plain `RolloutLine`s. They still have to pass `assertMinted` (and its\n * anti-Goodhart check) to reach an exporter — re-labeling a split is not\n * minting a reward.\n */\nexport function relabelImportedSplit(\n lines: readonly RolloutLine[],\n split: RolloutSplit,\n): RolloutLine[] {\n if (!ROLLOUT_SPLITS.includes(split)) {\n throw new Error(`relabelImportedSplit: unknown split ${String(split)}`)\n }\n return lines.map((line) => ({ ...line, task: { ...line.task, split } }))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rollout-CreDz__7.js","names":[],"sources":["../src/rollout/interchange/harbor.ts"],"sourcesContent":["/**\n * Harbor ATIF-v1.7 interchange — `tangle.rollout.v1` ⇄ Agent Trajectory\n * Interchange Format.\n *\n * ATIF is the portability format (spec:\n * https://www.harborframework.com/docs/agents/trajectory-format, normative\n * RFC: harbor-framework/harbor `rfcs/0001-trajectory-format.md`). It sits\n * BELOW the waist of the rollout hourglass in both directions — export reads\n * `RolloutLine[]`, import writes `RolloutLine[]` — and it is never a source\n * of training labels:\n *\n * ATIF models NO reward, NO judge verdict, NO task/split coordinates.\n *\n * Consequences, both deliberate:\n * - EXPORT drops `outcome.reward`, `outcome.reward_source` and\n * `outcome.verdict` entirely. They are not smuggled into `extra`: a\n * third-party reading our ATIF file must not be able to mistake an\n * agent-eval judge score for something ATIF sanctioned.\n * - IMPORT therefore mints UNLABELED lines: `reward: null` (the existing\n * \"null reward is a labeled gap, never 0\" semantics), `verdict: null`,\n * and a `provenance.gap` naming the missing label. An imported\n * trajectory is not a training example until a judge scores it.\n *\n * Everything else we own that ATIF has no field for travels in a namespaced\n * escrow at `extra.tangle.*`, so our own round-trip is exact while a foreign\n * reader can ignore it. Fields that neither ATIF nor the escrow can carry\n * come back explicitly null / fail-closed, never invented.\n *\n * THE ESCROW IS NAMESPACED, NOT AUTHENTICATED. Anyone can write\n * `extra.tangle.*` into a file. So the escrow may restore what a value IS, but\n * never what a line is ALLOWED to do: `task.split` is forced to `holdout` on\n * every import regardless of what the document claims, and promoting an\n * imported trajectory to a trainable split is an explicit, greppable act\n * (`relabelImportedSplit`) rather than a property of the file. The document\n * keeps its claim — the claim just is not authority.\n *\n * Multi-agent shape differs on purpose. ATIF EMBEDS children in\n * `subagent_trajectories`; we keep a flat ledger with a normalized\n * `parent_rollout_id` edge. Export assembles the tree, import flattens it.\n * `session_id` is RUN-scoped in ATIF, so it carries `run_id` — the coordinate\n * that is shared by every invocation of one run — not `rollout_id`, which\n * identifies a single invocation and would split one run across session ids.\n *\n * ROUND-TRIPPING IS IDEMPOTENT: `import(export(import(export(x))))` is\n * byte-identical to `import(export(x))`. Import composes `provenance.gap` as a\n * de-duplicated ordered set rather than appending, and it emits every\n * `ChatMessage` with keys in the canonical schema order (role, content,\n * reasoning_content, tool_calls, tool_call_id, name, is_copied_context), so a\n * ledger hashed on serialized bytes sees no diff across further passes. The\n * FIRST import may re-order a producer's keys — that is the canonicalization.\n *\n * NOT building a Letta converter. Letta's trajectory-v1 is a strict subset of\n * what we need from ATIF here — no per-step or aggregate cost, no\n * multi-agent/subagent structure, no token-id or logprob channel — so a Letta\n * sink would carry less than this one and add a second format to keep\n * correct. Decision recorded in docs/rollout.md; do not re-litigate without a\n * concrete consumer that reads Letta and cannot read ATIF.\n */\n\nimport {\n assertRolloutLine,\n type ChatMessage,\n type ChatRole,\n type ChatToolCall,\n type GatedEvidence,\n ROLLOUT_CAPTURES,\n ROLLOUT_ROLES,\n ROLLOUT_SCHEMA,\n ROLLOUT_SPLITS,\n type RolloutArtifacts,\n type RolloutCapture,\n type RolloutCostBlock,\n type RolloutLine,\n type RolloutPolicy,\n type RolloutRole,\n type RolloutSplit,\n type RolloutStep,\n type RolloutTask,\n type ToolDef,\n} from '../schema'\n\nexport const ATIF_SCHEMA_VERSION = 'ATIF-v1.7'\n\n/** Gap note on every imported line — ATIF carries no verdict, so nothing is scored. */\nexport const HARBOR_IMPORT_GAP = 'imported from Harbor ATIF; no verdict'\n\n/** Namespaced escrow key for everything ATIF does not model but we must not lose. */\nconst ESCROW = 'tangle'\n\n/**\n * Marks a step we synthesized purely to hold tool results that answered no\n * assistant turn IN THIS DOCUMENT. ATIF has no `tool` source, so such results\n * need a carrier step; the marker lets import drop the carrier instead of\n * inventing a turn.\n *\n * A carrier's results carry NO `source_call_id`. RFC 0001 rule 2 requires every\n * `source_call_id` to match a `tool_call_id` in the same step's `tool_calls`,\n * and a carrier declares no calls (a `system` step cannot legally make one), so\n * emitting the id there would produce an invalid document. The id is escrowed\n * instead and restored verbatim on import — the link survives without the\n * document lying about who made the call.\n */\nconst TOOL_RESULTS_ONLY = 'tool-results-only'\n\n// ---------------------------------------------------------------------------\n// ATIF-v1.7 wire types (RFC 0001). Optional fields are optional here too.\n// ---------------------------------------------------------------------------\n\nexport type HarborStepSource = 'system' | 'user' | 'agent'\n\nexport interface HarborImageSource {\n media_type: string\n path: string\n}\n\nexport interface HarborContentPart {\n type: 'text' | 'image'\n text?: string\n source?: HarborImageSource\n}\n\nexport interface HarborToolCall {\n tool_call_id: string\n function_name: string\n /** ATIF requires a decoded JSON object here, unlike our raw argument string. */\n arguments: Record<string, unknown>\n extra?: Record<string, unknown>\n}\n\nexport interface HarborSubagentTrajectoryRef {\n trajectory_id?: string\n trajectory_path?: string\n /** Informational only since v1.7 — never a resolution key. */\n session_id?: string\n extra?: Record<string, unknown>\n}\n\nexport interface HarborObservationResult {\n source_call_id?: string\n content?: string | HarborContentPart[]\n subagent_trajectory_ref?: HarborSubagentTrajectoryRef[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborObservation {\n results: HarborObservationResult[]\n}\n\nexport interface HarborMetrics {\n prompt_tokens?: number\n completion_tokens?: number\n cached_tokens?: number\n cost_usd?: number\n prompt_token_ids?: number[]\n completion_token_ids?: number[]\n logprobs?: number[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborStep {\n /** Ordinal, sequential from 1. */\n step_id: number\n timestamp?: string\n source: HarborStepSource\n model_name?: string\n reasoning_effort?: string | number\n message: string | HarborContentPart[]\n reasoning_content?: string\n tool_calls?: HarborToolCall[]\n observation?: HarborObservation\n metrics?: HarborMetrics\n llm_call_count?: number\n is_copied_context?: boolean\n extra?: Record<string, unknown>\n}\n\nexport interface HarborAgent {\n name: string\n version: string\n model_name?: string\n /** OpenAI function-calling schema — byte-identical to our `ToolDef`. */\n tool_definitions?: ToolDef[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborFinalMetrics {\n total_prompt_tokens?: number\n total_completion_tokens?: number\n total_cached_tokens?: number\n total_cost_usd?: number\n total_steps?: number\n extra?: Record<string, unknown>\n}\n\nexport interface HarborTrajectory {\n schema_version: string\n session_id?: string\n /** Required on embedded subagents; we always set it so lines stay joinable. */\n trajectory_id?: string\n agent: HarborAgent\n steps: HarborStep[]\n notes?: string\n final_metrics?: HarborFinalMetrics\n continued_trajectory_ref?: string\n subagent_trajectories?: HarborTrajectory[]\n extra?: Record<string, unknown>\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v)\n\nconst asString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined)\n\nconst asNumberOrNull = (v: unknown): number | null =>\n typeof v === 'number' && Number.isFinite(v) ? v : null\n\nconst asIntegerOrUndefined = (v: unknown): number | undefined =>\n Number.isInteger(v) ? (v as number) : undefined\n\nconst asNumberArray = (v: unknown): number[] | undefined =>\n Array.isArray(v) && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n ? (v as number[])\n : undefined\n\nconst asIntegerArray = (v: unknown): number[] | undefined =>\n Array.isArray(v) && v.every((n) => Number.isInteger(n)) ? (v as number[]) : undefined\n\n/**\n * Builds a `ChatMessage` with keys in the schema's declaration order.\n *\n * Object key order is insertion order in JS, so a message assembled\n * conditionally field-by-field serializes differently depending on which\n * optional fields were present — which makes a byte-hashed ledger see a diff\n * across an import that changed nothing. One builder, one order, stable bytes.\n */\nfunction canonicalChatMessage(parts: {\n role: ChatRole\n content: string | null\n reasoning_content?: string\n tool_calls?: ChatToolCall[]\n tool_call_id?: string\n name?: string\n is_copied_context?: boolean\n}): ChatMessage {\n const message: ChatMessage = { role: parts.role, content: parts.content }\n if (parts.reasoning_content !== undefined) message.reasoning_content = parts.reasoning_content\n if (parts.tool_calls !== undefined) message.tool_calls = parts.tool_calls\n if (parts.tool_call_id !== undefined) message.tool_call_id = parts.tool_call_id\n if (parts.name !== undefined) message.name = parts.name\n if (parts.is_copied_context === true) message.is_copied_context = true\n return message\n}\n\n/** Reads the `extra.tangle` escrow, tolerating a foreign file that has none. */\nfunction escrowOf(extra: Record<string, unknown> | undefined): Record<string, unknown> | undefined {\n if (!isRecord(extra)) return undefined\n const value = extra[ESCROW]\n return isRecord(value) ? value : undefined\n}\n\nfunction escrowSection(\n escrow: Record<string, unknown> | undefined,\n key: string,\n): Record<string, unknown> | undefined {\n if (escrow === undefined) return undefined\n const value = escrow[key]\n return isRecord(value) ? value : undefined\n}\n\n// ---------------------------------------------------------------------------\n// Export: RolloutLine[] → ATIF trajectory tree\n// ---------------------------------------------------------------------------\n\nfunction toHarborToolCall(call: ChatToolCall): HarborToolCall {\n // ATIF requires `arguments` to be a JSON object; ours is the raw\n // JSON-encoded string the model emitted, and models really do emit\n // malformed ones. Keep the exact bytes in `extra` so import restores the\n // string verbatim instead of re-serializing a normalized parse.\n let parsed: Record<string, unknown> | undefined\n try {\n const decoded: unknown = JSON.parse(call.function.arguments)\n if (isRecord(decoded)) parsed = decoded\n } catch {\n parsed = undefined\n }\n return {\n tool_call_id: call.id,\n function_name: call.function.name,\n arguments: parsed ?? {},\n extra: { [ESCROW]: { arguments_raw: call.function.arguments } },\n }\n}\n\n/**\n * `linked` = this result is attached to the step that actually declared the\n * call, so `source_call_id` is legal (RFC 0001 rule 2). When it is not, the id\n * goes to escrow instead of onto the wire.\n */\nfunction toObservationResult(message: ChatMessage, linked: boolean): HarborObservationResult {\n const result: HarborObservationResult = {}\n if (linked && message.tool_call_id !== undefined) result.source_call_id = message.tool_call_id\n if (message.content !== null) result.content = message.content\n const escrow: Record<string, unknown> = {}\n if (!linked && message.tool_call_id !== undefined) escrow.source_call_id = message.tool_call_id\n if (message.name !== undefined) escrow.name = message.name\n // `content: null` on a tool turn is meaningful (a tool that returned\n // nothing) and is not the same as the empty string ATIF would round-trip it to.\n if (message.content === null) escrow.content_null = true\n if (message.reasoning_content !== undefined) escrow.reasoning_content = message.reasoning_content\n if (message.is_copied_context === true) escrow.is_copied_context = true\n if (Object.keys(escrow).length > 0) result.extra = { [ESCROW]: escrow }\n return result\n}\n\n/** True when `step` is the agent turn that declared `callId` — the rule-2 test. */\nfunction declaresCall(step: HarborStep, callId: string | undefined): boolean {\n if (callId === undefined) return false\n return step.tool_calls?.some((call) => call.tool_call_id === callId) === true\n}\n\n/**\n * Attaches the four RL fields lifted from ATIF onto the agent step the span\n * describes. They are ALSO escrowed with the whole span under `extra.tangle`,\n * on purpose: the escrow is how our own round-trip stays exact, and these\n * native fields are how a foreign consumer — which never reads our escrow —\n * gets the logprobs and token ids at all. A field carried only in the escrow is\n * not an interchange field.\n */\nfunction applySpanMetrics(step: HarborStep, span: RolloutStep | undefined): void {\n if (span === undefined) return\n if (span.llm_call_count !== undefined) step.llm_call_count = span.llm_call_count\n const metrics: HarborMetrics = {}\n if (span.prompt_token_ids !== undefined) metrics.prompt_token_ids = span.prompt_token_ids\n if (span.completion_token_ids !== undefined) {\n metrics.completion_token_ids = span.completion_token_ids\n }\n if (span.logprobs !== undefined) metrics.logprobs = span.logprobs\n if (Object.keys(metrics).length > 0) step.metrics = metrics\n}\n\n/**\n * Coalescing fold, not a 1:1 map: ATIF has no `tool` source, so a tool result\n * becomes an `observation.results[]` entry on the agent step THAT DECLARED ITS\n * `tool_call_id`.\n *\n * Linking by id, not by adjacency. Adjacency emitted invalid documents in three\n * shapes the RFC forbids — an assistant turn with no `tool_calls` swallowing the\n * results that followed it, a result whose id matched none of the preceding\n * step's calls, and an unanswered result riding a `system` step that carried a\n * `source_call_id` it could never declare. Attaching only to the step that owns\n * the id also preserves message order exactly: a result either joins the step\n * immediately before it or becomes its own carrier at its own position.\n *\n * `line.steps` span projections are matched to agent steps in order (k-th llm\n * span → k-th agent step) purely to fill ATIF's native per-step `metrics`;\n * extra spans on either side are simply not matched, never invented.\n */\nfunction messagesToSteps(line: RolloutLine): HarborStep[] {\n const steps: HarborStep[] = []\n const llmSpans = (line.steps ?? []).filter((span) => span.kind === 'llm')\n let nextSpan = 0\n for (const message of line.messages) {\n if (message.role === 'tool') {\n const previous = steps[steps.length - 1]\n if (previous !== undefined && declaresCall(previous, message.tool_call_id)) {\n if (previous.observation === undefined) previous.observation = { results: [] }\n previous.observation.results.push(toObservationResult(message, true))\n continue\n }\n // A tool result answering no assistant turn in this document (truncated or\n // reconstructed transcript). It still has to survive, so it rides a marked\n // carrier step whose observation states no call id.\n const carrier: HarborStep = {\n step_id: steps.length + 1,\n source: 'system',\n message: '',\n observation: { results: [toObservationResult(message, false)] },\n extra: { [ESCROW]: { synthetic: TOOL_RESULTS_ONLY } },\n }\n if (message.is_copied_context === true) carrier.is_copied_context = true\n steps.push(carrier)\n continue\n }\n const step: HarborStep = {\n step_id: steps.length + 1,\n source: message.role === 'assistant' ? 'agent' : message.role,\n message: message.content ?? '',\n }\n const escrow: Record<string, unknown> = {}\n if (message.content === null) escrow.content_null = true\n if (message.name !== undefined) escrow.name = message.name\n if (message.role === 'assistant') {\n if (line.policy.model !== null) step.model_name = line.policy.model\n if (message.reasoning_content !== undefined) {\n step.reasoning_content = message.reasoning_content\n }\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n step.tool_calls = message.tool_calls.map(toHarborToolCall)\n }\n applySpanMetrics(step, llmSpans[nextSpan])\n nextSpan += 1\n } else if (message.reasoning_content !== undefined) {\n // ATIF confines `reasoning_content` to agent steps; ours is not confined.\n escrow.reasoning_content = message.reasoning_content\n }\n // RFC 0001 rule 7: a copied-context turn was not authored by this agent, and\n // an SFT pipeline MUST exclude it. Native ATIF field, both directions.\n if (message.is_copied_context === true) step.is_copied_context = true\n if (Object.keys(escrow).length > 0) step.extra = { [ESCROW]: escrow }\n steps.push(step)\n }\n return steps\n}\n\nfunction finalMetricsOf(line: RolloutLine, stepCount: number): HarborFinalMetrics {\n const metrics: HarborFinalMetrics = {}\n if (line.cost.tokens_in !== null) metrics.total_prompt_tokens = line.cost.tokens_in\n if (line.cost.tokens_out !== null) metrics.total_completion_tokens = line.cost.tokens_out\n if (line.cost.cache_read !== null) metrics.total_cached_tokens = line.cost.cache_read\n // Omitted, never 0, when cost was not captured — a fake 0 is a lie about spend.\n if (line.cost.usd !== null) metrics.total_cost_usd = line.cost.usd\n metrics.total_steps = stepCount\n // ATIF has no aggregate field for these three; `reasoning_tokens` under\n // `extra` is the key the RFC's own worked example uses.\n const extra: Record<string, unknown> = {}\n if (line.cost.tokens_reasoning !== null) extra.reasoning_tokens = line.cost.tokens_reasoning\n if (line.cost.cache_write !== null) extra.cache_write_tokens = line.cost.cache_write\n if (line.cost.wall_s !== null) extra.wall_s = line.cost.wall_s\n if (line.cost.llm_call_count !== undefined && line.cost.llm_call_count !== null) {\n extra.llm_call_count = line.cost.llm_call_count\n }\n if (Object.keys(extra).length > 0) metrics.extra = extra\n return metrics\n}\n\nfunction notesOf(line: RolloutLine): string | undefined {\n const parts: string[] = []\n if (line.provenance.gap !== undefined) parts.push(line.provenance.gap)\n if (line.outcome.realness_gated === true) {\n // ATIF has no gate field. A third-party consumer that ignores `extra`\n // would otherwise see a gamed trajectory with nothing marking it, so the\n // flag is stated in prose as well. This export carries no reward at all,\n // so it is not a training-data door — but it is an audit record.\n parts.push('realness-gated: this run faked its success signal (anti-Goodhart gate fired)')\n }\n return parts.length > 0 ? parts.join(' | ') : undefined\n}\n\nfunction toTrajectoryNode(line: RolloutLine): HarborTrajectory {\n const steps = messagesToSteps(line)\n const trajectory: HarborTrajectory = {\n schema_version: ATIF_SCHEMA_VERSION,\n // RUN-scoped, per the spec — so it is `run_id`, the coordinate every\n // invocation of one run shares. `rollout_id` identifies a single\n // invocation: using it gave two roots of the same run different session\n // ids, and foreign tooling that groups by session_id would split the run.\n session_id: line.run_id,\n trajectory_id: line.rollout_id,\n agent: {\n // ATIF requires both; ours are nullable, so a null is substituted here\n // and restored on import from the escrowed policy — never guessed back.\n name: line.policy.harness ?? 'unknown',\n version: line.policy.harness_version ?? '0.0.0',\n ...(line.policy.model !== null ? { model_name: line.policy.model } : {}),\n ...(line.tool_defs.length > 0 ? { tool_definitions: line.tool_defs } : {}),\n },\n steps,\n final_metrics: finalMetricsOf(line, steps.length),\n extra: {\n [ESCROW]: {\n schema: line.schema,\n rollout_id: line.rollout_id,\n parent_rollout_id: line.parent_rollout_id,\n run_id: line.run_id,\n ...(line.experiment_id !== undefined ? { experiment_id: line.experiment_id } : {}),\n ...(line.candidate_id !== undefined ? { candidate_id: line.candidate_id } : {}),\n generation: line.generation,\n candidate_index: line.candidate_index,\n role: line.role,\n task: line.task,\n policy: line.policy,\n // Span projections overlap the same turns as `steps[]`; folding them\n // into ATIF steps would double-count the run, so they stay escrowed.\n ...(line.steps !== undefined ? { spans: line.steps } : {}),\n outcome: {\n // reward / reward_source / verdict are deliberately absent — see the\n // module header. Only the non-scalar outcome fields travel.\n metrics: line.outcome.metrics,\n is_completed: line.outcome.is_completed,\n is_truncated: line.outcome.is_truncated,\n error: line.outcome.error,\n ...(line.outcome.realness_gated !== undefined\n ? { realness_gated: line.outcome.realness_gated }\n : {}),\n },\n artifacts: line.artifacts,\n provenance: line.provenance,\n },\n },\n }\n const notes = notesOf(line)\n if (notes !== undefined) trajectory.notes = notes\n return trajectory\n}\n\ninterface Forest {\n roots: RolloutLine[]\n childrenOf: Map<string, RolloutLine[]>\n}\n\nfunction buildForest(lines: RolloutLine[]): Forest {\n const byId = new Map<string, RolloutLine>()\n for (const line of lines) {\n if (byId.has(line.rollout_id)) {\n throw new Error(`duplicate rollout_id in input: ${line.rollout_id}`)\n }\n byId.set(line.rollout_id, line)\n }\n const roots: RolloutLine[] = []\n const childrenOf = new Map<string, RolloutLine[]>()\n for (const line of lines) {\n const parent = line.parent_rollout_id\n // A parent outside this set is a root OF WHAT WE HAVE: the edge is kept in\n // escrow so a later import restores the dangling pointer instead of nulling it.\n if (parent === null || !byId.has(parent)) {\n roots.push(line)\n continue\n }\n const siblings = childrenOf.get(parent)\n if (siblings === undefined) childrenOf.set(parent, [line])\n else siblings.push(line)\n }\n // Every line has a parent inside the set: the edges form a cycle with no\n // root. Returning zero documents would drop the whole episode silently.\n if (lines.length > 0 && roots.length === 0) {\n throw new Error(\n `parent_rollout_id cycle: no root among ${lines.length} lines (${lines.map((l) => l.rollout_id).join(', ')})`,\n )\n }\n return { roots, childrenOf }\n}\n\nfunction assemble(line: RolloutLine, forest: Forest, onPath: Set<string>): HarborTrajectory {\n if (onPath.has(line.rollout_id)) {\n throw new Error(`parent_rollout_id cycle through rollout_id ${line.rollout_id}`)\n }\n onPath.add(line.rollout_id)\n const node = toTrajectoryNode(line)\n const children = forest.childrenOf.get(line.rollout_id)\n if (children !== undefined && children.length > 0) {\n node.subagent_trajectories = children.map((child) => assemble(child, forest, onPath))\n }\n onPath.delete(line.rollout_id)\n return node\n}\n\n/**\n * Assemble one episode's flat lines into a single ATIF trajectory tree,\n * linked by `parent_rollout_id`.\n *\n * Reward, verdict and split are NOT emitted (ATIF models none of them); the\n * split and the rest of the task coordinates survive only in `extra.tangle`.\n *\n * We deliberately do NOT synthesize an `observation.subagent_trajectory_ref`\n * pointing at each child: our ledger records WHICH invocation spawned a\n * worker, not which STEP did, and attaching the ref to a guessed step would\n * fabricate a causal claim. Children are embedded in `subagent_trajectories`\n * (each with the `trajectory_id` the spec requires) and the edge is stated in\n * the child's escrowed `parent_rollout_id`.\n *\n * Throws when the lines are not one tree — use `toHarborTrajectories` for a forest.\n */\nexport function toHarborTrajectory(lines: RolloutLine[]): HarborTrajectory {\n const trees = toHarborTrajectories(lines)\n if (trees.length === 0) throw new Error('toHarborTrajectory: no lines')\n if (trees.length > 1) {\n const ids = trees.map((t) => t.trajectory_id ?? '?').join(', ')\n throw new Error(\n `toHarborTrajectory: ${trees.length} roots (${ids}) — ATIF is one tree per document; use toHarborTrajectories`,\n )\n }\n return trees[0]!\n}\n\n/** Every independent tree in the input, one ATIF document each. */\nexport function toHarborTrajectories(lines: RolloutLine[]): HarborTrajectory[] {\n const forest = buildForest(lines)\n return forest.roots.map((root) => assemble(root, forest, new Set()))\n}\n\n// ---------------------------------------------------------------------------\n// Import: ATIF trajectory tree → RolloutLine[]\n// ---------------------------------------------------------------------------\n\nfunction contentToString(message: string | HarborContentPart[]): string {\n if (typeof message === 'string') return message\n return message\n .map((part) =>\n part.type === 'image'\n ? // Our chat content is text-only. Describing the image is honest about\n // what the source held; dropping it silently would not be.\n `[image ${part.source?.media_type ?? 'unknown'} ${part.source?.path ?? ''}]`.trim()\n : (part.text ?? ''),\n )\n .join('\\n')\n}\n\nfunction fromHarborToolCall(call: HarborToolCall): ChatToolCall {\n const raw = asString(escrowOf(call.extra)?.arguments_raw)\n return {\n id: call.tool_call_id,\n type: 'function',\n function: { name: call.function_name, arguments: raw ?? JSON.stringify(call.arguments ?? {}) },\n }\n}\n\nfunction fromObservationResult(\n result: HarborObservationResult,\n callId: string | undefined,\n): ChatMessage {\n const escrow = escrowOf(result.extra)\n return canonicalChatMessage({\n role: 'tool',\n content:\n escrow?.content_null === true\n ? null\n : result.content === undefined\n ? ''\n : contentToString(result.content),\n reasoning_content: asString(escrow?.reasoning_content),\n tool_call_id: callId,\n name: asString(escrow?.name),\n is_copied_context: escrow?.is_copied_context === true,\n })\n}\n\nfunction stepsToMessages(steps: HarborStep[]): ChatMessage[] {\n const messages: ChatMessage[] = []\n for (const step of steps) {\n const escrow = escrowOf(step.extra)\n const carrierOnly = escrow?.synthetic === TOOL_RESULTS_ONLY\n if (!carrierOnly) {\n messages.push(\n canonicalChatMessage({\n role: step.source === 'agent' ? 'assistant' : step.source,\n content: escrow?.content_null === true ? null : contentToString(step.message),\n reasoning_content: step.reasoning_content ?? asString(escrow?.reasoning_content),\n tool_calls:\n step.tool_calls !== undefined && step.tool_calls.length > 0\n ? step.tool_calls.map(fromHarborToolCall)\n : undefined,\n name: asString(escrow?.name),\n is_copied_context: step.is_copied_context === true,\n }),\n )\n }\n for (const result of step.observation?.results ?? []) {\n const resultEscrow = escrowOf(result.extra)\n const callId = result.source_call_id ?? asString(resultEscrow?.source_call_id)\n if (carrierOnly) {\n // Our own carrier: every result on it was a tool turn, and its call id\n // (if the transcript had one) is in escrow, not on the wire.\n messages.push(fromObservationResult(result, callId))\n continue\n }\n if (typeof callId === 'string') {\n messages.push(fromObservationResult(result, callId))\n continue\n }\n // ATIF allows a result from a non-tool-calling action. Our chat schema\n // requires `tool_call_id` on a tool turn, so inventing one would forge a\n // link; the text is preserved as a system observation instead.\n if (result.content !== undefined) {\n messages.push(\n canonicalChatMessage({ role: 'system', content: contentToString(result.content) }),\n )\n }\n }\n }\n return messages\n}\n\nfunction taskFrom(escrow: Record<string, unknown> | undefined, fallbackId: string): RolloutTask {\n const task = escrowSection(escrow, 'task')\n return {\n suite: asString(task?.suite) ?? 'harbor-atif-import',\n instance_id: asString(task?.instance_id) ?? fallbackId,\n // ALWAYS holdout — the escrowed claim is read for nothing here.\n //\n // `extra.tangle.task.split` is a namespaced key, not an authenticated one:\n // a hand-written or third-party document can set `split: 'search'` as\n // easily as our own exporter can, and honouring it made \"this file says so\"\n // sufficient to walk into a training export. Trainability is a decision\n // about a file, so it is made by an operator through\n // `relabelImportedSplit`, never by the file about itself. The claim is not\n // destroyed — it stays readable in the source document.\n split: 'holdout',\n seed: asNumberOrNull(task?.seed),\n rep: asIntegerOrUndefined(task?.rep) ?? 0,\n }\n}\n\nfunction policyFrom(\n escrow: Record<string, unknown> | undefined,\n agent: HarborAgent,\n): RolloutPolicy {\n const escrowed = escrowSection(escrow, 'policy')\n if (escrowed !== undefined) {\n // Our own export: restore verbatim, including the nulls ATIF forced us to\n // substitute placeholders for in `agent.name` / `agent.version`.\n return {\n harness: asString(escrowed.harness) ?? null,\n harness_version: asString(escrowed.harness_version) ?? null,\n model: asString(escrowed.model) ?? null,\n provider: asString(escrowed.provider) ?? null,\n profile_commit: asString(escrowed.profile_commit) ?? null,\n ...(escrowed.prompt_hash !== undefined\n ? { prompt_hash: asString(escrowed.prompt_hash) ?? null }\n : {}),\n ...(escrowed.config_hash !== undefined\n ? { config_hash: asString(escrowed.config_hash) ?? null }\n : {}),\n ...(escrowed.agent_profile_cell_id !== undefined\n ? { agent_profile_cell_id: asString(escrowed.agent_profile_cell_id) ?? null }\n : {}),\n sampling: isRecord(escrowed.sampling) ? escrowed.sampling : null,\n }\n }\n return {\n harness: agent.name,\n harness_version: agent.version,\n model: agent.model_name ?? null,\n provider: null,\n profile_commit: null,\n sampling: null,\n }\n}\n\nfunction artifactsFrom(escrow: Record<string, unknown> | undefined): RolloutArtifacts {\n const artifacts = escrowSection(escrow, 'artifacts')\n return {\n patch_path: asString(artifacts?.patch_path) ?? null,\n run_dir: asString(artifacts?.run_dir) ?? null,\n transcript_ref: asString(artifacts?.transcript_ref) ?? null,\n }\n}\n\nfunction costFrom(final: HarborFinalMetrics | undefined): RolloutCostBlock {\n const rawExtra = final?.extra\n const extra = isRecord(rawExtra) ? rawExtra : undefined\n const calls = asIntegerOrUndefined(extra?.llm_call_count)\n return {\n usd: asNumberOrNull(final?.total_cost_usd),\n tokens_in: asNumberOrNull(final?.total_prompt_tokens),\n tokens_out: asNumberOrNull(final?.total_completion_tokens),\n tokens_reasoning: asNumberOrNull(extra?.reasoning_tokens),\n cache_read: asNumberOrNull(final?.total_cached_tokens),\n cache_write: asNumberOrNull(extra?.cache_write_tokens),\n wall_s: asNumberOrNull(extra?.wall_s),\n ...(calls !== undefined ? { llm_call_count: calls } : {}),\n }\n}\n\n/**\n * Recovers span projections from ATIF's NATIVE per-step channel, for documents\n * with no `extra.tangle.spans` escrow — i.e. everything a foreign producer\n * writes. Without this the logprobs and token ids a Harbor-native trainer\n * records would be read, validated, and then dropped on the floor.\n *\n * Only steps that actually carry one of the four fields produce a span: an\n * agent step with no metrics means \"not captured\", and inventing an empty span\n * for it would claim the run had a shape we did not observe.\n */\nfunction spansFromSteps(steps: HarborStep[]): RolloutStep[] {\n const spans: RolloutStep[] = []\n for (const step of steps) {\n if (step.source !== 'agent') continue\n const calls = asIntegerOrUndefined(step.llm_call_count)\n const promptIds = asIntegerArray(step.metrics?.prompt_token_ids)\n const completionIds = asIntegerArray(step.metrics?.completion_token_ids)\n const logprobs = asNumberArray(step.metrics?.logprobs)\n if (\n calls === undefined &&\n promptIds === undefined &&\n completionIds === undefined &&\n logprobs === undefined\n ) {\n continue\n }\n spans.push({\n kind: 'llm',\n name: step.model_name ?? 'chat',\n ...(calls !== undefined ? { llm_call_count: calls } : {}),\n ...(promptIds !== undefined ? { prompt_token_ids: promptIds } : {}),\n ...(completionIds !== undefined ? { completion_token_ids: completionIds } : {}),\n ...(logprobs !== undefined ? { logprobs } : {}),\n })\n }\n return spans\n}\n\n/**\n * Composes `provenance.gap` as an ordered SET of reasons.\n *\n * Appending made the note accrete on every pass (\"…no verdict | …no verdict\"),\n * which both grows without bound and breaks byte-level idempotency for a ledger\n * hashed on its serialized lines.\n */\nfunction composeGap(escrowedGap: string | undefined, added: readonly string[]): string {\n const parts: string[] = []\n const seen = new Set<string>()\n for (const raw of [...(escrowedGap?.split(' | ') ?? []), ...added]) {\n const reason = raw.trim()\n if (reason.length === 0 || seen.has(reason)) continue\n seen.add(reason)\n parts.push(reason)\n }\n return parts.join(' | ')\n}\n\nexport interface FromHarborOptions {\n /** Injected clock for deterministic output when the source carries no capture time. */\n now?: () => Date\n}\n\nfunction nodeToLine(\n trajectory: HarborTrajectory,\n parentId: string | null,\n capturedAt: string,\n): RolloutLine {\n const escrow = escrowOf(trajectory.extra)\n const rolloutId =\n asString(escrow?.rollout_id) ?? trajectory.trajectory_id ?? trajectory.session_id\n if (rolloutId === undefined || rolloutId.length === 0) {\n throw new Error(\n 'fromHarborTrajectory: trajectory has no trajectory_id or session_id — cannot mint a joinable rollout_id without inventing one',\n )\n }\n const outcome = escrowSection(escrow, 'outcome')\n const provenance = escrowSection(escrow, 'provenance')\n const capture = provenance?.capture\n const escrowedGap = asString(provenance?.gap)\n const role = escrow?.role\n const escrowedSpans = escrow?.spans\n // The escrow wins when it exists (our own export: exact, including an empty\n // array, which claims \"captured, none\" rather than \"not captured\"), and the\n // native per-step channel is the fallback (a foreign export: still signal).\n const nativeSpans = spansFromSteps(trajectory.steps)\n const spans: RolloutStep[] | undefined = Array.isArray(escrowedSpans)\n ? (escrowedSpans as RolloutStep[])\n : nativeSpans.length > 0\n ? nativeSpans\n : undefined\n const messages = stepsToMessages(trajectory.steps)\n const line: RolloutLine = {\n schema: ROLLOUT_SCHEMA,\n rollout_id: rolloutId,\n // The tree edge wins for embedded children; for a root, the escrowed\n // pointer may reference a line outside this document and is preserved.\n parent_rollout_id: parentId ?? asString(escrow?.parent_rollout_id) ?? null,\n run_id: asString(escrow?.run_id) ?? trajectory.session_id ?? rolloutId,\n // Required keys on the wire (0.127.0): a foreign document that never\n // stated them imports as explicit `null`, not as an absent field.\n experiment_id: asString(escrow?.experiment_id) ?? null,\n candidate_id: asString(escrow?.candidate_id) ?? null,\n generation: asIntegerOrUndefined(escrow?.generation) ?? null,\n candidate_index: asIntegerOrUndefined(escrow?.candidate_index) ?? null,\n role: ROLLOUT_ROLES.includes(role as RolloutRole) ? (role as RolloutRole) : 'agent',\n task: taskFrom(escrow, rolloutId),\n policy: policyFrom(escrow, trajectory.agent),\n messages,\n tool_defs: trajectory.agent.tool_definitions ?? [],\n ...(spans !== undefined ? { steps: spans } : {}),\n outcome: {\n // ATIF carries no label. Null is the labeled gap; a 0 here would be a\n // fabricated failure and a 1 a fabricated success.\n reward: null,\n reward_source: null,\n verdict: null,\n metrics: isRecord(outcome?.metrics) ? outcome.metrics : {},\n is_completed: typeof outcome?.is_completed === 'boolean' ? outcome.is_completed : true,\n is_truncated:\n typeof outcome?.is_truncated === 'boolean'\n ? outcome.is_truncated\n : trajectory.continued_trajectory_ref !== undefined,\n error: asString(outcome?.error) ?? null,\n // The anti-Goodhart flag is restored when the source document stated\n // it; the wire schema requires the field, so a document that never did\n // imports as `false`. That is safe here because the reward is already\n // forced to `null` (not trainable) and `realness_screened` stays\n // absent = unknown rather than claiming a screen ran.\n realness_gated: outcome?.realness_gated === true,\n },\n cost: costFrom(trajectory.final_metrics),\n artifacts: artifactsFrom(escrow),\n provenance: {\n captured_at: asString(provenance?.captured_at) ?? capturedAt,\n capture: ROLLOUT_CAPTURES.includes(capture as RolloutCapture)\n ? (capture as RolloutCapture)\n : 'backfill',\n gap: composeGap(escrowedGap, [HARBOR_IMPORT_GAP]),\n // Restored for the same reason `realness_gated` is, and with the opposite\n // risk profile from the reward: this is the gated run's own measurement\n // bag, moved off `outcome` by `gateGamedOutcome` so no exporter reads it\n // as training input. Dropping it here would silently destroy the audit\n // trail that says WHY the run was flagged and what it claimed, on the one\n // population an auditor most wants to inspect. It cannot be fail-open —\n // nothing projects `provenance` into a training row.\n ...(isRecord(provenance?.gated_evidence)\n ? { gated_evidence: provenance.gated_evidence as GatedEvidence }\n : {}),\n },\n }\n assertRolloutLine(line, `rollout line imported from ATIF trajectory ${rolloutId}`)\n return line\n}\n\n/**\n * Flatten an ATIF trajectory tree back into `tangle.rollout.v1` lines, parent\n * first, each child carrying `parent_rollout_id`.\n *\n * Every line comes back UNLABELED: `reward`, `reward_source` and `verdict` are\n * null and `provenance.gap` says why. ATIF models no verdict, so scoring an\n * imported trajectory is a judge's job, not this function's. Every line lands\n * on `holdout` whatever the document claims — see `relabelImportedSplit`.\n */\nexport function fromHarborTrajectory(\n trajectory: HarborTrajectory,\n options: FromHarborOptions = {},\n): RolloutLine[] {\n const capturedAt = (options.now?.() ?? new Date()).toISOString()\n const lines: RolloutLine[] = []\n const walk = (node: HarborTrajectory, parentId: string | null, onPath: Set<string>): void => {\n const line = nodeToLine(node, parentId, capturedAt)\n if (onPath.has(line.rollout_id)) {\n throw new Error(`subagent_trajectories cycle through trajectory_id ${line.rollout_id}`)\n }\n onPath.add(line.rollout_id)\n lines.push(line)\n for (const child of node.subagent_trajectories ?? []) {\n walk(child, line.rollout_id, onPath)\n }\n onPath.delete(line.rollout_id)\n }\n walk(trajectory, null, new Set())\n return lines\n}\n\n/**\n * THE explicit door out of `holdout` for imported lines.\n *\n * Import forces `holdout` because a document's own claim about its split is not\n * evidence — anyone can write `extra.tangle.task.split`. Promoting a file to a\n * trainable split is an operator's decision about provenance they verified, so\n * it is a separate, greppable call: `grep relabelImportedSplit` enumerates\n * every place foreign data was declared trainable, which is exactly the audit\n * the trusted-escrow version made impossible.\n *\n * Returns plain `RolloutLine`s. They still have to pass `assertMinted` (and its\n * anti-Goodhart check) to reach an exporter — re-labeling a split is not\n * minting a reward.\n */\nexport function relabelImportedSplit(\n lines: readonly RolloutLine[],\n split: RolloutSplit,\n): RolloutLine[] {\n if (!ROLLOUT_SPLITS.includes(split)) {\n throw new Error(`relabelImportedSplit: unknown split ${String(split)}`)\n }\n return lines.map((line) => ({ ...line, task: { ...line.task, split } }))\n}\n"],"mappings":"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"}
|
package/dist/{skillopt-optimization-method-BoIzh7Dl.js → skillopt-optimization-method-CF6a327Q.js}
RENAMED
|
@@ -6716,6 +6716,7 @@ async function runImprovementLoop(opts) {
|
|
|
6716
6716
|
const holdoutDeferred = (opts.holdout ?? "measured") === "deferred";
|
|
6717
6717
|
const baselineOnHoldout = holdoutDeferred ? await runCampaign({
|
|
6718
6718
|
...opts,
|
|
6719
|
+
labeledStore: "off",
|
|
6719
6720
|
costLedger,
|
|
6720
6721
|
costPhase: "holdout.deferred",
|
|
6721
6722
|
dispatchTimeoutMs,
|
|
@@ -6726,6 +6727,7 @@ async function runImprovementLoop(opts) {
|
|
|
6726
6727
|
runDir: `${opts.runDir}/holdout-deferred`
|
|
6727
6728
|
}) : await runCampaign({
|
|
6728
6729
|
...opts,
|
|
6730
|
+
labeledStore: "off",
|
|
6729
6731
|
costLedger,
|
|
6730
6732
|
costPhase: "holdout.baseline",
|
|
6731
6733
|
dispatchTimeoutMs,
|
|
@@ -6735,6 +6737,7 @@ async function runImprovementLoop(opts) {
|
|
|
6735
6737
|
});
|
|
6736
6738
|
const winnerOnHoldout = winnerIsBaseline || holdoutDeferred ? baselineOnHoldout : await runCampaign({
|
|
6737
6739
|
...opts,
|
|
6740
|
+
labeledStore: "off",
|
|
6738
6741
|
costLedger,
|
|
6739
6742
|
costPhase: "holdout.winner",
|
|
6740
6743
|
dispatchTimeoutMs,
|
|
@@ -6773,6 +6776,7 @@ async function runImprovementLoop(opts) {
|
|
|
6773
6776
|
neutralizedSurface = surface;
|
|
6774
6777
|
neutralizedOnHoldout = await runCampaign({
|
|
6775
6778
|
...opts,
|
|
6779
|
+
labeledStore: "off",
|
|
6776
6780
|
costLedger,
|
|
6777
6781
|
costPhase: "holdout.neutralized",
|
|
6778
6782
|
dispatchTimeoutMs,
|
|
@@ -7715,4 +7719,4 @@ function skillOptOptimizationMethod(config) {
|
|
|
7715
7719
|
//#endregion
|
|
7716
7720
|
export { SEARCH_LEDGER_FILE_CONTEXT as $, acquireSingleRunLock as A, dominates as At, surfaceContentHash as B, JudgeParseError as Bt, detectScale as C, llmJudge as Ct, runCanaries as D, fileVerdictCache as Dt, pairHoldout as E, contentHash as Et, assertCodeSurfaceIdentity as F, BackendIntegrityError as Ft, DEFAULT_MUTATION_PRIMITIVES as G, campaignBreakdown as H, assertComponentSurface as I, assertRealAgentReceipts as It, planCampaignRun as J, buildReflectionPrompt as K, codeSurfaceIdentityMaterial as L, assertRealBackend as Lt, compareOptimizationMethods as M, paretoFrontierWithCrowding as Mt, costFromLedgerSummary as N, scalarScore as Nt, composeGate as O, inMemoryVerdictCache as Ot, optimizationTokenUsageFromSummary as P, recoverTruncatedJson as Pt, inMemoryCampaignStorage as Q, componentSurfaceIdentityMaterial as R, summarizeAgentReceiptIntegrity as Rt, defaultProductionGate as S, hashScenarios as St, heldoutSignificance as T, canonicalJson as Tt, campaignMeanComposite as U, surfaceHash as V, compareRankKeys as W, createRunCostLedger as X, runCampaign as Y, fsCampaignStorage as Z, buildEvidenceVector as _, redTeamReport as _t, emitLoopProvenance as a, assertCampaignDesign as at, powerPreflight as b, Dataset as bt, provenanceRecordPath as c, campaignSplitDigest as ct, runImprovementLoop as d, REFERENCE_EQUIVALENCE_INPUT_LIMITS as dt, SearchLedgerConflictError as et, runOptimization as f, REFERENCE_EQUIVALENCE_JUDGE_VERSION as ft, gepaOptimizationMethod as g, redTeamDataset as gt, labelTrustRank as h, DEFAULT_RED_TEAM_CORPUS as ht, canonicalDigest as i, tangleTracesRoot as it, assertOptimizationResult as j, paretoFrontier as jt, externalTextOptimizationMethod as k, crowdingDistance as kt, provenanceSpansPath as l, campaignSplitDigestFromIdentities as lt, isProposedCandidate as m, runReferenceEquivalenceJudge as mt, buildLoopProvenanceRecord as n, SearchLedgerIntegrityError as nt, loopProvenanceArgsFromResult as o, assertCampaignSplitIdentity as ot, runEval as p, createReferenceEquivalenceJudge as pt, parseReflectionResponse as q, campaignMeasurementDigest as r, resolveRunDir as rt, loopProvenanceSpans as s, campaignScenarioIdentity as st, skillOptOptimizationMethod as t, SearchLedgerError as tt, verifyLoopProvenanceRecord as u, openAutoPr as ut, paretoPolicy as v, scoreRedTeamOutput as vt, dimensionRegressions as w, cachedJudge as wt, heldOutGate as x, HoldoutLockedError as xt, paretoSignificanceGate as y, toolNamesForRun as yt, renderSurfaceDiff as z, summarizeBackendIntegrity as zt };
|
|
7717
7721
|
|
|
7718
|
-
//# sourceMappingURL=skillopt-optimization-method-
|
|
7722
|
+
//# sourceMappingURL=skillopt-optimization-method-CF6a327Q.js.map
|