agentex-sdk 0.6.0__py3-none-any.whl → 0.6.2__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/_client.py +15 -1
- agentex/_version.py +1 -1
- agentex/lib/adk/providers/_modules/litellm.py +1 -1
- agentex/lib/adk/providers/_modules/openai.py +16 -1
- agentex/lib/adk/providers/_modules/sgp.py +1 -1
- agentex/lib/adk/providers/_modules/sync_provider.py +32 -24
- agentex/lib/cli/commands/init.py +7 -18
- agentex/lib/cli/templates/default/README.md.j2 +1 -1
- agentex/lib/cli/templates/default/dev.ipynb.j2 +1 -1
- agentex/lib/cli/templates/default/manifest.yaml.j2 +1 -4
- agentex/lib/cli/templates/default/project/acp.py.j2 +3 -3
- agentex/lib/cli/templates/default/test_agent.py.j2 +1 -1
- agentex/lib/cli/templates/sync/manifest.yaml.j2 +0 -3
- agentex/lib/cli/templates/temporal/README.md.j2 +1 -1
- agentex/lib/cli/templates/temporal/dev.ipynb.j2 +1 -1
- agentex/lib/cli/templates/temporal/manifest.yaml.j2 +2 -5
- agentex/lib/cli/templates/temporal/project/acp.py.j2 +1 -1
- agentex/lib/cli/templates/temporal/test_agent.py.j2 +1 -1
- agentex/lib/core/temporal/plugins/openai_agents/models/temporal_streaming_model.py +66 -0
- agentex/lib/core/temporal/plugins/openai_agents/models/temporal_tracing_model.py +94 -17
- agentex/lib/environment_variables.py +1 -1
- agentex/lib/sdk/config/agent_config.py +1 -1
- agentex/lib/sdk/fastacp/base/base_acp_server.py +4 -4
- agentex/lib/sdk/fastacp/fastacp.py +30 -16
- agentex/lib/sdk/fastacp/impl/{agentic_base_acp.py → async_base_acp.py} +10 -8
- agentex/lib/sdk/fastacp/tests/README.md +3 -3
- agentex/lib/sdk/fastacp/tests/conftest.py +4 -4
- agentex/lib/sdk/fastacp/tests/test_fastacp_factory.py +99 -72
- agentex/lib/sdk/fastacp/tests/test_integration.py +24 -24
- agentex/lib/types/fastacp.py +8 -5
- agentex/lib/utils/dev_tools/async_messages.py +1 -1
- agentex/resources/__init__.py +14 -0
- agentex/resources/deployment_history.py +272 -0
- agentex/types/__init__.py +3 -0
- agentex/types/agent.py +4 -1
- agentex/types/deployment_history.py +33 -0
- agentex/types/deployment_history_list_params.py +18 -0
- agentex/types/deployment_history_list_response.py +10 -0
- {agentex_sdk-0.6.0.dist-info → agentex_sdk-0.6.2.dist-info}/METADATA +1 -1
- {agentex_sdk-0.6.0.dist-info → agentex_sdk-0.6.2.dist-info}/RECORD +43 -39
- {agentex_sdk-0.6.0.dist-info → agentex_sdk-0.6.2.dist-info}/WHEEL +0 -0
- {agentex_sdk-0.6.0.dist-info → agentex_sdk-0.6.2.dist-info}/entry_points.txt +0 -0
- {agentex_sdk-0.6.0.dist-info → agentex_sdk-0.6.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -61,7 +61,7 @@ class EnvironmentVariables(BaseModel):
|
|
|
61
61
|
AGENT_DESCRIPTION: str | None = None
|
|
62
62
|
AGENT_ID: str | None = None
|
|
63
63
|
AGENT_API_KEY: str | None = None
|
|
64
|
-
ACP_TYPE: str | None = "
|
|
64
|
+
ACP_TYPE: str | None = "async"
|
|
65
65
|
AGENT_INPUT_TYPE: str | None = None
|
|
66
66
|
# ACP Configuration
|
|
67
67
|
ACP_URL: str
|
|
@@ -18,7 +18,7 @@ class AgentConfig(BaseModel):
|
|
|
18
18
|
description="The name of the agent.",
|
|
19
19
|
pattern=r"^[a-z0-9-]+$",
|
|
20
20
|
)
|
|
21
|
-
acp_type: Literal["sync", "agentic"] = Field(..., description="The type of agent.")
|
|
21
|
+
acp_type: Literal["sync", "async", "agentic"] = Field(..., description="The type of agent.")
|
|
22
22
|
agent_input_type: Literal["text", "json"] | None = Field(
|
|
23
23
|
default=None,
|
|
24
24
|
description="The type of input the agent accepts."
|
|
@@ -299,7 +299,7 @@ class BaseACPServer(FastAPI):
|
|
|
299
299
|
Define all possible decorators to be overriden and implemented by each ACP implementation
|
|
300
300
|
Then the users can override the default handlers by implementing their own handlers
|
|
301
301
|
|
|
302
|
-
ACP Type:
|
|
302
|
+
ACP Type: Async
|
|
303
303
|
Decorators:
|
|
304
304
|
- on_task_create
|
|
305
305
|
- on_task_event_send
|
|
@@ -310,14 +310,14 @@ class BaseACPServer(FastAPI):
|
|
|
310
310
|
- on_message_send
|
|
311
311
|
"""
|
|
312
312
|
|
|
313
|
-
# Type:
|
|
313
|
+
# Type: Async
|
|
314
314
|
def on_task_create(self, fn: Callable[[CreateTaskParams], Awaitable[Any]]):
|
|
315
315
|
"""Handle task/init method"""
|
|
316
316
|
wrapped = self._wrap_handler(fn)
|
|
317
317
|
self._handlers[RPCMethod.TASK_CREATE] = wrapped
|
|
318
318
|
return fn
|
|
319
319
|
|
|
320
|
-
# Type:
|
|
320
|
+
# Type: Async
|
|
321
321
|
def on_task_event_send(self, fn: Callable[[SendEventParams], Awaitable[Any]]):
|
|
322
322
|
"""Handle event/send method"""
|
|
323
323
|
|
|
@@ -335,7 +335,7 @@ class BaseACPServer(FastAPI):
|
|
|
335
335
|
self._handlers[RPCMethod.EVENT_SEND] = wrapped
|
|
336
336
|
return fn
|
|
337
337
|
|
|
338
|
-
# Type:
|
|
338
|
+
# Type: Async
|
|
339
339
|
def on_task_cancel(self, fn: Callable[[CancelTaskParams], Awaitable[Any]]):
|
|
340
340
|
"""Handle task/cancel method"""
|
|
341
341
|
wrapped = self._wrap_handler(fn)
|
|
@@ -4,23 +4,25 @@ import os
|
|
|
4
4
|
import inspect
|
|
5
5
|
from typing import Literal
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from typing_extensions import deprecated
|
|
7
8
|
|
|
8
9
|
from agentex.lib.types.fastacp import (
|
|
9
10
|
BaseACPConfig,
|
|
10
11
|
SyncACPConfig,
|
|
12
|
+
AsyncACPConfig,
|
|
11
13
|
AgenticACPConfig,
|
|
12
14
|
)
|
|
13
15
|
from agentex.lib.utils.logging import make_logger
|
|
14
16
|
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
|
15
17
|
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
|
18
|
+
from agentex.lib.sdk.fastacp.impl.async_base_acp import AsyncBaseACP
|
|
16
19
|
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
|
17
|
-
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
|
18
20
|
|
|
19
21
|
# Add new mappings between ACP types and configs here
|
|
20
22
|
# Add new mappings between ACP types and implementations here
|
|
21
23
|
AGENTIC_ACP_IMPLEMENTATIONS: dict[Literal["temporal", "base"], type[BaseACPServer]] = {
|
|
22
24
|
"temporal": TemporalACP,
|
|
23
|
-
"base":
|
|
25
|
+
"base": AsyncBaseACP,
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
logger = make_logger(__name__)
|
|
@@ -29,9 +31,10 @@ logger = make_logger(__name__)
|
|
|
29
31
|
class FastACP:
|
|
30
32
|
"""Factory for creating FastACP instances
|
|
31
33
|
|
|
32
|
-
Supports
|
|
34
|
+
Supports three main ACP types:
|
|
33
35
|
- "sync": Simple synchronous ACP implementation
|
|
34
|
-
- "
|
|
36
|
+
- "async": Advanced ACP with sub-types "base" or "temporal" (requires config)
|
|
37
|
+
- "agentic": (Deprecated, use "async") Identical to "async"
|
|
35
38
|
"""
|
|
36
39
|
|
|
37
40
|
@staticmethod
|
|
@@ -41,11 +44,11 @@ class FastACP:
|
|
|
41
44
|
return SyncACP.create(**kwargs)
|
|
42
45
|
|
|
43
46
|
@staticmethod
|
|
44
|
-
def
|
|
45
|
-
"""Create an
|
|
47
|
+
def create_async_acp(config: AsyncACPConfig, **kwargs) -> BaseACPServer:
|
|
48
|
+
"""Create an async ACP instance (base or temporal)
|
|
46
49
|
|
|
47
50
|
Args:
|
|
48
|
-
config:
|
|
51
|
+
config: AsyncACPConfig with type="base" or type="temporal"
|
|
49
52
|
**kwargs: Additional configuration parameters
|
|
50
53
|
"""
|
|
51
54
|
# Get implementation class
|
|
@@ -64,6 +67,17 @@ class FastACP:
|
|
|
64
67
|
else:
|
|
65
68
|
return implementation_class.create(**kwargs)
|
|
66
69
|
|
|
70
|
+
@staticmethod
|
|
71
|
+
@deprecated("Use create_async_acp instead")
|
|
72
|
+
def create_agentic_acp(config: AgenticACPConfig, **kwargs) -> BaseACPServer:
|
|
73
|
+
"""Create an async ACP instance (base or temporal)
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
config: AsyncACPConfig with type="base" or type="temporal"
|
|
77
|
+
**kwargs: Additional configuration parameters
|
|
78
|
+
"""
|
|
79
|
+
return FastACP.create_async_acp(config, **kwargs)
|
|
80
|
+
|
|
67
81
|
@staticmethod
|
|
68
82
|
def locate_build_info_path() -> None:
|
|
69
83
|
"""If a build-info.json file is present, set the BUILD_INFO_PATH environment variable"""
|
|
@@ -74,13 +88,13 @@ class FastACP:
|
|
|
74
88
|
|
|
75
89
|
@staticmethod
|
|
76
90
|
def create(
|
|
77
|
-
acp_type: Literal["sync", "agentic"], config: BaseACPConfig | None = None, **kwargs
|
|
78
|
-
) -> BaseACPServer | SyncACP |
|
|
91
|
+
acp_type: Literal["sync", "async", "agentic"], config: BaseACPConfig | None = None, **kwargs
|
|
92
|
+
) -> BaseACPServer | SyncACP | AsyncBaseACP | TemporalACP:
|
|
79
93
|
"""Main factory method to create any ACP type
|
|
80
94
|
|
|
81
95
|
Args:
|
|
82
|
-
acp_type: Type of ACP to create ("sync" or "agentic")
|
|
83
|
-
config: Configuration object. Required for agentic type.
|
|
96
|
+
acp_type: Type of ACP to create ("sync", "async", or "agentic")
|
|
97
|
+
config: Configuration object. Required for async/agentic type.
|
|
84
98
|
**kwargs: Additional configuration parameters
|
|
85
99
|
"""
|
|
86
100
|
|
|
@@ -89,9 +103,9 @@ class FastACP:
|
|
|
89
103
|
if acp_type == "sync":
|
|
90
104
|
sync_config = config if isinstance(config, SyncACPConfig) else None
|
|
91
105
|
return FastACP.create_sync_acp(sync_config, **kwargs)
|
|
92
|
-
elif acp_type == "agentic":
|
|
106
|
+
elif acp_type == "async" or acp_type == "agentic":
|
|
93
107
|
if config is None:
|
|
94
|
-
config =
|
|
95
|
-
if not isinstance(config,
|
|
96
|
-
raise ValueError("
|
|
97
|
-
return FastACP.
|
|
108
|
+
config = AsyncACPConfig(type="base")
|
|
109
|
+
if not isinstance(config, AsyncACPConfig):
|
|
110
|
+
raise ValueError("AsyncACPConfig is required for async/agentic ACP type")
|
|
111
|
+
return FastACP.create_async_acp(config, **kwargs)
|
|
@@ -13,9 +13,9 @@ from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
|
|
13
13
|
logger = make_logger(__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
class
|
|
16
|
+
class AsyncBaseACP(BaseACPServer):
|
|
17
17
|
"""
|
|
18
|
-
|
|
18
|
+
AsyncBaseACP implementation - a synchronous ACP that provides basic functionality
|
|
19
19
|
without any special async orchestration like Temporal.
|
|
20
20
|
|
|
21
21
|
This implementation provides simple synchronous processing of tasks
|
|
@@ -29,7 +29,7 @@ class AgenticBaseACP(BaseACPServer):
|
|
|
29
29
|
|
|
30
30
|
@classmethod
|
|
31
31
|
@override
|
|
32
|
-
def create(cls, **kwargs: Any) -> "
|
|
32
|
+
def create(cls, **kwargs: Any) -> "AsyncBaseACP":
|
|
33
33
|
"""Create and initialize SyncACP instance
|
|
34
34
|
|
|
35
35
|
Args:
|
|
@@ -38,9 +38,9 @@ class AgenticBaseACP(BaseACPServer):
|
|
|
38
38
|
Returns:
|
|
39
39
|
Initialized SyncACP instance
|
|
40
40
|
"""
|
|
41
|
-
logger.info("Initializing
|
|
41
|
+
logger.info("Initializing AsyncBaseACP instance")
|
|
42
42
|
instance = cls()
|
|
43
|
-
logger.info("
|
|
43
|
+
logger.info("AsyncBaseACP instance initialized with default handlers")
|
|
44
44
|
return instance
|
|
45
45
|
|
|
46
46
|
@override
|
|
@@ -50,13 +50,13 @@ class AgenticBaseACP(BaseACPServer):
|
|
|
50
50
|
@self.on_task_create
|
|
51
51
|
async def handle_create_task(params: CreateTaskParams) -> None: # type: ignore[unused-function]
|
|
52
52
|
"""Default create task handler - logs the task"""
|
|
53
|
-
logger.info(f"
|
|
53
|
+
logger.info(f"AsyncBaseACP creating task {params.task.id}")
|
|
54
54
|
|
|
55
55
|
@self.on_task_event_send
|
|
56
56
|
async def handle_event_send(params: SendEventParams) -> None: # type: ignore[unused-function]
|
|
57
57
|
"""Default event handler - logs the event"""
|
|
58
58
|
logger.info(
|
|
59
|
-
f"
|
|
59
|
+
f"AsyncBaseACP received event for task {params.task.id}: {params.event.id},"
|
|
60
60
|
f"content: {params.event.content}"
|
|
61
61
|
)
|
|
62
62
|
# TODO: Implement event handling logic here
|
|
@@ -70,4 +70,6 @@ class AgenticBaseACP(BaseACPServer):
|
|
|
70
70
|
@self.on_task_cancel
|
|
71
71
|
async def handle_cancel(params: CancelTaskParams) -> None: # type: ignore[unused-function]
|
|
72
72
|
"""Default cancel handler - logs the cancellation"""
|
|
73
|
-
logger.info(f"
|
|
73
|
+
logger.info(f"AsyncBaseACP canceling task {params.task.id}")
|
|
74
|
+
|
|
75
|
+
AgenticBaseACP = AsyncBaseACP
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# BaseACPServer Test Suite
|
|
2
2
|
|
|
3
|
-
This directory contains comprehensive tests for the `BaseACPServer` and its implementations (`SyncACP`, `
|
|
3
|
+
This directory contains comprehensive tests for the `BaseACPServer` and its implementations (`SyncACP`, `AsyncBaseACP`, and `TemporalACP`).
|
|
4
4
|
|
|
5
5
|
## Test Structure
|
|
6
6
|
|
|
@@ -29,7 +29,7 @@ The test suite is organized into several categories:
|
|
|
29
29
|
|
|
30
30
|
### 4. Implementation Tests (`test_implementations.py`)
|
|
31
31
|
- **TestSyncACP**: SyncACP-specific functionality
|
|
32
|
-
- **
|
|
32
|
+
- **TestAsyncBaseACP**: AsyncBaseACP-specific functionality
|
|
33
33
|
- **TestTemporalACP**: TemporalACP-specific functionality
|
|
34
34
|
- **TestImplementationComparison**: Differences between implementations
|
|
35
35
|
- **TestImplementationErrorHandling**: Implementation-specific error handling
|
|
@@ -165,7 +165,7 @@ Test components working together:
|
|
|
165
165
|
### Implementation Tests
|
|
166
166
|
Test specific ACP implementations:
|
|
167
167
|
- SyncACP behavior
|
|
168
|
-
-
|
|
168
|
+
- AsyncBaseACP send_event functionality
|
|
169
169
|
- TemporalACP workflow integration
|
|
170
170
|
- Implementation differences
|
|
171
171
|
|
|
@@ -23,8 +23,8 @@ from agentex.types.task_message import TaskMessageContent
|
|
|
23
23
|
from agentex.types.task_message_content import TextContent
|
|
24
24
|
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
|
25
25
|
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
|
26
|
+
from agentex.lib.sdk.fastacp.impl.async_base_acp import AsyncBaseACP
|
|
26
27
|
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
|
27
|
-
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
|
28
28
|
|
|
29
29
|
# Configure pytest-asyncio
|
|
30
30
|
pytest_plugins = ("pytest_asyncio",)
|
|
@@ -216,17 +216,17 @@ def agentic_base_acp_server():
|
|
|
216
216
|
with patch.dict(
|
|
217
217
|
"os.environ", {"AGENTEX_BASE_URL": ""}
|
|
218
218
|
): # Disable agent registration
|
|
219
|
-
server =
|
|
219
|
+
server = AsyncBaseACP()
|
|
220
220
|
return server
|
|
221
221
|
|
|
222
222
|
|
|
223
223
|
@pytest_asyncio.fixture
|
|
224
224
|
async def async_agentic_base_acp_server():
|
|
225
|
-
"""Fixture that provides an
|
|
225
|
+
"""Fixture that provides an AsyncBaseACP instance for async tests"""
|
|
226
226
|
with patch.dict(
|
|
227
227
|
"os.environ", {"AGENTEX_BASE_URL": ""}
|
|
228
228
|
): # Disable agent registration
|
|
229
|
-
server =
|
|
229
|
+
server = AsyncBaseACP.create()
|
|
230
230
|
return server
|
|
231
231
|
|
|
232
232
|
|
|
@@ -5,15 +5,15 @@ import pytest
|
|
|
5
5
|
|
|
6
6
|
from agentex.lib.types.fastacp import (
|
|
7
7
|
SyncACPConfig,
|
|
8
|
-
|
|
8
|
+
AsyncACPConfig,
|
|
9
9
|
TemporalACPConfig,
|
|
10
|
-
|
|
10
|
+
AsyncBaseACPConfig,
|
|
11
11
|
)
|
|
12
12
|
from agentex.lib.sdk.fastacp.fastacp import FastACP
|
|
13
13
|
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
|
14
14
|
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
|
15
|
+
from agentex.lib.sdk.fastacp.impl.async_base_acp import AsyncBaseACP
|
|
15
16
|
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
|
16
|
-
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class TestFastACPInitialization:
|
|
@@ -23,7 +23,7 @@ class TestFastACPInitialization:
|
|
|
23
23
|
"""Test that FastACP class exists and is properly structured"""
|
|
24
24
|
assert hasattr(FastACP, "create")
|
|
25
25
|
assert hasattr(FastACP, "create_sync_acp")
|
|
26
|
-
assert hasattr(FastACP, "
|
|
26
|
+
assert hasattr(FastACP, "create_async_acp")
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class TestSyncACPCreation:
|
|
@@ -82,62 +82,62 @@ class TestSyncACPCreation:
|
|
|
82
82
|
assert isinstance(sync_acp, SyncACP)
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
class
|
|
86
|
-
"""Test
|
|
85
|
+
class TestAsyncBaseACPCreation:
|
|
86
|
+
"""Test AsyncBaseACP creation through factory"""
|
|
87
87
|
|
|
88
88
|
@pytest.mark.asyncio
|
|
89
|
-
async def
|
|
90
|
-
"""Test creating
|
|
89
|
+
async def test_create_async_base_acp_direct_method(self):
|
|
90
|
+
"""Test creating AsyncBaseACP using direct method"""
|
|
91
91
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
92
|
-
config =
|
|
93
|
-
|
|
92
|
+
config = AsyncACPConfig(type="base")
|
|
93
|
+
async_acp = FastACP.create_async_acp(config=config)
|
|
94
94
|
|
|
95
|
-
assert isinstance(
|
|
96
|
-
assert isinstance(
|
|
95
|
+
assert isinstance(async_acp, AsyncBaseACP)
|
|
96
|
+
assert isinstance(async_acp, BaseACPServer)
|
|
97
97
|
|
|
98
98
|
@pytest.mark.asyncio
|
|
99
|
-
async def
|
|
100
|
-
"""Test creating
|
|
99
|
+
async def test_create_async_base_acp_with_specific_config(self):
|
|
100
|
+
"""Test creating AsyncBaseACP with AsyncBaseACPConfig"""
|
|
101
101
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
102
|
-
config =
|
|
103
|
-
|
|
102
|
+
config = AsyncBaseACPConfig(type="base")
|
|
103
|
+
async_acp = FastACP.create_async_acp(config=config)
|
|
104
104
|
|
|
105
|
-
assert isinstance(
|
|
105
|
+
assert isinstance(async_acp, AsyncBaseACP)
|
|
106
106
|
|
|
107
107
|
@pytest.mark.asyncio
|
|
108
|
-
async def
|
|
109
|
-
"""Test creating
|
|
108
|
+
async def test_create_async_base_acp_via_generic_create(self):
|
|
109
|
+
"""Test creating AsyncBaseACP via generic create method"""
|
|
110
110
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
111
|
-
config =
|
|
112
|
-
|
|
111
|
+
config = AsyncACPConfig(type="base")
|
|
112
|
+
async_acp = FastACP.create("async", config=config)
|
|
113
113
|
|
|
114
|
-
assert isinstance(
|
|
114
|
+
assert isinstance(async_acp, AsyncBaseACP)
|
|
115
115
|
|
|
116
116
|
@pytest.mark.asyncio
|
|
117
|
-
async def
|
|
118
|
-
"""Test creating
|
|
117
|
+
async def test_create_async_base_acp_with_enum(self):
|
|
118
|
+
"""Test creating AsyncBaseACP using ACPType enum"""
|
|
119
119
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
120
|
-
config =
|
|
121
|
-
|
|
120
|
+
config = AsyncACPConfig(type="base")
|
|
121
|
+
async_acp = FastACP.create("async", config=config)
|
|
122
122
|
|
|
123
|
-
assert isinstance(
|
|
123
|
+
assert isinstance(async_acp, AsyncBaseACP)
|
|
124
124
|
|
|
125
125
|
|
|
126
|
-
class
|
|
127
|
-
"""Test
|
|
126
|
+
class TestAsyncTemporalACPCreation:
|
|
127
|
+
"""Test AsyncTemporalACP (TemporalACP) creation through factory"""
|
|
128
128
|
|
|
129
129
|
@pytest.mark.asyncio
|
|
130
130
|
async def test_create_temporal_acp_direct_method(self):
|
|
131
131
|
"""Test creating TemporalACP using direct method"""
|
|
132
132
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
133
|
-
config =
|
|
133
|
+
config = AsyncACPConfig(type="temporal")
|
|
134
134
|
|
|
135
135
|
# Mock the TemporalACP.create method since it requires temporal dependencies
|
|
136
136
|
with patch.object(TemporalACP, "create", new_callable=AsyncMock) as mock_create:
|
|
137
137
|
mock_temporal_instance = MagicMock(spec=TemporalACP)
|
|
138
138
|
mock_create.return_value = mock_temporal_instance
|
|
139
139
|
|
|
140
|
-
temporal_acp = FastACP.
|
|
140
|
+
temporal_acp = FastACP.create_async_acp(config=config)
|
|
141
141
|
|
|
142
142
|
assert temporal_acp == mock_temporal_instance
|
|
143
143
|
mock_create.assert_called_once()
|
|
@@ -152,7 +152,7 @@ class TestAgenticTemporalACPCreation:
|
|
|
152
152
|
mock_temporal_instance = MagicMock(spec=TemporalACP)
|
|
153
153
|
mock_create.return_value = mock_temporal_instance
|
|
154
154
|
|
|
155
|
-
temporal_acp = FastACP.
|
|
155
|
+
temporal_acp = FastACP.create_async_acp(config=config)
|
|
156
156
|
|
|
157
157
|
assert temporal_acp == mock_temporal_instance
|
|
158
158
|
# Verify temporal_address was passed
|
|
@@ -162,13 +162,13 @@ class TestAgenticTemporalACPCreation:
|
|
|
162
162
|
async def test_create_temporal_acp_via_generic_create(self):
|
|
163
163
|
"""Test creating TemporalACP via generic create method"""
|
|
164
164
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
165
|
-
config =
|
|
165
|
+
config = AsyncACPConfig(type="temporal")
|
|
166
166
|
|
|
167
167
|
with patch.object(TemporalACP, "create", new_callable=AsyncMock) as mock_create:
|
|
168
168
|
mock_temporal_instance = MagicMock(spec=TemporalACP)
|
|
169
169
|
mock_create.return_value = mock_temporal_instance
|
|
170
170
|
|
|
171
|
-
temporal_acp = FastACP.create("
|
|
171
|
+
temporal_acp = FastACP.create("async", config=config)
|
|
172
172
|
|
|
173
173
|
assert temporal_acp == mock_temporal_instance
|
|
174
174
|
|
|
@@ -182,7 +182,7 @@ class TestAgenticTemporalACPCreation:
|
|
|
182
182
|
mock_temporal_instance = MagicMock(spec=TemporalACP)
|
|
183
183
|
mock_create.return_value = mock_temporal_instance
|
|
184
184
|
|
|
185
|
-
FastACP.
|
|
185
|
+
FastACP.create_async_acp(config=config)
|
|
186
186
|
|
|
187
187
|
mock_create.assert_called_once_with(temporal_address="custom-temporal:9999")
|
|
188
188
|
|
|
@@ -191,28 +191,28 @@ class TestConfigurationValidation:
|
|
|
191
191
|
"""Test configuration validation and error handling"""
|
|
192
192
|
|
|
193
193
|
@pytest.mark.asyncio
|
|
194
|
-
async def
|
|
195
|
-
"""Test that
|
|
194
|
+
async def test_async_requires_config(self):
|
|
195
|
+
"""Test that async ACP creation requires configuration"""
|
|
196
196
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
197
|
-
with pytest.raises(ValueError, match="
|
|
198
|
-
FastACP.create("
|
|
197
|
+
with pytest.raises(ValueError, match="AsyncACPConfig is required"):
|
|
198
|
+
FastACP.create("async")
|
|
199
199
|
|
|
200
200
|
@pytest.mark.asyncio
|
|
201
|
-
async def
|
|
202
|
-
"""Test that
|
|
201
|
+
async def test_async_requires_correct_config_type(self):
|
|
202
|
+
"""Test that async ACP creation requires AsyncACPConfig type"""
|
|
203
203
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
204
204
|
sync_config = SyncACPConfig()
|
|
205
205
|
|
|
206
|
-
with pytest.raises(ValueError, match="
|
|
207
|
-
FastACP.create("
|
|
206
|
+
with pytest.raises(ValueError, match="AsyncACPConfig is required"):
|
|
207
|
+
FastACP.create("async", config=sync_config)
|
|
208
208
|
|
|
209
209
|
@pytest.mark.asyncio
|
|
210
|
-
async def
|
|
211
|
-
"""Test that direct
|
|
210
|
+
async def test_async_direct_method_requires_config(self):
|
|
211
|
+
"""Test that direct async method requires configuration"""
|
|
212
212
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
213
213
|
# This should raise TypeError since config is required parameter
|
|
214
214
|
with pytest.raises(TypeError):
|
|
215
|
-
FastACP.
|
|
215
|
+
FastACP.create_async_acp() # type: ignore[call-arg]
|
|
216
216
|
|
|
217
217
|
def test_invalid_acp_type_string(self):
|
|
218
218
|
"""Test that invalid ACP type string raises ValueError"""
|
|
@@ -220,12 +220,12 @@ class TestConfigurationValidation:
|
|
|
220
220
|
with pytest.raises(ValueError):
|
|
221
221
|
asyncio.run(FastACP.create("invalid_type"))
|
|
222
222
|
|
|
223
|
-
def
|
|
224
|
-
"""Test that invalid
|
|
223
|
+
def test_invalid_async_type_in_config(self):
|
|
224
|
+
"""Test that invalid async type in config raises ValueError"""
|
|
225
225
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
226
226
|
# This should raise ValueError during config creation
|
|
227
227
|
with pytest.raises(ValueError):
|
|
228
|
-
|
|
228
|
+
AsyncACPConfig(type="invalid_async_type")
|
|
229
229
|
|
|
230
230
|
@pytest.mark.asyncio
|
|
231
231
|
async def test_unsupported_acp_type_enum(self):
|
|
@@ -234,6 +234,7 @@ class TestConfigurationValidation:
|
|
|
234
234
|
# Create a mock enum value that's not supported
|
|
235
235
|
with patch("agentex.sdk.fastacp.fastacp.ACPType") as mock_enum:
|
|
236
236
|
mock_enum.SYNC = "sync"
|
|
237
|
+
mock_enum.ASYNC = "async"
|
|
237
238
|
mock_enum.AGENTIC = "agentic"
|
|
238
239
|
unsupported_type = "unsupported"
|
|
239
240
|
|
|
@@ -253,26 +254,26 @@ class TestErrorHandling:
|
|
|
253
254
|
FastACP.create_sync_acp()
|
|
254
255
|
|
|
255
256
|
@pytest.mark.asyncio
|
|
256
|
-
async def
|
|
257
|
-
"""Test handling of
|
|
257
|
+
async def test_async_acp_creation_failure(self):
|
|
258
|
+
"""Test handling of AsyncACP creation failure"""
|
|
258
259
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
259
|
-
config =
|
|
260
|
+
config = AsyncACPConfig(type="base")
|
|
260
261
|
|
|
261
|
-
with patch.object(
|
|
262
|
+
with patch.object(AsyncBaseACP, "create", side_effect=Exception("Creation failed")):
|
|
262
263
|
with pytest.raises(Exception, match="Creation failed"):
|
|
263
|
-
FastACP.
|
|
264
|
+
FastACP.create_async_acp(config=config)
|
|
264
265
|
|
|
265
266
|
@pytest.mark.asyncio
|
|
266
267
|
async def test_temporal_acp_creation_failure(self):
|
|
267
268
|
"""Test handling of TemporalACP creation failure"""
|
|
268
269
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
269
|
-
config =
|
|
270
|
+
config = AsyncACPConfig(type="temporal")
|
|
270
271
|
|
|
271
272
|
with patch.object(
|
|
272
273
|
TemporalACP, "create", side_effect=Exception("Temporal connection failed")
|
|
273
274
|
):
|
|
274
275
|
with pytest.raises(Exception, match="Temporal connection failed"):
|
|
275
|
-
FastACP.
|
|
276
|
+
FastACP.create_async_acp(config=config)
|
|
276
277
|
|
|
277
278
|
|
|
278
279
|
class TestIntegrationScenarios:
|
|
@@ -286,34 +287,59 @@ class TestIntegrationScenarios:
|
|
|
286
287
|
sync_acp = FastACP.create("sync")
|
|
287
288
|
assert isinstance(sync_acp, SyncACP)
|
|
288
289
|
|
|
289
|
-
# Create
|
|
290
|
-
base_config =
|
|
291
|
-
|
|
292
|
-
assert isinstance(
|
|
290
|
+
# Create AsyncBaseACP
|
|
291
|
+
base_config = AsyncACPConfig(type="base")
|
|
292
|
+
async_base = FastACP.create("async", config=base_config)
|
|
293
|
+
assert isinstance(async_base, AsyncBaseACP)
|
|
293
294
|
|
|
294
295
|
# Create TemporalACP (mocked)
|
|
295
|
-
temporal_config =
|
|
296
|
+
temporal_config = AsyncACPConfig(type="temporal")
|
|
296
297
|
with patch.object(TemporalACP, "create", new_callable=AsyncMock) as mock_create:
|
|
297
298
|
mock_temporal_instance = MagicMock(spec=TemporalACP)
|
|
298
299
|
mock_create.return_value = mock_temporal_instance
|
|
299
300
|
|
|
300
|
-
temporal_acp = FastACP.create("
|
|
301
|
+
temporal_acp = FastACP.create("async", config=temporal_config)
|
|
301
302
|
assert temporal_acp == mock_temporal_instance
|
|
302
303
|
|
|
304
|
+
@pytest.mark.asyncio
|
|
305
|
+
async def test_async_type_backwards_compatibility(self):
|
|
306
|
+
"""Test that 'async' type works the same as 'async' for backwards compatibility"""
|
|
307
|
+
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
308
|
+
# Test async with base config
|
|
309
|
+
base_config = AsyncACPConfig(type="base")
|
|
310
|
+
async_base = FastACP.create("async", config=base_config)
|
|
311
|
+
assert isinstance(async_base, AsyncBaseACP)
|
|
312
|
+
|
|
313
|
+
# Test async with temporal config (mocked)
|
|
314
|
+
temporal_config = AsyncACPConfig(type="temporal")
|
|
315
|
+
with patch.object(TemporalACP, "create", new_callable=AsyncMock) as mock_create:
|
|
316
|
+
mock_temporal_instance = MagicMock(spec=TemporalACP)
|
|
317
|
+
mock_create.return_value = mock_temporal_instance
|
|
318
|
+
|
|
319
|
+
temporal_acp = FastACP.create("async", config=temporal_config)
|
|
320
|
+
assert temporal_acp == mock_temporal_instance
|
|
321
|
+
|
|
322
|
+
# Test that async requires config
|
|
323
|
+
with pytest.raises(ValueError, match="AsyncACPConfig is required"):
|
|
324
|
+
sync_config = SyncACPConfig()
|
|
325
|
+
FastACP.create("async", config=sync_config)
|
|
326
|
+
|
|
303
327
|
@pytest.mark.asyncio
|
|
304
328
|
async def test_configuration_driven_creation(self):
|
|
305
329
|
"""Test configuration-driven ACP creation"""
|
|
306
330
|
with patch.dict("os.environ", {"AGENTEX_BASE_URL": ""}):
|
|
307
331
|
configs = [
|
|
308
332
|
("sync", None),
|
|
309
|
-
("
|
|
310
|
-
("
|
|
333
|
+
("async", AsyncACPConfig(type="base")),
|
|
334
|
+
("async", AsyncACPConfig(type="base")),
|
|
335
|
+
("async", TemporalACPConfig(type="temporal", temporal_address="localhost:7233")),
|
|
336
|
+
("async", TemporalACPConfig(type="temporal", temporal_address="localhost:7233")),
|
|
311
337
|
]
|
|
312
338
|
|
|
313
339
|
created_acps = []
|
|
314
340
|
|
|
315
341
|
for acp_type, config in configs:
|
|
316
|
-
if acp_type
|
|
342
|
+
if acp_type in ("async", "async") and config and config.type == "temporal":
|
|
317
343
|
# Mock temporal creation
|
|
318
344
|
with patch.object(TemporalACP, "create", new_callable=AsyncMock) as mock_create:
|
|
319
345
|
mock_temporal_instance = MagicMock(spec=TemporalACP)
|
|
@@ -325,10 +351,11 @@ class TestIntegrationScenarios:
|
|
|
325
351
|
acp = FastACP.create(acp_type, config=config)
|
|
326
352
|
created_acps.append(acp)
|
|
327
353
|
|
|
328
|
-
assert len(created_acps) ==
|
|
354
|
+
assert len(created_acps) == 5
|
|
329
355
|
assert isinstance(created_acps[0], SyncACP)
|
|
330
|
-
assert isinstance(created_acps[1],
|
|
331
|
-
|
|
356
|
+
assert isinstance(created_acps[1], AsyncBaseACP)
|
|
357
|
+
assert isinstance(created_acps[2], AsyncBaseACP)
|
|
358
|
+
# Fourth and fifth ones are mocked TemporalACP
|
|
332
359
|
|
|
333
360
|
@pytest.mark.asyncio
|
|
334
361
|
async def test_factory_with_custom_kwargs(self):
|
|
@@ -338,7 +365,7 @@ class TestIntegrationScenarios:
|
|
|
338
365
|
sync_acp = FastACP.create_sync_acp(custom_param="test")
|
|
339
366
|
assert isinstance(sync_acp, SyncACP)
|
|
340
367
|
|
|
341
|
-
# Test
|
|
342
|
-
config =
|
|
343
|
-
|
|
344
|
-
assert isinstance(
|
|
368
|
+
# Test async base with kwargs
|
|
369
|
+
config = AsyncACPConfig(type="base")
|
|
370
|
+
async_acp = FastACP.create_async_acp(config=config, custom_param="test")
|
|
371
|
+
assert isinstance(async_acp, AsyncBaseACP)
|