Skip to content
Open
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
13 changes: 13 additions & 0 deletions src/vs/platform/agentHost/common/sessionConfigKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,16 @@ export function omitTransientSessionConfigValues<T>(values: Record<string, T>):
delete result[SessionConfigKey.ShellInitScripts];
return result;
}

/**
* Profile-scoped store of the user's last session-config picks. Shared so the Agents
* window and the chat input seed new sessions from the same choices.
*/
export const REMEMBERED_SESSION_CONFIG_STORAGE_KEY = 'sessions.agentHost.sessionConfigPicker.selectedValues';

const UNSAFE_SESSION_CONFIG_KEYS = new Set(['__proto__', 'constructor', 'prototype']);

/** Whether a session-config property may be carried from one session to the next. */
export function isRememberedSessionConfigKey(property: string): boolean {
return property !== SessionConfigKey.Branch && !UNSAFE_SESSION_CONFIG_KEYS.has(property);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { buildAnnotationsUri } from '../../../../../platform/agentHost/common/an
import { ChangesetKind } from '../../../../../platform/agentHost/common/changesetUri.js';
import { parseGitHubIssueUrl } from '../../../../../platform/agentHost/common/githubIssueReferences.js';
import { getEffectiveAgents } from '../../../../../platform/agentHost/common/customAgents.js';
import { KNOWN_MODE_VALUES, SessionConfigKey } from '../../../../../platform/agentHost/common/sessionConfigKeys.js';
import { isRememberedSessionConfigKey, KNOWN_MODE_VALUES, REMEMBERED_SESSION_CONFIG_STORAGE_KEY, SessionConfigKey } from '../../../../../platform/agentHost/common/sessionConfigKeys.js';
import { migrateLegacyAutopilotConfig } from '../../../../../platform/agentHost/common/agentHostSchema.js';
import { readAgentDevContainerWorktreeMetadata, withAgentDevContainerWorktreeMetadata, type IAgentDevContainerWorktreeMetadata } from '../../../../../platform/agentHost/common/meta/agentDevContainerWorktreeMeta.js';
import type { IAgentSubscription } from '../../../../../platform/agentHost/common/state/agentSubscription.js';
Expand Down Expand Up @@ -70,8 +70,6 @@ import { mapProtocolStatus } from './agentHostDiffs.js';
import { createActiveSessionSubscriptionObs, createChangesets, IAgentHostChangeset, selectMostRecentChatUri } from './agentHostSessionChangesets.js';
import { createSessionOutputObs, ISessionOutputObs } from './agentHostSessionFiles.js';

const STORAGE_KEY_REMEMBERED_SESSION_CONFIG_VALUES = 'sessions.agentHost.sessionConfigPicker.selectedValues';
const UNSAFE_SESSION_CONFIG_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
const SESSION_CHANGE_NOTIFICATION_DEBOUNCE_MS = 50;

function mergeSessionChangeEvents(events: readonly ISessionChangeEvent[]): ISessionChangeEvent {
Expand Down Expand Up @@ -284,10 +282,6 @@ function deserializeStatus(raw: ISerializedSessionMetadata): ProtocolSessionStat
return status;
}

function isRememberedSessionConfigKey(property: string): boolean {
return property !== SessionConfigKey.Branch && !UNSAFE_SESSION_CONFIG_KEYS.has(property);
}

function normalizeAutoApproveValue(value: unknown, policyRestricted: boolean): ChatPermissionLevel | undefined {
// `KNOWN_AUTO_APPROVE_VALUES` is intentionally tolerant of legacy values
// that are not real `ChatPermissionLevel`s. Validate against the enum here
Expand Down Expand Up @@ -3775,7 +3769,7 @@ export abstract class BaseAgentHostSessionsProvider extends Disposable implement
// Seed session config values from the last user picks, migrating any
// legacy `autoApprove='autopilot'` remembered value into the new
// `mode='autopilot'` shape before the per-axis precedence below runs.
const rememberedValues = this._storageService.getObject<Record<string, unknown>>(STORAGE_KEY_REMEMBERED_SESSION_CONFIG_VALUES, StorageScope.PROFILE, {});
const rememberedValues = this._storageService.getObject<Record<string, unknown>>(REMEMBERED_SESSION_CONFIG_STORAGE_KEY, StorageScope.PROFILE, {});
for (const [property, value] of Object.entries(rememberedValues)) {
if (typeof value === 'string' && isRememberedSessionConfigKey(property)) {
config[property] = value;
Expand Down Expand Up @@ -3867,15 +3861,15 @@ export abstract class BaseAgentHostSessionsProvider extends Disposable implement

// Remember portable config picks across sessions.
if (typeof normalizedValue === 'string' && isRememberedSessionConfigKey(property)) {
const rememberedValues = this._storageService.getObject<Record<string, unknown>>(STORAGE_KEY_REMEMBERED_SESSION_CONFIG_VALUES, StorageScope.PROFILE, {});
const rememberedValues = this._storageService.getObject<Record<string, unknown>>(REMEMBERED_SESSION_CONFIG_STORAGE_KEY, StorageScope.PROFILE, {});
const nextRememberedValues = Object.create(null) as Record<string, string>;
for (const [key, rememberedValue] of Object.entries(rememberedValues)) {
if (typeof rememberedValue === 'string' && isRememberedSessionConfigKey(key)) {
nextRememberedValues[key] = rememberedValue;
}
}
nextRememberedValues[property] = normalizedValue;
this._storageService.store(STORAGE_KEY_REMEMBERED_SESSION_CONFIG_VALUES, JSON.stringify(nextRememberedValues), StorageScope.PROFILE, StorageTarget.MACHINE);
this._storageService.store(REMEMBERED_SESSION_CONFIG_STORAGE_KEY, JSON.stringify(nextRememberedValues), StorageScope.PROFILE, StorageTarget.MACHINE);
}

// Mark resolution before firing so the first picker render is already inert.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ import { isEqual } from '../../../../../../base/common/resources.js';
import { URI } from '../../../../../../base/common/uri.js';
import { generateUuid } from '../../../../../../base/common/uuid.js';
import { IAgentHostService } from '../../../../../../platform/agentHost/common/agentService.js';
import { KNOWN_MODE_VALUES, SessionConfigKey } from '../../../../../../platform/agentHost/common/sessionConfigKeys.js';
import { isRememberedSessionConfigKey, KNOWN_MODE_VALUES, REMEMBERED_SESSION_CONFIG_STORAGE_KEY, SessionConfigKey } from '../../../../../../platform/agentHost/common/sessionConfigKeys.js';
import { IStorageService, StorageScope } from '../../../../../../platform/storage/common/storage.js';
import { migrateLegacyAutopilotConfig } from '../../../../../../platform/agentHost/common/agentHostSchema.js';
import { ActionType } from '../../../../../../platform/agentHost/common/state/protocol/actions.js';
import type { ResolveSessionConfigResult } from '../../../../../../platform/agentHost/common/state/protocol/commands.js';
Expand Down Expand Up @@ -291,6 +292,7 @@ export class AgentHostUntitledProvisionalSessionService extends Disposable imple
@IAgentHostImportConversationStore private readonly _importConversationStore: IAgentHostImportConversationStore,
@IAgentHostActiveClientService private readonly _activeClientService: IAgentHostActiveClientService,
@IUriIdentityService private readonly _uriIdentityService: IUriIdentityService,
@IStorageService private readonly _storageService: IStorageService,
) {
super();

Expand Down Expand Up @@ -1062,7 +1064,15 @@ export class AgentHostUntitledProvisionalSessionService extends Disposable imple
if (this._environmentService.isSessionsWindow) {
return undefined;
}
const config: Record<string, unknown> = { [SessionConfigKey.Isolation]: 'folder' };
// Seed from the picks the Agents window remembers, so a chip set there is not reset here.
const remembered: Record<string, unknown> = Object.create(null);
const rememberedValues = this._storageService.getObject<Record<string, unknown>>(REMEMBERED_SESSION_CONFIG_STORAGE_KEY, StorageScope.PROFILE, {});
for (const [property, value] of Object.entries(rememberedValues)) {
if (typeof value === 'string' && isRememberedSessionConfigKey(property)) {
remembered[property] = value;
}
}
const config: Record<string, unknown> = { ...remembered, [SessionConfigKey.Isolation]: 'folder' };
Comment on lines +1069 to +1075

const configuredDefaults = this._configurationService.getValue<IChatDefaultConfiguration>(ChatConfiguration.DefaultConfiguration);
const policyValue = this._configurationService.inspect<boolean>(ChatConfiguration.GlobalAutoApprove).policyValue;
Expand Down