copilotShellTools.ts ×11

Frontier kind: Code frontier

unlabeled · c_9a1c21fe273c

23 tests · 28676 LOC · 131 files · introduces 0 tests · 168 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
14 ranges168 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
2456 ranges28676 lines · 131 files · Browse complete extent
All tests (intent)
23 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: 168 introduced LOC across 14 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/agentHost/node/copilot/copilotShellTools.ts 155 introduced LOC · 11 ranges

Open complete file

384 * plus companion tools (read, write, shutdown, list).
385 */
386 > export async function createShellTools( copilotShellTools.ts
387 > shellManager: ShellManager,
388 > terminalManager: IAgentHostTerminalManager,
389 > logService: ILogService,
390 > confirmUnsandboxedExecution?: UnsandboxedCommandConfirmationHandler,
391 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
392 > ): Promise<Tool<any>[]> {
393 > const executable = await shellManager.getResolvedExecutable();
394 > const shellType = shellTypeForExecutable(executable);
395 > const engine = shellManager.getOrCreateSandboxEngine();
396 > const sandboxEnabled = await engine.isEnabled();
397 > const networkDomains = sandboxEnabled ? engine.getResolvedNetworkDomains() : undefined;
398 >
399 > const primaryTool: Tool<IShellToolArgs> = {
400 > name: shellType,
401 > description: shellType === 'bash'
402 > ? (isZsh(executable) ? createZshModelDescription(sandboxEnabled, networkDomains) : createBashModelDescription(sandboxEnabled, networkDomains))
403 : createPowerShellModelDescription(shellType, executable, sandboxEnabled, networkDomains),
404 > parameters: { copilotShellTools.ts
405 > type: 'object',
406 > properties: {
407 > command: { type: 'string', description: 'The command to execute' },
408 > timeout: { type: 'number', description: 'Timeout in milliseconds (default 120000)' },
409 > ...(sandboxEnabled ? {
410 requestUnsandboxedExecution: {
411 type: 'boolean',
416 description: 'A short explanation of the sandboxed execution failure or blocked-domain requirement that justifies retrying outside the sandbox. Only provide this when requestUnsandboxedExecution is true.',
417 },
418 > } : {}), copilotShellTools.ts
419 > },
420 > required: ['command'],
421 > },
422 > overridesBuiltInTool: true,
423 > handler: async (args, invocation) => {
424 const timeoutMs = args.timeout ?? DEFAULT_SHELL_COMMAND_TIMEOUT_MS;
425 const ref = await shellManager.getOrCreateShell(
514 }
515 },
517 >
518 > const readTool: Tool<IReadShellArgs> = {
519 > name: `read_${shellType}`,
520 > description: `Read the latest output from a running ${shellType} shell.`,
521 > parameters: {
522 > type: 'object',
523 > properties: {
524 > shell_id: { type: 'string', description: 'Shell ID to read from (optional; uses latest shell if omitted)' },
525 > },
526 > },
527 > overridesBuiltInTool: true,
528 > skipPermission: true,
529 > handler: (args) => {
530 const shells = shellManager.listShells();
531 const shell = args.shell_id
541 return makeSuccessResult(prepareOutputForModel(content));
542 },
544 >
545 > const writeTool: Tool<IWriteShellArgs> = {
546 > name: `write_${shellType}`,
547 > description: `Send input to a running ${shellType} shell (e.g. answering a prompt, sending Ctrl+C).`,
548 > parameters: {
549 > type: 'object',
550 > properties: {
551 > command: { type: 'string', description: 'Text to write to the shell stdin' },
552 > },
553 > required: ['command'],
554 > },
555 > overridesBuiltInTool: true,
556 > skipPermission: true,
557 > handler: async (args) => {
558 const shells = shellManager.listShells();
559 const shell = shells[shells.length - 1];
564 return makeSuccessResult('Input sent to shell.');
565 },
567 >
568 > const shutdownTool: Tool<IShutdownShellArgs> = {
569 > name: shellType === 'bash' ? 'bash_shutdown' : `${shellType}_shutdown`,
570 > description: `Stop a ${shellType} shell.`,
571 > parameters: {
572 > type: 'object',
573 > properties: {
574 > shell_id: { type: 'string', description: 'Shell ID to stop (optional; stops latest shell if omitted)' },
575 > },
576 > },
577 > overridesBuiltInTool: true,
578 > skipPermission: true,
579 > handler: (args) => {
580 if (args.shell_id) {
581 const success = shellManager.shutdownShell(args.shell_id);
592 return makeSuccessResult('Shell stopped.');
593 },
595 >
596 > const listTool: Tool<Record<string, never>> = {
597 > name: `list_${shellType}`,
598 > description: `List active ${shellType} shell instances.`,
599 > parameters: { type: 'object', properties: {} },
600 > overridesBuiltInTool: true,
601 > skipPermission: true,
602 > handler: () => {
603 const shells = shellManager.listShells();
604 if (shells.length === 0) {
612 return makeSuccessResult(descriptions.join('\n'));
613 },
615 >
616 > // Stub the *other* SDK built-in so the model can't bypass our override
617 > // (e.g. on Windows still calling `powershell` when Git Bash is configured).
618 > const otherShellType: ShellType = shellType === 'bash' ? 'powershell' : 'bash';
619 > const redirectMessage = `This tool is disabled because the configured shell is ${executable}. Use the \`${shellType}\` tool instead.`;
620 > const redirectTool: Tool<IShellToolArgs> = {
621 > name: otherShellType,
622 > description: redirectMessage,
623 > parameters: {
624 > type: 'object',
625 > properties: {
626 > command: { type: 'string', description: 'The command to execute' },
627 > timeout: { type: 'number', description: 'Timeout in milliseconds (default 120000)' },
628 > },
629 > required: ['command'],
630 > },
631 > overridesBuiltInTool: true,
632 > skipPermission: true,
633 > handler: () => {
634 return makeFailureResult(redirectMessage, 'wrong_shell');
635 },
637 >
638 > return [primaryTool, readTool, writeTool, shutdownTool, listTool, redirectTool];
639 > }
640
641 function isWindowsPowerShell(envShell: string): boolean {
732 }
733
734 > function createGenericDescription(shellType: string, isSandboxEnabled: boolean, networkDomains?: ITerminalSandboxResolvedNetworkDomains): string { copilotShellTools.ts
735 > const parts = [`
736 > Command Execution:
737 > - Use && to chain simple commands on one line
738 > - Prefer pipelines | over temporary files for data flow
739 > - Never create a sub-shell (eg. bash -c "command") unless explicitly asked
740 >
741 > Directory Management:
742 > - Prefer relative paths when navigating directories, only use absolute when the path is far away or the current cwd is not expected
743 > - By default (mode=sync), shell and cwd are reused by subsequent sync commands
744 > - Use $PWD for current directory references
745 > - Consider using pushd/popd for directory stack management
746 > - Supports directory shortcuts like ~ and -
747 >
748 > Program Execution:
749 > - Supports Python, Node.js, and other executables
750 > - Install packages via package managers (brew, apt, etc.)
751 > - Use which or command -v to verify command availability
752 >
753 > Async Mode:
754 > - For long-running tasks (e.g., servers), use mode=async
755 > - Returns a terminal ID for checking status and runtime later
756 >
757 > Use write_${shellType} to send commands or input to a terminal session.`];
758 >
759 > if (isSandboxEnabled) {
760 parts.push(createSandboxLines(networkDomains).join('\n'));
761 }
763 > parts.push(`
764 >
765 > Output Management:
766 > - Output is automatically truncated if longer than 60KB to prevent context overflow
767 > - Use head, tail, grep, awk to filter and limit output size
768 > - For pager commands, disable paging: git --no-pager or add | cat
769 > - Use wc -l to count lines before displaying large outputs
770 >
771 > Best Practices:
772 > - Quote variables: "$var" instead of $var to handle spaces
773 > - Use find with -exec or xargs for file operations
774 > - Be specific with commands to avoid excessive output
775 > - Avoid printing credentials unless absolutely required
776 > - NEVER run sleep or similar wait commands in a terminal. You will be automatically notified on your next turn when async terminal commands or timed-out sync commands complete or need input. Do NOT poll for completion.
777 >
778 > Interactive Input Handling:
779 > - When a terminal command is waiting for interactive input, do NOT suggest alternatives or ask the user whether to proceed. Instead, use the ask_user tool to collect the needed values from the user, then send them.
780 > - Send exactly one answer per prompt using write_${shellType}. Never send multiple answers in a single send.
781 > - After each send, call read_${shellType} to read the next prompt before sending the next answer.
782 > - Continue one prompt at a time until the command finishes.`);
783 >
784 > return parts.join('');
785 > }
786
787 function createBashModelDescription(isSandboxEnabled: boolean, networkDomains?: ITerminalSandboxResolvedNetworkDomains): string {
src/vs/platform/agentHost/node/copilot/agentHostSandboxEngine.ts 13 introduced LOC · 3 ranges

Open complete file

45
46 async getOS(): Promise<OperatingSystem> {
47 > return OS; agentHostSandboxEngine.ts
48 > }
49
50 async getRuntimeInfo(): Promise<ITerminalSandboxRuntimeInfo> {
107
108 getSandboxSetting<T>(settingId: string): T | undefined {
109 > // The agent host stores sandbox settings nested under a single agentHostSandboxEngine.ts
110 > // top-level `sandbox` object with prefix-free sub-keys (e.g.
111 > // `sandbox.enabled` rather than `chat.agent.sandbox.enabled`). Map
112 > // from the engine's modern setting ID into that sub-key namespace;
113 > // unknown IDs (which include all deprecated keys — handled host-side
114 > // by the workbench client) resolve to undefined.
115 > const innerKey = sandboxSettingIdToAgentHostKey[settingId];
116 > if (innerKey === undefined) {
117 return undefined;
118 }
119 > const sandbox = this._agentConfigurationService.getRootValue(sandboxConfigSchema, AgentHostSandboxConfigKey.Sandbox); agentHostSandboxEngine.ts
120 > return sandbox?.[innerKey] as T | undefined;
121 > }
122 }
123