dojozero 0.2.0__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.0 → dojozero-0.2.2}/.gitignore +9 -2
- {dojozero-0.2.0 → dojozero-0.2.2}/PKG-INFO +5 -71
- dojozero-0.2.2/README.md +25 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/pyproject.toml +1 -1
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/agents/_config.py +30 -5
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/_cache.py +6 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/_constants.py +32 -5
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/_endpoints.py +7 -6
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/_server.py +23 -8
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/_utils.py +49 -13
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/betting/_agent.py +1 -6
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/betting/_broker.py +5 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/betting/_metadata.py +4 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/betting/_models.py +4 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/cli.py +125 -7
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_filesystem_orchestrator_store.py +12 -2
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_models.py +2 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_tracing.py +51 -23
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_trial_orchestrator.py +13 -3
- {dojozero-0.2.0 → 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.0 → dojozero-0.2.2}/src/dojozero/dashboard_server/_gateway_routing.py +108 -1
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/dashboard_server/_scheduler.py +418 -35
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/dashboard_server/_server.py +515 -87
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/dashboard_server/_trial_manager.py +185 -6
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/__init__.py +6 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_hub.py +26 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/polymarket/_store.py +1 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/gateway/_adapter.py +48 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nba/_trial.py +2 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/ncaa/_trial.py +2 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nfl/_trial.py +2 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/sync_service/_sync.py +27 -7
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_agent_configs.py +105 -0
- dojozero-0.2.2/tests/test_arena_replay_seek.py +60 -0
- dojozero-0.2.2/tests/test_cluster.py +465 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_scheduler.py +420 -98
- dojozero-0.2.0/README.md +0 -91
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/_optional_alicloud.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/agents/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/agents/_social_board.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/agents/_toolkit.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/agents/_trial_utils.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/_config.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/_models.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/_redis_reader.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/arena_server/get_snapshot.sh +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/betting/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/betting/_config.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/betting/_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_actors.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_base.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_credentials.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_metadata.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_registry.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_runtime.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/core/_types.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/dashboard_server/_game_discovery.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/dashboard_server/_jsonl_utils.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/dashboard_server/_types.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_backtest.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_config.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_context.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_factory.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_game_info.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_models.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_processors.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_stores.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_streams.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_subscriptions.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/_utils.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/espn/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/espn/_api.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/espn/_state_tracker.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/espn/_stats_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/espn/_stats_fetcher.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/espn/_utils.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nba/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nba/_api.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nba/_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nba/_factory.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nba/_state_tracker.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nba/_store.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nba/_utils.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/ncaa/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/ncaa/_api.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/ncaa/_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/ncaa/_factory.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/ncaa/_state_tracker.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/ncaa/_store.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/ncaa/_utils.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nfl/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nfl/_api.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nfl/_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nfl/_factory.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nfl/_state_tracker.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nfl/_store.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/nfl/_utils.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/polymarket/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/polymarket/_api.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/polymarket/_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/polymarket/_factory.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/polymarket/_models.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/socialmedia/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_api.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_factory.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_store.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/socialmedia/_watchlist.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/websearch/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/websearch/_api.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/websearch/_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/websearch/_factory.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/websearch/_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/data/websearch/_store.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/gateway/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/gateway/_auth.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/gateway/_models.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/gateway/_rate_limit.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/gateway/_server.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/gateway/_sse.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nba/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nba/_agent.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nba/_datastream.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nba/_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/ncaa/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/ncaa/_agent.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/ncaa/_datastream.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/ncaa/_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nfl/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nfl/_agent.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nfl/_datastream.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/nfl/_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/ray_runtime/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/ray_runtime/_impl.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/sync_service/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/sync_service/_redis_client.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/sync_service/main.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/utils/__init__.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/utils/oss.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/src/dojozero/utils/time.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/conftest.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_agent_event_throttle.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_arena_event_deserialization.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_arena_span_grouping.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_betting_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_broker.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_cli_agents.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_dashboard.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_data_hub.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_data_nba.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_data_nfl.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_data_polymarket.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_game_state_tracker.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_gateway.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_metadata.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_nba_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_nba_moneyline_agent.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_nfl_formatters.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_nfl_moneyline_agent.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_oss.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_registry.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_social_board.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_socialmedia_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_span_models.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_stats_insight_events.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_subscriptions.py +0 -0
- {dojozero-0.2.0 → dojozero-0.2.2}/tests/test_websearch_events.py +0 -0
- {dojozero-0.2.0 → 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/
|
|
@@ -171,5 +172,11 @@ dojozero-store
|
|
|
171
172
|
package-lock.json
|
|
172
173
|
|
|
173
174
|
# logs
|
|
174
|
-
|
|
175
|
+
logs/
|
|
176
|
+
|
|
177
|
+
# node modules
|
|
175
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
|
|
@@ -44,7 +44,7 @@ Description-Content-Type: text/markdown
|
|
|
44
44
|
|
|
45
45
|
# DojoZero
|
|
46
46
|
|
|
47
|
-
A platform for running AI agents on realtime sport data and make predictions
|
|
47
|
+
A platform for running AI agents on realtime sport data to reason about game outcomes and make predictions. DojoZero provides an actor-based runtime with live data streams, agent orchestration, trial management, backtesting, and tracing. Currently supports NBA, NFL, and NCAA.
|
|
48
48
|
|
|
49
49
|
## Installation
|
|
50
50
|
|
|
@@ -52,83 +52,17 @@ A platform for running AI agents on realtime sport data and make predictions abo
|
|
|
52
52
|
pip install dojozero
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
Optional extras:
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
|
-
pip install dojozero[alicloud] # Alibaba Cloud integration (OSS,
|
|
58
|
+
pip install dojozero[alicloud] # Alibaba Cloud integration (OSS, SLS tracing)
|
|
59
59
|
pip install dojozero[redis] # Redis-backed data stores
|
|
60
60
|
pip install dojozero[ray] # Distributed execution via Ray
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
## Environment Setup
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
cp .env.example .env
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Quick Start
|
|
70
|
-
|
|
71
|
-
### Run a single trial locally
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
dojo0 run --params trial_params/nba-moneyline.yaml --trial-id nba-local-001
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Resume an interrupted trial
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
dojo0 run --trial-id nba-local-001 --resume-latest
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Run through dashboard server
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
# Start server with tracing
|
|
87
|
-
dojo0 serve --trace-backend jaeger
|
|
88
|
-
|
|
89
|
-
# Submit a trial from another terminal
|
|
90
|
-
dojo0 run \
|
|
91
|
-
--params trial_params/nba-moneyline.yaml \
|
|
92
|
-
--trial-id nba-server-001 \
|
|
93
|
-
--server http://localhost:8000
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Automatic scheduling with trial sources
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
dojo0 serve --trace-backend jaeger --trial-source "trial_sources/daily/*.yaml"
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Backtest from captured events
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
dojo0 backtest \
|
|
106
|
-
--events outputs/2026-01-12/401772976.jsonl \
|
|
107
|
-
--params outputs/2026-01-12/401772976.yaml \
|
|
108
|
-
--speed 100 --max-sleep 1
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Arena (live visualization)
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
dojo0 arena --trace-backend jaeger
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Command Index
|
|
118
|
-
|
|
119
|
-
| Command | Purpose |
|
|
120
|
-
|---------|---------|
|
|
121
|
-
| `dojo0 run` | Start a local or server-submitted trial |
|
|
122
|
-
| `dojo0 serve` | Dashboard / orchestration server |
|
|
123
|
-
| `dojo0 arena` | Trace-backed Arena visualization server |
|
|
124
|
-
| `dojo0 backtest` | Replay persisted event streams |
|
|
125
|
-
| `dojo0 list-sources` | List trial sources |
|
|
126
|
-
| `dojo0 list-trials` | List scheduled trials |
|
|
127
|
-
| `dojo0 clear-schedules` | Clear scheduled runs |
|
|
128
|
-
|
|
129
63
|
## Documentation
|
|
130
64
|
|
|
131
|
-
|
|
65
|
+
See the [full documentation](https://github.com/agentscope-ai/DojoZero/tree/main/docs) for setup, configuration, and usage guides.
|
|
132
66
|
|
|
133
67
|
## License
|
|
134
68
|
|
dojozero-0.2.2/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# DojoZero
|
|
2
|
+
|
|
3
|
+
A platform for running AI agents on realtime sport data to reason about game outcomes and make predictions. DojoZero provides an actor-based runtime with live data streams, agent orchestration, trial management, backtesting, and tracing. Currently supports NBA, NFL, and NCAA.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install dojozero
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Optional extras:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install dojozero[alicloud] # Alibaba Cloud integration (OSS, SLS tracing)
|
|
15
|
+
pip install dojozero[redis] # Redis-backed data stores
|
|
16
|
+
pip install dojozero[ray] # Distributed execution via Ray
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Documentation
|
|
20
|
+
|
|
21
|
+
See the [full documentation](https://github.com/agentscope-ai/DojoZero/tree/main/docs) for setup, configuration, and usage guides.
|
|
22
|
+
|
|
23
|
+
## License
|
|
24
|
+
|
|
25
|
+
MIT
|
|
@@ -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"
|
|
@@ -278,7 +278,10 @@ def create_model(llm_config: LLMConfig) -> ChatModelBase:
|
|
|
278
278
|
if model_type in "grok":
|
|
279
279
|
grok_client_kwargs: dict[str, Any] = {"base_url": "https://api.x.ai/v1"}
|
|
280
280
|
return OpenAIChatModel(
|
|
281
|
-
model_name=model_name,
|
|
281
|
+
model_name=model_name,
|
|
282
|
+
api_key=api_key,
|
|
283
|
+
stream=False,
|
|
284
|
+
client_kwargs=grok_client_kwargs,
|
|
282
285
|
)
|
|
283
286
|
elif model_type == "openai":
|
|
284
287
|
if base_url:
|
|
@@ -286,14 +289,36 @@ def create_model(llm_config: LLMConfig) -> ChatModelBase:
|
|
|
286
289
|
else:
|
|
287
290
|
client_kwargs = {}
|
|
288
291
|
return OpenAIChatModel(
|
|
289
|
-
model_name=model_name,
|
|
292
|
+
model_name=model_name,
|
|
293
|
+
api_key=api_key,
|
|
294
|
+
stream=False,
|
|
295
|
+
client_kwargs=client_kwargs,
|
|
290
296
|
)
|
|
291
297
|
elif model_type == "dashscope":
|
|
292
|
-
|
|
298
|
+
# qwen3.5-* series requires the MultiModalConversation endpoint even
|
|
299
|
+
# for text-only usage. The upstream agentscope SDK only auto-detects
|
|
300
|
+
# "-vl" / "qvq" suffixes/name patterns, so we explicitly opt-in here.
|
|
301
|
+
multimodality: bool | None = None
|
|
302
|
+
if model_name.startswith("qwen3.5"):
|
|
303
|
+
multimodality = True
|
|
304
|
+
return DashScopeChatModel(
|
|
305
|
+
model_name=model_name,
|
|
306
|
+
api_key=api_key,
|
|
307
|
+
multimodality=multimodality,
|
|
308
|
+
stream=False,
|
|
309
|
+
)
|
|
293
310
|
elif model_type == "anthropic":
|
|
294
|
-
return AnthropicChatModel(
|
|
311
|
+
return AnthropicChatModel(
|
|
312
|
+
model_name=model_name,
|
|
313
|
+
api_key=api_key,
|
|
314
|
+
stream=False,
|
|
315
|
+
)
|
|
295
316
|
elif model_type == "gemini":
|
|
296
|
-
return GeminiChatModel(
|
|
317
|
+
return GeminiChatModel(
|
|
318
|
+
model_name=model_name,
|
|
319
|
+
api_key=api_key,
|
|
320
|
+
stream=False,
|
|
321
|
+
)
|
|
297
322
|
else:
|
|
298
323
|
raise ValueError(f"Unknown model_type: {model_type}")
|
|
299
324
|
|
|
@@ -519,6 +519,12 @@ class ReplayMetaInfo:
|
|
|
519
519
|
odds_update_indices: list[int] = field(
|
|
520
520
|
default_factory=list
|
|
521
521
|
) # Indices of odds_update events
|
|
522
|
+
broker_state_update_indices: list[int] = field(
|
|
523
|
+
default_factory=list
|
|
524
|
+
) # Indices of broker.state_update events
|
|
525
|
+
broker_final_stats_indices: list[int] = field(
|
|
526
|
+
default_factory=list
|
|
527
|
+
) # Indices of broker.final_stats events
|
|
522
528
|
|
|
523
529
|
|
|
524
530
|
@dataclass
|
|
@@ -266,18 +266,45 @@ _NFL_TEAMS: dict[str, TeamIdentity] = {
|
|
|
266
266
|
_DEFAULT_TEAM_COLOR = "#666666"
|
|
267
267
|
|
|
268
268
|
|
|
269
|
-
def _get_team_identity(
|
|
269
|
+
def _get_team_identity(
|
|
270
|
+
tricode: str, league: str = "NBA", *, team_id: str = ""
|
|
271
|
+
) -> TeamIdentity:
|
|
270
272
|
"""Get team identity by tricode.
|
|
271
273
|
|
|
272
274
|
Returns TeamIdentity from static lookup. Falls back to a minimal identity
|
|
273
|
-
with the tricode as the name if not found
|
|
274
|
-
|
|
275
|
+
with the tricode as the name if not found.
|
|
276
|
+
|
|
277
|
+
For NBA/NFL, unknown tricodes use the ESPN CDN pattern
|
|
278
|
+
``/teamlogos/{league}/500/{tricode}.png``.
|
|
279
|
+
|
|
280
|
+
NCAA mens basketball logos on ESPN use **numeric** team IDs in
|
|
281
|
+
``/teamlogos/ncaa/500/{id}.png``; tricode-based URLs usually 404, so pass
|
|
282
|
+
``team_id`` from trial metadata when available, otherwise ``logo_url`` is
|
|
283
|
+
left empty to avoid broken images.
|
|
275
284
|
"""
|
|
276
|
-
|
|
285
|
+
lu = league.upper()
|
|
286
|
+
if lu == "NBA":
|
|
287
|
+
teams = _NBA_TEAMS
|
|
288
|
+
elif lu == "NFL":
|
|
289
|
+
teams = _NFL_TEAMS
|
|
290
|
+
else:
|
|
291
|
+
teams = {}
|
|
277
292
|
if tricode in teams:
|
|
278
293
|
return teams[tricode]
|
|
279
294
|
|
|
280
|
-
|
|
295
|
+
if lu == "NCAA":
|
|
296
|
+
logo_url = ""
|
|
297
|
+
tid = (team_id or "").strip()
|
|
298
|
+
if tid.isdigit():
|
|
299
|
+
logo_url = f"https://a.espncdn.com/i/teamlogos/ncaa/500/{tid}.png"
|
|
300
|
+
return TeamIdentity(
|
|
301
|
+
name=tricode,
|
|
302
|
+
tricode=tricode,
|
|
303
|
+
team_id=tid,
|
|
304
|
+
color=_DEFAULT_TEAM_COLOR,
|
|
305
|
+
logo_url=logo_url,
|
|
306
|
+
)
|
|
307
|
+
|
|
281
308
|
league_lower = league.lower()
|
|
282
309
|
logo_url = (
|
|
283
310
|
f"https://a.espncdn.com/i/teamlogos/{league_lower}/500/{tricode.lower()}.png"
|
|
@@ -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(
|
|
@@ -1473,6 +1473,8 @@ class TrialReplayController:
|
|
|
1473
1473
|
The snapshot includes:
|
|
1474
1474
|
- Meta events: agent_initialize, game_initialize, game_start
|
|
1475
1475
|
- Latest odds_update before the target position
|
|
1476
|
+
- Latest broker snapshot before the target position
|
|
1477
|
+
(prefer final_stats over state_update)
|
|
1476
1478
|
- Recent play items up to and including the target
|
|
1477
1479
|
|
|
1478
1480
|
Args:
|
|
@@ -1497,6 +1499,15 @@ class TrialReplayController:
|
|
|
1497
1499
|
# Collect item indices to include in snapshot (use set to avoid duplicates)
|
|
1498
1500
|
snapshot_indices: set[int] = set()
|
|
1499
1501
|
|
|
1502
|
+
def _latest_index_before(indices: list[int]) -> int | None:
|
|
1503
|
+
latest_idx = None
|
|
1504
|
+
for idx in indices:
|
|
1505
|
+
if idx <= target_item_index:
|
|
1506
|
+
latest_idx = idx
|
|
1507
|
+
else:
|
|
1508
|
+
break
|
|
1509
|
+
return latest_idx
|
|
1510
|
+
|
|
1500
1511
|
# 1. Add meta events (agent_initialize, game_initialize, game_start)
|
|
1501
1512
|
if self.meta.agent_initialize_item_index is not None:
|
|
1502
1513
|
snapshot_indices.add(self.meta.agent_initialize_item_index)
|
|
@@ -1507,17 +1518,21 @@ class TrialReplayController:
|
|
|
1507
1518
|
|
|
1508
1519
|
# 2. Find and add the latest odds_update before target_item_index
|
|
1509
1520
|
if self.meta.odds_update_indices:
|
|
1510
|
-
|
|
1511
|
-
latest_odds_idx = None
|
|
1512
|
-
for idx in self.meta.odds_update_indices:
|
|
1513
|
-
if idx <= target_item_index:
|
|
1514
|
-
latest_odds_idx = idx
|
|
1515
|
-
else:
|
|
1516
|
-
break # odds_update_indices are in chronological order
|
|
1521
|
+
latest_odds_idx = _latest_index_before(self.meta.odds_update_indices)
|
|
1517
1522
|
if latest_odds_idx is not None:
|
|
1518
1523
|
snapshot_indices.add(latest_odds_idx)
|
|
1519
1524
|
|
|
1520
|
-
# 3. Add
|
|
1525
|
+
# 3. Add the latest broker snapshot before target_item_index.
|
|
1526
|
+
# final_stats is preferred because it contains the ranking/statistics payload.
|
|
1527
|
+
latest_broker_idx = _latest_index_before(self.meta.broker_final_stats_indices)
|
|
1528
|
+
if latest_broker_idx is None:
|
|
1529
|
+
latest_broker_idx = _latest_index_before(
|
|
1530
|
+
self.meta.broker_state_update_indices
|
|
1531
|
+
)
|
|
1532
|
+
if latest_broker_idx is not None:
|
|
1533
|
+
snapshot_indices.add(latest_broker_idx)
|
|
1534
|
+
|
|
1535
|
+
# 4. Add recent items up to and including the target
|
|
1521
1536
|
start = max(0, target_item_index + 1 - self.snapshot_size)
|
|
1522
1537
|
for i in range(start, target_item_index + 1):
|
|
1523
1538
|
snapshot_indices.add(i)
|
|
@@ -46,6 +46,7 @@ TRIAL_INFO_OPERATION_NAMES = [
|
|
|
46
46
|
"event.game_result",
|
|
47
47
|
"event.nba_game_update",
|
|
48
48
|
"event.nfl_game_update",
|
|
49
|
+
"event.ncaa_game_update",
|
|
49
50
|
]
|
|
50
51
|
|
|
51
52
|
# Tag used by DojoZero to correlate all spans for a trial (see TrialOrchestrator, create_span_from_event).
|
|
@@ -258,15 +259,25 @@ def _resolve_team_identity(
|
|
|
258
259
|
fallback_tricode: str,
|
|
259
260
|
fallback_name: str,
|
|
260
261
|
league: str,
|
|
262
|
+
*,
|
|
263
|
+
team_id: str = "",
|
|
261
264
|
) -> TeamIdentity:
|
|
262
265
|
"""Resolve a team to a TeamIdentity, applying fallbacks as needed."""
|
|
263
266
|
if isinstance(team, TeamIdentity) and team:
|
|
264
|
-
|
|
267
|
+
resolved = team
|
|
265
268
|
if not team.tricode and fallback_tricode:
|
|
266
|
-
|
|
267
|
-
|
|
269
|
+
resolved = resolved.model_copy(update={"tricode": fallback_tricode})
|
|
270
|
+
if league.upper() == "NCAA" and not resolved.logo_url:
|
|
271
|
+
tid = (resolved.team_id or team_id or "").strip()
|
|
272
|
+
if tid.isdigit():
|
|
273
|
+
resolved = resolved.model_copy(
|
|
274
|
+
update={
|
|
275
|
+
"logo_url": f"https://a.espncdn.com/i/teamlogos/ncaa/500/{tid}.png"
|
|
276
|
+
}
|
|
277
|
+
)
|
|
278
|
+
return resolved
|
|
268
279
|
# Fallback to static lookup, then override name if provided
|
|
269
|
-
identity = _get_team_identity(fallback_tricode, league)
|
|
280
|
+
identity = _get_team_identity(fallback_tricode, league, team_id=team_id)
|
|
270
281
|
if fallback_name and fallback_name != identity.name:
|
|
271
282
|
return identity.model_copy(update={"name": fallback_name})
|
|
272
283
|
return identity
|
|
@@ -433,17 +444,33 @@ async def _extract_games_from_trials(
|
|
|
433
444
|
game_init = trial_info.get("game_init")
|
|
434
445
|
if isinstance(game_init, GameInitializeEvent):
|
|
435
446
|
home_team = _resolve_team_identity(
|
|
436
|
-
game_init.home_team,
|
|
447
|
+
game_init.home_team,
|
|
448
|
+
home_tricode,
|
|
449
|
+
"",
|
|
450
|
+
league,
|
|
451
|
+
team_id=str(metadata.get("home_team_id", "") or ""),
|
|
437
452
|
)
|
|
438
453
|
away_team = _resolve_team_identity(
|
|
439
|
-
game_init.away_team,
|
|
454
|
+
game_init.away_team,
|
|
455
|
+
away_tricode,
|
|
456
|
+
"",
|
|
457
|
+
league,
|
|
458
|
+
team_id=str(metadata.get("away_team_id", "") or ""),
|
|
440
459
|
)
|
|
441
460
|
else:
|
|
442
461
|
home_team = _resolve_team_identity(
|
|
443
|
-
"",
|
|
462
|
+
"",
|
|
463
|
+
home_tricode,
|
|
464
|
+
metadata.get("home_team_name", ""),
|
|
465
|
+
league,
|
|
466
|
+
team_id=str(metadata.get("home_team_id", "") or ""),
|
|
444
467
|
)
|
|
445
468
|
away_team = _resolve_team_identity(
|
|
446
|
-
"",
|
|
469
|
+
"",
|
|
470
|
+
away_tricode,
|
|
471
|
+
metadata.get("away_team_name", ""),
|
|
472
|
+
league,
|
|
473
|
+
team_id=str(metadata.get("away_team_id", "") or ""),
|
|
447
474
|
)
|
|
448
475
|
|
|
449
476
|
# Fetch bets for live games only (performance optimization)
|
|
@@ -804,7 +831,7 @@ def _compute_leaderboard_from_spans(
|
|
|
804
831
|
spans_by_trial: dict[str, list[SpanData]],
|
|
805
832
|
agent_info_cache: dict[str, AgentInfo],
|
|
806
833
|
trial_ids: list[str] | None = None,
|
|
807
|
-
limit: int =
|
|
834
|
+
limit: int | None = None,
|
|
808
835
|
) -> list[LeaderboardEntry]:
|
|
809
836
|
"""Compute agent leaderboard from pre-fetched spans.
|
|
810
837
|
|
|
@@ -815,7 +842,7 @@ def _compute_leaderboard_from_spans(
|
|
|
815
842
|
spans_by_trial: Pre-fetched spans grouped by trial_id
|
|
816
843
|
agent_info_cache: Pre-populated agent info cache (agent_id -> AgentInfo)
|
|
817
844
|
trial_ids: Optional list to filter which trials to process (None = all)
|
|
818
|
-
limit: Maximum entries to return
|
|
845
|
+
limit: Maximum entries to return (None = all)
|
|
819
846
|
|
|
820
847
|
Returns:
|
|
821
848
|
List of agents sorted by winnings (highest first)
|
|
@@ -910,9 +937,9 @@ def _compute_leaderboard_from_spans(
|
|
|
910
937
|
|
|
911
938
|
# Sort by winnings (descending) and add rank
|
|
912
939
|
leaderboard.sort(key=lambda x: x.winnings, reverse=True)
|
|
940
|
+
entries = leaderboard[:limit] if limit is not None else leaderboard
|
|
913
941
|
ranked = [
|
|
914
|
-
entry.model_copy(update={"rank": i + 1})
|
|
915
|
-
for i, entry in enumerate(leaderboard[:limit])
|
|
942
|
+
entry.model_copy(update={"rank": i + 1}) for i, entry in enumerate(entries)
|
|
916
943
|
]
|
|
917
944
|
|
|
918
945
|
return ranked
|
|
@@ -922,7 +949,7 @@ async def _compute_leaderboard(
|
|
|
922
949
|
trace_reader: TraceReader,
|
|
923
950
|
trial_ids: list[str],
|
|
924
951
|
cache: "LandingPageCache | None" = None,
|
|
925
|
-
limit: int =
|
|
952
|
+
limit: int | None = None,
|
|
926
953
|
) -> list[LeaderboardEntry]:
|
|
927
954
|
"""Compute agent leaderboard (on-demand version).
|
|
928
955
|
|
|
@@ -962,6 +989,7 @@ def _compute_replay_meta(
|
|
|
962
989
|
- play_item_indices: mapping from play_index to item_index
|
|
963
990
|
- periods: list of PeriodInfo with play counts per period
|
|
964
991
|
- meta event indices: agent_initialize, game_initialize, game_start, odds_update
|
|
992
|
+
- broker snapshot indices: state_update and final_stats
|
|
965
993
|
|
|
966
994
|
Args:
|
|
967
995
|
items: List of serialized span dicts with "category" and "data" keys
|
|
@@ -979,6 +1007,8 @@ def _compute_replay_meta(
|
|
|
979
1007
|
game_initialize_item_index: int | None = None
|
|
980
1008
|
game_start_item_index: int | None = None
|
|
981
1009
|
odds_update_indices: list[int] = []
|
|
1010
|
+
broker_state_update_indices: list[int] = []
|
|
1011
|
+
broker_final_stats_indices: list[int] = []
|
|
982
1012
|
|
|
983
1013
|
current_period: int = 1 # Default period
|
|
984
1014
|
|
|
@@ -995,6 +1025,10 @@ def _compute_replay_meta(
|
|
|
995
1025
|
game_start_item_index = item_index
|
|
996
1026
|
elif category == "odds_update":
|
|
997
1027
|
odds_update_indices.append(item_index)
|
|
1028
|
+
elif category == "state_update":
|
|
1029
|
+
broker_state_update_indices.append(item_index)
|
|
1030
|
+
elif category == "final_stats":
|
|
1031
|
+
broker_final_stats_indices.append(item_index)
|
|
998
1032
|
|
|
999
1033
|
# Track core category items (plays)
|
|
1000
1034
|
if category in core_categories:
|
|
@@ -1031,6 +1065,8 @@ def _compute_replay_meta(
|
|
|
1031
1065
|
game_initialize_item_index=game_initialize_item_index,
|
|
1032
1066
|
game_start_item_index=game_start_item_index,
|
|
1033
1067
|
odds_update_indices=odds_update_indices,
|
|
1068
|
+
broker_state_update_indices=broker_state_update_indices,
|
|
1069
|
+
broker_final_stats_indices=broker_final_stats_indices,
|
|
1034
1070
|
)
|
|
1035
1071
|
|
|
1036
1072
|
|
|
@@ -516,12 +516,7 @@ class BettingAgent(AgentBase, Agent[BettingAgentConfig]):
|
|
|
516
516
|
summary_request = self._build_summary_request()
|
|
517
517
|
if summary_request:
|
|
518
518
|
model = self._react_agent.model
|
|
519
|
-
|
|
520
|
-
model.stream = False
|
|
521
|
-
try:
|
|
522
|
-
resp = await model(summary_request)
|
|
523
|
-
finally:
|
|
524
|
-
model.stream = original_stream
|
|
519
|
+
resp = await model(summary_request)
|
|
525
520
|
resp_content = getattr(resp, "content", None)
|
|
526
521
|
events_summary, _ = _parse_response_content(resp_content)
|
|
527
522
|
if not events_summary:
|
|
@@ -262,6 +262,11 @@ class BrokerOperator(OperatorBase, Operator[BrokerOperatorConfig]):
|
|
|
262
262
|
len(self._bets),
|
|
263
263
|
)
|
|
264
264
|
|
|
265
|
+
@property
|
|
266
|
+
def has_unsettled_bets(self) -> bool:
|
|
267
|
+
"""Return True if there are active (unsettled) bets."""
|
|
268
|
+
return any(bet.status == BetStatus.ACTIVE for bet in self._bets.values())
|
|
269
|
+
|
|
265
270
|
def ensure_event_initialized(
|
|
266
271
|
self,
|
|
267
272
|
event_id: str,
|
|
@@ -67,6 +67,10 @@ class BettingTrialMetadata(BaseTrialMetadata):
|
|
|
67
67
|
away_team_name: str
|
|
68
68
|
game_date: str
|
|
69
69
|
|
|
70
|
+
# ESPN team IDs (for Arena logos, APIs; optional, default from game lookup)
|
|
71
|
+
home_team_id: str = ""
|
|
72
|
+
away_team_id: str = ""
|
|
73
|
+
|
|
70
74
|
# Polymarket (optional)
|
|
71
75
|
market_url: str | None = None
|
|
72
76
|
|
|
@@ -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
|
)
|