Skip to content

Commit 450128b

Browse files
SWE Destroyerclaude
andcommitted
Change health check port from 8080 to 5720 and centralize all port constants
- Change HEALTH_CHECK_PORT from generic 8080 to non-standard 5720 - Add DEBUG_PORT, TEMPORAL_ADDRESS, REDIS_URL, AGENTEX_API_BASE_URL to centralized ports.py - Update base_acp_server.py run() to reference ACP_SERVER_PORT constant - Update debug_config.py, debug.py, agents.py CLI to use centralized DEBUG_PORT - Update run_handlers.py to use TEMPORAL_ADDRESS and REDIS_URL from constants - Update tests to reflect new health check port default Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent aca728e commit 450128b

File tree

8 files changed

+102
-72
lines changed

8 files changed

+102
-72
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from agentex import Agentex
1313
from agentex.lib.cli.debug import DebugMode, DebugConfig
1414
from agentex.lib.utils.logging import make_logger
15+
from agentex.lib.constants.ports import DEBUG_PORT as _DEFAULT_DEBUG_PORT
1516
from agentex.lib.cli.utils.cli_utils import handle_questionary_cancellation
1617
from agentex.lib.sdk.config.validation import (
1718
EnvironmentsValidationError,
@@ -269,7 +270,9 @@ def run(
269270
debug: bool = typer.Option(False, help="Enable debug mode for both worker and ACP (disables auto-reload)"),
270271
debug_worker: bool = typer.Option(False, help="Enable debug mode for temporal worker only"),
271272
debug_acp: bool = typer.Option(False, help="Enable debug mode for ACP server only"),
272-
debug_port: int = typer.Option(5678, help="Port for remote debugging (worker uses this, ACP uses port+1)"),
273+
debug_port: int = typer.Option(
274+
_DEFAULT_DEBUG_PORT, help="Port for remote debugging (worker uses this, ACP uses port+1)"
275+
),
273276
wait_for_debugger: bool = typer.Option(False, help="Wait for debugger to attach before starting"),
274277
) -> None:
275278
"""

src/agentex/lib/cli/debug/debug_config.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
import socket
66
from enum import Enum
77

8+
from agentex.lib.constants.ports import DEBUG_PORT as _DEFAULT_DEBUG_PORT
89
from agentex.lib.utils.model_utils import BaseModel
910

1011

1112
class DebugMode(str, Enum):
1213
"""Debug mode options"""
14+
1315
WORKER = "worker"
1416
ACP = "acp"
1517
BOTH = "both"
@@ -18,91 +20,91 @@ class DebugMode(str, Enum):
1820

1921
class DebugConfig(BaseModel):
2022
"""Configuration for debug mode"""
21-
23+
2224
enabled: bool = False
2325
mode: DebugMode = DebugMode.NONE
24-
port: int = 5678
26+
port: int = _DEFAULT_DEBUG_PORT
2527
wait_for_attach: bool = False
2628
auto_port: bool = True # Automatically find available port if specified port is busy
27-
29+
2830
@classmethod
2931
def create_worker_debug(
30-
cls,
31-
port: int = 5678,
32+
cls,
33+
port: int = _DEFAULT_DEBUG_PORT,
3234
wait_for_attach: bool = False,
33-
auto_port: bool = True
35+
auto_port: bool = True,
3436
) -> "DebugConfig":
3537
"""Create debug config for worker debugging"""
3638
return cls(
3739
enabled=True,
3840
mode=DebugMode.WORKER,
3941
port=port,
4042
wait_for_attach=wait_for_attach,
41-
auto_port=auto_port
43+
auto_port=auto_port,
4244
)
43-
45+
4446
@classmethod
4547
def create_acp_debug(
46-
cls,
47-
port: int = 5679,
48+
cls,
49+
port: int = _DEFAULT_DEBUG_PORT + 1,
4850
wait_for_attach: bool = False,
49-
auto_port: bool = True
51+
auto_port: bool = True,
5052
) -> "DebugConfig":
5153
"""Create debug config for ACP debugging"""
5254
return cls(
5355
enabled=True,
5456
mode=DebugMode.ACP,
5557
port=port,
5658
wait_for_attach=wait_for_attach,
57-
auto_port=auto_port
59+
auto_port=auto_port,
5860
)
59-
61+
6062
@classmethod
6163
def create_both_debug(
62-
cls,
63-
worker_port: int = 5678,
64-
_acp_port: int = 5679,
64+
cls,
65+
worker_port: int = _DEFAULT_DEBUG_PORT,
66+
_acp_port: int = _DEFAULT_DEBUG_PORT + 1,
6567
wait_for_attach: bool = False,
66-
auto_port: bool = True
68+
auto_port: bool = True,
6769
) -> "DebugConfig":
6870
"""Create debug config for both worker and ACP debugging"""
6971
return cls(
7072
enabled=True,
7173
mode=DebugMode.BOTH,
7274
port=worker_port, # Primary port for worker
7375
wait_for_attach=wait_for_attach,
74-
auto_port=auto_port
76+
auto_port=auto_port,
7577
)
76-
78+
7779
def should_debug_worker(self) -> bool:
7880
"""Check if worker should be debugged"""
7981
return self.enabled and self.mode in (DebugMode.WORKER, DebugMode.BOTH)
80-
82+
8183
def should_debug_acp(self) -> bool:
8284
"""Check if ACP should be debugged"""
8385
return self.enabled and self.mode in (DebugMode.ACP, DebugMode.BOTH)
84-
86+
8587
def get_worker_port(self) -> int:
8688
"""Get port for worker debugging"""
8789
return self.port
88-
90+
8991
def get_acp_port(self) -> int:
9092
"""Get port for ACP debugging"""
9193
if self.mode == DebugMode.BOTH:
9294
return self.port + 1 # Use port + 1 for ACP when debugging both
9395
return self.port
9496

9597

96-
def find_available_port(start_port: int = 5678, max_attempts: int = 10) -> int:
98+
def find_available_port(start_port: int = _DEFAULT_DEBUG_PORT, max_attempts: int = 10) -> int:
9799
"""Find an available port starting from start_port"""
98100
for port in range(start_port, start_port + max_attempts):
99101
try:
100102
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
101-
s.bind(('localhost', port))
103+
s.bind(("localhost", port))
102104
return port
103105
except OSError:
104106
continue
105-
107+
106108
# If we can't find an available port, just return the start port
107109
# and let the debug server handle the error
108110
return start_port
@@ -112,4 +114,4 @@ def resolve_debug_port(config: DebugConfig, target_port: int) -> int:
112114
"""Resolve the actual port to use for debugging"""
113115
if config.auto_port:
114116
return find_available_port(target_port)
115-
return target_port
117+
return target_port

src/agentex/lib/cli/handlers/run_handlers.py

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
# Import debug functionality
1212
from agentex.lib.cli.debug import DebugConfig, start_acp_server_debug, start_temporal_worker_debug
1313
from agentex.lib.utils.logging import make_logger
14+
from agentex.lib.constants.ports import (
15+
REDIS_URL as _DEFAULT_REDIS_URL,
16+
TEMPORAL_ADDRESS as _DEFAULT_TEMPORAL_ADDRESS,
17+
)
1418
from agentex.lib.cli.utils.path_utils import (
1519
get_file_paths,
1620
calculate_uvicorn_target_for_local,
@@ -94,16 +98,16 @@ async def start_temporal_worker_with_reload(
9498
worker_process = await start_temporal_worker(worker_path, env, manifest_dir)
9599
process_manager.add_process(worker_process)
96100
return asyncio.create_task(stream_process_output(worker_process, "WORKER"))
97-
101+
98102
async def worker_runner() -> None:
99103
current_process: asyncio.subprocess.Process | None = None
100104
output_task: asyncio.Task[None] | None = None
101-
105+
102106
console.print(f"[blue]Starting Temporal worker with auto-reload from {worker_path}...[/blue]")
103-
107+
104108
async def start_worker() -> asyncio.subprocess.Process:
105109
nonlocal current_process, output_task
106-
110+
107111
# PRE-RESTART CLEANUP - NEW!
108112
if current_process is not None:
109113
# Extract agent name from worker path for cleanup
@@ -112,7 +116,7 @@ async def start_worker() -> asyncio.subprocess.Process:
112116
console.print(f"FOUND AGENT_NAME FROM ENV VARS: {agent_name} {agent_name is None}")
113117
if agent_name is None:
114118
agent_name = worker_path.parent.parent.name
115-
119+
116120
# Perform cleanup if configured
117121
if should_cleanup_on_restart():
118122
console.print("[yellow]Cleaning up workflows before worker restart...[/yellow]")
@@ -121,7 +125,7 @@ async def start_worker() -> asyncio.subprocess.Process:
121125
except Exception as e:
122126
logger.warning(f"Cleanup failed: {e}")
123127
console.print(f"[yellow]⚠ Cleanup failed: {str(e)}[/yellow]")
124-
128+
125129
# Clean up previous process
126130
if current_process and current_process.returncode is None:
127131
current_process.terminate()
@@ -130,41 +134,41 @@ async def start_worker() -> asyncio.subprocess.Process:
130134
except asyncio.TimeoutError:
131135
current_process.kill()
132136
await current_process.wait()
133-
137+
134138
# Cancel previous output task
135139
if output_task:
136140
output_task.cancel()
137141
try:
138142
await output_task
139143
except asyncio.CancelledError:
140144
pass
141-
145+
142146
current_process = await start_temporal_worker(worker_path, env, manifest_dir)
143147
process_manager.add_process(current_process)
144148
console.print("[green]Temporal worker started[/green]")
145149
return current_process
146-
150+
147151
try:
148152
# Start initial worker
149153
current_process = await start_worker()
150154
if current_process:
151155
output_task = asyncio.create_task(stream_process_output(current_process, "WORKER"))
152-
156+
153157
# Watch for file changes
154158
async for changes in awatch(manifest_dir, recursive=True):
155159
# Filter for Python files
156-
py_changes = [(change, path) for change, path in changes if str(path).endswith('.py')]
157-
160+
py_changes = [(change, path) for change, path in changes if str(path).endswith(".py")]
161+
158162
if py_changes:
159163
changed_files = [str(Path(path).relative_to(worker_path.parent)) for _, path in py_changes]
160164
console.print(f"[yellow]File changes detected: {changed_files}[/yellow]")
161165
console.print("[yellow]Restarting Temporal worker...[/yellow]")
162-
166+
163167
# Restart worker (with cleanup handled in start_worker)
164168
await start_worker()
165169
if current_process:
166170
output_task = asyncio.create_task(stream_process_output(current_process, "WORKER"))
167-
171+
168172
except asyncio.CancelledError:
169173
# Clean shutdown
170174
if output_task:
@@ -173,7 +177,7 @@ async def start_worker() -> asyncio.subprocess.Process:
173177
await output_task
174178
except asyncio.CancelledError:
175179
pass
176-
180+
177181
if current_process and current_process.returncode is None:
178182
current_process.terminate()
179183
try:
@@ -182,7 +186,7 @@ async def start_worker() -> asyncio.subprocess.Process:
182186
current_process.kill()
183187
await current_process.wait()
184188
raise
185-
189+
186190
return asyncio.create_task(worker_runner())
187191

188192

@@ -192,7 +196,7 @@ async def start_acp_server(
192196
"""Start the ACP server process"""
193197
# Use file path relative to manifest directory if possible
194198
uvicorn_target = calculate_uvicorn_target_for_local(acp_path, manifest_dir)
195-
199+
196200
cmd = [
197201
sys.executable,
198202
"-m",
@@ -296,11 +300,17 @@ async def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = Non
296300
manifest_dir = Path(manifest_path).parent
297301
if debug_config and debug_config.should_debug_acp():
298302
acp_process = await start_acp_server_debug(
299-
file_paths["acp"], manifest.local_development.agent.port, agent_env, debug_config # type: ignore[union-attr]
303+
file_paths["acp"],
304+
manifest.local_development.agent.port,
305+
agent_env,
306+
debug_config, # type: ignore[union-attr]
300307
)
301308
else:
302309
acp_process = await start_acp_server(
303-
file_paths["acp"], manifest.local_development.agent.port, agent_env, manifest_dir # type: ignore[union-attr]
310+
file_paths["acp"],
311+
manifest.local_development.agent.port,
312+
agent_env,
313+
manifest_dir, # type: ignore[union-attr]
304314
)
305315
process_manager.add_process(acp_process)
306316

@@ -313,14 +323,14 @@ async def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = Non
313323
if is_temporal_agent(manifest) and file_paths["worker"]:
314324
if debug_config and debug_config.should_debug_worker():
315325
# In debug mode, start worker without auto-reload to prevent conflicts
316-
worker_process = await start_temporal_worker_debug(
317-
file_paths["worker"], agent_env, debug_config
318-
)
326+
worker_process = await start_temporal_worker_debug(file_paths["worker"], agent_env, debug_config)
319327
process_manager.add_process(worker_process)
320328
worker_task = asyncio.create_task(stream_process_output(worker_process, "WORKER"))
321329
else:
322330
# Normal mode with auto-reload
323-
worker_task = await start_temporal_worker_with_reload(file_paths["worker"], agent_env, process_manager, manifest_dir)
331+
worker_task = await start_temporal_worker_with_reload(
332+
file_paths["worker"], agent_env, process_manager, manifest_dir
333+
)
324334
tasks.append(worker_task)
325335

326336
console.print(
@@ -333,7 +343,7 @@ async def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = Non
333343
await process_manager.wait_for_shutdown()
334344
except KeyboardInterrupt:
335345
console.print("\n[yellow]Received shutdown signal...[/yellow]")
336-
346+
337347
# Cancel output streaming tasks
338348
for task in tasks:
339349
task.cancel()
@@ -351,9 +361,6 @@ async def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = Non
351361
await process_manager.cleanup_processes()
352362

353363

354-
355-
356-
357364
def create_agent_environment(manifest: AgentManifest) -> dict[str, str]:
358365
"""Create environment variables for agent processes without modifying os.environ"""
359366
# Start with current environment
@@ -364,8 +371,8 @@ def create_agent_environment(manifest: AgentManifest) -> dict[str, str]:
364371
# TODO: Combine this logic with the deploy_handlers so that we can reuse the env vars
365372
env_vars = {
366373
"ENVIRONMENT": "development",
367-
"TEMPORAL_ADDRESS": "localhost:7233",
368-
"REDIS_URL": "redis://localhost:6379",
374+
"TEMPORAL_ADDRESS": _DEFAULT_TEMPORAL_ADDRESS,
375+
"REDIS_URL": _DEFAULT_REDIS_URL,
369376
"AGENT_NAME": manifest.agent.name,
370377
"ACP_TYPE": manifest.agent.acp_type,
371378
"ACP_URL": f"http://{manifest.local_development.agent.host_address}", # type: ignore[union-attr]
@@ -377,6 +384,7 @@ def create_agent_environment(manifest: AgentManifest) -> dict[str, str]:
377384

378385
# Add authorization principal if set - for local development, auth is optional
379386
from agentex.lib.cli.utils.auth_utils import _encode_principal_context
387+
380388
encoded_principal = _encode_principal_context(manifest)
381389
if encoded_principal:
382390
env_vars[EnvVarKeys.AUTH_PRINCIPAL_B64] = encoded_principal

src/agentex/lib/constants/ports.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,16 @@
1212
ACP_SERVER_PORT = 8718
1313

1414
# Health check endpoint default port (configurable via HEALTH_CHECK_PORT env var)
15-
HEALTH_CHECK_PORT = 8080
15+
HEALTH_CHECK_PORT = 5720
16+
17+
# Debug server default port (configurable via AGENTEX_DEBUG_PORT env var)
18+
DEBUG_PORT = 5678
19+
20+
# Temporal server default address (configurable via TEMPORAL_ADDRESS env var)
21+
TEMPORAL_ADDRESS = "localhost:7233"
22+
23+
# Default Redis URL (configurable via REDIS_URL env var)
24+
REDIS_URL = "redis://localhost:6379"
25+
26+
# AgentEx API base URL (configurable via AGENTEX_BASE_URL env var)
27+
AGENTEX_API_BASE_URL = f"http://localhost:{AGENTEX_API_PORT}"

src/agentex/lib/sdk/fastacp/base/base_acp_server.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,10 @@ async def async_generator(task_message_content_list: list[TaskMessageContent]):
382382
ACP Server Lifecycle Methods
383383
"""
384384

385-
def run(self, host: str = "0.0.0.0", port: int = 8718, **kwargs):
385+
def run(self, host: str = "0.0.0.0", port: int | None = None, **kwargs):
386386
"""Start the Uvicorn server for async handlers."""
387+
from agentex.lib.constants.ports import ACP_SERVER_PORT
388+
389+
if port is None:
390+
port = ACP_SERVER_PORT
387391
uvicorn.run(self, host=host, port=port, **kwargs)

src/agentex/lib/types/agent_configs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class TemporalConfig(BaseModel):
5555
)
5656
health_check_port: int | None = Field(
5757
default=None,
58-
description="Port for temporal worker health check endpoint. Defaults to 8080 if not specified.",
58+
description="Port for temporal worker health check endpoint. Defaults to HEALTH_CHECK_PORT (5720) if not specified.",
5959
)
6060

6161
@validator("workflows")

0 commit comments

Comments
 (0)