Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ export class RemoteAgentHostProtocolClient extends Disposable implements IAgentC
workingDirectory: typeof s.workingDirectory === 'string' ? toAgentHostUri(URI.parse(s.workingDirectory), this._connectionAuthority) : undefined,
isRead: !!(s.status & SessionStatus.IsRead),
isArchived: !!(s.status & SessionStatus.IsArchived),
changesets: s.changesets,
changes: s.changes
}));
}

Expand Down
21 changes: 14 additions & 7 deletions src/vs/platform/agentHost/common/agentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { IAgentSubscription } from './state/agentSubscription.js';
import type { IRemoteWatchHandle } from './agentHostFileSystemProvider.js';
import type { CompletionsParams, CompletionsResult, CreateTerminalParams, ResolveSessionConfigResult, SessionConfigCompletionsResult } from './state/protocol/commands.js';
import type { InvokeChangesetOperationParams, InvokeChangesetOperationResult } from './state/protocol/channels-changeset/commands.js';
import { ProtectedResourceMetadata, type ChangesetSummary, type ConfigSchema, type MessageAttachment, type ModelSelection, type AgentSelection, type SessionActiveClient, type ToolCallPendingConfirmationState, type ToolDefinition } from './state/protocol/state.js';
import { ProtectedResourceMetadata, type Changeset, type ChangesSummary, type ConfigSchema, type MessageAttachment, type ModelSelection, type AgentSelection, type SessionActiveClient, type ToolCallPendingConfirmationState, type ToolDefinition } from './state/protocol/state.js';
import type { ActionEnvelope, INotification, IRootConfigChangedAction, SessionAction, TerminalAction } from './state/sessionActions.js';
import type { ResourceCopyParams, ResourceCopyResult, ResourceDeleteParams, ResourceDeleteResult, ResourceListResult, ResourceMkdirParams, ResourceMkdirResult, ResourceMoveParams, ResourceMoveResult, ResourceReadResult, ResourceResolveParams, ResourceResolveResult, ResourceWatchState, ResourceWriteParams, ResourceWriteResult, CreateResourceWatchParams, CreateResourceWatchResult, IStateSnapshot } from './state/sessionProtocol.js';
import { ComponentToState, SessionInputResponseKind, SessionStatus, StateComponents, type ClientPluginCustomization, type Customization, type PendingMessage, type RootState, type SessionInputAnswer, type SessionMeta, type ToolCallResult, type Turn, type PolicyState } from './state/sessionState.js';
Expand Down Expand Up @@ -278,15 +278,22 @@ export interface IAgentSessionMetadata {
readonly customizationDirectory?: URI;
readonly isRead?: boolean;
readonly isArchived?: boolean;
/**
* Aggregate counts (additions / deletions / files) describing the
* `changeKind: 'session'` changeset for this session — the chip
* aggregate previously embedded in the catalogue entry. Mirrors
* `SessionSummary.changes`.
*/
readonly changes?: ChangesSummary;
/**
* Catalogue of changesets the agent can produce for this session — the
* {@link ChangesetSummary | catalogue} that travels on
* `SessionSummary.changesets`. Lightweight summary entries (id / label /
* URI template / aggregate counts) without per-file detail; clients
* subscribe to a specific expanded changeset URI when they need the full
* file list.
* {@link Changeset | catalogue} that travels on `SessionState.changesets`.
* Lightweight catalogue entries (label / URI template / `changeKind`)
* without per-file detail or aggregate counts; clients subscribe to a
* specific expanded changeset URI when they need the full file list,
* and consult {@link changes} for the chip-level aggregate.
*/
readonly changesets?: readonly ChangesetSummary[];
readonly changesets?: readonly Changeset[];
/**
* Side-channel metadata mirroring {@link SessionState._meta}, propagated
* to clients via per-session state subscriptions.
Expand Down
19 changes: 14 additions & 5 deletions src/vs/platform/agentHost/common/changesetUri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { localize } from '../../../nls.js';
import type { ChangesetSummary, URI } from './state/sessionState.js';
import type { Changeset, URI } from './state/sessionState.js';

/**
* Helpers for building / parsing the URI clients subscribe to in order to
Expand Down Expand Up @@ -281,9 +281,18 @@ export function parseCompareTurnsChangesetUri(uri: URI): { sessionUri: URI; orig
* compare-turns diffs construct the URI themselves from two known
* turn ids and subscribe directly.
*/
export function buildDefaultChangesetCatalogue(sessionUri: URI): ChangesetSummary[] {
export function buildDefaultChangesetCatalogue(sessionUri: URI): Changeset[] {
return [
{ label: sessionChangesetLabel(), uriTemplate: buildSessionChangesetUri(sessionUri) },
{ label: uncommittedChangesetLabel(), uriTemplate: buildUncommittedChangesetUri(sessionUri), description: uncommittedChangesetDescription() }
];
{
label: sessionChangesetLabel(),
uriTemplate: buildSessionChangesetUri(sessionUri),
changeKind: 'session'
},
{
label: uncommittedChangesetLabel(),
uriTemplate: buildUncommittedChangesetUri(sessionUri),
description: uncommittedChangesetDescription(),
changeKind: 'uncommitted'
}
] satisfies Changeset[];
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
740f6cf
0ce713b
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import type { StringOrMarkdown, FileEdit, ErrorInfo } from '../common/state.js';
*
* @category Changesets
*/
export interface ChangesetSummary {
export interface Changeset {
/** Human-readable label, e.g. `"Uncommitted Changes"`. */
label: string;
/**
Expand All @@ -44,12 +44,26 @@ export interface ChangesetSummary {
uriTemplate: string;
/** Optional longer description. */
description?: string;
/** Aggregate line additions across the changeset, when known. */
additions?: number;
/** Aggregate line deletions across the changeset, when known. */
deletions?: number;
/** Number of files in the changeset, when known. */
files?: number;
/**
* Advisory hint describing what kind of changeset this is, so clients can
* group, sort, or render an appropriate icon without parsing
* {@link uriTemplate}. Recognized values include:
*
* - `'session'`: a static, session-wide changeset covering all changes the
* agent has produced in this session.
* - `'branch'`: changes relative to a base branch (e.g. a feature branch
* diffed against `main`).
* - `'uncommitted'`: the workspace's current uncommitted changes.
* - `'turn'`: changes produced by a single turn. Typically paired with a
* `{turnId}` variable in {@link uriTemplate}.
* - `'compare-turns'`: a diff between two turns. Typically paired with
* `{originalTurnId}` and `{modifiedTurnId}` variables in
* {@link uriTemplate}.
*
* Implementations MAY provide additional values; clients SHOULD fall back
* to a reasonable default when an unknown value is encountered.
*/
changeKind: string;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ export interface SessionRemovedParams {
* {@link SessionSummary | `SessionSummary`} changes for a session the
* server has surfaced via `listSessions()` or `root/sessionAdded`.
* Servers MAY coalesce or debounce updates for noisy fields (for example,
* `modifiedAt` bumps while a turn is streaming, or rapidly changing
* `changesets`) at their discretion.
* `modifiedAt` bumps while a turn is streaming) at their discretion.
* - Clients that have no cached entry for `session` MAY ignore the
* notification; it is not a substitute for `root/sessionAdded`.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ActionType } from '../common/actions.js';
import type { StringOrMarkdown, ErrorInfo, FileEdit, UsageInfo, URI } from '../common/state.js';
import { ToolCallConfirmationReason, ToolCallCancellationReason, PendingMessageKind, type Message, type ResponsePart, type ToolCallResult, type ToolResultContent, type ToolDefinition, type SessionActiveClient, type Customization, type McpServerState, type SessionInputAnswer, type SessionInputRequest, type SessionInputResponseKind, type ConfirmationOption, type AgentSelection, type ToolCallContributor } from './state.js';
import type { ModelSelection } from '../channels-root/state.js';
import type { ChangesetSummary } from '../channels-changeset/state.js';
import type { Changeset } from '../channels-changeset/state.js';

// ─── Tool Call Action Base ───────────────────────────────────────────────────

Expand Down Expand Up @@ -478,14 +478,14 @@ export interface SessionActivityChangedAction {
}

/**
* The {@link ChangesetSummary | catalogue of changesets} the agent host
* The {@link Changeset | catalogue of changesets} the agent host
* advertises for this session changed. Replaces
* `state.summary.changesets` entirely (full-replacement semantics) — set
* to `undefined` to clear the catalogue.
* {@link SessionState.changesets | `state.changesets`} entirely
* (full-replacement semantics) — set to `undefined` to clear the
* catalogue.
*
* Producers dispatch this whenever entries are added, removed, or have
* their aggregate counts (`additions` / `deletions` / `files`) refreshed.
* The fan-out happens through this action so observers see catalogue
* Producers dispatch this whenever entries are added or removed. The
* fan-out happens through this action so observers see catalogue
* mutations in the same {@link ChangesetAction | per-changeset} action
* stream they already follow for file-level updates.
*
Expand All @@ -495,7 +495,7 @@ export interface SessionActivityChangedAction {
export interface SessionChangesetsChangedAction {
type: ActionType.SessionChangesetsChanged;
/** New catalogue, or `undefined` to clear it */
changesets: ChangesetSummary[] | undefined;
changesets: Changeset[] | undefined;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,11 +549,10 @@ export function sessionReducer(state: SessionState, action: SessionAction, log?:
};

case ActionType.SessionChangesetsChanged: {
const { changesets: _omit, ...summaryWithoutChangesets } = state.summary;
const newSummary = action.changesets
? { ...summaryWithoutChangesets, changesets: action.changesets }
: summaryWithoutChangesets;
return { ...state, summary: newSummary };
const { changesets: _omit, ...stateWithoutChangesets } = state;
return action.changesets
? { ...stateWithoutChangesets, changesets: action.changesets }
: stateWithoutChangesets;
}

case ActionType.SessionConfigChanged:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// allow-any-unicode-comment-file
// DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts

import type { ChangesetSummary } from '../channels-changeset/state.js';
import type { Changeset } from '../channels-changeset/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';

Expand Down Expand Up @@ -127,6 +127,14 @@ export interface SessionState {
* 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.
*
Expand Down Expand Up @@ -207,13 +215,29 @@ export interface SessionSummary {
/** The working directory URI for this session */
workingDirectory?: URI;
/**
* 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 ChangesetSummary} for the full shape and
* {@link /guide/changesets | Changesets} for an overview of the model.
*/
changesets?: ChangesetSummary[];
* 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;
}

/**
* 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 ─────────────────────────────────────────────────────────
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import type { RootState } from '../channels-root/state.js';
import type { SessionState } from '../channels-session/state.js';
import type { TerminalState } from '../channels-terminal/state.js';
import type { ChangesetState } from '../channels-changeset/state.js';
import type { ResourceWatchState } from '../channels-resource-watch/state.js';

// ─── Type Aliases ────────────────────────────────────────────────────────────

Expand Down Expand Up @@ -323,7 +322,7 @@ export interface Snapshot {
/** The subscribed channel URI (e.g. `ahp-root://` or `ahp-session:/<uuid>`) */
resource: URI;
/** The current state of the resource */
state: RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState;
state: RootState | SessionState | TerminalState | ChangesetState;
/** The `serverSeq` at which this snapshot was taken. Subsequent actions will have `serverSeq > fromSeq`. */
fromSeq: number;
}
4 changes: 2 additions & 2 deletions src/vs/platform/agentHost/common/state/sessionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
// Re-export everything from the protocol state module
export {
ChangesetOperationScope, ChangesetOperationStatus, ChangesetStatus, CustomizationLoadStatus,
CustomizationType, MessageAttachmentKind, MessageKind,
CustomizationType, McpServerStatus, MessageAttachmentKind, MessageKind,
PendingMessageKind,
PolicyState,
ResponsePartKind,
Expand All @@ -50,7 +50,7 @@ export {
SessionStatus, ToolCallCancellationReason, ToolCallConfirmationReason, ToolCallContributorKind, ToolCallStatus,
ToolResultContentType,
TurnState, type ActiveTurn, type AgentCustomization, type AgentInfo, type AgentSelection, type ChangesetFile,
type ChangesetOperation, type ChangesetState, type ChangesetSummary, type ChildCustomization, type ClientPluginCustomization, type ConfigPropertySchema,
type Changeset, type ChangesetOperation, type ChangesetState, type ChildCustomization, type ClientPluginCustomization, type ConfigPropertySchema,
type ConfigSchema,
type ContentRef, type Customization, type CustomizationDegradedState,
type CustomizationErrorState, type CustomizationLoadedState, type CustomizationLoadingState, type CustomizationLoadState, type DirectoryCustomization, type ErrorInfo, type HookCustomization, type FileEdit as ISessionFileDiff, type ToolResultEmbeddedResourceContent as IToolResultBinaryContent, type MarkdownResponsePart, type McpServerCustomization, type MessageAttachment,
Expand Down
Loading
Loading