/*---------------------------------------------------------------------------------------------
state.ts
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// allow-any-unicode-comment-file
// DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
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';
// ─── Chat State ──────────────────────────────────────────────────────────────
/**
* 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 {
// ── Summary fields (denormalized from 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
* {@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[];
/**
* The chat's primary working directory — the distinguished root this chat is
* centered on (e.g. the agent's process root for this chat, the default
* location for relative paths). MUST be one of this chat's effective working
* directories ({@link workingDirectories}, or the session's set when that is
* absent). Present when the agent advertises
* {@link MultipleWorkingDirectoriesCapability.requiresPrimary}.
*
* **Read-only and fixed at creation.** It is set from
* {@link CreateChatParams.primaryWorkingDirectory} (or, for the session's
* default chat, {@link CreateSessionParams.primaryWorkingDirectory}) and does
* not change over the chat's lifetime — there is no action to mutate it, and
* it does not participate in `session/chatUpdated`.
*/
primaryWorkingDirectory?: URI;
// ── Conversation contents ──────────────────────────────────────────
/** 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<string, unknown>;
}
/**
* 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[];
/**
* The chat's primary working directory.
* See {@link ChatState.primaryWorkingDirectory} for the full semantics.
*/
primaryWorkingDirectory?: URI;
}
/**
* Discriminant for {@link ChatOrigin} — how a chat came into existence.
*
* @category Chat State
*/
export 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
*/
export 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',
}
// ─── Pending Message Types ───────────────────────────────────────────────────
/**
* Discriminant for pending message kinds.
*
* @category Pending Message Types
*/
export 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;
}
// ─── Chat Input Types ────────────────────────────────────────────────────
/**
* How a client completed an input request.
*
* @category Chat Input Types
*/
export const enum ChatInputResponseKind {
Accept = 'accept',
Decline = 'decline',
Cancel = 'cancel',
}
/**
* Question/input control kind.
*
* @category Chat Input Types
*/
export 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<string, ChatInputAnswer>;
}
/**
* Answer value kind.
*
* @category Chat Input Types
*/
export 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
*/
export 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;
// ─── Turn Types ──────────────────────────────────────────────────────────────
/**
* How a turn ended.
*
* @category Turn Types
*/
export const enum TurnState {
Complete = 'complete',
Cancelled = 'cancelled',
Error = 'error',
}
/**
* Discriminant for {@link MessageAttachment} variants.
*
* @category Turn Types
*/
export 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;
/** Error details if state is `'error'` */
error?: ErrorInfo;
}
/**
* 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
*/
export 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',
/** 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, 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<string, unknown>;
}
/**
* 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<string, unknown>;
}
/**
* 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:/<uuid>/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 MUST belong to the same session as the message's chat.
* The host resolves the transcript from its first retained turn through
* `endTurn`, inclusive, when accepting the message. Later turns do not
* change the context represented by an already-sent attachment.
*
* 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. */
endTurn: string;
}
/**
* An attachment associated with a {@link Message}.
*
* @category Turn Types
*/
export type MessageAttachment =
| SimpleMessageAttachment
| MessageEmbeddedResourceAttachment
| MessageResourceAttachment
| MessageAnnotationsAttachment
| MessageChatAttachment;
// ─── Response Parts ──────────────────────────────────────────────────────────
/**
* Discriminant for response part types.
*
* @category Response Parts
*/
export const enum ResponsePartKind {
Markdown = 'markdown',
ContentRef = 'contentRef',
ToolCall = 'toolCall',
Reasoning = 'reasoning',
SystemNotification = 'systemNotification',
InputRequest = 'inputRequest',
}
/**
* @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 ResourceReponsePart 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
| ResourceReponsePart
| ToolCallResponsePart
| ReasoningResponsePart
| SystemNotificationResponsePart
| InputRequestResponsePart;
/**
* 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;
}
/**
* 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<string, unknown>;
}
// ─── Tool Call Types ─────────────────────────────────────────────────────────
/**
* Status of a tool call in the lifecycle state machine.
*
* @category Tool Call Types
*/
export 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
*/
export 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
*/
export const enum ToolCallRiskAssessmentKind {
Judge = 'judge',
}
/**
* Lifecycle status of an asynchronous model-judge confirmation decision.
*
* @category Tool Call Types
*/
export 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
*/
export const enum ToolCallCancellationReason {
Denied = 'denied',
Skipped = 'skipped',
ResultDenied = 'result-denied',
}
/**
* Whether a confirmation option represents an approval or denial action.
*
* @category Tool Call Types
*/
export 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;
}
export 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<string, unknown>;
}
/**
* Properties available once tool call parameters are fully received.
*
* @category Tool Call Types
*/
interface ToolCallParameterFields {
/** Message describing what the tool will do */
invocationMessage: StringOrMarkdown;
/** Raw tool input */
toolInput?: string;
}
/**
* 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<string, unknown>;
/** 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 so far */
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;
// ─── Tool Result Content ─────────────────────────────────────────────────────
/**
* Discriminant for tool result content types.
*
* @category Tool Result Content
*/
export 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;