agentex-sdk 0.2.6__py3-none-any.whl → 0.2.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
agentex/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "agentex"
4
- __version__ = "0.2.6" # x-release-please-version
4
+ __version__ = "0.2.7" # x-release-please-version
@@ -8,17 +8,18 @@ logger = make_logger(__name__)
8
8
 
9
9
 
10
10
  class EnvAuth(httpx.Auth):
11
- def __init__(self, header_name="x-agent-identity"):
11
+ def __init__(self, header_name="x-agent-api-key"):
12
12
  self.header_name = header_name
13
13
 
14
14
  def auth_flow(self, request):
15
15
  # This gets called for every request
16
16
  env_vars = EnvironmentVariables.refresh()
17
17
  if env_vars:
18
- agent_id = env_vars.AGENT_ID
19
- if agent_id:
20
- request.headers[self.header_name] = agent_id
21
- logger.info(f"Adding header {self.header_name}:{agent_id}")
18
+ agent_api_key = env_vars.AGENT_API_KEY
19
+ if agent_api_key:
20
+ request.headers[self.header_name] = agent_api_key
21
+ masked_key = agent_api_key[-4:] if agent_api_key and len(agent_api_key) > 4 else "****"
22
+ logger.info(f"Adding header {self.header_name}:{masked_key}")
22
23
  yield request
23
24
 
24
25
 
@@ -11,6 +11,7 @@ from agentex.lib.cli.handlers.agent_handlers import (
11
11
  build_agent,
12
12
  run_agent,
13
13
  )
14
+ from agentex.lib.cli.debug import DebugConfig, DebugMode
14
15
  from agentex.lib.cli.handlers.cleanup_handlers import cleanup_agent_workflows
15
16
  from agentex.lib.cli.handlers.deploy_handlers import (
16
17
  DeploymentError,
@@ -171,7 +172,13 @@ def run(
171
172
  False,
172
173
  help="Clean up existing workflows for this agent before starting"
173
174
  ),
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:
175
182
  """
176
183
  Run an agent locally from the given manifest.
177
184
  """
@@ -196,8 +203,35 @@ def run(
196
203
  console.print(f"[yellow]⚠ Pre-run cleanup failed: {str(e)}[/yellow]")
197
204
  logger.warning(f"Pre-run cleanup failed: {e}")
198
205
 
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
+
199
233
  try:
200
- run_agent(manifest_path=manifest)
234
+ run_agent(manifest_path=manifest, debug_config=debug_config)
201
235
  except Exception as e:
202
236
  typer.echo(f"Error running agent: {str(e)}", err=True)
203
237
  logger.exception("Error running agent")
@@ -0,0 +1,15 @@
1
+ """
2
+ Debug functionality for AgentEx CLI
3
+
4
+ Provides debug support for temporal workers and ACP servers during local development.
5
+ """
6
+
7
+ from .debug_config import DebugConfig, DebugMode
8
+ from .debug_handlers import start_acp_server_debug, start_temporal_worker_debug
9
+
10
+ __all__ = [
11
+ "DebugConfig",
12
+ "DebugMode",
13
+ "start_acp_server_debug",
14
+ "start_temporal_worker_debug",
15
+ ]
@@ -0,0 +1,116 @@
1
+ """
2
+ Debug configuration models for AgentEx CLI debugging.
3
+ """
4
+
5
+ import socket
6
+ from enum import Enum
7
+ from typing import Optional
8
+
9
+ from agentex.lib.utils.model_utils import BaseModel
10
+
11
+
12
+ class DebugMode(str, Enum):
13
+ """Debug mode options"""
14
+ WORKER = "worker"
15
+ ACP = "acp"
16
+ BOTH = "both"
17
+ NONE = "none"
18
+
19
+
20
+ class DebugConfig(BaseModel):
21
+ """Configuration for debug mode"""
22
+
23
+ enabled: bool = False
24
+ mode: DebugMode = DebugMode.NONE
25
+ port: int = 5678
26
+ wait_for_attach: bool = False
27
+ auto_port: bool = True # Automatically find available port if specified port is busy
28
+
29
+ @classmethod
30
+ def create_worker_debug(
31
+ cls,
32
+ port: int = 5678,
33
+ wait_for_attach: bool = False,
34
+ auto_port: bool = True
35
+ ) -> "DebugConfig":
36
+ """Create debug config for worker debugging"""
37
+ return cls(
38
+ enabled=True,
39
+ mode=DebugMode.WORKER,
40
+ port=port,
41
+ wait_for_attach=wait_for_attach,
42
+ auto_port=auto_port
43
+ )
44
+
45
+ @classmethod
46
+ def create_acp_debug(
47
+ cls,
48
+ port: int = 5679,
49
+ wait_for_attach: bool = False,
50
+ auto_port: bool = True
51
+ ) -> "DebugConfig":
52
+ """Create debug config for ACP debugging"""
53
+ return cls(
54
+ enabled=True,
55
+ mode=DebugMode.ACP,
56
+ port=port,
57
+ wait_for_attach=wait_for_attach,
58
+ auto_port=auto_port
59
+ )
60
+
61
+ @classmethod
62
+ def create_both_debug(
63
+ cls,
64
+ worker_port: int = 5678,
65
+ acp_port: int = 5679,
66
+ wait_for_attach: bool = False,
67
+ auto_port: bool = True
68
+ ) -> "DebugConfig":
69
+ """Create debug config for both worker and ACP debugging"""
70
+ return cls(
71
+ enabled=True,
72
+ mode=DebugMode.BOTH,
73
+ port=worker_port, # Primary port for worker
74
+ wait_for_attach=wait_for_attach,
75
+ auto_port=auto_port
76
+ )
77
+
78
+ def should_debug_worker(self) -> bool:
79
+ """Check if worker should be debugged"""
80
+ return self.enabled and self.mode in (DebugMode.WORKER, DebugMode.BOTH)
81
+
82
+ def should_debug_acp(self) -> bool:
83
+ """Check if ACP should be debugged"""
84
+ return self.enabled and self.mode in (DebugMode.ACP, DebugMode.BOTH)
85
+
86
+ def get_worker_port(self) -> int:
87
+ """Get port for worker debugging"""
88
+ return self.port
89
+
90
+ def get_acp_port(self) -> int:
91
+ """Get port for ACP debugging"""
92
+ if self.mode == DebugMode.BOTH:
93
+ return self.port + 1 # Use port + 1 for ACP when debugging both
94
+ return self.port
95
+
96
+
97
+ def find_available_port(start_port: int = 5678, max_attempts: int = 10) -> int:
98
+ """Find an available port starting from start_port"""
99
+ for port in range(start_port, start_port + max_attempts):
100
+ try:
101
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
102
+ s.bind(('localhost', port))
103
+ return port
104
+ except OSError:
105
+ continue
106
+
107
+ # If we can't find an available port, just return the start port
108
+ # and let the debug server handle the error
109
+ return start_port
110
+
111
+
112
+ def resolve_debug_port(config: DebugConfig, target_port: int) -> int:
113
+ """Resolve the actual port to use for debugging"""
114
+ if config.auto_port:
115
+ return find_available_port(target_port)
116
+ return target_port
@@ -0,0 +1,174 @@
1
+ """
2
+ Debug process handlers for AgentEx CLI.
3
+
4
+ Provides debug-enabled versions of ACP server and temporal worker startup.
5
+ """
6
+
7
+ import asyncio
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Dict, TYPE_CHECKING
11
+
12
+ from rich.console import Console
13
+
14
+ if TYPE_CHECKING:
15
+ import asyncio.subprocess
16
+
17
+ from .debug_config import DebugConfig, resolve_debug_port
18
+ from agentex.lib.utils.logging import make_logger
19
+
20
+ logger = make_logger(__name__)
21
+ console = Console()
22
+
23
+
24
+ async def start_temporal_worker_debug(
25
+ worker_path: Path,
26
+ env: Dict[str, str],
27
+ debug_config: DebugConfig
28
+ ):
29
+ """Start temporal worker with debug support"""
30
+
31
+ if not debug_config.should_debug_worker():
32
+ raise ValueError("Debug config is not configured for worker debugging")
33
+
34
+ # Resolve the actual debug port
35
+ debug_port = resolve_debug_port(debug_config, debug_config.get_worker_port())
36
+
37
+ # Add debug environment variables
38
+ debug_env = env.copy()
39
+ debug_env.update({
40
+ "AGENTEX_DEBUG_ENABLED": "true",
41
+ "AGENTEX_DEBUG_PORT": str(debug_port),
42
+ "AGENTEX_DEBUG_WAIT_FOR_ATTACH": str(debug_config.wait_for_attach).lower(),
43
+ "AGENTEX_DEBUG_TYPE": "worker"
44
+ })
45
+
46
+ # Start the worker process
47
+ # For debugging, use absolute path to run_worker.py to run from workspace root
48
+ worker_script = worker_path.parent / "run_worker.py"
49
+ cmd = [sys.executable, str(worker_script)]
50
+
51
+ console.print(f"[blue]🐛 Starting Temporal worker in debug mode[/blue]")
52
+ console.print(f"[yellow]📡 Debug server will listen on port {debug_port}[/yellow]")
53
+ console.print(f"[green]✓ VS Code should connect to: localhost:{debug_port}[/green]")
54
+
55
+ if debug_config.wait_for_attach:
56
+ console.print(f"[yellow]⏳ Worker will wait for debugger to attach[/yellow]")
57
+
58
+ console.print(f"[dim]💡 In your IDE: Attach to localhost:{debug_port}[/dim]")
59
+ console.print(f"[dim]🔧 If connection fails, check that VS Code launch.json uses port {debug_port}[/dim]")
60
+
61
+ return await asyncio.create_subprocess_exec(
62
+ *cmd,
63
+ cwd=Path.cwd(), # Run from current working directory (workspace root)
64
+ env=debug_env,
65
+ stdout=asyncio.subprocess.PIPE,
66
+ stderr=asyncio.subprocess.STDOUT,
67
+ )
68
+
69
+
70
+ async def start_acp_server_debug(
71
+ acp_path: Path,
72
+ port: int,
73
+ env: Dict[str, str],
74
+ debug_config: DebugConfig
75
+ ):
76
+ """Start ACP server with debug support"""
77
+
78
+ if not debug_config.should_debug_acp():
79
+ raise ValueError("Debug config is not configured for ACP debugging")
80
+
81
+ # Resolve the actual debug port
82
+ debug_port = resolve_debug_port(debug_config, debug_config.get_acp_port())
83
+
84
+ # Add debug environment variables
85
+ debug_env = env.copy()
86
+ debug_env.update({
87
+ "AGENTEX_DEBUG_ENABLED": "true",
88
+ "AGENTEX_DEBUG_PORT": str(debug_port),
89
+ "AGENTEX_DEBUG_WAIT_FOR_ATTACH": str(debug_config.wait_for_attach).lower(),
90
+ "AGENTEX_DEBUG_TYPE": "acp"
91
+ })
92
+
93
+ # Disable uvicorn auto-reload in debug mode to prevent conflicts
94
+ cmd = [
95
+ sys.executable,
96
+ "-m",
97
+ "uvicorn",
98
+ f"{acp_path.parent.name}.acp:acp",
99
+ "--port",
100
+ str(port),
101
+ "--host",
102
+ "0.0.0.0",
103
+ # Note: No --reload flag when debugging
104
+ ]
105
+
106
+ console.print(f"[blue]🐛 Starting ACP server in debug mode[/blue]")
107
+ console.print(f"[yellow]📡 Debug server will listen on port {debug_port}[/yellow]")
108
+
109
+ if debug_config.wait_for_attach:
110
+ console.print(f"[yellow]⏳ ACP server will wait for debugger to attach[/yellow]")
111
+
112
+ console.print(f"[dim]💡 In your IDE: Attach to localhost:{debug_port}[/dim]")
113
+
114
+ return await asyncio.create_subprocess_exec(
115
+ *cmd,
116
+ cwd=acp_path.parent.parent,
117
+ env=debug_env,
118
+ stdout=asyncio.subprocess.PIPE,
119
+ stderr=asyncio.subprocess.STDOUT,
120
+ )
121
+
122
+
123
+ def create_debug_startup_script() -> str:
124
+ """Create a Python script snippet for debug initialization"""
125
+ return '''
126
+ import os
127
+ import sys
128
+
129
+ # Debug initialization for AgentEx
130
+ if os.getenv("AGENTEX_DEBUG_ENABLED") == "true":
131
+ try:
132
+ import debugpy
133
+ debug_port = int(os.getenv("AGENTEX_DEBUG_PORT", "5678"))
134
+ debug_type = os.getenv("AGENTEX_DEBUG_TYPE", "unknown")
135
+ wait_for_attach = os.getenv("AGENTEX_DEBUG_WAIT_FOR_ATTACH", "false").lower() == "true"
136
+
137
+ # Configure debugpy
138
+ debugpy.configure(subProcess=False)
139
+ debugpy.listen(debug_port)
140
+
141
+ print(f"🐛 [{debug_type.upper()}] Debug server listening on port {debug_port}")
142
+
143
+ if wait_for_attach:
144
+ print(f"⏳ [{debug_type.upper()}] Waiting for debugger to attach...")
145
+ debugpy.wait_for_client()
146
+ print(f"✅ [{debug_type.upper()}] Debugger attached!")
147
+ else:
148
+ print(f"📡 [{debug_type.upper()}] Ready for debugger attachment")
149
+
150
+ except ImportError:
151
+ print("❌ debugpy not available. Install with: pip install debugpy")
152
+ sys.exit(1)
153
+ except Exception as e:
154
+ print(f"❌ Debug setup failed: {e}")
155
+ sys.exit(1)
156
+ '''
157
+
158
+
159
+ def inject_debug_code_to_worker_template() -> str:
160
+ """Generate debug code to inject into worker template"""
161
+ return """
162
+ # === DEBUG SETUP (Auto-generated by AgentEx CLI) ===
163
+ """ + create_debug_startup_script() + """
164
+ # === END DEBUG SETUP ===
165
+ """
166
+
167
+
168
+ def inject_debug_code_to_acp_template() -> str:
169
+ """Generate debug code to inject into ACP template"""
170
+ return """
171
+ # === DEBUG SETUP (Auto-generated by AgentEx CLI) ===
172
+ """ + create_debug_startup_script() + """
173
+ # === END DEBUG SETUP ===
174
+ """
@@ -7,6 +7,7 @@ from rich.console import Console
7
7
 
8
8
  from agentex.lib.cli.handlers.run_handlers import RunError
9
9
  from agentex.lib.cli.handlers.run_handlers import run_agent as _run_agent
10
+ from agentex.lib.cli.debug import DebugConfig
10
11
  from agentex.lib.sdk.config.agent_manifest import AgentManifest
11
12
  from agentex.lib.utils.logging import make_logger
12
13
 
@@ -126,7 +127,7 @@ def build_agent(
126
127
  return image_name
127
128
 
128
129
 
129
- def run_agent(manifest_path: str):
130
+ def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = None):
130
131
  """Run an agent locally from the given manifest"""
131
132
  import asyncio
132
133
  import signal
@@ -152,7 +153,7 @@ def run_agent(manifest_path: str):
152
153
  signal.signal(signal.SIGTERM, signal_handler)
153
154
 
154
155
  try:
155
- asyncio.run(_run_agent(manifest_path))
156
+ asyncio.run(_run_agent(manifest_path, debug_config))
156
157
  except KeyboardInterrupt:
157
158
  print("Shutdown completed.")
158
159
  sys.exit(0)
@@ -22,7 +22,7 @@ logger = make_logger(__name__)
22
22
  console = Console()
23
23
 
24
24
  TEMPORAL_WORKER_KEY = "temporal-worker"
25
- AGENTEX_AGENTS_HELM_CHART_VERSION = "0.1.4-v1-beta"
25
+ AGENTEX_AGENTS_HELM_CHART_VERSION = "0.1.6-v1-beta"
26
26
 
27
27
 
28
28
  class InputDeployOverrides(BaseModel):
@@ -204,7 +204,6 @@ def merge_deployment_configs(
204
204
  for pull_secret in manifest.deployment.imagePullSecrets
205
205
  ]
206
206
  helm_values["global"]["imagePullSecrets"] = pull_secrets
207
- # TODO: Remove this once i bump the chart version again
208
207
  helm_values["imagePullSecrets"] = pull_secrets
209
208
 
210
209
  # Apply cluster-specific overrides
@@ -18,6 +18,9 @@ from agentex.lib.cli.utils.path_utils import (
18
18
 
19
19
  from agentex.lib.environment_variables import EnvVarKeys
20
20
  from agentex.lib.sdk.config.agent_manifest import AgentManifest
21
+
22
+ # Import debug functionality
23
+ from agentex.lib.cli.debug import DebugConfig, start_acp_server_debug, start_temporal_worker_debug
21
24
  from agentex.lib.utils.logging import make_logger
22
25
 
23
26
  logger = make_logger(__name__)
@@ -249,7 +252,7 @@ async def stream_process_output(process: asyncio.subprocess.Process, prefix: str
249
252
  logger.debug(f"Output streaming ended for {prefix}: {e}")
250
253
 
251
254
 
252
- async def run_agent(manifest_path: str):
255
+ async def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = None):
253
256
  """Run an agent locally from the given manifest"""
254
257
 
255
258
  # Validate manifest exists
@@ -289,11 +292,16 @@ async def run_agent(manifest_path: str):
289
292
  )
290
293
  )
291
294
 
292
- # Start ACP server
295
+ # Start ACP server (with debug support if enabled)
293
296
  manifest_dir = Path(manifest_path).parent
294
- acp_process = await start_acp_server(
295
- file_paths["acp"], manifest.local_development.agent.port, agent_env, manifest_dir
296
- )
297
+ if debug_config and debug_config.should_debug_acp():
298
+ acp_process = await start_acp_server_debug(
299
+ file_paths["acp"], manifest.local_development.agent.port, agent_env, debug_config
300
+ )
301
+ else:
302
+ acp_process = await start_acp_server(
303
+ file_paths["acp"], manifest.local_development.agent.port, agent_env, manifest_dir
304
+ )
297
305
  process_manager.add_process(acp_process)
298
306
 
299
307
  # Start output streaming for ACP
@@ -301,9 +309,18 @@ async def run_agent(manifest_path: str):
301
309
 
302
310
  tasks = [acp_output_task]
303
311
 
304
- # Start temporal worker if needed
312
+ # Start temporal worker if needed (with debug support if enabled)
305
313
  if is_temporal_agent(manifest) and file_paths["worker"]:
306
- worker_task = await start_temporal_worker_with_reload(file_paths["worker"], agent_env, process_manager)
314
+ if debug_config and debug_config.should_debug_worker():
315
+ # 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
+ )
319
+ process_manager.add_process(worker_process)
320
+ worker_task = asyncio.create_task(stream_process_output(worker_process, "WORKER"))
321
+ else:
322
+ # Normal mode with auto-reload
323
+ worker_task = await start_temporal_worker_with_reload(file_paths["worker"], agent_env, process_manager)
307
324
  tasks.append(worker_task)
308
325
 
309
326
  console.print(
@@ -6,7 +6,6 @@ build-backend = "hatchling.build"
6
6
  name = "{{ project_name }}"
7
7
  version = "0.1.0"
8
8
  description = "{{ description }}"
9
- readme = "README.md"
10
9
  requires-python = ">=3.12"
11
10
  dependencies = [
12
11
  "agentex-sdk",
@@ -6,7 +6,6 @@ build-backend = "hatchling.build"
6
6
  name = "{{ project_name }}"
7
7
  version = "0.1.0"
8
8
  description = "{{ description }}"
9
- readme = "README.md"
10
9
  requires-python = ">=3.12"
11
10
  dependencies = [
12
11
  "agentex-sdk",
@@ -1,4 +1,35 @@
1
1
  import os
2
+ import sys
3
+
4
+ # === DEBUG SETUP (AgentEx CLI Debug Support) ===
5
+ if os.getenv("AGENTEX_DEBUG_ENABLED") == "true":
6
+ try:
7
+ import debugpy
8
+ debug_port = int(os.getenv("AGENTEX_DEBUG_PORT", "5679"))
9
+ debug_type = os.getenv("AGENTEX_DEBUG_TYPE", "acp")
10
+ wait_for_attach = os.getenv("AGENTEX_DEBUG_WAIT_FOR_ATTACH", "false").lower() == "true"
11
+
12
+ # Configure debugpy
13
+ debugpy.configure(subProcess=False)
14
+ debugpy.listen(debug_port)
15
+
16
+ print(f"🐛 [{debug_type.upper()}] Debug server listening on port {debug_port}")
17
+
18
+ if wait_for_attach:
19
+ print(f"⏳ [{debug_type.upper()}] Waiting for debugger to attach...")
20
+ debugpy.wait_for_client()
21
+ print(f"✅ [{debug_type.upper()}] Debugger attached!")
22
+ else:
23
+ print(f"📡 [{debug_type.upper()}] Ready for debugger attachment")
24
+
25
+ except ImportError:
26
+ print("❌ debugpy not available. Install with: pip install debugpy")
27
+ sys.exit(1)
28
+ except Exception as e:
29
+ print(f"❌ Debug setup failed: {e}")
30
+ sys.exit(1)
31
+ # === END DEBUG SETUP ===
32
+
2
33
  from agentex.lib.sdk.fastacp.fastacp import FastACP
3
34
  from agentex.lib.types.fastacp import TemporalACPConfig
4
35
 
@@ -1,9 +1,9 @@
1
1
  import asyncio
2
- import os
3
2
 
4
3
  from agentex.lib.core.temporal.activities import get_all_activities
5
4
  from agentex.lib.core.temporal.workers.worker import AgentexWorker
6
5
  from agentex.lib.utils.logging import make_logger
6
+ from agentex.lib.utils.debug import setup_debug_if_enabled
7
7
  from agentex.lib.environment_variables import EnvironmentVariables
8
8
 
9
9
  from workflow import {{ workflow_class }}
@@ -15,6 +15,9 @@ logger = make_logger(__name__)
15
15
 
16
16
 
17
17
  async def main():
18
+ # Setup debug mode if enabled
19
+ setup_debug_if_enabled()
20
+
18
21
  task_queue_name = environment_variables.WORKFLOW_TASK_QUEUE
19
22
  if task_queue_name is None:
20
23
  raise ValueError("WORKFLOW_TASK_QUEUE is not set")
@@ -6,7 +6,6 @@ build-backend = "hatchling.build"
6
6
  name = "{{ project_name }}"
7
7
  version = "0.1.0"
8
8
  description = "{{ description }}"
9
- readme = "README.md"
10
9
  requires-python = ">=3.12"
11
10
  dependencies = [
12
11
  "agentex-sdk",
@@ -20,6 +19,7 @@ dev = [
20
19
  "black",
21
20
  "isort",
22
21
  "flake8",
22
+ "debugpy>=1.8.15",
23
23
  ]
24
24
 
25
25
  [tool.hatch.build.targets.wheel]
@@ -64,7 +64,7 @@ class ACPService:
64
64
  else:
65
65
  raise ValueError("Either agent_name or agent_id must be provided")
66
66
 
67
- task_entry = Task.model_validate(json_rpc_response["result"])
67
+ task_entry = Task.model_validate(json_rpc_response.result)
68
68
  if span:
69
69
  span.output = task_entry.model_dump()
70
70
  return task_entry
@@ -115,7 +115,7 @@ class ACPService:
115
115
  else:
116
116
  raise ValueError("Either agent_name or agent_id must be provided")
117
117
 
118
- task_message = TaskMessage.model_validate(json_rpc_response["result"])
118
+ task_message = TaskMessage.model_validate(json_rpc_response.result)
119
119
  if span:
120
120
  span.output = task_message.model_dump()
121
121
  return task_message
@@ -147,7 +147,7 @@ class ACPService:
147
147
  agent_name=agent_name,
148
148
  method="event/send",
149
149
  params={
150
- "task_name": task_name,
150
+ "task_id": task_id,
151
151
  "content": cast(TaskMessageContentParam, content.model_dump()),
152
152
  },
153
153
  )
@@ -163,7 +163,7 @@ class ACPService:
163
163
  else:
164
164
  raise ValueError("Either agent_name or agent_id must be provided")
165
165
 
166
- event_entry = Event.model_validate(json_rpc_response["result"])
166
+ event_entry = Event.model_validate(json_rpc_response.result)
167
167
  if span:
168
168
  span.output = event_entry.model_dump()
169
169
  return event_entry
@@ -204,7 +204,7 @@ class ACPService:
204
204
  else:
205
205
  raise ValueError("Either task_name or task_id must be provided")
206
206
 
207
- task_entry = Task.model_validate(json_rpc_response["result"])
207
+ task_entry = Task.model_validate(json_rpc_response.result)
208
208
  if span:
209
209
  span.output = task_entry.model_dump()
210
210
  return task_entry
@@ -24,6 +24,8 @@ from temporalio.worker import (
24
24
  )
25
25
 
26
26
  from agentex.lib.utils.logging import make_logger
27
+ from agentex.lib.utils.registration import register_agent
28
+ from agentex.lib.environment_variables import EnvironmentVariables
27
29
 
28
30
  logger = make_logger(__name__)
29
31
 
@@ -103,9 +105,16 @@ class AgentexWorker:
103
105
  workflow: type,
104
106
  ):
105
107
  await self.start_health_check_server()
108
+ await self._register_agent()
106
109
  temporal_client = await get_temporal_client(
107
110
  temporal_address=os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"),
108
111
  )
112
+
113
+ # Enable debug mode if AgentEx debug is enabled (disables deadlock detection)
114
+ debug_enabled = os.environ.get("AGENTEX_DEBUG_ENABLED", "false").lower() == "true"
115
+ if debug_enabled:
116
+ logger.info("🐛 [WORKER] Temporal debug mode enabled - deadlock detection disabled")
117
+
109
118
  worker = Worker(
110
119
  client=temporal_client,
111
120
  task_queue=self.task_queue,
@@ -115,6 +124,7 @@ class AgentexWorker:
115
124
  workflow_runner=UnsandboxedWorkflowRunner(),
116
125
  max_concurrent_activities=self.max_concurrent_activities,
117
126
  build_id=str(uuid.uuid4()),
127
+ debug_mode=debug_enabled, # Disable deadlock detection in debug mode
118
128
  )
119
129
 
120
130
  logger.info(f"Starting workers for task queue: {self.task_queue}")
@@ -160,3 +170,17 @@ class AgentexWorker:
160
170
  f"Failed to start health check server on alternative port {alt_port}: {e}"
161
171
  )
162
172
  raise
173
+
174
+ """
175
+ Register the worker with the Agentex server.
176
+
177
+ Even though the Temporal server will also register the agent with the server,
178
+ doing this on the worker side is required to make sure that both share the API key
179
+ which is returned on registration and used to authenticate the worker with the Agentex server.
180
+ """
181
+ async def _register_agent(self):
182
+ env_vars = EnvironmentVariables.refresh()
183
+ if env_vars and env_vars.AGENTEX_BASE_URL:
184
+ await register_agent(env_vars)
185
+ else:
186
+ logger.warning("AGENTEX_BASE_URL not set, skipping worker registration")
@@ -23,6 +23,7 @@ class EnvVarKeys(str, Enum):
23
23
  AGENT_NAME = "AGENT_NAME"
24
24
  AGENT_DESCRIPTION = "AGENT_DESCRIPTION"
25
25
  AGENT_ID = "AGENT_ID"
26
+ AGENT_API_KEY = "AGENT_API_KEY"
26
27
  # ACP Configuration
27
28
  ACP_URL = "ACP_URL"
28
29
  ACP_PORT = "ACP_PORT"
@@ -52,6 +53,7 @@ class EnvironmentVariables(BaseModel):
52
53
  AGENT_NAME: str
53
54
  AGENT_DESCRIPTION: str | None = None
54
55
  AGENT_ID: str | None = None
56
+ AGENT_API_KEY: str | None = None
55
57
  ACP_TYPE: str | None = "agentic"
56
58
  # ACP Configuration
57
59
  ACP_URL: str
@@ -1,15 +1,10 @@
1
1
  import asyncio
2
- import base64
3
2
  import inspect
4
- import json
5
- import os
6
3
  from collections.abc import AsyncGenerator, Awaitable, Callable
7
4
  from contextlib import asynccontextmanager
8
5
  from typing import Any
9
6
 
10
- import httpx
11
7
  import uvicorn
12
- from agentex.lib.adk.utils._modules.client import create_async_agentex_client
13
8
  from fastapi import FastAPI, Request
14
9
  from fastapi.responses import StreamingResponse
15
10
  from pydantic import TypeAdapter, ValidationError
@@ -30,6 +25,7 @@ from agentex.lib.types.task_message_updates import StreamTaskMessageFull, TaskMe
30
25
  from agentex.types.task_message_content import TaskMessageContent
31
26
  from agentex.lib.utils.logging import make_logger
32
27
  from agentex.lib.utils.model_utils import BaseModel
28
+ from agentex.lib.utils.registration import register_agent
33
29
 
34
30
  logger = make_logger(__name__)
35
31
 
@@ -74,7 +70,7 @@ class BaseACPServer(FastAPI):
74
70
  async def lifespan_context(app: FastAPI):
75
71
  env_vars = EnvironmentVariables.refresh()
76
72
  if env_vars.AGENTEX_BASE_URL:
77
- await self._register_agent(env_vars)
73
+ await register_agent(env_vars)
78
74
  else:
79
75
  logger.warning("AGENTEX_BASE_URL not set, skipping agent registration")
80
76
 
@@ -101,6 +97,16 @@ class BaseACPServer(FastAPI):
101
97
  data = await request.json()
102
98
  rpc_request = JSONRPCRequest(**data)
103
99
 
100
+ # Check if the request is authenticated
101
+ if refreshed_environment_variables and getattr(refreshed_environment_variables, "AGENT_API_KEY", None):
102
+ authorization_header = request.headers.get("x-agent-api-key")
103
+ if authorization_header != refreshed_environment_variables.AGENT_API_KEY:
104
+ return JSONRPCResponse(
105
+ id=rpc_request.id,
106
+ error=JSONRPCError(code=-32601, message="Unauthorized"),
107
+ )
108
+
109
+
104
110
  # Check if method is valid first
105
111
  try:
106
112
  method = RPCMethod(rpc_request.method)
@@ -345,87 +351,4 @@ class BaseACPServer(FastAPI):
345
351
  """Start the Uvicorn server for async handlers."""
346
352
  uvicorn.run(self, host=host, port=port, **kwargs)
347
353
 
348
- def _get_auth_principal(self, env_vars: EnvironmentVariables):
349
- if not env_vars.AUTH_PRINCIPAL_B64:
350
- return None
351
-
352
- try:
353
- decoded_str = base64.b64decode(env_vars.AUTH_PRINCIPAL_B64).decode('utf-8')
354
- return json.loads(decoded_str)
355
- except Exception:
356
- return None
357
-
358
- async def _register_agent(self, env_vars: EnvironmentVariables):
359
- """Register this agent with the Agentex server"""
360
- # Build the agent's own URL
361
- full_acp_url = f"{env_vars.ACP_URL.rstrip('/')}:{env_vars.ACP_PORT}"
362
-
363
- description = (
364
- env_vars.AGENT_DESCRIPTION
365
- or f"Generic description for agent: {env_vars.AGENT_NAME}"
366
- )
367
-
368
- # Prepare registration data
369
- registration_data = {
370
- "name": env_vars.AGENT_NAME,
371
- "description": description,
372
- "acp_url": full_acp_url,
373
- "acp_type": env_vars.ACP_TYPE,
374
- "principal_context": self._get_auth_principal(env_vars)
375
- }
376
-
377
- if env_vars.AGENT_ID:
378
- registration_data["agent_id"] = env_vars.AGENT_ID
379
-
380
- # Make the registration request
381
- registration_url = f"{env_vars.AGENTEX_BASE_URL.rstrip('/')}/agents/register"
382
- # Retry logic with configurable attempts and delay
383
- max_retries = 3
384
- base_delay = 5 # seconds
385
- last_exception = None
386
-
387
- attempt = 0
388
- while attempt < max_retries:
389
- try:
390
- async with httpx.AsyncClient() as client:
391
- response = await client.post(
392
- registration_url, json=registration_data, timeout=30.0
393
- )
394
- if response.status_code == 200:
395
- agent = response.json()
396
- agent_id, agent_name = agent["id"], agent["name"]
397
-
398
- os.environ["AGENT_ID"] = agent_id
399
- os.environ["AGENT_NAME"] = agent_name
400
- env_vars.AGENT_ID = agent_id
401
- env_vars.AGENT_NAME = agent_name
402
- global refreshed_environment_variables
403
- refreshed_environment_variables = env_vars
404
- logger.info(
405
- f"Successfully registered agent '{env_vars.AGENT_NAME}' with Agentex server with acp_url: {full_acp_url}. Registration data: {registration_data}"
406
- )
407
- return # Success, exit the retry loop
408
- else:
409
- error_msg = f"Failed to register agent. Status: {response.status_code}, Response: {response.text}"
410
- logger.error(error_msg)
411
- last_exception = Exception(
412
- f"Failed to startup agent: {response.text}"
413
- )
414
-
415
- except Exception as e:
416
- logger.error(
417
- f"Exception during agent registration attempt {attempt + 1}: {e}"
418
- )
419
- last_exception = e
420
- attempt += 1
421
- if attempt < max_retries:
422
- delay = (attempt) * base_delay # 5, 10, 15 seconds
423
- logger.info(
424
- f"Retrying in {delay} seconds... (attempt {attempt}/{max_retries})"
425
- )
426
- await asyncio.sleep(delay)
427
-
428
- # If we get here, all retries failed
429
- raise last_exception or Exception(
430
- f"Failed to register agent after {max_retries} attempts"
431
- )
354
+
@@ -0,0 +1,63 @@
1
+ """
2
+ Debug utilities for AgentEx development.
3
+
4
+ Provides debugging setup functionality that can be used across different components.
5
+ """
6
+
7
+ import os
8
+ import debugpy # type: ignore
9
+
10
+
11
+ def setup_debug_if_enabled() -> None:
12
+ """
13
+ Setup debugpy if debug mode is enabled via environment variables.
14
+
15
+ This function checks for AgentEx debug environment variables and configures
16
+ debugpy accordingly. It's designed to be called early in worker startup.
17
+
18
+ Environment Variables:
19
+ AGENTEX_DEBUG_ENABLED: Set to "true" to enable debug mode
20
+ AGENTEX_DEBUG_PORT: Port for debug server (default: 5678)
21
+ AGENTEX_DEBUG_TYPE: Type identifier for logging (default: "worker")
22
+ AGENTEX_DEBUG_WAIT_FOR_ATTACH: Set to "true" to wait for debugger attachment
23
+
24
+ Raises:
25
+ Any exception from debugpy setup (will bubble up naturally)
26
+ """
27
+ if os.getenv("AGENTEX_DEBUG_ENABLED") == "true":
28
+ debug_port = int(os.getenv("AGENTEX_DEBUG_PORT", "5678"))
29
+ debug_type = os.getenv("AGENTEX_DEBUG_TYPE", "worker")
30
+ wait_for_attach = os.getenv("AGENTEX_DEBUG_WAIT_FOR_ATTACH", "false").lower() == "true"
31
+
32
+ # Configure debugpy
33
+ debugpy.configure(subProcess=False)
34
+ debugpy.listen(debug_port)
35
+
36
+ print(f"🐛 [{debug_type.upper()}] Debug server listening on port {debug_port}")
37
+
38
+ if wait_for_attach:
39
+ print(f"⏳ [{debug_type.upper()}] Waiting for debugger to attach...")
40
+ debugpy.wait_for_client()
41
+ print(f"✅ [{debug_type.upper()}] Debugger attached!")
42
+ else:
43
+ print(f"📡 [{debug_type.upper()}] Ready for debugger attachment")
44
+
45
+
46
+ def is_debug_enabled() -> bool:
47
+ """
48
+ Check if debug mode is currently enabled.
49
+
50
+ Returns:
51
+ bool: True if AGENTEX_DEBUG_ENABLED is set to "true"
52
+ """
53
+ return os.getenv("AGENTEX_DEBUG_ENABLED", "false").lower() == "true"
54
+
55
+
56
+ def get_debug_port() -> int:
57
+ """
58
+ Get the debug port from environment variables.
59
+
60
+ Returns:
61
+ int: Debug port (default: 5678)
62
+ """
63
+ return int(os.getenv("AGENTEX_DEBUG_PORT", "5678"))
@@ -0,0 +1,101 @@
1
+ import base64
2
+ import json
3
+ import os
4
+ import httpx
5
+ import asyncio
6
+
7
+ from agentex.lib.environment_variables import EnvironmentVariables, refreshed_environment_variables
8
+ from agentex.lib.utils.logging import make_logger
9
+
10
+ logger = make_logger(__name__)
11
+
12
+ def get_auth_principal(env_vars: EnvironmentVariables):
13
+ if not env_vars.AUTH_PRINCIPAL_B64:
14
+ return None
15
+
16
+ try:
17
+ decoded_str = base64.b64decode(env_vars.AUTH_PRINCIPAL_B64).decode('utf-8')
18
+ return json.loads(decoded_str)
19
+ except Exception:
20
+ return None
21
+
22
+ async def register_agent(env_vars: EnvironmentVariables):
23
+ """Register this agent with the Agentex server"""
24
+ if not env_vars.AGENTEX_BASE_URL:
25
+ logger.warning("AGENTEX_BASE_URL is not set, skipping registration")
26
+ return
27
+ # Build the agent's own URL
28
+ full_acp_url = f"{env_vars.ACP_URL.rstrip('/')}:{env_vars.ACP_PORT}"
29
+
30
+ description = (
31
+ env_vars.AGENT_DESCRIPTION
32
+ or f"Generic description for agent: {env_vars.AGENT_NAME}"
33
+ )
34
+
35
+ # Prepare registration data
36
+ registration_data = {
37
+ "name": env_vars.AGENT_NAME,
38
+ "description": description,
39
+ "acp_url": full_acp_url,
40
+ "acp_type": env_vars.ACP_TYPE,
41
+ "principal_context": get_auth_principal(env_vars)
42
+ }
43
+
44
+ if env_vars.AGENT_ID:
45
+ registration_data["agent_id"] = env_vars.AGENT_ID
46
+
47
+ # Make the registration request
48
+ registration_url = f"{env_vars.AGENTEX_BASE_URL.rstrip('/')}/agents/register"
49
+ # Retry logic with configurable attempts and delay
50
+ max_retries = 3
51
+ base_delay = 5 # seconds
52
+ last_exception = None
53
+
54
+ attempt = 0
55
+ while attempt < max_retries:
56
+ try:
57
+ async with httpx.AsyncClient() as client:
58
+ response = await client.post(
59
+ registration_url, json=registration_data, timeout=30.0
60
+ )
61
+ if response.status_code == 200:
62
+ agent = response.json()
63
+ agent_id, agent_name = agent["id"], agent["name"]
64
+ agent_api_key = agent["agent_api_key"]
65
+
66
+ os.environ["AGENT_ID"] = agent_id
67
+ os.environ["AGENT_NAME"] = agent_name
68
+ os.environ["AGENT_API_KEY"] = agent_api_key
69
+ env_vars.AGENT_ID = agent_id
70
+ env_vars.AGENT_NAME = agent_name
71
+ env_vars.AGENT_API_KEY = agent_api_key
72
+ global refreshed_environment_variables
73
+ refreshed_environment_variables = env_vars
74
+ logger.info(
75
+ f"Successfully registered agent '{env_vars.AGENT_NAME}' with Agentex server with acp_url: {full_acp_url}. Registration data: {registration_data}"
76
+ )
77
+ return # Success, exit the retry loop
78
+ else:
79
+ error_msg = f"Failed to register agent. Status: {response.status_code}, Response: {response.text}"
80
+ logger.error(error_msg)
81
+ last_exception = Exception(
82
+ f"Failed to startup agent: {response.text}"
83
+ )
84
+
85
+ except Exception as e:
86
+ logger.error(
87
+ f"Exception during agent registration attempt {attempt + 1}: {e}"
88
+ )
89
+ last_exception = e
90
+ attempt += 1
91
+ if attempt < max_retries:
92
+ delay = (attempt) * base_delay # 5, 10, 15 seconds
93
+ logger.info(
94
+ f"Retrying in {delay} seconds... (attempt {attempt}/{max_retries})"
95
+ )
96
+ await asyncio.sleep(delay)
97
+
98
+ # If we get here, all retries failed
99
+ raise last_exception or Exception(
100
+ f"Failed to register agent after {max_retries} attempts"
101
+ )
agentex/types/agent.py CHANGED
@@ -1,6 +1,7 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  from typing import Optional
4
+ from datetime import datetime
4
5
  from typing_extensions import Literal
5
6
 
6
7
  from .._models import BaseModel
@@ -16,12 +17,18 @@ class Agent(BaseModel):
16
17
  acp_type: AcpType
17
18
  """The type of the ACP Server (Either sync or agentic)"""
18
19
 
20
+ created_at: datetime
21
+ """The timestamp when the agent was created"""
22
+
19
23
  description: str
20
24
  """The description of the action."""
21
25
 
22
26
  name: str
23
27
  """The unique name of the agent."""
24
28
 
29
+ updated_at: datetime
30
+ """The timestamp when the agent was last updated"""
31
+
25
32
  status: Optional[Literal["Pending", "Building", "Ready", "Failed", "Unknown"]] = None
26
33
  """The status of the action, indicating if it's building, ready, failed, etc."""
27
34
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: agentex-sdk
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Summary: The official Python library for the agentex API
5
5
  Project-URL: Homepage, https://github.com/scaleapi/agentex-python
6
6
  Project-URL: Repository, https://github.com/scaleapi/agentex-python
@@ -126,6 +126,37 @@ asyncio.run(main())
126
126
 
127
127
  Functionality between the synchronous and asynchronous clients is otherwise identical.
128
128
 
129
+ ## Debugging
130
+
131
+ AgentEx provides built-in debugging support for **temporal projects** during local development.
132
+
133
+ ```bash
134
+ # Basic debugging
135
+ uv run agentex agents run --manifest manifest.yaml --debug-worker
136
+
137
+ # Wait for debugger to attach before starting
138
+ uv run agentex agents run --manifest manifest.yaml --debug-worker --wait-for-debugger
139
+
140
+ # Custom debug port
141
+ uv run agentex agents run --manifest manifest.yaml --debug-worker --debug-port 5679
142
+ ```
143
+
144
+ For **VS Code**, add this configuration to `.vscode/launch.json`:
145
+
146
+ ```json
147
+ {
148
+ "name": "Attach to AgentEx Worker",
149
+ "type": "debugpy",
150
+ "request": "attach",
151
+ "connect": { "host": "localhost", "port": 5678 },
152
+ "pathMappings": [{ "localRoot": "${workspaceFolder}", "remoteRoot": "." }],
153
+ "justMyCode": false,
154
+ "console": "integratedTerminal"
155
+ }
156
+ ```
157
+
158
+ The debug server automatically finds an available port starting from 5678 and prints connection details when starting.
159
+
129
160
  ### With aiohttp
130
161
 
131
162
  By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
@@ -11,7 +11,7 @@ agentex/_resource.py,sha256=S1t7wmR5WUvoDIhZjo_x-E7uoTJBynJ3d8tPJMQYdjw,1106
11
11
  agentex/_response.py,sha256=Tb9zazsnemO2rTxWtBjAD5WBqlhli5ZaXGbiKgdu5DE,28794
12
12
  agentex/_streaming.py,sha256=FNGJExRCF-vTRUZHFKUfoAWFhDGOB3XbioVCF37Jr7E,10104
13
13
  agentex/_types.py,sha256=KyKYySGIfHPod2hho1fPxssk5NuVn8C4MeMTtA-lg80,6198
14
- agentex/_version.py,sha256=aolBlxCYy9VLUtx44zgLOoBoWwq2ENVlfc7ry58WRF8,159
14
+ agentex/_version.py,sha256=juL3-lsGG8DrsKnzc0QzewhZCTZuJXw8vQoNFh7Of6g,159
15
15
  agentex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  agentex/_utils/__init__.py,sha256=PNZ_QJuzZEgyYXqkO1HVhGkj5IU9bglVUcw7H-Knjzw,2062
17
17
  agentex/_utils/_logs.py,sha256=LUjFPc3fweSChBUmjhQD8uYmwQAmFMNDuVFKfjYBQfM,777
@@ -25,7 +25,7 @@ agentex/_utils/_typing.py,sha256=D0DbbNu8GnYQTSICnTSHDGsYXj8TcAKyhejb0XcnjtY,460
25
25
  agentex/_utils/_utils.py,sha256=ts4CiiuNpFiGB6YMdkQRh2SZvYvsl7mAF-JWHCcLDf4,12312
26
26
  agentex/lib/.keep,sha256=wuNrz-5SXo3jJaJOJgz4vFHM41YH_g20F5cRQo0vLes,224
27
27
  agentex/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- agentex/lib/environment_variables.py,sha256=80YcUTKR5edoX2yNgajpLdS9dIe_RpHp68jlcbNR5ow,3175
28
+ agentex/lib/environment_variables.py,sha256=cCL7_cKDNuPyUTmuNLZVTDdFnJPmCsDZ5uN23MtZP-k,3248
29
29
  agentex/lib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  agentex/lib/adk/__init__.py,sha256=-PpVfEvYr_HD7TnxUWU8RCW2OnxfwpPxTW97dKTnqvI,1082
31
31
  agentex/lib/adk/_modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -45,21 +45,24 @@ agentex/lib/adk/providers/_modules/openai.py,sha256=QyjujK4JHiATB4xI9CiR67agcRhA
45
45
  agentex/lib/adk/providers/_modules/sgp.py,sha256=QszUPyeGBODfI5maYvlzErD87PsMsX6vrfC7n65WNjE,3224
46
46
  agentex/lib/adk/utils/__init__.py,sha256=7f6ayV0_fqyw5cwzVANNcZWGJZ-vrrYtZ0qi7KKBRFs,130
47
47
  agentex/lib/adk/utils/_modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- agentex/lib/adk/utils/_modules/client.py,sha256=1OltPs65W6B_g8SDAOrbLxmiDqxYodmbq5PtUdBmj-U,847
48
+ agentex/lib/adk/utils/_modules/client.py,sha256=zMBYsPr2zXpSynF2W_5SKOpALtXvS0cTNdcJX93ce1I,974
49
49
  agentex/lib/adk/utils/_modules/templating.py,sha256=wgjkE4uC1gsArK-exyxOOZwp5Yu7ePqviZuyTDlP9m0,3595
50
50
  agentex/lib/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  agentex/lib/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- agentex/lib/cli/commands/agents.py,sha256=PJVkopMLQEg4lOQf-Dvjb_b0TL6qaWTH2dN6_cxRneo,11417
52
+ agentex/lib/cli/commands/agents.py,sha256=ThpiifTcORxe2kHCfw0Cxm7_i--gHHtO8ZsqCSi2UaY,12957
53
53
  agentex/lib/cli/commands/init.py,sha256=JsfusiLTgPu5IAI0MVDR15qA6wx5R2ZowjUJ728GJyQ,8146
54
54
  agentex/lib/cli/commands/main.py,sha256=aDn9xJIIQQD33v3caET_NX-8eBxoWC3QfZGMUgjeGN8,1093
55
55
  agentex/lib/cli/commands/secrets.py,sha256=cVtsqyGGieBVM4dKkbJROmzR_NJRODFngcEbi1Nc92A,5604
56
56
  agentex/lib/cli/commands/tasks.py,sha256=9ARR0VgM2ZZXSFDlMiA_E9RDL2V7Piipp8Fna_OBrKQ,3652
57
57
  agentex/lib/cli/commands/uv.py,sha256=n6nk2F2gPUXrvWOljSN06Y5bOEnhaZH4rulproAJktA,3553
58
+ agentex/lib/cli/debug/__init__.py,sha256=dt_NjaWesD2M5BqtTKswWc23PGA_dC0uR2m61JP_xIc,378
59
+ agentex/lib/cli/debug/debug_config.py,sha256=Gl0rI1WUPwhehyDC0EdLo7S8q9hlBy41ZIu3NBUm6QQ,3415
60
+ agentex/lib/cli/debug/debug_handlers.py,sha256=i2Og0v5MPKIxG0uMZIp4NpmCpAro23t7PLCU4d7EKag,5684
58
61
  agentex/lib/cli/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- agentex/lib/cli/handlers/agent_handlers.py,sha256=ovhnQOa-lAi5g2J3BVutA0vbprsOFe0lt2qw-qIZah4,5470
62
+ agentex/lib/cli/handlers/agent_handlers.py,sha256=iVZ-4TSQJuq7XpPBYjYIN76M33XwxDjQTuNwTzzynec,5573
60
63
  agentex/lib/cli/handlers/cleanup_handlers.py,sha256=V1V0zeErOUGTgCQqjyUl6CWtzGjFW878uzFaLOQJEyQ,7073
61
- agentex/lib/cli/handlers/deploy_handlers.py,sha256=ULiW5hZr1PJ4wOJ1UnOkUpQiZaSDDk5w3BZxdDPMhos,14896
62
- agentex/lib/cli/handlers/run_handlers.py,sha256=2DkaGN27nHcL5pZeoOVdlhttnft_jtVdmv_POgnRASE,13923
64
+ agentex/lib/cli/handlers/deploy_handlers.py,sha256=pwdc-m5-auXzlDA-0-TzAPpIGxsYecPKXryrAIpELTM,14832
65
+ agentex/lib/cli/handlers/run_handlers.py,sha256=b02-ng64fMHdd7u2hB_tmwHrm2_0DL-pcA565JDpyPc,14949
63
66
  agentex/lib/cli/handlers/secret_handlers.py,sha256=VfAdAQovW9tG36Xgk_gGIGwTyFMxR3P6xc7fmAviNA8,24719
64
67
  agentex/lib/cli/templates/default/.dockerignore.j2,sha256=hweGFxw5eDZYsb5EnRHpv27o9M1HF2PEWOxqsfBBcAE,320
65
68
  agentex/lib/cli/templates/default/Dockerfile-uv.j2,sha256=tGJo_C4vwHYikV4QhGFtSiG6K7Nt4UDdJ71Gob_uTho,1109
@@ -67,7 +70,7 @@ agentex/lib/cli/templates/default/Dockerfile.j2,sha256=T7ouO3glVBo7U2I1TPQvgARyx
67
70
  agentex/lib/cli/templates/default/README.md.j2,sha256=4Sn_cY_TMfN_c5h-I_L3TgTrNKUvhzQvKGDZjS3n2Gw,6361
68
71
  agentex/lib/cli/templates/default/dev.ipynb.j2,sha256=8xY82gVfQ0mhzlEZzI4kLqIXCF19YgimLnpEirDMX8I,3395
69
72
  agentex/lib/cli/templates/default/manifest.yaml.j2,sha256=n-XK6LqSyBVY6a7KOfIlOQx4LbMNEVzzHIh6yEiqAhs,3752
70
- agentex/lib/cli/templates/default/pyproject.toml.j2,sha256=9cpTISM7rOoICWejV5GYMEwPn8RUmB6-E7csM1pmSFo,528
73
+ agentex/lib/cli/templates/default/pyproject.toml.j2,sha256=eyN6dYqJTFzb5WztJMxboy9Wc0XPXVnKYaF5JBxJE7o,507
71
74
  agentex/lib/cli/templates/default/requirements.txt.j2,sha256=iTmO-z8qFkUa1jTctFCs0WYuq7Sqi6VNQAwATakh2fQ,94
72
75
  agentex/lib/cli/templates/default/deploy/example.yaml.j2,sha256=sHIEuhtruyCfGPgeLQ1ilCCnRH0HpsqhDdQT44UWUaU,1554
73
76
  agentex/lib/cli/templates/default/project/acp.py.j2,sha256=XZsHNQaQDNvooarFt_NvM8rLQ-rpc_knKkNTPnRxtM4,1136
@@ -79,7 +82,7 @@ agentex/lib/cli/templates/sync/Dockerfile.j2,sha256=T7ouO3glVBo7U2I1TPQvgARyxXGL
79
82
  agentex/lib/cli/templates/sync/README.md.j2,sha256=_S7Ngl4qOUQHPFldLXDBvuIWPFU2-WcuxGmr5EXLX6k,8816
80
83
  agentex/lib/cli/templates/sync/dev.ipynb.j2,sha256=Z42iRveuI_k5LcJqWX-3H1glPtNTkxg_MKVe1lwuJos,6055
81
84
  agentex/lib/cli/templates/sync/manifest.yaml.j2,sha256=V497KXzvA76sHrgIJ5zRJptpIH8sGbSXZaIsEyp5NZ4,3747
82
- agentex/lib/cli/templates/sync/pyproject.toml.j2,sha256=9cpTISM7rOoICWejV5GYMEwPn8RUmB6-E7csM1pmSFo,528
85
+ agentex/lib/cli/templates/sync/pyproject.toml.j2,sha256=eyN6dYqJTFzb5WztJMxboy9Wc0XPXVnKYaF5JBxJE7o,507
83
86
  agentex/lib/cli/templates/sync/requirements.txt.j2,sha256=iTmO-z8qFkUa1jTctFCs0WYuq7Sqi6VNQAwATakh2fQ,94
84
87
  agentex/lib/cli/templates/sync/deploy/example.yaml.j2,sha256=sHIEuhtruyCfGPgeLQ1ilCCnRH0HpsqhDdQT44UWUaU,1554
85
88
  agentex/lib/cli/templates/sync/project/acp.py.j2,sha256=X5RaE9iR4Dp-kPJL0r1QAe6ohfiOTcYizwtwGW2GzHg,1003
@@ -89,11 +92,11 @@ agentex/lib/cli/templates/temporal/Dockerfile.j2,sha256=pcszlprNTqKMpYEtA4XYlc3v
89
92
  agentex/lib/cli/templates/temporal/README.md.j2,sha256=d6BQAZBf7lCKROXnpDu-Ml1Rq0OM8cCFEOpmStoPWfc,10132
90
93
  agentex/lib/cli/templates/temporal/dev.ipynb.j2,sha256=8xY82gVfQ0mhzlEZzI4kLqIXCF19YgimLnpEirDMX8I,3395
91
94
  agentex/lib/cli/templates/temporal/manifest.yaml.j2,sha256=S-hJlpVCnT62r66otqHa3iROOn1w_yYvehOOxvLQotY,4483
92
- agentex/lib/cli/templates/temporal/pyproject.toml.j2,sha256=hBZgFBkgdQ4x7lfmmUXuUL10ER11ojaDp_swnrg26Vo,546
95
+ agentex/lib/cli/templates/temporal/pyproject.toml.j2,sha256=MoR1g6KnGOQrXWOXhFKMw561kgpxy0tdom0KLtQe8A8,548
93
96
  agentex/lib/cli/templates/temporal/requirements.txt.j2,sha256=iTmO-z8qFkUa1jTctFCs0WYuq7Sqi6VNQAwATakh2fQ,94
94
97
  agentex/lib/cli/templates/temporal/deploy/example.yaml.j2,sha256=sHIEuhtruyCfGPgeLQ1ilCCnRH0HpsqhDdQT44UWUaU,1554
95
- agentex/lib/cli/templates/temporal/project/acp.py.j2,sha256=EXeLdpWmEFCHANNsRtOvT92jV_90IqiSp8lzh7YXyCI,1231
96
- agentex/lib/cli/templates/temporal/project/run_worker.py.j2,sha256=JA9MLcylkm7zvMiYZRX8-YhS6hrakvIbVq92Fhfh3bI,862
98
+ agentex/lib/cli/templates/temporal/project/acp.py.j2,sha256=Ha5oBaGT1WC93TEBfWMM7OtbmAYOF2t3PjY6uOL6mJE,2386
99
+ agentex/lib/cli/templates/temporal/project/run_worker.py.j2,sha256=kgEbi-NNKDEOcW7lWP1rfQhFHpqjLtUi0Bc7AjO9jQo,979
97
100
  agentex/lib/cli/templates/temporal/project/workflow.py.j2,sha256=VPnHnzr09i5y68vCOIJ8wTrc8KVHoDp5WooQew0GiWg,3210
98
101
  agentex/lib/cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
102
  agentex/lib/cli/utils/auth_utils.py,sha256=Y8pCqvQxhYtyQOzbpFZ_PUIp6vo8XGDOPdyoRI1_KG8,489
@@ -127,7 +130,7 @@ agentex/lib/core/services/adk/streaming.py,sha256=zIXxMaoL5iTTC8CvmNoG4lRQO5JHyW
127
130
  agentex/lib/core/services/adk/tasks.py,sha256=XEX0u4skq81Fn-gjTzSE_-Iv_mKySZHchpotxAsnJwg,2618
128
131
  agentex/lib/core/services/adk/tracing.py,sha256=w4mnIoq5m5iwlkDN_NOUjhi6hUpD958cYn1QR6hFgB8,1156
129
132
  agentex/lib/core/services/adk/acp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
- agentex/lib/core/services/adk/acp/acp.py,sha256=CDv9_tu44yV7ezeWFwxrX6K3DFCo2A7YFukHOd-8ygY,7575
133
+ agentex/lib/core/services/adk/acp/acp.py,sha256=Ei6r5CcM1RA7DqfTRpAWCmP7Buw97b3ajQuE4DsdSaQ,7559
131
134
  agentex/lib/core/services/adk/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
135
  agentex/lib/core/services/adk/providers/litellm.py,sha256=7RIVqQ5XaCP2cEL1pr4nl5jfG_0FDMvDTZVKu1iaN3M,9864
133
136
  agentex/lib/core/services/adk/providers/openai.py,sha256=Qply4Q7BJqRyukAuNPnFcLXf0eQWACaa5LamGc6xpTY,31559
@@ -159,7 +162,7 @@ agentex/lib/core/temporal/services/temporal_task_service.py,sha256=kXUOwcg1Suc0k
159
162
  agentex/lib/core/temporal/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
160
163
  agentex/lib/core/temporal/types/workflow.py,sha256=o8lBUloI44NTYFfbA1BLgzUneyN7aLbt042Eq_9OKo8,89
161
164
  agentex/lib/core/temporal/workers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
- agentex/lib/core/temporal/workers/worker.py,sha256=WY402Nk6wnsVmCjuOwhO__U8V2OIiRRMC86GDUOP0H4,5488
165
+ agentex/lib/core/temporal/workers/worker.py,sha256=kmdfs67UWjzxU9ZOE7vq_q4S4jj7jB5ZMyJkZYptrAY,6670
163
166
  agentex/lib/core/temporal/workflows/workflow.py,sha256=VTS4nqwdJqqjIy6nTyvFLdAoBHnunO8-8rVY0Gx5_zo,723
164
167
  agentex/lib/core/tracing/__init__.py,sha256=3dLjXGTwAJxi_xxwdh8Mt04pdLyzN9VxAl8XHmV70Ak,229
165
168
  agentex/lib/core/tracing/trace.py,sha256=45Nn0Z97kC_9XNyb9N8IWUFo0OIdb7dDZShhgOTGJB0,8952
@@ -178,7 +181,7 @@ agentex/lib/sdk/config/local_development_config.py,sha256=b1AZsOVo1RoHKbk8Nm5nC8
178
181
  agentex/lib/sdk/config/project_config.py,sha256=CGH_r9KbnSFMj2CnBkZnfg41L2o0TeVNz6MwBDKPT_U,3642
179
182
  agentex/lib/sdk/fastacp/__init__.py,sha256=UvAdexdnfb4z0F4a2sfXROFyh9EjH89kf3AxHPybzCM,75
180
183
  agentex/lib/sdk/fastacp/fastacp.py,sha256=K4D7a9EiJfCgWp2hrE_TbpZBaF4Uc46MfndZK3F9mA0,3061
181
- agentex/lib/sdk/fastacp/base/base_acp_server.py,sha256=sD2p6xC0vXiD6LTj-bYz4-dvh_HxH8_q-51f-hIV0jI,17670
184
+ agentex/lib/sdk/fastacp/base/base_acp_server.py,sha256=fkEVg5M4Ni2uPt_oiCP7_jfTmRvcC0o2VTg0Oka7mXA,14590
182
185
  agentex/lib/sdk/fastacp/impl/agentic_base_acp.py,sha256=LWLAlHrs-2Lc2UICBAEFL8c3JwTA6oxPnzUzW0qQWSA,2694
183
186
  agentex/lib/sdk/fastacp/impl/sync_acp.py,sha256=8FEDfBxI31NoVLX9nyckQ8QwA0UV4svC3fhGKgXBIwk,3862
184
187
  agentex/lib/sdk/fastacp/impl/temporal_acp.py,sha256=ZLqjzBBVrXJCXD2bFlrcDkFvpsXZp3thC2rTwZ6xNaY,3737
@@ -211,6 +214,7 @@ agentex/lib/types/tracing.py,sha256=0YBdy3aKvxIcpOW0podEAqsFl3yEKW4PswNf-QnMNqo,
211
214
  agentex/lib/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
212
215
  agentex/lib/utils/completions.py,sha256=m9TMwl9-nYK4DOQ8bNyj5YCFrxK3yN3zKvXmdINcIbo,4158
213
216
  agentex/lib/utils/console.py,sha256=HVP1NSF4idx40hlGB3ifuofy3rsc83WF_1yNpHYM99M,417
217
+ agentex/lib/utils/debug.py,sha256=1o2NjG8bZXTi63KTGjL3EmU_zMGapco7v5xoDuZRjU8,2148
214
218
  agentex/lib/utils/io.py,sha256=17p7dfUZ1YxTAc-n_g7eFOjzInoKi7Uedyad967EKYQ,754
215
219
  agentex/lib/utils/iterables.py,sha256=cD49hj98mtY0QPaS0ZA2kguNeGzRU4UfbZfwyASWdzY,319
216
220
  agentex/lib/utils/json_schema.py,sha256=nSHbi6LC-oWXHP6sMLCBychA7B0R2DItRIJNCCEzRsY,741
@@ -219,6 +223,7 @@ agentex/lib/utils/mcp.py,sha256=lYQPwKAOH6Gf2I_TeovhEG9YUijUPcN0rENNdT0Vk6c,505
219
223
  agentex/lib/utils/model_utils.py,sha256=_zPUIoSl-A7LsIuH-8I6aJBmbgjARbl7puMPh9lx5QU,1562
220
224
  agentex/lib/utils/parsing.py,sha256=2T-B4nJSupo2RLf9AkpV6VQHqDnF97ZBgO6zvGCauCo,369
221
225
  agentex/lib/utils/regex.py,sha256=Y3VcehCznAqa59D4WTwK_ki722oudHBlFqBk0I930zo,212
226
+ agentex/lib/utils/registration.py,sha256=FAL40KSMRCltHZcDtioGeRNgfB19Twqu6Srp4x7UMSU,3781
222
227
  agentex/lib/utils/temporal.py,sha256=sXo8OPMMXiyrF7OSBCJBuN_ufyQOD2bLOXgDbVZoyds,292
223
228
  agentex/lib/utils/dev_tools/__init__.py,sha256=oaHxw6ymfhNql-kzXHv3NWVHuqD4fHumasNXJG7kHTU,261
224
229
  agentex/lib/utils/dev_tools/async_messages.py,sha256=-alUK1KFltcRb6xtRtIJIRJW9Sf1FwDRgaNPhOn-luw,18105
@@ -234,7 +239,7 @@ agentex/resources/messages/batch.py,sha256=pegCmnjK_J0jek5ChX1pKpq5RmCucTYLbK69H
234
239
  agentex/resources/messages/messages.py,sha256=fuFmmGNOjRJVzmYHcfP2trg0yii0n9MPPCpt7F8fDs4,17930
235
240
  agentex/types/__init__.py,sha256=v-2hxFsIvOZ_2mZy-5RqILX0VJWG4sN9MRvXAbThqYI,3514
236
241
  agentex/types/acp_type.py,sha256=Fj-4SzmM6m95ck_ZXtNbcWggHiD9F49bxBLPbl1fxe4,208
237
- agentex/types/agent.py,sha256=WZRc8VZtc-JIeNHw5FsVTSMrxlaJ5A0ABvHv3t_zA4s,792
242
+ agentex/types/agent.py,sha256=t6CUsKSaK6Gs_X9g0YxSi5G3Hh21FrGVGnAD6MytVBk,981
238
243
  agentex/types/agent_list_params.py,sha256=81IWnRZ2rLfHH7GB6VkXShYjb44DO0guG1znJcV3tuI,316
239
244
  agentex/types/agent_list_response.py,sha256=g0b9Cw7j2yk14veyJORpF3me8iW7g7pr2USpXGokoFI,254
240
245
  agentex/types/agent_rpc_by_name_params.py,sha256=G6xkjrZKPmJvhwqgc68tAnzmb4wYh9k0zlcm9CsLQR0,2024
@@ -291,8 +296,8 @@ agentex/types/messages/batch_update_params.py,sha256=Ug5CThbD49a8j4qucg04OdmVrp_
291
296
  agentex/types/messages/batch_update_response.py,sha256=TbSBe6SuPzjXXWSj-nRjT1JHGBooTshHQQDa1AixQA8,278
292
297
  agentex/types/shared/__init__.py,sha256=IKs-Qn5Yja0kFh1G1kDqYZo43qrOu1hSoxlPdN-85dI,149
293
298
  agentex/types/shared/delete_response.py,sha256=8qH3zvQXaOHYQSHyXi7UQxdR4miTzR7V9K4zXVsiUyk,215
294
- agentex_sdk-0.2.6.dist-info/METADATA,sha256=qKBqHbctWyM-HfcIoAqlq01C9hGTktyz5k5XLMFkV7Y,14118
295
- agentex_sdk-0.2.6.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
296
- agentex_sdk-0.2.6.dist-info/entry_points.txt,sha256=V7vJuMZdF0UlvgX6KiBN7XUvq_cxF5kplcYvc1QlFaQ,62
297
- agentex_sdk-0.2.6.dist-info/licenses/LICENSE,sha256=Q1AOx2FtRcMlyMgQJ9eVN2WKPq2mQ33lnB4tvWxabLA,11337
298
- agentex_sdk-0.2.6.dist-info/RECORD,,
299
+ agentex_sdk-0.2.7.dist-info/METADATA,sha256=jDeAOkWMQtFYbgfRbFGwSITJDei-oGZIBYeDksRdq4o,15037
300
+ agentex_sdk-0.2.7.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
301
+ agentex_sdk-0.2.7.dist-info/entry_points.txt,sha256=V7vJuMZdF0UlvgX6KiBN7XUvq_cxF5kplcYvc1QlFaQ,62
302
+ agentex_sdk-0.2.7.dist-info/licenses/LICENSE,sha256=Q1AOx2FtRcMlyMgQJ9eVN2WKPq2mQ33lnB4tvWxabLA,11337
303
+ agentex_sdk-0.2.7.dist-info/RECORD,,