mech-client 0.2.8__tar.gz → 0.2.10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mech_client-0.2.8 → mech_client-0.2.10}/PKG-INFO +40 -7
- {mech_client-0.2.8 → mech_client-0.2.10}/README.md +34 -2
- mech_client-0.2.10/mech_client/__init__.py +3 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/cli.py +22 -1
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/interact.py +140 -28
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/subgraph.py +8 -2
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/wss.py +25 -15
- {mech_client-0.2.8 → mech_client-0.2.10}/pyproject.toml +7 -7
- mech_client-0.2.8/mech_client/__init__.py +0 -3
- {mech_client-0.2.8 → mech_client-0.2.10}/LICENSE +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/acn.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/__init__.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/README.md +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/__init__.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/acn.proto +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/acn_pb2.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/custom_types.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/dialogues.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/message.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/protocol.yaml +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/serialization.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/tests/__init__.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/tests/test_acn.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/tests/test_acn_dialogues.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/tests/test_acn_messages.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/README.md +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/__init__.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/acn_data_share.proto +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/acn_data_share_pb2.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/dialogues.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/message.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/protocol.yaml +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/serialization.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/tests/test_acn_data_share_dialogues.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/tests/test_acn_data_share_messages.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/p2p_libp2p_client/README.md +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/p2p_libp2p_client/__init__.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/p2p_libp2p_client/connection.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/p2p_libp2p_client/connection.yaml +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/prompt_to_ipfs.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/push_to_ipfs.py +0 -0
- {mech_client-0.2.8 → mech_client-0.2.10}/mech_client/to_png.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mech-client
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.10
|
|
4
4
|
Summary: Basic client to interact with a mech
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: David Minarsch
|
|
@@ -12,10 +12,10 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Requires-Dist: asn1crypto (>=1.4.0,<1.5.0)
|
|
14
14
|
Requires-Dist: gql (>=3.4.1)
|
|
15
|
-
Requires-Dist: open-aea-cli-ipfs (
|
|
16
|
-
Requires-Dist: open-aea-ledger-cosmos (
|
|
17
|
-
Requires-Dist: open-aea-ledger-ethereum (
|
|
18
|
-
Requires-Dist: open-aea[cli] (
|
|
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
19
|
Requires-Dist: websocket-client (>=0.32.0,<1)
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
|
|
@@ -54,7 +54,7 @@ Commands:
|
|
|
54
54
|
push-to-ipfs Upload a file to IPFS.
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
## Usage:
|
|
57
|
+
## CLI Usage:
|
|
58
58
|
|
|
59
59
|
First, create a private key in file `ethereum_private_key.txt` with this command:
|
|
60
60
|
|
|
@@ -63,6 +63,12 @@ aea generate-key ethereum
|
|
|
63
63
|
```
|
|
64
64
|
Ensure the private key carries funds on Gnosis Chain.
|
|
65
65
|
|
|
66
|
+
A keyfile is just a file with your ethereum private key as a hex-string, example:
|
|
67
|
+
```
|
|
68
|
+
0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd
|
|
69
|
+
```
|
|
70
|
+
In case you add your own, make sure you don't have any extra characters in the file, like newlines or spaces.
|
|
71
|
+
|
|
66
72
|
Second, run the following command to instruct the mech with `<prompt>` and `<agent_id>`:
|
|
67
73
|
|
|
68
74
|
```bash
|
|
@@ -115,6 +121,32 @@ Data arrived: https://gateway.autonolas.tech/ipfs/f0170122069b55e077430a00f3cbc3
|
|
|
115
121
|
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."}
|
|
116
122
|
```
|
|
117
123
|
|
|
124
|
+
## Programmatic Usage:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from mech_client.interact import interact, ConfirmationType
|
|
128
|
+
|
|
129
|
+
prompt_text = 'Will gnosis pay reach 100k cards in 2024?'
|
|
130
|
+
agent_id = 3
|
|
131
|
+
tool_name = "prediction-online"
|
|
132
|
+
|
|
133
|
+
result = interact(
|
|
134
|
+
prompt=prompt_text,
|
|
135
|
+
agent_id=agent_id,
|
|
136
|
+
tool=tool_name,
|
|
137
|
+
confirmation_type=ConfirmationType.ON_CHAIN,
|
|
138
|
+
private_key_path='PATH_HERE'
|
|
139
|
+
)
|
|
140
|
+
print(result)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
# Developer installation
|
|
144
|
+
To setup the development environment, run the following commands:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
poetry install && poetry shell
|
|
148
|
+
```
|
|
149
|
+
|
|
118
150
|
## Release guide:
|
|
119
151
|
|
|
120
152
|
- Bump versions in `pyproject.toml` and `mech_client/__init__.py`
|
|
@@ -122,4 +154,5 @@ Data from agent: {'requestId': 8165315352912459784908156736160684286126237100293
|
|
|
122
154
|
- `rm -rf dist`
|
|
123
155
|
- `autonomy packages sync --update-packages`
|
|
124
156
|
- `make eject-packages`
|
|
125
|
-
- then
|
|
157
|
+
- then create release PR and tag release
|
|
158
|
+
|
|
@@ -33,7 +33,7 @@ Commands:
|
|
|
33
33
|
push-to-ipfs Upload a file to IPFS.
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
## Usage:
|
|
36
|
+
## CLI Usage:
|
|
37
37
|
|
|
38
38
|
First, create a private key in file `ethereum_private_key.txt` with this command:
|
|
39
39
|
|
|
@@ -42,6 +42,12 @@ aea generate-key ethereum
|
|
|
42
42
|
```
|
|
43
43
|
Ensure the private key carries funds on Gnosis Chain.
|
|
44
44
|
|
|
45
|
+
A keyfile is just a file with your ethereum private key as a hex-string, example:
|
|
46
|
+
```
|
|
47
|
+
0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd
|
|
48
|
+
```
|
|
49
|
+
In case you add your own, make sure you don't have any extra characters in the file, like newlines or spaces.
|
|
50
|
+
|
|
45
51
|
Second, run the following command to instruct the mech with `<prompt>` and `<agent_id>`:
|
|
46
52
|
|
|
47
53
|
```bash
|
|
@@ -94,6 +100,32 @@ Data arrived: https://gateway.autonolas.tech/ipfs/f0170122069b55e077430a00f3cbc3
|
|
|
94
100
|
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."}
|
|
95
101
|
```
|
|
96
102
|
|
|
103
|
+
## Programmatic Usage:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from mech_client.interact import interact, ConfirmationType
|
|
107
|
+
|
|
108
|
+
prompt_text = 'Will gnosis pay reach 100k cards in 2024?'
|
|
109
|
+
agent_id = 3
|
|
110
|
+
tool_name = "prediction-online"
|
|
111
|
+
|
|
112
|
+
result = interact(
|
|
113
|
+
prompt=prompt_text,
|
|
114
|
+
agent_id=agent_id,
|
|
115
|
+
tool=tool_name,
|
|
116
|
+
confirmation_type=ConfirmationType.ON_CHAIN,
|
|
117
|
+
private_key_path='PATH_HERE'
|
|
118
|
+
)
|
|
119
|
+
print(result)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
# Developer installation
|
|
123
|
+
To setup the development environment, run the following commands:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
poetry install && poetry shell
|
|
127
|
+
```
|
|
128
|
+
|
|
97
129
|
## Release guide:
|
|
98
130
|
|
|
99
131
|
- Bump versions in `pyproject.toml` and `mech_client/__init__.py`
|
|
@@ -101,4 +133,4 @@ Data from agent: {'requestId': 8165315352912459784908156736160684286126237100293
|
|
|
101
133
|
- `rm -rf dist`
|
|
102
134
|
- `autonomy packages sync --update-packages`
|
|
103
135
|
- `make eject-packages`
|
|
104
|
-
- then
|
|
136
|
+
- then create release PR and tag release
|
|
@@ -57,12 +57,30 @@ def cli() -> None:
|
|
|
57
57
|
),
|
|
58
58
|
help="Data verification method (on-chain/off-chain)",
|
|
59
59
|
)
|
|
60
|
-
|
|
60
|
+
@click.option(
|
|
61
|
+
"--retries",
|
|
62
|
+
type=int,
|
|
63
|
+
help="Number of retries for sending a transaction",
|
|
64
|
+
)
|
|
65
|
+
@click.option(
|
|
66
|
+
"--timeout",
|
|
67
|
+
type=float,
|
|
68
|
+
help="Timeout to wait for the transaction",
|
|
69
|
+
)
|
|
70
|
+
@click.option(
|
|
71
|
+
"--sleep",
|
|
72
|
+
type=float,
|
|
73
|
+
help="Amount of sleep before retrying the transaction",
|
|
74
|
+
)
|
|
75
|
+
def interact( # pylint: disable=too-many-arguments
|
|
61
76
|
prompt: str,
|
|
62
77
|
agent_id: int,
|
|
63
78
|
tool: Optional[str],
|
|
64
79
|
key: Optional[str],
|
|
65
80
|
confirm: Optional[str] = None,
|
|
81
|
+
retries: Optional[int] = None,
|
|
82
|
+
timeout: Optional[float] = None,
|
|
83
|
+
sleep: Optional[float] = None,
|
|
66
84
|
) -> None:
|
|
67
85
|
"""Interact with a mech specifying a prompt and tool."""
|
|
68
86
|
try:
|
|
@@ -76,6 +94,9 @@ def interact(
|
|
|
76
94
|
if confirm is not None
|
|
77
95
|
else ConfirmationType.WAIT_FOR_BOTH
|
|
78
96
|
),
|
|
97
|
+
retries=retries,
|
|
98
|
+
timeout=timeout,
|
|
99
|
+
sleep=sleep,
|
|
79
100
|
)
|
|
80
101
|
except (ValueError, FileNotFoundError) as e:
|
|
81
102
|
raise click.ClickException(str(e)) from e
|
|
@@ -26,17 +26,19 @@ python client.py <prompt> <tool>
|
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
28
|
import asyncio
|
|
29
|
-
import json
|
|
30
29
|
import os
|
|
30
|
+
import time
|
|
31
31
|
import warnings
|
|
32
|
+
from datetime import datetime
|
|
32
33
|
from enum import Enum
|
|
33
34
|
from pathlib import Path
|
|
34
|
-
from typing import Any, List, Optional, Tuple
|
|
35
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
35
36
|
|
|
36
37
|
import requests
|
|
37
38
|
import websocket
|
|
38
39
|
from aea.crypto.base import Crypto
|
|
39
40
|
from aea_ledger_ethereum import EthereumApi, EthereumCrypto
|
|
41
|
+
from web3 import Web3
|
|
40
42
|
from web3.contract import Contract as Web3Contract
|
|
41
43
|
|
|
42
44
|
from mech_client.acn import (
|
|
@@ -63,6 +65,7 @@ LEDGER_CONFIG = {
|
|
|
63
65
|
"chain_id": 100,
|
|
64
66
|
"poa_chain": False,
|
|
65
67
|
"default_gas_price_strategy": "eip1559",
|
|
68
|
+
"is_gas_estimation_enabled": False,
|
|
66
69
|
}
|
|
67
70
|
PRIVATE_KEY_FILE_PATH = "ethereum_private_key.txt"
|
|
68
71
|
|
|
@@ -70,7 +73,19 @@ WSS_ENDPOINT = os.getenv(
|
|
|
70
73
|
"WEBSOCKET_ENDPOINT",
|
|
71
74
|
"wss://rpc.eu-central-2.gateway.fm/ws/v4/gnosis/non-archival/mainnet",
|
|
72
75
|
)
|
|
73
|
-
|
|
76
|
+
MANUAL_GAS_LIMIT = int(
|
|
77
|
+
os.getenv(
|
|
78
|
+
"MANUAL_GAS_LIMIT",
|
|
79
|
+
"100_000",
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
BLOCKSCOUT_API_URL = (
|
|
83
|
+
"https://gnosis.blockscout.com/api/v2/smart-contracts/{contract_address}"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
MAX_RETRIES = 3
|
|
87
|
+
WAIT_SLEEP = 3.0
|
|
88
|
+
TIMEOUT = 60.0
|
|
74
89
|
|
|
75
90
|
# Ignore a specific warning message
|
|
76
91
|
warnings.filterwarnings("ignore", "The log with transaction hash.*")
|
|
@@ -84,20 +99,54 @@ class ConfirmationType(Enum):
|
|
|
84
99
|
WAIT_FOR_BOTH = "wait-for-both"
|
|
85
100
|
|
|
86
101
|
|
|
87
|
-
def
|
|
102
|
+
def calculate_topic_id(event: Dict) -> str:
|
|
103
|
+
"""Caclulate topic ID"""
|
|
104
|
+
text = event["name"]
|
|
105
|
+
text += "("
|
|
106
|
+
for inp in event["inputs"]:
|
|
107
|
+
text += inp["type"]
|
|
108
|
+
text += ","
|
|
109
|
+
text = text[:-1]
|
|
110
|
+
text += ")"
|
|
111
|
+
return Web3.keccak(text=text).hex()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def get_event_signatures(abi: List) -> Tuple[str, str]:
|
|
115
|
+
"""Calculate `Request` and `Deliver` event topics"""
|
|
116
|
+
request, deliver = "", ""
|
|
117
|
+
for obj in abi:
|
|
118
|
+
if obj["type"] != "event":
|
|
119
|
+
continue
|
|
120
|
+
if obj["name"] == "Deliver":
|
|
121
|
+
deliver = calculate_topic_id(event=obj)
|
|
122
|
+
if obj["name"] == "Request":
|
|
123
|
+
request = calculate_topic_id(event=obj)
|
|
124
|
+
return request, deliver
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def get_abi(contract_address: str) -> List:
|
|
128
|
+
"""Get contract abi"""
|
|
129
|
+
abi_request_url = BLOCKSCOUT_API_URL.format(contract_address=contract_address)
|
|
130
|
+
response = requests.get(abi_request_url).json()
|
|
131
|
+
return response["abi"]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def get_contract(
|
|
135
|
+
contract_address: str, abi: List, ledger_api: EthereumApi
|
|
136
|
+
) -> Web3Contract:
|
|
88
137
|
"""
|
|
89
138
|
Returns a contract instance.
|
|
90
139
|
|
|
91
140
|
:param contract_address: The address of the contract.
|
|
92
141
|
:type contract_address: str
|
|
142
|
+
:param abi: ABI Object
|
|
143
|
+
:type abi: List
|
|
93
144
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
94
145
|
:type ledger_api: EthereumApi
|
|
95
146
|
:return: The contract instance.
|
|
96
147
|
:rtype: Web3Contract
|
|
97
148
|
"""
|
|
98
|
-
|
|
99
|
-
response = requests.get(abi_request_url).json()
|
|
100
|
-
abi = json.loads(response["result"])
|
|
149
|
+
|
|
101
150
|
return ledger_api.get_contract_instance(
|
|
102
151
|
{"abi": abi, "bytecode": "0x"}, contract_address
|
|
103
152
|
)
|
|
@@ -172,20 +221,25 @@ def verify_or_retrieve_tool(
|
|
|
172
221
|
def fetch_tools(agent_id: int, ledger_api: EthereumApi) -> List[str]:
|
|
173
222
|
"""Fetch tools for specified agent ID."""
|
|
174
223
|
mech_registry = get_contract(
|
|
175
|
-
contract_address=AGENT_REGISTRY_CONTRACT,
|
|
224
|
+
contract_address=AGENT_REGISTRY_CONTRACT,
|
|
225
|
+
abi=get_abi(AGENT_REGISTRY_CONTRACT),
|
|
226
|
+
ledger_api=ledger_api,
|
|
176
227
|
)
|
|
177
228
|
token_uri = mech_registry.functions.tokenURI(agent_id).call()
|
|
178
229
|
response = requests.get(token_uri).json()
|
|
179
230
|
return response["tools"]
|
|
180
231
|
|
|
181
232
|
|
|
182
|
-
def send_request( # pylint: disable=too-many-arguments
|
|
233
|
+
def send_request( # pylint: disable=too-many-arguments,too-many-locals
|
|
183
234
|
crypto: EthereumCrypto,
|
|
184
235
|
ledger_api: EthereumApi,
|
|
185
236
|
mech_contract: Web3Contract,
|
|
186
237
|
prompt: str,
|
|
187
238
|
tool: str,
|
|
188
239
|
price: int = 10_000_000_000_000_000,
|
|
240
|
+
retries: Optional[int] = None,
|
|
241
|
+
timeout: Optional[float] = None,
|
|
242
|
+
sleep: Optional[float] = None,
|
|
189
243
|
) -> None:
|
|
190
244
|
"""
|
|
191
245
|
Sends a request to the mech.
|
|
@@ -202,28 +256,58 @@ def send_request( # pylint: disable=too-many-arguments
|
|
|
202
256
|
:type tool: str
|
|
203
257
|
:param price: The price for the request (default: 10_000_000_000_000_000).
|
|
204
258
|
:type price: int
|
|
259
|
+
:param retries: Number of retries for sending a transaction
|
|
260
|
+
:type retries: int
|
|
261
|
+
:param timeout: Timeout to wait for the transaction
|
|
262
|
+
:type timeout: float
|
|
263
|
+
:param sleep: Amount of sleep before retrying the transaction
|
|
264
|
+
:type sleep: float
|
|
205
265
|
"""
|
|
206
266
|
v1_file_hash_hex_truncated, v1_file_hash_hex = push_metadata_to_ipfs(prompt, tool)
|
|
207
267
|
print(f"Prompt uploaded: https://gateway.autonolas.tech/ipfs/{v1_file_hash_hex}")
|
|
208
268
|
method_name = "request"
|
|
209
269
|
methord_args = {"data": v1_file_hash_hex_truncated}
|
|
210
|
-
tx_args = {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
270
|
+
tx_args = {
|
|
271
|
+
"sender_address": crypto.address,
|
|
272
|
+
"value": price,
|
|
273
|
+
"gas": MANUAL_GAS_LIMIT,
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
tries = 0
|
|
277
|
+
retries = retries or MAX_RETRIES
|
|
278
|
+
timeout = timeout or TIMEOUT
|
|
279
|
+
sleep = sleep or WAIT_SLEEP
|
|
280
|
+
deadline = datetime.now().timestamp() + timeout
|
|
281
|
+
|
|
282
|
+
while tries < retries and datetime.now().timestamp() < deadline:
|
|
283
|
+
tries += 1
|
|
284
|
+
try:
|
|
285
|
+
raw_transaction = ledger_api.build_transaction(
|
|
286
|
+
contract_instance=mech_contract,
|
|
287
|
+
method_name=method_name,
|
|
288
|
+
method_args=methord_args,
|
|
289
|
+
tx_args=tx_args,
|
|
290
|
+
raise_on_try=True,
|
|
291
|
+
)
|
|
292
|
+
signed_transaction = crypto.sign_transaction(raw_transaction)
|
|
293
|
+
transaction_digest = ledger_api.send_signed_transaction(
|
|
294
|
+
signed_transaction,
|
|
295
|
+
raise_on_try=True,
|
|
296
|
+
)
|
|
297
|
+
print(f"Transaction sent: https://gnosisscan.io/tx/{transaction_digest}")
|
|
298
|
+
return
|
|
299
|
+
except Exception as e: # pylint: disable=broad-except
|
|
300
|
+
print(
|
|
301
|
+
f"Error occured while sending the transaction: {e}; Retrying in {sleep}"
|
|
302
|
+
)
|
|
303
|
+
time.sleep(sleep)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def wait_for_data_url( # pylint: disable=too-many-arguments
|
|
224
307
|
request_id: str,
|
|
225
308
|
wss: websocket.WebSocket,
|
|
226
309
|
mech_contract: Web3Contract,
|
|
310
|
+
deliver_signature: str,
|
|
227
311
|
ledger_api: EthereumApi,
|
|
228
312
|
crypto: Crypto,
|
|
229
313
|
) -> Any:
|
|
@@ -236,6 +320,8 @@ def wait_for_data_url(
|
|
|
236
320
|
:type wss: websocket.WebSocket
|
|
237
321
|
:param mech_contract: The mech contract instance.
|
|
238
322
|
:type mech_contract: Web3Contract
|
|
323
|
+
:param deliver_signature: Topic signature for Deliver event
|
|
324
|
+
:type deliver_signature: str
|
|
239
325
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
240
326
|
:type ledger_api: EthereumApi
|
|
241
327
|
:param crypto: The cryptographic object.
|
|
@@ -250,6 +336,7 @@ def wait_for_data_url(
|
|
|
250
336
|
request_id=request_id,
|
|
251
337
|
wss=wss,
|
|
252
338
|
mech_contract=mech_contract,
|
|
339
|
+
deliver_signature=deliver_signature,
|
|
253
340
|
ledger_api=ledger_api,
|
|
254
341
|
loop=loop,
|
|
255
342
|
)
|
|
@@ -269,12 +356,15 @@ def wait_for_data_url(
|
|
|
269
356
|
return result
|
|
270
357
|
|
|
271
358
|
|
|
272
|
-
def interact(
|
|
359
|
+
def interact( # pylint: disable=too-many-arguments,too-many-locals
|
|
273
360
|
prompt: str,
|
|
274
361
|
agent_id: int,
|
|
275
362
|
tool: Optional[str] = None,
|
|
276
363
|
private_key_path: Optional[str] = None,
|
|
277
364
|
confirmation_type: ConfirmationType = ConfirmationType.WAIT_FOR_BOTH,
|
|
365
|
+
retries: Optional[int] = None,
|
|
366
|
+
timeout: Optional[float] = None,
|
|
367
|
+
sleep: Optional[float] = None,
|
|
278
368
|
) -> Any:
|
|
279
369
|
"""
|
|
280
370
|
Interact with agent mech contract.
|
|
@@ -290,9 +380,15 @@ def interact(
|
|
|
290
380
|
:param confirmation_type: The confirmation type for the interaction (default: ConfirmationType.WAIT_FOR_BOTH).
|
|
291
381
|
:type confirmation_type: ConfirmationType
|
|
292
382
|
:return: The data received from on-chain/off-chain.
|
|
383
|
+
:param retries: Number of retries for sending a transaction
|
|
384
|
+
:type retries: int
|
|
385
|
+
:param timeout: Timeout to wait for the transaction
|
|
386
|
+
:type timeout: float
|
|
387
|
+
:param sleep: Amount of sleep before retrying the transaction
|
|
388
|
+
:type sleep: float
|
|
293
389
|
:rtype: Any
|
|
294
390
|
"""
|
|
295
|
-
contract_address = query_agent_address(agent_id=agent_id)
|
|
391
|
+
contract_address = query_agent_address(agent_id=agent_id, timeout=timeout)
|
|
296
392
|
if contract_address is None:
|
|
297
393
|
raise ValueError(f"Agent with ID {agent_id} does not exist!")
|
|
298
394
|
|
|
@@ -307,19 +403,33 @@ def interact(
|
|
|
307
403
|
ledger_api = EthereumApi(**LEDGER_CONFIG)
|
|
308
404
|
|
|
309
405
|
tool = verify_or_retrieve_tool(agent_id=agent_id, ledger_api=ledger_api, tool=tool)
|
|
406
|
+
abi = get_abi(contract_address=contract_address)
|
|
310
407
|
mech_contract = get_contract(
|
|
311
|
-
contract_address=contract_address, ledger_api=ledger_api
|
|
408
|
+
contract_address=contract_address, abi=abi, ledger_api=ledger_api
|
|
409
|
+
)
|
|
410
|
+
request_event_signature, deliver_event_signature = get_event_signatures(abi=abi)
|
|
411
|
+
register_event_handlers(
|
|
412
|
+
wss=wss,
|
|
413
|
+
contract_address=contract_address,
|
|
414
|
+
crypto=crypto,
|
|
415
|
+
request_signature=request_event_signature,
|
|
416
|
+
deliver_signature=deliver_event_signature,
|
|
312
417
|
)
|
|
313
|
-
register_event_handlers(wss=wss, contract_address=contract_address, crypto=crypto)
|
|
314
418
|
send_request(
|
|
315
419
|
crypto=crypto,
|
|
316
420
|
ledger_api=ledger_api,
|
|
317
421
|
mech_contract=mech_contract,
|
|
318
422
|
prompt=prompt,
|
|
319
423
|
tool=tool,
|
|
424
|
+
retries=retries,
|
|
425
|
+
timeout=timeout,
|
|
426
|
+
sleep=sleep,
|
|
320
427
|
)
|
|
321
428
|
request_id = watch_for_request_id(
|
|
322
|
-
wss=wss,
|
|
429
|
+
wss=wss,
|
|
430
|
+
mech_contract=mech_contract,
|
|
431
|
+
ledger_api=ledger_api,
|
|
432
|
+
request_signature=request_event_signature,
|
|
323
433
|
)
|
|
324
434
|
print(f"Created on-chain request with ID {request_id}")
|
|
325
435
|
if confirmation_type == ConfirmationType.OFF_CHAIN:
|
|
@@ -328,6 +438,7 @@ def interact(
|
|
|
328
438
|
data_url = watch_for_data_url_from_wss_sync(
|
|
329
439
|
request_id=request_id,
|
|
330
440
|
wss=wss,
|
|
441
|
+
deliver_signature=deliver_event_signature,
|
|
331
442
|
mech_contract=mech_contract,
|
|
332
443
|
ledger_api=ledger_api,
|
|
333
444
|
)
|
|
@@ -336,6 +447,7 @@ def interact(
|
|
|
336
447
|
request_id=request_id,
|
|
337
448
|
wss=wss,
|
|
338
449
|
mech_contract=mech_contract,
|
|
450
|
+
deliver_signature=deliver_event_signature,
|
|
339
451
|
ledger_api=ledger_api,
|
|
340
452
|
crypto=crypto,
|
|
341
453
|
)
|
|
@@ -37,16 +37,22 @@ AGENT_QUERY_TEMPLATE = Template(
|
|
|
37
37
|
)
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def query_agent_address(
|
|
40
|
+
def query_agent_address(
|
|
41
|
+
agent_id: int, timeout: Optional[float] = None
|
|
42
|
+
) -> Optional[str]:
|
|
41
43
|
"""
|
|
42
44
|
Query agent address from subgraph.
|
|
43
45
|
|
|
44
46
|
:param agent_id: The ID of the agent.
|
|
47
|
+
:param timeout: Timeout for the request.
|
|
45
48
|
:type agent_id: int
|
|
46
49
|
:return: The agent address if found, None otherwise.
|
|
47
50
|
:rtype: Optional[str]
|
|
48
51
|
"""
|
|
49
|
-
client = Client(
|
|
52
|
+
client = Client(
|
|
53
|
+
transport=AIOHTTPTransport(url=MECH_SUBGRAPH_URL),
|
|
54
|
+
execute_timeout=timeout or 30.0,
|
|
55
|
+
)
|
|
50
56
|
response = client.execute(
|
|
51
57
|
document=gql(
|
|
52
58
|
request_string=AGENT_QUERY_TEMPLATE.substitute({"agent_id": agent_id})
|
|
@@ -31,16 +31,12 @@ from aea_ledger_ethereum import EthereumApi
|
|
|
31
31
|
from web3.contract import Contract as Web3Contract
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
EVENT_SIGNATURE_REQUEST = (
|
|
35
|
-
"0x4bda649efe6b98b0f9c1d5e859c29e20910f45c66dabfe6fad4a4881f7faf9cc"
|
|
36
|
-
)
|
|
37
|
-
EVENT_SIGNATURE_DELIVER = (
|
|
38
|
-
"0x3ec84da2cdc1ce60c063642b69ff2e65f3b69787a2b90443457ba274e51e7c72"
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
|
|
42
34
|
def register_event_handlers(
|
|
43
|
-
wss: websocket.WebSocket,
|
|
35
|
+
wss: websocket.WebSocket,
|
|
36
|
+
contract_address: str,
|
|
37
|
+
crypto: Crypto,
|
|
38
|
+
request_signature: str,
|
|
39
|
+
deliver_signature: str,
|
|
44
40
|
) -> None:
|
|
45
41
|
"""
|
|
46
42
|
Register event handlers.
|
|
@@ -51,6 +47,10 @@ def register_event_handlers(
|
|
|
51
47
|
:type contract_address: str
|
|
52
48
|
:param crypto: The cryptographic object.
|
|
53
49
|
:type crypto: Crypto
|
|
50
|
+
:param request_signature: Topic signature for Request event
|
|
51
|
+
:type request_signature: str
|
|
52
|
+
:param deliver_signature: Topic signature for Deliver event
|
|
53
|
+
:type deliver_signature: str
|
|
54
54
|
"""
|
|
55
55
|
|
|
56
56
|
subscription_request = {
|
|
@@ -62,7 +62,7 @@ def register_event_handlers(
|
|
|
62
62
|
{
|
|
63
63
|
"address": contract_address,
|
|
64
64
|
"topics": [
|
|
65
|
-
|
|
65
|
+
request_signature,
|
|
66
66
|
["0x" + "0" * 24 + crypto.address[2:]],
|
|
67
67
|
],
|
|
68
68
|
},
|
|
@@ -79,7 +79,7 @@ def register_event_handlers(
|
|
|
79
79
|
"method": "eth_subscribe",
|
|
80
80
|
"params": [
|
|
81
81
|
"logs",
|
|
82
|
-
{"address": contract_address, "topics": [
|
|
82
|
+
{"address": contract_address, "topics": [deliver_signature]},
|
|
83
83
|
],
|
|
84
84
|
}
|
|
85
85
|
content = bytes(json.dumps(subscription_deliver), "utf-8")
|
|
@@ -109,10 +109,11 @@ def wait_for_receipt(tx_hash: str, ledger_api: EthereumApi) -> Dict:
|
|
|
109
109
|
time.sleep(1)
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
def watch_for_request_id(
|
|
112
|
+
def watch_for_request_id( # pylint: disable=too-many-arguments
|
|
113
113
|
wss: websocket.WebSocket,
|
|
114
114
|
mech_contract: Web3Contract,
|
|
115
115
|
ledger_api: EthereumApi,
|
|
116
|
+
request_signature: str,
|
|
116
117
|
) -> str:
|
|
117
118
|
"""
|
|
118
119
|
Watches for events on mech.
|
|
@@ -124,6 +125,8 @@ def watch_for_request_id(
|
|
|
124
125
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
125
126
|
:type ledger_api: EthereumApi
|
|
126
127
|
:return: The requested ID.
|
|
128
|
+
:param request_signature: Topic signature for Request event
|
|
129
|
+
:type request_signature: str
|
|
127
130
|
:rtype: str
|
|
128
131
|
"""
|
|
129
132
|
while True:
|
|
@@ -132,7 +135,7 @@ def watch_for_request_id(
|
|
|
132
135
|
tx_hash = data["params"]["result"]["transactionHash"]
|
|
133
136
|
tx_receipt = wait_for_receipt(tx_hash=tx_hash, ledger_api=ledger_api)
|
|
134
137
|
event_signature = tx_receipt["logs"][0]["topics"][0].hex()
|
|
135
|
-
if event_signature !=
|
|
138
|
+
if event_signature != request_signature:
|
|
136
139
|
continue
|
|
137
140
|
|
|
138
141
|
rich_logs = mech_contract.events.Request().process_receipt(tx_receipt)
|
|
@@ -140,10 +143,11 @@ def watch_for_request_id(
|
|
|
140
143
|
return request_id
|
|
141
144
|
|
|
142
145
|
|
|
143
|
-
async def watch_for_data_url_from_wss(
|
|
146
|
+
async def watch_for_data_url_from_wss( # pylint: disable=too-many-arguments
|
|
144
147
|
request_id: str,
|
|
145
148
|
wss: websocket.WebSocket,
|
|
146
149
|
mech_contract: Web3Contract,
|
|
150
|
+
deliver_signature: str,
|
|
147
151
|
ledger_api: EthereumApi,
|
|
148
152
|
loop: asyncio.AbstractEventLoop,
|
|
149
153
|
) -> Any:
|
|
@@ -156,6 +160,8 @@ async def watch_for_data_url_from_wss(
|
|
|
156
160
|
:type wss: websocket.WebSocket
|
|
157
161
|
:param mech_contract: The mech contract instance.
|
|
158
162
|
:type mech_contract: Web3Contract
|
|
163
|
+
:param deliver_signature: Topic signature for Deliver event
|
|
164
|
+
:type deliver_signature: str
|
|
159
165
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
160
166
|
:type ledger_api: EthereumApi
|
|
161
167
|
:param loop: The event loop used for asynchronous operations.
|
|
@@ -172,7 +178,7 @@ async def watch_for_data_url_from_wss(
|
|
|
172
178
|
executor, wait_for_receipt, tx_hash, ledger_api
|
|
173
179
|
)
|
|
174
180
|
event_signature = tx_receipt["logs"][0]["topics"][0].hex()
|
|
175
|
-
if event_signature !=
|
|
181
|
+
if event_signature != deliver_signature:
|
|
176
182
|
continue
|
|
177
183
|
|
|
178
184
|
rich_logs = mech_contract.events.Deliver().process_receipt(tx_receipt)
|
|
@@ -186,6 +192,7 @@ def watch_for_data_url_from_wss_sync(
|
|
|
186
192
|
request_id: str,
|
|
187
193
|
wss: websocket.WebSocket,
|
|
188
194
|
mech_contract: Web3Contract,
|
|
195
|
+
deliver_signature: str,
|
|
189
196
|
ledger_api: EthereumApi,
|
|
190
197
|
) -> Any:
|
|
191
198
|
"""
|
|
@@ -197,6 +204,8 @@ def watch_for_data_url_from_wss_sync(
|
|
|
197
204
|
:type wss: websocket.WebSocket
|
|
198
205
|
:param mech_contract: The mech contract instance.
|
|
199
206
|
:type mech_contract: Web3Contract
|
|
207
|
+
:param deliver_signature: Topic signature for Deliver event
|
|
208
|
+
:type deliver_signature: str
|
|
200
209
|
:param ledger_api: The Ethereum API used for interacting with the ledger.
|
|
201
210
|
:type ledger_api: EthereumApi
|
|
202
211
|
:return: The data received from on-chain.
|
|
@@ -208,6 +217,7 @@ def watch_for_data_url_from_wss_sync(
|
|
|
208
217
|
request_id=request_id,
|
|
209
218
|
wss=wss,
|
|
210
219
|
mech_contract=mech_contract,
|
|
220
|
+
deliver_signature=deliver_signature,
|
|
211
221
|
ledger_api=ledger_api,
|
|
212
222
|
loop=loop,
|
|
213
223
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "mech-client"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.10"
|
|
4
4
|
description = "Basic client to interact with a mech"
|
|
5
5
|
authors = ["David Minarsch <david.minarsch@googlemail.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -26,20 +26,20 @@ include = [
|
|
|
26
26
|
|
|
27
27
|
[tool.poetry.dependencies]
|
|
28
28
|
python = "^3.10"
|
|
29
|
-
open-aea = {version = "
|
|
30
|
-
open-aea-ledger-ethereum = "
|
|
31
|
-
open-aea-cli-ipfs = "
|
|
29
|
+
open-aea = {version = "==1.50.0", extras = ["cli"]}
|
|
30
|
+
open-aea-ledger-ethereum = "==1.50.0"
|
|
31
|
+
open-aea-cli-ipfs = "==1.50.0"
|
|
32
32
|
websocket-client = ">=0.32.0,<1"
|
|
33
33
|
gql = ">=3.4.1"
|
|
34
34
|
asn1crypto = ">=1.4.0,<1.5.0"
|
|
35
|
-
open-aea-ledger-cosmos = "
|
|
35
|
+
open-aea-ledger-cosmos = "==1.50.0"
|
|
36
36
|
|
|
37
37
|
[tool.poetry.scripts]
|
|
38
38
|
mechx = "mech_client.cli:cli"
|
|
39
39
|
|
|
40
40
|
[tool.poetry.group.dev.dependencies]
|
|
41
|
-
open-autonomy = "==0.
|
|
42
|
-
tomte = {
|
|
41
|
+
open-autonomy = "==0.14.10"
|
|
42
|
+
tomte = {version = "0.2.15", extras = ["tox"]}
|
|
43
43
|
|
|
44
44
|
[build-system]
|
|
45
45
|
requires = ["poetry-core"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn/tests/test_acn_dialogues.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/acn_data_share.proto
RENAMED
|
File without changes
|
{mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/acn_data_share_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/acn_data_share/serialization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/p2p_libp2p_client/connection.py
RENAMED
|
File without changes
|
{mech_client-0.2.8 → mech_client-0.2.10}/mech_client/helpers/p2p_libp2p_client/connection.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|