agnt5 0.2.8a10__cp310-abi3-manylinux_2_34_x86_64.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.

Potentially problematic release.


This version of agnt5 might be problematic. Click here for more details.

agnt5/tracing.py ADDED
@@ -0,0 +1,196 @@
1
+ """
2
+ User-facing tracing API for AGNT5 SDK.
3
+
4
+ Provides decorators and context managers for instrumenting Python code with
5
+ OpenTelemetry spans. All spans are created via Rust FFI and exported through
6
+ the centralized Rust OpenTelemetry system.
7
+
8
+ Example:
9
+ ```python
10
+ from agnt5.tracing import span
11
+
12
+ @span("my_operation")
13
+ async def my_function(ctx, data):
14
+ # Your code here
15
+ return result
16
+
17
+ # Or use context manager
18
+ from agnt5.tracing import span_context
19
+
20
+ async def process():
21
+ with span_context("processing", user_id="123") as s:
22
+ data = await fetch_data()
23
+ s.set_attribute("records", str(len(data)))
24
+ return data
25
+ ```
26
+ """
27
+
28
+ import functools
29
+ import inspect
30
+ from contextlib import contextmanager
31
+ from typing import Any, Callable, Dict, Optional
32
+
33
+ from ._core import create_span as _create_span
34
+
35
+
36
+ def span(
37
+ name: Optional[str] = None,
38
+ component_type: str = "function",
39
+ runtime_context: Optional[Any] = None,
40
+ **attributes: str
41
+ ):
42
+ """
43
+ Decorator to automatically create spans for functions.
44
+
45
+ Args:
46
+ name: Span name (defaults to function name)
47
+ component_type: Component type (default: "function")
48
+ runtime_context: Optional RuntimeContext for trace linking
49
+ **attributes: Additional span attributes
50
+
51
+ Example:
52
+ ```python
53
+ @span("fetch_user_data", user_type="premium")
54
+ async def fetch_user(user_id: str):
55
+ return await db.get_user(user_id)
56
+ ```
57
+ """
58
+ def decorator(func: Callable) -> Callable:
59
+ span_name = name or func.__name__
60
+
61
+ if inspect.iscoroutinefunction(func):
62
+ @functools.wraps(func)
63
+ async def async_wrapper(*args, **kwargs):
64
+ # Try to extract runtime_context from first arg if it's a Context
65
+ ctx = runtime_context
66
+ if ctx is None and args:
67
+ from .context import Context
68
+ if isinstance(args[0], Context):
69
+ ctx = args[0]._runtime_context
70
+
71
+ with _create_span(span_name, component_type, ctx, attributes) as s:
72
+ try:
73
+ result = await func(*args, **kwargs)
74
+ # Span automatically marked as OK on success
75
+ return result
76
+ except Exception as e:
77
+ # Exception automatically recorded by PySpan.__exit__
78
+ raise
79
+ return async_wrapper
80
+ else:
81
+ @functools.wraps(func)
82
+ def sync_wrapper(*args, **kwargs):
83
+ # Try to extract runtime_context from first arg if it's a Context
84
+ ctx = runtime_context
85
+ if ctx is None and args:
86
+ from .context import Context
87
+ if isinstance(args[0], Context):
88
+ ctx = args[0]._runtime_context
89
+
90
+ with _create_span(span_name, component_type, ctx, attributes) as s:
91
+ try:
92
+ result = func(*args, **kwargs)
93
+ return result
94
+ except Exception as e:
95
+ raise
96
+ return sync_wrapper
97
+
98
+ return decorator
99
+
100
+
101
+ @contextmanager
102
+ def span_context(
103
+ name: str,
104
+ component_type: str = "operation",
105
+ runtime_context: Optional[Any] = None,
106
+ **attributes: str
107
+ ):
108
+ """
109
+ Context manager for creating spans around code blocks.
110
+
111
+ Args:
112
+ name: Span name
113
+ component_type: Component type (default: "operation")
114
+ runtime_context: Optional RuntimeContext for trace linking
115
+ **attributes: Span attributes
116
+
117
+ Yields:
118
+ PySpan object with set_attribute() and record_exception() methods
119
+
120
+ Example:
121
+ ```python
122
+ with span_context("db_query", runtime_context=ctx._runtime_context, table="users") as s:
123
+ results = query_database()
124
+ s.set_attribute("result_count", str(len(results)))
125
+ ```
126
+ """
127
+ s = _create_span(name, component_type, runtime_context, attributes)
128
+ try:
129
+ yield s
130
+ # Context manager automatically calls s.__exit__ which sets status
131
+ except Exception as e:
132
+ # Exception will be recorded by __exit__
133
+ raise
134
+ finally:
135
+ # PySpan's __exit__ is called automatically when context ends
136
+ pass
137
+
138
+
139
+ def create_task_span(name: str, runtime_context: Optional[Any] = None, **attributes: str):
140
+ """
141
+ Create a span for task execution.
142
+
143
+ Args:
144
+ name: Task name
145
+ runtime_context: Optional RuntimeContext for trace linking
146
+ **attributes: Task attributes
147
+
148
+ Returns:
149
+ PySpan object to use as context manager
150
+
151
+ Example:
152
+ ```python
153
+ with create_task_span("process_data", runtime_context=ctx._runtime_context, batch_size="100") as s:
154
+ result = await process()
155
+ ```
156
+ """
157
+ return _create_span(name, "task", runtime_context, attributes)
158
+
159
+
160
+ def create_workflow_span(name: str, runtime_context: Optional[Any] = None, **attributes: str):
161
+ """
162
+ Create a span for workflow execution.
163
+
164
+ Args:
165
+ name: Workflow name
166
+ runtime_context: Optional RuntimeContext for trace linking
167
+ **attributes: Workflow attributes
168
+
169
+ Returns:
170
+ PySpan object to use as context manager
171
+ """
172
+ return _create_span(name, "workflow", runtime_context, attributes)
173
+
174
+
175
+ def create_agent_span(name: str, runtime_context: Optional[Any] = None, **attributes: str):
176
+ """
177
+ Create a span for agent execution.
178
+
179
+ Args:
180
+ name: Agent name
181
+ runtime_context: Optional RuntimeContext for trace linking
182
+ **attributes: Agent attributes
183
+
184
+ Returns:
185
+ PySpan object to use as context manager
186
+ """
187
+ return _create_span(name, "agent", runtime_context, attributes)
188
+
189
+
190
+ __all__ = [
191
+ "span",
192
+ "span_context",
193
+ "create_task_span",
194
+ "create_workflow_span",
195
+ "create_agent_span",
196
+ ]
agnt5/types.py ADDED
@@ -0,0 +1,110 @@
1
+ """Type definitions and protocols for AGNT5 SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from enum import Enum
7
+ from typing import Any, Awaitable, Callable, Dict, List, Optional, Protocol, TypeVar, Union
8
+
9
+ # Type aliases
10
+ JSON = Union[Dict[str, Any], List[Any], str, int, float, bool, None]
11
+ HandlerFunc = Callable[..., Awaitable[Any]]
12
+
13
+ T = TypeVar("T")
14
+
15
+
16
+ class BackoffType(str, Enum):
17
+ """Backoff strategy for retry policies."""
18
+
19
+ CONSTANT = "constant"
20
+ LINEAR = "linear"
21
+ EXPONENTIAL = "exponential"
22
+
23
+
24
+ @dataclass
25
+ class RetryPolicy:
26
+ """Configuration for function retry behavior."""
27
+
28
+ max_attempts: int = 3
29
+ initial_interval_ms: int = 1000
30
+ max_interval_ms: int = 60000
31
+
32
+ def __post_init__(self) -> None:
33
+ if self.max_attempts < 1:
34
+ raise ValueError("max_attempts must be at least 1")
35
+ if self.initial_interval_ms < 0:
36
+ raise ValueError("initial_interval_ms must be non-negative")
37
+ if self.max_interval_ms < self.initial_interval_ms:
38
+ raise ValueError("max_interval_ms must be >= initial_interval_ms")
39
+
40
+
41
+ @dataclass
42
+ class BackoffPolicy:
43
+ """Configuration for retry backoff strategy."""
44
+
45
+ type: BackoffType = BackoffType.EXPONENTIAL
46
+ multiplier: float = 2.0
47
+
48
+ def __post_init__(self) -> None:
49
+ if self.multiplier <= 0:
50
+ raise ValueError("multiplier must be positive")
51
+
52
+
53
+ @dataclass
54
+ class FunctionConfig:
55
+ """Configuration for a function handler."""
56
+
57
+ name: str
58
+ handler: HandlerFunc
59
+ retries: Optional[RetryPolicy] = None
60
+ backoff: Optional[BackoffPolicy] = None
61
+ input_schema: Optional[Dict[str, Any]] = None
62
+ output_schema: Optional[Dict[str, Any]] = None
63
+ metadata: Optional[Dict[str, str]] = None
64
+
65
+
66
+ @dataclass
67
+ class WorkflowConfig:
68
+ """Configuration for a workflow handler."""
69
+
70
+ name: str
71
+ handler: HandlerFunc
72
+ input_schema: Optional[Dict[str, Any]] = None
73
+ output_schema: Optional[Dict[str, Any]] = None
74
+ metadata: Optional[Dict[str, str]] = None
75
+
76
+
77
+ class ContextProtocol(Protocol):
78
+ """Protocol defining the Context interface."""
79
+
80
+ @property
81
+ def run_id(self) -> str:
82
+ """Workflow/run identifier."""
83
+ ...
84
+
85
+ @property
86
+ def step_id(self) -> Optional[str]:
87
+ """Current step identifier."""
88
+ ...
89
+
90
+ @property
91
+ def attempt(self) -> int:
92
+ """Retry attempt number."""
93
+ ...
94
+
95
+ @property
96
+ def component_type(self) -> str:
97
+ """Component type: 'function', 'entity', 'workflow'."""
98
+ ...
99
+
100
+ async def get(self, key: str, default: Any = None) -> Any:
101
+ """Get value from state."""
102
+ ...
103
+
104
+ def set(self, key: str, value: Any) -> None:
105
+ """Set value in state."""
106
+ ...
107
+
108
+ def delete(self, key: str) -> None:
109
+ """Delete key from state."""
110
+ ...
agnt5/version.py ADDED
@@ -0,0 +1,19 @@
1
+ """Version information for agnt5 SDK."""
2
+
3
+
4
+ def _get_version() -> str:
5
+ """Get package version from installed metadata.
6
+
7
+ This uses importlib.metadata (Python 3.8+) to read the version from
8
+ the installed package metadata, maintaining pyproject.toml as the
9
+ single source of truth.
10
+
11
+ Returns:
12
+ Package version string, or "0.0.0+dev" for development installs.
13
+ """
14
+ try:
15
+ from importlib.metadata import version
16
+ return version("agnt5")
17
+ except Exception:
18
+ # Development/editable install fallback
19
+ return "0.0.0+dev"