Skip to content

Commit 14b8e7e

Browse files
committed
Adds a tool to the HITL orchestrator agent to allow users to change the active working directory
1 parent eb3082f commit 14b8e7e

5 files changed

Lines changed: 139 additions & 41 deletions

File tree

MaxKernel/hitl_agent/agent.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
unified_test_agent,
3232
validated_test_generation_agent,
3333
)
34-
from hitl_agent.tools.tools import filesystem_tool_r
34+
from hitl_agent.tools.tools import filesystem_tool_r, set_working_directory
3535

3636
# Root orchestration agent
3737
root_agent = CustomLlmAgent(
@@ -56,7 +56,8 @@
5656
autotune_agent, # Step 7: Auto-tune kernel
5757
],
5858
tools=[
59-
filesystem_tool_r
59+
filesystem_tool_r,
60+
set_working_directory,
6061
], # Read-only access - orchestrator delegates writes to sub-agents
6162
instruction=interactive_prompt.PROMPT,
6263
description="Orchestrates the human-in-the-loop kernel generation process with GPU to JAX conversion capability.",

MaxKernel/hitl_agent/prompts/interactive_prompt.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
### Your Capabilities
1111
1212
1. **Filesystem Tool (Read-Only)**: You have a `filesystem_tool` that can **only read and list files** - you cannot write files. All file writing must be delegated to the appropriate sub-agents. Assume that all files you need to read are located in {workdir}. For example, if the user asks to read file `script.py`, you should call the tool with the path `{workdir}/script.py`.
13-
2. **Specialist Sub-Agents**: You have a team of sub-agents you can delegate tasks to:
13+
2. **Set Working Directory Tool**: You have a `set_working_directory` tool that can update the active workspace/working directory path for the session. Use this tool when the user requests to switch, set, or change the active working directory or workspace folder.
14+
3. **Specialist Sub-Agents**: You have a team of sub-agents you can delegate tasks to:
1415
* **PlanKernelAgent**: Creates or revises optimization plans for Pallas kernels. Automatically presents plans to the user with approval options. Use for both new plans ("optimize X") and revisions ("change Y in the plan").
1516
* **ImplementKernelAgent**: Implements a Pallas kernel following an approved plan. Use ONLY after user approves the plan. Automatically asks the user about validation options after completion.
1617
* **ValidateKernelCompilationAgent**: Validates kernel compilation with automatic error fixing and debugging (up to 4 attempts). Use when user requests validation or wants to check compilation.
@@ -33,9 +34,13 @@
3334
* Is it test execution? (e.g., "Run the tests", "Test the kernels")
3435
* Is it profiling? (e.g., "Profile the kernel", "What are the bottlenecks?")
3536
* Is it GPU conversion? (e.g., "Convert CUDA to JAX", "Write JAX from PyTorch")
37+
* Is it setting/changing the workspace or working directory? (e.g., "Change working directory to /path/to/folder", "Set workspace folder to Y")
3638
3739
2. **Execute the Plan**:
3840
41+
* **If the request is to CHANGE/SET the workspace or working directory**:
42+
* **Action**: Call `set_working_directory` tool with the absolute path.
43+
3944
* **If the request is simple explanation** (like "What is a TPU?"):
4045
* **Action**: Delegate to `ExplanationAgent`.
4146
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Filesystem tools configuration for the HITL agent."""
2+
3+
import os
4+
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
5+
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
6+
from mcp import StdioServerParameters
7+
8+
from hitl_agent.config import WORKDIR
9+
10+
# Read-only filesystem tool for orchestration agent (no write access)
11+
filesystem_tool_r = MCPToolset(
12+
connection_params=StdioConnectionParams(
13+
server_params=StdioServerParameters(
14+
command="npx",
15+
args=[
16+
"-y", # Argument for npx to auto-confirm install
17+
"@modelcontextprotocol/server-filesystem@0.5.1",
18+
os.path.abspath(WORKDIR),
19+
],
20+
),
21+
),
22+
# Optional: Filter which tools from the MCP server are exposed
23+
tool_filter=["list_directory", "read_file"],
24+
)
25+
26+
# Read-write filesystem tool for sub-agents
27+
filesystem_tool_rw = MCPToolset(
28+
connection_params=StdioConnectionParams(
29+
server_params=StdioServerParameters(
30+
command="npx",
31+
args=[
32+
"-y", # Argument for npx to auto-confirm install
33+
"@modelcontextprotocol/server-filesystem@0.5.1",
34+
os.path.abspath(WORKDIR),
35+
],
36+
),
37+
),
38+
# Optional: Filter which tools from the MCP server are exposed
39+
tool_filter=["list_directory", "read_file", "write_file"],
40+
)
Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
"""Tool setup for HITL kernel generation agents."""
22

33
import logging
4-
import os
5-
64
from google.adk.models import LlmRequest
75
from google.adk.tools import ToolContext
8-
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
9-
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
106
from google.adk.tools.retrieval.vertex_ai_rag_retrieval import (
117
VertexAiRagRetrieval,
128
)
13-
from mcp import StdioServerParameters
149
from vertexai.preview import rag
1510

16-
from hitl_agent.config import RAG_CORPUS, WORKDIR
11+
from hitl_agent.config import RAG_CORPUS
1712
from hitl_agent.tools.search_api_tool import search_api_tool
13+
from hitl_agent.tools.workspace_tool import set_working_directory
14+
from hitl_agent.tools.filesystem_tools import filesystem_tool_r, filesystem_tool_rw
1815

1916

2017
# Custom VertexAiRagRetrieval that forces function_declarations mode to avoid
@@ -40,38 +37,6 @@ async def process_llm_request(
4037
)
4138

4239

43-
# Read-only filesystem tool for orchestration agent (no write access)
44-
filesystem_tool_r = MCPToolset(
45-
connection_params=StdioConnectionParams(
46-
server_params=StdioServerParameters(
47-
command="npx",
48-
args=[
49-
"-y", # Argument for npx to auto-confirm install
50-
"@modelcontextprotocol/server-filesystem@0.5.1",
51-
os.path.abspath(WORKDIR),
52-
],
53-
),
54-
),
55-
# Optional: Filter which tools from the MCP server are exposed
56-
tool_filter=["list_directory", "read_file"],
57-
)
58-
59-
# Read-write filesystem tool for sub-agents
60-
filesystem_tool_rw = MCPToolset(
61-
connection_params=StdioConnectionParams(
62-
server_params=StdioServerParameters(
63-
command="npx",
64-
args=[
65-
"-y", # Argument for npx to auto-confirm install
66-
"@modelcontextprotocol/server-filesystem@0.5.1",
67-
os.path.abspath(WORKDIR),
68-
],
69-
),
70-
),
71-
# Optional: Filter which tools from the MCP server are exposed
72-
tool_filter=["list_directory", "read_file", "write_file"],
73-
)
74-
7540
# Vertex AI RAG Engine tool
7641
vertex_ai_rag_tool = None
7742
if RAG_CORPUS:
@@ -96,4 +61,5 @@ async def process_llm_request(
9661
"filesystem_tool_rw",
9762
"vertex_ai_rag_tool",
9863
"CompatibleVertexAiRagRetrieval",
64+
"set_working_directory",
9965
]
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""Tool for dynamically updating the active workspace directory."""
2+
3+
import logging
4+
import os
5+
from google.adk.tools import FunctionTool, ToolContext
6+
from google.adk.tools.mcp_tool.mcp_session_manager import MCPSessionManager
7+
8+
import hitl_agent.config as config
9+
from hitl_agent.tools.filesystem_tools import filesystem_tool_r, filesystem_tool_rw
10+
11+
12+
async def set_working_directory_fn(path: str, tool_context: ToolContext) -> str:
13+
"""Set the active workspace/working directory path for the session.
14+
15+
All filesystem tools (list_directory, read_file, write_file) will use
16+
the new path.
17+
18+
Args:
19+
path: The absolute path of the directory.
20+
21+
Returns:
22+
A string containing the operation result description:
23+
- If successful: "Successfully switched working directory to: <abs_path>"
24+
- If failed: "Error: Path '<path>' does not exist." or "Error: Path '<path>' is not a directory."
25+
"""
26+
if not os.path.exists(path):
27+
return f"Error: Path '{path}' does not exist."
28+
if not os.path.isdir(path):
29+
return f"Error: Path '{path}' is not a directory."
30+
31+
abs_path = os.path.abspath(path)
32+
33+
# Update in-memory config variables
34+
config.WORKDIR = abs_path
35+
os.environ["WORKDIR"] = abs_path
36+
37+
# Update .env file
38+
try:
39+
env_path = ".env"
40+
if os.path.exists(env_path):
41+
with open(env_path, "r") as f:
42+
lines = f.readlines()
43+
with open(env_path, "w") as f:
44+
updated = False
45+
for line in lines:
46+
if line.strip().startswith("WORKDIR="):
47+
f.write(f'WORKDIR="{abs_path}"\n')
48+
updated = True
49+
else:
50+
f.write(line)
51+
if not updated:
52+
f.write(f'WORKDIR="{abs_path}"\n')
53+
except Exception as e:
54+
logging.error(f"Failed to update .env: {e}")
55+
56+
# Update active filesystem tools
57+
# Update read-only filesystem tool
58+
params_r = filesystem_tool_r._connection_params
59+
server_params_r = getattr(params_r, "server_params", None) or params_r
60+
if hasattr(server_params_r, "args") and len(server_params_r.args) >= 2:
61+
server_params_r.args[-1] = abs_path
62+
await filesystem_tool_r.close()
63+
filesystem_tool_r._mcp_session_manager = MCPSessionManager(
64+
connection_params=filesystem_tool_r._connection_params,
65+
errlog=filesystem_tool_r._errlog,
66+
sampling_callback=filesystem_tool_r._sampling_callback,
67+
sampling_capabilities=filesystem_tool_r._sampling_capabilities,
68+
)
69+
70+
# Update read-write filesystem tool
71+
params_rw = filesystem_tool_rw._connection_params
72+
server_params_rw = getattr(params_rw, "server_params", None) or params_rw
73+
if hasattr(server_params_rw, "args") and len(server_params_rw.args) >= 2:
74+
server_params_rw.args[-1] = abs_path
75+
await filesystem_tool_rw.close()
76+
filesystem_tool_rw._mcp_session_manager = MCPSessionManager(
77+
connection_params=filesystem_tool_rw._connection_params,
78+
errlog=filesystem_tool_rw._errlog,
79+
sampling_callback=filesystem_tool_rw._sampling_callback,
80+
sampling_capabilities=filesystem_tool_rw._sampling_capabilities,
81+
)
82+
83+
return f"Successfully switched working directory to: {abs_path}"
84+
85+
86+
set_working_directory = FunctionTool(set_working_directory_fn)

0 commit comments

Comments
 (0)