dojozero 0.2.1__tar.gz → 0.2.2__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.
- {dojozero-0.2.1 → dojozero-0.2.2}/.gitignore +7 -2
- {dojozero-0.2.1 → dojozero-0.2.2}/PKG-INFO +1 -1
- {dojozero-0.2.1 → dojozero-0.2.2}/pyproject.toml +1 -1
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/_endpoints.py +7 -6
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/_utils.py +5 -5
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/betting/_models.py +4 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/cli.py +69 -3
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_filesystem_orchestrator_store.py +12 -2
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_trial_orchestrator.py +13 -3
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/dashboard_server/__init__.py +9 -0
- dojozero-0.2.2/src/dojozero/dashboard_server/_cluster.py +433 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/dashboard_server/_gateway_routing.py +108 -1
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/dashboard_server/_scheduler.py +336 -33
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/dashboard_server/_server.py +501 -84
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/dashboard_server/_trial_manager.py +33 -2
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/gateway/_adapter.py +48 -0
- dojozero-0.2.2/tests/test_cluster.py +465 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_scheduler.py +420 -98
- {dojozero-0.2.1 → dojozero-0.2.2}/README.md +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/_optional_alicloud.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/agents/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/agents/_config.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/agents/_social_board.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/agents/_toolkit.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/agents/_trial_utils.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/_cache.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/_config.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/_constants.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/_models.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/_redis_reader.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/_server.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/arena_server/get_snapshot.sh +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/betting/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/betting/_agent.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/betting/_broker.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/betting/_config.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/betting/_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/betting/_metadata.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_actors.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_base.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_credentials.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_metadata.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_models.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_registry.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_runtime.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_tracing.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/core/_types.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/dashboard_server/_game_discovery.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/dashboard_server/_jsonl_utils.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/dashboard_server/_types.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_backtest.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_config.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_context.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_factory.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_game_info.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_hub.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_models.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_processors.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_stores.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_streams.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_subscriptions.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/_utils.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/espn/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/espn/_api.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/espn/_state_tracker.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/espn/_stats_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/espn/_stats_fetcher.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/espn/_utils.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nba/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nba/_api.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nba/_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nba/_factory.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nba/_state_tracker.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nba/_store.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nba/_utils.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/ncaa/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/ncaa/_api.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/ncaa/_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/ncaa/_factory.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/ncaa/_state_tracker.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/ncaa/_store.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/ncaa/_utils.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nfl/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nfl/_api.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nfl/_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nfl/_factory.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nfl/_state_tracker.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nfl/_store.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/nfl/_utils.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/polymarket/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/polymarket/_api.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/polymarket/_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/polymarket/_factory.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/polymarket/_models.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/polymarket/_store.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/socialmedia/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_api.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_factory.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_store.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_watchlist.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/websearch/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/websearch/_api.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/websearch/_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/websearch/_factory.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/websearch/_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/data/websearch/_store.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/gateway/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/gateway/_auth.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/gateway/_models.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/gateway/_rate_limit.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/gateway/_server.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/gateway/_sse.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nba/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nba/_agent.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nba/_datastream.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nba/_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nba/_trial.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/ncaa/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/ncaa/_agent.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/ncaa/_datastream.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/ncaa/_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/ncaa/_trial.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nfl/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nfl/_agent.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nfl/_datastream.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nfl/_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/nfl/_trial.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/ray_runtime/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/ray_runtime/_impl.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/sync_service/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/sync_service/_redis_client.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/sync_service/_sync.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/sync_service/main.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/utils/__init__.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/utils/oss.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/src/dojozero/utils/time.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/conftest.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_agent_configs.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_agent_event_throttle.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_arena_event_deserialization.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_arena_replay_seek.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_arena_span_grouping.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_betting_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_broker.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_cli_agents.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_dashboard.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_data_hub.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_data_nba.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_data_nfl.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_data_polymarket.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_game_state_tracker.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_gateway.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_metadata.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_nba_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_nba_moneyline_agent.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_nfl_formatters.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_nfl_moneyline_agent.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_oss.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_registry.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_social_board.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_socialmedia_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_span_models.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_stats_insight_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_subscriptions.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_websearch_events.py +0 -0
- {dojozero-0.2.1 → dojozero-0.2.2}/tests/test_websearch_formatters.py +0 -0
|
@@ -158,7 +158,8 @@ uv.lock
|
|
|
158
158
|
Thumbs.db
|
|
159
159
|
|
|
160
160
|
# Sample scenario artifacts
|
|
161
|
-
dojozero-store
|
|
161
|
+
dojozero-store/
|
|
162
|
+
store/
|
|
162
163
|
|
|
163
164
|
# Data
|
|
164
165
|
/outputs/
|
|
@@ -174,4 +175,8 @@ package-lock.json
|
|
|
174
175
|
logs/
|
|
175
176
|
|
|
176
177
|
# node modules
|
|
177
|
-
node_modules/
|
|
178
|
+
node_modules/
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
agents/llms/*.yaml
|
|
182
|
+
!agents/llms/default.yaml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dojozero
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A platform for running AI agents on realtime sport data and make predictions about game outcomes.
|
|
5
5
|
Project-URL: Homepage, https://github.com/agentscope-ai/DojoZero
|
|
6
6
|
Project-URL: Repository, https://github.com/agentscope-ai/DojoZero
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dojozero"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "A platform for running AI agents on realtime sport data and make predictions about game outcomes."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -357,11 +357,11 @@ def register_rest_endpoints(app: FastAPI) -> None:
|
|
|
357
357
|
default=None,
|
|
358
358
|
description="Filter by league: 'NBA', 'NFL', etc.",
|
|
359
359
|
),
|
|
360
|
-
limit: int = Query(
|
|
361
|
-
default=
|
|
362
|
-
description="Maximum number of agents to return.",
|
|
360
|
+
limit: int | None = Query(
|
|
361
|
+
default=None,
|
|
362
|
+
description="Maximum number of agents to return. Returns all if not specified.",
|
|
363
363
|
ge=1,
|
|
364
|
-
le=
|
|
364
|
+
le=1000,
|
|
365
365
|
),
|
|
366
366
|
) -> JSONResponse:
|
|
367
367
|
"""Get agent leaderboard ranked by winnings.
|
|
@@ -379,8 +379,9 @@ def register_rest_endpoints(app: FastAPI) -> None:
|
|
|
379
379
|
if leaderboard is None:
|
|
380
380
|
leaderboard = await refresher.refresh_leaderboard_on_demand(league=league)
|
|
381
381
|
|
|
382
|
-
# Apply limit
|
|
383
|
-
|
|
382
|
+
# Apply limit only if specified
|
|
383
|
+
if limit is not None:
|
|
384
|
+
leaderboard = leaderboard[:limit]
|
|
384
385
|
|
|
385
386
|
response = LeaderboardResponse(leaderboard=leaderboard)
|
|
386
387
|
return JSONResponse(
|
|
@@ -831,7 +831,7 @@ def _compute_leaderboard_from_spans(
|
|
|
831
831
|
spans_by_trial: dict[str, list[SpanData]],
|
|
832
832
|
agent_info_cache: dict[str, AgentInfo],
|
|
833
833
|
trial_ids: list[str] | None = None,
|
|
834
|
-
limit: int =
|
|
834
|
+
limit: int | None = None,
|
|
835
835
|
) -> list[LeaderboardEntry]:
|
|
836
836
|
"""Compute agent leaderboard from pre-fetched spans.
|
|
837
837
|
|
|
@@ -842,7 +842,7 @@ def _compute_leaderboard_from_spans(
|
|
|
842
842
|
spans_by_trial: Pre-fetched spans grouped by trial_id
|
|
843
843
|
agent_info_cache: Pre-populated agent info cache (agent_id -> AgentInfo)
|
|
844
844
|
trial_ids: Optional list to filter which trials to process (None = all)
|
|
845
|
-
limit: Maximum entries to return
|
|
845
|
+
limit: Maximum entries to return (None = all)
|
|
846
846
|
|
|
847
847
|
Returns:
|
|
848
848
|
List of agents sorted by winnings (highest first)
|
|
@@ -937,9 +937,9 @@ def _compute_leaderboard_from_spans(
|
|
|
937
937
|
|
|
938
938
|
# Sort by winnings (descending) and add rank
|
|
939
939
|
leaderboard.sort(key=lambda x: x.winnings, reverse=True)
|
|
940
|
+
entries = leaderboard[:limit] if limit is not None else leaderboard
|
|
940
941
|
ranked = [
|
|
941
|
-
entry.model_copy(update={"rank": i + 1})
|
|
942
|
-
for i, entry in enumerate(leaderboard[:limit])
|
|
942
|
+
entry.model_copy(update={"rank": i + 1}) for i, entry in enumerate(entries)
|
|
943
943
|
]
|
|
944
944
|
|
|
945
945
|
return ranked
|
|
@@ -949,7 +949,7 @@ async def _compute_leaderboard(
|
|
|
949
949
|
trace_reader: TraceReader,
|
|
950
950
|
trial_ids: list[str],
|
|
951
951
|
cache: "LandingPageCache | None" = None,
|
|
952
|
-
limit: int =
|
|
952
|
+
limit: int | None = None,
|
|
953
953
|
) -> list[LeaderboardEntry]:
|
|
954
954
|
"""Compute agent leaderboard (on-demand version).
|
|
955
955
|
|
|
@@ -435,6 +435,10 @@ class AgentInfo(BaseModel):
|
|
|
435
435
|
"""Agent registration payload for tracing (agent.agent_initialize span)."""
|
|
436
436
|
|
|
437
437
|
agent_id: str = Field(default="", description="Unique ID for the agent")
|
|
438
|
+
display_name: str = Field(
|
|
439
|
+
default="",
|
|
440
|
+
description="Human-readable display name (e.g., GitHub username or custom name)",
|
|
441
|
+
)
|
|
438
442
|
persona: str = Field(
|
|
439
443
|
default="", description="Agent persona tag (e.g., 'degen', 'whale', 'shark')"
|
|
440
444
|
)
|
|
@@ -34,6 +34,7 @@ from dojozero.data.polymarket import PolymarketAPI
|
|
|
34
34
|
from dojozero.utils import utc_iso_to_local
|
|
35
35
|
from dojozero.core import TrialBuilderNotFoundError as _TrialBuilderNotFoundError
|
|
36
36
|
from dojozero.dashboard_server import InitialTrialSourceDict
|
|
37
|
+
from dojozero.dashboard_server._scheduler import SchedulerStore
|
|
37
38
|
|
|
38
39
|
try: # Optional Ray dependency
|
|
39
40
|
from dojozero.ray_runtime import RayActorRuntimeProvider
|
|
@@ -389,6 +390,26 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
389
390
|
action="store_true",
|
|
390
391
|
help="Disable HTTP gateway for external agents (gateway is enabled by default).",
|
|
391
392
|
)
|
|
393
|
+
# Cluster arguments
|
|
394
|
+
serve_parser.add_argument(
|
|
395
|
+
"--server-id",
|
|
396
|
+
dest="server_id",
|
|
397
|
+
default=None,
|
|
398
|
+
help="Unique server identifier for cluster mode (default: hostname).",
|
|
399
|
+
)
|
|
400
|
+
serve_parser.add_argument(
|
|
401
|
+
"--server-url",
|
|
402
|
+
dest="server_url",
|
|
403
|
+
default=None,
|
|
404
|
+
help="Externally reachable URL for this server (default: http://{host}:{port}).",
|
|
405
|
+
)
|
|
406
|
+
serve_parser.add_argument(
|
|
407
|
+
"--cluster-redis-url",
|
|
408
|
+
dest="cluster_redis_url",
|
|
409
|
+
default=os.environ.get("DOJOZERO_CLUSTER_REDIS_URL"),
|
|
410
|
+
help="Redis URL for cluster leader election and peer discovery (enables redis mode). "
|
|
411
|
+
"Falls back to DOJOZERO_CLUSTER_REDIS_URL env var.",
|
|
412
|
+
)
|
|
392
413
|
|
|
393
414
|
# Arena Server command
|
|
394
415
|
arena_parser = subparsers.add_parser(
|
|
@@ -2020,10 +2041,17 @@ async def _serve_command(args: argparse.Namespace) -> int:
|
|
|
2020
2041
|
args.store_directory if args.store_directory else Path(DEFAULT_STORE_DIRECTORY)
|
|
2021
2042
|
)
|
|
2022
2043
|
|
|
2023
|
-
# Create scheduler store
|
|
2024
|
-
|
|
2044
|
+
# Create scheduler store — Redis in cluster mode, file otherwise
|
|
2045
|
+
cluster_redis_url: str | None = getattr(args, "cluster_redis_url", None)
|
|
2025
2046
|
|
|
2026
|
-
|
|
2047
|
+
if cluster_redis_url:
|
|
2048
|
+
from dojozero.dashboard_server._scheduler import RedisSchedulerStore
|
|
2049
|
+
|
|
2050
|
+
scheduler_store: SchedulerStore = RedisSchedulerStore(cluster_redis_url)
|
|
2051
|
+
else:
|
|
2052
|
+
from dojozero.dashboard_server._scheduler import FileSchedulerStore
|
|
2053
|
+
|
|
2054
|
+
scheduler_store = FileSchedulerStore(store_path)
|
|
2027
2055
|
|
|
2028
2056
|
# Expand glob patterns and load trial source configurations
|
|
2029
2057
|
import glob as glob_module
|
|
@@ -2109,6 +2137,43 @@ async def _serve_command(args: argparse.Namespace) -> int:
|
|
|
2109
2137
|
"enabled" if local_auth else "disabled",
|
|
2110
2138
|
)
|
|
2111
2139
|
|
|
2140
|
+
# Build cluster config if Redis cluster URL is provided
|
|
2141
|
+
cluster_config = None
|
|
2142
|
+
server_id_arg: str | None = getattr(args, "server_id", None)
|
|
2143
|
+
server_url_arg: str | None = getattr(args, "server_url", None)
|
|
2144
|
+
|
|
2145
|
+
if cluster_redis_url:
|
|
2146
|
+
from dojozero.dashboard_server._cluster import ClusterConfig
|
|
2147
|
+
|
|
2148
|
+
if server_url_arg:
|
|
2149
|
+
server_url = server_url_arg
|
|
2150
|
+
elif host in ("0.0.0.0", "::"):
|
|
2151
|
+
# Resolve to a reachable IP so peers can forward trials to us.
|
|
2152
|
+
# In Kubernetes, expose status.podIP as the POD_IP env var via
|
|
2153
|
+
# the Downward API. The socket fallback works on plain VMs but
|
|
2154
|
+
# may return 127.0.0.1 inside containers — warn if that happens.
|
|
2155
|
+
import socket
|
|
2156
|
+
|
|
2157
|
+
pod_ip = os.environ.get("POD_IP", "").strip()
|
|
2158
|
+
if not pod_ip:
|
|
2159
|
+
pod_ip = socket.gethostbyname(socket.gethostname())
|
|
2160
|
+
if pod_ip.startswith("127."):
|
|
2161
|
+
LOGGER.warning(
|
|
2162
|
+
"Resolved server IP is %s which is not routable by "
|
|
2163
|
+
"peers. Set --server-url or the POD_IP env var to "
|
|
2164
|
+
"this server's reachable address.",
|
|
2165
|
+
pod_ip,
|
|
2166
|
+
)
|
|
2167
|
+
server_url = f"http://{pod_ip}:{port}"
|
|
2168
|
+
else:
|
|
2169
|
+
server_url = f"http://{host}:{port}"
|
|
2170
|
+
cluster_config = ClusterConfig(
|
|
2171
|
+
server_id=server_id_arg or "",
|
|
2172
|
+
server_url=server_url,
|
|
2173
|
+
redis_url=cluster_redis_url,
|
|
2174
|
+
)
|
|
2175
|
+
LOGGER.info("Cluster mode enabled (redis_url=%s)", cluster_redis_url)
|
|
2176
|
+
|
|
2112
2177
|
await run_dashboard_server(
|
|
2113
2178
|
orchestrator=orchestrator,
|
|
2114
2179
|
scheduler_store=scheduler_store,
|
|
@@ -2124,6 +2189,7 @@ async def _serve_command(args: argparse.Namespace) -> int:
|
|
|
2124
2189
|
enable_gateway=enable_gateway,
|
|
2125
2190
|
authenticator=authenticator,
|
|
2126
2191
|
no_scheduler=no_scheduler,
|
|
2192
|
+
cluster_config=cluster_config,
|
|
2127
2193
|
)
|
|
2128
2194
|
return 0
|
|
2129
2195
|
|
|
@@ -74,12 +74,22 @@ class FileSystemOrchestratorStore(OrchestratorStore):
|
|
|
74
74
|
spec = self._read_spec(spec_path)
|
|
75
75
|
status_path = trial_dir / self.STATUS_FILE
|
|
76
76
|
status = self._read_status(status_path) if status_path.exists() else None
|
|
77
|
-
|
|
77
|
+
# Read owner_server_id from spec file (stored alongside spec)
|
|
78
|
+
spec_payload = self._read_json(spec_path)
|
|
79
|
+
owner_server_id = spec_payload.get("owner_server_id")
|
|
80
|
+
return TrialRecord(
|
|
81
|
+
spec=spec,
|
|
82
|
+
last_status=status,
|
|
83
|
+
owner_server_id=owner_server_id,
|
|
84
|
+
)
|
|
78
85
|
|
|
79
86
|
def upsert_trial_record(self, record: TrialRecord) -> None:
|
|
80
87
|
trial_dir = self._trial_dir(record.trial_id)
|
|
81
88
|
trial_dir.mkdir(parents=True, exist_ok=True)
|
|
82
|
-
|
|
89
|
+
spec_data = self._serialize_spec(record.spec)
|
|
90
|
+
if record.owner_server_id is not None:
|
|
91
|
+
spec_data["owner_server_id"] = record.owner_server_id
|
|
92
|
+
self._write_json(trial_dir / self.SPEC_FILE, spec_data)
|
|
83
93
|
if record.last_status is not None:
|
|
84
94
|
self._write_json(
|
|
85
95
|
trial_dir / self.STATUS_FILE, self._serialize_status(record.last_status)
|
|
@@ -297,6 +297,7 @@ class TrialRecord:
|
|
|
297
297
|
|
|
298
298
|
spec: TrialSpec
|
|
299
299
|
last_status: TrialStatus | None = None
|
|
300
|
+
owner_server_id: str | None = None
|
|
300
301
|
|
|
301
302
|
@property
|
|
302
303
|
def trial_id(self) -> str:
|
|
@@ -448,15 +449,24 @@ class TrialOrchestrator:
|
|
|
448
449
|
"""Access the underlying OrchestratorStore."""
|
|
449
450
|
return self._store
|
|
450
451
|
|
|
451
|
-
async def launch_trial(
|
|
452
|
-
|
|
452
|
+
async def launch_trial(
|
|
453
|
+
self,
|
|
454
|
+
spec: TrialSpec,
|
|
455
|
+
owner_server_id: str | None = None,
|
|
456
|
+
) -> TrialStatus:
|
|
457
|
+
"""Instantiate and start every actor defined in *spec*.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
spec: Trial specification.
|
|
461
|
+
owner_server_id: Server that owns this trial (cluster mode).
|
|
462
|
+
"""
|
|
453
463
|
|
|
454
464
|
LOGGER.info("launching trial '%s'", spec.trial_id)
|
|
455
465
|
spec = self._apply_resume_from_spec(spec)
|
|
456
466
|
normalized_spec = self._normalize_spec(spec)
|
|
457
467
|
record = self._catalog.get(spec.trial_id)
|
|
458
468
|
if record is None:
|
|
459
|
-
record = TrialRecord(spec=normalized_spec)
|
|
469
|
+
record = TrialRecord(spec=normalized_spec, owner_server_id=owner_server_id)
|
|
460
470
|
elif record.spec != normalized_spec:
|
|
461
471
|
raise OrchestratorError(
|
|
462
472
|
f"trial '{spec.trial_id}' already registered with a different configuration"
|
|
@@ -8,6 +8,10 @@ This package provides the Dashboard Server functionality including:
|
|
|
8
8
|
Moved from core module to keep server-related code separate from core abstractions.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
from ._cluster import (
|
|
12
|
+
ClusterConfig,
|
|
13
|
+
PeerInfo,
|
|
14
|
+
)
|
|
11
15
|
from ._game_discovery import (
|
|
12
16
|
GameInfo,
|
|
13
17
|
NBAGameFetcher,
|
|
@@ -17,6 +21,7 @@ from ._game_discovery import (
|
|
|
17
21
|
)
|
|
18
22
|
from ._scheduler import (
|
|
19
23
|
FileSchedulerStore,
|
|
24
|
+
RedisSchedulerStore,
|
|
20
25
|
ScheduledTrial,
|
|
21
26
|
ScheduledTrialPhase,
|
|
22
27
|
ScheduleManager,
|
|
@@ -60,6 +65,9 @@ from ._types import (
|
|
|
60
65
|
)
|
|
61
66
|
|
|
62
67
|
__all__ = [
|
|
68
|
+
# Cluster
|
|
69
|
+
"ClusterConfig",
|
|
70
|
+
"PeerInfo",
|
|
63
71
|
# Server
|
|
64
72
|
"create_dashboard_app",
|
|
65
73
|
"run_dashboard_server",
|
|
@@ -78,6 +86,7 @@ __all__ = [
|
|
|
78
86
|
"ScheduledTrialPhase",
|
|
79
87
|
"SchedulerStore",
|
|
80
88
|
"FileSchedulerStore",
|
|
89
|
+
"RedisSchedulerStore",
|
|
81
90
|
# Trial Sources
|
|
82
91
|
"TrialSource",
|
|
83
92
|
"TrialSourceConfig",
|