agnt5 0.2.2__cp39-abi3-macosx_11_0_arm64.whl → 0.2.4__cp39-abi3-macosx_11_0_arm64.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/tool.py CHANGED
@@ -130,7 +130,7 @@ def _extract_schema_from_function(func: Callable) -> Dict[str, Any]:
130
130
  "required": required
131
131
  }
132
132
 
133
- # Extract return type for output schema (optional, not strictly needed for Phase 1)
133
+ # Extract return type for output schema (optional for basic tool functionality)
134
134
  return_type = sig.return_annotation
135
135
  output_schema = None
136
136
  if return_type != inspect.Parameter.empty:
@@ -223,20 +223,32 @@ class Tool:
223
223
  ConfigurationError: If tool requires confirmation (not yet implemented)
224
224
  """
225
225
  if self.confirmation:
226
- # In Phase 1, we can't implement actual confirmation
227
- # Just log a warning
226
+ # TODO: Implement actual confirmation workflow
227
+ # For now, just log a warning
228
228
  logger.warning(
229
- f"Tool '{self.name}' requires confirmation but confirmation is not implemented in Phase 1"
229
+ f"Tool '{self.name}' requires confirmation but confirmation is not yet implemented"
230
230
  )
231
231
 
232
- # Execute handler
233
- logger.debug(f"Invoking tool '{self.name}' with args: {list(kwargs.keys())}")
232
+ # Create span for tool execution with trace linking
233
+ from ._core import create_span
234
234
 
235
- # Handler is already async (validated in tool() decorator)
236
- result = await self.handler(ctx, **kwargs)
235
+ logger.debug(f"Invoking tool '{self.name}' with args: {list(kwargs.keys())}")
237
236
 
238
- logger.debug(f"Tool '{self.name}' completed successfully")
239
- return result
237
+ # Create span with runtime_context for parent-child span linking
238
+ with create_span(
239
+ self.name,
240
+ "tool",
241
+ ctx._runtime_context if hasattr(ctx, "_runtime_context") else None,
242
+ {
243
+ "tool.name": self.name,
244
+ "tool.args": ",".join(kwargs.keys()),
245
+ },
246
+ ) as span:
247
+ # Handler is already async (validated in tool() decorator)
248
+ result = await self.handler(ctx, **kwargs)
249
+
250
+ logger.debug(f"Tool '{self.name}' completed successfully")
251
+ return result
240
252
 
241
253
  def get_schema(self) -> Dict[str, Any]:
242
254
  """
@@ -363,7 +375,9 @@ def tool(
363
375
 
364
376
  @functools.wraps(original_func)
365
377
  async def async_wrapper(*args, **kwargs):
366
- return original_func(*args, **kwargs)
378
+ # Run sync function in thread pool to prevent blocking event loop
379
+ loop = asyncio.get_running_loop()
380
+ return await loop.run_in_executor(None, lambda: original_func(*args, **kwargs))
367
381
 
368
382
  handler_func = async_wrapper
369
383
  else:
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
+ ]