feat: session_state read tool so she can see the HUD

She could write everything the HUD shows but not read most of it back (stack,
live net, alligator state, scar/confidence entries) — so "what's my live net?"
or "what's in my confidence bank?" was a memory guess.

- session_state tool returns the same bundle the HUD renders, as a readable
  summary; added to the Cash toolset.
- Cash card tells her the HUD exists, that she and it share the same data, and to
  answer where-am-I questions from session_state, never memory.
- test_modes.py +1; 42 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-19 23:16:40 +00:00
parent 974ee33f71
commit 35c973df05
3 changed files with 55 additions and 2 deletions
+9 -2
View File
@@ -41,8 +41,8 @@ _BASE = ("journal_write", "note")
# The full live cash-game toolset (incl. Brian's mental-game rituals).
_CASH_TOOLS = _BASE + _LOOKUPS + (
"start_session", "add_buyin", "log_stack", "log_hand", "record_hand",
"add_read", "analyze_spot", "session_stats", "end_session", "generate_recap",
"scar_note", "confidence_bank", "alligator_blood", "reset_ritual",
"add_read", "analyze_spot", "session_stats", "session_state", "end_session",
"generate_recap", "scar_note", "confidence_bank", "alligator_blood", "reset_ritual",
)
# Talk mode also gets start_session as the *entry point*: opening a session from a
@@ -71,6 +71,13 @@ question, call analyze_spot and report its numbers — never eyeball board math.
session current as the night goes; you can pull session_stats or a player's profile whenever \
it helps. When he's ready to leave, end_session, and write the recap if he wants it.
Everything you log appears on Brian's live HUD (the Session view) — stack, live net, \
hands, villains, the confidence bank, the scar notes, and whether Alligator Blood is on. \
That HUD and you read the SAME data. So when he asks where he's at — his stack, his live \
net, what's in the bank tonight, whether gator mode is on — call session_state and answer \
from what it returns, never from memory. You can point him at the HUD too ("it's on your \
Session screen"), but you can always just tell him.
BRIAN'S RITUALS — his mental-game system. Run them, don't just reference them:
• SCAR NOTE (scar_note) — a painful, instructive mistake to study. Log it when he punts, \
gets over-attached, or leaks — and classify it honestly: punt (his error), cooler \
+30
View File
@@ -187,6 +187,29 @@ def _end_session(args: dict, ctx: dict) -> str:
return f"Session #{s['id']} closed — net {s['net']:+.0f} over {s['hours']}h{hourly}."
def _session_state(args: dict, ctx: dict) -> str:
h = poker.hud()
if not h:
return "No live session right now."
s, st, r = h["session"], h["stack"], h["rituals"]
L = [f"{s.get('stakes') or '?'} {s.get('game') or ''} @ {s.get('venue') or '?'} "
f"{h['stats']['hands_logged']} hands logged"]
if st.get("current") is not None:
L.append(f"Stack ${st['current']:g} (in {st['buy_in']:g}, live net {st['net']:+.0f})")
else:
L.append(f"Stack not logged yet (in {st['buy_in']:g})")
L.append("🐊 Alligator Blood is ON" if r["alligator"] else "Alligator Blood: off")
if r["confidence"]:
L.append("Confidence bank: " + " | ".join(c["content"] for c in r["confidence"][-4:]))
if r["scars"]:
L.append("Scar notes: " + " | ".join(
sc["content"] + (f" [{sc['classification']}]" if sc.get("classification") else "")
for sc in r["scars"][-4:]))
if r["resets"]:
L.append(f"{len(r['resets'])} reset(s) this session")
return "\n".join(L)
def _session_stats(args: dict, ctx: dict) -> str:
st = poker.session_stats()
if not st:
@@ -402,6 +425,13 @@ TOOLS.update({
"session_stats": {"handler": _session_stats, "spec": _f(
"session_stats", "Get money + hand summary for the current/most-recent session.",
{}, [])},
"session_state": {"handler": _session_state, "spec": _f(
"session_state",
"Read back the CURRENT live-session state — the same data Brian sees on his HUD: "
"stack, live net, whether Alligator Blood is on, and the scar notes / "
"confidence-bank entries so far. Use whenever he asks where he's at, what's in "
"the bank, his stack or net, or if gator mode is on — answer from THIS, not memory.",
{}, [])},
"running_stats": {"handler": _running_stats, "spec": _f(
"running_stats",
"Cumulative results across closed sessions (net, $/hr, by stake). Optionally filter.",
+16
View File
@@ -159,6 +159,22 @@ def test_rituals_in_hud(lyra):
assert len(r["scars"]) == 1 and len(r["confidence"]) == 1 and len(r["resets"]) == 1
def test_session_state_readback(lyra):
_, poker, _, tools = lyra
assert "no live session" in tools.dispatch("session_state", {}, {}).lower()
poker.start_session(venue="Meadows", stakes="2/5", buy_in=500)
tools.dispatch("log_stack", {"amount": 720}, {})
tools.dispatch("confidence_bank", {"content": "great river fold"}, {})
tools.dispatch("alligator_blood", {"on": True}, {})
out = tools.dispatch("session_state", {}, {})
assert "720" in out # current stack
assert "+220" in out or "220" in out # live net
assert "Alligator Blood is ON" in out
assert "great river fold" in out
def test_rituals_require_live_session(lyra):
_, poker, _, tools = lyra
# tools degrade gracefully (no exception) when nothing is open