Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add quickstart scripts #690

Open
wants to merge 32 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3e6b646
Feat: Quickstart
OjusWiZard Jan 9, 2025
e747819
fix: support mainnet RPCs
OjusWiZard Jan 10, 2025
5de9dcf
Feat: Support Mech
OjusWiZard Jan 14, 2025
6faa044
Merge branch 'fix/meme-staging' into feat/multi-agent-middleware
OjusWiZard Jan 15, 2025
dc07fdc
fix: persistent data in docker
OjusWiZard Jan 15, 2025
873f9f5
chore: add mech activity checker ABI
OjusWiZard Jan 15, 2025
f877f0e
fix: logs analysis
OjusWiZard Jan 15, 2025
da4cf63
chore: parity with trader-quickstart
OjusWiZard Jan 16, 2025
73072bc
fix: broken ABI links
OjusWiZard Jan 20, 2025
db9f3d4
Merge branch 'fix/meme-staging' into feat/multi-agent-middleware
OjusWiZard Jan 21, 2025
558b0d9
fix: update service config with latest env_variables
OjusWiZard Jan 21, 2025
c5e3850
chore: add qs_beta_expert 15 and 16 staking
OjusWiZard Jan 21, 2025
18c776a
fix: use_mech_marketplace in qs_beta_expert_15/16
OjusWiZard Jan 22, 2025
2f9b03b
chore: clean unused code
OjusWiZard Jan 22, 2025
b839c5b
chore: consistent quickstart function names
OjusWiZard Jan 23, 2025
0e02b41
added validator and slots avail handler
Mohsinsiddi Jan 27, 2025
4fdff54
fix: dynamic mech contract address
OjusWiZard Jan 27, 2025
d6749a3
Merge branch 'fix/meme-staging' into feat/multi-agent-middleware
OjusWiZard Jan 27, 2025
06f8692
added unstake onchain handler in reset-staking cli cmd
Mohsinsiddi Jan 28, 2025
6d13128
uncommitted unused codes
Mohsinsiddi Jan 28, 2025
448edc9
added validator and slots avail handler (#712)
Mohsinsiddi Jan 29, 2025
4fa023c
Merge branch 'fix/meme-staging' into feat/multi-agent-middleware
OjusWiZard Jan 31, 2025
a087719
resolved merge conflicts
Mohsinsiddi Feb 3, 2025
d17616c
updated reset flow based on PR reviews
Mohsinsiddi Feb 4, 2025
0d60c59
refactoring code with PR
Mohsinsiddi Feb 4, 2025
ae6e642
fixed a bug of handling if not can_unstake case
Mohsinsiddi Feb 4, 2025
1f9ca73
refactored code
Mohsinsiddi Feb 4, 2025
a54b99e
refactored code
Mohsinsiddi Feb 4, 2025
e47e429
refactored code
Mohsinsiddi Feb 4, 2025
a106639
Merge branch 'fix/meme-staging' into feat/multi-agent-middleware
OjusWiZard Feb 4, 2025
24c30b8
updated as per reviewed on PR
Mohsinsiddi Feb 4, 2025
18e1408
Merge pull request #719 from valory-xyz/feat/reset_staking
OjusWiZard Feb 5, 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
106 changes: 104 additions & 2 deletions operate/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,16 @@

from operate import services
from operate.account.user import UserAccount
from operate.constants import KEY, KEYS, OPERATE, SERVICES
from operate.constants import KEY, KEYS, OPERATE_HOME, SERVICES
from operate.ledger.profiles import DEFAULT_NEW_SAFE_FUNDS_AMOUNT
from operate.operate_types import Chain, DeploymentStatus, LedgerType
from operate.quickstart.reset_password import reset_password
from operate.quickstart.reset_staking import reset_staking
from operate.quickstart.analyse_logs import analyse_logs
from operate.quickstart.claim_staking_rewards import claim_staking_rewards
from operate.quickstart.run_service import run_service
from operate.quickstart.stop_service import stop_service
from operate.quickstart.terminate_on_chain_service import terminate_service
from operate.services.health_checker import HealthChecker
from operate.wallet.master import MasterWalletManager

Expand Down Expand Up @@ -75,7 +82,7 @@ def __init__(
) -> None:
"""Initialize object."""
super().__init__()
self._path = (home or (Path.cwd() / OPERATE)).resolve()
self._path = (home or OPERATE_HOME).resolve()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would the removal of Path.cwd not cause any issue?

Copy link
Member Author

Choose a reason for hiding this comment

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

OPERATE_HOME is already defined as Path.cwd() / OPERATE in operate/constants.py

self._services = self._path / SERVICES
self._keys = self._path / KEYS
self._master_key = self._path / KEY
Expand Down Expand Up @@ -940,6 +947,101 @@ def _daemon(
server.run()


@_operate.command(name="quickstart")
def quickstart(
config: Annotated[str, params.String(help="Quickstart config file path")],
) -> None:
"""Quickstart."""
operate = OperateApp()
operate.setup()
run_service(operate=operate, config_path=config)


OjusWiZard marked this conversation as resolved.
Show resolved Hide resolved
@_operate.command(name="quickstop")
def quickstop(
config: Annotated[str, params.String(help="Quickstart config file path")],
) -> None:
"""Quickstart."""
operate = OperateApp()
operate.setup()
stop_service(operate=operate, config_path=config)


@_operate.command(name="terminate")
def terminate(
config: Annotated[str, params.String(help="Quickstart config file path")],
) -> None:
"""Quickstart."""
operate = OperateApp()
operate.setup()
terminate_service(operate=operate, config_path=config)


@_operate.command(name="claim")
def quickclaim(
config: Annotated[str, params.String(help="Quickstart config file path")],
) -> None:
"""Quickclaim staking rewards."""
operate = OperateApp()
operate.setup()
claim_staking_rewards(operate=operate, config_path=config)


@_operate.command(name="reset-staking")
def quick_reset_staking(
config: Annotated[str, params.String(help="Quickstart config file path")],
) -> None:
"""Reset staking."""
operate = OperateApp()
operate.setup()
reset_staking(operate=operate, config_path=config)


@_operate.command(name="reset-password")
def quick_reset_password() -> None:
"""Reset password."""
operate = OperateApp()
operate.setup()
reset_password(operate=operate)


@_operate.command(name="analyse-logs")
def quick_analyse_logs(
config: Annotated[str, params.String(help="Quickstart config file path")],
from_dir: Annotated[str, params.String(help="Path to the logs directory. If not provided, it is auto-detected.", default="")],
agent: Annotated[str, params.String(help="The agent name to analyze (default: 'aea_0').", default="aea_0")],
reset_db: Annotated[bool, params.Boolean(help="Use this flag to disable resetting the log database.", default=False)],
start_time: Annotated[str, params.String(help="Start time in `YYYY-MM-DD H:M:S,MS` format.", default="")],
end_time: Annotated[str, params.String(help="End time in `YYYY-MM-DD H:M:S,MS` format.", default="")],
log_level: Annotated[str, params.String(help="Logging level. (INFO, DEBUG, WARNING, ERROR, CRITICAL)", default="INFO")],
period: Annotated[int, params.Integer(help="Period ID.", default="")],
round: Annotated[str, params.String(help="Round name.", default="")],
behaviour: Annotated[str, params.String(help="Behaviour name filter.", default="")],
fsm: Annotated[bool, params.Boolean(help="Print only the FSM execution path.", default=False)],
include_regex: Annotated[str, params.String(help="Regex pattern to include in the result.", default="")],
exclude_regex: Annotated[str, params.String(help="Regex pattern to exclude from the result.", default="")],
) -> None:
"""Analyse the logs of an agent."""
operate = OperateApp()
operate.setup()
analyse_logs(
operate=operate,
config_path=config,
from_dir=from_dir,
agent=agent,
reset_db=reset_db,
start_time=start_time,
end_time=end_time,
log_level=log_level,
period=period,
round=round,
behaviour=behaviour,
fsm=fsm,
include_regex=include_regex,
exclude_regex=exclude_regex
)


def main() -> None:
"""CLI entry point."""
run(cli=_operate)
Expand Down
18 changes: 17 additions & 1 deletion operate/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@

"""Constants."""

from pathlib import Path

from operate.operate_types import Chain


OPERATE = ".operate"
OPERATE_HOME = Path.cwd() / OPERATE
CONFIG = "config.json"
SERVICES = "services"
KEYS = "keys"
Expand All @@ -31,12 +37,22 @@
KEYS_JSON = "keys.json"
DOCKER_COMPOSE_YAML = "docker-compose.yaml"
SERVICE_YAML = "service.yaml"
STAKED_BONDING_TOKEN = "OLAS"
ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"

ON_CHAIN_INTERACT_TIMEOUT = 120.0
ON_CHAIN_INTERACT_RETRIES = 40
ON_CHAIN_INTERACT_SLEEP = 3.0

HEALTH_CHECK_URL = "http://127.0.0.1:8716/healthcheck" # possible DNS issues on windows so use IP address

SAFE_WEBAPP_URL = "https://app.safe.global/home?safe=gno:"
TM_CONTROL_URL = "http://localhost:8080"
IPFS_ADDRESS = "https://gateway.autonolas.tech/ipfs/f01701220{hash}"
ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"

# TODO: These links may break in the future, use a more robust approach
MECH_CONTRACT_JSON_URL = "https://raw.githubusercontent.com/valory-xyz/mech/refs/tags/v0.8.0/packages/valory/contracts/agent_mech/build/AgentMech.json"
STAKING_TOKEN_INSTANCE_ABI_PATH = 'https://raw.githubusercontent.com/valory-xyz/trader/refs/tags/v0.23.0/packages/valory/contracts/staking_token/build/StakingToken.json'
MECH_ACTIVITY_CHECKER_JSON_URL = 'https://raw.githubusercontent.com/valory-xyz/autonolas-staking-programmes/refs/heads/main/abis/0.8.25/SingleMechActivityChecker.json'
SERVICE_REGISTRY_TOKEN_UTILITY_JSON_URL = "https://raw.githubusercontent.com/valory-xyz/open-autonomy/refs/tags/v0.18.4/packages/valory/contracts/service_registry_token_utility/build/ServiceRegistryTokenUtility.json"
MECH_AGENT_FACTORY_JSON_URL = "https://raw.githubusercontent.com/valory-xyz/ai-registry-mech/main/abis/0.8.25/AgentFactory.json"
Comment on lines +52 to +58
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why aren't we using the built-in framework contracts ?

Copy link
Member Author

Choose a reason for hiding this comment

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

you mean from open-autonomy? They are not there.

17 changes: 17 additions & 0 deletions operate/ledger/profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@
"pearl_beta_4": "0x3052451e1eAee78e62E169AfdF6288F8791F2918",
"pearl_beta_5": "0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4",
"pearl_beta_mech_marketplace": "0xDaF34eC46298b53a3d24CBCb431E84eBd23927dA",
"quickstart_beta_hobbyist": "0x389B46c259631Acd6a69Bde8B6cEe218230bAE8C",
"quickstart_beta_hobbyist_2": "0x238EB6993b90a978ec6AAD7530d6429c949C08DA",
"quickstart_beta_expert": "0x5344B7DD311e5d3DdDd46A4f71481bD7b05AAA3e",
"quickstart_beta_expert_2": "0xb964e44c126410df341ae04B13aB10A985fE3513",
"quickstart_beta_expert_3": "0x80faD33Cadb5F53f9D29F02Db97D682E8b101618",
"quickstart_beta_expert_4": "0xaD9d891134443B443D7F30013c7e14Fe27F2E029",
"quickstart_beta_expert_5": "0xE56dF1E563De1B10715cB313D514af350D207212",
"quickstart_beta_expert_6": "0x2546214aEE7eEa4bEE7689C81231017CA231Dc93",
"quickstart_beta_expert_7": "0xD7A3C8b975f71030135f1a66e9e23164d54fF455",
"quickstart_beta_expert_8": "0x356C108D49C5eebd21c84c04E9162de41933030c",
"quickstart_beta_expert_9": "0x17dBAe44BC5618Cc254055b386A29576b4F87015",
"quickstart_beta_expert_10": "0xB0ef657b8302bd2c74B6E6D9B2b4b39145b19c6f",
"quickstart_beta_expert_11": "0x3112c1613eAC3dBAE3D4E38CeF023eb9E2C91CF7",
"quickstart_beta_expert_12": "0xF4a75F476801B3fBB2e7093aCDcc3576593Cc1fc",
"quickstart_beta_expert_15_mech_marketplace": "0x88eB38FF79fBa8C19943C0e5Acfa67D5876AdCC1",
"quickstart_beta_expert_16_mech_marketplace": "0x6c65430515c70a3f5E62107CC301685B7D46f991",
"mech_marketplace": "0x998dEFafD094817EF329f6dc79c703f1CF18bC90",
},
Chain.OPTIMISTIC: {
"optimus_alpha": "0x88996bbdE7f982D93214881756840cE2c77C4992",
Expand Down
13 changes: 11 additions & 2 deletions operate/operate_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,18 @@ class LedgerConfig(LocalResource):
LedgerConfigs = t.Dict[str, LedgerConfig]


class NodeConfig(TypedDict):
"""Deployment node config."""

ports: t.Optional[t.Dict[t.Union[str, int], t.Dict[int, int]]]
volumes: t.Optional[t.Union[t.Dict[str, str], t.Dict[t.Union[str, int], t.Dict[str, str]]]]


class DeploymentConfig(TypedDict):
"""Deployments template."""

volumes: t.Dict[str, str]

agent: t.Optional[NodeConfig]
tendermint: t.Optional[NodeConfig]

class FundRequirementsTemplate(TypedDict):
"""Fund requirement template."""
Expand Down Expand Up @@ -241,11 +248,13 @@ class ServiceTemplate(TypedDict, total=False):
"""Service template."""

name: str
agent_id: int
hash: str
image: str
description: str
service_version: str
home_chain: str
staking_programs: t.Dict[str, str]
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the purpose of this ?

Copy link
Member Author

Choose a reason for hiding this comment

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

so I need you to check a service template of the quickstart
I'm basically planning to move these staking_programs mapping from operate/ledger/profiles.py:STAKING to the service template. So that the middleware is configurable and agent-agnostic

Copy link
Collaborator

@jmoreira-valory jmoreira-valory Jan 23, 2025

Choose a reason for hiding this comment

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

Makes sense moving the staking program to the service template, but the staking contract addresses are per chain. I.e., let's not assume they can only be made on the home chain.

configurations: ConfigurationTemplates
env_variables: EnvVariables

Expand Down
92 changes: 92 additions & 0 deletions operate/quickstart/analyse_logs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import json
import os
import subprocess
import sys
from pathlib import Path
from typing import TYPE_CHECKING

from operate.constants import DEPLOYMENT

if TYPE_CHECKING:
from operate.cli import OperateApp


def find_build_directory(config_file: Path, operate: "OperateApp") -> Path:
"""Find the appropriate build directory of the configured service."""
with open(config_file, "r") as f:
config = json.load(f)
config_service_hash = config.get("hash")

services = operate.service_manager()._get_all_services()
for service in services:
if service.hash == config_service_hash:
build_dir = service.path / DEPLOYMENT
if not build_dir.exists():
print(f"{config.get('name')} not deployed.")
sys.exit(1)
return build_dir

print(f"{config.get('name')} not found.")
sys.exit(1)


def run_analysis(logs_dir, **kwargs):
"""Run the log analysis command."""
command = [
"poetry", "run", "autonomy", "analyse", "logs",
"--from-dir", logs_dir,
]
if kwargs.get("agent"):
command.extend(["--agent", kwargs.get("agent")])
if kwargs.get("reset_db"):
command.extend(["--reset-db"])
if kwargs.get("start_time"):
command.extend(["--start-time", kwargs.get("start_time")])
if kwargs.get("end_time"):
command.extend(["--end-time", kwargs.get("end_time")])
if kwargs.get("log_level"):
command.extend(["--log-level", kwargs.get("log_level")])
if kwargs.get("period"):
command.extend(["--period", kwargs.get("period")])
if kwargs.get("round"):
command.extend(["--round", kwargs.get("round")])
if kwargs.get("behaviour"):
command.extend(["--behaviour", kwargs.get("behaviour")])
if kwargs.get("fsm"):
command.extend(["--fsm"])
if kwargs.get("include_regex"):
command.extend(["--include-regex", kwargs.get("include_regex")])
if kwargs.get("exclude_regex"):
command.extend(["--exclude-regex", kwargs.get("exclude_regex")])

try:
subprocess.run(command, check=True)
print("Analysis completed successfully.")
except subprocess.CalledProcessError as e:
print(f"Command failed with exit code {e.returncode}")
sys.exit(e.returncode)
except FileNotFoundError:
print("Poetry or autonomy not found. Ensure they are installed and accessible.")
sys.exit(1)


def analyse_logs(
operate: "OperateApp",
config_path: str,
**kwargs
):

config_file = Path(config_path)
if not config_file.exists():
print(f"Config file '{config_file}' not found.")
sys.exit(1)

# Auto-detect the logs directory
build_dir = find_build_directory(config_file, operate)
logs_dir = os.path.join(build_dir, "persistent_data", "logs")
if not os.path.exists(logs_dir):
print(f"Logs directory '{logs_dir}' not found.")
sys.exit(1)

# Run the analysis
run_analysis(logs_dir, **kwargs)
Loading
Loading