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 CHANGED
@@ -1,3 +1,3 @@
1
1
  """Mech client."""
2
2
 
3
- __version__ = "0.2.11"
3
+ __version__ = "0.2.12"
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 = BLOCKSCOUT_API_URL.format(contract_address=contract_address)
192
+ abi_request_url = contract_abi_url.format(contract_address=contract_address)
126
193
  response = requests.get(abi_request_url).json()
127
- return response["abi"]
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, ledger_api: EthereumApi, tool: Optional[str] = None
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(agent_id=agent_id, ledger_api=ledger_api)
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(agent_id: int, ledger_api: EthereumApi) -> List[str]:
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=AGENT_REGISTRY_CONTRACT,
221
- abi=get_abi(AGENT_REGISTRY_CONTRACT),
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
- ) -> None:
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": MANUAL_GAS_LIMIT,
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
- contract_address = query_agent_address(agent_id=agent_id, timeout=timeout)
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(WSS_ENDPOINT)
541
+ wss = websocket.create_connection(mech_config.wss_endpoint)
427
542
  crypto = EthereumCrypto(private_key_path=private_key_path)
428
- ledger_api = EthereumApi(**LEDGER_CONFIG)
543
+ ledger_api = EthereumApi(**asdict(ledger_config))
429
544
 
430
- tool = verify_or_retrieve_tool(agent_id=agent_id, ledger_api=ledger_api, tool=tool)
431
- abi = get_abi(contract_address=contract_address)
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, timeout: Optional[float] = None
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=MECH_SUBGRAPH_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=MECH_SUBGRAPH_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.11
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 MANUAL_GAS_LIMIT=200000
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=gBjxKCL17t0uinR0QxPEduX_ZxmuNvsWEzEKtUJGnXA,43
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=mhvNPLFTdtRlDNCFD0LMQxJCchR1itRCmmGhJHwCgrg,4399
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=fMF1ggphSHF3lJAGAX8d5sWJHdI8uvYUEEXZgrIF7ac,15648
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=rkMkIY2Ovz6KdMT5Ip2_hnPkZVJdXKfgh_Eiw0p_4fU,4049
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.11.dist-info/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
39
- mech_client-0.2.11.dist-info/METADATA,sha256=O-X6H6niKPFbS6NSNpmO6RHwm8Zsohbya7cghFMbt_E,5771
40
- mech_client-0.2.11.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
41
- mech_client-0.2.11.dist-info/entry_points.txt,sha256=SbRMRsayzD8XfNXhgwPuXEqQsdZ5Bw9XDPnUuaDExyY,45
42
- mech_client-0.2.11.dist-info/RECORD,,
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,,