mycelium-sdk 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.
- mycelium_sdk-0.1.0/PKG-INFO +130 -0
- mycelium_sdk-0.1.0/README.md +113 -0
- mycelium_sdk-0.1.0/mycelium_sdk/__init__.py +35 -0
- mycelium_sdk-0.1.0/mycelium_sdk/adapters/__init__.py +23 -0
- mycelium_sdk-0.1.0/mycelium_sdk/adapters/anthropic.py +81 -0
- mycelium_sdk-0.1.0/mycelium_sdk/adapters/gemini.py +59 -0
- mycelium_sdk-0.1.0/mycelium_sdk/adapters/langgraph.py +76 -0
- mycelium_sdk-0.1.0/mycelium_sdk/agent_loop.py +203 -0
- mycelium_sdk-0.1.0/mycelium_sdk/banner.py +62 -0
- mycelium_sdk-0.1.0/mycelium_sdk/constants.py +62 -0
- mycelium_sdk-0.1.0/mycelium_sdk/context.py +419 -0
- mycelium_sdk-0.1.0/mycelium_sdk/contract_client.py +122 -0
- mycelium_sdk-0.1.0/mycelium_sdk/contracts/escrow.wasm +0 -0
- mycelium_sdk-0.1.0/mycelium_sdk/crypto.py +122 -0
- mycelium_sdk-0.1.0/mycelium_sdk/hive.py +256 -0
- mycelium_sdk-0.1.0/mycelium_sdk/logging.py +83 -0
- mycelium_sdk-0.1.0/mycelium_sdk/models.py +145 -0
- mycelium_sdk-0.1.0/mycelium_sdk/rpc.py +115 -0
- mycelium_sdk-0.1.0/mycelium_sdk/scval.py +77 -0
- mycelium_sdk-0.1.0/mycelium_sdk/spec.py +165 -0
- mycelium_sdk-0.1.0/mycelium_sdk/x402/__init__.py +1 -0
- mycelium_sdk-0.1.0/mycelium_sdk/x402/settlement.py +137 -0
- mycelium_sdk-0.1.0/mycelium_sdk.egg-info/PKG-INFO +130 -0
- mycelium_sdk-0.1.0/mycelium_sdk.egg-info/SOURCES.txt +37 -0
- mycelium_sdk-0.1.0/mycelium_sdk.egg-info/dependency_links.txt +1 -0
- mycelium_sdk-0.1.0/mycelium_sdk.egg-info/requires.txt +13 -0
- mycelium_sdk-0.1.0/mycelium_sdk.egg-info/top_level.txt +1 -0
- mycelium_sdk-0.1.0/pyproject.toml +27 -0
- mycelium_sdk-0.1.0/setup.cfg +4 -0
- mycelium_sdk-0.1.0/tests/test_adapters.py +64 -0
- mycelium_sdk-0.1.0/tests/test_agent_loop.py +127 -0
- mycelium_sdk-0.1.0/tests/test_context.py +81 -0
- mycelium_sdk-0.1.0/tests/test_contract_client.py +96 -0
- mycelium_sdk-0.1.0/tests/test_crypto.py +40 -0
- mycelium_sdk-0.1.0/tests/test_hive.py +136 -0
- mycelium_sdk-0.1.0/tests/test_live_testnet.py +91 -0
- mycelium_sdk-0.1.0/tests/test_rpc_resilience.py +117 -0
- mycelium_sdk-0.1.0/tests/test_spec.py +102 -0
- mycelium_sdk-0.1.0/tests/test_x402.py +67 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mycelium-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Mycelium on-chain agent SDK (signing, contract calls, hive discovery, x402)
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: stellar-sdk<15,>=14
|
|
8
|
+
Requires-Dist: cryptography>=42
|
|
9
|
+
Requires-Dist: requests>=2.31
|
|
10
|
+
Provides-Extra: langgraph
|
|
11
|
+
Requires-Dist: langgraph; extra == "langgraph"
|
|
12
|
+
Requires-Dist: langchain-core; extra == "langgraph"
|
|
13
|
+
Provides-Extra: gemini
|
|
14
|
+
Requires-Dist: google-generativeai; extra == "gemini"
|
|
15
|
+
Provides-Extra: anthropic
|
|
16
|
+
Requires-Dist: anthropic; extra == "anthropic"
|
|
17
|
+
|
|
18
|
+
# Mycelium SDK
|
|
19
|
+
|
|
20
|
+
The Mycelium SDK provides a clean, Python-first interface for orchestrating autonomous agents, verifying cryptographically signed payloads, querying the Swarm Hive Registry, and settling M2M payments via the x402 Commerce Protocol on the Stellar/Soroban network.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
The SDK can be installed directly from PyPI (or via the wrapper `mycelium-stellar` package):
|
|
25
|
+
```bash
|
|
26
|
+
pip install mycelium-sdk
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Core Architecture
|
|
32
|
+
|
|
33
|
+
The SDK handles all off-chain agent logic, cryptography, AI orchestration, and RPC interactions with Soroban.
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
┌──────────────────────────────┐
|
|
37
|
+
│ AI Framework │
|
|
38
|
+
│ (LangGraph/Gemini/etc.) │
|
|
39
|
+
└──────────────┬───────────────┘
|
|
40
|
+
│
|
|
41
|
+
▼
|
|
42
|
+
┌──────────────────────────────┐
|
|
43
|
+
│ Mycelium SDK │
|
|
44
|
+
│ (AgentContext & HiveClient) │
|
|
45
|
+
└──────────────┬───────────────┘
|
|
46
|
+
│
|
|
47
|
+
▼
|
|
48
|
+
┌──────────────────────────────┐
|
|
49
|
+
│ Stellar Soroban Network │
|
|
50
|
+
│ (RPC, Ledger Queries) │
|
|
51
|
+
└──────────────────────────────┘
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Primary APIs
|
|
57
|
+
|
|
58
|
+
### 1. `AgentContext`
|
|
59
|
+
Manages on-chain identity, cryptographic keypairs, and transaction orchestration.
|
|
60
|
+
* `AgentContext(keypair_path: str, network_type: str = "testnet")`
|
|
61
|
+
- Loads an encrypted wallet keypair from local storage.
|
|
62
|
+
* `AgentContext.read_only(network_type: str = "testnet")`
|
|
63
|
+
- Initializes a read-only context (does not require a keypair; ideal for registry scans).
|
|
64
|
+
* `AgentContext.from_keypair(keypair: Keypair, network_type: str = "testnet")`
|
|
65
|
+
- Initializes a context from an in-memory `stellar_sdk.Keypair` object.
|
|
66
|
+
* `call_contract(contract_id: str, function_name: str, args: list, send: bool = False)`
|
|
67
|
+
- Invokes an on-chain smart contract function.
|
|
68
|
+
* `acall_contract(contract_id: str, function_name: str, args: list)`
|
|
69
|
+
- Asynchronous contract invocation wrapper.
|
|
70
|
+
|
|
71
|
+
### 2. `HiveClient`
|
|
72
|
+
Interfaces with the on-chain Hive Registry to register, discover, and resolve agents.
|
|
73
|
+
* `register_agent(name: str, capability_hash: str, endpoint: str)`
|
|
74
|
+
- Registers the agent's unique name, capabilities, and HTTPS service endpoint.
|
|
75
|
+
* `resolve_agent(name: str) -> dict`
|
|
76
|
+
- Resolves an agent name to its public address, capabilities, endpoint, and reputation.
|
|
77
|
+
* `lookup_partner_agent(capability: str) -> list[dict]`
|
|
78
|
+
- Scans the ledger to discover agents matching a specific service capability.
|
|
79
|
+
|
|
80
|
+
### 3. `EscrowPaymentRouter` (x402 Commerce)
|
|
81
|
+
Manages multi-agent escrow settlements and trustless commerce routing.
|
|
82
|
+
* `create_locked_escrow(recipient: str, amount: str, token: str = None) -> str`
|
|
83
|
+
- Locks funds on-chain under an escrow contract router.
|
|
84
|
+
* `release_escrow(escrow_id: str, signature: str)`
|
|
85
|
+
- Releases locked funds to the recipient agent after cryptographic validation.
|
|
86
|
+
* `refund_escrow(escrow_id: str)`
|
|
87
|
+
- Reclaims locked funds after a predetermined expiry period.
|
|
88
|
+
* **Note**: `EscrowPaymentManager` is maintained as a backward-compatible alias.
|
|
89
|
+
|
|
90
|
+
### 4. `run_agent_loop`
|
|
91
|
+
Executes autonomous agent orchestration loops wired to cloud LLM APIs (Anthropic, Gemini, etc.) and exposes on-chain interactions as executable LLM tools.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Code Example: Autonomous Payment Agent
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import os
|
|
99
|
+
from mycelium import AgentContext, HiveClient, run_agent_loop, ContractTool
|
|
100
|
+
|
|
101
|
+
# Load sovereign on-chain identity
|
|
102
|
+
context = AgentContext(keypair_path=".mycelium/wallet.json", network_type="testnet")
|
|
103
|
+
hive = HiveClient(context)
|
|
104
|
+
|
|
105
|
+
# On-chain contract ID
|
|
106
|
+
CONTRACT_ID = os.environ.get("MYCELIUM_CONTRACT_ID")
|
|
107
|
+
|
|
108
|
+
def main():
|
|
109
|
+
print(f"Agent online as: {context.keypair.public_key}")
|
|
110
|
+
|
|
111
|
+
# Run the autonomous execution loop
|
|
112
|
+
response = run_agent_loop(
|
|
113
|
+
"Scan the registry for an agent offering translation capabilities, "
|
|
114
|
+
"negotiate a settlement, and execute the payment.",
|
|
115
|
+
context=context,
|
|
116
|
+
provider="gemini",
|
|
117
|
+
model="gemini-1.5-pro",
|
|
118
|
+
api_key=os.environ.get("GEMINI_API_KEY"),
|
|
119
|
+
contract_id=CONTRACT_ID,
|
|
120
|
+
tools=[
|
|
121
|
+
ContractTool("increment"),
|
|
122
|
+
ContractTool("get_count", read_only=True),
|
|
123
|
+
],
|
|
124
|
+
hive=hive
|
|
125
|
+
)
|
|
126
|
+
print(f"Loop Response:\n{response}")
|
|
127
|
+
|
|
128
|
+
if __name__ == "__main__":
|
|
129
|
+
main()
|
|
130
|
+
```
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Mycelium SDK
|
|
2
|
+
|
|
3
|
+
The Mycelium SDK provides a clean, Python-first interface for orchestrating autonomous agents, verifying cryptographically signed payloads, querying the Swarm Hive Registry, and settling M2M payments via the x402 Commerce Protocol on the Stellar/Soroban network.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
The SDK can be installed directly from PyPI (or via the wrapper `mycelium-stellar` package):
|
|
8
|
+
```bash
|
|
9
|
+
pip install mycelium-sdk
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Core Architecture
|
|
15
|
+
|
|
16
|
+
The SDK handles all off-chain agent logic, cryptography, AI orchestration, and RPC interactions with Soroban.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
┌──────────────────────────────┐
|
|
20
|
+
│ AI Framework │
|
|
21
|
+
│ (LangGraph/Gemini/etc.) │
|
|
22
|
+
└──────────────┬───────────────┘
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
┌──────────────────────────────┐
|
|
26
|
+
│ Mycelium SDK │
|
|
27
|
+
│ (AgentContext & HiveClient) │
|
|
28
|
+
└──────────────┬───────────────┘
|
|
29
|
+
│
|
|
30
|
+
▼
|
|
31
|
+
┌──────────────────────────────┐
|
|
32
|
+
│ Stellar Soroban Network │
|
|
33
|
+
│ (RPC, Ledger Queries) │
|
|
34
|
+
└──────────────────────────────┘
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Primary APIs
|
|
40
|
+
|
|
41
|
+
### 1. `AgentContext`
|
|
42
|
+
Manages on-chain identity, cryptographic keypairs, and transaction orchestration.
|
|
43
|
+
* `AgentContext(keypair_path: str, network_type: str = "testnet")`
|
|
44
|
+
- Loads an encrypted wallet keypair from local storage.
|
|
45
|
+
* `AgentContext.read_only(network_type: str = "testnet")`
|
|
46
|
+
- Initializes a read-only context (does not require a keypair; ideal for registry scans).
|
|
47
|
+
* `AgentContext.from_keypair(keypair: Keypair, network_type: str = "testnet")`
|
|
48
|
+
- Initializes a context from an in-memory `stellar_sdk.Keypair` object.
|
|
49
|
+
* `call_contract(contract_id: str, function_name: str, args: list, send: bool = False)`
|
|
50
|
+
- Invokes an on-chain smart contract function.
|
|
51
|
+
* `acall_contract(contract_id: str, function_name: str, args: list)`
|
|
52
|
+
- Asynchronous contract invocation wrapper.
|
|
53
|
+
|
|
54
|
+
### 2. `HiveClient`
|
|
55
|
+
Interfaces with the on-chain Hive Registry to register, discover, and resolve agents.
|
|
56
|
+
* `register_agent(name: str, capability_hash: str, endpoint: str)`
|
|
57
|
+
- Registers the agent's unique name, capabilities, and HTTPS service endpoint.
|
|
58
|
+
* `resolve_agent(name: str) -> dict`
|
|
59
|
+
- Resolves an agent name to its public address, capabilities, endpoint, and reputation.
|
|
60
|
+
* `lookup_partner_agent(capability: str) -> list[dict]`
|
|
61
|
+
- Scans the ledger to discover agents matching a specific service capability.
|
|
62
|
+
|
|
63
|
+
### 3. `EscrowPaymentRouter` (x402 Commerce)
|
|
64
|
+
Manages multi-agent escrow settlements and trustless commerce routing.
|
|
65
|
+
* `create_locked_escrow(recipient: str, amount: str, token: str = None) -> str`
|
|
66
|
+
- Locks funds on-chain under an escrow contract router.
|
|
67
|
+
* `release_escrow(escrow_id: str, signature: str)`
|
|
68
|
+
- Releases locked funds to the recipient agent after cryptographic validation.
|
|
69
|
+
* `refund_escrow(escrow_id: str)`
|
|
70
|
+
- Reclaims locked funds after a predetermined expiry period.
|
|
71
|
+
* **Note**: `EscrowPaymentManager` is maintained as a backward-compatible alias.
|
|
72
|
+
|
|
73
|
+
### 4. `run_agent_loop`
|
|
74
|
+
Executes autonomous agent orchestration loops wired to cloud LLM APIs (Anthropic, Gemini, etc.) and exposes on-chain interactions as executable LLM tools.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Code Example: Autonomous Payment Agent
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
import os
|
|
82
|
+
from mycelium import AgentContext, HiveClient, run_agent_loop, ContractTool
|
|
83
|
+
|
|
84
|
+
# Load sovereign on-chain identity
|
|
85
|
+
context = AgentContext(keypair_path=".mycelium/wallet.json", network_type="testnet")
|
|
86
|
+
hive = HiveClient(context)
|
|
87
|
+
|
|
88
|
+
# On-chain contract ID
|
|
89
|
+
CONTRACT_ID = os.environ.get("MYCELIUM_CONTRACT_ID")
|
|
90
|
+
|
|
91
|
+
def main():
|
|
92
|
+
print(f"Agent online as: {context.keypair.public_key}")
|
|
93
|
+
|
|
94
|
+
# Run the autonomous execution loop
|
|
95
|
+
response = run_agent_loop(
|
|
96
|
+
"Scan the registry for an agent offering translation capabilities, "
|
|
97
|
+
"negotiate a settlement, and execute the payment.",
|
|
98
|
+
context=context,
|
|
99
|
+
provider="gemini",
|
|
100
|
+
model="gemini-1.5-pro",
|
|
101
|
+
api_key=os.environ.get("GEMINI_API_KEY"),
|
|
102
|
+
contract_id=CONTRACT_ID,
|
|
103
|
+
tools=[
|
|
104
|
+
ContractTool("increment"),
|
|
105
|
+
ContractTool("get_count", read_only=True),
|
|
106
|
+
],
|
|
107
|
+
hive=hive
|
|
108
|
+
)
|
|
109
|
+
print(f"Loop Response:\n{response}")
|
|
110
|
+
|
|
111
|
+
if __name__ == "__main__":
|
|
112
|
+
main()
|
|
113
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from mycelium_sdk.context import AgentContext, StellarNetwork, TxResult
|
|
2
|
+
from mycelium_sdk.hive import HiveClient
|
|
3
|
+
from mycelium_sdk.x402.settlement import EscrowPaymentRouter, EscrowPaymentManager
|
|
4
|
+
from mycelium_sdk.constants import HIVEMIND_REGISTRY_ADDRESS
|
|
5
|
+
from mycelium_sdk.banner import print_banner, show_startup_banner
|
|
6
|
+
from mycelium_sdk.agent_loop import run_agent_loop, ContractTool
|
|
7
|
+
from mycelium_sdk.contract_client import ContractClient
|
|
8
|
+
from mycelium_sdk import logging
|
|
9
|
+
from mycelium_sdk import scval
|
|
10
|
+
from mycelium_sdk.scval import (
|
|
11
|
+
u32, u64, u128, i32, i64, i128, address, symbol, string, bytes_val, boolean,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"AgentContext",
|
|
16
|
+
"StellarNetwork",
|
|
17
|
+
"TxResult",
|
|
18
|
+
"HiveClient",
|
|
19
|
+
"EscrowPaymentRouter",
|
|
20
|
+
"EscrowPaymentManager",
|
|
21
|
+
"HIVEMIND_REGISTRY_ADDRESS",
|
|
22
|
+
"print_banner",
|
|
23
|
+
"show_startup_banner",
|
|
24
|
+
# one-call agent loop helper (collapses agent.py boilerplate)
|
|
25
|
+
"run_agent_loop",
|
|
26
|
+
"ContractTool",
|
|
27
|
+
# typed contract client: ctx.contract(cid).add(40)
|
|
28
|
+
"ContractClient",
|
|
29
|
+
# structured logging (configure(quiet=True) for production agents)
|
|
30
|
+
"logging",
|
|
31
|
+
# width-correct Soroban value helpers (no stellar_sdk import needed)
|
|
32
|
+
"scval",
|
|
33
|
+
"u32", "u64", "u128", "i32", "i64", "i128",
|
|
34
|
+
"address", "symbol", "string", "bytes_val", "boolean",
|
|
35
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AI orchestrator adapters (sdk.md §4).
|
|
3
|
+
|
|
4
|
+
These bridge the on-chain SDK (`AgentContext` / `HiveClient`) to popular LLM
|
|
5
|
+
frameworks by exposing contract calls as framework-native "tools". Each adapter
|
|
6
|
+
lives in its own module and imports its framework lazily, so the heavy optional
|
|
7
|
+
dependency is only required if you actually use that adapter:
|
|
8
|
+
|
|
9
|
+
pip install "mycelium[langgraph]" # or [gemini] / [anthropic]
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
|
|
13
|
+
from mycelium_sdk import AgentContext
|
|
14
|
+
from mycelium_sdk.adapters.langgraph import make_contract_tool
|
|
15
|
+
|
|
16
|
+
ctx = AgentContext(".mycelium/wallet.json")
|
|
17
|
+
trade = make_contract_tool(ctx, "execute_trade",
|
|
18
|
+
description="Execute an on-chain trade.")
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from mycelium_sdk.adapters import langgraph, gemini, anthropic
|
|
22
|
+
|
|
23
|
+
__all__ = ["langgraph", "gemini", "anthropic"]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Anthropic (Claude) adapter.
|
|
3
|
+
|
|
4
|
+
Anthropic tool use is schema-driven: you pass JSON tool definitions to the
|
|
5
|
+
Messages API, then dispatch the model's `tool_use` blocks back to your code.
|
|
6
|
+
This adapter generates the tool schema for an on-chain contract call and a
|
|
7
|
+
dispatcher that executes the call. The `anthropic` SDK is only needed to run the
|
|
8
|
+
conversation loop, not to build the schema; install it with `mycelium[anthropic]`.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def require_anthropic():
|
|
15
|
+
"""Import the anthropic client, with a clear error if the extra is missing."""
|
|
16
|
+
try:
|
|
17
|
+
import anthropic
|
|
18
|
+
except ImportError as exc: # pragma: no cover - depends on optional extra
|
|
19
|
+
raise ImportError(
|
|
20
|
+
"The Anthropic adapter needs the anthropic SDK. Install it with:\n"
|
|
21
|
+
" pip install 'mycelium[anthropic]'"
|
|
22
|
+
) from exc
|
|
23
|
+
return anthropic
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def contract_tool_schema(
|
|
27
|
+
name: str,
|
|
28
|
+
description: str,
|
|
29
|
+
contract_id: Optional[str] = None,
|
|
30
|
+
) -> Dict[str, Any]:
|
|
31
|
+
"""
|
|
32
|
+
Build an Anthropic tool definition for an on-chain contract call. The tool
|
|
33
|
+
takes an `args` array; if `contract_id` is not fixed here, a `contract_id`
|
|
34
|
+
string field is added to the schema.
|
|
35
|
+
"""
|
|
36
|
+
properties: Dict[str, Any] = {
|
|
37
|
+
"args": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"description": "Positional arguments for the contract function.",
|
|
40
|
+
"items": {},
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
required = ["args"]
|
|
44
|
+
if contract_id is None:
|
|
45
|
+
properties["contract_id"] = {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "The target Soroban contract id.",
|
|
48
|
+
}
|
|
49
|
+
required.append("contract_id")
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
"name": name,
|
|
53
|
+
"description": description,
|
|
54
|
+
"input_schema": {"type": "object", "properties": properties, "required": required},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def make_tool_dispatcher(
|
|
59
|
+
context,
|
|
60
|
+
function_name: str,
|
|
61
|
+
contract_id: Optional[str] = None,
|
|
62
|
+
read_only: bool = False,
|
|
63
|
+
) -> Callable[[Dict[str, Any]], str]:
|
|
64
|
+
"""
|
|
65
|
+
Build a dispatcher that executes a Claude `tool_use` block's `input` dict by
|
|
66
|
+
invoking `function_name` on the contract, returning a string for the
|
|
67
|
+
tool_result.
|
|
68
|
+
"""
|
|
69
|
+
def dispatch(tool_input: Dict[str, Any]) -> str:
|
|
70
|
+
target = contract_id or tool_input.get("contract_id")
|
|
71
|
+
if not target:
|
|
72
|
+
return "Error: no contract_id provided."
|
|
73
|
+
try:
|
|
74
|
+
result = context.call_contract(
|
|
75
|
+
target, function_name, list(tool_input.get("args", [])), read_only=read_only
|
|
76
|
+
)
|
|
77
|
+
return f"On-chain result: {getattr(result, 'return_value', result)}"
|
|
78
|
+
except Exception as e:
|
|
79
|
+
return f"Contract call failed: {e}"
|
|
80
|
+
|
|
81
|
+
return dispatch
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Google Gemini adapter (sdk.md §4.2).
|
|
3
|
+
|
|
4
|
+
Produces plain Python callables that Gemini's automatic function-calling can
|
|
5
|
+
invoke directly (Gemini reads the function signature + docstring), each backed
|
|
6
|
+
by a live on-chain call. Requires `google-generativeai` (install
|
|
7
|
+
`mycelium[gemini]`) only if you build a `GenerativeModel` from them — the helpers
|
|
8
|
+
themselves return ordinary functions.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from typing import Any, Callable, List, Optional
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def require_genai():
|
|
15
|
+
"""Import google.generativeai, with a clear error if the extra is missing."""
|
|
16
|
+
try:
|
|
17
|
+
import google.generativeai as genai
|
|
18
|
+
except ImportError as exc: # pragma: no cover - depends on optional extra
|
|
19
|
+
raise ImportError(
|
|
20
|
+
"The Gemini adapter needs google-generativeai. Install it with:\n"
|
|
21
|
+
" pip install 'mycelium[gemini]'"
|
|
22
|
+
) from exc
|
|
23
|
+
return genai
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def make_contract_function(
|
|
27
|
+
context,
|
|
28
|
+
function_name: str,
|
|
29
|
+
contract_id: str,
|
|
30
|
+
read_only: bool = False,
|
|
31
|
+
) -> Callable[..., str]:
|
|
32
|
+
"""
|
|
33
|
+
Build a Gemini-callable function that invokes `function_name` on
|
|
34
|
+
`contract_id`. The returned function takes a single `args` list and returns
|
|
35
|
+
a human-readable result string for the model.
|
|
36
|
+
"""
|
|
37
|
+
def contract_call(args: List[Any]) -> str:
|
|
38
|
+
"""Invoke an on-chain Soroban contract function and return the result."""
|
|
39
|
+
try:
|
|
40
|
+
result = context.call_contract(contract_id, function_name, list(args), read_only=read_only)
|
|
41
|
+
return f"On-chain result: {getattr(result, 'return_value', result)}"
|
|
42
|
+
except Exception as e:
|
|
43
|
+
return f"Contract call failed: {e}"
|
|
44
|
+
|
|
45
|
+
contract_call.__name__ = function_name
|
|
46
|
+
return contract_call
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def make_resolve_agent_function(hive_client) -> Callable[[str], str]:
|
|
50
|
+
"""A Gemini-callable function that resolves an agent via the Hive Registry."""
|
|
51
|
+
def lookup_partner_agent(name_tag: str) -> str:
|
|
52
|
+
"""Query the Hive Registry to find a registered service agent by name."""
|
|
53
|
+
try:
|
|
54
|
+
meta = hive_client.resolve_agent(name_tag)
|
|
55
|
+
return f"Agent found. Public Key: {meta['public_key']}, Endpoint: {meta['endpoint']}"
|
|
56
|
+
except Exception:
|
|
57
|
+
return "Agent name not registered in the Hive Registry."
|
|
58
|
+
|
|
59
|
+
return lookup_partner_agent
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LangGraph / LangChain adapter (sdk.md §4.1).
|
|
3
|
+
|
|
4
|
+
Turns an on-chain contract function into a LangChain `@tool` that a LangGraph
|
|
5
|
+
node can invoke. Requires `langchain-core` (install `mycelium[langgraph]`).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Callable, List, Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _require_langchain():
|
|
12
|
+
try:
|
|
13
|
+
from langchain_core.tools import tool # noqa: F401
|
|
14
|
+
except ImportError as exc: # pragma: no cover - depends on optional extra
|
|
15
|
+
raise ImportError(
|
|
16
|
+
"The LangGraph adapter needs langchain-core. Install it with:\n"
|
|
17
|
+
" pip install 'mycelium[langgraph]'"
|
|
18
|
+
) from exc
|
|
19
|
+
return tool
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def make_contract_tool(
|
|
23
|
+
context,
|
|
24
|
+
function_name: str,
|
|
25
|
+
contract_id: Optional[str] = None,
|
|
26
|
+
description: Optional[str] = None,
|
|
27
|
+
name: Optional[str] = None,
|
|
28
|
+
read_only: bool = False,
|
|
29
|
+
) -> Callable:
|
|
30
|
+
"""
|
|
31
|
+
Build a LangChain tool that invokes `function_name` on a Soroban contract.
|
|
32
|
+
|
|
33
|
+
The returned tool accepts a single `args` list (the contract call arguments).
|
|
34
|
+
If `contract_id` is omitted, the tool's first argument is treated as the
|
|
35
|
+
target contract id.
|
|
36
|
+
"""
|
|
37
|
+
tool = _require_langchain()
|
|
38
|
+
tool_name = name or function_name
|
|
39
|
+
tool_doc = description or f"Invoke '{function_name}' on a Soroban contract."
|
|
40
|
+
|
|
41
|
+
@tool(tool_name)
|
|
42
|
+
def _contract_tool(args: List[Any]) -> str:
|
|
43
|
+
target = contract_id
|
|
44
|
+
call_args = list(args)
|
|
45
|
+
if target is None:
|
|
46
|
+
if not call_args:
|
|
47
|
+
return "Error: no contract_id provided and none configured."
|
|
48
|
+
target, call_args = call_args[0], call_args[1:]
|
|
49
|
+
try:
|
|
50
|
+
result = context.call_contract(target, function_name, call_args, read_only=read_only)
|
|
51
|
+
tx_hash = getattr(result, "hash", None)
|
|
52
|
+
return (
|
|
53
|
+
f"Settled on-chain. Tx: {tx_hash}, return: {getattr(result, 'return_value', result)}"
|
|
54
|
+
if tx_hash else f"Result: {result}"
|
|
55
|
+
)
|
|
56
|
+
except Exception as e: # surface failures to the agent loop
|
|
57
|
+
return f"Contract call failed: {e}"
|
|
58
|
+
|
|
59
|
+
_contract_tool.__doc__ = tool_doc
|
|
60
|
+
return _contract_tool
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def make_resolve_agent_tool(hive_client, name: str = "lookup_partner_agent") -> Callable:
|
|
64
|
+
"""A LangChain tool that resolves an agent name via the Hive Registry."""
|
|
65
|
+
tool = _require_langchain()
|
|
66
|
+
|
|
67
|
+
@tool(name)
|
|
68
|
+
def _resolve(name_tag: str) -> str:
|
|
69
|
+
"""Look up a registered agent by its unique name in the Hive Registry."""
|
|
70
|
+
try:
|
|
71
|
+
meta = hive_client.resolve_agent(name_tag)
|
|
72
|
+
return f"Agent found. Public Key: {meta['public_key']}, Endpoint: {meta['endpoint']}"
|
|
73
|
+
except Exception:
|
|
74
|
+
return "Agent name not registered in the Hive Registry."
|
|
75
|
+
|
|
76
|
+
return _resolve
|