voxagent 0.1.0__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.
Files changed (53) hide show
  1. voxagent/__init__.py +143 -0
  2. voxagent/_version.py +5 -0
  3. voxagent/agent/__init__.py +32 -0
  4. voxagent/agent/abort.py +178 -0
  5. voxagent/agent/core.py +902 -0
  6. voxagent/code/__init__.py +9 -0
  7. voxagent/mcp/__init__.py +16 -0
  8. voxagent/mcp/manager.py +188 -0
  9. voxagent/mcp/tool.py +152 -0
  10. voxagent/providers/__init__.py +110 -0
  11. voxagent/providers/anthropic.py +498 -0
  12. voxagent/providers/augment.py +293 -0
  13. voxagent/providers/auth.py +116 -0
  14. voxagent/providers/base.py +268 -0
  15. voxagent/providers/chatgpt.py +415 -0
  16. voxagent/providers/claudecode.py +162 -0
  17. voxagent/providers/cli_base.py +265 -0
  18. voxagent/providers/codex.py +183 -0
  19. voxagent/providers/failover.py +90 -0
  20. voxagent/providers/google.py +532 -0
  21. voxagent/providers/groq.py +96 -0
  22. voxagent/providers/ollama.py +425 -0
  23. voxagent/providers/openai.py +435 -0
  24. voxagent/providers/registry.py +175 -0
  25. voxagent/py.typed +1 -0
  26. voxagent/security/__init__.py +14 -0
  27. voxagent/security/events.py +75 -0
  28. voxagent/security/filter.py +169 -0
  29. voxagent/security/registry.py +87 -0
  30. voxagent/session/__init__.py +39 -0
  31. voxagent/session/compaction.py +237 -0
  32. voxagent/session/lock.py +103 -0
  33. voxagent/session/model.py +109 -0
  34. voxagent/session/storage.py +184 -0
  35. voxagent/streaming/__init__.py +52 -0
  36. voxagent/streaming/emitter.py +286 -0
  37. voxagent/streaming/events.py +255 -0
  38. voxagent/subagent/__init__.py +20 -0
  39. voxagent/subagent/context.py +124 -0
  40. voxagent/subagent/definition.py +172 -0
  41. voxagent/tools/__init__.py +32 -0
  42. voxagent/tools/context.py +50 -0
  43. voxagent/tools/decorator.py +175 -0
  44. voxagent/tools/definition.py +131 -0
  45. voxagent/tools/executor.py +109 -0
  46. voxagent/tools/policy.py +89 -0
  47. voxagent/tools/registry.py +89 -0
  48. voxagent/types/__init__.py +46 -0
  49. voxagent/types/messages.py +134 -0
  50. voxagent/types/run.py +176 -0
  51. voxagent-0.1.0.dist-info/METADATA +186 -0
  52. voxagent-0.1.0.dist-info/RECORD +53 -0
  53. voxagent-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,255 @@
1
+ """Stream event data types.
2
+
3
+ This module defines typed event payloads for the streaming event system.
4
+ Each event type is a Pydantic model that can be serialized/deserialized.
5
+
6
+ Event Categories:
7
+ - Lifecycle Events: RunStartEvent, RunEndEvent, RunErrorEvent
8
+ - Inference Events: AssistantStartEvent, TextDeltaEvent, AssistantEndEvent
9
+ - Tool Events: ToolStartEvent, ToolOutputEvent, ToolEndEvent
10
+ - Context Events: CompactionStartEvent, CompactionEndEvent
11
+ """
12
+
13
+ from datetime import datetime, timezone
14
+ from typing import Literal
15
+
16
+ from pydantic import BaseModel, Field
17
+
18
+ from voxagent.types import Message, ToolCall, ToolResult
19
+
20
+
21
+ def _utc_now() -> datetime:
22
+ """Return current UTC time."""
23
+ return datetime.now(timezone.utc)
24
+
25
+
26
+ # =============================================================================
27
+ # Base Event
28
+ # =============================================================================
29
+
30
+
31
+ class BaseEvent(BaseModel):
32
+ """Base class for all stream events.
33
+
34
+ Attributes:
35
+ run_id: Unique identifier for the current agent run.
36
+ """
37
+
38
+ run_id: str
39
+
40
+
41
+ # =============================================================================
42
+ # Lifecycle Events
43
+ # =============================================================================
44
+
45
+
46
+ class RunStartEvent(BaseEvent):
47
+ """Event emitted when an agent run starts.
48
+
49
+ Attributes:
50
+ run_id: Unique identifier for the run.
51
+ session_key: Session key for the run.
52
+ timestamp: When the run started.
53
+ event_type: Discriminator field for type narrowing.
54
+ """
55
+
56
+ session_key: str
57
+ timestamp: datetime = Field(default_factory=_utc_now)
58
+ event_type: Literal["run_start"] = "run_start"
59
+
60
+
61
+ class RunEndEvent(BaseEvent):
62
+ """Event emitted when an agent run ends.
63
+
64
+ Attributes:
65
+ run_id: Unique identifier for the run.
66
+ messages: Final list of messages from the run.
67
+ aborted: Whether the run was aborted.
68
+ timed_out: Whether the run timed out.
69
+ timestamp: When the run ended.
70
+ event_type: Discriminator field for type narrowing.
71
+ """
72
+
73
+ messages: list[Message]
74
+ aborted: bool = False
75
+ timed_out: bool = False
76
+ timestamp: datetime = Field(default_factory=_utc_now)
77
+ event_type: Literal["run_end"] = "run_end"
78
+
79
+
80
+ class RunErrorEvent(BaseEvent):
81
+ """Event emitted when an agent run encounters an error.
82
+
83
+ Attributes:
84
+ run_id: Unique identifier for the run.
85
+ error: Error message.
86
+ timestamp: When the error occurred.
87
+ event_type: Discriminator field for type narrowing.
88
+ """
89
+
90
+ error: str
91
+ timestamp: datetime = Field(default_factory=_utc_now)
92
+ event_type: Literal["run_error"] = "run_error"
93
+
94
+
95
+ # =============================================================================
96
+ # Inference Events
97
+ # =============================================================================
98
+
99
+
100
+ class AssistantStartEvent(BaseEvent):
101
+ """Event emitted when the assistant starts generating a response.
102
+
103
+ Attributes:
104
+ run_id: Unique identifier for the run.
105
+ event_type: Discriminator field for type narrowing.
106
+ """
107
+
108
+ event_type: Literal["assistant_start"] = "assistant_start"
109
+
110
+
111
+ class TextDeltaEvent(BaseEvent):
112
+ """Event emitted for each text chunk from the assistant.
113
+
114
+ Attributes:
115
+ run_id: Unique identifier for the run.
116
+ delta: The text chunk.
117
+ event_type: Discriminator field for type narrowing.
118
+ """
119
+
120
+ delta: str
121
+ event_type: Literal["text_delta"] = "text_delta"
122
+
123
+
124
+ class AssistantEndEvent(BaseEvent):
125
+ """Event emitted when the assistant finishes generating a response.
126
+
127
+ Attributes:
128
+ run_id: Unique identifier for the run.
129
+ message: The complete assistant message.
130
+ event_type: Discriminator field for type narrowing.
131
+ """
132
+
133
+ message: Message
134
+ event_type: Literal["assistant_end"] = "assistant_end"
135
+
136
+
137
+ # =============================================================================
138
+ # Tool Events
139
+ # =============================================================================
140
+
141
+
142
+ class ToolStartEvent(BaseEvent):
143
+ """Event emitted when a tool execution starts.
144
+
145
+ Attributes:
146
+ run_id: Unique identifier for the run.
147
+ tool_call: The tool call being executed.
148
+ event_type: Discriminator field for type narrowing.
149
+ """
150
+
151
+ tool_call: ToolCall
152
+ event_type: Literal["tool_start"] = "tool_start"
153
+
154
+
155
+ class ToolOutputEvent(BaseEvent):
156
+ """Event emitted for streaming tool output.
157
+
158
+ Attributes:
159
+ run_id: Unique identifier for the run.
160
+ tool_call_id: ID of the tool call.
161
+ delta: Output chunk from the tool.
162
+ event_type: Discriminator field for type narrowing.
163
+ """
164
+
165
+ tool_call_id: str
166
+ delta: str
167
+ event_type: Literal["tool_output"] = "tool_output"
168
+
169
+
170
+ class ToolEndEvent(BaseEvent):
171
+ """Event emitted when a tool execution ends.
172
+
173
+ Attributes:
174
+ run_id: Unique identifier for the run.
175
+ tool_call_id: ID of the tool call.
176
+ result: The tool result.
177
+ event_type: Discriminator field for type narrowing.
178
+ """
179
+
180
+ tool_call_id: str
181
+ result: ToolResult
182
+ event_type: Literal["tool_end"] = "tool_end"
183
+
184
+
185
+ # =============================================================================
186
+ # Context Events
187
+ # =============================================================================
188
+
189
+
190
+ class CompactionStartEvent(BaseEvent):
191
+ """Event emitted when context compaction starts.
192
+
193
+ Attributes:
194
+ run_id: Unique identifier for the run.
195
+ message_count: Number of messages before compaction.
196
+ token_count: Number of tokens before compaction.
197
+ event_type: Discriminator field for type narrowing.
198
+ """
199
+
200
+ message_count: int
201
+ token_count: int
202
+ event_type: Literal["compaction_start"] = "compaction_start"
203
+
204
+
205
+ class CompactionEndEvent(BaseEvent):
206
+ """Event emitted when context compaction ends.
207
+
208
+ Attributes:
209
+ run_id: Unique identifier for the run.
210
+ messages_removed: Number of messages removed.
211
+ tokens_saved: Number of tokens saved.
212
+ event_type: Discriminator field for type narrowing.
213
+ """
214
+
215
+ messages_removed: int
216
+ tokens_saved: int
217
+ event_type: Literal["compaction_end"] = "compaction_end"
218
+
219
+
220
+ # =============================================================================
221
+ # Union Type
222
+ # =============================================================================
223
+
224
+
225
+ StreamEventData = (
226
+ RunStartEvent
227
+ | RunEndEvent
228
+ | RunErrorEvent
229
+ | AssistantStartEvent
230
+ | TextDeltaEvent
231
+ | AssistantEndEvent
232
+ | ToolStartEvent
233
+ | ToolOutputEvent
234
+ | ToolEndEvent
235
+ | CompactionStartEvent
236
+ | CompactionEndEvent
237
+ )
238
+
239
+
240
+ __all__ = [
241
+ "AssistantEndEvent",
242
+ "AssistantStartEvent",
243
+ "BaseEvent",
244
+ "CompactionEndEvent",
245
+ "CompactionStartEvent",
246
+ "RunEndEvent",
247
+ "RunErrorEvent",
248
+ "RunStartEvent",
249
+ "StreamEventData",
250
+ "TextDeltaEvent",
251
+ "ToolEndEvent",
252
+ "ToolOutputEvent",
253
+ "ToolStartEvent",
254
+ ]
255
+
@@ -0,0 +1,20 @@
1
+ """Sub-agent support for voxagent.
2
+
3
+ This module provides the ability to register agents as tools that can be called
4
+ by parent agents, enabling hierarchical agent composition and delegation.
5
+ """
6
+
7
+ from voxagent.subagent.context import (
8
+ DEFAULT_MAX_DEPTH,
9
+ MaxDepthExceededError,
10
+ SubAgentContext,
11
+ )
12
+ from voxagent.subagent.definition import SubAgentDefinition
13
+
14
+ __all__ = [
15
+ "SubAgentDefinition",
16
+ "SubAgentContext",
17
+ "MaxDepthExceededError",
18
+ "DEFAULT_MAX_DEPTH",
19
+ ]
20
+
@@ -0,0 +1,124 @@
1
+ """Sub-agent context for depth tracking and propagation.
2
+
3
+ This module provides SubAgentContext which extends ToolContext with
4
+ depth tracking to prevent infinite recursion in nested agent calls.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, TypeVar
10
+
11
+ from pydantic import ConfigDict, Field
12
+
13
+ from voxagent.providers.base import AbortSignal
14
+ from voxagent.tools.context import ToolContext
15
+
16
+ T = TypeVar("T")
17
+
18
+ # Default maximum depth for nested agent calls
19
+ DEFAULT_MAX_DEPTH = 5
20
+
21
+
22
+ class MaxDepthExceededError(Exception):
23
+ """Raised when sub-agent call exceeds maximum depth."""
24
+
25
+ def __init__(self, depth: int, max_depth: int) -> None:
26
+ self.depth = depth
27
+ self.max_depth = max_depth
28
+ super().__init__(
29
+ f"Maximum sub-agent depth exceeded: {depth} > {max_depth}. "
30
+ "This may indicate infinite recursion or an overly deep agent hierarchy."
31
+ )
32
+
33
+
34
+ class SubAgentContext(ToolContext[T]):
35
+ """Extended context for sub-agent execution with depth tracking.
36
+
37
+ Extends ToolContext with:
38
+ - depth: Current nesting level (0 = root agent)
39
+ - max_depth: Maximum allowed nesting depth
40
+ - parent_run_id: Run ID of the parent agent (for tracing)
41
+
42
+ Attributes:
43
+ depth: Current depth in the agent hierarchy (0 = root).
44
+ max_depth: Maximum allowed depth before raising MaxDepthExceededError.
45
+ parent_run_id: The run_id of the parent agent that spawned this sub-agent.
46
+ """
47
+
48
+ depth: int = Field(default=0, ge=0)
49
+ max_depth: int = Field(default=DEFAULT_MAX_DEPTH, ge=1)
50
+ parent_run_id: str | None = None
51
+
52
+ model_config = ConfigDict(arbitrary_types_allowed=True)
53
+
54
+ def check_depth(self) -> None:
55
+ """Raise MaxDepthExceededError if depth exceeds max_depth."""
56
+ if self.depth >= self.max_depth:
57
+ raise MaxDepthExceededError(self.depth, self.max_depth)
58
+
59
+ def child_context(
60
+ self,
61
+ abort_signal: AbortSignal | None = None,
62
+ deps: Any = None,
63
+ session_id: str | None = None,
64
+ run_id: str | None = None,
65
+ ) -> "SubAgentContext[Any]":
66
+ """Create a child context with incremented depth.
67
+
68
+ Args:
69
+ abort_signal: Abort signal for the child (uses parent's if None).
70
+ deps: Dependencies for the child (uses parent's if None).
71
+ session_id: Session ID for the child (uses parent's if None).
72
+ run_id: Run ID for the child agent.
73
+
74
+ Returns:
75
+ New SubAgentContext with depth + 1.
76
+
77
+ Raises:
78
+ MaxDepthExceededError: If the new depth exceeds max_depth.
79
+ """
80
+ new_depth = self.depth + 1
81
+ if new_depth > self.max_depth:
82
+ raise MaxDepthExceededError(new_depth, self.max_depth)
83
+
84
+ return SubAgentContext(
85
+ abort_signal=abort_signal or self.abort_signal,
86
+ deps=deps if deps is not None else self.deps,
87
+ session_id=session_id or self.session_id,
88
+ run_id=run_id,
89
+ retry_count=0, # Reset retry count for child
90
+ depth=new_depth,
91
+ max_depth=self.max_depth,
92
+ parent_run_id=self.run_id, # Current run becomes parent
93
+ )
94
+
95
+ @classmethod
96
+ def from_tool_context(
97
+ cls,
98
+ context: ToolContext,
99
+ depth: int = 0,
100
+ max_depth: int = DEFAULT_MAX_DEPTH,
101
+ parent_run_id: str | None = None,
102
+ ) -> "SubAgentContext[Any]":
103
+ """Create SubAgentContext from a regular ToolContext.
104
+
105
+ Args:
106
+ context: The source ToolContext.
107
+ depth: Initial depth (default 0).
108
+ max_depth: Maximum depth (default DEFAULT_MAX_DEPTH).
109
+ parent_run_id: Parent run ID for tracing.
110
+
111
+ Returns:
112
+ New SubAgentContext with depth tracking.
113
+ """
114
+ return cls(
115
+ abort_signal=context.abort_signal,
116
+ deps=context.deps,
117
+ session_id=context.session_id,
118
+ run_id=context.run_id,
119
+ retry_count=context.retry_count,
120
+ depth=depth,
121
+ max_depth=max_depth,
122
+ parent_run_id=parent_run_id,
123
+ )
124
+
@@ -0,0 +1,172 @@
1
+ """Sub-agent definition for voxagent.
2
+
3
+ This module provides SubAgentDefinition, a ToolDefinition subclass that wraps
4
+ an Agent and makes it callable as a tool by a parent agent.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+ from typing import TYPE_CHECKING, Any
11
+
12
+ from voxagent.subagent.context import (
13
+ DEFAULT_MAX_DEPTH,
14
+ MaxDepthExceededError,
15
+ SubAgentContext,
16
+ )
17
+ from voxagent.tools.context import ToolContext
18
+ from voxagent.tools.definition import ToolDefinition
19
+
20
+ if TYPE_CHECKING:
21
+ from voxagent.agent.core import Agent
22
+
23
+
24
+ class SubAgentDefinition(ToolDefinition):
25
+ """A ToolDefinition that wraps an Agent as a callable tool.
26
+
27
+ This allows parent agents to delegate tasks to specialized child agents.
28
+ The child agent inherits context (abort signal, deps, session) from parent.
29
+
30
+ Example:
31
+ researcher = Agent(model="...", system_prompt="You research topics...")
32
+
33
+ parent = Agent(
34
+ model="...",
35
+ sub_agents=[researcher], # Auto-converted to SubAgentDefinition
36
+ )
37
+ """
38
+
39
+ def __init__(
40
+ self,
41
+ agent: "Agent[Any, Any]",
42
+ name: str | None = None,
43
+ description: str | None = None,
44
+ max_depth: int = DEFAULT_MAX_DEPTH,
45
+ ) -> None:
46
+ """Initialize SubAgentDefinition.
47
+
48
+ Args:
49
+ agent: The Agent instance to wrap as a tool.
50
+ name: Tool name (defaults to agent name or 'sub_agent').
51
+ description: Tool description (defaults to agent's system prompt).
52
+ max_depth: Maximum nesting depth for recursive calls.
53
+ """
54
+ # Determine tool name
55
+ tool_name = name or getattr(agent, "name", None) or "sub_agent"
56
+ tool_name = self._sanitize_name(tool_name)
57
+
58
+ # Determine description
59
+ tool_desc = description or agent._system_prompt or f"Delegate to {tool_name}"
60
+ # Truncate long descriptions for tool schema
61
+ if len(tool_desc) > 500:
62
+ tool_desc = tool_desc[:497] + "..."
63
+
64
+ # Validate name manually (don't call parent __init__ with execute)
65
+ if not re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", tool_name):
66
+ raise ValueError(
67
+ f"Tool name '{tool_name}' is invalid. "
68
+ "Must contain only alphanumeric characters and underscores."
69
+ )
70
+
71
+ self.name = tool_name
72
+ self.description = tool_desc
73
+ self.parameters = {
74
+ "type": "object",
75
+ "properties": {
76
+ "task": {
77
+ "type": "string",
78
+ "description": "The task or query to delegate to this agent.",
79
+ }
80
+ },
81
+ "required": ["task"],
82
+ }
83
+ self.is_async = True
84
+
85
+ # Sub-agent specific attributes
86
+ self._agent = agent
87
+ self._max_depth = max_depth
88
+
89
+ # Set execute placeholder
90
+ self.execute = self._execute_placeholder
91
+
92
+ @staticmethod
93
+ def _sanitize_name(name: str) -> str:
94
+ """Sanitize agent name to be a valid tool name."""
95
+ # Replace spaces and invalid chars with underscores
96
+ sanitized = re.sub(r"[^a-zA-Z0-9_]", "_", name)
97
+ # Ensure doesn't start with digit
98
+ if sanitized and sanitized[0].isdigit():
99
+ sanitized = "_" + sanitized
100
+ return sanitized or "sub_agent"
101
+
102
+ async def _execute_placeholder(self, **params: Any) -> Any:
103
+ """Placeholder - actual execution happens in run()."""
104
+ raise NotImplementedError("Use run() instead")
105
+
106
+ async def run(self, params: dict[str, Any], context: ToolContext) -> Any:
107
+ """Execute the sub-agent with the given task.
108
+
109
+ Args:
110
+ params: Must contain 'task' key with the prompt for the sub-agent.
111
+ context: The ToolContext from the parent agent.
112
+
113
+ Returns:
114
+ The sub-agent's response text.
115
+
116
+ Raises:
117
+ MaxDepthExceededError: If nesting depth exceeds max_depth.
118
+ """
119
+ task = params.get("task", "")
120
+ if not task:
121
+ return "Error: No task provided for sub-agent"
122
+
123
+ # Convert or get SubAgentContext with depth tracking
124
+ if isinstance(context, SubAgentContext):
125
+ sub_context = context
126
+ else:
127
+ sub_context = SubAgentContext.from_tool_context(
128
+ context, depth=0, max_depth=self._max_depth
129
+ )
130
+
131
+ # Check depth before spawning child
132
+ try:
133
+ child_context = sub_context.child_context(
134
+ run_id=None, # Agent.run() will create new run_id
135
+ )
136
+ except MaxDepthExceededError as e:
137
+ return f"Error: {e}"
138
+
139
+ # Run the sub-agent
140
+ try:
141
+ print(f"\n🤖 SUB-AGENT CALLED: {self.name}")
142
+ print(f" Task: {task[:100]}{'...' if len(task) > 100 else ''}")
143
+ print(f" Depth: {child_context.depth}/{child_context.max_depth}")
144
+
145
+ result = await self._agent.run(
146
+ prompt=task,
147
+ deps=child_context.deps,
148
+ session_key=child_context.session_id,
149
+ # Pass depth info via message_history metadata (optional)
150
+ )
151
+
152
+ if result.error:
153
+ return f"Sub-agent error: {result.error}"
154
+
155
+ # Return the agent's response
156
+ if result.assistant_texts:
157
+ return result.assistant_texts[-1] # Last response
158
+ return "Sub-agent completed with no response"
159
+
160
+ except Exception as e:
161
+ return f"Sub-agent execution error: {type(e).__name__}: {e}"
162
+
163
+ @property
164
+ def agent(self) -> "Agent[Any, Any]":
165
+ """Get the wrapped Agent instance."""
166
+ return self._agent
167
+
168
+ @property
169
+ def max_depth(self) -> int:
170
+ """Get the maximum nesting depth."""
171
+ return self._max_depth
172
+
@@ -0,0 +1,32 @@
1
+ """Tool system for agent tool definitions and execution.
2
+
3
+ This subpackage provides:
4
+ - Tool definitions with typed parameters
5
+ - Tool registry for dynamic registration
6
+ - Tool policies for allow/deny filtering
7
+ - Tool execution with abort signal support
8
+ """
9
+
10
+ from voxagent.tools.context import AbortError, ToolContext
11
+ from voxagent.tools.decorator import tool
12
+ from voxagent.tools.definition import ToolDefinition
13
+ from voxagent.tools.executor import execute_tool
14
+ from voxagent.tools.policy import ToolPolicy, apply_tool_policies
15
+ from voxagent.tools.registry import (
16
+ ToolAlreadyRegisteredError,
17
+ ToolNotFoundError,
18
+ ToolRegistry,
19
+ )
20
+
21
+ __all__ = [
22
+ "AbortError",
23
+ "ToolAlreadyRegisteredError",
24
+ "ToolContext",
25
+ "ToolDefinition",
26
+ "ToolNotFoundError",
27
+ "ToolPolicy",
28
+ "ToolRegistry",
29
+ "apply_tool_policies",
30
+ "execute_tool",
31
+ "tool",
32
+ ]
@@ -0,0 +1,50 @@
1
+ """Tool context for voxagent."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Generic, TypeVar
6
+
7
+ from pydantic import BaseModel, ConfigDict
8
+
9
+ from voxagent.providers.base import AbortSignal
10
+
11
+ T = TypeVar("T")
12
+
13
+
14
+ class AbortError(Exception):
15
+ """Raised when an operation is aborted."""
16
+
17
+ def __init__(self, message: str = "Operation aborted") -> None:
18
+ super().__init__(message)
19
+
20
+
21
+ class ToolContext(BaseModel, Generic[T]):
22
+ """Runtime context passed to tool functions.
23
+
24
+ Replaces PydanticAI's RunContext with a simpler, more focused API.
25
+
26
+ Attributes:
27
+ abort_signal: Signal to check for abort requests
28
+ deps: Optional dependencies injected by the agent
29
+ session_id: Current session ID
30
+ run_id: Current run ID
31
+ retry_count: Number of times this tool has been retried
32
+ """
33
+
34
+ abort_signal: AbortSignal
35
+ deps: T | None = None
36
+ session_id: str | None = None
37
+ run_id: str | None = None
38
+ retry_count: int = 0
39
+
40
+ model_config = ConfigDict(arbitrary_types_allowed=True)
41
+
42
+ def is_aborted(self) -> bool:
43
+ """Check if the operation has been aborted."""
44
+ return self.abort_signal.aborted
45
+
46
+ def check_abort(self) -> None:
47
+ """Raise AbortError if aborted."""
48
+ if self.abort_signal.aborted:
49
+ raise AbortError("Operation aborted")
50
+