/**
 * Agent Stream Consumer
 *
 * Single source of truth for the SDK-stream event-loop switch shared
 * between `InteractiveSessionService.completeBootAsync` and
 * `InteractiveSessionService.executeAndPersistTurn`. Before this
 * collaborator existed, the two call sites each inlined ~140 lines of
 * near-identical switch code — this class dedupes them behind a single
 * `consume()` method that branches on `mode` ('boot' | 'turn') only
 * where behavior legitimately differs.
 *
 * ## CRITICAL — Ordering invariant (do NOT violate)
 *
 * Every `persistToolEvent` call inside the switch is `await`-ed. This
 * is NOT stylistic — it is an ordering invariant the frontend depends
 * on. `SessionPersistence` uses a process-wide monotonic clock
 * (`nextMessageDate`) to guarantee strictly-increasing `createdAt`
 * timestamps for consecutive rows even when the SDK emits `tool_use`
 * and `tool_result` in the same millisecond. If the consumer fires a
 * persist call with `void` instead of `await`, two rows can interleave
 * and end up with identical `createdAt` values, which breaks
 * `ORDER BY created_at ASC` in `interactiveMessageRepo.findByFeatureId`
 * and in turn breaks the tool->Output pairing in
 * `StepTracker.classifyMessages` on the frontend.
 *
 * The regression is codified by:
 *
 * - `tests/unit/infrastructure/services/interactive/core/session-persistence.test.ts`
 *   "persistToolEvent timestamps are strictly increasing under a frozen clock"
 * - `tests/unit/infrastructure/services/interactive/runtime/agent-stream.consumer.test.ts`
 *   "awaits every persistToolEvent so back-to-back tool_use + tool_result never overlap"
 *
 * Do not replace `await` with `void` anywhere in this file.
 *
 * ## Mode differences
 *
 * | Event   | boot                                               | turn                                                 |
 * | ------- | -------------------------------------------------- | ---------------------------------------------------- |
 * | (any)   | Calls `watchdog.bump()` before the switch          | No watchdog                                          |
 * | init    | Passes through unchanged                           | Ignored (avoid repeat "Session started" messages)    |
 * | done    | Captures `handle.sessionId` on result, NO usage    | Accumulates usage in the returned result             |
 * | error   | Throws                                             | Logs via `ILogger`, notifies, continues              |
 */
import type { SessionPersistence } from '../core/session-persistence.js';
import type { StreamEventDispatcher } from '../core/stream-event-dispatcher.js';
import type { SessionState } from '../core/session-registry.js';
import type { ILogger } from '../../../../application/ports/output/services/logger.interface.js';
import type { InteractiveAgentSessionHandle } from '../../../../application/ports/output/agents/interactive-agent-executor.interface.js';
import type { BootWatchdog } from '../lifecycle/boot-watchdog.js';
export type StreamConsumeMode = 'boot' | 'turn';
export interface StreamConsumeUsage {
    costUsd: number;
    inputTokens: number;
    outputTokens: number;
    numTurns: number;
}
export interface StreamConsumeResult {
    /**
     * `'done'` when the stream emitted a `done` event; `'ended-without-done'`
     * when the async iterator finished (or was aborted) without one.
     */
    completed: 'done' | 'ended-without-done';
    /**
     * Usage metadata captured from the `done` (turn mode) or `error` (turn
     * mode, when the SDK still reports cost) event. Always `undefined`
     * in boot mode — boot greetings don't count toward session usage.
     */
    usage?: StreamConsumeUsage;
    /**
     * The agent SDK session id read off the handle when the `done` event
     * fired during boot. The bootstrapper uses this to reconcile the DB
     * row and detect CWD-mismatch resumption failures. Always `undefined`
     * in turn mode.
     */
    agentSessionIdFromHandle?: string;
}
export declare class AgentStreamConsumer {
    private readonly persistence;
    private readonly dispatcher;
    private readonly logger;
    constructor(persistence: SessionPersistence, dispatcher: StreamEventDispatcher, logger: ILogger);
    consume(handle: InteractiveAgentSessionHandle, state: SessionState, mode: StreamConsumeMode, abortController: AbortController, watchdog?: BootWatchdog): Promise<StreamConsumeResult>;
    /**
     * Handle a single event. Returns `'stream-done'` when the caller
     * should exit the loop with `completed: 'done'`; `'error-with-usage'`
     * when a turn-mode error event also carried usage that the caller
     * should harvest on its way to the natural end of the stream.
     */
    private handleEvent;
    private readUsage;
}
//# sourceMappingURL=agent-stream.consumer.d.ts.map