@ponythewhite/base-context 1.0.10 → 1.0.12
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 +22 -0
- package/dist/base-context-runtime/pyproject.toml +1 -1
- package/dist/base-context-runtime/uv.lock +1 -1
- package/dist/build-info.json +1 -1
- package/dist/bundle/amazon-bedrock.js +3 -3
- package/dist/bundle/{anthropic-5PSCZEER.js → anthropic-BJVPUMPB.js} +2 -2
- package/dist/bundle/{azure-openai-responses-AYTLJR33.js → azure-openai-responses-ERRMAXK6.js} +4 -5
- package/dist/bundle/{bundled-modules-MX6YNAM2.js → bundled-modules-WCGPZI2H.js} +5 -5
- package/dist/bundle/{chunk-D3KOF57W.js → chunk-25VYRAC6.js} +14 -1
- package/dist/bundle/{chunk-2IPDSTDR.js → chunk-AEMRBMI2.js} +9 -9
- package/dist/bundle/{chunk-Q3MBSBEB.js → chunk-FOGKLC7V.js} +1 -1
- package/dist/bundle/{chunk-UHLGPYMI.js → chunk-IAKHCQA2.js} +185 -39
- package/dist/bundle/{chunk-KT2BNEPE.js → chunk-MUFZODP5.js} +1 -1
- package/dist/bundle/{chunk-QKIFBA7N.js → chunk-Q6UAHLII.js} +2 -2
- package/dist/bundle/{chunk-CDXQNS5P.js → chunk-YGV3Y4AD.js} +1009 -185
- package/dist/bundle/{cli-main-D7W3WWCV.js → cli-main-CTYDQHFE.js} +4 -4
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/{google-HTMCUJ7X.js → google-4GA4YMUX.js} +2 -2
- package/dist/bundle/{google-vertex-ZQO65AXF.js → google-vertex-7AMALD7D.js} +2 -2
- package/dist/bundle/{main-5J3QBZ5Y.js → main-GVGK354K.js} +5 -5
- package/dist/bundle/{mistral-SB7LU56G.js → mistral-74BXMNRM.js} +1 -1
- package/dist/bundle/{openai-codex-responses-5CEW4VN3.js → openai-codex-responses-COXNC4IH.js} +2 -2
- package/dist/bundle/{openai-completions-BAZJQSS2.js → openai-completions-BCSA5Q6S.js} +2 -2
- package/dist/bundle/{openai-responses-VHOE427P.js → openai-responses-ONCIZSJS.js} +3 -3
- package/dist/core/agent-session.d.ts +6 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +445 -146
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/canonical-context.d.ts +19 -3
- package/dist/core/canonical-context.d.ts.map +1 -1
- package/dist/core/canonical-context.js +130 -9
- package/dist/core/canonical-context.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +9 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +29 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context-epoch-copy.d.ts +1 -1
- package/dist/core/context-epoch-copy.d.ts.map +1 -1
- package/dist/core/context-epoch-copy.js +18 -7
- package/dist/core/context-epoch-copy.js.map +1 -1
- package/dist/core/context-epoch.d.ts +4 -0
- package/dist/core/context-epoch.d.ts.map +1 -1
- package/dist/core/context-epoch.js +8 -1
- package/dist/core/context-epoch.js.map +1 -1
- package/dist/core/context-tree.d.ts +14 -11
- package/dist/core/context-tree.d.ts.map +1 -1
- package/dist/core/context-tree.js +145 -9
- package/dist/core/context-tree.js.map +1 -1
- package/dist/core/history-index-worker.d.ts.map +1 -1
- package/dist/core/history-index-worker.js +59 -6
- package/dist/core/history-index-worker.js.map +1 -1
- package/dist/core/history-index.d.ts +17 -0
- package/dist/core/history-index.d.ts.map +1 -1
- package/dist/core/history-index.js +22 -0
- package/dist/core/history-index.js.map +1 -1
- package/dist/core/inference-coordinator.d.ts +1 -1
- package/dist/core/inference-coordinator.d.ts.map +1 -1
- package/dist/core/inference-coordinator.js +23 -6
- package/dist/core/inference-coordinator.js.map +1 -1
- package/dist/core/messages.d.ts +2 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +2 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/refinement/refinement.d.ts +2 -0
- package/dist/core/refinement/refinement.d.ts.map +1 -1
- package/dist/core/refinement/refinement.js +10 -1
- package/dist/core/refinement/refinement.js.map +1 -1
- package/dist/core/request-usage.d.ts +34 -0
- package/dist/core/request-usage.d.ts.map +1 -0
- package/dist/core/request-usage.js +111 -0
- package/dist/core/request-usage.js.map +1 -0
- package/dist/core/request-view-selection.d.ts +2 -1
- package/dist/core/request-view-selection.d.ts.map +1 -1
- package/dist/core/request-view-selection.js +29 -2
- package/dist/core/request-view-selection.js.map +1 -1
- package/dist/core/session-fork-messages.d.ts +5 -0
- package/dist/core/session-fork-messages.d.ts.map +1 -1
- package/dist/core/session-fork-messages.js +44 -0
- package/dist/core/session-fork-messages.js.map +1 -1
- package/dist/core/session-history-index.d.ts +5 -0
- package/dist/core/session-history-index.d.ts.map +1 -1
- package/dist/core/session-history-index.js +7 -0
- package/dist/core/session-history-index.js.map +1 -1
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +155 -13
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-tree.d.ts +9 -0
- package/dist/core/session-tree.d.ts.map +1 -1
- package/dist/core/session-tree.js +71 -11
- package/dist/core/session-tree.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +7 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts +2 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +4 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js +8 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
- package/dist/modes/agent-connection/in-process-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/in-process-agent-connection.js +4 -4
- package/dist/modes/agent-connection/in-process-agent-connection.js.map +1 -1
- package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-mode.js +4 -4
- package/dist/modes/daemon/daemon-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-protocol.d.ts +13 -3
- package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-protocol.js +10 -2
- package/dist/modes/daemon/daemon-protocol.js.map +1 -1
- package/dist/modes/daemon/daemon-session-summarizer.d.ts +3 -0
- package/dist/modes/daemon/daemon-session-summarizer.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-session-summarizer.js +71 -32
- package/dist/modes/daemon/daemon-session-summarizer.js.map +1 -1
- package/dist/modes/interactive/components/context-tree-format.d.ts.map +1 -1
- package/dist/modes/interactive/components/context-tree-format.js +49 -0
- package/dist/modes/interactive/components/context-tree-format.js.map +1 -1
- package/docs/compaction.md +27 -3
- package/docs/context-management.md +17 -1
- package/docs/rlm.md +1 -1
- package/docs/settings.md +12 -0
- package/docs/usage.md +24 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-epoch.d.ts","sourceRoot":"","sources":["../../src/core/context-epoch.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderRequestRepresentation, RequestTokenAssessment, Usage } from \"@ponythewhite/base-context-ai\";\nimport { requestTokenRouteIdentity } from \"@ponythewhite/base-context-ai\";\nimport { stringifyBoundedJson } from \"./bounded-json.js\";\nimport type { ContextRef, IndexedSourceEvent } from \"./history-index.js\";\nimport type { SourceSnapshotRef } from \"./request-events.js\";\nimport { MAX_RESOURCE_REVISION_BYTES } from \"./resource-view.js\";\nimport type { SelectedSkillReference } from \"./selected-skills.js\";\nimport type { CompiledTaskFrame } from \"./task-frame.js\";\n\nexport const CONTEXT_EPOCH_DETAIL = \"baseContextEpoch\";\n/** Internal admission, not a field accepted by ordinary appendCompaction callers. */\nexport const appendContextEpoch = Symbol(\"appendContextEpoch\");\nexport const CONTEXT_EPOCH_RENDERER = \"native-canonical-epoch/4\";\nexport const CONTEXT_POLICY_EPOCH_RENDERER = \"native-canonical-epoch/5\";\nexport const CONTEXT_TOOL_EPOCH_RENDERER = \"native-canonical-epoch/6\";\n/** Selection-bearing v4/v5/v6 variants; older readers must refuse rather than drop these refs. */\nexport const CONTEXT_SKILL_EPOCH_RENDERER = \"native-canonical-epoch/7\";\n/** Source-backed summary with retained public tool groups, not a measured MAIN request. */\nexport const CONTEXT_TOOL_SUMMARY_RENDERER = \"native-canonical-epoch/8\";\n/** Public recipes may record absent admission, never a fabricated execution outcome. */\nexport const CONTEXT_INTERRUPTED_TOOL_RENDERER = \"native-canonical-epoch/9\";\n\n/** Descriptive, source-backed outcomes in the existing accepted epoch, not an execution store. */\nexport interface ToolContinuationGroup {\n\treadonly assistantEntryId: string;\n\treadonly calls: readonly (\n\t\t| {\n\t\t\t\treadonly admission?: never;\n\t\t\t\treadonly executionId: string;\n\t\t\t\treadonly intent: Pick<IndexedSourceEvent, \"id\" | \"sequence\" | \"revision\">;\n\t\t\t\treadonly outcome: \"outcome_unknown\" | \"not_started\" | \"completed\" | \"failed\";\n\t\t\t\treadonly result?: Pick<IndexedSourceEvent, \"id\" | \"sequence\" | \"revision\">;\n\t\t }\n\t\t| {\n\t\t\t\treadonly admission: \"absent\";\n\t\t\t\t/** Absence is scoped to this exact captured branch prefix, not external effects. */\n\t\t\t\treadonly source: SourceSnapshotRef;\n\t\t\t\treadonly executionId?: never;\n\t\t\t\treadonly intent?: never;\n\t\t\t\treadonly outcome?: never;\n\t\t\t\treadonly result?: never;\n\t\t }\n\t)[];\n}\nexport type ContextMode = \"on\" | \"off\";\n\n/** Compatibility retained from an accepted native request, not measurement or replay credit. */\nexport interface ContextEpochRequestContract {\n\treadonly api: string;\n\treadonly provider: string;\n\treadonly route: string;\n\treadonly model: string;\n\treadonly replayContract: ContextReplayContract;\n}\nexport type ContextReplayContract = \"complete-context\" | \"message-groups\";\n\n/** An ordinary summary and its retained source recipes share the existing compaction ACK. */\nexport interface ContextEpochSummary {\n\treadonly summary: string;\n\treadonly details?: Record<string, unknown>;\n\treadonly fromHook?: boolean;\n\treadonly customInstructions?: string;\n\treadonly usage?: Usage;\n}\n\n/** A frozen read recipe, not a second copy of an archived message body. */\nexport interface EpochViewReference {\n\treadonly source: SourceSnapshotRef;\n\treadonly ref: ContextRef;\n\treadonly sourceRevision: string;\n\t/** Present only for an existing rendered compaction summary. */\n\treadonly retainedMessageCount?: number;\n\treadonly rendering?: \"public-history/1\" | \"public-tool-continuation/1\";\n}\n\ninterface ContextEpochFields {\n\treadonly renderer:\n\t\t| \"native-canonical-epoch/1\"\n\t\t| \"native-canonical-epoch/2\"\n\t\t| \"native-canonical-epoch/3\"\n\t\t| typeof CONTEXT_EPOCH_RENDERER\n\t\t| typeof CONTEXT_POLICY_EPOCH_RENDERER\n\t\t| typeof CONTEXT_TOOL_EPOCH_RENDERER\n\t\t| typeof CONTEXT_SKILL_EPOCH_RENDERER\n\t\t| typeof CONTEXT_TOOL_SUMMARY_RENDERER\n\t\t| typeof CONTEXT_INTERRUPTED_TOOL_RENDERER;\n\treadonly source: SourceSnapshotRef;\n\treadonly includeSummary?: true;\n\t/** Granted by an actual accepted adapter projection, never a caller profile name. */\n\treadonly replayContract?: ContextReplayContract;\n\t/** Actual adapter permission to leave completed native groups for a fresh public window. */\n\treadonly publicWindow?: true;\n\t/** Frozen public transition. Later native messages are not silently converted. */\n\treadonly continuation?: {\n\t\treadonly kind: \"harness-summary\" | \"portable-checkpoint\";\n\t\treadonly publicTailThrough: SourceSnapshotRef;\n\t};\n\treadonly views: readonly EpochViewReference[];\n\t/** Captured versions, not a body cache or authority inferred from transcript markup. */\n\treadonly selectedSkills?: readonly SelectedSkillReference[];\n\t/** v6 requests and v8 summaries retain whole public groups and their exact outcome refs. */\n\treadonly toolContinuations?: readonly ToolContinuationGroup[];\n\t/** Derived display only. The task reducer remains the authority for later changes. */\n\treadonly taskFrame?: CompiledTaskFrame;\n\t/** Accepted-state comparison only; saved metadata never establishes current resource liveness. */\n\treadonly resourceRevision?: string;\n\treadonly literalTailId: string;\n}\n\n/** v5 policy-only null is a mode ACK, not an ordinary summary or a measured request. */\nexport type ContextEpochCheckpoint = ContextEpochFields &\n\t(\n\t\t| {\n\t\t\t\treadonly version: 1 | 2 | 3 | 4 | 6;\n\t\t\t\treadonly representation: string | null;\n\t\t\t\treadonly mode?: never;\n\t\t\t\treadonly policyOnly?: never;\n\t\t\t\treadonly requestContract?: never;\n\t\t\t\treadonly pendingRequestContract?: never;\n\t\t }\n\t\t| {\n\t\t\t\treadonly version: 8;\n\t\t\t\treadonly mode: ContextMode;\n\t\t\t\treadonly representation: null;\n\t\t\t\treadonly includeSummary: true;\n\t\t\t\treadonly policyOnly?: never;\n\t\t\t\treadonly requestContract?: never;\n\t\t\t\treadonly pendingRequestContract?: never;\n\t\t }\n\t\t| {\n\t\t\t\treadonly version: 5;\n\t\t\t\treadonly mode: ContextMode;\n\t\t\t\treadonly representation: null;\n\t\t\t\treadonly policyOnly: true;\n\t\t\t\treadonly includeSummary?: never;\n\t\t\t\treadonly requestContract?: ContextEpochRequestContract;\n\t\t\t\treadonly pendingRequestContract?: true;\n\t\t }\n\t);\n\nexport function contextEpochMode(\n\tcheckpoint: ContextEpochCheckpoint | undefined,\n\tinitial: ContextMode = \"on\",\n): ContextMode {\n\treturn checkpoint ? (checkpoint.version === 5 || checkpoint.version === 8 ? checkpoint.mode : \"on\") : initial;\n}\n\nfunction isRequestContract(value: unknown): value is ContextEpochRequestContract {\n\tif (!value || typeof value !== \"object\") return false;\n\treturn (\n\t\t[\"api\", \"provider\", \"route\", \"model\"].every(\n\t\t\t(key) =>\n\t\t\t\tkey in value &&\n\t\t\t\ttypeof (value as Record<string, unknown>)[key] === \"string\" &&\n\t\t\t\t(value as Record<string, unknown>)[key] !== \"\",\n\t\t) &&\n\t\t\"replayContract\" in value &&\n\t\t(value.replayContract === \"complete-context\" || value.replayContract === \"message-groups\")\n\t);\n}\n\n/** Only call with a qualified checkpoint, never raw compaction marker data. */\nexport function retainedContextRequestContract(\n\tcheckpoint: ContextEpochCheckpoint | undefined,\n): ContextEpochRequestContract | undefined {\n\tif (!checkpoint) return;\n\tif (checkpoint.requestContract) return structuredClone(checkpoint.requestContract);\n\tif (!checkpoint.representation) return;\n\tconst accepted: unknown = JSON.parse(checkpoint.representation);\n\tif (!accepted || typeof accepted !== \"object\") throw new Error(\"Accepted context request contract is unavailable\");\n\tconst value = { ...accepted, replayContract: checkpoint.replayContract ?? \"complete-context\" };\n\tif (!isRequestContract(value)) throw new Error(\"Accepted context request contract is unavailable\");\n\treturn {\n\t\tapi: value.api,\n\t\tprovider: value.provider,\n\t\troute: value.route,\n\t\tmodel: value.model,\n\t\treplayContract: value.replayContract,\n\t};\n}\n\n/** Identity comes from the actual final native serialization, not a model/profile label. */\nexport function contextRequestContract(\n\trequest: ProviderRequestRepresentation,\n\treplayContract: ContextReplayContract,\n): ContextEpochRequestContract {\n\tconst route = requestTokenRouteIdentity(request.url);\n\tconst body: unknown = request.body === undefined ? undefined : JSON.parse(request.body);\n\tif (\n\t\t!route ||\n\t\t!body ||\n\t\ttypeof body !== \"object\" ||\n\t\t!(\"model\" in body) ||\n\t\ttypeof body.model !== \"string\" ||\n\t\t!body.model\n\t)\n\t\tthrow new Error(\"Native context request identity is unavailable\");\n\treturn { api: request.api, provider: request.provider, route, model: body.model, replayContract };\n}\n\nexport function assertContextRequestContract(\n\tcontract: ContextEpochRequestContract,\n\trequest: ProviderRequestRepresentation,\n\treplayContract: ContextReplayContract,\n): void {\n\tconst actual = contextRequestContract(request, replayContract);\n\tif (\n\t\tactual.api !== contract.api ||\n\t\tactual.provider !== contract.provider ||\n\t\tactual.route !== contract.route ||\n\t\tactual.model !== contract.model ||\n\t\tactual.replayContract !== contract.replayContract\n\t)\n\t\tthrow new Error(\"Retained context requires its accepted native request contract\");\n}\n\nexport function snapshotContextEpoch<T extends ContextEpochCheckpoint>(value: T, maxBytes: number): T {\n\treturn JSON.parse(stringifyBoundedJson(value, maxBytes)) as T;\n}\n\n/** Called only after checking the source frame's genuine epoch qualification. */\nexport function readContextEpoch(details: unknown, maxBytes: number): ContextEpochCheckpoint | undefined {\n\tif (!details || typeof details !== \"object\" || !(CONTEXT_EPOCH_DETAIL in details)) return;\n\tconst value: unknown = details[CONTEXT_EPOCH_DETAIL];\n\tif (\n\t\t!value ||\n\t\ttypeof value !== \"object\" ||\n\t\t!(\"version\" in value) ||\n\t\t!(\"renderer\" in value) ||\n\t\t!(\n\t\t\t(value.version === 1 && value.renderer === \"native-canonical-epoch/1\") ||\n\t\t\t(value.version === 2 && value.renderer === \"native-canonical-epoch/2\") ||\n\t\t\t(value.version === 3 && value.renderer === \"native-canonical-epoch/3\") ||\n\t\t\t(value.version === 4 && value.renderer === \"native-canonical-epoch/4\") ||\n\t\t\t(value.version === 5 && value.renderer === CONTEXT_POLICY_EPOCH_RENDERER) ||\n\t\t\t(value.version === 6 && value.renderer === CONTEXT_TOOL_EPOCH_RENDERER) ||\n\t\t\t(value.version === 8 && value.renderer === CONTEXT_TOOL_SUMMARY_RENDERER) ||\n\t\t\t([6, 8].includes(value.version as number) && value.renderer === CONTEXT_INTERRUPTED_TOOL_RENDERER) ||\n\t\t\t([4, 5, 6].includes(value.version as number) && value.renderer === CONTEXT_SKILL_EPOCH_RENDERER)\n\t\t) ||\n\t\t(value.renderer === CONTEXT_SKILL_EPOCH_RENDERER ||\n\t\t((value.version === 8 || value.renderer === CONTEXT_INTERRUPTED_TOOL_RENDERER) && \"selectedSkills\" in value)\n\t\t\t? !(\"selectedSkills\" in value) ||\n\t\t\t\t!Array.isArray(value.selectedSkills) ||\n\t\t\t\tvalue.selectedSkills.length === 0 ||\n\t\t\t\tvalue.selectedSkills.some(\n\t\t\t\t\t(item) =>\n\t\t\t\t\t\t!item ||\n\t\t\t\t\t\ttypeof item.name !== \"string\" ||\n\t\t\t\t\t\t!item.view ||\n\t\t\t\t\t\t![\"custom_message\", \"custom\"].includes(item.view.ref?.kind) ||\n\t\t\t\t\t\ttypeof item.view.sourceRevision !== \"string\",\n\t\t\t\t) ||\n\t\t\t\tnew Set(value.selectedSkills.map((item) => item.name)).size !== value.selectedSkills.length\n\t\t\t: \"selectedSkills\" in value) ||\n\t\t!(\"source\" in value) ||\n\t\t!value.source ||\n\t\t!(\"views\" in value) ||\n\t\t!Array.isArray(value.views) ||\n\t\t!(\"literalTailId\" in value) ||\n\t\ttypeof value.literalTailId !== \"string\" ||\n\t\t!(\"representation\" in value) ||\n\t\t(value.version === 5 || value.version === 8\n\t\t\t? !(\"mode\" in value) || (value.mode !== \"on\" && value.mode !== \"off\")\n\t\t\t: \"mode\" in value) ||\n\t\t(value.version === 8 &&\n\t\t\t(value.representation !== null || !(\"includeSummary\" in value) || value.includeSummary !== true)) ||\n\t\t(value.version === 5 &&\n\t\t\t(value.representation !== null || !(\"policyOnly\" in value) || value.policyOnly !== true)) ||\n\t\t(\"policyOnly\" in value &&\n\t\t\t(value.version !== 5 ||\n\t\t\t\tvalue.policyOnly !== true ||\n\t\t\t\tvalue.representation !== null ||\n\t\t\t\t\"includeSummary\" in value)) ||\n\t\t(\"pendingRequestContract\" in value &&\n\t\t\t(value.version !== 5 ||\n\t\t\t\t!(\"mode\" in value) ||\n\t\t\t\tvalue.mode !== \"off\" ||\n\t\t\t\tvalue.pendingRequestContract !== true ||\n\t\t\t\t\"requestContract\" in value)) ||\n\t\t(\"requestContract\" in value && (value.version !== 5 || !isRequestContract(value.requestContract))) ||\n\t\t!(\n\t\t\ttypeof value.representation === \"string\" ||\n\t\t\t(value.version === 5 && value.representation === null && \"policyOnly\" in value && value.policyOnly === true) ||\n\t\t\t((value.version === 2 || value.version === 3 || value.version === 4 || value.version === 8) &&\n\t\t\t\tvalue.representation === null &&\n\t\t\t\t\"includeSummary\" in value &&\n\t\t\t\tvalue.includeSummary === true)\n\t\t) ||\n\t\t(\"includeSummary\" in value &&\n\t\t\t((value.version !== 2 && value.version !== 3 && value.version !== 4 && value.version !== 8) ||\n\t\t\t\tvalue.includeSummary !== true ||\n\t\t\t\tvalue.representation !== null)) ||\n\t\t(\"replayContract\" in value &&\n\t\t\tvalue.replayContract !== \"complete-context\" &&\n\t\t\tvalue.replayContract !== \"message-groups\") ||\n\t\t(\"resourceRevision\" in value &&\n\t\t\t(typeof value.resourceRevision !== \"string\" ||\n\t\t\t\tBuffer.byteLength(value.resourceRevision, \"utf8\") > MAX_RESOURCE_REVISION_BYTES)) ||\n\t\t(\"publicWindow\" in value &&\n\t\t\t((value.version !== 3 &&\n\t\t\t\tvalue.version !== 4 &&\n\t\t\t\tvalue.version !== 5 &&\n\t\t\t\tvalue.version !== 6 &&\n\t\t\t\tvalue.version !== 8) ||\n\t\t\t\tvalue.publicWindow !== true)) ||\n\t\t(\"toolContinuations\" in value && value.version !== 6 && value.version !== 8) ||\n\t\t((value.version === 6 || value.version === 8) &&\n\t\t\t(!(\"toolContinuations\" in value) ||\n\t\t\t\t!Array.isArray(value.toolContinuations) ||\n\t\t\t\t!value.toolContinuations.length ||\n\t\t\t\t!(\"replayContract\" in value) ||\n\t\t\t\t(value.version === 6 &&\n\t\t\t\t\t(!(\"publicWindow\" in value) ||\n\t\t\t\t\t\tvalue.publicWindow !== true ||\n\t\t\t\t\t\tvalue.replayContract !== \"message-groups\")))) ||\n\t\t(\"continuation\" in value &&\n\t\t\t((value.version !== 3 &&\n\t\t\t\tvalue.version !== 4 &&\n\t\t\t\tvalue.version !== 5 &&\n\t\t\t\tvalue.version !== 6 &&\n\t\t\t\tvalue.version !== 8) ||\n\t\t\t\t!value.continuation ||\n\t\t\t\ttypeof value.continuation !== \"object\" ||\n\t\t\t\t!(\"kind\" in value.continuation) ||\n\t\t\t\t(value.continuation.kind !== \"harness-summary\" &&\n\t\t\t\t\t((value.version !== 4 && value.version !== 5 && value.version !== 6) ||\n\t\t\t\t\t\tvalue.continuation.kind !== \"portable-checkpoint\")) ||\n\t\t\t\t!(\"publicTailThrough\" in value.continuation) ||\n\t\t\t\t!value.continuation.publicTailThrough))\n\t)\n\t\tthrow new Error(\"Invalid committed context epoch\");\n\treturn snapshotContextEpoch(value as ContextEpochCheckpoint, maxBytes);\n}\n\n/** Stable representation, not the changing input, an auth envelope, or a cache-hit claim. */\nexport function contextEpochRepresentation(\n\trequest: ProviderRequestRepresentation,\n\tassessment: RequestTokenAssessment | undefined,\n\tmaxBytes: number,\n\tunbudgetedPublic = false,\n\tresponseItemIdentity?: string,\n): string {\n\tif (\n\t\t(!assessment && !unbudgetedPublic) ||\n\t\t(assessment &&\n\t\t\t(!assessment.profile ||\n\t\t\t\tassessment.limitSource !== \"explicit-profile\" ||\n\t\t\t\t!assessment.route ||\n\t\t\t\t!assessment.model)) ||\n\t\trequest.body === undefined\n\t)\n\t\tthrow new Error(\"Committed context epoch requires its explicit request profile\");\n\tconst identity = assessment ?? contextRequestContract(request, \"message-groups\");\n\tconst body: unknown = JSON.parse(request.body);\n\tif (!body || typeof body !== \"object\" || Array.isArray(body))\n\t\tthrow new Error(\"Context epoch request representation is unavailable\");\n\tconst configuration: Record<string, unknown> = {};\n\tconst fields = new Set([\n\t\t\"model\",\n\t\t\"instructions\",\n\t\t\"stream\",\n\t\t\"max_output_tokens\",\n\t\t\"max_tokens\",\n\t\t\"max_completion_tokens\",\n\t\t\"temperature\",\n\t\t\"top_p\",\n\t\t\"text\",\n\t\t\"tools\",\n\t\t\"tool_choice\",\n\t\t\"parallel_tool_calls\",\n\t\t\"store\",\n\t\t\"reasoning\",\n\t\t\"service_tier\",\n\t\t\"truncation\",\n\t\t\"include\",\n\t\t\"prompt_cache_retention\",\n\t\t\"stream_options\",\n\t]);\n\tif (\n\t\trequest.api === \"openai-completions\" &&\n\t\trequest.provider === \"deepseek\" &&\n\t\trequest.url === \"https://api.deepseek.com/chat/completions\" &&\n\t\tidentity.route === request.url &&\n\t\t\"model\" in body &&\n\t\tbody.model === \"deepseek-flash\" &&\n\t\tidentity.model === body.model\n\t) {\n\t\tfields.add(\"thinking\");\n\t\tfields.add(\"reasoning_effort\");\n\t}\n\tfor (const [key, value] of Object.entries(body)) {\n\t\tif ([\"input\", \"messages\", \"previous_response_id\", \"prompt_cache_key\"].includes(key)) continue;\n\t\t// Unknown payload extensions may contain private data or change the representation.\n\t\tif (!fields.has(key)) throw new Error(\"Unsupported context epoch request configuration\");\n\t\tconfiguration[key] = value;\n\t}\n\tconst input: unknown = \"input\" in body ? body.input : \"messages\" in body ? body.messages : undefined;\n\tif (!Array.isArray(input)) throw new Error(\"Context epoch request messages are unavailable\");\n\tconst policy = input.filter(\n\t\t(item: unknown) =>\n\t\t\titem && typeof item === \"object\" && \"role\" in item && (item.role === \"system\" || item.role === \"developer\"),\n\t);\n\treturn stringifyBoundedJson(\n\t\t{\n\t\t\trenderer: CONTEXT_EPOCH_RENDERER,\n\t\t\t...(responseItemIdentity ? { responseItemIdentity } : {}),\n\t\t\tapi: request.api,\n\t\t\tprovider: request.provider,\n\t\t\troute: identity.route,\n\t\t\tmodel: identity.model,\n\t\t\t...(assessment\n\t\t\t\t? {\n\t\t\t\t\t\tprofile: assessment.profile,\n\t\t\t\t\t\tcontextTokens: assessment.contextTokens,\n\t\t\t\t\t\toutputReserveTokens: assessment.outputReserveTokens,\n\t\t\t\t\t}\n\t\t\t\t: { budget: \"unbudgeted\" }),\n\t\t\tconfiguration,\n\t\t\tpolicy,\n\t\t},\n\t\tmaxBytes,\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-epoch.d.ts","sourceRoot":"","sources":["../../src/core/context-epoch.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderRequestRepresentation, RequestTokenAssessment, Usage } from \"@ponythewhite/base-context-ai\";\nimport { requestTokenRouteIdentity } from \"@ponythewhite/base-context-ai\";\nimport { stringifyBoundedJson } from \"./bounded-json.js\";\nimport type { ContextRef, IndexedSourceEvent } from \"./history-index.js\";\nimport type { SourceSnapshotRef } from \"./request-events.js\";\nimport { MAX_RESOURCE_REVISION_BYTES } from \"./resource-view.js\";\nimport type { SelectedSkillReference } from \"./selected-skills.js\";\nimport type { CompiledTaskFrame } from \"./task-frame.js\";\n\nexport const CONTEXT_EPOCH_DETAIL = \"baseContextEpoch\";\n/** Internal admission, not a field accepted by ordinary appendCompaction callers. */\nexport const appendContextEpoch = Symbol(\"appendContextEpoch\");\nexport const CONTEXT_EPOCH_RENDERER = \"native-canonical-epoch/4\";\nexport const CONTEXT_POLICY_EPOCH_RENDERER = \"native-canonical-epoch/5\";\nexport const CONTEXT_TOOL_EPOCH_RENDERER = \"native-canonical-epoch/6\";\n/** Selection-bearing v4/v5/v6 variants; older readers must refuse rather than drop these refs. */\nexport const CONTEXT_SKILL_EPOCH_RENDERER = \"native-canonical-epoch/7\";\n/** Source-backed summary with retained public tool groups, not a measured MAIN request. */\nexport const CONTEXT_TOOL_SUMMARY_RENDERER = \"native-canonical-epoch/8\";\n/** Public recipes may record absent admission, never a fabricated execution outcome. */\nexport const CONTEXT_INTERRUPTED_TOOL_RENDERER = \"native-canonical-epoch/9\";\n\n/** Descriptive, source-backed outcomes in the existing accepted epoch, not an execution store. */\nexport interface ToolContinuationGroup {\n\treadonly assistantEntryId: string;\n\treadonly calls: readonly (\n\t\t| {\n\t\t\t\treadonly admission?: never;\n\t\t\t\treadonly executionId: string;\n\t\t\t\treadonly intent: Pick<IndexedSourceEvent, \"id\" | \"sequence\" | \"revision\">;\n\t\t\t\treadonly outcome: \"outcome_unknown\" | \"not_started\" | \"completed\" | \"failed\";\n\t\t\t\treadonly result?: Pick<IndexedSourceEvent, \"id\" | \"sequence\" | \"revision\">;\n\t\t }\n\t\t| {\n\t\t\t\treadonly admission: \"absent\";\n\t\t\t\t/** Absence is scoped to this exact captured branch prefix, not external effects. */\n\t\t\t\treadonly source: SourceSnapshotRef;\n\t\t\t\treadonly executionId?: never;\n\t\t\t\treadonly intent?: never;\n\t\t\t\treadonly outcome?: never;\n\t\t\t\treadonly result?: never;\n\t\t }\n\t)[];\n}\nexport type ContextMode = \"on\" | \"off\";\n\n/** Compatibility retained from an accepted native request, not measurement or replay credit. */\nexport interface ContextEpochRequestContract {\n\treadonly api: string;\n\treadonly provider: string;\n\treadonly route: string;\n\treadonly model: string;\n\treadonly replayContract: ContextReplayContract;\n}\nexport type ContextReplayContract = \"complete-context\" | \"message-groups\";\n\n/** An ordinary summary and its retained source recipes share the existing compaction ACK. */\nexport interface ContextEpochSummary {\n\treadonly summary: string;\n\treadonly details?: Record<string, unknown>;\n\treadonly fromHook?: boolean;\n\treadonly customInstructions?: string;\n\treadonly usage?: Usage;\n}\n\n/** A frozen read recipe, not a second copy of an archived message body. */\nexport interface EpochViewReference {\n\treadonly source: SourceSnapshotRef;\n\treadonly ref: ContextRef;\n\treadonly sourceRevision: string;\n\t/** Present only for an existing rendered compaction summary. */\n\treadonly retainedMessageCount?: number;\n\treadonly rendering?: \"public-history/1\" | \"public-tool-continuation/1\";\n}\n\ninterface ContextEpochFields {\n\treadonly renderer:\n\t\t| \"native-canonical-epoch/1\"\n\t\t| \"native-canonical-epoch/2\"\n\t\t| \"native-canonical-epoch/3\"\n\t\t| typeof CONTEXT_EPOCH_RENDERER\n\t\t| typeof CONTEXT_POLICY_EPOCH_RENDERER\n\t\t| typeof CONTEXT_TOOL_EPOCH_RENDERER\n\t\t| typeof CONTEXT_SKILL_EPOCH_RENDERER\n\t\t| typeof CONTEXT_TOOL_SUMMARY_RENDERER\n\t\t| typeof CONTEXT_INTERRUPTED_TOOL_RENDERER;\n\treadonly source: SourceSnapshotRef;\n\treadonly includeSummary?: true;\n\t/** Granted by an actual accepted adapter projection, never a caller profile name. */\n\treadonly replayContract?: ContextReplayContract;\n\t/** Actual adapter permission to leave completed native groups for a fresh public window. */\n\treadonly publicWindow?: true;\n\t/** Frozen public transition. Later native messages are not silently converted. */\n\treadonly continuation?: {\n\t\treadonly kind: \"harness-summary\" | \"portable-checkpoint\";\n\t\treadonly publicTailThrough: SourceSnapshotRef;\n\t};\n\treadonly views: readonly EpochViewReference[];\n\t/** Captured versions, not a body cache or authority inferred from transcript markup. */\n\treadonly selectedSkills?: readonly SelectedSkillReference[];\n\t/** v6 requests and v8 summaries retain whole public groups and their exact outcome refs. */\n\treadonly toolContinuations?: readonly ToolContinuationGroup[];\n\t/** Derived display only. The task reducer remains the authority for later changes. */\n\treadonly taskFrame?: CompiledTaskFrame;\n\t/** Accepted-state comparison only; saved metadata never establishes current resource liveness. */\n\treadonly resourceRevision?: string;\n\treadonly literalTailId: string;\n}\n\n/** v5 policy-only null is a mode ACK, not an ordinary summary or a measured request. */\nexport type ContextEpochCheckpoint = ContextEpochFields &\n\t(\n\t\t| {\n\t\t\t\treadonly version: 1 | 2 | 3 | 4 | 6;\n\t\t\t\treadonly representation: string | null;\n\t\t\t\treadonly mode?: never;\n\t\t\t\treadonly policyOnly?: never;\n\t\t\t\treadonly requestContract?: never;\n\t\t\t\treadonly pendingRequestContract?: never;\n\t\t }\n\t\t| {\n\t\t\t\treadonly version: 8;\n\t\t\t\treadonly mode: ContextMode;\n\t\t\t\treadonly representation: null;\n\t\t\t\treadonly includeSummary: true;\n\t\t\t\treadonly policyOnly?: never;\n\t\t\t\treadonly requestContract?: never;\n\t\t\t\treadonly pendingRequestContract?: never;\n\t\t }\n\t\t| {\n\t\t\t\treadonly version: 5;\n\t\t\t\treadonly mode: ContextMode;\n\t\t\t\treadonly representation: null;\n\t\t\t\treadonly policyOnly: true;\n\t\t\t\treadonly includeSummary?: never;\n\t\t\t\treadonly requestContract?: ContextEpochRequestContract;\n\t\t\t\treadonly pendingRequestContract?: true;\n\t\t }\n\t);\n\nexport function contextEpochMode(\n\tcheckpoint: ContextEpochCheckpoint | undefined,\n\tinitial: ContextMode = \"on\",\n): ContextMode {\n\treturn checkpoint ? (checkpoint.version === 5 || checkpoint.version === 8 ? checkpoint.mode : \"on\") : initial;\n}\n\nfunction isRequestContract(value: unknown): value is ContextEpochRequestContract {\n\tif (!value || typeof value !== \"object\") return false;\n\treturn (\n\t\t[\"api\", \"provider\", \"route\", \"model\"].every(\n\t\t\t(key) =>\n\t\t\t\tkey in value &&\n\t\t\t\ttypeof (value as Record<string, unknown>)[key] === \"string\" &&\n\t\t\t\t(value as Record<string, unknown>)[key] !== \"\",\n\t\t) &&\n\t\t\"replayContract\" in value &&\n\t\t(value.replayContract === \"complete-context\" || value.replayContract === \"message-groups\")\n\t);\n}\n\n/** Only call with a qualified checkpoint, never raw compaction marker data. */\nexport function retainedContextRequestContract(\n\tcheckpoint: ContextEpochCheckpoint | undefined,\n): ContextEpochRequestContract | undefined {\n\tif (!checkpoint) return;\n\tif (checkpoint.requestContract) return structuredClone(checkpoint.requestContract);\n\tif (!checkpoint.representation) return;\n\tconst accepted: unknown = JSON.parse(checkpoint.representation);\n\tif (!accepted || typeof accepted !== \"object\") throw new Error(\"Accepted context request contract is unavailable\");\n\tconst value = { ...accepted, replayContract: checkpoint.replayContract ?? \"complete-context\" };\n\tif (!isRequestContract(value)) throw new Error(\"Accepted context request contract is unavailable\");\n\treturn {\n\t\tapi: value.api,\n\t\tprovider: value.provider,\n\t\troute: value.route,\n\t\tmodel: value.model,\n\t\treplayContract: value.replayContract,\n\t};\n}\n\n/** Identity comes from the actual final native serialization, not a model/profile label. */\nexport function contextRequestContract(\n\trequest: ProviderRequestRepresentation,\n\treplayContract: ContextReplayContract,\n): ContextEpochRequestContract {\n\tconst route = requestTokenRouteIdentity(request.url);\n\tconst body: unknown = request.body === undefined ? undefined : JSON.parse(request.body);\n\tif (\n\t\t!route ||\n\t\t!body ||\n\t\ttypeof body !== \"object\" ||\n\t\t!(\"model\" in body) ||\n\t\ttypeof body.model !== \"string\" ||\n\t\t!body.model\n\t)\n\t\tthrow new Error(\"Native context request identity is unavailable\");\n\treturn { api: request.api, provider: request.provider, route, model: body.model, replayContract };\n}\n\nexport function assertContextRequestContract(\n\tcontract: ContextEpochRequestContract,\n\trequest: ProviderRequestRepresentation,\n\treplayContract: ContextReplayContract,\n): void {\n\tconst actual = contextRequestContract(request, replayContract);\n\tif (\n\t\tactual.api !== contract.api ||\n\t\tactual.provider !== contract.provider ||\n\t\tactual.route !== contract.route ||\n\t\tactual.model !== contract.model ||\n\t\tactual.replayContract !== contract.replayContract\n\t)\n\t\tthrow new Error(\"Retained context requires its accepted native request contract\");\n}\n\nexport function snapshotContextEpoch<T extends ContextEpochCheckpoint>(value: T, maxBytes: number): T {\n\treturn JSON.parse(stringifyBoundedJson(value, maxBytes)) as T;\n}\n\n/** Called only after checking the source frame's genuine epoch qualification. */\nexport function readContextEpoch(details: unknown, maxBytes: number): ContextEpochCheckpoint | undefined {\n\tif (!details || typeof details !== \"object\" || !(CONTEXT_EPOCH_DETAIL in details)) return;\n\tconst value: unknown = details[CONTEXT_EPOCH_DETAIL];\n\tif (\n\t\t!value ||\n\t\ttypeof value !== \"object\" ||\n\t\t!(\"version\" in value) ||\n\t\t!(\"renderer\" in value) ||\n\t\t!(\n\t\t\t(value.version === 1 && value.renderer === \"native-canonical-epoch/1\") ||\n\t\t\t(value.version === 2 && value.renderer === \"native-canonical-epoch/2\") ||\n\t\t\t(value.version === 3 && value.renderer === \"native-canonical-epoch/3\") ||\n\t\t\t(value.version === 4 && value.renderer === \"native-canonical-epoch/4\") ||\n\t\t\t(value.version === 5 && value.renderer === CONTEXT_POLICY_EPOCH_RENDERER) ||\n\t\t\t(value.version === 6 && value.renderer === CONTEXT_TOOL_EPOCH_RENDERER) ||\n\t\t\t(value.version === 8 && value.renderer === CONTEXT_TOOL_SUMMARY_RENDERER) ||\n\t\t\t([6, 8].includes(value.version as number) && value.renderer === CONTEXT_INTERRUPTED_TOOL_RENDERER) ||\n\t\t\t([4, 5, 6].includes(value.version as number) && value.renderer === CONTEXT_SKILL_EPOCH_RENDERER)\n\t\t) ||\n\t\t(value.renderer === CONTEXT_SKILL_EPOCH_RENDERER ||\n\t\t((value.version === 8 || value.renderer === CONTEXT_INTERRUPTED_TOOL_RENDERER) && \"selectedSkills\" in value)\n\t\t\t? !(\"selectedSkills\" in value) ||\n\t\t\t\t!Array.isArray(value.selectedSkills) ||\n\t\t\t\tvalue.selectedSkills.length === 0 ||\n\t\t\t\tvalue.selectedSkills.some(\n\t\t\t\t\t(item) =>\n\t\t\t\t\t\t!item ||\n\t\t\t\t\t\ttypeof item.name !== \"string\" ||\n\t\t\t\t\t\t!item.view ||\n\t\t\t\t\t\t![\"custom_message\", \"custom\"].includes(item.view.ref?.kind) ||\n\t\t\t\t\t\ttypeof item.view.sourceRevision !== \"string\",\n\t\t\t\t) ||\n\t\t\t\tnew Set(value.selectedSkills.map((item) => item.name)).size !== value.selectedSkills.length\n\t\t\t: \"selectedSkills\" in value) ||\n\t\t!(\"source\" in value) ||\n\t\t!value.source ||\n\t\t!(\"views\" in value) ||\n\t\t!Array.isArray(value.views) ||\n\t\t!(\"literalTailId\" in value) ||\n\t\ttypeof value.literalTailId !== \"string\" ||\n\t\t!(\"representation\" in value) ||\n\t\t(value.version === 5 || value.version === 8\n\t\t\t? !(\"mode\" in value) || (value.mode !== \"on\" && value.mode !== \"off\")\n\t\t\t: \"mode\" in value) ||\n\t\t(value.version === 8 &&\n\t\t\t(value.representation !== null || !(\"includeSummary\" in value) || value.includeSummary !== true)) ||\n\t\t(value.version === 5 &&\n\t\t\t(value.representation !== null || !(\"policyOnly\" in value) || value.policyOnly !== true)) ||\n\t\t(\"policyOnly\" in value &&\n\t\t\t(value.version !== 5 ||\n\t\t\t\tvalue.policyOnly !== true ||\n\t\t\t\tvalue.representation !== null ||\n\t\t\t\t\"includeSummary\" in value)) ||\n\t\t(\"pendingRequestContract\" in value &&\n\t\t\t(value.version !== 5 ||\n\t\t\t\t!(\"mode\" in value) ||\n\t\t\t\tvalue.mode !== \"off\" ||\n\t\t\t\tvalue.pendingRequestContract !== true ||\n\t\t\t\t\"requestContract\" in value)) ||\n\t\t(\"requestContract\" in value && (value.version !== 5 || !isRequestContract(value.requestContract))) ||\n\t\t!(\n\t\t\ttypeof value.representation === \"string\" ||\n\t\t\t(value.version === 5 && value.representation === null && \"policyOnly\" in value && value.policyOnly === true) ||\n\t\t\t((value.version === 2 || value.version === 3 || value.version === 4 || value.version === 8) &&\n\t\t\t\tvalue.representation === null &&\n\t\t\t\t\"includeSummary\" in value &&\n\t\t\t\tvalue.includeSummary === true)\n\t\t) ||\n\t\t(\"includeSummary\" in value &&\n\t\t\t((value.version !== 2 && value.version !== 3 && value.version !== 4 && value.version !== 8) ||\n\t\t\t\tvalue.includeSummary !== true ||\n\t\t\t\tvalue.representation !== null)) ||\n\t\t(\"replayContract\" in value &&\n\t\t\tvalue.replayContract !== \"complete-context\" &&\n\t\t\tvalue.replayContract !== \"message-groups\") ||\n\t\t(\"resourceRevision\" in value &&\n\t\t\t(typeof value.resourceRevision !== \"string\" ||\n\t\t\t\tBuffer.byteLength(value.resourceRevision, \"utf8\") > MAX_RESOURCE_REVISION_BYTES)) ||\n\t\t(\"publicWindow\" in value &&\n\t\t\t((value.version !== 3 &&\n\t\t\t\tvalue.version !== 4 &&\n\t\t\t\tvalue.version !== 5 &&\n\t\t\t\tvalue.version !== 6 &&\n\t\t\t\tvalue.version !== 8) ||\n\t\t\t\tvalue.publicWindow !== true)) ||\n\t\t(\"toolContinuations\" in value && value.version !== 6 && value.version !== 8) ||\n\t\t((value.version === 6 || value.version === 8) &&\n\t\t\t(!(\"toolContinuations\" in value) ||\n\t\t\t\t!Array.isArray(value.toolContinuations) ||\n\t\t\t\t!value.toolContinuations.length ||\n\t\t\t\t!(\"replayContract\" in value) ||\n\t\t\t\t(value.version === 6 &&\n\t\t\t\t\t(!(\"publicWindow\" in value) ||\n\t\t\t\t\t\tvalue.publicWindow !== true ||\n\t\t\t\t\t\tvalue.replayContract !== \"message-groups\")))) ||\n\t\t(\"continuation\" in value &&\n\t\t\t((value.version !== 3 &&\n\t\t\t\tvalue.version !== 4 &&\n\t\t\t\tvalue.version !== 5 &&\n\t\t\t\tvalue.version !== 6 &&\n\t\t\t\tvalue.version !== 8) ||\n\t\t\t\t!value.continuation ||\n\t\t\t\ttypeof value.continuation !== \"object\" ||\n\t\t\t\t!(\"kind\" in value.continuation) ||\n\t\t\t\t(value.continuation.kind !== \"harness-summary\" &&\n\t\t\t\t\t((value.version !== 4 && value.version !== 5 && value.version !== 6) ||\n\t\t\t\t\t\tvalue.continuation.kind !== \"portable-checkpoint\")) ||\n\t\t\t\t!(\"publicTailThrough\" in value.continuation) ||\n\t\t\t\t!value.continuation.publicTailThrough))\n\t)\n\t\tthrow new Error(\"Invalid committed context epoch\");\n\treturn snapshotContextEpoch(value as ContextEpochCheckpoint, maxBytes);\n}\n\n/** This configuration cannot be persisted as an epoch; it may still be valid full-native input. */\nexport class UnsupportedContextEpochConfigurationError extends Error {\n\tconstructor() {\n\t\tsuper(\"Unsupported context epoch request configuration\");\n\t\tthis.name = \"UnsupportedContextEpochConfigurationError\";\n\t}\n}\n\n/** Stable representation, not the changing input, an auth envelope, or a cache-hit claim. */\nexport function contextEpochRepresentation(\n\trequest: ProviderRequestRepresentation,\n\tassessment: RequestTokenAssessment | undefined,\n\tmaxBytes: number,\n\tunbudgetedPublic = false,\n\tresponseItemIdentity?: string,\n): string {\n\tif (\n\t\t(!assessment && !unbudgetedPublic) ||\n\t\t(assessment &&\n\t\t\t(!assessment.profile ||\n\t\t\t\tassessment.limitSource !== \"explicit-profile\" ||\n\t\t\t\t!assessment.route ||\n\t\t\t\t!assessment.model)) ||\n\t\trequest.body === undefined\n\t)\n\t\tthrow new Error(\"Committed context epoch requires its explicit request profile\");\n\tconst identity = assessment ?? contextRequestContract(request, \"message-groups\");\n\tconst body: unknown = JSON.parse(request.body);\n\tif (!body || typeof body !== \"object\" || Array.isArray(body))\n\t\tthrow new Error(\"Context epoch request representation is unavailable\");\n\tconst configuration: Record<string, unknown> = {};\n\tconst fields = new Set([\n\t\t\"model\",\n\t\t\"instructions\",\n\t\t\"stream\",\n\t\t\"max_output_tokens\",\n\t\t\"max_tokens\",\n\t\t\"max_completion_tokens\",\n\t\t\"temperature\",\n\t\t\"top_p\",\n\t\t\"text\",\n\t\t\"tools\",\n\t\t\"tool_choice\",\n\t\t\"parallel_tool_calls\",\n\t\t\"store\",\n\t\t\"reasoning\",\n\t\t\"service_tier\",\n\t\t\"truncation\",\n\t\t\"include\",\n\t\t\"prompt_cache_retention\",\n\t\t\"stream_options\",\n\t]);\n\tif (\n\t\trequest.api === \"openai-completions\" &&\n\t\trequest.provider === \"deepseek\" &&\n\t\trequest.url === \"https://api.deepseek.com/chat/completions\" &&\n\t\tidentity.route === request.url &&\n\t\t\"model\" in body &&\n\t\tbody.model === \"deepseek-flash\" &&\n\t\tidentity.model === body.model\n\t) {\n\t\tfields.add(\"thinking\");\n\t\tfields.add(\"reasoning_effort\");\n\t}\n\tfor (const [key, value] of Object.entries(body)) {\n\t\tif ([\"input\", \"messages\", \"previous_response_id\", \"prompt_cache_key\"].includes(key)) continue;\n\t\t// Unknown payload extensions may contain private data or change the representation.\n\t\tif (!fields.has(key)) throw new UnsupportedContextEpochConfigurationError();\n\t\tconfiguration[key] = value;\n\t}\n\tconst input: unknown = \"input\" in body ? body.input : \"messages\" in body ? body.messages : undefined;\n\tif (!Array.isArray(input)) throw new Error(\"Context epoch request messages are unavailable\");\n\tconst policy = input.filter(\n\t\t(item: unknown) =>\n\t\t\titem && typeof item === \"object\" && \"role\" in item && (item.role === \"system\" || item.role === \"developer\"),\n\t);\n\treturn stringifyBoundedJson(\n\t\t{\n\t\t\trenderer: CONTEXT_EPOCH_RENDERER,\n\t\t\t...(responseItemIdentity ? { responseItemIdentity } : {}),\n\t\t\tapi: request.api,\n\t\t\tprovider: request.provider,\n\t\t\troute: identity.route,\n\t\t\tmodel: identity.model,\n\t\t\t...(assessment\n\t\t\t\t? {\n\t\t\t\t\t\tprofile: assessment.profile,\n\t\t\t\t\t\tcontextTokens: assessment.contextTokens,\n\t\t\t\t\t\toutputReserveTokens: assessment.outputReserveTokens,\n\t\t\t\t\t}\n\t\t\t\t: { budget: \"unbudgeted\" }),\n\t\t\tconfiguration,\n\t\t\tpolicy,\n\t\t},\n\t\tmaxBytes,\n\t);\n}\n"]}
|
|
@@ -178,6 +178,13 @@ export function readContextEpoch(details, maxBytes) {
|
|
|
178
178
|
throw new Error("Invalid committed context epoch");
|
|
179
179
|
return snapshotContextEpoch(value, maxBytes);
|
|
180
180
|
}
|
|
181
|
+
/** This configuration cannot be persisted as an epoch; it may still be valid full-native input. */
|
|
182
|
+
export class UnsupportedContextEpochConfigurationError extends Error {
|
|
183
|
+
constructor() {
|
|
184
|
+
super("Unsupported context epoch request configuration");
|
|
185
|
+
this.name = "UnsupportedContextEpochConfigurationError";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
181
188
|
/** Stable representation, not the changing input, an auth envelope, or a cache-hit claim. */
|
|
182
189
|
export function contextEpochRepresentation(request, assessment, maxBytes, unbudgetedPublic = false, responseItemIdentity) {
|
|
183
190
|
if ((!assessment && !unbudgetedPublic) ||
|
|
@@ -229,7 +236,7 @@ export function contextEpochRepresentation(request, assessment, maxBytes, unbudg
|
|
|
229
236
|
continue;
|
|
230
237
|
// Unknown payload extensions may contain private data or change the representation.
|
|
231
238
|
if (!fields.has(key))
|
|
232
|
-
throw new
|
|
239
|
+
throw new UnsupportedContextEpochConfigurationError();
|
|
233
240
|
configuration[key] = value;
|
|
234
241
|
}
|
|
235
242
|
const input = "input" in body ? body.input : "messages" in body ? body.messages : undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-epoch.js","sourceRoot":"","sources":["../../src/core/context-epoch.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderRequestRepresentation, RequestTokenAssessment, Usage } from \"@ponythewhite/base-context-ai\";\nimport { requestTokenRouteIdentity } from \"@ponythewhite/base-context-ai\";\nimport { stringifyBoundedJson } from \"./bounded-json.js\";\nimport type { ContextRef, IndexedSourceEvent } from \"./history-index.js\";\nimport type { SourceSnapshotRef } from \"./request-events.js\";\nimport { MAX_RESOURCE_REVISION_BYTES } from \"./resource-view.js\";\nimport type { SelectedSkillReference } from \"./selected-skills.js\";\nimport type { CompiledTaskFrame } from \"./task-frame.js\";\n\nexport const CONTEXT_EPOCH_DETAIL = \"baseContextEpoch\";\n/** Internal admission, not a field accepted by ordinary appendCompaction callers. */\nexport const appendContextEpoch = Symbol(\"appendContextEpoch\");\nexport const CONTEXT_EPOCH_RENDERER = \"native-canonical-epoch/4\";\nexport const CONTEXT_POLICY_EPOCH_RENDERER = \"native-canonical-epoch/5\";\nexport const CONTEXT_TOOL_EPOCH_RENDERER = \"native-canonical-epoch/6\";\n/** Selection-bearing v4/v5/v6 variants; older readers must refuse rather than drop these refs. */\nexport const CONTEXT_SKILL_EPOCH_RENDERER = \"native-canonical-epoch/7\";\n/** Source-backed summary with retained public tool groups, not a measured MAIN request. */\nexport const CONTEXT_TOOL_SUMMARY_RENDERER = \"native-canonical-epoch/8\";\n/** Public recipes may record absent admission, never a fabricated execution outcome. */\nexport const CONTEXT_INTERRUPTED_TOOL_RENDERER = \"native-canonical-epoch/9\";\n\n/** Descriptive, source-backed outcomes in the existing accepted epoch, not an execution store. */\nexport interface ToolContinuationGroup {\n\treadonly assistantEntryId: string;\n\treadonly calls: readonly (\n\t\t| {\n\t\t\t\treadonly admission?: never;\n\t\t\t\treadonly executionId: string;\n\t\t\t\treadonly intent: Pick<IndexedSourceEvent, \"id\" | \"sequence\" | \"revision\">;\n\t\t\t\treadonly outcome: \"outcome_unknown\" | \"not_started\" | \"completed\" | \"failed\";\n\t\t\t\treadonly result?: Pick<IndexedSourceEvent, \"id\" | \"sequence\" | \"revision\">;\n\t\t }\n\t\t| {\n\t\t\t\treadonly admission: \"absent\";\n\t\t\t\t/** Absence is scoped to this exact captured branch prefix, not external effects. */\n\t\t\t\treadonly source: SourceSnapshotRef;\n\t\t\t\treadonly executionId?: never;\n\t\t\t\treadonly intent?: never;\n\t\t\t\treadonly outcome?: never;\n\t\t\t\treadonly result?: never;\n\t\t }\n\t)[];\n}\nexport type ContextMode = \"on\" | \"off\";\n\n/** Compatibility retained from an accepted native request, not measurement or replay credit. */\nexport interface ContextEpochRequestContract {\n\treadonly api: string;\n\treadonly provider: string;\n\treadonly route: string;\n\treadonly model: string;\n\treadonly replayContract: ContextReplayContract;\n}\nexport type ContextReplayContract = \"complete-context\" | \"message-groups\";\n\n/** An ordinary summary and its retained source recipes share the existing compaction ACK. */\nexport interface ContextEpochSummary {\n\treadonly summary: string;\n\treadonly details?: Record<string, unknown>;\n\treadonly fromHook?: boolean;\n\treadonly customInstructions?: string;\n\treadonly usage?: Usage;\n}\n\n/** A frozen read recipe, not a second copy of an archived message body. */\nexport interface EpochViewReference {\n\treadonly source: SourceSnapshotRef;\n\treadonly ref: ContextRef;\n\treadonly sourceRevision: string;\n\t/** Present only for an existing rendered compaction summary. */\n\treadonly retainedMessageCount?: number;\n\treadonly rendering?: \"public-history/1\" | \"public-tool-continuation/1\";\n}\n\ninterface ContextEpochFields {\n\treadonly renderer:\n\t\t| \"native-canonical-epoch/1\"\n\t\t| \"native-canonical-epoch/2\"\n\t\t| \"native-canonical-epoch/3\"\n\t\t| typeof CONTEXT_EPOCH_RENDERER\n\t\t| typeof CONTEXT_POLICY_EPOCH_RENDERER\n\t\t| typeof CONTEXT_TOOL_EPOCH_RENDERER\n\t\t| typeof CONTEXT_SKILL_EPOCH_RENDERER\n\t\t| typeof CONTEXT_TOOL_SUMMARY_RENDERER\n\t\t| typeof CONTEXT_INTERRUPTED_TOOL_RENDERER;\n\treadonly source: SourceSnapshotRef;\n\treadonly includeSummary?: true;\n\t/** Granted by an actual accepted adapter projection, never a caller profile name. */\n\treadonly replayContract?: ContextReplayContract;\n\t/** Actual adapter permission to leave completed native groups for a fresh public window. */\n\treadonly publicWindow?: true;\n\t/** Frozen public transition. Later native messages are not silently converted. */\n\treadonly continuation?: {\n\t\treadonly kind: \"harness-summary\" | \"portable-checkpoint\";\n\t\treadonly publicTailThrough: SourceSnapshotRef;\n\t};\n\treadonly views: readonly EpochViewReference[];\n\t/** Captured versions, not a body cache or authority inferred from transcript markup. */\n\treadonly selectedSkills?: readonly SelectedSkillReference[];\n\t/** v6 requests and v8 summaries retain whole public groups and their exact outcome refs. */\n\treadonly toolContinuations?: readonly ToolContinuationGroup[];\n\t/** Derived display only. The task reducer remains the authority for later changes. */\n\treadonly taskFrame?: CompiledTaskFrame;\n\t/** Accepted-state comparison only; saved metadata never establishes current resource liveness. */\n\treadonly resourceRevision?: string;\n\treadonly literalTailId: string;\n}\n\n/** v5 policy-only null is a mode ACK, not an ordinary summary or a measured request. */\nexport type ContextEpochCheckpoint = ContextEpochFields &\n\t(\n\t\t| {\n\t\t\t\treadonly version: 1 | 2 | 3 | 4 | 6;\n\t\t\t\treadonly representation: string | null;\n\t\t\t\treadonly mode?: never;\n\t\t\t\treadonly policyOnly?: never;\n\t\t\t\treadonly requestContract?: never;\n\t\t\t\treadonly pendingRequestContract?: never;\n\t\t }\n\t\t| {\n\t\t\t\treadonly version: 8;\n\t\t\t\treadonly mode: ContextMode;\n\t\t\t\treadonly representation: null;\n\t\t\t\treadonly includeSummary: true;\n\t\t\t\treadonly policyOnly?: never;\n\t\t\t\treadonly requestContract?: never;\n\t\t\t\treadonly pendingRequestContract?: never;\n\t\t }\n\t\t| {\n\t\t\t\treadonly version: 5;\n\t\t\t\treadonly mode: ContextMode;\n\t\t\t\treadonly representation: null;\n\t\t\t\treadonly policyOnly: true;\n\t\t\t\treadonly includeSummary?: never;\n\t\t\t\treadonly requestContract?: ContextEpochRequestContract;\n\t\t\t\treadonly pendingRequestContract?: true;\n\t\t }\n\t);\n\nexport function contextEpochMode(\n\tcheckpoint: ContextEpochCheckpoint | undefined,\n\tinitial: ContextMode = \"on\",\n): ContextMode {\n\treturn checkpoint ? (checkpoint.version === 5 || checkpoint.version === 8 ? checkpoint.mode : \"on\") : initial;\n}\n\nfunction isRequestContract(value: unknown): value is ContextEpochRequestContract {\n\tif (!value || typeof value !== \"object\") return false;\n\treturn (\n\t\t[\"api\", \"provider\", \"route\", \"model\"].every(\n\t\t\t(key) =>\n\t\t\t\tkey in value &&\n\t\t\t\ttypeof (value as Record<string, unknown>)[key] === \"string\" &&\n\t\t\t\t(value as Record<string, unknown>)[key] !== \"\",\n\t\t) &&\n\t\t\"replayContract\" in value &&\n\t\t(value.replayContract === \"complete-context\" || value.replayContract === \"message-groups\")\n\t);\n}\n\n/** Only call with a qualified checkpoint, never raw compaction marker data. */\nexport function retainedContextRequestContract(\n\tcheckpoint: ContextEpochCheckpoint | undefined,\n): ContextEpochRequestContract | undefined {\n\tif (!checkpoint) return;\n\tif (checkpoint.requestContract) return structuredClone(checkpoint.requestContract);\n\tif (!checkpoint.representation) return;\n\tconst accepted: unknown = JSON.parse(checkpoint.representation);\n\tif (!accepted || typeof accepted !== \"object\") throw new Error(\"Accepted context request contract is unavailable\");\n\tconst value = { ...accepted, replayContract: checkpoint.replayContract ?? \"complete-context\" };\n\tif (!isRequestContract(value)) throw new Error(\"Accepted context request contract is unavailable\");\n\treturn {\n\t\tapi: value.api,\n\t\tprovider: value.provider,\n\t\troute: value.route,\n\t\tmodel: value.model,\n\t\treplayContract: value.replayContract,\n\t};\n}\n\n/** Identity comes from the actual final native serialization, not a model/profile label. */\nexport function contextRequestContract(\n\trequest: ProviderRequestRepresentation,\n\treplayContract: ContextReplayContract,\n): ContextEpochRequestContract {\n\tconst route = requestTokenRouteIdentity(request.url);\n\tconst body: unknown = request.body === undefined ? undefined : JSON.parse(request.body);\n\tif (\n\t\t!route ||\n\t\t!body ||\n\t\ttypeof body !== \"object\" ||\n\t\t!(\"model\" in body) ||\n\t\ttypeof body.model !== \"string\" ||\n\t\t!body.model\n\t)\n\t\tthrow new Error(\"Native context request identity is unavailable\");\n\treturn { api: request.api, provider: request.provider, route, model: body.model, replayContract };\n}\n\nexport function assertContextRequestContract(\n\tcontract: ContextEpochRequestContract,\n\trequest: ProviderRequestRepresentation,\n\treplayContract: ContextReplayContract,\n): void {\n\tconst actual = contextRequestContract(request, replayContract);\n\tif (\n\t\tactual.api !== contract.api ||\n\t\tactual.provider !== contract.provider ||\n\t\tactual.route !== contract.route ||\n\t\tactual.model !== contract.model ||\n\t\tactual.replayContract !== contract.replayContract\n\t)\n\t\tthrow new Error(\"Retained context requires its accepted native request contract\");\n}\n\nexport function snapshotContextEpoch<T extends ContextEpochCheckpoint>(value: T, maxBytes: number): T {\n\treturn JSON.parse(stringifyBoundedJson(value, maxBytes)) as T;\n}\n\n/** Called only after checking the source frame's genuine epoch qualification. */\nexport function readContextEpoch(details: unknown, maxBytes: number): ContextEpochCheckpoint | undefined {\n\tif (!details || typeof details !== \"object\" || !(CONTEXT_EPOCH_DETAIL in details)) return;\n\tconst value: unknown = details[CONTEXT_EPOCH_DETAIL];\n\tif (\n\t\t!value ||\n\t\ttypeof value !== \"object\" ||\n\t\t!(\"version\" in value) ||\n\t\t!(\"renderer\" in value) ||\n\t\t!(\n\t\t\t(value.version === 1 && value.renderer === \"native-canonical-epoch/1\") ||\n\t\t\t(value.version === 2 && value.renderer === \"native-canonical-epoch/2\") ||\n\t\t\t(value.version === 3 && value.renderer === \"native-canonical-epoch/3\") ||\n\t\t\t(value.version === 4 && value.renderer === \"native-canonical-epoch/4\") ||\n\t\t\t(value.version === 5 && value.renderer === CONTEXT_POLICY_EPOCH_RENDERER) ||\n\t\t\t(value.version === 6 && value.renderer === CONTEXT_TOOL_EPOCH_RENDERER) ||\n\t\t\t(value.version === 8 && value.renderer === CONTEXT_TOOL_SUMMARY_RENDERER) ||\n\t\t\t([6, 8].includes(value.version as number) && value.renderer === CONTEXT_INTERRUPTED_TOOL_RENDERER) ||\n\t\t\t([4, 5, 6].includes(value.version as number) && value.renderer === CONTEXT_SKILL_EPOCH_RENDERER)\n\t\t) ||\n\t\t(value.renderer === CONTEXT_SKILL_EPOCH_RENDERER ||\n\t\t((value.version === 8 || value.renderer === CONTEXT_INTERRUPTED_TOOL_RENDERER) && \"selectedSkills\" in value)\n\t\t\t? !(\"selectedSkills\" in value) ||\n\t\t\t\t!Array.isArray(value.selectedSkills) ||\n\t\t\t\tvalue.selectedSkills.length === 0 ||\n\t\t\t\tvalue.selectedSkills.some(\n\t\t\t\t\t(item) =>\n\t\t\t\t\t\t!item ||\n\t\t\t\t\t\ttypeof item.name !== \"string\" ||\n\t\t\t\t\t\t!item.view ||\n\t\t\t\t\t\t![\"custom_message\", \"custom\"].includes(item.view.ref?.kind) ||\n\t\t\t\t\t\ttypeof item.view.sourceRevision !== \"string\",\n\t\t\t\t) ||\n\t\t\t\tnew Set(value.selectedSkills.map((item) => item.name)).size !== value.selectedSkills.length\n\t\t\t: \"selectedSkills\" in value) ||\n\t\t!(\"source\" in value) ||\n\t\t!value.source ||\n\t\t!(\"views\" in value) ||\n\t\t!Array.isArray(value.views) ||\n\t\t!(\"literalTailId\" in value) ||\n\t\ttypeof value.literalTailId !== \"string\" ||\n\t\t!(\"representation\" in value) ||\n\t\t(value.version === 5 || value.version === 8\n\t\t\t? !(\"mode\" in value) || (value.mode !== \"on\" && value.mode !== \"off\")\n\t\t\t: \"mode\" in value) ||\n\t\t(value.version === 8 &&\n\t\t\t(value.representation !== null || !(\"includeSummary\" in value) || value.includeSummary !== true)) ||\n\t\t(value.version === 5 &&\n\t\t\t(value.representation !== null || !(\"policyOnly\" in value) || value.policyOnly !== true)) ||\n\t\t(\"policyOnly\" in value &&\n\t\t\t(value.version !== 5 ||\n\t\t\t\tvalue.policyOnly !== true ||\n\t\t\t\tvalue.representation !== null ||\n\t\t\t\t\"includeSummary\" in value)) ||\n\t\t(\"pendingRequestContract\" in value &&\n\t\t\t(value.version !== 5 ||\n\t\t\t\t!(\"mode\" in value) ||\n\t\t\t\tvalue.mode !== \"off\" ||\n\t\t\t\tvalue.pendingRequestContract !== true ||\n\t\t\t\t\"requestContract\" in value)) ||\n\t\t(\"requestContract\" in value && (value.version !== 5 || !isRequestContract(value.requestContract))) ||\n\t\t!(\n\t\t\ttypeof value.representation === \"string\" ||\n\t\t\t(value.version === 5 && value.representation === null && \"policyOnly\" in value && value.policyOnly === true) ||\n\t\t\t((value.version === 2 || value.version === 3 || value.version === 4 || value.version === 8) &&\n\t\t\t\tvalue.representation === null &&\n\t\t\t\t\"includeSummary\" in value &&\n\t\t\t\tvalue.includeSummary === true)\n\t\t) ||\n\t\t(\"includeSummary\" in value &&\n\t\t\t((value.version !== 2 && value.version !== 3 && value.version !== 4 && value.version !== 8) ||\n\t\t\t\tvalue.includeSummary !== true ||\n\t\t\t\tvalue.representation !== null)) ||\n\t\t(\"replayContract\" in value &&\n\t\t\tvalue.replayContract !== \"complete-context\" &&\n\t\t\tvalue.replayContract !== \"message-groups\") ||\n\t\t(\"resourceRevision\" in value &&\n\t\t\t(typeof value.resourceRevision !== \"string\" ||\n\t\t\t\tBuffer.byteLength(value.resourceRevision, \"utf8\") > MAX_RESOURCE_REVISION_BYTES)) ||\n\t\t(\"publicWindow\" in value &&\n\t\t\t((value.version !== 3 &&\n\t\t\t\tvalue.version !== 4 &&\n\t\t\t\tvalue.version !== 5 &&\n\t\t\t\tvalue.version !== 6 &&\n\t\t\t\tvalue.version !== 8) ||\n\t\t\t\tvalue.publicWindow !== true)) ||\n\t\t(\"toolContinuations\" in value && value.version !== 6 && value.version !== 8) ||\n\t\t((value.version === 6 || value.version === 8) &&\n\t\t\t(!(\"toolContinuations\" in value) ||\n\t\t\t\t!Array.isArray(value.toolContinuations) ||\n\t\t\t\t!value.toolContinuations.length ||\n\t\t\t\t!(\"replayContract\" in value) ||\n\t\t\t\t(value.version === 6 &&\n\t\t\t\t\t(!(\"publicWindow\" in value) ||\n\t\t\t\t\t\tvalue.publicWindow !== true ||\n\t\t\t\t\t\tvalue.replayContract !== \"message-groups\")))) ||\n\t\t(\"continuation\" in value &&\n\t\t\t((value.version !== 3 &&\n\t\t\t\tvalue.version !== 4 &&\n\t\t\t\tvalue.version !== 5 &&\n\t\t\t\tvalue.version !== 6 &&\n\t\t\t\tvalue.version !== 8) ||\n\t\t\t\t!value.continuation ||\n\t\t\t\ttypeof value.continuation !== \"object\" ||\n\t\t\t\t!(\"kind\" in value.continuation) ||\n\t\t\t\t(value.continuation.kind !== \"harness-summary\" &&\n\t\t\t\t\t((value.version !== 4 && value.version !== 5 && value.version !== 6) ||\n\t\t\t\t\t\tvalue.continuation.kind !== \"portable-checkpoint\")) ||\n\t\t\t\t!(\"publicTailThrough\" in value.continuation) ||\n\t\t\t\t!value.continuation.publicTailThrough))\n\t)\n\t\tthrow new Error(\"Invalid committed context epoch\");\n\treturn snapshotContextEpoch(value as ContextEpochCheckpoint, maxBytes);\n}\n\n/** Stable representation, not the changing input, an auth envelope, or a cache-hit claim. */\nexport function contextEpochRepresentation(\n\trequest: ProviderRequestRepresentation,\n\tassessment: RequestTokenAssessment | undefined,\n\tmaxBytes: number,\n\tunbudgetedPublic = false,\n\tresponseItemIdentity?: string,\n): string {\n\tif (\n\t\t(!assessment && !unbudgetedPublic) ||\n\t\t(assessment &&\n\t\t\t(!assessment.profile ||\n\t\t\t\tassessment.limitSource !== \"explicit-profile\" ||\n\t\t\t\t!assessment.route ||\n\t\t\t\t!assessment.model)) ||\n\t\trequest.body === undefined\n\t)\n\t\tthrow new Error(\"Committed context epoch requires its explicit request profile\");\n\tconst identity = assessment ?? contextRequestContract(request, \"message-groups\");\n\tconst body: unknown = JSON.parse(request.body);\n\tif (!body || typeof body !== \"object\" || Array.isArray(body))\n\t\tthrow new Error(\"Context epoch request representation is unavailable\");\n\tconst configuration: Record<string, unknown> = {};\n\tconst fields = new Set([\n\t\t\"model\",\n\t\t\"instructions\",\n\t\t\"stream\",\n\t\t\"max_output_tokens\",\n\t\t\"max_tokens\",\n\t\t\"max_completion_tokens\",\n\t\t\"temperature\",\n\t\t\"top_p\",\n\t\t\"text\",\n\t\t\"tools\",\n\t\t\"tool_choice\",\n\t\t\"parallel_tool_calls\",\n\t\t\"store\",\n\t\t\"reasoning\",\n\t\t\"service_tier\",\n\t\t\"truncation\",\n\t\t\"include\",\n\t\t\"prompt_cache_retention\",\n\t\t\"stream_options\",\n\t]);\n\tif (\n\t\trequest.api === \"openai-completions\" &&\n\t\trequest.provider === \"deepseek\" &&\n\t\trequest.url === \"https://api.deepseek.com/chat/completions\" &&\n\t\tidentity.route === request.url &&\n\t\t\"model\" in body &&\n\t\tbody.model === \"deepseek-flash\" &&\n\t\tidentity.model === body.model\n\t) {\n\t\tfields.add(\"thinking\");\n\t\tfields.add(\"reasoning_effort\");\n\t}\n\tfor (const [key, value] of Object.entries(body)) {\n\t\tif ([\"input\", \"messages\", \"previous_response_id\", \"prompt_cache_key\"].includes(key)) continue;\n\t\t// Unknown payload extensions may contain private data or change the representation.\n\t\tif (!fields.has(key)) throw new Error(\"Unsupported context epoch request configuration\");\n\t\tconfiguration[key] = value;\n\t}\n\tconst input: unknown = \"input\" in body ? body.input : \"messages\" in body ? body.messages : undefined;\n\tif (!Array.isArray(input)) throw new Error(\"Context epoch request messages are unavailable\");\n\tconst policy = input.filter(\n\t\t(item: unknown) =>\n\t\t\titem && typeof item === \"object\" && \"role\" in item && (item.role === \"system\" || item.role === \"developer\"),\n\t);\n\treturn stringifyBoundedJson(\n\t\t{\n\t\t\trenderer: CONTEXT_EPOCH_RENDERER,\n\t\t\t...(responseItemIdentity ? { responseItemIdentity } : {}),\n\t\t\tapi: request.api,\n\t\t\tprovider: request.provider,\n\t\t\troute: identity.route,\n\t\t\tmodel: identity.model,\n\t\t\t...(assessment\n\t\t\t\t? {\n\t\t\t\t\t\tprofile: assessment.profile,\n\t\t\t\t\t\tcontextTokens: assessment.contextTokens,\n\t\t\t\t\t\toutputReserveTokens: assessment.outputReserveTokens,\n\t\t\t\t\t}\n\t\t\t\t: { budget: \"unbudgeted\" }),\n\t\t\tconfiguration,\n\t\t\tpolicy,\n\t\t},\n\t\tmaxBytes,\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-epoch.js","sourceRoot":"","sources":["../../src/core/context-epoch.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderRequestRepresentation, RequestTokenAssessment, Usage } from \"@ponythewhite/base-context-ai\";\nimport { requestTokenRouteIdentity } from \"@ponythewhite/base-context-ai\";\nimport { stringifyBoundedJson } from \"./bounded-json.js\";\nimport type { ContextRef, IndexedSourceEvent } from \"./history-index.js\";\nimport type { SourceSnapshotRef } from \"./request-events.js\";\nimport { MAX_RESOURCE_REVISION_BYTES } from \"./resource-view.js\";\nimport type { SelectedSkillReference } from \"./selected-skills.js\";\nimport type { CompiledTaskFrame } from \"./task-frame.js\";\n\nexport const CONTEXT_EPOCH_DETAIL = \"baseContextEpoch\";\n/** Internal admission, not a field accepted by ordinary appendCompaction callers. */\nexport const appendContextEpoch = Symbol(\"appendContextEpoch\");\nexport const CONTEXT_EPOCH_RENDERER = \"native-canonical-epoch/4\";\nexport const CONTEXT_POLICY_EPOCH_RENDERER = \"native-canonical-epoch/5\";\nexport const CONTEXT_TOOL_EPOCH_RENDERER = \"native-canonical-epoch/6\";\n/** Selection-bearing v4/v5/v6 variants; older readers must refuse rather than drop these refs. */\nexport const CONTEXT_SKILL_EPOCH_RENDERER = \"native-canonical-epoch/7\";\n/** Source-backed summary with retained public tool groups, not a measured MAIN request. */\nexport const CONTEXT_TOOL_SUMMARY_RENDERER = \"native-canonical-epoch/8\";\n/** Public recipes may record absent admission, never a fabricated execution outcome. */\nexport const CONTEXT_INTERRUPTED_TOOL_RENDERER = \"native-canonical-epoch/9\";\n\n/** Descriptive, source-backed outcomes in the existing accepted epoch, not an execution store. */\nexport interface ToolContinuationGroup {\n\treadonly assistantEntryId: string;\n\treadonly calls: readonly (\n\t\t| {\n\t\t\t\treadonly admission?: never;\n\t\t\t\treadonly executionId: string;\n\t\t\t\treadonly intent: Pick<IndexedSourceEvent, \"id\" | \"sequence\" | \"revision\">;\n\t\t\t\treadonly outcome: \"outcome_unknown\" | \"not_started\" | \"completed\" | \"failed\";\n\t\t\t\treadonly result?: Pick<IndexedSourceEvent, \"id\" | \"sequence\" | \"revision\">;\n\t\t }\n\t\t| {\n\t\t\t\treadonly admission: \"absent\";\n\t\t\t\t/** Absence is scoped to this exact captured branch prefix, not external effects. */\n\t\t\t\treadonly source: SourceSnapshotRef;\n\t\t\t\treadonly executionId?: never;\n\t\t\t\treadonly intent?: never;\n\t\t\t\treadonly outcome?: never;\n\t\t\t\treadonly result?: never;\n\t\t }\n\t)[];\n}\nexport type ContextMode = \"on\" | \"off\";\n\n/** Compatibility retained from an accepted native request, not measurement or replay credit. */\nexport interface ContextEpochRequestContract {\n\treadonly api: string;\n\treadonly provider: string;\n\treadonly route: string;\n\treadonly model: string;\n\treadonly replayContract: ContextReplayContract;\n}\nexport type ContextReplayContract = \"complete-context\" | \"message-groups\";\n\n/** An ordinary summary and its retained source recipes share the existing compaction ACK. */\nexport interface ContextEpochSummary {\n\treadonly summary: string;\n\treadonly details?: Record<string, unknown>;\n\treadonly fromHook?: boolean;\n\treadonly customInstructions?: string;\n\treadonly usage?: Usage;\n}\n\n/** A frozen read recipe, not a second copy of an archived message body. */\nexport interface EpochViewReference {\n\treadonly source: SourceSnapshotRef;\n\treadonly ref: ContextRef;\n\treadonly sourceRevision: string;\n\t/** Present only for an existing rendered compaction summary. */\n\treadonly retainedMessageCount?: number;\n\treadonly rendering?: \"public-history/1\" | \"public-tool-continuation/1\";\n}\n\ninterface ContextEpochFields {\n\treadonly renderer:\n\t\t| \"native-canonical-epoch/1\"\n\t\t| \"native-canonical-epoch/2\"\n\t\t| \"native-canonical-epoch/3\"\n\t\t| typeof CONTEXT_EPOCH_RENDERER\n\t\t| typeof CONTEXT_POLICY_EPOCH_RENDERER\n\t\t| typeof CONTEXT_TOOL_EPOCH_RENDERER\n\t\t| typeof CONTEXT_SKILL_EPOCH_RENDERER\n\t\t| typeof CONTEXT_TOOL_SUMMARY_RENDERER\n\t\t| typeof CONTEXT_INTERRUPTED_TOOL_RENDERER;\n\treadonly source: SourceSnapshotRef;\n\treadonly includeSummary?: true;\n\t/** Granted by an actual accepted adapter projection, never a caller profile name. */\n\treadonly replayContract?: ContextReplayContract;\n\t/** Actual adapter permission to leave completed native groups for a fresh public window. */\n\treadonly publicWindow?: true;\n\t/** Frozen public transition. Later native messages are not silently converted. */\n\treadonly continuation?: {\n\t\treadonly kind: \"harness-summary\" | \"portable-checkpoint\";\n\t\treadonly publicTailThrough: SourceSnapshotRef;\n\t};\n\treadonly views: readonly EpochViewReference[];\n\t/** Captured versions, not a body cache or authority inferred from transcript markup. */\n\treadonly selectedSkills?: readonly SelectedSkillReference[];\n\t/** v6 requests and v8 summaries retain whole public groups and their exact outcome refs. */\n\treadonly toolContinuations?: readonly ToolContinuationGroup[];\n\t/** Derived display only. The task reducer remains the authority for later changes. */\n\treadonly taskFrame?: CompiledTaskFrame;\n\t/** Accepted-state comparison only; saved metadata never establishes current resource liveness. */\n\treadonly resourceRevision?: string;\n\treadonly literalTailId: string;\n}\n\n/** v5 policy-only null is a mode ACK, not an ordinary summary or a measured request. */\nexport type ContextEpochCheckpoint = ContextEpochFields &\n\t(\n\t\t| {\n\t\t\t\treadonly version: 1 | 2 | 3 | 4 | 6;\n\t\t\t\treadonly representation: string | null;\n\t\t\t\treadonly mode?: never;\n\t\t\t\treadonly policyOnly?: never;\n\t\t\t\treadonly requestContract?: never;\n\t\t\t\treadonly pendingRequestContract?: never;\n\t\t }\n\t\t| {\n\t\t\t\treadonly version: 8;\n\t\t\t\treadonly mode: ContextMode;\n\t\t\t\treadonly representation: null;\n\t\t\t\treadonly includeSummary: true;\n\t\t\t\treadonly policyOnly?: never;\n\t\t\t\treadonly requestContract?: never;\n\t\t\t\treadonly pendingRequestContract?: never;\n\t\t }\n\t\t| {\n\t\t\t\treadonly version: 5;\n\t\t\t\treadonly mode: ContextMode;\n\t\t\t\treadonly representation: null;\n\t\t\t\treadonly policyOnly: true;\n\t\t\t\treadonly includeSummary?: never;\n\t\t\t\treadonly requestContract?: ContextEpochRequestContract;\n\t\t\t\treadonly pendingRequestContract?: true;\n\t\t }\n\t);\n\nexport function contextEpochMode(\n\tcheckpoint: ContextEpochCheckpoint | undefined,\n\tinitial: ContextMode = \"on\",\n): ContextMode {\n\treturn checkpoint ? (checkpoint.version === 5 || checkpoint.version === 8 ? checkpoint.mode : \"on\") : initial;\n}\n\nfunction isRequestContract(value: unknown): value is ContextEpochRequestContract {\n\tif (!value || typeof value !== \"object\") return false;\n\treturn (\n\t\t[\"api\", \"provider\", \"route\", \"model\"].every(\n\t\t\t(key) =>\n\t\t\t\tkey in value &&\n\t\t\t\ttypeof (value as Record<string, unknown>)[key] === \"string\" &&\n\t\t\t\t(value as Record<string, unknown>)[key] !== \"\",\n\t\t) &&\n\t\t\"replayContract\" in value &&\n\t\t(value.replayContract === \"complete-context\" || value.replayContract === \"message-groups\")\n\t);\n}\n\n/** Only call with a qualified checkpoint, never raw compaction marker data. */\nexport function retainedContextRequestContract(\n\tcheckpoint: ContextEpochCheckpoint | undefined,\n): ContextEpochRequestContract | undefined {\n\tif (!checkpoint) return;\n\tif (checkpoint.requestContract) return structuredClone(checkpoint.requestContract);\n\tif (!checkpoint.representation) return;\n\tconst accepted: unknown = JSON.parse(checkpoint.representation);\n\tif (!accepted || typeof accepted !== \"object\") throw new Error(\"Accepted context request contract is unavailable\");\n\tconst value = { ...accepted, replayContract: checkpoint.replayContract ?? \"complete-context\" };\n\tif (!isRequestContract(value)) throw new Error(\"Accepted context request contract is unavailable\");\n\treturn {\n\t\tapi: value.api,\n\t\tprovider: value.provider,\n\t\troute: value.route,\n\t\tmodel: value.model,\n\t\treplayContract: value.replayContract,\n\t};\n}\n\n/** Identity comes from the actual final native serialization, not a model/profile label. */\nexport function contextRequestContract(\n\trequest: ProviderRequestRepresentation,\n\treplayContract: ContextReplayContract,\n): ContextEpochRequestContract {\n\tconst route = requestTokenRouteIdentity(request.url);\n\tconst body: unknown = request.body === undefined ? undefined : JSON.parse(request.body);\n\tif (\n\t\t!route ||\n\t\t!body ||\n\t\ttypeof body !== \"object\" ||\n\t\t!(\"model\" in body) ||\n\t\ttypeof body.model !== \"string\" ||\n\t\t!body.model\n\t)\n\t\tthrow new Error(\"Native context request identity is unavailable\");\n\treturn { api: request.api, provider: request.provider, route, model: body.model, replayContract };\n}\n\nexport function assertContextRequestContract(\n\tcontract: ContextEpochRequestContract,\n\trequest: ProviderRequestRepresentation,\n\treplayContract: ContextReplayContract,\n): void {\n\tconst actual = contextRequestContract(request, replayContract);\n\tif (\n\t\tactual.api !== contract.api ||\n\t\tactual.provider !== contract.provider ||\n\t\tactual.route !== contract.route ||\n\t\tactual.model !== contract.model ||\n\t\tactual.replayContract !== contract.replayContract\n\t)\n\t\tthrow new Error(\"Retained context requires its accepted native request contract\");\n}\n\nexport function snapshotContextEpoch<T extends ContextEpochCheckpoint>(value: T, maxBytes: number): T {\n\treturn JSON.parse(stringifyBoundedJson(value, maxBytes)) as T;\n}\n\n/** Called only after checking the source frame's genuine epoch qualification. */\nexport function readContextEpoch(details: unknown, maxBytes: number): ContextEpochCheckpoint | undefined {\n\tif (!details || typeof details !== \"object\" || !(CONTEXT_EPOCH_DETAIL in details)) return;\n\tconst value: unknown = details[CONTEXT_EPOCH_DETAIL];\n\tif (\n\t\t!value ||\n\t\ttypeof value !== \"object\" ||\n\t\t!(\"version\" in value) ||\n\t\t!(\"renderer\" in value) ||\n\t\t!(\n\t\t\t(value.version === 1 && value.renderer === \"native-canonical-epoch/1\") ||\n\t\t\t(value.version === 2 && value.renderer === \"native-canonical-epoch/2\") ||\n\t\t\t(value.version === 3 && value.renderer === \"native-canonical-epoch/3\") ||\n\t\t\t(value.version === 4 && value.renderer === \"native-canonical-epoch/4\") ||\n\t\t\t(value.version === 5 && value.renderer === CONTEXT_POLICY_EPOCH_RENDERER) ||\n\t\t\t(value.version === 6 && value.renderer === CONTEXT_TOOL_EPOCH_RENDERER) ||\n\t\t\t(value.version === 8 && value.renderer === CONTEXT_TOOL_SUMMARY_RENDERER) ||\n\t\t\t([6, 8].includes(value.version as number) && value.renderer === CONTEXT_INTERRUPTED_TOOL_RENDERER) ||\n\t\t\t([4, 5, 6].includes(value.version as number) && value.renderer === CONTEXT_SKILL_EPOCH_RENDERER)\n\t\t) ||\n\t\t(value.renderer === CONTEXT_SKILL_EPOCH_RENDERER ||\n\t\t((value.version === 8 || value.renderer === CONTEXT_INTERRUPTED_TOOL_RENDERER) && \"selectedSkills\" in value)\n\t\t\t? !(\"selectedSkills\" in value) ||\n\t\t\t\t!Array.isArray(value.selectedSkills) ||\n\t\t\t\tvalue.selectedSkills.length === 0 ||\n\t\t\t\tvalue.selectedSkills.some(\n\t\t\t\t\t(item) =>\n\t\t\t\t\t\t!item ||\n\t\t\t\t\t\ttypeof item.name !== \"string\" ||\n\t\t\t\t\t\t!item.view ||\n\t\t\t\t\t\t![\"custom_message\", \"custom\"].includes(item.view.ref?.kind) ||\n\t\t\t\t\t\ttypeof item.view.sourceRevision !== \"string\",\n\t\t\t\t) ||\n\t\t\t\tnew Set(value.selectedSkills.map((item) => item.name)).size !== value.selectedSkills.length\n\t\t\t: \"selectedSkills\" in value) ||\n\t\t!(\"source\" in value) ||\n\t\t!value.source ||\n\t\t!(\"views\" in value) ||\n\t\t!Array.isArray(value.views) ||\n\t\t!(\"literalTailId\" in value) ||\n\t\ttypeof value.literalTailId !== \"string\" ||\n\t\t!(\"representation\" in value) ||\n\t\t(value.version === 5 || value.version === 8\n\t\t\t? !(\"mode\" in value) || (value.mode !== \"on\" && value.mode !== \"off\")\n\t\t\t: \"mode\" in value) ||\n\t\t(value.version === 8 &&\n\t\t\t(value.representation !== null || !(\"includeSummary\" in value) || value.includeSummary !== true)) ||\n\t\t(value.version === 5 &&\n\t\t\t(value.representation !== null || !(\"policyOnly\" in value) || value.policyOnly !== true)) ||\n\t\t(\"policyOnly\" in value &&\n\t\t\t(value.version !== 5 ||\n\t\t\t\tvalue.policyOnly !== true ||\n\t\t\t\tvalue.representation !== null ||\n\t\t\t\t\"includeSummary\" in value)) ||\n\t\t(\"pendingRequestContract\" in value &&\n\t\t\t(value.version !== 5 ||\n\t\t\t\t!(\"mode\" in value) ||\n\t\t\t\tvalue.mode !== \"off\" ||\n\t\t\t\tvalue.pendingRequestContract !== true ||\n\t\t\t\t\"requestContract\" in value)) ||\n\t\t(\"requestContract\" in value && (value.version !== 5 || !isRequestContract(value.requestContract))) ||\n\t\t!(\n\t\t\ttypeof value.representation === \"string\" ||\n\t\t\t(value.version === 5 && value.representation === null && \"policyOnly\" in value && value.policyOnly === true) ||\n\t\t\t((value.version === 2 || value.version === 3 || value.version === 4 || value.version === 8) &&\n\t\t\t\tvalue.representation === null &&\n\t\t\t\t\"includeSummary\" in value &&\n\t\t\t\tvalue.includeSummary === true)\n\t\t) ||\n\t\t(\"includeSummary\" in value &&\n\t\t\t((value.version !== 2 && value.version !== 3 && value.version !== 4 && value.version !== 8) ||\n\t\t\t\tvalue.includeSummary !== true ||\n\t\t\t\tvalue.representation !== null)) ||\n\t\t(\"replayContract\" in value &&\n\t\t\tvalue.replayContract !== \"complete-context\" &&\n\t\t\tvalue.replayContract !== \"message-groups\") ||\n\t\t(\"resourceRevision\" in value &&\n\t\t\t(typeof value.resourceRevision !== \"string\" ||\n\t\t\t\tBuffer.byteLength(value.resourceRevision, \"utf8\") > MAX_RESOURCE_REVISION_BYTES)) ||\n\t\t(\"publicWindow\" in value &&\n\t\t\t((value.version !== 3 &&\n\t\t\t\tvalue.version !== 4 &&\n\t\t\t\tvalue.version !== 5 &&\n\t\t\t\tvalue.version !== 6 &&\n\t\t\t\tvalue.version !== 8) ||\n\t\t\t\tvalue.publicWindow !== true)) ||\n\t\t(\"toolContinuations\" in value && value.version !== 6 && value.version !== 8) ||\n\t\t((value.version === 6 || value.version === 8) &&\n\t\t\t(!(\"toolContinuations\" in value) ||\n\t\t\t\t!Array.isArray(value.toolContinuations) ||\n\t\t\t\t!value.toolContinuations.length ||\n\t\t\t\t!(\"replayContract\" in value) ||\n\t\t\t\t(value.version === 6 &&\n\t\t\t\t\t(!(\"publicWindow\" in value) ||\n\t\t\t\t\t\tvalue.publicWindow !== true ||\n\t\t\t\t\t\tvalue.replayContract !== \"message-groups\")))) ||\n\t\t(\"continuation\" in value &&\n\t\t\t((value.version !== 3 &&\n\t\t\t\tvalue.version !== 4 &&\n\t\t\t\tvalue.version !== 5 &&\n\t\t\t\tvalue.version !== 6 &&\n\t\t\t\tvalue.version !== 8) ||\n\t\t\t\t!value.continuation ||\n\t\t\t\ttypeof value.continuation !== \"object\" ||\n\t\t\t\t!(\"kind\" in value.continuation) ||\n\t\t\t\t(value.continuation.kind !== \"harness-summary\" &&\n\t\t\t\t\t((value.version !== 4 && value.version !== 5 && value.version !== 6) ||\n\t\t\t\t\t\tvalue.continuation.kind !== \"portable-checkpoint\")) ||\n\t\t\t\t!(\"publicTailThrough\" in value.continuation) ||\n\t\t\t\t!value.continuation.publicTailThrough))\n\t)\n\t\tthrow new Error(\"Invalid committed context epoch\");\n\treturn snapshotContextEpoch(value as ContextEpochCheckpoint, maxBytes);\n}\n\n/** This configuration cannot be persisted as an epoch; it may still be valid full-native input. */\nexport class UnsupportedContextEpochConfigurationError extends Error {\n\tconstructor() {\n\t\tsuper(\"Unsupported context epoch request configuration\");\n\t\tthis.name = \"UnsupportedContextEpochConfigurationError\";\n\t}\n}\n\n/** Stable representation, not the changing input, an auth envelope, or a cache-hit claim. */\nexport function contextEpochRepresentation(\n\trequest: ProviderRequestRepresentation,\n\tassessment: RequestTokenAssessment | undefined,\n\tmaxBytes: number,\n\tunbudgetedPublic = false,\n\tresponseItemIdentity?: string,\n): string {\n\tif (\n\t\t(!assessment && !unbudgetedPublic) ||\n\t\t(assessment &&\n\t\t\t(!assessment.profile ||\n\t\t\t\tassessment.limitSource !== \"explicit-profile\" ||\n\t\t\t\t!assessment.route ||\n\t\t\t\t!assessment.model)) ||\n\t\trequest.body === undefined\n\t)\n\t\tthrow new Error(\"Committed context epoch requires its explicit request profile\");\n\tconst identity = assessment ?? contextRequestContract(request, \"message-groups\");\n\tconst body: unknown = JSON.parse(request.body);\n\tif (!body || typeof body !== \"object\" || Array.isArray(body))\n\t\tthrow new Error(\"Context epoch request representation is unavailable\");\n\tconst configuration: Record<string, unknown> = {};\n\tconst fields = new Set([\n\t\t\"model\",\n\t\t\"instructions\",\n\t\t\"stream\",\n\t\t\"max_output_tokens\",\n\t\t\"max_tokens\",\n\t\t\"max_completion_tokens\",\n\t\t\"temperature\",\n\t\t\"top_p\",\n\t\t\"text\",\n\t\t\"tools\",\n\t\t\"tool_choice\",\n\t\t\"parallel_tool_calls\",\n\t\t\"store\",\n\t\t\"reasoning\",\n\t\t\"service_tier\",\n\t\t\"truncation\",\n\t\t\"include\",\n\t\t\"prompt_cache_retention\",\n\t\t\"stream_options\",\n\t]);\n\tif (\n\t\trequest.api === \"openai-completions\" &&\n\t\trequest.provider === \"deepseek\" &&\n\t\trequest.url === \"https://api.deepseek.com/chat/completions\" &&\n\t\tidentity.route === request.url &&\n\t\t\"model\" in body &&\n\t\tbody.model === \"deepseek-flash\" &&\n\t\tidentity.model === body.model\n\t) {\n\t\tfields.add(\"thinking\");\n\t\tfields.add(\"reasoning_effort\");\n\t}\n\tfor (const [key, value] of Object.entries(body)) {\n\t\tif ([\"input\", \"messages\", \"previous_response_id\", \"prompt_cache_key\"].includes(key)) continue;\n\t\t// Unknown payload extensions may contain private data or change the representation.\n\t\tif (!fields.has(key)) throw new UnsupportedContextEpochConfigurationError();\n\t\tconfiguration[key] = value;\n\t}\n\tconst input: unknown = \"input\" in body ? body.input : \"messages\" in body ? body.messages : undefined;\n\tif (!Array.isArray(input)) throw new Error(\"Context epoch request messages are unavailable\");\n\tconst policy = input.filter(\n\t\t(item: unknown) =>\n\t\t\titem && typeof item === \"object\" && \"role\" in item && (item.role === \"system\" || item.role === \"developer\"),\n\t);\n\treturn stringifyBoundedJson(\n\t\t{\n\t\t\trenderer: CONTEXT_EPOCH_RENDERER,\n\t\t\t...(responseItemIdentity ? { responseItemIdentity } : {}),\n\t\t\tapi: request.api,\n\t\t\tprovider: request.provider,\n\t\t\troute: identity.route,\n\t\t\tmodel: identity.model,\n\t\t\t...(assessment\n\t\t\t\t? {\n\t\t\t\t\t\tprofile: assessment.profile,\n\t\t\t\t\t\tcontextTokens: assessment.contextTokens,\n\t\t\t\t\t\toutputReserveTokens: assessment.outputReserveTokens,\n\t\t\t\t\t}\n\t\t\t\t: { budget: \"unbudgeted\" }),\n\t\t\tconfiguration,\n\t\t\tpolicy,\n\t\t},\n\t\tmaxBytes,\n\t);\n}\n"]}
|
|
@@ -2,6 +2,7 @@ import type { Usage } from "@ponythewhite/base-context-ai";
|
|
|
2
2
|
import type { RlmChildAgentStatus } from "./agent-session.js";
|
|
3
3
|
import type { ContextUsage } from "./extensions/index.js";
|
|
4
4
|
import type { SourceSnapshotRef } from "./request-events.js";
|
|
5
|
+
import { type OwnRequestUsage } from "./request-usage.js";
|
|
5
6
|
import type { SessionHistoryReadLimits } from "./session-history-index.js";
|
|
6
7
|
import { type SessionEntry, type SessionManager } from "./session-manager.js";
|
|
7
8
|
/** Resolves a model's context window so disk-only nodes can report utilization. */
|
|
@@ -21,6 +22,8 @@ export interface ContextTreeNode {
|
|
|
21
22
|
};
|
|
22
23
|
ownUsage: Usage;
|
|
23
24
|
totalUsage: Usage;
|
|
25
|
+
/** Existing generation receipts for this session's captured source, never child aggregates. */
|
|
26
|
+
ownRequestUsage?: OwnRequestUsage;
|
|
24
27
|
contextUsage?: ContextUsage;
|
|
25
28
|
children: ContextTreeNode[];
|
|
26
29
|
}
|
|
@@ -30,7 +33,7 @@ export interface ContextTreeRequestLimits extends SessionHistoryReadLimits {
|
|
|
30
33
|
maxMetadataBytes: number;
|
|
31
34
|
maxDirectoryEntries: number;
|
|
32
35
|
}
|
|
33
|
-
/** Small request-local counters and one
|
|
36
|
+
/** Small request-local counters and one history-projection reduction tail. */
|
|
34
37
|
export declare class ContextTreeRequest {
|
|
35
38
|
readonly limits: Readonly<ContextTreeRequestLimits>;
|
|
36
39
|
private nodes;
|
|
@@ -61,26 +64,26 @@ export declare function computeOwnAndTotalUsage(branch: SessionEntry[], allEntri
|
|
|
61
64
|
ownUsage: Usage;
|
|
62
65
|
totalUsage: Usage;
|
|
63
66
|
};
|
|
67
|
+
interface ContextTreeUsage {
|
|
68
|
+
ownUsage: Usage;
|
|
69
|
+
totalUsage: Usage;
|
|
70
|
+
ownRequestUsage?: OwnRequestUsage;
|
|
71
|
+
hasPostCompactionUsage?: boolean;
|
|
72
|
+
}
|
|
64
73
|
/** Complete bounded snapshot of an explicitly resident Manager, never an index-error fallback.
|
|
65
74
|
* This synchronous reduction runs in the pre-await live-tree capture walk. It never
|
|
66
75
|
* retains a decoded resident snapshot while native/disk work waits for a slot.
|
|
67
76
|
*/
|
|
68
|
-
export declare function readResidentContextTreeUsage(manager: SessionManager, limits?: SessionHistoryReadLimits, availabilityMaxSourceBytes?: number):
|
|
69
|
-
ownUsage: Usage;
|
|
70
|
-
totalUsage: Usage;
|
|
71
|
-
hasPostCompactionUsage?: boolean;
|
|
72
|
-
};
|
|
77
|
+
export declare function readResidentContextTreeUsage(manager: SessionManager, limits?: SessionHistoryReadLimits, availabilityMaxSourceBytes?: number): ContextTreeUsage;
|
|
73
78
|
/** Detached, complete source usage and its exact captured parent branch. */
|
|
74
|
-
export declare function readContextTreeUsage(manager: SessionManager, limits?: SessionHistoryReadLimits, request?: ContextTreeRequest, availabilityMaxSourceBytes?: number): Promise<{
|
|
79
|
+
export declare function readContextTreeUsage(manager: SessionManager, limits?: SessionHistoryReadLimits, request?: ContextTreeRequest, availabilityMaxSourceBytes?: number): Promise<(ContextTreeUsage & {
|
|
75
80
|
source: SourceSnapshotRef;
|
|
76
|
-
|
|
77
|
-
totalUsage: Usage;
|
|
78
|
-
hasPostCompactionUsage?: boolean;
|
|
79
|
-
} | undefined>;
|
|
81
|
+
}) | undefined>;
|
|
80
82
|
/** Complete or refuse, sharing the request's slot and counters with descendants.
|
|
81
83
|
* Internal identity is an already-admitted registered run, including its empty placeholder.
|
|
82
84
|
*/
|
|
83
85
|
export declare function loadContextTreeChildFromDisk(childSessionDir: string, resolveContextWindow: ContextWindowResolver, limits?: Partial<ContextTreeRequestLimits> | ContextTreeRequest, identity?: Pick<ContextTreeNode, "id" | "label" | "status">): Promise<ContextTreeNode | undefined>;
|
|
84
86
|
/** Persisted children, in existing directory order, excluding already represented live IDs. */
|
|
85
87
|
export declare function loadContextTreeChildrenFromDisk(rlmSessionDir: string | undefined, resolveContextWindow: ContextWindowResolver, skipIds?: ReadonlySet<string>, limits?: Partial<ContextTreeRequestLimits> | ContextTreeRequest): Promise<ContextTreeNode[]>;
|
|
88
|
+
export {};
|
|
86
89
|
//# sourceMappingURL=context-tree.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-tree.d.ts","sourceRoot":"","sources":["../../src/core/context-tree.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, opendirSync, statSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport type { AssistantMessage, Usage } from \"@ponythewhite/base-context-ai\";\nimport type { RlmChildAgentStatus } from \"./agent-session.js\";\nimport { stringifyBoundedJson } from \"./bounded-json.js\";\nimport { calculateContextTokens, estimateContextTokens } from \"./compaction/index.js\";\nimport { exportHistoryLimits, readSessionHistoryFile } from \"./export-html/history.js\";\nimport type { ContextUsage } from \"./extensions/index.js\";\nimport type { ParentPathCursor } from \"./history-index.js\";\nimport type { SourceSnapshotRef } from \"./request-events.js\";\nimport type { SessionHistoryReadLimits } from \"./session-history-index.js\";\nimport {\n\tapplyChildUsageAttributions,\n\tbuildSessionContext,\n\ttype SessionEntry,\n\ttype SessionManager,\n} from \"./session-manager.js\";\nimport { addAssistantUsage, cloneUsage, emptyUsage, subtractAssistantUsage } from \"./usage.js\";\n\n/** Resolves a model's context window so disk-only nodes can report utilization. */\nexport type ContextWindowResolver = (provider: string, modelId: string) => number | undefined;\n\n/**\n * One agent in the context overview: the main session or an RLM (sub-)agent.\n * `ownUsage` excludes descendants; `totalUsage` includes completed descendants, matching /usage.\n */\nexport interface ContextTreeNode {\n\t/** \"root\" for the session itself; sub-xxxx for an RLM child. */\n\tid: string;\n\tlabel: string;\n\tstatus: \"active\" | RlmChildAgentStatus;\n\tmodel?: { provider: string; id: string };\n\townUsage: Usage;\n\ttotalUsage: Usage;\n\tcontextUsage?: ContextUsage;\n\tchildren: ContextTreeNode[];\n}\n\n/** Shared by one overview request, not by concurrent requests or the process. */\nexport interface ContextTreeRequestLimits extends SessionHistoryReadLimits {\n\tmaxNodes: number;\n\tmaxMetadataBytes: number;\n\tmaxDirectoryEntries: number;\n}\n\nclass ContextTreeLimitError extends Error {}\n\n/** Small request-local counters and one full-history reduction tail. */\nexport class ContextTreeRequest {\n\treadonly limits: Readonly<ContextTreeRequestLimits>;\n\tprivate nodes = 0;\n\tprivate metadataBytes = 0;\n\tprivate directoryEntries = 0;\n\tprivate readTail: Promise<void> = Promise.resolve();\n\n\tconstructor(limits: Partial<ContextTreeRequestLimits> = {}) {\n\t\tthis.limits = Object.freeze({\n\t\t\t...exportHistoryLimits(limits),\n\t\t\tmaxNodes: limits.maxNodes ?? 256,\n\t\t\tmaxMetadataBytes: limits.maxMetadataBytes ?? 4 * 1024 * 1024,\n\t\t\tmaxDirectoryEntries: limits.maxDirectoryEntries ?? 16_384,\n\t\t});\n\t\tif (!Object.values(this.limits).every((value) => Number.isSafeInteger(value) && value > 0))\n\t\t\tthrow new Error(\"Invalid context tree request limits\");\n\t}\n\n\tadmitNode(): void {\n\t\tif (this.nodes >= this.limits.maxNodes) throw new ContextTreeLimitError(\"Context tree node budget exceeded\");\n\t\tthis.nodes++;\n\t}\n\n\tretainMetadata(value: unknown): number {\n\t\tlet json: string;\n\t\ttry {\n\t\t\tjson = stringifyBoundedJson(value, this.limits.maxMetadataBytes - this.metadataBytes);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message === \"JSON byte limit exceeded\")\n\t\t\t\tthrow new ContextTreeLimitError(\"Context tree metadata byte budget exceeded\", { cause: error });\n\t\t\tthrow error;\n\t\t}\n\t\tconst bytes = Buffer.byteLength(json);\n\t\tthis.metadataBytes += bytes;\n\t\treturn bytes;\n\t}\n\n\treleaseMetadata(bytes: number): void {\n\t\tthis.metadataBytes -= bytes;\n\t}\n\n\tdirectoryEntry(): void {\n\t\tif (this.directoryEntries >= this.limits.maxDirectoryEntries)\n\t\t\tthrow new ContextTreeLimitError(\"Context tree directory entry budget exceeded\");\n\t\tthis.directoryEntries++;\n\t}\n\n\tread<T>(read: () => Promise<T>): Promise<T> {\n\t\tconst result = this.readTail.then(read);\n\t\tthis.readTail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n}\n\nfunction treeRequest(limits: Partial<ContextTreeRequestLimits> | ContextTreeRequest): ContextTreeRequest {\n\treturn limits instanceof ContextTreeRequest ? limits : new ContextTreeRequest(limits);\n}\n\nfunction isAssistantEntry(entry: SessionEntry): entry is SessionEntry & {\n\ttype: \"message\";\n\tmessage: AssistantMessage;\n} {\n\treturn entry.type === \"message\" && entry.message.role === \"assistant\";\n}\n\nfunction readUserMessageText(content: unknown): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\tif (!Array.isArray(content)) {\n\t\treturn \"\";\n\t}\n\treturn content\n\t\t.filter(\n\t\t\t(block): block is { type: \"text\"; text: string } =>\n\t\t\t\ttypeof block === \"object\" &&\n\t\t\t\tblock !== null &&\n\t\t\t\t(block as { type?: unknown }).type === \"text\" &&\n\t\t\t\ttypeof (block as { text?: unknown }).text === \"string\",\n\t\t)\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\nfunction compactLabel(text: string, maxLength = 80): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\tif (compact.length <= maxLength) {\n\t\treturn compact;\n\t}\n\treturn `${compact.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;\n}\n\n/**\n * Usage totals for one agent: `totalUsage` sums the branch's assistant usage\n * (attributed aggregates, so descendants are included), `ownUsage` removes the\n * attributions targeting those assistants. Attribution entries are matched by\n * target across ALL entries, not just the branch: attributions rewrite the\n * target assistant's usage no matter which branch they were appended on, so a\n * fork that keeps the assistant but drops the attribution entry must still\n * subtract it.\n *\n * Totals are deliberately cumulative across compactions: compaction shrinks\n * the model-facing context, not what the session has spent, so assistants\n * dropped from the resolved context still count here.\n */\nexport function computeOwnAndTotalUsage(\n\tbranch: SessionEntry[],\n\tallEntries: SessionEntry[],\n): { ownUsage: Usage; totalUsage: Usage } {\n\tconst totalUsage = emptyUsage();\n\tconst branchAssistantIds = new Set<string>();\n\tfor (const entry of branch) {\n\t\tif (isAssistantEntry(entry)) {\n\t\t\tbranchAssistantIds.add(entry.id);\n\t\t\taddAssistantUsage(totalUsage, entry.message.usage);\n\t\t} else if ((entry.type === \"compaction\" || entry.type === \"branch_summary\") && entry.usage) {\n\t\t\taddAssistantUsage(totalUsage, entry.usage);\n\t\t}\n\t}\n\tconst ownUsage = cloneUsage(totalUsage);\n\tfor (const entry of allEntries) {\n\t\tif (entry.type === \"child_usage_attributed\" && branchAssistantIds.has(entry.targetId)) {\n\t\t\tsubtractAssistantUsage(ownUsage, entry.childUsage);\n\t\t}\n\t}\n\treturn { ownUsage, totalUsage };\n}\n\n/** Complete bounded snapshot of an explicitly resident Manager, never an index-error fallback.\n * This synchronous reduction runs in the pre-await live-tree capture walk. It never\n * retains a decoded resident snapshot while native/disk work waits for a slot.\n */\nexport function readResidentContextTreeUsage(\n\tmanager: SessionManager,\n\tlimits: SessionHistoryReadLimits = { maxEntries: 16_384, maxSourceBytes: 64 * 1024 * 1024 },\n\tavailabilityMaxSourceBytes?: number,\n): { ownUsage: Usage; totalUsage: Usage; hasPostCompactionUsage?: boolean } {\n\tconst snapshot = manager.materializeResidentHistory(limits);\n\tconst branch = branchEntries(snapshot.entries, snapshot.leafId, availabilityMaxSourceBytes !== undefined);\n\tif (availabilityMaxSourceBytes !== undefined) {\n\t\tif (!Number.isSafeInteger(availabilityMaxSourceBytes) || availabilityMaxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid parent-path materialization limits\");\n\t\tif (branch.length > 16_384) throw new Error(\"Parent-path entry budget exceeded\");\n\t\tlet bytes = 0;\n\t\tfor (const entry of branch) {\n\t\t\tbytes += Buffer.byteLength(stringifyBoundedJson(entry, availabilityMaxSourceBytes - bytes));\n\t\t}\n\t}\n\treturn {\n\t\t...computeOwnAndTotalUsage(branch, snapshot.entries),\n\t\t...(availabilityMaxSourceBytes === undefined ? {} : { hasPostCompactionUsage: hasPostCompactionUsage(branch) }),\n\t};\n}\n\n/** Detached, complete source usage and its exact captured parent branch. */\nexport async function readContextTreeUsage(\n\tmanager: SessionManager,\n\tlimits: SessionHistoryReadLimits = { maxEntries: 16_384, maxSourceBytes: 64 * 1024 * 1024 },\n\trequest?: ContextTreeRequest,\n\tavailabilityMaxSourceBytes?: number,\n): Promise<\n\t{ source: SourceSnapshotRef; ownUsage: Usage; totalUsage: Usage; hasPostCompactionUsage?: boolean } | undefined\n> {\n\tif (!manager.supportsCapturedHistoryReads()) return undefined;\n\tconst sourceLimits = request?.limits ?? limits;\n\tconst capturedLimits = { maxEntries: sourceLimits.maxEntries, maxSourceBytes: sourceLimits.maxSourceBytes };\n\t// The actual source frontier binds NOW, never after waiting for the reduction slot.\n\treturn manager.readSourceHistory((history) => {\n\t\trequest?.retainMetadata(history.source);\n\t\tconst reduce = async () => {\n\t\t\tconst materialized = await history.materialize(capturedLimits);\n\t\t\tconst allEntries = materialized.entries.map(({ entry }) => entry);\n\t\t\tapplyChildUsageAttributions(allEntries);\n\t\t\tconst byId = new Map(allEntries.map((entry) => [entry.id, entry]));\n\t\t\tconst branch: SessionEntry[] = [];\n\t\t\tlet cursor: ParentPathCursor | undefined;\n\t\t\tdo {\n\t\t\t\tconst page = await history.parentPath({ cursor });\n\t\t\t\tfor (const reference of page.events) {\n\t\t\t\t\tconst entry = byId.get(reference.id);\n\t\t\t\t\tif (!entry) throw new Error(\"Context-tree parent-path entry source is unavailable\");\n\t\t\t\t\tbranch.push(entry);\n\t\t\t\t}\n\t\t\t\tcursor = page.nextCursor ?? undefined;\n\t\t\t} while (cursor);\n\t\t\tlet available: boolean | undefined;\n\t\t\tif (availabilityMaxSourceBytes !== undefined) {\n\t\t\t\tconst bootstrap = await history.branchBootstrap();\n\t\t\t\tavailable = !bootstrap.latestCompaction;\n\t\t\t\tconst reference = bootstrap.contextUsageAssistant;\n\t\t\t\tif (bootstrap.latestCompaction && reference) {\n\t\t\t\t\tconst updates = await history.branchContext.contextUpdates({\n\t\t\t\t\t\tkind: \"assistant-usage\",\n\t\t\t\t\t\ttargetId: reference.id,\n\t\t\t\t\t});\n\t\t\t\t\tconst bytes =\n\t\t\t\t\t\treference.locator.length + updates.refs.reduce((sum, update) => sum + update.locator.length, 0);\n\t\t\t\t\tif (bytes > availabilityMaxSourceBytes) throw new Error(\"Context usage source byte budget exceeded\");\n\t\t\t\t\tconst assistant = byId.get(reference.id);\n\t\t\t\t\tif (!assistant || !isAssistantEntry(assistant))\n\t\t\t\t\t\tthrow new Error(\"Context usage assistant source is unavailable\");\n\t\t\t\t\t// Full-source ordered projection above includes off-branch attributions.\n\t\t\t\t\tavailable = calculateContextTokens(assistant.message.usage) > 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst usage = {\n\t\t\t\t...computeOwnAndTotalUsage(branch, allEntries),\n\t\t\t\t...(available === undefined ? {} : { hasPostCompactionUsage: available }),\n\t\t\t};\n\t\t\trequest?.retainMetadata(usage);\n\t\t\treturn { source: history.source, ...usage };\n\t\t};\n\t\treturn request ? request.read(reduce) : reduce();\n\t});\n}\n\nfunction hasPostCompactionUsage(branch: SessionEntry[]): boolean {\n\tlet boundary = -1;\n\tfor (let index = branch.length - 1; index >= 0; index--) {\n\t\tif (branch[index].type === \"compaction\") {\n\t\t\tboundary = index;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (boundary < 0) return true;\n\tfor (let index = branch.length - 1; index > boundary; index--) {\n\t\tconst entry = branch[index];\n\t\tif (!isAssistantEntry(entry)) continue;\n\t\tif (entry.message.stopReason !== \"aborted\" && entry.message.stopReason !== \"error\")\n\t\t\treturn calculateContextTokens(entry.message.usage) > 0;\n\t}\n\treturn false;\n}\n\n/**\n * Current context utilization from persisted entries, mirroring\n * AgentSession.getContextUsage(): unknown right after a compaction until the\n * next assistant response, otherwise the last assistant usage plus an\n * estimate for trailing messages (tool results, queued user input) that have\n * not hit the model yet.\n */\nfunction computeContextUsageFromEntries(\n\tallEntries: SessionEntry[],\n\tbranch: SessionEntry[],\n\tcontextWindow: number | undefined,\n): ContextUsage | undefined {\n\tif (!contextWindow || contextWindow <= 0) {\n\t\treturn undefined;\n\t}\n\n\tif (!hasPostCompactionUsage(branch)) {\n\t\treturn { tokens: null, contextWindow, percent: null };\n\t}\n\n\tconst estimate = estimateContextTokens(buildSessionContext(allEntries).messages);\n\tif (estimate.tokens <= 0) {\n\t\treturn undefined;\n\t}\n\treturn { tokens: estimate.tokens, contextWindow, percent: (estimate.tokens / contextWindow) * 100 };\n}\n\n/**\n * Entries on the current branch, root to leaf, mirroring\n * SessionManager.getBranch(): the leaf is the last appended entry and the\n * branch is its parentId chain. Keeps forked/abandoned paths out of usage\n * sums so disk nodes match what a live session would report.\n */\nfunction branchEntries(entries: SessionEntry[], leafId?: string | null, strict = false): SessionEntry[] {\n\tif (entries.length === 0) {\n\t\tif (strict && leafId !== undefined && leafId !== null) throw new Error(\"Parent path lineage is unresolved\");\n\t\treturn [];\n\t}\n\tconst byId = new Map(entries.map((entry) => [entry.id, entry]));\n\tconst branch: SessionEntry[] = [];\n\tconst seen = new Set<string>();\n\tlet current: SessionEntry | undefined =\n\t\tleafId === undefined ? entries[entries.length - 1] : leafId === null ? undefined : byId.get(leafId);\n\tif (strict && leafId !== undefined && leafId !== null && !current)\n\t\tthrow new Error(\"Parent path lineage is unresolved\");\n\twhile (current && !seen.has(current.id)) {\n\t\tseen.add(current.id);\n\t\tbranch.push(current);\n\t\tconst parentId = current.parentId;\n\t\tconst hasParent = strict ? parentId !== null : !!parentId;\n\t\tcurrent = hasParent ? byId.get(parentId!) : undefined;\n\t\tif (strict && hasParent && !current) throw new Error(\"Parent path lineage is unresolved\");\n\t}\n\tif (strict && current) throw new Error(\"Parent path lineage is unresolved\");\n\treturn branch.reverse();\n}\n\n/**\n * Terminal status for a persisted child, inferred from how its last assistant\n * turn ended: errored and aborted runs should not render as successful.\n */\nfunction statusFromBranch(entries: SessionEntry[]): \"done\" | \"error\" | \"cancelled\" {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tconst entry = entries[i];\n\t\tif (!isAssistantEntry(entry)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (entry.message.stopReason === \"error\") {\n\t\t\treturn \"error\";\n\t\t}\n\t\tif (entry.message.stopReason === \"aborted\") {\n\t\t\treturn \"cancelled\";\n\t\t}\n\t\treturn \"done\";\n\t}\n\treturn \"done\";\n}\n\n/** Stream names; opening/reading errors keep the caller's existing policy. */\nfunction visitDirectory(dirPath: string, request: ContextTreeRequest, visit: (name: string) => void): void {\n\tconst dir = opendirSync(dirPath);\n\ttry {\n\t\tfor (let entry = dir.readSync(); entry !== null; entry = dir.readSync()) {\n\t\t\trequest.directoryEntry();\n\t\t\tvisit(entry.name);\n\t\t}\n\t} catch (error) {\n\t\ttry {\n\t\t\tdir.closeSync();\n\t\t} catch (closeError) {\n\t\t\tthrow new AggregateError([error, closeError], \"Context tree directory read and close failed\");\n\t\t}\n\t\tthrow error;\n\t}\n\tdir.closeSync();\n}\n\n// readdirSync used UTF8 lexical order; retain its stable mtime-tie ordering.\nfunction comparePaths(a: string, b: string): number {\n\treturn Buffer.compare(Buffer.from(a), Buffer.from(b));\n}\n\nfunction findSessionFile(dir: string, request: ContextTreeRequest): { path: string; bytes: number } | undefined {\n\tlet newest: { path: string; mtime: number; bytes: number } | undefined;\n\ttry {\n\t\tvisitDirectory(dir, request, (name) => {\n\t\t\tif (!name.endsWith(\".jsonl\")) return;\n\t\t\tconst path = join(dir, name);\n\t\t\tlet mtime: number;\n\t\t\ttry {\n\t\t\t\tmtime = statSync(path).mtime.getTime();\n\t\t\t} catch {\n\t\t\t\treturn; // Skip unreadable files.\n\t\t\t}\n\t\t\tif (!newest || mtime > newest.mtime || (mtime === newest.mtime && comparePaths(path, newest.path) < 0)) {\n\t\t\t\tif (newest) request.releaseMetadata(newest.bytes);\n\t\t\t\tnewest = undefined;\n\t\t\t\tconst bytes = request.retainMetadata(path);\n\t\t\t\tnewest = { path, mtime, bytes };\n\t\t\t}\n\t\t});\n\t\treturn newest;\n\t} catch (error) {\n\t\tif (newest) request.releaseMetadata(newest.bytes);\n\t\tthrow error;\n\t}\n}\n\nfunction listChildSessionDirs(rlmSessionDir: string, request: ContextTreeRequest): { paths: string[]; bytes: number } {\n\tconst paths: string[] = [];\n\tlet bytes = 0;\n\ttry {\n\t\tvisitDirectory(rlmSessionDir, request, (name) => {\n\t\t\tif (!name.startsWith(\"sub-\")) return;\n\t\t\tconst path = join(rlmSessionDir, name);\n\t\t\ttry {\n\t\t\t\tif (!statSync(path).isDirectory()) return;\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbytes += request.retainMetadata(path);\n\t\t\tpaths.push(path);\n\t\t});\n\t} catch (error) {\n\t\trequest.releaseMetadata(bytes);\n\t\tif (error instanceof ContextTreeLimitError || error instanceof AggregateError) throw error;\n\t\treturn { paths: [], bytes: 0 };\n\t}\n\tpaths.sort(comparePaths).sort((a, b) => {\n\t\ttry {\n\t\t\treturn statSync(a).mtime.getTime() - statSync(b).mtime.getTime();\n\t\t} catch {\n\t\t\treturn 0;\n\t\t}\n\t});\n\treturn { paths, bytes };\n}\n\n/**\n * Build a context node for a completed RLM child from its persisted session\n * dir (sub-xxxx/). Children that already attributed grandchild usage carry the\n * aggregate on their assistant messages (applyChildUsageAttributions), so own\n * usage is recovered by subtracting the attribution entries. Returns undefined\n * when the dir holds no readable session.\n */\nasync function readContextTreeChildNodeFromDisk(\n\tchildSessionDir: string,\n\tsessionFile: string,\n\tresolveContextWindow: ContextWindowResolver,\n\trequest: ContextTreeRequest,\n\tidentity?: Pick<ContextTreeNode, \"id\" | \"label\" | \"status\">,\n): Promise<ContextTreeNode | undefined> {\n\tconst allEntries = (await readSessionHistoryFile(sessionFile, request.limits)).filter(\n\t\t(entry): entry is SessionEntry => entry.type !== \"session\",\n\t);\n\tconst branch = branchEntries(allEntries);\n\tif (branch.length === 0) {\n\t\treturn undefined;\n\t}\n\n\tconst { ownUsage, totalUsage } = computeOwnAndTotalUsage(branch, allEntries);\n\n\tlet model: { provider: string; id: string } | undefined;\n\tfor (const entry of branch) {\n\t\tif (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, id: entry.modelId };\n\t\t}\n\t}\n\n\tlet label = \"\";\n\tfor (const entry of branch) {\n\t\tif (entry.type === \"message\" && entry.message.role === \"user\") {\n\t\t\tlabel = compactLabel(readUserMessageText(entry.message.content));\n\t\t\tif (label) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst contextWindow = model ? resolveContextWindow(model.provider, model.id) : undefined;\n\n\tconst metadata = {\n\t\t...(identity ?? {\n\t\t\tid: basename(childSessionDir),\n\t\t\tlabel: label || \"child agent\",\n\t\t\tstatus: statusFromBranch(branch),\n\t\t}),\n\t\tmodel,\n\t\townUsage,\n\t\ttotalUsage,\n\t\tcontextUsage: computeContextUsageFromEntries(allEntries, branch, contextWindow),\n\t};\n\t// A registered run's identity was already admitted by its live parent.\n\trequest.retainMetadata(identity ? { model, ownUsage, totalUsage, contextUsage: metadata.contextUsage } : metadata);\n\treturn { ...metadata, children: [] };\n}\n\n/** Complete or refuse, sharing the request's slot and counters with descendants.\n * Internal identity is an already-admitted registered run, including its empty placeholder.\n */\nexport async function loadContextTreeChildFromDisk(\n\tchildSessionDir: string,\n\tresolveContextWindow: ContextWindowResolver,\n\tlimits: Partial<ContextTreeRequestLimits> | ContextTreeRequest = {},\n\tidentity?: Pick<ContextTreeNode, \"id\" | \"label\" | \"status\">,\n): Promise<ContextTreeNode | undefined> {\n\tconst request = treeRequest(limits);\n\tconst directoryBytes = request.retainMetadata(childSessionDir);\n\tlet sessionFile: { path: string; bytes: number } | undefined;\n\tlet node: ContextTreeNode | undefined;\n\ttry {\n\t\tsessionFile = findSessionFile(childSessionDir, request);\n\t\tif (sessionFile && existsSync(sessionFile.path)) {\n\t\t\t// A header-only history still consumes one bounded source admission.\n\t\t\tif (!identity) request.admitNode();\n\t\t\tnode = await request.read(() =>\n\t\t\t\treadContextTreeChildNodeFromDisk(\n\t\t\t\t\tchildSessionDir,\n\t\t\t\t\tsessionFile!.path,\n\t\t\t\t\tresolveContextWindow,\n\t\t\t\t\trequest,\n\t\t\t\t\tidentity,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t} finally {\n\t\tif (sessionFile) request.releaseMetadata(sessionFile.bytes);\n\t\trequest.releaseMetadata(directoryBytes);\n\t}\n\tif (node) {\n\t\t// The full source has been reduced and the serial slot released before recursion.\n\t\tnode.children = await loadContextTreeChildrenFromDisk(childSessionDir, resolveContextWindow, undefined, request);\n\t} else if (identity) {\n\t\tconst usage = { ownUsage: emptyUsage(), totalUsage: emptyUsage() };\n\t\trequest.retainMetadata(usage);\n\t\tnode = { ...identity, ...usage, children: [] };\n\t}\n\treturn node;\n}\n\n/** Persisted children, in existing directory order, excluding already represented live IDs. */\nexport async function loadContextTreeChildrenFromDisk(\n\trlmSessionDir: string | undefined,\n\tresolveContextWindow: ContextWindowResolver,\n\tskipIds?: ReadonlySet<string>,\n\tlimits: Partial<ContextTreeRequestLimits> | ContextTreeRequest = {},\n): Promise<ContextTreeNode[]> {\n\tconst request = treeRequest(limits);\n\tconst skippedIds = new Set<string>();\n\tlet metadataBytes = 0;\n\ttry {\n\t\t// A caller-provided skip set is bounded before copying, too.\n\t\tif (skipIds && skipIds.size > request.limits.maxDirectoryEntries)\n\t\t\tthrow new ContextTreeLimitError(\"Context tree directory entry budget exceeded\");\n\t\tfor (const id of skipIds ?? []) {\n\t\t\tmetadataBytes += request.retainMetadata(id);\n\t\t\tskippedIds.add(id);\n\t\t}\n\t\tif (!rlmSessionDir || !existsSync(rlmSessionDir)) return [];\n\t\tmetadataBytes += request.retainMetadata(rlmSessionDir);\n\t\tconst directories = listChildSessionDirs(rlmSessionDir, request);\n\t\tmetadataBytes += directories.bytes;\n\t\tconst nodes: ContextTreeNode[] = [];\n\t\tfor (const childDir of directories.paths) {\n\t\t\tif (skippedIds.has(basename(childDir))) continue;\n\t\t\tconst node = await loadContextTreeChildFromDisk(childDir, resolveContextWindow, request);\n\t\t\tif (node) nodes.push(node);\n\t\t}\n\t\treturn nodes;\n\t} finally {\n\t\trequest.releaseMetadata(metadataBytes);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-tree.d.ts","sourceRoot":"","sources":["../../src/core/context-tree.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, opendirSync, statSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport type { AssistantMessage, Usage } from \"@ponythewhite/base-context-ai\";\nimport type { RlmChildAgentStatus } from \"./agent-session.js\";\nimport { stringifyBoundedJson } from \"./bounded-json.js\";\nimport { calculateContextTokens, estimateContextTokens } from \"./compaction/index.js\";\nimport { exportHistoryLimits } from \"./export-html/history.js\";\nimport type { ContextUsage } from \"./extensions/index.js\";\nimport type { IndexedSourceEvent, ParentPathCursor } from \"./history-index.js\";\nimport type { SourceSnapshotRef } from \"./request-events.js\";\nimport { type OwnRequestUsage, RequestUsageAccumulator } from \"./request-usage.js\";\nimport type { SessionHistoryReadLimits } from \"./session-history-index.js\";\nimport { readCapturedSessionJournal } from \"./session-journal-reader.js\";\nimport {\n\tapplyChildUsageAttributions,\n\tbuildSessionContext,\n\ttype FileEntry,\n\ttype SessionEntry,\n\ttype SessionManager,\n} from \"./session-manager.js\";\nimport { addAssistantUsage, cloneUsage, emptyUsage, subtractAssistantUsage } from \"./usage.js\";\n\n/** Resolves a model's context window so disk-only nodes can report utilization. */\nexport type ContextWindowResolver = (provider: string, modelId: string) => number | undefined;\n\n/**\n * One agent in the context overview: the main session or an RLM (sub-)agent.\n * `ownUsage` excludes descendants; `totalUsage` includes completed descendants, matching /usage.\n */\nexport interface ContextTreeNode {\n\t/** \"root\" for the session itself; sub-xxxx for an RLM child. */\n\tid: string;\n\tlabel: string;\n\tstatus: \"active\" | RlmChildAgentStatus;\n\tmodel?: { provider: string; id: string };\n\townUsage: Usage;\n\ttotalUsage: Usage;\n\t/** Existing generation receipts for this session's captured source, never child aggregates. */\n\townRequestUsage?: OwnRequestUsage;\n\tcontextUsage?: ContextUsage;\n\tchildren: ContextTreeNode[];\n}\n\n/** Shared by one overview request, not by concurrent requests or the process. */\nexport interface ContextTreeRequestLimits extends SessionHistoryReadLimits {\n\tmaxNodes: number;\n\tmaxMetadataBytes: number;\n\tmaxDirectoryEntries: number;\n}\n\nclass ContextTreeLimitError extends Error {}\n\n/** Small request-local counters and one history-projection reduction tail. */\nexport class ContextTreeRequest {\n\treadonly limits: Readonly<ContextTreeRequestLimits>;\n\tprivate nodes = 0;\n\tprivate metadataBytes = 0;\n\tprivate directoryEntries = 0;\n\tprivate readTail: Promise<void> = Promise.resolve();\n\n\tconstructor(limits: Partial<ContextTreeRequestLimits> = {}) {\n\t\tthis.limits = Object.freeze({\n\t\t\t...exportHistoryLimits(limits),\n\t\t\tmaxNodes: limits.maxNodes ?? 256,\n\t\t\tmaxMetadataBytes: limits.maxMetadataBytes ?? 4 * 1024 * 1024,\n\t\t\tmaxDirectoryEntries: limits.maxDirectoryEntries ?? 16_384,\n\t\t});\n\t\tif (!Object.values(this.limits).every((value) => Number.isSafeInteger(value) && value > 0))\n\t\t\tthrow new Error(\"Invalid context tree request limits\");\n\t}\n\n\tadmitNode(): void {\n\t\tif (this.nodes >= this.limits.maxNodes) throw new ContextTreeLimitError(\"Context tree node budget exceeded\");\n\t\tthis.nodes++;\n\t}\n\n\tretainMetadata(value: unknown): number {\n\t\tlet json: string;\n\t\ttry {\n\t\t\tjson = stringifyBoundedJson(value, this.limits.maxMetadataBytes - this.metadataBytes);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message === \"JSON byte limit exceeded\")\n\t\t\t\tthrow new ContextTreeLimitError(\"Context tree metadata byte budget exceeded\", { cause: error });\n\t\t\tthrow error;\n\t\t}\n\t\tconst bytes = Buffer.byteLength(json);\n\t\tthis.metadataBytes += bytes;\n\t\treturn bytes;\n\t}\n\n\treleaseMetadata(bytes: number): void {\n\t\tthis.metadataBytes -= bytes;\n\t}\n\n\tdirectoryEntry(): void {\n\t\tif (this.directoryEntries >= this.limits.maxDirectoryEntries)\n\t\t\tthrow new ContextTreeLimitError(\"Context tree directory entry budget exceeded\");\n\t\tthis.directoryEntries++;\n\t}\n\n\tread<T>(read: () => Promise<T>): Promise<T> {\n\t\tconst result = this.readTail.then(read);\n\t\tthis.readTail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n}\n\nfunction treeRequest(limits: Partial<ContextTreeRequestLimits> | ContextTreeRequest): ContextTreeRequest {\n\treturn limits instanceof ContextTreeRequest ? limits : new ContextTreeRequest(limits);\n}\n\nfunction isAssistantEntry(entry: SessionEntry): entry is SessionEntry & {\n\ttype: \"message\";\n\tmessage: AssistantMessage;\n} {\n\treturn entry.type === \"message\" && entry.message.role === \"assistant\";\n}\n\nfunction readUserMessageText(content: unknown): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\tif (!Array.isArray(content)) {\n\t\treturn \"\";\n\t}\n\treturn content\n\t\t.filter(\n\t\t\t(block): block is { type: \"text\"; text: string } =>\n\t\t\t\ttypeof block === \"object\" &&\n\t\t\t\tblock !== null &&\n\t\t\t\t(block as { type?: unknown }).type === \"text\" &&\n\t\t\t\ttypeof (block as { text?: unknown }).text === \"string\",\n\t\t)\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\nfunction compactLabel(text: string, maxLength = 80): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\tif (compact.length <= maxLength) {\n\t\treturn compact;\n\t}\n\treturn `${compact.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;\n}\n\n/**\n * Usage totals for one agent: `totalUsage` sums the branch's assistant usage\n * (attributed aggregates, so descendants are included), `ownUsage` removes the\n * attributions targeting those assistants. Attribution entries are matched by\n * target across ALL entries, not just the branch: attributions rewrite the\n * target assistant's usage no matter which branch they were appended on, so a\n * fork that keeps the assistant but drops the attribution entry must still\n * subtract it.\n *\n * Totals are deliberately cumulative across compactions: compaction shrinks\n * the model-facing context, not what the session has spent, so assistants\n * dropped from the resolved context still count here.\n */\nexport function computeOwnAndTotalUsage(\n\tbranch: SessionEntry[],\n\tallEntries: SessionEntry[],\n): { ownUsage: Usage; totalUsage: Usage } {\n\tconst totalUsage = emptyUsage();\n\tconst branchAssistantIds = new Set<string>();\n\tfor (const entry of branch) {\n\t\tif (isAssistantEntry(entry)) {\n\t\t\tbranchAssistantIds.add(entry.id);\n\t\t\taddAssistantUsage(totalUsage, entry.message.usage);\n\t\t} else if ((entry.type === \"compaction\" || entry.type === \"branch_summary\") && entry.usage) {\n\t\t\taddAssistantUsage(totalUsage, entry.usage);\n\t\t}\n\t}\n\tconst ownUsage = cloneUsage(totalUsage);\n\tfor (const entry of allEntries) {\n\t\tif (entry.type === \"child_usage_attributed\" && branchAssistantIds.has(entry.targetId)) {\n\t\t\tsubtractAssistantUsage(ownUsage, entry.childUsage);\n\t\t}\n\t}\n\treturn { ownUsage, totalUsage };\n}\n\ninterface ContextTreeUsage {\n\townUsage: Usage;\n\ttotalUsage: Usage;\n\townRequestUsage?: OwnRequestUsage;\n\thasPostCompactionUsage?: boolean;\n}\n\n/** Complete bounded snapshot of an explicitly resident Manager, never an index-error fallback.\n * This synchronous reduction runs in the pre-await live-tree capture walk. It never\n * retains a decoded resident snapshot while native/disk work waits for a slot.\n */\nexport function readResidentContextTreeUsage(\n\tmanager: SessionManager,\n\tlimits: SessionHistoryReadLimits = { maxEntries: 16_384, maxSourceBytes: 64 * 1024 * 1024 },\n\tavailabilityMaxSourceBytes?: number,\n): ContextTreeUsage {\n\tconst snapshot = manager.materializeResidentHistory(limits);\n\tconst receipts = new RequestUsageAccumulator(manager.getSessionId());\n\tfor (const entry of snapshot.entries) if (entry.type === \"request\") receipts.add(entry.request);\n\tconst ownRequestUsage = receipts.finish();\n\tconst branch = branchEntries(snapshot.entries, snapshot.leafId, availabilityMaxSourceBytes !== undefined);\n\tif (availabilityMaxSourceBytes !== undefined) {\n\t\tif (!Number.isSafeInteger(availabilityMaxSourceBytes) || availabilityMaxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid parent-path materialization limits\");\n\t\tif (branch.length > 16_384) throw new Error(\"Parent-path entry budget exceeded\");\n\t\tlet bytes = 0;\n\t\tfor (const entry of branch) {\n\t\t\tbytes += Buffer.byteLength(stringifyBoundedJson(entry, availabilityMaxSourceBytes - bytes));\n\t\t}\n\t}\n\treturn {\n\t\t...computeOwnAndTotalUsage(branch, snapshot.entries),\n\t\t...(ownRequestUsage ? { ownRequestUsage } : {}),\n\t\t...(availabilityMaxSourceBytes === undefined ? {} : { hasPostCompactionUsage: hasPostCompactionUsage(branch) }),\n\t};\n}\n\nfunction isContextTreeUsageReference(reference: IndexedSourceEvent): boolean {\n\treturn (\n\t\t(reference.kind === \"message\" && reference.authority === \"assistant\") ||\n\t\treference.kind === \"compaction\" ||\n\t\treference.kind === \"branch_summary\" ||\n\t\treference.kind === \"child_usage_attributed\"\n\t);\n}\n\n/** Detached, complete source usage and its exact captured parent branch. */\nexport async function readContextTreeUsage(\n\tmanager: SessionManager,\n\tlimits: SessionHistoryReadLimits = { maxEntries: 16_384, maxSourceBytes: 64 * 1024 * 1024 },\n\trequest?: ContextTreeRequest,\n\tavailabilityMaxSourceBytes?: number,\n): Promise<(ContextTreeUsage & { source: SourceSnapshotRef }) | undefined> {\n\tif (!manager.supportsCapturedHistoryReads()) return undefined;\n\tconst sourceLimits = request?.limits ?? limits;\n\tconst capturedLimits = { maxEntries: sourceLimits.maxEntries, maxSourceBytes: sourceLimits.maxSourceBytes };\n\tif (!Object.values(capturedLimits).every((value) => Number.isSafeInteger(value) && value > 0))\n\t\tthrow new Error(\"Invalid history materialization limits\");\n\t// The actual source frontier binds NOW, never after waiting for the reduction slot.\n\treturn manager.readSourceHistory((history) => {\n\t\trequest?.retainMetadata(history.source);\n\t\tconst reduce = async () => {\n\t\t\tconst allEntries: SessionEntry[] = [];\n\t\t\tlet receipts: RequestUsageAccumulator | undefined = new RequestUsageAccumulator(history.source.sessionId);\n\t\t\tlet requestEntries = 0;\n\t\t\tlet requestBytes = 0;\n\t\t\tlet sourceBytes = 0;\n\t\t\tlet after = 0;\n\t\t\tfor (;;) {\n\t\t\t\tconst page = await history.page(after);\n\t\t\t\tif (page.indexedThrough < history.source.sourceSequence)\n\t\t\t\t\tthrow new Error(\"Captured history has incomplete index coverage\");\n\t\t\t\tfor (const reference of page.events) {\n\t\t\t\t\tif (reference.kind === \"request\" && receipts) {\n\t\t\t\t\t\trequestEntries++;\n\t\t\t\t\t\trequestBytes += reference.locator.length;\n\t\t\t\t\t\tif (requestEntries > capturedLimits.maxEntries || requestBytes > capturedLimits.maxSourceBytes) {\n\t\t\t\t\t\t\treceipts = undefined;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst hydrated = await history.hydrateEntry(reference.id, reference.locator.length);\n\t\t\t\t\t\t\t\tif (hydrated?.entry.type !== \"request\") receipts = undefined;\n\t\t\t\t\t\t\t\telse receipts.add(hydrated.entry.request);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Optional accounting metadata must not prevent the context overview.\n\t\t\t\t\t\t\t\treceipts = undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!isContextTreeUsageReference(reference)) continue;\n\t\t\t\t\tif (allEntries.length >= capturedLimits.maxEntries) throw new Error(\"History entry budget exceeded\");\n\t\t\t\t\tif (sourceBytes + reference.locator.length > capturedLimits.maxSourceBytes)\n\t\t\t\t\t\tthrow new Error(\"History source byte budget exceeded\");\n\t\t\t\t\tconst hydrated = await history.hydrateEntry(reference.id, capturedLimits.maxSourceBytes - sourceBytes);\n\t\t\t\t\tif (!hydrated) throw new Error(\"Context-tree usage entry source is unavailable\");\n\t\t\t\t\tallEntries.push(hydrated.entry);\n\t\t\t\t\tsourceBytes += reference.locator.length;\n\t\t\t\t}\n\t\t\t\tif (page.nextAfter === null) break;\n\t\t\t\tafter = page.nextAfter;\n\t\t\t}\n\t\t\tapplyChildUsageAttributions(allEntries);\n\t\t\tconst byId = new Map(allEntries.map((entry) => [entry.id, entry]));\n\t\t\tconst branch: SessionEntry[] = [];\n\t\t\tlet cursor: ParentPathCursor | undefined;\n\t\t\tdo {\n\t\t\t\tconst page = await history.parentPath({ cursor });\n\t\t\t\tfor (const reference of page.events) {\n\t\t\t\t\tif (!isContextTreeUsageReference(reference)) continue;\n\t\t\t\t\tconst entry = byId.get(reference.id);\n\t\t\t\t\tif (!entry) throw new Error(\"Context-tree parent-path entry source is unavailable\");\n\t\t\t\t\tbranch.push(entry);\n\t\t\t\t}\n\t\t\t\tcursor = page.nextCursor ?? undefined;\n\t\t\t} while (cursor);\n\t\t\tlet available: boolean | undefined;\n\t\t\tif (availabilityMaxSourceBytes !== undefined) {\n\t\t\t\tconst bootstrap = await history.branchBootstrap();\n\t\t\t\tavailable = !bootstrap.latestCompaction;\n\t\t\t\tconst reference = bootstrap.contextUsageAssistant;\n\t\t\t\tif (bootstrap.latestCompaction && reference) {\n\t\t\t\t\tconst updates = await history.branchContext.contextUpdates({\n\t\t\t\t\t\tkind: \"assistant-usage\",\n\t\t\t\t\t\ttargetId: reference.id,\n\t\t\t\t\t});\n\t\t\t\t\tconst bytes =\n\t\t\t\t\t\treference.locator.length + updates.refs.reduce((sum, update) => sum + update.locator.length, 0);\n\t\t\t\t\tif (bytes > availabilityMaxSourceBytes) throw new Error(\"Context usage source byte budget exceeded\");\n\t\t\t\t\tconst assistant = byId.get(reference.id);\n\t\t\t\t\tif (!assistant || !isAssistantEntry(assistant))\n\t\t\t\t\t\tthrow new Error(\"Context usage assistant source is unavailable\");\n\t\t\t\t\t// Full-source ordered projection above includes off-branch attributions.\n\t\t\t\t\tavailable = calculateContextTokens(assistant.message.usage) > 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst ownRequestUsage = receipts?.finish();\n\t\t\tconst usage = {\n\t\t\t\t...computeOwnAndTotalUsage(branch, allEntries),\n\t\t\t\t...(ownRequestUsage ? { ownRequestUsage } : {}),\n\t\t\t\t...(available === undefined ? {} : { hasPostCompactionUsage: available }),\n\t\t\t};\n\t\t\trequest?.retainMetadata(usage);\n\t\t\treturn { source: history.source, ...usage };\n\t\t};\n\t\treturn request ? request.read(reduce) : reduce();\n\t});\n}\n\nfunction hasPostCompactionUsage(branch: SessionEntry[]): boolean {\n\tlet boundary = -1;\n\tfor (let index = branch.length - 1; index >= 0; index--) {\n\t\tif (branch[index].type === \"compaction\") {\n\t\t\tboundary = index;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (boundary < 0) return true;\n\tfor (let index = branch.length - 1; index > boundary; index--) {\n\t\tconst entry = branch[index];\n\t\tif (!isAssistantEntry(entry)) continue;\n\t\tif (entry.message.stopReason !== \"aborted\" && entry.message.stopReason !== \"error\")\n\t\t\treturn calculateContextTokens(entry.message.usage) > 0;\n\t}\n\treturn false;\n}\n\n/**\n * Current context utilization from persisted entries, mirroring\n * AgentSession.getContextUsage(): unknown right after a compaction until the\n * next assistant response, otherwise the last assistant usage plus an\n * estimate for trailing messages (tool results, queued user input) that have\n * not hit the model yet.\n */\nfunction computeContextUsageFromEntries(\n\tallEntries: SessionEntry[],\n\tbranch: SessionEntry[],\n\tcontextWindow: number | undefined,\n): ContextUsage | undefined {\n\tif (!contextWindow || contextWindow <= 0) {\n\t\treturn undefined;\n\t}\n\n\tif (!hasPostCompactionUsage(branch)) {\n\t\treturn { tokens: null, contextWindow, percent: null };\n\t}\n\n\tconst estimate = estimateContextTokens(buildSessionContext(allEntries, branch.at(-1)?.id ?? null).messages);\n\tif (estimate.tokens <= 0) {\n\t\treturn undefined;\n\t}\n\treturn { tokens: estimate.tokens, contextWindow, percent: (estimate.tokens / contextWindow) * 100 };\n}\n\n/**\n * Entries on the current branch, root to leaf, mirroring\n * SessionManager.getBranch(): the leaf is the last appended entry and the\n * branch is its parentId chain. Keeps forked/abandoned paths out of usage\n * sums so disk nodes match what a live session would report.\n */\nfunction branchEntries(entries: SessionEntry[], leafId?: string | null, strict = false): SessionEntry[] {\n\tif (entries.length === 0) {\n\t\tif (strict && leafId !== undefined && leafId !== null) throw new Error(\"Parent path lineage is unresolved\");\n\t\treturn [];\n\t}\n\tconst byId = new Map(entries.map((entry) => [entry.id, entry]));\n\tconst branch: SessionEntry[] = [];\n\tconst seen = new Set<string>();\n\tlet current: SessionEntry | undefined =\n\t\tleafId === undefined ? entries[entries.length - 1] : leafId === null ? undefined : byId.get(leafId);\n\tif (strict && leafId !== undefined && leafId !== null && !current)\n\t\tthrow new Error(\"Parent path lineage is unresolved\");\n\twhile (current && !seen.has(current.id)) {\n\t\tseen.add(current.id);\n\t\tbranch.push(current);\n\t\tconst parentId = current.parentId;\n\t\tconst hasParent = strict ? parentId !== null : !!parentId;\n\t\tcurrent = hasParent ? byId.get(parentId!) : undefined;\n\t\tif (strict && hasParent && !current) throw new Error(\"Parent path lineage is unresolved\");\n\t}\n\tif (strict && current) throw new Error(\"Parent path lineage is unresolved\");\n\treturn branch.reverse();\n}\n\n/**\n * Terminal status for a persisted child, inferred from how its last assistant\n * turn ended: errored and aborted runs should not render as successful.\n */\nfunction statusFromBranch(entries: SessionEntry[]): \"done\" | \"error\" | \"cancelled\" {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tconst entry = entries[i];\n\t\tif (!isAssistantEntry(entry)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (entry.message.stopReason === \"error\") {\n\t\t\treturn \"error\";\n\t\t}\n\t\tif (entry.message.stopReason === \"aborted\") {\n\t\t\treturn \"cancelled\";\n\t\t}\n\t\treturn \"done\";\n\t}\n\treturn \"done\";\n}\n\n/** Stream names; opening/reading errors keep the caller's existing policy. */\nfunction visitDirectory(dirPath: string, request: ContextTreeRequest, visit: (name: string) => void): void {\n\tconst dir = opendirSync(dirPath);\n\ttry {\n\t\tfor (let entry = dir.readSync(); entry !== null; entry = dir.readSync()) {\n\t\t\trequest.directoryEntry();\n\t\t\tvisit(entry.name);\n\t\t}\n\t} catch (error) {\n\t\ttry {\n\t\t\tdir.closeSync();\n\t\t} catch (closeError) {\n\t\t\tthrow new AggregateError([error, closeError], \"Context tree directory read and close failed\");\n\t\t}\n\t\tthrow error;\n\t}\n\tdir.closeSync();\n}\n\n// readdirSync used UTF8 lexical order; retain its stable mtime-tie ordering.\nfunction comparePaths(a: string, b: string): number {\n\treturn Buffer.compare(Buffer.from(a), Buffer.from(b));\n}\n\nfunction findSessionFile(dir: string, request: ContextTreeRequest): { path: string; bytes: number } | undefined {\n\tlet newest: { path: string; mtime: number; bytes: number } | undefined;\n\ttry {\n\t\tvisitDirectory(dir, request, (name) => {\n\t\t\tif (!name.endsWith(\".jsonl\")) return;\n\t\t\tconst path = join(dir, name);\n\t\t\tlet mtime: number;\n\t\t\ttry {\n\t\t\t\tmtime = statSync(path).mtime.getTime();\n\t\t\t} catch {\n\t\t\t\treturn; // Skip unreadable files.\n\t\t\t}\n\t\t\tif (!newest || mtime > newest.mtime || (mtime === newest.mtime && comparePaths(path, newest.path) < 0)) {\n\t\t\t\tif (newest) request.releaseMetadata(newest.bytes);\n\t\t\t\tnewest = undefined;\n\t\t\t\tconst bytes = request.retainMetadata(path);\n\t\t\t\tnewest = { path, mtime, bytes };\n\t\t\t}\n\t\t});\n\t\treturn newest;\n\t} catch (error) {\n\t\tif (newest) request.releaseMetadata(newest.bytes);\n\t\tthrow error;\n\t}\n}\n\nfunction listChildSessionDirs(rlmSessionDir: string, request: ContextTreeRequest): { paths: string[]; bytes: number } {\n\tconst paths: string[] = [];\n\tlet bytes = 0;\n\ttry {\n\t\tvisitDirectory(rlmSessionDir, request, (name) => {\n\t\t\tif (!name.startsWith(\"sub-\")) return;\n\t\t\tconst path = join(rlmSessionDir, name);\n\t\t\ttry {\n\t\t\t\tif (!statSync(path).isDirectory()) return;\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbytes += request.retainMetadata(path);\n\t\t\tpaths.push(path);\n\t\t});\n\t} catch (error) {\n\t\trequest.releaseMetadata(bytes);\n\t\tif (error instanceof ContextTreeLimitError || error instanceof AggregateError) throw error;\n\t\treturn { paths: [], bytes: 0 };\n\t}\n\tpaths.sort(comparePaths).sort((a, b) => {\n\t\ttry {\n\t\t\treturn statSync(a).mtime.getTime() - statSync(b).mtime.getTime();\n\t\t} catch {\n\t\t\treturn 0;\n\t\t}\n\t});\n\treturn { paths, bytes };\n}\n\n/** Read a fixed disk prefix without retaining private request or tool-intent bodies. */\nasync function readContextTreeProjectionFromDisk(\n\tsessionFile: string,\n\trequest: ContextTreeRequest,\n): Promise<{\n\tentries: SessionEntry[];\n\tleafId: string | null;\n\thasSourceLeaf: boolean;\n\townRequestUsage?: OwnRequestUsage;\n}> {\n\tconst entries: SessionEntry[] = [];\n\tconst hiddenParents = new Map<string, string | null>();\n\tlet leafId: string | null = null;\n\tlet hasHeader = false;\n\tlet receipts: RequestUsageAccumulator | undefined;\n\tlet requestEntries = 0;\n\tlet requestBytes = 0;\n\tlet sourceBytes = 0;\n\tlet metadataBytes = 0;\n\ttry {\n\t\tawait readCapturedSessionJournal(sessionFile, (record) => {\n\t\t\tconst value = record.entry;\n\t\t\tif (!value || typeof value !== \"object\" || !(\"type\" in value) || typeof value.type !== \"string\")\n\t\t\t\tthrow new Error(\"Invalid session journal entry\");\n\t\t\tconst entry = value as FileEntry;\n\t\t\tif (!hasHeader) {\n\t\t\t\tif (entry.type !== \"session\" || typeof entry.id !== \"string\")\n\t\t\t\t\tthrow new Error(\"Session source has no valid header\");\n\t\t\t\thasHeader = true;\n\t\t\t\treceipts = new RequestUsageAccumulator(entry.id);\n\t\t\t}\n\t\t\tif (entry.type === \"request\" && receipts) {\n\t\t\t\trequestEntries++;\n\t\t\t\trequestBytes += record.source?.locator.length ?? Buffer.byteLength(record.json) + 1;\n\t\t\t\tif (requestEntries > request.limits.maxEntries || requestBytes > request.limits.maxSourceBytes)\n\t\t\t\t\treceipts = undefined;\n\t\t\t\telse receipts.add(entry.request);\n\t\t\t}\n\t\t\tif (entry.type !== \"session\") leafId = entry.id;\n\t\t\tif (entry.type === \"request\" || entry.type === \"tool_intent\") {\n\t\t\t\tmetadataBytes += request.retainMetadata([entry.id, entry.parentId]);\n\t\t\t\thiddenParents.set(entry.id, entry.parentId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst bytes = record.source?.locator.length ?? Buffer.byteLength(record.json) + 1;\n\t\t\tif (sourceBytes + bytes > request.limits.maxSourceBytes)\n\t\t\t\tthrow new ContextTreeLimitError(\"Context tree source byte budget exceeded\");\n\t\t\tsourceBytes += bytes;\n\t\t\tif (entry.type === \"session\") return;\n\t\t\tif (entries.length >= request.limits.maxEntries)\n\t\t\t\tthrow new ContextTreeLimitError(\"Context tree entry budget exceeded\");\n\t\t\tentries.push(entry);\n\t\t});\n\t\tconst visibleParent = (id: string | null): string | null => {\n\t\t\tlet remaining = hiddenParents.size;\n\t\t\twhile (id !== null && hiddenParents.has(id)) {\n\t\t\t\tif (remaining-- === 0) throw new Error(\"Parent path lineage is unresolved\");\n\t\t\t\tid = hiddenParents.get(id)!;\n\t\t\t}\n\t\t\treturn id;\n\t\t};\n\t\tfor (const entry of entries) entry.parentId = visibleParent(entry.parentId);\n\t\t// A trailing private record can select an older branch, not the last visible entry.\n\t\tconst hasSourceLeaf = leafId !== null;\n\t\tleafId = visibleParent(leafId);\n\t\tapplyChildUsageAttributions(entries);\n\t\tconst ownRequestUsage = receipts?.finish();\n\t\treturn { entries, leafId, hasSourceLeaf, ...(ownRequestUsage ? { ownRequestUsage } : {}) };\n\t} finally {\n\t\trequest.releaseMetadata(metadataBytes);\n\t}\n}\n\n/**\n * Build a context node for a completed RLM child from its persisted session\n * dir (sub-xxxx/). Children that already attributed grandchild usage carry the\n * aggregate on their assistant messages (applyChildUsageAttributions), so own\n * usage is recovered by subtracting the attribution entries. Returns undefined\n * when the dir holds no readable session.\n */\nasync function readContextTreeChildNodeFromDisk(\n\tchildSessionDir: string,\n\tsessionFile: string,\n\tresolveContextWindow: ContextWindowResolver,\n\trequest: ContextTreeRequest,\n\tidentity?: Pick<ContextTreeNode, \"id\" | \"label\" | \"status\">,\n): Promise<ContextTreeNode | undefined> {\n\tconst {\n\t\tentries: allEntries,\n\t\tleafId,\n\t\thasSourceLeaf,\n\t\townRequestUsage,\n\t} = await readContextTreeProjectionFromDisk(sessionFile, request);\n\tconst branch = branchEntries(allEntries, leafId);\n\tif (branch.length === 0 && !hasSourceLeaf) {\n\t\treturn undefined;\n\t}\n\n\tconst { ownUsage, totalUsage } = computeOwnAndTotalUsage(branch, allEntries);\n\n\tlet model: { provider: string; id: string } | undefined;\n\tfor (const entry of branch) {\n\t\tif (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, id: entry.modelId };\n\t\t}\n\t}\n\n\tlet label = \"\";\n\tfor (const entry of branch) {\n\t\tif (entry.type === \"message\" && entry.message.role === \"user\") {\n\t\t\tlabel = compactLabel(readUserMessageText(entry.message.content));\n\t\t\tif (label) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst contextWindow = model ? resolveContextWindow(model.provider, model.id) : undefined;\n\n\tconst metadata = {\n\t\t...(identity ?? {\n\t\t\tid: basename(childSessionDir),\n\t\t\tlabel: label || \"child agent\",\n\t\t\tstatus: statusFromBranch(branch),\n\t\t}),\n\t\tmodel,\n\t\townUsage,\n\t\ttotalUsage,\n\t\t...(ownRequestUsage ? { ownRequestUsage } : {}),\n\t\tcontextUsage: computeContextUsageFromEntries(allEntries, branch, contextWindow),\n\t};\n\t// A registered run's identity was already admitted by its live parent.\n\trequest.retainMetadata(\n\t\tidentity ? { model, ownUsage, totalUsage, ownRequestUsage, contextUsage: metadata.contextUsage } : metadata,\n\t);\n\treturn { ...metadata, children: [] };\n}\n\n/** Complete or refuse, sharing the request's slot and counters with descendants.\n * Internal identity is an already-admitted registered run, including its empty placeholder.\n */\nexport async function loadContextTreeChildFromDisk(\n\tchildSessionDir: string,\n\tresolveContextWindow: ContextWindowResolver,\n\tlimits: Partial<ContextTreeRequestLimits> | ContextTreeRequest = {},\n\tidentity?: Pick<ContextTreeNode, \"id\" | \"label\" | \"status\">,\n): Promise<ContextTreeNode | undefined> {\n\tconst request = treeRequest(limits);\n\tconst directoryBytes = request.retainMetadata(childSessionDir);\n\tlet sessionFile: { path: string; bytes: number } | undefined;\n\tlet node: ContextTreeNode | undefined;\n\ttry {\n\t\tsessionFile = findSessionFile(childSessionDir, request);\n\t\tif (sessionFile && existsSync(sessionFile.path)) {\n\t\t\t// A header-only history still consumes one bounded source admission.\n\t\t\tif (!identity) request.admitNode();\n\t\t\tnode = await request.read(() =>\n\t\t\t\treadContextTreeChildNodeFromDisk(\n\t\t\t\t\tchildSessionDir,\n\t\t\t\t\tsessionFile!.path,\n\t\t\t\t\tresolveContextWindow,\n\t\t\t\t\trequest,\n\t\t\t\t\tidentity,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t} finally {\n\t\tif (sessionFile) request.releaseMetadata(sessionFile.bytes);\n\t\trequest.releaseMetadata(directoryBytes);\n\t}\n\tif (node) {\n\t\t// The full source has been reduced and the serial slot released before recursion.\n\t\tnode.children = await loadContextTreeChildrenFromDisk(childSessionDir, resolveContextWindow, undefined, request);\n\t} else if (identity) {\n\t\tconst usage = { ownUsage: emptyUsage(), totalUsage: emptyUsage() };\n\t\trequest.retainMetadata(usage);\n\t\tnode = { ...identity, ...usage, children: [] };\n\t}\n\treturn node;\n}\n\n/** Persisted children, in existing directory order, excluding already represented live IDs. */\nexport async function loadContextTreeChildrenFromDisk(\n\trlmSessionDir: string | undefined,\n\tresolveContextWindow: ContextWindowResolver,\n\tskipIds?: ReadonlySet<string>,\n\tlimits: Partial<ContextTreeRequestLimits> | ContextTreeRequest = {},\n): Promise<ContextTreeNode[]> {\n\tconst request = treeRequest(limits);\n\tconst skippedIds = new Set<string>();\n\tlet metadataBytes = 0;\n\ttry {\n\t\t// A caller-provided skip set is bounded before copying, too.\n\t\tif (skipIds && skipIds.size > request.limits.maxDirectoryEntries)\n\t\t\tthrow new ContextTreeLimitError(\"Context tree directory entry budget exceeded\");\n\t\tfor (const id of skipIds ?? []) {\n\t\t\tmetadataBytes += request.retainMetadata(id);\n\t\t\tskippedIds.add(id);\n\t\t}\n\t\tif (!rlmSessionDir || !existsSync(rlmSessionDir)) return [];\n\t\tmetadataBytes += request.retainMetadata(rlmSessionDir);\n\t\tconst directories = listChildSessionDirs(rlmSessionDir, request);\n\t\tmetadataBytes += directories.bytes;\n\t\tconst nodes: ContextTreeNode[] = [];\n\t\tfor (const childDir of directories.paths) {\n\t\t\tif (skippedIds.has(basename(childDir))) continue;\n\t\t\tconst node = await loadContextTreeChildFromDisk(childDir, resolveContextWindow, request);\n\t\t\tif (node) nodes.push(node);\n\t\t}\n\t\treturn nodes;\n\t} finally {\n\t\trequest.releaseMetadata(metadataBytes);\n\t}\n}\n"]}
|