agnt5 0.1.0__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.
- agnt5/__init__.py +307 -0
- agnt5/__pycache__/__init__.cpython-311.pyc +0 -0
- agnt5/__pycache__/agent.cpython-311.pyc +0 -0
- agnt5/__pycache__/context.cpython-311.pyc +0 -0
- agnt5/__pycache__/durable.cpython-311.pyc +0 -0
- agnt5/__pycache__/extraction.cpython-311.pyc +0 -0
- agnt5/__pycache__/memory.cpython-311.pyc +0 -0
- agnt5/__pycache__/reflection.cpython-311.pyc +0 -0
- agnt5/__pycache__/runtime.cpython-311.pyc +0 -0
- agnt5/__pycache__/task.cpython-311.pyc +0 -0
- agnt5/__pycache__/tool.cpython-311.pyc +0 -0
- agnt5/__pycache__/tracing.cpython-311.pyc +0 -0
- agnt5/__pycache__/types.cpython-311.pyc +0 -0
- agnt5/__pycache__/workflow.cpython-311.pyc +0 -0
- agnt5/_core.abi3.so +0 -0
- agnt5/agent.py +1086 -0
- agnt5/context.py +406 -0
- agnt5/durable.py +1050 -0
- agnt5/extraction.py +410 -0
- agnt5/llm/__init__.py +179 -0
- agnt5/llm/__pycache__/__init__.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/anthropic.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/azure.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/base.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/google.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/mistral.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/openai.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/together.cpython-311.pyc +0 -0
- agnt5/llm/anthropic.py +319 -0
- agnt5/llm/azure.py +348 -0
- agnt5/llm/base.py +315 -0
- agnt5/llm/google.py +373 -0
- agnt5/llm/mistral.py +330 -0
- agnt5/llm/model_registry.py +467 -0
- agnt5/llm/models.json +227 -0
- agnt5/llm/openai.py +334 -0
- agnt5/llm/together.py +377 -0
- agnt5/memory.py +746 -0
- agnt5/reflection.py +514 -0
- agnt5/runtime.py +699 -0
- agnt5/task.py +476 -0
- agnt5/testing.py +451 -0
- agnt5/tool.py +516 -0
- agnt5/tracing.py +624 -0
- agnt5/types.py +210 -0
- agnt5/workflow.py +897 -0
- agnt5-0.1.0.dist-info/METADATA +93 -0
- agnt5-0.1.0.dist-info/RECORD +49 -0
- agnt5-0.1.0.dist-info/WHEEL +4 -0
agnt5/context.py
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Context management for the AGNT5 SDK.
|
|
3
|
+
|
|
4
|
+
Provides execution context for agents, tools, and workflows with
|
|
5
|
+
support for distributed tracing, state management, and error handling.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, Optional, List, Union, TypeVar, ContextManager, Generic, Type
|
|
9
|
+
from contextvars import ContextVar
|
|
10
|
+
from contextlib import contextmanager
|
|
11
|
+
import uuid
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
import logging
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
|
|
16
|
+
from .types import ExecutionContext, ExecutionState, Message
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
# Context variable for the current execution context
|
|
22
|
+
_current_context: ContextVar[Optional["Context"]] = ContextVar("agnt5_context", default=None)
|
|
23
|
+
|
|
24
|
+
T = TypeVar('T')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class Context:
|
|
29
|
+
"""
|
|
30
|
+
Execution context for AGNT5 operations with durable primitives integration.
|
|
31
|
+
|
|
32
|
+
Provides access to:
|
|
33
|
+
- Execution metadata (ID, timestamps, state)
|
|
34
|
+
- Distributed tracing information
|
|
35
|
+
- Shared state and variables
|
|
36
|
+
- Error handling and recovery
|
|
37
|
+
- Durable function calls via ctx.call()
|
|
38
|
+
- Durable sleep via ctx.sleep()
|
|
39
|
+
- Durable object access via ctx.get_object()
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
```python
|
|
43
|
+
from agnt5 import Context, get_context
|
|
44
|
+
|
|
45
|
+
# Get current context
|
|
46
|
+
ctx = get_context()
|
|
47
|
+
|
|
48
|
+
# Make durable service calls
|
|
49
|
+
result = await ctx.call("data_service", "process", input_data)
|
|
50
|
+
|
|
51
|
+
# Durable sleep
|
|
52
|
+
await ctx.sleep(30)
|
|
53
|
+
|
|
54
|
+
# Access durable objects
|
|
55
|
+
memory = await ctx.get_object(AgentMemory, "user_123")
|
|
56
|
+
|
|
57
|
+
# Store state
|
|
58
|
+
await ctx.set("user_id", "123")
|
|
59
|
+
user_id = await ctx.get("user_id")
|
|
60
|
+
```
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
execution_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
|
64
|
+
parent_id: Optional[str] = None
|
|
65
|
+
name: Optional[str] = None
|
|
66
|
+
|
|
67
|
+
# Execution state
|
|
68
|
+
state: ExecutionState = ExecutionState.PENDING
|
|
69
|
+
started_at: Optional[datetime] = None
|
|
70
|
+
completed_at: Optional[datetime] = None
|
|
71
|
+
|
|
72
|
+
# Metadata
|
|
73
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
74
|
+
|
|
75
|
+
# State storage
|
|
76
|
+
_state: Dict[str, Any] = field(default_factory=dict, init=False)
|
|
77
|
+
|
|
78
|
+
# Conversation history (for agents)
|
|
79
|
+
_messages: List[Message] = field(default_factory=list, init=False)
|
|
80
|
+
|
|
81
|
+
# Error information
|
|
82
|
+
error: Optional[Exception] = None
|
|
83
|
+
error_count: int = 0
|
|
84
|
+
|
|
85
|
+
def __post_init__(self):
|
|
86
|
+
"""Initialize context after creation."""
|
|
87
|
+
if self.state == ExecutionState.RUNNING and not self.started_at:
|
|
88
|
+
self.started_at = datetime.utcnow()
|
|
89
|
+
|
|
90
|
+
async def set(self, key: str, value: Any) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Set a value in the context state with durable persistence.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
key: State key
|
|
96
|
+
value: State value
|
|
97
|
+
"""
|
|
98
|
+
from .durable import _runtime_client
|
|
99
|
+
|
|
100
|
+
if _runtime_client:
|
|
101
|
+
await _runtime_client.save_state(key, value)
|
|
102
|
+
else:
|
|
103
|
+
self._state[key] = value
|
|
104
|
+
|
|
105
|
+
async def get(self, key: str, default: Any = None) -> Any:
|
|
106
|
+
"""
|
|
107
|
+
Get a value from the context state with durable persistence.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
key: State key
|
|
111
|
+
default: Default value if key not found
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
State value or default
|
|
115
|
+
"""
|
|
116
|
+
from .durable import _runtime_client
|
|
117
|
+
|
|
118
|
+
if _runtime_client:
|
|
119
|
+
return await _runtime_client.load_state(key, default)
|
|
120
|
+
else:
|
|
121
|
+
return self._state.get(key, default)
|
|
122
|
+
|
|
123
|
+
async def update(self, **kwargs) -> None:
|
|
124
|
+
"""Update multiple state values with durable persistence."""
|
|
125
|
+
for key, value in kwargs.items():
|
|
126
|
+
await self.set(key, value)
|
|
127
|
+
|
|
128
|
+
async def clear(self) -> None:
|
|
129
|
+
"""Clear all state values with durable persistence."""
|
|
130
|
+
from .durable import _runtime_client
|
|
131
|
+
|
|
132
|
+
if _runtime_client:
|
|
133
|
+
for key in list(self._state.keys()):
|
|
134
|
+
await _runtime_client.delete_state(key)
|
|
135
|
+
else:
|
|
136
|
+
self._state.clear()
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def state_dict(self) -> Dict[str, Any]:
|
|
140
|
+
"""Get a copy of the state dictionary."""
|
|
141
|
+
return self._state.copy()
|
|
142
|
+
|
|
143
|
+
def add_message(self, message: Message) -> None:
|
|
144
|
+
"""Add a message to the conversation history."""
|
|
145
|
+
self._messages.append(message)
|
|
146
|
+
|
|
147
|
+
def get_messages(self) -> List[Message]:
|
|
148
|
+
"""Get the conversation history."""
|
|
149
|
+
return self._messages.copy()
|
|
150
|
+
|
|
151
|
+
def clear_messages(self) -> None:
|
|
152
|
+
"""Clear the conversation history."""
|
|
153
|
+
self._messages.clear()
|
|
154
|
+
|
|
155
|
+
def create_child(self, name: str) -> "Context":
|
|
156
|
+
"""
|
|
157
|
+
Create a child context.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
name: Name for the child context
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
Child context
|
|
164
|
+
"""
|
|
165
|
+
child = Context(
|
|
166
|
+
execution_id=str(uuid.uuid4()),
|
|
167
|
+
parent_id=self.execution_id,
|
|
168
|
+
name=name,
|
|
169
|
+
state=ExecutionState.PENDING,
|
|
170
|
+
metadata=self.metadata.copy(),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Copy parent state
|
|
174
|
+
child._state = self._state.copy()
|
|
175
|
+
|
|
176
|
+
return child
|
|
177
|
+
|
|
178
|
+
def record_error(self, error: Exception) -> None:
|
|
179
|
+
"""Record an error in the context."""
|
|
180
|
+
self.error = error
|
|
181
|
+
self.error_count += 1
|
|
182
|
+
logger.error(f"Error in context {self.execution_id}: {error}")
|
|
183
|
+
|
|
184
|
+
async def call(self, service: str, method: str, *args, **kwargs) -> Any:
|
|
185
|
+
"""
|
|
186
|
+
Make a durable external service call via the runtime.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
service: Service name
|
|
190
|
+
method: Method name
|
|
191
|
+
*args: Method arguments
|
|
192
|
+
**kwargs: Method keyword arguments
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Service response
|
|
196
|
+
"""
|
|
197
|
+
from .durable import _runtime_client
|
|
198
|
+
|
|
199
|
+
if _runtime_client:
|
|
200
|
+
return await _runtime_client.call_service(service, method, *args, **kwargs)
|
|
201
|
+
else:
|
|
202
|
+
# Fallback to mock response for testing
|
|
203
|
+
logger.info(f"Mock service call: {service}.{method}")
|
|
204
|
+
return f"mock_response_from_{service}_{method}"
|
|
205
|
+
|
|
206
|
+
async def sleep(self, seconds: float) -> None:
|
|
207
|
+
"""
|
|
208
|
+
Durable sleep that survives restarts.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
seconds: Duration to sleep in seconds
|
|
212
|
+
"""
|
|
213
|
+
from .durable import _runtime_client
|
|
214
|
+
import asyncio
|
|
215
|
+
|
|
216
|
+
if _runtime_client:
|
|
217
|
+
await _runtime_client.durable_sleep(seconds)
|
|
218
|
+
else:
|
|
219
|
+
# Fallback for testing
|
|
220
|
+
logger.info(f"Mock durable sleep: {seconds} seconds")
|
|
221
|
+
await asyncio.sleep(seconds)
|
|
222
|
+
|
|
223
|
+
async def get_object(self, object_class: Type[Any], object_id: str) -> Any:
|
|
224
|
+
"""
|
|
225
|
+
Get or create a durable object instance.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
object_class: The durable object class
|
|
229
|
+
object_id: Unique identifier for the object instance
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Durable object instance
|
|
233
|
+
"""
|
|
234
|
+
from .durable import _runtime_client
|
|
235
|
+
|
|
236
|
+
if _runtime_client:
|
|
237
|
+
return await _runtime_client.get_object(object_class, object_id)
|
|
238
|
+
else:
|
|
239
|
+
# Fallback: create object directly
|
|
240
|
+
return await object_class.get_or_create(object_id)
|
|
241
|
+
|
|
242
|
+
def mark_completed(self, success: bool = True) -> None:
|
|
243
|
+
"""Mark the context as completed."""
|
|
244
|
+
self.completed_at = datetime.utcnow()
|
|
245
|
+
self.state = ExecutionState.COMPLETED if success else ExecutionState.FAILED
|
|
246
|
+
|
|
247
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
248
|
+
"""Convert context to dictionary for serialization."""
|
|
249
|
+
return {
|
|
250
|
+
"execution_id": self.execution_id,
|
|
251
|
+
"parent_id": self.parent_id,
|
|
252
|
+
"name": self.name,
|
|
253
|
+
"state": self.state.value,
|
|
254
|
+
"started_at": self.started_at.isoformat() if self.started_at else None,
|
|
255
|
+
"completed_at": self.completed_at.isoformat() if self.completed_at else None,
|
|
256
|
+
"metadata": self.metadata,
|
|
257
|
+
"state_data": self._state,
|
|
258
|
+
"error": str(self.error) if self.error else None,
|
|
259
|
+
"error_count": self.error_count,
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@classmethod
|
|
263
|
+
def from_dict(cls, data: Dict[str, Any]) -> "Context":
|
|
264
|
+
"""Create context from dictionary."""
|
|
265
|
+
ctx = cls(
|
|
266
|
+
execution_id=data["execution_id"],
|
|
267
|
+
parent_id=data.get("parent_id"),
|
|
268
|
+
name=data.get("name"),
|
|
269
|
+
state=ExecutionState(data["state"]),
|
|
270
|
+
metadata=data.get("metadata", {}),
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
# Restore timestamps
|
|
274
|
+
if data.get("started_at"):
|
|
275
|
+
ctx.started_at = datetime.fromisoformat(data["started_at"])
|
|
276
|
+
if data.get("completed_at"):
|
|
277
|
+
ctx.completed_at = datetime.fromisoformat(data["completed_at"])
|
|
278
|
+
|
|
279
|
+
# Restore state
|
|
280
|
+
ctx._state = data.get("state_data", {})
|
|
281
|
+
|
|
282
|
+
# Restore error info
|
|
283
|
+
ctx.error_count = data.get("error_count", 0)
|
|
284
|
+
|
|
285
|
+
return ctx
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def get_context() -> Context:
|
|
289
|
+
"""
|
|
290
|
+
Get the current execution context.
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
Current context or creates a new one if none exists
|
|
294
|
+
"""
|
|
295
|
+
ctx = _current_context.get()
|
|
296
|
+
if ctx is None:
|
|
297
|
+
ctx = Context()
|
|
298
|
+
_current_context.set(ctx)
|
|
299
|
+
return ctx
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def set_context(ctx: Context) -> None:
|
|
303
|
+
"""
|
|
304
|
+
Set the current execution context.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
ctx: Context to set as current
|
|
308
|
+
"""
|
|
309
|
+
_current_context.set(ctx)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
@contextmanager
|
|
313
|
+
def use_context(ctx: Context) -> ContextManager[Context]:
|
|
314
|
+
"""
|
|
315
|
+
Context manager to temporarily use a specific context.
|
|
316
|
+
|
|
317
|
+
Example:
|
|
318
|
+
```python
|
|
319
|
+
ctx = Context(name="my-operation")
|
|
320
|
+
|
|
321
|
+
with use_context(ctx):
|
|
322
|
+
# All operations here use ctx
|
|
323
|
+
agent = Agent("my-agent")
|
|
324
|
+
await agent.run("Hello")
|
|
325
|
+
```
|
|
326
|
+
"""
|
|
327
|
+
previous = _current_context.get()
|
|
328
|
+
_current_context.set(ctx)
|
|
329
|
+
|
|
330
|
+
try:
|
|
331
|
+
yield ctx
|
|
332
|
+
finally:
|
|
333
|
+
_current_context.set(previous)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
@contextmanager
|
|
337
|
+
def create_context(
|
|
338
|
+
name: Optional[str] = None,
|
|
339
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
340
|
+
) -> ContextManager[Context]:
|
|
341
|
+
"""
|
|
342
|
+
Create and use a new context.
|
|
343
|
+
|
|
344
|
+
Example:
|
|
345
|
+
```python
|
|
346
|
+
with create_context("data-processing") as ctx:
|
|
347
|
+
# Operations in this context
|
|
348
|
+
ctx.set("batch_size", 100)
|
|
349
|
+
process_data()
|
|
350
|
+
```
|
|
351
|
+
"""
|
|
352
|
+
ctx = Context(
|
|
353
|
+
name=name,
|
|
354
|
+
metadata=metadata or {},
|
|
355
|
+
state=ExecutionState.RUNNING,
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
with use_context(ctx):
|
|
359
|
+
yield ctx
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
class ContextualValue(Generic[T]):
|
|
363
|
+
"""
|
|
364
|
+
A value that is bound to the current context.
|
|
365
|
+
|
|
366
|
+
Example:
|
|
367
|
+
```python
|
|
368
|
+
# Define a contextual value
|
|
369
|
+
current_user = ContextualValue[str]("current_user")
|
|
370
|
+
|
|
371
|
+
# Set in context
|
|
372
|
+
with create_context("request") as ctx:
|
|
373
|
+
current_user.set("alice")
|
|
374
|
+
|
|
375
|
+
# Get from anywhere in the call stack
|
|
376
|
+
user = current_user.get() # "alice"
|
|
377
|
+
```
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
def __init__(self, key: str, default: Optional[T] = None):
|
|
381
|
+
"""Initialize a contextual value."""
|
|
382
|
+
self.key = key
|
|
383
|
+
self.default = default
|
|
384
|
+
|
|
385
|
+
def get(self) -> Optional[T]:
|
|
386
|
+
"""Get the value from the current context."""
|
|
387
|
+
ctx = get_context()
|
|
388
|
+
return ctx.get(self.key, self.default)
|
|
389
|
+
|
|
390
|
+
def set(self, value: T) -> None:
|
|
391
|
+
"""Set the value in the current context."""
|
|
392
|
+
ctx = get_context()
|
|
393
|
+
ctx.set(self.key, value)
|
|
394
|
+
|
|
395
|
+
def clear(self) -> None:
|
|
396
|
+
"""Clear the value from the current context."""
|
|
397
|
+
ctx = get_context()
|
|
398
|
+
if self.key in ctx._state:
|
|
399
|
+
del ctx._state[self.key]
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
# Common contextual values
|
|
403
|
+
current_agent = ContextualValue[str]("current_agent")
|
|
404
|
+
current_workflow = ContextualValue[str]("current_workflow")
|
|
405
|
+
current_user = ContextualValue[str]("current_user")
|
|
406
|
+
current_tenant = ContextualValue[str]("current_tenant")
|