import type { ActionResultError, ApprovalCandidateOutcome, AuthorizationOutcome, UnstampedMessageStreamEvent } from "#protocol/message.js"; import type { InputRequest, InputResponse } from "#shared/input.js"; import type { JsonValue } from "#shared/json.js"; export interface SessionTurn { readonly turnId: string; readonly sequence: number; readonly status: "active" | "completed" | "cancelled" | "failed"; /** The open turn is parked, holding on its tasks or on a person: a sign-in, approval, or question. */ readonly waiting?: boolean; /** The step the turn's latest `step.started` opened; absent before its first. */ readonly stepIndex?: number; /** The turn streamed assistant output, so steering can no longer restart it. */ readonly outputStarted?: boolean; } export interface SessionInput { readonly request: InputRequest; readonly sequence: number; readonly turnId: string; readonly stepIndex: number; /** The task whose run asks, when a task asks. */ readonly taskId?: string; /** The call a relayed request serves. */ readonly callId?: string; /** `responded` is client-only: an answer this client sent that the stream hasn't settled. */ readonly status: "open" | "responded" | "settled"; readonly response?: InputResponse; readonly outcome?: string; } /** One call that started or reached a task, settled by its `task.settled`. */ export interface ConversationTaskCall { readonly callId: string; readonly turnId: string; readonly status: "working" | "completed" | "failed" | "cancelled"; /** The call's result; present only when `status` is `"completed"`. */ readonly output?: JsonValue; /** Why the call failed; present only when `status` is `"failed"`. */ readonly error?: { readonly message: string; }; } export interface ConversationTask { readonly taskId: string; /** The tool whose call started the task. */ readonly name: string; /** * `"agent"` when a subagent's tool, local or remote, started the task; `"tool"` for an authored * tool, including one that opens sessions with `ctx.agent`. */ readonly kind: "agent" | "tool"; /** Calls in the order they started or reached the task. */ readonly calls: Readonly>; } /** * Where a call stands, as the stream reports it. A task call runs until its `task.settled`, * not until the receipt the model reads. */ export type SessionCallStatus = "running" | "awaiting-input" | "completed" | "failed" | "rejected" | "cancelled"; interface SessionCallFields { readonly callId: string; /** The tool, subagent, or skill the call invokes. */ readonly name: string; readonly turnId: string; readonly stepIndex: number; /** The approval request the call awaits, or awaited. */ readonly requestId?: string; } /** * One call the session made. A call that started or reached a task keeps only the link to it: * the task's call record is where it stands, so the projection holds each outcome once. */ export type SessionCall = SessionCallFields & ({ readonly status: SessionCallStatus; readonly error?: ActionResultError; readonly taskId?: undefined; } | { readonly taskId: string; readonly status?: undefined; readonly error?: undefined; }); export interface SessionAuthorization { /** The attempt's `attemptId`, or its connection name from a writer that sent none. */ readonly attemptId: string; readonly name: string; readonly sequence: number; readonly turnId: string; readonly stepIndex: number; readonly taskId?: string; readonly principalId?: string; /** The approval candidate whose responder signs in. */ readonly candidateId?: string; readonly status: "required" | AuthorizationOutcome; /** The sign-in resumes its work through a callback, rather than inline. */ readonly awaitsCallback?: true; } /** One responder's decision on an approval, as `approval.candidate` reports it. */ export interface SessionApprovalCandidate { readonly candidateId: string; readonly requestId: string; readonly outcome: ApprovalCandidateOutcome; } export interface SessionProjection { /** `session.started` was published. */ readonly started?: true; /** The session ended with `session.completed` or `session.failed`. */ readonly ended?: true; readonly activeTurnId?: string; /** The sequence the next turn takes. */ readonly nextSequence: number; readonly turns: Readonly>; /** By `requestId`. */ readonly inputs: Readonly>; /** By `taskId`. */ readonly tasks: Readonly>; /** By `callId`. */ readonly calls: Readonly>; /** By `attemptId`. */ readonly authorizations: Readonly>; /** By `candidateId`. */ readonly candidates: Readonly>; } export declare function initialSessionProjection(): SessionProjection; export declare function isSettledCallStatus(status: SessionCallStatus): boolean; /** * Folds one stream event into a session's lifecycle. Events this fold doesn't track, and * client-only events, return `state` unchanged, so callers may pass any event through it. */ export declare function foldSession(state: S, event: UnstampedMessageStreamEvent | { readonly type: string; }): S; /** The coordinates the active turn's events carry, or the next turn's when none is open. */ export declare function turnCoordinates(state: SessionProjection): { readonly sequence: number; readonly stepIndex: number; readonly turnId: string; }; /** Inputs awaiting an answer, including requests introduced in earlier turns. */ export declare function openInputs(state: SessionProjection): readonly SessionInput[]; /** Sign-ins the session still waits on. */ export declare function openSignIns(state: SessionProjection): readonly SessionAuthorization[]; /** Task calls whose run hasn't settled them. */ export declare function workingTaskCalls(state: SessionProjection): readonly ConversationTaskCall[]; /** * A call's status for a reader. A call still running when its turn ended, or when the reader's * stream stopped (`streaming: false`), reads as `interrupted`; a task call runs past its turn. */ export declare function callStatus(state: SessionProjection, callId: string, options?: { readonly streaming?: boolean; }): SessionCallStatus | "interrupted" | undefined; /** A call's status as the stream reported it: a task call's is its task call's. */ export declare function reportedCallStatus(state: SessionProjection, call: SessionCall): SessionCallStatus; /** * Drops what closed, so a long-lived session's stored projection stays proportional to its * open work. `keep` names closed requests and calls that execution state still references. */ export declare function pruneSessionProjection(state: SessionProjection, keep?: { readonly requestIds?: Iterable; readonly callIds?: Iterable; }): SessionProjection; export {};