diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b461c8ae..761766c5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -29,3 +29,30 @@ _Put an `x` in the boxes that apply._ ## Further comments If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... + +DELETE INCLUSIVE THIS AND BELOW FOR STANDARD PR +------ + +## Release summary + +Version number: [e.g. 1.0.1] + +## Release details + +Describe in short the main changes with the new release. + +## Checklist + +_Put an `x` in the boxes that apply._ + +- [ ] I have read the [CONTRIBUTING](../master/CONTRIBUTING.rst) doc +- [ ] I am making a pull request against the `master` branch (left side), from `develop` +- [ ] Lint and unit tests pass locally +- [ ] I built the documentation and updated it with the latest changes +- [ ] I've added an item in `HISTORY.rst` for this release +- [ ] I bumped the version number in the `tac/__version__.py` file. +- [ ] I bumped the version number in every Docker image of the repo and published it. Also, I built and published them with tag `latest` + +## Further comments + +Write here any other comment about the release, if any. diff --git a/.gitignore b/.gitignore index c2f3efb6..2395e550 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,11 @@ data/* !data/oef-logs data/oef-logs/* !data/.gitkeep +!data/shared +data/shared/* +!data/shared/.gitkeep +scripts/data/* + notebooks/.ipynb_checkpoints diff --git a/HISTORY.rst b/HISTORY.rst index ce487b06..790d4c61 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -46,3 +46,9 @@ Release History - Adds versioning to TAC via `version_id` - Ports `tac` protocol from aea repo - Multiple small fixes + +0.1.7 (2019-10-02) +------------------- + +- Improves launcher gui +- Multiple small fixes diff --git a/README.md b/README.md index cbee3a6a..45b09243 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,23 @@ This repository contains submodules. Clone with recursive strategy: The controller GUI at http://localhost:8097 provides real time insights. -## Option 2: Step by step: +## Option 2: Launcher GUI: -- [x] You have followed the steps under 'Dependencies' and 'Preliminaries' below +- [x] Follow the steps under 'Dependencies' and 'Preliminaries' below +- [x] Build the sandbox: + + cd sandbox && docker-compose build && cd .. + +- [x] Enter the virtual environment and start the launcher GUI. Then launch the sandbox with your prefered configs: + + pipenv shell + python tac/gui/launcher/app.py + +The controller GUI at http://localhost:8097 provides real time insights. + +## Option 3: Step by step: + +- [x] Follow the steps under 'Dependencies' and 'Preliminaries' below - [x] In one terminal, build the sandbox and then launch it: cd sandbox && docker-compose build @@ -29,7 +43,7 @@ The controller GUI at http://localhost:8097 provides real time insights. - [x] Optionally, in another terminal, enter the virtual environment and connect a template agent to the sandbox: pipenv shell - python templates/v1/basic.py --name my_agent --dashboard + python templates/v1/basic.py --name my_agent --dashboard --expected-version-id tac_v1 The sandbox is starting up:
diff --git a/data/shared/.gitkeep b/data/shared/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/sandbox/.env b/sandbox/.env
index 98d3cb13..c9ef2e3b 100644
--- a/sandbox/.env
+++ b/sandbox/.env
@@ -5,7 +5,7 @@ SERVICES_INTERVAL=5
OEF_ADDR=172.28.1.1
OEF_PORT=10000
DATA_OUTPUT_DIR=data
-VERSION_ID=1
+VERSION_ID=tac_v1
LOWER_BOUND_FACTOR=0
UPPER_BOUND_FACTOR=0
TX_FEE=0.1
@@ -16,4 +16,5 @@ SEED=42
WHITELIST=
REGISTER_AS=both
SEARCH_FOR=both
-PENDING_TRANSACTION_TIMEOUT=120
\ No newline at end of file
+PENDING_TRANSACTION_TIMEOUT=120
+SHARED_DIR="./../data/shared"
\ No newline at end of file
diff --git a/sandbox/docker-compose.yml b/sandbox/docker-compose.yml
index 848a624d..ba43d907 100644
--- a/sandbox/docker-compose.yml
+++ b/sandbox/docker-compose.yml
@@ -106,6 +106,12 @@ services:
- "${SEED}"
- "--whitelist-file"
- "${WHITELIST}"
+ - "--version-id"
+ - "${VERSION_ID}"
+ volumes:
+ - type: bind
+ source: ${SHARED_DIR}
+ target: /build/data/shared
networks:
main_net:
ipam:
diff --git a/sandbox/playground.py b/sandbox/playground.py
index 355763c2..1328bfcd 100644
--- a/sandbox/playground.py
+++ b/sandbox/playground.py
@@ -40,7 +40,7 @@
from tac.agents.participant.v1.examples.strategy import BaselineStrategy
from tac.platform.game.base import GameData
-CUR_PATH = inspect.getfile(inspect.currentframe())
+CUR_PATH = inspect.getfile(inspect.currentframe()) # type: ignore
ROOT_DIR = os.path.join(os.path.dirname(CUR_PATH), "..")
diff --git a/sandbox/run_iterated_games.py b/sandbox/run_iterated_games.py
index ef2eb865..60120114 100644
--- a/sandbox/run_iterated_games.py
+++ b/sandbox/run_iterated_games.py
@@ -37,7 +37,7 @@
from tac.platform.game.stats import GameStats
-OUR_DIRECTORY = os.path.dirname(inspect.getfile(inspect.currentframe()))
+OUR_DIRECTORY = os.path.dirname(inspect.getfile(inspect.currentframe())) # type: ignore
ROOT_DIR = os.path.join(OUR_DIRECTORY, "..")
logging.basicConfig(level=logging.INFO)
diff --git a/scripts/launch.py b/scripts/launch.py
index eadd70ae..d6573a30 100644
--- a/scripts/launch.py
+++ b/scripts/launch.py
@@ -30,8 +30,9 @@
import docker
from tac.agents.participant.v1.examples.baseline import main as participant_agent_main
+from tac.platform.shared_sim_status import register_shared_dir, get_shared_dir
-CUR_PATH = inspect.getfile(inspect.currentframe())
+CUR_PATH = inspect.getfile(inspect.currentframe()) # type: ignore
ROOT_DIR = os.path.join(os.path.dirname(CUR_PATH), "..")
@@ -59,6 +60,9 @@ def __enter__(self):
self._stop_oef_search_images()
self._build_sandbox()
+ register_shared_dir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../data/shared'))
+ os.environ['SHARED_DIR'] = get_shared_dir()
+
print("Launching sandbox...")
self.sandbox_process = subprocess.Popen(["docker-compose", "up", "--abort-on-container-exit"],
env=os.environ,
@@ -80,11 +84,11 @@ def wait_for_oef():
":"
], env=os.environ, cwd=ROOT_DIR)
- wait_for_oef.wait(30)
+ wait_for_oef.wait(60)
if __name__ == '__main__':
with Sandbox():
wait_for_oef()
- participant_agent_main(name="my_agent", dashboard=True)
+ participant_agent_main(name="my_agent", dashboard=True, expected_version_id='tac_v1')
diff --git a/scripts/launch_alt.py b/scripts/launch_alt.py
index 2616802c..20bbd9f1 100644
--- a/scripts/launch_alt.py
+++ b/scripts/launch_alt.py
@@ -33,9 +33,10 @@
import tac
from tac.platform.oef_health_check import OEFHealthCheck
+from tac.platform.shared_sim_status import register_shared_dir, get_shared_dir
from tac.platform.simulation import parse_arguments, build_simulation_parameters
-CUR_PATH = inspect.getfile(inspect.currentframe())
+CUR_PATH = inspect.getfile(inspect.currentframe()) # type: ignore
ROOT_DIR = os.path.join(os.path.dirname(CUR_PATH), "..")
stack_tracer = importlib.import_module("stack_tracer", package=CUR_PATH)
@@ -83,6 +84,10 @@ def __enter__(self):
self._stop_oef_search_images()
script_path = os.path.join("scripts", "oef", "launch.py")
configuration_file_path = os.path.join("scripts", "oef", "launch_config.json")
+
+ register_shared_dir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../data/shared'))
+ os.environ['SHARED_DIR'] = get_shared_dir()
+
print("Launching new OEF Node...")
self.oef_process = subprocess.Popen(["python3", script_path, "-c", configuration_file_path, "--background"],
stdout=subprocess.PIPE, env=os.environ, cwd=ROOT_DIR)
@@ -103,7 +108,7 @@ def _get_image_id(self):
if __name__ == '__main__':
- sys.argv += ['--dashboard']
+ sys.argv += ['--dashboard', '--version-id', 'tac_v1']
args = parse_arguments()
simulation_params = build_simulation_parameters(args)
diff --git a/setup.py b/setup.py
index e0d7263e..710d19fa 100644
--- a/setup.py
+++ b/setup.py
@@ -80,9 +80,11 @@
+ glob.glob("sandbox/*.py")
+ glob.glob("sandbox/*.sh")),
("templates/v1", glob.glob("templates/v1/*.py")),
+ ("scripts/oef", glob.glob("scripts/oef/*.json")),
("simulation/v1", glob.glob("simulation/v1/*")),
("oef_search_pluto_scripts", glob.glob("oef_search_pluto_scripts/*.py") + glob.glob("oef_search_pluto_scripts/*.json"))
],
license=about['__license__'],
)
+
diff --git a/simulation/v1/tac_agent_spawner.py b/simulation/v1/tac_agent_spawner.py
index 0d6a6966..109d695c 100644
--- a/simulation/v1/tac_agent_spawner.py
+++ b/simulation/v1/tac_agent_spawner.py
@@ -19,10 +19,14 @@
# ------------------------------------------------------------------------------
"""Spawn several TAC agents."""
+import os
+from tac.platform.shared_sim_status import register_shared_dir
from tac.platform.simulation import parse_arguments, build_simulation_parameters, run
if __name__ == '__main__':
+ register_shared_dir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../data/shared'))
+
arguments = parse_arguments()
simulation_parameters = build_simulation_parameters(arguments)
run(simulation_parameters)
diff --git a/tac/__init__.py b/tac/__init__.py
index f6c941d0..42cfd044 100644
--- a/tac/__init__.py
+++ b/tac/__init__.py
@@ -36,5 +36,5 @@
logger.addHandler(handler)
logger.propagate = False
-ROOT_DIR = os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), "..")
+ROOT_DIR = os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), "..") # type: ignore
diff --git a/tac/__version__.py b/tac/__version__.py
index 75006734..78337f09 100644
--- a/tac/__version__.py
+++ b/tac/__version__.py
@@ -23,7 +23,7 @@
__title__ = 'tac'
__description__ = 'Trading Agent Competition agents'
__url__ = 'https://github.com/fetchai/agents-tac.git'
-__version__ = '0.1.6'
+__version__ = '0.1.7'
__author__ = 'Fetch.AI Limited'
__license__ = 'Apache 2.0'
__copyright__ = '2019 Fetch.AI Limited'
diff --git a/tac/agents/controller/agent.py b/tac/agents/controller/agent.py
index cdce820a..794db6b1 100644
--- a/tac/agents/controller/agent.py
+++ b/tac/agents/controller/agent.py
@@ -20,16 +20,16 @@
# ------------------------------------------------------------------------------
"""This module contains the ControllerAgent."""
-
import argparse
import datetime
+import dateutil.parser
import logging
import pprint
import random
import time
from typing import Optional
-import dateutil.parser
+
from aea.agent import Agent
from aea.channels.oef.connection import OEFMailBox
from aea.mail.base import Envelope
@@ -37,6 +37,7 @@
from tac.agents.controller.base.handlers import OEFHandler, GameHandler, AgentMessageDispatcher
from tac.agents.controller.base.tac_parameters import TACParameters
from tac.platform.game.base import GamePhase
+from tac.platform.shared_sim_status import set_controller_state, ControllerAgentState
from tac.gui.monitor import Monitor, NullMonitor, VisdomMonitor
if __name__ != "__main__":
@@ -82,6 +83,7 @@ def __init__(self, name: str,
self.last_activity = datetime.datetime.now()
logger.debug("[{}]: Initialized myself as Controller Agent :\n{}".format(self.name, pprint.pformat(vars())))
+ set_controller_state(self.game_handler.tac_parameters.version_id, ControllerAgentState.STARTING)
def act(self) -> None:
"""
@@ -96,10 +98,14 @@ def act(self) -> None:
logger.debug("[{}]: waiting for starting the competition: start_time={}, current_time={}, timedelta ={}s"
.format(self.name, str(self.game_handler.tac_parameters.start_time), str(now), seconds_to_wait))
self.game_handler.competition_start = now + datetime.timedelta(seconds=seconds_to_wait + self.game_handler.tac_parameters.registration_timedelta.seconds)
+
time.sleep(seconds_to_wait)
logger.debug("[{}]: Register competition with parameters: {}"
.format(self.name, pprint.pformat(self.game_handler.tac_parameters.__dict__)))
self.oef_handler.register_tac()
+
+ set_controller_state(self.game_handler.tac_parameters.version_id, ControllerAgentState.REGISTRATION_OPEN)
+
self.game_handler._game_phase = GamePhase.GAME_SETUP
elif self.game_handler.game_phase == GamePhase.GAME_SETUP:
assert self.game_handler.competition_start is not None, "No competition start time set!"
@@ -108,6 +114,9 @@ def act(self) -> None:
logger.debug("[{}]: Checking if we can start the competition.".format(self.name))
min_nb_agents = self.game_handler.tac_parameters.min_nb_agents
nb_reg_agents = len(self.game_handler.registered_agents)
+
+ set_controller_state(self.game_handler.tac_parameters.version_id, ControllerAgentState.RUNNING)
+
if nb_reg_agents >= min_nb_agents:
logger.debug("[{}]: Start competition. Registered agents: {}, minimum number of agents: {}."
.format(self.name, nb_reg_agents, min_nb_agents))
@@ -115,6 +124,7 @@ def act(self) -> None:
else:
logger.debug("[{}]: Not enough agents to start TAC. Registered agents: {}, minimum number of agents: {}."
.format(self.name, nb_reg_agents, min_nb_agents))
+ set_controller_state(self.game_handler.tac_parameters.version_id, ControllerAgentState.STOPPING_UNSUFFICIENT_AGENTS)
self.stop()
return
elif self.game_handler.game_phase == GamePhase.GAME:
@@ -122,10 +132,12 @@ def act(self) -> None:
inactivity_duration = current_time - self.last_activity
if inactivity_duration > self.game_handler.tac_parameters.inactivity_timedelta:
logger.debug("[{}]: Inactivity timeout expired. Terminating...".format(self.name))
+ set_controller_state(self.game_handler.tac_parameters.version_id, ControllerAgentState.FINISHED_INACTIVITY)
self.stop()
return
elif current_time > self.game_handler.tac_parameters.end_time:
logger.debug("[{}]: Competition timeout expired. Terminating...".format(self.name))
+ set_controller_state(self.game_handler.tac_parameters.version_id, ControllerAgentState.FINISHED_GAME_TIMEOUT)
self.stop()
return
diff --git a/tac/gui/dashboards/agent.py b/tac/gui/dashboards/agent.py
index ef141d84..777ac525 100644
--- a/tac/gui/dashboards/agent.py
+++ b/tac/gui/dashboards/agent.py
@@ -32,7 +32,7 @@
from tac.gui.dashboards.helpers import generate_html_table_from_dict, escape_html
from tac.platform.game.base import Transaction
-CUR_PATH = inspect.getfile(inspect.currentframe())
+CUR_PATH = inspect.getfile(inspect.currentframe()) # type: ignore
CUR_DIR = os.path.dirname(CUR_PATH)
ROOT_PATH = os.path.join(CUR_DIR, "..", "..")
diff --git a/tac/gui/dashboards/base.py b/tac/gui/dashboards/base.py
index b324c342..4336aa81 100644
--- a/tac/gui/dashboards/base.py
+++ b/tac/gui/dashboards/base.py
@@ -28,7 +28,7 @@
from visdom import Visdom
-CUR_PATH = inspect.getfile(inspect.currentframe())
+CUR_PATH = inspect.getfile(inspect.currentframe()) # type: ignore
CUR_DIR = os.path.dirname(CUR_PATH)
diff --git a/tac/gui/launcher/api/__init__.py b/tac/gui/launcher/api/__init__.py
index 37850ab3..240b772a 100644
--- a/tac/gui/launcher/api/__init__.py
+++ b/tac/gui/launcher/api/__init__.py
@@ -17,12 +17,13 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+"""Register the resources with flask and set up the shared status file."""
-"""Define the REST APIs for the launcher app."""
from flask_restful import Api
from .resources.sandboxes import SandboxList, Sandbox
from .resources.agents import Agent
+from tac.platform.shared_sim_status import clear_temp_dir
def create_api(app):
@@ -32,3 +33,5 @@ def create_api(app):
api.add_resource(SandboxList, "/sandboxes")
api.add_resource(Sandbox, "/sandboxes/
{% endfor %}
+
+
+ The controller GUI: http://localhost:8097
diff --git a/tac/gui/launcher/templates/launcher.html b/tac/gui/launcher/templates/launcher.html
index c82a67bc..479284fe 100644
--- a/tac/gui/launcher/templates/launcher.html
+++ b/tac/gui/launcher/templates/launcher.html
@@ -16,11 +16,16 @@ Sandbox Configurations
onclick='this.form.target="btn-start-sandbox";'>
-
+
+ Agent Configurations
@@ -35,15 +40,21 @@ Agent Configurations
onclick='this.form.target="btn-start-agent";'>
-
-
-
+
+
+The controller GUI: http://localhost:8097{% endblock %}
{% block scripts %}
{% endblock %}
diff --git a/tac/platform/shared_sim_status.py b/tac/platform/shared_sim_status.py
new file mode 100644
index 00000000..a7a10d04
--- /dev/null
+++ b/tac/platform/shared_sim_status.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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.
+#
+# ------------------------------------------------------------------------------
+
+"""Pass status of systems between docker images and processes using the file system and a bind mount in docker."""
+
+import glob
+import os
+
+from enum import Enum
+
+from aea.agent import AgentState
+
+
+class ControllerAgentState(Enum):
+ """The state of execution of the TAC cotnroller agent."""
+
+ NONE = "State not set"
+ STARTING_DOCKER = "Starting docker image"
+ STARTING = "Starting controller agent"
+ REGISTRATION_OPEN = "Registration is open for agents to connect"
+ RUNNING = "Running simulation"
+ STOPPING_UNSUFFICIENT_AGENTS = "Stopping due to insufficient agente registered"
+ FINISHED_INACTIVITY = "Finished due to inactivity timeout"
+ FINISHED_GAME_TIMEOUT = "Finished due to game timeout"
+
+
+def register_shared_dir(temp_dir) -> None:
+ """Call this from somewhere near the entry point of the program to set he location of the temp directory."""
+ # print("register_shared_dir: " + temp_dir)
+ # logging.error("register_shared_dir: " + temp_dir)
+
+ os.environ['TAC_SHARED_DIR'] = temp_dir
+
+
+def get_shared_dir() -> str:
+ """Call this to return the bases shared folder location."""
+ return os.environ['TAC_SHARED_DIR']
+
+
+def clear_temp_dir() -> None:
+ """Call this once at the beginning (after registering the temp director) - cleans out dir of old status files."""
+ shared_dir = str(os.getenv('TAC_SHARED_DIR'))
+ # Get a list of all the file paths that ends with .txt from in specified directory
+ file_list = glob.glob(os.path.join(shared_dir, '*.txt'))
+
+ # Iterate over the list of filepaths & remove each file.
+ for filePath in file_list:
+ os.remove(filePath)
+
+
+def set_controller_state(game_id: str, state: ControllerAgentState) -> None:
+ """Set controller state."""
+ _set_str_status("controller_" + game_id, str(state.name))
+
+
+def get_controller_state(game_id: str) -> ControllerAgentState:
+ """Get controller state."""
+ key = _get_str_status("controller_" + game_id)
+ if key != "":
+ return ControllerAgentState[key]
+ else:
+ return ControllerAgentState.NONE
+
+
+def get_controller_last_time(game_id: str, ) -> float:
+ """Return the last time the controller state was changed as UTC time."""
+ return _get_last_status_time("controller_" + game_id)
+
+
+def remove_controller_state(game_id: str) -> None:
+ """Remove the status file from the temp folder."""
+ temp_file_path = _construct_temp_filename("controller_" + game_id)
+ if temp_file_path is not None:
+ os.remove(temp_file_path)
+
+
+def set_agent_state(game_id: str, state: AgentState) -> None:
+ """Set agent state."""
+ if state is not None:
+ _set_str_status("agent_" + game_id, str(state.name))
+ else:
+ _set_str_status("agent_" + game_id, "")
+
+
+def get_agent_state(game_id: str) -> AgentState:
+ """Get agent state."""
+ key = _get_str_status("agent_" + game_id)
+ if key != "":
+ return AgentState[key]
+ else:
+ # This is well dodgy, but I don't have a good thing to return in this case
+ return AgentState.INITIATED
+
+
+def remove_agent_state(game_id: str) -> None:
+ """Remove the status file from the temp folder."""
+ temp_file_path = _construct_temp_filename("agent_" + game_id)
+ if temp_file_path is not None:
+ os.remove(temp_file_path)
+
+
+def _get_last_status_time(id_name) -> float:
+ """Return the last time the agent state was changed as UTC time."""
+ return os.path.getmtime(_construct_temp_filename(id_name))
+
+
+def _construct_temp_filename(id_name) -> str:
+ shared_dir = os.getenv('TAC_SHARED_DIR')
+
+ # Actually it is fine not to set this up - should just fail gracefully as
+ # this is only needed when using the GUI launcher
+ # assert shared_dir is not None, "must call register_shared_dir() from entry point of program"
+
+ if shared_dir is not None and os.path.isdir(shared_dir):
+ return os.path.join(shared_dir, "tempfile_" + id_name + "_status.txt")
+ return ""
+
+
+def _set_str_status(id_name, status) -> None:
+ temp_file_path = _construct_temp_filename(id_name)
+ if temp_file_path != "":
+ f = open(temp_file_path, "w+")
+ f.write(status)
+ f.close()
+
+
+def _get_str_status(id_name):
+ temp_file_path = _construct_temp_filename(id_name)
+ if temp_file_path != "":
+ if (os.path.isfile(temp_file_path)):
+ f = open(temp_file_path, "r")
+ status = f.read()
+ f.close()
+ return status
+
+ return ""
diff --git a/templates/v1/advanced.py b/templates/v1/advanced.py
index 1ac8b195..6f95cd18 100644
--- a/templates/v1/advanced.py
+++ b/templates/v1/advanced.py
@@ -48,6 +48,7 @@ def parse_arguments():
parser.add_argument("--services-interval", type=int, default=10, help="The number of seconds to wait before doing another search.")
parser.add_argument("--pending-transaction-timeout", type=int, default=30, help="The timeout in seconds to wait for pending transaction/negotiations.")
parser.add_argument("--private-key-pem", default=None, help="Path to a file containing a private key in PEM format.")
+ parser.add_argument("--expected-version-id", type=str, help="The epected version id of the TAC.")
parser.add_argument("--rejoin", action="store_true", default=False, help="Whether the agent is joining a running TAC.")
parser.add_argument("--dashboard", action="store_true", help="Show the agent dashboard.")
parser.add_argument("--visdom-addr", type=str, default="localhost", help="IP address to the Visdom server")
@@ -128,7 +129,7 @@ def main():
strategy = MyStrategy(register_as=RegisterAs(args.register_as), search_for=SearchFor(args.search_for), is_world_modeling=args.is_world_modeling)
agent = BaselineAgent(name=args.name, oef_addr=args.oef_addr, oef_port=args.oef_port, agent_timeout=args.agent_timeout, strategy=strategy,
max_reactions=args.max_reactions, services_interval=args.services_interval, pending_transaction_timeout=args.pending_transaction_timeout,
- dashboard=agent_dashboard, private_key_pem=args.private_key_pem)
+ dashboard=agent_dashboard, private_key_pem=args.private_key_pem, expected_version_id=args.expected_version_id)
try:
agent.start(rejoin=args.rejoin)
diff --git a/templates/v1/basic.py b/templates/v1/basic.py
index d881c2d7..1b32ac91 100644
--- a/templates/v1/basic.py
+++ b/templates/v1/basic.py
@@ -29,6 +29,7 @@
from tac.agents.participant.v1.examples.strategy import BaselineStrategy
from tac.gui.dashboards.agent import AgentDashboard
+
logger = logging.getLogger(__name__)
@@ -46,6 +47,7 @@ def parse_arguments():
parser.add_argument("--services-interval", type=int, default=5, help="The number of seconds to wait before doing another search.")
parser.add_argument("--pending-transaction-timeout", type=int, default=30, help="The timeout in seconds to wait for pending transaction/negotiations.")
parser.add_argument("--private-key-pem", default=None, help="Path to a file containing a private key in PEM format.")
+ parser.add_argument("--expected-version-id", type=str, help="The expected version id of the TAC.")
parser.add_argument("--rejoin", action="store_true", default=False, help="Whether the agent is joining a running TAC.")
parser.add_argument("--dashboard", action="store_true", help="Show the agent dashboard.")
parser.add_argument("--visdom-addr", type=str, default="localhost", help="IP address to the Visdom server")
@@ -66,7 +68,7 @@ def main():
strategy = BaselineStrategy(register_as=RegisterAs(args.register_as), search_for=SearchFor(args.search_for), is_world_modeling=args.is_world_modeling)
agent = BaselineAgent(name=args.name, oef_addr=args.oef_addr, oef_port=args.oef_port, agent_timeout=args.agent_timeout, strategy=strategy,
max_reactions=args.max_reactions, services_interval=args.services_interval, pending_transaction_timeout=args.pending_transaction_timeout,
- dashboard=agent_dashboard, private_key_pem=args.private_key_pem)
+ dashboard=agent_dashboard, private_key_pem=args.private_key_pem, expected_version_id=args.expected_version_id)
try:
agent.start(rejoin=args.rejoin)
diff --git a/templates/v1/expert.py b/templates/v1/expert.py
index 1b2b1501..a73dcf3a 100644
--- a/templates/v1/expert.py
+++ b/templates/v1/expert.py
@@ -23,6 +23,7 @@
import argparse
import logging
+import random
from typing import Optional
from aea.agent import Agent
@@ -39,6 +40,7 @@ def parse_arguments():
parser.add_argument("--oef-port", default=10000, help="TCP/IP port of the OEF Agent")
parser.add_argument("--agent-timeout", type=float, default=1.0, help="The time in (fractions of) seconds to time out an agent between act and react.")
parser.add_argument("--private-key-pem", default=None, help="Path to a file containing a private key in PEM format.")
+ parser.add_argument("--expected-version-id", type=str, help="The epected version id of the TAC.")
return parser.parse_args()
@@ -46,10 +48,11 @@ def parse_arguments():
class MyAgent(Agent):
"""My agent implementation."""
- def __init__(self, name: str, oef_addr: str, oef_port: int, agent_timeout: float = 1.0, private_key_pem_path: Optional[str] = None):
+ def __init__(self, name: str, oef_addr: str, oef_port: int, agent_timeout: float = 1.0, private_key_pem_path: Optional[str] = None, expected_version_id: str = str(random.randint(0, 10000))):
"""Agent initialization."""
super().__init__(name, private_key_pem_path, agent_timeout)
self.mailbox = OEFMailBox(self.crypto.public_key, oef_addr, oef_port)
+ self.expected_version_id = expected_version_id
raise NotImplementedError("Your agent must implement the interface defined in Agent.")
@@ -58,7 +61,7 @@ def main():
"""Run the script."""
args = parse_arguments()
- agent = MyAgent(name=args.name, oef_addr=args.oef_addr, oef_port=args.oef_port, agent_timeout=args.agent_timeout, private_key_pem_path=args.private_key_pem)
+ agent = MyAgent(name=args.name, oef_addr=args.oef_addr, oef_port=args.oef_port, agent_timeout=args.agent_timeout, private_key_pem_path=args.private_key_pem, expected_version_id=args.expected_version_id)
try:
agent.start()
diff --git a/tests/conftest.py b/tests/conftest.py
index a8c092a2..f23b1800 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -33,7 +33,7 @@
logger = logging.getLogger(__name__)
-CUR_PATH = inspect.getfile(inspect.currentframe())
+CUR_PATH = inspect.getfile(inspect.currentframe()) # type: ignore
ROOT_DIR = os.path.join(os.path.dirname(CUR_PATH), "..")