/** * Interface to the `@henkaku-center/jsonl-reduce` package. * * The reducer is resolved via dynamic import so chi-commons stays loadable * when it is missing; callers surface `JsonlReduceUnavailableError` and fall * back to raw (R0) browsing. Reducer metadata is the source of truth for * lineage and titles. */ export const JSONL_REDUCE_PACKAGE = "@henkaku-center/jsonl-reduce"; /** customType of the reduction-metadata entry inside reduced artifacts. */ export const REDUCTION_METADATA_CUSTOM_TYPE = "jsonl-reduce.reduction"; /** * Pick the reduction model: first configured preference (`reduceModels` in * the chi-base-managed config) available in Pi's model registry. Callers fall * back to the active session model when none match. */ export function pickReductionModel( preferred: readonly string[], available: readonly string[], ): string | undefined { return preferred.find((id) => available.includes(id)); } /** Caller-supplied model adapter (jsonl-reduce `ModelAdapter`). */ export interface ReductionModelAdapter { id: string; complete(prompt: string, options: { maxOutputTokens: number }): Promise; } /** Subset of jsonl-reduce `ReduceOptions` that chi-commons uses. */ export interface JsonlReduceOptions { dialect: "pi-v3"; reducerVersion: string; promptVersion: string; scope: "session-span" | "session" | "selection"; budget: { maxOutputTokens: number; targetCompression?: number }; model?: ReductionModelAdapter; } /** Subset of jsonl-reduce `ReductionMetadata` that chi-commons consumes. */ export interface JsonlReduceMetadata { reducerVersion: string; promptVersion: string; modelId: string | null; /** Operation cache key and canonical output-content identity. */ reductionKey: string; artifactHash?: string; outputSessionId: string; /** Ordered input session IDs. */ inputSessionIds: string[]; /** Exact lineage back to source logs. */ sources: Array<{ sessionId: string; entryIds: string[] }>; outputTokensEstimate: number; timeRange: { startedAt: string; endedAt: string } | null; title: string; } export interface JsonlReduceAssembledSelection { sessionJsonl: string; selectionHash: string; refMap: ReadonlyMap; coverage: unknown; directInputs: unknown[]; segments: unknown[]; } export interface JsonlReduceSessionSlice { sessionJsonl: string; sourceLeafId: string; orderedEntryIds: string[]; artifactHash?: string; } export interface JsonlReduceResult { /** Reduced Pi v3 JSONL (a full session document including a header). */ outputJsonl: string; metadata: JsonlReduceMetadata; warnings: string[]; } export type JsonlReduce = ( input: string | JsonlReduceAssembledSelection, options: JsonlReduceOptions, ) => Promise; export type AssembleSelection = (slices: readonly JsonlReduceSessionSlice[]) => JsonlReduceAssembledSelection; export class JsonlReduceUnavailableError extends Error { constructor(detail?: string) { super( "jsonl-reduce is not installed" + (detail ? ": " + detail : "") + ". Reduction is unavailable; raw (R0) sources can still be browsed and inserted.", ); this.name = "JsonlReduceUnavailableError"; } } /** Resolve the jsonl-reduce implementation or throw `JsonlReduceUnavailableError`. */ async function loadModule(): Promise> { try { return (await import(JSONL_REDUCE_PACKAGE)) as Record; } catch (error) { throw new JsonlReduceUnavailableError( error instanceof Error ? error.message : String(error), ); } } export async function loadJsonlReduce(): Promise { const mod = await loadModule(); const fn = mod.jsonlReduce; if (typeof fn !== "function") { throw new JsonlReduceUnavailableError("package does not export jsonlReduce"); } return fn as JsonlReduce; } export async function loadAssembleSelection(): Promise { const mod = await loadModule(); const fn = mod.assembleSelection; if (typeof fn !== "function") { throw new JsonlReduceUnavailableError("package does not export assembleSelection"); } return fn as AssembleSelection; }