import type { ChatNoticeLevel, NoticeAction } from '../core/types/agent-types.js'; export type HistoryEventType = 'user' | 'assistant' | 'tool' | 'interaction'; export interface HistoryDebugDetails { /** Exact text handed to the adapter for this user turn. */ agentMessage?: string; /** Unabridged structured input for a tool call. */ toolInput?: unknown; /** Full normalized result correlated to the tool call by backend tool-use id. */ toolResult?: { content: string; isError: boolean; }; } export type InteractionKind = 'ask-user' | 'plan-approval'; export type InteractionStatus = 'pending' | 'answered' | 'approved' | 'rejected' | 'expired' | 'cancelled'; export type InteractionResolvedVia = 'web' | 'slack' | 'timeout' | 'restart' | 'command'; export interface InteractionQuestion { question: string; header: string; options: { label: string; description?: string; }[]; multiSelect: boolean; } export interface InteractionPayload { questions?: InteractionQuestion[]; /** Optional severity of an ask-user card ('info'|'warning'|'error') — absent = neutral look. */ level?: 'info' | 'warning' | 'error'; planContent?: string; planFilePath?: string | null; } export interface InteractionResult { answers?: Record; feedback?: string; } /** A resolved history event (turnIndex derived at read time). */ export interface HistoryEvent { type: HistoryEventType; /** user / assistant message text (omitted for tool events). */ text?: string; /** Semantic chat notice styling for system-authored assistant messages. */ noticeLevel?: ChatNoticeLevel; /** Control offered by that notice; persisted so it survives a transcript reload. */ noticeAction?: NoticeAction; /** tool name (tool events only). */ toolName?: string; /** compact tool input summary (tool events only). */ toolInput?: string; /** Sensitive lossless fields captured only by DEBUG-enabled orchestration. */ debug?: HistoryDebugDetails; /** interaction subtype: 'ask-user-answered' | 'plan-approved' | 'plan-rejected' (LEGACY interaction rows only). */ subtype?: string; /** Interaction entity fields (interaction rows with an id; merged created+resolved on read). */ id?: string; kind?: InteractionKind; status?: InteractionStatus; payload?: InteractionPayload; result?: InteractionResult; resolvedVia?: InteractionResolvedVia; resolvedAt?: string; ts: string; /** Groups events under the user turn that triggered them. */ turnIndex: number; /** Optional file attachments (user events from web composer). */ attachments?: { name: string; path: string; size: number; mimeType: string; type: 'image' | 'video' | 'file'; }[]; /** Present on a user event that replaced an earlier message via edit+rewind. Derived on read * from the preceding `edit-marker` raw line (the marker itself is never emitted). */ edited?: { originalText: string; originalTs: string; }; } /** Raw line as persisted (no turnIndex — derived on read). * `edit-marker` is a persistence-only line (message edit + rewind): appended right before the * edited user event's re-send; on read it attaches to the NEXT user event as `edited` and is * never emitted as an event itself. */ interface RawEvent { type: HistoryEventType | 'edit-marker' | 'debug-user-prompt' | 'debug-tool-result'; /** edit-marker lines only. */ originalText?: string; /** edit-marker lines only. */ originalTs?: string; text?: string; noticeLevel?: ChatNoticeLevel; noticeAction?: NoticeAction; toolName?: string; toolInput?: string; /** DEBUG-only correlation and lossless payload fields. */ toolUseId?: string; fullInput?: unknown; agentMessage?: string; isError?: boolean; /** interaction subtype (LEGACY interaction lines only). */ subtype?: string; /** Interaction entity fields (created / resolved lines). */ id?: string; kind?: InteractionKind; status?: InteractionStatus; payload?: InteractionPayload; result?: InteractionResult; resolvedVia?: InteractionResolvedVia; ts: string; /** Optional file attachments (user events from web composer). */ attachments?: { name: string; path: string; size: number; mimeType: string; type: 'image' | 'video' | 'file'; }[]; /** Internal idempotency key for a recovered pending injection. Never emitted by getHistory. */ sourceId?: string; } export interface SessionHistory { sessionId: string; events: HistoryEvent[]; /** Internal committed pending ids used to suppress a cross-store handoff duplicate. */ committedSourceIds?: string[]; } /** Compact, backend-agnostic one-line summary of a tool call's input for the history. * Shared by the direct conversation path (agent-runner) and thread steps (thread-transcript) * so both record identical tool-input summaries. */ export declare function summarizeToolInputForHistory(input: any): string; export declare class ConversationHistoryRepo { /** Per-session serial write chain — keeps concurrent appends from interleaving a line. */ private writeChains; private dirReady; private ensureDir; private append; /** Append a user message — starts a new turn (turn boundaries are derived on read). * An optional `ts` override lets the caller share a single timestamp with the * EventBus event so the web UI's content-based de-dup produces identical keys. */ appendUser(sessionId: string, opts: { text: string; ts?: string; attachments?: { name: string; path: string; size: number; mimeType: string; type: 'image' | 'video' | 'file'; }[]; agentMessage?: string; sourceId?: string; }): Promise; /** Attach the exact adapter message after prompt assembly to the preceding visible user row. */ appendUserPrompt(sessionId: string, opts: { agentMessage: string; ts?: string; }): Promise; /** Append an assistant message. Streaming partials are collapsed at read time. * An optional `ts` override lets the caller share a single timestamp with the EventBus event. * Optional `attachments` carry agent-sent files (20a) — the assistant-side mirror of the user * composer's uploads. Present only for the file-send path; ordinary assistant text omits it. */ appendAssistant(sessionId: string, opts: { text: string; ts?: string; attachments?: { name: string; path: string; size: number; mimeType: string; type: 'image' | 'video' | 'file'; }[]; noticeLevel?: ChatNoticeLevel; noticeAction?: NoticeAction; }): Promise; /** Append a tool call. * An optional `ts` override lets the caller share a single timestamp with the EventBus event. */ appendTool(sessionId: string, opts: { toolName: string; toolInput?: string; ts?: string; toolUseId?: string; fullInput?: unknown; }): Promise; /** Append a full normalized tool result; read-time correlation keeps it on the tool row. */ appendToolResult(sessionId: string, opts: { toolUseId: string; content: string; isError: boolean; ts?: string; }): Promise; /** Append an interaction CREATED record (status pending, full payload snapshot). * The later resolved record with the same id merges into this row at read time. */ appendInteractionCreated(sessionId: string, opts: { id: string; kind: InteractionKind; payload: InteractionPayload; text: string; ts?: string; }): Promise; /** Append an interaction RESOLVED record (final status + result). Merged into the created * row by id at read time; kept standalone if no created row exists (defensive). */ appendInteractionResolved(sessionId: string, opts: { id: string; status: InteractionStatus; result?: InteractionResult; resolvedVia: InteractionResolvedVia; text: string; ts?: string; }): Promise; /** Append an EDIT MARKER (message edit + rewind): records the replaced message's original * text/ts so the next user event reads back with an `edited` field. Call after * {@link truncateFromTurn} and before re-sending the edited message. */ appendEditMarker(sessionId: string, opts: { originalText: string; originalTs: string; }): Promise; /** * Rewind support: drop every line from the `turnIndex`-th user event onward (plus a directly * preceding edit-marker, which belonged to the removed user event). Serialized on the same * per-session write chain as appends. Returns the removed opening user event's text/ts/attachments * (for the edit marker + attachment reuse), or null when the turn does not exist. */ truncateFromTurn(sessionId: string, turnIndex: number): Promise<{ text: string; ts: string; attachments?: RawEvent['attachments']; } | null>; /** * Read a session's history. Derives turnIndex (each `user` event opens a new turn) and * collapses consecutive same-turn assistant events whose texts are prefix-related (a * streaming backend that emitted the message as it grew). Returns null when absent/empty. */ getHistory(sessionId: string): Promise; /** True when a recovered pending injection has already appended its committed user row. */ hasUserSourceId(sessionId: string, sourceId: string): Promise; /** * The first user message's text for a session, or null when there is none. Used to title a session * from its opening message (the left-rail display name for label-less sessions). Reads the JSONL and * stops at the first `user` line, so it does not parse the whole history. */ getFirstUserText(sessionId: string): Promise; clear(sessionId: string): Promise; /** Wait for all in-flight appends to land (graceful SIGTERM drain). */ flush(): Promise; } export declare const conversationHistory: ConversationHistoryRepo; export {};