Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
0a8c331
WIP: integrate operate
KahanMajmudar Sep 17, 2025
9d23caa
read safe address
KahanMajmudar Sep 17, 2025
788cfdc
add safe-eth as dep
KahanMajmudar Sep 17, 2025
d859d31
safe tx for marketplace interact
KahanMajmudar Sep 17, 2025
33d538f
chore: update
jmoreira-valory Sep 17, 2025
02756e3
note
KahanMajmudar Sep 17, 2025
d8c1090
chore: update
jmoreira-valory Sep 18, 2025
02a1baa
Merge commit '02756e3fdba9c5213f3fae35e9129c36b9b4f142' into feat/ola…
jmoreira-valory Sep 18, 2025
d6d9f86
Merge pull request #117 from valory-xyz/feat/olas-service-j1
jmoreira-valory Sep 18, 2025
b1dca34
better operate env
KahanMajmudar Sep 18, 2025
4b6220d
chore: update poetry
jmoreira-valory Sep 18, 2025
2c7fdca
remove setup.py
KahanMajmudar Sep 29, 2025
09bd2d2
default to agent mode
KahanMajmudar Sep 29, 2025
69436cc
adds gas estimtion for safe tx
KahanMajmudar Sep 29, 2025
b163980
safe tx for approve tokens
KahanMajmudar Sep 30, 2025
3d75727
refactor: agent mode data for cli
KahanMajmudar Sep 30, 2025
5a05f84
safe tx for deposit native
KahanMajmudar Sep 30, 2025
0a5b889
fix: approve token price
KahanMajmudar Sep 30, 2025
7eed682
safe tx for deposit token
KahanMajmudar Sep 30, 2025
c600834
refactor: safe functions
KahanMajmudar Sep 30, 2025
0e2af10
fix: format code
KahanMajmudar Sep 30, 2025
5b16752
fix: safe txs for tokens
KahanMajmudar Oct 2, 2025
9655aa1
chore: funding requirements
jmoreira-valory Oct 2, 2025
8d836d4
chore: middleware
jmoreira-valory Oct 2, 2025
f3807e7
WIP: mech client service and agent
KahanMajmudar Oct 2, 2025
3c2defb
fix: packages
jmoreira-valory Oct 2, 2025
eda8554
chore: update
jmoreira-valory Oct 2, 2025
90f4869
fix: template
jmoreira-valory Oct 2, 2025
1b407dc
chore: update
jmoreira-valory Oct 2, 2025
815027d
update: latest hash
KahanMajmudar Oct 3, 2025
4159a0d
feat: agent mode for nvm
KahanMajmudar Oct 3, 2025
815de7d
Merge branch 'main' into feat/olas-service
KahanMajmudar Oct 6, 2025
c1446bb
update operate folder name and location
KahanMajmudar Oct 6, 2025
c069a51
better operate path and key management
KahanMajmudar Oct 6, 2025
d8db0fe
update agent desc
KahanMajmudar Oct 6, 2025
38ca5fb
fix: vulture
KahanMajmudar Oct 7, 2025
6b61c5f
fix: flake8
KahanMajmudar Oct 7, 2025
8f2ef7e
fix: darglint
KahanMajmudar Oct 7, 2025
3e4fe44
fix: mypy
KahanMajmudar Oct 7, 2025
bd55d80
fix: pylint
KahanMajmudar Oct 7, 2025
1ba208d
fix: liccheck
KahanMajmudar Oct 7, 2025
19f9571
fix: typos
KahanMajmudar Oct 7, 2025
808dd08
better UX for agent mode
KahanMajmudar Oct 7, 2025
5767ba1
prelim test with new agent
KahanMajmudar Oct 8, 2025
eb9bbe0
fix: flake8
KahanMajmudar Oct 8, 2025
a04309f
fix: unref var
KahanMajmudar Oct 8, 2025
389111e
fix: mypy
KahanMajmudar Oct 8, 2025
48711aa
fix: condition
KahanMajmudar Oct 8, 2025
80984a1
cwd as operate path
KahanMajmudar Oct 8, 2025
9496c50
fix: correct cmd
KahanMajmudar Oct 8, 2025
679ba36
better setup mode
KahanMajmudar Oct 8, 2025
ba5f734
chore: update middleware
jmoreira-valory Oct 8, 2025
7f6604e
fetch agent mode data now uses operate keys manager
KahanMajmudar Oct 9, 2025
545ea6f
fix: format-code
KahanMajmudar Oct 9, 2025
df47e25
update funds requirements
KahanMajmudar Oct 9, 2025
02d78da
update operate path
KahanMajmudar Oct 9, 2025
d6aeacf
base support for nvm purchase
KahanMajmudar Oct 9, 2025
3b8c5dd
fix: liccheck
KahanMajmudar Oct 9, 2025
5605583
fix: flake8
KahanMajmudar Oct 9, 2025
2b04d44
fix: vulture
KahanMajmudar Oct 9, 2025
9b089ae
fix: mypy
KahanMajmudar Oct 9, 2025
e924e3e
fix: liccheck
KahanMajmudar Oct 9, 2025
190c2af
rename patch function
KahanMajmudar Oct 9, 2025
7876c78
fetch agent mode is on or not
KahanMajmudar Oct 9, 2025
5e53c23
fix: format code
KahanMajmudar Oct 9, 2025
d33a9d9
fix: duplicate imports
KahanMajmudar Oct 9, 2025
3017ffd
chore: update middleware
jmoreira-valory Oct 9, 2025
4ea273e
chore: update
jmoreira-valory Oct 9, 2025
65485e8
Merge pull request #123 from valory-xyz/feat/olas-service-2
KahanMajmudar Oct 10, 2025
29fbeaf
update default master eoa funds for gnosis
KahanMajmudar Oct 10, 2025
7f3b79a
nvm naming update
KahanMajmudar Oct 10, 2025
94f4662
update olas address for celo
KahanMajmudar Oct 10, 2025
188fc2e
add info for agent mode
KahanMajmudar Oct 10, 2025
b672531
fix: deposit native for agent mode
KahanMajmudar Oct 10, 2025
85a4c60
supported network info for agent mode
KahanMajmudar Oct 10, 2025
d17a790
chore: update middleware
jmoreira-valory Oct 10, 2025
0c4f2f3
integrate new keys manager function
KahanMajmudar Oct 10, 2025
0392cb9
Merge branch 'main' into feat/olas-service
KahanMajmudar Oct 10, 2025
a432b34
fix: ci
KahanMajmudar Oct 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
packages/valory/
mech_client/helpers/acn
mech_client/helpers/acn_data_share
mech_client/helpers/p2p_libp2p_client

packages/valory/connections
packages/valory/protocols
packages/valory/skills
packages/open_aea

keys
ethereum_private_key.txt
acn_cert.txt

Expand All @@ -12,6 +17,8 @@ temp/
.tox/
__pycache__
.env
.operate*
keys.json

.idea/
.idea/*
.idea/*
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@ Once you have your API key, you'll need to configure it in your environment. Use
export MECHX_API_KEY=<your api key>
```

### Set up agent mode for on-chain interactions (For Latest Marketplace Mechs only)
There are two modes you can use the mechx for on-chain interactions. Currently `agent-mode` is only supported for gnosis network
- *agent mode* (Recommended): This allows to register your on-chain interactions as agent on the olas protocol and allows for A2A activity to be reflected on the client
- *client mode*: Simple on-chain interations using EOA

```bash
cp .example.env .env
```
:note: For better reliability, it is recommended to use a stable third-party RPC provider.

```bash
mechx setup-agent-mode
```

To use client-mode, simply supply `--client-mode` flag before the cli command.

```bash
mechx --client-mode <rest of the cli command>
```

### Generate Mech requests

#### Select the mech you are going to send requests to
Expand Down
24 changes: 24 additions & 0 deletions config/mech_client.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "Mech Client (agent mode)",
"hash": "bafybeicrsrqajrzgweh7q4grfsbkkadovyqzfouqgb5lmxyqulqv7mjaye",
"description": "The mech_client service to allow interacting with on-chain mechs",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the description from the service.

"image": "https://gateway.autonolas.tech/ipfs/bafybeidzpenez565d7vp7jexfrwisa2wijzx6vwcffli57buznyyqkrceq",
"service_version": "v0.1.0",
"home_chain": "gnosis",
"configurations": {
"gnosis": {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a configuration for the other chain?

"agent_id": 77,
"nft": "bafybeifgj3kackzfoq4fxjiuousm6epgwx7jbc3n2gjwzjgvtbbz7fc3su",
"threshold": 1,
"use_mech_marketplace": false,
"cost_of_bond": 1,
"fund_requirements": {
"0x0000000000000000000000000000000000000000": {
"agent": 100000000000000000,
"safe": 100000000000000000
}
}
}
},
"env_variables": {}
}
209 changes: 204 additions & 5 deletions mech_client/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,22 @@
"""Mech client CLI module."""
import json
import os
import sys
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple

import click
from click import ClickException
from operate.cli import OperateApp
from operate.constants import NO_STAKING_PROGRAM_ID, ZERO_ADDRESS
from operate.ledger.profiles import DEFAULT_MASTER_EOA_FUNDS
from operate.operate_types import Chain, ServiceTemplate
from operate.quickstart.run_service import (
QuickstartConfig,
load_local_config,
run_service,
)
from operate.services.manage import KeysManager
from tabulate import tabulate # type: ignore

from mech_client import __version__
Expand Down Expand Up @@ -58,10 +70,135 @@
from scripts.nvm_subscribe import main as nvm_subscribe_main


CURR_DIR = Path(__file__).resolve().parent
BASE_DIR = CURR_DIR.parent
GNOSIS_TEMPLATE_CONFIG_PATH = BASE_DIR / "config" / "mech_client.json"
OPERATE_FOLDER_NAME = ".operate_mech_client"
SETUP_MODE_COMMAND = "setup-agent-mode"
DEFAULT_NETWORK = "gnosis"


DEFAULT_MASTER_EOA_FUNDS.update(
{
Chain.ARBITRUM_ONE: {ZERO_ADDRESS: 5_000_000_000_000_000},
Chain.BASE: {ZERO_ADDRESS: 5_000_000_000_000_000},
Chain.CELO: {ZERO_ADDRESS: 1_500_000_000_000_000_000},
Chain.ETHEREUM: {ZERO_ADDRESS: 20_000_000_000_000_000},
Chain.GNOSIS: {ZERO_ADDRESS: 200_000_000_000_000_000},
Chain.MODE: {ZERO_ADDRESS: 500_000_000_000_000},
Chain.OPTIMISM: {ZERO_ADDRESS: 5_000_000_000_000_000},
Chain.POLYGON: {ZERO_ADDRESS: 1_500_000_000_000_000_000},
}
)


def get_operate_path() -> Path:
"""Fetches the operate path for the mech client service"""
home = Path.home()
operate_path = home.joinpath(OPERATE_FOLDER_NAME)
return operate_path


def is_agent_mode(ctx: click.Context) -> bool:
"""Fetches whether agent mode is on or not"""
client_mode = ctx.obj.get("client_mode", False)
agent_mode = not client_mode
return agent_mode


def mech_client_configure_local_config(
template: ServiceTemplate, operate: "OperateApp"
) -> QuickstartConfig:
"""Configure local quickstart configuration."""
config = load_local_config(operate=operate, service_name=template["name"])

if config.rpc is None:
config.rpc = {}

for chain in template["configurations"]:
config.rpc[chain] = os.getenv("MECHX_RPC_URL")

config.principal_chain = template["home_chain"]

# set chain configs in the service template
for chain in template["configurations"]:
template["configurations"][chain] |= {
"staking_program_id": NO_STAKING_PROGRAM_ID,
"rpc": config.rpc[chain],
"cost_of_bond": 1,
}

if config.user_provided_args is None:
config.user_provided_args = {}

config.store()
return config


def fetch_agent_mode_data(chain_config: Optional[str]) -> Tuple[str, str]:
"""Fetches the agent mode data of safe address and the EOA private key path"""
chain_config = chain_config or DEFAULT_NETWORK

# This is acceptable way to as the main functionality
# of keys manager is to allow access to the required data.
operate_path = get_operate_path()
operate = OperateApp(operate_path)
keys_manager = KeysManager(
path=operate._keys, # pylint: disable=protected-access
logger=operate.wallet_manager.logger,
)
service_manager = operate.service_manager()
service_config_id = service_manager.json[0]["service_config_id"]
service = operate.service_manager().load(service_config_id)

key = keys_manager.get_private_key_file(service.agent_addresses[0])
safe = service.chain_configs[chain_config].chain_data.multisig

return safe, key


@click.group(name="mechx") # type: ignore
@click.version_option(__version__, prog_name="mechx")
def cli() -> None:
@click.option(
"--client-mode",
is_flag=True,
help="Enables client mode",
)
@click.pass_context
def cli(ctx: click.Context, client_mode: bool) -> None:
"""Command-line tool for interacting with mechs."""
ctx.ensure_object(dict)
ctx.obj["client_mode"] = client_mode

cli_command = ctx.invoked_subcommand if ctx.invoked_subcommand else None
is_setup_called = cli_command == SETUP_MODE_COMMAND

if not is_setup_called and not client_mode:
click.echo("Agent mode enabled")
operate_path = get_operate_path()
if not operate_path.exists():
raise ClickException(
f"""Operate path does not exists at: {operate_path}. Setup agent mode using mechx setup-agent-mode."""
)


@click.command()
def setup_agent_mode() -> None:
"""Sets up the agent mode for users"""
operate_path = get_operate_path()
operate = OperateApp(operate_path)
operate.setup()

sys.modules[
"operate.quickstart.run_service"
].configure_local_config = mech_client_configure_local_config # type: ignore

run_service(
operate=operate,
config_path=GNOSIS_TEMPLATE_CONFIG_PATH,
build_only=True,
skip_dependency_check=False,
)


@click.command()
Expand Down Expand Up @@ -133,14 +270,17 @@ def cli() -> None:
type=str,
help="Id of the mech's chain configuration (stored configs/mechs.json)",
)
@click.pass_context
def interact( # pylint: disable=too-many-arguments,too-many-locals
ctx: click.Context,
prompts: tuple,
agent_id: int,
priority_mech: str,
use_prepaid: bool,
use_offchain: bool,
key: Optional[str],
tools: Optional[tuple],
safe: Optional[str] = None,
extra_attribute: Optional[List[str]] = None,
confirm: Optional[str] = None,
retries: Optional[int] = None,
Expand All @@ -150,6 +290,9 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
) -> None:
"""Interact with a mech specifying a prompt and tool."""
try:
agent_mode = is_agent_mode(ctx)
click.echo(f"Running interact with agent_mode={agent_mode}")

extra_attributes_dict: Dict[str, Any] = {}
if extra_attribute:
for pair in extra_attribute:
Expand All @@ -171,9 +314,18 @@ def interact( # pylint: disable=too-many-arguments,too-many-locals
f"The number of prompts ({len(prompts)}) must match the number of tools ({len(tools)})"
)

if agent_mode:
safe, key = fetch_agent_mode_data(chain_config)
if not safe or not key:
raise ClickException(
"Cannot fetch safe or key data for the agent mode."
)

marketplace_interact_(
prompts=prompts,
priority_mech=priority_mech,
agent_mode=agent_mode,
safe_address=safe,
use_prepaid=use_prepaid,
use_offchain=use_offchain,
mech_offchain_url=mech_offchain_url,
Expand Down Expand Up @@ -459,14 +611,29 @@ def tool_io_schema_for_marketplace_mech(tool_id: str, chain_config: str) -> None
type=click.Path(exists=True, file_okay=True, dir_okay=False),
help="Path to private key to use for deposit",
)
@click.pass_context
def deposit_native(
ctx: click.Context,
amount_to_deposit: str,
key: Optional[str],
safe: Optional[str] = None,
chain_config: Optional[str] = None,
) -> None:
"""Deposits Native balance for prepaid requests."""
agent_mode = is_agent_mode(ctx)
click.echo(f"Running deposit native with agent_mode={agent_mode}")

if agent_mode:
safe, key = fetch_agent_mode_data(chain_config)
if not safe or not key:
raise ClickException("Cannot fetch safe or key data for the agent mode.")

deposit_native_main(
amount=amount_to_deposit, private_key_path=key, chain_config=chain_config
agent_mode=agent_mode,
safe_address=safe,
amount=amount_to_deposit,
private_key_path=key,
chain_config=chain_config,
)


Expand All @@ -482,14 +649,29 @@ def deposit_native(
type=click.Path(exists=True, file_okay=True, dir_okay=False),
help="Path to private key to use for deposit",
)
@click.pass_context
def deposit_token(
ctx: click.Context,
amount_to_deposit: str,
key: Optional[str],
safe: Optional[str] = None,
chain_config: Optional[str] = None,
) -> None:
"""Deposits Token balance for prepaid requests."""
agent_mode = is_agent_mode(ctx)
click.echo(f"Running deposit token with agent_mode={agent_mode}")

if agent_mode:
safe, key = fetch_agent_mode_data(chain_config)
if not safe or not key:
raise ClickException("Cannot fetch safe or key data for the agent mode.")

deposit_token_main(
amount=amount_to_deposit, private_key_path=key, chain_config=chain_config
agent_mode=agent_mode,
safe_address=safe,
amount=amount_to_deposit,
private_key_path=key,
chain_config=chain_config,
)


Expand All @@ -504,12 +686,28 @@ def deposit_token(
type=click.Path(exists=True, file_okay=True, dir_okay=False),
help="Path to private key to use for deposit",
)
@click.pass_context
def nvm_subscribe(
ctx: click.Context,
key: str,
chain_config: str,
safe: Optional[str] = None,
) -> None:
"""Allows to purchase nvm subscription for nvm mech requests."""
nvm_subscribe_main(private_key_path=key, chain_config=chain_config)
agent_mode = is_agent_mode(ctx)
click.echo(f"Running purchase nvm subscription with agent_mode={agent_mode}")

if agent_mode:
safe, key = fetch_agent_mode_data(chain_config)
if not safe or not key:
raise ClickException("Cannot fetch safe or key data for the agent mode.")

nvm_subscribe_main(
agent_mode=agent_mode,
safe_address=safe,
private_key_path=key,
chain_config=chain_config,
)


@click.command(name="fetch-mm-mechs-info")
Expand Down Expand Up @@ -560,6 +758,7 @@ def query_mm_mechs_info_cli(
return None


cli.add_command(setup_agent_mode)
cli.add_command(interact)
cli.add_command(prompt_to_ipfs)
cli.add_command(push_to_ipfs)
Expand All @@ -577,4 +776,4 @@ def query_mm_mechs_info_cli(


if __name__ == "__main__":
cli()
cli() # pylint: disable=no-value-for-parameter
Loading