agentnode-sdk 0.3.0__tar.gz → 0.4.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.
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/.env.example +8 -8
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/.gitignore +12 -0
- agentnode_sdk-0.4.1/CHANGELOG.md +40 -0
- agentnode_sdk-0.4.1/PKG-INFO +219 -0
- agentnode_sdk-0.4.1/README.md +196 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/agentnode.lock +23 -23
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/agentnode_sdk/__init__.py +17 -1
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/agentnode_sdk/async_client.py +156 -139
- agentnode_sdk-0.4.1/agentnode_sdk/cli/__init__.py +1 -0
- agentnode_sdk-0.4.1/agentnode_sdk/cli/__main__.py +5 -0
- agentnode_sdk-0.4.1/agentnode_sdk/cli/commands.py +405 -0
- agentnode_sdk-0.4.1/agentnode_sdk/cli/main.py +125 -0
- agentnode_sdk-0.4.1/agentnode_sdk/cli/output.py +48 -0
- agentnode_sdk-0.4.1/agentnode_sdk/cli/setup_wizard.py +128 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/agentnode_sdk/client.py +1021 -706
- agentnode_sdk-0.4.1/agentnode_sdk/compatibility.py +139 -0
- agentnode_sdk-0.4.1/agentnode_sdk/config.py +159 -0
- agentnode_sdk-0.4.1/agentnode_sdk/detect.py +200 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/agentnode_sdk/installer.py +500 -453
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/agentnode_sdk/models.py +39 -0
- agentnode_sdk-0.4.1/agentnode_sdk/policy.py +15 -0
- agentnode_sdk-0.4.1/agentnode_sdk/runner.py +99 -0
- agentnode_sdk-0.4.1/agentnode_sdk/runtime.py +1279 -0
- agentnode_sdk-0.4.1/agentnode_sdk/runtimes/__init__.py +5 -0
- agentnode_sdk-0.4.1/agentnode_sdk/runtimes/mcp_runner.py +270 -0
- agentnode_sdk-0.3.0/agentnode_sdk/runner.py → agentnode_sdk-0.4.1/agentnode_sdk/runtimes/python_runner.py +325 -298
- agentnode_sdk-0.4.1/agentnode_sdk/runtimes/remote_runner.py +25 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/pyproject.toml +37 -34
- agentnode_sdk-0.4.1/scripts/analyze_scores.py +328 -0
- agentnode_sdk-0.4.1/scripts/batch_verify.py +422 -0
- agentnode_sdk-0.4.1/scripts/ci_smoke_test.py +180 -0
- agentnode_sdk-0.4.1/scripts/generate_compatibility_artifacts.py +397 -0
- agentnode_sdk-0.4.1/scripts/verify_toolcalls.py +328 -0
- agentnode_sdk-0.4.1/scripts/weekly_retest.sh +139 -0
- agentnode_sdk-0.4.1/tests/conftest.py +233 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/tests/test_async_client.py +343 -283
- agentnode_sdk-0.4.1/tests/test_auto_upgrade_policy.py +119 -0
- agentnode_sdk-0.4.1/tests/test_cli.py +308 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/tests/test_client.py +187 -152
- agentnode_sdk-0.4.1/tests/test_client_sprint_b.py +159 -0
- agentnode_sdk-0.4.1/tests/test_config.py +222 -0
- agentnode_sdk-0.4.1/tests/test_detect.py +210 -0
- agentnode_sdk-0.4.1/tests/test_detect_and_install.py +170 -0
- agentnode_sdk-0.4.1/tests/test_e2e_runtime.py +1156 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/tests/test_edge_cases.py +442 -442
- agentnode_sdk-0.4.1/tests/test_installer_sprint_b.py +51 -0
- agentnode_sdk-0.4.1/tests/test_provider_matrix.py +967 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/tests/test_runner.py +355 -315
- agentnode_sdk-0.4.1/tests/test_runtime.py +885 -0
- agentnode_sdk-0.4.1/tests/test_smart.py +345 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/tests/test_v02.py +210 -210
- agentnode_sdk-0.3.0/PKG-INFO +0 -93
- agentnode_sdk-0.3.0/README.md +0 -70
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/agentnode_sdk/exceptions.py +0 -0
- {agentnode_sdk-0.3.0 → agentnode_sdk-0.4.1}/tests/__init__.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# AgentNode SDK — Environment Variables (optional)
|
|
2
|
-
# These can be passed to AgentNode() constructor instead.
|
|
3
|
-
|
|
4
|
-
# API endpoint
|
|
5
|
-
AGENTNODE_API_URL=https://api.agentnode.net
|
|
6
|
-
|
|
7
|
-
# API key
|
|
8
|
-
AGENTNODE_API_KEY=ank_your-api-key-here
|
|
1
|
+
# AgentNode SDK — Environment Variables (optional)
|
|
2
|
+
# These can be passed to AgentNode() constructor instead.
|
|
3
|
+
|
|
4
|
+
# API endpoint
|
|
5
|
+
AGENTNODE_API_URL=https://api.agentnode.net
|
|
6
|
+
|
|
7
|
+
# API key
|
|
8
|
+
AGENTNODE_API_KEY=ank_your-api-key-here
|
|
@@ -40,6 +40,9 @@ htmlcov/
|
|
|
40
40
|
*.tar.gz
|
|
41
41
|
*.whl
|
|
42
42
|
|
|
43
|
+
# Test score artifacts
|
|
44
|
+
.artifacts/
|
|
45
|
+
|
|
43
46
|
# Spec documents
|
|
44
47
|
*.docx
|
|
45
48
|
|
|
@@ -65,3 +68,12 @@ packages_dump.json
|
|
|
65
68
|
snapshot_nonowner.txt
|
|
66
69
|
seo/
|
|
67
70
|
backend/scripts/enrichment_*.json
|
|
71
|
+
|
|
72
|
+
# Internal documentation (not for GitHub)
|
|
73
|
+
internal/
|
|
74
|
+
|
|
75
|
+
# Internal ops scripts (crawl, enrichment, import)
|
|
76
|
+
scripts/crawl_*.py
|
|
77
|
+
scripts/enrich_*.py
|
|
78
|
+
scripts/import_candidates.py
|
|
79
|
+
candidates*.json
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.1 — Security & Correctness
|
|
4
|
+
|
|
5
|
+
**Behavioral change:** `run_tool(mode="auto")` now always executes via
|
|
6
|
+
subprocess isolation, regardless of trust level. This makes the
|
|
7
|
+
documented isolation guarantee true by default. `mode="direct"` remains
|
|
8
|
+
available as an explicit opt-in for performance-critical workloads that
|
|
9
|
+
knowingly share in-process globals.
|
|
10
|
+
|
|
11
|
+
**Migration note:** Tools that rely on shared in-process state
|
|
12
|
+
(module-level globals, process-wide singletons) should explicitly pass
|
|
13
|
+
`mode="direct"` going forward.
|
|
14
|
+
|
|
15
|
+
### Fixes
|
|
16
|
+
|
|
17
|
+
- **AsyncAgentNode /v1 base URL** — the async client now appends `/v1` to
|
|
18
|
+
`base_url` when missing, matching `AgentNode` (sync). Previously all
|
|
19
|
+
`AsyncAgentNode` calls hit `/packages/...` and 404ed against
|
|
20
|
+
production. (P0-04)
|
|
21
|
+
- **AgentNodeClient.install()** now POSTs
|
|
22
|
+
`POST /v1/packages/{slug}/install` so the backend tracks the install
|
|
23
|
+
event. Previously installs went untracked. (P0-05)
|
|
24
|
+
- **run_tool(mode="auto") always uses subprocess** — see behavioral
|
|
25
|
+
change above. (P0-06)
|
|
26
|
+
- **Response parsing hardening** — `_handle`/`_request` no longer crash
|
|
27
|
+
on non-dict JSON error bodies or HTML/plain-text 2xx responses; both
|
|
28
|
+
are now surfaced as `AgentNodeError`. (P1-SDK3, P1-SDK4)
|
|
29
|
+
- **run_tool reserved kwargs** — passing the internal `entry` kwarg via
|
|
30
|
+
`**kwargs` now raises `TypeError` instead of silently shadowing the
|
|
31
|
+
dispatcher's forwarding path. (P1-SDK5)
|
|
32
|
+
- **Installer download ceiling** — `download_artifact` now enforces a
|
|
33
|
+
500 MB hard ceiling (`MAX_DOWNLOAD_BYTES`). Declared
|
|
34
|
+
`Content-Length` is checked up front; streamed bytes are checked per
|
|
35
|
+
chunk. Oversized downloads are aborted and the partial file removed.
|
|
36
|
+
(P1-SDK6)
|
|
37
|
+
- **run_tool dispatch logging** — `runner.run_tool` now emits an `INFO`
|
|
38
|
+
log line with the resolved runtime and mode, so callers can confirm
|
|
39
|
+
what mode `auto` actually picked without inspecting the
|
|
40
|
+
`RunToolResult` after the fact. (P1-SDK10)
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentnode-sdk
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Python SDK for AgentNode — the open upgrade and discovery infrastructure for AI agents.
|
|
5
|
+
Project-URL: Homepage, https://agentnode.net
|
|
6
|
+
Project-URL: Repository, https://github.com/agentnode-ai/agentnode
|
|
7
|
+
Project-URL: Documentation, https://agentnode.net/docs
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: agent,agentnode,ai,capabilities,langchain,mcp
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: httpx>=0.25
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
20
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
21
|
+
Requires-Dist: respx; extra == 'dev'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# agentnode-sdk
|
|
25
|
+
|
|
26
|
+
Python SDK for [AgentNode](https://agentnode.net) — the open upgrade and discovery infrastructure for AI agents.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install agentnode-sdk
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start — LLM Agent Runtime
|
|
35
|
+
|
|
36
|
+
Connect any LLM agent to AgentNode in three lines. The Runtime provides tool definitions, system prompt, and a tool-loop engine. Tested across 22 models — works with OpenAI, Anthropic, Gemini, Mistral, DeepSeek, Qwen, Llama, and more.
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
40
|
+
|
|
41
|
+
runtime = AgentNodeRuntime()
|
|
42
|
+
|
|
43
|
+
# Get tools + system prompt for your provider
|
|
44
|
+
bundle = runtime.tool_bundle()
|
|
45
|
+
# → { "tools": [...], "system_prompt": "..." }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### OpenAI
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from openai import OpenAI
|
|
52
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
53
|
+
|
|
54
|
+
runtime = AgentNodeRuntime()
|
|
55
|
+
client = OpenAI()
|
|
56
|
+
|
|
57
|
+
result = runtime.run(
|
|
58
|
+
provider="openai",
|
|
59
|
+
client=client,
|
|
60
|
+
model="gpt-4o",
|
|
61
|
+
messages=[{"role": "user", "content": "Count the words in 'Hello world'"}],
|
|
62
|
+
)
|
|
63
|
+
print(result.content)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Anthropic
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from anthropic import Anthropic
|
|
70
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
71
|
+
|
|
72
|
+
runtime = AgentNodeRuntime()
|
|
73
|
+
client = Anthropic()
|
|
74
|
+
|
|
75
|
+
result = runtime.run(
|
|
76
|
+
provider="anthropic",
|
|
77
|
+
client=client,
|
|
78
|
+
model="claude-sonnet-4-6",
|
|
79
|
+
messages=[{"role": "user", "content": "Search for PDF tools on AgentNode"}],
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Gemini
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from google import genai
|
|
87
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
88
|
+
|
|
89
|
+
runtime = AgentNodeRuntime()
|
|
90
|
+
client = genai.Client()
|
|
91
|
+
|
|
92
|
+
result = runtime.run(
|
|
93
|
+
provider="gemini",
|
|
94
|
+
client=client,
|
|
95
|
+
model="gemini-2.5-flash",
|
|
96
|
+
messages=[{"role": "user", "content": "What AgentNode tools are available?"}],
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### OpenRouter (Mistral, DeepSeek, Qwen, Llama, and more)
|
|
101
|
+
|
|
102
|
+
Use any OpenAI-compatible provider by passing a custom `base_url`:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from openai import OpenAI
|
|
106
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
107
|
+
|
|
108
|
+
runtime = AgentNodeRuntime()
|
|
109
|
+
client = OpenAI(
|
|
110
|
+
api_key="sk-or-...",
|
|
111
|
+
base_url="https://openrouter.ai/api/v1",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
result = runtime.run(
|
|
115
|
+
provider="openai",
|
|
116
|
+
client=client,
|
|
117
|
+
model="mistralai/mistral-large", # or deepseek/deepseek-chat, qwen/qwen-plus, etc.
|
|
118
|
+
messages=[{"role": "user", "content": "Find and install a PDF reader tool"}],
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Generic / Manual Tool Calling
|
|
123
|
+
|
|
124
|
+
For any provider that supports tool calling, use `handle()` to dispatch calls manually:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
runtime = AgentNodeRuntime()
|
|
128
|
+
|
|
129
|
+
# Get tool definitions in your provider's format
|
|
130
|
+
tools = runtime.as_openai_tools() # OpenAI format
|
|
131
|
+
tools = runtime.as_anthropic_tools() # Anthropic format
|
|
132
|
+
tools = runtime.as_gemini_tools() # Gemini format
|
|
133
|
+
tools = runtime.as_generic_tools() # Generic format
|
|
134
|
+
|
|
135
|
+
# When the LLM makes a tool call, dispatch it:
|
|
136
|
+
result = runtime.handle("agentnode_search", {"query": "pdf extraction"})
|
|
137
|
+
# → {"success": true, "result": {"total": 5, "results": [...]}}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Three Surfaces
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
CLI → for humans (search, install, publish)
|
|
144
|
+
SDK / Client → for programmatic access (search, resolve, install, run)
|
|
145
|
+
Runtime → for LLM agents (tool registration, dispatch, auto-loop)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## API Reference
|
|
149
|
+
|
|
150
|
+
### `AgentNodeRuntime`
|
|
151
|
+
|
|
152
|
+
Zero-config LLM agent integration.
|
|
153
|
+
|
|
154
|
+
| Method | Description |
|
|
155
|
+
|--------|-------------|
|
|
156
|
+
| `tool_specs()` | Internal typed tool definitions (`list[ToolSpec]`) |
|
|
157
|
+
| `as_openai_tools()` | Tools in OpenAI function-calling format |
|
|
158
|
+
| `as_anthropic_tools()` | Tools in Anthropic format |
|
|
159
|
+
| `as_generic_tools()` | Tools in generic/baseline format |
|
|
160
|
+
| `system_prompt()` | AgentNode system prompt block (append to yours) |
|
|
161
|
+
| `tool_bundle()` | Combined `{"tools": [...], "system_prompt": "..."}` |
|
|
162
|
+
| `handle(tool_name, arguments)` | Dispatch a tool call. Returns dict. Never throws. |
|
|
163
|
+
| `run(provider, client, messages, model, ...)` | Auto-loop with tool dispatch. Never throws. |
|
|
164
|
+
|
|
165
|
+
**Constructor:**
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
AgentNodeRuntime(
|
|
169
|
+
client=None, # Optional AgentNodeClient
|
|
170
|
+
api_key=None, # Optional API key
|
|
171
|
+
minimum_trust_level="verified", # "verified" | "trusted" | "curated"
|
|
172
|
+
)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**5 Meta-Tools** (automatically registered):
|
|
176
|
+
|
|
177
|
+
| Tool | Description |
|
|
178
|
+
|------|-------------|
|
|
179
|
+
| `agentnode_capabilities` | List installed packages (local, no API call) |
|
|
180
|
+
| `agentnode_search` | Search the registry (max 5 results) |
|
|
181
|
+
| `agentnode_install` | Install a package by slug |
|
|
182
|
+
| `agentnode_run` | Execute an installed tool |
|
|
183
|
+
| `agentnode_acquire` | Search + install in one step |
|
|
184
|
+
|
|
185
|
+
### `AgentNodeClient`
|
|
186
|
+
|
|
187
|
+
The programmatic client with typed return models.
|
|
188
|
+
|
|
189
|
+
| Method | Description |
|
|
190
|
+
|--------|-------------|
|
|
191
|
+
| `search(query, ...)` | Search packages by keyword or capability |
|
|
192
|
+
| `resolve(capabilities, ...)` | Resolve capability gaps to ranked packages |
|
|
193
|
+
| `install(slug, ...)` | Download, verify, and install locally |
|
|
194
|
+
| `resolve_and_install(capabilities, ...)` | Resolve + install in one call |
|
|
195
|
+
| `run_tool(slug, tool_name=, ...)` | Run a tool with trust-aware isolation |
|
|
196
|
+
| `smart_run(fn, ...)` | Wrap logic with auto-detect, install, retry |
|
|
197
|
+
| `detect_and_install(error, ...)` | Detect capability gap and install |
|
|
198
|
+
|
|
199
|
+
### `run_tool()` (standalone)
|
|
200
|
+
|
|
201
|
+
Top-level function for running tools with process isolation.
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from agentnode_sdk import run_tool
|
|
205
|
+
|
|
206
|
+
result = run_tool("pdf-reader-pack", mode="auto", file_path="report.pdf")
|
|
207
|
+
# result.success, result.result, result.error, result.mode_used, result.duration_ms
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Isolation contract.** `mode="auto"` always resolves to `subprocess`,
|
|
211
|
+
regardless of the package's trust level. This makes the isolation
|
|
212
|
+
guarantee true by default. If you need in-process execution (for
|
|
213
|
+
example, to share module-level state with the tool), pass
|
|
214
|
+
`mode="direct"` explicitly — that is an opt-in performance trade-off,
|
|
215
|
+
not a default.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# agentnode-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK for [AgentNode](https://agentnode.net) — the open upgrade and discovery infrastructure for AI agents.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install agentnode-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start — LLM Agent Runtime
|
|
12
|
+
|
|
13
|
+
Connect any LLM agent to AgentNode in three lines. The Runtime provides tool definitions, system prompt, and a tool-loop engine. Tested across 22 models — works with OpenAI, Anthropic, Gemini, Mistral, DeepSeek, Qwen, Llama, and more.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
17
|
+
|
|
18
|
+
runtime = AgentNodeRuntime()
|
|
19
|
+
|
|
20
|
+
# Get tools + system prompt for your provider
|
|
21
|
+
bundle = runtime.tool_bundle()
|
|
22
|
+
# → { "tools": [...], "system_prompt": "..." }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### OpenAI
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from openai import OpenAI
|
|
29
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
30
|
+
|
|
31
|
+
runtime = AgentNodeRuntime()
|
|
32
|
+
client = OpenAI()
|
|
33
|
+
|
|
34
|
+
result = runtime.run(
|
|
35
|
+
provider="openai",
|
|
36
|
+
client=client,
|
|
37
|
+
model="gpt-4o",
|
|
38
|
+
messages=[{"role": "user", "content": "Count the words in 'Hello world'"}],
|
|
39
|
+
)
|
|
40
|
+
print(result.content)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Anthropic
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from anthropic import Anthropic
|
|
47
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
48
|
+
|
|
49
|
+
runtime = AgentNodeRuntime()
|
|
50
|
+
client = Anthropic()
|
|
51
|
+
|
|
52
|
+
result = runtime.run(
|
|
53
|
+
provider="anthropic",
|
|
54
|
+
client=client,
|
|
55
|
+
model="claude-sonnet-4-6",
|
|
56
|
+
messages=[{"role": "user", "content": "Search for PDF tools on AgentNode"}],
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Gemini
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from google import genai
|
|
64
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
65
|
+
|
|
66
|
+
runtime = AgentNodeRuntime()
|
|
67
|
+
client = genai.Client()
|
|
68
|
+
|
|
69
|
+
result = runtime.run(
|
|
70
|
+
provider="gemini",
|
|
71
|
+
client=client,
|
|
72
|
+
model="gemini-2.5-flash",
|
|
73
|
+
messages=[{"role": "user", "content": "What AgentNode tools are available?"}],
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### OpenRouter (Mistral, DeepSeek, Qwen, Llama, and more)
|
|
78
|
+
|
|
79
|
+
Use any OpenAI-compatible provider by passing a custom `base_url`:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from openai import OpenAI
|
|
83
|
+
from agentnode_sdk import AgentNodeRuntime
|
|
84
|
+
|
|
85
|
+
runtime = AgentNodeRuntime()
|
|
86
|
+
client = OpenAI(
|
|
87
|
+
api_key="sk-or-...",
|
|
88
|
+
base_url="https://openrouter.ai/api/v1",
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
result = runtime.run(
|
|
92
|
+
provider="openai",
|
|
93
|
+
client=client,
|
|
94
|
+
model="mistralai/mistral-large", # or deepseek/deepseek-chat, qwen/qwen-plus, etc.
|
|
95
|
+
messages=[{"role": "user", "content": "Find and install a PDF reader tool"}],
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Generic / Manual Tool Calling
|
|
100
|
+
|
|
101
|
+
For any provider that supports tool calling, use `handle()` to dispatch calls manually:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
runtime = AgentNodeRuntime()
|
|
105
|
+
|
|
106
|
+
# Get tool definitions in your provider's format
|
|
107
|
+
tools = runtime.as_openai_tools() # OpenAI format
|
|
108
|
+
tools = runtime.as_anthropic_tools() # Anthropic format
|
|
109
|
+
tools = runtime.as_gemini_tools() # Gemini format
|
|
110
|
+
tools = runtime.as_generic_tools() # Generic format
|
|
111
|
+
|
|
112
|
+
# When the LLM makes a tool call, dispatch it:
|
|
113
|
+
result = runtime.handle("agentnode_search", {"query": "pdf extraction"})
|
|
114
|
+
# → {"success": true, "result": {"total": 5, "results": [...]}}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Three Surfaces
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
CLI → for humans (search, install, publish)
|
|
121
|
+
SDK / Client → for programmatic access (search, resolve, install, run)
|
|
122
|
+
Runtime → for LLM agents (tool registration, dispatch, auto-loop)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## API Reference
|
|
126
|
+
|
|
127
|
+
### `AgentNodeRuntime`
|
|
128
|
+
|
|
129
|
+
Zero-config LLM agent integration.
|
|
130
|
+
|
|
131
|
+
| Method | Description |
|
|
132
|
+
|--------|-------------|
|
|
133
|
+
| `tool_specs()` | Internal typed tool definitions (`list[ToolSpec]`) |
|
|
134
|
+
| `as_openai_tools()` | Tools in OpenAI function-calling format |
|
|
135
|
+
| `as_anthropic_tools()` | Tools in Anthropic format |
|
|
136
|
+
| `as_generic_tools()` | Tools in generic/baseline format |
|
|
137
|
+
| `system_prompt()` | AgentNode system prompt block (append to yours) |
|
|
138
|
+
| `tool_bundle()` | Combined `{"tools": [...], "system_prompt": "..."}` |
|
|
139
|
+
| `handle(tool_name, arguments)` | Dispatch a tool call. Returns dict. Never throws. |
|
|
140
|
+
| `run(provider, client, messages, model, ...)` | Auto-loop with tool dispatch. Never throws. |
|
|
141
|
+
|
|
142
|
+
**Constructor:**
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
AgentNodeRuntime(
|
|
146
|
+
client=None, # Optional AgentNodeClient
|
|
147
|
+
api_key=None, # Optional API key
|
|
148
|
+
minimum_trust_level="verified", # "verified" | "trusted" | "curated"
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**5 Meta-Tools** (automatically registered):
|
|
153
|
+
|
|
154
|
+
| Tool | Description |
|
|
155
|
+
|------|-------------|
|
|
156
|
+
| `agentnode_capabilities` | List installed packages (local, no API call) |
|
|
157
|
+
| `agentnode_search` | Search the registry (max 5 results) |
|
|
158
|
+
| `agentnode_install` | Install a package by slug |
|
|
159
|
+
| `agentnode_run` | Execute an installed tool |
|
|
160
|
+
| `agentnode_acquire` | Search + install in one step |
|
|
161
|
+
|
|
162
|
+
### `AgentNodeClient`
|
|
163
|
+
|
|
164
|
+
The programmatic client with typed return models.
|
|
165
|
+
|
|
166
|
+
| Method | Description |
|
|
167
|
+
|--------|-------------|
|
|
168
|
+
| `search(query, ...)` | Search packages by keyword or capability |
|
|
169
|
+
| `resolve(capabilities, ...)` | Resolve capability gaps to ranked packages |
|
|
170
|
+
| `install(slug, ...)` | Download, verify, and install locally |
|
|
171
|
+
| `resolve_and_install(capabilities, ...)` | Resolve + install in one call |
|
|
172
|
+
| `run_tool(slug, tool_name=, ...)` | Run a tool with trust-aware isolation |
|
|
173
|
+
| `smart_run(fn, ...)` | Wrap logic with auto-detect, install, retry |
|
|
174
|
+
| `detect_and_install(error, ...)` | Detect capability gap and install |
|
|
175
|
+
|
|
176
|
+
### `run_tool()` (standalone)
|
|
177
|
+
|
|
178
|
+
Top-level function for running tools with process isolation.
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from agentnode_sdk import run_tool
|
|
182
|
+
|
|
183
|
+
result = run_tool("pdf-reader-pack", mode="auto", file_path="report.pdf")
|
|
184
|
+
# result.success, result.result, result.error, result.mode_used, result.duration_ms
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Isolation contract.** `mode="auto"` always resolves to `subprocess`,
|
|
188
|
+
regardless of the package's trust level. This makes the isolation
|
|
189
|
+
guarantee true by default. If you need in-process execution (for
|
|
190
|
+
example, to share module-level state with the tool), pass
|
|
191
|
+
`mode="direct"` explicitly — that is an opt-in performance trade-off,
|
|
192
|
+
not a default.
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"lockfile_version": "0.1",
|
|
3
|
-
"updated_at": "2026-03-18T02:18:53.827839+00:00",
|
|
4
|
-
"packages": {
|
|
5
|
-
"word-counter-pack": {
|
|
6
|
-
"version": "1.0.0",
|
|
7
|
-
"package_type": "toolpack",
|
|
8
|
-
"entrypoint": "word_counter_pack.tool",
|
|
9
|
-
"capability_ids": [
|
|
10
|
-
"data_cleaning"
|
|
11
|
-
],
|
|
12
|
-
"tools": [
|
|
13
|
-
{
|
|
14
|
-
"name": "count_words",
|
|
15
|
-
"entrypoint": "word_counter_pack.tool:count_words"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
18
|
-
"artifact_hash": "sha256:445388c86aa2b20c3e748f58b2d221548f1f3f71ff5c715a64cdc80966fab03c",
|
|
19
|
-
"installed_at": "2026-03-18T02:18:53.827396+00:00",
|
|
20
|
-
"source": "sdk"
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"lockfile_version": "0.1",
|
|
3
|
+
"updated_at": "2026-03-18T02:18:53.827839+00:00",
|
|
4
|
+
"packages": {
|
|
5
|
+
"word-counter-pack": {
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"package_type": "toolpack",
|
|
8
|
+
"entrypoint": "word_counter_pack.tool",
|
|
9
|
+
"capability_ids": [
|
|
10
|
+
"data_cleaning"
|
|
11
|
+
],
|
|
12
|
+
"tools": [
|
|
13
|
+
{
|
|
14
|
+
"name": "count_words",
|
|
15
|
+
"entrypoint": "word_counter_pack.tool:count_words"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"artifact_hash": "sha256:445388c86aa2b20c3e748f58b2d221548f1f3f71ff5c715a64cdc80966fab03c",
|
|
19
|
+
"installed_at": "2026-03-18T02:18:53.827396+00:00",
|
|
20
|
+
"source": "sdk"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from agentnode_sdk.async_client import AsyncAgentNode
|
|
4
4
|
from agentnode_sdk.client import AgentNode, AgentNodeClient
|
|
5
|
+
from agentnode_sdk.config import load_config, config_path, installation_behavior_label
|
|
6
|
+
from agentnode_sdk.detect import detect_gap
|
|
5
7
|
from agentnode_sdk.exceptions import (
|
|
6
8
|
AgentNodeError,
|
|
7
9
|
AgentNodeToolError,
|
|
@@ -13,6 +15,8 @@ from agentnode_sdk.exceptions import (
|
|
|
13
15
|
from agentnode_sdk.installer import load_tool
|
|
14
16
|
from agentnode_sdk.models import (
|
|
15
17
|
CanInstallResult,
|
|
18
|
+
DetectAndInstallResult,
|
|
19
|
+
DetectedGap,
|
|
16
20
|
InstallMetadata,
|
|
17
21
|
InstallResult,
|
|
18
22
|
PackageDetail,
|
|
@@ -21,19 +25,26 @@ from agentnode_sdk.models import (
|
|
|
21
25
|
RunToolResult,
|
|
22
26
|
SearchHit,
|
|
23
27
|
SearchResult,
|
|
28
|
+
SmartRunResult,
|
|
24
29
|
)
|
|
30
|
+
from agentnode_sdk.compatibility import recommend_model
|
|
25
31
|
from agentnode_sdk.runner import run_tool
|
|
32
|
+
from agentnode_sdk.runtime import AgentNodeRuntime
|
|
26
33
|
|
|
27
34
|
# Convenience aliases
|
|
28
35
|
Client = AgentNodeClient
|
|
29
36
|
ToolError = AgentNodeToolError
|
|
30
37
|
|
|
31
|
-
__version__ = "0.
|
|
38
|
+
__version__ = "0.4.0"
|
|
32
39
|
__all__ = [
|
|
33
40
|
"AgentNode",
|
|
34
41
|
"AsyncAgentNode",
|
|
35
42
|
"AgentNodeClient",
|
|
36
43
|
"Client",
|
|
44
|
+
"load_config",
|
|
45
|
+
"config_path",
|
|
46
|
+
"installation_behavior_label",
|
|
47
|
+
"detect_gap",
|
|
37
48
|
"load_tool",
|
|
38
49
|
"run_tool",
|
|
39
50
|
"AgentNodeError",
|
|
@@ -52,4 +63,9 @@ __all__ = [
|
|
|
52
63
|
"InstallResult",
|
|
53
64
|
"CanInstallResult",
|
|
54
65
|
"RunToolResult",
|
|
66
|
+
"DetectedGap",
|
|
67
|
+
"DetectAndInstallResult",
|
|
68
|
+
"SmartRunResult",
|
|
69
|
+
"AgentNodeRuntime",
|
|
70
|
+
"recommend_model",
|
|
55
71
|
]
|