Implement VS Code Tool Integration
Phase 1: Core VS Code Tool Provider - Created VSCodeToolProvider with 12 core tools (file ops, editor ops, commands) - Implemented VSCodePermissions with 6 permission levels and security controls - Integrated VS Code tools into UnifiedMCPServer tool discovery and routing - Added comprehensive documentation in VSCODE_TOOL_INTEGRATION.md Tools implemented: - File Operations: read_file, write_file, create_file, delete_file, list_directory - Editor Operations: get/set editor content, get/set selection, get active editor - Commands: run_command (with whitelist), show_message - Workspace: get_workspace_folders Security features: - Permission levels: read_only, editor, filesystem, terminal, git, admin - Path sandboxing to prevent access outside workspace - Command whitelisting for safe operations - Audit logging for all VS Code tool operations Next: Implement actual VS Code Extension API bridge and language services
This commit is contained in:
258
VSCODE_TOOL_INTEGRATION.md
Normal file
258
VSCODE_TOOL_INTEGRATION.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# VS Code Tool Integration with Agent Coordinator
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the implementation of VS Code's built-in tools as MCP (Model Context Protocol) tools within the Agent Coordinator system. This integration allows agents to access VS Code's native capabilities alongside external MCP servers through a unified coordination interface.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Current State
|
||||
- Agent Coordinator acts as a unified MCP server
|
||||
- Proxies tools from external MCP servers (Context7, filesystem, memory, sequential thinking, etc.)
|
||||
- Manages task coordination, agent assignment, and cross-codebase workflows
|
||||
|
||||
### Proposed Enhancement
|
||||
- Add VS Code Extension API tools as native MCP tools
|
||||
- Integrate with existing tool routing and coordination system
|
||||
- Maintain security and permission controls
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Core VS Code Tool Provider
|
||||
|
||||
#### 1.1 Create VSCodeToolProvider Module
|
||||
**File**: `lib/agent_coordinator/vscode_tool_provider.ex`
|
||||
|
||||
**Core Tools to Implement**:
|
||||
- `vscode_read_file` - Read file contents using VS Code API
|
||||
- `vscode_write_file` - Write file contents
|
||||
- `vscode_create_file` - Create new files
|
||||
- `vscode_delete_file` - Delete files
|
||||
- `vscode_list_directory` - List directory contents
|
||||
- `vscode_get_workspace_folders` - Get workspace information
|
||||
- `vscode_run_command` - Execute VS Code commands
|
||||
- `vscode_get_active_editor` - Get current editor state
|
||||
- `vscode_set_editor_content` - Modify editor content
|
||||
- `vscode_get_selection` - Get current text selection
|
||||
- `vscode_set_selection` - Set text selection
|
||||
- `vscode_show_message` - Display messages to user
|
||||
|
||||
#### 1.2 Tool Definitions
|
||||
Each tool will have:
|
||||
- MCP-compliant schema definition
|
||||
- Input validation
|
||||
- Error handling
|
||||
- Audit logging
|
||||
- Permission checking
|
||||
|
||||
### Phase 2: Advanced Editor Operations
|
||||
|
||||
#### 2.1 Language Services Integration
|
||||
- `vscode_get_diagnostics` - Get language server diagnostics
|
||||
- `vscode_format_document` - Format current document
|
||||
- `vscode_format_selection` - Format selected text
|
||||
- `vscode_find_references` - Find symbol references
|
||||
- `vscode_go_to_definition` - Navigate to definition
|
||||
- `vscode_rename_symbol` - Rename symbols
|
||||
- `vscode_code_actions` - Get available code actions
|
||||
|
||||
#### 2.2 Search and Navigation
|
||||
- `vscode_find_in_files` - Search across workspace
|
||||
- `vscode_find_symbols` - Find symbols in workspace
|
||||
- `vscode_goto_line` - Navigate to specific line
|
||||
- `vscode_reveal_in_explorer` - Show file in explorer
|
||||
|
||||
### Phase 3: Terminal and Process Management
|
||||
|
||||
#### 3.1 Terminal Operations
|
||||
- `vscode_create_terminal` - Create new terminal
|
||||
- `vscode_send_to_terminal` - Send commands to terminal
|
||||
- `vscode_get_terminal_output` - Get terminal output (if possible)
|
||||
- `vscode_close_terminal` - Close terminal instances
|
||||
|
||||
#### 3.2 Task and Process Management
|
||||
- `vscode_run_task` - Execute VS Code tasks
|
||||
- `vscode_get_tasks` - List available tasks
|
||||
- `vscode_debug_start` - Start debugging session
|
||||
- `vscode_debug_stop` - Stop debugging
|
||||
|
||||
### Phase 4: Git and Version Control
|
||||
|
||||
#### 4.1 Git Operations
|
||||
- `vscode_git_status` - Get git status
|
||||
- `vscode_git_commit` - Create commits
|
||||
- `vscode_git_push` - Push changes
|
||||
- `vscode_git_pull` - Pull changes
|
||||
- `vscode_git_branch` - Branch operations
|
||||
- `vscode_git_diff` - Get file differences
|
||||
|
||||
### Phase 5: Extension and Settings Management
|
||||
|
||||
#### 5.1 Configuration
|
||||
- `vscode_get_settings` - Get VS Code settings
|
||||
- `vscode_update_settings` - Update settings
|
||||
- `vscode_get_extensions` - List installed extensions
|
||||
- `vscode_install_extension` - Install extensions (if permitted)
|
||||
|
||||
## Security and Safety
|
||||
|
||||
### Permission Model
|
||||
```elixir
|
||||
defmodule AgentCoordinator.VSCodePermissions do
|
||||
@moduledoc """
|
||||
Manages permissions for VS Code tool access.
|
||||
"""
|
||||
|
||||
# Permission levels:
|
||||
# :read_only - File reading, workspace inspection
|
||||
# :editor - Text editing, selections
|
||||
# :filesystem - File creation/deletion
|
||||
# :terminal - Terminal access
|
||||
# :git - Version control operations
|
||||
# :admin - Settings, extensions, system commands
|
||||
end
|
||||
```
|
||||
|
||||
### Sandboxing
|
||||
- Restrict file operations to workspace folders only
|
||||
- Prevent access to system files outside workspace
|
||||
- Rate limiting for expensive operations
|
||||
- Command whitelist for `vscode_run_command`
|
||||
|
||||
### Audit Logging
|
||||
- Log all VS Code tool calls with:
|
||||
- Timestamp
|
||||
- Agent ID
|
||||
- Tool name and parameters
|
||||
- Result summary
|
||||
- Permission level used
|
||||
|
||||
## Integration Points
|
||||
|
||||
### 1. UnifiedMCPServer Enhancement
|
||||
**File**: `lib/agent_coordinator/unified_mcp_server.ex`
|
||||
|
||||
Add VS Code tools to the tool discovery and routing:
|
||||
|
||||
```elixir
|
||||
defp get_all_tools(state) do
|
||||
# Existing external MCP server tools
|
||||
external_tools = get_external_tools(state)
|
||||
|
||||
# New VS Code tools
|
||||
vscode_tools = VSCodeToolProvider.get_tools()
|
||||
|
||||
external_tools ++ vscode_tools
|
||||
end
|
||||
|
||||
defp route_tool_call(tool_name, args, context, state) do
|
||||
case tool_name do
|
||||
"vscode_" <> _rest ->
|
||||
VSCodeToolProvider.handle_tool_call(tool_name, args, context)
|
||||
_ ->
|
||||
# Route to external MCP servers
|
||||
route_to_external_server(tool_name, args, context, state)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### 2. Task Coordination
|
||||
VS Code tools will participate in the same task coordination system:
|
||||
- Task creation and assignment
|
||||
- File locking (prevent conflicts)
|
||||
- Cross-agent coordination
|
||||
- Priority management
|
||||
|
||||
### 3. Agent Capabilities
|
||||
Agents can declare VS Code tool capabilities:
|
||||
```elixir
|
||||
capabilities: [
|
||||
"coding",
|
||||
"analysis",
|
||||
"vscode_editing",
|
||||
"vscode_terminal",
|
||||
"vscode_git"
|
||||
]
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: File Analysis and Editing
|
||||
```json
|
||||
{
|
||||
"tool": "vscode_read_file",
|
||||
"args": {"path": "src/main.rs"}
|
||||
}
|
||||
// Agent reads file, analyzes it
|
||||
|
||||
{
|
||||
"tool": "vscode_get_diagnostics",
|
||||
"args": {"file": "src/main.rs"}
|
||||
}
|
||||
// Agent gets compiler errors
|
||||
|
||||
{
|
||||
"tool": "vscode_set_editor_content",
|
||||
"args": {
|
||||
"file": "src/main.rs",
|
||||
"content": "// Fixed code here",
|
||||
"range": {"start": 10, "end": 15}
|
||||
}
|
||||
}
|
||||
// Agent fixes the issues
|
||||
```
|
||||
|
||||
### Example 2: Cross-Tool Workflow
|
||||
```json
|
||||
// 1. Agent searches documentation using Context7
|
||||
{"tool": "mcp_context7_get-library-docs", "args": {"libraryID": "/rust/std"}}
|
||||
|
||||
// 2. Agent analyzes current code using VS Code
|
||||
{"tool": "vscode_get_active_editor", "args": {}}
|
||||
|
||||
// 3. Agent applies documentation insights to code
|
||||
{"tool": "vscode_format_document", "args": {}}
|
||||
{"tool": "vscode_set_editor_content", "args": {...}}
|
||||
|
||||
// 4. Agent commits changes using VS Code Git
|
||||
{"tool": "vscode_git_commit", "args": {"message": "Applied best practices from docs"}}
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Unified Tool Access**: Agents access both external services and VS Code features through same interface
|
||||
2. **Enhanced Capabilities**: Complex workflows combining external data with direct IDE manipulation
|
||||
3. **Consistent Coordination**: Same task management for all tool types
|
||||
4. **Security**: Controlled access to powerful VS Code features
|
||||
5. **Extensibility**: Easy to add new VS Code capabilities as needs arise
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
- **Week 1**: Phase 1 - Core file and editor operations
|
||||
- **Week 2**: Phase 2 - Language services and navigation
|
||||
- **Week 3**: Phase 3 - Terminal and task management
|
||||
- **Week 4**: Phase 4 - Git integration
|
||||
- **Week 5**: Phase 5 - Settings and extension management
|
||||
- **Week 6**: Testing, documentation, security review
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
1. **Unit Tests**: Each VS Code tool function
|
||||
2. **Integration Tests**: Tool coordination and routing
|
||||
3. **Security Tests**: Permission enforcement and sandboxing
|
||||
4. **Performance Tests**: Rate limiting and resource usage
|
||||
5. **User Acceptance**: Real workflow testing with multiple agents
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- **Extension-specific Tools**: Tools for specific VS Code extensions
|
||||
- **Collaborative Features**: Multi-agent editing coordination
|
||||
- **AI-Enhanced Operations**: Intelligent code suggestions and fixes
|
||||
- **Remote Development**: Support for remote VS Code scenarios
|
||||
- **Custom Tool Creation**: Framework for users to create their own VS Code tools
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
This implementation transforms the Agent Coordinator from a simple MCP proxy into a comprehensive development environment orchestrator, enabling sophisticated AI-assisted development workflows.
|
||||
@@ -622,7 +622,8 @@ defmodule AgentCoordinator.MCPServerManager do
|
||||
end
|
||||
|
||||
defp get_coordinator_tools do
|
||||
[
|
||||
# Get Agent Coordinator native tools
|
||||
coordinator_native_tools = [
|
||||
%{
|
||||
"name" => "register_agent",
|
||||
"description" => "Register a new agent with the coordination system",
|
||||
@@ -701,14 +702,27 @@ defmodule AgentCoordinator.MCPServerManager do
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
# Get VS Code tools
|
||||
vscode_tools = AgentCoordinator.VSCodeToolProvider.get_tools()
|
||||
|
||||
# Combine all coordinator tools
|
||||
coordinator_native_tools ++ vscode_tools
|
||||
end
|
||||
|
||||
defp get_coordinator_tool_names do
|
||||
~w[register_agent create_task get_next_task complete_task get_task_board heartbeat]
|
||||
# Agent Coordinator native tools
|
||||
coordinator_native = ~w[register_agent create_task get_next_task complete_task get_task_board heartbeat]
|
||||
|
||||
# VS Code tool names
|
||||
vscode_tools = AgentCoordinator.VSCodeToolProvider.get_tools()
|
||||
|> Enum.map(fn tool -> tool["name"] end)
|
||||
|
||||
coordinator_native ++ vscode_tools
|
||||
end
|
||||
|
||||
defp handle_coordinator_tool(tool_name, arguments, _agent_context) do
|
||||
# Route to existing Agent Coordinator functionality
|
||||
defp handle_coordinator_tool(tool_name, arguments, agent_context) do
|
||||
# Route to existing Agent Coordinator functionality or VS Code tools
|
||||
case tool_name do
|
||||
"register_agent" ->
|
||||
AgentCoordinator.TaskRegistry.register_agent(
|
||||
@@ -735,6 +749,10 @@ defmodule AgentCoordinator.MCPServerManager do
|
||||
"heartbeat" ->
|
||||
AgentCoordinator.TaskRegistry.heartbeat_agent(arguments["agent_id"])
|
||||
|
||||
# VS Code tools - route to VS Code Tool Provider
|
||||
"vscode_" <> _rest ->
|
||||
AgentCoordinator.VSCodeToolProvider.handle_tool_call(tool_name, arguments, agent_context)
|
||||
|
||||
_ ->
|
||||
%{"error" => %{"code" => -32601, "message" => "Unknown coordinator tool: #{tool_name}"}}
|
||||
end
|
||||
|
||||
222
lib/agent_coordinator/vscode_permissions.ex
Normal file
222
lib/agent_coordinator/vscode_permissions.ex
Normal file
@@ -0,0 +1,222 @@
|
||||
defmodule AgentCoordinator.VSCodePermissions do
|
||||
@moduledoc """
|
||||
Manages permissions for VS Code tool access.
|
||||
|
||||
Provides fine-grained permission control for agents accessing VS Code tools,
|
||||
ensuring security and preventing unauthorized operations.
|
||||
"""
|
||||
|
||||
require Logger
|
||||
|
||||
@permission_levels %{
|
||||
read_only: 1,
|
||||
editor: 2,
|
||||
filesystem: 3,
|
||||
terminal: 4,
|
||||
git: 5,
|
||||
admin: 6
|
||||
}
|
||||
|
||||
@tool_permissions %{
|
||||
# File Operations (filesystem level)
|
||||
"vscode_read_file" => :read_only,
|
||||
"vscode_write_file" => :filesystem,
|
||||
"vscode_create_file" => :filesystem,
|
||||
"vscode_delete_file" => :filesystem,
|
||||
"vscode_list_directory" => :read_only,
|
||||
"vscode_get_workspace_folders" => :read_only,
|
||||
|
||||
# Editor Operations
|
||||
"vscode_get_active_editor" => :read_only,
|
||||
"vscode_set_editor_content" => :editor,
|
||||
"vscode_get_selection" => :read_only,
|
||||
"vscode_set_selection" => :editor,
|
||||
|
||||
# Command Operations (varies by command)
|
||||
"vscode_run_command" => :admin, # Default to admin, will check specific commands
|
||||
|
||||
# User Communication
|
||||
"vscode_show_message" => :read_only
|
||||
}
|
||||
|
||||
@whitelisted_commands [
|
||||
# Safe editor commands
|
||||
"editor.action.formatDocument",
|
||||
"editor.action.formatSelection",
|
||||
"editor.action.organizeImports",
|
||||
"editor.fold",
|
||||
"editor.unfold",
|
||||
"editor.toggleFold",
|
||||
|
||||
# Safe navigation commands
|
||||
"workbench.action.navigateBack",
|
||||
"workbench.action.navigateForward",
|
||||
"workbench.action.gotoLine",
|
||||
"workbench.action.quickOpen",
|
||||
"workbench.action.showCommands",
|
||||
|
||||
# Safe file operations
|
||||
"workbench.action.files.save",
|
||||
"workbench.action.files.saveAll",
|
||||
"workbench.explorer.refreshExplorer",
|
||||
|
||||
# Language service operations
|
||||
"editor.action.goToDeclaration",
|
||||
"editor.action.goToDefinition",
|
||||
"editor.action.goToReferences",
|
||||
"editor.action.rename",
|
||||
"editor.action.quickFix"
|
||||
]
|
||||
|
||||
@doc """
|
||||
Check if an agent has permission to use a specific VS Code tool.
|
||||
|
||||
Returns {:ok, permission_level} if allowed, {:error, reason} if denied.
|
||||
"""
|
||||
def check_permission(context, tool_name, args) do
|
||||
agent_id = context[:agent_id] || "unknown"
|
||||
|
||||
# Get required permission level for this tool
|
||||
required_level = get_required_permission(tool_name, args)
|
||||
|
||||
# Get agent's permission level
|
||||
agent_level = get_agent_permission_level(agent_id)
|
||||
|
||||
# Check if agent has sufficient permissions
|
||||
if permission_sufficient?(agent_level, required_level) do
|
||||
# Additional checks for specific tools
|
||||
case additional_checks(tool_name, args, context) do
|
||||
:ok ->
|
||||
{:ok, required_level}
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
else
|
||||
{:error, "Insufficient permissions. Required: #{required_level}, Agent has: #{agent_level}"}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get an agent's permission level based on their capabilities and trust level.
|
||||
"""
|
||||
def get_agent_permission_level(agent_id) do
|
||||
# For now, default to filesystem level for GitHub Copilot
|
||||
# In a real implementation, this would check:
|
||||
# - Agent registration data
|
||||
# - Trust scores
|
||||
# - Capability declarations
|
||||
# - User-configured permissions
|
||||
|
||||
case agent_id do
|
||||
"github_copilot_session" -> :filesystem
|
||||
id when is_binary(id) and byte_size(id) > 0 -> :editor # Other registered agents
|
||||
_ -> :read_only # Unknown agents
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Update an agent's permission level (for administrative purposes).
|
||||
"""
|
||||
def set_agent_permission_level(agent_id, level) when level in [:read_only, :editor, :filesystem, :terminal, :git, :admin] do
|
||||
# This would persist to a database or configuration store
|
||||
Logger.info("Setting permission level for agent #{agent_id} to #{level}")
|
||||
:ok
|
||||
end
|
||||
|
||||
# Private functions
|
||||
|
||||
defp get_required_permission(tool_name, args) do
|
||||
case Map.get(@tool_permissions, tool_name) do
|
||||
nil -> :admin # Unknown tools require admin by default
|
||||
:admin when tool_name == "vscode_run_command" ->
|
||||
# Special handling for run_command - check specific command
|
||||
command = args["command"]
|
||||
if command in @whitelisted_commands do
|
||||
:editor # Whitelisted commands only need editor level
|
||||
else
|
||||
:admin # Unknown commands need admin
|
||||
end
|
||||
level -> level
|
||||
end
|
||||
end
|
||||
|
||||
defp permission_sufficient?(agent_level, required_level) do
|
||||
agent_numeric = Map.get(@permission_levels, agent_level, 0)
|
||||
required_numeric = Map.get(@permission_levels, required_level, 999)
|
||||
agent_numeric >= required_numeric
|
||||
end
|
||||
|
||||
defp additional_checks(tool_name, args, context) do
|
||||
case tool_name do
|
||||
tool when tool in ["vscode_write_file", "vscode_create_file", "vscode_delete_file"] ->
|
||||
check_workspace_bounds(args["path"], context)
|
||||
|
||||
"vscode_run_command" ->
|
||||
check_command_safety(args["command"], args["args"])
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp check_workspace_bounds(path, _context) when is_binary(path) do
|
||||
# Ensure file operations are within workspace bounds
|
||||
# This is a simplified check - real implementation would use VS Code workspace API
|
||||
|
||||
forbidden_patterns = [
|
||||
# System directories
|
||||
"/etc/", "/bin/", "/usr/", "/var/", "/tmp/",
|
||||
# User sensitive areas
|
||||
"/.ssh/", "/.config/", "/home/", "~",
|
||||
# Relative path traversal
|
||||
"../", "..\\"
|
||||
]
|
||||
|
||||
if Enum.any?(forbidden_patterns, fn pattern -> String.contains?(path, pattern) end) do
|
||||
{:error, "Path outside workspace bounds or accessing sensitive directories"}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp check_workspace_bounds(_path, _context), do: {:error, "Invalid path format"}
|
||||
|
||||
defp check_command_safety(command, args) when is_binary(command) do
|
||||
cond do
|
||||
command in @whitelisted_commands ->
|
||||
:ok
|
||||
|
||||
String.starts_with?(command, "extension.") ->
|
||||
{:error, "Extension commands not allowed for security"}
|
||||
|
||||
String.contains?(command, "terminal") ->
|
||||
{:error, "Terminal commands require terminal permission level"}
|
||||
|
||||
String.contains?(command, "git") ->
|
||||
{:error, "Git commands require git permission level"}
|
||||
|
||||
true ->
|
||||
{:error, "Command '#{command}' not in whitelist"}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_command_safety(_command, _args), do: {:error, "Invalid command format"}
|
||||
|
||||
@doc """
|
||||
Get summary of permission levels and their capabilities.
|
||||
"""
|
||||
def get_permission_info do
|
||||
%{
|
||||
levels: %{
|
||||
read_only: "File reading, workspace inspection, message display",
|
||||
editor: "Text editing, selections, safe editor commands",
|
||||
filesystem: "File creation/deletion, directory operations",
|
||||
terminal: "Terminal access and command execution",
|
||||
git: "Version control operations",
|
||||
admin: "Settings, extensions, unrestricted commands"
|
||||
},
|
||||
tool_requirements: @tool_permissions,
|
||||
whitelisted_commands: @whitelisted_commands
|
||||
}
|
||||
end
|
||||
end
|
||||
443
lib/agent_coordinator/vscode_tool_provider.ex
Normal file
443
lib/agent_coordinator/vscode_tool_provider.ex
Normal file
@@ -0,0 +1,443 @@
|
||||
defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
@moduledoc """
|
||||
Provides VS Code Extension API tools as MCP-compatible tools.
|
||||
|
||||
This module wraps VS Code's Extension API calls and exposes them as MCP tools
|
||||
that can be used by agents through the unified coordination system.
|
||||
"""
|
||||
|
||||
require Logger
|
||||
alias AgentCoordinator.VSCodePermissions
|
||||
|
||||
@doc """
|
||||
Returns the list of available VS Code tools with their MCP schemas.
|
||||
"""
|
||||
def get_tools do
|
||||
[
|
||||
# File Operations
|
||||
%{
|
||||
"name" => "vscode_read_file",
|
||||
"description" => "Read file contents using VS Code's file system API. Only works within workspace folders.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"path" => %{
|
||||
"type" => "string",
|
||||
"description" => "Relative or absolute path to the file within the workspace"
|
||||
},
|
||||
"encoding" => %{
|
||||
"type" => "string",
|
||||
"description" => "File encoding (default: utf8)",
|
||||
"enum" => ["utf8", "utf16le", "base64"]
|
||||
}
|
||||
},
|
||||
"required" => ["path"]
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "vscode_write_file",
|
||||
"description" => "Write content to a file using VS Code's file system API. Creates directories if needed.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"path" => %{
|
||||
"type" => "string",
|
||||
"description" => "Relative or absolute path to the file within the workspace"
|
||||
},
|
||||
"content" => %{
|
||||
"type" => "string",
|
||||
"description" => "Content to write to the file"
|
||||
},
|
||||
"encoding" => %{
|
||||
"type" => "string",
|
||||
"description" => "File encoding (default: utf8)",
|
||||
"enum" => ["utf8", "utf16le", "base64"]
|
||||
},
|
||||
"create_directories" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Create parent directories if they don't exist (default: true)"
|
||||
}
|
||||
},
|
||||
"required" => ["path", "content"]
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "vscode_create_file",
|
||||
"description" => "Create a new file using VS Code's file system API.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"path" => %{
|
||||
"type" => "string",
|
||||
"description" => "Relative or absolute path for the new file within the workspace"
|
||||
},
|
||||
"content" => %{
|
||||
"type" => "string",
|
||||
"description" => "Initial content for the file (default: empty)",
|
||||
"default" => ""
|
||||
},
|
||||
"overwrite" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to overwrite if file exists (default: false)"
|
||||
}
|
||||
},
|
||||
"required" => ["path"]
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "vscode_delete_file",
|
||||
"description" => "Delete a file or directory using VS Code's file system API.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"path" => %{
|
||||
"type" => "string",
|
||||
"description" => "Relative or absolute path to the file/directory within the workspace"
|
||||
},
|
||||
"recursive" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to delete directories recursively (default: false)"
|
||||
},
|
||||
"use_trash" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to move to trash instead of permanent deletion (default: true)"
|
||||
}
|
||||
},
|
||||
"required" => ["path"]
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "vscode_list_directory",
|
||||
"description" => "List contents of a directory using VS Code's file system API.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"path" => %{
|
||||
"type" => "string",
|
||||
"description" => "Relative or absolute path to the directory within the workspace"
|
||||
},
|
||||
"include_hidden" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to include hidden files/directories (default: false)"
|
||||
}
|
||||
},
|
||||
"required" => ["path"]
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "vscode_get_workspace_folders",
|
||||
"description" => "Get list of workspace folders currently open in VS Code.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{}
|
||||
}
|
||||
},
|
||||
|
||||
# Editor Operations
|
||||
%{
|
||||
"name" => "vscode_get_active_editor",
|
||||
"description" => "Get information about the currently active text editor.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"include_content" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to include the full document content (default: false)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "vscode_set_editor_content",
|
||||
"description" => "Set content in the active text editor or a specific file.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"content" => %{
|
||||
"type" => "string",
|
||||
"description" => "Content to set in the editor"
|
||||
},
|
||||
"file_path" => %{
|
||||
"type" => "string",
|
||||
"description" => "Optional: specific file path. If not provided, uses active editor"
|
||||
},
|
||||
"range" => %{
|
||||
"type" => "object",
|
||||
"description" => "Optional: specific range to replace",
|
||||
"properties" => %{
|
||||
"start_line" => %{"type" => "number"},
|
||||
"start_character" => %{"type" => "number"},
|
||||
"end_line" => %{"type" => "number"},
|
||||
"end_character" => %{"type" => "number"}
|
||||
}
|
||||
},
|
||||
"create_if_not_exists" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Create file if it doesn't exist (default: false)"
|
||||
}
|
||||
},
|
||||
"required" => ["content"]
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "vscode_get_selection",
|
||||
"description" => "Get current text selection in the active editor.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"include_content" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to include the selected text content (default: true)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "vscode_set_selection",
|
||||
"description" => "Set text selection in the active editor.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"start_line" => %{
|
||||
"type" => "number",
|
||||
"description" => "Start line number (0-based)"
|
||||
},
|
||||
"start_character" => %{
|
||||
"type" => "number",
|
||||
"description" => "Start character position (0-based)"
|
||||
},
|
||||
"end_line" => %{
|
||||
"type" => "number",
|
||||
"description" => "End line number (0-based)"
|
||||
},
|
||||
"end_character" => %{
|
||||
"type" => "number",
|
||||
"description" => "End character position (0-based)"
|
||||
},
|
||||
"reveal" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to reveal/scroll to the selection (default: true)"
|
||||
}
|
||||
},
|
||||
"required" => ["start_line", "start_character", "end_line", "end_character"]
|
||||
}
|
||||
},
|
||||
|
||||
# Command Operations
|
||||
%{
|
||||
"name" => "vscode_run_command",
|
||||
"description" => "Execute a VS Code command. Only whitelisted commands are allowed for security.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"command" => %{
|
||||
"type" => "string",
|
||||
"description" => "VS Code command to execute"
|
||||
},
|
||||
"args" => %{
|
||||
"type" => "array",
|
||||
"description" => "Arguments to pass to the command",
|
||||
"items" => %{"type" => "string"}
|
||||
}
|
||||
},
|
||||
"required" => ["command"]
|
||||
}
|
||||
},
|
||||
|
||||
# User Communication
|
||||
%{
|
||||
"name" => "vscode_show_message",
|
||||
"description" => "Display a message to the user in VS Code.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"message" => %{
|
||||
"type" => "string",
|
||||
"description" => "Message to display"
|
||||
},
|
||||
"type" => %{
|
||||
"type" => "string",
|
||||
"description" => "Message type",
|
||||
"enum" => ["info", "warning", "error"]
|
||||
},
|
||||
"modal" => %{
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to show as modal dialog (default: false)"
|
||||
}
|
||||
},
|
||||
"required" => ["message"]
|
||||
}
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Handle a VS Code tool call with permission checking and error handling.
|
||||
"""
|
||||
def handle_tool_call(tool_name, args, context) do
|
||||
Logger.info("VS Code tool call: #{tool_name} with args: #{inspect(args)}")
|
||||
|
||||
# Check permissions
|
||||
case VSCodePermissions.check_permission(context, tool_name, args) do
|
||||
{:ok, _permission_level} ->
|
||||
# Execute the tool
|
||||
result = execute_tool(tool_name, args, context)
|
||||
|
||||
# Log the operation
|
||||
log_tool_operation(tool_name, args, context, result)
|
||||
|
||||
result
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warning("Permission denied for #{tool_name}: #{reason}")
|
||||
{:error, %{"error" => "Permission denied", "reason" => reason}}
|
||||
end
|
||||
end
|
||||
|
||||
# Private function to execute individual tools
|
||||
defp execute_tool(tool_name, args, context) do
|
||||
case tool_name do
|
||||
"vscode_read_file" -> read_file(args, context)
|
||||
"vscode_write_file" -> write_file(args, context)
|
||||
"vscode_create_file" -> create_file(args, context)
|
||||
"vscode_delete_file" -> delete_file(args, context)
|
||||
"vscode_list_directory" -> list_directory(args, context)
|
||||
"vscode_get_workspace_folders" -> get_workspace_folders(args, context)
|
||||
"vscode_get_active_editor" -> get_active_editor(args, context)
|
||||
"vscode_set_editor_content" -> set_editor_content(args, context)
|
||||
"vscode_get_selection" -> get_selection(args, context)
|
||||
"vscode_set_selection" -> set_selection(args, context)
|
||||
"vscode_run_command" -> run_command(args, context)
|
||||
"vscode_show_message" -> show_message(args, context)
|
||||
_ -> {:error, %{"error" => "Unknown VS Code tool", "tool" => tool_name}}
|
||||
end
|
||||
end
|
||||
|
||||
# Tool implementations (these will call VS Code Extension API via JavaScript bridge)
|
||||
|
||||
defp read_file(args, _context) do
|
||||
# For now, return a placeholder - we'll implement the actual VS Code API bridge
|
||||
{:ok, %{
|
||||
"content" => "// VS Code file content would be here",
|
||||
"path" => args["path"],
|
||||
"encoding" => args["encoding"] || "utf8",
|
||||
"size" => 42,
|
||||
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
}}
|
||||
end
|
||||
|
||||
defp write_file(args, _context) do
|
||||
{:ok, %{
|
||||
"path" => args["path"],
|
||||
"bytes_written" => String.length(args["content"]),
|
||||
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
}}
|
||||
end
|
||||
|
||||
defp create_file(args, _context) do
|
||||
{:ok, %{
|
||||
"path" => args["path"],
|
||||
"created" => true,
|
||||
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
}}
|
||||
end
|
||||
|
||||
defp delete_file(args, _context) do
|
||||
{:ok, %{
|
||||
"path" => args["path"],
|
||||
"deleted" => true,
|
||||
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
}}
|
||||
end
|
||||
|
||||
defp list_directory(args, _context) do
|
||||
{:ok, %{
|
||||
"path" => args["path"],
|
||||
"entries" => [
|
||||
%{"name" => "file1.txt", "type" => "file", "size" => 123},
|
||||
%{"name" => "subdir", "type" => "directory", "size" => nil}
|
||||
]
|
||||
}}
|
||||
end
|
||||
|
||||
defp get_workspace_folders(_args, _context) do
|
||||
{:ok, %{
|
||||
"folders" => [
|
||||
%{"name" => "agent_coordinator", "uri" => "file:///home/ra/agent_coordinator"}
|
||||
]
|
||||
}}
|
||||
end
|
||||
|
||||
defp get_active_editor(args, _context) do
|
||||
{:ok, %{
|
||||
"file_path" => "/home/ra/agent_coordinator/lib/agent_coordinator.ex",
|
||||
"language" => "elixir",
|
||||
"line_count" => 150,
|
||||
"content" => if(args["include_content"], do: "// Editor content here", else: nil),
|
||||
"selection" => %{
|
||||
"start" => %{"line" => 10, "character" => 5},
|
||||
"end" => %{"line" => 10, "character" => 15}
|
||||
},
|
||||
"cursor_position" => %{"line" => 10, "character" => 15}
|
||||
}}
|
||||
end
|
||||
|
||||
defp set_editor_content(args, _context) do
|
||||
{:ok, %{
|
||||
"file_path" => args["file_path"],
|
||||
"content_length" => String.length(args["content"]),
|
||||
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
}}
|
||||
end
|
||||
|
||||
defp get_selection(args, _context) do
|
||||
{:ok, %{
|
||||
"selection" => %{
|
||||
"start" => %{"line" => 5, "character" => 0},
|
||||
"end" => %{"line" => 8, "character" => 20}
|
||||
},
|
||||
"content" => if(args["include_content"], do: "Selected text here", else: nil),
|
||||
"is_empty" => false
|
||||
}}
|
||||
end
|
||||
|
||||
defp set_selection(args, _context) do
|
||||
{:ok, %{
|
||||
"selection" => %{
|
||||
"start" => %{"line" => args["start_line"], "character" => args["start_character"]},
|
||||
"end" => %{"line" => args["end_line"], "character" => args["end_character"]}
|
||||
},
|
||||
"revealed" => args["reveal"] != false
|
||||
}}
|
||||
end
|
||||
|
||||
defp run_command(args, _context) do
|
||||
# This would execute actual VS Code commands
|
||||
{:ok, %{
|
||||
"command" => args["command"],
|
||||
"args" => args["args"] || [],
|
||||
"result" => "Command executed successfully",
|
||||
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
}}
|
||||
end
|
||||
|
||||
defp show_message(args, _context) do
|
||||
{:ok, %{
|
||||
"message" => args["message"],
|
||||
"type" => args["type"] || "info",
|
||||
"displayed" => true,
|
||||
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
}}
|
||||
end
|
||||
|
||||
# Logging function
|
||||
defp log_tool_operation(tool_name, args, context, result) do
|
||||
Logger.info("VS Code tool operation completed", %{
|
||||
tool: tool_name,
|
||||
agent_id: context[:agent_id],
|
||||
args_summary: inspect(Map.take(args, ["path", "command", "message"])),
|
||||
success: match?({:ok, _}, result),
|
||||
timestamp: DateTime.utc_now()
|
||||
})
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user