agentex-sdk 0.4.18__py3-none-any.whl → 0.4.20__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 +0 -1
- agentex/_utils/_typing.py +3 -1
- agentex/_version.py +1 -1
- agentex/lib/adk/__init__.py +3 -0
- agentex/lib/adk/_modules/acp.py +3 -1
- agentex/lib/adk/_modules/agent_task_tracker.py +3 -1
- agentex/lib/adk/_modules/agents.py +3 -1
- agentex/lib/adk/_modules/events.py +3 -1
- agentex/lib/adk/_modules/messages.py +3 -1
- agentex/lib/adk/_modules/state.py +3 -1
- agentex/lib/adk/_modules/streaming.py +3 -1
- agentex/lib/adk/_modules/tasks.py +4 -2
- agentex/lib/adk/_modules/tracing.py +3 -1
- agentex/lib/adk/providers/__init__.py +2 -2
- agentex/lib/adk/providers/_modules/litellm.py +10 -11
- agentex/lib/adk/providers/_modules/openai.py +27 -28
- agentex/lib/adk/providers/_modules/sgp.py +5 -6
- agentex/lib/adk/utils/_modules/client.py +4 -1
- agentex/lib/adk/utils/_modules/templating.py +5 -6
- agentex/lib/cli/commands/agents.py +21 -21
- agentex/lib/cli/commands/init.py +3 -3
- agentex/lib/cli/commands/main.py +3 -3
- agentex/lib/cli/commands/secrets.py +10 -10
- agentex/lib/cli/commands/tasks.py +26 -28
- agentex/lib/cli/commands/uv.py +1 -1
- agentex/lib/cli/debug/__init__.py +1 -1
- agentex/lib/cli/debug/debug_config.py +1 -2
- agentex/lib/cli/debug/debug_handlers.py +6 -4
- agentex/lib/cli/handlers/agent_handlers.py +15 -16
- agentex/lib/cli/handlers/cleanup_handlers.py +1 -1
- agentex/lib/cli/handlers/deploy_handlers.py +41 -55
- agentex/lib/cli/handlers/run_handlers.py +13 -16
- agentex/lib/cli/handlers/secret_handlers.py +25 -25
- agentex/lib/cli/templates/temporal/project/acp.py.j2 +11 -8
- agentex/lib/cli/utils/auth_utils.py +3 -2
- agentex/lib/cli/utils/credential_utils.py +1 -1
- agentex/lib/cli/utils/kubectl_utils.py +3 -3
- agentex/lib/cli/utils/kubernetes_secrets_utils.py +4 -4
- agentex/lib/cli/utils/path_utils.py +2 -2
- agentex/lib/core/adapters/llm/adapter_litellm.py +9 -4
- agentex/lib/core/adapters/llm/adapter_sgp.py +10 -7
- agentex/lib/core/adapters/llm/port.py +1 -1
- agentex/lib/core/adapters/streams/adapter_redis.py +7 -4
- agentex/lib/core/adapters/streams/port.py +1 -1
- agentex/lib/core/clients/temporal/temporal_client.py +34 -34
- agentex/lib/core/clients/temporal/types.py +1 -1
- agentex/lib/core/clients/temporal/utils.py +9 -12
- agentex/lib/core/services/adk/acp/acp.py +6 -6
- agentex/lib/core/services/adk/agent_task_tracker.py +1 -1
- agentex/lib/core/services/adk/agents.py +1 -1
- agentex/lib/core/services/adk/events.py +1 -1
- agentex/lib/core/services/adk/messages.py +5 -6
- agentex/lib/core/services/adk/providers/litellm.py +10 -10
- agentex/lib/core/services/adk/providers/openai.py +75 -43
- agentex/lib/core/services/adk/providers/sgp.py +3 -3
- agentex/lib/core/services/adk/state.py +5 -1
- agentex/lib/core/services/adk/streaming.py +19 -19
- agentex/lib/core/services/adk/tasks.py +8 -2
- agentex/lib/core/services/adk/tracing.py +3 -2
- agentex/lib/core/services/adk/utils/templating.py +4 -2
- agentex/lib/core/temporal/activities/__init__.py +27 -27
- agentex/lib/core/temporal/activities/activity_helpers.py +1 -1
- agentex/lib/core/temporal/activities/adk/acp/acp_activities.py +4 -4
- agentex/lib/core/temporal/activities/adk/agent_task_tracker_activities.py +1 -1
- agentex/lib/core/temporal/activities/adk/agents_activities.py +2 -2
- agentex/lib/core/temporal/activities/adk/events_activities.py +1 -1
- agentex/lib/core/temporal/activities/adk/messages_activities.py +3 -3
- agentex/lib/core/temporal/activities/adk/providers/litellm_activities.py +4 -4
- agentex/lib/core/temporal/activities/adk/providers/sgp_activities.py +1 -1
- agentex/lib/core/temporal/activities/adk/state_activities.py +1 -1
- agentex/lib/core/temporal/activities/adk/streaming_activities.py +3 -3
- agentex/lib/core/temporal/activities/adk/tasks_activities.py +2 -2
- agentex/lib/core/temporal/activities/adk/tracing_activities.py +1 -1
- agentex/lib/core/temporal/activities/adk/utils/templating_activities.py +1 -1
- agentex/lib/core/temporal/services/temporal_task_service.py +7 -7
- agentex/lib/core/temporal/workers/worker.py +31 -40
- agentex/lib/core/temporal/workflows/workflow.py +2 -2
- agentex/lib/core/tracing/__init__.py +2 -2
- agentex/lib/core/tracing/processors/agentex_tracing_processor.py +6 -6
- agentex/lib/core/tracing/processors/sgp_tracing_processor.py +16 -16
- agentex/lib/core/tracing/processors/tracing_processor_interface.py +1 -1
- agentex/lib/core/tracing/trace.py +7 -7
- agentex/lib/core/tracing/tracer.py +2 -2
- agentex/lib/core/tracing/tracing_processor_manager.py +43 -13
- agentex/lib/environment_variables.py +5 -4
- agentex/lib/sdk/config/agent_config.py +2 -2
- agentex/lib/sdk/config/agent_manifest.py +8 -8
- agentex/lib/sdk/config/environment_config.py +10 -2
- agentex/lib/sdk/config/project_config.py +6 -6
- agentex/lib/sdk/config/validation.py +2 -2
- agentex/lib/sdk/fastacp/base/base_acp_server.py +31 -13
- agentex/lib/sdk/fastacp/fastacp.py +14 -15
- agentex/lib/sdk/fastacp/impl/agentic_base_acp.py +4 -5
- agentex/lib/sdk/fastacp/impl/sync_acp.py +7 -7
- agentex/lib/sdk/fastacp/impl/temporal_acp.py +28 -19
- agentex/lib/sdk/fastacp/tests/conftest.py +18 -16
- agentex/lib/sdk/fastacp/tests/run_tests.py +1 -1
- agentex/lib/sdk/fastacp/tests/test_base_acp_server.py +4 -4
- agentex/lib/sdk/fastacp/tests/test_fastacp_factory.py +8 -8
- agentex/lib/sdk/fastacp/tests/test_integration.py +15 -14
- agentex/lib/sdk/state_machine/__init__.py +1 -1
- agentex/lib/sdk/state_machine/noop_workflow.py +5 -3
- agentex/lib/sdk/state_machine/state_machine.py +18 -12
- agentex/lib/sdk/utils/messages.py +5 -5
- agentex/lib/types/acp.py +2 -2
- agentex/lib/types/agent_configs.py +1 -1
- agentex/lib/types/converters.py +4 -2
- agentex/lib/types/credentials.py +1 -1
- agentex/lib/types/fastacp.py +4 -5
- agentex/lib/types/tracing.py +1 -1
- agentex/lib/utils/completions.py +5 -5
- agentex/lib/utils/console.py +1 -1
- agentex/lib/utils/debug.py +10 -5
- agentex/lib/utils/dev_tools/async_messages.py +11 -12
- agentex/lib/utils/iterables.py +1 -1
- agentex/lib/utils/json_schema.py +4 -4
- agentex/lib/utils/logging.py +62 -14
- agentex/lib/utils/mcp.py +1 -0
- agentex/lib/utils/model_utils.py +4 -5
- agentex/lib/utils/registration.py +5 -4
- agentex/resources/agents.py +11 -4
- agentex/types/agent_rpc_response.py +3 -3
- agentex/types/data_content.py +1 -1
- agentex/types/tool_request_content.py +1 -1
- agentex/types/tool_response_content.py +0 -1
- {agentex_sdk-0.4.18.dist-info → agentex_sdk-0.4.20.dist-info}/METADATA +4 -1
- {agentex_sdk-0.4.18.dist-info → agentex_sdk-0.4.20.dist-info}/RECORD +130 -130
- {agentex_sdk-0.4.18.dist-info → agentex_sdk-0.4.20.dist-info}/WHEEL +0 -0
- {agentex_sdk-0.4.18.dist-info → agentex_sdk-0.4.20.dist-info}/entry_points.txt +0 -0
- {agentex_sdk-0.4.18.dist-info → agentex_sdk-0.4.20.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,10 @@
|
|
1
1
|
import os
|
2
2
|
import re
|
3
|
-
from pathlib import Path
|
4
3
|
from typing import Any, TypeVar
|
4
|
+
from pathlib import Path
|
5
5
|
|
6
6
|
import yaml
|
7
|
-
from jinja2 import BaseLoader, Environment,
|
7
|
+
from jinja2 import BaseLoader, Environment, TemplateError, StrictUndefined
|
8
8
|
|
9
9
|
T = TypeVar("T")
|
10
10
|
|
@@ -35,10 +35,10 @@ def _extract_variables_section(raw_config_str: str) -> str:
|
|
35
35
|
def ProjectConfigLoader(
|
36
36
|
config_path: str, model: type[T] | None = None, env_path: str | None = None
|
37
37
|
) -> dict[str, Any] | T:
|
38
|
-
|
39
|
-
|
40
|
-
env = _load_env(
|
41
|
-
raw_config_str = _load_file_as_str(
|
38
|
+
config_path_obj = Path(config_path)
|
39
|
+
env_path_obj = Path(env_path) if env_path else config_path_obj.parent / ".env"
|
40
|
+
env = _load_env(env_path_obj)
|
41
|
+
raw_config_str = _load_file_as_str(config_path_obj)
|
42
42
|
raw_config_str = _preprocess_template(raw_config_str)
|
43
43
|
|
44
44
|
# Extract and render only the variables section
|
@@ -5,11 +5,11 @@ This module provides validation functions for agent configurations,
|
|
5
5
|
with clear error messages and best practices enforcement.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from pathlib import Path
|
9
8
|
from typing import Any, Dict, List, Optional
|
9
|
+
from pathlib import Path
|
10
10
|
|
11
|
-
from agentex.lib.sdk.config.environment_config import AgentEnvironmentsConfig, AgentEnvironmentConfig
|
12
11
|
from agentex.lib.utils.logging import make_logger
|
12
|
+
from agentex.lib.sdk.config.environment_config import AgentEnvironmentConfig, AgentEnvironmentsConfig
|
13
13
|
|
14
14
|
logger = make_logger(__name__)
|
15
15
|
|
@@ -1,32 +1,35 @@
|
|
1
|
+
import uuid
|
1
2
|
import asyncio
|
2
3
|
import inspect
|
4
|
+
from typing import Any
|
3
5
|
from datetime import datetime
|
4
|
-
from collections.abc import AsyncGenerator, Awaitable, Callable
|
5
6
|
from contextlib import asynccontextmanager
|
6
|
-
from
|
7
|
+
from collections.abc import Callable, Awaitable, AsyncGenerator
|
7
8
|
|
8
9
|
import uvicorn
|
9
10
|
from fastapi import FastAPI, Request
|
10
|
-
from fastapi.responses import StreamingResponse
|
11
11
|
from pydantic import TypeAdapter, ValidationError
|
12
|
+
from fastapi.responses import StreamingResponse
|
13
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
12
14
|
|
13
|
-
# from agentex.lib.sdk.fastacp.types import BaseACPConfig
|
14
|
-
from agentex.lib.environment_variables import EnvironmentVariables, refreshed_environment_variables
|
15
15
|
from agentex.lib.types.acp import (
|
16
|
-
PARAMS_MODEL_BY_METHOD,
|
17
16
|
RPC_SYNC_METHODS,
|
18
|
-
|
19
|
-
CreateTaskParams,
|
17
|
+
PARAMS_MODEL_BY_METHOD,
|
20
18
|
RPCMethod,
|
21
19
|
SendEventParams,
|
20
|
+
CancelTaskParams,
|
21
|
+
CreateTaskParams,
|
22
22
|
SendMessageParams,
|
23
23
|
)
|
24
|
+
from agentex.lib.utils.logging import make_logger, ctx_var_request_id
|
24
25
|
from agentex.lib.types.json_rpc import JSONRPCError, JSONRPCRequest, JSONRPCResponse
|
25
|
-
from agentex.types.task_message_update import StreamTaskMessageFull, TaskMessageUpdate
|
26
|
-
from agentex.types.task_message_content import TaskMessageContent
|
27
|
-
from agentex.lib.utils.logging import make_logger
|
28
26
|
from agentex.lib.utils.model_utils import BaseModel
|
29
27
|
from agentex.lib.utils.registration import register_agent
|
28
|
+
|
29
|
+
# from agentex.lib.sdk.fastacp.types import BaseACPConfig
|
30
|
+
from agentex.lib.environment_variables import EnvironmentVariables, refreshed_environment_variables
|
31
|
+
from agentex.types.task_message_update import TaskMessageUpdate, StreamTaskMessageFull
|
32
|
+
from agentex.types.task_message_content import TaskMessageContent
|
30
33
|
from agentex.lib.sdk.fastacp.base.constants import (
|
31
34
|
FASTACP_HEADER_SKIP_EXACT,
|
32
35
|
FASTACP_HEADER_SKIP_PREFIXES,
|
@@ -38,6 +41,19 @@ logger = make_logger(__name__)
|
|
38
41
|
task_message_update_adapter = TypeAdapter(TaskMessageUpdate)
|
39
42
|
|
40
43
|
|
44
|
+
class RequestIDMiddleware(BaseHTTPMiddleware):
|
45
|
+
"""Middleware to extract or generate request IDs and add them to logs and response headers"""
|
46
|
+
|
47
|
+
async def dispatch(self, request: Request, call_next): # type: ignore[override]
|
48
|
+
# Extract request ID from header or generate a new one if there isn't one
|
49
|
+
request_id = request.headers.get("x-request-id") or uuid.uuid4().hex
|
50
|
+
# Store request ID in request state for access in handlers
|
51
|
+
ctx_var_request_id.set(request_id)
|
52
|
+
# Process request
|
53
|
+
response = await call_next(request)
|
54
|
+
return response
|
55
|
+
|
56
|
+
|
41
57
|
class BaseACPServer(FastAPI):
|
42
58
|
"""
|
43
59
|
AsyncAgentACP provides RPC-style hooks for agent events and commands asynchronously.
|
@@ -56,6 +72,8 @@ class BaseACPServer(FastAPI):
|
|
56
72
|
self.post("/api")(self._handle_jsonrpc)
|
57
73
|
|
58
74
|
# Method handlers
|
75
|
+
# this just adds a request ID to the request and response headers
|
76
|
+
self.add_middleware(RequestIDMiddleware)
|
59
77
|
self._handlers: dict[RPCMethod, Callable] = {}
|
60
78
|
|
61
79
|
@classmethod
|
@@ -72,7 +90,7 @@ class BaseACPServer(FastAPI):
|
|
72
90
|
|
73
91
|
def get_lifespan_function(self):
|
74
92
|
@asynccontextmanager
|
75
|
-
async def lifespan_context(app: FastAPI):
|
93
|
+
async def lifespan_context(app: FastAPI): # noqa: ARG001
|
76
94
|
env_vars = EnvironmentVariables.refresh()
|
77
95
|
if env_vars.AGENTEX_BASE_URL:
|
78
96
|
await register_agent(env_vars)
|
@@ -371,4 +389,4 @@ class BaseACPServer(FastAPI):
|
|
371
389
|
"""Start the Uvicorn server for async handlers."""
|
372
390
|
uvicorn.run(self, host=host, port=port, **kwargs)
|
373
391
|
|
374
|
-
|
392
|
+
|
@@ -1,18 +1,18 @@
|
|
1
|
-
import inspect
|
2
1
|
import os
|
2
|
+
import inspect
|
3
|
+
from typing import Literal
|
3
4
|
from pathlib import Path
|
4
5
|
|
5
|
-
from typing import Any, Literal
|
6
|
-
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
7
|
-
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
8
|
-
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
9
|
-
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
10
6
|
from agentex.lib.types.fastacp import (
|
11
|
-
AgenticACPConfig,
|
12
7
|
BaseACPConfig,
|
13
8
|
SyncACPConfig,
|
9
|
+
AgenticACPConfig,
|
14
10
|
)
|
15
11
|
from agentex.lib.utils.logging import make_logger
|
12
|
+
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
13
|
+
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
14
|
+
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
15
|
+
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
16
16
|
|
17
17
|
# Add new mappings between ACP types and configs here
|
18
18
|
# Add new mappings between ACP types and implementations here
|
@@ -23,6 +23,7 @@ AGENTIC_ACP_IMPLEMENTATIONS: dict[Literal["temporal", "base"], type[BaseACPServe
|
|
23
23
|
|
24
24
|
logger = make_logger(__name__)
|
25
25
|
|
26
|
+
|
26
27
|
class FastACP:
|
27
28
|
"""Factory for creating FastACP instances
|
28
29
|
|
@@ -33,7 +34,7 @@ class FastACP:
|
|
33
34
|
|
34
35
|
@staticmethod
|
35
36
|
# Note: the config is optional and not used right now but is there to be extended in the future
|
36
|
-
def create_sync_acp(config: SyncACPConfig | None = None, **kwargs) -> SyncACP:
|
37
|
+
def create_sync_acp(config: SyncACPConfig | None = None, **kwargs) -> SyncACP: # noqa: ARG004
|
37
38
|
"""Create a SyncACP instance"""
|
38
39
|
return SyncACP.create(**kwargs)
|
39
40
|
|
@@ -52,9 +53,9 @@ class FastACP:
|
|
52
53
|
# Extract temporal_address and plugins from config if it's a TemporalACPConfig
|
53
54
|
temporal_config = kwargs.copy()
|
54
55
|
if hasattr(config, "temporal_address"):
|
55
|
-
temporal_config["temporal_address"] = config.temporal_address
|
56
|
+
temporal_config["temporal_address"] = config.temporal_address # type: ignore[attr-defined]
|
56
57
|
if hasattr(config, "plugins"):
|
57
|
-
temporal_config["plugins"] = config.plugins
|
58
|
+
temporal_config["plugins"] = config.plugins # type: ignore[attr-defined]
|
58
59
|
return implementation_class.create(**temporal_config)
|
59
60
|
else:
|
60
61
|
return implementation_class.create(**kwargs)
|
@@ -69,9 +70,7 @@ class FastACP:
|
|
69
70
|
|
70
71
|
@staticmethod
|
71
72
|
def create(
|
72
|
-
acp_type: Literal["sync", "agentic"],
|
73
|
-
config: BaseACPConfig | None = None,
|
74
|
-
**kwargs
|
73
|
+
acp_type: Literal["sync", "agentic"], config: BaseACPConfig | None = None, **kwargs
|
75
74
|
) -> BaseACPServer | SyncACP | AgenticBaseACP | TemporalACP:
|
76
75
|
"""Main factory method to create any ACP type
|
77
76
|
|
@@ -79,10 +78,10 @@ class FastACP:
|
|
79
78
|
acp_type: Type of ACP to create ("sync" or "agentic")
|
80
79
|
config: Configuration object. Required for agentic type.
|
81
80
|
**kwargs: Additional configuration parameters
|
82
|
-
"""
|
81
|
+
"""
|
83
82
|
|
84
83
|
FastACP.locate_build_info_path()
|
85
|
-
|
84
|
+
|
86
85
|
if acp_type == "sync":
|
87
86
|
sync_config = config if isinstance(config, SyncACPConfig) else None
|
88
87
|
return FastACP.create_sync_acp(sync_config, **kwargs)
|
@@ -1,15 +1,14 @@
|
|
1
1
|
from typing import Any
|
2
|
-
|
3
|
-
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
4
2
|
from typing_extensions import override
|
5
|
-
|
6
|
-
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
3
|
+
|
7
4
|
from agentex.lib.types.acp import (
|
5
|
+
SendEventParams,
|
8
6
|
CancelTaskParams,
|
9
7
|
CreateTaskParams,
|
10
|
-
SendEventParams,
|
11
8
|
)
|
12
9
|
from agentex.lib.utils.logging import make_logger
|
10
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
11
|
+
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
13
12
|
|
14
13
|
logger = make_logger(__name__)
|
15
14
|
|
@@ -1,16 +1,16 @@
|
|
1
|
-
from collections.abc import AsyncGenerator
|
2
1
|
from typing import Any, override
|
2
|
+
from collections.abc import AsyncGenerator
|
3
3
|
|
4
|
-
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
5
4
|
from agentex.lib.types.acp import SendMessageParams
|
5
|
+
from agentex.lib.utils.logging import make_logger
|
6
|
+
from agentex.types.task_message_delta import TextDelta
|
6
7
|
from agentex.types.task_message_update import (
|
7
|
-
StreamTaskMessageDelta,
|
8
|
-
StreamTaskMessageFull,
|
9
8
|
TaskMessageUpdate,
|
9
|
+
StreamTaskMessageFull,
|
10
|
+
StreamTaskMessageDelta,
|
10
11
|
)
|
11
|
-
from agentex.types.
|
12
|
-
from agentex.
|
13
|
-
from agentex.lib.utils.logging import make_logger
|
12
|
+
from agentex.types.task_message_content import TextContent, TaskMessageContent
|
13
|
+
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
14
14
|
|
15
15
|
logger = make_logger(__name__)
|
16
16
|
|
@@ -1,18 +1,18 @@
|
|
1
|
+
from typing import Any, Callable, AsyncGenerator, override
|
1
2
|
from contextlib import asynccontextmanager
|
2
|
-
from typing import Any, AsyncGenerator, Callable
|
3
3
|
|
4
4
|
from fastapi import FastAPI
|
5
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
6
|
from agentex.lib.types.acp import (
|
7
|
+
SendEventParams,
|
11
8
|
CancelTaskParams,
|
12
9
|
CreateTaskParams,
|
13
|
-
SendEventParams,
|
14
10
|
)
|
15
11
|
from agentex.lib.utils.logging import make_logger
|
12
|
+
from agentex.lib.environment_variables import EnvironmentVariables
|
13
|
+
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
14
|
+
from agentex.lib.core.clients.temporal.temporal_client import TemporalClient
|
15
|
+
from agentex.lib.core.temporal.services.temporal_task_service import TemporalTaskService
|
16
16
|
|
17
17
|
logger = make_logger(__name__)
|
18
18
|
|
@@ -24,7 +24,10 @@ class TemporalACP(BaseACPServer):
|
|
24
24
|
"""
|
25
25
|
|
26
26
|
def __init__(
|
27
|
-
self,
|
27
|
+
self,
|
28
|
+
temporal_address: str,
|
29
|
+
temporal_task_service: TemporalTaskService | None = None,
|
30
|
+
plugins: list[Any] | None = None,
|
28
31
|
):
|
29
32
|
super().__init__()
|
30
33
|
self._temporal_task_service = temporal_task_service
|
@@ -32,6 +35,7 @@ class TemporalACP(BaseACPServer):
|
|
32
35
|
self._plugins = plugins or []
|
33
36
|
|
34
37
|
@classmethod
|
38
|
+
@override
|
35
39
|
def create(cls, temporal_address: str, plugins: list[Any] | None = None) -> "TemporalACP":
|
36
40
|
logger.info("Initializing TemporalACP instance")
|
37
41
|
|
@@ -41,7 +45,7 @@ class TemporalACP(BaseACPServer):
|
|
41
45
|
logger.info("TemporalACP instance initialized now")
|
42
46
|
return temporal_acp
|
43
47
|
|
44
|
-
|
48
|
+
@override
|
45
49
|
def get_lifespan_function(self) -> Callable[[FastAPI], AsyncGenerator[None, None]]:
|
46
50
|
@asynccontextmanager
|
47
51
|
async def lifespan(app: FastAPI):
|
@@ -52,8 +56,7 @@ class TemporalACP(BaseACPServer):
|
|
52
56
|
if self._temporal_task_service is None:
|
53
57
|
env_vars = EnvironmentVariables.refresh()
|
54
58
|
temporal_client = await TemporalClient.create(
|
55
|
-
temporal_address=self._temporal_address,
|
56
|
-
plugins=self._plugins
|
59
|
+
temporal_address=self._temporal_address, plugins=self._plugins
|
57
60
|
)
|
58
61
|
self._temporal_task_service = TemporalTaskService(
|
59
62
|
temporal_client=temporal_client,
|
@@ -61,11 +64,12 @@ class TemporalACP(BaseACPServer):
|
|
61
64
|
)
|
62
65
|
|
63
66
|
# Call parent lifespan for agent registration
|
64
|
-
async with super().get_lifespan_function()(app):
|
67
|
+
async with super().get_lifespan_function()(app): # type: ignore[misc]
|
65
68
|
yield
|
66
69
|
|
67
|
-
return lifespan
|
70
|
+
return lifespan # type: ignore[return-value]
|
68
71
|
|
72
|
+
@override
|
69
73
|
def _setup_handlers(self):
|
70
74
|
"""Set up the handlers for temporal workflow operations"""
|
71
75
|
|
@@ -73,17 +77,21 @@ class TemporalACP(BaseACPServer):
|
|
73
77
|
async def handle_task_create(params: CreateTaskParams) -> None:
|
74
78
|
"""Default create task handler - logs the task"""
|
75
79
|
logger.info(f"TemporalACP received task create rpc call for task {params.task.id}")
|
76
|
-
|
80
|
+
if self._temporal_task_service is not None:
|
81
|
+
await self._temporal_task_service.submit_task(
|
82
|
+
agent=params.agent, task=params.task, params=params.params
|
83
|
+
)
|
77
84
|
|
78
85
|
@self.on_task_event_send
|
79
86
|
async def handle_event_send(params: SendEventParams) -> None:
|
80
87
|
"""Forward messages to running workflows via TaskService"""
|
81
88
|
try:
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
89
|
+
if self._temporal_task_service is not None:
|
90
|
+
await self._temporal_task_service.send_event(
|
91
|
+
agent=params.agent,
|
92
|
+
task=params.task,
|
93
|
+
event=params.event,
|
94
|
+
)
|
87
95
|
|
88
96
|
except Exception as e:
|
89
97
|
logger.error(f"Failed to send message: {e}")
|
@@ -93,7 +101,8 @@ class TemporalACP(BaseACPServer):
|
|
93
101
|
async def handle_cancel(params: CancelTaskParams) -> None:
|
94
102
|
"""Cancel running workflows via TaskService"""
|
95
103
|
try:
|
96
|
-
|
104
|
+
if self._temporal_task_service is not None:
|
105
|
+
await self._temporal_task_service.cancel(task_id=params.task.id)
|
97
106
|
except Exception as e:
|
98
107
|
logger.error(f"Failed to cancel task: {e}")
|
99
108
|
raise
|
@@ -1,28 +1,28 @@
|
|
1
|
-
import asyncio
|
2
|
-
import socket
|
3
1
|
import time
|
2
|
+
import socket
|
3
|
+
import asyncio
|
4
4
|
from typing import Any
|
5
5
|
from unittest.mock import AsyncMock, patch
|
6
6
|
|
7
7
|
import httpx
|
8
8
|
import pytest
|
9
|
-
import pytest_asyncio
|
10
9
|
import uvicorn
|
10
|
+
import pytest_asyncio
|
11
11
|
|
12
|
-
from agentex.
|
13
|
-
from agentex.
|
14
|
-
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
15
|
-
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
12
|
+
from agentex.types.task import Task
|
13
|
+
from agentex.types.agent import Agent
|
16
14
|
from agentex.lib.types.acp import (
|
17
15
|
CancelTaskParams,
|
18
16
|
CreateTaskParams,
|
19
17
|
SendMessageParams,
|
20
18
|
)
|
21
19
|
from agentex.lib.types.json_rpc import JSONRPCRequest
|
22
|
-
from agentex.types.agent import Agent
|
23
20
|
from agentex.types.task_message import TaskMessageContent
|
24
21
|
from agentex.types.task_message_content import TextContent
|
25
|
-
from agentex.
|
22
|
+
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
23
|
+
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
24
|
+
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
25
|
+
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
26
26
|
|
27
27
|
# Configure pytest-asyncio
|
28
28
|
pytest_plugins = ("pytest_asyncio",)
|
@@ -47,7 +47,7 @@ def free_port() -> int:
|
|
47
47
|
def sample_task() -> Task:
|
48
48
|
"""Fixture that provides a sample Task object"""
|
49
49
|
return Task(
|
50
|
-
id="test-task-123",
|
50
|
+
id="test-task-123", status="RUNNING"
|
51
51
|
)
|
52
52
|
|
53
53
|
|
@@ -72,6 +72,8 @@ def sample_send_message_params(
|
|
72
72
|
name="test-agent",
|
73
73
|
description="test-agent",
|
74
74
|
acp_type="sync",
|
75
|
+
created_at="2023-01-01T00:00:00Z",
|
76
|
+
updated_at="2023-01-01T00:00:00Z",
|
75
77
|
),
|
76
78
|
task=sample_task,
|
77
79
|
content=sample_message_content,
|
@@ -83,8 +85,8 @@ def sample_send_message_params(
|
|
83
85
|
def sample_cancel_task_params() -> CancelTaskParams:
|
84
86
|
"""Fixture that provides sample CancelTaskParams"""
|
85
87
|
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",
|
88
|
+
agent=Agent(id="test-agent-456", name="test-agent", description="test-agent", acp_type="sync", created_at="2023-01-01T00:00:00Z", updated_at="2023-01-01T00:00:00Z"),
|
89
|
+
task=Task(id="test-task-123", status="RUNNING"),
|
88
90
|
)
|
89
91
|
|
90
92
|
|
@@ -92,7 +94,7 @@ def sample_cancel_task_params() -> CancelTaskParams:
|
|
92
94
|
def sample_create_task_params(sample_task: Task) -> CreateTaskParams:
|
93
95
|
"""Fixture that provides sample CreateTaskParams"""
|
94
96
|
return CreateTaskParams(
|
95
|
-
agent=Agent(id="test-agent-456", name="test-agent", description="test-agent", acp_type="sync"),
|
97
|
+
agent=Agent(id="test-agent-456", name="test-agent", description="test-agent", acp_type="sync", created_at="2023-01-01T00:00:00Z", updated_at="2023-01-01T00:00:00Z"),
|
96
98
|
task=sample_task,
|
97
99
|
params={},
|
98
100
|
)
|
@@ -202,7 +204,7 @@ async def async_sync_acp_server():
|
|
202
204
|
with patch.dict(
|
203
205
|
"os.environ", {"AGENTEX_BASE_URL": ""}
|
204
206
|
): # Disable agent registration
|
205
|
-
server =
|
207
|
+
server = SyncACP.create()
|
206
208
|
return server
|
207
209
|
|
208
210
|
|
@@ -222,7 +224,7 @@ async def async_agentic_base_acp_server():
|
|
222
224
|
with patch.dict(
|
223
225
|
"os.environ", {"AGENTEX_BASE_URL": ""}
|
224
226
|
): # Disable agent registration
|
225
|
-
server =
|
227
|
+
server = AgenticBaseACP.create()
|
226
228
|
return server
|
227
229
|
|
228
230
|
|
@@ -242,7 +244,7 @@ async def mock_temporal_acp_server():
|
|
242
244
|
mock_temporal_client.create.return_value = AsyncMock()
|
243
245
|
mock_agentex_client.return_value = AsyncMock()
|
244
246
|
|
245
|
-
server =
|
247
|
+
server = TemporalACP.create(temporal_address="localhost:7233")
|
246
248
|
return server
|
247
249
|
|
248
250
|
|
@@ -1,15 +1,16 @@
|
|
1
|
+
# ruff: noqa: ARG001
|
1
2
|
import asyncio
|
2
3
|
from unittest.mock import patch
|
3
4
|
|
4
5
|
import pytest
|
5
6
|
from fastapi.testclient import TestClient
|
6
7
|
|
7
|
-
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
8
8
|
from agentex.lib.types.acp import (
|
9
|
-
CancelTaskParams,
|
10
9
|
RPCMethod,
|
11
10
|
SendEventParams,
|
11
|
+
CancelTaskParams,
|
12
12
|
)
|
13
|
+
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
13
14
|
|
14
15
|
|
15
16
|
class TestBaseACPServerInitialization:
|
@@ -21,7 +22,7 @@ class TestBaseACPServerInitialization:
|
|
21
22
|
server = BaseACPServer()
|
22
23
|
|
23
24
|
# Check that FastAPI routes are set up
|
24
|
-
routes = [route.path for route in server.routes]
|
25
|
+
routes = [route.path for route in server.routes] # type: ignore[attr-defined]
|
25
26
|
assert "/healthz" in routes
|
26
27
|
assert "/api" in routes
|
27
28
|
|
@@ -141,7 +142,6 @@ class TestJSONRPCEndpointCore:
|
|
141
142
|
data = response.json()
|
142
143
|
assert data["jsonrpc"] == "2.0"
|
143
144
|
assert data["id"] == "test-1"
|
144
|
-
print("DATA", data)
|
145
145
|
# Should return immediate acknowledgment
|
146
146
|
assert data["result"]["status"] == "processing"
|
147
147
|
|
@@ -3,17 +3,17 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|
3
3
|
|
4
4
|
import pytest
|
5
5
|
|
6
|
-
from agentex.lib.sdk.fastacp.base.base_acp_server import BaseACPServer
|
7
|
-
from agentex.lib.sdk.fastacp.fastacp import FastACP
|
8
|
-
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
9
|
-
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
10
|
-
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
11
6
|
from agentex.lib.types.fastacp import (
|
12
|
-
AgenticACPConfig,
|
13
|
-
AgenticBaseACPConfig,
|
14
7
|
SyncACPConfig,
|
8
|
+
AgenticACPConfig,
|
15
9
|
TemporalACPConfig,
|
10
|
+
AgenticBaseACPConfig,
|
16
11
|
)
|
12
|
+
from agentex.lib.sdk.fastacp.fastacp import FastACP
|
13
|
+
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
14
|
+
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
15
|
+
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:
|
@@ -212,7 +212,7 @@ class TestConfigurationValidation:
|
|
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.create_agentic_acp()
|
215
|
+
FastACP.create_agentic_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"""
|
@@ -1,18 +1,19 @@
|
|
1
|
+
# ruff: noqa: ARG001
|
1
2
|
import asyncio
|
2
3
|
from unittest.mock import AsyncMock, MagicMock, patch
|
3
4
|
|
4
5
|
import httpx
|
5
6
|
import pytest
|
6
7
|
|
7
|
-
from agentex.lib.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
8
|
-
from agentex.lib.sdk.fastacp.impl.sync_acp import SyncACP
|
9
|
-
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
|
10
8
|
from agentex.lib.types.acp import (
|
11
|
-
CancelTaskParams,
|
12
|
-
CreateTaskParams,
|
13
9
|
RPCMethod,
|
14
10
|
SendEventParams,
|
11
|
+
CancelTaskParams,
|
12
|
+
CreateTaskParams,
|
15
13
|
)
|
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.sdk.fastacp.impl.agentic_base_acp import AgenticBaseACP
|
16
17
|
|
17
18
|
|
18
19
|
class TestImplementationBehavior:
|
@@ -48,7 +49,7 @@ class TestImplementationBehavior:
|
|
48
49
|
mock_temporal_instance.temporal_client = MagicMock()
|
49
50
|
mock_create.return_value = mock_temporal_instance
|
50
51
|
|
51
|
-
temporal_acp =
|
52
|
+
temporal_acp = TemporalACP.create(temporal_address="localhost:7233")
|
52
53
|
|
53
54
|
assert temporal_acp == mock_temporal_instance
|
54
55
|
assert hasattr(temporal_acp, "temporal_client")
|
@@ -67,8 +68,8 @@ class TestRealWorldScenarios:
|
|
67
68
|
messages_received.append(
|
68
69
|
{
|
69
70
|
"task_id": params.task.id,
|
70
|
-
"message_content": params.message.content,
|
71
|
-
"author": params.message.author,
|
71
|
+
"message_content": params.message.content, # type: ignore[attr-defined]
|
72
|
+
"author": params.message.author, # type: ignore[attr-defined]
|
72
73
|
}
|
73
74
|
)
|
74
75
|
return {"processed": True}
|
@@ -127,7 +128,7 @@ class TestRealWorldScenarios:
|
|
127
128
|
|
128
129
|
@agentic_base_acp.on_task_cancel
|
129
130
|
async def cancel_handler(params: CancelTaskParams):
|
130
|
-
task_events.append(("cancelled", params.task_id))
|
131
|
+
task_events.append(("cancelled", params.task_id)) # type: ignore[attr-defined]
|
131
132
|
|
132
133
|
runner = test_server_runner(agentic_base_acp, free_port)
|
133
134
|
await runner.start()
|
@@ -209,7 +210,7 @@ class TestErrorRecovery:
|
|
209
210
|
@sync_acp.on_task_event_send
|
210
211
|
async def unreliable_handler(params: SendEventParams):
|
211
212
|
nonlocal failure_count, success_count
|
212
|
-
if "fail" in params.message.content:
|
213
|
+
if "fail" in params.message.content: # type: ignore[attr-defined]
|
213
214
|
failure_count += 1
|
214
215
|
raise RuntimeError("Simulated handler failure")
|
215
216
|
else:
|
@@ -326,7 +327,7 @@ class TestSpecialCases:
|
|
326
327
|
@sync_acp.on_task_event_send
|
327
328
|
async def tracking_handler(params: SendEventParams):
|
328
329
|
nonlocal notifications_received, requests_received
|
329
|
-
if "notification" in params.message.content:
|
330
|
+
if "notification" in params.message.content: # type: ignore[attr-defined]
|
330
331
|
notifications_received += 1
|
331
332
|
else:
|
332
333
|
requests_received += 1
|
@@ -397,7 +398,7 @@ class TestSpecialCases:
|
|
397
398
|
@sync_acp.on_task_event_send
|
398
399
|
async def unicode_handler(params: SendEventParams):
|
399
400
|
nonlocal received_message
|
400
|
-
received_message = params.message.content
|
401
|
+
received_message = params.message.content # type: ignore[attr-defined]
|
401
402
|
return {"unicode_handled": True}
|
402
403
|
|
403
404
|
runner = test_server_runner(sync_acp, free_port)
|
@@ -458,9 +459,9 @@ class TestImplementationIsolation:
|
|
458
459
|
return {"agentic": True}
|
459
460
|
|
460
461
|
# Create test parameters
|
461
|
-
message_params = SendEventParams(
|
462
|
+
message_params = SendEventParams( # type: ignore[call-arg]
|
462
463
|
task={"id": "isolation-test-task", "agent_id": "test-agent", "status": "RUNNING"},
|
463
|
-
|
464
|
+
event={"type": "text", "author": "user", "content": "Isolation test"}, # type: ignore[misc]
|
464
465
|
)
|
465
466
|
|
466
467
|
# Execute sync handler
|
@@ -1,8 +1,9 @@
|
|
1
|
+
from typing import TYPE_CHECKING, override
|
2
|
+
|
1
3
|
from pydantic import BaseModel
|
2
4
|
|
3
|
-
from agentex.lib.sdk.state_machine.state_workflow import StateWorkflow
|
4
5
|
from agentex.lib.utils.logging import make_logger
|
5
|
-
from
|
6
|
+
from agentex.lib.sdk.state_machine.state_workflow import StateWorkflow
|
6
7
|
|
7
8
|
if TYPE_CHECKING:
|
8
9
|
from agentex.lib.sdk.state_machine import StateMachine
|
@@ -15,7 +16,8 @@ class NoOpWorkflow(StateWorkflow):
|
|
15
16
|
Workflow that does nothing. This is commonly used as a terminal state.
|
16
17
|
"""
|
17
18
|
|
19
|
+
@override
|
18
20
|
async def execute(
|
19
21
|
self, state_machine: "StateMachine", state_machine_data: BaseModel | None = None
|
20
22
|
) -> str:
|
21
|
-
|
23
|
+
return state_machine.get_current_state() # Stay in current state
|