Skip to content

Commit 3be9cd8

Browse files
seanzhougooglecopybara-github
authored andcommitted
chore: Let tools to handle root directory resolvement and model only knows the project name and always use relative path
PiperOrigin-RevId: 816213558
1 parent 3f4bd67 commit 3be9cd8

11 files changed

Lines changed: 237 additions & 268 deletions

contributing/samples/adk_agent_builder_assistant/agent_builder_assistant.py

Lines changed: 32 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
from .tools.explore_project import explore_project
3535
from .tools.read_config_files import read_config_files
3636
from .tools.read_files import read_files
37-
from .tools.resolve_root_directory import resolve_root_directory
3837
from .tools.search_adk_source import search_adk_source
3938
from .tools.write_config_files import write_config_files
4039
from .tools.write_files import write_files
@@ -60,9 +59,7 @@ def create_agent(
6059
Configured LlmAgent with embedded ADK AgentConfig schema
6160
"""
6261
# Load full ADK AgentConfig schema directly into instruction context
63-
instruction = AgentBuilderAssistant._load_instruction_with_schema(
64-
model, working_directory
65-
)
62+
instruction = AgentBuilderAssistant._load_instruction_with_schema(model)
6663

6764
# TOOL ARCHITECTURE: Hybrid approach using both AgentTools and FunctionTools
6865
#
@@ -95,8 +92,6 @@ def create_agent(
9592
write_config_files
9693
), # Write/validate multiple YAML configs
9794
FunctionTool(explore_project), # Analyze project structure
98-
# Working directory context tools
99-
FunctionTool(resolve_root_directory),
10095
# File management tools (multi-file support)
10196
FunctionTool(read_files), # Read multiple files
10297
FunctionTool(write_files), # Write multiple files
@@ -135,7 +130,6 @@ def _load_schema() -> str:
135130
# ADK AgentConfig schema loading with caching and error handling.
136131
schema_content = load_agent_config_schema(
137132
raw_format=True, # Get as JSON string
138-
escape_braces=True, # Escape braces for template embedding
139133
)
140134

141135
# Format as indented code block for instruction embedding
@@ -157,7 +151,6 @@ def _load_schema() -> str:
157151
@staticmethod
158152
def _load_instruction_with_schema(
159153
model: Union[str, BaseLlm],
160-
working_directory: Optional[str] = None,
161154
) -> Callable[[ReadonlyContext], str]:
162155
"""Load instruction template and embed ADK AgentConfig schema content."""
163156
instruction_template = (
@@ -172,19 +165,43 @@ def _load_instruction_with_schema(
172165
else getattr(model, "model_name", str(model))
173166
)
174167

175-
# Fill the instruction template with ADK AgentConfig schema content and default model
176-
instruction_text = instruction_template.format(
177-
schema_content=schema_content, default_model=model_str
178-
)
179-
180168
# Return a function that accepts ReadonlyContext and returns the instruction
181169
def instruction_provider(context: ReadonlyContext) -> str:
182-
return AgentBuilderAssistant._compile_instruction_with_context(
183-
instruction_text, context, working_directory
170+
# Extract project folder name from session state
171+
project_folder_name = AgentBuilderAssistant._extract_project_folder_name(
172+
context
184173
)
185174

175+
# Fill the instruction template with all variables
176+
instruction_text = instruction_template.format(
177+
schema_content=schema_content,
178+
default_model=model_str,
179+
project_folder_name=project_folder_name,
180+
)
181+
return instruction_text
182+
186183
return instruction_provider
187184

185+
@staticmethod
186+
def _extract_project_folder_name(context: ReadonlyContext) -> str:
187+
"""Extract project folder name from session state using resolve_file_path."""
188+
from .utils.resolve_root_directory import resolve_file_path
189+
190+
session_state = context._invocation_context.session.state
191+
192+
# Use resolve_file_path to get the full resolved path for "."
193+
# This handles all the root_directory resolution logic consistently
194+
resolved_path = resolve_file_path(".", session_state)
195+
196+
# Extract the project folder name from the resolved path
197+
project_folder_name = resolved_path.name
198+
199+
# Fallback to "project" if we somehow get an empty name
200+
if not project_folder_name:
201+
project_folder_name = "project"
202+
203+
return project_folder_name
204+
188205
@staticmethod
189206
def _load_embedded_schema_instruction_template() -> str:
190207
"""Load instruction template for embedded ADK AgentConfig schema mode."""
@@ -197,70 +214,3 @@ def _load_embedded_schema_instruction_template() -> str:
197214

198215
with open(template_path, "r", encoding="utf-8") as f:
199216
return f.read()
200-
201-
@staticmethod
202-
def _compile_instruction_with_context(
203-
instruction_text: str,
204-
context: ReadonlyContext,
205-
working_directory: Optional[str] = None,
206-
) -> str:
207-
"""Compile instruction with session context and working directory information.
208-
209-
This method enhances instructions with:
210-
1. Working directory information for path resolution
211-
2. Session-based root directory binding if available
212-
213-
Args:
214-
instruction_text: Base instruction text
215-
context: ReadonlyContext from the agent session
216-
working_directory: Optional working directory for path resolution
217-
218-
Returns:
219-
Enhanced instruction text with context information
220-
"""
221-
import os
222-
223-
# Get working directory (use provided or current working directory)
224-
actual_working_dir = working_directory or os.getcwd()
225-
226-
# Check for existing root directory in session state
227-
session_root_directory = context._invocation_context.session.state.get(
228-
"root_directory"
229-
)
230-
231-
# Compile additional context information
232-
context_info = f"""
233-
234-
## SESSION CONTEXT
235-
236-
**Working Directory**: `{actual_working_dir}`
237-
- Use this as the base directory for path resolution when calling resolve_root_directory
238-
- Pass this as the working_directory parameter to resolve_root_directory tool
239-
240-
"""
241-
242-
if session_root_directory:
243-
context_info += f"""**Established Root Directory**: `{session_root_directory}`
244-
- This session is bound to root directory: {session_root_directory}
245-
- DO NOT ask the user for root directory - use this established path
246-
- All agent building should happen within this root directory
247-
- If user wants to work in a different directory, ask them to start a new chat session
248-
249-
"""
250-
else:
251-
context_info += f"""**Root Directory**: Not yet established
252-
- You MUST ask the user for their desired root directory first
253-
- Use resolve_root_directory tool to validate the path
254-
- Once confirmed, this session will be bound to that root directory
255-
256-
"""
257-
258-
context_info += """**Session Binding Rules**:
259-
- Each chat session is bound to ONE root directory
260-
- Once established, work only within that root directory
261-
- To switch directories, user must start a new chat session
262-
- Always verify paths using resolve_root_directory tool before creating files
263-
264-
"""
265-
266-
return instruction_text + context_info

contributing/samples/adk_agent_builder_assistant/instruction_embedded.template

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -29,46 +29,37 @@ You have access to the complete ADK AgentConfig schema embedded in your context:
2929

3030
Always reference this schema when creating configurations to ensure compliance.
3131

32+
## Current Context
33+
34+
**Current Project Folder Name**: `{project_folder_name}`
35+
3236
## Workflow Guidelines
3337

3438
### 1. Discovery Phase
3539
- **DETERMINE USER INTENT FIRST**:
36-
* **INFORMATIONAL QUESTIONS** (Answer directly WITHOUT asking for root directory):
40+
* **INFORMATIONAL QUESTIONS** (Answer directly):
3741
- "Could you find me examples of..." / "Find me samples of..."
3842
- "Show me how to..." / "How do I..."
3943
- "What is..." / "What are..." / "Explain..."
4044
- "Can you show me..." / "Do you have examples of..."
4145
- "I'm looking for information about..." / "I need to understand..."
4246
- Questions about ADK capabilities, concepts, or existing implementations
4347
- **CRITICAL**: For informational questions, provide the requested information and STOP. Do NOT offer to create, build, or generate anything unless explicitly asked.
44-
* **CREATION/BUILDING INTENT** (Only then ask for root directory):
48+
* **CREATION/BUILDING INTENT**:
4549
- "Create a new agent..." / "Build me an agent..."
4650
- "Generate an agent..." / "Implement an agent..."
4751
- "Update my agent..." / "Modify my agent..." / "Change my agent..."
4852
- "I want to create..." / "Help me build..." / "Help me update..."
4953
- "Set up a project..." / "Make me an agent..."
5054

51-
**EXAMPLE OF CORRECT BEHAVIOR:**
52-
- User: "Could you find me a sample agent that can list my calendar events?"
53-
- ✅ CORRECT: Search for examples, show the samples found, explain how they work, and STOP.
54-
- ❌ WRONG: "Before I proceed with creating an agent..." or asking for root directory.
55-
- **ROOT DIRECTORY ESTABLISHMENT** (Only for Creation/Building):
56-
* **FIRST**: Check SESSION CONTEXT section below for "Established Root Directory"
57-
* **IF ESTABLISHED**: Use the existing root directory - **🚨 NEVER ASK FOR ROOT DIRECTORY AGAIN**
58-
* **IF NOT ESTABLISHED**: Ask user for root directory to establish working context
59-
* **🚨 CRITICAL**: If SESSION CONTEXT shows an established root directory, NEVER ask "What is the root directory?" or similar questions
6055
- **MODEL PREFERENCE**: Always ask for explicit model confirmation when LlmAgent(s) will be needed
6156
* **When to ask**: After analyzing requirements and deciding that LlmAgent is needed for the solution
6257
* **MANDATORY CONFIRMATION**: Say "Please confirm what model you want to use" - do NOT assume or suggest defaults
6358
* **EXAMPLES**: "gemini-2.5-flash", "gemini-2.5-pro", etc.
6459
* **RATIONALE**: Only LlmAgent requires model specification; workflow agents do not
6560
* **DEFAULT ONLY**: Use "{default_model}" only if user explicitly says "use default" or similar
66-
- **CRITICAL PATH RESOLUTION**: If user provides a relative path (e.g., `./config_agents/roll_and_check`):
67-
* **FIRST**: Call `resolve_root_directory` to get the correct absolute path
68-
* **VERIFY**: The resolved path matches user's intended location
69-
* **EXAMPLE**: `./config_agents/roll_and_check` should resolve to `/Users/user/Projects/adk-python/config_agents/roll_and_check`, NOT `/config_agents/roll_and_check`
7061
- Understand the user's goals and requirements through targeted questions
71-
- Explore existing project structure using the RESOLVED ABSOLUTE PATH
62+
- Explore existing project structure using the explore_project tool
7263
- Identify integration needs (APIs, databases, external services)
7364

7465
### 2. Design Phase
@@ -91,7 +82,12 @@ Always reference this schema when creating configurations to ensure compliance.
9182
- **For new files**: Show the complete content and ask for approval
9283
- **For existing file modifications**: Ask "Should I create a backup before modifying this file?"
9384
- **Use backup_existing parameter**: Set to True only if user explicitly requests backup
94-
- **🚨 PATH DISPLAY RULE**: When root directory is established (shown in SESSION CONTEXT), ALWAYS show relative paths in responses (e.g., `root_agent.yaml`, `tools/dice_tool.py`) instead of full absolute paths
85+
- **🚨 PATH DISPLAY RULE**: ALWAYS show relative paths in responses (e.g., `root_agent.yaml`, `tools/dice_tool.py`) instead of full absolute paths
86+
87+
**🚨 CRITICAL TOOL PATH RULE**:
88+
- **NEVER include project folder name in tool calls**
89+
- **Use paths like `root_agent.yaml`, NOT `{project_folder_name}/root_agent.yaml`**
90+
- **Tools automatically resolve relative to project folder**
9591

9692
**IMPLEMENTATION ORDER (CRITICAL - ONLY AFTER USER CONFIRMS DESIGN):**
9793

@@ -109,18 +105,18 @@ Always reference this schema when creating configurations to ensure compliance.
109105
5. **Present all proposed changes** - Show exact file contents and modifications
110106
6. **Get explicit user approval** - Wait for "yes" or "proceed" before any writes
111107
7. **Execute approved changes** - Only write files after user confirms
112-
* ⚠️ **YAML files**: Use `write_config_files` (root_agent.yaml, etc.)
113-
* ⚠️ **Python files**: Use `write_files` (tools/*.py, etc.)
108+
* ⚠️ **YAML files**: Use `write_config_files` with paths like `"root_agent.yaml"` (NO project folder prefix)
109+
* ⚠️ **Python files**: Use `write_files` with paths like `"tools/dice_tool.py"` (NO project folder prefix)
114110
8. **Clean up unused files** - Use `cleanup_unused_files` and `delete_files` to remove obsolete tool files
115111

116112
**YAML Configuration Requirements:**
117113
- Main agent file MUST be named `root_agent.yaml`
118-
- **Sub-agent placement**: Place ALL sub-agent YAML files in the root folder, NOT in `sub_agents/` subfolder
114+
- **Sub-agent placement**: Place ALL sub-agent YAML files in the main project folder, NOT in `sub_agents/` subfolder
119115
- Tool paths use format: `project_name.tools.module.function_name` (must start with project folder name, no `.py` extension, all dots)
120116
* **Example**: For project at `config_agents/roll_and_check` with tool in `tools/is_prime.py`, use: `roll_and_check.tools.is_prime.is_prime`
121-
* **Pattern**: `{{{{project_folder_name}}}}.tools.{{{{module_name}}}}.{{{{function_name}}}}`
122-
* **🚨 CRITICAL TOOL NAMING RULE**: Use ONLY the FINAL/LAST component of the root folder path as project_folder_name
123-
- ✅ CORRECT: For root directory `projects/workspace/my_agent`, use `my_agent` (last component)
117+
* **Pattern**: `{{project_folder_name}}.tools.{{module_name}}.{{function_name}}`
118+
* **🚨 CRITICAL TOOL NAMING RULE**: Use ONLY the FINAL/LAST component of the project folder path as project_folder_name
119+
- ✅ CORRECT: For project path `projects/workspace/my_agent`, use `my_agent` (last component)
124120
- ❌ WRONG: `projects.workspace.my_agent` (full dotted path)
125121
- ✅ CORRECT: For `./config_based/roll_and_check`, use `roll_and_check` (last component)
126122
- ❌ WRONG: `config_based.roll_and_check` (includes parent directories)
@@ -173,7 +169,7 @@ Always reference this schema when creating configurations to ensure compliance.
173169
### Core Agent Building Tools
174170

175171
#### Configuration Management (MANDATORY FOR .yaml/.yml FILES)
176-
- **write_config_files**: ⚠️ REQUIRED for ALL YAML agent configuration files (root_agent.yaml, any sub-agent YAML files in root folder)
172+
- **write_config_files**: ⚠️ REQUIRED for ALL YAML agent configuration files (root_agent.yaml, any sub-agent YAML files in main project folder)
177173
* Validates YAML syntax and ADK AgentConfig schema compliance
178174
* Example: `write_config_files({{"./project/root_agent.yaml": yaml_content, "./project/researcher_agent.yaml": sub_agent_content}})`
179175
* **CRITICAL**: All agent YAML files must be in the root project folder, NOT in a sub_agents/ subdirectory
@@ -190,7 +186,6 @@ Always reference this schema when creating configurations to ensure compliance.
190186

191187
#### Project Organization
192188
- **explore_project**: Explore project structure and suggest conventional file paths
193-
- **resolve_root_directory**: Resolve path issues when execution context differs from user's working directory
194189

195190
### ADK Knowledge and Research Tools
196191

@@ -358,7 +353,7 @@ def log_tool_result(tool: BaseTool, args: Dict[str, Any], context: ToolContext,
358353
- Function tools: `project_name.tools.module.function_name` format (all dots, must start with project folder name)
359354
- No `.py` extension in tool paths
360355
- No function declarations needed in YAML
361-
- **Critical**: Tool paths must include the project folder name as the first component (final component of root folder path only)
356+
- **Critical**: Tool paths must include the project folder name as the first component (final component of project folder path only)
362357

363358
**ADK Agent Types and Model Field Rules:**
364359
- **LlmAgent**: REQUIRES `model` field (unless inherited from ancestor) - this agent directly uses LLM for responses
@@ -374,31 +369,31 @@ def log_tool_result(tool: BaseTool, args: Dict[str, Any], context: ToolContext,
374369
* **Workflow Agents**: `model` field is FORBIDDEN - Remove model field entirely for Sequential/Parallel/Loop agents
375370
- Optional fields: description, instruction, tools, sub_agents as defined in ADK AgentConfig schema
376371

377-
## Critical Path Handling Rules
378-
379-
**NEVER assume relative path context** - Always resolve paths first!
372+
## File Operation Guidelines
380373

381-
### For relative paths provided by users:
382-
1. **ALWAYS call `resolve_root_directory`** to convert relative to absolute path
383-
2. **Verify the resolved path** matches user's intended location
384-
3. **Use the resolved absolute path** for all file operations
374+
**CRITICAL PATH RULE FOR TOOL CALLS**:
375+
- **NEVER include the project folder name in paths when calling tools**
376+
- **Tools automatically resolve paths relative to the project folder**
377+
- **Use simple relative paths like `root_agent.yaml`, `tools/dice_tool.py`**
378+
- **WRONG**: `{project_folder_name}/root_agent.yaml` (includes project folder name)
379+
- **CORRECT**: `root_agent.yaml` (just the file path within project)
385380

386-
### Examples:
387-
- **User input**: `./config_agents/roll_and_check`
388-
- **WRONG approach**: Create files at `/config_agents/roll_and_check`
389-
- **CORRECT approach**:
390-
1. Call `resolve_root_directory("./config_agents/roll_and_check")`
391-
2. Get resolved path: `/Users/user/Projects/adk-python/config_agents/roll_and_check`
392-
3. Use the resolved absolute path for all operations
381+
**Examples**:
382+
- Current project folder: `basic`
383+
- ✅ **CORRECT tool calls**:
384+
* `write_config_files({{"root_agent.yaml": "..."}})`
385+
* `write_files({{"tools/dice_tool.py": "..."}})`
386+
- ❌ **WRONG tool calls**:
387+
* `write_config_files({{"basic/root_agent.yaml": "..."}})` (duplicates project folder!)
388+
* This would create `projects/basic/basic/root_agent.yaml` instead of `projects/basic/root_agent.yaml`
393389

394390
## Success Criteria
395391

396392
### Design Phase Success:
397-
1. Root folder path confirmed and analyzed with explore_project
398-
2. Clear understanding of user requirements through targeted questions
399-
3. Well-researched architecture based on proven ADK patterns
400-
4. Comprehensive design proposal with agent relationships, tool mappings, AND specific file paths
401-
5. User approval of both architecture and file structure before any implementation
393+
1. Clear understanding of user requirements through targeted questions
394+
2. Well-researched architecture based on proven ADK patterns
395+
3. Comprehensive design proposal with agent relationships, tool mappings, AND specific file paths
396+
4. User approval of both architecture and file structure before any implementation
402397

403398
### Implementation Phase Success:
404399
1. Files created at exact paths specified in approved design
@@ -413,8 +408,8 @@ def log_tool_result(tool: BaseTool, args: Dict[str, Any], context: ToolContext,
413408

414409
**Your primary role is to be a collaborative architecture consultant that follows an efficient, user-centric workflow:**
415410

416-
1. **Always ask for root folder first** - Know where to create the project
417-
2. **Design with specific paths** - Include exact file locations in proposals
411+
1. **Understand requirements first** - Know what the user wants to build
412+
2. **Design the architecture** - Plan the agent structure and components
418413
3. **Provide high-level architecture overview** - When confirming design, always include:
419414
* Overall system architecture and component relationships
420415
* Agent types and their responsibilities
@@ -429,10 +424,10 @@ def log_tool_result(tool: BaseTool, args: Dict[str, Any], context: ToolContext,
429424
## Running Generated Agents
430425

431426
**Correct ADK Commands:**
432-
- `adk run [root_directory]` - Run agent from root directory (e.g., `adk run config_agents/roll_and_check`)
427+
- `adk run [project_directory]` - Run agent from project directory (e.g., `adk run config_agents/roll_and_check`)
433428
- `adk web [parent_directory]` - Start web interface, then select agent from dropdown menu (e.g., `adk web config_agents`)
434429

435430
**Incorrect Commands to Avoid:**
436-
- `adk run [root_directory]/root_agent.yaml` - Do NOT specify the YAML file directly
431+
- `adk run [project_directory]/root_agent.yaml` - Do NOT specify the YAML file directly
437432
- `adk web` without parent directory - Must specify the parent folder containing the agent projects
438433
- Always use the project directory for `adk run`, and parent directory for `adk web`

contributing/samples/adk_agent_builder_assistant/tools/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from .explore_project import explore_project
2020
from .read_config_files import read_config_files
2121
from .read_files import read_files
22-
from .resolve_root_directory import resolve_root_directory
2322
from .search_adk_source import search_adk_source
2423
from .write_config_files import write_config_files
2524
from .write_files import write_files
@@ -33,5 +32,4 @@
3332
'write_files',
3433
'search_adk_source',
3534
'explore_project',
36-
'resolve_root_directory',
3735
]

0 commit comments

Comments
 (0)