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,85 @@
|
|
1
|
+
from agentex import AsyncAgentex
|
2
|
+
from agentex.lib.core.tracing.tracer import AsyncTracer
|
3
|
+
from agentex.lib.utils.logging import make_logger
|
4
|
+
from agentex.types.agent_task_tracker import AgentTaskTracker
|
5
|
+
|
6
|
+
logger = make_logger(__name__)
|
7
|
+
|
8
|
+
|
9
|
+
class AgentTaskTrackerService:
|
10
|
+
def __init__(
|
11
|
+
self, agentex_client: AsyncAgentex, tracer: AsyncTracer,
|
12
|
+
):
|
13
|
+
self._agentex_client = agentex_client
|
14
|
+
self._tracer = tracer
|
15
|
+
|
16
|
+
async def get_agent_task_tracker(
|
17
|
+
self,
|
18
|
+
tracker_id: str,
|
19
|
+
trace_id: str | None = None,
|
20
|
+
parent_span_id: str | None = None,
|
21
|
+
) -> AgentTaskTracker:
|
22
|
+
trace = self._tracer.trace(trace_id)
|
23
|
+
async with trace.span(
|
24
|
+
parent_id=parent_span_id,
|
25
|
+
name="get_agent_task_tracker",
|
26
|
+
input={"tracker_id": tracker_id},
|
27
|
+
) as span:
|
28
|
+
tracker = await self._agentex_client.tracker.retrieve(
|
29
|
+
tracker_id
|
30
|
+
)
|
31
|
+
if span:
|
32
|
+
span.output = tracker.model_dump()
|
33
|
+
return tracker
|
34
|
+
|
35
|
+
async def get_by_task_and_agent(
|
36
|
+
self,
|
37
|
+
task_id: str,
|
38
|
+
agent_id: str,
|
39
|
+
trace_id: str | None = None,
|
40
|
+
parent_span_id: str | None = None,
|
41
|
+
) -> AgentTaskTracker | None:
|
42
|
+
trace = self._tracer.trace(trace_id)
|
43
|
+
async with trace.span(
|
44
|
+
parent_id=parent_span_id,
|
45
|
+
name="get_by_task_and_agent",
|
46
|
+
input={"task_id": task_id, "agent_id": agent_id},
|
47
|
+
) as span:
|
48
|
+
trackers = await self._agentex_client.tracker.list(
|
49
|
+
task_id=task_id,
|
50
|
+
agent_id=agent_id,
|
51
|
+
)
|
52
|
+
tracker = trackers[0] if trackers else None
|
53
|
+
if span:
|
54
|
+
span.output = tracker.model_dump() if tracker else None
|
55
|
+
return tracker
|
56
|
+
|
57
|
+
async def update_agent_task_tracker(
|
58
|
+
self,
|
59
|
+
tracker_id: str,
|
60
|
+
last_processed_event_id: str | None = None,
|
61
|
+
status: str | None = None,
|
62
|
+
status_reason: str | None = None,
|
63
|
+
trace_id: str | None = None,
|
64
|
+
parent_span_id: str | None = None,
|
65
|
+
) -> AgentTaskTracker:
|
66
|
+
trace = self._tracer.trace(trace_id)
|
67
|
+
async with trace.span(
|
68
|
+
parent_id=parent_span_id,
|
69
|
+
name="update_agent_task_tracker",
|
70
|
+
input={
|
71
|
+
"tracker_id": tracker_id,
|
72
|
+
"last_processed_event_id": last_processed_event_id,
|
73
|
+
"status": status,
|
74
|
+
"status_reason": status_reason,
|
75
|
+
},
|
76
|
+
) as span:
|
77
|
+
tracker = await self._agentex_client.tracker.update(
|
78
|
+
tracker_id=tracker_id,
|
79
|
+
last_processed_event_id=last_processed_event_id,
|
80
|
+
status=status,
|
81
|
+
status_reason=status_reason,
|
82
|
+
)
|
83
|
+
if span:
|
84
|
+
span.output = tracker.model_dump()
|
85
|
+
return tracker
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from agentex import AsyncAgentex
|
4
|
+
from agentex.lib.core.tracing.tracer import AsyncTracer
|
5
|
+
from agentex.types.agent import Agent
|
6
|
+
from agentex.lib.utils.logging import make_logger
|
7
|
+
from agentex.lib.utils.temporal import heartbeat_if_in_workflow
|
8
|
+
|
9
|
+
logger = make_logger(__name__)
|
10
|
+
|
11
|
+
|
12
|
+
class AgentsService:
|
13
|
+
def __init__(
|
14
|
+
self,
|
15
|
+
agentex_client: AsyncAgentex,
|
16
|
+
tracer: AsyncTracer,
|
17
|
+
):
|
18
|
+
self._agentex_client = agentex_client
|
19
|
+
self._tracer = tracer
|
20
|
+
|
21
|
+
async def get_agent(
|
22
|
+
self,
|
23
|
+
agent_id: Optional[str] = None,
|
24
|
+
agent_name: Optional[str] = None,
|
25
|
+
trace_id: Optional[str] = None,
|
26
|
+
parent_span_id: Optional[str] = None,
|
27
|
+
) -> Agent:
|
28
|
+
trace = self._tracer.trace(trace_id)
|
29
|
+
async with trace.span(
|
30
|
+
parent_id=parent_span_id,
|
31
|
+
name="get_agent",
|
32
|
+
input={"agent_id": agent_id, "agent_name": agent_name},
|
33
|
+
) as span:
|
34
|
+
heartbeat_if_in_workflow("get agent")
|
35
|
+
if agent_id:
|
36
|
+
agent = await self._agentex_client.agents.retrieve(agent_id=agent_id)
|
37
|
+
elif agent_name:
|
38
|
+
agent = await self._agentex_client.agents.retrieve_by_name(agent_name=agent_name)
|
39
|
+
else:
|
40
|
+
raise ValueError("Either agent_id or agent_name must be provided")
|
41
|
+
if span:
|
42
|
+
span.output = agent.model_dump()
|
43
|
+
return agent
|
@@ -0,0 +1,61 @@
|
|
1
|
+
from agentex import AsyncAgentex
|
2
|
+
from agentex.lib.core.tracing.tracer import AsyncTracer
|
3
|
+
from agentex.types.event import Event
|
4
|
+
from agentex.lib.utils.logging import make_logger
|
5
|
+
|
6
|
+
logger = make_logger(__name__)
|
7
|
+
|
8
|
+
|
9
|
+
class EventsService:
|
10
|
+
def __init__(
|
11
|
+
self, agentex_client: AsyncAgentex, tracer: AsyncTracer
|
12
|
+
):
|
13
|
+
self._agentex_client = agentex_client
|
14
|
+
self._tracer = tracer
|
15
|
+
|
16
|
+
async def get_event(
|
17
|
+
self,
|
18
|
+
event_id: str,
|
19
|
+
trace_id: str | None = None,
|
20
|
+
parent_span_id: str | None = None,
|
21
|
+
) -> Event | None:
|
22
|
+
trace = self._tracer.trace(trace_id)
|
23
|
+
async with trace.span(
|
24
|
+
parent_id=parent_span_id,
|
25
|
+
name="get_event",
|
26
|
+
input={"event_id": event_id},
|
27
|
+
) as span:
|
28
|
+
event = await self._agentex_client.events.retrieve(event_id=event_id)
|
29
|
+
if span:
|
30
|
+
span.output = event.model_dump()
|
31
|
+
return event
|
32
|
+
|
33
|
+
async def list_events(
|
34
|
+
self,
|
35
|
+
task_id: str,
|
36
|
+
agent_id: str,
|
37
|
+
last_processed_event_id: str | None = None,
|
38
|
+
limit: int | None = None,
|
39
|
+
trace_id: str | None = None,
|
40
|
+
parent_span_id: str | None = None,
|
41
|
+
) -> list[Event]:
|
42
|
+
trace = self._tracer.trace(trace_id)
|
43
|
+
async with trace.span(
|
44
|
+
parent_id=parent_span_id,
|
45
|
+
name="list_events",
|
46
|
+
input={
|
47
|
+
"task_id": task_id,
|
48
|
+
"agent_id": agent_id,
|
49
|
+
"last_processed_event_id": last_processed_event_id,
|
50
|
+
"limit": limit,
|
51
|
+
},
|
52
|
+
) as span:
|
53
|
+
events = await self._agentex_client.events.list(
|
54
|
+
task_id=task_id,
|
55
|
+
agent_id=agent_id,
|
56
|
+
last_processed_event_id=last_processed_event_id,
|
57
|
+
limit=limit,
|
58
|
+
)
|
59
|
+
if span:
|
60
|
+
span.output = [event.model_dump() for event in events]
|
61
|
+
return events
|
@@ -0,0 +1,164 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Any, Coroutine, cast
|
3
|
+
|
4
|
+
from agentex import AsyncAgentex
|
5
|
+
from agentex.lib.core.services.adk.streaming import StreamingService
|
6
|
+
from agentex.lib.core.tracing.tracer import AsyncTracer
|
7
|
+
from agentex.lib.types.task_message_updates import StreamTaskMessageFull, TaskMessageUpdate
|
8
|
+
from agentex.types.task_message import TaskMessage, TaskMessageContent
|
9
|
+
from agentex.lib.utils.logging import make_logger
|
10
|
+
from agentex.lib.utils.temporal import heartbeat_if_in_workflow
|
11
|
+
from agentex.types.task_message_content_param import TaskMessageContentParam
|
12
|
+
|
13
|
+
logger = make_logger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
class MessagesService:
|
17
|
+
def __init__(
|
18
|
+
self,
|
19
|
+
agentex_client: AsyncAgentex,
|
20
|
+
streaming_service: StreamingService,
|
21
|
+
tracer: AsyncTracer,
|
22
|
+
):
|
23
|
+
self._agentex_client = agentex_client
|
24
|
+
self._streaming_service = streaming_service
|
25
|
+
self._tracer = tracer
|
26
|
+
|
27
|
+
async def create_message(
|
28
|
+
self,
|
29
|
+
task_id: str,
|
30
|
+
content: TaskMessageContent,
|
31
|
+
emit_updates: bool = True,
|
32
|
+
trace_id: str | None = None,
|
33
|
+
parent_span_id: str | None = None,
|
34
|
+
) -> TaskMessage:
|
35
|
+
trace = self._tracer.trace(trace_id)
|
36
|
+
async with trace.span(
|
37
|
+
parent_id=parent_span_id,
|
38
|
+
name="create_message",
|
39
|
+
input={"task_id": task_id, "message": content},
|
40
|
+
) as span:
|
41
|
+
heartbeat_if_in_workflow("create message")
|
42
|
+
task_message = await self._agentex_client.messages.create(
|
43
|
+
task_id=task_id,
|
44
|
+
content=content.model_dump(),
|
45
|
+
)
|
46
|
+
if emit_updates:
|
47
|
+
await self._emit_updates([task_message])
|
48
|
+
if span:
|
49
|
+
span.output = task_message.model_dump()
|
50
|
+
return task_message
|
51
|
+
|
52
|
+
async def update_message(
|
53
|
+
self,
|
54
|
+
task_id: str,
|
55
|
+
message_id: str,
|
56
|
+
content: TaskMessageContent,
|
57
|
+
trace_id: str | None = None,
|
58
|
+
parent_span_id: str | None = None,
|
59
|
+
) -> TaskMessage:
|
60
|
+
trace = self._tracer.trace(trace_id)
|
61
|
+
async with trace.span(
|
62
|
+
parent_id=parent_span_id,
|
63
|
+
name="update_message",
|
64
|
+
input={
|
65
|
+
"task_id": task_id,
|
66
|
+
"message_id": message_id,
|
67
|
+
"message": content,
|
68
|
+
},
|
69
|
+
) as span:
|
70
|
+
heartbeat_if_in_workflow("update message")
|
71
|
+
task_message = await self._agentex_client.messages.update(
|
72
|
+
task_id=task_id,
|
73
|
+
message_id=message_id,
|
74
|
+
content=content.model_dump(),
|
75
|
+
)
|
76
|
+
if span:
|
77
|
+
span.output = task_message.model_dump()
|
78
|
+
return task_message
|
79
|
+
|
80
|
+
async def create_messages_batch(
|
81
|
+
self,
|
82
|
+
task_id: str,
|
83
|
+
contents: list[TaskMessageContent],
|
84
|
+
emit_updates: bool = True,
|
85
|
+
trace_id: str | None = None,
|
86
|
+
parent_span_id: str | None = None,
|
87
|
+
) -> list[TaskMessage]:
|
88
|
+
trace = self._tracer.trace(trace_id)
|
89
|
+
async with trace.span(
|
90
|
+
parent_id=parent_span_id,
|
91
|
+
name="create_messages_batch",
|
92
|
+
input={"task_id": task_id, "messages": contents},
|
93
|
+
) as span:
|
94
|
+
heartbeat_if_in_workflow("create messages batch")
|
95
|
+
task_messages = await self._agentex_client.messages.batch.create(
|
96
|
+
task_id=task_id,
|
97
|
+
contents=[content.model_dump() for content in contents],
|
98
|
+
)
|
99
|
+
if emit_updates:
|
100
|
+
await self._emit_updates(task_messages)
|
101
|
+
if span:
|
102
|
+
span.output = [task_message.model_dump() for task_message in task_messages]
|
103
|
+
return task_messages
|
104
|
+
|
105
|
+
async def update_messages_batch(
|
106
|
+
self,
|
107
|
+
task_id: str,
|
108
|
+
updates: dict[str, TaskMessageContent],
|
109
|
+
trace_id: str | None = None,
|
110
|
+
parent_span_id: str | None = None,
|
111
|
+
) -> list[TaskMessage]:
|
112
|
+
trace = self._tracer.trace(trace_id)
|
113
|
+
async with trace.span(
|
114
|
+
parent_id=parent_span_id,
|
115
|
+
name="update_messages_batch",
|
116
|
+
input={"task_id": task_id, "updates": updates},
|
117
|
+
) as span:
|
118
|
+
heartbeat_if_in_workflow("update messages batch")
|
119
|
+
task_messages = await self._agentex_client.messages.batch.update(
|
120
|
+
task_id=task_id,
|
121
|
+
updates={
|
122
|
+
message_id: content.model_dump()
|
123
|
+
for message_id, content in updates.items()
|
124
|
+
},
|
125
|
+
)
|
126
|
+
if span:
|
127
|
+
span.output = [task_message.model_dump() for task_message in task_messages]
|
128
|
+
return task_messages
|
129
|
+
|
130
|
+
async def list_messages(
|
131
|
+
self,
|
132
|
+
task_id: str,
|
133
|
+
limit: int | None = None,
|
134
|
+
trace_id: str | None = None,
|
135
|
+
parent_span_id: str | None = None,
|
136
|
+
) -> list[TaskMessage]:
|
137
|
+
trace = self._tracer.trace(trace_id)
|
138
|
+
async with trace.span(
|
139
|
+
parent_id=parent_span_id,
|
140
|
+
name="list_messages",
|
141
|
+
input={"task_id": task_id, "limit": limit},
|
142
|
+
) as span:
|
143
|
+
heartbeat_if_in_workflow("list messages")
|
144
|
+
task_messages = await self._agentex_client.messages.list(
|
145
|
+
task_id=task_id,
|
146
|
+
limit=limit,
|
147
|
+
)
|
148
|
+
if span:
|
149
|
+
span.output = [task_message.model_dump() for task_message in task_messages]
|
150
|
+
return task_messages
|
151
|
+
|
152
|
+
async def _emit_updates(self, task_messages: list[TaskMessage]) -> None:
|
153
|
+
stream_update_handlers: list[Coroutine[Any, Any, TaskMessageUpdate | None]] = []
|
154
|
+
for task_message in task_messages:
|
155
|
+
stream_update_handler = self._streaming_service.stream_update(
|
156
|
+
update=StreamTaskMessageFull(
|
157
|
+
type="full",
|
158
|
+
parent_task_message=task_message,
|
159
|
+
content=task_message.content,
|
160
|
+
)
|
161
|
+
)
|
162
|
+
stream_update_handlers.append(stream_update_handler)
|
163
|
+
|
164
|
+
await asyncio.gather(*stream_update_handlers)
|
File without changes
|
@@ -0,0 +1,256 @@
|
|
1
|
+
from collections.abc import AsyncGenerator
|
2
|
+
|
3
|
+
from agentex import AsyncAgentex
|
4
|
+
from agentex.lib.core.adapters.llm.adapter_litellm import LiteLLMGateway
|
5
|
+
from agentex.lib.core.services.adk.streaming import StreamingService
|
6
|
+
from agentex.lib.core.tracing.tracer import AsyncTracer
|
7
|
+
from agentex.lib.types.llm_messages import (
|
8
|
+
Completion,
|
9
|
+
LLMConfig,
|
10
|
+
)
|
11
|
+
from agentex.lib.types.task_message_updates import (
|
12
|
+
StreamTaskMessageDelta,
|
13
|
+
StreamTaskMessageFull,
|
14
|
+
TextDelta,
|
15
|
+
)
|
16
|
+
from agentex.types.task_message import TaskMessage
|
17
|
+
from agentex.types.task_message_content import TextContent
|
18
|
+
from agentex.lib.utils import logging
|
19
|
+
from agentex.lib.utils.completions import concat_completion_chunks
|
20
|
+
from agentex.lib.utils.temporal import heartbeat_if_in_workflow
|
21
|
+
|
22
|
+
logger = logging.make_logger(__name__)
|
23
|
+
|
24
|
+
|
25
|
+
class LiteLLMService:
|
26
|
+
def __init__(
|
27
|
+
self,
|
28
|
+
agentex_client: AsyncAgentex,
|
29
|
+
streaming_service: StreamingService,
|
30
|
+
tracer: AsyncTracer,
|
31
|
+
llm_gateway: LiteLLMGateway | None = None,
|
32
|
+
):
|
33
|
+
self.agentex_client = agentex_client
|
34
|
+
self.llm_gateway = llm_gateway
|
35
|
+
self.streaming_service = streaming_service
|
36
|
+
self.tracer = tracer
|
37
|
+
|
38
|
+
async def chat_completion(
|
39
|
+
self,
|
40
|
+
llm_config: LLMConfig,
|
41
|
+
trace_id: str | None = None,
|
42
|
+
parent_span_id: str | None = None,
|
43
|
+
) -> Completion:
|
44
|
+
trace = self.tracer.trace(trace_id)
|
45
|
+
async with trace.span(
|
46
|
+
parent_id=parent_span_id,
|
47
|
+
name="chat_completion",
|
48
|
+
input=llm_config.model_dump(),
|
49
|
+
) as span:
|
50
|
+
heartbeat_if_in_workflow("chat completion")
|
51
|
+
if self.llm_gateway is None:
|
52
|
+
raise ValueError("LLM Gateway is not set")
|
53
|
+
completion = await self.llm_gateway.acompletion(**llm_config.model_dump())
|
54
|
+
if span:
|
55
|
+
span.output = completion.model_dump()
|
56
|
+
return completion
|
57
|
+
|
58
|
+
async def chat_completion_auto_send(
|
59
|
+
self,
|
60
|
+
task_id: str,
|
61
|
+
llm_config: LLMConfig,
|
62
|
+
trace_id: str | None = None,
|
63
|
+
parent_span_id: str | None = None,
|
64
|
+
) -> TaskMessage | None:
|
65
|
+
"""
|
66
|
+
Chat completion with automatic TaskMessage creation. This does not stream the completion. To stream use chat_completion_stream_auto_send.
|
67
|
+
|
68
|
+
Args:
|
69
|
+
task_id (str): The ID of the task to run the agent for.
|
70
|
+
llm_config (LLMConfig): The configuration for the LLM (must have stream=True).
|
71
|
+
|
72
|
+
Returns:
|
73
|
+
TaskMessage: A TaskMessage object
|
74
|
+
"""
|
75
|
+
|
76
|
+
if llm_config.stream:
|
77
|
+
raise ValueError(
|
78
|
+
"LLM config must not have stream=True. To stream use `chat_completion_stream` or `chat_completion_stream_auto_send`."
|
79
|
+
)
|
80
|
+
|
81
|
+
if self.llm_gateway is None:
|
82
|
+
raise ValueError("LLM Gateway is not set")
|
83
|
+
|
84
|
+
trace = self.tracer.trace(trace_id)
|
85
|
+
async with trace.span(
|
86
|
+
parent_id=parent_span_id,
|
87
|
+
name="chat_completion_auto_send",
|
88
|
+
input=llm_config.model_dump(),
|
89
|
+
) as span:
|
90
|
+
heartbeat_if_in_workflow("chat completion auto send")
|
91
|
+
|
92
|
+
async with self.streaming_service.streaming_task_message_context(
|
93
|
+
task_id=task_id,
|
94
|
+
initial_content=TextContent(
|
95
|
+
author="agent",
|
96
|
+
content="",
|
97
|
+
format="markdown",
|
98
|
+
),
|
99
|
+
) as streaming_context:
|
100
|
+
completion = await self.llm_gateway.acompletion(**llm_config.model_dump())
|
101
|
+
if (
|
102
|
+
completion.choices
|
103
|
+
and len(completion.choices) > 0
|
104
|
+
and completion.choices[0].message
|
105
|
+
):
|
106
|
+
final_content = TextContent(
|
107
|
+
author="agent",
|
108
|
+
content=completion.choices[0].message.content or "",
|
109
|
+
format="markdown",
|
110
|
+
)
|
111
|
+
await streaming_context.stream_update(
|
112
|
+
update=StreamTaskMessageFull(
|
113
|
+
parent_task_message=streaming_context.task_message,
|
114
|
+
content=final_content,
|
115
|
+
),
|
116
|
+
)
|
117
|
+
else:
|
118
|
+
raise ValueError("No completion message returned from LLM")
|
119
|
+
|
120
|
+
if span:
|
121
|
+
if streaming_context.task_message:
|
122
|
+
span.output = streaming_context.task_message.model_dump()
|
123
|
+
return streaming_context.task_message if streaming_context.task_message else None
|
124
|
+
|
125
|
+
async def chat_completion_stream(
|
126
|
+
self,
|
127
|
+
llm_config: LLMConfig,
|
128
|
+
trace_id: str | None = None,
|
129
|
+
parent_span_id: str | None = None,
|
130
|
+
) -> AsyncGenerator[Completion, None]:
|
131
|
+
"""
|
132
|
+
Stream chat completion chunks using LiteLLM.
|
133
|
+
|
134
|
+
Args:
|
135
|
+
llm_config (LLMConfig): The configuration for the LLM (must have stream=True).
|
136
|
+
trace_id (Optional[str]): The trace ID for tracing.
|
137
|
+
parent_span_id (Optional[str]): The parent span ID for tracing.
|
138
|
+
|
139
|
+
Returns:
|
140
|
+
AsyncGenerator[Completion, None]: Generator yielding completion chunks
|
141
|
+
|
142
|
+
Raises:
|
143
|
+
ValueError: If called from within a Temporal workflow or if stream=False
|
144
|
+
"""
|
145
|
+
if not llm_config.stream:
|
146
|
+
raise ValueError("LLM config must have stream=True for streaming")
|
147
|
+
|
148
|
+
if self.llm_gateway is None:
|
149
|
+
raise ValueError("LLM Gateway is not set")
|
150
|
+
|
151
|
+
trace = self.tracer.trace(trace_id)
|
152
|
+
async with trace.span(
|
153
|
+
parent_id=parent_span_id,
|
154
|
+
name="chat_completion_stream",
|
155
|
+
input=llm_config.model_dump(),
|
156
|
+
) as span:
|
157
|
+
# Direct streaming outside temporal - yield each chunk as it comes
|
158
|
+
chunks: list[Completion] = []
|
159
|
+
async for chunk in self.llm_gateway.acompletion_stream(
|
160
|
+
**llm_config.model_dump()
|
161
|
+
):
|
162
|
+
chunks.append(chunk)
|
163
|
+
yield chunk
|
164
|
+
if span:
|
165
|
+
span.output = concat_completion_chunks(chunks).model_dump()
|
166
|
+
|
167
|
+
async def chat_completion_stream_auto_send(
|
168
|
+
self,
|
169
|
+
task_id: str,
|
170
|
+
llm_config: LLMConfig,
|
171
|
+
trace_id: str | None = None,
|
172
|
+
parent_span_id: str | None = None,
|
173
|
+
) -> TaskMessage | None:
|
174
|
+
"""
|
175
|
+
Stream chat completion with automatic TaskMessage creation and streaming.
|
176
|
+
|
177
|
+
Args:
|
178
|
+
task_id (str): The ID of the task to run the agent for.
|
179
|
+
llm_config (LLMConfig): The configuration for the LLM (must have stream=True).
|
180
|
+
|
181
|
+
Returns:
|
182
|
+
TaskMessage: A TaskMessage object
|
183
|
+
"""
|
184
|
+
heartbeat_if_in_workflow("chat completion stream")
|
185
|
+
|
186
|
+
if self.llm_gateway is None:
|
187
|
+
raise ValueError("LLM Gateway is not set")
|
188
|
+
|
189
|
+
if not llm_config.stream:
|
190
|
+
llm_config.stream = True
|
191
|
+
|
192
|
+
trace = self.tracer.trace(trace_id)
|
193
|
+
async with trace.span(
|
194
|
+
parent_id=parent_span_id,
|
195
|
+
name="chat_completion_stream",
|
196
|
+
input=llm_config.model_dump(),
|
197
|
+
) as span:
|
198
|
+
# Use streaming context manager
|
199
|
+
async with self.streaming_service.streaming_task_message_context(
|
200
|
+
task_id=task_id,
|
201
|
+
initial_content=TextContent(
|
202
|
+
author="agent",
|
203
|
+
content="",
|
204
|
+
format="markdown",
|
205
|
+
),
|
206
|
+
) as streaming_context:
|
207
|
+
# Get the streaming response
|
208
|
+
chunks = []
|
209
|
+
async for response in self.llm_gateway.acompletion_stream(
|
210
|
+
**llm_config.model_dump()
|
211
|
+
):
|
212
|
+
heartbeat_if_in_workflow("chat completion streaming")
|
213
|
+
if (
|
214
|
+
response.choices
|
215
|
+
and len(response.choices) > 0
|
216
|
+
and response.choices[0].delta
|
217
|
+
):
|
218
|
+
delta = response.choices[0].delta.content
|
219
|
+
if delta:
|
220
|
+
# Stream the chunk via the context manager
|
221
|
+
await streaming_context.stream_update(
|
222
|
+
update=StreamTaskMessageDelta(
|
223
|
+
parent_task_message=streaming_context.task_message,
|
224
|
+
delta=TextDelta(text_delta=delta),
|
225
|
+
),
|
226
|
+
)
|
227
|
+
heartbeat_if_in_workflow("content chunk streamed")
|
228
|
+
|
229
|
+
# Store the chunk for final message assembly
|
230
|
+
chunks.append(response)
|
231
|
+
|
232
|
+
# Update the final message content
|
233
|
+
complete_message = concat_completion_chunks(chunks)
|
234
|
+
if (
|
235
|
+
complete_message
|
236
|
+
and complete_message.choices
|
237
|
+
and complete_message.choices[0].message
|
238
|
+
):
|
239
|
+
final_content = TextContent(
|
240
|
+
author="agent",
|
241
|
+
content=complete_message.choices[0].message.content or "",
|
242
|
+
)
|
243
|
+
await streaming_context.stream_update(
|
244
|
+
update=StreamTaskMessageFull(
|
245
|
+
parent_task_message=streaming_context.task_message,
|
246
|
+
content=final_content,
|
247
|
+
),
|
248
|
+
)
|
249
|
+
|
250
|
+
heartbeat_if_in_workflow("chat completion stream complete")
|
251
|
+
|
252
|
+
if span:
|
253
|
+
if streaming_context.task_message:
|
254
|
+
span.output = streaming_context.task_message.model_dump()
|
255
|
+
|
256
|
+
return streaming_context.task_message if streaming_context.task_message else None
|