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,311 @@
|
|
1
|
+
import asyncio
|
2
|
+
from contextlib import asynccontextmanager, contextmanager
|
3
|
+
from datetime import UTC, datetime
|
4
|
+
from typing import Any, AsyncGenerator
|
5
|
+
import uuid
|
6
|
+
|
7
|
+
from pydantic import BaseModel
|
8
|
+
|
9
|
+
from agentex import Agentex, AsyncAgentex
|
10
|
+
from agentex.lib.core.tracing.processors.tracing_processor_interface import (
|
11
|
+
AsyncTracingProcessor,
|
12
|
+
SyncTracingProcessor,
|
13
|
+
)
|
14
|
+
from agentex.lib.utils.logging import make_logger
|
15
|
+
from agentex.lib.utils.model_utils import recursive_model_dump
|
16
|
+
from agentex.types.span import Span
|
17
|
+
|
18
|
+
logger = make_logger(__name__)
|
19
|
+
|
20
|
+
|
21
|
+
class Trace:
|
22
|
+
"""
|
23
|
+
Trace is a wrapper around the Agentex API for tracing.
|
24
|
+
It provides a context manager for spans and a way to start and end spans.
|
25
|
+
It also provides a way to get spans by ID and list all spans in a trace.
|
26
|
+
"""
|
27
|
+
|
28
|
+
def __init__(
|
29
|
+
self,
|
30
|
+
processors: list[SyncTracingProcessor],
|
31
|
+
client: Agentex,
|
32
|
+
trace_id: str | None = None,
|
33
|
+
):
|
34
|
+
"""
|
35
|
+
Initialize a new trace with the specified trace ID.
|
36
|
+
|
37
|
+
Args:
|
38
|
+
trace_id: Required trace ID to use for this trace.
|
39
|
+
processors: Optional list of tracing processors to use for this trace.
|
40
|
+
"""
|
41
|
+
self.processors = processors
|
42
|
+
self.client = client
|
43
|
+
self.trace_id = trace_id
|
44
|
+
|
45
|
+
def start_span(
|
46
|
+
self,
|
47
|
+
name: str,
|
48
|
+
parent_id: str | None = None,
|
49
|
+
input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None,
|
50
|
+
data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None,
|
51
|
+
) -> Span:
|
52
|
+
"""
|
53
|
+
Start a new span and register it with the API.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
name: Name of the span.
|
57
|
+
parent_id: Optional parent span ID.
|
58
|
+
input: Optional input data for the span.
|
59
|
+
data: Optional additional data for the span.
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
The newly created span.
|
63
|
+
"""
|
64
|
+
|
65
|
+
if not self.trace_id:
|
66
|
+
raise ValueError("Trace ID is required to start a span")
|
67
|
+
|
68
|
+
# Create a span using the client's spans resource
|
69
|
+
start_time = datetime.now(UTC)
|
70
|
+
|
71
|
+
serialized_input = recursive_model_dump(input) if input else None
|
72
|
+
serialized_data = recursive_model_dump(data) if data else None
|
73
|
+
id = str(uuid.uuid4())
|
74
|
+
|
75
|
+
span = Span(
|
76
|
+
id=id,
|
77
|
+
trace_id=self.trace_id,
|
78
|
+
name=name,
|
79
|
+
parent_id=parent_id,
|
80
|
+
start_time=start_time,
|
81
|
+
input=serialized_input,
|
82
|
+
data=serialized_data,
|
83
|
+
)
|
84
|
+
|
85
|
+
for processor in self.processors:
|
86
|
+
processor.on_span_start(span)
|
87
|
+
|
88
|
+
return span
|
89
|
+
|
90
|
+
def end_span(
|
91
|
+
self,
|
92
|
+
span: Span,
|
93
|
+
) -> Span:
|
94
|
+
"""
|
95
|
+
End a span by updating it with any changes made to the span object.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
span: The span object to update.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
The updated span.
|
102
|
+
"""
|
103
|
+
if span.end_time is None:
|
104
|
+
span.end_time = datetime.now(UTC)
|
105
|
+
|
106
|
+
span.input = recursive_model_dump(span.input) if span.input else None
|
107
|
+
span.output = recursive_model_dump(span.output) if span.output else None
|
108
|
+
span.data = recursive_model_dump(span.data) if span.data else None
|
109
|
+
|
110
|
+
for processor in self.processors:
|
111
|
+
processor.on_span_end(span)
|
112
|
+
|
113
|
+
return span
|
114
|
+
|
115
|
+
def get_span(self, span_id: str) -> Span:
|
116
|
+
"""
|
117
|
+
Get a span by ID.
|
118
|
+
|
119
|
+
Args:
|
120
|
+
span_id: The ID of the span to get.
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
The requested span.
|
124
|
+
"""
|
125
|
+
# Query from Agentex API
|
126
|
+
span = self.client.spans.retrieve(span_id)
|
127
|
+
return span
|
128
|
+
|
129
|
+
def list_spans(self) -> list[Span]:
|
130
|
+
"""
|
131
|
+
List all spans in this trace.
|
132
|
+
|
133
|
+
Returns:
|
134
|
+
List of spans in this trace.
|
135
|
+
"""
|
136
|
+
# Query from Agentex API
|
137
|
+
spans = self.client.spans.list(trace_id=self.trace_id)
|
138
|
+
return spans
|
139
|
+
|
140
|
+
@contextmanager
|
141
|
+
def span(
|
142
|
+
self,
|
143
|
+
name: str,
|
144
|
+
parent_id: str | None = None,
|
145
|
+
input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None,
|
146
|
+
data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None,
|
147
|
+
):
|
148
|
+
"""
|
149
|
+
Context manager for spans.
|
150
|
+
If trace_id is falsy, acts as a no-op context manager.
|
151
|
+
"""
|
152
|
+
if not self.trace_id:
|
153
|
+
yield None
|
154
|
+
return
|
155
|
+
span = self.start_span(name, parent_id, input, data)
|
156
|
+
try:
|
157
|
+
yield span
|
158
|
+
finally:
|
159
|
+
self.end_span(span)
|
160
|
+
|
161
|
+
|
162
|
+
class AsyncTrace:
|
163
|
+
"""
|
164
|
+
AsyncTrace is a wrapper around the Agentex API for tracing.
|
165
|
+
It provides a context manager for spans and a way to start and end spans.
|
166
|
+
It also provides a way to get spans by ID and list all spans in a trace.
|
167
|
+
"""
|
168
|
+
|
169
|
+
def __init__(
|
170
|
+
self,
|
171
|
+
processors: list[AsyncTracingProcessor],
|
172
|
+
client: AsyncAgentex,
|
173
|
+
trace_id: str | None = None,
|
174
|
+
):
|
175
|
+
"""
|
176
|
+
Initialize a new trace with the specified trace ID.
|
177
|
+
|
178
|
+
Args:
|
179
|
+
trace_id: Required trace ID to use for this trace.
|
180
|
+
processors: Optional list of tracing processors to use for this trace.
|
181
|
+
"""
|
182
|
+
self.processors = processors
|
183
|
+
self.client = client
|
184
|
+
self.trace_id = trace_id
|
185
|
+
|
186
|
+
async def start_span(
|
187
|
+
self,
|
188
|
+
name: str,
|
189
|
+
parent_id: str | None = None,
|
190
|
+
input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None,
|
191
|
+
data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None,
|
192
|
+
) -> Span:
|
193
|
+
"""
|
194
|
+
Start a new span and register it with the API.
|
195
|
+
|
196
|
+
Args:
|
197
|
+
name: Name of the span.
|
198
|
+
parent_id: Optional parent span ID.
|
199
|
+
input: Optional input data for the span.
|
200
|
+
data: Optional additional data for the span.
|
201
|
+
|
202
|
+
Returns:
|
203
|
+
The newly created span.
|
204
|
+
"""
|
205
|
+
if not self.trace_id:
|
206
|
+
raise ValueError("Trace ID is required to start a span")
|
207
|
+
|
208
|
+
# Create a span using the client's spans resource
|
209
|
+
start_time = datetime.now(UTC)
|
210
|
+
|
211
|
+
serialized_input = recursive_model_dump(input) if input else None
|
212
|
+
serialized_data = recursive_model_dump(data) if data else None
|
213
|
+
id = str(uuid.uuid4())
|
214
|
+
|
215
|
+
span = Span(
|
216
|
+
id=id,
|
217
|
+
trace_id=self.trace_id,
|
218
|
+
name=name,
|
219
|
+
parent_id=parent_id,
|
220
|
+
start_time=start_time,
|
221
|
+
input=serialized_input,
|
222
|
+
data=serialized_data,
|
223
|
+
)
|
224
|
+
|
225
|
+
if self.processors:
|
226
|
+
await asyncio.gather(
|
227
|
+
*[processor.on_span_start(span) for processor in self.processors]
|
228
|
+
)
|
229
|
+
|
230
|
+
return span
|
231
|
+
|
232
|
+
async def end_span(
|
233
|
+
self,
|
234
|
+
span: Span,
|
235
|
+
) -> Span:
|
236
|
+
"""
|
237
|
+
End a span by updating it with any changes made to the span object.
|
238
|
+
|
239
|
+
Args:
|
240
|
+
span: The span object to update.
|
241
|
+
|
242
|
+
Returns:
|
243
|
+
The updated span.
|
244
|
+
"""
|
245
|
+
if span.end_time is None:
|
246
|
+
span.end_time = datetime.now(UTC)
|
247
|
+
|
248
|
+
span.input = recursive_model_dump(span.input) if span.input else None
|
249
|
+
span.output = recursive_model_dump(span.output) if span.output else None
|
250
|
+
span.data = recursive_model_dump(span.data) if span.data else None
|
251
|
+
|
252
|
+
if self.processors:
|
253
|
+
await asyncio.gather(
|
254
|
+
*[processor.on_span_end(span) for processor in self.processors]
|
255
|
+
)
|
256
|
+
|
257
|
+
return span
|
258
|
+
|
259
|
+
async def get_span(self, span_id: str) -> Span:
|
260
|
+
"""
|
261
|
+
Get a span by ID.
|
262
|
+
|
263
|
+
Args:
|
264
|
+
span_id: The ID of the span to get.
|
265
|
+
|
266
|
+
Returns:
|
267
|
+
The requested span.
|
268
|
+
"""
|
269
|
+
# Query from Agentex API
|
270
|
+
span = await self.client.spans.retrieve(span_id)
|
271
|
+
return span
|
272
|
+
|
273
|
+
async def list_spans(self) -> list[Span]:
|
274
|
+
"""
|
275
|
+
List all spans in this trace.
|
276
|
+
|
277
|
+
Returns:
|
278
|
+
List of spans in this trace.
|
279
|
+
"""
|
280
|
+
# Query from Agentex API
|
281
|
+
spans = await self.client.spans.list(trace_id=self.trace_id)
|
282
|
+
return spans
|
283
|
+
|
284
|
+
@asynccontextmanager
|
285
|
+
async def span(
|
286
|
+
self,
|
287
|
+
name: str,
|
288
|
+
parent_id: str | None = None,
|
289
|
+
input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None,
|
290
|
+
data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None,
|
291
|
+
) -> AsyncGenerator[Span | None, None]:
|
292
|
+
"""
|
293
|
+
Context manager for spans.
|
294
|
+
|
295
|
+
Args:
|
296
|
+
name: Name of the span.
|
297
|
+
parent_id: Optional parent span ID.
|
298
|
+
input: Optional input data for the span.
|
299
|
+
data: Optional additional data for the span.
|
300
|
+
|
301
|
+
Yields:
|
302
|
+
The span object.
|
303
|
+
"""
|
304
|
+
if not self.trace_id:
|
305
|
+
yield None
|
306
|
+
return
|
307
|
+
span = await self.start_span(name, parent_id, input, data)
|
308
|
+
try:
|
309
|
+
yield span
|
310
|
+
finally:
|
311
|
+
await self.end_span(span)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
from agentex import Agentex, AsyncAgentex
|
2
|
+
from agentex.lib.core.tracing.trace import AsyncTrace, Trace
|
3
|
+
from agentex.lib.core.tracing.tracing_processor_manager import (
|
4
|
+
get_async_tracing_processors,
|
5
|
+
get_sync_tracing_processors,
|
6
|
+
)
|
7
|
+
|
8
|
+
|
9
|
+
class Tracer:
|
10
|
+
"""
|
11
|
+
Tracer is the main entry point for tracing in Agentex.
|
12
|
+
It manages the client connection and creates traces.
|
13
|
+
"""
|
14
|
+
|
15
|
+
def __init__(self, client: Agentex):
|
16
|
+
"""
|
17
|
+
Initialize a new sync tracer with the provided client.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
client: Agentex client instance used for API communication.
|
21
|
+
"""
|
22
|
+
self.client = client
|
23
|
+
|
24
|
+
def trace(self, trace_id: str | None = None) -> Trace:
|
25
|
+
"""
|
26
|
+
Create a new trace with the given trace ID.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
trace_id: The trace ID to use.
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
A new Trace instance.
|
33
|
+
"""
|
34
|
+
return Trace(
|
35
|
+
processors=get_sync_tracing_processors(),
|
36
|
+
client=self.client,
|
37
|
+
trace_id=trace_id,
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
class AsyncTracer:
|
42
|
+
"""
|
43
|
+
AsyncTracer is the async version of Tracer.
|
44
|
+
It manages the async client connection and creates async traces.
|
45
|
+
"""
|
46
|
+
|
47
|
+
def __init__(self, client: AsyncAgentex):
|
48
|
+
"""
|
49
|
+
Initialize a new async tracer with the provided client.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
client: AsyncAgentex client instance used for API communication.
|
53
|
+
"""
|
54
|
+
self.client = client
|
55
|
+
|
56
|
+
def trace(self, trace_id: str | None = None) -> AsyncTrace:
|
57
|
+
"""
|
58
|
+
Create a new trace with the given trace ID.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
trace_id: The trace ID to use.
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
A new AsyncTrace instance.
|
65
|
+
"""
|
66
|
+
return AsyncTrace(
|
67
|
+
processors=get_async_tracing_processors(),
|
68
|
+
client=self.client,
|
69
|
+
trace_id=trace_id,
|
70
|
+
)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
from threading import Lock
|
2
|
+
|
3
|
+
from agentex.lib.core.tracing.processors.agentex_tracing_processor import (
|
4
|
+
AgentexAsyncTracingProcessor,
|
5
|
+
AgentexSyncTracingProcessor,
|
6
|
+
)
|
7
|
+
from agentex.lib.core.tracing.processors.sgp_tracing_processor import (
|
8
|
+
SGPAsyncTracingProcessor,
|
9
|
+
SGPSyncTracingProcessor,
|
10
|
+
)
|
11
|
+
from agentex.lib.core.tracing.processors.tracing_processor_interface import (
|
12
|
+
AsyncTracingProcessor,
|
13
|
+
SyncTracingProcessor,
|
14
|
+
)
|
15
|
+
from agentex.lib.types.tracing import AgentexTracingProcessorConfig, TracingProcessorConfig
|
16
|
+
|
17
|
+
|
18
|
+
class TracingProcessorManager:
|
19
|
+
def __init__(self):
|
20
|
+
# Mapping of processor config type to processor class
|
21
|
+
self.sync_config_registry: dict[str, type[SyncTracingProcessor]] = {
|
22
|
+
"agentex": AgentexSyncTracingProcessor,
|
23
|
+
"sgp": SGPSyncTracingProcessor,
|
24
|
+
}
|
25
|
+
self.async_config_registry: dict[str, type[AsyncTracingProcessor]] = {
|
26
|
+
"agentex": AgentexAsyncTracingProcessor,
|
27
|
+
"sgp": SGPAsyncTracingProcessor,
|
28
|
+
}
|
29
|
+
# Cache for processors
|
30
|
+
self.sync_processors: list[SyncTracingProcessor] = []
|
31
|
+
self.async_processors: list[AsyncTracingProcessor] = []
|
32
|
+
self.lock = Lock()
|
33
|
+
|
34
|
+
def add_processor_config(self, processor_config: TracingProcessorConfig) -> None:
|
35
|
+
with self.lock:
|
36
|
+
sync_processor = self.sync_config_registry[processor_config.type]
|
37
|
+
async_processor = self.async_config_registry[processor_config.type]
|
38
|
+
self.sync_processors.append(sync_processor(processor_config))
|
39
|
+
self.async_processors.append(async_processor(processor_config))
|
40
|
+
|
41
|
+
def set_processor_configs(self, processor_configs: list[TracingProcessorConfig]):
|
42
|
+
with self.lock:
|
43
|
+
for processor_config in processor_configs:
|
44
|
+
self.add_processor_config(processor_config)
|
45
|
+
|
46
|
+
def get_sync_processors(self) -> list[SyncTracingProcessor]:
|
47
|
+
return self.sync_processors
|
48
|
+
|
49
|
+
def get_async_processors(self) -> list[AsyncTracingProcessor]:
|
50
|
+
return self.async_processors
|
51
|
+
|
52
|
+
|
53
|
+
# Global instance
|
54
|
+
GLOBAL_TRACING_PROCESSOR_MANAGER = TracingProcessorManager()
|
55
|
+
|
56
|
+
add_tracing_processor_config = GLOBAL_TRACING_PROCESSOR_MANAGER.add_processor_config
|
57
|
+
set_tracing_processor_configs = GLOBAL_TRACING_PROCESSOR_MANAGER.set_processor_configs
|
58
|
+
get_sync_tracing_processors = GLOBAL_TRACING_PROCESSOR_MANAGER.get_sync_processors
|
59
|
+
get_async_tracing_processors = GLOBAL_TRACING_PROCESSOR_MANAGER.get_async_processors
|
60
|
+
|
61
|
+
# Add the Agentex tracing processor by default
|
62
|
+
add_tracing_processor_config(AgentexTracingProcessorConfig())
|
@@ -0,0 +1,87 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import os
|
4
|
+
from enum import Enum
|
5
|
+
from pathlib import Path
|
6
|
+
|
7
|
+
from dotenv import load_dotenv
|
8
|
+
|
9
|
+
from agentex.lib.utils.model_utils import BaseModel
|
10
|
+
|
11
|
+
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
12
|
+
|
13
|
+
|
14
|
+
class EnvVarKeys(str, Enum):
|
15
|
+
ENVIRONMENT = "ENVIRONMENT"
|
16
|
+
TEMPORAL_ADDRESS = "TEMPORAL_ADDRESS"
|
17
|
+
REDIS_URL = "REDIS_URL"
|
18
|
+
AGENTEX_BASE_URL = "AGENTEX_BASE_URL"
|
19
|
+
# Agent Identifiers
|
20
|
+
AGENT_NAME = "AGENT_NAME"
|
21
|
+
AGENT_DESCRIPTION = "AGENT_DESCRIPTION"
|
22
|
+
AGENT_ID = "AGENT_ID"
|
23
|
+
# ACP Configuration
|
24
|
+
ACP_URL = "ACP_URL"
|
25
|
+
ACP_PORT = "ACP_PORT"
|
26
|
+
ACP_TYPE = "ACP_TYPE"
|
27
|
+
# Workflow Configuraiton
|
28
|
+
WORKFLOW_NAME = "WORKFLOW_NAME"
|
29
|
+
WORKFLOW_TASK_QUEUE = "WORKFLOW_TASK_QUEUE"
|
30
|
+
|
31
|
+
|
32
|
+
class Environment(str, Enum):
|
33
|
+
DEV = "development"
|
34
|
+
STAGING = "staging"
|
35
|
+
PROD = "production"
|
36
|
+
|
37
|
+
|
38
|
+
refreshed_environment_variables = None
|
39
|
+
|
40
|
+
|
41
|
+
class EnvironmentVariables(BaseModel):
|
42
|
+
ENVIRONMENT: str = Environment.DEV
|
43
|
+
TEMPORAL_ADDRESS: str | None = "localhost:7233"
|
44
|
+
REDIS_URL: str | None = None
|
45
|
+
AGENTEX_BASE_URL: str | None = "http://localhost:5003"
|
46
|
+
# Agent Identifiers
|
47
|
+
AGENT_NAME: str
|
48
|
+
AGENT_DESCRIPTION: str | None = None
|
49
|
+
AGENT_ID: str | None = None
|
50
|
+
ACP_TYPE: str | None = "agentic"
|
51
|
+
# ACP Configuration
|
52
|
+
ACP_URL: str
|
53
|
+
ACP_PORT: int = 8000
|
54
|
+
# Workflow Configuration
|
55
|
+
WORKFLOW_TASK_QUEUE: str | None = None
|
56
|
+
WORKFLOW_NAME: str | None = None
|
57
|
+
|
58
|
+
@classmethod
|
59
|
+
def refresh(cls) -> EnvironmentVariables | None:
|
60
|
+
global refreshed_environment_variables
|
61
|
+
if refreshed_environment_variables is not None:
|
62
|
+
return refreshed_environment_variables
|
63
|
+
|
64
|
+
if os.environ.get(EnvVarKeys.ENVIRONMENT) == Environment.DEV:
|
65
|
+
# Load global .env file first
|
66
|
+
global_env_path = PROJECT_ROOT / ".env"
|
67
|
+
if global_env_path.exists():
|
68
|
+
print(f"Loading global environment variables FROM: {global_env_path}")
|
69
|
+
load_dotenv(dotenv_path=global_env_path, override=False)
|
70
|
+
|
71
|
+
# Load local project .env.local file (takes precedence)
|
72
|
+
local_env_path = Path.cwd().parent / ".env.local"
|
73
|
+
if local_env_path.exists():
|
74
|
+
print(f"Loading local environment variables FROM: {local_env_path}")
|
75
|
+
load_dotenv(dotenv_path=local_env_path, override=True)
|
76
|
+
|
77
|
+
# Create kwargs dict with environment variables, using None for missing values
|
78
|
+
# Pydantic will use the default values when None is passed for optional fields
|
79
|
+
kwargs = {}
|
80
|
+
for key in EnvVarKeys:
|
81
|
+
env_value = os.environ.get(key.value)
|
82
|
+
if env_value is not None:
|
83
|
+
kwargs[key.value] = env_value
|
84
|
+
|
85
|
+
environment_variables = EnvironmentVariables(**kwargs)
|
86
|
+
refreshed_environment_variables = environment_variables
|
87
|
+
return refreshed_environment_variables
|
agentex/lib/py.typed
ADDED
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,61 @@
|
|
1
|
+
from typing import Any, Literal
|
2
|
+
|
3
|
+
from pydantic import Field
|
4
|
+
|
5
|
+
from agentex.lib.types.agent_configs import TemporalConfig, TemporalWorkflowConfig
|
6
|
+
from agentex.lib.types.credentials import CredentialMapping
|
7
|
+
from agentex.lib.utils.logging import make_logger
|
8
|
+
from agentex.lib.utils.model_utils import BaseModel
|
9
|
+
|
10
|
+
logger = make_logger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
class AgentConfig(BaseModel):
|
14
|
+
name: str = Field(
|
15
|
+
...,
|
16
|
+
description="The name of the agent.",
|
17
|
+
pattern=r"^[a-z0-9-]+$",
|
18
|
+
)
|
19
|
+
acp_type: Literal["sync", "agentic"] = Field(..., description="The type of agent.")
|
20
|
+
description: str = Field(..., description="The description of the agent.")
|
21
|
+
env: dict[str, str] | None = Field(
|
22
|
+
default=None, description="Environment variables to set directly in the agent deployment"
|
23
|
+
)
|
24
|
+
credentials: list[CredentialMapping | dict[str, Any]] | None = Field(
|
25
|
+
default=None,
|
26
|
+
description="List of credential mappings to mount to the agent deployment. Supports both legacy format and new typed credentials.",
|
27
|
+
)
|
28
|
+
temporal: TemporalConfig | None = Field(
|
29
|
+
default=None, description="Temporal workflow configuration for this agent"
|
30
|
+
)
|
31
|
+
|
32
|
+
def is_temporal_agent(self) -> bool:
|
33
|
+
"""Check if this agent uses Temporal workflows"""
|
34
|
+
# Check temporal config with enabled flag
|
35
|
+
if self.temporal and self.temporal.enabled:
|
36
|
+
return True
|
37
|
+
return False
|
38
|
+
|
39
|
+
def get_temporal_workflow_config(self) -> TemporalWorkflowConfig | None:
|
40
|
+
"""Get temporal workflow configuration, checking both new and legacy formats"""
|
41
|
+
# Check new workflows list first
|
42
|
+
if self.temporal and self.temporal.enabled and self.temporal.workflows:
|
43
|
+
return self.temporal.workflows[0] # Return first workflow for backward compatibility
|
44
|
+
|
45
|
+
# Check legacy single workflow
|
46
|
+
if self.temporal and self.temporal.enabled and self.temporal.workflow:
|
47
|
+
return self.temporal.workflow
|
48
|
+
|
49
|
+
return None
|
50
|
+
|
51
|
+
def get_temporal_workflows(self) -> list[TemporalWorkflowConfig]:
|
52
|
+
"""Get all temporal workflow configurations"""
|
53
|
+
# Check new workflows list first
|
54
|
+
if self.temporal and self.temporal.enabled and self.temporal.workflows:
|
55
|
+
return self.temporal.workflows
|
56
|
+
|
57
|
+
# Check legacy single workflow
|
58
|
+
if self.temporal and self.temporal.enabled and self.temporal.workflow:
|
59
|
+
return [self.temporal.workflow]
|
60
|
+
|
61
|
+
return []
|