Add dynamic agent registry and options mandate

Introduces a dashboard-managed agent registry (`state/agents.json`) used by nightly research and market-open execution, including support for custom/disabled agents and per-agent time budgets. Expands personas to four agents (adds Maverick), shifts pick targets to include mandatory options, and updates prompts/finalization nudges to enforce option research without hard-failing runs.

Strengthens execution safety by adding option-specific guardrails (conviction floor, premium cap, reserved option slot through trade/day/buying-power caps), validates OCC option symbols in schemas, and normalizes invalid option direction cases. The dashboard was refactored into modular views, adds an Agents admin tab, and improves live portfolio visibility with Alpaca-first data and snapshot fallback.
This commit is contained in:
Aryan Singh committed 2026-07-07 22:00:20 -05:00
1 parent b3821abd69
commit e1ac514f30
36 files changed
+1476 -294

No files matched your search

+14 -6
View File
@@ -21,7 +21,7 @@ from loguru import logger # noqa: E402
from agents.graph import run_agent # noqa: E402
from agents.schemas import RunManifest # noqa: E402
from config.personas import PERSONAS # noqa: E402
from config.agent_registry import load_personas # noqa: E402
from config.settings import get_settings # noqa: E402
from llm import server # noqa: E402
from llm.client import resolve_model_id # noqa: E402
@@ -71,10 +71,12 @@ def main(compressed: bool = False) -> int:
cp.write_manifest(manifest)
hard_stop = local_hard_stop_ts(s.hard_stop, s.local_tz)
per_agent_cap_s = 5 * 60 if compressed else s.per_agent_wallclock_min * 60
step_budget = 12 if compressed else s.per_agent_step_budget
min_steps = 4 if compressed else s.per_agent_min_steps
min_seconds = 60 if compressed else s.per_agent_min_minutes * 60
# dashboard-managed registry: built-ins + overrides + custom agents, disabled excluded
personas = load_personas()
logger.info("agents tonight: {}", ", ".join(p.id for p in personas))
# shared ground truth for all agents tonight (computed, deterministic)
regime = market_regime()
@@ -83,12 +85,18 @@ def main(compressed: bool = False) -> int:
outputs = []
records: dict[str, str] = {}
for i, persona in enumerate(PERSONAS):
for i, persona in enumerate(personas):
# per-agent budgets (dashboard-editable), falling back to the global settings
if compressed:
per_agent_cap_s, min_seconds = 5 * 60, 60
else:
per_agent_cap_s = (persona.time_budget_min or s.per_agent_wallclock_min) * 60
min_seconds = (persona.min_research_min or s.per_agent_min_minutes) * 60
now = time.time()
if now >= hard_stop:
logger.warning("hard stop reached; skipping {} remaining agents", len(PERSONAS) - i)
logger.warning("hard stop reached; skipping {} remaining agents", len(personas) - i)
break
deadline = next_deadline(now, hard_stop, len(PERSONAS) - i, per_agent_cap_s)
deadline = next_deadline(now, hard_stop, len(personas) - i, per_agent_cap_s)
logger.info("--- {} until {} ---", persona.id,
datetime.fromtimestamp(deadline).strftime("%H:%M:%S"))
if not server.server_up(): # recover if a prior agent left oMLX unresponsive