mech-client 0.2.11__py3-none-any.whl → 0.2.13__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 +98 -0
- mech_client/interact.py +197 -54
- mech_client/subgraph.py +32 -10
- mech_client/wss.py +22 -15
- mech_client-0.2.13.dist-info/METADATA +293 -0
- {mech_client-0.2.11.dist-info → mech_client-0.2.13.dist-info}/RECORD +11 -10
- mech_client-0.2.11.dist-info/METADATA +0 -164
- {mech_client-0.2.11.dist-info → mech_client-0.2.13.dist-info}/LICENSE +0 -0
- {mech_client-0.2.11.dist-info → mech_client-0.2.13.dist-info}/WHEEL +0 -0
- {mech_client-0.2.11.dist-info → mech_client-0.2.13.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,98 @@
|
|
|
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
|
+
"transaction_url": "https://gnosisscan.io/tx/{transaction_digest}",
|
|
16
|
+
"subgraph_url": "https://api.studio.thegraph.com/query/57238/mech/version/latest"
|
|
17
|
+
},
|
|
18
|
+
"arbitrum": {
|
|
19
|
+
"agent_registry_contract": "0xa4799B083E0068732456EF45ff9fe5c683658327",
|
|
20
|
+
"rpc_url": "https://arbitrum.llamarpc.com",
|
|
21
|
+
"wss_endpoint": "wss://arbitrum.gateway.tenderly.co",
|
|
22
|
+
"ledger_config": {
|
|
23
|
+
"address": "https://arbitrum.llamarpc.com",
|
|
24
|
+
"chain_id": 42161,
|
|
25
|
+
"poa_chain": false,
|
|
26
|
+
"default_gas_price_strategy": "eip1559",
|
|
27
|
+
"is_gas_estimation_enabled": false
|
|
28
|
+
},
|
|
29
|
+
"gas_limit": 100000,
|
|
30
|
+
"contract_abi_url": "https://api.arbiscan.io/api?module=contract&action=getabi&address={contract_address}",
|
|
31
|
+
"transaction_url": "https://arbiscan.io/tx/{transaction_digest}",
|
|
32
|
+
"subgraph_url": ""
|
|
33
|
+
},
|
|
34
|
+
"polygon": {
|
|
35
|
+
"agent_registry_contract": "0x984cf72FDe8B5aA910e9e508aC5e007ae5BDcC9C",
|
|
36
|
+
"rpc_url": "https://polygon-bor-rpc.publicnode.com",
|
|
37
|
+
"wss_endpoint": "wss://polygon.gateway.tenderly.co",
|
|
38
|
+
"ledger_config": {
|
|
39
|
+
"address": "https://polygon-bor-rpc.publicnode.com",
|
|
40
|
+
"chain_id": 137,
|
|
41
|
+
"poa_chain": true,
|
|
42
|
+
"default_gas_price_strategy": "eip1559",
|
|
43
|
+
"is_gas_estimation_enabled": false
|
|
44
|
+
},
|
|
45
|
+
"gas_limit": 100000,
|
|
46
|
+
"contract_abi_url": "https://api.polygonscan.com/api?module=contract&action=getabi&address={contract_address}",
|
|
47
|
+
"transaction_url": "https://polygonscan.com/tx/{transaction_digest}",
|
|
48
|
+
"subgraph_url": ""
|
|
49
|
+
},
|
|
50
|
+
"base": {
|
|
51
|
+
"agent_registry_contract": "0x88DE734655184a09B70700aE4F72364d1ad23728",
|
|
52
|
+
"rpc_url": "https://base.llamarpc.com",
|
|
53
|
+
"wss_endpoint": "wss://base.gateway.tenderly.co",
|
|
54
|
+
"ledger_config": {
|
|
55
|
+
"address": "https://base.llamarpc.com",
|
|
56
|
+
"chain_id": 8453,
|
|
57
|
+
"poa_chain": false,
|
|
58
|
+
"default_gas_price_strategy": "eip1559",
|
|
59
|
+
"is_gas_estimation_enabled": false
|
|
60
|
+
},
|
|
61
|
+
"gas_limit": 100000,
|
|
62
|
+
"contract_abi_url": "https://api.basescan.org/api?module=contract&action=getabi&address={contract_address}",
|
|
63
|
+
"transaction_url": "https://basescan.org/tx/{transaction_digest}",
|
|
64
|
+
"subgraph_url": ""
|
|
65
|
+
},
|
|
66
|
+
"celo": {
|
|
67
|
+
"agent_registry_contract": "0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA",
|
|
68
|
+
"rpc_url": "https://forno.celo.org",
|
|
69
|
+
"wss_endpoint": "wss://forno.celo.org/ws",
|
|
70
|
+
"ledger_config": {
|
|
71
|
+
"address": "https://forno.celo.org",
|
|
72
|
+
"chain_id": 42220,
|
|
73
|
+
"poa_chain": true,
|
|
74
|
+
"default_gas_price_strategy": "eip1559",
|
|
75
|
+
"is_gas_estimation_enabled": false
|
|
76
|
+
},
|
|
77
|
+
"gas_limit": 250000,
|
|
78
|
+
"contract_abi_url": "https://api.celoscan.io/api?module=contract&action=getabi&address={contract_address}",
|
|
79
|
+
"transaction_url": "https://celoscan.io/tx/{transaction_digest}",
|
|
80
|
+
"subgraph_url": ""
|
|
81
|
+
},
|
|
82
|
+
"optimism": {
|
|
83
|
+
"agent_registry_contract": "0x75D529FAe220bC8db714F0202193726b46881B76",
|
|
84
|
+
"rpc_url": "https://mainnet.optimism.io",
|
|
85
|
+
"wss_endpoint": "wss://optimism.gateway.tenderly.co",
|
|
86
|
+
"ledger_config": {
|
|
87
|
+
"address": "https://mainnet.optimism.io",
|
|
88
|
+
"chain_id": 10,
|
|
89
|
+
"poa_chain": false,
|
|
90
|
+
"default_gas_price_strategy": "eip1559",
|
|
91
|
+
"is_gas_estimation_enabled": false
|
|
92
|
+
},
|
|
93
|
+
"gas_limit": 100000,
|
|
94
|
+
"contract_abi_url": "https://api-optimistic.etherscan.io/api?module=contract&action=getabi&address={contract_address}",
|
|
95
|
+
"transaction_url": "https://optimistic.etherscan.io/tx/{transaction_digest}",
|
|
96
|
+
"subgraph_url": ""
|
|
97
|
+
}
|
|
98
|
+
}
|
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,85 @@ 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: # pylint: disable=too-many-instance-attributes
|
|
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
|
+
transaction_url: str
|
|
114
|
+
subgraph_url: str
|
|
115
|
+
|
|
116
|
+
def __post_init__(self) -> None:
|
|
117
|
+
"""Post initialization to override with environment variables."""
|
|
118
|
+
agent_registry_contract = os.getenv("MECHX_AGENT_REGISTRY_CONTRACT")
|
|
119
|
+
if agent_registry_contract:
|
|
120
|
+
self.agent_registry_contract = agent_registry_contract
|
|
121
|
+
|
|
122
|
+
rpc_url = os.getenv("MECHX_CHAIN_RPC")
|
|
123
|
+
if rpc_url:
|
|
124
|
+
self.rpc_url = rpc_url
|
|
125
|
+
|
|
126
|
+
wss_endpoint = os.getenv("MECHX_WSS_ENDPOINT")
|
|
127
|
+
if wss_endpoint:
|
|
128
|
+
self.wss_endpoint = wss_endpoint
|
|
129
|
+
|
|
130
|
+
gas_limit = os.getenv("MECHX_GAS_LIMIT")
|
|
131
|
+
if gas_limit:
|
|
132
|
+
self.gas_limit = int(gas_limit)
|
|
133
|
+
|
|
134
|
+
contract_abi_url = os.getenv("MECHX_CONTRACT_ABI_URL")
|
|
135
|
+
if contract_abi_url:
|
|
136
|
+
self.contract_abi_url = contract_abi_url
|
|
137
|
+
|
|
138
|
+
transaction_url = os.getenv("MECHX_TRANSACTION_URL")
|
|
139
|
+
if transaction_url:
|
|
140
|
+
self.transaction_url = transaction_url
|
|
141
|
+
|
|
142
|
+
subgraph_url = os.getenv("MECHX_SUBGRAPH_URL")
|
|
143
|
+
if subgraph_url:
|
|
144
|
+
self.subgraph_url = subgraph_url
|
|
145
|
+
|
|
146
|
+
|
|
90
147
|
class ConfirmationType(Enum):
|
|
91
148
|
"""Verification type."""
|
|
92
149
|
|
|
@@ -95,6 +152,21 @@ class ConfirmationType(Enum):
|
|
|
95
152
|
WAIT_FOR_BOTH = "wait-for-both"
|
|
96
153
|
|
|
97
154
|
|
|
155
|
+
def get_mech_config(chain_config: Optional[str] = None) -> MechConfig:
|
|
156
|
+
"""Get `MechConfig` configuration"""
|
|
157
|
+
with open(MECH_CONFIGS, "r", encoding="UTF-8") as file:
|
|
158
|
+
data = json.load(file)
|
|
159
|
+
|
|
160
|
+
if chain_config is None:
|
|
161
|
+
chain_config = next(iter(data))
|
|
162
|
+
|
|
163
|
+
print(f"Chain configuration: {chain_config}")
|
|
164
|
+
entry = data[chain_config].copy()
|
|
165
|
+
ledger_config = LedgerConfig(**entry.pop("ledger_config"))
|
|
166
|
+
mech_config = MechConfig(**entry, ledger_config=ledger_config)
|
|
167
|
+
return mech_config
|
|
168
|
+
|
|
169
|
+
|
|
98
170
|
def calculate_topic_id(event: Dict) -> str:
|
|
99
171
|
"""Caclulate topic ID"""
|
|
100
172
|
text = event["name"]
|
|
@@ -120,11 +192,22 @@ def get_event_signatures(abi: List) -> Tuple[str, str]:
|
|
|
120
192
|
return request, deliver
|
|
121
193
|
|
|
122
194
|
|
|
123
|
-
def get_abi(contract_address: str) -> List:
|
|
195
|
+
def get_abi(contract_address: str, contract_abi_url: str) -> List:
|
|
124
196
|
"""Get contract abi"""
|
|
125
|
-
abi_request_url =
|
|
197
|
+
abi_request_url = contract_abi_url.format(contract_address=contract_address)
|
|
126
198
|
response = requests.get(abi_request_url).json()
|
|
127
|
-
|
|
199
|
+
|
|
200
|
+
if "result" in response:
|
|
201
|
+
result = response["result"]
|
|
202
|
+
try:
|
|
203
|
+
abi = json.loads(result)
|
|
204
|
+
except json.JSONDecodeError:
|
|
205
|
+
print("Error: Failed to parse 'result' field as JSON")
|
|
206
|
+
sys.exit(1)
|
|
207
|
+
else:
|
|
208
|
+
abi = response.get("abi")
|
|
209
|
+
|
|
210
|
+
return abi if abi else []
|
|
128
211
|
|
|
129
212
|
|
|
130
213
|
def get_contract(
|
|
@@ -190,7 +273,11 @@ def _tool_selector_prompt(available_tools: List[str]) -> str:
|
|
|
190
273
|
|
|
191
274
|
|
|
192
275
|
def verify_or_retrieve_tool(
|
|
193
|
-
agent_id: int,
|
|
276
|
+
agent_id: int,
|
|
277
|
+
ledger_api: EthereumApi,
|
|
278
|
+
agent_registry_contract: str,
|
|
279
|
+
contract_abi_url: str,
|
|
280
|
+
tool: Optional[str] = None,
|
|
194
281
|
) -> str:
|
|
195
282
|
"""
|
|
196
283
|
Checks if the tool is valid and for what agent.
|
|
@@ -199,12 +286,21 @@ def verify_or_retrieve_tool(
|
|
|
199
286
|
:type agent_id: int
|
|
200
287
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
201
288
|
:type ledger_api: EthereumApi
|
|
289
|
+
:param agent_registry_contract: Agent registry contract address.
|
|
290
|
+
:type agent_registry_contract: str
|
|
291
|
+
:param contract_abi_url: Block explorer URL.
|
|
292
|
+
:type contract_abi_url: str
|
|
202
293
|
:param tool: The tool to verify or retrieve (optional).
|
|
203
294
|
:type tool: Optional[str]
|
|
204
295
|
:return: The result of the verification or retrieval.
|
|
205
296
|
:rtype: str
|
|
206
297
|
"""
|
|
207
|
-
available_tools = fetch_tools(
|
|
298
|
+
available_tools = fetch_tools(
|
|
299
|
+
agent_id=agent_id,
|
|
300
|
+
ledger_api=ledger_api,
|
|
301
|
+
agent_registry_contract=agent_registry_contract,
|
|
302
|
+
contract_abi_url=contract_abi_url,
|
|
303
|
+
)
|
|
208
304
|
if tool is not None and tool not in available_tools:
|
|
209
305
|
raise ValueError(
|
|
210
306
|
f"Provided tool `{tool}` not in the list of available tools; Available tools={available_tools}"
|
|
@@ -214,11 +310,16 @@ def verify_or_retrieve_tool(
|
|
|
214
310
|
return _tool_selector_prompt(available_tools=available_tools)
|
|
215
311
|
|
|
216
312
|
|
|
217
|
-
def fetch_tools(
|
|
313
|
+
def fetch_tools(
|
|
314
|
+
agent_id: int,
|
|
315
|
+
ledger_api: EthereumApi,
|
|
316
|
+
agent_registry_contract: str,
|
|
317
|
+
contract_abi_url: str,
|
|
318
|
+
) -> List[str]:
|
|
218
319
|
"""Fetch tools for specified agent ID."""
|
|
219
320
|
mech_registry = get_contract(
|
|
220
|
-
contract_address=
|
|
221
|
-
abi=get_abi(
|
|
321
|
+
contract_address=agent_registry_contract,
|
|
322
|
+
abi=get_abi(agent_registry_contract, contract_abi_url),
|
|
222
323
|
ledger_api=ledger_api,
|
|
223
324
|
)
|
|
224
325
|
token_uri = mech_registry.functions.tokenURI(agent_id).call()
|
|
@@ -230,6 +331,7 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
230
331
|
crypto: EthereumCrypto,
|
|
231
332
|
ledger_api: EthereumApi,
|
|
232
333
|
mech_contract: Web3Contract,
|
|
334
|
+
gas_limit: int,
|
|
233
335
|
prompt: str,
|
|
234
336
|
tool: str,
|
|
235
337
|
extra_attributes: Optional[Dict[str, Any]] = None,
|
|
@@ -237,7 +339,7 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
237
339
|
retries: Optional[int] = None,
|
|
238
340
|
timeout: Optional[float] = None,
|
|
239
341
|
sleep: Optional[float] = None,
|
|
240
|
-
) ->
|
|
342
|
+
) -> Optional[str]:
|
|
241
343
|
"""
|
|
242
344
|
Sends a request to the mech.
|
|
243
345
|
|
|
@@ -247,6 +349,8 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
247
349
|
:type ledger_api: EthereumApi
|
|
248
350
|
:param mech_contract: The mech contract instance.
|
|
249
351
|
:type mech_contract: Web3Contract
|
|
352
|
+
:param gas_limit: Gas limit.
|
|
353
|
+
:type gas_limit: int
|
|
250
354
|
:param prompt: The request prompt.
|
|
251
355
|
:type prompt: str
|
|
252
356
|
:param tool: The requested tool.
|
|
@@ -261,6 +365,8 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
261
365
|
:type timeout: float
|
|
262
366
|
:param sleep: Amount of sleep before retrying the transaction
|
|
263
367
|
:type sleep: float
|
|
368
|
+
:return: The transaction hash.
|
|
369
|
+
:rtype: Optional[str]
|
|
264
370
|
"""
|
|
265
371
|
v1_file_hash_hex_truncated, v1_file_hash_hex = push_metadata_to_ipfs(
|
|
266
372
|
prompt, tool, extra_attributes
|
|
@@ -271,7 +377,7 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
271
377
|
tx_args = {
|
|
272
378
|
"sender_address": crypto.address,
|
|
273
379
|
"value": price,
|
|
274
|
-
"gas":
|
|
380
|
+
"gas": gas_limit,
|
|
275
381
|
}
|
|
276
382
|
|
|
277
383
|
tries = 0
|
|
@@ -295,19 +401,20 @@ def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
295
401
|
signed_transaction,
|
|
296
402
|
raise_on_try=True,
|
|
297
403
|
)
|
|
298
|
-
|
|
299
|
-
return
|
|
404
|
+
return transaction_digest
|
|
300
405
|
except Exception as e: # pylint: disable=broad-except
|
|
301
406
|
print(
|
|
302
407
|
f"Error occured while sending the transaction: {e}; Retrying in {sleep}"
|
|
303
408
|
)
|
|
304
409
|
time.sleep(sleep)
|
|
410
|
+
return None
|
|
305
411
|
|
|
306
412
|
|
|
307
413
|
def wait_for_data_url( # pylint: disable=too-many-arguments
|
|
308
414
|
request_id: str,
|
|
309
415
|
wss: websocket.WebSocket,
|
|
310
416
|
mech_contract: Web3Contract,
|
|
417
|
+
subgraph_url: str,
|
|
311
418
|
deliver_signature: str,
|
|
312
419
|
ledger_api: EthereumApi,
|
|
313
420
|
crypto: Crypto,
|
|
@@ -322,6 +429,8 @@ def wait_for_data_url( # pylint: disable=too-many-arguments
|
|
|
322
429
|
:type wss: websocket.WebSocket
|
|
323
430
|
:param mech_contract: The mech contract instance.
|
|
324
431
|
:type mech_contract: Web3Contract
|
|
432
|
+
:param subgraph_url: Subgraph URL.
|
|
433
|
+
:type subgraph_url: str
|
|
325
434
|
:param deliver_signature: Topic signature for Deliver event
|
|
326
435
|
:type deliver_signature: str
|
|
327
436
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
@@ -357,12 +466,16 @@ def wait_for_data_url( # pylint: disable=too-many-arguments
|
|
|
357
466
|
loop=loop,
|
|
358
467
|
)
|
|
359
468
|
)
|
|
360
|
-
mech_task = loop.create_task(
|
|
361
|
-
watch_for_data_url_from_subgraph(request_id=request_id)
|
|
362
|
-
)
|
|
363
|
-
tasks.append(mech_task)
|
|
364
469
|
tasks.append(on_chain_task)
|
|
365
470
|
|
|
471
|
+
if subgraph_url:
|
|
472
|
+
mech_task = loop.create_task(
|
|
473
|
+
watch_for_data_url_from_subgraph(
|
|
474
|
+
request_id=request_id, url=subgraph_url
|
|
475
|
+
)
|
|
476
|
+
)
|
|
477
|
+
tasks.append(mech_task)
|
|
478
|
+
|
|
366
479
|
async def _wait_for_tasks() -> Any: # type: ignore
|
|
367
480
|
"""Wait for tasks to finish."""
|
|
368
481
|
(finished, *_), unfinished = await asyncio.wait(
|
|
@@ -371,7 +484,8 @@ def wait_for_data_url( # pylint: disable=too-many-arguments
|
|
|
371
484
|
)
|
|
372
485
|
for task in unfinished:
|
|
373
486
|
task.cancel()
|
|
374
|
-
|
|
487
|
+
if unfinished:
|
|
488
|
+
await asyncio.wait(unfinished)
|
|
375
489
|
return finished.result()
|
|
376
490
|
|
|
377
491
|
result = loop.run_until_complete(_wait_for_tasks())
|
|
@@ -388,6 +502,7 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
388
502
|
retries: Optional[int] = None,
|
|
389
503
|
timeout: Optional[float] = None,
|
|
390
504
|
sleep: Optional[float] = None,
|
|
505
|
+
chain_config: Optional[str] = None,
|
|
391
506
|
) -> Any:
|
|
392
507
|
"""
|
|
393
508
|
Interact with agent mech contract.
|
|
@@ -411,9 +526,18 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
411
526
|
:type timeout: float
|
|
412
527
|
:param sleep: Amount of sleep before retrying the transaction
|
|
413
528
|
:type sleep: float
|
|
529
|
+
:param chain_config: Id of the mech's chain configuration (stored configs/mechs.json)
|
|
530
|
+
:type chain_config: str:
|
|
414
531
|
:rtype: Any
|
|
415
532
|
"""
|
|
416
|
-
|
|
533
|
+
mech_config = get_mech_config(chain_config)
|
|
534
|
+
ledger_config = mech_config.ledger_config
|
|
535
|
+
contract_address = query_agent_address(
|
|
536
|
+
agent_id=agent_id,
|
|
537
|
+
timeout=timeout,
|
|
538
|
+
url=mech_config.subgraph_url,
|
|
539
|
+
chain_config=chain_config,
|
|
540
|
+
)
|
|
417
541
|
if contract_address is None:
|
|
418
542
|
raise ValueError(f"Agent with ID {agent_id} does not exist!")
|
|
419
543
|
|
|
@@ -423,12 +547,21 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
423
547
|
f"Private key file `{private_key_path}` does not exist!"
|
|
424
548
|
)
|
|
425
549
|
|
|
426
|
-
wss = websocket.create_connection(
|
|
550
|
+
wss = websocket.create_connection(mech_config.wss_endpoint)
|
|
427
551
|
crypto = EthereumCrypto(private_key_path=private_key_path)
|
|
428
|
-
ledger_api = EthereumApi(**
|
|
552
|
+
ledger_api = EthereumApi(**asdict(ledger_config))
|
|
429
553
|
|
|
430
|
-
tool = verify_or_retrieve_tool(
|
|
431
|
-
|
|
554
|
+
tool = verify_or_retrieve_tool(
|
|
555
|
+
agent_id=agent_id,
|
|
556
|
+
ledger_api=ledger_api,
|
|
557
|
+
tool=tool,
|
|
558
|
+
agent_registry_contract=mech_config.agent_registry_contract,
|
|
559
|
+
contract_abi_url=mech_config.contract_abi_url,
|
|
560
|
+
)
|
|
561
|
+
abi = get_abi(
|
|
562
|
+
contract_address=contract_address,
|
|
563
|
+
contract_abi_url=mech_config.contract_abi_url,
|
|
564
|
+
)
|
|
432
565
|
mech_contract = get_contract(
|
|
433
566
|
contract_address=contract_address, abi=abi, ledger_api=ledger_api
|
|
434
567
|
)
|
|
@@ -440,10 +573,12 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
440
573
|
request_signature=request_event_signature,
|
|
441
574
|
deliver_signature=deliver_event_signature,
|
|
442
575
|
)
|
|
443
|
-
|
|
576
|
+
print("Sending request...")
|
|
577
|
+
transaction_digest = send_request(
|
|
444
578
|
crypto=crypto,
|
|
445
579
|
ledger_api=ledger_api,
|
|
446
580
|
mech_contract=mech_contract,
|
|
581
|
+
gas_limit=mech_config.gas_limit,
|
|
447
582
|
prompt=prompt,
|
|
448
583
|
tool=tool,
|
|
449
584
|
extra_attributes=extra_attributes,
|
|
@@ -451,6 +586,11 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
451
586
|
timeout=timeout,
|
|
452
587
|
sleep=sleep,
|
|
453
588
|
)
|
|
589
|
+
transaction_url_formatted = mech_config.transaction_url.format(
|
|
590
|
+
transaction_digest=transaction_digest
|
|
591
|
+
)
|
|
592
|
+
print(f"Transaction sent: {transaction_url_formatted}")
|
|
593
|
+
print("Waiting for transaction receipt...")
|
|
454
594
|
request_id = watch_for_request_id(
|
|
455
595
|
wss=wss,
|
|
456
596
|
mech_contract=mech_contract,
|
|
@@ -458,17 +598,20 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
458
598
|
request_signature=request_event_signature,
|
|
459
599
|
)
|
|
460
600
|
print(f"Created on-chain request with ID {request_id}")
|
|
601
|
+
print("Waiting for Mech response...")
|
|
461
602
|
data_url = wait_for_data_url(
|
|
462
603
|
request_id=request_id,
|
|
463
604
|
wss=wss,
|
|
464
605
|
mech_contract=mech_contract,
|
|
606
|
+
subgraph_url=mech_config.subgraph_url,
|
|
465
607
|
deliver_signature=deliver_event_signature,
|
|
466
608
|
ledger_api=ledger_api,
|
|
467
609
|
crypto=crypto,
|
|
468
610
|
confirmation_type=confirmation_type,
|
|
469
611
|
)
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
612
|
+
if data_url:
|
|
613
|
+
print(f"Data arrived: {data_url}")
|
|
614
|
+
data = requests.get(f"{data_url}/{request_id}").json()
|
|
615
|
+
print(f"Data from agent: {data}")
|
|
616
|
+
return data
|
|
617
|
+
return None
|
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
|
|
mech_client/wss.py
CHANGED
|
@@ -170,19 +170,26 @@ async def watch_for_data_url_from_wss( # pylint: disable=too-many-arguments
|
|
|
170
170
|
:rtype: Any
|
|
171
171
|
"""
|
|
172
172
|
with ThreadPoolExecutor() as executor:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
173
|
+
try:
|
|
174
|
+
while True:
|
|
175
|
+
msg = await loop.run_in_executor(executor=executor, func=wss.recv)
|
|
176
|
+
data = json.loads(msg)
|
|
177
|
+
tx_hash = data["params"]["result"]["transactionHash"]
|
|
178
|
+
tx_receipt = await loop.run_in_executor(
|
|
179
|
+
executor, wait_for_receipt, tx_hash, ledger_api
|
|
180
|
+
)
|
|
181
|
+
event_signature = tx_receipt["logs"][0]["topics"][0].hex()
|
|
182
|
+
if event_signature != deliver_signature:
|
|
183
|
+
continue
|
|
184
|
+
|
|
185
|
+
rich_logs = mech_contract.events.Deliver().process_receipt(tx_receipt)
|
|
186
|
+
data = cast(bytes, rich_logs[0]["args"]["data"])
|
|
187
|
+
if request_id != str(rich_logs[0]["args"]["requestId"]):
|
|
188
|
+
continue
|
|
189
|
+
return f"https://gateway.autonolas.tech/ipfs/f01701220{data.hex()}"
|
|
190
|
+
except websocket.WebSocketConnectionClosedException as e:
|
|
191
|
+
print(f"WebSocketConnectionClosedException {repr(e)}")
|
|
192
|
+
print(
|
|
193
|
+
"Error: The WSS connection was likely closed by the remote party. Please, try using another WSS provider."
|
|
179
194
|
)
|
|
180
|
-
|
|
181
|
-
if event_signature != deliver_signature:
|
|
182
|
-
continue
|
|
183
|
-
|
|
184
|
-
rich_logs = mech_contract.events.Deliver().process_receipt(tx_receipt)
|
|
185
|
-
data = cast(bytes, rich_logs[0]["args"]["data"])
|
|
186
|
-
if request_id != str(rich_logs[0]["args"]["requestId"]):
|
|
187
|
-
continue
|
|
188
|
-
return f"https://gateway.autonolas.tech/ipfs/f01701220{data.hex()}"
|
|
195
|
+
return None
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mech-client
|
|
3
|
+
Version: 0.2.13
|
|
4
|
+
Summary: Basic client to interact with a mech
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Author: David Minarsch
|
|
7
|
+
Author-email: david.minarsch@googlemail.com
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Requires-Dist: asn1crypto (>=1.4.0,<1.5.0)
|
|
14
|
+
Requires-Dist: gql (>=3.4.1)
|
|
15
|
+
Requires-Dist: open-aea-cli-ipfs (==1.50.0)
|
|
16
|
+
Requires-Dist: open-aea-ledger-cosmos (==1.50.0)
|
|
17
|
+
Requires-Dist: open-aea-ledger-ethereum (==1.50.0)
|
|
18
|
+
Requires-Dist: open-aea[cli] (==1.50.0)
|
|
19
|
+
Requires-Dist: websocket-client (>=0.32.0,<1)
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# Mech Client
|
|
23
|
+
|
|
24
|
+
A basic client to interact with an AI Mech. [AI Mechs](https://github.com/valory-xyz/mech) allow users to post requests for AI tasks on-chain, and get their result delivered.
|
|
25
|
+
|
|
26
|
+
> **:warning: Warning** <br />
|
|
27
|
+
> **This is a *hacky* alpha version of the client. Don't rely on it as production software.**
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
- Python >=3.10
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
Find the latest available release on [PyPi](https://pypi.org/project/mech-client/#description).
|
|
36
|
+
|
|
37
|
+
We recommend that you create a virtual Python environment using [Poetry](https://python-poetry.org/). Set up your virtual environment as follows:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
poetry new my_project
|
|
41
|
+
cd my_project
|
|
42
|
+
poetry shell
|
|
43
|
+
poetry add mech-client
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Alternatively, you can also install the Mech Client in your local Python installation:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install mech-client
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If you require to use the Mech Client programmatically, please see [this section](#programmatic-usage) below.
|
|
53
|
+
|
|
54
|
+
## CLI Usage
|
|
55
|
+
|
|
56
|
+
Display the available options:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
mechx --help
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
Usage: mechx [OPTIONS] COMMAND [ARGS]...
|
|
64
|
+
|
|
65
|
+
Command-line tool for interacting with mechs.
|
|
66
|
+
|
|
67
|
+
Options:
|
|
68
|
+
--version Show the version and exit.
|
|
69
|
+
--help Show this message and exit.
|
|
70
|
+
|
|
71
|
+
Commands:
|
|
72
|
+
interact Interact with a mech specifying a prompt and tool.
|
|
73
|
+
prompt-to-ipfs Upload a prompt and tool to IPFS as metadata.
|
|
74
|
+
push-to-ipfs Upload a file to IPFS.
|
|
75
|
+
to-png Convert a stability AI API's diffusion model output...
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Set up the EOA and private key
|
|
79
|
+
|
|
80
|
+
To use the Mech Client you need an EOA account and its associated private key stored in a text file `ethereum_private_key.txt`. You can set it up in two ways:
|
|
81
|
+
|
|
82
|
+
- Use any software of your choice (e.g., [Metamask](https://metamask.io/)) and copy the private key:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
echo -n YOUR_PRIVATE_KEY > ethereum_private_key.txt
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Do not include any leading or trailing spaces, tabs or newlines, or any other character in the file `ethereum_private_key.txt`.
|
|
89
|
+
|
|
90
|
+
- Alternatively, use the Open AEA command `generate-key` (you'll need to install [Open AEA](https://pypi.org/project/open-aea/) and its [Ethereum ledger plugin](https://pypi.org/project/open-aea-ledger-ethereum/)):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
aea generate-key ethereum
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
and display the corresponding EOA:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
python -c "from web3 import Web3; print(Web3().eth.account.from_key(open('ethereum_private_key.txt').read()).address)"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The EOA you use must have enough funds to pay for the Mech requests, or alternatively, use a Nevermined subscription.
|
|
103
|
+
|
|
104
|
+
> **:warning: Warning** <br />
|
|
105
|
+
> * **If the generated EOA account is for development purposes, make sure it does not contain large amounts of funds.**
|
|
106
|
+
>
|
|
107
|
+
> * **If you store the key file in a local Git repository, we recommend that you add it to `.gitignore` in order to avoid publishing it unintentionally:**
|
|
108
|
+
>
|
|
109
|
+
> ```bash
|
|
110
|
+
> echo ethereum_private_key.txt >> .gitignore
|
|
111
|
+
> ```
|
|
112
|
+
|
|
113
|
+
### Select the mech you are going to send requests to
|
|
114
|
+
|
|
115
|
+
Mechs are deployed to several networks. Find the list of supported networks and corresponging mech addresses [here](https://github.com/valory-xyz/mech?tab=readme-ov-file#examples-of-deployed-mechs).
|
|
116
|
+
|
|
117
|
+
### Generate Mech requests
|
|
118
|
+
|
|
119
|
+
The basic usage of the Mech Client is as follows:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
mechx interact <prompt> <agent_id>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
where agent with `<agent_id>` will process `<prompt>` with the default options. Each chain has its own set of Mech agents. You can find the agent IDs for each chain on the [Mech Hub](https://aimechs.autonolas.network/registry) or on the [Mech repository](https://github.com/valory-xyz/mech?tab=readme-ov-file#examples-of-deployed-mechs).
|
|
126
|
+
|
|
127
|
+
Some useful options:
|
|
128
|
+
|
|
129
|
+
- `--key <private_key_path>`: Specifies the path of the private key. The default value is `./ethereum_private_key.txt`.
|
|
130
|
+
- `--tool <name>`: Name of the tool to process the prompt. If you are aware about the tools that are provided by an agent you can directly provide its name using this option. If not provided, it will show a list of available tools for the agent so that you can select which one you want to use:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
Select prompting tool
|
|
134
|
+
|--------------------------------------------------|
|
|
135
|
+
| ID | Tool |
|
|
136
|
+
|--------------------------------------------------|
|
|
137
|
+
| 0 | openai-text-davinci-002 |
|
|
138
|
+
| ...| ... |
|
|
139
|
+
|--------------------------------------------------|
|
|
140
|
+
Tool ID >
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
- `--chain-config <name>`: Use default chain configuration parameters (RPC, WSS, ...). [See below](#chain-configuration) for more details. Available values are
|
|
144
|
+
- `arbitrum`
|
|
145
|
+
- `base`
|
|
146
|
+
- `celo`
|
|
147
|
+
- `gnosis` (Default)
|
|
148
|
+
- `optimism`
|
|
149
|
+
- `polygon`
|
|
150
|
+
|
|
151
|
+
- `--confirm <type>`: Specify how to wait for the result of your request:
|
|
152
|
+
- `off-chain`: Wait for the result using the ACN.
|
|
153
|
+
- `on-chain`: Wait for the result using the Subgraph and the Websocket subscription (whichever arrives first).
|
|
154
|
+
- `wait-for-both` (Default): Wait for the result using both `off-chain` and `on-chain` (whichever arrives first).
|
|
155
|
+
|
|
156
|
+
### Example
|
|
157
|
+
|
|
158
|
+
Example of a request specifying a key file and tool:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
mechx interact "write a short poem" 6 --key ~/ethereum_private_key.txt --tool openai-gpt-3.5-turbo --chain-config gnosis --confirm on-chain
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
You will see an output like this:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
Chain configuration: gnosis
|
|
168
|
+
Prompt uploaded: https://gateway.autonolas.tech/ipfs/f01701220af9e4e8b4bd62d76394064f493081917bcc0b9c34a4aff60f82623b717617279
|
|
169
|
+
Transaction sent: https://gnosisscan.io/tx/0x61359f9cc6a1debb07d34ce1038f6aa30d25257c17edeb2b161741805e43e8d0
|
|
170
|
+
Waiting for transaction receipt...
|
|
171
|
+
Created on-chain request with ID 100407405856633966395081711430940962809568685031934329025999216833965518452765
|
|
172
|
+
Data arrived: https://gateway.autonolas.tech/ipfs/f01701220a462120d5bb03f406fa5ef3573df77184a20ab6343d7bade76bd321654aa7251
|
|
173
|
+
Data from agent: {'requestId': 100407405856633966395081711430940962809568685031934329025999216833965518452765, 'result': "In a world of chaos and strife,\nThere's beauty in the simplest of life.\nA gentle breeze whispers through the trees,\nAnd birds sing melodies with ease.\n\nThe sun sets in a fiery hue,\nPainting the sky in shades of blue.\nStars twinkle in the darkness above,\nGuiding us with their light and love.\n\nSo take a moment to pause and see,\nThe wonders of this world so free.\nEmbrace the joy that each day brings,\nAnd let your heart soar on gentle wings.", 'prompt': 'write a short poem', 'cost_dict': {}, 'metadata': {'model': None, 'tool': 'openai-gpt-3.5-turbo'}}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
> **:pencil2: Note** <br />
|
|
177
|
+
> **If you encounter an "Out of gas" error when executing the Mech Client, you will need to increase the gas limit, e.g.,**
|
|
178
|
+
>
|
|
179
|
+
> ```bash
|
|
180
|
+
> export MECHX_GAS_LIMIT=200000
|
|
181
|
+
> ```
|
|
182
|
+
|
|
183
|
+
### Chain configuration
|
|
184
|
+
|
|
185
|
+
Default configurations for different chains are stored in the file [configs/mechs.json](./mech_client/configs/mechs.json). If `--chain-config` parameter is not specified, the Mech Client will choose the first configuration on the JSON.
|
|
186
|
+
|
|
187
|
+
Additionally, you can override any configuration parameter by exporting any of the following environment variables:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
MECHX_CHAIN_RPC
|
|
191
|
+
MECHX_WSS_ENDPOINT
|
|
192
|
+
MECHX_GAS_LIMIT
|
|
193
|
+
MECHX_CONTRACT_ABI_URL
|
|
194
|
+
MECHX_TRANSACTION_URL
|
|
195
|
+
MECHX_SUBGRAPH_URL
|
|
196
|
+
|
|
197
|
+
MECHX_LEDGER_ADDRESS
|
|
198
|
+
MECHX_LEDGER_CHAIN_ID
|
|
199
|
+
MECHX_LEDGER_POA_CHAIN
|
|
200
|
+
MECHX_LEDGER_DEFAULT_GAS_PRICE_STRATEGY
|
|
201
|
+
MECHX_LEDGER_IS_GAS_ESTIMATION_ENABLED
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Programmatic usage
|
|
205
|
+
|
|
206
|
+
You can also use the Mech Client as a library on your Python project.
|
|
207
|
+
|
|
208
|
+
1. Set up the private key as specified [above](#set-up-the-private-key). Store the resulting key file (e.g., `ethereum_private_key.txt`) in a convenient and secure location.
|
|
209
|
+
|
|
210
|
+
2. Create Python script `my_script.py`:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
touch my_script.py
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
3. Edit `my_script.py` as follows:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from mech_client.interact import interact, ConfirmationType
|
|
220
|
+
|
|
221
|
+
prompt_text = 'Will Gnosis pay reach 100k cards in 2024?'
|
|
222
|
+
agent_id = 6
|
|
223
|
+
tool_name = "prediction-online"
|
|
224
|
+
chain_config = "gnosis"
|
|
225
|
+
private_key_path="ethereum_private_key.txt"
|
|
226
|
+
|
|
227
|
+
result = interact(
|
|
228
|
+
prompt=prompt_text,
|
|
229
|
+
agent_id=agent_id,
|
|
230
|
+
tool=tool_name,
|
|
231
|
+
chain_config=chain_config,
|
|
232
|
+
confirmation_type=ConfirmationType.ON_CHAIN,
|
|
233
|
+
private_key_path=private_key_path
|
|
234
|
+
)
|
|
235
|
+
print(result)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Developer installation
|
|
239
|
+
|
|
240
|
+
To setup the development environment for this project, clone the repository and run the following commands:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
poetry install
|
|
244
|
+
poetry shell
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Release guide
|
|
248
|
+
|
|
249
|
+
- Bump versions in `pyproject.toml`.`mech_client/__init__.py` and `SECURITY.md`
|
|
250
|
+
- `poetry lock`
|
|
251
|
+
- `rm -rf dist`
|
|
252
|
+
- `autonomy packages sync --update-packages`
|
|
253
|
+
- `make eject-packages`
|
|
254
|
+
- Then, create a release PR and tag the release.
|
|
255
|
+
|
|
256
|
+
## FAQ
|
|
257
|
+
|
|
258
|
+
<details>
|
|
259
|
+
|
|
260
|
+
<summary><b>On which chains are AI Mechs deployed?</b></summary>
|
|
261
|
+
|
|
262
|
+
The [Mech repository](https://github.com/valory-xyz/mech?tab=readme-ov-file#examples-of-deployed-mechs) contains the latest information on deployed Mechs.
|
|
263
|
+
|
|
264
|
+
</details>
|
|
265
|
+
|
|
266
|
+
<details>
|
|
267
|
+
|
|
268
|
+
<summary><b>Are AI Mechs deployed on testnets?</b></summary>
|
|
269
|
+
|
|
270
|
+
No. AI Mechs are currently deployed only on mainnets.
|
|
271
|
+
|
|
272
|
+
</details>
|
|
273
|
+
|
|
274
|
+
<details>
|
|
275
|
+
|
|
276
|
+
<summary><b>Where can I find the agent ID?</b></summary>
|
|
277
|
+
|
|
278
|
+
You can find the agent IDs for each chain on the [Mech Hub](https://aimechs.autonolas.network/registry) or on the [Mech repository](https://github.com/valory-xyz/mech?tab=readme-ov-file#examples-of-deployed-mechs).
|
|
279
|
+
|
|
280
|
+
</details>
|
|
281
|
+
|
|
282
|
+
<details>
|
|
283
|
+
|
|
284
|
+
<summary><b>How do I access an AI Mech on a different chain?</b></summary>
|
|
285
|
+
|
|
286
|
+
Use the `--chain-config <name>` parameter together with a valid `<agent_id>`, for example:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
mechx interact "write a short poem" 2 --key ./ethereum_private_key.txt --tool openai-gpt-4 --chain-config celo --confirm on-chain
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
</details>
|
|
293
|
+
|
|
@@ -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=IABnne1lWi62l84Hzqh3XrP659uPKme2k32yAI0HBrg,4488
|
|
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=E9AW_gRMkz8fRDeQSl9Dd97X_405GodA8Xylv5ZavzQ,20189
|
|
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
|
-
mech_client/wss.py,sha256=
|
|
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.
|
|
38
|
+
mech_client/wss.py,sha256=hRInQjjsyOrs8dmgBb2VpJvpNt6Tx0aEiY3OhOPQvIs,6600
|
|
39
|
+
mech_client-0.2.13.dist-info/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
|
|
40
|
+
mech_client-0.2.13.dist-info/METADATA,sha256=cTHX-evOL7lNFFgPhDA0Iyt3jFEW-Fd6zB-IjNyPlRU,10544
|
|
41
|
+
mech_client-0.2.13.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
|
42
|
+
mech_client-0.2.13.dist-info/entry_points.txt,sha256=SbRMRsayzD8XfNXhgwPuXEqQsdZ5Bw9XDPnUuaDExyY,45
|
|
43
|
+
mech_client-0.2.13.dist-info/RECORD,,
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: mech-client
|
|
3
|
-
Version: 0.2.11
|
|
4
|
-
Summary: Basic client to interact with a mech
|
|
5
|
-
License: Apache-2.0
|
|
6
|
-
Author: David Minarsch
|
|
7
|
-
Author-email: david.minarsch@googlemail.com
|
|
8
|
-
Requires-Python: >=3.10,<4.0
|
|
9
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Requires-Dist: asn1crypto (>=1.4.0,<1.5.0)
|
|
14
|
-
Requires-Dist: gql (>=3.4.1)
|
|
15
|
-
Requires-Dist: open-aea-cli-ipfs (==1.50.0)
|
|
16
|
-
Requires-Dist: open-aea-ledger-cosmos (==1.50.0)
|
|
17
|
-
Requires-Dist: open-aea-ledger-ethereum (==1.50.0)
|
|
18
|
-
Requires-Dist: open-aea[cli] (==1.50.0)
|
|
19
|
-
Requires-Dist: websocket-client (>=0.32.0,<1)
|
|
20
|
-
Description-Content-Type: text/markdown
|
|
21
|
-
|
|
22
|
-
# mech-client
|
|
23
|
-
Basic client to interact with a mech
|
|
24
|
-
|
|
25
|
-
> **Warning**<br />
|
|
26
|
-
> **This is a hacky alpha version of the client - don't rely on it as production software.**
|
|
27
|
-
|
|
28
|
-
## Installation
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
pip install mech-client
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Then, set a websocket endpoint for Gnosis RPC like so:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
export WEBSOCKET_ENDPOINT=<YOUR ENDPOINT>
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
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
|
-
|
|
42
|
-
```bash
|
|
43
|
-
export MANUAL_GAS_LIMIT=200000
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## CLI:
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
Usage: mechx [OPTIONS] COMMAND [ARGS]...
|
|
50
|
-
|
|
51
|
-
Command-line tool for interacting with mechs.
|
|
52
|
-
|
|
53
|
-
Options:
|
|
54
|
-
--version Show the version and exit.
|
|
55
|
-
--help Show this message and exit.
|
|
56
|
-
|
|
57
|
-
Commands:
|
|
58
|
-
interact Interact with a mech specifying a prompt and tool.
|
|
59
|
-
prompt-to-ipfs Upload a prompt and tool to IPFS as metadata.
|
|
60
|
-
push-to-ipfs Upload a file to IPFS.
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## CLI Usage:
|
|
64
|
-
|
|
65
|
-
First, create a private key in file `ethereum_private_key.txt` with this command:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
aea generate-key ethereum
|
|
69
|
-
```
|
|
70
|
-
Ensure the private key carries funds on Gnosis Chain.
|
|
71
|
-
|
|
72
|
-
A keyfile is just a file with your ethereum private key as a hex-string, example:
|
|
73
|
-
```
|
|
74
|
-
0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd
|
|
75
|
-
```
|
|
76
|
-
In case you add your own, make sure you don't have any extra characters in the file, like newlines or spaces.
|
|
77
|
-
|
|
78
|
-
Second, run the following command to instruct the mech with `<prompt>` and `<agent_id>`:
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
mechx interact <prompt> <agent_id>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
The command will prompt you with all available tools for the agent and you can select which tool you want to use
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
Select prompting tool
|
|
88
|
-
|--------------------------------------------------|
|
|
89
|
-
| ID | Tool |
|
|
90
|
-
|--------------------------------------------------|
|
|
91
|
-
| 0 | openai-text-davinci-002 |
|
|
92
|
-
| ...| ... |
|
|
93
|
-
|--------------------------------------------------|
|
|
94
|
-
Tool ID >
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
If you are aware about the tools that are provided by an agent you can directly provide tool as a command line argument
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
mechx interact <prompt> <agent_id> --tool <tool>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
If you already have a funded key file on locally you can provide path the key using `--key` flag.
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
mechx interact <prompt> <agent_id> --key <key_file>
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Example output:
|
|
110
|
-
```bash
|
|
111
|
-
mechx interact "write a short poem" 3 --key ~/gnosis_key --tool openai-text-davinci-003
|
|
112
|
-
Prompt uploaded: https://gateway.autonolas.tech/ipfs/f01701220ad773628911d12e28f005e3f249e990d684e5dba07542259195602f9afed30bf
|
|
113
|
-
Transaction sent: https://gnosisscan.io/tx/0x0d9209e32e965a820b9e80accfcd71ea3b1174b9758dd251c2e627a60ec426a5
|
|
114
|
-
Created on-chain request with ID 111240237160304797537720810617416341148235899500021985333360197012735240803849
|
|
115
|
-
Data arrived: https://gateway.autonolas.tech/ipfs/bafybeifk2h35ncszlze7t64rpblfo45rezc33xzbya3cjiyumtaioyat3e
|
|
116
|
-
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
|
-
```
|
|
118
|
-
|
|
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
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
mechx interact "write a short poem" 3 --key ~/gnosis_key --tool openai-text-davinci-003 --confirm on-chain
|
|
123
|
-
Prompt uploaded: https://gateway.autonolas.tech/ipfs/f017012205e37f761221a8ba4005e91c36b94153e9432b8888ff2acae6b101dd5a5de6768
|
|
124
|
-
Transaction sent: https://gnosisscan.io/tx/0xf1ef63f617717bbb8deb09699af99aa39f10155d33796de2fd7eb61c9c1458b6
|
|
125
|
-
Created on-chain request with ID 81653153529124597849081567361606842861262371002932574194580478443414142139857
|
|
126
|
-
Data arrived: https://gateway.autonolas.tech/ipfs/f0170122069b55e077430a00f3cbc3b069347e901396f978ff160eb2b0a947872be1848b7
|
|
127
|
-
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
|
-
```
|
|
129
|
-
|
|
130
|
-
## Programmatic Usage:
|
|
131
|
-
|
|
132
|
-
```python
|
|
133
|
-
from mech_client.interact import interact, ConfirmationType
|
|
134
|
-
|
|
135
|
-
prompt_text = 'Will gnosis pay reach 100k cards in 2024?'
|
|
136
|
-
agent_id = 3
|
|
137
|
-
tool_name = "prediction-online"
|
|
138
|
-
|
|
139
|
-
result = interact(
|
|
140
|
-
prompt=prompt_text,
|
|
141
|
-
agent_id=agent_id,
|
|
142
|
-
tool=tool_name,
|
|
143
|
-
confirmation_type=ConfirmationType.ON_CHAIN,
|
|
144
|
-
private_key_path='PATH_HERE'
|
|
145
|
-
)
|
|
146
|
-
print(result)
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
# Developer installation
|
|
150
|
-
To setup the development environment, run the following commands:
|
|
151
|
-
|
|
152
|
-
```bash
|
|
153
|
-
poetry install && poetry shell
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
## Release guide:
|
|
157
|
-
|
|
158
|
-
- Bump versions in `pyproject.toml`, `mech_client/__init__.py` and `SECURITY.md`
|
|
159
|
-
- `poetry lock`
|
|
160
|
-
- `rm -rf dist`
|
|
161
|
-
- `autonomy packages sync --update-packages`
|
|
162
|
-
- `make eject-packages`
|
|
163
|
-
- then create release PR and tag release
|
|
164
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|