/** * Pure message-mutation kernel for the master chat-stream reducer. * * These helpers were absorbed from `use-nats-chat-adapter.ts` in Phase 3 of * the chat unification — they are the ONE implementation of "apply a stream * fragment to a message thread". The reducer (`chat-stream-reducer.ts`) and * the cross-side projections (`chat-dialog-store.ts`) both build on them. * * REFERENTIAL-STABILITY CONTRACT: every helper clones ONLY the touched * message object (and the touched segment slot inside it). A value-level * no-op — e.g. a replayed duplicate EXECUTED_TOOL whose merge would write * identical values — returns the PRIOR references untouched, so React * memoization over untouched messages survives redeliveries. * * Framework-free: no React, no timers. */ import type { ApprovalBatchExecutionState, ChatApprovalStatus, MessageSegment, ToolExecutionSegment, ToolExecutionData } from '../types'; import type { UnifiedChatMessage } from '../types/unified-chat-state.types'; export declare function nextId(role: 'user' | 'assistant'): string; /** * Realtime user/direct/system chunks can be replays of rows already on * screen. Content-window dedup is the LAST layer (seq-less transports only) * — see the layer list in `chat-stream-reducer.ts`. */ export declare const CONTENT_DEDUP_WINDOW = 4; export declare const SYSTEM_DEDUP_WINDOW = 10; export declare function hasRecentMessage(prev: UnifiedChatMessage[], predicate: (message: UnifiedChatMessage) => boolean, window: number): boolean; /** * Replace (or append) the trailing assistant message with the latest * accumulated segments. */ export declare function updateTrailingAssistant(prev: UnifiedChatMessage[], segments: MessageSegment[]): UnifiedChatMessage[]; /** * Append-mode counterpart of `updateTrailingAssistant` for post-MESSAGE_END * continuation fragments (`SegmentsUpdateMetadata.append`). Coalesces * trailing fragments of the same type, mirroring the accumulator; block deltas * upsert by identity (see `upsertKey`) so a replayed emit stays idempotent. */ export declare function appendToTrailingAssistant(prev: UnifiedChatMessage[], segments: MessageSegment[]): UnifiedChatMessage[]; /** * THE approval-resolution rule for a single segment — one predicate for * both containers (the message-array projections here AND the flat * segment list in `MessageSegmentAccumulator.updateApprovalStatus`), so * the two paths can never drift: * - `approval_request` matched on `data.requestId` → status flip; * - `approval_batch` anchor (`data.approvalRequestId`, the server's * `batch:` — never a row id) → status flip; * - `approval_batch` ROW (`toolCalls[].toolExecutionRequestId`) → * tick that row's execution (check on approved, cross otherwise) * without touching the batch status. * - `escalation_offer` matched on `data.offerId` → status flip + * resolver stamp. Escalation offers are backed by the SAME * `ToolApprovalRequest` collection as command approvals, so the two id * spaces are one and a cross-match is impossible. * Returns the SAME reference when nothing matched or changed. */ export declare function applyApprovalStatusToSegment(s: MessageSegment, requestId: string, status: ChatApprovalStatus, resolvedByName?: string | null): MessageSegment; /** * Next state for a batch row's execution slot from a tool-execution * chunk — folds the never-downgrade guard (redelivered EXECUTING after * EXECUTED landed) and the EXECUTED/EXECUTING ternary into ONE rule * shared by the message projection and the accumulator. Returns null * for the no-op case (caller keeps prior references). */ export declare function nextBatchExecution(prevExec: ApprovalBatchExecutionState | undefined, toolData: ToolExecutionData): ApprovalBatchExecutionState | null; /** The executions-map triple-spread — one home for the write shape. */ export declare function withBatchExecution; }; }>(seg: S, execId: string, state: ApprovalBatchExecutionState): S; /** * Flip ONLY an approval_batch segment's status — no execution writes. * The click-time optimistic flip uses this instead of * `projectApprovalResolutionToMessages` as defense-in-depth: even if a * (misbehaving) server emitted a batchId colliding with a row's * proposal id, the flip could not pre-tick that row's execution to a * false success before its confirm actually ran. */ export declare function projectBatchStatusToMessages(prev: UnifiedChatMessage[], anchorId: string, status: ChatApprovalStatus): UnifiedChatMessage[]; /** * Mark ONE batch row's confirm as FAILED (expired proposal, network * error): tick its execution icon to the failure cross so the row's * loader doesn't spin forever. Batch status is untouched — other rows * may still be resolving. */ export declare function projectBatchRowFailureToMessages(prev: UnifiedChatMessage[], rowRequestId: string): UnifiedChatMessage[]; /** * Upsert a standalone context-compaction segment into the trailing assistant * bubble. Compaction emissions arrive as the accumulator's CUMULATIVE array — * only the compaction segment itself may be applied, or interleaved * continuation text would duplicate. A `completed` segment replaces the last * `started` one in place. */ export declare function upsertTrailingCompaction(prev: UnifiedChatMessage[], segments: MessageSegment[]): UnifiedChatMessage[]; /** * Cross-message tool-execution updater for post-MESSAGE_END tool chunks * (approved commands executing after the approval bubble, async batch * results). Scans messages from the end: * 1) an `approval_batch` whose `toolCalls` contains the execution id → * merge into its `executions` map; * 2) a matching `tool_execution` segment (same id, or EXECUTING with the * same tool for legacy id-less backends) → update in place; * 3) no match → append the segment to the trailing assistant bubble. * * A value-level no-op (replayed duplicate) returns `prev` untouched. */ export declare function applyToolExecutionToMessages(prev: UnifiedChatMessage[], segment: ToolExecutionSegment): UnifiedChatMessage[]; /** * Merge-only variant of `applyToolExecutionToMessages` — the pure projection * used for the cross-SIDE fan-out in `chat-dialog-store.ts`. Updates a * matching batch slot / tool segment when present; returns `null` when * nothing matches (the caller decides whether to append — projections never * do, so a tool that belongs to one side only never grows a card on the * other). */ export declare function mergeToolExecutionIfPresent(prev: UnifiedChatMessage[], segment: ToolExecutionSegment): UnifiedChatMessage[] | null; /** * Project an approval resolution onto the thread — the ONE rule lives in * `applyApprovalStatusToSegment` (shared with the accumulator's flat * segment list); this is just its message-array projection via * `mapSegments`. */ export declare function projectApprovalResolutionToMessages(prev: UnifiedChatMessage[], requestId: string, status: ChatApprovalStatus, resolvedByName?: string | null): UnifiedChatMessage[]; //# sourceMappingURL=message-mutations.d.ts.map