nielsr HF Staff commited on
Commit
55dcdf3
·
1 Parent(s): 49729e3

Add missing import

Browse files
Files changed (2) hide show
  1. agents/MODAL_DEBUGGING.md +17 -12
  2. agents/agent.py +9 -2
agents/MODAL_DEBUGGING.md CHANGED
@@ -37,34 +37,39 @@ os.environ["USE_CWD_AS_PROJECT_ROOT"] = "1"
37
  PROJECT_ROOT = Path(os.getcwd()) if os.environ.get("USE_CWD_AS_PROJECT_ROOT") else SCRIPT_DIR.parent
38
  ```
39
 
40
- ### 4. ✅ Overly Complex ClaudeAgentOptions
41
- Removed unnecessary options that might cause issues:
42
- - Removed `mcp_servers` (Exa MCP server)
43
- - Removed `cwd` parameter
44
- - Removed `stderr` callback
45
- - Removed `max_turns`
46
- - Removed `extra_args={"debug-to-stderr": None}`
47
-
48
- **Simplified to:**
49
  ```python
 
 
 
50
  options = ClaudeAgentOptions(
51
  system_prompt=system_prompt,
52
  permission_mode="bypassPermissions",
53
  settings=settings_path,
 
54
  )
55
  ```
56
 
 
 
 
 
 
57
  ## Working Configuration
58
 
59
  ### modal_agent.py Key Points:
60
  - Python 3.11 (matching working example)
61
  - Correct sys.path order (mounted code takes priority)
62
  - Set `USE_CWD_AS_PROJECT_ROOT=1` before importing agent
63
- - Minimal secrets: just `anthropic` and `github-token`
64
 
65
  ### agent.py Key Points:
66
- - Simple `ClaudeAgentOptions` with just system_prompt, permission_mode, settings
67
  - Dynamic `PROJECT_ROOT` based on environment variable
 
68
 
69
  ## Test Command
70
 
@@ -72,7 +77,7 @@ options = ClaudeAgentOptions(
72
  uv run modal run agents/modal_agent.py --conference-name neurips
73
  ```
74
 
75
- Expected: Multiple messages (50+), web searches, file edits, git operations.
76
 
77
  ## Modal Secrets Required
78
 
 
37
  PROJECT_ROOT = Path(os.getcwd()) if os.environ.get("USE_CWD_AS_PROJECT_ROOT") else SCRIPT_DIR.parent
38
  ```
39
 
40
+ ### 4. ✅ stderr Callback REQUIRED (CRITICAL!)
41
+ **This was the key fix discovered on 2025-12-26:** The `stderr` callback MUST be provided for the SDK to work on Modal. Without it, the async generator only yields the SystemMessage and then exits immediately.
42
+
43
+ **Required configuration:**
 
 
 
 
 
44
  ```python
45
+ def on_stderr(data: str):
46
+ print(f"[stderr] {data.strip()}")
47
+
48
  options = ClaudeAgentOptions(
49
  system_prompt=system_prompt,
50
  permission_mode="bypassPermissions",
51
  settings=settings_path,
52
+ stderr=on_stderr, # REQUIRED for Modal!
53
  )
54
  ```
55
 
56
+ The stderr callback likely helps keep the async event loop properly active in Modal's serverless environment.
57
+
58
+ ### 5. ✅ MCP Servers Disabled
59
+ Exa MCP server causes issues on Modal. Set `DISABLE_EXA_MCP=1` to use the built-in WebSearch tool instead.
60
+
61
  ## Working Configuration
62
 
63
  ### modal_agent.py Key Points:
64
  - Python 3.11 (matching working example)
65
  - Correct sys.path order (mounted code takes priority)
66
  - Set `USE_CWD_AS_PROJECT_ROOT=1` before importing agent
67
+ - Set `DISABLE_EXA_MCP=1` to disable MCP servers
68
 
69
  ### agent.py Key Points:
70
+ - `ClaudeAgentOptions` with system_prompt, permission_mode, settings, AND stderr callback
71
  - Dynamic `PROJECT_ROOT` based on environment variable
72
+ - MCP servers only enabled when not on Modal
73
 
74
  ## Test Command
75
 
 
77
  uv run modal run agents/modal_agent.py --conference-name neurips
78
  ```
79
 
80
+ Expected: Multiple messages (28+), web searches, file edits, git operations.
81
 
82
  ## Modal Secrets Required
83
 
agents/agent.py CHANGED
@@ -25,6 +25,7 @@ from claude_agent_sdk import (
25
  UserMessage,
26
  query,
27
  )
 
28
 
29
  # Script directory for resolving relative paths
30
  SCRIPT_DIR = Path(__file__).parent
@@ -163,10 +164,18 @@ async def find_conference_deadlines(conference_name: str) -> None:
163
 
164
  # Only pass mcp_servers if we have any configured
165
  # Passing empty dict or MCP servers can cause issues in some environments
 
 
 
 
 
 
 
166
  options_kwargs = {
167
  "system_prompt": system_prompt,
168
  "permission_mode": "bypassPermissions",
169
  "settings": settings_path,
 
170
  }
171
  if mcp_servers:
172
  options_kwargs["mcp_servers"] = mcp_servers
@@ -185,8 +194,6 @@ async def find_conference_deadlines(conference_name: str) -> None:
185
 
186
  print(f"Starting agent query with settings: {settings_path}")
187
  print(f"Settings path exists: {Path(settings_path).exists()}")
188
- print(f"System prompt length: {len(system_prompt)}")
189
- print(f"Conference data loaded: {len(conference_data)} characters")
190
 
191
  message_count = 0
192
  try:
 
25
  UserMessage,
26
  query,
27
  )
28
+ from claude_agent_sdk.types import McpHttpServerConfig
29
 
30
  # Script directory for resolving relative paths
31
  SCRIPT_DIR = Path(__file__).parent
 
164
 
165
  # Only pass mcp_servers if we have any configured
166
  # Passing empty dict or MCP servers can cause issues in some environments
167
+
168
+ # IMPORTANT: stderr callback is required for Modal to work correctly!
169
+ # Without it, the SDK only returns SystemMessage (init) and then exits.
170
+ # See agents/MODAL_DEBUGGING.md for details.
171
+ def on_stderr(data: str):
172
+ print(f"[stderr] {data.strip()}")
173
+
174
  options_kwargs = {
175
  "system_prompt": system_prompt,
176
  "permission_mode": "bypassPermissions",
177
  "settings": settings_path,
178
+ "stderr": on_stderr, # Capture stderr to see what Claude Code is doing
179
  }
180
  if mcp_servers:
181
  options_kwargs["mcp_servers"] = mcp_servers
 
194
 
195
  print(f"Starting agent query with settings: {settings_path}")
196
  print(f"Settings path exists: {Path(settings_path).exists()}")
 
 
197
 
198
  message_count = 0
199
  try: