/** * Realtime events are delivery hints only. The sync event points clients at * durable database state; agent activity, typing, presence, and call signaling * are ephemeral. */ import type { AgentTurnBackgroundTerminalSummary, AgentTurnSubagentSummary } from "../agent/types.js"; export interface RealtimeLimits { maxEventBytes: number; maxIdLength: number; maxSyncChats: number; maxSyncAreas: number; maxAreaLength: number; maxTypingTtlMs: number; maxAgentActivityTtlMs: number; maxSessionDescriptionBytes: number; maxIceCandidateBytes: number; maxPresenceUsers: number; maxPresenceTtlMs: number; maxDocumentPresenceStateBytes: number; maxDocumentPresenceTtlMs: number; } export declare const DEFAULT_REALTIME_LIMITS: Readonly; /** An unsigned SQLite INTEGER encoded losslessly for JSON transport. */ export type RealtimeSequence = string; export interface ChatSyncPoint { readonly chatId: string; readonly pts: RealtimeSequence; } export interface SyncHintEvent { readonly type: "sync"; readonly sequence: RealtimeSequence; readonly chats: readonly ChatSyncPoint[]; readonly areas: readonly string[]; } export type DurableSyncHintEvent = SyncHintEvent; export interface TypingEvent { readonly type: "typing"; readonly chatId: string; readonly userId: string; readonly active: boolean; readonly occurredAt: number; /** Required for active typing and intentionally short-lived. */ readonly expiresAt?: number; } export type AgentActivityPhase = "thinking" | "typing"; /** * Short-lived progress for one agent turn. Clients must expire active entries * locally and must not reconcile this event through durable sync state. */ export interface AgentActivityEvent { readonly type: "agent.activity"; readonly chatId: string; readonly agentUserId: string; /** The user message that caused this turn, used as its stable public identity. */ readonly turnId: string; readonly active: boolean; readonly phase: AgentActivityPhase; /** Total model tokens reported for this turn so far. */ readonly tokenCount: number; readonly startedAt: number; readonly occurredAt: number; readonly subagents: readonly AgentTurnSubagentSummary[]; readonly backgroundTerminals: readonly AgentTurnBackgroundTerminalSummary[]; /** Required for active activity and intentionally short-lived. */ readonly expiresAt?: number; } export type PresenceStatus = "online" | "offline"; export interface PresenceSnapshot { readonly userId: string; readonly status: PresenceStatus; readonly connectionCount: number; readonly lastSeenAt?: number; /** Required while online so each observer can expire a silent lease locally. */ readonly expiresAt?: number; } export type PresenceChange = "activity" | "expired" | "disconnected"; export interface PresenceEvent { readonly type: "presence"; readonly change: PresenceChange; readonly snapshot: PresenceSnapshot; readonly occurredAt: number; } export interface WebRtcSessionDescriptionSignal { readonly kind: "offer" | "answer"; readonly sdp: string; } export interface WebRtcIceCandidateSignal { readonly kind: "ice-candidate"; readonly candidate: string; readonly sdpMid?: string | null; readonly sdpMLineIndex?: number | null; readonly usernameFragment?: string | null; } export interface WebRtcHangupSignal { readonly kind: "hangup"; readonly reason?: "ended" | "declined" | "busy" | "failed"; } export type WebRtcSignal = WebRtcSessionDescriptionSignal | WebRtcIceCandidateSignal | WebRtcHangupSignal; export interface CallSignalEvent { readonly type: "call.signal"; readonly callId: string; readonly chatId: string; readonly senderUserId: string; /** Omit for a signal addressed to every authorized call participant. */ readonly recipientUserId?: string; readonly signal: WebRtcSignal; readonly occurredAt: number; } /** Ephemeral invalidation only; clients reconcile the current tree through HTTP. */ export interface WorkspaceChangedEvent { readonly type: "workspace.changed"; readonly chatId: string; readonly occurredAt: number; } /** * Hint that a collaborative document accepted new content. Clients reconcile * durable content through the document getDifference endpoint, never from this event. */ export interface DocumentUpdatedEvent { readonly type: "document.updated"; /** Present when delivered through one attached channel; absent on the owner's user topic. */ readonly chatId?: string; readonly documentId: string; readonly sequence: RealtimeSequence; readonly occurredAt: number; } /** One editing participant of a collaborative document, expired locally by each observer. */ export interface DocumentPresenceSnapshot { readonly documentId: string; readonly userId: string; readonly clientId: string; /** Monotonic per client so stale out-of-order deliveries are discarded. */ readonly revision: number; readonly active: boolean; /** Opaque editor awareness payload (cursor, selection, identity). */ readonly state?: unknown; /** Required while active so observers can expire a silent participant. */ readonly expiresAt?: number; } export interface DocumentPresenceEvent { readonly type: "document.presence"; /** Present when delivered through one attached channel; absent on the owner's user topic. */ readonly chatId?: string; readonly presence: DocumentPresenceSnapshot; readonly occurredAt: number; } export type RealtimeEvent = SyncHintEvent | TypingEvent | AgentActivityEvent | PresenceEvent | CallSignalEvent | WorkspaceChangedEvent | DocumentUpdatedEvent | DocumentPresenceEvent; export type RealtimeEventType = RealtimeEvent["type"]; export type RealtimeTopic = "server" | "presence" | `user:${string}` | `chat:${string}` | `call:${string}`; export declare const realtimeTopics: Readonly<{ server: "server"; presence: "presence"; user: (userId: string) => RealtimeTopic; chat: (chatId: string) => RealtimeTopic; call: (callId: string) => RealtimeTopic; }>; export declare function assertRealtimeTopic(topic: string, limits?: RealtimeLimits): asserts topic is RealtimeTopic; export declare function assertRealtimeEvent(event: RealtimeEvent, limits?: RealtimeLimits): void; export declare function assertRealtimeId(value: string | undefined, name: string, limits?: RealtimeLimits): asserts value is string; export declare function assertSequence(value: string, name?: string): void; //# sourceMappingURL=events.d.ts.map