From 17ab95dc9809c1bd1c0bd09bd2da3ff11b51ee60 Mon Sep 17 00:00:00 2001 From: serversdown Date: Wed, 24 Jun 2026 16:21:03 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Decide=20mode=20=E2=80=94=20a=20tie-bre?= =?UTF-8?q?aker=20that=20settles=20choices=20instead=20of=20listing=20opti?= =?UTF-8?q?ons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brian's bottleneck is committing, not generating options, so a pros/cons dump makes it worse. Decide mode's card: get the real decision crisp, weigh it against what HE values + past regrets (pull running_stats/recent_sessions for poker/money calls), MAKE the call with the one or two reasons that tip it, pressure-test it once, and stand behind it — no "it's up to you." Read-only lookups, no live logging. Sixth mode (Talk/Poker/Build/Explore/Study/Decide); added to UI selectors, labels, badge-cycle. Suite 96 green, ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- lyra/modes.py | 24 +++++++++++++++++++++++- lyra/web/static/index.html | 7 +++++-- tests/test_modes.py | 6 +++++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lyra/modes.py b/lyra/modes.py index d640dcb..efec2f7 100644 --- a/lyra/modes.py +++ b/lyra/modes.py @@ -59,6 +59,9 @@ _TALK_TOOLS = _BASE + _LOOKUPS + ("start_session",) # Study = poker review away from the table: read-only lookups + equity, no live logging. _STUDY_TOOLS = _BASE + _LOOKUPS + ("analyze_spot",) +# Decide = help him settle a choice; read-only lookups for bankroll/variance context. +_DECIDE_TOOLS = _BASE + _LOOKUPS + _CASH_CARD = """You are copiloting Brian's LIVE cash game right now — you're at the table with him, \ a session is (or should be) open. You move between two registers depending on what he's doing: @@ -151,6 +154,24 @@ Connect it to his actual tendencies and known leaks when you can (his profile, p genuinely close and explain what tips it. This is the slow, careful counterpart to live Poker mode.""" +_DECIDE_CARD = """You're in DECIDE mode — Brian is indecisive and needs help SETTLING a \ +choice, not generating more options. Be the tie-breaker who knows him. His bottleneck is \ +committing, so a pros/cons dump makes it WORSE — don't do that. + +• GET THE REAL DECISION CRISP. What's actually being chosen, the genuine constraints, the \ +deadline. Cut the noise to the one or two things that actually decide it. +• WEIGH IT AGAINST HIM. Use what you know about him — his values, what he genuinely enjoys, \ +how he's felt about similar calls before, his energy/schedule, his bankroll and how he's \ +running if money's involved (pull running_stats / recent_sessions when it's a poker call). \ +The point is HIS satisfaction and regret, not a generic optimum. +• MAKE THE CALL. Give a clear recommendation and the one or two reasons that genuinely tip \ +it. Commit — don't hedge, don't hand the indecision back with "it's up to you." +• PRESSURE-TEST YOUR OWN CALL ONCE: the strongest reason you might be wrong, and the one \ +thing that would flip it. Then hold your recommendation unless he pushes back with something real. + +Warm but firm — he asked you to help him stop spinning. Decide, and stand behind it.""" + + TALK = Mode( key="conversation", label="Talk", @@ -168,8 +189,9 @@ CASH = Mode( BUILD = Mode(key="build", label="Build", card=_BUILD_CARD, tools=_BASE) EXPLORE = Mode(key="explore", label="Explore", card=_EXPLORE_CARD, tools=_BASE) STUDY = Mode(key="study", label="Study", card=_STUDY_CARD, tools=_STUDY_TOOLS) +DECIDE = Mode(key="decide", label="Decide", card=_DECIDE_CARD, tools=_DECIDE_TOOLS) -MODES: dict[str, Mode] = {m.key: m for m in (TALK, CASH, BUILD, EXPLORE, STUDY)} +MODES: dict[str, Mode] = {m.key: m for m in (TALK, CASH, BUILD, EXPLORE, STUDY, DECIDE)} DEFAULT = TALK.key diff --git a/lyra/web/static/index.html b/lyra/web/static/index.html index e677d12..b1711fb 100644 --- a/lyra/web/static/index.html +++ b/lyra/web/static/index.html @@ -30,6 +30,7 @@ + @@ -73,6 +74,7 @@ +
@@ -613,8 +615,9 @@ // ----- Conversation modes (Talk / Poker / Build / Explore / Study) ----- const MODE_LABELS = { conversation: "💬 Talk", poker_cash: "♠ Poker", - build: "🛠 Build", explore: "🔭 Explore", study: "📐 Study" }; - const MODE_ORDER = ["conversation", "poker_cash", "build", "explore", "study"]; + build: "🛠 Build", explore: "🔭 Explore", study: "📐 Study", + decide: "⚖️ Decide" }; + const MODE_ORDER = ["conversation", "poker_cash", "build", "explore", "study", "decide"]; // Reflect a mode value across the controls + header accent (no network call). function applyMode(value) { diff --git a/tests/test_modes.py b/tests/test_modes.py index 7bfdeb7..8543714 100644 --- a/tests/test_modes.py +++ b/tests/test_modes.py @@ -50,7 +50,11 @@ def test_every_mode_tool_exists(lyra): def test_work_modes_present_and_gated(lyra): _, _, modes, tools = lyra # the full set Brian chose - assert set(modes.MODES) == {"conversation", "poker_cash", "build", "explore", "study"} + assert set(modes.MODES) == {"conversation", "poker_cash", "build", "explore", "study", "decide"} + # Decide = read-only lookups for context, no live logging; has a real card + decide = _names(tools.specs(modes.DECIDE.tools)) + assert {"running_stats", "recent_sessions"} <= decide and "log_hand" not in decide + assert modes.DECIDE.card # Build/Explore are conversational: base agency tools only, no live poker logging for key in ("build", "explore"): names = _names(tools.specs(modes.get(key).tools))