agentex-sdk 0.2.4__py3-none-any.whl → 0.2.6__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.
Files changed (45) hide show
  1. agentex/_base_client.py +4 -1
  2. agentex/_files.py +4 -4
  3. agentex/_version.py +1 -1
  4. agentex/lib/adk/_modules/acp.py +2 -2
  5. agentex/lib/adk/_modules/agent_task_tracker.py +2 -2
  6. agentex/lib/adk/_modules/agents.py +2 -2
  7. agentex/lib/adk/_modules/events.py +2 -2
  8. agentex/lib/adk/_modules/messages.py +2 -2
  9. agentex/lib/adk/_modules/state.py +2 -2
  10. agentex/lib/adk/_modules/streaming.py +2 -2
  11. agentex/lib/adk/_modules/tasks.py +2 -2
  12. agentex/lib/adk/_modules/tracing.py +2 -2
  13. agentex/lib/adk/providers/_modules/litellm.py +2 -1
  14. agentex/lib/adk/providers/_modules/openai.py +2 -1
  15. agentex/lib/adk/providers/_modules/sgp.py +2 -1
  16. agentex/lib/adk/utils/_modules/client.py +20 -35
  17. agentex/lib/adk/utils/_modules/templating.py +2 -1
  18. agentex/lib/cli/commands/agents.py +3 -3
  19. agentex/lib/cli/handlers/agent_handlers.py +1 -1
  20. agentex/lib/cli/handlers/cleanup_handlers.py +9 -15
  21. agentex/lib/cli/handlers/deploy_handlers.py +29 -5
  22. agentex/lib/cli/handlers/run_handlers.py +19 -93
  23. agentex/lib/cli/templates/sync/project/acp.py.j2 +15 -64
  24. agentex/lib/cli/utils/path_utils.py +143 -0
  25. agentex/lib/core/temporal/activities/__init__.py +2 -1
  26. agentex/lib/core/tracing/processors/agentex_tracing_processor.py +2 -1
  27. agentex/lib/environment_variables.py +5 -1
  28. agentex/lib/sdk/fastacp/base/base_acp_server.py +5 -4
  29. agentex/lib/sdk/fastacp/impl/agentic_base_acp.py +3 -1
  30. agentex/lib/types/converters.py +60 -0
  31. agentex/resources/agents.py +9 -8
  32. agentex/resources/messages/messages.py +4 -0
  33. agentex/resources/tasks.py +63 -14
  34. agentex/types/__init__.py +2 -2
  35. agentex/types/message_list_params.py +1 -0
  36. agentex/types/shared/__init__.py +3 -0
  37. agentex/types/shared/delete_response.py +11 -0
  38. agentex/types/task_list_params.py +14 -0
  39. {agentex_sdk-0.2.4.dist-info → agentex_sdk-0.2.6.dist-info}/METADATA +2 -2
  40. {agentex_sdk-0.2.4.dist-info → agentex_sdk-0.2.6.dist-info}/RECORD +43 -40
  41. agentex/types/task_delete_by_name_response.py +0 -8
  42. agentex/types/task_delete_response.py +0 -8
  43. {agentex_sdk-0.2.4.dist-info → agentex_sdk-0.2.6.dist-info}/WHEEL +0 -0
  44. {agentex_sdk-0.2.4.dist-info → agentex_sdk-0.2.6.dist-info}/entry_points.txt +0 -0
  45. {agentex_sdk-0.2.4.dist-info → agentex_sdk-0.2.6.dist-info}/licenses/LICENSE +0 -0
@@ -11,6 +11,11 @@ from agentex.lib.cli.handlers.cleanup_handlers import (
11
11
  cleanup_agent_workflows,
12
12
  should_cleanup_on_restart
13
13
  )
14
+ from agentex.lib.cli.utils.path_utils import (
15
+ get_file_paths,
16
+ calculate_uvicorn_target_for_local,
17
+ )
18
+
14
19
  from agentex.lib.environment_variables import EnvVarKeys
15
20
  from agentex.lib.sdk.config.agent_manifest import AgentManifest
16
21
  from agentex.lib.utils.logging import make_logger
@@ -104,7 +109,10 @@ async def start_temporal_worker_with_reload(
104
109
  # PRE-RESTART CLEANUP - NEW!
105
110
  if current_process is not None:
106
111
  # Extract agent name from worker path for cleanup
107
- agent_name = worker_path.parent.parent.name
112
+
113
+ agent_name = env.get("AGENT_NAME")
114
+ if agent_name is None:
115
+ agent_name = worker_path.parent.parent.name
108
116
 
109
117
  # Perform cleanup if configured
110
118
  if should_cleanup_on_restart():
@@ -180,15 +188,17 @@ async def start_temporal_worker_with_reload(
180
188
 
181
189
 
182
190
  async def start_acp_server(
183
- acp_path: Path, port: int, env: dict[str, str]
191
+ acp_path: Path, port: int, env: dict[str, str], manifest_dir: Path
184
192
  ) -> asyncio.subprocess.Process:
185
193
  """Start the ACP server process"""
186
- # Use the actual file path instead of module path for better reload detection
194
+ # Use file path relative to manifest directory if possible
195
+ uvicorn_target = calculate_uvicorn_target_for_local(acp_path, manifest_dir)
196
+
187
197
  cmd = [
188
198
  sys.executable,
189
199
  "-m",
190
200
  "uvicorn",
191
- f"{acp_path.parent.name}.acp:acp",
201
+ f"{uvicorn_target}:acp",
192
202
  "--reload",
193
203
  "--reload-dir",
194
204
  str(acp_path.parent), # Watch the project directory specifically
@@ -201,7 +211,7 @@ async def start_acp_server(
201
211
  console.print(f"[blue]Starting ACP server from {acp_path} on port {port}...[/blue]")
202
212
  return await asyncio.create_subprocess_exec(
203
213
  *cmd,
204
- cwd=acp_path.parent.parent,
214
+ cwd=manifest_dir, # Always use manifest directory as CWD for consistency
205
215
  env=env,
206
216
  stdout=asyncio.subprocess.PIPE,
207
217
  stderr=asyncio.subprocess.STDOUT,
@@ -218,7 +228,7 @@ async def start_temporal_worker(
218
228
 
219
229
  return await asyncio.create_subprocess_exec(
220
230
  *cmd,
221
- cwd=worker_path.parent,
231
+ cwd=worker_path.parent, # Use worker directory as CWD for imports to work
222
232
  env=env,
223
233
  stdout=asyncio.subprocess.PIPE,
224
234
  stderr=asyncio.subprocess.STDOUT,
@@ -280,8 +290,9 @@ async def run_agent(manifest_path: str):
280
290
  )
281
291
 
282
292
  # Start ACP server
293
+ manifest_dir = Path(manifest_path).parent
283
294
  acp_process = await start_acp_server(
284
- file_paths["acp"], manifest.local_development.agent.port, agent_env
295
+ file_paths["acp"], manifest.local_development.agent.port, agent_env, manifest_dir
285
296
  )
286
297
  process_manager.add_process(acp_process)
287
298
 
@@ -291,7 +302,7 @@ async def run_agent(manifest_path: str):
291
302
  tasks = [acp_output_task]
292
303
 
293
304
  # Start temporal worker if needed
294
- if is_temporal_agent(manifest):
305
+ if is_temporal_agent(manifest) and file_paths["worker"]:
295
306
  worker_task = await start_temporal_worker_with_reload(file_paths["worker"], agent_env, process_manager)
296
307
  tasks.append(worker_task)
297
308
 
@@ -323,92 +334,7 @@ async def run_agent(manifest_path: str):
323
334
  await process_manager.cleanup_processes()
324
335
 
325
336
 
326
- def resolve_and_validate_path(base_path: Path, configured_path: str, file_type: str) -> Path:
327
- """Resolve and validate a configured path"""
328
- path_obj = Path(configured_path)
329
-
330
- if path_obj.is_absolute():
331
- # Absolute path - use as-is
332
- resolved_path = path_obj
333
- else:
334
- # Relative path - resolve relative to manifest directory
335
- resolved_path = (base_path / configured_path).resolve()
336
-
337
- # Validate the file exists
338
- if not resolved_path.exists():
339
- raise RunError(
340
- f"{file_type} file not found: {resolved_path}\n"
341
- f" Configured path: {configured_path}\n"
342
- f" Resolved from manifest: {base_path}"
343
- )
344
-
345
- # Validate it's actually a file
346
- if not resolved_path.is_file():
347
- raise RunError(f"{file_type} path is not a file: {resolved_path}")
348
-
349
- return resolved_path
350
-
351
-
352
- def validate_path_security(resolved_path: Path, manifest_dir: Path) -> None:
353
- """Basic security validation for resolved paths"""
354
- try:
355
- # Ensure the resolved path is accessible
356
- resolved_path.resolve()
357
-
358
- # Optional: Add warnings for paths that go too far up
359
- try:
360
- # Check if path goes more than 3 levels up from manifest
361
- relative_to_manifest = resolved_path.relative_to(manifest_dir.parent.parent.parent)
362
- if str(relative_to_manifest).startswith(".."):
363
- logger.warning(
364
- f"Path goes significantly outside project structure: {resolved_path}"
365
- )
366
- except ValueError:
367
- # Path is outside the tree - that's okay, just log it
368
- logger.info(f"Using path outside manifest directory tree: {resolved_path}")
369
-
370
- except Exception as e:
371
- raise RunError(f"Path resolution failed: {resolved_path} - {str(e)}") from e
372
-
373
337
 
374
- def get_file_paths(manifest: AgentManifest, manifest_path: str) -> dict[str, Path]:
375
- """Get resolved file paths from manifest configuration"""
376
- manifest_dir = Path(manifest_path).parent.resolve()
377
-
378
- # Use configured paths or fall back to defaults for backward compatibility
379
- if manifest.local_development and manifest.local_development.paths:
380
- paths_config = manifest.local_development.paths
381
-
382
- # Resolve ACP path
383
- acp_path = resolve_and_validate_path(manifest_dir, paths_config.acp, "ACP server")
384
- validate_path_security(acp_path, manifest_dir)
385
-
386
- # Resolve worker path if specified
387
- worker_path = None
388
- if paths_config.worker:
389
- worker_path = resolve_and_validate_path(
390
- manifest_dir, paths_config.worker, "Temporal worker"
391
- )
392
- validate_path_security(worker_path, manifest_dir)
393
- else:
394
- # Backward compatibility: use old hardcoded structure
395
- project_dir = manifest_dir / "project"
396
- acp_path = project_dir / "acp.py"
397
- worker_path = project_dir / "run_worker.py" if is_temporal_agent(manifest) else None
398
-
399
- # Validate backward compatibility paths
400
- if not acp_path.exists():
401
- raise RunError(f"ACP file not found: {acp_path}")
402
-
403
- if worker_path and not worker_path.exists():
404
- raise RunError(f"Worker file not found: {worker_path}")
405
-
406
- return {
407
- "acp": acp_path,
408
- "worker": worker_path,
409
- "acp_dir": acp_path.parent,
410
- "worker_dir": worker_path.parent if worker_path else None,
411
- }
412
338
 
413
339
 
414
340
  def create_agent_environment(manifest: AgentManifest) -> dict[str, str]:
@@ -1,75 +1,26 @@
1
- import json
2
- from agentex.lib import adk
1
+ from typing import AsyncGenerator, Union
3
2
  from agentex.lib.sdk.fastacp.fastacp import FastACP
4
- from agentex.lib.types.fastacp import AgenticACPConfig
5
- from agentex.lib.types.acp import CancelTaskParams, CreateTaskParams, SendEventParams
3
+ from agentex.lib.types.acp import SendMessageParams
6
4
 
5
+ from agentex.lib.types.task_message_updates import TaskMessageUpdate
6
+ from agentex.types.task_message_content import TaskMessageContent
7
7
  from agentex.types.text_content import TextContent
8
8
  from agentex.lib.utils.logging import make_logger
9
9
 
10
10
  logger = make_logger(__name__)
11
11
 
12
12
 
13
- # Create an ACP server with base configuration
14
- # This sets up the core server that will handle task creation, events, and cancellation
13
+ # Create an ACP server
15
14
  acp = FastACP.create(
16
- acp_type="agentic",
17
- config=AgenticACPConfig(
18
- type="base",
19
- ),
15
+ acp_type="sync",
20
16
  )
21
17
 
22
- @acp.on_task_create
23
- async def handle_task_create(params: CreateTaskParams):
24
- # This handler is called first whenever a new task is created.
25
- # It's a good place to initialize any state or resources needed for the task.
26
-
27
- #########################################################
28
- # 1. (👋) Do task initialization here.
29
- #########################################################
30
-
31
- # Acknowledge that the task has been created.
32
- await adk.messages.create(
33
- task_id=params.task.id,
34
- content=TextContent(
35
- author="agent",
36
- content=f"Hello! I've received your task. Normally you can do some state initialization here, or just pass and do nothing until you get your first event. For now I'm just acknowledging that I've received a task with the following params:\n\n{json.dumps(params.params, indent=2)}.\n\nYou should only see this message once, when the task is created. All subsequent events will be handled by the `on_task_event_send` handler.",
37
- ),
38
- )
39
-
40
- @acp.on_task_event_send
41
- async def handle_event_send(params: SendEventParams):
42
- # This handler is called whenever a new event (like a message) is sent to the task
43
-
44
- #########################################################
45
- # 2. (👋) Echo back the client's message to show it in the UI.
46
- #########################################################
47
-
48
- # This is not done by default so the agent developer has full control over what is shown to the user.
49
- if params.event.content:
50
- await adk.messages.create(task_id=params.task.id, content=params.event.content)
51
-
52
- #########################################################
53
- # 3. (👋) Send a simple response message.
54
- #########################################################
55
-
56
- # In future tutorials, this is where we'll add more sophisticated response logic.
57
- await adk.messages.create(
58
- task_id=params.task.id,
59
- content=TextContent(
60
- author="agent",
61
- content=f"Hello! I've received your message. I can't respond right now, but in future tutorials we'll see how you can get me to intelligently respond to your message.",
62
- ),
63
- )
64
-
65
- @acp.on_task_cancel
66
- async def handle_task_cancel(params: CancelTaskParams):
67
- # This handler is called when a task is cancelled.
68
- # It's useful for cleaning up any resources or state associated with the task.
69
-
70
- #########################################################
71
- # 4. (👋) Do task cleanup here.
72
- #########################################################
73
-
74
- # This is mostly for durable workflows that are cancellable like Temporal, but we will leave it here for demonstration purposes.
75
- logger.info(f"Hello! I've received task cancel for task {params.task.id}: {params.task}. This isn't necessary for this example, but it's good to know that it's available.")
18
+ @acp.on_message_send
19
+ async def handle_message_send(
20
+ params: SendMessageParams
21
+ ) -> TaskMessageContent | list[TaskMessageContent] | AsyncGenerator[TaskMessageUpdate, None]:
22
+ """Default message handler with streaming support"""
23
+ return TextContent(
24
+ author="agent",
25
+ content=f"Hello! I've received your message. Here's a generic response, but in future tutorials we'll see how you can get me to intelligently respond to your message. This is what I heard you say: {params.content.content}",
26
+ )
@@ -0,0 +1,143 @@
1
+ from pathlib import Path
2
+ from typing import Dict
3
+
4
+ from agentex.lib.sdk.config.agent_manifest import AgentManifest
5
+ from agentex.lib.utils.logging import make_logger
6
+
7
+ logger = make_logger(__name__)
8
+
9
+
10
+ class PathResolutionError(Exception):
11
+ """An error occurred during path resolution"""
12
+
13
+
14
+ def resolve_and_validate_path(base_path: Path, configured_path: str, file_type: str) -> Path:
15
+ """Resolve and validate a configured path"""
16
+ path_obj = Path(configured_path)
17
+
18
+ if path_obj.is_absolute():
19
+ # Absolute path - resolve to canonical form
20
+ resolved_path = path_obj.resolve()
21
+ else:
22
+ # Relative path - resolve relative to manifest directory
23
+ resolved_path = (base_path / configured_path).resolve()
24
+
25
+ # Validate the file exists
26
+ if not resolved_path.exists():
27
+ raise PathResolutionError(
28
+ f"{file_type} file not found: {resolved_path}\n"
29
+ f" Configured path: {configured_path}\n"
30
+ f" Resolved from manifest: {base_path}"
31
+ )
32
+
33
+ # Validate it's actually a file
34
+ if not resolved_path.is_file():
35
+ raise PathResolutionError(f"{file_type} path is not a file: {resolved_path}")
36
+
37
+ return resolved_path
38
+
39
+
40
+ def validate_path_security(resolved_path: Path, manifest_dir: Path) -> None:
41
+ """Basic security validation for resolved paths"""
42
+ try:
43
+ # Ensure the resolved path is accessible
44
+ resolved_path.resolve()
45
+
46
+ # Optional: Add warnings for paths that go too far up
47
+ try:
48
+ # Check if path goes more than 3 levels up from manifest
49
+ relative_to_manifest = resolved_path.relative_to(manifest_dir.parent.parent.parent)
50
+ if str(relative_to_manifest).startswith(".."):
51
+ logger.warning(
52
+ f"Path goes significantly outside project structure: {resolved_path}"
53
+ )
54
+ except ValueError:
55
+ # Path is outside the tree - that's okay, just log it
56
+ logger.info(f"Using path outside manifest directory tree: {resolved_path}")
57
+
58
+ except Exception as e:
59
+ raise PathResolutionError(f"Path resolution failed: {resolved_path} - {str(e)}") from e
60
+
61
+
62
+ def get_file_paths(manifest: AgentManifest, manifest_path: str) -> Dict[str, Path | None]:
63
+ """Get resolved file paths from manifest configuration"""
64
+ manifest_dir = Path(manifest_path).parent.resolve()
65
+
66
+ # Use configured paths or fall back to defaults for backward compatibility
67
+ if manifest.local_development and manifest.local_development.paths:
68
+ paths_config = manifest.local_development.paths
69
+
70
+ # Resolve ACP path
71
+ acp_path = resolve_and_validate_path(manifest_dir, paths_config.acp, "ACP server")
72
+ validate_path_security(acp_path, manifest_dir)
73
+
74
+ # Resolve worker path if specified
75
+ worker_path = None
76
+ if paths_config.worker:
77
+ worker_path = resolve_and_validate_path(
78
+ manifest_dir, paths_config.worker, "Temporal worker"
79
+ )
80
+ validate_path_security(worker_path, manifest_dir)
81
+ else:
82
+ # Backward compatibility: use old hardcoded structure
83
+ project_dir = manifest_dir / "project"
84
+ acp_path = (project_dir / "acp.py").resolve()
85
+ worker_path = (project_dir / "run_worker.py").resolve() if manifest.agent.is_temporal_agent() else None
86
+
87
+ # Validate backward compatibility paths
88
+ if not acp_path.exists():
89
+ raise PathResolutionError(f"ACP file not found: {acp_path}")
90
+
91
+ if worker_path and not worker_path.exists():
92
+ raise PathResolutionError(f"Worker file not found: {worker_path}")
93
+
94
+ return {
95
+ "acp": acp_path,
96
+ "worker": worker_path,
97
+ "acp_dir": acp_path.parent,
98
+ "worker_dir": worker_path.parent if worker_path else None,
99
+ }
100
+
101
+
102
+ def calculate_uvicorn_target_for_local(acp_path: Path, manifest_dir: Path) -> str:
103
+ """Calculate the uvicorn target path for local development"""
104
+ # Ensure both paths are resolved to canonical form for accurate comparison
105
+ acp_resolved = acp_path.resolve()
106
+ manifest_resolved = manifest_dir.resolve()
107
+
108
+ try:
109
+ # Try to use path relative to manifest directory
110
+ acp_relative = acp_resolved.relative_to(manifest_resolved)
111
+ # Convert to module notation: project/acp.py -> project.acp
112
+ module_path = str(acp_relative.with_suffix('')) # Remove .py extension
113
+ module_path = module_path.replace('/', '.') # Convert slashes to dots
114
+ module_path = module_path.replace('\\', '.') # Handle Windows paths
115
+ return module_path
116
+ except ValueError:
117
+ # Path cannot be made relative - use absolute file path
118
+ logger.warning(f"ACP file {acp_resolved} cannot be made relative to manifest directory {manifest_resolved}, using absolute file path")
119
+ return str(acp_resolved)
120
+
121
+
122
+ def calculate_docker_acp_module(manifest: AgentManifest, manifest_path: str) -> str:
123
+ """Calculate the Python module path for the ACP file in the Docker container
124
+
125
+ This should return the same module notation as local development for consistency.
126
+ """
127
+ # Use the same logic as local development
128
+ manifest_dir = Path(manifest_path).parent
129
+
130
+ # Get the configured ACP path (could be relative or absolute)
131
+ if manifest.local_development and manifest.local_development.paths:
132
+ acp_config_path = manifest.local_development.paths.acp
133
+ else:
134
+ acp_config_path = "project/acp.py" # Default
135
+
136
+ # Resolve to actual file path
137
+ acp_path = resolve_and_validate_path(manifest_dir, acp_config_path, "ACP")
138
+
139
+ # Use the same module calculation as local development
140
+ return calculate_uvicorn_target_for_local(acp_path, manifest_dir)
141
+
142
+
143
+
@@ -1,3 +1,4 @@
1
+ from agentex.lib.adk.utils._modules.client import create_async_agentex_client
1
2
  from scale_gp import SGPClient, SGPClientError
2
3
 
3
4
  from agentex import AsyncAgentex
@@ -58,7 +59,7 @@ def get_all_activities(sgp_client=None):
58
59
 
59
60
  llm_gateway = LiteLLMGateway()
60
61
  stream_repository = RedisStreamRepository()
61
- agentex_client = AsyncAgentex()
62
+ agentex_client = create_async_agentex_client()
62
63
  tracer = AsyncTracer(agentex_client)
63
64
 
64
65
  # Services
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Dict, override
2
2
 
3
3
  from agentex import Agentex, AsyncAgentex
4
+ from agentex.lib.adk.utils._modules.client import create_async_agentex_client
4
5
  from agentex.lib.core.tracing.processors.tracing_processor_interface import (
5
6
  AsyncTracingProcessor,
6
7
  SyncTracingProcessor,
@@ -65,7 +66,7 @@ class AgentexSyncTracingProcessor(SyncTracingProcessor):
65
66
 
66
67
  class AgentexAsyncTracingProcessor(AsyncTracingProcessor):
67
68
  def __init__(self, config: AgentexTracingProcessorConfig):
68
- self.client = AsyncAgentex()
69
+ self.client = create_async_agentex_client()
69
70
 
70
71
  @override
71
72
  async def on_span_start(self, span: Span) -> None:
@@ -4,12 +4,15 @@ import os
4
4
  from enum import Enum
5
5
  from pathlib import Path
6
6
 
7
+ from agentex.lib.utils.logging import make_logger
7
8
  from dotenv import load_dotenv
8
9
 
9
10
  from agentex.lib.utils.model_utils import BaseModel
10
11
 
11
12
  PROJECT_ROOT = Path(__file__).resolve().parents[2]
12
13
 
14
+ logger = make_logger(__name__)
15
+
13
16
 
14
17
  class EnvVarKeys(str, Enum):
15
18
  ENVIRONMENT = "ENVIRONMENT"
@@ -37,7 +40,7 @@ class Environment(str, Enum):
37
40
  PROD = "production"
38
41
 
39
42
 
40
- refreshed_environment_variables = None
43
+ refreshed_environment_variables: "EnvironmentVariables" | None = None
41
44
 
42
45
 
43
46
  class EnvironmentVariables(BaseModel):
@@ -64,6 +67,7 @@ class EnvironmentVariables(BaseModel):
64
67
  if refreshed_environment_variables is not None:
65
68
  return refreshed_environment_variables
66
69
 
70
+ logger.info("Refreshing environment variables")
67
71
  if os.environ.get(EnvVarKeys.ENVIRONMENT) == Environment.DEV:
68
72
  # Load global .env file first
69
73
  global_env_path = PROJECT_ROOT / ".env"
@@ -9,7 +9,7 @@ from typing import Any
9
9
 
10
10
  import httpx
11
11
  import uvicorn
12
- from agentex.lib.adk.utils._modules.client import get_async_agentex_client
12
+ from agentex.lib.adk.utils._modules.client import create_async_agentex_client
13
13
  from fastapi import FastAPI, Request
14
14
  from fastapi.responses import StreamingResponse
15
15
  from pydantic import TypeAdapter, ValidationError
@@ -397,9 +397,10 @@ class BaseACPServer(FastAPI):
397
397
 
398
398
  os.environ["AGENT_ID"] = agent_id
399
399
  os.environ["AGENT_NAME"] = agent_name
400
- refreshed_environment_variables.AGENT_ID = agent_id
401
- refreshed_environment_variables.AGENT_NAME = agent_name
402
- get_async_agentex_client() # refresh cache
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
403
404
  logger.info(
404
405
  f"Successfully registered agent '{env_vars.AGENT_NAME}' with Agentex server with acp_url: {full_acp_url}. Registration data: {registration_data}"
405
406
  )
@@ -1,4 +1,6 @@
1
1
  from typing import Any
2
+
3
+ from agentex.lib.adk.utils._modules.client import create_async_agentex_client
2
4
  from typing_extensions import override
3
5
  from agentex import AsyncAgentex
4
6
  from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
@@ -24,7 +26,7 @@ class AgenticBaseACP(BaseACPServer):
24
26
  def __init__(self):
25
27
  super().__init__()
26
28
  self._setup_handlers()
27
- self._agentex_client = AsyncAgentex()
29
+ self._agentex_client = create_async_agentex_client()
28
30
 
29
31
  @classmethod
30
32
  @override
@@ -0,0 +1,60 @@
1
+ from agentex.types.task_message import TaskMessage
2
+ from agentex.types.text_content import TextContent
3
+ from agentex.types.tool_request_content import ToolRequestContent
4
+ from agentex.types.tool_response_content import ToolResponseContent
5
+ import json
6
+ from agents import TResponseInputItem
7
+
8
+
9
+ def convert_task_messages_to_oai_agents_inputs(
10
+ task_messages: list[TaskMessage],
11
+ ) -> list[TResponseInputItem]:
12
+ """
13
+ Convert a list of TaskMessages to a list of OpenAI Agents SDK inputs (TResponseInputItem).
14
+
15
+ Args:
16
+ task_messages: The list of TaskMessages to convert.
17
+
18
+ Returns:
19
+ A list of OpenAI Agents SDK inputs (TResponseInputItem).
20
+ """
21
+ converted_messages = []
22
+ for task_message in task_messages:
23
+ task_message_content = task_message.content
24
+ if isinstance(task_message_content, TextContent):
25
+ converted_messages.append(
26
+ {
27
+ "role": (
28
+ "user" if task_message_content.author == "user" else "assistant"
29
+ ),
30
+ "content": task_message_content.content,
31
+ }
32
+ )
33
+ elif isinstance(task_message_content, ToolRequestContent):
34
+ converted_messages.append(
35
+ {
36
+ "type": "function_call",
37
+ "call_id": task_message_content.tool_call_id,
38
+ "name": task_message_content.name,
39
+ "arguments": json.dumps(task_message_content.arguments),
40
+ }
41
+ )
42
+ elif isinstance(task_message_content, ToolResponseContent):
43
+ content_str = (
44
+ task_message_content.content
45
+ if isinstance(task_message_content.content, str)
46
+ else json.dumps(task_message_content.content)
47
+ )
48
+ converted_messages.append(
49
+ {
50
+ "type": "function_call_output",
51
+ "call_id": task_message_content.tool_call_id,
52
+ "output": content_str,
53
+ }
54
+ )
55
+ else:
56
+ raise ValueError(
57
+ f"Unsupported content type for converting TaskMessage to OpenAI Agents SDK input: {type(task_message.content)}"
58
+ )
59
+
60
+ return converted_messages
@@ -23,6 +23,7 @@ from ..types.agent import Agent
23
23
  from .._base_client import make_request_options
24
24
  from ..types.agent_rpc_response import AgentRpcResponse, CancelTaskResponse, CreateTaskResponse, SendEventResponse, SendMessageResponse, SendMessageStreamResponse
25
25
  from ..types.agent_list_response import AgentListResponse
26
+ from ..types.shared.delete_response import DeleteResponse
26
27
 
27
28
  __all__ = ["AgentsResource", "AsyncAgentsResource"]
28
29
 
@@ -127,7 +128,7 @@ class AgentsResource(SyncAPIResource):
127
128
  extra_query: Query | None = None,
128
129
  extra_body: Body | None = None,
129
130
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
130
- ) -> Agent:
131
+ ) -> DeleteResponse:
131
132
  """
132
133
  Delete an agent by its unique ID.
133
134
 
@@ -147,7 +148,7 @@ class AgentsResource(SyncAPIResource):
147
148
  options=make_request_options(
148
149
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
149
150
  ),
150
- cast_to=Agent,
151
+ cast_to=DeleteResponse,
151
152
  )
152
153
 
153
154
  def delete_by_name(
@@ -160,7 +161,7 @@ class AgentsResource(SyncAPIResource):
160
161
  extra_query: Query | None = None,
161
162
  extra_body: Body | None = None,
162
163
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
163
- ) -> Agent:
164
+ ) -> DeleteResponse:
164
165
  """
165
166
  Delete an agent by its unique name.
166
167
 
@@ -180,7 +181,7 @@ class AgentsResource(SyncAPIResource):
180
181
  options=make_request_options(
181
182
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
182
183
  ),
183
- cast_to=Agent,
184
+ cast_to=DeleteResponse,
184
185
  )
185
186
 
186
187
  def retrieve_by_name(
@@ -667,7 +668,7 @@ class AsyncAgentsResource(AsyncAPIResource):
667
668
  extra_query: Query | None = None,
668
669
  extra_body: Body | None = None,
669
670
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
670
- ) -> Agent:
671
+ ) -> DeleteResponse:
671
672
  """
672
673
  Delete an agent by its unique ID.
673
674
 
@@ -687,7 +688,7 @@ class AsyncAgentsResource(AsyncAPIResource):
687
688
  options=make_request_options(
688
689
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
689
690
  ),
690
- cast_to=Agent,
691
+ cast_to=DeleteResponse,
691
692
  )
692
693
 
693
694
  async def delete_by_name(
@@ -700,7 +701,7 @@ class AsyncAgentsResource(AsyncAPIResource):
700
701
  extra_query: Query | None = None,
701
702
  extra_body: Body | None = None,
702
703
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
703
- ) -> Agent:
704
+ ) -> DeleteResponse:
704
705
  """
705
706
  Delete an agent by its unique name.
706
707
 
@@ -720,7 +721,7 @@ class AsyncAgentsResource(AsyncAPIResource):
720
721
  options=make_request_options(
721
722
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
722
723
  ),
723
- cast_to=Agent,
724
+ cast_to=DeleteResponse,
724
725
  )
725
726
 
726
727
  async def retrieve_by_name(
@@ -192,6 +192,8 @@ class MessagesResource(SyncAPIResource):
192
192
  List Messages
193
193
 
194
194
  Args:
195
+ task_id: The task ID
196
+
195
197
  extra_headers: Send extra headers
196
198
 
197
199
  extra_query: Add additional query parameters to the request
@@ -377,6 +379,8 @@ class AsyncMessagesResource(AsyncAPIResource):
377
379
  List Messages
378
380
 
379
381
  Args:
382
+ task_id: The task ID
383
+
380
384
  extra_headers: Send extra headers
381
385
 
382
386
  extra_query: Add additional query parameters to the request