agentex-sdk 0.1.0a6__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/__init__.py +103 -0
- agentex/_base_client.py +1992 -0
- agentex/_client.py +506 -0
- agentex/_compat.py +219 -0
- agentex/_constants.py +14 -0
- agentex/_exceptions.py +108 -0
- agentex/_files.py +123 -0
- agentex/_models.py +829 -0
- agentex/_qs.py +150 -0
- agentex/_resource.py +43 -0
- agentex/_response.py +830 -0
- agentex/_streaming.py +333 -0
- agentex/_types.py +219 -0
- agentex/_utils/__init__.py +57 -0
- agentex/_utils/_logs.py +25 -0
- agentex/_utils/_proxy.py +65 -0
- agentex/_utils/_reflection.py +42 -0
- agentex/_utils/_resources_proxy.py +24 -0
- agentex/_utils/_streams.py +12 -0
- agentex/_utils/_sync.py +86 -0
- agentex/_utils/_transform.py +447 -0
- agentex/_utils/_typing.py +151 -0
- agentex/_utils/_utils.py +422 -0
- agentex/_version.py +4 -0
- agentex/lib/.keep +4 -0
- agentex/lib/__init__.py +0 -0
- agentex/lib/adk/__init__.py +41 -0
- agentex/lib/adk/_modules/__init__.py +0 -0
- agentex/lib/adk/_modules/acp.py +247 -0
- agentex/lib/adk/_modules/agent_task_tracker.py +176 -0
- agentex/lib/adk/_modules/agents.py +77 -0
- agentex/lib/adk/_modules/events.py +141 -0
- agentex/lib/adk/_modules/messages.py +285 -0
- agentex/lib/adk/_modules/state.py +291 -0
- agentex/lib/adk/_modules/streaming.py +75 -0
- agentex/lib/adk/_modules/tasks.py +124 -0
- agentex/lib/adk/_modules/tracing.py +194 -0
- agentex/lib/adk/providers/__init__.py +9 -0
- agentex/lib/adk/providers/_modules/__init__.py +0 -0
- agentex/lib/adk/providers/_modules/litellm.py +232 -0
- agentex/lib/adk/providers/_modules/openai.py +416 -0
- agentex/lib/adk/providers/_modules/sgp.py +85 -0
- agentex/lib/adk/utils/__init__.py +5 -0
- agentex/lib/adk/utils/_modules/__init__.py +0 -0
- agentex/lib/adk/utils/_modules/templating.py +94 -0
- agentex/lib/cli/__init__.py +0 -0
- agentex/lib/cli/commands/__init__.py +0 -0
- agentex/lib/cli/commands/agents.py +328 -0
- agentex/lib/cli/commands/init.py +227 -0
- agentex/lib/cli/commands/main.py +33 -0
- agentex/lib/cli/commands/secrets.py +169 -0
- agentex/lib/cli/commands/tasks.py +118 -0
- agentex/lib/cli/commands/uv.py +133 -0
- agentex/lib/cli/handlers/__init__.py +0 -0
- agentex/lib/cli/handlers/agent_handlers.py +160 -0
- agentex/lib/cli/handlers/cleanup_handlers.py +186 -0
- agentex/lib/cli/handlers/deploy_handlers.py +351 -0
- agentex/lib/cli/handlers/run_handlers.py +452 -0
- agentex/lib/cli/handlers/secret_handlers.py +670 -0
- agentex/lib/cli/templates/default/.dockerignore.j2 +43 -0
- agentex/lib/cli/templates/default/Dockerfile-uv.j2 +42 -0
- agentex/lib/cli/templates/default/Dockerfile.j2 +42 -0
- agentex/lib/cli/templates/default/README.md.j2 +193 -0
- agentex/lib/cli/templates/default/deploy/example.yaml.j2 +55 -0
- agentex/lib/cli/templates/default/manifest.yaml.j2 +116 -0
- agentex/lib/cli/templates/default/project/acp.py.j2 +29 -0
- agentex/lib/cli/templates/default/pyproject.toml.j2 +33 -0
- agentex/lib/cli/templates/default/requirements.txt.j2 +5 -0
- agentex/lib/cli/templates/deploy/Screenshot 2025-03-19 at 10.36.57/342/200/257AM.png +0 -0
- agentex/lib/cli/templates/deploy/example.yaml.j2 +55 -0
- agentex/lib/cli/templates/sync/.dockerignore.j2 +43 -0
- agentex/lib/cli/templates/sync/Dockerfile-uv.j2 +42 -0
- agentex/lib/cli/templates/sync/Dockerfile.j2 +42 -0
- agentex/lib/cli/templates/sync/README.md.j2 +293 -0
- agentex/lib/cli/templates/sync/deploy/example.yaml.j2 +55 -0
- agentex/lib/cli/templates/sync/manifest.yaml.j2 +116 -0
- agentex/lib/cli/templates/sync/project/acp.py.j2 +26 -0
- agentex/lib/cli/templates/sync/pyproject.toml.j2 +33 -0
- agentex/lib/cli/templates/sync/requirements.txt.j2 +5 -0
- agentex/lib/cli/templates/temporal/.dockerignore.j2 +43 -0
- agentex/lib/cli/templates/temporal/Dockerfile-uv.j2 +48 -0
- agentex/lib/cli/templates/temporal/Dockerfile.j2 +48 -0
- agentex/lib/cli/templates/temporal/README.md.j2 +316 -0
- agentex/lib/cli/templates/temporal/deploy/example.yaml.j2 +55 -0
- agentex/lib/cli/templates/temporal/manifest.yaml.j2 +137 -0
- agentex/lib/cli/templates/temporal/project/acp.py.j2 +30 -0
- agentex/lib/cli/templates/temporal/project/run_worker.py.j2 +33 -0
- agentex/lib/cli/templates/temporal/project/workflow.py.j2 +66 -0
- agentex/lib/cli/templates/temporal/pyproject.toml.j2 +34 -0
- agentex/lib/cli/templates/temporal/requirements.txt.j2 +5 -0
- agentex/lib/cli/utils/cli_utils.py +14 -0
- agentex/lib/cli/utils/credential_utils.py +103 -0
- agentex/lib/cli/utils/exceptions.py +6 -0
- agentex/lib/cli/utils/kubectl_utils.py +135 -0
- agentex/lib/cli/utils/kubernetes_secrets_utils.py +185 -0
- agentex/lib/core/__init__.py +0 -0
- agentex/lib/core/adapters/__init__.py +0 -0
- agentex/lib/core/adapters/llm/__init__.py +1 -0
- agentex/lib/core/adapters/llm/adapter_litellm.py +46 -0
- agentex/lib/core/adapters/llm/adapter_sgp.py +55 -0
- agentex/lib/core/adapters/llm/port.py +24 -0
- agentex/lib/core/adapters/streams/adapter_redis.py +128 -0
- agentex/lib/core/adapters/streams/port.py +50 -0
- agentex/lib/core/clients/__init__.py +1 -0
- agentex/lib/core/clients/temporal/__init__.py +0 -0
- agentex/lib/core/clients/temporal/temporal_client.py +181 -0
- agentex/lib/core/clients/temporal/types.py +47 -0
- agentex/lib/core/clients/temporal/utils.py +56 -0
- agentex/lib/core/services/__init__.py +0 -0
- agentex/lib/core/services/adk/__init__.py +0 -0
- agentex/lib/core/services/adk/acp/__init__.py +0 -0
- agentex/lib/core/services/adk/acp/acp.py +210 -0
- agentex/lib/core/services/adk/agent_task_tracker.py +85 -0
- agentex/lib/core/services/adk/agents.py +43 -0
- agentex/lib/core/services/adk/events.py +61 -0
- agentex/lib/core/services/adk/messages.py +164 -0
- agentex/lib/core/services/adk/providers/__init__.py +0 -0
- agentex/lib/core/services/adk/providers/litellm.py +256 -0
- agentex/lib/core/services/adk/providers/openai.py +723 -0
- agentex/lib/core/services/adk/providers/sgp.py +99 -0
- agentex/lib/core/services/adk/state.py +120 -0
- agentex/lib/core/services/adk/streaming.py +262 -0
- agentex/lib/core/services/adk/tasks.py +69 -0
- agentex/lib/core/services/adk/tracing.py +36 -0
- agentex/lib/core/services/adk/utils/__init__.py +0 -0
- agentex/lib/core/services/adk/utils/templating.py +58 -0
- agentex/lib/core/temporal/__init__.py +0 -0
- agentex/lib/core/temporal/activities/__init__.py +207 -0
- agentex/lib/core/temporal/activities/activity_helpers.py +37 -0
- agentex/lib/core/temporal/activities/adk/__init__.py +0 -0
- agentex/lib/core/temporal/activities/adk/acp/__init__.py +0 -0
- agentex/lib/core/temporal/activities/adk/acp/acp_activities.py +86 -0
- agentex/lib/core/temporal/activities/adk/agent_task_tracker_activities.py +76 -0
- agentex/lib/core/temporal/activities/adk/agents_activities.py +35 -0
- agentex/lib/core/temporal/activities/adk/events_activities.py +50 -0
- agentex/lib/core/temporal/activities/adk/messages_activities.py +94 -0
- agentex/lib/core/temporal/activities/adk/providers/__init__.py +0 -0
- agentex/lib/core/temporal/activities/adk/providers/litellm_activities.py +71 -0
- agentex/lib/core/temporal/activities/adk/providers/openai_activities.py +210 -0
- agentex/lib/core/temporal/activities/adk/providers/sgp_activities.py +42 -0
- agentex/lib/core/temporal/activities/adk/state_activities.py +85 -0
- agentex/lib/core/temporal/activities/adk/streaming_activities.py +33 -0
- agentex/lib/core/temporal/activities/adk/tasks_activities.py +48 -0
- agentex/lib/core/temporal/activities/adk/tracing_activities.py +55 -0
- agentex/lib/core/temporal/activities/adk/utils/__init__.py +0 -0
- agentex/lib/core/temporal/activities/adk/utils/templating_activities.py +41 -0
- agentex/lib/core/temporal/services/__init__.py +0 -0
- agentex/lib/core/temporal/services/temporal_task_service.py +69 -0
- agentex/lib/core/temporal/types/__init__.py +0 -0
- agentex/lib/core/temporal/types/workflow.py +5 -0
- agentex/lib/core/temporal/workers/__init__.py +0 -0
- agentex/lib/core/temporal/workers/worker.py +162 -0
- agentex/lib/core/temporal/workflows/workflow.py +26 -0
- agentex/lib/core/tracing/__init__.py +5 -0
- agentex/lib/core/tracing/processors/agentex_tracing_processor.py +117 -0
- agentex/lib/core/tracing/processors/sgp_tracing_processor.py +119 -0
- agentex/lib/core/tracing/processors/tracing_processor_interface.py +40 -0
- agentex/lib/core/tracing/trace.py +311 -0
- agentex/lib/core/tracing/tracer.py +70 -0
- agentex/lib/core/tracing/tracing_processor_manager.py +62 -0
- agentex/lib/environment_variables.py +87 -0
- agentex/lib/py.typed +0 -0
- agentex/lib/sdk/__init__.py +0 -0
- agentex/lib/sdk/config/__init__.py +0 -0
- agentex/lib/sdk/config/agent_config.py +61 -0
- agentex/lib/sdk/config/agent_manifest.py +219 -0
- agentex/lib/sdk/config/build_config.py +35 -0
- agentex/lib/sdk/config/deployment_config.py +117 -0
- agentex/lib/sdk/config/local_development_config.py +56 -0
- agentex/lib/sdk/config/project_config.py +103 -0
- agentex/lib/sdk/fastacp/__init__.py +3 -0
- agentex/lib/sdk/fastacp/base/base_acp_server.py +406 -0
- agentex/lib/sdk/fastacp/fastacp.py +74 -0
- agentex/lib/sdk/fastacp/impl/agentic_base_acp.py +72 -0
- agentex/lib/sdk/fastacp/impl/sync_acp.py +109 -0
- agentex/lib/sdk/fastacp/impl/temporal_acp.py +97 -0
- agentex/lib/sdk/fastacp/tests/README.md +297 -0
- agentex/lib/sdk/fastacp/tests/conftest.py +307 -0
- agentex/lib/sdk/fastacp/tests/pytest.ini +10 -0
- agentex/lib/sdk/fastacp/tests/run_tests.py +227 -0
- agentex/lib/sdk/fastacp/tests/test_base_acp_server.py +450 -0
- agentex/lib/sdk/fastacp/tests/test_fastacp_factory.py +344 -0
- agentex/lib/sdk/fastacp/tests/test_integration.py +477 -0
- agentex/lib/sdk/state_machine/__init__.py +6 -0
- agentex/lib/sdk/state_machine/noop_workflow.py +21 -0
- agentex/lib/sdk/state_machine/state.py +10 -0
- agentex/lib/sdk/state_machine/state_machine.py +189 -0
- agentex/lib/sdk/state_machine/state_workflow.py +16 -0
- agentex/lib/sdk/utils/__init__.py +0 -0
- agentex/lib/sdk/utils/messages.py +223 -0
- agentex/lib/types/__init__.py +0 -0
- agentex/lib/types/acp.py +94 -0
- agentex/lib/types/agent_configs.py +79 -0
- agentex/lib/types/agent_results.py +29 -0
- agentex/lib/types/credentials.py +34 -0
- agentex/lib/types/fastacp.py +61 -0
- agentex/lib/types/files.py +13 -0
- agentex/lib/types/json_rpc.py +49 -0
- agentex/lib/types/llm_messages.py +354 -0
- agentex/lib/types/task_message_updates.py +171 -0
- agentex/lib/types/tracing.py +34 -0
- agentex/lib/utils/__init__.py +0 -0
- agentex/lib/utils/completions.py +131 -0
- agentex/lib/utils/console.py +14 -0
- agentex/lib/utils/io.py +29 -0
- agentex/lib/utils/iterables.py +14 -0
- agentex/lib/utils/json_schema.py +23 -0
- agentex/lib/utils/logging.py +31 -0
- agentex/lib/utils/mcp.py +17 -0
- agentex/lib/utils/model_utils.py +46 -0
- agentex/lib/utils/parsing.py +15 -0
- agentex/lib/utils/regex.py +6 -0
- agentex/lib/utils/temporal.py +13 -0
- agentex/py.typed +0 -0
- agentex/resources/__init__.py +103 -0
- agentex/resources/agents.py +707 -0
- agentex/resources/events.py +294 -0
- agentex/resources/messages/__init__.py +33 -0
- agentex/resources/messages/batch.py +271 -0
- agentex/resources/messages/messages.py +492 -0
- agentex/resources/spans.py +557 -0
- agentex/resources/states.py +544 -0
- agentex/resources/tasks.py +615 -0
- agentex/resources/tracker.py +384 -0
- agentex/types/__init__.py +56 -0
- agentex/types/acp_type.py +7 -0
- agentex/types/agent.py +29 -0
- agentex/types/agent_list_params.py +13 -0
- agentex/types/agent_list_response.py +10 -0
- agentex/types/agent_rpc_by_name_params.py +21 -0
- agentex/types/agent_rpc_params.py +51 -0
- agentex/types/agent_rpc_params1.py +21 -0
- agentex/types/agent_rpc_response.py +20 -0
- agentex/types/agent_rpc_result.py +90 -0
- agentex/types/agent_task_tracker.py +34 -0
- agentex/types/data_content.py +30 -0
- agentex/types/data_content_param.py +31 -0
- agentex/types/data_delta.py +14 -0
- agentex/types/event.py +29 -0
- agentex/types/event_list_params.py +22 -0
- agentex/types/event_list_response.py +10 -0
- agentex/types/message_author.py +7 -0
- agentex/types/message_create_params.py +18 -0
- agentex/types/message_list_params.py +14 -0
- agentex/types/message_list_response.py +10 -0
- agentex/types/message_style.py +7 -0
- agentex/types/message_update_params.py +18 -0
- agentex/types/messages/__init__.py +8 -0
- agentex/types/messages/batch_create_params.py +16 -0
- agentex/types/messages/batch_create_response.py +10 -0
- agentex/types/messages/batch_update_params.py +16 -0
- agentex/types/messages/batch_update_response.py +10 -0
- agentex/types/shared/__init__.py +3 -0
- agentex/types/shared/task_message_update.py +83 -0
- agentex/types/span.py +36 -0
- agentex/types/span_create_params.py +40 -0
- agentex/types/span_list_params.py +12 -0
- agentex/types/span_list_response.py +10 -0
- agentex/types/span_update_params.py +37 -0
- agentex/types/state.py +25 -0
- agentex/types/state_create_params.py +16 -0
- agentex/types/state_list_params.py +16 -0
- agentex/types/state_list_response.py +10 -0
- agentex/types/state_update_params.py +16 -0
- agentex/types/task.py +23 -0
- agentex/types/task_delete_by_name_response.py +8 -0
- agentex/types/task_delete_response.py +8 -0
- agentex/types/task_list_response.py +10 -0
- agentex/types/task_message.py +33 -0
- agentex/types/task_message_content.py +16 -0
- agentex/types/task_message_content_param.py +17 -0
- agentex/types/task_message_delta.py +16 -0
- agentex/types/text_content.py +53 -0
- agentex/types/text_content_param.py +54 -0
- agentex/types/text_delta.py +14 -0
- agentex/types/tool_request_content.py +36 -0
- agentex/types/tool_request_content_param.py +37 -0
- agentex/types/tool_request_delta.py +18 -0
- agentex/types/tool_response_content.py +36 -0
- agentex/types/tool_response_content_param.py +36 -0
- agentex/types/tool_response_delta.py +18 -0
- agentex/types/tracker_list_params.py +16 -0
- agentex/types/tracker_list_response.py +10 -0
- agentex/types/tracker_update_params.py +19 -0
- agentex_sdk-0.1.0a6.dist-info/METADATA +426 -0
- agentex_sdk-0.1.0a6.dist-info/RECORD +289 -0
- agentex_sdk-0.1.0a6.dist-info/WHEEL +4 -0
- agentex_sdk-0.1.0a6.dist-info/entry_points.txt +2 -0
- agentex_sdk-0.1.0a6.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
from contextlib import asynccontextmanager
|
2
|
+
from typing import AsyncGenerator, Callable
|
3
|
+
|
4
|
+
from fastapi import FastAPI
|
5
|
+
|
6
|
+
from agentex.lib.core.clients.temporal.temporal_client import TemporalClient
|
7
|
+
from agentex.lib.core.temporal.services.temporal_task_service import TemporalTaskService
|
8
|
+
from agentex.lib.environment_variables import EnvironmentVariables
|
9
|
+
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
10
|
+
from agentex.lib.types.acp import (
|
11
|
+
CancelTaskParams,
|
12
|
+
CreateTaskParams,
|
13
|
+
SendEventParams,
|
14
|
+
)
|
15
|
+
from agentex.lib.utils.logging import make_logger
|
16
|
+
|
17
|
+
logger = make_logger(__name__)
|
18
|
+
|
19
|
+
|
20
|
+
class TemporalACP(BaseACPServer):
|
21
|
+
"""
|
22
|
+
Temporal-specific implementation of AsyncAgentACP.
|
23
|
+
Uses TaskService to forward operations to temporal workflows.
|
24
|
+
"""
|
25
|
+
|
26
|
+
def __init__(
|
27
|
+
self, temporal_address: str, temporal_task_service: TemporalTaskService | None = None
|
28
|
+
):
|
29
|
+
super().__init__()
|
30
|
+
self._temporal_task_service = temporal_task_service
|
31
|
+
self._temporal_address = temporal_address
|
32
|
+
|
33
|
+
@classmethod
|
34
|
+
def create(cls, temporal_address: str) -> "TemporalACP":
|
35
|
+
logger.info("Initializing TemporalACP instance")
|
36
|
+
|
37
|
+
# Create instance without temporal client initially
|
38
|
+
temporal_acp = cls(temporal_address=temporal_address)
|
39
|
+
temporal_acp._setup_handlers()
|
40
|
+
logger.info("TemporalACP instance initialized now")
|
41
|
+
return temporal_acp
|
42
|
+
|
43
|
+
# This is to override the lifespan function of the base
|
44
|
+
def get_lifespan_function(self) -> Callable[[FastAPI], AsyncGenerator[None, None]]:
|
45
|
+
@asynccontextmanager
|
46
|
+
async def lifespan(app: FastAPI):
|
47
|
+
# Create temporal client during startup
|
48
|
+
if self._temporal_address is None:
|
49
|
+
raise ValueError("Temporal address is not set")
|
50
|
+
|
51
|
+
if self._temporal_task_service is None:
|
52
|
+
env_vars = EnvironmentVariables.refresh()
|
53
|
+
temporal_client = await TemporalClient.create(
|
54
|
+
temporal_address=self._temporal_address
|
55
|
+
)
|
56
|
+
self._temporal_task_service = TemporalTaskService(
|
57
|
+
temporal_client=temporal_client,
|
58
|
+
env_vars=env_vars,
|
59
|
+
)
|
60
|
+
|
61
|
+
# Call parent lifespan for agent registration
|
62
|
+
async with super().get_lifespan_function()(app):
|
63
|
+
yield
|
64
|
+
|
65
|
+
return lifespan
|
66
|
+
|
67
|
+
def _setup_handlers(self):
|
68
|
+
"""Set up the handlers for temporal workflow operations"""
|
69
|
+
|
70
|
+
@self.on_task_create
|
71
|
+
async def handle_task_create(params: CreateTaskParams) -> None:
|
72
|
+
"""Default create task handler - logs the task"""
|
73
|
+
logger.info(f"TemporalACP received task create rpc call for task {params.task.id}")
|
74
|
+
await self._temporal_task_service.submit_task(agent=params.agent, task=params.task)
|
75
|
+
|
76
|
+
@self.on_task_event_send
|
77
|
+
async def handle_event_send(params: SendEventParams) -> None:
|
78
|
+
"""Forward messages to running workflows via TaskService"""
|
79
|
+
try:
|
80
|
+
await self._temporal_task_service.send_event(
|
81
|
+
agent=params.agent,
|
82
|
+
task=params.task,
|
83
|
+
event=params.event,
|
84
|
+
)
|
85
|
+
|
86
|
+
except Exception as e:
|
87
|
+
logger.error(f"Failed to send message: {e}")
|
88
|
+
raise
|
89
|
+
|
90
|
+
@self.on_task_cancel
|
91
|
+
async def handle_cancel(params: CancelTaskParams) -> None:
|
92
|
+
"""Cancel running workflows via TaskService"""
|
93
|
+
try:
|
94
|
+
await self._temporal_task_service.cancel(task_id=params.task.id)
|
95
|
+
except Exception as e:
|
96
|
+
logger.error(f"Failed to cancel task: {e}")
|
97
|
+
raise
|
@@ -0,0 +1,297 @@
|
|
1
|
+
# BaseACPServer Test Suite
|
2
|
+
|
3
|
+
This directory contains comprehensive tests for the `BaseACPServer` and its implementations (`SyncACP`, `AgenticBaseACP`, and `TemporalACP`).
|
4
|
+
|
5
|
+
## Test Structure
|
6
|
+
|
7
|
+
The test suite is organized into several categories:
|
8
|
+
|
9
|
+
### 1. Core Unit Tests (`test_base_acp_server.py`)
|
10
|
+
- **TestBaseACPServerInitialization**: Server initialization and setup
|
11
|
+
- **TestHealthCheckEndpoint**: Health check endpoint functionality
|
12
|
+
- **TestJSONRPCEndpointCore**: Basic JSON-RPC endpoint functionality
|
13
|
+
- **TestHandlerRegistration**: Handler registration and management
|
14
|
+
- **TestBackgroundProcessing**: Background task processing
|
15
|
+
- **TestErrorHandling**: Basic error handling scenarios
|
16
|
+
|
17
|
+
### 2. JSON-RPC Endpoint Tests (`test_json_rpc_endpoints.py`)
|
18
|
+
- **TestJSONRPCMethodHandling**: Method routing and execution
|
19
|
+
- **TestJSONRPCParameterValidation**: Parameter parsing and validation
|
20
|
+
- **TestJSONRPCResponseFormat**: Response formatting compliance
|
21
|
+
- **TestJSONRPCErrorCodes**: JSON-RPC 2.0 error code compliance
|
22
|
+
- **TestJSONRPCConcurrency**: Concurrent request handling
|
23
|
+
|
24
|
+
### 3. Integration Tests (`test_server_integration.py`)
|
25
|
+
- **TestServerLifecycle**: Server startup, running, and shutdown
|
26
|
+
- **TestHTTPClientIntegration**: Real HTTP client interactions
|
27
|
+
- **TestHandlerExecutionIntegration**: Handler execution in server environment
|
28
|
+
- **TestServerPerformance**: Performance characteristics
|
29
|
+
|
30
|
+
### 4. Implementation Tests (`test_implementations.py`)
|
31
|
+
- **TestSyncACP**: SyncACP-specific functionality
|
32
|
+
- **TestAgenticBaseACP**: AgenticBaseACP-specific functionality
|
33
|
+
- **TestTemporalACP**: TemporalACP-specific functionality
|
34
|
+
- **TestImplementationComparison**: Differences between implementations
|
35
|
+
- **TestImplementationErrorHandling**: Implementation-specific error handling
|
36
|
+
|
37
|
+
### 5. Error Handling Tests (`test_error_handling.py`)
|
38
|
+
- **TestMalformedRequestHandling**: Invalid and malformed requests
|
39
|
+
- **TestHandlerErrorHandling**: Handler-level error scenarios
|
40
|
+
- **TestServerErrorHandling**: Server-level error handling
|
41
|
+
- **TestEdgeCases**: Edge cases and boundary conditions
|
42
|
+
|
43
|
+
## Running Tests
|
44
|
+
|
45
|
+
### Prerequisites
|
46
|
+
|
47
|
+
Install test dependencies:
|
48
|
+
```bash
|
49
|
+
pip install pytest pytest-asyncio httpx pytest-cov pytest-xdist
|
50
|
+
```
|
51
|
+
|
52
|
+
### Basic Usage
|
53
|
+
|
54
|
+
Run all tests:
|
55
|
+
```bash
|
56
|
+
python run_tests.py
|
57
|
+
```
|
58
|
+
|
59
|
+
Run specific test categories:
|
60
|
+
```bash
|
61
|
+
python run_tests.py --category unit
|
62
|
+
python run_tests.py --category integration
|
63
|
+
python run_tests.py --category implementations
|
64
|
+
python run_tests.py --category error
|
65
|
+
```
|
66
|
+
|
67
|
+
### Advanced Options
|
68
|
+
|
69
|
+
Run with coverage:
|
70
|
+
```bash
|
71
|
+
python run_tests.py --coverage
|
72
|
+
```
|
73
|
+
|
74
|
+
Run in parallel:
|
75
|
+
```bash
|
76
|
+
python run_tests.py --parallel 4
|
77
|
+
```
|
78
|
+
|
79
|
+
Run with increased verbosity:
|
80
|
+
```bash
|
81
|
+
python run_tests.py -vv
|
82
|
+
```
|
83
|
+
|
84
|
+
Stop on first failure:
|
85
|
+
```bash
|
86
|
+
python run_tests.py --failfast
|
87
|
+
```
|
88
|
+
|
89
|
+
Run only failed tests from last run:
|
90
|
+
```bash
|
91
|
+
python run_tests.py --lf
|
92
|
+
```
|
93
|
+
|
94
|
+
### Quick Test Options
|
95
|
+
|
96
|
+
For development, use these quick test commands:
|
97
|
+
|
98
|
+
```bash
|
99
|
+
# Quick smoke tests
|
100
|
+
python run_tests.py smoke
|
101
|
+
|
102
|
+
# Quick development tests
|
103
|
+
python run_tests.py quick
|
104
|
+
|
105
|
+
# Performance tests only
|
106
|
+
python run_tests.py perf
|
107
|
+
```
|
108
|
+
|
109
|
+
### Direct pytest Usage
|
110
|
+
|
111
|
+
You can also run tests directly with pytest:
|
112
|
+
|
113
|
+
```bash
|
114
|
+
# Run all tests
|
115
|
+
pytest
|
116
|
+
|
117
|
+
# Run specific test file
|
118
|
+
pytest test_base_acp_server.py
|
119
|
+
|
120
|
+
# Run specific test class
|
121
|
+
pytest test_base_acp_server.py::TestBaseACPServerInitialization
|
122
|
+
|
123
|
+
# Run specific test method
|
124
|
+
pytest test_base_acp_server.py::TestBaseACPServerInitialization::test_base_acp_server_init
|
125
|
+
|
126
|
+
# Run with markers
|
127
|
+
pytest -m "not slow"
|
128
|
+
```
|
129
|
+
|
130
|
+
## Test Configuration
|
131
|
+
|
132
|
+
### Fixtures (`conftest.py`)
|
133
|
+
|
134
|
+
The test suite uses several fixtures:
|
135
|
+
|
136
|
+
- **`free_port`**: Provides a free port for testing
|
137
|
+
- **`sample_task`**, **`sample_message`**: Sample data objects
|
138
|
+
- **`base_acp_server`**, **`sync_acp`**, **`agentic_base_acp`**, **`mock_temporal_acp`**: Server instances
|
139
|
+
- **`test_server_runner`**: Manages server lifecycle for integration tests
|
140
|
+
- **`jsonrpc_client_factory`**: Creates JSON-RPC test clients
|
141
|
+
- **`mock_env_vars`**: Mocked environment variables
|
142
|
+
|
143
|
+
### Test Utilities
|
144
|
+
|
145
|
+
- **`TestServerRunner`**: Manages server startup/shutdown for integration tests
|
146
|
+
- **`JSONRPCTestClient`**: Simplified JSON-RPC client for testing
|
147
|
+
- **`find_free_port()`**: Utility to find available ports
|
148
|
+
|
149
|
+
## Test Categories Explained
|
150
|
+
|
151
|
+
### Unit Tests
|
152
|
+
Focus on individual components in isolation:
|
153
|
+
- Server initialization
|
154
|
+
- Handler registration
|
155
|
+
- Basic endpoint functionality
|
156
|
+
- Parameter validation
|
157
|
+
|
158
|
+
### Integration Tests
|
159
|
+
Test components working together:
|
160
|
+
- Full server lifecycle
|
161
|
+
- Real HTTP requests
|
162
|
+
- Handler execution in server context
|
163
|
+
- Performance characteristics
|
164
|
+
|
165
|
+
### Implementation Tests
|
166
|
+
Test specific ACP implementations:
|
167
|
+
- SyncACP behavior
|
168
|
+
- AgenticBaseACP send_event functionality
|
169
|
+
- TemporalACP workflow integration
|
170
|
+
- Implementation differences
|
171
|
+
|
172
|
+
### Error Handling Tests
|
173
|
+
Comprehensive error scenarios:
|
174
|
+
- Malformed JSON-RPC requests
|
175
|
+
- Handler exceptions
|
176
|
+
- Server error recovery
|
177
|
+
- Edge cases and boundary conditions
|
178
|
+
|
179
|
+
## Writing New Tests
|
180
|
+
|
181
|
+
### Test Naming Convention
|
182
|
+
- Test files: `test_*.py`
|
183
|
+
- Test classes: `Test*`
|
184
|
+
- Test methods: `test_*`
|
185
|
+
|
186
|
+
### Async Test Example
|
187
|
+
```python
|
188
|
+
@pytest.mark.asyncio
|
189
|
+
async def test_my_async_functionality(self, base_acp_server):
|
190
|
+
# Your async test code here
|
191
|
+
result = await some_async_operation()
|
192
|
+
assert result is not None
|
193
|
+
```
|
194
|
+
|
195
|
+
### Integration Test Example
|
196
|
+
```python
|
197
|
+
@pytest.mark.asyncio
|
198
|
+
async def test_server_integration(self, base_acp_server, free_port, test_server_runner):
|
199
|
+
runner = test_server_runner(base_acp_server, free_port)
|
200
|
+
await runner.start()
|
201
|
+
|
202
|
+
try:
|
203
|
+
# Test server functionality
|
204
|
+
async with httpx.AsyncClient() as client:
|
205
|
+
response = await client.get(f"http://127.0.0.1:{free_port}/healthz")
|
206
|
+
assert response.status_code == 200
|
207
|
+
finally:
|
208
|
+
await runner.stop()
|
209
|
+
```
|
210
|
+
|
211
|
+
### Handler Test Example
|
212
|
+
```python
|
213
|
+
@pytest.mark.asyncio
|
214
|
+
async def test_custom_handler(self, base_acp_server):
|
215
|
+
handler_called = False
|
216
|
+
|
217
|
+
@base_acp_server.on_task_event_send
|
218
|
+
async def test_handler(params: SendEventParams):
|
219
|
+
nonlocal handler_called
|
220
|
+
handler_called = True
|
221
|
+
return {"handled": True}
|
222
|
+
|
223
|
+
# Test handler execution
|
224
|
+
params = SendEventParams(...)
|
225
|
+
result = await base_acp_server._handlers[RPCMethod.EVENT_SEND](params)
|
226
|
+
|
227
|
+
assert handler_called is True
|
228
|
+
assert result["handled"] is True
|
229
|
+
```
|
230
|
+
|
231
|
+
## Continuous Integration
|
232
|
+
|
233
|
+
The test suite is designed to work well in CI environments:
|
234
|
+
|
235
|
+
- Tests are isolated and don't interfere with each other
|
236
|
+
- Ports are dynamically allocated to avoid conflicts
|
237
|
+
- Background tasks are properly cleaned up
|
238
|
+
- Timeouts are reasonable for CI environments
|
239
|
+
|
240
|
+
### CI Configuration Example
|
241
|
+
|
242
|
+
```yaml
|
243
|
+
# .github/workflows/test.yml
|
244
|
+
name: Tests
|
245
|
+
on: [push, pull_request]
|
246
|
+
jobs:
|
247
|
+
test:
|
248
|
+
runs-on: ubuntu-latest
|
249
|
+
steps:
|
250
|
+
- uses: actions/checkout@v2
|
251
|
+
- uses: actions/setup-python@v2
|
252
|
+
with:
|
253
|
+
python-version: '3.9'
|
254
|
+
- run: pip install -r requirements.txt
|
255
|
+
- run: pip install pytest pytest-asyncio httpx pytest-cov
|
256
|
+
- run: cd agentex/sdk/fastacp/tests && python run_tests.py --coverage
|
257
|
+
```
|
258
|
+
|
259
|
+
## Troubleshooting
|
260
|
+
|
261
|
+
### Common Issues
|
262
|
+
|
263
|
+
1. **Port conflicts**: Tests use dynamic port allocation, but if you see port conflicts, try running tests sequentially:
|
264
|
+
```bash
|
265
|
+
python run_tests.py --parallel 1
|
266
|
+
```
|
267
|
+
|
268
|
+
2. **Async test failures**: Make sure all async tests are marked with `@pytest.mark.asyncio`
|
269
|
+
|
270
|
+
3. **Handler not found errors**: Ensure handlers are properly registered before testing
|
271
|
+
|
272
|
+
4. **Timeout issues**: Some tests have built-in delays for background processing. If tests are flaky, increase sleep times in test code.
|
273
|
+
|
274
|
+
### Debug Mode
|
275
|
+
|
276
|
+
Run tests with maximum verbosity and no capture:
|
277
|
+
```bash
|
278
|
+
pytest -vvv -s --tb=long
|
279
|
+
```
|
280
|
+
|
281
|
+
### Memory Issues
|
282
|
+
|
283
|
+
If you encounter memory issues with large tests:
|
284
|
+
```bash
|
285
|
+
python run_tests.py --markers "not memory_intensive"
|
286
|
+
```
|
287
|
+
|
288
|
+
## Contributing
|
289
|
+
|
290
|
+
When adding new tests:
|
291
|
+
|
292
|
+
1. Follow the existing test structure and naming conventions
|
293
|
+
2. Add appropriate docstrings explaining what the test does
|
294
|
+
3. Use fixtures for common setup
|
295
|
+
4. Clean up resources properly (especially in integration tests)
|
296
|
+
5. Add tests to the appropriate category in `run_tests.py`
|
297
|
+
6. Update this README if adding new test categories or significant functionality
|
@@ -0,0 +1,307 @@
|
|
1
|
+
import asyncio
|
2
|
+
import socket
|
3
|
+
import time
|
4
|
+
from typing import Any
|
5
|
+
from unittest.mock import AsyncMock, patch
|
6
|
+
|
7
|
+
import httpx
|
8
|
+
import pytest
|
9
|
+
import pytest_asyncio
|
10
|
+
import uvicorn
|
11
|
+
|
12
|
+
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
13
|
+
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
14
|
+
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
15
|
+
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
16
|
+
from agentex.lib.types.acp import (
|
17
|
+
CancelTaskParams,
|
18
|
+
CreateTaskParams,
|
19
|
+
SendMessageParams,
|
20
|
+
)
|
21
|
+
from agentex.lib.types.json_rpc import JSONRPCRequest
|
22
|
+
from agentex.types.agent import Agent
|
23
|
+
from agentex.types.task_message import TaskMessageContent
|
24
|
+
from agentex.types.task_message_content import TextContent
|
25
|
+
from agentex.types.task import Task
|
26
|
+
|
27
|
+
# Configure pytest-asyncio
|
28
|
+
pytest_plugins = ("pytest_asyncio",)
|
29
|
+
|
30
|
+
|
31
|
+
def find_free_port() -> int:
|
32
|
+
"""Find a free port for testing"""
|
33
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
34
|
+
s.bind(("", 0))
|
35
|
+
s.listen(1)
|
36
|
+
port = s.getsockname()[1]
|
37
|
+
return port
|
38
|
+
|
39
|
+
|
40
|
+
@pytest.fixture
|
41
|
+
def free_port() -> int:
|
42
|
+
"""Fixture that provides a free port for testing"""
|
43
|
+
return find_free_port()
|
44
|
+
|
45
|
+
|
46
|
+
@pytest.fixture
|
47
|
+
def sample_task() -> Task:
|
48
|
+
"""Fixture that provides a sample Task object"""
|
49
|
+
return Task(
|
50
|
+
id="test-task-123", agent_id="test-agent-456", status=TaskStatus.RUNNING
|
51
|
+
)
|
52
|
+
|
53
|
+
|
54
|
+
@pytest.fixture
|
55
|
+
def sample_message_content() -> TaskMessageContent:
|
56
|
+
"""Fixture that provides a sample TaskMessage object"""
|
57
|
+
return TextContent(
|
58
|
+
type="text",
|
59
|
+
author="user",
|
60
|
+
content="Hello, this is a test message",
|
61
|
+
)
|
62
|
+
|
63
|
+
|
64
|
+
@pytest.fixture
|
65
|
+
def sample_send_message_params(
|
66
|
+
sample_task: Task, sample_message_content: TaskMessageContent
|
67
|
+
) -> SendMessageParams:
|
68
|
+
"""Fixture that provides sample SendMessageParams"""
|
69
|
+
return SendMessageParams(
|
70
|
+
agent=Agent(
|
71
|
+
id="test-agent-456",
|
72
|
+
name="test-agent",
|
73
|
+
description="test-agent",
|
74
|
+
acp_type="sync",
|
75
|
+
),
|
76
|
+
task=sample_task,
|
77
|
+
content=sample_message_content,
|
78
|
+
stream=False,
|
79
|
+
)
|
80
|
+
|
81
|
+
|
82
|
+
@pytest.fixture
|
83
|
+
def sample_cancel_task_params() -> CancelTaskParams:
|
84
|
+
"""Fixture that provides sample CancelTaskParams"""
|
85
|
+
return CancelTaskParams(
|
86
|
+
agent=Agent(id="test-agent-456", name="test-agent", description="test-agent", acp_type="sync"),
|
87
|
+
task=Task(id="test-task-123", agent_id="test-agent-456", status="running"),
|
88
|
+
)
|
89
|
+
|
90
|
+
|
91
|
+
@pytest.fixture
|
92
|
+
def sample_create_task_params(sample_task: Task) -> CreateTaskParams:
|
93
|
+
"""Fixture that provides sample CreateTaskParams"""
|
94
|
+
return CreateTaskParams(
|
95
|
+
agent=Agent(id="test-agent-456", name="test-agent", description="test-agent", acp_type="sync"),
|
96
|
+
task=sample_task,
|
97
|
+
params={},
|
98
|
+
)
|
99
|
+
|
100
|
+
|
101
|
+
class TestServerRunner:
|
102
|
+
"""Utility class for running test servers"""
|
103
|
+
|
104
|
+
def __init__(self, app: BaseACPServer, port: int):
|
105
|
+
self.app = app
|
106
|
+
self.port = port
|
107
|
+
self.server = None
|
108
|
+
self.server_task = None
|
109
|
+
|
110
|
+
async def start(self):
|
111
|
+
"""Start the server in a background task"""
|
112
|
+
config = uvicorn.Config(
|
113
|
+
app=self.app,
|
114
|
+
host="127.0.0.1",
|
115
|
+
port=self.port,
|
116
|
+
log_level="error", # Reduce noise in tests
|
117
|
+
)
|
118
|
+
self.server = uvicorn.Server(config)
|
119
|
+
self.server_task = asyncio.create_task(self.server.serve())
|
120
|
+
|
121
|
+
# Wait for server to be ready
|
122
|
+
await self._wait_for_server()
|
123
|
+
|
124
|
+
async def stop(self):
|
125
|
+
"""Stop the server"""
|
126
|
+
if self.server:
|
127
|
+
self.server.should_exit = True
|
128
|
+
if self.server_task:
|
129
|
+
try:
|
130
|
+
await asyncio.wait_for(self.server_task, timeout=5.0)
|
131
|
+
except TimeoutError:
|
132
|
+
self.server_task.cancel()
|
133
|
+
try:
|
134
|
+
await self.server_task
|
135
|
+
except asyncio.CancelledError:
|
136
|
+
pass
|
137
|
+
|
138
|
+
async def _wait_for_server(self, timeout: float = 10.0):
|
139
|
+
"""Wait for server to be ready to accept connections"""
|
140
|
+
start_time = time.time()
|
141
|
+
while time.time() - start_time < timeout:
|
142
|
+
try:
|
143
|
+
async with httpx.AsyncClient() as client:
|
144
|
+
response = await client.get(f"http://127.0.0.1:{self.port}/healthz")
|
145
|
+
if response.status_code == 200:
|
146
|
+
return
|
147
|
+
except (httpx.ConnectError, httpx.ConnectTimeout):
|
148
|
+
await asyncio.sleep(0.1)
|
149
|
+
raise TimeoutError(f"Server did not start within {timeout} seconds")
|
150
|
+
|
151
|
+
|
152
|
+
@pytest_asyncio.fixture
|
153
|
+
async def test_server_runner():
|
154
|
+
"""Fixture that provides a TestServerRunner factory"""
|
155
|
+
runners = []
|
156
|
+
|
157
|
+
def create_runner(app: BaseACPServer, port: int) -> TestServerRunner:
|
158
|
+
runner = TestServerRunner(app, port)
|
159
|
+
runners.append(runner)
|
160
|
+
return runner
|
161
|
+
|
162
|
+
yield create_runner
|
163
|
+
|
164
|
+
# Cleanup all runners
|
165
|
+
for runner in runners:
|
166
|
+
await runner.stop()
|
167
|
+
|
168
|
+
|
169
|
+
@pytest.fixture
|
170
|
+
def base_acp_server():
|
171
|
+
"""Fixture that provides a BaseACPServer instance for sync tests"""
|
172
|
+
with patch.dict(
|
173
|
+
"os.environ", {"AGENTEX_BASE_URL": ""}
|
174
|
+
): # Disable agent registration
|
175
|
+
server = BaseACPServer()
|
176
|
+
return server
|
177
|
+
|
178
|
+
|
179
|
+
@pytest_asyncio.fixture
|
180
|
+
async def async_base_acp_server():
|
181
|
+
"""Fixture that provides a BaseACPServer instance for async tests"""
|
182
|
+
with patch.dict(
|
183
|
+
"os.environ", {"AGENTEX_BASE_URL": ""}
|
184
|
+
): # Disable agent registration
|
185
|
+
server = BaseACPServer.create()
|
186
|
+
return server
|
187
|
+
|
188
|
+
|
189
|
+
@pytest.fixture
|
190
|
+
def sync_acp_server():
|
191
|
+
"""Fixture that provides a SyncACP instance for sync tests"""
|
192
|
+
with patch.dict(
|
193
|
+
"os.environ", {"AGENTEX_BASE_URL": ""}
|
194
|
+
): # Disable agent registration
|
195
|
+
server = SyncACP()
|
196
|
+
return server
|
197
|
+
|
198
|
+
|
199
|
+
@pytest_asyncio.fixture
|
200
|
+
async def async_sync_acp_server():
|
201
|
+
"""Fixture that provides a SyncACP instance for async tests"""
|
202
|
+
with patch.dict(
|
203
|
+
"os.environ", {"AGENTEX_BASE_URL": ""}
|
204
|
+
): # Disable agent registration
|
205
|
+
server = await SyncACP.create()
|
206
|
+
return server
|
207
|
+
|
208
|
+
|
209
|
+
@pytest.fixture
|
210
|
+
def agentic_base_acp_server():
|
211
|
+
"""Fixture that provides an AgenticBaseACP instance for sync tests"""
|
212
|
+
with patch.dict(
|
213
|
+
"os.environ", {"AGENTEX_BASE_URL": ""}
|
214
|
+
): # Disable agent registration
|
215
|
+
server = AgenticBaseACP()
|
216
|
+
return server
|
217
|
+
|
218
|
+
|
219
|
+
@pytest_asyncio.fixture
|
220
|
+
async def async_agentic_base_acp_server():
|
221
|
+
"""Fixture that provides an AgenticBaseACP instance for async tests"""
|
222
|
+
with patch.dict(
|
223
|
+
"os.environ", {"AGENTEX_BASE_URL": ""}
|
224
|
+
): # Disable agent registration
|
225
|
+
server = await AgenticBaseACP.create()
|
226
|
+
return server
|
227
|
+
|
228
|
+
|
229
|
+
@pytest_asyncio.fixture
|
230
|
+
async def mock_temporal_acp_server():
|
231
|
+
"""Fixture that provides a mocked TemporalACP instance"""
|
232
|
+
with patch.dict(
|
233
|
+
"os.environ", {"AGENTEX_BASE_URL": ""}
|
234
|
+
): # Disable agent registration
|
235
|
+
with patch(
|
236
|
+
"agentex.sdk.fastacp.impl.temporal_acp.TemporalClient"
|
237
|
+
) as mock_temporal_client:
|
238
|
+
with patch(
|
239
|
+
"agentex.sdk.fastacp.impl.temporal_acp.AsyncAgentexClient"
|
240
|
+
) as mock_agentex_client:
|
241
|
+
# Mock the temporal client creation
|
242
|
+
mock_temporal_client.create.return_value = AsyncMock()
|
243
|
+
mock_agentex_client.return_value = AsyncMock()
|
244
|
+
|
245
|
+
server = await TemporalACP.create(temporal_address="localhost:7233")
|
246
|
+
return server
|
247
|
+
|
248
|
+
|
249
|
+
class JSONRPCTestClient:
|
250
|
+
"""Test client for making JSON-RPC requests"""
|
251
|
+
|
252
|
+
def __init__(self, base_url: str):
|
253
|
+
self.base_url = base_url
|
254
|
+
|
255
|
+
async def call_method(
|
256
|
+
self, method: str, params: dict[str, Any], request_id: str | None = "test-1"
|
257
|
+
) -> dict[str, Any]:
|
258
|
+
"""Make a JSON-RPC method call"""
|
259
|
+
request = JSONRPCRequest(method=method, params=params, id=request_id)
|
260
|
+
|
261
|
+
async with httpx.AsyncClient() as client:
|
262
|
+
response = await client.post(
|
263
|
+
f"{self.base_url}/api",
|
264
|
+
json=request.model_dump(),
|
265
|
+
headers={"Content-Type": "application/json"},
|
266
|
+
)
|
267
|
+
return response.json()
|
268
|
+
|
269
|
+
async def send_notification(
|
270
|
+
self, method: str, params: dict[str, Any]
|
271
|
+
) -> dict[str, Any]:
|
272
|
+
"""Send a JSON-RPC notification (no ID)"""
|
273
|
+
return await self.call_method(method, params, request_id=None)
|
274
|
+
|
275
|
+
async def health_check(self) -> dict[str, Any]:
|
276
|
+
"""Check server health"""
|
277
|
+
async with httpx.AsyncClient() as client:
|
278
|
+
response = await client.get(f"{self.base_url}/healthz")
|
279
|
+
return response.json()
|
280
|
+
|
281
|
+
|
282
|
+
@pytest.fixture
|
283
|
+
def jsonrpc_client_factory():
|
284
|
+
"""Fixture that provides a JSONRPCTestClient factory"""
|
285
|
+
|
286
|
+
def create_client(base_url: str) -> JSONRPCTestClient:
|
287
|
+
return JSONRPCTestClient(base_url)
|
288
|
+
|
289
|
+
return create_client
|
290
|
+
|
291
|
+
|
292
|
+
# Mock environment variables for testing
|
293
|
+
@pytest.fixture
|
294
|
+
def mock_env_vars():
|
295
|
+
"""Fixture that mocks environment variables"""
|
296
|
+
env_vars = {
|
297
|
+
"AGENTEX_BASE_URL": "", # Disable agent registration by default
|
298
|
+
"AGENT_NAME": "test-agent",
|
299
|
+
"AGENT_DESCRIPTION": "Test agent description",
|
300
|
+
"ACP_URL": "http://localhost",
|
301
|
+
"ACP_PORT": "8000",
|
302
|
+
"WORKFLOW_NAME": "test-workflow",
|
303
|
+
"WORKFLOW_TASK_QUEUE": "test-queue",
|
304
|
+
}
|
305
|
+
|
306
|
+
with patch.dict("os.environ", env_vars):
|
307
|
+
yield env_vars
|