@caupulican/pi-adaptative 0.80.88 → 0.80.89
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 +29 -0
- package/dist/core/agent-session.d.ts +35 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +262 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/context/brain-curator.d.ts +88 -0
- package/dist/core/context/brain-curator.d.ts.map +1 -0
- package/dist/core/context/brain-curator.js +192 -0
- package/dist/core/context/brain-curator.js.map +1 -0
- package/dist/core/context/context-composition.d.ts +122 -0
- package/dist/core/context/context-composition.d.ts.map +1 -0
- package/dist/core/context/context-composition.js +163 -0
- package/dist/core/context/context-composition.js.map +1 -0
- package/dist/core/context/context-prompt-enforcement.d.ts +13 -0
- package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -1
- package/dist/core/context/context-prompt-enforcement.js +17 -2
- package/dist/core/context/context-prompt-enforcement.js.map +1 -1
- package/dist/core/context-gc.d.ts +13 -0
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +6 -0
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/research/model-fitness.d.ts +3 -0
- package/dist/core/research/model-fitness.d.ts.map +1 -1
- package/dist/core/research/model-fitness.js +54 -3
- package/dist/core/research/model-fitness.js.map +1 -1
- package/dist/core/settings-manager.d.ts +13 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +19 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +6 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/components/fitness-role-selector.d.ts +13 -0
- package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/fitness-role-selector.js +65 -0
- package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +84 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +91 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-gc.js","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { ToolResultMessage } from \"@caupulican/pi-ai\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { estimateTokens } from \"./compaction/compaction.ts\";\n\nexport interface SemanticMemoryGcSettings {\n\tenabled?: boolean;\n\t/** Number of newest Automata/Mind injected pages to preserve verbatim. */\n\tpreserveRecentPages?: number;\n\t/** Minimum provider-visible text chars before a stale semantic memory page is packed. */\n\tminChars?: number;\n\t/** Markers that identify deterministic Automata/Mind context pages. */\n\tmarkers?: string[];\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean;\n\t/** Number of most recent AgentMessage rows to preserve verbatim. */\n\tpreserveRecentMessages?: number;\n\t/** Minimum provider-visible text chars before a stale tool result is packed. */\n\tminToolResultChars?: number;\n\t/** Tool names eligible for stale result packing. */\n\ttools?: string[];\n\t/** Provider-context control for deterministic Automata/Mind semantic memory pages. */\n\tsemanticMemory?: SemanticMemoryGcSettings;\n}\n\nexport interface NormalizedContextGcSettings extends Omit<Required<ContextGcSettings>, \"semanticMemory\"> {\n\tsemanticMemory: Required<SemanticMemoryGcSettings>;\n}\n\nexport interface ContextGcOptions extends NormalizedContextGcSettings {\n\tcwd: string;\n\tstorageDir?: string;\n\twritePayloads?: boolean;\n}\n\nexport interface ContextGcPackedRecord {\n\ttoolName: string;\n\ttoolCallId: string;\n\tmessageIndex: number;\n\treason: \"superseded-read\" | \"stale-tool-result\" | \"stale-semantic-memory\";\n\toriginalChars: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tstoragePath?: string;\n\tpath?: string;\n\tcommand?: string;\n\tkey?: string;\n}\n\nexport interface ContextGcReport {\n\tenabled: boolean;\n\tpackedCount: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tsavedTokens: number;\n\trecords: ContextGcPackedRecord[];\n}\n\nexport interface ContextGcResult {\n\tmessages: AgentMessage[];\n\treport: ContextGcReport;\n}\n\nconst DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS: Required<SemanticMemoryGcSettings> = {\n\tenabled: true,\n\tpreserveRecentPages: 1,\n\tminChars: 900,\n\tmarkers: [\n\t\t// Generic memory-subsystem recall page marker (brand-free). Provider-specific markers are\n\t\t// merged in dynamically at runtime via MemoryManager.getContextMarkers().\n\t\t\"<memory_context\",\n\t\t// Pre-existing provider-specific markers (to be generalized to provider-declared markers).\n\t\t\"<automata_context\",\n\t\t\"<automata_response\",\n\t\t\"<automata_query\",\n\t\t\"<automata_fetch\",\n\t\t\"<memory_lifecycle_audit\",\n\t\t\"<memory_lifecycle_purge\",\n\t\t\"<automata_doctor\",\n\t\t\"<automata_optimizer\",\n\t\t\"<automata_mesh\",\n\t],\n};\n\nexport const DEFAULT_CONTEXT_GC_SETTINGS: NormalizedContextGcSettings = {\n\tenabled: true,\n\tpreserveRecentMessages: 8,\n\tminToolResultChars: 1200,\n\ttools: [\n\t\t\"read\",\n\t\t\"bash\",\n\t\t\"rg\",\n\t\t\"grep\",\n\t\t\"find\",\n\t\t\"ls\",\n\t\t\"skill_open\",\n\t\t\"automata_graph_status\",\n\t\t\"automata_graph_search\",\n\t\t\"automata_graph_query\",\n\t\t\"automata_graph_neighbors\",\n\t\t\"automata_graph_path\",\n\t\t\"automata_graph_pointer_pack\",\n\t\t\"learning_query_memory\",\n\t\t\"subagent\",\n\t\t\"task_steps\",\n\t\t\"task_background\",\n\t\t\"task_goal\",\n\t\t\"run_ledger\",\n\t\t\"context_headroom_retrieve\",\n\t\t\"headroom_retrieve\",\n\t],\n\tsemanticMemory: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS,\n};\n\ntype ToolCallMeta = {\n\tid: string;\n\tname: string;\n\targs: Record<string, unknown>;\n\tmessageIndex: number;\n};\n\nfunction cap(text: string, limit = 220): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\treturn compact.length > limit ? `${compact.slice(0, Math.max(0, limit - 1))}…` : compact;\n}\n\nfunction normalizeSemanticMemoryGcSettings(settings?: SemanticMemoryGcSettings): Required<SemanticMemoryGcSettings> {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.enabled,\n\t\tpreserveRecentPages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentPages ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.preserveRecentPages),\n\t\t),\n\t\tminChars: Math.max(0, Math.floor(settings?.minChars ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.minChars)),\n\t\tmarkers:\n\t\t\tsettings?.markers && settings.markers.length > 0\n\t\t\t\t? settings.markers\n\t\t\t\t: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.markers,\n\t};\n}\n\nfunction normalizeContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_CONTEXT_GC_SETTINGS.enabled,\n\t\tpreserveRecentMessages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentMessages ?? DEFAULT_CONTEXT_GC_SETTINGS.preserveRecentMessages),\n\t\t),\n\t\tminToolResultChars: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.minToolResultChars ?? DEFAULT_CONTEXT_GC_SETTINGS.minToolResultChars),\n\t\t),\n\t\ttools: settings?.tools && settings.tools.length > 0 ? settings.tools : DEFAULT_CONTEXT_GC_SETTINGS.tools,\n\t\tsemanticMemory: normalizeSemanticMemoryGcSettings(settings?.semanticMemory),\n\t};\n}\n\nexport function getContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn normalizeContextGcSettings(settings);\n}\n\nfunction textContentParts(content: unknown): string[] | undefined {\n\tif (typeof content === \"string\") return [content];\n\tif (!Array.isArray(content)) return undefined;\n\tconst parts: string[] = [];\n\tfor (const part of content) {\n\t\tif (typeof part !== \"object\" || part === null) return undefined;\n\t\tconst typed = part as { type?: string; text?: string; mimeType?: string };\n\t\tif (typed.type === \"text\" && typeof typed.text === \"string\") parts.push(typed.text);\n\t\telse if (typed.type === \"image\") return undefined;\n\t\telse return undefined;\n\t}\n\treturn parts;\n}\n\nfunction contentText(content: unknown): string | undefined {\n\tif (typeof content === \"string\") return content;\n\treturn textContentParts(content)?.join(\"\\n\");\n}\n\nfunction toolResultParts(message: ToolResultMessage): string[] {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\" && part.text) parts.push(part.text);\n\t\telse if (part.type === \"image\") parts.push(`[image ${part.mimeType}]`);\n\t}\n\treturn parts;\n}\n\nfunction toolResultText(message: ToolResultMessage): string {\n\treturn toolResultParts(message).join(\"\\n\");\n}\n\nfunction smallStringSlice(value: string, start?: number, end?: number): string {\n\tconst sliced = value.slice(start, end);\n\treturn sliced ? ` ${sliced}`.slice(1) : \"\";\n}\n\nfunction joinedPartsContainMarker(parts: string[], marker: string): boolean {\n\tif (marker.length === 0) return true;\n\tconst tailLength = marker.length - 1;\n\tlet tail = \"\";\n\tlet first = true;\n\tfor (const part of parts) {\n\t\tif (part.includes(marker)) return true;\n\t\tif (!first && `${tail}\\n${smallStringSlice(part, 0, tailLength)}`.includes(marker)) return true;\n\t\tif (tailLength === 0) tail = \"\";\n\t\telse if (part.length >= tailLength) tail = smallStringSlice(part, -tailLength);\n\t\telse tail = `${tail}${first ? \"\" : \"\\n\"}${part}`.slice(-tailLength);\n\t\tfirst = false;\n\t}\n\treturn false;\n}\n\nfunction joinedPartsContainAnyMarker(parts: string[], markers: readonly string[]): boolean {\n\treturn markers.some((marker) => joinedPartsContainMarker(parts, marker));\n}\n\nfunction isSemanticMemoryCustomMessage(message: AgentMessage): boolean {\n\tif (message.role !== \"custom\") return false;\n\tconst customType = String((message as { customType?: unknown }).customType ?? \"\").toLowerCase();\n\treturn customType.includes(\"automata\") || customType.includes(\"memory\") || customType.includes(\"mind\");\n}\n\nfunction agentMessageText(message: AgentMessage): string | undefined {\n\tif (message.role === \"toolResult\") return toolResultText(message);\n\tif (isSemanticMemoryCustomMessage(message)) return contentText((message as { content?: unknown }).content);\n\treturn undefined;\n}\n\nfunction semanticMessageHasMarker(message: AgentMessage, settings: Required<SemanticMemoryGcSettings>): boolean {\n\tif (message.role === \"toolResult\") return joinedPartsContainAnyMarker(toolResultParts(message), settings.markers);\n\tif (isSemanticMemoryCustomMessage(message)) {\n\t\tconst parts = textContentParts((message as { content?: unknown }).content);\n\t\treturn parts ? joinedPartsContainAnyMarker(parts, settings.markers) : false;\n\t}\n\treturn false;\n}\n\ninterface ContextGcPlan {\n\tcalls: Map<string, ToolCallMeta>;\n\tlatestReadByPath: Map<string, string>;\n\tsemanticIndexes: number[];\n}\n\nfunction normalizeToolPath(cwd: string, value: unknown): string | undefined {\n\tif (typeof value !== \"string\" || value.trim() === \"\") return undefined;\n\tconst path = value.trim();\n\treturn normalizePath(isAbsolute(path) ? path : resolve(cwd, path));\n}\n\nfunction collectContextGcPlan(\n\tmessages: AgentMessage[],\n\tcwd: string,\n\tsemanticSettings: Required<SemanticMemoryGcSettings>,\n): ContextGcPlan {\n\tconst calls = new Map<string, ToolCallMeta>();\n\tconst readResultCallIds: string[] = [];\n\tconst semanticIndexes: number[] = [];\n\n\tfor (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {\n\t\tconst message = messages[messageIndex];\n\t\tif (message.role === \"assistant\") {\n\t\t\tfor (const part of message.content) {\n\t\t\t\tif (part.type !== \"toolCall\") continue;\n\t\t\t\tcalls.set(part.id, {\n\t\t\t\t\tid: part.id,\n\t\t\t\t\tname: part.name,\n\t\t\t\t\targs: part.arguments ?? {},\n\t\t\t\t\tmessageIndex,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (message.role === \"toolResult\" && message.toolName === \"read\") {\n\t\t\treadResultCallIds.push(message.toolCallId);\n\t\t}\n\n\t\tif (semanticSettings.enabled && semanticMessageHasMarker(message, semanticSettings)) {\n\t\t\tsemanticIndexes.push(messageIndex);\n\t\t}\n\t}\n\n\tconst latestReadByPath = new Map<string, string>();\n\tfor (const toolCallId of readResultCallIds) {\n\t\tconst call = calls.get(toolCallId);\n\t\tconst path = normalizeToolPath(cwd, call?.args.path);\n\t\tif (path) latestReadByPath.set(path, toolCallId);\n\t}\n\n\treturn { calls, latestReadByPath, semanticIndexes };\n}\n\nfunction storagePathFor(storageDir: string | undefined, key: string): string | undefined {\n\tif (!storageDir || !isAbsolute(storageDir)) return undefined;\n\treturn resolve(storageDir, `${key}.txt`);\n}\n\nfunction maybeStoreOriginal(options: ContextGcOptions, key: string, original: string): string | undefined {\n\tconst path = storagePathFor(options.storageDir, key);\n\tif (!path || !options.writePayloads) return path;\n\ttry {\n\t\tmkdirSync(options.storageDir!, { recursive: true });\n\t\tif (!existsSync(path)) writeFileSync(path, original, \"utf8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn path;\n}\n\nfunction reasonText(record: ContextGcPackedRecord): string {\n\tif (record.reason === \"superseded-read\") return \"older read snapshot superseded by a later read of the same file\";\n\tif (record.reason === \"stale-semantic-memory\") {\n\t\treturn \"older Automata/Mind semantic context page outside the semantic-memory freshness window\";\n\t}\n\treturn \"stale bulky tool output outside the recent context window\";\n}\n\nfunction buildSummary(record: ContextGcPackedRecord): string {\n\tconst semantic = record.reason === \"stale-semantic-memory\";\n\tconst lines = [\n\t\tsemantic ? \"[Semantic GC packed stale Automata/Mind context page]\" : \"[Context GC packed stale tool result]\",\n\t\tsemantic ? undefined : `tool: ${record.toolName}`,\n\t\trecord.path ? `path: ${record.path}` : undefined,\n\t\trecord.command ? `command: ${cap(record.command)}` : undefined,\n\t\t`reason: ${reasonText(record)}`,\n\t\t`original: ${record.originalChars} chars (~${record.originalTokens} tokens)`,\n\t\trecord.storagePath\n\t\t\t? `exact old provider-visible text stored at: ${record.storagePath}`\n\t\t\t: \"exact old provider-visible text retained in the session log, not inline in provider context\",\n\t\tsemantic\n\t\t\t? \"If this memory context matters, query Automata/Mind again with the same topic/filter or fetch the drawer pointers from the stored page.\"\n\t\t\t: record.path\n\t\t\t\t? \"For current file contents, use the read tool on the path above. For the exact old output, read the stored payload path if present.\"\n\t\t\t\t: \"If this exact old output matters, retrieve/read the stored payload path if present or rerun the tool command.\",\n\t\t\"Do not rely on this summary as the original content.\",\n\t].filter((line): line is string => line !== undefined);\n\treturn lines.join(\"\\n\");\n}\n\nfunction gcDetails(message: { details?: unknown }, record: ContextGcPackedRecord): Record<string, unknown> {\n\treturn {\n\t\t...(typeof message.details === \"object\" && message.details !== null ? message.details : {}),\n\t\tcontextGc: {\n\t\t\tpacked: true,\n\t\t\toriginalChars: record.originalChars,\n\t\t\toriginalTokens: record.originalTokens,\n\t\t\tstoragePath: record.storagePath,\n\t\t\treason: record.reason,\n\t\t},\n\t};\n}\n\nfunction makePackedToolResult(message: ToolResultMessage, record: ContextGcPackedRecord): ToolResultMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...message,\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message, record),\n\t};\n}\n\nfunction makePackedSemanticMemoryMessage(message: AgentMessage, record: ContextGcPackedRecord): AgentMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...(message as unknown as Record<string, unknown>),\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message as { details?: unknown }, record),\n\t} as AgentMessage;\n}\n\nexport function applyContextGc(\n\tmessages: AgentMessage[],\n\trawSettings: ContextGcSettings & { cwd?: string; storageDir?: string; writePayloads?: boolean },\n): ContextGcResult {\n\tconst settings = normalizeContextGcSettings(rawSettings);\n\tconst baseReport: ContextGcReport = {\n\t\tenabled: settings.enabled,\n\t\tpackedCount: 0,\n\t\toriginalTokens: 0,\n\t\tpackedTokens: 0,\n\t\tsavedTokens: 0,\n\t\trecords: [],\n\t};\n\tif (!settings.enabled) return { messages, report: baseReport };\n\n\tconst options: ContextGcOptions = {\n\t\t...settings,\n\t\tcwd: rawSettings.cwd ?? process.cwd(),\n\t\tstorageDir: rawSettings.storageDir,\n\t\twritePayloads: rawSettings.writePayloads ?? true,\n\t};\n\tconst eligibleTools = new Set(options.tools);\n\tconst plan = collectContextGcPlan(messages, options.cwd, options.semanticMemory);\n\tconst recentStart = Math.max(0, messages.length - options.preserveRecentMessages);\n\tconst semanticIndexSet = new Set(plan.semanticIndexes);\n\tconst preservedSemanticIndexes = new Set(\n\t\toptions.semanticMemory.preserveRecentPages > 0\n\t\t\t? plan.semanticIndexes.slice(-options.semanticMemory.preserveRecentPages)\n\t\t\t: [],\n\t);\n\tconst nextMessages = messages.slice();\n\tlet changed = false;\n\n\tfor (let index = 0; index < messages.length; index++) {\n\t\tconst message = messages[index];\n\t\tif (semanticIndexSet.has(index) && !preservedSemanticIndexes.has(index) && index < recentStart) {\n\t\t\tconst originalText = agentMessageText(message);\n\t\t\tif (originalText && originalText.length >= options.semanticMemory.minChars) {\n\t\t\t\tconst originalTokens = estimateTokens(message);\n\t\t\t\tconst key = createHash(\"sha256\")\n\t\t\t\t\t.update(`semantic-memory\\0${index}\\0${originalText}`)\n\t\t\t\t\t.digest(\"hex\")\n\t\t\t\t\t.slice(0, 24);\n\t\t\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\t\t\tconst record: ContextGcPackedRecord = {\n\t\t\t\t\ttoolName: \"automata-mind\",\n\t\t\t\t\ttoolCallId: `semantic-${index}`,\n\t\t\t\t\tmessageIndex: index,\n\t\t\t\t\treason: \"stale-semantic-memory\",\n\t\t\t\t\toriginalChars: originalText.length,\n\t\t\t\t\toriginalTokens,\n\t\t\t\t\tpackedTokens: 0,\n\t\t\t\t\tstoragePath,\n\t\t\t\t\tkey,\n\t\t\t\t};\n\t\t\t\tconst packed = makePackedSemanticMemoryMessage(message, record);\n\t\t\t\trecord.packedTokens = estimateTokens(packed);\n\t\t\t\tnextMessages[index] = packed;\n\t\t\t\tbaseReport.records.push(record);\n\t\t\t\tbaseReport.originalTokens += record.originalTokens;\n\t\t\t\tbaseReport.packedTokens += record.packedTokens;\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (message.role !== \"toolResult\") continue;\n\t\tif (!eligibleTools.has(message.toolName)) continue;\n\t\tif (index >= recentStart) continue;\n\n\t\tconst originalText = toolResultText(message);\n\t\tif (originalText.length < options.minToolResultChars) continue;\n\n\t\tconst call = plan.calls.get(message.toolCallId);\n\t\tconst path = normalizeToolPath(options.cwd, call?.args.path);\n\t\tlet reason: ContextGcPackedRecord[\"reason\"] = \"stale-tool-result\";\n\t\tif (message.toolName === \"read\" && path) {\n\t\t\tif (plan.latestReadByPath.get(path) === message.toolCallId) continue;\n\t\t\treason = \"superseded-read\";\n\t\t}\n\n\t\tconst originalTokens = estimateTokens(message);\n\t\tconst key = createHash(\"sha256\")\n\t\t\t.update(`${message.toolName}\\0${message.toolCallId}\\0${originalText}`)\n\t\t\t.digest(\"hex\")\n\t\t\t.slice(0, 24);\n\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\tconst record: ContextGcPackedRecord = {\n\t\t\ttoolName: message.toolName,\n\t\t\ttoolCallId: message.toolCallId,\n\t\t\tmessageIndex: index,\n\t\t\treason,\n\t\t\toriginalChars: originalText.length,\n\t\t\toriginalTokens,\n\t\t\tpackedTokens: 0,\n\t\t\tstoragePath,\n\t\t\tpath,\n\t\t\tcommand: typeof call?.args.command === \"string\" ? call.args.command : undefined,\n\t\t\tkey,\n\t\t};\n\t\tconst packed = makePackedToolResult(message, record);\n\t\trecord.packedTokens = estimateTokens(packed);\n\t\tnextMessages[index] = packed as AgentMessage;\n\t\tbaseReport.records.push(record);\n\t\tbaseReport.originalTokens += record.originalTokens;\n\t\tbaseReport.packedTokens += record.packedTokens;\n\t\tchanged = true;\n\t}\n\n\tbaseReport.packedCount = baseReport.records.length;\n\tbaseReport.savedTokens = Math.max(0, baseReport.originalTokens - baseReport.packedTokens);\n\treturn { messages: changed ? nextMessages : messages, report: baseReport };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-gc.js","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { ToolResultMessage } from \"@caupulican/pi-ai\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { estimateTokens } from \"./compaction/compaction.ts\";\n\nexport interface SemanticMemoryGcSettings {\n\tenabled?: boolean;\n\t/** Number of newest Automata/Mind injected pages to preserve verbatim. */\n\tpreserveRecentPages?: number;\n\t/** Minimum provider-visible text chars before a stale semantic memory page is packed. */\n\tminChars?: number;\n\t/** Markers that identify deterministic Automata/Mind context pages. */\n\tmarkers?: string[];\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean;\n\t/** Number of most recent AgentMessage rows to preserve verbatim. */\n\tpreserveRecentMessages?: number;\n\t/** Minimum provider-visible text chars before a stale tool result is packed. */\n\tminToolResultChars?: number;\n\t/** Tool names eligible for stale result packing. */\n\ttools?: string[];\n\t/** Provider-context control for deterministic Automata/Mind semantic memory pages. */\n\tsemanticMemory?: SemanticMemoryGcSettings;\n}\n\nexport interface NormalizedContextGcSettings extends Omit<Required<ContextGcSettings>, \"semanticMemory\"> {\n\tsemanticMemory: Required<SemanticMemoryGcSettings>;\n}\n\n/**\n * Brain-curation hooks (both optional; absent hooks are byte-for-byte today's behavior).\n * `resolveDigest` is a pure lookup keyed by the record's content hash; `onPacked` lets the\n * caller enqueue digest work with the exact original text at the moment it is packed.\n */\nexport interface ContextGcCurationHooks {\n\tresolveDigest?: (digestKey: string) => string | undefined;\n\tonPacked?: (record: ContextGcPackedRecord, originalText: string) => void;\n}\n\nexport interface ContextGcOptions extends NormalizedContextGcSettings {\n\tcwd: string;\n\tstorageDir?: string;\n\twritePayloads?: boolean;\n\tcuration?: ContextGcCurationHooks;\n}\n\nexport interface ContextGcPackedRecord {\n\ttoolName: string;\n\ttoolCallId: string;\n\tmessageIndex: number;\n\treason: \"superseded-read\" | \"stale-tool-result\" | \"stale-semantic-memory\";\n\toriginalChars: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tstoragePath?: string;\n\tpath?: string;\n\tcommand?: string;\n\tkey?: string;\n\t/** Brain-curator semantic digest of the packed content (model-generated; advisory only). */\n\tdigest?: string;\n}\n\nexport interface ContextGcReport {\n\tenabled: boolean;\n\tpackedCount: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tsavedTokens: number;\n\trecords: ContextGcPackedRecord[];\n}\n\nexport interface ContextGcResult {\n\tmessages: AgentMessage[];\n\treport: ContextGcReport;\n}\n\nconst DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS: Required<SemanticMemoryGcSettings> = {\n\tenabled: true,\n\tpreserveRecentPages: 1,\n\tminChars: 900,\n\tmarkers: [\n\t\t// Generic memory-subsystem recall page marker (brand-free). Provider-specific markers are\n\t\t// merged in dynamically at runtime via MemoryManager.getContextMarkers().\n\t\t\"<memory_context\",\n\t\t// Pre-existing provider-specific markers (to be generalized to provider-declared markers).\n\t\t\"<automata_context\",\n\t\t\"<automata_response\",\n\t\t\"<automata_query\",\n\t\t\"<automata_fetch\",\n\t\t\"<memory_lifecycle_audit\",\n\t\t\"<memory_lifecycle_purge\",\n\t\t\"<automata_doctor\",\n\t\t\"<automata_optimizer\",\n\t\t\"<automata_mesh\",\n\t],\n};\n\nexport const DEFAULT_CONTEXT_GC_SETTINGS: NormalizedContextGcSettings = {\n\tenabled: true,\n\tpreserveRecentMessages: 8,\n\tminToolResultChars: 1200,\n\ttools: [\n\t\t\"read\",\n\t\t\"bash\",\n\t\t\"rg\",\n\t\t\"grep\",\n\t\t\"find\",\n\t\t\"ls\",\n\t\t\"skill_open\",\n\t\t\"automata_graph_status\",\n\t\t\"automata_graph_search\",\n\t\t\"automata_graph_query\",\n\t\t\"automata_graph_neighbors\",\n\t\t\"automata_graph_path\",\n\t\t\"automata_graph_pointer_pack\",\n\t\t\"learning_query_memory\",\n\t\t\"subagent\",\n\t\t\"task_steps\",\n\t\t\"task_background\",\n\t\t\"task_goal\",\n\t\t\"run_ledger\",\n\t\t\"context_headroom_retrieve\",\n\t\t\"headroom_retrieve\",\n\t],\n\tsemanticMemory: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS,\n};\n\ntype ToolCallMeta = {\n\tid: string;\n\tname: string;\n\targs: Record<string, unknown>;\n\tmessageIndex: number;\n};\n\nfunction cap(text: string, limit = 220): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\treturn compact.length > limit ? `${compact.slice(0, Math.max(0, limit - 1))}…` : compact;\n}\n\nfunction normalizeSemanticMemoryGcSettings(settings?: SemanticMemoryGcSettings): Required<SemanticMemoryGcSettings> {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.enabled,\n\t\tpreserveRecentPages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentPages ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.preserveRecentPages),\n\t\t),\n\t\tminChars: Math.max(0, Math.floor(settings?.minChars ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.minChars)),\n\t\tmarkers:\n\t\t\tsettings?.markers && settings.markers.length > 0\n\t\t\t\t? settings.markers\n\t\t\t\t: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.markers,\n\t};\n}\n\nfunction normalizeContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_CONTEXT_GC_SETTINGS.enabled,\n\t\tpreserveRecentMessages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentMessages ?? DEFAULT_CONTEXT_GC_SETTINGS.preserveRecentMessages),\n\t\t),\n\t\tminToolResultChars: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.minToolResultChars ?? DEFAULT_CONTEXT_GC_SETTINGS.minToolResultChars),\n\t\t),\n\t\ttools: settings?.tools && settings.tools.length > 0 ? settings.tools : DEFAULT_CONTEXT_GC_SETTINGS.tools,\n\t\tsemanticMemory: normalizeSemanticMemoryGcSettings(settings?.semanticMemory),\n\t};\n}\n\nexport function getContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn normalizeContextGcSettings(settings);\n}\n\nfunction textContentParts(content: unknown): string[] | undefined {\n\tif (typeof content === \"string\") return [content];\n\tif (!Array.isArray(content)) return undefined;\n\tconst parts: string[] = [];\n\tfor (const part of content) {\n\t\tif (typeof part !== \"object\" || part === null) return undefined;\n\t\tconst typed = part as { type?: string; text?: string; mimeType?: string };\n\t\tif (typed.type === \"text\" && typeof typed.text === \"string\") parts.push(typed.text);\n\t\telse if (typed.type === \"image\") return undefined;\n\t\telse return undefined;\n\t}\n\treturn parts;\n}\n\nfunction contentText(content: unknown): string | undefined {\n\tif (typeof content === \"string\") return content;\n\treturn textContentParts(content)?.join(\"\\n\");\n}\n\nfunction toolResultParts(message: ToolResultMessage): string[] {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\" && part.text) parts.push(part.text);\n\t\telse if (part.type === \"image\") parts.push(`[image ${part.mimeType}]`);\n\t}\n\treturn parts;\n}\n\nfunction toolResultText(message: ToolResultMessage): string {\n\treturn toolResultParts(message).join(\"\\n\");\n}\n\nfunction smallStringSlice(value: string, start?: number, end?: number): string {\n\tconst sliced = value.slice(start, end);\n\treturn sliced ? ` ${sliced}`.slice(1) : \"\";\n}\n\nfunction joinedPartsContainMarker(parts: string[], marker: string): boolean {\n\tif (marker.length === 0) return true;\n\tconst tailLength = marker.length - 1;\n\tlet tail = \"\";\n\tlet first = true;\n\tfor (const part of parts) {\n\t\tif (part.includes(marker)) return true;\n\t\tif (!first && `${tail}\\n${smallStringSlice(part, 0, tailLength)}`.includes(marker)) return true;\n\t\tif (tailLength === 0) tail = \"\";\n\t\telse if (part.length >= tailLength) tail = smallStringSlice(part, -tailLength);\n\t\telse tail = `${tail}${first ? \"\" : \"\\n\"}${part}`.slice(-tailLength);\n\t\tfirst = false;\n\t}\n\treturn false;\n}\n\nfunction joinedPartsContainAnyMarker(parts: string[], markers: readonly string[]): boolean {\n\treturn markers.some((marker) => joinedPartsContainMarker(parts, marker));\n}\n\nfunction isSemanticMemoryCustomMessage(message: AgentMessage): boolean {\n\tif (message.role !== \"custom\") return false;\n\tconst customType = String((message as { customType?: unknown }).customType ?? \"\").toLowerCase();\n\treturn customType.includes(\"automata\") || customType.includes(\"memory\") || customType.includes(\"mind\");\n}\n\nfunction agentMessageText(message: AgentMessage): string | undefined {\n\tif (message.role === \"toolResult\") return toolResultText(message);\n\tif (isSemanticMemoryCustomMessage(message)) return contentText((message as { content?: unknown }).content);\n\treturn undefined;\n}\n\nfunction semanticMessageHasMarker(message: AgentMessage, settings: Required<SemanticMemoryGcSettings>): boolean {\n\tif (message.role === \"toolResult\") return joinedPartsContainAnyMarker(toolResultParts(message), settings.markers);\n\tif (isSemanticMemoryCustomMessage(message)) {\n\t\tconst parts = textContentParts((message as { content?: unknown }).content);\n\t\treturn parts ? joinedPartsContainAnyMarker(parts, settings.markers) : false;\n\t}\n\treturn false;\n}\n\ninterface ContextGcPlan {\n\tcalls: Map<string, ToolCallMeta>;\n\tlatestReadByPath: Map<string, string>;\n\tsemanticIndexes: number[];\n}\n\nfunction normalizeToolPath(cwd: string, value: unknown): string | undefined {\n\tif (typeof value !== \"string\" || value.trim() === \"\") return undefined;\n\tconst path = value.trim();\n\treturn normalizePath(isAbsolute(path) ? path : resolve(cwd, path));\n}\n\nfunction collectContextGcPlan(\n\tmessages: AgentMessage[],\n\tcwd: string,\n\tsemanticSettings: Required<SemanticMemoryGcSettings>,\n): ContextGcPlan {\n\tconst calls = new Map<string, ToolCallMeta>();\n\tconst readResultCallIds: string[] = [];\n\tconst semanticIndexes: number[] = [];\n\n\tfor (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {\n\t\tconst message = messages[messageIndex];\n\t\tif (message.role === \"assistant\") {\n\t\t\tfor (const part of message.content) {\n\t\t\t\tif (part.type !== \"toolCall\") continue;\n\t\t\t\tcalls.set(part.id, {\n\t\t\t\t\tid: part.id,\n\t\t\t\t\tname: part.name,\n\t\t\t\t\targs: part.arguments ?? {},\n\t\t\t\t\tmessageIndex,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (message.role === \"toolResult\" && message.toolName === \"read\") {\n\t\t\treadResultCallIds.push(message.toolCallId);\n\t\t}\n\n\t\tif (semanticSettings.enabled && semanticMessageHasMarker(message, semanticSettings)) {\n\t\t\tsemanticIndexes.push(messageIndex);\n\t\t}\n\t}\n\n\tconst latestReadByPath = new Map<string, string>();\n\tfor (const toolCallId of readResultCallIds) {\n\t\tconst call = calls.get(toolCallId);\n\t\tconst path = normalizeToolPath(cwd, call?.args.path);\n\t\tif (path) latestReadByPath.set(path, toolCallId);\n\t}\n\n\treturn { calls, latestReadByPath, semanticIndexes };\n}\n\nfunction storagePathFor(storageDir: string | undefined, key: string): string | undefined {\n\tif (!storageDir || !isAbsolute(storageDir)) return undefined;\n\treturn resolve(storageDir, `${key}.txt`);\n}\n\nfunction maybeStoreOriginal(options: ContextGcOptions, key: string, original: string): string | undefined {\n\tconst path = storagePathFor(options.storageDir, key);\n\tif (!path || !options.writePayloads) return path;\n\ttry {\n\t\tmkdirSync(options.storageDir!, { recursive: true });\n\t\tif (!existsSync(path)) writeFileSync(path, original, \"utf8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn path;\n}\n\nfunction reasonText(record: ContextGcPackedRecord): string {\n\tif (record.reason === \"superseded-read\") return \"older read snapshot superseded by a later read of the same file\";\n\tif (record.reason === \"stale-semantic-memory\") {\n\t\treturn \"older Automata/Mind semantic context page outside the semantic-memory freshness window\";\n\t}\n\treturn \"stale bulky tool output outside the recent context window\";\n}\n\nfunction buildSummary(record: ContextGcPackedRecord): string {\n\tconst semantic = record.reason === \"stale-semantic-memory\";\n\tconst lines = [\n\t\tsemantic ? \"[Semantic GC packed stale Automata/Mind context page]\" : \"[Context GC packed stale tool result]\",\n\t\tsemantic ? undefined : `tool: ${record.toolName}`,\n\t\trecord.path ? `path: ${record.path}` : undefined,\n\t\trecord.command ? `command: ${cap(record.command)}` : undefined,\n\t\t`reason: ${reasonText(record)}`,\n\t\t`original: ${record.originalChars} chars (~${record.originalTokens} tokens)`,\n\t\trecord.digest ? `summary (auto-digest, machine paraphrase, not authoritative): ${record.digest}` : undefined,\n\t\trecord.storagePath\n\t\t\t? `exact old provider-visible text stored at: ${record.storagePath}`\n\t\t\t: \"exact old provider-visible text retained in the session log, not inline in provider context\",\n\t\tsemantic\n\t\t\t? \"If this memory context matters, query Automata/Mind again with the same topic/filter or fetch the drawer pointers from the stored page.\"\n\t\t\t: record.path\n\t\t\t\t? \"For current file contents, use the read tool on the path above. For the exact old output, read the stored payload path if present.\"\n\t\t\t\t: \"If this exact old output matters, retrieve/read the stored payload path if present or rerun the tool command.\",\n\t\t\"Do not rely on this summary as the original content.\",\n\t].filter((line): line is string => line !== undefined);\n\treturn lines.join(\"\\n\");\n}\n\nfunction gcDetails(message: { details?: unknown }, record: ContextGcPackedRecord): Record<string, unknown> {\n\treturn {\n\t\t...(typeof message.details === \"object\" && message.details !== null ? message.details : {}),\n\t\tcontextGc: {\n\t\t\tpacked: true,\n\t\t\toriginalChars: record.originalChars,\n\t\t\toriginalTokens: record.originalTokens,\n\t\t\tstoragePath: record.storagePath,\n\t\t\treason: record.reason,\n\t\t},\n\t};\n}\n\nfunction makePackedToolResult(message: ToolResultMessage, record: ContextGcPackedRecord): ToolResultMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...message,\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message, record),\n\t};\n}\n\nfunction makePackedSemanticMemoryMessage(message: AgentMessage, record: ContextGcPackedRecord): AgentMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...(message as unknown as Record<string, unknown>),\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message as { details?: unknown }, record),\n\t} as AgentMessage;\n}\n\nexport function applyContextGc(\n\tmessages: AgentMessage[],\n\trawSettings: ContextGcSettings & {\n\t\tcwd?: string;\n\t\tstorageDir?: string;\n\t\twritePayloads?: boolean;\n\t\tcuration?: ContextGcCurationHooks;\n\t},\n): ContextGcResult {\n\tconst settings = normalizeContextGcSettings(rawSettings);\n\tconst baseReport: ContextGcReport = {\n\t\tenabled: settings.enabled,\n\t\tpackedCount: 0,\n\t\toriginalTokens: 0,\n\t\tpackedTokens: 0,\n\t\tsavedTokens: 0,\n\t\trecords: [],\n\t};\n\tif (!settings.enabled) return { messages, report: baseReport };\n\n\tconst options: ContextGcOptions = {\n\t\t...settings,\n\t\tcwd: rawSettings.cwd ?? process.cwd(),\n\t\tstorageDir: rawSettings.storageDir,\n\t\twritePayloads: rawSettings.writePayloads ?? true,\n\t\tcuration: rawSettings.curation,\n\t};\n\tconst eligibleTools = new Set(options.tools);\n\tconst plan = collectContextGcPlan(messages, options.cwd, options.semanticMemory);\n\tconst recentStart = Math.max(0, messages.length - options.preserveRecentMessages);\n\tconst semanticIndexSet = new Set(plan.semanticIndexes);\n\tconst preservedSemanticIndexes = new Set(\n\t\toptions.semanticMemory.preserveRecentPages > 0\n\t\t\t? plan.semanticIndexes.slice(-options.semanticMemory.preserveRecentPages)\n\t\t\t: [],\n\t);\n\tconst nextMessages = messages.slice();\n\tlet changed = false;\n\n\tfor (let index = 0; index < messages.length; index++) {\n\t\tconst message = messages[index];\n\t\tif (semanticIndexSet.has(index) && !preservedSemanticIndexes.has(index) && index < recentStart) {\n\t\t\tconst originalText = agentMessageText(message);\n\t\t\tif (originalText && originalText.length >= options.semanticMemory.minChars) {\n\t\t\t\tconst originalTokens = estimateTokens(message);\n\t\t\t\tconst key = createHash(\"sha256\")\n\t\t\t\t\t.update(`semantic-memory\\0${index}\\0${originalText}`)\n\t\t\t\t\t.digest(\"hex\")\n\t\t\t\t\t.slice(0, 24);\n\t\t\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\t\t\tconst record: ContextGcPackedRecord = {\n\t\t\t\t\ttoolName: \"automata-mind\",\n\t\t\t\t\ttoolCallId: `semantic-${index}`,\n\t\t\t\t\tmessageIndex: index,\n\t\t\t\t\treason: \"stale-semantic-memory\",\n\t\t\t\t\toriginalChars: originalText.length,\n\t\t\t\t\toriginalTokens,\n\t\t\t\t\tpackedTokens: 0,\n\t\t\t\t\tstoragePath,\n\t\t\t\t\tkey,\n\t\t\t\t};\n\t\t\t\trecord.digest = options.curation?.resolveDigest?.(key);\n\t\t\t\toptions.curation?.onPacked?.(record, originalText);\n\t\t\t\tconst packed = makePackedSemanticMemoryMessage(message, record);\n\t\t\t\trecord.packedTokens = estimateTokens(packed);\n\t\t\t\tnextMessages[index] = packed;\n\t\t\t\tbaseReport.records.push(record);\n\t\t\t\tbaseReport.originalTokens += record.originalTokens;\n\t\t\t\tbaseReport.packedTokens += record.packedTokens;\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (message.role !== \"toolResult\") continue;\n\t\tif (!eligibleTools.has(message.toolName)) continue;\n\t\tif (index >= recentStart) continue;\n\n\t\tconst originalText = toolResultText(message);\n\t\tif (originalText.length < options.minToolResultChars) continue;\n\n\t\tconst call = plan.calls.get(message.toolCallId);\n\t\tconst path = normalizeToolPath(options.cwd, call?.args.path);\n\t\tlet reason: ContextGcPackedRecord[\"reason\"] = \"stale-tool-result\";\n\t\tif (message.toolName === \"read\" && path) {\n\t\t\tif (plan.latestReadByPath.get(path) === message.toolCallId) continue;\n\t\t\treason = \"superseded-read\";\n\t\t}\n\n\t\tconst originalTokens = estimateTokens(message);\n\t\tconst key = createHash(\"sha256\")\n\t\t\t.update(`${message.toolName}\\0${message.toolCallId}\\0${originalText}`)\n\t\t\t.digest(\"hex\")\n\t\t\t.slice(0, 24);\n\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\tconst record: ContextGcPackedRecord = {\n\t\t\ttoolName: message.toolName,\n\t\t\ttoolCallId: message.toolCallId,\n\t\t\tmessageIndex: index,\n\t\t\treason,\n\t\t\toriginalChars: originalText.length,\n\t\t\toriginalTokens,\n\t\t\tpackedTokens: 0,\n\t\t\tstoragePath,\n\t\t\tpath,\n\t\t\tcommand: typeof call?.args.command === \"string\" ? call.args.command : undefined,\n\t\t\tkey,\n\t\t};\n\t\trecord.digest = options.curation?.resolveDigest?.(key);\n\t\toptions.curation?.onPacked?.(record, originalText);\n\t\tconst packed = makePackedToolResult(message, record);\n\t\trecord.packedTokens = estimateTokens(packed);\n\t\tnextMessages[index] = packed as AgentMessage;\n\t\tbaseReport.records.push(record);\n\t\tbaseReport.originalTokens += record.originalTokens;\n\t\tbaseReport.packedTokens += record.packedTokens;\n\t\tchanged = true;\n\t}\n\n\tbaseReport.packedCount = baseReport.records.length;\n\tbaseReport.savedTokens = Math.max(0, baseReport.originalTokens - baseReport.packedTokens);\n\treturn { messages: changed ? nextMessages : messages, report: baseReport };\n}\n"]}
|
|
@@ -68,11 +68,14 @@ export interface ModelFitnessReport {
|
|
|
68
68
|
search: LaneFitnessScore;
|
|
69
69
|
/** Heavy-lifter surface: can the model emit a well-formed tool call against a schema? */
|
|
70
70
|
toolCall: LaneFitnessScore;
|
|
71
|
+
/** Curator surface: can the model digest a context chunk to strict JSON WITHOUT losing key facts? */
|
|
72
|
+
digest: LaneFitnessScore;
|
|
71
73
|
totalCostUsd: number;
|
|
72
74
|
}
|
|
73
75
|
/** Static prompts for the heavy-lifter surfaces (stable for provider prompt caching). */
|
|
74
76
|
export declare const SEARCH_PROBE_SYSTEM_PROMPT: string;
|
|
75
77
|
export declare const TOOL_CALL_PROBE_SYSTEM_PROMPT: string;
|
|
78
|
+
export { CURATION_DIGEST_SYSTEM_PROMPT as DIGEST_PROBE_SYSTEM_PROMPT } from "../context/brain-curator.ts";
|
|
76
79
|
export declare function runModelFitnessProbe(options: ModelFitnessOptions): Promise<ModelFitnessReport>;
|
|
77
80
|
/** Compact human-readable report for tool output / interactive display. Bounded, no raw dumps. */
|
|
78
81
|
export declare function formatModelFitnessReport(model: string, report: ModelFitnessReport): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-fitness.d.ts","sourceRoot":"","sources":["../../../src/core/research/model-fitness.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AAEH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,iGAAiG;IACjG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kGAAkG;IAClG,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEjC,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,qFAAqF;AACrF,eAAO,MAAM,6BAA6B,EAAE,SAAS,kBAAkB,EAOtE,CAAC;AAEF,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,eAAe,CAAC;IAC1B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,iBAAiB,CAAC;IACzB,8EAA8E;IAC9E,MAAM,EAAE,gBAAgB,CAAC;IACzB,yFAAyF;IACzF,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,yFAAyF;AACzF,eAAO,MAAM,0BAA0B,QAK3B,CAAC;AAEb,eAAO,MAAM,6BAA6B,QAK9B,CAAC;AAsEb,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA4JpG;AAED,kGAAkG;AAClG,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAgB1F","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\nimport type { CapabilityEnvelope } from \"../autonomy/contracts.ts\";\nimport { runWorker } from \"../delegation/worker-runner.ts\";\nimport { runRouteJudge } from \"../model-router/route-judge.ts\";\nimport { runResearch } from \"./research-runner.ts\";\n\n/**\n * Model fitness probe: measures whether a candidate model can actually drive the harness's\n * subagent contracts — the research lane, the scout-worker lane, and the routing judge — by\n * running each real runner against the model and scoring parse/success rates plus judge\n * discrimination. Provider-free: the completion executor is injected, so this works against any\n * registered model (local Ollama models included) and against faux providers in tests.\n */\n\nexport interface FitnessCompletion {\n\ttext: string;\n\tcostUsd: number;\n\tstopReason: string;\n\t/** Output tokens generated (for tok/s). Optional: providers that don't report it are skipped. */\n\toutputTokens?: number;\n\t/** Pure generation time in ms (e.g. Ollama eval_duration). Falls back to wall-clock if absent. */\n\tevalMs?: number;\n}\n\nexport type FitnessComplete = (args: {\n\tsystemPrompt: string;\n\tuserPrompt: string;\n\tsignal?: AbortSignal;\n}) => Promise<FitnessCompletion>;\n\nexport interface JudgeFitnessPrompt {\n\tprompt: string;\n\t/** True when the prompt is planning-shaped and must never route cheap. */\n\tplanning: boolean;\n}\n\n/** Default judge probe set: three planning-shaped prompts, three trivial lookups. */\nexport const DEFAULT_JUDGE_FITNESS_PROMPTS: readonly JudgeFitnessPrompt[] = [\n\t{ prompt: \"how should we plan the migration of the session storage layer?\", planning: true },\n\t{ prompt: \"design an approach for splitting the settings manager\", planning: true },\n\t{ prompt: \"draft a roadmap for the autonomy rework\", planning: true },\n\t{ prompt: \"what does the resolvePath function return?\", planning: false },\n\t{ prompt: \"list the files in the delegation module\", planning: false },\n\t{ prompt: \"why is this test flaky?\", planning: false },\n];\n\nexport interface ModelFitnessOptions {\n\tcomplete: FitnessComplete;\n\t/** Trials per lane surface. Default 3. */\n\ttrials?: number;\n\t/** Wall-clock budget per call in ms. Default 120000. */\n\tmaxWallClockMs?: number;\n\tjudgePrompts?: readonly JudgeFitnessPrompt[];\n\tsignal?: AbortSignal;\n\t/** Injected clock for latency measurement (test seam). Defaults to Date.now. */\n\tnow?: () => number;\n}\n\nexport interface LaneFitnessScore {\n\tsucceeded: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the surface's calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface JudgeFitnessScore {\n\tparsed: number;\n\tplanningElevated: number;\n\tplanningTotal: number;\n\ttrivialCheap: number;\n\ttrivialTotal: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the judge calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface ModelFitnessReport {\n\ttrials: number;\n\t/** Aggregate output tokens/second across ALL probe calls (the headline speed number). */\n\ttokensPerSecond?: number;\n\tresearch: LaneFitnessScore;\n\tworker: LaneFitnessScore;\n\tjudge: JudgeFitnessScore;\n\t/** Heavy-lifter surface: can the model formulate a structured search plan? */\n\tsearch: LaneFitnessScore;\n\t/** Heavy-lifter surface: can the model emit a well-formed tool call against a schema? */\n\ttoolCall: LaneFitnessScore;\n\ttotalCostUsd: number;\n}\n\n/** Static prompts for the heavy-lifter surfaces (stable for provider prompt caching). */\nexport const SEARCH_PROBE_SYSTEM_PROMPT = [\n\t\"You plan code searches for a coding agent. You never answer the question yourself.\",\n\t\"Given a question about a codebase, respond with STRICT JSON only - no prose:\",\n\t'{\"queries\":[{\"pattern\":\"<regex or literal to grep>\",\"glob\":\"<file glob like **/*.ts>\"}]}',\n\t\"Return 1 to 4 queries, most specific first.\",\n].join(\"\\n\");\n\nexport const TOOL_CALL_PROBE_SYSTEM_PROMPT = [\n\t\"You operate tools for a coding agent. You have exactly one tool:\",\n\t\"grep(pattern: string, path: string) - search files under a path for a pattern.\",\n\t\"Respond to every task with STRICT JSON only - no prose:\",\n\t'{\"tool\":\"grep\",\"arguments\":{\"pattern\":\"<pattern>\",\"path\":\"<path>\"}}',\n].join(\"\\n\");\n\nconst SEARCH_PROBE_TASKS: readonly string[] = [\n\t\"Where is the retry/backoff logic for HTTP requests implemented?\",\n\t\"Which files define the settings for background research?\",\n\t\"Find where session entries of type custom are appended.\",\n];\n\nconst TOOL_CALL_PROBE_TASKS: readonly string[] = [\n\t\"Find usages of the function resolveCliModel under src/.\",\n\t\"Search for the string 'budget_exhausted' in the core directory.\",\n\t\"Locate where LaneTracker is instantiated under src/core.\",\n];\n\nfunction parseSearchPlan(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst queries = (parsed as { queries?: unknown }).queries;\n\tif (!Array.isArray(queries) || queries.length === 0 || queries.length > 8) return false;\n\treturn queries.every(\n\t\t(query) =>\n\t\t\tquery &&\n\t\t\ttypeof query === \"object\" &&\n\t\t\ttypeof (query as { pattern?: unknown }).pattern === \"string\" &&\n\t\t\t(query as { pattern: string }).pattern.trim().length > 0,\n\t);\n}\n\nfunction parseToolCall(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst record = parsed as { tool?: unknown; arguments?: unknown };\n\tif (record.tool !== \"grep\") return false;\n\tconst args = record.arguments;\n\tif (!args || typeof args !== \"object\" || Array.isArray(args)) return false;\n\tconst pattern = (args as { pattern?: unknown }).pattern;\n\tconst path = (args as { path?: unknown }).path;\n\treturn (\n\t\ttypeof pattern === \"string\" && pattern.trim().length > 0 && typeof path === \"string\" && path.trim().length > 0\n\t);\n}\n\nfunction extractJsonObject(text: string): unknown | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(candidate);\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n\t\t} catch {\n\t\t\t// try next candidate\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction fitnessEnvelope(): CapabilityEnvelope {\n\treturn {\n\t\tid: \"model-fitness-probe\",\n\t\tcapabilities: [\"research\", \"read_files\", \"memory_read\"],\n\t\tmaxEstimatedUsd: 1,\n\t\tcreatedAt: new Date().toISOString(),\n\t};\n}\n\nexport async function runModelFitnessProbe(options: ModelFitnessOptions): Promise<ModelFitnessReport> {\n\tconst trials = Math.max(1, Math.min(options.trials ?? 3, 20));\n\tconst maxWallClockMs = options.maxWallClockMs ?? 120_000;\n\tconst judgePrompts = options.judgePrompts ?? DEFAULT_JUDGE_FITNESS_PROMPTS;\n\tconst now = options.now ?? Date.now;\n\tlet totalCostUsd = 0;\n\n\t// Token-speed instrumentation: the lane runners' own contracts carry text/cost only, so the\n\t// completer is wrapped once here and generation stats are accumulated per surface.\n\tconst overallSpeed = { tokens: 0, evalMs: 0 };\n\tlet surfaceSpeed = { tokens: 0, evalMs: 0 };\n\tconst complete: FitnessComplete = async (args) => {\n\t\tconst completion = await options.complete(args);\n\t\tconst tokens = completion.outputTokens ?? 0;\n\t\tconst evalMs = completion.evalMs ?? 0;\n\t\tif (tokens > 0 && evalMs > 0) {\n\t\t\tsurfaceSpeed.tokens += tokens;\n\t\t\tsurfaceSpeed.evalMs += evalMs;\n\t\t\toverallSpeed.tokens += tokens;\n\t\t\toverallSpeed.evalMs += evalMs;\n\t\t}\n\t\treturn completion;\n\t};\n\tconst takeSurfaceSpeed = (): number | undefined => {\n\t\tconst speed =\n\t\t\tsurfaceSpeed.evalMs > 0 ? Math.round((surfaceSpeed.tokens / surfaceSpeed.evalMs) * 1000) : undefined;\n\t\tsurfaceSpeed = { tokens: 0, evalMs: 0 };\n\t\treturn speed;\n\t};\n\n\tconst research: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst result = await runResearch({\n\t\t\tquery: `fitness:probe requirements:req-${i}`,\n\t\t\tcontext: [\n\t\t\t\t\"Goal: add a retry helper to the HTTP client module\",\n\t\t\t\t\"Open requirements:\",\n\t\t\t\t\"- Find what retry/backoff conventions the codebase already uses\",\n\t\t\t\t\"- Identify which call sites would adopt the helper\",\n\t\t\t].join(\"\\n\"),\n\t\t\tenvelope: fitnessEnvelope(),\n\t\t\tmaxUsd: 1,\n\t\t\tmaxSources: 8,\n\t\t\tmaxFindings: 5,\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tresearch.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tif (result.status === \"succeeded\") research.succeeded++;\n\t\tresearch.outcomes.push(`${result.status}/${result.reasonCode}`);\n\t}\n\tresearch.meanMs = Math.round(research.meanMs / trials);\n\tresearch.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst worker: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst outcome = await runWorker({\n\t\t\trequest: {\n\t\t\t\tid: `fitness-worker-${i}`,\n\t\t\t\tinstructions:\n\t\t\t\t\t\"Summarize in two sentences what a capability envelope is: a declared set of allowed tools, paths, and capability names that bounds what a delegated worker may do.\",\n\t\t\t\troute: { tier: \"cheap\", risk: \"read-only\", confidence: 1, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\t\tenvelope: { id: `fitness-env-${i}`, capabilities: [\"read_files\"], maxEstimatedUsd: 1 },\n\t\t\t\tmaxEstimatedUsd: 1,\n\t\t\t},\n\t\t\tmaxUsd: 1,\n\t\t\tmaxWallClockMs,\n\t\t\tusageReportId: `fitness:${i}`,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tworker.meanMs += now() - started;\n\t\ttotalCostUsd += outcome.costUsd;\n\t\tif (outcome.result.status === \"completed\" && outcome.accepted) worker.succeeded++;\n\t\tworker.outcomes.push(`${outcome.result.status}/${outcome.reasonCode}`);\n\t}\n\tworker.meanMs = Math.round(worker.meanMs / trials);\n\tworker.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst judge: JudgeFitnessScore = {\n\t\tparsed: 0,\n\t\tplanningElevated: 0,\n\t\tplanningTotal: judgePrompts.filter((entry) => entry.planning).length,\n\t\ttrivialCheap: 0,\n\t\ttrivialTotal: judgePrompts.filter((entry) => !entry.planning).length,\n\t\ttotal: judgePrompts.length,\n\t\toutcomes: [],\n\t\tmeanMs: 0,\n\t};\n\tfor (const entry of judgePrompts) {\n\t\tconst started = now();\n\t\tconst result = await runRouteJudge({\n\t\t\tprompt: entry.prompt,\n\t\t\tbaseline: { tier: \"cheap\", risk: \"read-only\", confidence: 0.5, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tjudge.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tconst tier = result.decision.tier;\n\t\tif (result.verdict) {\n\t\t\tjudge.parsed++;\n\t\t\t// A useful judge must both keep planning off the cheap tier AND actually send trivial\n\t\t\t// prompts there — all-medium verdicts are safe but save nothing.\n\t\t\tif (entry.planning && tier !== \"cheap\") judge.planningElevated++;\n\t\t\tif (!entry.planning && tier === \"cheap\") judge.trivialCheap++;\n\t\t}\n\t\tjudge.outcomes.push(\n\t\t\t`\"${entry.prompt.slice(0, 40)}\" -> ${tier}${result.fallbackReason ? ` (${result.fallbackReason})` : \"\"}`,\n\t\t);\n\t}\n\tjudge.meanMs = judgePrompts.length > 0 ? Math.round(judge.meanMs / judgePrompts.length) : 0;\n\tjudge.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst probeSurface = async (\n\t\tsystemPrompt: string,\n\t\ttasks: readonly string[],\n\t\taccepts: (text: string) => boolean,\n\t): Promise<LaneFitnessScore> => {\n\t\tconst score: LaneFitnessScore = { succeeded: 0, total: tasks.length, outcomes: [], meanMs: 0 };\n\t\tfor (const task of tasks) {\n\t\t\tconst started = now();\n\t\t\t// Same wall-clock envelope as the lane surfaces — a hung model must not hang the probe.\n\t\t\tconst bounded = await runBoundedCompletion({\n\t\t\t\tmaxWallClockMs,\n\t\t\t\tsignal: options.signal,\n\t\t\t\texecute: (signal) => complete({ systemPrompt, userPrompt: task, signal }),\n\t\t\t});\n\t\t\tif (bounded.completion) totalCostUsd += bounded.completion.costUsd;\n\t\t\tif (bounded.failure || !bounded.completion) {\n\t\t\t\tscore.outcomes.push(bounded.failure ? bounded.failure.status : \"completion_error\");\n\t\t\t} else {\n\t\t\t\tconst ok = accepts(bounded.completion.text);\n\t\t\t\tif (ok) score.succeeded++;\n\t\t\t\tscore.outcomes.push(ok ? \"ok\" : \"unparseable_output\");\n\t\t\t}\n\t\t\tscore.meanMs += now() - started;\n\t\t}\n\t\tscore.meanMs = tasks.length > 0 ? Math.round(score.meanMs / tasks.length) : 0;\n\t\treturn score;\n\t};\n\n\tconst search = await probeSurface(SEARCH_PROBE_SYSTEM_PROMPT, SEARCH_PROBE_TASKS, parseSearchPlan);\n\tsearch.tokensPerSecond = takeSurfaceSpeed();\n\tconst toolCall = await probeSurface(TOOL_CALL_PROBE_SYSTEM_PROMPT, TOOL_CALL_PROBE_TASKS, parseToolCall);\n\ttoolCall.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst tokensPerSecond =\n\t\toverallSpeed.evalMs > 0 ? Math.round((overallSpeed.tokens / overallSpeed.evalMs) * 1000) : undefined;\n\n\treturn { trials, tokensPerSecond, research, worker, judge, search, toolCall, totalCostUsd };\n}\n\n/** Compact human-readable report for tool output / interactive display. Bounded, no raw dumps. */\nexport function formatModelFitnessReport(model: string, report: ModelFitnessReport): string {\n\tconst speed = (tokensPerSecond: number | undefined) =>\n\t\ttokensPerSecond !== undefined ? `, ~${tokensPerSecond} tok/s` : \"\";\n\tconst lines = [\n\t\t`Model fitness: ${model} (${report.trials} trials/lane${speed(report.tokensPerSecond)})`,\n\t\t`- research lane: ${report.research.succeeded}/${report.research.total} succeeded, mean ${report.research.meanMs}ms${speed(report.research.tokensPerSecond)} [${report.research.outcomes.join(\", \")}]`,\n\t\t`- worker lane: ${report.worker.succeeded}/${report.worker.total} completed+accepted, mean ${report.worker.meanMs}ms${speed(report.worker.tokensPerSecond)} [${report.worker.outcomes.join(\", \")}]`,\n\t\t`- search plans: ${report.search.succeeded}/${report.search.total} well-formed, mean ${report.search.meanMs}ms${speed(report.search.tokensPerSecond)}`,\n\t\t`- tool calls: ${report.toolCall.succeeded}/${report.toolCall.total} well-formed, mean ${report.toolCall.meanMs}ms${speed(report.toolCall.tokensPerSecond)}`,\n\t\t`- route judge: parsed ${report.judge.parsed}/${report.judge.total}, planning-elevated ${report.judge.planningElevated}/${report.judge.planningTotal}, trivial-cheap ${report.judge.trivialCheap}/${report.judge.trivialTotal}, mean ${report.judge.meanMs}ms${speed(report.judge.tokensPerSecond)}`,\n\t\t...report.judge.outcomes.map((outcome) => ` ${outcome}`),\n\t];\n\tif (report.totalCostUsd > 0) {\n\t\tlines.push(`- probe cost: $${report.totalCostUsd.toFixed(4)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-fitness.d.ts","sourceRoot":"","sources":["../../../src/core/research/model-fitness.ts"],"names":[],"mappings":"AAOA;;;;;;GAMG;AAEH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,iGAAiG;IACjG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kGAAkG;IAClG,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEjC,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,qFAAqF;AACrF,eAAO,MAAM,6BAA6B,EAAE,SAAS,kBAAkB,EAOtE,CAAC;AAEF,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,eAAe,CAAC;IAC1B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,iBAAiB,CAAC;IACzB,8EAA8E;IAC9E,MAAM,EAAE,gBAAgB,CAAC;IACzB,yFAAyF;IACzF,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,qGAAqG;IACrG,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,yFAAyF;AACzF,eAAO,MAAM,0BAA0B,QAK3B,CAAC;AAEb,eAAO,MAAM,6BAA6B,QAK9B,CAAC;AASb,OAAO,EAAE,6BAA6B,IAAI,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AA6G1G,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkKpG;AAED,kGAAkG;AAClG,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAiB1F","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\nimport type { CapabilityEnvelope } from \"../autonomy/contracts.ts\";\nimport { CURATION_DIGEST_SYSTEM_PROMPT } from \"../context/brain-curator.ts\";\nimport { runWorker } from \"../delegation/worker-runner.ts\";\nimport { runRouteJudge } from \"../model-router/route-judge.ts\";\nimport { runResearch } from \"./research-runner.ts\";\n\n/**\n * Model fitness probe: measures whether a candidate model can actually drive the harness's\n * subagent contracts — the research lane, the scout-worker lane, and the routing judge — by\n * running each real runner against the model and scoring parse/success rates plus judge\n * discrimination. Provider-free: the completion executor is injected, so this works against any\n * registered model (local Ollama models included) and against faux providers in tests.\n */\n\nexport interface FitnessCompletion {\n\ttext: string;\n\tcostUsd: number;\n\tstopReason: string;\n\t/** Output tokens generated (for tok/s). Optional: providers that don't report it are skipped. */\n\toutputTokens?: number;\n\t/** Pure generation time in ms (e.g. Ollama eval_duration). Falls back to wall-clock if absent. */\n\tevalMs?: number;\n}\n\nexport type FitnessComplete = (args: {\n\tsystemPrompt: string;\n\tuserPrompt: string;\n\tsignal?: AbortSignal;\n}) => Promise<FitnessCompletion>;\n\nexport interface JudgeFitnessPrompt {\n\tprompt: string;\n\t/** True when the prompt is planning-shaped and must never route cheap. */\n\tplanning: boolean;\n}\n\n/** Default judge probe set: three planning-shaped prompts, three trivial lookups. */\nexport const DEFAULT_JUDGE_FITNESS_PROMPTS: readonly JudgeFitnessPrompt[] = [\n\t{ prompt: \"how should we plan the migration of the session storage layer?\", planning: true },\n\t{ prompt: \"design an approach for splitting the settings manager\", planning: true },\n\t{ prompt: \"draft a roadmap for the autonomy rework\", planning: true },\n\t{ prompt: \"what does the resolvePath function return?\", planning: false },\n\t{ prompt: \"list the files in the delegation module\", planning: false },\n\t{ prompt: \"why is this test flaky?\", planning: false },\n];\n\nexport interface ModelFitnessOptions {\n\tcomplete: FitnessComplete;\n\t/** Trials per lane surface. Default 3. */\n\ttrials?: number;\n\t/** Wall-clock budget per call in ms. Default 120000. */\n\tmaxWallClockMs?: number;\n\tjudgePrompts?: readonly JudgeFitnessPrompt[];\n\tsignal?: AbortSignal;\n\t/** Injected clock for latency measurement (test seam). Defaults to Date.now. */\n\tnow?: () => number;\n}\n\nexport interface LaneFitnessScore {\n\tsucceeded: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the surface's calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface JudgeFitnessScore {\n\tparsed: number;\n\tplanningElevated: number;\n\tplanningTotal: number;\n\ttrivialCheap: number;\n\ttrivialTotal: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the judge calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface ModelFitnessReport {\n\ttrials: number;\n\t/** Aggregate output tokens/second across ALL probe calls (the headline speed number). */\n\ttokensPerSecond?: number;\n\tresearch: LaneFitnessScore;\n\tworker: LaneFitnessScore;\n\tjudge: JudgeFitnessScore;\n\t/** Heavy-lifter surface: can the model formulate a structured search plan? */\n\tsearch: LaneFitnessScore;\n\t/** Heavy-lifter surface: can the model emit a well-formed tool call against a schema? */\n\ttoolCall: LaneFitnessScore;\n\t/** Curator surface: can the model digest a context chunk to strict JSON WITHOUT losing key facts? */\n\tdigest: LaneFitnessScore;\n\ttotalCostUsd: number;\n}\n\n/** Static prompts for the heavy-lifter surfaces (stable for provider prompt caching). */\nexport const SEARCH_PROBE_SYSTEM_PROMPT = [\n\t\"You plan code searches for a coding agent. You never answer the question yourself.\",\n\t\"Given a question about a codebase, respond with STRICT JSON only - no prose:\",\n\t'{\"queries\":[{\"pattern\":\"<regex or literal to grep>\",\"glob\":\"<file glob like **/*.ts>\"}]}',\n\t\"Return 1 to 4 queries, most specific first.\",\n].join(\"\\n\");\n\nexport const TOOL_CALL_PROBE_SYSTEM_PROMPT = [\n\t\"You operate tools for a coding agent. You have exactly one tool:\",\n\t\"grep(pattern: string, path: string) - search files under a path for a pattern.\",\n\t\"Respond to every task with STRICT JSON only - no prose:\",\n\t'{\"tool\":\"grep\",\"arguments\":{\"pattern\":\"<pattern>\",\"path\":\"<path>\"}}',\n].join(\"\\n\");\n\nconst SEARCH_PROBE_TASKS: readonly string[] = [\n\t\"Where is the retry/backoff logic for HTTP requests implemented?\",\n\t\"Which files define the settings for background research?\",\n\t\"Find where session entries of type custom are appended.\",\n];\n\n// The probe measures the REAL curation contract — same prompt the BrainCurator ships.\nexport { CURATION_DIGEST_SYSTEM_PROMPT as DIGEST_PROBE_SYSTEM_PROMPT } from \"../context/brain-curator.ts\";\n\n/**\n * Digest probe chunks each carry a NONCE identifier that cannot be guessed from the\n * instructions: acceptance requires the digest to RETAIN the nonce verbatim, so the score\n * measures extraction fidelity, not narration (a model cannot pass by paraphrasing).\n */\nconst DIGEST_PROBE_TASKS: readonly { chunk: string; nonce: string }[] = [\n\t{\n\t\tnonce: \"retryWithJitter_zx41\",\n\t\tchunk: [\n\t\t\t\"grep results for 'retry' under src/http:\",\n\t\t\t\"src/http/client.ts:88: export function retryWithJitter_zx41(fn, attempts = 3) {\",\n\t\t\t\"src/http/client.ts:112: // exponential backoff capped at 30s\",\n\t\t\t\"src/http/pool.ts:41: client.retry = false\",\n\t\t].join(\"\\n\"),\n\t},\n\t{\n\t\tnonce: \"ERR_QM_7734\",\n\t\tchunk: [\n\t\t\t\"$ npm run migrate\",\n\t\t\t\"migrating 14 files...\",\n\t\t\t\"error ERR_QM_7734: column 'owner_id' missing on table sessions (migration 0009)\",\n\t\t\t\"exit code 1\",\n\t\t].join(\"\\n\"),\n\t},\n\t{\n\t\tnonce: \"v3.9.2-hotfix.1\",\n\t\tchunk: [\n\t\t\t\"read package.json (34 lines):\",\n\t\t\t' \"name\": \"acme-billing\",',\n\t\t\t' \"version\": \"v3.9.2-hotfix.1\",',\n\t\t\t' \"engines\": { \"node\": \">=22\" },',\n\t\t].join(\"\\n\"),\n\t},\n];\n\nfunction parseDigest(text: string, nonce: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst digest = (parsed as { digest?: unknown }).digest;\n\tif (typeof digest !== \"string\") return false;\n\tconst trimmed = digest.trim();\n\t// Bounded and faithful: short enough to be a stub annotation, still carrying the nonce fact.\n\treturn trimmed.length > 0 && trimmed.length <= 240 && trimmed.includes(nonce);\n}\n\nconst TOOL_CALL_PROBE_TASKS: readonly string[] = [\n\t\"Find usages of the function resolveCliModel under src/.\",\n\t\"Search for the string 'budget_exhausted' in the core directory.\",\n\t\"Locate where LaneTracker is instantiated under src/core.\",\n];\n\nfunction parseSearchPlan(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst queries = (parsed as { queries?: unknown }).queries;\n\tif (!Array.isArray(queries) || queries.length === 0 || queries.length > 8) return false;\n\treturn queries.every(\n\t\t(query) =>\n\t\t\tquery &&\n\t\t\ttypeof query === \"object\" &&\n\t\t\ttypeof (query as { pattern?: unknown }).pattern === \"string\" &&\n\t\t\t(query as { pattern: string }).pattern.trim().length > 0,\n\t);\n}\n\nfunction parseToolCall(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst record = parsed as { tool?: unknown; arguments?: unknown };\n\tif (record.tool !== \"grep\") return false;\n\tconst args = record.arguments;\n\tif (!args || typeof args !== \"object\" || Array.isArray(args)) return false;\n\tconst pattern = (args as { pattern?: unknown }).pattern;\n\tconst path = (args as { path?: unknown }).path;\n\treturn (\n\t\ttypeof pattern === \"string\" && pattern.trim().length > 0 && typeof path === \"string\" && path.trim().length > 0\n\t);\n}\n\nfunction extractJsonObject(text: string): unknown | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(candidate);\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n\t\t} catch {\n\t\t\t// try next candidate\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction fitnessEnvelope(): CapabilityEnvelope {\n\treturn {\n\t\tid: \"model-fitness-probe\",\n\t\tcapabilities: [\"research\", \"read_files\", \"memory_read\"],\n\t\tmaxEstimatedUsd: 1,\n\t\tcreatedAt: new Date().toISOString(),\n\t};\n}\n\nexport async function runModelFitnessProbe(options: ModelFitnessOptions): Promise<ModelFitnessReport> {\n\tconst trials = Math.max(1, Math.min(options.trials ?? 3, 20));\n\tconst maxWallClockMs = options.maxWallClockMs ?? 120_000;\n\tconst judgePrompts = options.judgePrompts ?? DEFAULT_JUDGE_FITNESS_PROMPTS;\n\tconst now = options.now ?? Date.now;\n\tlet totalCostUsd = 0;\n\n\t// Token-speed instrumentation: the lane runners' own contracts carry text/cost only, so the\n\t// completer is wrapped once here and generation stats are accumulated per surface.\n\tconst overallSpeed = { tokens: 0, evalMs: 0 };\n\tlet surfaceSpeed = { tokens: 0, evalMs: 0 };\n\tconst complete: FitnessComplete = async (args) => {\n\t\tconst completion = await options.complete(args);\n\t\tconst tokens = completion.outputTokens ?? 0;\n\t\tconst evalMs = completion.evalMs ?? 0;\n\t\tif (tokens > 0 && evalMs > 0) {\n\t\t\tsurfaceSpeed.tokens += tokens;\n\t\t\tsurfaceSpeed.evalMs += evalMs;\n\t\t\toverallSpeed.tokens += tokens;\n\t\t\toverallSpeed.evalMs += evalMs;\n\t\t}\n\t\treturn completion;\n\t};\n\tconst takeSurfaceSpeed = (): number | undefined => {\n\t\tconst speed =\n\t\t\tsurfaceSpeed.evalMs > 0 ? Math.round((surfaceSpeed.tokens / surfaceSpeed.evalMs) * 1000) : undefined;\n\t\tsurfaceSpeed = { tokens: 0, evalMs: 0 };\n\t\treturn speed;\n\t};\n\n\tconst research: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst result = await runResearch({\n\t\t\tquery: `fitness:probe requirements:req-${i}`,\n\t\t\tcontext: [\n\t\t\t\t\"Goal: add a retry helper to the HTTP client module\",\n\t\t\t\t\"Open requirements:\",\n\t\t\t\t\"- Find what retry/backoff conventions the codebase already uses\",\n\t\t\t\t\"- Identify which call sites would adopt the helper\",\n\t\t\t].join(\"\\n\"),\n\t\t\tenvelope: fitnessEnvelope(),\n\t\t\tmaxUsd: 1,\n\t\t\tmaxSources: 8,\n\t\t\tmaxFindings: 5,\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tresearch.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tif (result.status === \"succeeded\") research.succeeded++;\n\t\tresearch.outcomes.push(`${result.status}/${result.reasonCode}`);\n\t}\n\tresearch.meanMs = Math.round(research.meanMs / trials);\n\tresearch.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst worker: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst outcome = await runWorker({\n\t\t\trequest: {\n\t\t\t\tid: `fitness-worker-${i}`,\n\t\t\t\tinstructions:\n\t\t\t\t\t\"Summarize in two sentences what a capability envelope is: a declared set of allowed tools, paths, and capability names that bounds what a delegated worker may do.\",\n\t\t\t\troute: { tier: \"cheap\", risk: \"read-only\", confidence: 1, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\t\tenvelope: { id: `fitness-env-${i}`, capabilities: [\"read_files\"], maxEstimatedUsd: 1 },\n\t\t\t\tmaxEstimatedUsd: 1,\n\t\t\t},\n\t\t\tmaxUsd: 1,\n\t\t\tmaxWallClockMs,\n\t\t\tusageReportId: `fitness:${i}`,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tworker.meanMs += now() - started;\n\t\ttotalCostUsd += outcome.costUsd;\n\t\tif (outcome.result.status === \"completed\" && outcome.accepted) worker.succeeded++;\n\t\tworker.outcomes.push(`${outcome.result.status}/${outcome.reasonCode}`);\n\t}\n\tworker.meanMs = Math.round(worker.meanMs / trials);\n\tworker.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst judge: JudgeFitnessScore = {\n\t\tparsed: 0,\n\t\tplanningElevated: 0,\n\t\tplanningTotal: judgePrompts.filter((entry) => entry.planning).length,\n\t\ttrivialCheap: 0,\n\t\ttrivialTotal: judgePrompts.filter((entry) => !entry.planning).length,\n\t\ttotal: judgePrompts.length,\n\t\toutcomes: [],\n\t\tmeanMs: 0,\n\t};\n\tfor (const entry of judgePrompts) {\n\t\tconst started = now();\n\t\tconst result = await runRouteJudge({\n\t\t\tprompt: entry.prompt,\n\t\t\tbaseline: { tier: \"cheap\", risk: \"read-only\", confidence: 0.5, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tjudge.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tconst tier = result.decision.tier;\n\t\tif (result.verdict) {\n\t\t\tjudge.parsed++;\n\t\t\t// A useful judge must both keep planning off the cheap tier AND actually send trivial\n\t\t\t// prompts there — all-medium verdicts are safe but save nothing.\n\t\t\tif (entry.planning && tier !== \"cheap\") judge.planningElevated++;\n\t\t\tif (!entry.planning && tier === \"cheap\") judge.trivialCheap++;\n\t\t}\n\t\tjudge.outcomes.push(\n\t\t\t`\"${entry.prompt.slice(0, 40)}\" -> ${tier}${result.fallbackReason ? ` (${result.fallbackReason})` : \"\"}`,\n\t\t);\n\t}\n\tjudge.meanMs = judgePrompts.length > 0 ? Math.round(judge.meanMs / judgePrompts.length) : 0;\n\tjudge.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst probeSurface = async (\n\t\tsystemPrompt: string,\n\t\ttasks: readonly string[],\n\t\taccepts: (text: string, taskIndex: number) => boolean,\n\t): Promise<LaneFitnessScore> => {\n\t\tconst score: LaneFitnessScore = { succeeded: 0, total: tasks.length, outcomes: [], meanMs: 0 };\n\t\tfor (const [taskIndex, task] of tasks.entries()) {\n\t\t\tconst started = now();\n\t\t\t// Same wall-clock envelope as the lane surfaces — a hung model must not hang the probe.\n\t\t\tconst bounded = await runBoundedCompletion({\n\t\t\t\tmaxWallClockMs,\n\t\t\t\tsignal: options.signal,\n\t\t\t\texecute: (signal) => complete({ systemPrompt, userPrompt: task, signal }),\n\t\t\t});\n\t\t\tif (bounded.completion) totalCostUsd += bounded.completion.costUsd;\n\t\t\tif (bounded.failure || !bounded.completion) {\n\t\t\t\tscore.outcomes.push(bounded.failure ? bounded.failure.status : \"completion_error\");\n\t\t\t} else {\n\t\t\t\tconst ok = accepts(bounded.completion.text, taskIndex);\n\t\t\t\tif (ok) score.succeeded++;\n\t\t\t\tscore.outcomes.push(ok ? \"ok\" : \"unparseable_output\");\n\t\t\t}\n\t\t\tscore.meanMs += now() - started;\n\t\t}\n\t\tscore.meanMs = tasks.length > 0 ? Math.round(score.meanMs / tasks.length) : 0;\n\t\treturn score;\n\t};\n\n\tconst search = await probeSurface(SEARCH_PROBE_SYSTEM_PROMPT, SEARCH_PROBE_TASKS, parseSearchPlan);\n\tsearch.tokensPerSecond = takeSurfaceSpeed();\n\tconst toolCall = await probeSurface(TOOL_CALL_PROBE_SYSTEM_PROMPT, TOOL_CALL_PROBE_TASKS, parseToolCall);\n\ttoolCall.tokensPerSecond = takeSurfaceSpeed();\n\tconst digest = await probeSurface(\n\t\tCURATION_DIGEST_SYSTEM_PROMPT,\n\t\tDIGEST_PROBE_TASKS.map((task) => task.chunk),\n\t\t(text, taskIndex) => parseDigest(text, DIGEST_PROBE_TASKS[taskIndex]!.nonce),\n\t);\n\tdigest.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst tokensPerSecond =\n\t\toverallSpeed.evalMs > 0 ? Math.round((overallSpeed.tokens / overallSpeed.evalMs) * 1000) : undefined;\n\n\treturn { trials, tokensPerSecond, research, worker, judge, search, toolCall, digest, totalCostUsd };\n}\n\n/** Compact human-readable report for tool output / interactive display. Bounded, no raw dumps. */\nexport function formatModelFitnessReport(model: string, report: ModelFitnessReport): string {\n\tconst speed = (tokensPerSecond: number | undefined) =>\n\t\ttokensPerSecond !== undefined ? `, ~${tokensPerSecond} tok/s` : \"\";\n\tconst lines = [\n\t\t`Model fitness: ${model} (${report.trials} trials/lane${speed(report.tokensPerSecond)})`,\n\t\t`- research lane: ${report.research.succeeded}/${report.research.total} succeeded, mean ${report.research.meanMs}ms${speed(report.research.tokensPerSecond)} [${report.research.outcomes.join(\", \")}]`,\n\t\t`- worker lane: ${report.worker.succeeded}/${report.worker.total} completed+accepted, mean ${report.worker.meanMs}ms${speed(report.worker.tokensPerSecond)} [${report.worker.outcomes.join(\", \")}]`,\n\t\t`- search plans: ${report.search.succeeded}/${report.search.total} well-formed, mean ${report.search.meanMs}ms${speed(report.search.tokensPerSecond)}`,\n\t\t`- tool calls: ${report.toolCall.succeeded}/${report.toolCall.total} well-formed, mean ${report.toolCall.meanMs}ms${speed(report.toolCall.tokensPerSecond)}`,\n\t\t`- digests: ${report.digest.succeeded}/${report.digest.total} faithful, mean ${report.digest.meanMs}ms${speed(report.digest.tokensPerSecond)}`,\n\t\t`- route judge: parsed ${report.judge.parsed}/${report.judge.total}, planning-elevated ${report.judge.planningElevated}/${report.judge.planningTotal}, trivial-cheap ${report.judge.trivialCheap}/${report.judge.trivialTotal}, mean ${report.judge.meanMs}ms${speed(report.judge.tokensPerSecond)}`,\n\t\t...report.judge.outcomes.map((outcome) => ` ${outcome}`),\n\t];\n\tif (report.totalCostUsd > 0) {\n\t\tlines.push(`- probe cost: $${report.totalCostUsd.toFixed(4)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { runBoundedCompletion } from "../autonomy/bounded-completion.js";
|
|
2
|
+
import { CURATION_DIGEST_SYSTEM_PROMPT } from "../context/brain-curator.js";
|
|
2
3
|
import { runWorker } from "../delegation/worker-runner.js";
|
|
3
4
|
import { runRouteJudge } from "../model-router/route-judge.js";
|
|
4
5
|
import { runResearch } from "./research-runner.js";
|
|
@@ -29,6 +30,53 @@ const SEARCH_PROBE_TASKS = [
|
|
|
29
30
|
"Which files define the settings for background research?",
|
|
30
31
|
"Find where session entries of type custom are appended.",
|
|
31
32
|
];
|
|
33
|
+
// The probe measures the REAL curation contract — same prompt the BrainCurator ships.
|
|
34
|
+
export { CURATION_DIGEST_SYSTEM_PROMPT as DIGEST_PROBE_SYSTEM_PROMPT } from "../context/brain-curator.js";
|
|
35
|
+
/**
|
|
36
|
+
* Digest probe chunks each carry a NONCE identifier that cannot be guessed from the
|
|
37
|
+
* instructions: acceptance requires the digest to RETAIN the nonce verbatim, so the score
|
|
38
|
+
* measures extraction fidelity, not narration (a model cannot pass by paraphrasing).
|
|
39
|
+
*/
|
|
40
|
+
const DIGEST_PROBE_TASKS = [
|
|
41
|
+
{
|
|
42
|
+
nonce: "retryWithJitter_zx41",
|
|
43
|
+
chunk: [
|
|
44
|
+
"grep results for 'retry' under src/http:",
|
|
45
|
+
"src/http/client.ts:88: export function retryWithJitter_zx41(fn, attempts = 3) {",
|
|
46
|
+
"src/http/client.ts:112: // exponential backoff capped at 30s",
|
|
47
|
+
"src/http/pool.ts:41: client.retry = false",
|
|
48
|
+
].join("\n"),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
nonce: "ERR_QM_7734",
|
|
52
|
+
chunk: [
|
|
53
|
+
"$ npm run migrate",
|
|
54
|
+
"migrating 14 files...",
|
|
55
|
+
"error ERR_QM_7734: column 'owner_id' missing on table sessions (migration 0009)",
|
|
56
|
+
"exit code 1",
|
|
57
|
+
].join("\n"),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
nonce: "v3.9.2-hotfix.1",
|
|
61
|
+
chunk: [
|
|
62
|
+
"read package.json (34 lines):",
|
|
63
|
+
' "name": "acme-billing",',
|
|
64
|
+
' "version": "v3.9.2-hotfix.1",',
|
|
65
|
+
' "engines": { "node": ">=22" },',
|
|
66
|
+
].join("\n"),
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
function parseDigest(text, nonce) {
|
|
70
|
+
const parsed = extractJsonObject(text);
|
|
71
|
+
if (!parsed)
|
|
72
|
+
return false;
|
|
73
|
+
const digest = parsed.digest;
|
|
74
|
+
if (typeof digest !== "string")
|
|
75
|
+
return false;
|
|
76
|
+
const trimmed = digest.trim();
|
|
77
|
+
// Bounded and faithful: short enough to be a stub annotation, still carrying the nonce fact.
|
|
78
|
+
return trimmed.length > 0 && trimmed.length <= 240 && trimmed.includes(nonce);
|
|
79
|
+
}
|
|
32
80
|
const TOOL_CALL_PROBE_TASKS = [
|
|
33
81
|
"Find usages of the function resolveCliModel under src/.",
|
|
34
82
|
"Search for the string 'budget_exhausted' in the core directory.",
|
|
@@ -206,7 +254,7 @@ export async function runModelFitnessProbe(options) {
|
|
|
206
254
|
judge.tokensPerSecond = takeSurfaceSpeed();
|
|
207
255
|
const probeSurface = async (systemPrompt, tasks, accepts) => {
|
|
208
256
|
const score = { succeeded: 0, total: tasks.length, outcomes: [], meanMs: 0 };
|
|
209
|
-
for (const task of tasks) {
|
|
257
|
+
for (const [taskIndex, task] of tasks.entries()) {
|
|
210
258
|
const started = now();
|
|
211
259
|
// Same wall-clock envelope as the lane surfaces — a hung model must not hang the probe.
|
|
212
260
|
const bounded = await runBoundedCompletion({
|
|
@@ -220,7 +268,7 @@ export async function runModelFitnessProbe(options) {
|
|
|
220
268
|
score.outcomes.push(bounded.failure ? bounded.failure.status : "completion_error");
|
|
221
269
|
}
|
|
222
270
|
else {
|
|
223
|
-
const ok = accepts(bounded.completion.text);
|
|
271
|
+
const ok = accepts(bounded.completion.text, taskIndex);
|
|
224
272
|
if (ok)
|
|
225
273
|
score.succeeded++;
|
|
226
274
|
score.outcomes.push(ok ? "ok" : "unparseable_output");
|
|
@@ -234,8 +282,10 @@ export async function runModelFitnessProbe(options) {
|
|
|
234
282
|
search.tokensPerSecond = takeSurfaceSpeed();
|
|
235
283
|
const toolCall = await probeSurface(TOOL_CALL_PROBE_SYSTEM_PROMPT, TOOL_CALL_PROBE_TASKS, parseToolCall);
|
|
236
284
|
toolCall.tokensPerSecond = takeSurfaceSpeed();
|
|
285
|
+
const digest = await probeSurface(CURATION_DIGEST_SYSTEM_PROMPT, DIGEST_PROBE_TASKS.map((task) => task.chunk), (text, taskIndex) => parseDigest(text, DIGEST_PROBE_TASKS[taskIndex].nonce));
|
|
286
|
+
digest.tokensPerSecond = takeSurfaceSpeed();
|
|
237
287
|
const tokensPerSecond = overallSpeed.evalMs > 0 ? Math.round((overallSpeed.tokens / overallSpeed.evalMs) * 1000) : undefined;
|
|
238
|
-
return { trials, tokensPerSecond, research, worker, judge, search, toolCall, totalCostUsd };
|
|
288
|
+
return { trials, tokensPerSecond, research, worker, judge, search, toolCall, digest, totalCostUsd };
|
|
239
289
|
}
|
|
240
290
|
/** Compact human-readable report for tool output / interactive display. Bounded, no raw dumps. */
|
|
241
291
|
export function formatModelFitnessReport(model, report) {
|
|
@@ -246,6 +296,7 @@ export function formatModelFitnessReport(model, report) {
|
|
|
246
296
|
`- worker lane: ${report.worker.succeeded}/${report.worker.total} completed+accepted, mean ${report.worker.meanMs}ms${speed(report.worker.tokensPerSecond)} [${report.worker.outcomes.join(", ")}]`,
|
|
247
297
|
`- search plans: ${report.search.succeeded}/${report.search.total} well-formed, mean ${report.search.meanMs}ms${speed(report.search.tokensPerSecond)}`,
|
|
248
298
|
`- tool calls: ${report.toolCall.succeeded}/${report.toolCall.total} well-formed, mean ${report.toolCall.meanMs}ms${speed(report.toolCall.tokensPerSecond)}`,
|
|
299
|
+
`- digests: ${report.digest.succeeded}/${report.digest.total} faithful, mean ${report.digest.meanMs}ms${speed(report.digest.tokensPerSecond)}`,
|
|
249
300
|
`- route judge: parsed ${report.judge.parsed}/${report.judge.total}, planning-elevated ${report.judge.planningElevated}/${report.judge.planningTotal}, trivial-cheap ${report.judge.trivialCheap}/${report.judge.trivialTotal}, mean ${report.judge.meanMs}ms${speed(report.judge.tokensPerSecond)}`,
|
|
250
301
|
...report.judge.outcomes.map((outcome) => ` ${outcome}`),
|
|
251
302
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-fitness.js","sourceRoot":"","sources":["../../../src/core/research/model-fitness.ts"],"names":[],"mappings":"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","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\nimport type { CapabilityEnvelope } from \"../autonomy/contracts.ts\";\nimport { runWorker } from \"../delegation/worker-runner.ts\";\nimport { runRouteJudge } from \"../model-router/route-judge.ts\";\nimport { runResearch } from \"./research-runner.ts\";\n\n/**\n * Model fitness probe: measures whether a candidate model can actually drive the harness's\n * subagent contracts — the research lane, the scout-worker lane, and the routing judge — by\n * running each real runner against the model and scoring parse/success rates plus judge\n * discrimination. Provider-free: the completion executor is injected, so this works against any\n * registered model (local Ollama models included) and against faux providers in tests.\n */\n\nexport interface FitnessCompletion {\n\ttext: string;\n\tcostUsd: number;\n\tstopReason: string;\n\t/** Output tokens generated (for tok/s). Optional: providers that don't report it are skipped. */\n\toutputTokens?: number;\n\t/** Pure generation time in ms (e.g. Ollama eval_duration). Falls back to wall-clock if absent. */\n\tevalMs?: number;\n}\n\nexport type FitnessComplete = (args: {\n\tsystemPrompt: string;\n\tuserPrompt: string;\n\tsignal?: AbortSignal;\n}) => Promise<FitnessCompletion>;\n\nexport interface JudgeFitnessPrompt {\n\tprompt: string;\n\t/** True when the prompt is planning-shaped and must never route cheap. */\n\tplanning: boolean;\n}\n\n/** Default judge probe set: three planning-shaped prompts, three trivial lookups. */\nexport const DEFAULT_JUDGE_FITNESS_PROMPTS: readonly JudgeFitnessPrompt[] = [\n\t{ prompt: \"how should we plan the migration of the session storage layer?\", planning: true },\n\t{ prompt: \"design an approach for splitting the settings manager\", planning: true },\n\t{ prompt: \"draft a roadmap for the autonomy rework\", planning: true },\n\t{ prompt: \"what does the resolvePath function return?\", planning: false },\n\t{ prompt: \"list the files in the delegation module\", planning: false },\n\t{ prompt: \"why is this test flaky?\", planning: false },\n];\n\nexport interface ModelFitnessOptions {\n\tcomplete: FitnessComplete;\n\t/** Trials per lane surface. Default 3. */\n\ttrials?: number;\n\t/** Wall-clock budget per call in ms. Default 120000. */\n\tmaxWallClockMs?: number;\n\tjudgePrompts?: readonly JudgeFitnessPrompt[];\n\tsignal?: AbortSignal;\n\t/** Injected clock for latency measurement (test seam). Defaults to Date.now. */\n\tnow?: () => number;\n}\n\nexport interface LaneFitnessScore {\n\tsucceeded: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the surface's calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface JudgeFitnessScore {\n\tparsed: number;\n\tplanningElevated: number;\n\tplanningTotal: number;\n\ttrivialCheap: number;\n\ttrivialTotal: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the judge calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface ModelFitnessReport {\n\ttrials: number;\n\t/** Aggregate output tokens/second across ALL probe calls (the headline speed number). */\n\ttokensPerSecond?: number;\n\tresearch: LaneFitnessScore;\n\tworker: LaneFitnessScore;\n\tjudge: JudgeFitnessScore;\n\t/** Heavy-lifter surface: can the model formulate a structured search plan? */\n\tsearch: LaneFitnessScore;\n\t/** Heavy-lifter surface: can the model emit a well-formed tool call against a schema? */\n\ttoolCall: LaneFitnessScore;\n\ttotalCostUsd: number;\n}\n\n/** Static prompts for the heavy-lifter surfaces (stable for provider prompt caching). */\nexport const SEARCH_PROBE_SYSTEM_PROMPT = [\n\t\"You plan code searches for a coding agent. You never answer the question yourself.\",\n\t\"Given a question about a codebase, respond with STRICT JSON only - no prose:\",\n\t'{\"queries\":[{\"pattern\":\"<regex or literal to grep>\",\"glob\":\"<file glob like **/*.ts>\"}]}',\n\t\"Return 1 to 4 queries, most specific first.\",\n].join(\"\\n\");\n\nexport const TOOL_CALL_PROBE_SYSTEM_PROMPT = [\n\t\"You operate tools for a coding agent. You have exactly one tool:\",\n\t\"grep(pattern: string, path: string) - search files under a path for a pattern.\",\n\t\"Respond to every task with STRICT JSON only - no prose:\",\n\t'{\"tool\":\"grep\",\"arguments\":{\"pattern\":\"<pattern>\",\"path\":\"<path>\"}}',\n].join(\"\\n\");\n\nconst SEARCH_PROBE_TASKS: readonly string[] = [\n\t\"Where is the retry/backoff logic for HTTP requests implemented?\",\n\t\"Which files define the settings for background research?\",\n\t\"Find where session entries of type custom are appended.\",\n];\n\nconst TOOL_CALL_PROBE_TASKS: readonly string[] = [\n\t\"Find usages of the function resolveCliModel under src/.\",\n\t\"Search for the string 'budget_exhausted' in the core directory.\",\n\t\"Locate where LaneTracker is instantiated under src/core.\",\n];\n\nfunction parseSearchPlan(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst queries = (parsed as { queries?: unknown }).queries;\n\tif (!Array.isArray(queries) || queries.length === 0 || queries.length > 8) return false;\n\treturn queries.every(\n\t\t(query) =>\n\t\t\tquery &&\n\t\t\ttypeof query === \"object\" &&\n\t\t\ttypeof (query as { pattern?: unknown }).pattern === \"string\" &&\n\t\t\t(query as { pattern: string }).pattern.trim().length > 0,\n\t);\n}\n\nfunction parseToolCall(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst record = parsed as { tool?: unknown; arguments?: unknown };\n\tif (record.tool !== \"grep\") return false;\n\tconst args = record.arguments;\n\tif (!args || typeof args !== \"object\" || Array.isArray(args)) return false;\n\tconst pattern = (args as { pattern?: unknown }).pattern;\n\tconst path = (args as { path?: unknown }).path;\n\treturn (\n\t\ttypeof pattern === \"string\" && pattern.trim().length > 0 && typeof path === \"string\" && path.trim().length > 0\n\t);\n}\n\nfunction extractJsonObject(text: string): unknown | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(candidate);\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n\t\t} catch {\n\t\t\t// try next candidate\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction fitnessEnvelope(): CapabilityEnvelope {\n\treturn {\n\t\tid: \"model-fitness-probe\",\n\t\tcapabilities: [\"research\", \"read_files\", \"memory_read\"],\n\t\tmaxEstimatedUsd: 1,\n\t\tcreatedAt: new Date().toISOString(),\n\t};\n}\n\nexport async function runModelFitnessProbe(options: ModelFitnessOptions): Promise<ModelFitnessReport> {\n\tconst trials = Math.max(1, Math.min(options.trials ?? 3, 20));\n\tconst maxWallClockMs = options.maxWallClockMs ?? 120_000;\n\tconst judgePrompts = options.judgePrompts ?? DEFAULT_JUDGE_FITNESS_PROMPTS;\n\tconst now = options.now ?? Date.now;\n\tlet totalCostUsd = 0;\n\n\t// Token-speed instrumentation: the lane runners' own contracts carry text/cost only, so the\n\t// completer is wrapped once here and generation stats are accumulated per surface.\n\tconst overallSpeed = { tokens: 0, evalMs: 0 };\n\tlet surfaceSpeed = { tokens: 0, evalMs: 0 };\n\tconst complete: FitnessComplete = async (args) => {\n\t\tconst completion = await options.complete(args);\n\t\tconst tokens = completion.outputTokens ?? 0;\n\t\tconst evalMs = completion.evalMs ?? 0;\n\t\tif (tokens > 0 && evalMs > 0) {\n\t\t\tsurfaceSpeed.tokens += tokens;\n\t\t\tsurfaceSpeed.evalMs += evalMs;\n\t\t\toverallSpeed.tokens += tokens;\n\t\t\toverallSpeed.evalMs += evalMs;\n\t\t}\n\t\treturn completion;\n\t};\n\tconst takeSurfaceSpeed = (): number | undefined => {\n\t\tconst speed =\n\t\t\tsurfaceSpeed.evalMs > 0 ? Math.round((surfaceSpeed.tokens / surfaceSpeed.evalMs) * 1000) : undefined;\n\t\tsurfaceSpeed = { tokens: 0, evalMs: 0 };\n\t\treturn speed;\n\t};\n\n\tconst research: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst result = await runResearch({\n\t\t\tquery: `fitness:probe requirements:req-${i}`,\n\t\t\tcontext: [\n\t\t\t\t\"Goal: add a retry helper to the HTTP client module\",\n\t\t\t\t\"Open requirements:\",\n\t\t\t\t\"- Find what retry/backoff conventions the codebase already uses\",\n\t\t\t\t\"- Identify which call sites would adopt the helper\",\n\t\t\t].join(\"\\n\"),\n\t\t\tenvelope: fitnessEnvelope(),\n\t\t\tmaxUsd: 1,\n\t\t\tmaxSources: 8,\n\t\t\tmaxFindings: 5,\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tresearch.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tif (result.status === \"succeeded\") research.succeeded++;\n\t\tresearch.outcomes.push(`${result.status}/${result.reasonCode}`);\n\t}\n\tresearch.meanMs = Math.round(research.meanMs / trials);\n\tresearch.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst worker: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst outcome = await runWorker({\n\t\t\trequest: {\n\t\t\t\tid: `fitness-worker-${i}`,\n\t\t\t\tinstructions:\n\t\t\t\t\t\"Summarize in two sentences what a capability envelope is: a declared set of allowed tools, paths, and capability names that bounds what a delegated worker may do.\",\n\t\t\t\troute: { tier: \"cheap\", risk: \"read-only\", confidence: 1, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\t\tenvelope: { id: `fitness-env-${i}`, capabilities: [\"read_files\"], maxEstimatedUsd: 1 },\n\t\t\t\tmaxEstimatedUsd: 1,\n\t\t\t},\n\t\t\tmaxUsd: 1,\n\t\t\tmaxWallClockMs,\n\t\t\tusageReportId: `fitness:${i}`,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tworker.meanMs += now() - started;\n\t\ttotalCostUsd += outcome.costUsd;\n\t\tif (outcome.result.status === \"completed\" && outcome.accepted) worker.succeeded++;\n\t\tworker.outcomes.push(`${outcome.result.status}/${outcome.reasonCode}`);\n\t}\n\tworker.meanMs = Math.round(worker.meanMs / trials);\n\tworker.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst judge: JudgeFitnessScore = {\n\t\tparsed: 0,\n\t\tplanningElevated: 0,\n\t\tplanningTotal: judgePrompts.filter((entry) => entry.planning).length,\n\t\ttrivialCheap: 0,\n\t\ttrivialTotal: judgePrompts.filter((entry) => !entry.planning).length,\n\t\ttotal: judgePrompts.length,\n\t\toutcomes: [],\n\t\tmeanMs: 0,\n\t};\n\tfor (const entry of judgePrompts) {\n\t\tconst started = now();\n\t\tconst result = await runRouteJudge({\n\t\t\tprompt: entry.prompt,\n\t\t\tbaseline: { tier: \"cheap\", risk: \"read-only\", confidence: 0.5, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tjudge.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tconst tier = result.decision.tier;\n\t\tif (result.verdict) {\n\t\t\tjudge.parsed++;\n\t\t\t// A useful judge must both keep planning off the cheap tier AND actually send trivial\n\t\t\t// prompts there — all-medium verdicts are safe but save nothing.\n\t\t\tif (entry.planning && tier !== \"cheap\") judge.planningElevated++;\n\t\t\tif (!entry.planning && tier === \"cheap\") judge.trivialCheap++;\n\t\t}\n\t\tjudge.outcomes.push(\n\t\t\t`\"${entry.prompt.slice(0, 40)}\" -> ${tier}${result.fallbackReason ? ` (${result.fallbackReason})` : \"\"}`,\n\t\t);\n\t}\n\tjudge.meanMs = judgePrompts.length > 0 ? Math.round(judge.meanMs / judgePrompts.length) : 0;\n\tjudge.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst probeSurface = async (\n\t\tsystemPrompt: string,\n\t\ttasks: readonly string[],\n\t\taccepts: (text: string) => boolean,\n\t): Promise<LaneFitnessScore> => {\n\t\tconst score: LaneFitnessScore = { succeeded: 0, total: tasks.length, outcomes: [], meanMs: 0 };\n\t\tfor (const task of tasks) {\n\t\t\tconst started = now();\n\t\t\t// Same wall-clock envelope as the lane surfaces — a hung model must not hang the probe.\n\t\t\tconst bounded = await runBoundedCompletion({\n\t\t\t\tmaxWallClockMs,\n\t\t\t\tsignal: options.signal,\n\t\t\t\texecute: (signal) => complete({ systemPrompt, userPrompt: task, signal }),\n\t\t\t});\n\t\t\tif (bounded.completion) totalCostUsd += bounded.completion.costUsd;\n\t\t\tif (bounded.failure || !bounded.completion) {\n\t\t\t\tscore.outcomes.push(bounded.failure ? bounded.failure.status : \"completion_error\");\n\t\t\t} else {\n\t\t\t\tconst ok = accepts(bounded.completion.text);\n\t\t\t\tif (ok) score.succeeded++;\n\t\t\t\tscore.outcomes.push(ok ? \"ok\" : \"unparseable_output\");\n\t\t\t}\n\t\t\tscore.meanMs += now() - started;\n\t\t}\n\t\tscore.meanMs = tasks.length > 0 ? Math.round(score.meanMs / tasks.length) : 0;\n\t\treturn score;\n\t};\n\n\tconst search = await probeSurface(SEARCH_PROBE_SYSTEM_PROMPT, SEARCH_PROBE_TASKS, parseSearchPlan);\n\tsearch.tokensPerSecond = takeSurfaceSpeed();\n\tconst toolCall = await probeSurface(TOOL_CALL_PROBE_SYSTEM_PROMPT, TOOL_CALL_PROBE_TASKS, parseToolCall);\n\ttoolCall.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst tokensPerSecond =\n\t\toverallSpeed.evalMs > 0 ? Math.round((overallSpeed.tokens / overallSpeed.evalMs) * 1000) : undefined;\n\n\treturn { trials, tokensPerSecond, research, worker, judge, search, toolCall, totalCostUsd };\n}\n\n/** Compact human-readable report for tool output / interactive display. Bounded, no raw dumps. */\nexport function formatModelFitnessReport(model: string, report: ModelFitnessReport): string {\n\tconst speed = (tokensPerSecond: number | undefined) =>\n\t\ttokensPerSecond !== undefined ? `, ~${tokensPerSecond} tok/s` : \"\";\n\tconst lines = [\n\t\t`Model fitness: ${model} (${report.trials} trials/lane${speed(report.tokensPerSecond)})`,\n\t\t`- research lane: ${report.research.succeeded}/${report.research.total} succeeded, mean ${report.research.meanMs}ms${speed(report.research.tokensPerSecond)} [${report.research.outcomes.join(\", \")}]`,\n\t\t`- worker lane: ${report.worker.succeeded}/${report.worker.total} completed+accepted, mean ${report.worker.meanMs}ms${speed(report.worker.tokensPerSecond)} [${report.worker.outcomes.join(\", \")}]`,\n\t\t`- search plans: ${report.search.succeeded}/${report.search.total} well-formed, mean ${report.search.meanMs}ms${speed(report.search.tokensPerSecond)}`,\n\t\t`- tool calls: ${report.toolCall.succeeded}/${report.toolCall.total} well-formed, mean ${report.toolCall.meanMs}ms${speed(report.toolCall.tokensPerSecond)}`,\n\t\t`- route judge: parsed ${report.judge.parsed}/${report.judge.total}, planning-elevated ${report.judge.planningElevated}/${report.judge.planningTotal}, trivial-cheap ${report.judge.trivialCheap}/${report.judge.trivialTotal}, mean ${report.judge.meanMs}ms${speed(report.judge.tokensPerSecond)}`,\n\t\t...report.judge.outcomes.map((outcome) => ` ${outcome}`),\n\t];\n\tif (report.totalCostUsd > 0) {\n\t\tlines.push(`- probe cost: $${report.totalCostUsd.toFixed(4)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-fitness.js","sourceRoot":"","sources":["../../../src/core/research/model-fitness.ts"],"names":[],"mappings":"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","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\nimport type { CapabilityEnvelope } from \"../autonomy/contracts.ts\";\nimport { CURATION_DIGEST_SYSTEM_PROMPT } from \"../context/brain-curator.ts\";\nimport { runWorker } from \"../delegation/worker-runner.ts\";\nimport { runRouteJudge } from \"../model-router/route-judge.ts\";\nimport { runResearch } from \"./research-runner.ts\";\n\n/**\n * Model fitness probe: measures whether a candidate model can actually drive the harness's\n * subagent contracts — the research lane, the scout-worker lane, and the routing judge — by\n * running each real runner against the model and scoring parse/success rates plus judge\n * discrimination. Provider-free: the completion executor is injected, so this works against any\n * registered model (local Ollama models included) and against faux providers in tests.\n */\n\nexport interface FitnessCompletion {\n\ttext: string;\n\tcostUsd: number;\n\tstopReason: string;\n\t/** Output tokens generated (for tok/s). Optional: providers that don't report it are skipped. */\n\toutputTokens?: number;\n\t/** Pure generation time in ms (e.g. Ollama eval_duration). Falls back to wall-clock if absent. */\n\tevalMs?: number;\n}\n\nexport type FitnessComplete = (args: {\n\tsystemPrompt: string;\n\tuserPrompt: string;\n\tsignal?: AbortSignal;\n}) => Promise<FitnessCompletion>;\n\nexport interface JudgeFitnessPrompt {\n\tprompt: string;\n\t/** True when the prompt is planning-shaped and must never route cheap. */\n\tplanning: boolean;\n}\n\n/** Default judge probe set: three planning-shaped prompts, three trivial lookups. */\nexport const DEFAULT_JUDGE_FITNESS_PROMPTS: readonly JudgeFitnessPrompt[] = [\n\t{ prompt: \"how should we plan the migration of the session storage layer?\", planning: true },\n\t{ prompt: \"design an approach for splitting the settings manager\", planning: true },\n\t{ prompt: \"draft a roadmap for the autonomy rework\", planning: true },\n\t{ prompt: \"what does the resolvePath function return?\", planning: false },\n\t{ prompt: \"list the files in the delegation module\", planning: false },\n\t{ prompt: \"why is this test flaky?\", planning: false },\n];\n\nexport interface ModelFitnessOptions {\n\tcomplete: FitnessComplete;\n\t/** Trials per lane surface. Default 3. */\n\ttrials?: number;\n\t/** Wall-clock budget per call in ms. Default 120000. */\n\tmaxWallClockMs?: number;\n\tjudgePrompts?: readonly JudgeFitnessPrompt[];\n\tsignal?: AbortSignal;\n\t/** Injected clock for latency measurement (test seam). Defaults to Date.now. */\n\tnow?: () => number;\n}\n\nexport interface LaneFitnessScore {\n\tsucceeded: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the surface's calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface JudgeFitnessScore {\n\tparsed: number;\n\tplanningElevated: number;\n\tplanningTotal: number;\n\ttrivialCheap: number;\n\ttrivialTotal: number;\n\ttotal: number;\n\toutcomes: string[];\n\tmeanMs: number;\n\t/** Mean output tokens/second across the judge calls; undefined when not reported. */\n\ttokensPerSecond?: number;\n}\n\nexport interface ModelFitnessReport {\n\ttrials: number;\n\t/** Aggregate output tokens/second across ALL probe calls (the headline speed number). */\n\ttokensPerSecond?: number;\n\tresearch: LaneFitnessScore;\n\tworker: LaneFitnessScore;\n\tjudge: JudgeFitnessScore;\n\t/** Heavy-lifter surface: can the model formulate a structured search plan? */\n\tsearch: LaneFitnessScore;\n\t/** Heavy-lifter surface: can the model emit a well-formed tool call against a schema? */\n\ttoolCall: LaneFitnessScore;\n\t/** Curator surface: can the model digest a context chunk to strict JSON WITHOUT losing key facts? */\n\tdigest: LaneFitnessScore;\n\ttotalCostUsd: number;\n}\n\n/** Static prompts for the heavy-lifter surfaces (stable for provider prompt caching). */\nexport const SEARCH_PROBE_SYSTEM_PROMPT = [\n\t\"You plan code searches for a coding agent. You never answer the question yourself.\",\n\t\"Given a question about a codebase, respond with STRICT JSON only - no prose:\",\n\t'{\"queries\":[{\"pattern\":\"<regex or literal to grep>\",\"glob\":\"<file glob like **/*.ts>\"}]}',\n\t\"Return 1 to 4 queries, most specific first.\",\n].join(\"\\n\");\n\nexport const TOOL_CALL_PROBE_SYSTEM_PROMPT = [\n\t\"You operate tools for a coding agent. You have exactly one tool:\",\n\t\"grep(pattern: string, path: string) - search files under a path for a pattern.\",\n\t\"Respond to every task with STRICT JSON only - no prose:\",\n\t'{\"tool\":\"grep\",\"arguments\":{\"pattern\":\"<pattern>\",\"path\":\"<path>\"}}',\n].join(\"\\n\");\n\nconst SEARCH_PROBE_TASKS: readonly string[] = [\n\t\"Where is the retry/backoff logic for HTTP requests implemented?\",\n\t\"Which files define the settings for background research?\",\n\t\"Find where session entries of type custom are appended.\",\n];\n\n// The probe measures the REAL curation contract — same prompt the BrainCurator ships.\nexport { CURATION_DIGEST_SYSTEM_PROMPT as DIGEST_PROBE_SYSTEM_PROMPT } from \"../context/brain-curator.ts\";\n\n/**\n * Digest probe chunks each carry a NONCE identifier that cannot be guessed from the\n * instructions: acceptance requires the digest to RETAIN the nonce verbatim, so the score\n * measures extraction fidelity, not narration (a model cannot pass by paraphrasing).\n */\nconst DIGEST_PROBE_TASKS: readonly { chunk: string; nonce: string }[] = [\n\t{\n\t\tnonce: \"retryWithJitter_zx41\",\n\t\tchunk: [\n\t\t\t\"grep results for 'retry' under src/http:\",\n\t\t\t\"src/http/client.ts:88: export function retryWithJitter_zx41(fn, attempts = 3) {\",\n\t\t\t\"src/http/client.ts:112: // exponential backoff capped at 30s\",\n\t\t\t\"src/http/pool.ts:41: client.retry = false\",\n\t\t].join(\"\\n\"),\n\t},\n\t{\n\t\tnonce: \"ERR_QM_7734\",\n\t\tchunk: [\n\t\t\t\"$ npm run migrate\",\n\t\t\t\"migrating 14 files...\",\n\t\t\t\"error ERR_QM_7734: column 'owner_id' missing on table sessions (migration 0009)\",\n\t\t\t\"exit code 1\",\n\t\t].join(\"\\n\"),\n\t},\n\t{\n\t\tnonce: \"v3.9.2-hotfix.1\",\n\t\tchunk: [\n\t\t\t\"read package.json (34 lines):\",\n\t\t\t' \"name\": \"acme-billing\",',\n\t\t\t' \"version\": \"v3.9.2-hotfix.1\",',\n\t\t\t' \"engines\": { \"node\": \">=22\" },',\n\t\t].join(\"\\n\"),\n\t},\n];\n\nfunction parseDigest(text: string, nonce: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst digest = (parsed as { digest?: unknown }).digest;\n\tif (typeof digest !== \"string\") return false;\n\tconst trimmed = digest.trim();\n\t// Bounded and faithful: short enough to be a stub annotation, still carrying the nonce fact.\n\treturn trimmed.length > 0 && trimmed.length <= 240 && trimmed.includes(nonce);\n}\n\nconst TOOL_CALL_PROBE_TASKS: readonly string[] = [\n\t\"Find usages of the function resolveCliModel under src/.\",\n\t\"Search for the string 'budget_exhausted' in the core directory.\",\n\t\"Locate where LaneTracker is instantiated under src/core.\",\n];\n\nfunction parseSearchPlan(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst queries = (parsed as { queries?: unknown }).queries;\n\tif (!Array.isArray(queries) || queries.length === 0 || queries.length > 8) return false;\n\treturn queries.every(\n\t\t(query) =>\n\t\t\tquery &&\n\t\t\ttypeof query === \"object\" &&\n\t\t\ttypeof (query as { pattern?: unknown }).pattern === \"string\" &&\n\t\t\t(query as { pattern: string }).pattern.trim().length > 0,\n\t);\n}\n\nfunction parseToolCall(text: string): boolean {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return false;\n\tconst record = parsed as { tool?: unknown; arguments?: unknown };\n\tif (record.tool !== \"grep\") return false;\n\tconst args = record.arguments;\n\tif (!args || typeof args !== \"object\" || Array.isArray(args)) return false;\n\tconst pattern = (args as { pattern?: unknown }).pattern;\n\tconst path = (args as { path?: unknown }).path;\n\treturn (\n\t\ttypeof pattern === \"string\" && pattern.trim().length > 0 && typeof path === \"string\" && path.trim().length > 0\n\t);\n}\n\nfunction extractJsonObject(text: string): unknown | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(candidate);\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n\t\t} catch {\n\t\t\t// try next candidate\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction fitnessEnvelope(): CapabilityEnvelope {\n\treturn {\n\t\tid: \"model-fitness-probe\",\n\t\tcapabilities: [\"research\", \"read_files\", \"memory_read\"],\n\t\tmaxEstimatedUsd: 1,\n\t\tcreatedAt: new Date().toISOString(),\n\t};\n}\n\nexport async function runModelFitnessProbe(options: ModelFitnessOptions): Promise<ModelFitnessReport> {\n\tconst trials = Math.max(1, Math.min(options.trials ?? 3, 20));\n\tconst maxWallClockMs = options.maxWallClockMs ?? 120_000;\n\tconst judgePrompts = options.judgePrompts ?? DEFAULT_JUDGE_FITNESS_PROMPTS;\n\tconst now = options.now ?? Date.now;\n\tlet totalCostUsd = 0;\n\n\t// Token-speed instrumentation: the lane runners' own contracts carry text/cost only, so the\n\t// completer is wrapped once here and generation stats are accumulated per surface.\n\tconst overallSpeed = { tokens: 0, evalMs: 0 };\n\tlet surfaceSpeed = { tokens: 0, evalMs: 0 };\n\tconst complete: FitnessComplete = async (args) => {\n\t\tconst completion = await options.complete(args);\n\t\tconst tokens = completion.outputTokens ?? 0;\n\t\tconst evalMs = completion.evalMs ?? 0;\n\t\tif (tokens > 0 && evalMs > 0) {\n\t\t\tsurfaceSpeed.tokens += tokens;\n\t\t\tsurfaceSpeed.evalMs += evalMs;\n\t\t\toverallSpeed.tokens += tokens;\n\t\t\toverallSpeed.evalMs += evalMs;\n\t\t}\n\t\treturn completion;\n\t};\n\tconst takeSurfaceSpeed = (): number | undefined => {\n\t\tconst speed =\n\t\t\tsurfaceSpeed.evalMs > 0 ? Math.round((surfaceSpeed.tokens / surfaceSpeed.evalMs) * 1000) : undefined;\n\t\tsurfaceSpeed = { tokens: 0, evalMs: 0 };\n\t\treturn speed;\n\t};\n\n\tconst research: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst result = await runResearch({\n\t\t\tquery: `fitness:probe requirements:req-${i}`,\n\t\t\tcontext: [\n\t\t\t\t\"Goal: add a retry helper to the HTTP client module\",\n\t\t\t\t\"Open requirements:\",\n\t\t\t\t\"- Find what retry/backoff conventions the codebase already uses\",\n\t\t\t\t\"- Identify which call sites would adopt the helper\",\n\t\t\t].join(\"\\n\"),\n\t\t\tenvelope: fitnessEnvelope(),\n\t\t\tmaxUsd: 1,\n\t\t\tmaxSources: 8,\n\t\t\tmaxFindings: 5,\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tresearch.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tif (result.status === \"succeeded\") research.succeeded++;\n\t\tresearch.outcomes.push(`${result.status}/${result.reasonCode}`);\n\t}\n\tresearch.meanMs = Math.round(research.meanMs / trials);\n\tresearch.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst worker: LaneFitnessScore = { succeeded: 0, total: trials, outcomes: [], meanMs: 0 };\n\tfor (let i = 0; i < trials; i++) {\n\t\tconst started = now();\n\t\tconst outcome = await runWorker({\n\t\t\trequest: {\n\t\t\t\tid: `fitness-worker-${i}`,\n\t\t\t\tinstructions:\n\t\t\t\t\t\"Summarize in two sentences what a capability envelope is: a declared set of allowed tools, paths, and capability names that bounds what a delegated worker may do.\",\n\t\t\t\troute: { tier: \"cheap\", risk: \"read-only\", confidence: 1, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\t\tenvelope: { id: `fitness-env-${i}`, capabilities: [\"read_files\"], maxEstimatedUsd: 1 },\n\t\t\t\tmaxEstimatedUsd: 1,\n\t\t\t},\n\t\t\tmaxUsd: 1,\n\t\t\tmaxWallClockMs,\n\t\t\tusageReportId: `fitness:${i}`,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tworker.meanMs += now() - started;\n\t\ttotalCostUsd += outcome.costUsd;\n\t\tif (outcome.result.status === \"completed\" && outcome.accepted) worker.succeeded++;\n\t\tworker.outcomes.push(`${outcome.result.status}/${outcome.reasonCode}`);\n\t}\n\tworker.meanMs = Math.round(worker.meanMs / trials);\n\tworker.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst judge: JudgeFitnessScore = {\n\t\tparsed: 0,\n\t\tplanningElevated: 0,\n\t\tplanningTotal: judgePrompts.filter((entry) => entry.planning).length,\n\t\ttrivialCheap: 0,\n\t\ttrivialTotal: judgePrompts.filter((entry) => !entry.planning).length,\n\t\ttotal: judgePrompts.length,\n\t\toutcomes: [],\n\t\tmeanMs: 0,\n\t};\n\tfor (const entry of judgePrompts) {\n\t\tconst started = now();\n\t\tconst result = await runRouteJudge({\n\t\t\tprompt: entry.prompt,\n\t\t\tbaseline: { tier: \"cheap\", risk: \"read-only\", confidence: 0.5, reasonCode: \"fitness_probe\", reasons: [] },\n\t\t\tmaxWallClockMs,\n\t\t\tsignal: options.signal,\n\t\t\tcomplete,\n\t\t});\n\t\tjudge.meanMs += now() - started;\n\t\ttotalCostUsd += result.costUsd;\n\t\tconst tier = result.decision.tier;\n\t\tif (result.verdict) {\n\t\t\tjudge.parsed++;\n\t\t\t// A useful judge must both keep planning off the cheap tier AND actually send trivial\n\t\t\t// prompts there — all-medium verdicts are safe but save nothing.\n\t\t\tif (entry.planning && tier !== \"cheap\") judge.planningElevated++;\n\t\t\tif (!entry.planning && tier === \"cheap\") judge.trivialCheap++;\n\t\t}\n\t\tjudge.outcomes.push(\n\t\t\t`\"${entry.prompt.slice(0, 40)}\" -> ${tier}${result.fallbackReason ? ` (${result.fallbackReason})` : \"\"}`,\n\t\t);\n\t}\n\tjudge.meanMs = judgePrompts.length > 0 ? Math.round(judge.meanMs / judgePrompts.length) : 0;\n\tjudge.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst probeSurface = async (\n\t\tsystemPrompt: string,\n\t\ttasks: readonly string[],\n\t\taccepts: (text: string, taskIndex: number) => boolean,\n\t): Promise<LaneFitnessScore> => {\n\t\tconst score: LaneFitnessScore = { succeeded: 0, total: tasks.length, outcomes: [], meanMs: 0 };\n\t\tfor (const [taskIndex, task] of tasks.entries()) {\n\t\t\tconst started = now();\n\t\t\t// Same wall-clock envelope as the lane surfaces — a hung model must not hang the probe.\n\t\t\tconst bounded = await runBoundedCompletion({\n\t\t\t\tmaxWallClockMs,\n\t\t\t\tsignal: options.signal,\n\t\t\t\texecute: (signal) => complete({ systemPrompt, userPrompt: task, signal }),\n\t\t\t});\n\t\t\tif (bounded.completion) totalCostUsd += bounded.completion.costUsd;\n\t\t\tif (bounded.failure || !bounded.completion) {\n\t\t\t\tscore.outcomes.push(bounded.failure ? bounded.failure.status : \"completion_error\");\n\t\t\t} else {\n\t\t\t\tconst ok = accepts(bounded.completion.text, taskIndex);\n\t\t\t\tif (ok) score.succeeded++;\n\t\t\t\tscore.outcomes.push(ok ? \"ok\" : \"unparseable_output\");\n\t\t\t}\n\t\t\tscore.meanMs += now() - started;\n\t\t}\n\t\tscore.meanMs = tasks.length > 0 ? Math.round(score.meanMs / tasks.length) : 0;\n\t\treturn score;\n\t};\n\n\tconst search = await probeSurface(SEARCH_PROBE_SYSTEM_PROMPT, SEARCH_PROBE_TASKS, parseSearchPlan);\n\tsearch.tokensPerSecond = takeSurfaceSpeed();\n\tconst toolCall = await probeSurface(TOOL_CALL_PROBE_SYSTEM_PROMPT, TOOL_CALL_PROBE_TASKS, parseToolCall);\n\ttoolCall.tokensPerSecond = takeSurfaceSpeed();\n\tconst digest = await probeSurface(\n\t\tCURATION_DIGEST_SYSTEM_PROMPT,\n\t\tDIGEST_PROBE_TASKS.map((task) => task.chunk),\n\t\t(text, taskIndex) => parseDigest(text, DIGEST_PROBE_TASKS[taskIndex]!.nonce),\n\t);\n\tdigest.tokensPerSecond = takeSurfaceSpeed();\n\n\tconst tokensPerSecond =\n\t\toverallSpeed.evalMs > 0 ? Math.round((overallSpeed.tokens / overallSpeed.evalMs) * 1000) : undefined;\n\n\treturn { trials, tokensPerSecond, research, worker, judge, search, toolCall, digest, totalCostUsd };\n}\n\n/** Compact human-readable report for tool output / interactive display. Bounded, no raw dumps. */\nexport function formatModelFitnessReport(model: string, report: ModelFitnessReport): string {\n\tconst speed = (tokensPerSecond: number | undefined) =>\n\t\ttokensPerSecond !== undefined ? `, ~${tokensPerSecond} tok/s` : \"\";\n\tconst lines = [\n\t\t`Model fitness: ${model} (${report.trials} trials/lane${speed(report.tokensPerSecond)})`,\n\t\t`- research lane: ${report.research.succeeded}/${report.research.total} succeeded, mean ${report.research.meanMs}ms${speed(report.research.tokensPerSecond)} [${report.research.outcomes.join(\", \")}]`,\n\t\t`- worker lane: ${report.worker.succeeded}/${report.worker.total} completed+accepted, mean ${report.worker.meanMs}ms${speed(report.worker.tokensPerSecond)} [${report.worker.outcomes.join(\", \")}]`,\n\t\t`- search plans: ${report.search.succeeded}/${report.search.total} well-formed, mean ${report.search.meanMs}ms${speed(report.search.tokensPerSecond)}`,\n\t\t`- tool calls: ${report.toolCall.succeeded}/${report.toolCall.total} well-formed, mean ${report.toolCall.meanMs}ms${speed(report.toolCall.tokensPerSecond)}`,\n\t\t`- digests: ${report.digest.succeeded}/${report.digest.total} faithful, mean ${report.digest.meanMs}ms${speed(report.digest.tokensPerSecond)}`,\n\t\t`- route judge: parsed ${report.judge.parsed}/${report.judge.total}, planning-elevated ${report.judge.planningElevated}/${report.judge.planningTotal}, trivial-cheap ${report.judge.trivialCheap}/${report.judge.trivialTotal}, mean ${report.judge.meanMs}ms${speed(report.judge.tokensPerSecond)}`,\n\t\t...report.judge.outcomes.map((outcome) => ` ${outcome}`),\n\t];\n\tif (report.totalCostUsd > 0) {\n\t\tlines.push(`- probe cost: $${report.totalCostUsd.toFixed(4)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -48,9 +48,16 @@ export interface MemoryRetrievalSettings {
|
|
|
48
48
|
maxResults?: number;
|
|
49
49
|
includeInPrompt?: boolean;
|
|
50
50
|
}
|
|
51
|
+
export interface ContextCurationSettings {
|
|
52
|
+
enabled?: boolean;
|
|
53
|
+
/** Local model ref ("provider/id" or bare id) used for curation jobs. Required to drain. */
|
|
54
|
+
model?: string;
|
|
55
|
+
maxJobsPerTurn?: number;
|
|
56
|
+
}
|
|
51
57
|
export interface ContextPolicySettings {
|
|
52
58
|
enforcement?: ContextPromptEnforcementSettings;
|
|
53
59
|
memory?: MemoryRetrievalSettings;
|
|
60
|
+
curation?: ContextCurationSettings;
|
|
54
61
|
}
|
|
55
62
|
export declare const MEMORY_RETRIEVAL_MAX_RESULTS_MIN = 1;
|
|
56
63
|
export declare const MEMORY_RETRIEVAL_MAX_RESULTS_MAX = 20;
|
|
@@ -536,6 +543,12 @@ export declare class SettingsManager {
|
|
|
536
543
|
preserveRecentMessages: number;
|
|
537
544
|
minChars: number;
|
|
538
545
|
};
|
|
546
|
+
getContextCurationSettings(): {
|
|
547
|
+
enabled: boolean;
|
|
548
|
+
model?: string;
|
|
549
|
+
maxJobsPerTurn: number;
|
|
550
|
+
};
|
|
551
|
+
setContextCurationSettings(settings: ContextCurationSettings, scope?: SettingsScope): void;
|
|
539
552
|
setContextPromptEnforcementSettings(settings: ContextPromptEnforcementSettings, scope?: SettingsScope): void;
|
|
540
553
|
getMemoryRetrievalSettings(): {
|
|
541
554
|
enabled: boolean;
|