/** * Per-session append-only event log. * * Foundation for the new `session.*` RPC family. Replaces the implicit * "chat history with role conflation + injected messages" model with an * explicit, append-only stream where every event has a `participantId`, * a typed `kind`, and a monotonic `eventId`. * * Architecture: * - One log per `sessionId`, identified by a free-form string. * - Each `appendEvent` allocates the next monotonic `eventId` for that * session and notifies all subscribers in order. * - Subscribers can resume from any prior eventId — the log keeps a * bounded in-memory tail (default 1000 events) plus the on-disk * JSONL mirror at `~/.skykoi/sessions/.events.jsonl` for * deeper replay. * - Cancel signals are first-class events; the koi runtime's main * loop watches for them and aborts via AbortSignal. * * Threading: this module is the single source of truth on the gateway * for "what happened in session X". The platform-side Postgres mirror * (Session/Participant/SessionEvent tables) is a durable shadow; the * gateway is the realtime hot path. */ export declare const SESSION_PROTOCOL_VERSION = 1; export type ParticipantKind = "user" | "voice-koi" | "koi" | "sub-koi" | "tool" | "webhook"; export type EventKind = "utterance" | "tool_call" | "tool_progress" | "tool_result" | "activity" | "cancel" | "participant_join" | "participant_leave" | "system" | "media" | "marker" | "revision" | "redaction" | "typing"; export interface SessionEvent { eventId: string; sessionId: string; participantId: string; kind: EventKind; content: unknown; /** * Provenance tag — same shape as the platform's EventSource. Lets * consumers (utterance triggers, mirrors) tell apart koi outputs * ("model" / "tool" / "system") from user input ("typed" / "spoken" * / "external"). Optional; legacy callers that don't set it land in * the user-input bucket by default. */ source?: string; parentEventId?: string; replyToEventId?: string; causedByEventId?: string; revisedFromEventId?: string; redactedEventId?: string; mentions?: string[]; traceId?: string; ts: string; schemaVersion: number; } export interface AppendArgs { sessionId: string; participantId: string; kind: EventKind; content: unknown; source?: string; parentEventId?: string; replyToEventId?: string; causedByEventId?: string; revisedFromEventId?: string; redactedEventId?: string; mentions?: string[]; traceId?: string; } export type EventListener = (e: SessionEvent) => void; export type ClearEventLogResult = { status: "missing"; path: string; } | { status: "archived"; path: string; archivedPath: string; } | { status: "removed"; path: string; }; /** * Append an event to a session's log. Allocates the next monotonic * `eventId`, writes the JSONL mirror, and then fans out to subscribers. * Returns the event so the caller can use its `eventId` * as a `parentEventId` reference for follow-up events. */ export declare function appendEvent(args: AppendArgs): SessionEvent; /** * Subscribe to live events for a session. Returns an unsubscribe * function. The caller is responsible for calling it on disconnect. */ export declare function subscribe(sessionId: string, fn: EventListener): () => void; export declare function subscribeAll(fn: EventListener): () => void; /** * Read events strictly after `sinceEventId`. * * Hot reconnects are served from the bounded in-memory tail. Cold reconnects * and reconnects that need more than the hot tail fall back to the JSONL * mirror so refresh never silently loses tool/media/reaction history. */ export declare function readEventsSince(sessionId: string, sinceEventId?: string, limit?: number): SessionEvent[]; /** * Cold-load the in-memory state for a session from its on-disk JSONL. * Idempotent — safe to call before the first subscribe to populate the * tail. If the file is missing, returns an empty session. */ export declare function hydrateSession(sessionId: string): Promise; export declare function getLastEventId(sessionId: string): string; export declare function clearEventLogForSession(sessionId: string, opts?: { hardDelete?: boolean; reason?: string; }): ClearEventLogResult; /** Test/reset hook — clears in-memory state. Disk file is untouched. */ export declare function _resetForTests(): void;