axio 0.8.0__tar.gz → 0.9.1__tar.gz
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.
- {axio-0.8.0 → axio-0.9.1}/PKG-INFO +26 -33
- {axio-0.8.0 → axio-0.9.1}/README.md +24 -30
- {axio-0.8.0 → axio-0.9.1}/pyproject.toml +5 -3
- axio-0.9.1/src/axio/__init__.py +74 -0
- axio-0.9.1/src/axio/agent.py +523 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/agent_loader.py +21 -28
- {axio-0.8.0 → axio-0.9.1}/src/axio/blocks.py +56 -4
- {axio-0.8.0 → axio-0.9.1}/src/axio/compaction.py +2 -2
- axio-0.9.1/src/axio/events.py +183 -0
- axio-0.9.1/src/axio/field.py +179 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/models.py +9 -0
- axio-0.9.1/src/axio/permission.py +66 -0
- axio-0.9.1/src/axio/realtime.py +225 -0
- axio-0.9.1/src/axio/schema.py +145 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/testing.py +4 -7
- axio-0.9.1/src/axio/tool.py +256 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/tool_args.py +9 -0
- axio-0.9.1/src/axio/transport.py +211 -0
- {axio-0.8.0 → axio-0.9.1}/tests/test_agent_branch.py +10 -13
- axio-0.9.1/tests/test_agent_capabilities.py +106 -0
- {axio-0.8.0 → axio-0.9.1}/tests/test_agent_permission.py +37 -49
- {axio-0.8.0 → axio-0.9.1}/tests/test_agent_run.py +10 -13
- {axio-0.8.0 → axio-0.9.1}/tests/test_agent_tools.py +128 -48
- {axio-0.8.0 → axio-0.9.1}/tests/test_blocks.py +38 -2
- {axio-0.8.0 → axio-0.9.1}/tests/test_compaction.py +1 -1
- {axio-0.8.0 → axio-0.9.1}/tests/test_context.py +1 -1
- {axio-0.8.0 → axio-0.9.1}/tests/test_events.py +1 -1
- {axio-0.8.0 → axio-0.9.1}/tests/test_exceptions.py +8 -10
- axio-0.9.1/tests/test_field.py +328 -0
- axio-0.9.1/tests/test_init.py +13 -0
- axio-0.9.1/tests/test_permission.py +92 -0
- axio-0.9.1/tests/test_realtime.py +463 -0
- axio-0.9.1/tests/test_schema.py +394 -0
- axio-0.9.1/tests/test_selector.py +67 -0
- {axio-0.8.0 → axio-0.9.1}/tests/test_stream.py +1 -1
- axio-0.9.1/tests/test_testing.py +150 -0
- axio-0.9.1/tests/test_tool.py +650 -0
- {axio-0.8.0 → axio-0.9.1}/tests/test_tool_args.py +5 -5
- {axio-0.8.0 → axio-0.9.1}/tests/test_transport.py +31 -3
- {axio-0.8.0 → axio-0.9.1}/tests/test_types.py +4 -5
- axio-0.8.0/src/axio/__init__.py +0 -1
- axio-0.8.0/src/axio/agent.py +0 -258
- axio-0.8.0/src/axio/events.py +0 -98
- axio-0.8.0/src/axio/permission.py +0 -61
- axio-0.8.0/src/axio/tool.py +0 -76
- axio-0.8.0/src/axio/transport.py +0 -107
- axio-0.8.0/tests/test_permission.py +0 -29
- axio-0.8.0/tests/test_tool.py +0 -161
- {axio-0.8.0 → axio-0.9.1}/.github/workflows/publish.yml +0 -0
- {axio-0.8.0 → axio-0.9.1}/.github/workflows/tests.yml +0 -0
- {axio-0.8.0 → axio-0.9.1}/.gitignore +0 -0
- {axio-0.8.0 → axio-0.9.1}/LICENSE +0 -0
- {axio-0.8.0 → axio-0.9.1}/Makefile +0 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/context.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/exceptions.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/messages.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/py.typed +0 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/selector.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/stream.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/src/axio/types.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/tests/conftest.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/tests/test_agent_loader.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/tests/test_agent_stream.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/tests/test_models.py +0 -0
- {axio-0.8.0 → axio-0.9.1}/uv.lock +0 -0
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: axio
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: Minimal, streaming-first, protocol-driven foundation for LLM-powered agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/mosquito/axio-agent
|
|
6
6
|
Project-URL: Repository, https://github.com/mosquito/axio-agent
|
|
7
7
|
License: MIT
|
|
8
8
|
License-File: LICENSE
|
|
9
|
-
Keywords: agent,ai,async,llm,protocol,
|
|
9
|
+
Keywords: agent,ai,async,llm,protocol,streaming
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
|
-
Requires-Dist: pydantic>=2
|
|
12
11
|
Description-Content-Type: text/markdown
|
|
13
12
|
|
|
14
13
|
# axio
|
|
@@ -19,16 +18,16 @@ Description-Content-Type: text/markdown
|
|
|
19
18
|
|
|
20
19
|
Minimal, streaming-first, protocol-driven foundation for LLM-powered agents.
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
No dependencies. Three protocols. An agent loop that just works.
|
|
23
22
|
|
|
24
23
|
## Features
|
|
25
24
|
|
|
26
|
-
- **Streaming agent loop**
|
|
27
|
-
- **Three clean protocols**
|
|
28
|
-
- **Concurrent tool dispatch**
|
|
29
|
-
- **Context compaction**
|
|
30
|
-
- **Testing helpers**
|
|
31
|
-
- **Plugin-ready**
|
|
25
|
+
- **Streaming agent loop** - `run_stream()` yields typed events as they arrive; no buffering, no polling
|
|
26
|
+
- **Three clean protocols** - `CompletionTransport`, `ContextStore`, `PermissionGuard`; swap any piece without touching the rest
|
|
27
|
+
- **Concurrent tool dispatch** - all tool calls in a turn run via `asyncio.gather` automatically
|
|
28
|
+
- **Context compaction** - `compact_context()` summarises old history to stay within token limits
|
|
29
|
+
- **Testing helpers** - `StubTransport`, `make_tool_use_response()`, `make_echo_tool()` ship in `axio.testing`
|
|
30
|
+
- **Plugin-ready** - entry-point groups (`axio.tools`, `axio.transport`, `axio.guards`) for drop-in extensions
|
|
32
31
|
|
|
33
32
|
## Installation
|
|
34
33
|
|
|
@@ -57,17 +56,14 @@ sys.modules["axio_transport_openai"] = _m
|
|
|
57
56
|
import asyncio
|
|
58
57
|
from axio.agent import Agent
|
|
59
58
|
from axio.context import MemoryContextStore
|
|
60
|
-
from axio.tool import Tool
|
|
59
|
+
from axio.tool import Tool
|
|
61
60
|
|
|
62
61
|
# 1. Define a tool
|
|
63
|
-
|
|
62
|
+
async def greet(name: str) -> str:
|
|
64
63
|
"""Return a greeting for the given name."""
|
|
65
|
-
name
|
|
66
|
-
|
|
67
|
-
async def __call__(self) -> str:
|
|
68
|
-
return f"Hello, {self.name}!"
|
|
64
|
+
return f"Hello, {name}!"
|
|
69
65
|
|
|
70
|
-
greet_tool = Tool(name="greet", description="Greet someone by name", handler=
|
|
66
|
+
greet_tool = Tool(name="greet", description="Greet someone by name", handler=greet)
|
|
71
67
|
|
|
72
68
|
# 2. Wire up the agent (transport comes from an axio-transport-* package)
|
|
73
69
|
from axio_transport_openai import OpenAITransport
|
|
@@ -144,9 +140,9 @@ class MyContextStore(ContextStore):
|
|
|
144
140
|
async def get_history(self) -> list[Message]:
|
|
145
141
|
return list(self._messages)
|
|
146
142
|
|
|
147
|
-
# Everything else
|
|
143
|
+
# Everything else - session_id, close(), fork(), clear(),
|
|
148
144
|
# get/set_context_tokens(), add_context_tokens(), list_sessions()
|
|
149
|
-
#
|
|
145
|
+
# - has a default implementation.
|
|
150
146
|
```
|
|
151
147
|
|
|
152
148
|
### PermissionGuard
|
|
@@ -158,11 +154,12 @@ class MyContextStore(ContextStore):
|
|
|
158
154
|
```python
|
|
159
155
|
from typing import Any
|
|
160
156
|
from axio.permission import PermissionGuard
|
|
157
|
+
from axio.tool import Tool
|
|
161
158
|
|
|
162
159
|
class MyGuard(PermissionGuard):
|
|
163
|
-
async def check(self,
|
|
164
|
-
# return
|
|
165
|
-
return
|
|
160
|
+
async def check(self, tool: Tool[Any], **kwargs: Any) -> dict[str, Any]:
|
|
161
|
+
# return kwargs to allow, raise GuardError to deny
|
|
162
|
+
return kwargs
|
|
166
163
|
```
|
|
167
164
|
|
|
168
165
|
## Stream events
|
|
@@ -173,29 +170,25 @@ class MyGuard(PermissionGuard):
|
|
|
173
170
|
| `ToolUseStart` | Tool call begins (name + id) |
|
|
174
171
|
| `ToolInputDelta` | Streaming JSON fragment for tool arguments |
|
|
175
172
|
| `ToolResult` | Tool execution result |
|
|
176
|
-
| `IterationEnd` | One LLM round complete
|
|
173
|
+
| `IterationEnd` | One LLM round complete - carries `Usage` + `StopReason` |
|
|
177
174
|
| `Error` | Transport or tool exception |
|
|
178
|
-
| `SessionEndEvent` | Agent loop finished
|
|
175
|
+
| `SessionEndEvent` | Agent loop finished - carries total `Usage` |
|
|
179
176
|
|
|
180
177
|
## Tools
|
|
181
178
|
|
|
182
179
|
<!-- name: test_readme_tools -->
|
|
183
180
|
```python
|
|
184
|
-
from axio.tool import Tool
|
|
181
|
+
from axio.tool import Tool
|
|
185
182
|
|
|
186
|
-
|
|
183
|
+
async def summarise(text: str, max_words: int = 20) -> str:
|
|
187
184
|
"""Summarise the given text in one sentence."""
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
async def __call__(self) -> str:
|
|
192
|
-
# your implementation
|
|
193
|
-
return "..."
|
|
185
|
+
# your implementation
|
|
186
|
+
return "..."
|
|
194
187
|
|
|
195
188
|
tool = Tool(
|
|
196
189
|
name="summarise",
|
|
197
190
|
description="Summarise text", # overrides docstring if set
|
|
198
|
-
handler=
|
|
191
|
+
handler=summarise,
|
|
199
192
|
concurrency=4, # max parallel executions
|
|
200
193
|
)
|
|
201
194
|
```
|
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
Minimal, streaming-first, protocol-driven foundation for LLM-powered agents.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
No dependencies. Three protocols. An agent loop that just works.
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **Streaming agent loop**
|
|
14
|
-
- **Three clean protocols**
|
|
15
|
-
- **Concurrent tool dispatch**
|
|
16
|
-
- **Context compaction**
|
|
17
|
-
- **Testing helpers**
|
|
18
|
-
- **Plugin-ready**
|
|
13
|
+
- **Streaming agent loop** - `run_stream()` yields typed events as they arrive; no buffering, no polling
|
|
14
|
+
- **Three clean protocols** - `CompletionTransport`, `ContextStore`, `PermissionGuard`; swap any piece without touching the rest
|
|
15
|
+
- **Concurrent tool dispatch** - all tool calls in a turn run via `asyncio.gather` automatically
|
|
16
|
+
- **Context compaction** - `compact_context()` summarises old history to stay within token limits
|
|
17
|
+
- **Testing helpers** - `StubTransport`, `make_tool_use_response()`, `make_echo_tool()` ship in `axio.testing`
|
|
18
|
+
- **Plugin-ready** - entry-point groups (`axio.tools`, `axio.transport`, `axio.guards`) for drop-in extensions
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
21
|
|
|
@@ -44,17 +44,14 @@ sys.modules["axio_transport_openai"] = _m
|
|
|
44
44
|
import asyncio
|
|
45
45
|
from axio.agent import Agent
|
|
46
46
|
from axio.context import MemoryContextStore
|
|
47
|
-
from axio.tool import Tool
|
|
47
|
+
from axio.tool import Tool
|
|
48
48
|
|
|
49
49
|
# 1. Define a tool
|
|
50
|
-
|
|
50
|
+
async def greet(name: str) -> str:
|
|
51
51
|
"""Return a greeting for the given name."""
|
|
52
|
-
name
|
|
53
|
-
|
|
54
|
-
async def __call__(self) -> str:
|
|
55
|
-
return f"Hello, {self.name}!"
|
|
52
|
+
return f"Hello, {name}!"
|
|
56
53
|
|
|
57
|
-
greet_tool = Tool(name="greet", description="Greet someone by name", handler=
|
|
54
|
+
greet_tool = Tool(name="greet", description="Greet someone by name", handler=greet)
|
|
58
55
|
|
|
59
56
|
# 2. Wire up the agent (transport comes from an axio-transport-* package)
|
|
60
57
|
from axio_transport_openai import OpenAITransport
|
|
@@ -131,9 +128,9 @@ class MyContextStore(ContextStore):
|
|
|
131
128
|
async def get_history(self) -> list[Message]:
|
|
132
129
|
return list(self._messages)
|
|
133
130
|
|
|
134
|
-
# Everything else
|
|
131
|
+
# Everything else - session_id, close(), fork(), clear(),
|
|
135
132
|
# get/set_context_tokens(), add_context_tokens(), list_sessions()
|
|
136
|
-
#
|
|
133
|
+
# - has a default implementation.
|
|
137
134
|
```
|
|
138
135
|
|
|
139
136
|
### PermissionGuard
|
|
@@ -145,11 +142,12 @@ class MyContextStore(ContextStore):
|
|
|
145
142
|
```python
|
|
146
143
|
from typing import Any
|
|
147
144
|
from axio.permission import PermissionGuard
|
|
145
|
+
from axio.tool import Tool
|
|
148
146
|
|
|
149
147
|
class MyGuard(PermissionGuard):
|
|
150
|
-
async def check(self,
|
|
151
|
-
# return
|
|
152
|
-
return
|
|
148
|
+
async def check(self, tool: Tool[Any], **kwargs: Any) -> dict[str, Any]:
|
|
149
|
+
# return kwargs to allow, raise GuardError to deny
|
|
150
|
+
return kwargs
|
|
153
151
|
```
|
|
154
152
|
|
|
155
153
|
## Stream events
|
|
@@ -160,29 +158,25 @@ class MyGuard(PermissionGuard):
|
|
|
160
158
|
| `ToolUseStart` | Tool call begins (name + id) |
|
|
161
159
|
| `ToolInputDelta` | Streaming JSON fragment for tool arguments |
|
|
162
160
|
| `ToolResult` | Tool execution result |
|
|
163
|
-
| `IterationEnd` | One LLM round complete
|
|
161
|
+
| `IterationEnd` | One LLM round complete - carries `Usage` + `StopReason` |
|
|
164
162
|
| `Error` | Transport or tool exception |
|
|
165
|
-
| `SessionEndEvent` | Agent loop finished
|
|
163
|
+
| `SessionEndEvent` | Agent loop finished - carries total `Usage` |
|
|
166
164
|
|
|
167
165
|
## Tools
|
|
168
166
|
|
|
169
167
|
<!-- name: test_readme_tools -->
|
|
170
168
|
```python
|
|
171
|
-
from axio.tool import Tool
|
|
169
|
+
from axio.tool import Tool
|
|
172
170
|
|
|
173
|
-
|
|
171
|
+
async def summarise(text: str, max_words: int = 20) -> str:
|
|
174
172
|
"""Summarise the given text in one sentence."""
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
async def __call__(self) -> str:
|
|
179
|
-
# your implementation
|
|
180
|
-
return "..."
|
|
173
|
+
# your implementation
|
|
174
|
+
return "..."
|
|
181
175
|
|
|
182
176
|
tool = Tool(
|
|
183
177
|
name="summarise",
|
|
184
178
|
description="Summarise text", # overrides docstring if set
|
|
185
|
-
handler=
|
|
179
|
+
handler=summarise,
|
|
186
180
|
concurrency=4, # max parallel executions
|
|
187
181
|
)
|
|
188
182
|
```
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "axio"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.9.1" # bumped to the git tag by CI on publish
|
|
4
4
|
description = "Minimal, streaming-first, protocol-driven foundation for LLM-powered agents"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
7
7
|
license = {text = "MIT"}
|
|
8
|
-
keywords = ["llm", "agent", "ai", "async", "streaming", "
|
|
9
|
-
dependencies = [
|
|
8
|
+
keywords = ["llm", "agent", "ai", "async", "streaming", "protocol"]
|
|
9
|
+
dependencies = []
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
[project.urls]
|
|
@@ -25,6 +25,7 @@ testpaths = ["tests", "README.md"]
|
|
|
25
25
|
|
|
26
26
|
[tool.ruff]
|
|
27
27
|
line-length = 119
|
|
28
|
+
output-format = "concise"
|
|
28
29
|
target-version = "py312"
|
|
29
30
|
|
|
30
31
|
[tool.ruff.lint]
|
|
@@ -34,6 +35,7 @@ select = ["E", "F", "I", "UP"]
|
|
|
34
35
|
strict = true
|
|
35
36
|
python_version = "3.12"
|
|
36
37
|
|
|
38
|
+
|
|
37
39
|
[dependency-groups]
|
|
38
40
|
dev = [
|
|
39
41
|
"pytest>=8",
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""axio - public API."""
|
|
2
|
+
|
|
3
|
+
from .agent import Agent
|
|
4
|
+
from .blocks import TextBlock, ToolResultBlock, ToolUseBlock
|
|
5
|
+
from .context import ContextStore, MemoryContextStore
|
|
6
|
+
from .events import (
|
|
7
|
+
AudioOutputDelta,
|
|
8
|
+
IterationEnd,
|
|
9
|
+
SpeechStarted,
|
|
10
|
+
SpeechStopped,
|
|
11
|
+
StreamEvent,
|
|
12
|
+
TextDelta,
|
|
13
|
+
ToolInputDelta,
|
|
14
|
+
ToolResult,
|
|
15
|
+
ToolUseStart,
|
|
16
|
+
TranscriptDelta,
|
|
17
|
+
TurnComplete,
|
|
18
|
+
)
|
|
19
|
+
from .exceptions import GuardError, HandlerError
|
|
20
|
+
from .field import Field, FieldInfo, StrictStr
|
|
21
|
+
from .messages import Message
|
|
22
|
+
from .permission import ConcurrentGuard, PermissionGuard
|
|
23
|
+
from .realtime import RealtimeAgent
|
|
24
|
+
from .selector import ToolSelector
|
|
25
|
+
from .stream import AgentStream
|
|
26
|
+
from .tool import CONTEXT, Tool
|
|
27
|
+
from .transport import CompletionTransport, RealtimeSession, RealtimeTransport
|
|
28
|
+
from .types import StopReason, Usage
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
# core
|
|
32
|
+
"Agent",
|
|
33
|
+
"Tool",
|
|
34
|
+
"CONTEXT",
|
|
35
|
+
"ContextStore",
|
|
36
|
+
"MemoryContextStore",
|
|
37
|
+
"CompletionTransport",
|
|
38
|
+
# events
|
|
39
|
+
"StreamEvent",
|
|
40
|
+
"TextDelta",
|
|
41
|
+
"IterationEnd",
|
|
42
|
+
"ToolUseStart",
|
|
43
|
+
"ToolInputDelta",
|
|
44
|
+
"ToolResult",
|
|
45
|
+
# realtime
|
|
46
|
+
"RealtimeAgent",
|
|
47
|
+
"RealtimeTransport",
|
|
48
|
+
"RealtimeSession",
|
|
49
|
+
"AudioOutputDelta",
|
|
50
|
+
"TranscriptDelta",
|
|
51
|
+
"SpeechStarted",
|
|
52
|
+
"SpeechStopped",
|
|
53
|
+
"TurnComplete",
|
|
54
|
+
# messages & blocks
|
|
55
|
+
"Message",
|
|
56
|
+
"TextBlock",
|
|
57
|
+
"ToolUseBlock",
|
|
58
|
+
"ToolResultBlock",
|
|
59
|
+
# types & errors
|
|
60
|
+
"StopReason",
|
|
61
|
+
"Usage",
|
|
62
|
+
"GuardError",
|
|
63
|
+
"HandlerError",
|
|
64
|
+
# permissions
|
|
65
|
+
"PermissionGuard",
|
|
66
|
+
"ConcurrentGuard",
|
|
67
|
+
# field annotations
|
|
68
|
+
"Field",
|
|
69
|
+
"FieldInfo",
|
|
70
|
+
"StrictStr",
|
|
71
|
+
# advanced
|
|
72
|
+
"ToolSelector",
|
|
73
|
+
"AgentStream",
|
|
74
|
+
]
|