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.
Files changed (39) hide show
  1. mycelium_sdk-0.1.0/PKG-INFO +130 -0
  2. mycelium_sdk-0.1.0/README.md +113 -0
  3. mycelium_sdk-0.1.0/mycelium_sdk/__init__.py +35 -0
  4. mycelium_sdk-0.1.0/mycelium_sdk/adapters/__init__.py +23 -0
  5. mycelium_sdk-0.1.0/mycelium_sdk/adapters/anthropic.py +81 -0
  6. mycelium_sdk-0.1.0/mycelium_sdk/adapters/gemini.py +59 -0
  7. mycelium_sdk-0.1.0/mycelium_sdk/adapters/langgraph.py +76 -0
  8. mycelium_sdk-0.1.0/mycelium_sdk/agent_loop.py +203 -0
  9. mycelium_sdk-0.1.0/mycelium_sdk/banner.py +62 -0
  10. mycelium_sdk-0.1.0/mycelium_sdk/constants.py +62 -0
  11. mycelium_sdk-0.1.0/mycelium_sdk/context.py +419 -0
  12. mycelium_sdk-0.1.0/mycelium_sdk/contract_client.py +122 -0
  13. mycelium_sdk-0.1.0/mycelium_sdk/contracts/escrow.wasm +0 -0
  14. mycelium_sdk-0.1.0/mycelium_sdk/crypto.py +122 -0
  15. mycelium_sdk-0.1.0/mycelium_sdk/hive.py +256 -0
  16. mycelium_sdk-0.1.0/mycelium_sdk/logging.py +83 -0
  17. mycelium_sdk-0.1.0/mycelium_sdk/models.py +145 -0
  18. mycelium_sdk-0.1.0/mycelium_sdk/rpc.py +115 -0
  19. mycelium_sdk-0.1.0/mycelium_sdk/scval.py +77 -0
  20. mycelium_sdk-0.1.0/mycelium_sdk/spec.py +165 -0
  21. mycelium_sdk-0.1.0/mycelium_sdk/x402/__init__.py +1 -0
  22. mycelium_sdk-0.1.0/mycelium_sdk/x402/settlement.py +137 -0
  23. mycelium_sdk-0.1.0/mycelium_sdk.egg-info/PKG-INFO +130 -0
  24. mycelium_sdk-0.1.0/mycelium_sdk.egg-info/SOURCES.txt +37 -0
  25. mycelium_sdk-0.1.0/mycelium_sdk.egg-info/dependency_links.txt +1 -0
  26. mycelium_sdk-0.1.0/mycelium_sdk.egg-info/requires.txt +13 -0
  27. mycelium_sdk-0.1.0/mycelium_sdk.egg-info/top_level.txt +1 -0
  28. mycelium_sdk-0.1.0/pyproject.toml +27 -0
  29. mycelium_sdk-0.1.0/setup.cfg +4 -0
  30. mycelium_sdk-0.1.0/tests/test_adapters.py +64 -0
  31. mycelium_sdk-0.1.0/tests/test_agent_loop.py +127 -0
  32. mycelium_sdk-0.1.0/tests/test_context.py +81 -0
  33. mycelium_sdk-0.1.0/tests/test_contract_client.py +96 -0
  34. mycelium_sdk-0.1.0/tests/test_crypto.py +40 -0
  35. mycelium_sdk-0.1.0/tests/test_hive.py +136 -0
  36. mycelium_sdk-0.1.0/tests/test_live_testnet.py +91 -0
  37. mycelium_sdk-0.1.0/tests/test_rpc_resilience.py +117 -0
  38. mycelium_sdk-0.1.0/tests/test_spec.py +102 -0
  39. 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