Skip to content

Commit 9b84e7f

Browse files
Merge pull request #6 from stainless-sdks/feat/debugging-worker
Add --debug-workers to support breakpoint workflow with vscode
2 parents df8429c + 138fb4d commit 9b84e7f

20 files changed

Lines changed: 562 additions & 15 deletions

File tree

.vscode/launch.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Attach to AgentEx Worker",
6+
"type": "debugpy",
7+
"request": "attach",
8+
"connect": {
9+
"host": "localhost",
10+
"port": 5678
11+
},
12+
"pathMappings": [
13+
{
14+
"localRoot": "${workspaceFolder}",
15+
"remoteRoot": "."
16+
}
17+
],
18+
"justMyCode": false,
19+
"console": "integratedTerminal"
20+
},
21+
{
22+
"name": "Attach to AgentEx Worker (Port 5679)",
23+
"type": "debugpy",
24+
"request": "attach",
25+
"connect": {
26+
"host": "localhost",
27+
"port": 5679
28+
},
29+
"pathMappings": [
30+
{
31+
"localRoot": "${workspaceFolder}",
32+
"remoteRoot": "."
33+
}
34+
],
35+
"justMyCode": false,
36+
"console": "integratedTerminal"
37+
}
38+
]
39+
}

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,37 @@ asyncio.run(main())
6767

6868
Functionality between the synchronous and asynchronous clients is otherwise identical.
6969

70+
## Debugging
71+
72+
AgentEx provides built-in debugging support for **temporal projects** during local development.
73+
74+
```bash
75+
# Basic debugging
76+
uv run agentex agents run --manifest manifest.yaml --debug-worker
77+
78+
# Wait for debugger to attach before starting
79+
uv run agentex agents run --manifest manifest.yaml --debug-worker --wait-for-debugger
80+
81+
# Custom debug port
82+
uv run agentex agents run --manifest manifest.yaml --debug-worker --debug-port 5679
83+
```
84+
85+
For **VS Code**, add this configuration to `.vscode/launch.json`:
86+
87+
```json
88+
{
89+
"name": "Attach to AgentEx Worker",
90+
"type": "debugpy",
91+
"request": "attach",
92+
"connect": { "host": "localhost", "port": 5678 },
93+
"pathMappings": [{ "localRoot": "${workspaceFolder}", "remoteRoot": "." }],
94+
"justMyCode": false,
95+
"console": "integratedTerminal"
96+
}
97+
```
98+
99+
The debug server automatically finds an available port starting from 5678 and prints connection details when starting.
100+
70101
### With aiohttp
71102

72103
By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.

examples/tutorials/10_agentic/10_temporal/000_hello_acp/project/run_worker.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import asyncio
2-
import os
32

43
from agentex.lib.core.temporal.activities import get_all_activities
54
from agentex.lib.core.temporal.workers.worker import AgentexWorker
65
from agentex.lib.utils.logging import make_logger
6+
from agentex.lib.utils.debug import setup_debug_if_enabled
77
from agentex.lib.environment_variables import EnvironmentVariables
88

99
from workflow import At000HelloAcpWorkflow
@@ -15,6 +15,9 @@
1515

1616

1717
async def main():
18+
# Setup debug mode if enabled
19+
setup_debug_if_enabled()
20+
1821
task_queue_name = environment_variables.WORKFLOW_TASK_QUEUE
1922
if task_queue_name is None:
2023
raise ValueError("WORKFLOW_TASK_QUEUE is not set")

examples/tutorials/10_agentic/10_temporal/000_hello_acp/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dev = [
1919
"black",
2020
"isort",
2121
"flake8",
22+
"debugpy>=1.8.15",
2223
]
2324

2425
[tool.hatch.build.targets.wheel]

examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/run_worker.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from agentex.lib.core.temporal.activities import get_all_activities
44
from agentex.lib.core.temporal.workers.worker import AgentexWorker
55
from agentex.lib.utils.logging import make_logger
6+
from agentex.lib.utils.debug import setup_debug_if_enabled
67
from agentex.lib.environment_variables import EnvironmentVariables
78

89
from workflow import At010AgentChatWorkflow
@@ -15,6 +16,9 @@
1516

1617

1718
async def main():
19+
# Setup debug mode if enabled
20+
setup_debug_if_enabled()
21+
1822
task_queue_name = environment_variables.WORKFLOW_TASK_QUEUE
1923
if task_queue_name is None:
2024
raise ValueError("WORKFLOW_TASK_QUEUE is not set")

examples/tutorials/10_agentic/10_temporal/010_agent_chat/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ readme = "README.md"
1010
requires-python = ">=3.12"
1111
dependencies = [
1212
"agentex-sdk",
13+
"debugpy>=1.8.15",
1314
"scale-gp",
1415
]
1516

@@ -30,4 +31,4 @@ target-version = ['py312']
3031

3132
[tool.isort]
3233
profile = "black"
33-
line_length = 88
34+
line_length = 88

examples/tutorials/10_agentic/10_temporal/020_state_machine/project/run_worker.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from agentex.lib.core.temporal.activities import get_all_activities
44
from agentex.lib.core.temporal.workers.worker import AgentexWorker
55
from agentex.lib.utils.logging import make_logger
6+
from agentex.lib.utils.debug import setup_debug_if_enabled
67
from agentex.lib.environment_variables import EnvironmentVariables
78

89
from workflow import At020StateMachineWorkflow
@@ -14,6 +15,9 @@
1415

1516

1617
async def main():
18+
# Setup debug mode if enabled
19+
setup_debug_if_enabled()
20+
1721
task_queue_name = environment_variables.WORKFLOW_TASK_QUEUE
1822
if task_queue_name is None:
1923
raise ValueError("WORKFLOW_TASK_QUEUE is not set")

examples/tutorials/10_agentic/10_temporal/020_state_machine/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dev = [
1919
"black",
2020
"isort",
2121
"flake8",
22+
"debugpy>=1.8.15",
2223
]
2324

2425
[tool.hatch.build.targets.wheel]

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ dependencies = [
3838
"pytest>=8.4.0",
3939
"pytest-asyncio>=1.0.0",
4040
"scale-gp-beta==0.1.0a20",
41-
"ipykernel>=6.29.5",
41+
"ipykernel>=6.29.5",
4242
]
4343
requires-python = ">= 3.12,<4"
4444
classifiers = [
@@ -86,6 +86,7 @@ dev-dependencies = [
8686
"rich>=13.7.1",
8787
"nest_asyncio==1.6.0",
8888
"pytest-xdist>=3.6.1",
89+
"debugpy>=1.8.15",
8990
]
9091

9192
[tool.rye.scripts]

src/agentex/lib/cli/commands/agents.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
build_agent,
1212
run_agent,
1313
)
14+
from agentex.lib.cli.debug import DebugConfig, DebugMode
1415
from agentex.lib.cli.handlers.cleanup_handlers import cleanup_agent_workflows
1516
from agentex.lib.cli.handlers.deploy_handlers import (
1617
DeploymentError,
@@ -171,7 +172,13 @@ def run(
171172
False,
172173
help="Clean up existing workflows for this agent before starting"
173174
),
174-
):
175+
# Debug options
176+
debug: bool = typer.Option(False, help="Enable debug mode for both worker and ACP (disables auto-reload)"),
177+
debug_worker: bool = typer.Option(False, help="Enable debug mode for temporal worker only"),
178+
debug_acp: bool = typer.Option(False, help="Enable debug mode for ACP server only"),
179+
debug_port: int = typer.Option(5678, help="Port for remote debugging (worker uses this, ACP uses port+1)"),
180+
wait_for_debugger: bool = typer.Option(False, help="Wait for debugger to attach before starting"),
181+
) -> None:
175182
"""
176183
Run an agent locally from the given manifest.
177184
"""
@@ -196,8 +203,35 @@ def run(
196203
console.print(f"[yellow]⚠ Pre-run cleanup failed: {str(e)}[/yellow]")
197204
logger.warning(f"Pre-run cleanup failed: {e}")
198205

206+
# Create debug configuration based on CLI flags
207+
debug_config = None
208+
if debug or debug_worker or debug_acp:
209+
# Determine debug mode
210+
if debug:
211+
mode = DebugMode.BOTH
212+
elif debug_worker and debug_acp:
213+
mode = DebugMode.BOTH
214+
elif debug_worker:
215+
mode = DebugMode.WORKER
216+
elif debug_acp:
217+
mode = DebugMode.ACP
218+
else:
219+
mode = DebugMode.NONE
220+
221+
debug_config = DebugConfig(
222+
enabled=True,
223+
mode=mode,
224+
port=debug_port,
225+
wait_for_attach=wait_for_debugger,
226+
auto_port=False # Use fixed port to match VS Code launch.json
227+
)
228+
229+
console.print(f"[blue]🐛 Debug mode enabled: {mode.value}[/blue]")
230+
if wait_for_debugger:
231+
console.print("[yellow]⏳ Processes will wait for debugger attachment[/yellow]")
232+
199233
try:
200-
run_agent(manifest_path=manifest)
234+
run_agent(manifest_path=manifest, debug_config=debug_config)
201235
except Exception as e:
202236
typer.echo(f"Error running agent: {str(e)}", err=True)
203237
logger.exception("Error running agent")

0 commit comments

Comments
 (0)