agent-assembly 0.0.1a4__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.
- agent_assembly-0.0.1a4/LICENSE +22 -0
- agent_assembly-0.0.1a4/PKG-INFO +202 -0
- agent_assembly-0.0.1a4/README.md +171 -0
- agent_assembly-0.0.1a4/agent_assembly/__init__.py +122 -0
- agent_assembly-0.0.1a4/agent_assembly/_install.py +56 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/__init__.py +4 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/base.py +158 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/crewai/__init__.py +6 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/crewai/adapter.py +28 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/crewai/patch.py +484 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/google_adk/__init__.py +6 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/google_adk/adapter.py +51 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/google_adk/patch.py +357 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langchain/__init__.py +21 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langchain/adapter.py +47 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langchain/callback_handler.py +320 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langchain/langgraph_patch.py +33 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langchain/patch.py +36 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langchain/runtime.py +44 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langgraph/__init__.py +6 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langgraph/adapter.py +40 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/langgraph/patch.py +574 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/mcp/__init__.py +6 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/mcp/adapter.py +40 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/mcp/patch.py +311 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/openai_agents/__init__.py +6 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/openai_agents/adapter.py +49 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/openai_agents/patch.py +487 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/pydantic_ai/__init__.py +6 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/pydantic_ai/adapter.py +40 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/pydantic_ai/patch.py +403 -0
- agent_assembly-0.0.1a4/agent_assembly/adapters/registry.py +213 -0
- agent_assembly-0.0.1a4/agent_assembly/cli/__init__.py +1 -0
- agent_assembly-0.0.1a4/agent_assembly/cli/adapter_validator.py +295 -0
- agent_assembly-0.0.1a4/agent_assembly/cli/main.py +61 -0
- agent_assembly-0.0.1a4/agent_assembly/cli/output.py +24 -0
- agent_assembly-0.0.1a4/agent_assembly/client/__init__.py +6 -0
- agent_assembly-0.0.1a4/agent_assembly/client/dispatch.py +28 -0
- agent_assembly-0.0.1a4/agent_assembly/client/emitter.py +50 -0
- agent_assembly-0.0.1a4/agent_assembly/client/gateway.py +218 -0
- agent_assembly-0.0.1a4/agent_assembly/core/__init__.py +29 -0
- agent_assembly-0.0.1a4/agent_assembly/core/assembly.py +326 -0
- agent_assembly-0.0.1a4/agent_assembly/core/gateway_resolver.py +183 -0
- agent_assembly-0.0.1a4/agent_assembly/core/lineage.py +47 -0
- agent_assembly-0.0.1a4/agent_assembly/core/spawn.py +32 -0
- agent_assembly-0.0.1a4/agent_assembly/exceptions/__init__.py +77 -0
- agent_assembly-0.0.1a4/agent_assembly/models/__init__.py +5 -0
- agent_assembly-0.0.1a4/agent_assembly/models/agent.py +37 -0
- agent_assembly-0.0.1a4/agent_assembly/op_control.py +216 -0
- agent_assembly-0.0.1a4/agent_assembly/proto/__init__.py +0 -0
- agent_assembly-0.0.1a4/agent_assembly/proto/common_pb2.py +44 -0
- agent_assembly-0.0.1a4/agent_assembly/proto/common_pb2.pyi +65 -0
- agent_assembly-0.0.1a4/agent_assembly/proto/common_pb2_grpc.py +24 -0
- agent_assembly-0.0.1a4/agent_assembly/proto/policy_pb2.py +67 -0
- agent_assembly-0.0.1a4/agent_assembly/proto/policy_pb2.pyi +160 -0
- agent_assembly-0.0.1a4/agent_assembly/proto/policy_pb2_grpc.py +208 -0
- agent_assembly-0.0.1a4/agent_assembly/py.typed +0 -0
- agent_assembly-0.0.1a4/agent_assembly/runtime.py +134 -0
- agent_assembly-0.0.1a4/agent_assembly/types.py +145 -0
- agent_assembly-0.0.1a4/pyproject.toml +118 -0
- agent_assembly-0.0.1a4/rust/Cargo.lock +1664 -0
- agent_assembly-0.0.1a4/rust/Cargo.toml +3 -0
- agent_assembly-0.0.1a4/rust/aa-ffi-python/Cargo.toml +21 -0
- agent_assembly-0.0.1a4/rust/aa-ffi-python/src/lib.rs +719 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025 Bryant Liu
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-assembly
|
|
3
|
+
Version: 0.0.1a4
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
7
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Dist: pydantic>=2.0.0,<3.0.0
|
|
15
|
+
Requires-Dist: httpx>=0.27.0,<1.0.0
|
|
16
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
17
|
+
Requires-Dist: grpcio>=1.66,<2
|
|
18
|
+
Requires-Dist: protobuf>=5,<8
|
|
19
|
+
Requires-Dist: agent-assembly[runtime] ; extra == 'all'
|
|
20
|
+
Provides-Extra: all
|
|
21
|
+
Provides-Extra: runtime
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Summary: Python SDK for AI Agent Assembly - A governance-native runtime for AI agents
|
|
24
|
+
Keywords: ai-agent,governance,mcp,assembly,runtime,policy
|
|
25
|
+
Author-email: Agent Assembly Team <team@agent-assembly.dev>
|
|
26
|
+
Requires-Python: >=3.12, <4.0
|
|
27
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
28
|
+
Project-URL: Homepage, https://github.com/agent-assembly/python-sdk
|
|
29
|
+
Project-URL: Repository, https://github.com/agent-assembly/python-sdk
|
|
30
|
+
|
|
31
|
+
# Agent Assembly Python SDK
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/agent-assembly/)
|
|
34
|
+
[](https://pypi.org/project/agent-assembly/)
|
|
35
|
+
[](https://github.com/AI-agent-assembly/python-sdk/actions/workflows/ci.yaml)
|
|
36
|
+
[](./LICENSE)
|
|
37
|
+
|
|
38
|
+
Python SDK for **AI Agent Assembly** — a governance-native runtime for AI agents. One `init_assembly()` call wires your agent into the policy gateway, applies pre-execution allow/deny on tool calls, and emits audit events without changing how the agent itself is written.
|
|
39
|
+
|
|
40
|
+
## Why use it
|
|
41
|
+
|
|
42
|
+
- **Framework adapters** for LangChain, LangGraph, CrewAI, OpenAI Agents, Pydantic AI, and MCP servers — drop in, no SDK rewrites required.
|
|
43
|
+
- **Pre-execution policy enforcement** via the `FrameworkAdapter` ABC — block disallowed tool calls before they hit the LLM.
|
|
44
|
+
- **Audit trail** — every tool call, prompt, and policy decision is emitted to the gateway with full agent lineage (parent / root / team).
|
|
45
|
+
- **Native PyO3 fast path** (optional) — drop into a Rust runtime client when you need sub-millisecond policy checks.
|
|
46
|
+
- **Typed throughout** — Pydantic models for every gateway payload, mypy strict on adapter base and registry.
|
|
47
|
+
|
|
48
|
+
## Requirements
|
|
49
|
+
|
|
50
|
+
- **Python** `>=3.12,<4.0` (3.12, 3.13, 3.14 are tested in CI)
|
|
51
|
+
- **Rust toolchain** (stable channel) — only required for building the optional native extension via `maturin develop`. Pure-Python users do not need Rust.
|
|
52
|
+
- **uv** ≥ 0.4 — recommended for managing the dev environment. (`pip` works for plain installs.)
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
### Use the SDK in your project
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install agent-assembly
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
(Once published to PyPI. Until then, install directly from GitHub:)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install git+https://github.com/AI-agent-assembly/python-sdk.git
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Develop on the SDK
|
|
69
|
+
|
|
70
|
+
Clone the repo and sync the dev environment with `uv`:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/AI-agent-assembly/python-sdk.git
|
|
74
|
+
cd python-sdk
|
|
75
|
+
uv sync
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
To build the optional PyO3 extension locally (requires Rust):
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
uv tool run maturin develop --manifest-path rust/aa-ffi-python/Cargo.toml --release
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The pure-Python SDK works without the native extension — `maturin develop` is only needed if you want the sub-millisecond `RuntimeClient` fast path.
|
|
85
|
+
|
|
86
|
+
## Quick Start
|
|
87
|
+
|
|
88
|
+
A governed LangChain ReAct agent that runs offline against a mock LLM. The example imports LangChain in addition to the SDK, so install both:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install agent-assembly langchain langchain-community
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from langchain.agents import AgentExecutor, create_react_agent
|
|
96
|
+
from langchain.tools import Tool
|
|
97
|
+
from langchain_community.llms import FakeListLLM
|
|
98
|
+
from langchain_core.prompts import PromptTemplate
|
|
99
|
+
|
|
100
|
+
from agent_assembly import init_assembly
|
|
101
|
+
|
|
102
|
+
with init_assembly(
|
|
103
|
+
gateway_url="http://localhost:8080",
|
|
104
|
+
api_key="dev-key",
|
|
105
|
+
agent_id="quickstart-agent",
|
|
106
|
+
mode="sdk-only",
|
|
107
|
+
):
|
|
108
|
+
llm = FakeListLLM(responses=[
|
|
109
|
+
"Thought: I should look up the user.\nAction: whoami\nAction Input: alice\n",
|
|
110
|
+
"Thought: I have the answer.\nFinal Answer: alice is in engineering\n",
|
|
111
|
+
])
|
|
112
|
+
tools = [Tool(name="whoami", func=lambda name: f"{name} is in engineering", description="who")]
|
|
113
|
+
prompt = PromptTemplate.from_template(
|
|
114
|
+
"Use the tools.\n{tools}\nTool names: {tool_names}\nQ: {input}\n{agent_scratchpad}"
|
|
115
|
+
)
|
|
116
|
+
executor = AgentExecutor(agent=create_react_agent(llm, tools, prompt), tools=tools, max_iterations=2)
|
|
117
|
+
print(executor.invoke({"input": "Which team is alice on?"})["output"])
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
What this does:
|
|
121
|
+
|
|
122
|
+
1. `init_assembly()` registers the agent with the gateway and auto-loads the LangChain adapter — every tool call from now on goes through the policy gate.
|
|
123
|
+
2. The `FakeListLLM` replays canned responses so the example runs **offline** with no real LLM.
|
|
124
|
+
3. The `with` block tears down the gateway connection and unwinds adapter hooks on exit.
|
|
125
|
+
|
|
126
|
+
## Public API
|
|
127
|
+
|
|
128
|
+
- `init_assembly(gateway_url, api_key, agent_id=None, mode="auto") -> AssemblyContext`
|
|
129
|
+
- `GatewayClient.register_agent() -> dict`
|
|
130
|
+
- `GatewayClient.check_policy_compliance(action: str) -> dict`
|
|
131
|
+
- Exceptions: `AssemblyError`, `AgentError`, `PolicyError`, `GatewayError`, `ConfigurationError`
|
|
132
|
+
- Data models: `AgentConfig`, `AgentState`, `PolicyEvaluation`
|
|
133
|
+
|
|
134
|
+
## Error Handling
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from agent_assembly import init_assembly
|
|
138
|
+
from agent_assembly.exceptions import ConfigurationError
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
context = init_assembly(gateway_url="", api_key="my-api-key", agent_id="my-agent-001")
|
|
142
|
+
except ConfigurationError as exc:
|
|
143
|
+
print(f"Invalid configuration: {exc}")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Development
|
|
147
|
+
|
|
148
|
+
Run tests:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
uv run pytest
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Run integration tests:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
uv run pytest -m integration
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Lint and type-check:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
uv run ruff check .
|
|
164
|
+
uv run mypy agent_assembly
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Native Core Extension (AAASM-55)
|
|
168
|
+
|
|
169
|
+
Build and install the PyO3 extension locally:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
uv tool run maturin develop --manifest-path rust/aa-ffi-python/Cargo.toml --release
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Validate native module import:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from agent_assembly._core import RuntimeClient, GovernanceEvent, PolicyResult
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Run opt-in native integration tests:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
AAASM_RUN_NATIVE_CORE_TESTS=1 uv run pytest test/integration/test_native_core_runtime.py
|
|
185
|
+
AAASM_RUN_MATURIN_TESTS=1 uv run pytest test/integration/test_native_core_maturin.py
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Documentation
|
|
189
|
+
|
|
190
|
+
- **Project docs (rendered)** — https://ai-agent-assembly.github.io/python-sdk/ *(versioned via `mike`; pick `latest` or `stable` from the version selector)*
|
|
191
|
+
- **Architecture** — [rendered](https://ai-agent-assembly.github.io/python-sdk/latest/architecture/) / [source](./docs/architecture/index.md) — adapter pattern, PyO3 FFI, `init_assembly()` lifecycle, with a Mermaid flow diagram.
|
|
192
|
+
- **API reference** — [rendered](https://ai-agent-assembly.github.io/python-sdk/latest/api-reference/) / [source](./docs/api-reference/index.md) — auto-generated from package docstrings via `mkdocstrings`. Per-module pages: [Client](./docs/api-reference/client.md), [Exceptions](./docs/api-reference/exceptions.md), [Models](./docs/api-reference/models.md).
|
|
193
|
+
- **ADRs** — [`docs/development/adr/`](./docs/development/adr/) (architecture decision records)
|
|
194
|
+
|
|
195
|
+
## Contributing
|
|
196
|
+
|
|
197
|
+
Please read [**CONTRIBUTING.md**](./CONTRIBUTING.md) before opening a PR — it covers dev environment setup, framework adapter authoring, the test/lint command list, branch naming, and the PR checklist.
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
[MIT License](./LICENSE)
|
|
202
|
+
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Agent Assembly Python SDK
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/agent-assembly/)
|
|
4
|
+
[](https://pypi.org/project/agent-assembly/)
|
|
5
|
+
[](https://github.com/AI-agent-assembly/python-sdk/actions/workflows/ci.yaml)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
Python SDK for **AI Agent Assembly** — a governance-native runtime for AI agents. One `init_assembly()` call wires your agent into the policy gateway, applies pre-execution allow/deny on tool calls, and emits audit events without changing how the agent itself is written.
|
|
9
|
+
|
|
10
|
+
## Why use it
|
|
11
|
+
|
|
12
|
+
- **Framework adapters** for LangChain, LangGraph, CrewAI, OpenAI Agents, Pydantic AI, and MCP servers — drop in, no SDK rewrites required.
|
|
13
|
+
- **Pre-execution policy enforcement** via the `FrameworkAdapter` ABC — block disallowed tool calls before they hit the LLM.
|
|
14
|
+
- **Audit trail** — every tool call, prompt, and policy decision is emitted to the gateway with full agent lineage (parent / root / team).
|
|
15
|
+
- **Native PyO3 fast path** (optional) — drop into a Rust runtime client when you need sub-millisecond policy checks.
|
|
16
|
+
- **Typed throughout** — Pydantic models for every gateway payload, mypy strict on adapter base and registry.
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- **Python** `>=3.12,<4.0` (3.12, 3.13, 3.14 are tested in CI)
|
|
21
|
+
- **Rust toolchain** (stable channel) — only required for building the optional native extension via `maturin develop`. Pure-Python users do not need Rust.
|
|
22
|
+
- **uv** ≥ 0.4 — recommended for managing the dev environment. (`pip` works for plain installs.)
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### Use the SDK in your project
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install agent-assembly
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
(Once published to PyPI. Until then, install directly from GitHub:)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install git+https://github.com/AI-agent-assembly/python-sdk.git
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Develop on the SDK
|
|
39
|
+
|
|
40
|
+
Clone the repo and sync the dev environment with `uv`:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/AI-agent-assembly/python-sdk.git
|
|
44
|
+
cd python-sdk
|
|
45
|
+
uv sync
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
To build the optional PyO3 extension locally (requires Rust):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv tool run maturin develop --manifest-path rust/aa-ffi-python/Cargo.toml --release
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The pure-Python SDK works without the native extension — `maturin develop` is only needed if you want the sub-millisecond `RuntimeClient` fast path.
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
A governed LangChain ReAct agent that runs offline against a mock LLM. The example imports LangChain in addition to the SDK, so install both:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install agent-assembly langchain langchain-community
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from langchain.agents import AgentExecutor, create_react_agent
|
|
66
|
+
from langchain.tools import Tool
|
|
67
|
+
from langchain_community.llms import FakeListLLM
|
|
68
|
+
from langchain_core.prompts import PromptTemplate
|
|
69
|
+
|
|
70
|
+
from agent_assembly import init_assembly
|
|
71
|
+
|
|
72
|
+
with init_assembly(
|
|
73
|
+
gateway_url="http://localhost:8080",
|
|
74
|
+
api_key="dev-key",
|
|
75
|
+
agent_id="quickstart-agent",
|
|
76
|
+
mode="sdk-only",
|
|
77
|
+
):
|
|
78
|
+
llm = FakeListLLM(responses=[
|
|
79
|
+
"Thought: I should look up the user.\nAction: whoami\nAction Input: alice\n",
|
|
80
|
+
"Thought: I have the answer.\nFinal Answer: alice is in engineering\n",
|
|
81
|
+
])
|
|
82
|
+
tools = [Tool(name="whoami", func=lambda name: f"{name} is in engineering", description="who")]
|
|
83
|
+
prompt = PromptTemplate.from_template(
|
|
84
|
+
"Use the tools.\n{tools}\nTool names: {tool_names}\nQ: {input}\n{agent_scratchpad}"
|
|
85
|
+
)
|
|
86
|
+
executor = AgentExecutor(agent=create_react_agent(llm, tools, prompt), tools=tools, max_iterations=2)
|
|
87
|
+
print(executor.invoke({"input": "Which team is alice on?"})["output"])
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
What this does:
|
|
91
|
+
|
|
92
|
+
1. `init_assembly()` registers the agent with the gateway and auto-loads the LangChain adapter — every tool call from now on goes through the policy gate.
|
|
93
|
+
2. The `FakeListLLM` replays canned responses so the example runs **offline** with no real LLM.
|
|
94
|
+
3. The `with` block tears down the gateway connection and unwinds adapter hooks on exit.
|
|
95
|
+
|
|
96
|
+
## Public API
|
|
97
|
+
|
|
98
|
+
- `init_assembly(gateway_url, api_key, agent_id=None, mode="auto") -> AssemblyContext`
|
|
99
|
+
- `GatewayClient.register_agent() -> dict`
|
|
100
|
+
- `GatewayClient.check_policy_compliance(action: str) -> dict`
|
|
101
|
+
- Exceptions: `AssemblyError`, `AgentError`, `PolicyError`, `GatewayError`, `ConfigurationError`
|
|
102
|
+
- Data models: `AgentConfig`, `AgentState`, `PolicyEvaluation`
|
|
103
|
+
|
|
104
|
+
## Error Handling
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from agent_assembly import init_assembly
|
|
108
|
+
from agent_assembly.exceptions import ConfigurationError
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
context = init_assembly(gateway_url="", api_key="my-api-key", agent_id="my-agent-001")
|
|
112
|
+
except ConfigurationError as exc:
|
|
113
|
+
print(f"Invalid configuration: {exc}")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Development
|
|
117
|
+
|
|
118
|
+
Run tests:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv run pytest
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Run integration tests:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
uv run pytest -m integration
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Lint and type-check:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
uv run ruff check .
|
|
134
|
+
uv run mypy agent_assembly
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Native Core Extension (AAASM-55)
|
|
138
|
+
|
|
139
|
+
Build and install the PyO3 extension locally:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
uv tool run maturin develop --manifest-path rust/aa-ffi-python/Cargo.toml --release
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Validate native module import:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from agent_assembly._core import RuntimeClient, GovernanceEvent, PolicyResult
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Run opt-in native integration tests:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
AAASM_RUN_NATIVE_CORE_TESTS=1 uv run pytest test/integration/test_native_core_runtime.py
|
|
155
|
+
AAASM_RUN_MATURIN_TESTS=1 uv run pytest test/integration/test_native_core_maturin.py
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Documentation
|
|
159
|
+
|
|
160
|
+
- **Project docs (rendered)** — https://ai-agent-assembly.github.io/python-sdk/ *(versioned via `mike`; pick `latest` or `stable` from the version selector)*
|
|
161
|
+
- **Architecture** — [rendered](https://ai-agent-assembly.github.io/python-sdk/latest/architecture/) / [source](./docs/architecture/index.md) — adapter pattern, PyO3 FFI, `init_assembly()` lifecycle, with a Mermaid flow diagram.
|
|
162
|
+
- **API reference** — [rendered](https://ai-agent-assembly.github.io/python-sdk/latest/api-reference/) / [source](./docs/api-reference/index.md) — auto-generated from package docstrings via `mkdocstrings`. Per-module pages: [Client](./docs/api-reference/client.md), [Exceptions](./docs/api-reference/exceptions.md), [Models](./docs/api-reference/models.md).
|
|
163
|
+
- **ADRs** — [`docs/development/adr/`](./docs/development/adr/) (architecture decision records)
|
|
164
|
+
|
|
165
|
+
## Contributing
|
|
166
|
+
|
|
167
|
+
Please read [**CONTRIBUTING.md**](./CONTRIBUTING.md) before opening a PR — it covers dev environment setup, framework adapter authoring, the test/lint command list, branch naming, and the PR checklist.
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
[MIT License](./LICENSE)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Agent Assembly Python SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
import importlib
|
|
7
|
+
import importlib.util
|
|
8
|
+
import sys
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
__version__ = "0.0.1a4"
|
|
12
|
+
|
|
13
|
+
# AAASM-1696: top-level exports are resolved lazily so that lightweight
|
|
14
|
+
# submodules (e.g. `agent_assembly.runtime`, which is stdlib-only) can be
|
|
15
|
+
# imported without dragging in the SDK's third-party dependency surface
|
|
16
|
+
# (`httpx`, `pydantic`, …). See PEP 562.
|
|
17
|
+
_LAZY_EXPORTS: dict[str, str] = {
|
|
18
|
+
"init_assembly": "agent_assembly.core",
|
|
19
|
+
"AssemblyContext": "agent_assembly.core",
|
|
20
|
+
"GovernanceInterceptor": "agent_assembly.adapters",
|
|
21
|
+
"FrameworkAdapter": "agent_assembly.adapters",
|
|
22
|
+
"AssemblyError": "agent_assembly.exceptions",
|
|
23
|
+
"AgentError": "agent_assembly.exceptions",
|
|
24
|
+
"PolicyError": "agent_assembly.exceptions",
|
|
25
|
+
"GatewayError": "agent_assembly.exceptions",
|
|
26
|
+
"ConfigurationError": "agent_assembly.exceptions",
|
|
27
|
+
"AdapterValidationError": "agent_assembly.exceptions",
|
|
28
|
+
"ToolExecutionBlockedError": "agent_assembly.exceptions",
|
|
29
|
+
"MCPToolBlockedError": "agent_assembly.exceptions",
|
|
30
|
+
"AuditEvent": "agent_assembly.types",
|
|
31
|
+
"CallStackNode": "agent_assembly.types",
|
|
32
|
+
"CallStackNodeKind": "agent_assembly.types",
|
|
33
|
+
"GovernanceEvent": "agent_assembly._core",
|
|
34
|
+
"PolicyResult": "agent_assembly._core",
|
|
35
|
+
"PolicyTimeoutError": "agent_assembly._core",
|
|
36
|
+
"RuntimeClient": "agent_assembly._core",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_ALWAYS_EXPORTED: list[str] = [
|
|
40
|
+
"__version__",
|
|
41
|
+
"init_assembly",
|
|
42
|
+
"AssemblyContext",
|
|
43
|
+
"GovernanceInterceptor",
|
|
44
|
+
"FrameworkAdapter",
|
|
45
|
+
"AssemblyError",
|
|
46
|
+
"AgentError",
|
|
47
|
+
"PolicyError",
|
|
48
|
+
"GatewayError",
|
|
49
|
+
"ConfigurationError",
|
|
50
|
+
"AdapterValidationError",
|
|
51
|
+
"ToolExecutionBlockedError",
|
|
52
|
+
"MCPToolBlockedError",
|
|
53
|
+
"AuditEvent",
|
|
54
|
+
"CallStackNode",
|
|
55
|
+
"CallStackNodeKind",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
_OPTIONAL_CORE: list[str] = [
|
|
59
|
+
"RuntimeClient",
|
|
60
|
+
"GovernanceEvent",
|
|
61
|
+
"PolicyResult",
|
|
62
|
+
"PolicyTimeoutError",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _core_available() -> bool:
|
|
67
|
+
if "agent_assembly._core" in sys.modules:
|
|
68
|
+
return True
|
|
69
|
+
try:
|
|
70
|
+
return importlib.util.find_spec("agent_assembly._core") is not None
|
|
71
|
+
except (ModuleNotFoundError, ValueError):
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
__all__: list[str] = list(_ALWAYS_EXPORTED)
|
|
76
|
+
if _core_available():
|
|
77
|
+
__all__.extend(_OPTIONAL_CORE)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def __getattr__(name: str) -> Any:
|
|
81
|
+
module_name = _LAZY_EXPORTS.get(name)
|
|
82
|
+
if module_name is None:
|
|
83
|
+
raise AttributeError(f"module 'agent_assembly' has no attribute {name!r}")
|
|
84
|
+
try:
|
|
85
|
+
module = importlib.import_module(module_name)
|
|
86
|
+
except ImportError:
|
|
87
|
+
if module_name == "agent_assembly._core":
|
|
88
|
+
raise AttributeError(
|
|
89
|
+
f"module 'agent_assembly' has no attribute {name!r}: the native '_core' extension is not built"
|
|
90
|
+
) from None
|
|
91
|
+
raise
|
|
92
|
+
value = getattr(module, name)
|
|
93
|
+
globals()[name] = value
|
|
94
|
+
return value
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def __dir__() -> list[str]:
|
|
98
|
+
return sorted(set(__all__) | set(globals()))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
if TYPE_CHECKING:
|
|
102
|
+
from agent_assembly.adapters import FrameworkAdapter, GovernanceInterceptor
|
|
103
|
+
from agent_assembly.core import AssemblyContext, init_assembly
|
|
104
|
+
from agent_assembly.exceptions import (
|
|
105
|
+
AdapterValidationError,
|
|
106
|
+
AgentError,
|
|
107
|
+
AssemblyError,
|
|
108
|
+
ConfigurationError,
|
|
109
|
+
GatewayError,
|
|
110
|
+
MCPToolBlockedError,
|
|
111
|
+
PolicyError,
|
|
112
|
+
ToolExecutionBlockedError,
|
|
113
|
+
)
|
|
114
|
+
from agent_assembly.types import AuditEvent, CallStackNode, CallStackNodeKind
|
|
115
|
+
|
|
116
|
+
with contextlib.suppress(ImportError):
|
|
117
|
+
from agent_assembly._core import (
|
|
118
|
+
GovernanceEvent,
|
|
119
|
+
PolicyResult,
|
|
120
|
+
PolicyTimeoutError,
|
|
121
|
+
RuntimeClient,
|
|
122
|
+
)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Install-time runtime binary resolution for the agent-assembly Python SDK.
|
|
2
|
+
|
|
3
|
+
This module is the lean, blocking presence check for the ``aasm`` sidecar
|
|
4
|
+
binary. It is intentionally separate from :mod:`agent_assembly.runtime`,
|
|
5
|
+
which manages the full lifecycle (port probe + subprocess spawn). The
|
|
6
|
+
intended use is at import time or at the start of long-running scripts:
|
|
7
|
+
fail fast with a clear install hint when the binary is unavailable, before
|
|
8
|
+
the user discovers it via a subtle subprocess failure deep in the SDK call.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import shutil
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"BINARY_NAME",
|
|
19
|
+
"INSTALL_HINT",
|
|
20
|
+
"WHEEL_BUNDLED_BIN",
|
|
21
|
+
"ensure_runtime",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
BINARY_NAME = "aasm"
|
|
25
|
+
|
|
26
|
+
# Path where the platform-wheel ([runtime] extra) bundles the sidecar binary.
|
|
27
|
+
# Mirrors the location runtime.py's find_aasm_binary() also searches, so
|
|
28
|
+
# both modules observe the same wheel artifact without coordination.
|
|
29
|
+
WHEEL_BUNDLED_BIN = Path(__file__).resolve().parent / "bin" / BINARY_NAME
|
|
30
|
+
|
|
31
|
+
INSTALL_HINT = (
|
|
32
|
+
"agent-assembly runtime binary `aasm` was not found.\n"
|
|
33
|
+
" Install the platform wheel: pip install agent-assembly[runtime]\n"
|
|
34
|
+
" Or install manually: brew install agent-assembly/tap/aasm\n"
|
|
35
|
+
" curl -fsSL https://get.agent-assembly.io | sh"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def ensure_runtime() -> Path:
|
|
40
|
+
"""Return the resolved path to the ``aasm`` sidecar binary.
|
|
41
|
+
|
|
42
|
+
Search order, fast to slow:
|
|
43
|
+
|
|
44
|
+
1. ``$PATH`` (Homebrew tap, ``cargo install``, ``curl`` installer default).
|
|
45
|
+
2. ``agent_assembly/bin/aasm`` bundled by the ``[runtime]`` platform wheel.
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
RuntimeError: when no binary is found on either path. The message
|
|
49
|
+
carries :data:`INSTALL_HINT` with copy-paste install commands.
|
|
50
|
+
"""
|
|
51
|
+
path_hit = shutil.which(BINARY_NAME)
|
|
52
|
+
if path_hit:
|
|
53
|
+
return Path(path_hit)
|
|
54
|
+
if WHEEL_BUNDLED_BIN.is_file() and os.access(WHEEL_BUNDLED_BIN, os.X_OK):
|
|
55
|
+
return WHEEL_BUNDLED_BIN
|
|
56
|
+
raise RuntimeError(INSTALL_HINT)
|