| /** |
| * Shared provenance contract for context-compaction source references. |
| * |
| * `SynthesisSourceRef` historically lived in the synthesis-cache module, but |
| * its four kinds are produced by several independent subsystems (archive |
| * retrieval, history-compact blocks, history search) and consumed by both |
| * synthesis-cache and history-compact. Extracting the contract into a leaf |
| * lets every producer/consumer depend on it without reaching across domain |
| * modules. `SynthesisSourceRef` is retained as a compatibility alias. |
| */ |
| import { nonEmpty } from './context-budget-helpers.js'; |
| |
| export type ArchivedToolResultReason = 'stale_tool_result_pruned_before_compact'; |
| |
| export interface ArchivedToolResultSourceRef { |
| kind: 'archived_tool_result'; |
| sessionId: string; |
| turnId: string; |
| runtimeEventId: string; |
| toolCallId: string; |
| toolName: string; |
| artifactId: string; |
| bodySha256: string; |
| originalEstimatedTokens: number; |
| originalBytes: number; |
| placeholderReason: ArchivedToolResultReason; |
| } |
| |
| export interface RuntimeEventSourceRef { |
| kind: 'runtime_event'; |
| sessionId: string; |
| turnId: string; |
| runtimeEventId: string; |
| role: 'user' | 'model' | 'tool' | 'system'; |
| contentKind: string; |
| } |
| |
| export interface HistorySearchHitSourceRef { |
| kind: 'history_search_hit'; |
| sessionId: string; |
| turnId: string; |
| runtimeEventId: string; |
| score: number; |
| matchedTerms: string[]; |
| } |
| |
| export interface LiveToolResultSourceRef { |
| kind: 'live_tool_result'; |
| sessionId: string; |
| turnId: string; |
| runtimeEventId: string; |
| toolCallId: string; |
| toolName: string; |
| argsSha256: string; |
| resultSha256: string; |
| artifactId?: string; |
| } |
| |
| export type ContextSourceRef = |
| | ArchivedToolResultSourceRef |
| | RuntimeEventSourceRef |
| | HistorySearchHitSourceRef |
| | LiveToolResultSourceRef; |
| |
| /** Compatibility alias; new code should use {@link ContextSourceRef}. */ |
| export type SynthesisSourceRef = ContextSourceRef; |
| |
| export function isValidSynthesisSourceRef(value: unknown): value is SynthesisSourceRef { |
| if (!value || typeof value !== 'object') return false; |
| const ref = value as Partial<SynthesisSourceRef>; |
| if (ref.kind === 'archived_tool_result') { |
| const archived = ref as Partial<Extract<SynthesisSourceRef, { kind: 'archived_tool_result' }>>; |
| return ( |
| nonEmpty(archived.sessionId) && |
| nonEmpty(archived.turnId) && |
| nonEmpty(archived.runtimeEventId) && |
| nonEmpty(archived.toolCallId) && |
| nonEmpty(archived.toolName) && |
| nonEmpty(archived.artifactId) && |
| nonEmpty(archived.bodySha256) && |
| Number.isFinite(archived.originalEstimatedTokens) && |
| Number.isFinite(archived.originalBytes) && |
| archived.placeholderReason === 'stale_tool_result_pruned_before_compact' |
| ); |
| } |
| if ( |
| ref.kind === 'runtime_event' || |
| ref.kind === 'history_search_hit' || |
| ref.kind === 'live_tool_result' |
| ) { |
| return ( |
| nonEmpty((ref as { sessionId?: string }).sessionId) && |
| nonEmpty((ref as { turnId?: string }).turnId) && |
| nonEmpty((ref as { runtimeEventId?: string }).runtimeEventId) |
| ); |
| } |
| return false; |
| } |