Skip to content

Commit

Permalink
feat: add support for dynamic pricing
Browse files Browse the repository at this point in the history
  • Loading branch information
0xArdi committed Feb 13, 2024
1 parent 6f00c4e commit 8406d29
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 10 deletions.
6 changes: 3 additions & 3 deletions packages/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
"dev": {
"connection/valory/websocket_client/0.1.0": "bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm",
"skill/valory/contract_subscription/0.1.0": "bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4",
"agent/valory/mech/0.1.0": "bafybeibwlyxqtitnfgmt2liuygv75pydlvih23e2ilwpr6xlffac5flyse",
"agent/valory/mech/0.1.0": "bafybeiazsvppldwszwte6m2htcd3glh2kk35cb7fql73stdeijcbphilgq",
"skill/valory/mech_abci/0.1.0": "bafybeieimp7xzxcnbzsuunf2xkcy5juulhmzsmkq2v3sw3o3lgssb53cnu",
"contract/valory/agent_mech/0.1.0": "bafybeiepxumywg6z2zapqzc3bg3iey23cmlgjzxisqox5j74o5i2texr5e",
"service/valory/mech/0.1.0": "bafybeicw64tjmcx6fbffwhpgdabmnxfwbuk6cycwrcu4me3hplcleu4mze",
"service/valory/mech/0.1.0": "bafybeidyogsdqt5vo26hkwgegwalxawgux3xjub4orae3ptsqphhedbqra",
"protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq",
"skill/valory/task_submission_abci/0.1.0": "bafybeib4m2bwgchloqss3wotsx4rz7qqkwydaesiqkls2zq7zbtp6jtpsi",
"skill/valory/task_execution/0.1.0": "bafybeieercgbjemdjiovecetxadurwil26cs2swleupmbgc4py2rg6e2kq",
"skill/valory/task_execution/0.1.0": "bafybeicsbtef4hbuuevraqdyicswlnc3i54fzxeqcjzh5soo5wjvh5ecni",
"contract/valory/agent_registry/0.1.0": "bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu",
"protocol/valory/websocket_client/0.1.0": "bafybeih43mnztdv3v2hetr2k3gezg7d3yj4ur7cxdvcyaqhg65e52s5sf4",
"skill/valory/websocket_client/0.1.0": "bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta",
Expand Down
3 changes: 2 additions & 1 deletion packages/valory/agents/mech/aea-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ skills:
- valory/registration_abci:0.1.0:bafybeic2ynseiak7jpta7jfwuqwyp453b4p7lolr4wihxmpn633uekv5am
- valory/reset_pause_abci:0.1.0:bafybeidzajbe3erygeh2xbd6lrjv7nsptznjuzrt24ykgvhgotdeyhfnba
- valory/subscription_abci:0.1.0:bafybeigaxq7m2dqv2huhg5jvb4jx3rysqwvvjj2xhojow3t3zzuwq2k4ie
- valory/task_execution:0.1.0:bafybeieercgbjemdjiovecetxadurwil26cs2swleupmbgc4py2rg6e2kq
- valory/task_execution:0.1.0:bafybeicsbtef4hbuuevraqdyicswlnc3i54fzxeqcjzh5soo5wjvh5ecni
- valory/task_submission_abci:0.1.0:bafybeib4m2bwgchloqss3wotsx4rz7qqkwydaesiqkls2zq7zbtp6jtpsi
- valory/termination_abci:0.1.0:bafybeie4zvjfxvdu7qrulmur3chpjz3kpj5m4bjsxvpk4gvj5zbyyayfaa
- valory/transaction_settlement_abci:0.1.0:bafybeiaefgqbs7zsn5xe5kdwrujj7ivygkn3ujpw6crnvi3knvxw75qmja
Expand Down Expand Up @@ -203,6 +203,7 @@ models:
agent_index: ${int:0}
num_agents: ${int:4}
from_block_range: ${int:50000}
mech_to_config: ${list:[["0x77af31De935740567Cf4fF1986D04B2c964A786a",["use_dynamic_pricing","false"]]]}
timeout_limit: ${int:3}
max_block_window: ${int:500}
---
Expand Down
6 changes: 5 additions & 1 deletion packages/valory/services/mech/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license: Apache-2.0
fingerprint:
README.md: bafybeif7ia4jdlazy6745ke2k2x5yoqlwsgwr6sbztbgqtwvs3ndm2p7ba
fingerprint_ignore_patterns: []
agent: valory/mech:0.1.0:bafybeibwlyxqtitnfgmt2liuygv75pydlvih23e2ilwpr6xlffac5flyse
agent: valory/mech:0.1.0:bafybeiazsvppldwszwte6m2htcd3glh2kk35cb7fql73stdeijcbphilgq
number_of_agents: 4
deployment:
agent:
Expand Down Expand Up @@ -177,6 +177,7 @@ type: skill
agent_index: ${AGENT_INDEX_0:int:0}
num_agents: ${NUM_AGENTS:int:4}
timeout_limit: ${TIMEOUT_LIMIT:int:3}
mech_to_config: ${list:[["0xFf82123dFB52ab75C417195c5fDB87630145ae81",["use_dynamic_pricing","false"]],["0x77af31De935740567Cf4fF1986D04B2c964A786a",["use_dynamic_pricing","false"]]]}
max_block_window: ${MAX_BLOCK_WINDOW:int:500}
1:
models:
Expand All @@ -189,6 +190,7 @@ type: skill
polling_interval: ${POLLING_INTERVAL:float:30.0}
agent_index: ${AGENT_INDEX_1:int:1}
num_agents: ${NUM_AGENTS:int:4}
mech_to_config: ${list:[["0xFf82123dFB52ab75C417195c5fDB87630145ae81",["use_dynamic_pricing","false"]],["0x77af31De935740567Cf4fF1986D04B2c964A786a",["use_dynamic_pricing","false"]]]}
timeout_limit: ${TIMEOUT_LIMIT:int:3}
max_block_window: ${MAX_BLOCK_WINDOW:int:500}
2:
Expand All @@ -202,6 +204,7 @@ type: skill
polling_interval: ${POLLING_INTERVAL:float:30.0}
agent_index: ${AGENT_INDEX_2:int:2}
num_agents: ${NUM_AGENTS:int:4}
mech_to_config: ${list:[["0xFf82123dFB52ab75C417195c5fDB87630145ae81",["use_dynamic_pricing","false"]],["0x77af31De935740567Cf4fF1986D04B2c964A786a",["use_dynamic_pricing","false"]]]}
timeout_limit: ${TIMEOUT_LIMIT:int:3}
max_block_window: ${MAX_BLOCK_WINDOW:int:500}
3:
Expand All @@ -216,6 +219,7 @@ type: skill
agent_index: ${AGENT_INDEX_3:int:3}
num_agents: ${NUM_AGENTS:int:4}
timeout_limit: ${TIMEOUT_LIMIT:int:3}
mech_to_config: ${list:[["0xFf82123dFB52ab75C417195c5fDB87630145ae81",["use_dynamic_pricing","false"]],["0x77af31De935740567Cf4fF1986D04B2c964A786a",["use_dynamic_pricing","false"]]]}
max_block_window: ${MAX_BLOCK_WINDOW:int:500}
---
public_id: valory/ledger:0.19.0
Expand Down
16 changes: 15 additions & 1 deletion packages/valory/skills/task_execution/behaviours.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from aea.protocols.base import Message
from aea.protocols.dialogue.base import Dialogue
from aea.skills.behaviours import SimpleBehaviour
from eth_abi import encode

from packages.valory.connections.ipfs.connection import IpfsDialogues
from packages.valory.connections.ipfs.connection import PUBLIC_ID as IPFS_CONNECTION_ID
Expand All @@ -49,6 +50,9 @@
from packages.valory.protocols.ledger_api import LedgerApiMessage
from packages.valory.skills.task_execution.models import Params
from packages.valory.skills.task_execution.utils.benchmarks import TokenCounterCallback
from packages.valory.skills.task_execution.utils.cost_calculation import (
get_cost_for_done_task,
)
from packages.valory.skills.task_execution.utils.ipfs import (
ComponentPackageLoader,
get_ipfs_file_hash,
Expand Down Expand Up @@ -454,7 +458,17 @@ def _handle_store_response(self, message: IpfsMessage, dialogue: Dialogue) -> No
data=ipfs_hash,
)
done_task = cast(Dict[str, Any], self._done_task)
done_task["task_result"] = to_multihash(ipfs_hash)
task_result = to_multihash(ipfs_hash)
cost = get_cost_for_done_task(done_task)
self.context.logger.info(f"Cost for task {req_id}: {cost}")
mech_config = self.params.mech_to_config[done_task["mech_address"]]
if mech_config.use_dynamic_pricing:
self.context.logger.info(f"Dynamic pricing is enabled for task {req_id}.")
task_result = encode(
["uint256", "bytes"], [cost, bytes.fromhex(task_result)]
)

done_task["task_result"] = task_result
# add to done tasks, in thread safe way
with self.done_tasks_lock:
self.done_tasks.append(done_task)
Expand Down
33 changes: 33 additions & 0 deletions packages/valory/skills/task_execution/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,28 @@
# ------------------------------------------------------------------------------

"""This module contains the shared state for the abci skill of Mech."""
import dataclasses
from collections import defaultdict
from typing import Any, Callable, Dict, List, Optional, cast

from aea.exceptions import enforce
from aea.skills.base import Model


@dataclasses.dataclass
class MechConfig:
"""Mech config dataclass."""

use_dynamic_pricing: bool

@staticmethod
def from_dict(raw_dict: Dict[str, Any]) -> "MechConfig":
"""From dict."""
return MechConfig(
use_dynamic_pricing=raw_dict["use_dynamic_pricing"].lower() == "true"
)


class Params(Model):
"""A model to represent params for multiple abci apps."""

Expand Down Expand Up @@ -66,6 +81,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
enforce(self.max_block_window is not None, "max_block_window must be set!")
# maps the request id to the number of times it has timed out
self.request_id_to_num_timeouts: Dict[int, int] = defaultdict(lambda: 0)
self.mech_to_config: Dict[str, MechConfig] = self._parse_mech_configs(kwargs)
super().__init__(*args, **kwargs)

def _nested_list_todict_workaround(
Expand All @@ -78,3 +94,20 @@ def _nested_list_todict_workaround(
if len(values) == 0:
raise ValueError(f"No {key} specified!")
return {value[0]: value[1] for value in values}

def _parse_mech_configs(self, kwargs: Dict) -> Dict[str, MechConfig]:
"""Parse the mech configs."""
mech_configs_json = self._nested_list_todict_workaround(
kwargs, "mech_to_config"
)
mech_configs = {
mech: MechConfig.from_dict(config)
for mech, config in mech_configs_json.items()
}
for self.agent_mech_contract_addresses in mech_configs.keys():
enforce(
self.agent_mech_contract_addresses
in self.agent_mech_contract_addresses,
f"agent_mech_contract_addresses {self.agent_mech_contract_addresses} must be in mech_configs!",
)
return mech_configs
13 changes: 10 additions & 3 deletions packages/valory/skills/task_execution/skill.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ license: Apache-2.0
aea_version: '>=1.0.0, <2.0.0'
fingerprint:
__init__.py: bafybeidqhvvlnthkbnmrdkdeyjyx2f2ab6z4xdgmagh7welqnh2v6wczx4
behaviours.py: bafybeihprwot27csugwpoimsqcwprxu5bstqpvanot3nkmfgvhbr66ww4y
behaviours.py: bafybeihxko4mv7dpeypi6g2v4zgdmwwvurnfd3yzdgyxvxx6oydr5izjd4
dialogues.py: bafybeid4zxalqdlo5mw4yfbuf34hx4jp5ay5z6chm4zviwu4cj7fudtwca
handlers.py: bafybeidbt5ezj74cgfogk3w4uw4si2grlnk5g54veyumw7g5yh6gdscywu
models.py: bafybeihgclxctyltuehj2f4fzj26edptqugrrm4phd6ovuulezrqot6qo4
models.py: bafybeiaz5lwhqzfv2azbdqjozwm5sums5eoingrhd2wz6syr4qiddftbhm
utils/__init__.py: bafybeiccdijaigu6e5p2iruwo5mkk224o7ywedc7nr6xeu5fpmhjqgk24e
utils/benchmarks.py: bafybeibdwt4svz24ahok4x4h2rpeotlmlmvifccd27oizsz5bjwj6dqree
utils/ipfs.py: bafybeidinbdqkidix44ibz5hug7inkcbijooag53gr5mtbaa72tk335uqq
utils/cost_calculation.py: bafybeib7wpojbriolfvrdb57ts6wl3cz5p4is2myofpvde7isr5iqztjem
utils/ipfs.py: bafybeibffem6y23fxdilc373kge4z6ht7phshbnlqbl55irb2xr7brdrlm
utils/task.py: bafybeieuziu7owtk543z3umgmayhjh67klftk7vrhz24l6rlaii5lvkqh4
fingerprint_ignore_patterns: []
connections:
Expand Down Expand Up @@ -84,6 +85,10 @@ models:
- stabilityai-stable-diffusion-768-v2-1
from_block_range: 50000
num_agents: 4
mech_to_config:
- - '0x9A676e781A523b5d0C0e43731313A708CB607508'
- - - use_dynamic_pricing
- 'false'
polling_interval: 30.0
task_deadline: 240.0
max_block_window: 500
Expand Down Expand Up @@ -111,4 +116,6 @@ dependencies:
version: ==0.5.1
anthropic:
version: ==0.3.11
eth-abi:
version: ==4.0.0
is_abstract: false
49 changes: 49 additions & 0 deletions packages/valory/skills/task_execution/utils/cost_calculation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2024 Valory AG
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------
"""Calculate the cost for tools."""
import logging
from typing import Any, Dict, cast

from packages.valory.skills.task_execution import PUBLIC_ID


_logger = logging.getLogger(
f"aea.packages.{PUBLIC_ID.author}.contracts.{PUBLIC_ID.name}.utils.cost_calculation"
)

DEFAULT_PRICE = 1 * 10**16


def get_cost_for_done_task(
done_task: Dict[str, Any], fallback_price: int = DEFAULT_PRICE
) -> int:
"""Get the cost for a done task."""
cost_dict = done_task.get("cost_dict", {})
if cost_dict == {}:
_logger.warning(f"Cost dict not found in done task {done_task['request_id']}.")
return fallback_price
total_cost = cost_dict.get("total_cost", None)
if total_cost is None:
_logger.warning(
f"Total cost not found in cost dict {cost_dict} for {done_task['request_id']}."
)
return fallback_price

total_cost = cast(float, total_cost)
return int(total_cost * 10**18)
2 changes: 1 addition & 1 deletion packages/valory/skills/task_execution/utils/ipfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def get_ipfs_file_hash(data: bytes) -> str:
return file_hash


def to_multihash(hash_string: str) -> bytes:
def to_multihash(hash_string: str) -> str:
"""To multihash string."""
# Decode the Base32 CID to bytes
cid_bytes = multibase.decode(hash_string)
Expand Down
3 changes: 3 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ ignore_missing_imports = True
[mypy-certifi.*]
ignore_missing_imports = True

[mypy-eth_abi.*]
ignore_missing_imports = True

[mypy-pandas.*]
ignore_missing_imports = True

Expand Down

0 comments on commit 8406d29

Please sign in to comment.