claudeAgentSession.ts ×14

Frontier kind: Code frontier

unlabeled · c_1e8f903dc45f

110 tests · 55358 LOC · 346 files · introduces 0 tests · 116 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
15 ranges116 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
5279 ranges55358 lines · 346 files · Browse complete extent
All tests (intent)
110 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 116 introduced LOC across 15 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/agentHost/node/claude/claudeAgentSession.ts 109 introduced LOC · 14 ranges

Open complete file

428 */
429 async materialize(ctx: IMaterializeContext): Promise<void> {
430 > if (this._pipeline) { claudeAgentSession.ts
431 throw new Error('ClaudeAgentSession is already materialized');
432 }
433 > // Adopt the host-resolved working directory (e.g. an isolated worktree) claudeAgentSession.ts
434 > // before it's read below; falls back to the session's `workspace` when the
435 > // host didn't resolve a dedicated directory.
436 > if (ctx.workingDirectory && !isEqual(ctx.workingDirectory, this.workingDirectory)) {
437 this._workingDirectory = ctx.workingDirectory;
438 this._watchCustomizations(ctx.workingDirectory);
439 }
440 > if (!this.workingDirectory) { claudeAgentSession.ts
441 throw new Error(`Cannot materialize Claude session ${this.sessionId}: workingDirectory is required`);
442 }
443 > this._transportKind = ctx.transport.kind; claudeAgentSession.ts
444 >
445 > const permissionMode = readClaudePermissionMode(this._configurationService, this._storageUri) ?? this._permissionModeFallback;
446 > const { mcpServers, allowedTools } = await this._buildStartupToolWiring(ctx.serverToolHost);
447 > const agentName = await resolveClaudeAgentName(this._provisionalAgent, this._fileService, this._logService, this.sessionId);
448 >
449 > const options = await buildOptions(
450 > {
451 > sessionId: this.sessionId,
452 > workingDirectory: this.workingDirectory,
453 > model: this._provisionalModel,
454 > abortController: this.abortController,
455 > permissionMode,
456 > canUseTool: ctx.canUseTool,
457 > onElicitation: ctx.onElicitation,
458 > isResume: ctx.isResume,
459 > resumeSessionAt: this._pendingResumeSessionAt,
460 > mcpServers,
461 > allowedTools,
462 > plugins: this.clientCustomizationsDiff.consume(this._desiredClientPluginPaths()),
463 > agent: agentName,
464 > },
465 > ctx.transport,
466 > data => this._logService.error(`[Claude SDK stderr] ${data}`),
467 > );
468 >
469 > this._logService.info(`[Claude] session ${this.sessionId}: enableFileCheckpointing=${options.enableFileCheckpointing} isResume=${ctx.isResume}`);
470 >
471 > const warm = await this._sdkService.startup({ options });
472 >
473 > if (this.abortController.signal.aborted) {
474 await warm[Symbol.asyncDispose]();
475 throw new CancellationError();
476 }
478 > const dbRef = this._sessionDataService.openDatabase(this._storageUri);
479 > let pipeline: ClaudeSdkPipeline;
480 > try {
481 > pipeline = this._register(this._instantiationService.createInstance(
482 > ClaudeSdkPipeline,
483 > this.sessionId,
484 > this.sessionUri,
485 > this._chatChannelUri,
486 > warm,
487 > this.abortController,
488 > dbRef,
489 > this.subagents,
490 > (toolName: string) => this.toolDiff.model.ownerOf(toolName),
491 > ));
492 > } catch (err) {
493 dbRef.dispose();
494 await warm[Symbol.asyncDispose]();
495 throw err;
496 }
497 > this._register(pipeline.onDidProduceSignal(s => this._onDidSessionProgress.fire(this._enrichSignalWithMcpContributor(this._enrichSignalWithCredits(s))))); claudeAgentSession.ts
498 > this._pipeline = pipeline;
499 > // The materialize succeeded with the staged anchor applied to `Options`
500 > // — clear it now so it isn't re-applied. A throw before this point (e.g.
501 > // `startup` / pipeline-create) leaves it staged for the next retry.
502 > this._pendingResumeSessionAt = undefined;
503 >
504 > // Seed the pipeline's bijective config cache so a rebuild re-applies
505 > // the user's last-chosen model / effort without losing the picker
506 > // config. Read provisional state directly off the session.
507 > pipeline.seedCurrentConfig(
508 > toSdkModelId(this._provisionalModel?.id),
509 > toRuntimeEffortLevel(resolveClaudeEffort(this._provisionalModel)),
510 > permissionMode,
511 > );
512 >
513 > // Fresh sessions persist their customization-directory / model /
514 > // permissionMode overlay so a later resume re-reads them. Resume
515 > // sessions skip the write because they READ from the overlay
516 > // upstream and would otherwise overwrite their source.
517 > if (!ctx.isResume) {
518 try {
519 await this._metadataStore.write(this._storageUri, {
528 }
529 }
531 > // Final pre-commit abort gate. The first gate above caught aborts
532 > // that landed while `sdk.startup()` was in flight; this one catches
533 > // aborts that landed during the metadata write (a separate async
534 > // boundary). Without it, a racing `disposeSession` could complete
535 > // before this method returns and leave the pipeline live.
536 > if (this.abortController.signal.aborted) {
537 throw new CancellationError();
538 }
582 // sees them as server-provided. Execution happens in-process via the
583 // server-tool MCP server built in `_buildStartupToolWiring`.
584 > ctx.serverToolHost?.advertise(this._storageUri.toString()); claudeAgentSession.ts
585 >
586 > // Surface the SDK-resolved customization tier to the workbench.
587 > // Pre-materialize, getSessionCustomizations returns only the
588 > // client-pushed slice; firing here prompts the workbench to refetch
589 > // and pick up the bundled `Discovered in Claude` entry.
590 > this._onDidCustomizationsChange.fire();
591 > }
592
593 /**
608 */
609 private async _buildStartupToolWiring(
610 > serverToolHost: IAgentServerToolHost | undefined, claudeAgentSession.ts
611 > ): Promise<{ mcpServers: Record<string, McpSdkServerConfigWithInstance> | undefined; allowedTools: readonly string[] | undefined }> {
612 > const clientServers = await buildClientMcpServers(this.toolDiff, this._pendingClientToolCalls, this._sdkService);
613 > const serverToolServer = serverToolHost
614 ? await buildServerToolMcpServer(serverToolHost, this._storageUri.toString(), this._sdkService)
615 > : undefined; claudeAgentSession.ts
616 > const mcpServers = (!clientServers && !serverToolServer)
617 ? undefined
618 : {
620 ...(serverToolServer ? { [CLAUDE_SERVER_TOOL_MCP_SERVER_NAME]: serverToolServer } : {}),
621 };
622 > // Exclude server tools that require user confirmation from the claudeAgentSession.ts
623 > // auto-approve allow-list so the SDK surfaces them via `canUseTool`
624 > // (the host then renders a custom confirmation) instead of running them
625 > // silently.
626 > const autoApproveToolNames = serverToolHost
627 ? serverToolHost.toolNames.filter(name => !serverToolHost.requiresConfirmation(name))
628 > : undefined; claudeAgentSession.ts
629 > return { mcpServers, allowedTools: autoApproveToolNames ? serverToolAllowList(autoApproveToolNames) : undefined };
630 > }
631
632 /** True once {@link materialize} has installed the SDK pipeline. */
1067
1068 private _desiredClientPluginPaths(): readonly URI[] {
1069 > const state = this._sessionCustomizations; claudeAgentSession.ts
1070 > const desiredById = new Map(state.map(customization => [customization.id, customization.enabled]));
1071 > const paths: URI[] = [];
1072 > for (const synced of this.clientCustomizationsDiff.model.state.get().synced) {
1073 if (synced.pluginDir && (desiredById.get(synced.customization.id) ?? synced.customization.enabled) !== false) {
1074 paths.push(synced.pluginDir);
1075 }
1076 }
1077 > return paths; claudeAgentSession.ts
1078 > }
1079
1080 async startMcpServer(id: string): Promise<void> {
src/vs/platform/agentHost/node/claude/claudeSdkOptions.ts 7 introduced LOC · 1 range

Open complete file

162 * {@link SessionClientToolsDiff.markDirty}.
163 */
164 > export async function buildClientMcpServers( claudeSdkOptions.ts
165 > toolDiff: SessionClientToolsDiff,
166 > registry: PendingRequestRegistry<CallToolResult>,
167 > sdkService: IClaudeAgentSdkService,
168 > ): Promise<Record<string, McpSdkServerConfigWithInstance> | undefined> {
169 > const tools = toolDiff.consume();
170 > if (tools.length === 0) {
171 return undefined;
172 }