/**
 * Session State Types — Per-session state, turns, messages, response parts,
 * tool calls, and elicitation/input requests exposed on `ahp-session:` channels.
 *
 * @module channels-session/state
 */

import type { Changeset } from '../channels-changeset/state.js';
import type { AnnotationsSummary } from '../channels-annotations/state.js';
import type { ModelSelection } from '../channels-root/state.js';
import type {
  ConfigPropertySchema,
  ContentRef,
  ErrorInfo,
  FileEdit,
  Icon,
  ProtectedResourceMetadata,
  StringOrMarkdown,
  TextRange,
  TextSelection,
  URI,
  UsageInfo,
} from '../common/state.js';

// ─── 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;
}

// ─── Session State ───────────────────────────────────────────────────────────

/**
 * Session initialization state.
 *
 * @category Session State
 */
export const enum SessionLifecycle {
  Creating = 'creating',
  Ready = 'ready',
  CreationFailed = 'creationFailed',
}

/**
 * Bitset of summary-level session status flags.
 *
 * Use bitwise checks instead of equality for non-terminal activity. For example,
 * `status & SessionStatus.InProgress` matches both ordinary in-progress turns
 * and turns that are paused waiting for input.
 *
 * @category Session State
 */
export const enum SessionStatus {
  /** Session is idle — no turn is active. */
  Idle = 1,
  /** Session ended with an error. */
  Error = 1 << 1,
  /** A turn is actively streaming. */
  InProgress = 1 << 3,
  /** A turn is in progress but blocked waiting for user input or tool confirmation. */
  InputNeeded = (1 << 3) | (1 << 4),
  /** The client has viewed this session since its last modification. */
  IsRead = 1 << 5,
  /** The session has been archived by the client. */
  IsArchived = 1 << 6,
}

/**
 * Full state for a single session, loaded when a client subscribes to the session's URI.
 *
 * @category Session State
 */
export interface SessionState {
  /** Lightweight session metadata */
  summary: SessionSummary;
  /** Session initialization state */
  lifecycle: SessionLifecycle;
  /** Error details if creation failed */
  creationError?: ErrorInfo;
  /** Tools provided by the server (agent host) for this session */
  serverTools?: ToolDefinition[];
  /** The client currently providing tools and interactive capabilities to this session */
  activeClient?: SessionActiveClient;
  /** Completed turns */
  turns: Turn[];
  /** 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[];
  /** Requests for user input that are currently blocking or informing session progress */
  inputRequests?: SessionInputRequest[];
  /** Session configuration schema and current values */
  config?: SessionConfigState;
  /**
   * Top-level customizations active in this session.
   *
   * Always one of the {@link Customization} variants:
   *
   * - Container customizations ({@link PluginCustomization},
   *   {@link DirectoryCustomization}) whose children — agents, skills,
   *   prompts, rules, hooks, MCP servers — live in each container's
   *   {@link ContainerCustomizationBase.children | `children`} array.
   * - Top-level {@link McpServerCustomization} entries the host
   *   surfaces directly (for example a globally-configured MCP server
   *   that isn't bundled in a plugin or directory). MCP servers may
   *   also appear as children of a container.
   *
   * Client-published plugins arrive via
   * {@link SessionActiveClient.customizations | `activeClient.customizations`}
   * and the host propagates them into this list (typically with the
   * container's `clientId` set and `children` populated). Clients
   * publish in container shape only; bare MCP servers at the top level
   * are server-originated.
   */
  customizations?: Customization[];
  /**
   * Catalogue of changesets the server can produce for this session. Each
   * entry advertises a subscribable view of file changes (uncommitted,
   * session-wide, per-turn, etc.) and the URI template the client expands
   * before subscribing. See {@link Changeset} for the full shape and
   * {@link /guide/changesets | Changesets} for an overview of the model.
   */
  changesets?: Changeset[];
  /**
   * Additional provider-specific metadata for this session.
   *
   * Clients MAY look for well-known keys here to provide enhanced UI.
   * For example, a `git` key may provide extra git metadata about the session's
   * workingDirectory.
   */
  _meta?: Record<string, unknown>;
}

/**
 * The client currently providing tools and interactive capabilities to a session.
 *
 * Only one client may be active per session at a time. The server SHOULD
 * automatically unset the active client if that client disconnects.
 *
 * @category Session State
 */
export interface SessionActiveClient {
  /** Client identifier (matches `clientId` from `initialize`) */
  clientId: string;
  /** Human-readable client name (e.g. `"VS Code"`) */
  displayName?: string;
  /** Tools this client provides to the session */
  tools: ToolDefinition[];
  /**
   * Plugin customizations this client contributes to the session.
   *
   * Clients publish in [Open Plugins](https://open-plugins.com/) format
   * — i.e. always container-shaped plugins. They MAY synthesize virtual
   * plugins in memory and rely on the host to expand them into concrete
   * children inside {@link SessionState.customizations}.
   */
  customizations?: ClientPluginCustomization[];
}

/**
 * Server-owned project metadata for a session.
 *
 * @category Session State
 */
export interface ProjectInfo {
  /** Project URI */
  uri: URI;
  /** Human-readable project name */
  displayName: string;
}

/**
 * @category Session State
 */
export interface SessionSummary {
  /** Session URI */
  resource: URI;
  /** Agent provider ID */
  provider: string;
  /** Session title */
  title: string;
  /** Current session status */
  status: SessionStatus;
  /** Human-readable description of what the session is currently doing */
  activity?: string;
  /** Creation timestamp */
  createdAt: number;
  /** Last modification timestamp */
  modifiedAt: number;
  /** Server-owned project for this session */
  project?: ProjectInfo;
  /** Currently selected model */
  model?: ModelSelection;
  /**
   * Currently selected custom agent.
   *
   * Absent (`undefined`) means no custom agent is selected for this session
   * — the session uses the provider's default behavior.
   */
  agent?: AgentSelection;
  /** The working directory URI for this session */
  workingDirectory?: URI;
  /**
  * Aggregate summary of file changes associated with this session. Servers
  * may populate this to give clients a quick at-a-glance view of the
  * session's footprint (e.g., for list rendering) without requiring the
  * client to subscribe to a changeset.
  */
  changes?: ChangesSummary;
  /**
   * Lightweight summary of this session's inline annotations channel
   * (`ahp-session:/<uuid>/annotations`). Surfaced so badge UI can render
   * annotation / entry counts without subscribing. Absent when the session
   * does not expose an annotations channel.
   */
  annotations?: AnnotationsSummary;
}

/**
 * Aggregate counts describing the file changes associated with a session.
 *
 * All fields are optional so servers can populate only the metrics they
 * cheaply have available.
 *
 * @category Session State
 */
export interface ChangesSummary {
  /** Total number of inserted lines across all changed files. */
  additions?: number;
  /** Total number of deleted lines across all changed files. */
  deletions?: number;
  /** Number of files that have changes. */
  files?: number;
}

// ─── Model Selection ─────────────────────────────────────────────────────────
// `ModelSelection` is declared in channels-root/state.ts (the model lives on
// `AgentInfo`); we import it above for use in `SessionSummary.model`.

// ─── Agent Selection ─────────────────────────────────────────────────────────

/**
 * A selected custom agent for a session.
 *
 * The `uri` identifies a specific custom agent (matching an
 * {@link AgentCustomization.uri | `AgentCustomization.uri`} exposed via
 * the session's effective customizations). Consumers resolve the agent's
 * display name by looking up `uri` in the session's customization tree.
 *
 * A session with no `agent` selected uses the provider's default behavior.
 *
 * @category Session State
 */
export interface AgentSelection {
  /** Stable agent URI (matches an {@link AgentCustomization.uri}). */
  uri: URI;
}

// ─── Session Config Types ────────────────────────────────────────────────────

/**
 * A session configuration property descriptor.
 *
 * Extends the generic {@link ConfigPropertySchema} with session-specific
 * display extensions.
 *
 * @category Session Config Types
 */
export interface SessionConfigPropertySchema extends ConfigPropertySchema {
  /**
   * Display extension: when `true`, the full set of allowed values is too large
   * to enumerate statically. The client SHOULD use `sessionConfigCompletions`
   * to fetch matching values based on user input. Any values in `enum` are
   * seed/recent values for initial display.
   */
  enumDynamic?: boolean;
  /** When `true`, the user may change this property after session creation */
  sessionMutable?: boolean;
}

/**
 * A JSON Schema object describing available session configuration metadata.
 *
 * @category Session Config Types
 */
export interface SessionConfigSchema {
  /** JSON Schema: always `'object'` */
  type: 'object';
  /** JSON Schema: property descriptors keyed by property id */
  properties: Record<string, SessionConfigPropertySchema>;
  /** JSON Schema: list of required property ids */
  required?: string[];
}

/**
 * Live session configuration metadata.
 *
 * The schema describes the available configuration properties and the values
 * contain the current value for each resolved property.
 *
 * @category Session Config Types
 */
export interface SessionConfigState {
  /** JSON Schema describing available configuration properties */
  schema: SessionConfigSchema;
  /** Current configuration values */
  values: Record<string, unknown>;
}

// ─── Session Input Types ────────────────────────────────────────────────────

/**
 * How a client completed an input request.
 *
 * @category Session Input Types
 */
export const enum SessionInputResponseKind {
  Accept = 'accept',
  Decline = 'decline',
  Cancel = 'cancel',
}

/**
 * Question/input control kind.
 *
 * @category Session Input Types
 */
export const enum SessionInputQuestionKind {
  Text = 'text',
  Number = 'number',
  Integer = 'integer',
  Boolean = 'boolean',
  SingleSelect = 'single-select',
  MultiSelect = 'multi-select',
}

/**
 * A choice in a select-style question.
 *
 * @category Session Input Types
 */
export interface SessionInputOption {
  /** 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 SessionInputQuestionBase {
  /** 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 session input request. */
export interface SessionInputTextQuestion extends SessionInputQuestionBase {
  kind: SessionInputQuestionKind.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 session input request. */
export interface SessionInputNumberQuestion extends SessionInputQuestionBase {
  kind: SessionInputQuestionKind.Number | SessionInputQuestionKind.Integer;
  /**
   * Minimum value
   * @format float
   */
  min?: number;
  /**
   * Maximum value
   * @format float
   */
  max?: number;
  /**
   * Default numeric value
   * @format float
   */
  defaultValue?: number;
}

/** Boolean question within a session input request. */
export interface SessionInputBooleanQuestion extends SessionInputQuestionBase {
  kind: SessionInputQuestionKind.Boolean;
  /** Default boolean value */
  defaultValue?: boolean;
}

/** Single-select question within a session input request. */
export interface SessionInputSingleSelectQuestion extends SessionInputQuestionBase {
  kind: SessionInputQuestionKind.SingleSelect;
  /** Options the user may select from */
  options: SessionInputOption[];
  /** Whether the user may enter text instead of selecting an option */
  allowFreeformInput?: boolean;
}

/** Multi-select question within a session input request. */
export interface SessionInputMultiSelectQuestion extends SessionInputQuestionBase {
  kind: SessionInputQuestionKind.MultiSelect;
  /** Options the user may select from */
  options: SessionInputOption[];
  /** 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 session input request.
 *
 * @category Session Input Types
 */
export type SessionInputQuestion = SessionInputTextQuestion
  | SessionInputNumberQuestion
  | SessionInputBooleanQuestion
  | SessionInputSingleSelectQuestion
  | SessionInputMultiSelectQuestion;

/**
 * A live request for user input.
 *
 * The server creates or replaces requests with `session/inputRequested`.
 * Clients sync drafts with `session/inputAnswerChanged` and complete requests
 * with `session/inputCompleted`.
 *
 * @category Session Input Types
 */
export interface SessionInputRequest {
  /** 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?: SessionInputQuestion[];
  /** Current draft or submitted answers, keyed by question ID */
  answers?: Record<string, SessionInputAnswer>;
}

/**
 * Answer value kind.
 *
 * @category Session Input Types
 */
export const enum SessionInputAnswerValueKind {
  Text = 'text',
  Number = 'number',
  Boolean = 'boolean',
  Selected = 'selected',
  SelectedMany = 'selected-many',
}

/**
 * Value captured for one answer.
 *
 * @category Session Input Types
 */
export interface SessionInputTextAnswerValue {
  kind: SessionInputAnswerValueKind.Text;
  value: string;
}

export interface SessionInputNumberAnswerValue {
  kind: SessionInputAnswerValueKind.Number;
  /** @format float */
  value: number;
}

export interface SessionInputBooleanAnswerValue {
  kind: SessionInputAnswerValueKind.Boolean;
  value: boolean;
}

export interface SessionInputSelectedAnswerValue {
  kind: SessionInputAnswerValueKind.Selected;
  value: string;
  /** Free-form text entered instead of selecting an option */
  freeformValues?: string[];
}

export interface SessionInputSelectedManyAnswerValue {
  kind: SessionInputAnswerValueKind.SelectedMany;
  value: string[];
  /** Free-form text entered in addition to selected options */
  freeformValues?: string[];
}

export type SessionInputAnswerValue = SessionInputTextAnswerValue
  | SessionInputNumberAnswerValue
  | SessionInputBooleanAnswerValue
  | SessionInputSelectedAnswerValue
  | SessionInputSelectedManyAnswerValue;

export interface SessionInputAnswered {
  /** Answer state */
  state: SessionInputAnswerState.Draft | SessionInputAnswerState.Submitted;
  /** Answer value */
  value: SessionInputAnswerValue;
}

export interface SessionInputSkipped {
  /** Answer state */
  state: SessionInputAnswerState.Skipped;
  /** Free-form reason or value captured while skipping, if any */
  freeformValues?: string[];
}

/**
 * Answer lifecycle state.
 *
 * @category Session Input Types
 */
export const enum SessionInputAnswerState {
  Draft = 'draft',
  Submitted = 'submitted',
  Skipped = 'skipped',
}

/**
 * Draft, submitted, or skipped answer for one question.
 *
 * @category Session Input Types
 */
export type SessionInputAnswer = SessionInputAnswered | SessionInputSkipped;

// ─── 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',
}

/**
 * A completed request/response cycle.
 *
 * @category Turn Types
 */
export interface Turn {
  /** Turn identifier */
  id: string;
  /** 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;
  /** 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 Message types.
 *
 * @category Turn Types
 */
export enum MessageKind {
  User = 'user',
  SystemNotification = 'systemNotification',
}

/**
 * A message that initiates or steers a turn. Messages can originate from the
 * user or be system-generated (see {@link MessageKind}).
 *
 * 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: { kind: MessageKind };
  /** File/selection attachments */
  attachments?: MessageAttachment[];
  /**
   * 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 associated with a {@link Message}.
 *
 * @category Turn Types
 */
export type MessageAttachment =
  | SimpleMessageAttachment
  | MessageEmbeddedResourceAttachment
  | MessageResourceAttachment
  | MessageAnnotationsAttachment;

// ─── Response Parts ──────────────────────────────────────────────────────────

/**
 * Discriminant for response part types.
 *
 * @category Response Parts
 */
export const enum ResponsePartKind {
  Markdown = 'markdown',
  ContentRef = 'contentRef',
  ToolCall = 'toolCall',
  Reasoning = 'reasoning',
  SystemNotification = 'systemNotification',
}

/**
 * @category Response Parts
 */
export interface MarkdownResponsePart {
  /** Discriminant */
  kind: ResponsePartKind.Markdown;
  /** Part identifier, used by `session/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 `session/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;

/**
 * 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;
}


// ─── 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',
  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',
}

/**
 * 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 `session/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;
  /**
   * 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;
  /** 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[];
}

/**
 * Tool is actively executing.
 *
 * @category Tool Call Types
 */
export interface ToolCallRunningState extends ToolCallBase, ToolCallParameterFields {
  status: ToolCallStatus.Running;
  /** How the tool was confirmed for execution */
  confirmed: ToolCallConfirmationReason;
  /** The confirmation option the user selected, if confirmation options were provided */
  selectedOption?: ConfirmationOption;
  /**
   * 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[];
}

/**
 * Tool finished executing, waiting for client to approve the result.
 *
 * @category Tool Call Types
 */
export interface ToolCallPendingResultConfirmationState extends ToolCallBase, ToolCallParameterFields, ToolCallResult {
  status: ToolCallStatus.PendingResultConfirmation;
  /** How the tool was confirmed for execution */
  confirmed: ToolCallConfirmationReason;
  /** The confirmation option the user selected, if confirmation options were provided */
  selectedOption?: ConfirmationOption;
}

/**
 * Tool completed successfully or with an error.
 *
 * @category Tool Call Types
 */
export interface ToolCallCompletedState extends ToolCallBase, ToolCallParameterFields, ToolCallResult {
  status: ToolCallStatus.Completed;
  /** How the tool was confirmed for execution */
  confirmed: ToolCallConfirmationReason;
  /** The confirmation option the user selected, if confirmation options were provided */
  selectedOption?: ConfirmationOption;
}

/**
 * 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
  | ToolCallPendingResultConfirmationState
  | ToolCallCompletedState
  | ToolCallCancelledState;

// ─── Tool Definition Types ───────────────────────────────────────────────────

/**
 * Describes a tool available in a session, provided by either the server or the active client.
 *
 * @category Tool Definition Types
 */
export interface ToolDefinition {
  /** Unique tool identifier */
  name: string;
  /** Human-readable display name */
  title?: string;
  /** Description of what the tool does */
  description?: string;
  /**
   * JSON Schema defining the expected input parameters.
   *
   * Optional because client-provided tools may not have formal schemas.
   * Mirrors MCP `Tool.inputSchema`.
   */
  inputSchema?: {
    type: 'object';
    properties?: Record<string, object>;
    required?: string[];
  };
  /**
   * JSON Schema defining the structure of the tool's output.
   *
   * Mirrors MCP `Tool.outputSchema`.
   */
  outputSchema?: {
    type: 'object';
    properties?: Record<string, object>;
    required?: string[];
  };
  /** Behavioral hints about the tool. All properties are advisory. */
  annotations?: ToolAnnotations;
  /**
   * Additional provider-specific metadata.
   *
   * Mirrors the MCP `_meta` convention.
   */
  _meta?: Record<string, unknown>;
}

/**
 * Behavioral hints about a tool. All properties are advisory and not
 * guaranteed to faithfully describe tool behavior.
 *
 * Mirrors MCP `ToolAnnotations` from the Model Context Protocol specification.
 *
 * @category Tool Definition Types
 */
export interface ToolAnnotations {
  /** Alternate human-readable title */
  title?: string;
  /** Tool does not modify its environment (default: false) */
  readOnlyHint?: boolean;
  /** Tool may perform destructive updates (default: true) */
  destructiveHint?: boolean;
  /** Repeated calls with the same arguments have no additional effect (default: false) */
  idempotentHint?: boolean;
  /** Tool may interact with external entities (default: true) */
  openWorldHint?: boolean;
}

// ─── 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.
 *
 * @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;
}

/**
 * A reference to a subagent session spawned by a tool.
 *
 * Clients can subscribe to the subagent's session URI to stream its
 * progress in real time, including inner tool calls and responses.
 *
 * @category Tool Result Content
 */
export interface ToolResultSubagentContent {
  type: ToolResultContentType.Subagent;
  /** Subagent session URI (subscribable for full session 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
 * `ToolResultSubagentContent` for subagent sessions (AHP extensions).
 *
 * @category Tool Result Content
 */
export type ToolResultContent =
  | ToolResultTextContent
  | ToolResultEmbeddedResourceContent
  | ToolResultResourceContent
  | ToolResultFileEditContent
  | ToolResultTerminalContent
  | ToolResultSubagentContent;

// ─── Customization Types ─────────────────────────────────────────────────────

/**
 * Discriminant for the kind of customization.
 *
 * Top-level entries in {@link SessionState.customizations} and
 * {@link AgentInfo.customizations} are either container customizations
 * ({@link CustomizationType.Plugin | `Plugin`} or
 * {@link CustomizationType.Directory | `Directory`}) or
 * {@link CustomizationType.McpServer | `McpServer`} entries surfaced
 * directly by the host. The remaining types appear only as children of
 * a container.
 *
 * @category Customization Types
 */
export const enum CustomizationType {
  Plugin = 'plugin',
  Directory = 'directory',
  Agent = 'agent',
  Skill = 'skill',
  Prompt = 'prompt',
  Rule = 'rule',
  Hook = 'hook',
  McpServer = 'mcpServer',
}

/**
 * Customization types that appear as children of a
 * {@link PluginCustomization} or {@link DirectoryCustomization}.
 *
 * @category Customization Types
 */
export type ChildCustomizationType =
  | CustomizationType.Agent
  | CustomizationType.Skill
  | CustomizationType.Prompt
  | CustomizationType.Rule
  | CustomizationType.Hook
  | CustomizationType.McpServer;

/**
 * Fields shared by every customization variant.
 *
 * @category Customization Types
 */
interface CustomizationBase {
  /**
   * Session-unique opaque identifier. Used by every action that targets a
   * specific customization. Minted by whoever publishes the customization
   * (typically the agent host).
   */
  id: string;
  /**
   * Source URI for this customization. A plugin URL, a file URI, or a
   * directory URI.
   *
   * For declarations that live inside a larger file — e.g. an MCP
   * server declared inline in a `plugins.json` manifest — `uri` points
   * to the containing file and {@link CustomizationBase.range | `range`}
   * narrows it to the declaration's span.
   */
  uri: URI;
  /** Human-readable name. */
  name: string;
  /** Icons for UI display. */
  icons?: Icon[];
  /**
   * Optional span within {@link CustomizationBase.uri | `uri`} when this
   * customization is a subset of a larger file (for example, one entry
   * in an inline `mcpServers` block of a `plugins.json` manifest).
   * Absent when the customization covers the whole resource.
   */
  range?: TextRange;
}

/**
 * Discriminant values for {@link CustomizationLoadState}.
 *
 * @category Customization Types
 */
export const enum CustomizationLoadStatus {
  Loading = 'loading',
  Loaded = 'loaded',
  Degraded = 'degraded',
  Error = 'error',
}

/**
 * Container is being loaded by the host.
 *
 * @category Customization Types
 */
export interface CustomizationLoadingState {
  kind: CustomizationLoadStatus.Loading;
}

/**
 * Container loaded successfully.
 *
 * @category Customization Types
 */
export interface CustomizationLoadedState {
  kind: CustomizationLoadStatus.Loaded;
}

/**
 * Container partially loaded but has warnings.
 *
 * @category Customization Types
 */
export interface CustomizationDegradedState {
  kind: CustomizationLoadStatus.Degraded;
  /** Human-readable description of the warning. */
  message: string;
}

/**
 * Container failed to load.
 *
 * @category Customization Types
 */
export interface CustomizationErrorState {
  kind: CustomizationLoadStatus.Error;
  /** Human-readable error message. */
  message: string;
}

/**
 * Discriminated load state for a container customization
 * ({@link PluginCustomization} or {@link DirectoryCustomization}).
 *
 * @category Customization Types
 */
export type CustomizationLoadState =
  | CustomizationLoadingState
  | CustomizationLoadedState
  | CustomizationDegradedState
  | CustomizationErrorState;

/**
 * Fields shared by container customizations.
 *
 * @category Customization Types
 */
interface ContainerCustomizationBase extends CustomizationBase {
  /** Whether this container is currently enabled. */
  enabled: boolean;
  /**
   * `clientId` of the client that contributed this container. Absent for
   * server-originated entries.
   */
  clientId?: string;
  /**
   * Host-reported load state. Absent means the host has not yet reported
   * a load state for this container.
   */
  load?: CustomizationLoadState;
  /**
   * Children discovered inside this container.
   *
   * Absent means the host has not parsed this container yet. An empty
   * array means the host parsed the container and it contributes
   * nothing.
   */
  children?: ChildCustomization[];
}

/**
 * An [Open Plugins](https://open-plugins.com/) plugin.
 *
 * @category Customization Types
 */
export interface PluginCustomization extends ContainerCustomizationBase {
  type: CustomizationType.Plugin;
}

/**
 * A {@link PluginCustomization} as published by a client. Extends the
 * server-facing shape with an opaque `nonce` so the host can detect when
 * the client's view of a plugin has changed and re-parse only as needed.
 *
 * Clients SHOULD include a `nonce`. Server-side fields like
 * {@link ContainerCustomizationBase.children | `children`} and
 * {@link ContainerCustomizationBase.load | `load`} are typically left
 * absent on publication and populated by the host when the resolved
 * plugin appears in {@link SessionState.customizations}.
 *
 * @category Customization Types
 */
export interface ClientPluginCustomization extends PluginCustomization {
  /** Opaque version token used by the host to detect changes. */
  nonce?: string;
}

/**
 * A directory the host watches for this session.
 *
 * Presence in the customization list signals that the host may discover
 * customizations from this directory. When `writable` is `true`, clients
 * MAY persist new customizations into the directory using
 * [`resourceWrite`](/reference/common#resourcewrite); the host will
 * then surface the resulting child via the customization actions.
 *
 * The directory may not yet exist on disk.
 *
 * @category Customization Types
 */
export interface DirectoryCustomization extends ContainerCustomizationBase {
  type: CustomizationType.Directory;
  /** Which child customization type this directory holds. */
  contents: ChildCustomizationType;
  /** Whether clients may write into this directory. */
  writable: boolean;
}

/**
 * A custom agent contributed by a plugin or directory.
 *
 * Mirrors the [Open Plugins agent](https://open-plugins.com/agent-builders/components/agents)
 * format: a markdown file with YAML frontmatter, where the body is the
 * agent's system prompt.
 *
 * @category Customization Types
 */
export interface AgentCustomization extends CustomizationBase {
  type: CustomizationType.Agent;
  /**
   * Short description of what the agent specializes in and when to
   * invoke it. Sourced from the agent file's frontmatter `description`.
   */
  description?: string;
  /**
   * Additional provider-specific metadata for this custom agent.
   *
   * Mirrors the MCP `_meta` convention.
   */
  _meta?: Record<string, unknown>;
}

/**
 * A skill contributed by a plugin or directory.
 *
 * Covers both [Open Plugins skill formats](https://open-plugins.com/agent-builders/components/skills)
 * — the `skills/` directory layout (one subdirectory per skill, each with
 * a `SKILL.md`) and the flatter `commands/` directory of slash-command
 * skills.
 *
 * @category Customization Types
 */
export interface SkillCustomization extends CustomizationBase {
  type: CustomizationType.Skill;
  /**
   * Short description used for help text and auto-invocation matching.
   * Sourced from the skill's frontmatter `description`.
   */
  description?: string;
  /**
   * When `true`, only the user can invoke this skill — the agent will not
   * auto-invoke it. Sourced from the command skill's frontmatter
   * `disable-model-invocation` flag.
   */
  disableModelInvocation?: boolean;
}

/**
 * A prompt contributed by a plugin or directory.
 *
 * @category Customization Types
 */
export interface PromptCustomization extends CustomizationBase {
  type: CustomizationType.Prompt;
  /** Short description of what the prompt does. */
  description?: string;
}

/**
 * A rule contributed by a plugin or directory.
 *
 * Mirrors the [Open Plugins rule](https://open-plugins.com/agent-builders/components/rules)
 * format: a markdown file (e.g. `.mdc`) whose body is injected into
 * context while the rule is active. This type also covers tool-specific
 * "instruction" formats (e.g. VS Code Copilot's
 * `.github/instructions/*.md`), which differ only in naming — they
 * share the same semantics of `description`, optional always-on
 * activation, and optional glob scoping.
 *
 * @category Customization Types
 */
export interface RuleCustomization extends CustomizationBase {
  type: CustomizationType.Rule;
  /**
   * Description of what the rule enforces.
   */
  description?: string;
  /**
   * When `true`, the rule is always active (subject to `globs` if any).
   * When `false` or absent, the agent or user decides whether to apply
   * the rule.
   */
  alwaysApply?: boolean;
  /**
   * Glob patterns the rule applies to. When present, the rule is only
   * active for matching files.
   */
  globs?: string[];
}

/**
 * A hook manifest contributed by a plugin or directory.
 *
 * @category Customization Types
 */
export interface HookCustomization extends CustomizationBase {
  type: CustomizationType.Hook;
}

/**
 * An MCP server contributed by a plugin or directory.
 *
 * When the server is declared inline in the containing plugin manifest,
 * `uri` points at the manifest file and
 * {@link CustomizationBase.range | `range`} narrows it to the
 * declaration's span.
 *
 * The MCP server customization also reflects its current status.
 *
 * @category Customization Types
 */
export interface McpServerCustomization extends CustomizationBase {
  type: CustomizationType.McpServer;
  /**
   * Whether this MCP server is currently enabled.
   */
  enabled: boolean;
  /**
   * Current lifecycle state of the MCP server.
   */
  state: McpServerState;
  /**
   * An `mcp://`-protocol channel the client uses to side-channel traffic
   * into the upstream MCP server itself. The channel is NOT a fresh raw MCP
   * connection: it piggybacks on the AHP transport
   * and skips the MCP `initialize` sequence.
   *
   * The agent host MAY only serve a subset of MCP on this
   * channel; the served subset is described by domain-specific
   * capabilities such as those in
   * {@link McpServerCustomizationApps.capabilities}.
   *
   * The channel URI SHOULD be stable across the server's lifetime, but
   * the agent host MAY change it (for example across a restart) and
   * MAY only expose it while the server is in
   * {@link McpServerStatus.Ready | `Ready`}. Absence means no
   * side-channel is currently available.
   */
  channel?: URI;
  /**
   * MCP App support. This property SHOULD be advertised for MCP servers
   * which support apps.
   */
  mcpApp?: McpServerCustomizationApps;
}

/**
 * Information from the agent host needed to render MCP Apps served
 * by this MCP server.
 *
 * @category MCP Server State
 */
export interface McpServerCustomizationApps {
  /**
   * The subset of MCP App
   * [`HostCapabilities`](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx)
   * the AHP host can satisfy for Views backed by this server. The
   * client feeds these straight through into the `hostCapabilities` of
   * the `ui/initialize` response delivered to the View.
   */
  capabilities: AhpMcpUiHostCapabilities;
}

/**
 * The subset of MCP App
 * [`HostCapabilities`](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx)
 * an AHP host can derive from the upstream MCP server (and from AHP's own
 * forwarding plumbing). Advertised on
 * {@link McpServerCustomizationApps.capabilities} so clients can pass it
 * through into the `hostCapabilities` of the `ui/initialize` response
 * delivered to an MCP App View.
 *
 * Field names mirror the MCP Apps spec exactly, so the AHP-side producer
 * can pass them straight through into the `hostCapabilities` of the
 * `ui/initialize` response delivered to the View.
 *
 * Capabilities outside this set (`openLinks`, `downloadFile`, `sandbox`,
 * `experimental`) are decided locally by whichever AHP client renders the
 * View and are NOT part of this AHP-level advertisement — only the
 * server-derived subset is.
 *
 * An agent host MUST only advertise a capability when it actually accepts the
 * corresponding methods/notifications on the `mcp://` channel:
 *
 * - {@link serverTools}: host proxies `tools/list` and `tools/call` to
 *   the MCP server. When `listChanged` is `true`, the host also forwards
 *   `notifications/tools/list_changed`.
 * - {@link serverResources}: host proxies `resources/read`,
 *   `resources/list`, and `resources/templates/list` to the MCP server.
 *   When `listChanged` is `true`, the host also forwards
 *   `notifications/resources/list_changed`.
 * - {@link logging}: host accepts `notifications/message` log entries
 *   from the App and forwards them via `mcpNotification` (and forwards
 *   `logging/setLevel` calls to the server).
 * - {@link sampling}: host serves `sampling/createMessage` via
 *   `mcpMethodCall`. When `sampling.tools` is present, the host also
 *   accepts SEP-1577 `tools` / `toolChoice` / `tool_use` content blocks
 *   inside `CreateMessageRequest`.
 *
 * @category MCP Server State
 * @see {@link https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx | MCP Apps spec (SEP-1865)}
 */
export interface AhpMcpUiHostCapabilities {
  /** Producer proxies the MCP `tools/*` methods to the upstream server. */
  serverTools?: {
    /** Producer forwards `notifications/tools/list_changed` from the server. */
    listChanged?: boolean;
  };
  /** Producer proxies the MCP `resources/*` methods to the upstream server. */
  serverResources?: {
    /** Producer forwards `notifications/resources/list_changed` from the server. */
    listChanged?: boolean;
  };
  /** Producer accepts `notifications/message` log entries from the App via `mcpNotification`. */
  logging?: Record<string, never>;
  /** Producer serves `sampling/createMessage` via `mcpMethodCall`. */
  sampling?: {
    /**
     * Producer accepts SEP-1577 `tools` / `toolChoice` / `tool_use` content
     * blocks inside `CreateMessageRequest`.
     */
    tools?: Record<string, never>;
  };
}

/**
 * Child customizations that live inside a {@link PluginCustomization} or
 * {@link DirectoryCustomization}.
 *
 * @category Customization Types
 */
export type ChildCustomization =
  | AgentCustomization
  | SkillCustomization
  | PromptCustomization
  | RuleCustomization
  | HookCustomization
  | McpServerCustomization;

/**
 * A top-level customization active in a session. Either a container
 * ({@link PluginCustomization} or {@link DirectoryCustomization}) whose
 * leaf customizations live in its
 * {@link ContainerCustomizationBase.children | `children`} array, or a
 * bare {@link McpServerCustomization} surfaced directly by the host.
 *
 * @category Customization Types
 */
export type Customization =
  | PluginCustomization
  | DirectoryCustomization
  | McpServerCustomization;


// ─── MCP Server State ────────────────────────────────────────────────────────

/**
 * Discriminant for the {@link McpServerState} union.
 *
 * @category MCP Server State
 */
export const enum McpServerStatus {
  /** Server has been registered but is not yet running. */
  Starting = 'starting',
  /** Server is running and serving requests. */
  Ready = 'ready',
  /**
   * Server is reachable but requires additional authentication before it
   * can start, or before it can serve a particular request. Carries the
   * RFC 9728 Protected Resource Metadata the client needs to obtain a
   * token; the client then pushes the token via the existing
   * `authenticate` command.
   */
  AuthRequired = 'authRequired',
  /** Server failed to start, crashed, or otherwise transitioned to a fatal error. */
  Error = 'error',
  /** Server has been shut down. */
  Stopped = 'stopped',
}

/**
 * Why an MCP server is currently in the {@link McpServerStatus.AuthRequired}
 * state. Mirrors the three failure modes defined by the
 * [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization.md).
 *
 * @category MCP Server State
 */
export const enum McpAuthRequiredReason {
  /** No token has been provided yet (HTTP 401, no prior token). */
  Required = 'required',
  /** A previously valid token expired or was revoked (HTTP 401). */
  Expired = 'expired',
  /**
   * Step-up auth: a token is present but its scopes are insufficient for
   * the requested operation (HTTP 403 with
   * `WWW-Authenticate: Bearer error="insufficient_scope"`).
   *
   * Unlike {@link Required} and {@link Expired} — which typically surface
   * before any tool work is in flight — `InsufficientScope` is almost
   * always triggered by an MCP request issued mid-turn (a `tools/call`,
   * `resources/read`, etc.). The host SHOULD pair the
   * {@link McpServerAuthRequiredState} transition with
   * {@link SessionStatus.InputNeeded} on
   * {@link SessionSummary.status | the session} so the activity becomes
   * visible at the session-summary level, and clients SHOULD watch for
   * this kind on any
   * {@link McpServerCustomization | MCP server} backing a running tool
   * call so they can present an explicit "grant more access" affordance
   * tied to the blocked tool call.
   */
  InsufficientScope = 'insufficientScope',
}

/**
 * Server is registered with the host but has not yet started.
 *
 * @category MCP Server State
 */
export interface McpServerStartingState {
  kind: McpServerStatus.Starting;
}

/**
 * Server is running and serving requests.
 *
 * @category MCP Server State
 */
export interface McpServerReadyState {
  kind: McpServerStatus.Ready;
}

/**
 * Server is reachable but cannot serve requests until the client
 * authenticates. Mirrors the discovery flow defined by
 * [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728)
 * (Protected Resource Metadata) and the OAuth 2.1 / RFC 6750 challenge
 * semantics required by the MCP authorization spec.
 *
 * Clients react to this state by calling the existing `authenticate`
 * command with the {@link ProtectedResourceMetadata.resource | resource}
 * carried here. There is **no** `notify/authRequired` notification for
 * MCP servers — the action stream is the single source of truth.
 *
 * When the transition is triggered by a request issued during a turn
 * — most commonly
 * {@link McpAuthRequiredReason.InsufficientScope | `InsufficientScope`}
 * surfacing mid-tool-call — the host SHOULD also raise
 * {@link SessionStatus.InputNeeded} on the session so the block is
 * visible at the summary level. Clients SHOULD watch this status on
 * any MCP server backing a running tool call and surface an explicit
 * affordance (e.g. a "grant additional access" prompt) tied to that
 * tool call, rather than relying on the user to notice the
 * customization’s status badge.
 *
 * @category MCP Server State
 */
export interface McpServerAuthRequiredState {
  kind: McpServerStatus.AuthRequired;
  /** Why authentication is required. */
  reason: McpAuthRequiredReason;
  /**
   * RFC 9728 Protected Resource Metadata. The `resource` field is the
   * canonical MCP server URI per RFC 8707, used as the OAuth `resource`
   * indicator. `authorization_servers` is REQUIRED by the MCP
   * authorization spec.
   */
  resource: ProtectedResourceMetadata;
  /**
   * Scopes required for the current challenge, parsed from the
   * `WWW-Authenticate: Bearer scope="…"` header (or `scopes_supported`
   * fallback). Authoritative for the next authorization request — clients
   * MUST NOT assume any subset/superset relationship to
   * `resource.scopes_supported`.
   */
  requiredScopes?: string[];
  /** Human-readable hint, typically from the OAuth `error_description`. */
  description?: string;
}

/**
 * Server failed to start, crashed, or otherwise transitioned to a
 * non-recoverable error. Use {@link McpServerStatus.AuthRequired}
 * for authentication failures.
 *
 * @category MCP Server State
 */
export interface McpServerErrorState {
  kind: McpServerStatus.Error;
  /** Error details. */
  error: ErrorInfo;
}

/**
 * Server has been shut down. The host MAY remove the server from the
 * session entirely shortly after this state.
 *
 * @category MCP Server State
 */
export interface McpServerStoppedState {
  kind: McpServerStatus.Stopped;
}

/**
 * Discriminated union of all MCP server lifecycle states.
 * Discriminated by `kind` (a {@link McpServerStatus} value).
 *
 * @category MCP Server State
 */
export type McpServerState =
  | McpServerStartingState
  | McpServerReadyState
  | McpServerAuthRequiredState
  | McpServerErrorState
  | McpServerStoppedState;
