Skip to content
Merged
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 @@ -880,7 +880,7 @@ export class RemoteAgentHostProtocolClient extends Disposable implements IAgentC
const promise = this._sendRequest('createSession', {
channel: session.toString(),
provider,
workingDirectories: config?.workingDirectory ? [fromAgentHostUri(config.workingDirectory).toString()] : undefined,
workingDirectories: config?.workingDirectories?.map(d => fromAgentHostUri(d).toString()),
fork: config?.fork ? { session: fromAgentHostUri(config.fork.session).toString(), turnId: config.fork.turnId } : undefined,
config: config?.config,
activeClient: config?.activeClient,
Expand Down Expand Up @@ -1051,6 +1051,7 @@ export class RemoteAgentHostProtocolClient extends Disposable implements IAgentC
status: s.status,
activity: s.activity,
workingDirectory: typeof s.workingDirectories?.[0] === 'string' ? toAgentHostUri(URI.parse(s.workingDirectories?.[0]), this._connectionAuthority) : undefined,
workingDirectories: s.workingDirectories?.map(d => toAgentHostUri(URI.parse(d), this._connectionAuthority)),
isRead: !!(s.status & SessionStatus.IsRead),
isArchived: !!(s.status & SessionStatus.IsArchived),
changes: s.changes,
Expand Down
49 changes: 42 additions & 7 deletions src/vs/platform/agentHost/common/agentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,8 @@ export interface IAgentSessionMetadata {
readonly status?: SessionStatus;
/** Human-readable description of what the session is currently doing. */
readonly activity?: string;
readonly workingDirectory?: URI;
/** All working directories available to the session (index 0 = primary). */
readonly workingDirectories?: readonly URI[];
readonly isRead?: boolean;
readonly isArchived?: boolean;
/**
Expand Down Expand Up @@ -768,8 +769,19 @@ export interface IAgentSessionProjectInfo {
export interface IAgentCreateSessionResult {
readonly session: URI;
readonly project?: IAgentSessionProjectInfo;
/** The resolved working directory, which may differ from the requested one (e.g. worktree). */
readonly workingDirectory?: URI;
/**
* The single working directory the provider resolved for this session — its
* process root. This may differ from the requested primary (e.g. a
* workspace-less session runs in a provider-assigned scratch dir). It is NOT
* the full multi-root set: a provider only resolves the one directory its
* subprocess launches in. The host assembles the session's set by replacing
* the requested primary (index 0) with this value while keeping the requested
* tail. Worktree remaps and the fully-resolved set land later, on the first
* send, via {@link IAgentMaterializeSessionEvent.workingDirectories}.
* `undefined` means the provider did not resolve a directory (the host keeps
* the requested set as-is).
*/
readonly resolvedWorkingDirectory?: URI;
/**
* `true` when the agent only allocated an in-memory placeholder for this
* session (no SDK session, no worktree, no on-disk state). Materialization
Expand All @@ -789,7 +801,14 @@ export interface IAgentCreateSessionResult {
*/
export interface IAgentMaterializeSessionEvent {
readonly session: URI;
readonly workingDirectory: URI | undefined;
/**
* The complete resolved working-directory set (index 0 = the resolved process
* root, e.g. a worktree). The host replaces index 0 of the current session set
* with this set's index 0 while preserving the rest of the current set — the
* resume path can only report the single process cwd, so its tail is owned
* by the restored session state.
*/
readonly workingDirectories: readonly URI[] | undefined;
readonly project: IAgentSessionProjectInfo | undefined;
}

Expand Down Expand Up @@ -907,7 +926,20 @@ export interface IAgentCreateSessionConfig {
*/
readonly agent?: AgentSelection;
readonly session?: URI;
readonly workingDirectory?: URI;
/**
* The working directories the session's agent is granted tool access to,
* ordered so that index 0 is the intended process root (the "primary").
*
* Distinct values:
* - `undefined` — no directories requested (workspace-less inference applies);
* - `[]` — explicitly no directories;
* - `[dir, …]` — the ordered set (index 0 = primary/process root).
*
* A client MUST NOT supply more than one entry unless the agent advertises
* the `multipleWorkingDirectories` capability (not advertised yet). During
* the compatibility phase callers supply exactly one directory (`[dir]`).
*/
readonly workingDirectories?: readonly URI[];
readonly config?: Record<string, unknown>;
/**
* Eagerly claim the active client role for the new session. When provided,
Expand Down Expand Up @@ -1184,9 +1216,12 @@ export interface IAgentChats {

/**
* Send a user message into `chat`; on first send, the host passes the resolved
* working directory (or `undefined` for workspace-less sessions).
* working directories (index 0 = the process root / resolved worktree, followed
* by any additional roots). `undefined` for workspace-less sessions. Providers
* launch their subprocess in index 0; the full set is recorded in the
* materialization receipt.
*/
sendMessage(chat: URI, prompt: string, workingDirectory: URI | undefined, attachments?: readonly MessageAttachment[], turnId?: string, senderClientId?: string, clientType?: AgentHostClientType): Promise<void>;
sendMessage(chat: URI, prompt: string, workingDirectories: readonly URI[] | undefined, attachments?: readonly MessageAttachment[], turnId?: string, senderClientId?: string, clientType?: AgentHostClientType): Promise<void>;

/** Abort the in-flight turn for `chat`. */
abort(chat: URI): Promise<void>;
Expand Down
23 changes: 23 additions & 0 deletions src/vs/platform/agentHost/node/agentConfigurationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,20 @@ export interface IAgentConfigurationService {
* to the parent (subagent) session's working directory when the
* session itself does not have one set. The host layer does not carry
* a working directory.
* @deprecated Use {@link getEffectiveWorkingDirectories} instead, which preserves every root instead of collapsing to the primary.
*/
getEffectiveWorkingDirectory(session: ProtocolURI): string | undefined;

/**
* Returns the full ordered set of effective working directories for a
* session (index 0 = primary), falling back to the parent (subagent)
* session's set when the session itself does not have one set. Mirrors
* {@link getEffectiveWorkingDirectory} but preserves every root instead
* of collapsing to the primary. The host layer does not carry a working
* directory.
*/
getEffectiveWorkingDirectories(session: ProtocolURI): string[] | undefined;

/**
* Whether a fresh worktree-isolation session's worktree has not yet been
* created. Agents consult this to defer prewarming (and any other eager
Expand Down Expand Up @@ -230,6 +241,18 @@ export class AgentConfigurationService extends Disposable implements IAgentConfi
return undefined;
}

getEffectiveWorkingDirectories(session: ProtocolURI): string[] | undefined {
const own = this._stateManager.getSessionState(session)?.workingDirectories;
if (own !== undefined) {
return own;
}
const parentInfo = parseSubagentSessionUri(session);
if (parentInfo) {
return this._stateManager.getSessionState(parentInfo.parentSession.toString())?.workingDirectories;
}
return undefined;
}

isWorkingDirectoryPending(session: ProtocolURI): boolean {
return this._worktree?.isWorkingDirectoryPending(AgentSession.id(session)) ?? false;
}
Expand Down
Loading
Loading