Skip to content

Commit 5270254

Browse files
Let the setup banner reload an agent's configuration (#331848)
* Let the setup banner reload an agent's configuration A user who finishes setup outside the app — `claude login` in a terminal, an exported key — leaves no signal the app can see, so the banner kept asking them to sign in to something they had already signed in to. Give them a way to say "look again", and rename the docs link to "learn more" now that it is one of two links rather than the only one. The re-look is the tail of a download promoted to its own gesture: restart chat discovery, then refresh models. `AgentSdkSetupChannel` grows a second request key rather than per-agent code, so agent #3 still needs no edit here — one consumed nonce per key, cleared as it is claimed, so a repeat press still lands. The reload clause folds into each of the four `noAccount` sentences rather than trailing them: it is unconditional, so the table stays at four branches and no localized string is assembled from fragments. * Rank the no-account copy as the buttons rank it, and harden its links Read the sentence in the order the routes are weighted: GitHub sign-in leads, as the primary button; the provider sign-in follows; reload and docs trail, being the copy's only links rather than buttons. Reload and docs become their own sentences — kept as trailing clauses they would have fallen under the "if you already set up Claude elsewhere" conditional, which does not scope docs. Addresses review feedback: build both `command:` hrefs through `createCommandUri` instead of by hand (`encodeURIComponent` leaves `)` alone, so an agent id containing one closed the markdown link destination early), and escape the host-supplied display name and sign-in provider before interpolating them into markdown this banner trusts for two commands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Rewrite the no-account copy, and point Claude at its integrations docs The four sentences now put every sign-in route and the reload into one "or" list, ranked as the buttons rank them, and give the docs their own trailing sentence. Claude's docs URL moves to the third-party integrations page, which is what "other ways to set up Claude" actually means: Console, Bedrock, Vertex, Foundry, Teams and Enterprise. "Set up" is the verb, two words, as the rest of the string already had it. Both agents' URL constants still described the workbench as labelling a button. It has been a link since docs stopped being an action. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 506d2e1 commit 5270254

9 files changed

Lines changed: 225 additions & 54 deletions

File tree

src/vs/platform/agentHost/common/agentSdkSetup.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ const AGENT_SDK_SETUP_STATUS_KEY_PREFIX = 'vscode.agentSdkSetup.status.';
1818

1919
export const AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY = 'vscode.agentSdkSetup.downloadRequest';
2020

21+
/**
22+
* Ask an agent to look again at a setup the user completed outside the app
23+
* (`claude login`, an exported key) — the only completion signal there is.
24+
*/
25+
export const AGENT_SDK_SETUP_RELOAD_REQUEST_KEY = 'vscode.agentSdkSetup.reloadRequest';
26+
2127
export function agentSdkSetupStatusKey(agent: string): string {
2228
return `${AGENT_SDK_SETUP_STATUS_KEY_PREFIX}${agent}`;
2329
}

src/vs/platform/agentHost/node/agentSdkSetupChannel.ts

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { Disposable } from '../../../base/common/lifecycle.js';
77
import { ILogService } from '../../log/common/log.js';
8-
import { AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY, AgentSdkDownloadStatus, IAgentSdkSetupInfo, agentSdkSetupStatusKey, isAgentSdkSetupRequestFor } from '../common/agentSdkSetup.js';
8+
import { AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY, AGENT_SDK_SETUP_RELOAD_REQUEST_KEY, AgentSdkDownloadStatus, IAgentSdkSetupInfo, agentSdkSetupStatusKey, isAgentSdkSetupRequestFor } from '../common/agentSdkSetup.js';
99
import { IAgentConfigurationService } from './agentConfigurationService.js';
1010
import { IAgentSdkDownloader, IAgentSdkPackage } from './agentSdkDownloader.js';
1111

@@ -33,14 +33,14 @@ export interface IAgentSdkSetupChannelAgent {
3333

3434
/**
3535
* One agent's side of the SDK setup channel: publishes whether its SDK is on
36-
* disk, and performs the download the workbench asks for. Every agent needs the
37-
* same nonce handling, latching and publish ordering, so only the calls in
38-
* {@link IAgentSdkSetupChannelAgent} differ.
36+
* disk, performs the download the workbench asks for, and looks again when it
37+
* asks for that. Every agent needs the same nonce handling, latching and publish
38+
* ordering, so only the calls in {@link IAgentSdkSetupChannelAgent} differ.
3939
*/
4040
export class AgentSdkSetupChannel extends Disposable {
4141

42-
/** Consumed request nonce, so a root-config change we caused isn't re-handled. */
43-
private _lastRequest: string | undefined;
42+
/** Consumed request nonce per request key, so a root-config change we caused isn't re-handled. */
43+
private readonly _lastRequests = new Map<string, string>();
4444

4545
/**
4646
* Latched while the *explicit* download runs. {@link IAgentSdkSetupChannelAgent.isSdkLocal}
@@ -80,13 +80,27 @@ export class AgentSdkSetupChannel extends Disposable {
8080
}
8181

8282
private _handleRequest(): void {
83-
const request = this._configurationService.getRootConfigValues?.()[AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY];
84-
if (!isAgentSdkSetupRequestFor(request, this._agent.id) || request.request === this._lastRequest) {
85-
return;
83+
const values = this._configurationService.getRootConfigValues?.() ?? {};
84+
if (this._takeRequest(values, AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY)) {
85+
void this._download();
86+
}
87+
if (this._takeRequest(values, AGENT_SDK_SETUP_RELOAD_REQUEST_KEY)) {
88+
this._logService.info(`[AgentSdkSetup] ${this._agent.id}: reloading the agent's configuration at the user's request`);
89+
// Nothing to publish: the SDK is already on disk either way, and what the
90+
// banner reads is the catalog the re-look republishes.
91+
void this._lookAgain();
92+
}
93+
}
94+
95+
/** Claim one request addressed to this agent, clearing the key so a repeat press still lands. */
96+
private _takeRequest(values: Readonly<Record<string, unknown>>, key: string): boolean {
97+
const request = values[key];
98+
if (!isAgentSdkSetupRequestFor(request, this._agent.id) || request.request === this._lastRequests.get(key)) {
99+
return false;
86100
}
87-
this._lastRequest = request.request;
88-
this._configurationService.updateRootConfig({ [AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY]: undefined });
89-
void this._download();
101+
this._lastRequests.set(key, request.request);
102+
this._configurationService.updateRootConfig({ [key]: undefined });
103+
return true;
90104
}
91105

92106
/**
@@ -110,12 +124,21 @@ export class AgentSdkSetupChannel extends Disposable {
110124
this._downloadInFlight = false;
111125
progressInterest.dispose();
112126
}
127+
await this._lookAgain();
128+
}
129+
130+
/**
131+
* Re-read the world: the tail of a download, and the whole of a reload. Both
132+
* gestures change exactly what these two calls see — one puts the SDK on disk,
133+
* the other follows a `claude login` the app could not observe.
134+
*/
135+
private async _lookAgain(): Promise<void> {
113136
// Chat discovery deferred itself while there was no SDK to read the catalog
114137
// from; this is the one moment that can change.
115138
this._agent.restartChatDiscovery();
116-
// Second, not first: the refresh is what asks the fresh SDK about the account,
117-
// so announcing `ready` ahead of it would show "no account found" to a user
118-
// who has one for as long as enumeration takes.
139+
// Second, not first: the refresh is what asks the SDK about the account, so
140+
// announcing `ready` ahead of it would show "no account found" to a user who
141+
// has one for as long as enumeration takes.
119142
await this._agent.refreshModels();
120143
}
121144
}

src/vs/platform/agentHost/node/claude/claudeAgent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ import { IAgentHostOTelService } from '../../common/otel/agentHostOTelService.js
6868

6969
const USER_AGENT_PREFIX = 'vscode_claude_code';
7070

71-
/** Where a user goes to establish Claude credentials; the workbench labels the button. */
72-
const CLAUDE_SETUP_DOCS_URL = 'https://docs.claude.com/en/docs/claude-code/setup';
71+
/** Where a user goes to establish Claude credentials; the workbench labels the link. */
72+
const CLAUDE_SETUP_DOCS_URL = 'https://code.claude.com/docs/en/third-party-integrations';
7373

7474
/**
7575
* Returns true if `m` is a Claude-family model that should be advertised

src/vs/platform/agentHost/node/codex/codexAgent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ const CODEX_THINKING_LEVEL_KEY = 'thinkingLevel';
175175
*/
176176
const USER_AGENT_PREFIX = 'vscode_codex';
177177

178-
/** Where a user finishes setting Codex up outside the app; the workbench labels the button. */
178+
/** Where a user finishes setting Codex up outside the app; the workbench labels the link. */
179179
const CODEX_SETUP_DOCS_URL = 'https://learn.chatgpt.com/codex/auth';
180180

181181
/**

src/vs/platform/agentHost/test/node/claudeAgent.test.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ import { createClaudeInternalMcpServerCustomization } from '../../node/claude/cu
7777
import { ClaudeSessionMetadataStore } from '../../node/claude/claudeSessionMetadataStore.js';
7878
import { ClaudeSessionConfigKey } from '../../common/claudeSessionConfigKeys.js';
7979
import { ClaudeAgentSdkService, IClaudeAgentSdkService, IClaudeSdkBindings } from '../../node/claude/claudeAgentSdkService.js';
80-
import { AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY, readAgentSdkSetupInfos } from '../../common/agentSdkSetup.js';
80+
import { AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY, AGENT_SDK_SETUP_RELOAD_REQUEST_KEY, readAgentSdkSetupInfos } from '../../common/agentSdkSetup.js';
8181
import { IAgentSdkDownloader } from '../../node/agentSdkDownloader.js';
8282
import { RecordingAgentSdkDownloader } from './testAgentSdkDownloader.js';
8383
import { PendingRequestRegistry } from '../../common/pendingRequestRegistry.js';
@@ -6073,6 +6073,11 @@ suite('ClaudeAgent — agent SDK setup channel', () => {
60736073
ctx.configService.updateRootConfig({ [AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY]: { agent, request } });
60746074
}
60756075

6076+
/** Addresses a reload request the same way, as the banner's link does. */
6077+
function dispatchReload(ctx: ITestContext, agent = 'claude', request = 'req-1'): void {
6078+
ctx.configService.updateRootConfig({ [AGENT_SDK_SETUP_RELOAD_REQUEST_KEY]: { agent, request } });
6079+
}
6080+
60766081
/** Waits for the ctor's queued publish (and any refresh it chains) to settle. */
60776082
async function settle(): Promise<void> {
60786083
for (let i = 0; i < 20; i++) {
@@ -6087,7 +6092,7 @@ suite('ClaudeAgent — agent SDK setup channel', () => {
60876092
assert.deepStrictEqual(readSetup(ctx), {
60886093
agent: 'claude',
60896094
download: 'ready',
6090-
setupDocsUrl: 'https://docs.claude.com/en/docs/claude-code/setup',
6095+
setupDocsUrl: 'https://code.claude.com/docs/en/third-party-integrations',
60916096
// No in-app sign-in: every Claude credential is established outside the
60926097
// app, so the banner can only point at the docs.
60936098
signInProviderName: undefined,
@@ -6264,6 +6269,52 @@ suite('ClaudeAgent — agent SDK setup channel', () => {
62646269
migratable: [],
62656270
});
62666271
});
6272+
6273+
test('a reload re-asks the SDK for the account the user set up elsewhere, fetching nothing', async () => {
6274+
// Setup happens outside the app, so nothing fires when it finishes — a fresh
6275+
// `accountInfo()` is the only way to see it, and the SDK is already on disk.
6276+
const ctx = createTestContext(disposables);
6277+
await settle();
6278+
const before = ctx.sdk.accountInfoCallCount;
6279+
ctx.sdk.accountInfoResult = NATIVE_ACCOUNT;
6280+
ctx.sdk.supportedModelsResult = [
6281+
{ value: 'claude-sonnet-4-5-20250929', displayName: 'Claude Sonnet 4.5', description: '', supportedEffortLevels: ['high'] },
6282+
];
6283+
6284+
dispatchReload(ctx);
6285+
await settle();
6286+
6287+
assert.deepStrictEqual({
6288+
asked: ctx.sdk.accountInfoCallCount > before,
6289+
fetches: ctx.sdk.ensureAvailableCalls,
6290+
models: ctx.agent.models.get().map(model => model.name),
6291+
// Consumed like the download key, so pressing the link twice is two reloads.
6292+
key: ctx.configService.getRootConfigValues()[AGENT_SDK_SETUP_RELOAD_REQUEST_KEY],
6293+
}, {
6294+
asked: true,
6295+
fetches: 0,
6296+
models: ['Claude Sonnet 4.5'],
6297+
key: undefined,
6298+
});
6299+
});
6300+
6301+
test('a reload addressed to another agent is ignored', async () => {
6302+
const ctx = createTestContext(disposables);
6303+
await settle();
6304+
const before = ctx.sdk.accountInfoCallCount;
6305+
6306+
dispatchReload(ctx, 'codex');
6307+
await settle();
6308+
6309+
assert.deepStrictEqual({
6310+
asked: ctx.sdk.accountInfoCallCount > before,
6311+
// Left in place for the agent it names, rather than consumed by this one.
6312+
key: ctx.configService.getRootConfigValues()[AGENT_SDK_SETUP_RELOAD_REQUEST_KEY],
6313+
}, {
6314+
asked: false,
6315+
key: { agent: 'codex', request: 'req-1' },
6316+
});
6317+
});
62676318
});
62686319

62696320
suite('ClaudeAgent — per-session provider', () => {

src/vs/platform/agentHost/test/node/codex/codexModelRefresh.test.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { IAgentHostSessionTitleSignal } from '../../../node/agentHostSessionTitl
2121
import { IAgentSdkDownloader } from '../../../node/agentSdkDownloader.js';
2222
import { RecordingAgentSdkDownloader } from '../testAgentSdkDownloader.js';
2323
import { IAgentHostCheckpointService, NULL_CHECKPOINT_SERVICE } from '../../../common/agentHostCheckpointService.js';
24-
import { AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY, readAgentSdkSetupInfos } from '../../../common/agentSdkSetup.js';
24+
import { AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY, AGENT_SDK_SETUP_RELOAD_REQUEST_KEY, readAgentSdkSetupInfos } from '../../../common/agentSdkSetup.js';
2525
import { CodexAgent, toCodexModelSelectionId } from '../../../node/codex/codexAgent.js';
2626
import { ICodexProxyService } from '../../../node/codex/codexProxyService.js';
2727
import { ICopilotApiService } from '../../../node/shared/copilotApiService.js';
@@ -681,6 +681,11 @@ suite('CodexAgent — agent SDK setup channel', () => {
681681
ctx.configurationService.updateRootConfig({ [AGENT_SDK_SETUP_DOWNLOAD_REQUEST_KEY]: { agent, request } });
682682
}
683683

684+
/** Addresses a reload request the same way, as the banner's link does. */
685+
function dispatchReload(ctx: ITestAgentContext, agent = 'codex', request = 'req-1'): void {
686+
ctx.configurationService.updateRootConfig({ [AGENT_SDK_SETUP_RELOAD_REQUEST_KEY]: { agent, request } });
687+
}
688+
684689
/** Waits for the ctor's queued publish (and any refresh it chains) to settle. */
685690
async function settle(): Promise<void> {
686691
for (let i = 0; i < 20; i++) {
@@ -840,4 +845,22 @@ suite('CodexAgent — agent SDK setup channel', () => {
840845
held: 0,
841846
});
842847
});
848+
849+
test('a reload is claimed here too, since the request handling is the shared channel and not per-agent code', async () => {
850+
const ctx = createAgentContext(disposables, async () => []);
851+
ctx.agent['_ensureConnection'] = async () => { throw new Error('offline'); };
852+
await settle();
853+
854+
dispatchReload(ctx);
855+
await settle();
856+
857+
assert.deepStrictEqual({
858+
key: ctx.configurationService.getRootConfigValues()[AGENT_SDK_SETUP_RELOAD_REQUEST_KEY],
859+
// Reload only re-reads what is already there; nothing is ever fetched.
860+
interests: ctx.sdkDownloader.progressInterests,
861+
}, {
862+
key: undefined,
863+
interests: [],
864+
});
865+
});
843866
});

src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSdkSetupNotification.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { Disposable, DisposableStore } from '../../../../../../base/common/lifecycle.js';
77
import { Event } from '../../../../../../base/common/event.js';
8+
import { createCommandUri, escapeMarkdownSyntaxTokens, IMarkdownString, MarkdownString } from '../../../../../../base/common/htmlContent.js';
89
import { localize } from '../../../../../../nls.js';
910
import { AgentHostAllowSignedOutWhenUsableSettingId, IAgentHostService } from '../../../../../../platform/agentHost/common/agentService.js';
1011
import { LOCAL_AGENT_HOST_SCHEME_PREFIX } from '../../../../../../platform/agentHost/common/agentHostConnectionsService.js';
@@ -84,25 +85,39 @@ export function getAgentSdkSetupStateToReport(previous: AgentSdkSetupState | und
8485

8586
// #region Banner
8687

88+
/** Trusted for the commands its links address, and nothing else. */
89+
function setupMarkdown(value: string): MarkdownString {
90+
return new MarkdownString(value, { isTrusted: { enabledCommands: [AGENT_SDK_SETUP_OPEN_DOCS_COMMAND_ID, AGENT_SDK_SETUP_RELOAD_COMMAND_ID] } });
91+
}
92+
8793
/**
8894
* The "no account" second line: one whole sentence per combination of routes,
8995
* never assembled from localized fragments, because clause order is not stable
90-
* across languages. The GitHub clause is unconditional — every agent behind this
91-
* banner reaches models through our Copilot proxy once signed in, which is
92-
* workbench knowledge rather than something an agent could declare.
96+
* across languages. The routes share one "or" list, ranked as the buttons rank
97+
* them and led by the unconditional GitHub clause: reaching models through our
98+
* Copilot proxy is workbench knowledge, not something an agent declares.
9399
*/
94-
function noAccountDescription(setup: IAgentSdkSetupInfo, displayName: string): string {
95-
const provider = setup.signInProviderName;
96-
if (provider && setup.setupDocsUrl) {
97-
return localize('agentHost.sdkSetup.noAccountDescription.all', "Sign in to GitHub to use GitHub Copilot models, sign in to {0} to use your {0} subscription, or read the instructions for other ways to set up {1}.", provider, displayName);
100+
function noAccountDescription(setup: IAgentSdkSetupInfo, displayName: string): IMarkdownString {
101+
// Both nouns are the host's, and this string is trusted for two commands, so
102+
// they are escaped rather than interpolated raw: `[]()` in a name would
103+
// otherwise synthesize a link to either one.
104+
const name = escapeMarkdownSyntaxTokens(displayName);
105+
const provider = setup.signInProviderName && escapeMarkdownSyntaxTokens(setup.signInProviderName);
106+
// `command:` hrefs, so a link in the copy takes the same route a button would —
107+
// funnel step and URL validation included. Both carry the agent id and nothing
108+
// else: the docs command resolves the URL from the agent's own declaration.
109+
const reload = createCommandUri(AGENT_SDK_SETUP_RELOAD_COMMAND_ID, setup.agent).toString();
110+
const docs = setup.setupDocsUrl ? createCommandUri(AGENT_SDK_SETUP_OPEN_DOCS_COMMAND_ID, setup.agent).toString() : undefined;
111+
if (provider && docs) {
112+
return setupMarkdown(localize('agentHost.sdkSetup.noAccountDescription.all', "Sign in to GitHub to use GitHub Copilot models, sign in to {2} to use your {2} subscription, or [reload the configuration]({1}) if you have set up {0} elsewhere. For other ways to set up {0}, [learn more]({3}) on their docs.", name, reload, provider, docs));
98113
}
99114
if (provider) {
100-
return localize('agentHost.sdkSetup.noAccountDescription.signIn', "Sign in to GitHub to use GitHub Copilot models, or sign in to {0} to use your {0} subscription.", provider);
115+
return setupMarkdown(localize('agentHost.sdkSetup.noAccountDescription.signIn', "Sign in to GitHub to use GitHub Copilot models, sign in to {2} to use your {2} subscription, or [reload the configuration]({1}) if you have set up {0} elsewhere.", name, reload, provider));
101116
}
102-
if (setup.setupDocsUrl) {
103-
return localize('agentHost.sdkSetup.noAccountDescription.docs', "Sign in to GitHub to use GitHub Copilot models, or read the instructions for other ways to set up {0}.", displayName);
117+
if (docs) {
118+
return setupMarkdown(localize('agentHost.sdkSetup.noAccountDescription.docs', "Sign in to GitHub to use GitHub Copilot models or [reload the configuration]({1}) if you have set up {0} elsewhere. For other ways to set up {0}, [learn more]({2}) on their docs.", name, reload, docs));
104119
}
105-
return localize('agentHost.sdkSetup.noAccountDescription', "Sign in to GitHub to use GitHub Copilot models.");
120+
return setupMarkdown(localize('agentHost.sdkSetup.noAccountDescription', "Sign in to GitHub to use GitHub Copilot models or [reload the configuration]({1}) if you have set up {0} elsewhere.", name, reload));
106121
}
107122

108123
/**
@@ -197,9 +212,6 @@ export function createAgentSdkSetupNotification(setup: IAgentSdkSetupInfo, displ
197212
};
198213
}
199214
const actions: IChatInputNotificationAction[] = [];
200-
if (setup.setupDocsUrl) {
201-
actions.push(action(localize('agentHost.sdkSetup.docsAction', "Setup Instructions"), AGENT_SDK_SETUP_OPEN_DOCS_COMMAND_ID));
202-
}
203215
if (setup.signInProviderName) {
204216
actions.push(action(localize('agentHost.sdkSetup.signInAction', "Sign in to {0}", setup.signInProviderName), AGENT_SDK_SETUP_SIGN_IN_COMMAND_ID));
205217
}
@@ -220,6 +232,7 @@ export function createAgentSdkSetupNotification(setup: IAgentSdkSetupInfo, displ
220232

221233
export const AGENT_SDK_SETUP_DOWNLOAD_COMMAND_ID = 'workbench.action.chat.agentHost.downloadAgentSdk';
222234
export const AGENT_SDK_SETUP_OPEN_DOCS_COMMAND_ID = 'workbench.action.chat.agentHost.openAgentSetupDocs';
235+
export const AGENT_SDK_SETUP_RELOAD_COMMAND_ID = 'workbench.action.chat.agentHost.reloadAgentConfiguration';
223236
export const AGENT_SDK_SETUP_GITHUB_SIGN_IN_COMMAND_ID = 'workbench.action.chat.agentHost.signInToGitHubForAgent';
224237
export const AGENT_SDK_SETUP_SIGN_IN_COMMAND_ID = 'workbench.action.chat.agentHost.signInToAgent';
225238

@@ -239,6 +252,7 @@ function registerAgentSdkSetupCommand(id: string, run: (setupService: IAgentSdkS
239252

240253
registerAgentSdkSetupCommand(AGENT_SDK_SETUP_DOWNLOAD_COMMAND_ID, (setupService, agent) => setupService.requestDownload(agent));
241254
registerAgentSdkSetupCommand(AGENT_SDK_SETUP_OPEN_DOCS_COMMAND_ID, (setupService, agent) => setupService.openSetupDocs(agent));
255+
registerAgentSdkSetupCommand(AGENT_SDK_SETUP_RELOAD_COMMAND_ID, (setupService, agent) => setupService.requestReload(agent));
242256
registerAgentSdkSetupCommand(AGENT_SDK_SETUP_GITHUB_SIGN_IN_COMMAND_ID, (setupService, agent) => setupService.signInToGitHub(agent));
243257
registerAgentSdkSetupCommand(AGENT_SDK_SETUP_SIGN_IN_COMMAND_ID, (setupService, agent) => setupService.signIn(agent));
244258

0 commit comments

Comments
 (0)