agentnode-sdk 0.1.0__tar.gz → 0.2.0__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.
@@ -0,0 +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
@@ -15,10 +15,11 @@ cli/dist/
15
15
  web/.next/
16
16
  web/out/
17
17
 
18
- # Environment
18
+ # Environment & Secrets
19
19
  .env
20
20
  .env.local
21
21
  .env.production
22
+ .pypirc
22
23
 
23
24
  # IDE
24
25
  .idea/
@@ -42,5 +43,25 @@ htmlcov/
42
43
  # Spec documents
43
44
  *.docx
44
45
 
46
+ # Screenshots & temp files
47
+ *.png
48
+ screenshots/
49
+ test-screenshots/
50
+ spec_extracted.txt
51
+ calendar.ics
52
+ events.json
53
+
54
+ # Playwright
55
+ .playwright-mcp/
56
+
45
57
  # Claude Code
46
58
  .claude/
59
+
60
+ # Internal growth / marketing content
61
+ growth/
62
+ backend/.next/
63
+ kwfinder-*.md
64
+ packages_dump.json
65
+ snapshot_nonowner.txt
66
+ seo/
67
+ backend/scripts/enrichment_*.json
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentnode-sdk
3
+ Version: 0.2.0
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
35
+
36
+ ```python
37
+ from agentnode_sdk import AgentNodeClient
38
+ from agentnode_sdk.installer import load_tool
39
+
40
+ client = AgentNodeClient(api_key="ank_...")
41
+
42
+ # Search for packages
43
+ results = client.search("pdf extraction")
44
+ for hit in results.hits:
45
+ print(f"{hit.slug} — {hit.summary}")
46
+
47
+ # Resolve capability gaps
48
+ resolved = client.resolve(
49
+ capabilities=["pdf_extraction"],
50
+ framework="langchain",
51
+ )
52
+
53
+ # v0.2: Load specific tools from multi-tool packs
54
+ describe = load_tool("csv-analyzer-pack", tool_name="describe")
55
+ result = describe({"file_path": "data.csv"})
56
+
57
+ # Single-tool packs — no tool_name needed
58
+ extract = load_tool("pdf-reader-pack")
59
+ pdf = extract({"file_path": "report.pdf"})
60
+ ```
61
+
62
+ ## API Reference
63
+
64
+ ### `AgentNodeClient`
65
+
66
+ The main client with typed return models.
67
+
68
+ | Method | Description |
69
+ |--------|-------------|
70
+ | `search(query, ...)` | Search packages by keyword or capability |
71
+ | `resolve(capabilities, ...)` | Resolve capability gaps to ranked packages |
72
+ | `get_package(slug)` | Get package details |
73
+ | `get_install_metadata(slug)` | Get install info (artifact, permissions, deps) |
74
+ | `download(slug)` | Track download and get artifact URL |
75
+ | `load_tool(slug, tool_name=)` | Load a tool function from an installed pack (v0.2) |
76
+
77
+ ### `AgentNode`
78
+
79
+ Lightweight client returning raw dicts.
80
+
81
+ | Method | Description |
82
+ |--------|-------------|
83
+ | `search(query, ...)` | Search packages |
84
+ | `resolve_upgrade(missing_capability, ...)` | Resolve a single capability gap |
85
+ | `check_policy(package_slug, ...)` | Evaluate security policy |
86
+ | `get_install_metadata(slug)` | Get install metadata |
87
+ | `install(slug)` | Create installation record |
88
+ | `recommend(missing_capabilities)` | Get recommendations |
89
+ | `validate(manifest)` | Validate a package manifest |
90
+
91
+ ## License
92
+
93
+ MIT
@@ -0,0 +1,70 @@
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
12
+
13
+ ```python
14
+ from agentnode_sdk import AgentNodeClient
15
+ from agentnode_sdk.installer import load_tool
16
+
17
+ client = AgentNodeClient(api_key="ank_...")
18
+
19
+ # Search for packages
20
+ results = client.search("pdf extraction")
21
+ for hit in results.hits:
22
+ print(f"{hit.slug} — {hit.summary}")
23
+
24
+ # Resolve capability gaps
25
+ resolved = client.resolve(
26
+ capabilities=["pdf_extraction"],
27
+ framework="langchain",
28
+ )
29
+
30
+ # v0.2: Load specific tools from multi-tool packs
31
+ describe = load_tool("csv-analyzer-pack", tool_name="describe")
32
+ result = describe({"file_path": "data.csv"})
33
+
34
+ # Single-tool packs — no tool_name needed
35
+ extract = load_tool("pdf-reader-pack")
36
+ pdf = extract({"file_path": "report.pdf"})
37
+ ```
38
+
39
+ ## API Reference
40
+
41
+ ### `AgentNodeClient`
42
+
43
+ The main client with typed return models.
44
+
45
+ | Method | Description |
46
+ |--------|-------------|
47
+ | `search(query, ...)` | Search packages by keyword or capability |
48
+ | `resolve(capabilities, ...)` | Resolve capability gaps to ranked packages |
49
+ | `get_package(slug)` | Get package details |
50
+ | `get_install_metadata(slug)` | Get install info (artifact, permissions, deps) |
51
+ | `download(slug)` | Track download and get artifact URL |
52
+ | `load_tool(slug, tool_name=)` | Load a tool function from an installed pack (v0.2) |
53
+
54
+ ### `AgentNode`
55
+
56
+ Lightweight client returning raw dicts.
57
+
58
+ | Method | Description |
59
+ |--------|-------------|
60
+ | `search(query, ...)` | Search packages |
61
+ | `resolve_upgrade(missing_capability, ...)` | Resolve a single capability gap |
62
+ | `check_policy(package_slug, ...)` | Evaluate security policy |
63
+ | `get_install_metadata(slug)` | Get install metadata |
64
+ | `install(slug)` | Create installation record |
65
+ | `recommend(missing_capabilities)` | Get recommendations |
66
+ | `validate(manifest)` | Validate a package manifest |
67
+
68
+ ## License
69
+
70
+ MIT
@@ -0,0 +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,14 +1,20 @@
1
1
  """AgentNode Python SDK — discover, resolve, and install AI agent capabilities."""
2
2
 
3
+ from agentnode_sdk.async_client import AsyncAgentNode
3
4
  from agentnode_sdk.client import AgentNode, AgentNodeClient
4
5
  from agentnode_sdk.exceptions import (
5
6
  AgentNodeError,
7
+ AgentNodeToolError,
6
8
  AuthError,
7
9
  NotFoundError,
10
+ RateLimitError,
8
11
  ValidationError,
9
12
  )
13
+ from agentnode_sdk.installer import load_tool
10
14
  from agentnode_sdk.models import (
15
+ CanInstallResult,
11
16
  InstallMetadata,
17
+ InstallResult,
12
18
  PackageDetail,
13
19
  ResolvedPackage,
14
20
  ResolveResult,
@@ -16,13 +22,23 @@ from agentnode_sdk.models import (
16
22
  SearchResult,
17
23
  )
18
24
 
19
- __version__ = "0.1.0"
25
+ # Convenience aliases
26
+ Client = AgentNodeClient
27
+ ToolError = AgentNodeToolError
28
+
29
+ __version__ = "0.2.0"
20
30
  __all__ = [
21
31
  "AgentNode",
32
+ "AsyncAgentNode",
22
33
  "AgentNodeClient",
34
+ "Client",
35
+ "load_tool",
23
36
  "AgentNodeError",
37
+ "AgentNodeToolError",
38
+ "ToolError",
24
39
  "NotFoundError",
25
40
  "AuthError",
41
+ "RateLimitError",
26
42
  "ValidationError",
27
43
  "PackageDetail",
28
44
  "SearchResult",
@@ -30,4 +46,6 @@ __all__ = [
30
46
  "ResolveResult",
31
47
  "ResolvedPackage",
32
48
  "InstallMetadata",
49
+ "InstallResult",
50
+ "CanInstallResult",
33
51
  ]
@@ -0,0 +1,139 @@
1
+ """Async AgentNode API client. Mirrors AgentNode (sync) using httpx.AsyncClient."""
2
+ from __future__ import annotations
3
+
4
+ import httpx
5
+
6
+ from agentnode_sdk.client import DEFAULT_BASE_URL, ERROR_CLASS_MAP
7
+ from agentnode_sdk.exceptions import AgentNodeError
8
+
9
+
10
+ class AsyncAgentNode:
11
+ """Async variant of the AgentNode SDK client. Returns plain dicts."""
12
+
13
+ def __init__(self, api_key: str, base_url: str = DEFAULT_BASE_URL):
14
+ self._client = httpx.AsyncClient(
15
+ base_url=base_url.rstrip("/"),
16
+ headers={"X-API-Key": api_key},
17
+ timeout=30,
18
+ )
19
+
20
+ async def close(self):
21
+ await self._client.aclose()
22
+
23
+ async def __aenter__(self):
24
+ return self
25
+
26
+ async def __aexit__(self, *args):
27
+ await self.close()
28
+
29
+ # --- Public API ---
30
+
31
+ async def search(
32
+ self,
33
+ query: str = "",
34
+ capability_id: str = "",
35
+ framework: str = "",
36
+ sort_by: str = "relevance",
37
+ page: int = 1,
38
+ ) -> dict:
39
+ body = {k: v for k, v in {
40
+ "q": query,
41
+ "capability_id": capability_id,
42
+ "framework": framework,
43
+ "sort_by": sort_by,
44
+ "page": page,
45
+ }.items() if v}
46
+ return self._handle(await self._client.post("/search", json=body))
47
+
48
+ async def resolve_upgrade(
49
+ self,
50
+ missing_capability: str,
51
+ framework: str = "",
52
+ runtime: str = "",
53
+ current_capabilities: list[str] | None = None,
54
+ policy: dict | None = None,
55
+ ) -> dict:
56
+ return await self._post(
57
+ "/resolve-upgrade",
58
+ missing_capability=missing_capability,
59
+ current_capabilities=current_capabilities or [],
60
+ framework=framework,
61
+ runtime=runtime,
62
+ policy=policy or {},
63
+ )
64
+
65
+ async def check_policy(
66
+ self,
67
+ package_slug: str,
68
+ framework: str = "",
69
+ policy: dict | None = None,
70
+ ) -> dict:
71
+ return await self._post(
72
+ "/check-policy",
73
+ package_slug=package_slug,
74
+ framework=framework,
75
+ policy=policy or {},
76
+ )
77
+
78
+ async def get_install_metadata(self, package_slug: str, version: str = "") -> dict:
79
+ """Read-only install metadata. Does NOT create installation records."""
80
+ params = {"version": version} if version else {}
81
+ return self._handle(
82
+ await self._client.get(f"/packages/{package_slug}/install-info", params=params)
83
+ )
84
+
85
+ async def get_package(self, slug: str) -> dict:
86
+ return self._handle(await self._client.get(f"/packages/{slug}"))
87
+
88
+ async def validate(self, manifest: dict) -> dict:
89
+ return self._handle(
90
+ await self._client.post("/packages/validate", json={"manifest": manifest})
91
+ )
92
+
93
+ async def install(
94
+ self,
95
+ package_slug: str,
96
+ version: str = "",
97
+ source: str = "sdk",
98
+ event_type: str = "install",
99
+ ) -> dict:
100
+ """Create installation record and get artifact URL."""
101
+ body: dict = {"source": source, "event_type": event_type}
102
+ if version:
103
+ body["version"] = version
104
+ return self._handle(
105
+ await self._client.post(f"/packages/{package_slug}/install", json=body)
106
+ )
107
+
108
+ async def recommend(
109
+ self,
110
+ missing_capabilities: list[str],
111
+ framework: str = "",
112
+ runtime: str = "",
113
+ ) -> dict:
114
+ return await self._post(
115
+ "/recommend",
116
+ missing_capabilities=missing_capabilities,
117
+ framework=framework,
118
+ runtime=runtime,
119
+ )
120
+
121
+ # --- Internal ---
122
+
123
+ async def _post(self, path: str, **kwargs) -> dict:
124
+ body = {k: v for k, v in kwargs.items() if v is not None and v != ""}
125
+ return self._handle(await self._client.post(path, json=body))
126
+
127
+ def _handle(self, response: httpx.Response) -> dict:
128
+ """Parse response. Raise typed AgentNodeError on API errors."""
129
+ if response.status_code >= 400:
130
+ try:
131
+ body = response.json()
132
+ err = body.get("error", {})
133
+ code = err.get("code", "UNKNOWN")
134
+ message = err.get("message", response.text)
135
+ except (ValueError, KeyError):
136
+ code, message = "UNKNOWN", response.text
137
+ exc_class = ERROR_CLASS_MAP.get(response.status_code, AgentNodeError)
138
+ raise exc_class(code, message)
139
+ return response.json()