mech-client 0.2.11__py3-none-any.whl → 0.2.12__py3-none-any.whl
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.
- mech_client/__init__.py +1 -1
- mech_client/cli.py +12 -5
- mech_client/configs/mechs.json +92 -0
- mech_client/interact.py +170 -43
- mech_client/subgraph.py +32 -10
- {mech_client-0.2.11.dist-info → mech_client-0.2.12.dist-info}/METADATA +29 -9
- {mech_client-0.2.11.dist-info → mech_client-0.2.12.dist-info}/RECORD +10 -9
- {mech_client-0.2.11.dist-info → mech_client-0.2.12.dist-info}/LICENSE +0 -0
- {mech_client-0.2.11.dist-info → mech_client-0.2.12.dist-info}/WHEEL +0 -0
- {mech_client-0.2.11.dist-info → mech_client-0.2.12.dist-info}/entry_points.txt +0 -0
mech_client/__init__.py
CHANGED
mech_client/cli.py
CHANGED
|
@@ -40,6 +40,11 @@ def cli() -> None:
|
|
|
40
40
|
@click.command()
|
|
41
41
|
@click.argument("prompt")
|
|
42
42
|
@click.argument("agent_id", type=int)
|
|
43
|
+
@click.option(
|
|
44
|
+
"--key",
|
|
45
|
+
type=click.Path(exists=True, file_okay=True, dir_okay=False),
|
|
46
|
+
help="Path to private key to use for request minting",
|
|
47
|
+
)
|
|
43
48
|
@click.option(
|
|
44
49
|
"--tool",
|
|
45
50
|
type=str,
|
|
@@ -52,11 +57,6 @@ def cli() -> None:
|
|
|
52
57
|
help="Extra attribute (key=value) to be included in the request metadata",
|
|
53
58
|
metavar="KEY=VALUE",
|
|
54
59
|
)
|
|
55
|
-
@click.option(
|
|
56
|
-
"--key",
|
|
57
|
-
type=click.Path(exists=True, file_okay=True, dir_okay=False),
|
|
58
|
-
help="Path to private key to use for request minting",
|
|
59
|
-
)
|
|
60
60
|
@click.option(
|
|
61
61
|
"--confirm",
|
|
62
62
|
type=click.Choice(
|
|
@@ -79,6 +79,11 @@ def cli() -> None:
|
|
|
79
79
|
type=float,
|
|
80
80
|
help="Amount of sleep before retrying the transaction",
|
|
81
81
|
)
|
|
82
|
+
@click.option(
|
|
83
|
+
"--chain-config",
|
|
84
|
+
type=str,
|
|
85
|
+
help="Id of the mech's chain configuration (stored configs/mechs.json)",
|
|
86
|
+
)
|
|
82
87
|
def interact( # pylint: disable=too-many-arguments
|
|
83
88
|
prompt: str,
|
|
84
89
|
agent_id: int,
|
|
@@ -89,6 +94,7 @@ def interact( # pylint: disable=too-many-arguments
|
|
|
89
94
|
retries: Optional[int] = None,
|
|
90
95
|
timeout: Optional[float] = None,
|
|
91
96
|
sleep: Optional[float] = None,
|
|
97
|
+
chain_config: Optional[str] = None,
|
|
92
98
|
) -> None:
|
|
93
99
|
"""Interact with a mech specifying a prompt and tool."""
|
|
94
100
|
try:
|
|
@@ -112,6 +118,7 @@ def interact( # pylint: disable=too-many-arguments
|
|
|
112
118
|
retries=retries,
|
|
113
119
|
timeout=timeout,
|
|
114
120
|
sleep=sleep,
|
|
121
|
+
chain_config=chain_config,
|
|
115
122
|
)
|
|
116
123
|
except (ValueError, FileNotFoundError) as e:
|
|
117
124
|
raise click.ClickException(str(e)) from e
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"gnosis": {
|
|
3
|
+
"agent_registry_contract": "0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA",
|
|
4
|
+
"rpc_url": "https://rpc.eu-central-2.gateway.fm/v4/gnosis/non-archival/mainnet",
|
|
5
|
+
"wss_endpoint": "wss://rpc.eu-central-2.gateway.fm/ws/v4/gnosis/non-archival/mainnet",
|
|
6
|
+
"ledger_config": {
|
|
7
|
+
"address": "https://rpc.eu-central-2.gateway.fm/v4/gnosis/non-archival/mainnet",
|
|
8
|
+
"chain_id": 100,
|
|
9
|
+
"poa_chain": false,
|
|
10
|
+
"default_gas_price_strategy": "eip1559",
|
|
11
|
+
"is_gas_estimation_enabled": false
|
|
12
|
+
},
|
|
13
|
+
"gas_limit": 100000,
|
|
14
|
+
"contract_abi_url": "https://gnosis.blockscout.com/api/v2/smart-contracts/{contract_address}",
|
|
15
|
+
"subgraph_url": "https://api.studio.thegraph.com/query/57238/mech/version/latest"
|
|
16
|
+
},
|
|
17
|
+
"arbitrum": {
|
|
18
|
+
"agent_registry_contract": "0xa4799B083E0068732456EF45ff9fe5c683658327",
|
|
19
|
+
"rpc_url": "https://arbitrum.llamarpc.com",
|
|
20
|
+
"wss_endpoint": "wss://arbitrum.gateway.tenderly.co",
|
|
21
|
+
"ledger_config": {
|
|
22
|
+
"address": "https://arbitrum.llamarpc.com",
|
|
23
|
+
"chain_id": 42161,
|
|
24
|
+
"poa_chain": false,
|
|
25
|
+
"default_gas_price_strategy": "eip1559",
|
|
26
|
+
"is_gas_estimation_enabled": false
|
|
27
|
+
},
|
|
28
|
+
"gas_limit": 100000,
|
|
29
|
+
"contract_abi_url": "https://api.arbiscan.io/api?module=contract&action=getabi&address={contract_address}",
|
|
30
|
+
"subgraph_url": ""
|
|
31
|
+
},
|
|
32
|
+
"polygon": {
|
|
33
|
+
"agent_registry_contract": "0x984cf72FDe8B5aA910e9e508aC5e007ae5BDcC9C",
|
|
34
|
+
"rpc_url": "https://polygon-bor-rpc.publicnode.com",
|
|
35
|
+
"wss_endpoint": "wss://polygon.gateway.tenderly.co",
|
|
36
|
+
"ledger_config": {
|
|
37
|
+
"address": "https://polygon-bor-rpc.publicnode.com",
|
|
38
|
+
"chain_id": 137,
|
|
39
|
+
"poa_chain": true,
|
|
40
|
+
"default_gas_price_strategy": "eip1559",
|
|
41
|
+
"is_gas_estimation_enabled": false
|
|
42
|
+
},
|
|
43
|
+
"gas_limit": 100000,
|
|
44
|
+
"contract_abi_url": "https://api.polygonscan.com/api?module=contract&action=getabi&address={contract_address}",
|
|
45
|
+
"subgraph_url": ""
|
|
46
|
+
},
|
|
47
|
+
"base": {
|
|
48
|
+
"agent_registry_contract": "0x88DE734655184a09B70700aE4F72364d1ad23728",
|
|
49
|
+
"rpc_url": "https://base.llamarpc.com",
|
|
50
|
+
"wss_endpoint": "wss://base.gateway.tenderly.co",
|
|
51
|
+
"ledger_config": {
|
|
52
|
+
"address": "https://base.llamarpc.com",
|
|
53
|
+
"chain_id": 8453,
|
|
54
|
+
"poa_chain": false,
|
|
55
|
+
"default_gas_price_strategy": "eip1559",
|
|
56
|
+
"is_gas_estimation_enabled": false
|
|
57
|
+
},
|
|
58
|
+
"gas_limit": 100000,
|
|
59
|
+
"contract_abi_url": "https://api.basescan.org/api?module=contract&action=getabi&address={contract_address}",
|
|
60
|
+
"subgraph_url": ""
|
|
61
|
+
},
|
|
62
|
+
"celo": {
|
|
63
|
+
"agent_registry_contract": "0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA",
|
|
64
|
+
"rpc_url": "https://forno.celo.org",
|
|
65
|
+
"wss_endpoint": "wss://forno.celo.org/ws",
|
|
66
|
+
"ledger_config": {
|
|
67
|
+
"address": "https://forno.celo.org",
|
|
68
|
+
"chain_id": 42220,
|
|
69
|
+
"poa_chain": false,
|
|
70
|
+
"default_gas_price_strategy": "eip1559",
|
|
71
|
+
"is_gas_estimation_enabled": false
|
|
72
|
+
},
|
|
73
|
+
"gas_limit": 100000,
|
|
74
|
+
"contract_abi_url": "https://api.celoscan.io/api?module=contract&action=getabi&address={contract_address}",
|
|
75
|
+
"subgraph_url": ""
|
|
76
|
+
},
|
|
77
|
+
"optimism": {
|
|
78
|
+
"agent_registry_contract": "0x75D529FAe220bC8db714F0202193726b46881B76",
|
|
79
|
+
"rpc_url": "https://mainnet.optimism.io",
|
|
80
|
+
"wss_endpoint": "wss://optimism.gateway.tenderly.co",
|
|
81
|
+
"ledger_config": {
|
|
82
|
+
"address": "https://mainnet.optimism.io",
|
|
83
|
+
"chain_id": 10,
|
|
84
|
+
"poa_chain": false,
|
|
85
|
+
"default_gas_price_strategy": "eip1559",
|
|
86
|
+
"is_gas_estimation_enabled": false
|
|
87
|
+
},
|
|
88
|
+
"gas_limit": 100000,
|
|
89
|
+
"contract_abi_url": "https://api-optimistic.etherscan.io/api?module=contract&action=getabi&address={contract_address}",
|
|
90
|
+
"subgraph_url": ""
|
|
91
|
+
}
|
|
92
|
+
}
|
mech_client/interact.py
CHANGED
|
@@ -26,9 +26,12 @@ python client.py <prompt> <tool>
|
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
28
|
import asyncio
|
|
29
|
+
import json
|
|
29
30
|
import os
|
|
31
|
+
import sys
|
|
30
32
|
import time
|
|
31
33
|
import warnings
|
|
34
|
+
from dataclasses import asdict, dataclass
|
|
32
35
|
from datetime import datetime
|
|
33
36
|
from enum import Enum
|
|
34
37
|
from pathlib import Path
|
|
@@ -51,33 +54,8 @@ from mech_client.wss import (
|
|
|
51
54
|
)
|
|
52
55
|
|
|
53
56
|
|
|
54
|
-
AGENT_REGISTRY_CONTRACT = "0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA"
|
|
55
|
-
MECHX_CHAIN_RPC = os.environ.get(
|
|
56
|
-
"MECHX_CHAIN_RPC",
|
|
57
|
-
"https://rpc.eu-central-2.gateway.fm/v4/gnosis/non-archival/mainnet",
|
|
58
|
-
)
|
|
59
|
-
LEDGER_CONFIG = {
|
|
60
|
-
"address": MECHX_CHAIN_RPC,
|
|
61
|
-
"chain_id": 100,
|
|
62
|
-
"poa_chain": False,
|
|
63
|
-
"default_gas_price_strategy": "eip1559",
|
|
64
|
-
"is_gas_estimation_enabled": False,
|
|
65
|
-
}
|
|
66
57
|
PRIVATE_KEY_FILE_PATH = "ethereum_private_key.txt"
|
|
67
|
-
|
|
68
|
-
WSS_ENDPOINT = os.getenv(
|
|
69
|
-
"WEBSOCKET_ENDPOINT",
|
|
70
|
-
"wss://rpc.eu-central-2.gateway.fm/ws/v4/gnosis/non-archival/mainnet",
|
|
71
|
-
)
|
|
72
|
-
MANUAL_GAS_LIMIT = int(
|
|
73
|
-
os.getenv(
|
|
74
|
-
"MANUAL_GAS_LIMIT",
|
|
75
|
-
"100_000",
|
|
76
|
-
)
|
|
77
|
-
)
|
|
78
|
-
BLOCKSCOUT_API_URL = (
|
|
79
|
-
"https://gnosis.blockscout.com/api/v2/smart-contracts/{contract_address}"
|
|
80
|
-
)
|
|
58
|
+
MECH_CONFIGS = Path(__file__).parent / "configs" / "mechs.json"
|
|
81
59
|
|
|
82
60
|
MAX_RETRIES = 3
|
|
83
61
|
WAIT_SLEEP = 3.0
|
|
@@ -87,6 +65,80 @@ TIMEOUT = 60.0
|
|
|
87
65
|
warnings.filterwarnings("ignore", "The log with transaction hash.*")
|
|
88
66
|
|
|
89
67
|
|
|
68
|
+
@dataclass
|
|
69
|
+
class LedgerConfig:
|
|
70
|
+
"""Ledger configuration"""
|
|
71
|
+
|
|
72
|
+
address: str
|
|
73
|
+
chain_id: int
|
|
74
|
+
poa_chain: bool
|
|
75
|
+
default_gas_price_strategy: str
|
|
76
|
+
is_gas_estimation_enabled: bool
|
|
77
|
+
|
|
78
|
+
def __post_init__(self) -> None:
|
|
79
|
+
"""Post initialization to override with environment variables."""
|
|
80
|
+
address = os.getenv("MECHX_LEDGER_ADDRESS")
|
|
81
|
+
if address:
|
|
82
|
+
self.address = address
|
|
83
|
+
|
|
84
|
+
chain_id = os.getenv("MECHX_LEDGER_CHAIN_ID")
|
|
85
|
+
if chain_id:
|
|
86
|
+
self.chain_id = int(chain_id)
|
|
87
|
+
|
|
88
|
+
poa_chain = os.getenv("MECHX_LEDGER_POA_CHAIN")
|
|
89
|
+
if poa_chain:
|
|
90
|
+
self.poa_chain = bool(poa_chain)
|
|
91
|
+
|
|
92
|
+
default_gas_price_strategy = os.getenv(
|
|
93
|
+
"MECHX_LEDGER_DEFAULT_GAS_PRICE_STRATEGY"
|
|
94
|
+
)
|
|
95
|
+
if default_gas_price_strategy:
|
|
96
|
+
self.default_gas_price_strategy = default_gas_price_strategy
|
|
97
|
+
|
|
98
|
+
is_gas_estimation_enabled = os.getenv("MECHX_LEDGER_IS_GAS_ESTIMATION_ENABLED")
|
|
99
|
+
if is_gas_estimation_enabled:
|
|
100
|
+
self.is_gas_estimation_enabled = bool(is_gas_estimation_enabled)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class MechConfig:
|
|
105
|
+
"""Mech configuration"""
|
|
106
|
+
|
|
107
|
+
agent_registry_contract: str
|
|
108
|
+
rpc_url: str
|
|
109
|
+
wss_endpoint: str
|
|
110
|
+
ledger_config: LedgerConfig
|
|
111
|
+
gas_limit: int
|
|
112
|
+
contract_abi_url: str
|
|
113
|
+
subgraph_url: str
|
|
114
|
+
|
|
115
|
+
def __post_init__(self) -> None:
|
|
116
|
+
"""Post initialization to override with environment variables."""
|
|
117
|
+
agent_registry_contract = os.getenv("MECHX_AGENT_REGISTRY_CONTRACT")
|
|
118
|
+
if agent_registry_contract:
|
|
119
|
+
self.agent_registry_contract = agent_registry_contract
|
|
120
|
+
|
|
121
|
+
rpc_url = os.getenv("MECHX_CHAIN_RPC")
|
|
122
|
+
if rpc_url:
|
|
123
|
+
self.rpc_url = rpc_url
|
|
124
|
+
|
|
125
|
+
wss_endpoint = os.getenv("MECHX_WSS_ENDPOINT")
|
|
126
|
+
if wss_endpoint:
|
|
127
|
+
self.wss_endpoint = wss_endpoint
|
|
128
|
+
|
|
129
|
+
gas_limit = os.getenv("MECHX_GAS_LIMIT")
|
|
130
|
+
if gas_limit:
|
|
131
|
+
self.gas_limit = int(gas_limit)
|
|
132
|
+
|
|
133
|
+
contract_abi_url = os.getenv("MECHX_CONTRACT_ABI_URL")
|
|
134
|
+
if contract_abi_url:
|
|
135
|
+
self.contract_abi_url = contract_abi_url
|
|
136
|
+
|
|
137
|
+
subgraph_url = os.getenv("MECHX_SUBGRAPH_URL")
|
|
138
|
+
if subgraph_url:
|
|
139
|
+
self.subgraph_url = subgraph_url
|
|
140
|
+
|
|
141
|
+
|
|
90
142
|
class ConfirmationType(Enum):
|
|
91
143
|
"""Verification type."""
|
|
92
144
|
|
|
@@ -95,6 +147,21 @@ class ConfirmationType(Enum):
|
|
|
95
147
|
WAIT_FOR_BOTH = "wait-for-both"
|
|
96
148
|
|
|
97
149
|
|
|
150
|
+
def get_mech_config(chain_config: Optional[str] = None) -> MechConfig:
|
|
151
|
+
"""Get `MechConfig` configuration"""
|
|
152
|
+
with open(MECH_CONFIGS, "r", encoding="UTF-8") as file:
|
|
153
|
+
data = json.load(file)
|
|
154
|
+
|
|
155
|
+
if chain_config is None:
|
|
156
|
+
chain_config = next(iter(data))
|
|
157
|
+
|
|
158
|
+
print(f"Chain configuration: {chain_config}")
|
|
159
|
+
entry = data[chain_config].copy()
|
|
160
|
+
ledger_config = LedgerConfig(**entry.pop("ledger_config"))
|
|
161
|
+
mech_config = MechConfig(**entry, ledger_config=ledger_config)
|
|
162
|
+
return mech_config
|
|
163
|
+
|
|
164
|
+
|
|
98
165
|
def calculate_topic_id(event: Dict) -> str:
|
|
99
166
|
"""Caclulate topic ID"""
|
|
100
167
|
text = event["name"]
|
|
@@ -120,11 +187,22 @@ def get_event_signatures(abi: List) -> Tuple[str, str]:
|
|
|
120
187
|
return request, deliver
|
|
121
188
|
|
|
122
189
|
|
|
123
|
-
def get_abi(contract_address: str) -> List:
|
|
190
|
+
def get_abi(contract_address: str, contract_abi_url: str) -> List:
|
|
124
191
|
"""Get contract abi"""
|
|
125
|
-
abi_request_url =
|
|
192
|
+
abi_request_url = contract_abi_url.format(contract_address=contract_address)
|
|
126
193
|
response = requests.get(abi_request_url).json()
|
|
127
|
-
|
|
194
|
+
|
|
195
|
+
if "result" in response:
|
|
196
|
+
result = response["result"]
|
|
197
|
+
try:
|
|
198
|
+
abi = json.loads(result)
|
|
199
|
+
except json.JSONDecodeError:
|
|
200
|
+
print("Error: Failed to parse 'result' field as JSON")
|
|
201
|
+
sys.exit(1)
|
|
202
|
+
else:
|
|
203
|
+
abi = response.get("abi")
|
|
204
|
+
|
|
205
|
+
return abi if abi else []
|
|
128
206
|
|
|
129
207
|
|
|
130
208
|
def get_contract(
|
|
@@ -190,7 +268,11 @@ def _tool_selector_prompt(available_tools: List[str]) -> str:
|
|
|
190
268
|
|
|
191
269
|
|
|
192
270
|
def verify_or_retrieve_tool(
|
|
193
|
-
agent_id: int,
|
|
271
|
+
agent_id: int,
|
|
272
|
+
ledger_api: EthereumApi,
|
|
273
|
+
agent_registry_contract: str,
|
|
274
|
+
contract_abi_url: str,
|
|
275
|
+
tool: Optional[str] = None,
|
|
194
276
|
) -> str:
|
|
195
277
|
"""
|
|
196
278
|
Checks if the tool is valid and for what agent.
|
|
@@ -199,12 +281,21 @@ def verify_or_retrieve_tool(
|
|
|
199
281
|
:type agent_id: int
|
|
200
282
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
201
283
|
:type ledger_api: EthereumApi
|
|
284
|
+
:param agent_registry_contract: Agent registry contract address.
|
|
285
|
+
:type agent_registry_contract: str
|
|
286
|
+
:param contract_abi_url: Block explorer URL.
|
|
287
|
+
:type contract_abi_url: str
|
|
202
288
|
:param tool: The tool to verify or retrieve (optional).
|
|
203
289
|
:type tool: Optional[str]
|
|
204
290
|
:return: The result of the verification or retrieval.
|
|
205
291
|
:rtype: str
|
|
206
292
|
"""
|
|
207
|
-
available_tools = fetch_tools(
|
|
293
|
+
available_tools = fetch_tools(
|
|
294
|
+
agent_id=agent_id,
|
|
295
|
+
ledger_api=ledger_api,
|
|
296
|
+
agent_registry_contract=agent_registry_contract,
|
|
297
|
+
contract_abi_url=contract_abi_url,
|
|
298
|
+
)
|
|
208
299
|
if tool is not None and tool not in available_tools:
|
|
209
300
|
raise ValueError(
|
|
210
301
|
f"Provided tool `{tool}` not in the list of available tools; Available tools={available_tools}"
|
|
@@ -214,11 +305,16 @@ def verify_or_retrieve_tool(
|
|
|
214
305
|
return _tool_selector_prompt(available_tools=available_tools)
|
|
215
306
|
|
|
216
307
|
|
|
217
|
-
def fetch_tools(
|
|
308
|
+
def fetch_tools(
|
|
309
|
+
agent_id: int,
|
|
310
|
+
ledger_api: EthereumApi,
|
|
311
|
+
agent_registry_contract: str,
|
|
312
|
+
contract_abi_url: str,
|
|
313
|
+
) -> List[str]:
|
|
218
314
|
"""Fetch tools for specified agent ID."""
|
|
219
315
|
mech_registry = get_contract(
|
|
220
|
-
contract_address=
|
|
221
|
-
abi=get_abi(
|
|
316
|
+
contract_address=agent_registry_contract,
|
|
317
|
+
abi=get_abi(agent_registry_contract, contract_abi_url),
|
|
222
318
|
ledger_api=ledger_api,
|
|
223
319
|
)
|
|
224
320
|
token_uri = mech_registry.functions.tokenURI(agent_id).call()
|
|
@@ -230,6 +326,7 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
230
326
|
crypto: EthereumCrypto,
|
|
231
327
|
ledger_api: EthereumApi,
|
|
232
328
|
mech_contract: Web3Contract,
|
|
329
|
+
gas_limit: int,
|
|
233
330
|
prompt: str,
|
|
234
331
|
tool: str,
|
|
235
332
|
extra_attributes: Optional[Dict[str, Any]] = None,
|
|
@@ -237,7 +334,7 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
237
334
|
retries: Optional[int] = None,
|
|
238
335
|
timeout: Optional[float] = None,
|
|
239
336
|
sleep: Optional[float] = None,
|
|
240
|
-
) ->
|
|
337
|
+
) -> Optional[str]:
|
|
241
338
|
"""
|
|
242
339
|
Sends a request to the mech.
|
|
243
340
|
|
|
@@ -247,6 +344,8 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
247
344
|
:type ledger_api: EthereumApi
|
|
248
345
|
:param mech_contract: The mech contract instance.
|
|
249
346
|
:type mech_contract: Web3Contract
|
|
347
|
+
:param gas_limit: Gas limit.
|
|
348
|
+
:type gas_limit: int
|
|
250
349
|
:param prompt: The request prompt.
|
|
251
350
|
:type prompt: str
|
|
252
351
|
:param tool: The requested tool.
|
|
@@ -261,6 +360,8 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
261
360
|
:type timeout: float
|
|
262
361
|
:param sleep: Amount of sleep before retrying the transaction
|
|
263
362
|
:type sleep: float
|
|
363
|
+
:return: The transaction hash.
|
|
364
|
+
:rtype: Optional[str]
|
|
264
365
|
"""
|
|
265
366
|
v1_file_hash_hex_truncated, v1_file_hash_hex = push_metadata_to_ipfs(
|
|
266
367
|
prompt, tool, extra_attributes
|
|
@@ -271,7 +372,7 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
271
372
|
tx_args = {
|
|
272
373
|
"sender_address": crypto.address,
|
|
273
374
|
"value": price,
|
|
274
|
-
"gas":
|
|
375
|
+
"gas": gas_limit,
|
|
275
376
|
}
|
|
276
377
|
|
|
277
378
|
tries = 0
|
|
@@ -296,18 +397,20 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
296
397
|
raise_on_try=True,
|
|
297
398
|
)
|
|
298
399
|
print(f"Transaction sent: https://gnosisscan.io/tx/{transaction_digest}")
|
|
299
|
-
return
|
|
400
|
+
return transaction_digest
|
|
300
401
|
except Exception as e: # pylint: disable=broad-except
|
|
301
402
|
print(
|
|
302
403
|
f"Error occured while sending the transaction: {e}; Retrying in {sleep}"
|
|
303
404
|
)
|
|
304
405
|
time.sleep(sleep)
|
|
406
|
+
return None
|
|
305
407
|
|
|
306
408
|
|
|
307
409
|
def wait_for_data_url( # pylint: disable=too-many-arguments
|
|
308
410
|
request_id: str,
|
|
309
411
|
wss: websocket.WebSocket,
|
|
310
412
|
mech_contract: Web3Contract,
|
|
413
|
+
subgraph_url: str,
|
|
311
414
|
deliver_signature: str,
|
|
312
415
|
ledger_api: EthereumApi,
|
|
313
416
|
crypto: Crypto,
|
|
@@ -322,6 +425,8 @@ def wait_for_data_url( # pylint: disable=too-many-arguments
|
|
|
322
425
|
:type wss: websocket.WebSocket
|
|
323
426
|
:param mech_contract: The mech contract instance.
|
|
324
427
|
:type mech_contract: Web3Contract
|
|
428
|
+
:param subgraph_url: Subgraph URL.
|
|
429
|
+
:type subgraph_url: str
|
|
325
430
|
:param deliver_signature: Topic signature for Deliver event
|
|
326
431
|
:type deliver_signature: str
|
|
327
432
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
@@ -358,7 +463,7 @@ def wait_for_data_url( # pylint: disable=too-many-arguments
|
|
|
358
463
|
)
|
|
359
464
|
)
|
|
360
465
|
mech_task = loop.create_task(
|
|
361
|
-
watch_for_data_url_from_subgraph(request_id=request_id)
|
|
466
|
+
watch_for_data_url_from_subgraph(request_id=request_id, url=subgraph_url)
|
|
362
467
|
)
|
|
363
468
|
tasks.append(mech_task)
|
|
364
469
|
tasks.append(on_chain_task)
|
|
@@ -388,6 +493,7 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
388
493
|
retries: Optional[int] = None,
|
|
389
494
|
timeout: Optional[float] = None,
|
|
390
495
|
sleep: Optional[float] = None,
|
|
496
|
+
chain_config: Optional[str] = None,
|
|
391
497
|
) -> Any:
|
|
392
498
|
"""
|
|
393
499
|
Interact with agent mech contract.
|
|
@@ -411,9 +517,18 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
411
517
|
:type timeout: float
|
|
412
518
|
:param sleep: Amount of sleep before retrying the transaction
|
|
413
519
|
:type sleep: float
|
|
520
|
+
:param chain_config: Id of the mech's chain configuration (stored configs/mechs.json)
|
|
521
|
+
:type chain_config: str:
|
|
414
522
|
:rtype: Any
|
|
415
523
|
"""
|
|
416
|
-
|
|
524
|
+
mech_config = get_mech_config(chain_config)
|
|
525
|
+
ledger_config = mech_config.ledger_config
|
|
526
|
+
contract_address = query_agent_address(
|
|
527
|
+
agent_id=agent_id,
|
|
528
|
+
timeout=timeout,
|
|
529
|
+
url=mech_config.subgraph_url,
|
|
530
|
+
chain_config=chain_config,
|
|
531
|
+
)
|
|
417
532
|
if contract_address is None:
|
|
418
533
|
raise ValueError(f"Agent with ID {agent_id} does not exist!")
|
|
419
534
|
|
|
@@ -423,12 +538,21 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
423
538
|
f"Private key file `{private_key_path}` does not exist!"
|
|
424
539
|
)
|
|
425
540
|
|
|
426
|
-
wss = websocket.create_connection(
|
|
541
|
+
wss = websocket.create_connection(mech_config.wss_endpoint)
|
|
427
542
|
crypto = EthereumCrypto(private_key_path=private_key_path)
|
|
428
|
-
ledger_api = EthereumApi(**
|
|
543
|
+
ledger_api = EthereumApi(**asdict(ledger_config))
|
|
429
544
|
|
|
430
|
-
tool = verify_or_retrieve_tool(
|
|
431
|
-
|
|
545
|
+
tool = verify_or_retrieve_tool(
|
|
546
|
+
agent_id=agent_id,
|
|
547
|
+
ledger_api=ledger_api,
|
|
548
|
+
tool=tool,
|
|
549
|
+
agent_registry_contract=mech_config.agent_registry_contract,
|
|
550
|
+
contract_abi_url=mech_config.contract_abi_url,
|
|
551
|
+
)
|
|
552
|
+
abi = get_abi(
|
|
553
|
+
contract_address=contract_address,
|
|
554
|
+
contract_abi_url=mech_config.contract_abi_url,
|
|
555
|
+
)
|
|
432
556
|
mech_contract = get_contract(
|
|
433
557
|
contract_address=contract_address, abi=abi, ledger_api=ledger_api
|
|
434
558
|
)
|
|
@@ -444,6 +568,7 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
444
568
|
crypto=crypto,
|
|
445
569
|
ledger_api=ledger_api,
|
|
446
570
|
mech_contract=mech_contract,
|
|
571
|
+
gas_limit=mech_config.gas_limit,
|
|
447
572
|
prompt=prompt,
|
|
448
573
|
tool=tool,
|
|
449
574
|
extra_attributes=extra_attributes,
|
|
@@ -451,6 +576,7 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
451
576
|
timeout=timeout,
|
|
452
577
|
sleep=sleep,
|
|
453
578
|
)
|
|
579
|
+
print("Waiting for transaction receipt...")
|
|
454
580
|
request_id = watch_for_request_id(
|
|
455
581
|
wss=wss,
|
|
456
582
|
mech_contract=mech_contract,
|
|
@@ -462,6 +588,7 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
462
588
|
request_id=request_id,
|
|
463
589
|
wss=wss,
|
|
464
590
|
mech_contract=mech_contract,
|
|
591
|
+
subgraph_url=mech_config.subgraph_url,
|
|
465
592
|
deliver_signature=deliver_event_signature,
|
|
466
593
|
ledger_api=ledger_api,
|
|
467
594
|
crypto=crypto,
|
mech_client/subgraph.py
CHANGED
|
@@ -27,7 +27,6 @@ from gql import Client, gql
|
|
|
27
27
|
from gql.transport.aiohttp import AIOHTTPTransport
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
MECH_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/57238/mech/version/latest"
|
|
31
30
|
AGENT_QUERY_TEMPLATE = Template(
|
|
32
31
|
"""{
|
|
33
32
|
createMeches(where:{agentId:$agent_id}) {
|
|
@@ -51,20 +50,38 @@ DELIVER_QUERY_TEMPLATE = Template(
|
|
|
51
50
|
DEFAULT_TIMEOUT = 600.0
|
|
52
51
|
|
|
53
52
|
|
|
54
|
-
def query_agent_address(
|
|
55
|
-
agent_id: int,
|
|
53
|
+
def query_agent_address( # pylint: disable=too-many-return-statements
|
|
54
|
+
agent_id: int,
|
|
55
|
+
url: str,
|
|
56
|
+
timeout: Optional[float] = None,
|
|
57
|
+
chain_config: Optional[str] = None,
|
|
56
58
|
) -> Optional[str]:
|
|
57
59
|
"""
|
|
58
60
|
Query agent address from subgraph.
|
|
59
61
|
|
|
60
62
|
:param agent_id: The ID of the agent.
|
|
61
|
-
:param timeout: Timeout for the request.
|
|
62
63
|
:type agent_id: int
|
|
64
|
+
:param url: Subgraph URL.
|
|
65
|
+
:type url: str
|
|
66
|
+
:param timeout: Timeout for the request.
|
|
67
|
+
:type timeout: Optional[float]
|
|
68
|
+
:type chain_config: Optional[str]:
|
|
63
69
|
:return: The agent address if found, None otherwise.
|
|
64
70
|
:rtype: Optional[str]
|
|
65
71
|
"""
|
|
72
|
+
# temporary hard coded until subgraph present
|
|
73
|
+
if chain_config == "base" and agent_id == 2:
|
|
74
|
+
return "0x111D7DB1B752AB4D2cC0286983D9bd73a49bac6c"
|
|
75
|
+
if chain_config == "arbitrum" and agent_id == 2:
|
|
76
|
+
return "0x1FDAD3a5af5E96e5a64Fc0662B1814458F114597"
|
|
77
|
+
if chain_config == "polygon" and agent_id == 2:
|
|
78
|
+
return "0xbF92568718982bf65ee4af4F7020205dE2331a8a"
|
|
79
|
+
if chain_config == "celo" and agent_id == 2:
|
|
80
|
+
return "0x230eD015735c0D01EA0AaD2786Ed6Bd3C6e75912"
|
|
81
|
+
if chain_config == "optimism" and agent_id == 2:
|
|
82
|
+
return "0xDd40E7D93c37eFD860Bd53Ab90b2b0a8D05cf71a"
|
|
66
83
|
client = Client(
|
|
67
|
-
transport=AIOHTTPTransport(url=
|
|
84
|
+
transport=AIOHTTPTransport(url=url),
|
|
68
85
|
execute_timeout=timeout or 30.0,
|
|
69
86
|
)
|
|
70
87
|
response = client.execute(
|
|
@@ -81,19 +98,22 @@ def query_agent_address(
|
|
|
81
98
|
|
|
82
99
|
|
|
83
100
|
async def query_deliver_hash(
|
|
84
|
-
request_id: str, timeout: Optional[float] = None
|
|
101
|
+
request_id: str, url: str, timeout: Optional[float] = None
|
|
85
102
|
) -> Optional[str]:
|
|
86
103
|
"""
|
|
87
104
|
Query deliver IPFS hash from subgraph.
|
|
88
105
|
|
|
89
106
|
:param request_id: The ID of the mech request.
|
|
90
|
-
:param timeout: Timeout for the request.
|
|
91
107
|
:type request_id: str
|
|
108
|
+
:param url: Subgraph URL.
|
|
109
|
+
:type url: str
|
|
110
|
+
:param timeout: Timeout for the request.
|
|
111
|
+
:type timeout: Optional[float]
|
|
92
112
|
:return: The deliver IPFS hash if found, None otherwise.
|
|
93
113
|
:rtype: Optional[str]
|
|
94
114
|
"""
|
|
95
115
|
client = Client(
|
|
96
|
-
transport=AIOHTTPTransport(url=
|
|
116
|
+
transport=AIOHTTPTransport(url=url),
|
|
97
117
|
execute_timeout=timeout or 30.0,
|
|
98
118
|
)
|
|
99
119
|
response = await client.execute_async(
|
|
@@ -110,13 +130,15 @@ async def query_deliver_hash(
|
|
|
110
130
|
|
|
111
131
|
|
|
112
132
|
async def watch_for_data_url_from_subgraph(
|
|
113
|
-
request_id: str, timeout: Optional[float] = None
|
|
133
|
+
request_id: str, url: str, timeout: Optional[float] = None
|
|
114
134
|
) -> Optional[str]:
|
|
115
135
|
"""
|
|
116
136
|
Continuously query for data URL until it's available or timeout is reached.
|
|
117
137
|
|
|
118
138
|
:param request_id: The ID of the mech request.
|
|
119
139
|
:type request_id: str
|
|
140
|
+
:param url: Subgraph URL.
|
|
141
|
+
:type url: str
|
|
120
142
|
:param timeout: Maximum time to wait for the data URL in seconds. Defaults to DEFAULT_TIMEOUT.
|
|
121
143
|
:type timeout: Optional[float]
|
|
122
144
|
:return: Data URL if available within timeout, otherwise None.
|
|
@@ -125,7 +147,7 @@ async def watch_for_data_url_from_subgraph(
|
|
|
125
147
|
timeout = timeout or DEFAULT_TIMEOUT
|
|
126
148
|
start_time = asyncio.get_event_loop().time()
|
|
127
149
|
while True:
|
|
128
|
-
response = await query_deliver_hash(request_id=request_id)
|
|
150
|
+
response = await query_deliver_hash(request_id=request_id, url=url)
|
|
129
151
|
if response is not None:
|
|
130
152
|
return f"https://gateway.autonolas.tech/ipfs/{response}"
|
|
131
153
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mech-client
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.12
|
|
4
4
|
Summary: Basic client to interact with a mech
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: David Minarsch
|
|
@@ -31,16 +31,10 @@ Basic client to interact with a mech
|
|
|
31
31
|
pip install mech-client
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Then, set a websocket endpoint for Gnosis RPC like so:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
export WEBSOCKET_ENDPOINT=<YOUR ENDPOINT>
|
|
38
|
-
```
|
|
39
|
-
|
|
40
34
|
Note: If you encounter an "Out of gas" error when executing the tool, you will need to increase the gas limit by setting, e.g.,
|
|
41
35
|
|
|
42
36
|
```bash
|
|
43
|
-
export
|
|
37
|
+
export MECHX_GAS_LIMIT=200000
|
|
44
38
|
```
|
|
45
39
|
|
|
46
40
|
## CLI:
|
|
@@ -109,6 +103,7 @@ mechx interact <prompt> <agent_id> --key <key_file>
|
|
|
109
103
|
Example output:
|
|
110
104
|
```bash
|
|
111
105
|
mechx interact "write a short poem" 3 --key ~/gnosis_key --tool openai-text-davinci-003
|
|
106
|
+
Chain configuration: gnosis
|
|
112
107
|
Prompt uploaded: https://gateway.autonolas.tech/ipfs/f01701220ad773628911d12e28f005e3f249e990d684e5dba07542259195602f9afed30bf
|
|
113
108
|
Transaction sent: https://gnosisscan.io/tx/0x0d9209e32e965a820b9e80accfcd71ea3b1174b9758dd251c2e627a60ec426a5
|
|
114
109
|
Created on-chain request with ID 111240237160304797537720810617416341148235899500021985333360197012735240803849
|
|
@@ -116,10 +111,11 @@ Data arrived: https://gateway.autonolas.tech/ipfs/bafybeifk2h35ncszlze7t64rpblfo
|
|
|
116
111
|
Data from agent: {'requestId': 111240237160304797537720810617416341148235899500021985333360197012735240803849, 'result': "\n\nI am brave and I'm strong\nI don't hide away my song\nI am here and I'm proud\nMy voice will be heard loud!"}
|
|
117
112
|
```
|
|
118
113
|
|
|
119
|
-
By default the client will wait for data to arrive from on-chain using the websocket subscription and off-chain using the ACN and show you the result which arrives first. You can specify the type of confirmation you want using `--confirm` flag like this
|
|
114
|
+
By default the client will wait for data to arrive from on-chain using the websocket subscription and subgraph, and off-chain using the ACN and show you the result which arrives first. You can specify the type of confirmation you want using `--confirm` flag like this
|
|
120
115
|
|
|
121
116
|
```bash
|
|
122
117
|
mechx interact "write a short poem" 3 --key ~/gnosis_key --tool openai-text-davinci-003 --confirm on-chain
|
|
118
|
+
Chain configuration: gnosis
|
|
123
119
|
Prompt uploaded: https://gateway.autonolas.tech/ipfs/f017012205e37f761221a8ba4005e91c36b94153e9432b8888ff2acae6b101dd5a5de6768
|
|
124
120
|
Transaction sent: https://gnosisscan.io/tx/0xf1ef63f617717bbb8deb09699af99aa39f10155d33796de2fd7eb61c9c1458b6
|
|
125
121
|
Created on-chain request with ID 81653153529124597849081567361606842861262371002932574194580478443414142139857
|
|
@@ -127,6 +123,30 @@ Data arrived: https://gateway.autonolas.tech/ipfs/f0170122069b55e077430a00f3cbc3
|
|
|
127
123
|
Data from agent: {'requestId': 81653153529124597849081567361606842861262371002932574194580478443414142139857, 'result': "\n\nA summer breeze, so sweet,\nA gentle reminder of summer's heat.\nThe sky so blue, no cloud in sight,\nA perfect day, a wondrous sight."}
|
|
128
124
|
```
|
|
129
125
|
|
|
126
|
+
### Chain configuration
|
|
127
|
+
|
|
128
|
+
Configurations for different chains are stored in the file `configs/mechs.json`. By default, `mech interact` will choose the first configuration on the JSON. You can specify which config you want to use using the `--chain-config` flag, for example,
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
mechx interact <prompt> <agent_id> --chain-config gnosis
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Additionally, you can override any configuration parameter by exporting any of the following environment variables:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
MECHX_CHAIN_RPC
|
|
138
|
+
MECHX_WSS_ENDPOINT
|
|
139
|
+
MECHX_GAS_LIMIT
|
|
140
|
+
MECHX_CONTRACT_ABI_URL
|
|
141
|
+
MECHX_SUBGRAPH_URL
|
|
142
|
+
|
|
143
|
+
MECHX_LEDGER_ADDRESS
|
|
144
|
+
MECHX_LEDGER_CHAIN_ID
|
|
145
|
+
MECHX_LEDGER_POA_CHAIN
|
|
146
|
+
MECHX_LEDGER_DEFAULT_GAS_PRICE_STRATEGY
|
|
147
|
+
MECHX_LEDGER_IS_GAS_ESTIMATION_ENABLED
|
|
148
|
+
```
|
|
149
|
+
|
|
130
150
|
## Programmatic Usage:
|
|
131
151
|
|
|
132
152
|
```python
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
mech_client/__init__.py,sha256=
|
|
1
|
+
mech_client/__init__.py,sha256=s8E8bTccJTXUKsK6N8pSwD7FabU-dQUps-y98raJYZQ,43
|
|
2
2
|
mech_client/acn.py,sha256=Rj_jLPvJ5loDQfGbu3a_O24cJC4SwIErLceSz_zVYS8,5356
|
|
3
|
-
mech_client/cli.py,sha256=
|
|
3
|
+
mech_client/cli.py,sha256=QnC3Z_vth__ZiU12chRl8q5LYDLjyjzaofB41mWlq8c,4608
|
|
4
|
+
mech_client/configs/mechs.json,sha256=ed7mp5Z6qC8QuLIx4iqV9Y_u3KmIOhf3zMfpdZ951cQ,4026
|
|
4
5
|
mech_client/helpers/__init__.py,sha256=f13zpwGDaKQUjML-5Iq66rRfzg8IS5UNK5I8gBr7w54,1028
|
|
5
6
|
mech_client/helpers/acn/README.md,sha256=WMXR2Lk0IpWjr3vpZ8cxcTHk4gwsx4wC06UPkwj9dbQ,1641
|
|
6
7
|
mech_client/helpers/acn/__init__.py,sha256=72WrGEDIuYKvlWQnTajFQ9bNrDy2sFfTYDP62he4doI,1141
|
|
@@ -29,14 +30,14 @@ mech_client/helpers/p2p_libp2p_client/README.md,sha256=6x9s6P7TdKkcvAS1wMFHXRz4a
|
|
|
29
30
|
mech_client/helpers/p2p_libp2p_client/__init__.py,sha256=-GOP3D_JnmXTDomrMLCbnRk7vRQmihIqTYvyIPzx-q4,879
|
|
30
31
|
mech_client/helpers/p2p_libp2p_client/connection.py,sha256=pvfHtI-NhgDbay1wLNit6m8InH4c0p00c3hQo0I2jwQ,27887
|
|
31
32
|
mech_client/helpers/p2p_libp2p_client/connection.yaml,sha256=giYV5FwwugD7ha9IqFHJtvs-Oz1jC5og9rpkstrTqoc,1763
|
|
32
|
-
mech_client/interact.py,sha256=
|
|
33
|
+
mech_client/interact.py,sha256=uRJEcJ8idIm-erGNNBugLGVgYwVO9HmSl2NKPvy248w,19631
|
|
33
34
|
mech_client/prompt_to_ipfs.py,sha256=XqSIBko15MEkpWOQNT97fRI6jNxMF5EDBDEPOJFdhyk,2533
|
|
34
35
|
mech_client/push_to_ipfs.py,sha256=IfvgaPU79N_ZmCPF9d7sPCYz2uduZH0KjT_HQ2LHXoQ,2059
|
|
35
|
-
mech_client/subgraph.py,sha256=
|
|
36
|
+
mech_client/subgraph.py,sha256=4vY6QFyUVs15gS0SvanJbvAxb3aie07IuxQnfMMnStc,4931
|
|
36
37
|
mech_client/to_png.py,sha256=pjUcFJ63MJj_r73eqnfqCWMtlpsrj6H4ZmgvIEmRcFw,2581
|
|
37
38
|
mech_client/wss.py,sha256=klvSOMoUbt8-NwVBNH1G3Tlu4Ll9192dgmr6fA1hGNc,6214
|
|
38
|
-
mech_client-0.2.
|
|
39
|
-
mech_client-0.2.
|
|
40
|
-
mech_client-0.2.
|
|
41
|
-
mech_client-0.2.
|
|
42
|
-
mech_client-0.2.
|
|
39
|
+
mech_client-0.2.12.dist-info/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
|
|
40
|
+
mech_client-0.2.12.dist-info/METADATA,sha256=orPKVVfYHtc3tJn0u_FH258fNBiDWpEXddPyn5Buboo,6443
|
|
41
|
+
mech_client-0.2.12.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
|
42
|
+
mech_client-0.2.12.dist-info/entry_points.txt,sha256=SbRMRsayzD8XfNXhgwPuXEqQsdZ5Bw9XDPnUuaDExyY,45
|
|
43
|
+
mech_client-0.2.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|