zambo-llamaindex 0.1.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.
- zambo_llamaindex-0.1.0/LICENSE +21 -0
- zambo_llamaindex-0.1.0/PKG-INFO +92 -0
- zambo_llamaindex-0.1.0/README.md +68 -0
- zambo_llamaindex-0.1.0/pyproject.toml +35 -0
- zambo_llamaindex-0.1.0/setup.cfg +4 -0
- zambo_llamaindex-0.1.0/src/zambo_llamaindex/__init__.py +21 -0
- zambo_llamaindex-0.1.0/src/zambo_llamaindex/client.py +109 -0
- zambo_llamaindex-0.1.0/src/zambo_llamaindex/tools.py +117 -0
- zambo_llamaindex-0.1.0/src/zambo_llamaindex.egg-info/PKG-INFO +92 -0
- zambo_llamaindex-0.1.0/src/zambo_llamaindex.egg-info/SOURCES.txt +11 -0
- zambo_llamaindex-0.1.0/src/zambo_llamaindex.egg-info/dependency_links.txt +1 -0
- zambo_llamaindex-0.1.0/src/zambo_llamaindex.egg-info/requires.txt +1 -0
- zambo_llamaindex-0.1.0/src/zambo_llamaindex.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zambo (zambo.dev)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zambo-llamaindex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Zambo's 100+ live tools as LlamaIndex FunctionTools. Every call mints a verifiable AER-1 execution receipt.
|
|
5
|
+
Author-email: Zambo <brennanzambo@zambo.dev>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zambo.dev
|
|
8
|
+
Project-URL: Documentation, https://zambo.dev/aer-1/
|
|
9
|
+
Project-URL: Repository, https://zambo.dev
|
|
10
|
+
Keywords: llamaindex,llama-index,agents,ai-agents,zambo,mcp,receipts,verification
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: llama-index-core>=0.10
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# zambo-llamaindex
|
|
26
|
+
|
|
27
|
+
Give your LlamaIndex agent Zambo's 100+ live tools. Every tool call is executed by Zambo and mints a **verifiable AER-1 receipt**: a public URL carrying the tool, its arguments, the observed result, a SHA-256 fingerprint, and machine-readable JSON-LD.
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from llama_index.core.agent.workflow import FunctionAgent
|
|
31
|
+
from zambo_llamaindex import zambo_tools
|
|
32
|
+
|
|
33
|
+
agent = FunctionAgent(
|
|
34
|
+
name="Zambo assistant",
|
|
35
|
+
description="Assistant with live Zambo tools.",
|
|
36
|
+
tools=zambo_tools(["live_price", "prompt_shield"]),
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Each `zambo_tool(name)` returns a real `llama_index.core.tools.FunctionTool`. Attach one or a batch to any LlamaIndex agent that accepts tools.
|
|
41
|
+
|
|
42
|
+
No account. No API key. Free tier: 20 calls per tool per day.
|
|
43
|
+
|
|
44
|
+
## What the receipt actually proves
|
|
45
|
+
|
|
46
|
+
Each receipt page (for example `https://zambo.dev/run/<id>`) is Zambo's tamper-evident record that **Zambo executed the tool call itself**: the tool name, the exact arguments your agent sent, the observed result, a timestamp, and a SHA-256 fingerprint of the record, published as JSON-LD. Anyone can re-verify it with no account.
|
|
47
|
+
|
|
48
|
+
Every tool's output ends with a `Verifiable receipt: <url>` line, so the agent sees the proof next to every call. You can also hook receipts programmatically:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from zambo_llamaindex import zambo_tool
|
|
52
|
+
|
|
53
|
+
def on_receipt(tool_name, receipt_url):
|
|
54
|
+
print(f"[receipt] {tool_name}: {receipt_url}")
|
|
55
|
+
|
|
56
|
+
price_tool = zambo_tool("live_price", on_receipt=on_receipt)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install zambo-llamaindex
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## One tool, custom schema
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from zambo_llamaindex import zambo_tool
|
|
69
|
+
|
|
70
|
+
price_tool = zambo_tool(
|
|
71
|
+
"live_price",
|
|
72
|
+
params_json_schema={
|
|
73
|
+
"type": "object",
|
|
74
|
+
"properties": {"symbol": {"type": "string"}},
|
|
75
|
+
"required": ["symbol"],
|
|
76
|
+
},
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Browse the full catalog any time with `zambo_llamaindex.list_tools()`, or pick tools by use case through Zambo's `capability_search` tool.
|
|
81
|
+
|
|
82
|
+
## Notes
|
|
83
|
+
|
|
84
|
+
- Zambo calls need no key and no signup. Heavy agent runs (dozens of tool calls) will reach the free daily limit; the tool raises a clear error and the run continues with the other tools.
|
|
85
|
+
- Receipts are public by design. Do not pass secrets as tool arguments.
|
|
86
|
+
|
|
87
|
+
## Links
|
|
88
|
+
|
|
89
|
+
- Zambo: https://zambo.dev
|
|
90
|
+
- AER-1 receipt spec: https://zambo.dev/aer-1/
|
|
91
|
+
|
|
92
|
+
MIT License.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# zambo-llamaindex
|
|
2
|
+
|
|
3
|
+
Give your LlamaIndex agent Zambo's 100+ live tools. Every tool call is executed by Zambo and mints a **verifiable AER-1 receipt**: a public URL carrying the tool, its arguments, the observed result, a SHA-256 fingerprint, and machine-readable JSON-LD.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from llama_index.core.agent.workflow import FunctionAgent
|
|
7
|
+
from zambo_llamaindex import zambo_tools
|
|
8
|
+
|
|
9
|
+
agent = FunctionAgent(
|
|
10
|
+
name="Zambo assistant",
|
|
11
|
+
description="Assistant with live Zambo tools.",
|
|
12
|
+
tools=zambo_tools(["live_price", "prompt_shield"]),
|
|
13
|
+
)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Each `zambo_tool(name)` returns a real `llama_index.core.tools.FunctionTool`. Attach one or a batch to any LlamaIndex agent that accepts tools.
|
|
17
|
+
|
|
18
|
+
No account. No API key. Free tier: 20 calls per tool per day.
|
|
19
|
+
|
|
20
|
+
## What the receipt actually proves
|
|
21
|
+
|
|
22
|
+
Each receipt page (for example `https://zambo.dev/run/<id>`) is Zambo's tamper-evident record that **Zambo executed the tool call itself**: the tool name, the exact arguments your agent sent, the observed result, a timestamp, and a SHA-256 fingerprint of the record, published as JSON-LD. Anyone can re-verify it with no account.
|
|
23
|
+
|
|
24
|
+
Every tool's output ends with a `Verifiable receipt: <url>` line, so the agent sees the proof next to every call. You can also hook receipts programmatically:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from zambo_llamaindex import zambo_tool
|
|
28
|
+
|
|
29
|
+
def on_receipt(tool_name, receipt_url):
|
|
30
|
+
print(f"[receipt] {tool_name}: {receipt_url}")
|
|
31
|
+
|
|
32
|
+
price_tool = zambo_tool("live_price", on_receipt=on_receipt)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install zambo-llamaindex
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## One tool, custom schema
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from zambo_llamaindex import zambo_tool
|
|
45
|
+
|
|
46
|
+
price_tool = zambo_tool(
|
|
47
|
+
"live_price",
|
|
48
|
+
params_json_schema={
|
|
49
|
+
"type": "object",
|
|
50
|
+
"properties": {"symbol": {"type": "string"}},
|
|
51
|
+
"required": ["symbol"],
|
|
52
|
+
},
|
|
53
|
+
)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Browse the full catalog any time with `zambo_llamaindex.list_tools()`, or pick tools by use case through Zambo's `capability_search` tool.
|
|
57
|
+
|
|
58
|
+
## Notes
|
|
59
|
+
|
|
60
|
+
- Zambo calls need no key and no signup. Heavy agent runs (dozens of tool calls) will reach the free daily limit; the tool raises a clear error and the run continues with the other tools.
|
|
61
|
+
- Receipts are public by design. Do not pass secrets as tool arguments.
|
|
62
|
+
|
|
63
|
+
## Links
|
|
64
|
+
|
|
65
|
+
- Zambo: https://zambo.dev
|
|
66
|
+
- AER-1 receipt spec: https://zambo.dev/aer-1/
|
|
67
|
+
|
|
68
|
+
MIT License.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "zambo-llamaindex"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Zambo's 100+ live tools as LlamaIndex FunctionTools. Every call mints a verifiable AER-1 execution receipt."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Zambo", email = "brennanzambo@zambo.dev" }]
|
|
13
|
+
keywords = ["llamaindex", "llama-index", "agents", "ai-agents", "zambo", "mcp", "receipts", "verification"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"llama-index-core>=0.10",
|
|
26
|
+
]
|
|
27
|
+
optional-dependencies = {}
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://zambo.dev"
|
|
31
|
+
Documentation = "https://zambo.dev/aer-1/"
|
|
32
|
+
Repository = "https://zambo.dev"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
where = ["src"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Zambo's 100+ live tools as LlamaIndex FunctionTools.
|
|
2
|
+
|
|
3
|
+
Every tool call is executed by Zambo (https://zambo.dev/api/mcp) and mints a
|
|
4
|
+
verifiable AER-1 receipt: a public URL carrying the tool, its arguments, the
|
|
5
|
+
observed result, a SHA-256 fingerprint, and machine-readable JSON-LD.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .client import ZamboReceipt, ZamboResult, call_tool, list_tools
|
|
9
|
+
from .tools import lookup_receipt, zambo_tool, zambo_tools
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"zambo_tool",
|
|
13
|
+
"zambo_tools",
|
|
14
|
+
"lookup_receipt",
|
|
15
|
+
"call_tool",
|
|
16
|
+
"list_tools",
|
|
17
|
+
"ZamboReceipt",
|
|
18
|
+
"ZamboResult",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Minimal Zambo MCP client over plain JSON-RPC.
|
|
2
|
+
|
|
3
|
+
Pure stdlib (urllib), no third-party dependencies. Talks to the live
|
|
4
|
+
https://zambo.dev/api/mcp endpoint: no auth, no account, free tier.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import http.client
|
|
11
|
+
import time
|
|
12
|
+
import urllib.error
|
|
13
|
+
import urllib.request
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
|
|
16
|
+
MCP_URL = "https://zambo.dev/api/mcp"
|
|
17
|
+
_TIMEOUT = 60
|
|
18
|
+
_MAX_ATTEMPTS = 6
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class ZamboReceipt:
|
|
23
|
+
"""A verifiable AER-1 execution receipt minted by a Zambo tool call."""
|
|
24
|
+
|
|
25
|
+
id: str
|
|
26
|
+
url: str
|
|
27
|
+
status: str = ""
|
|
28
|
+
tool: str = ""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class ZamboResult:
|
|
33
|
+
text: str
|
|
34
|
+
receipt: ZamboReceipt | None = None
|
|
35
|
+
raw: dict = field(default_factory=dict)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _post(payload: dict) -> dict:
|
|
39
|
+
body = json.dumps(payload).encode("utf-8")
|
|
40
|
+
last_error: Exception | None = None
|
|
41
|
+
for attempt in range(_MAX_ATTEMPTS):
|
|
42
|
+
request = urllib.request.Request(
|
|
43
|
+
MCP_URL,
|
|
44
|
+
data=body,
|
|
45
|
+
headers={"Content-Type": "application/json", "Accept": "application/json"},
|
|
46
|
+
method="POST",
|
|
47
|
+
)
|
|
48
|
+
try:
|
|
49
|
+
with urllib.request.urlopen(request, timeout=_TIMEOUT) as response:
|
|
50
|
+
return json.loads(response.read().decode("utf-8"))
|
|
51
|
+
except (
|
|
52
|
+
urllib.error.URLError,
|
|
53
|
+
ConnectionError,
|
|
54
|
+
TimeoutError,
|
|
55
|
+
json.JSONDecodeError,
|
|
56
|
+
http.client.IncompleteRead,
|
|
57
|
+
http.client.RemoteDisconnected,
|
|
58
|
+
http.client.BadStatusLine,
|
|
59
|
+
) as exc:
|
|
60
|
+
last_error = exc
|
|
61
|
+
time.sleep(1.5 * (attempt + 1))
|
|
62
|
+
raise RuntimeError(f"Zambo API call failed after {_MAX_ATTEMPTS} attempts: {last_error}")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def call_tool(tool_name: str, arguments: dict) -> ZamboResult:
|
|
66
|
+
"""Call a Zambo MCP tool and return its result plus the receipt.
|
|
67
|
+
|
|
68
|
+
Every call mints a verifiable AER-1 receipt: a public URL carrying the
|
|
69
|
+
tool, arguments, observed result, SHA-256 fingerprint, and JSON-LD.
|
|
70
|
+
"""
|
|
71
|
+
response = _post(
|
|
72
|
+
{
|
|
73
|
+
"jsonrpc": "2.0",
|
|
74
|
+
"id": f"zambo-llamaindex-{int(time.time() * 1000)}",
|
|
75
|
+
"method": "tools/call",
|
|
76
|
+
"params": {"name": tool_name, "arguments": arguments},
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
if "error" in response:
|
|
80
|
+
raise RuntimeError(f"Zambo tool '{tool_name}' error: {response['error']}")
|
|
81
|
+
|
|
82
|
+
result = response.get("result", {})
|
|
83
|
+
receipt_data = result.get("_receipt", {}) or {}
|
|
84
|
+
|
|
85
|
+
receipt = None
|
|
86
|
+
receipt_id = receipt_data.get("id")
|
|
87
|
+
if receipt_id:
|
|
88
|
+
receipt = ZamboReceipt(
|
|
89
|
+
id=receipt_id,
|
|
90
|
+
url=receipt_data.get("audit") or f"https://zambo.dev/run/{receipt_id}",
|
|
91
|
+
status=receipt_data.get("status", ""),
|
|
92
|
+
tool=receipt_data.get("tool", tool_name),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
text_parts = []
|
|
96
|
+
for item in result.get("content", []) or []:
|
|
97
|
+
if isinstance(item, dict) and "text" in item:
|
|
98
|
+
text_parts.append(str(item["text"]))
|
|
99
|
+
text = "\n".join(text_parts).strip()
|
|
100
|
+
|
|
101
|
+
return ZamboResult(text=text, receipt=receipt, raw=result)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def list_tools() -> list[dict]:
|
|
105
|
+
"""Return the live Zambo tool catalog (name + description)."""
|
|
106
|
+
response = _post({"jsonrpc": "2.0", "id": "zambo-tools-list", "method": "tools/list", "params": {}})
|
|
107
|
+
if "error" in response:
|
|
108
|
+
raise RuntimeError(f"Zambo tools/list error: {response['error']}")
|
|
109
|
+
return response.get("result", {}).get("tools", []) or []
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""LlamaIndex FunctionTools backed by live Zambo execution.
|
|
2
|
+
|
|
3
|
+
Each tool below is a real llama_index.core.tools.FunctionTool. When the agent
|
|
4
|
+
invokes it, the call is executed by Zambo (https://zambo.dev/api/mcp) and
|
|
5
|
+
mints a verifiable AER-1 receipt: public URL, tool, arguments, observed
|
|
6
|
+
result, SHA-256 fingerprint, machine-readable JSON-LD.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import threading
|
|
13
|
+
import time
|
|
14
|
+
from typing import Any, Callable
|
|
15
|
+
|
|
16
|
+
from . import client as _client
|
|
17
|
+
|
|
18
|
+
# (tool_name, arguments_json) -> (receipt_url, finished_at). Written by the
|
|
19
|
+
# tool wrapper on every invocation. Thread-safe.
|
|
20
|
+
_invocation_registry: dict[tuple[str, str], tuple[str, float]] = {}
|
|
21
|
+
_registry_lock = threading.Lock()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _record_invocation(tool_name: str, arguments_json: str, receipt_url: str) -> None:
|
|
25
|
+
with _registry_lock:
|
|
26
|
+
_invocation_registry[(tool_name, arguments_json)] = (receipt_url, time.time())
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def lookup_receipt(tool_name: str, arguments_json: str) -> str | None:
|
|
30
|
+
"""Return the most recent receipt URL for a (tool, args) invocation."""
|
|
31
|
+
with _registry_lock:
|
|
32
|
+
entry = _invocation_registry.get((tool_name, arguments_json))
|
|
33
|
+
return entry[0] if entry else None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
_TYPE_MAP = {
|
|
37
|
+
"string": str,
|
|
38
|
+
"number": float,
|
|
39
|
+
"integer": int,
|
|
40
|
+
"boolean": bool,
|
|
41
|
+
"array": list,
|
|
42
|
+
"object": dict,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _json_schema_to_model(tool_name: str, schema: dict):
|
|
47
|
+
"""Build a pydantic model from a simple JSON object schema.
|
|
48
|
+
|
|
49
|
+
Maps property types via _TYPE_MAP; properties listed in `required` have
|
|
50
|
+
no default, all others default to None. Only object-type schemas are
|
|
51
|
+
supported; Zambo validates arguments server-side.
|
|
52
|
+
"""
|
|
53
|
+
from pydantic import create_model
|
|
54
|
+
|
|
55
|
+
properties = schema.get("properties", {}) or {}
|
|
56
|
+
required = set(schema.get("required", []) or [])
|
|
57
|
+
fields: dict = {}
|
|
58
|
+
for prop, spec in properties.items():
|
|
59
|
+
spec = spec if isinstance(spec, dict) else {}
|
|
60
|
+
py_type = _TYPE_MAP.get(spec.get("type", "string"), str)
|
|
61
|
+
if prop in required:
|
|
62
|
+
fields[prop] = (py_type, ...)
|
|
63
|
+
else:
|
|
64
|
+
fields[prop] = (py_type | None, None)
|
|
65
|
+
return create_model(f"{tool_name}_args", **fields) # type: ignore[call-overload]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def zambo_tool(
|
|
69
|
+
tool_name: str,
|
|
70
|
+
description: str | None = None,
|
|
71
|
+
params_json_schema: dict | None = None,
|
|
72
|
+
on_receipt: Callable[[str, str], Any] | None = None,
|
|
73
|
+
):
|
|
74
|
+
"""Build a LlamaIndex FunctionTool backed by a Zambo MCP tool.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
tool_name: Name of the Zambo tool (see client.list_tools(), e.g.
|
|
78
|
+
"live_price", "ghost_audit_site", "prompt_shield").
|
|
79
|
+
description: Override the tool description shown to the model.
|
|
80
|
+
params_json_schema: Override the JSON schema for the tool's arguments.
|
|
81
|
+
Defaults to a permissive object schema; Zambo validates server-side.
|
|
82
|
+
on_receipt: Optional callback invoked as on_receipt(tool_name,
|
|
83
|
+
receipt_url) after every successful invocation.
|
|
84
|
+
"""
|
|
85
|
+
from llama_index.core.tools import FunctionTool # local import: llama-index is a dependency
|
|
86
|
+
|
|
87
|
+
def _invoke(**kwargs: Any) -> str:
|
|
88
|
+
arguments = dict(kwargs)
|
|
89
|
+
result = _client.call_tool(tool_name, arguments)
|
|
90
|
+
|
|
91
|
+
receipt_url = result.receipt.url if result.receipt else ""
|
|
92
|
+
if receipt_url:
|
|
93
|
+
_record_invocation(tool_name, json.dumps(arguments, sort_keys=True), receipt_url)
|
|
94
|
+
if on_receipt is not None:
|
|
95
|
+
on_receipt(tool_name, receipt_url)
|
|
96
|
+
|
|
97
|
+
output = result.text or "(empty result)"
|
|
98
|
+
if receipt_url:
|
|
99
|
+
output += f"\n\nVerifiable receipt: {receipt_url}"
|
|
100
|
+
return output
|
|
101
|
+
|
|
102
|
+
fn_schema = None
|
|
103
|
+
if params_json_schema is not None:
|
|
104
|
+
fn_schema = _json_schema_to_model(tool_name, params_json_schema)
|
|
105
|
+
|
|
106
|
+
return FunctionTool.from_defaults(
|
|
107
|
+
fn=_invoke,
|
|
108
|
+
name=tool_name,
|
|
109
|
+
description=description
|
|
110
|
+
or f"Zambo tool '{tool_name}' (zambo.dev). Every call mints a verifiable execution receipt.",
|
|
111
|
+
fn_schema=fn_schema,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def zambo_tools(tool_names: list[str], **kwargs: Any) -> list:
|
|
116
|
+
"""Build several Zambo-backed FunctionTools at once."""
|
|
117
|
+
return [zambo_tool(name, **kwargs) for name in tool_names]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zambo-llamaindex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Zambo's 100+ live tools as LlamaIndex FunctionTools. Every call mints a verifiable AER-1 execution receipt.
|
|
5
|
+
Author-email: Zambo <brennanzambo@zambo.dev>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zambo.dev
|
|
8
|
+
Project-URL: Documentation, https://zambo.dev/aer-1/
|
|
9
|
+
Project-URL: Repository, https://zambo.dev
|
|
10
|
+
Keywords: llamaindex,llama-index,agents,ai-agents,zambo,mcp,receipts,verification
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: llama-index-core>=0.10
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# zambo-llamaindex
|
|
26
|
+
|
|
27
|
+
Give your LlamaIndex agent Zambo's 100+ live tools. Every tool call is executed by Zambo and mints a **verifiable AER-1 receipt**: a public URL carrying the tool, its arguments, the observed result, a SHA-256 fingerprint, and machine-readable JSON-LD.
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from llama_index.core.agent.workflow import FunctionAgent
|
|
31
|
+
from zambo_llamaindex import zambo_tools
|
|
32
|
+
|
|
33
|
+
agent = FunctionAgent(
|
|
34
|
+
name="Zambo assistant",
|
|
35
|
+
description="Assistant with live Zambo tools.",
|
|
36
|
+
tools=zambo_tools(["live_price", "prompt_shield"]),
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Each `zambo_tool(name)` returns a real `llama_index.core.tools.FunctionTool`. Attach one or a batch to any LlamaIndex agent that accepts tools.
|
|
41
|
+
|
|
42
|
+
No account. No API key. Free tier: 20 calls per tool per day.
|
|
43
|
+
|
|
44
|
+
## What the receipt actually proves
|
|
45
|
+
|
|
46
|
+
Each receipt page (for example `https://zambo.dev/run/<id>`) is Zambo's tamper-evident record that **Zambo executed the tool call itself**: the tool name, the exact arguments your agent sent, the observed result, a timestamp, and a SHA-256 fingerprint of the record, published as JSON-LD. Anyone can re-verify it with no account.
|
|
47
|
+
|
|
48
|
+
Every tool's output ends with a `Verifiable receipt: <url>` line, so the agent sees the proof next to every call. You can also hook receipts programmatically:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from zambo_llamaindex import zambo_tool
|
|
52
|
+
|
|
53
|
+
def on_receipt(tool_name, receipt_url):
|
|
54
|
+
print(f"[receipt] {tool_name}: {receipt_url}")
|
|
55
|
+
|
|
56
|
+
price_tool = zambo_tool("live_price", on_receipt=on_receipt)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install zambo-llamaindex
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## One tool, custom schema
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from zambo_llamaindex import zambo_tool
|
|
69
|
+
|
|
70
|
+
price_tool = zambo_tool(
|
|
71
|
+
"live_price",
|
|
72
|
+
params_json_schema={
|
|
73
|
+
"type": "object",
|
|
74
|
+
"properties": {"symbol": {"type": "string"}},
|
|
75
|
+
"required": ["symbol"],
|
|
76
|
+
},
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Browse the full catalog any time with `zambo_llamaindex.list_tools()`, or pick tools by use case through Zambo's `capability_search` tool.
|
|
81
|
+
|
|
82
|
+
## Notes
|
|
83
|
+
|
|
84
|
+
- Zambo calls need no key and no signup. Heavy agent runs (dozens of tool calls) will reach the free daily limit; the tool raises a clear error and the run continues with the other tools.
|
|
85
|
+
- Receipts are public by design. Do not pass secrets as tool arguments.
|
|
86
|
+
|
|
87
|
+
## Links
|
|
88
|
+
|
|
89
|
+
- Zambo: https://zambo.dev
|
|
90
|
+
- AER-1 receipt spec: https://zambo.dev/aer-1/
|
|
91
|
+
|
|
92
|
+
MIT License.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/zambo_llamaindex/__init__.py
|
|
5
|
+
src/zambo_llamaindex/client.py
|
|
6
|
+
src/zambo_llamaindex/tools.py
|
|
7
|
+
src/zambo_llamaindex.egg-info/PKG-INFO
|
|
8
|
+
src/zambo_llamaindex.egg-info/SOURCES.txt
|
|
9
|
+
src/zambo_llamaindex.egg-info/dependency_links.txt
|
|
10
|
+
src/zambo_llamaindex.egg-info/requires.txt
|
|
11
|
+
src/zambo_llamaindex.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
llama-index-core>=0.10
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
zambo_llamaindex
|