{"version":3,"file":"context-token.d.ts","sourceRoot":"","sources":["../../../src/core/context-runtime/context-token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAoB,IAAI,EAAqB,MAAM,uBAAuB,CAAC;AACvF,OAAO,EACN,WAAW,EACX,KAAK,YAAY,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,mFAAmF;AACnF,wBAAgB,0BAA0B,CACzC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,SAAS,EAClC,UAAU,GAAE,eAAoB,GAC9B,MAAM,CAaR;AAED,MAAM,WAAW,eAAe;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CACf;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,GAAE,eAAoB,GAAG,MAAM,CAwDrG;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,eAAe,EAAE,UAAU,GAAE,eAAoB,GAAG,MAAM,CAU/G;AAED,qDAAqD;AACrD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,UAAU,GAAE,eAAoB,GAAG,MAAM,CAM3G;AAED,MAAM,WAAW,kBAAkB;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,eAAe,EACzB,UAAU,GAAE,eAAoB,GAC9B,kBAAkB,CA0BpB","sourcesContent":["/**\n * Token accounting for context virtualization.\n *\n * Uses the tiered token accounting module (content-class aware conservative\n * fallback, calibrated uplift when provider usage is available). The governor\n * must never under-count, so estimation is always upper-biased.\n */\n\nimport type { AgentMessage } from \"@apholdings/jensen-agent-core\";\nimport type { AssistantMessage, Tool, ToolResultMessage } from \"@apholdings/jensen-ai\";\nimport {\n\tanalyzeText,\n\ttype ContentClass,\n\testimateTextTokens,\n\tMAX_CALIBRATED_MULTIPLIER,\n\tresolveAccountingMode,\n\ttype TokenAccountingMode,\n\ttype TokenAccountingOptions,\n} from \"./token-accounting.js\";\n\nexport { analyzeText, estimateTextTokens, MAX_CALIBRATED_MULTIPLIER, resolveAccountingMode };\nexport type { ContentClass, TokenAccountingMode, TokenAccountingOptions };\n\nexport interface TokenAccounting {\n\t/** Calibrated multiplier from provider-usage observation (>= 1). */\n\tcalibratedMultiplier?: number;\n}\n\n/** Estimate the token cost of the stable prefix (system prompt + tool schemas). */\nexport function estimateStablePrefixTokens(\n\tsystemPrompt: string,\n\ttools: readonly Tool[] | undefined,\n\taccounting: TokenAccounting = {},\n): number {\n\tlet total = estimateTextTokens(systemPrompt, \"system-prompt\", accounting);\n\tfor (const tool of tools ?? []) {\n\t\ttotal += estimateTextTokens(tool.name, \"tool-schema\", accounting);\n\t\ttotal += estimateTextTokens(tool.description, \"tool-schema\", accounting);\n\t\ttry {\n\t\t\ttotal += estimateTextTokens(JSON.stringify(tool.parameters ?? {}), \"json\", accounting);\n\t\t} catch {\n\t\t\t// Non-serializable schema: fall back to a small fixed allowance.\n\t\t\ttotal += 64;\n\t\t}\n\t}\n\treturn total;\n}\n\nexport interface ContextAssembly {\n\tsystemPrompt: string;\n\tdynamicPrompt?: string;\n\tmessages: AgentMessage[];\n\ttools?: Tool[];\n}\n\n/** Estimate the cost of a message, choosing a content class per role/block. */\nexport function estimateMessageTokens(message: AgentMessage, accounting: TokenAccounting = {}): number {\n\tswitch (message.role) {\n\t\tcase \"user\": {\n\t\t\tconst content = (message as { content: string | Array<{ type: string; text?: string }> }).content;\n\t\t\tif (typeof content === \"string\") return estimateTextTokens(content, \"prose\", accounting);\n\t\t\tlet total = 0;\n\t\t\tfor (const block of content) {\n\t\t\t\tif (block.type === \"text\" && block.text) total += estimateTextTokens(block.text, \"prose\", accounting);\n\t\t\t}\n\t\t\treturn total;\n\t\t}\n\t\tcase \"assistant\": {\n\t\t\tconst assistant = message as AssistantMessage;\n\t\t\tlet total = 0;\n\t\t\tfor (const block of assistant.content) {\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\ttotal += estimateTextTokens(block.text, \"prose\", accounting);\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\ttotal += estimateTextTokens(block.thinking, \"prose\", accounting);\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\ttotal += estimateTextTokens(block.name, \"code\", accounting);\n\t\t\t\t\ttotal += estimateTextTokens(JSON.stringify(block.arguments), \"json\", accounting);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn total;\n\t\t}\n\t\tcase \"toolResult\": {\n\t\t\tconst result = message as ToolResultMessage;\n\t\t\tlet total = 0;\n\t\t\tfor (const block of result.content) {\n\t\t\t\tif (block.type === \"text\" && block.text) {\n\t\t\t\t\ttotal += estimateTextTokens(block.text, \"tool-result\", accounting);\n\t\t\t\t} else if (block.type === \"image\") {\n\t\t\t\t\t// Image payloads are encoded as data URLs; conservatively allow ~1200 tokens.\n\t\t\t\t\ttotal += 1200;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn total;\n\t\t}\n\t\tcase \"bashExecution\": {\n\t\t\tconst bash = message as { command: string; output: string };\n\t\t\treturn (\n\t\t\t\testimateTextTokens(bash.command, \"code\", accounting) + estimateTextTokens(bash.output, \"log\", accounting)\n\t\t\t);\n\t\t}\n\t\tcase \"custom\": {\n\t\t\tconst content = (message as { content: string }).content;\n\t\t\treturn typeof content === \"string\" ? estimateTextTokens(content, \"prose\", accounting) : 0;\n\t\t}\n\t\tcase \"branchSummary\":\n\t\tcase \"compactionSummary\": {\n\t\t\treturn estimateTextTokens((message as { summary: string }).summary, \"prose\", accounting);\n\t\t}\n\t\tdefault:\n\t\t\treturn 0;\n\t}\n}\n\n/**\n * Estimate the total input tokens Jensen would send for this assembly,\n * including system prompt, tool schemas, and the host-context dynamic prompt.\n */\nexport function estimateAssemblyInputTokens(assembly: ContextAssembly, accounting: TokenAccounting = {}): number {\n\tlet total = estimateStablePrefixTokens(assembly.systemPrompt, assembly.tools, accounting);\n\tif (assembly.dynamicPrompt) {\n\t\t// dynamicPrompt is injected as a `<host-context>` user message.\n\t\ttotal += estimateTextTokens(`<host-context>\\n${assembly.dynamicPrompt}\\n</host-context>`, \"prose\", accounting);\n\t}\n\tfor (const message of assembly.messages) {\n\t\ttotal += estimateMessageTokens(message, accounting);\n\t}\n\treturn total;\n}\n\n/** Estimate the token cost of a list of messages. */\nexport function estimateMessageTokensFor(messages: AgentMessage[], accounting: TokenAccounting = {}): number {\n\tlet total = 0;\n\tfor (const message of messages) {\n\t\ttotal += estimateMessageTokens(message, accounting);\n\t}\n\treturn total;\n}\n\nexport interface ContextRegionCosts {\n\tsystemPromptTokens: number;\n\ttoolSchemaTokens: number;\n\tdynamicPromptTokens: number;\n\tmessageTokens: number;\n\t/** systemPrompt + toolSchema + dynamicPrompt (the fixed prefix). */\n\tfixedPrefixTokens: number;\n}\n\n/**\n * Structured, per-region cost breakdown used for fixed-prefix diagnostics and\n * telemetry. Never used to fabricate completion authority.\n */\nexport function estimateContextRegionCosts(\n\tassembly: ContextAssembly,\n\taccounting: TokenAccounting = {},\n): ContextRegionCosts {\n\tconst systemPromptTokens = estimateTextTokens(assembly.systemPrompt, \"system-prompt\", accounting);\n\tconst toolSchemaTokens = (() => {\n\t\tlet total = 0;\n\t\tfor (const tool of assembly.tools ?? []) {\n\t\t\ttotal += estimateTextTokens(tool.name, \"tool-schema\", accounting);\n\t\t\ttotal += estimateTextTokens(tool.description, \"tool-schema\", accounting);\n\t\t\ttry {\n\t\t\t\ttotal += estimateTextTokens(JSON.stringify(tool.parameters ?? {}), \"json\", accounting);\n\t\t\t} catch {\n\t\t\t\ttotal += 64;\n\t\t\t}\n\t\t}\n\t\treturn total;\n\t})();\n\tconst dynamicPromptTokens = assembly.dynamicPrompt\n\t\t? estimateTextTokens(`<host-context>\\n${assembly.dynamicPrompt}\\n</host-context>`, \"prose\", accounting)\n\t\t: 0;\n\tconst messageTokens = estimateMessageTokensFor(assembly.messages, accounting);\n\treturn {\n\t\tsystemPromptTokens,\n\t\ttoolSchemaTokens,\n\t\tdynamicPromptTokens,\n\t\tmessageTokens,\n\t\tfixedPrefixTokens: systemPromptTokens + toolSchemaTokens + dynamicPromptTokens,\n\t};\n}\n"]}