/** * Chat State Types — Per-chat turns, messages, response parts, tool calls, * and elicitation/input requests exposed on `ahp-chat:` channels. * * Stability: 2 - Stable * * @module channels-chat/state */ import type { ModelSelection } from '../channels-root/state.js'; import type { AgentSelection, McpAuthRequirement, SessionStatus } from '../channels-session/state.js'; import type { ContentRef, ErrorInfo, FileEdit, StringOrMarkdown, TextRange, TextSelection, URI, UsageInfo } from '../common/state.js'; /** * Full state for a single chat, loaded when a client subscribes to the chat's * URI. * * The lightweight catalog representation of a chat is {@link ChatSummary}, * carried in {@link SessionState.chats | `SessionState.chats`}. `ChatState` * **denormalizes** every {@link ChatSummary} field directly onto itself so * subscribers receive one flat object instead of having to merge a nested * `summary` sub-object. Producers MUST keep the two representations * consistent: any change to the inlined fields below SHOULD also be * announced on the parent session via the matching * {@link SessionChatUpdatedAction | `session/chatUpdated`} action. * * @category Chat State */ export interface ChatState { /** Chat URI */ resource: URI; /** Chat title */ title: string; /** Current chat status (reuses SessionStatus shape) */ status: SessionStatus; /** Human-readable description of what the chat is currently doing */ activity?: string; /** Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`) */ modifiedAt: string; /** How this chat came into existence */ origin?: ChatOrigin; /** * How the user can interact with this chat. See {@link ChatInteractivity}. * * Supports agent-team patterns where worker chats are read-only or hidden. * Absence defaults to {@link ChatInteractivity.Full} for backward * compatibility. */ interactivity?: ChatInteractivity; /** * The subset of the session's * {@link SessionState.workingDirectories | `workingDirectories`} that this * chat's agent has tool access to. Every entry MUST be present in the owning * session's `workingDirectories`; servers MUST reject a * `chat/workingDirectorySet` action that violates this constraint. * * When absent, the chat inherits the full session set. When present but empty * (not recommended), the chat has no working-directory tool access at all. * * Dispatch `chat/workingDirectorySet` / `chat/workingDirectoryRemoved` to * update the subset on a running chat. */ workingDirectories?: URI[]; /** Completed turns */ turns: Turn[]; /** * Cursor for loading older completed turns into this chat state. * * Presence means `turns` is a tail window and more historical turns are * available. Pass this opaque cursor to `fetchTurns`; the host MUST insert * the loaded turns into state and update or clear this cursor before * responding. Absence means the state contains all retained turns. */ turnsNextCursor?: string; /** Currently in-progress turn */ activeTurn?: ActiveTurn; /** Message to inject into the current turn at a convenient point */ steeringMessage?: PendingMessage; /** Messages to send automatically as new turns after the current turn finishes */ queuedMessages?: PendingMessage[]; /** * The user's in-progress draft input for this chat — the message they are * composing but have not sent yet, including its * {@link Message.model | model} / {@link Message.agent | agent} selection * and attachments. * * Clients MAY periodically sync their local input state into this field so * a draft survives reloads and is visible to other clients viewing the same * chat. Eager syncing is **not** required — clients SHOULD debounce and MAY * sync only at convenient points. When presenting input UI for an existing * chat, clients SHOULD use any `draft` to initialize their input state. * Cleared (set to `undefined`) once the message is sent. */ draft?: Message; /** * Additional provider-specific metadata for this chat. */ _meta?: Record; } /** * Lightweight catalog entry for a chat, carried in * {@link SessionState.chats | `SessionState.chats`}. The full conversation * lives in {@link ChatState}, which inlines (denormalizes) every field below. * * @category Chat State */ export interface ChatSummary { /** Chat URI */ resource: URI; /** Chat title */ title: string; /** Current chat status (reuses SessionStatus shape) */ status: SessionStatus; /** Human-readable description of what the chat is currently doing */ activity?: string; /** Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`) */ modifiedAt: string; /** How this chat came into existence */ origin?: ChatOrigin; /** * How the user can interact with this chat. See {@link ChatInteractivity}. * * Supports agent-team patterns where worker chats are read-only or hidden. * Absence defaults to {@link ChatInteractivity.Full} for backward * compatibility. */ interactivity?: ChatInteractivity; /** * The subset of the session's working directories this chat uses. * See {@link ChatState.workingDirectories} for the full semantics. */ workingDirectories?: URI[]; } /** * Discriminant for {@link ChatOrigin} — how a chat came into existence. * * @category Chat State * @nonexhaustive */ export declare const enum ChatOriginKind { /** User created the chat explicitly (e.g. via the host UI). */ User = "user", /** Forked from an existing chat at a specific turn. */ Fork = "fork", /** Created as an independent side conversation from a specific turn. */ SideChat = "sideChat", /** Spawned by a tool call running in another chat (e.g. a sub-agent delegation). */ Tool = "tool" } /** * Immutable selected-text snapshot captured when a side chat is created. * * The host records this exact text when it accepts `createChat`; later changes * to the source chat do not alter it. * * @category Chat State */ export interface SideChatSelection { /** * Exact selected-text snapshot captured at `createChat` acceptance. * * MUST be non-empty. */ text: string; /** * Optional provenance for the response part that contained {@link text} when * the host took the snapshot. * * Advisory only: this is not a live range or offset and MUST NOT be used to * recompute `text`. */ responsePartId?: string; } /** * How a chat came into existence. Clients MAY use it to render * contextual UI (parent indicators, fork markers, "spawned by tool" badges). * * Fork and side-chat origins both carry a stable top-level `turnId` alongside * their discriminated `kind` value instead of snapshotting whether that turn * was active or historical at creation time. Consumers resolve the identifier * against the * source chat's current `activeTurn` or retained `turns` as needed. * * When a host accepts side-chat creation from the source chat's current active * turn, it snapshots the retained history plus that turn's current user * message and any partial assistant response already available. Later * source-turn deltas do not retroactively change the created side chat's * starting context, and once the source turn completes it is still referenced * by the same `turnId`. Side-chat origins MAY also retain an immutable * {@link SideChatSelection | selected-text snapshot} captured at acceptance * time; any `responsePartId` there is provenance only, not a range. * * The `tool` variant records a tool-spawned worker from the worker's side: its * `chat`/`toolCallId` identify the spawning tool call in the parent chat. This * is the canonical record of the spawn relationship. The same edge is surfaced * from the parent's side by {@link ToolResultSubagentContent}, whose `resource` * is this chat's URI; hosts MUST keep the two consistent. * * @category Chat State */ export type ChatOrigin = { kind: ChatOriginKind.User; } | { kind: ChatOriginKind.Fork; chat: URI; turnId: string; } | { kind: ChatOriginKind.SideChat; chat: URI; turnId: string; selection?: SideChatSelection; } | { kind: ChatOriginKind.Tool; chat: URI; toolCallId: string; }; /** * How a user can interact with a chat. * * - `Full` — user can send messages and watch (default when absent) * - `ReadOnly` — user can watch but not send messages (e.g. agent team workers) * - `Hidden` — internal worker not shown in UI at all * * Supports the agent-team pattern where a lead chat is fully interactive and * worker chats are read-only (visible for observability) or hidden (internal * implementation detail). The harness sets this based on the chat's role; * the UI uses it to show appropriate controls. * * @category Chat State * @exhaustive */ export declare const enum ChatInteractivity { /** User can send messages and watch (default when absent) */ Full = "full", /** User can watch but not send messages */ ReadOnly = "read-only", /** Internal worker not shown in UI at all */ Hidden = "hidden" } /** * Discriminant for pending message kinds. * * @category Pending Message Types * @exhaustive */ export declare const enum PendingMessageKind { /** Injected into the current turn at a convenient point */ Steering = "steering", /** Sent automatically as a new turn after the current turn finishes */ Queued = "queued" } /** * A message queued for future delivery to the agent. * * Steering messages are injected into the current turn mid-flight. * Queued messages are automatically started as new turns after the * current turn naturally finishes. * * @category Pending Message Types */ export interface PendingMessage { /** Unique identifier for this pending message */ id: string; /** The message that will start the next turn */ message: Message; } /** * How a client completed an input request. * * @category Chat Input Types * @exhaustive */ export declare const enum ChatInputResponseKind { Accept = "accept", Decline = "decline", Cancel = "cancel" } /** * Question/input control kind. * * @category Chat Input Types * @nonexhaustive */ export declare const enum ChatInputQuestionKind { Text = "text", Number = "number", Integer = "integer", Boolean = "boolean", SingleSelect = "single-select", MultiSelect = "multi-select" } /** * A choice in a select-style question. * * @category Chat Input Types */ export interface ChatInputOption { /** Stable option identifier; for MCP enum values this is the enum string */ id: string; /** Display label */ label: string; /** Optional secondary text */ description?: string; /** Whether this option is the recommended/default choice */ recommended?: boolean; } interface ChatInputQuestionBase { /** Stable question identifier used as the key in `answers` */ id: string; /** Short display title */ title?: string; /** Prompt shown to the user */ message: string; /** Whether the user must answer this question to accept the request */ required?: boolean; } /** Text question within a chat input request. */ export interface ChatInputTextQuestion extends ChatInputQuestionBase { kind: ChatInputQuestionKind.Text; /** Format hint for text questions, such as `email`, `uri`, `date`, or `date-time` */ format?: string; /** Minimum string length */ min?: number; /** Maximum string length */ max?: number; /** Default text */ defaultValue?: string; } /** Numeric question within a chat input request. */ export interface ChatInputNumberQuestion extends ChatInputQuestionBase { kind: ChatInputQuestionKind.Number | ChatInputQuestionKind.Integer; /** * Minimum value * @format float */ min?: number; /** * Maximum value * @format float */ max?: number; /** * Default numeric value * @format float */ defaultValue?: number; } /** Boolean question within a chat input request. */ export interface ChatInputBooleanQuestion extends ChatInputQuestionBase { kind: ChatInputQuestionKind.Boolean; /** Default boolean value */ defaultValue?: boolean; } /** Single-select question within a chat input request. */ export interface ChatInputSingleSelectQuestion extends ChatInputQuestionBase { kind: ChatInputQuestionKind.SingleSelect; /** Options the user may select from */ options: ChatInputOption[]; /** Whether the user may enter text instead of selecting an option */ allowFreeformInput?: boolean; } /** Multi-select question within a chat input request. */ export interface ChatInputMultiSelectQuestion extends ChatInputQuestionBase { kind: ChatInputQuestionKind.MultiSelect; /** Options the user may select from */ options: ChatInputOption[]; /** Whether the user may enter text in addition to selecting options */ allowFreeformInput?: boolean; /** Minimum selected item count */ min?: number; /** Maximum selected item count */ max?: number; } /** * One question within a chat input request. * * @category Chat Input Types */ export type ChatInputQuestion = ChatInputTextQuestion | ChatInputNumberQuestion | ChatInputBooleanQuestion | ChatInputSingleSelectQuestion | ChatInputMultiSelectQuestion; /** * The request payload carried by an {@link InputRequestResponsePart}. * * The server creates or replaces the containing response part with * `chat/inputRequested`. Clients sync drafts with `chat/inputAnswerChanged` * and submit responses with `chat/inputCompleted`. * * @category Chat Input Types */ export interface ChatInputRequest { /** Stable request identifier */ id: string; /** Display message for the request as a whole */ message?: string; /** URL the user should review or open, for URL-style elicitations */ url?: URI; /** Ordered questions to ask the user */ questions?: ChatInputQuestion[]; /** Current draft or submitted answers, keyed by question ID */ answers?: Record; } /** * Answer value kind. * * @category Chat Input Types * @nonexhaustive */ export declare const enum ChatInputAnswerValueKind { Text = "text", Number = "number", Boolean = "boolean", Selected = "selected", SelectedMany = "selected-many" } /** * Value captured for one answer. * * @category Chat Input Types */ export interface ChatInputTextAnswerValue { kind: ChatInputAnswerValueKind.Text; value: string; } export interface ChatInputNumberAnswerValue { kind: ChatInputAnswerValueKind.Number; /** @format float */ value: number; } export interface ChatInputBooleanAnswerValue { kind: ChatInputAnswerValueKind.Boolean; value: boolean; } export interface ChatInputSelectedAnswerValue { kind: ChatInputAnswerValueKind.Selected; value: string; /** Free-form text entered instead of selecting an option */ freeformValues?: string[]; } export interface ChatInputSelectedManyAnswerValue { kind: ChatInputAnswerValueKind.SelectedMany; value: string[]; /** Free-form text entered in addition to selected options */ freeformValues?: string[]; } export type ChatInputAnswerValue = ChatInputTextAnswerValue | ChatInputNumberAnswerValue | ChatInputBooleanAnswerValue | ChatInputSelectedAnswerValue | ChatInputSelectedManyAnswerValue; export interface ChatInputAnswered { /** Answer state */ state: ChatInputAnswerState.Draft | ChatInputAnswerState.Submitted; /** Answer value */ value: ChatInputAnswerValue; } export interface ChatInputSkipped { /** Answer state */ state: ChatInputAnswerState.Skipped; /** Free-form reason or value captured while skipping, if any */ freeformValues?: string[]; } /** * Answer lifecycle state. * * @category Chat Input Types * @exhaustive */ export declare const enum ChatInputAnswerState { Draft = "draft", Submitted = "submitted", Skipped = "skipped" } /** * Draft, submitted, or skipped answer for one question. * * @category Chat Input Types */ export type ChatInputAnswer = ChatInputAnswered | ChatInputSkipped; /** * How a turn ended. * * @category Turn Types * @exhaustive */ export declare const enum TurnState { Complete = "complete", Cancelled = "cancelled", Error = "error" } /** * Discriminant for {@link MessageAttachment} variants. * * @category Turn Types * @nonexhaustive */ export declare const enum MessageAttachmentKind { /** A simple, opaque attachment whose representation is described by the producer. */ Simple = "simple", /** An attachment whose data is embedded inline as a base64 string. */ EmbeddedResource = "embeddedResource", /** An attachment that references a resource by URI. */ Resource = "resource", /** An attachment that references annotations on an annotations channel. */ Annotations = "annotations", /** An attachment that references a bounded transcript from another chat. */ Chat = "chat" } /** * A completed request/response cycle. * * @category Turn Types */ export interface Turn { /** Turn identifier */ id: string; /** ISO 8601 timestamp when this turn started. */ startedAt?: string; /** Turn duration in milliseconds. */ duration?: number; /** The message that initiated the turn */ message: Message; /** * All response content in stream order: text, tool calls, reasoning, and content refs. * * Consumers should derive display text by concatenating markdown parts, * and find tool calls by filtering for `ToolCall` parts. */ responseParts: ResponsePart[]; /** Token usage info */ usage: UsageInfo | undefined; /** How the turn ended */ state: TurnState; } /** * An in-progress turn — the assistant is actively streaming. * * @category Turn Types */ export interface ActiveTurn { /** Turn identifier */ id: string; /** ISO 8601 timestamp when this turn started. */ startedAt: string; /** The message that initiated the turn */ message: Message; /** * All response content in stream order: text, tool calls, reasoning, and content refs. * * Tool call parts include `pendingPermissions` when permissions are awaiting user approval. */ responseParts: ResponsePart[]; /** Token usage info */ usage: UsageInfo | undefined; } /** * Discriminant for {@link MessageOrigin} — identifies who produced a message. * * @category Turn Types * @nonexhaustive */ export declare enum MessageKind { /** Sent directly by the user. */ User = "user", /** * Produced by the agent itself rather than the user — for example, an agent * that seeds the first message of a chat it spawned. */ Agent = "agent", /** * Produced by a tool rather than the user — for example, a tool that spawns a * worker chat whose first message carries a seed prompt. */ Tool = "tool", /** Emitted automatically when an automation run starts a session. */ Automation = "automation", /** A system-generated notification rather than a direct user message. */ SystemNotification = "systemNotification" } /** * Identifies the origin of a {@link Message} — who produced it. For the message * that initiates a turn ({@link Turn.message}), this is also the origin of the * turn; for steering or queued messages it is just the origin of that message. * * @category Turn Types */ export interface MessageOrigin { /** The kind of actor that produced the message. */ kind: MessageKind; } /** * A message that initiates or steers a turn. Messages can originate from the * user, the agent, a tool, an automation, or be system-generated (see * {@link MessageOrigin}). * * Attachments MAY be referenced inside {@link Message.text} via their * {@link MessageAttachmentBase.range} field. Attachments without a range are * still associated with the message but do not correspond to a specific span * in the text. * * @category Turn Types */ export interface Message { /** Message text */ text: string; /** The origin of the message */ origin: MessageOrigin; /** File/selection attachments */ attachments?: MessageAttachment[]; /** * The model this message was, or will be, sent with. * * For historic user/agent messages this records the model actually used, so * a client editing or resending the message can retain that selection. For a * {@link ChatState.draft | draft} it carries the model the user picked for * the message they are composing. Absent means the agent host's default * model applies. */ model?: ModelSelection; /** * The custom agent this message was, or will be, sent with. * * For historic messages this records the agent actually used; for a * {@link ChatState.draft | draft} it carries the agent the user picked. * Absent means no custom agent — the provider's default behavior applies. */ agent?: AgentSelection; /** * Additional provider-specific metadata for this message. * * Clients MAY look for well-known keys here to provide enhanced UI, and * agent hosts MAY use it to carry context that does not fit any other * field. Mirrors the MCP `_meta` convention. */ _meta?: Record; } /** * Common fields shared by all {@link MessageAttachment} variants. * * @category Turn Types */ export interface MessageAttachmentBase { /** * A human-readable label for the attachment (e.g. the filename of a file * attachment). Used for display in UI. */ label: string; /** * If defined, the range in {@link Message.text} that references this * attachment. This is a text range, not a byte range. */ range?: TextRange; /** * Advisory display hint for clients rendering this attachment. Recognized * values include: * * - `'image'`: the attachment is an image * - `'document'`: the attachment is a textual document * - `'symbol'`: the attachment is a code symbol (e.g. a function or class) * - `'directory'`: the attachment is a folder * - `'selection'`: the attachment is a selection within a document * * Implementations MAY provide additional values; clients SHOULD fall back * to a reasonable default when an unknown value is encountered. */ displayKind?: string; /** * Additional implementation-defined metadata for the attachment. * * If the attachment was produced by the `completions` command, the client * MUST preserve every property of `_meta` originally returned by the agent * host when sending the user message containing the accepted completion. */ _meta?: Record; } /** * A simple, opaque attachment whose model representation is described by * the producer. * * @category Turn Types */ export interface SimpleMessageAttachment extends MessageAttachmentBase { /** Discriminant */ type: MessageAttachmentKind.Simple; /** * Representation of the attachment as it should be shown to the model. * * If the attachment was produced by the client, this property MUST be * defined so the agent host can correctly interpret the attachment. This * property MAY be omitted when the attachment originated from a * `completions` response. */ modelRepresentation?: string; } /** * An attachment whose data is embedded inline as a base64 string. * * Use this for small binary payloads (e.g. a pasted image) that should be * delivered with the user message itself rather than fetched separately. * * @category Turn Types */ export interface MessageEmbeddedResourceAttachment extends MessageAttachmentBase { /** Discriminant */ type: MessageAttachmentKind.EmbeddedResource; /** Base64-encoded binary data */ data: string; /** Content MIME type (e.g. `"image/png"`, `"application/pdf"`) */ contentType: string; /** * Optional selection within the attached textual resource. * * Only meaningful for textual resources. */ selection?: TextSelection; } /** * An attachment that references a resource by URI. The content is not * delivered inline; consumers can fetch it via `resourceRead` when needed. * * @category Turn Types */ export interface MessageResourceAttachment extends MessageAttachmentBase, ContentRef { /** Discriminant */ type: MessageAttachmentKind.Resource; /** * Optional selection within the referenced textual resource. * * Only meaningful for textual resources. */ selection?: TextSelection; } /** * An attachment that references annotations on a session's annotations * channel (see {@link AnnotationsState}). * * When {@link annotationIds} is omitted the attachment references every * annotation on the channel; when present it references only the listed * {@link Annotation.id | annotation ids}. * * @category Turn Types */ export interface MessageAnnotationsAttachment extends MessageAttachmentBase { /** Discriminant */ type: MessageAttachmentKind.Annotations; /** * The annotations channel URI (typically `ahp-session://annotations`). * Matches {@link AnnotationsSummary.resource}. */ resource: URI; /** * Specific {@link Annotation.id | annotation ids} to reference. When * omitted, the attachment references all annotations on the channel. */ annotationIds?: string[]; } /** * An attachment that references a chat transcript through a fixed completed * turn. * * The referenced chat MAY belong to a different session than the message's * chat. The attachment's model representation identifies the chat in a way * that hosts can resolve regardless of the session that owns it. * * When `endTurn` is omitted, the host MUST resolve and pin the referenced * chat's latest completed turn when accepting the message. This lets clients * attach a chat without knowing its turn identifiers. When provided, `endTurn` * MUST reference a completed, retained turn. The host resolves the transcript * from its first retained turn through the pinned turn, inclusive. Later turns * do not change the context represented by an already-sent attachment. * * When the referenced chat has no completed retained turns, the resolved * transcript is empty and hosts MUST NOT reject the attachment on that basis. * * Hosts MUST NOT recursively expand chat attachments found inside the * referenced transcript. Clients SHOULD keep rendering `label` if the * referenced chat is later pruned, and treat opening `resource` as best-effort. * * @category Turn Types */ export interface MessageChatAttachment extends MessageAttachmentBase { /** Discriminant */ type: MessageAttachmentKind.Chat; /** URI of the referenced chat. */ resource: URI; /** * Last completed turn included in the referenced transcript. When omitted, * the host pins the latest completed turn when accepting the message. */ endTurn?: string; } /** * An attachment associated with a {@link Message}. * * @category Turn Types */ export type MessageAttachment = SimpleMessageAttachment | MessageEmbeddedResourceAttachment | MessageResourceAttachment | MessageAnnotationsAttachment | MessageChatAttachment; /** * Discriminant for response part types. * * @category Response Parts * @nonexhaustive */ export declare const enum ResponsePartKind { Markdown = "markdown", ContentRef = "contentRef", ToolCall = "toolCall", Reasoning = "reasoning", SystemNotification = "systemNotification", InputRequest = "inputRequest", Error = "error" } /** * @category Response Parts */ export interface MarkdownResponsePart { /** Discriminant */ kind: ResponsePartKind.Markdown; /** Part identifier, used by `chat/delta` to target this part for content appends */ id: string; /** Markdown content */ content: string; } /** * A content part that's a reference to large content stored outside the state tree. * * @category Response Parts */ export interface ResourceResponsePart extends ContentRef { /** Discriminant */ kind: ResponsePartKind.ContentRef; } /** * A tool call represented as a response part. * * Tool calls are part of the response stream, interleaved with text and * reasoning. The `toolCall.toolCallId` serves as the part identifier for * actions that target this part. * * @category Response Parts */ export interface ToolCallResponsePart { /** Discriminant */ kind: ResponsePartKind.ToolCall; /** Full tool call lifecycle state */ toolCall: ToolCallState; } /** * Reasoning/thinking content from the model. * * @category Response Parts */ export interface ReasoningResponsePart { /** Discriminant */ kind: ResponsePartKind.Reasoning; /** Part identifier, used by `chat/reasoning` to target this part for content appends */ id: string; /** Accumulated reasoning text */ content: string; } /** * @category Response Parts */ export type ResponsePart = MarkdownResponsePart | ResourceResponsePart | ToolCallResponsePart | ReasoningResponsePart | SystemNotificationResponsePart | InputRequestResponsePart | ErrorResponsePart; /** * A live or resolved input request (elicitation) in the turn response stream. * * The server inserts the part with `chat/inputRequested`. While * {@link response} is absent, clients can update answer drafts with * `chat/inputAnswerChanged` and submit a response with `chat/inputCompleted`. * Completion updates this part in place so its stream position is stable and * the full interaction remains durable and backfillable via `fetchTurns`. * * If the turn ends without a submitted response, the unresolved part remains * in the completed turn transcript with {@link response} absent. * * @category Response Parts */ export interface InputRequestResponsePart { /** Discriminant */ kind: ResponsePartKind.InputRequest; /** * The request, carrying its `id`, `message`, `url`, `questions`, and current * draft or submitted `answers`. */ request: ChatInputRequest; /** * How the request was resolved. Absent until a client submits `accept`, * `decline`, or `cancel` with `chat/inputCompleted`. */ response?: ChatInputResponseKind; } /** * An error encountered while processing a turn. * * This is the detailed source of truth for the error. {@link Turn.state} * remains {@link TurnState.Error} while the turn is stopped at this error so * clients can detect the terminal state without inspecting response parts. * * When {@link resumable} is `true`, a client may dispatch `chat/turnResume` * while this is the latest turn and its state is {@link TurnState.Error}. * Clients decide whether and how to present that affordance. * * @category Response Parts */ export interface ErrorResponsePart { /** Discriminant */ kind: ResponsePartKind.Error; /** Error details. */ error: ErrorInfo; /** Whether the host can resume the turn from this error. Only `true` enables resume. */ resumable?: boolean; } /** * A system notification surfaced as part of the response stream. * * System notifications are messages authored by the agent harness * that need to be visible to both the agent (for situational awareness) and * the user (for transcript continuity). Examples include "background subagent * X completed" or "task Y was cancelled". * * @category Response Parts */ export interface SystemNotificationResponsePart { /** Discriminant */ kind: ResponsePartKind.SystemNotification; /** The text of the system notification */ content: StringOrMarkdown; /** * Additional provider-specific metadata for this notification. * * A host MAY attach a machine-readable descriptor of what triggered the * notification so clients can categorize, icon, group, filter, or localize * it without parsing `content`. Clients MAY look for well-known keys here to * provide enhanced UI, and MUST render coherently from `content` alone when * `_meta` is absent or unrecognized. */ _meta?: Record; } /** * Status of a tool call in the lifecycle state machine. * * @category Tool Call Types * @nonexhaustive */ export declare const enum ToolCallStatus { Streaming = "streaming", PendingConfirmation = "pending-confirmation", Running = "running", /** * Running paused because the MCP server backing this call needs * authentication (typically step-up auth for insufficient scope, * surfacing mid-execution). See {@link ToolCallAuthRequiredState}. */ AuthRequired = "auth-required", PendingResultConfirmation = "pending-result-confirmation", Completed = "completed", Cancelled = "cancelled" } /** * How a tool call was confirmed for execution. * * - `NotNeeded` — No confirmation required (auto-approved) * - `UserAction` — User explicitly approved * - `Setting` — Approved by a persistent user setting * * @category Tool Call Types * @nonexhaustive */ export declare const enum ToolCallConfirmationReason { NotNeeded = "not-needed", UserAction = "user-action", Setting = "setting" } /** * Identifies a model judge as the source of a confirmation requirement. * * @category Tool Call Types * @nonexhaustive */ export declare const enum ToolCallRiskAssessmentKind { Judge = "judge" } /** * Lifecycle status of an asynchronous model-judge confirmation decision. * * @category Tool Call Types * @nonexhaustive */ export declare const enum ToolCallRiskAssessmentStatus { Loading = "loading", Complete = "complete" } interface ToolCallRiskAssessmentBase { kind: ToolCallRiskAssessmentKind; } /** * The model judge is still evaluating the tool call. * * @category Tool Call Types */ export interface ToolCallRiskAssessmentLoadingState extends ToolCallRiskAssessmentBase { status: ToolCallRiskAssessmentStatus.Loading; } /** * The model judge has completed its evaluation. * * @category Tool Call Types */ export interface ToolCallRiskAssessmentCompleteState extends ToolCallRiskAssessmentBase { status: ToolCallRiskAssessmentStatus.Complete; reason: StringOrMarkdown; /** * The judge's normalized safety score, where `0` is unsafe and `1` is safe. * @format float */ safety: number; } export type ToolCallRiskAssessment = ToolCallRiskAssessmentLoadingState | ToolCallRiskAssessmentCompleteState; /** * Why a tool call was cancelled. * * @category Tool Call Types * @exhaustive */ export declare const enum ToolCallCancellationReason { Denied = "denied", Skipped = "skipped", ResultDenied = "result-denied" } /** * Whether a confirmation option represents an approval or denial action. * * @category Tool Call Types * @nonexhaustive */ export declare const enum ConfirmationOptionKind { Approve = "approve", Deny = "deny" } /** * A confirmation option that the server offers for a tool call awaiting * approval. Allows richer choices beyond simple approve/deny — for example, * "Approve in this Session" or "Deny with reason." * * @category Tool Call Types */ export interface ConfirmationOption { /** Unique identifier for the option, returned in the confirmed action */ id: string; /** Human-readable label displayed to the user */ label: string; /** Whether this option represents an approval or denial */ kind: ConfirmationOptionKind; /** * Logical group number for visual categorisation. * * Clients SHOULD display options in the order they are defined and MAY * use differing group numbers to insert dividers between logical clusters * of options. */ group?: number; } /** * Identifies the source of a tool call's implementation. * * @category Tool Call Types * @nonexhaustive */ export declare const enum ToolCallContributorKind { Client = "client", MCP = "mcp" } export interface ToolCallClientContributor { kind: ToolCallContributorKind.Client; /** * If this tool is provided by a client, the `clientId` of the owning client. * Absent for server-side tools. * * When set, the identified client is responsible for executing the tool and * dispatching `chat/toolCallComplete` with the result. */ clientId: string; } export interface ToolCallMcpContributor { kind: ToolCallContributorKind.MCP; /** * Customization ID of the corresponding MCP server in {@link SessionState.customizations}. */ customizationId: string; } export type ToolCallContributor = ToolCallClientContributor | ToolCallMcpContributor; /** * Metadata common to all tool call states. * * @category Tool Call Types * @remarks * Fields like `toolName` carry agent-specific identifiers on the wire despite the * agent-agnostic design principle. These exist for debugging and logging purposes. * A future version may move these to a separate diagnostic channel or namespace them * more clearly. */ interface ToolCallBase { /** Unique tool call identifier */ toolCallId: string; /** Internal tool name (for debugging/logging) */ toolName: string; /** Human-readable tool name */ displayName: string; /** Human-readable description of what the tool invocation intends to do */ intention?: string; /** * Reference to the contributor of the tool being called. */ contributor?: ToolCallContributor; /** * Additional provider-specific metadata for this tool call. * * This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865) * `McpUiToolMeta` found in MCP tool calls, which may be used in combination * with the {@link contributor} to serve MCP Apps. */ _meta?: Record; } /** * Properties available once tool call parameters are fully received. * * @category Tool Call Types */ interface ToolCallParameterFields { /** Message describing what the tool will do */ invocationMessage: StringOrMarkdown; /** * Final tool input. * * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, * the host MUST replace the resource contents before echoing the accepted * confirmation action. Clients MUST NOT cache tool input across confirmation. */ toolInput?: ToolInput; } /** * Tool input represented inline or by reference. * * @category Tool Call Types */ export type ToolInput = string | ContentRef; /** * Tool execution result details, available after execution completes. * * @category Tool Call Types */ export interface ToolCallResult { /** Whether the tool succeeded */ success: boolean; /** Past-tense description of what the tool did */ pastTenseMessage: StringOrMarkdown; /** * Unstructured result content blocks. * * This mirrors the `content` field of MCP `CallToolResult`. */ content?: ToolResultContent[]; /** * Optional structured result object. * * This mirrors the `structuredContent` field of MCP `CallToolResult`. */ structuredContent?: Record; /** Error details if the tool failed */ error?: { message: string; code?: string; }; } /** * LM is streaming the tool call parameters. * * @category Tool Call Types */ export interface ToolCallStreamingState extends ToolCallBase { status: ToolCallStatus.Streaming; /** Partial parameters accumulated from tool-call deltas. */ partialInput?: string; /** Progress message shown while parameters are streaming */ invocationMessage?: StringOrMarkdown; } /** * Parameters are complete, or a running tool requires re-confirmation * (e.g. a mid-execution permission check). * * @category Tool Call Types */ export interface ToolCallPendingConfirmationState extends ToolCallBase, ToolCallParameterFields { status: ToolCallStatus.PendingConfirmation; /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ confirmationTitle?: StringOrMarkdown; /** Risk assessment that informed the confirmation requirement. */ riskAssessment?: ToolCallRiskAssessment; /** File edits that this tool call will perform, for preview before confirmation */ edits?: { items: FileEdit[]; }; /** Whether the agent host allows the client to edit the tool's input parameters before confirming */ editable?: boolean; /** * Options the server offers for this confirmation. When present, the client * SHOULD render these instead of a plain approve/deny UI. Each option * belongs to a {@link ConfirmationOptionGroup} so the client can still * categorise the choices. */ options?: ConfirmationOption[]; } /** * Fields present on every tool call state that exists **after** confirmation * has been resolved: {@link ToolCallRunningState}, {@link ToolCallAuthRequiredState}, * {@link ToolCallPendingResultConfirmationState}, and {@link ToolCallCompletedState}. * `ToolCallPendingConfirmationState` (not yet confirmed) and * `ToolCallCancelledState` (the denial path — never ran) don't satisfy this * invariant, so they keep their own `selectedOption` field independently * rather than extending this one. * * @category Tool Call Types */ interface ToolCallPostConfirmationFields { /** How the tool was confirmed for execution */ confirmed: ToolCallConfirmationReason; /** The confirmation option the user selected, if confirmation options were provided */ selectedOption?: ConfirmationOption; } /** * Tool is actively executing. * * @category Tool Call Types */ export interface ToolCallRunningState extends ToolCallBase, ToolCallParameterFields, ToolCallPostConfirmationFields { status: ToolCallStatus.Running; /** * Partial content produced while the tool is still executing. * * For example, a terminal content block lets clients subscribe to live * output before the tool completes. */ content?: ToolResultContent[]; } /** * A running tool call is paused because the MCP server backing it needs * authentication — most commonly {@link McpAuthRequirement.reason | * `insufficientScope`} step-up auth triggered by the `tools/call` request * itself. Only ever reached from {@link ToolCallRunningState}, and normally * returns there once authenticated: `running` → `auth-required` → `running` * → …. A client MAY instead cancel the invocation without authenticating by * dispatching a `chat/toolCallComplete` with a **failed** result, always * moving straight to {@link ToolCallCompletedState} — * `requiresResultConfirmation` is ignored on this path, so it can never * enter {@link ToolCallPendingResultConfirmationState}. A **successful** * result dispatched from this state is invalid and MUST be rejected/ignored * as a no-op by the reducer, since execution never resumed after the * challenge. * * This is the tool-call-level counterpart to * {@link McpServerAuthRequiredState} — that state means the MCP *server* * cannot serve any request; this one means *this specific invocation* is * waiting on the same kind of challenge. The two are dispatched * independently and MAY be true at the same time, or not: an * `insufficientScope` challenge triggered by a single tool call, for * example, need not block the whole server. * * Because the challenge is always resolved by pushing a token via the * existing `authenticate` command, this state can only originate from a * tool call {@link ToolCallContributorKind.MCP | contributed by an MCP * server} — `contributor` is narrowed accordingly (unlike the optional, * multi-kind `contributor` on other tool call states). * * @category Tool Call Types */ export interface ToolCallAuthRequiredState extends ToolCallBase, ToolCallParameterFields, ToolCallPostConfirmationFields { status: ToolCallStatus.AuthRequired; /** The MCP server that contributed this tool call — always MCP, never a client tool. */ contributor: ToolCallMcpContributor; /** The authentication challenge blocking this invocation. */ auth: McpAuthRequirement; /** Partial content produced before the call paused for authentication. */ content?: ToolResultContent[]; } /** * Tool finished executing, waiting for client to approve the result. * * @category Tool Call Types */ export interface ToolCallPendingResultConfirmationState extends ToolCallBase, ToolCallParameterFields, ToolCallResult, ToolCallPostConfirmationFields { status: ToolCallStatus.PendingResultConfirmation; } /** * Tool completed successfully or with an error. * * @category Tool Call Types */ export interface ToolCallCompletedState extends ToolCallBase, ToolCallParameterFields, ToolCallResult, ToolCallPostConfirmationFields { status: ToolCallStatus.Completed; } /** * Tool call was cancelled before execution. * * @category Tool Call Types */ export interface ToolCallCancelledState extends ToolCallBase, ToolCallParameterFields { status: ToolCallStatus.Cancelled; /** Why the tool was cancelled */ reason: ToolCallCancellationReason; /** Optional message explaining the cancellation */ reasonMessage?: StringOrMarkdown; /** What the user suggested doing instead */ userSuggestion?: Message; /** The confirmation option the user selected, if confirmation options were provided */ selectedOption?: ConfirmationOption; } /** * Discriminated union of all tool call lifecycle states. * * See the [state model guide](/guide/state-model.html#tool-call-lifecycle) * for the full state machine diagram. * * @category Tool Call Types */ export type ToolCallState = ToolCallStreamingState | ToolCallPendingConfirmationState | ToolCallRunningState | ToolCallAuthRequiredState | ToolCallPendingResultConfirmationState | ToolCallCompletedState | ToolCallCancelledState; /** * The two tool-call states that block on a client confirmation: parameter * confirmation before execution ({@link ToolCallPendingConfirmationState}) and * result confirmation after execution * ({@link ToolCallPendingResultConfirmationState}). * * {@link ToolCallAuthRequiredState} is intentionally **not** part of this * union: it doesn't block on a `chat/toolCallConfirmed`-style client * decision, it blocks on the client completing an OAuth flow and calling * `authenticate`. See {@link SessionToolAuthenticationRequest} for its * session-level surfacing. * * Surfaced at the session level by {@link SessionToolConfirmationRequest}. * * @category Tool Call Types */ export type ToolCallConfirmationState = ToolCallPendingConfirmationState | ToolCallPendingResultConfirmationState; /** * Discriminant for tool result content types. * * @category Tool Result Content * @nonexhaustive */ export declare const enum ToolResultContentType { Text = "text", EmbeddedResource = "embeddedResource", Resource = "resource", FileEdit = "fileEdit", Terminal = "terminal", Subagent = "subagent" } /** * Text content in a tool result. * * Mirrors MCP `TextContent`. * * @category Tool Result Content */ export interface ToolResultTextContent { type: ToolResultContentType.Text; /** The text content */ text: string; } /** * Base64-encoded binary content embedded in a tool result. * * Mirrors MCP `EmbeddedResource` for inline binary data. * * @category Tool Result Content */ export interface ToolResultEmbeddedResourceContent { type: ToolResultContentType.EmbeddedResource; /** Base64-encoded data */ data: string; /** Content type (e.g. `"image/png"`, `"application/pdf"`) */ contentType: string; } /** * A reference to a resource stored outside the tool result. * * Wraps {@link ContentRef} for lazy-loading large results. * * @category Tool Result Content */ export interface ToolResultResourceContent extends ContentRef { type: ToolResultContentType.Resource; } /** * Describes a file modification performed by a tool. * * @category Tool Result Content */ export interface ToolResultFileEditContent extends FileEdit { type: ToolResultContentType.FileEdit; } /** * A reference to a terminal whose output is relevant to this tool result. * * Clients can subscribe to the terminal's URI to stream its output in real * time, providing live feedback while a tool is executing. * * When the command exits, {@link result} is filled in on the completed * result, retaining the outcome for clients that did not subscribe. This * records the command's exit, not the terminal's — the terminal may keep * running afterwards. * * @category Tool Result Content */ export interface ToolResultTerminalContent { type: ToolResultContentType.Terminal; /** Terminal URI (subscribable for full terminal state) */ resource: URI; /** Display title for the terminal content */ title: string; /** * Whether this terminal-style resource is backed by a pseudoterminal. * When `false`, output is plain text and clients do not need to parse * VT sequences. */ isPty?: boolean; /** Outcome of the command, present once it has exited. */ result?: TerminalCommandResult; } /** * Outcome of a command run in a terminal-style tool, filled in on * {@link ToolResultTerminalContent.result} once the command exits. * * @category Tool Result Content */ export interface TerminalCommandResult { /** Exit code from the completed command, if reported by the runtime */ exitCode?: number; /** * Preview of the command's output, for clients that are not subscribed * to the terminal or that arrive after it is disposed. When `isPty` is * `true` the preview may contain VT sequences; when `false` it is plain * text. */ preview?: string; /** Whether `preview` is known to be incomplete or truncated */ truncated?: boolean; } /** * A reference, embedded in a tool result, to a worker chat spawned by the tool * call (a sub-agent delegation), referenced by a chat URI (`ahp-chat:/...`). * * This is the spawning tool call's forward view of the worker. The worker chat * records the same edge in reverse via its {@link ChatOrigin} (`kind: 'tool'`), * whose `toolCallId` identifies the tool call that emitted this content. * * @category Tool Result Content */ export interface ToolResultSubagentContent { type: ToolResultContentType.Subagent; /** Worker chat URI (subscribable for full chat state) */ resource: URI; /** Display title for the subagent */ title: string; /** Internal agent name */ agentName?: string; /** Human-readable description of the subagent's task */ description?: string; } /** * Content block in a tool result. * * Mirrors the content blocks in MCP `CallToolResult.content`, plus * `ToolResultResourceContent` for lazy-loading large results, * `ToolResultFileEditContent` for file edit diffs, * `ToolResultTerminalContent` for live terminal output and * command completion metadata, and * `ToolResultSubagentContent` for tool-spawned worker chats (AHP extensions). * * @category Tool Result Content */ export type ToolResultContent = ToolResultTextContent | ToolResultEmbeddedResourceContent | ToolResultResourceContent | ToolResultFileEditContent | ToolResultTerminalContent | ToolResultSubagentContent; export {}; //# sourceMappingURL=state.d.ts.map