fix(tui): poll kanban_notify_subs for task event delivery to TUI sessions - #59963
fix(tui): poll kanban_notify_subs for task event delivery to TUI sessions#59963isheng-eqi wants to merge 6 commits into
Conversation
…usResearch#58774) _restore_or_build_system_prompt unconditionally restored the session-DB stored prompt when it matched the current runtime identity, even when the caller set an explicit ephemeral_system_prompt (e.g. /personality). Check ephemeral_system_prompt before the stored-prompt fast path so a deliberate personality switch takes effect immediately instead of being silently ignored until the next fresh session.
…nto fix/58774-personality-ephemeral
…ibuteError (NousResearch#59845) The Copilot x-initiator injection block calls agent._is_copilot_url() without a getattr guard, unlike the sibling _is_user_initiated_turn check one line above. On some agent construction paths (module-reload, wrapper agents) _is_copilot_url may be missing, causing every API call in the conversation to fail with AttributeError and the cron job to error out. Wrap the call with getattr(agent, '_is_copilot_url', lambda: False)() so non-Copilot and partially-initialized agents fall through cleanly. Github-Issue:NousResearch#59845
…nt delivery The TUI notification poller (_notification_poller_loop) only watched process_registry.completion_queue, never polling kanban_notify_subs. Kanban task subscriptions with platform='tui' were therefore never delivered — the gateway's _kanban_notifier_watcher has no TUI adapter, and the TUI poller had no kanban polling logic. Add _poll_kanban_task_events() which mirrors the gateway watcher's pattern: list kanban_notify_subs for the session, claim unseen terminal events via kanban_db.claim_unseen_events_for_sub(), and emit status.update messages to the TUI session. Polled every ~5 seconds on the existing completion_queue.get() timeout path. Github-Issue:NousResearch#59960
falkoro
left a comment
There was a problem hiding this comment.
Reviewed this while writing up the comparison with my duplicate (#60085 — happy for whichever version the maintainers prefer to land). One functional issue worth fixing either way:
_poll_kanban_task_events reads the session key from the wrong place. It uses os.environ.get("HERMES_SESSION_KEY") in the poller thread, but subscriptions are written with chat_id from the session-context bridge: kanban_tools._maybe_auto_subscribe reads get_session_env("HERMES_SESSION_KEY"), which is a ContextVar set per agent turn via _set_session_context(session["session_key"]) (gateway/session_context.py — the env fallback only applies when the ContextVar was never set). The TUI server's own process env normally has no HERMES_SESSION_KEY, so the poller returns early and never delivers; and in a multi-session desktop, a single process-level env value can't distinguish sessions — whichever value happens to be set would route every session's notifications to one key.
Since the poller already receives the session dict, the fix is one line: session_key = str(session.get("session_key") or "").
Two smaller parity notes vs the gateway notifier (gateway/kanban_watchers.py), take or leave: it iterates all boards (subs on non-default boards deliver too), and it unsubscribes at a final task status (done/archived) so rows don't accumulate per completed task.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the missing TUI delivery leg. The current main poller still only drains process_registry.completion_queue (tui_gateway/server.py:8719-8740), so the underlying bug remains.
Problems
tui_gateway/server.py:8318readsHERMES_SESSION_KEYfromos.environ. TUI turns bind the key through_set_session_context()/set_session_vars()(tui_gateway/server.py:1990-2015,8977-8980), which uses ContextVars. The poller can therefore return early, and a process-global value would not isolate desktop sessions.tui_gateway/server.py:8326opens only the default board. The gateway notifier enumerates all boards (gateway/kanban_watchers.py:209-295), so subscriptions on an explicitly selected board would remain undelivered.- The change has no TUI kanban regression tests, and it retains final subscriptions unlike the gateway cleanup rule (
gateway/kanban_watchers.py:484-492).
Suggested changes
- Key the poller from
session["session_key"], then test cross-session isolation. - Mirror gateway multi-board polling and final-status unsubscribe behavior.
- Keep the salvage focused on the TUI change; the unrelated core prompt/cache changes should be separated.
This is an automated hermes-sweeper review.
| from hermes_cli import kanban_db as _kb | ||
|
|
||
| session_key = os.environ.get("HERMES_SESSION_KEY", "") | ||
| if not session_key: |
There was a problem hiding this comment.
Use str(session.get("session_key") or "") here. TUI turns bind this key through the session-context ContextVar, not the server process environment; this poller otherwise normally returns early and a shared env value cannot isolate simultaneous desktop sessions.
| try: | ||
| conn = _kb.connect() | ||
| except Exception: | ||
| return |
There was a problem hiding this comment.
This only opens the default board, but subscriptions are stored in the board selected when kanban_create connects. Mirror the gateway notifier's all-board iteration so non-default-board TUI subscriptions can be delivered.
|
Nice tracing of the delivery-path gap — the two-leg diagnosis (no TUI adapter in the gateway watcher, poller only draining Coordination note: the earlier #60085 (open, fixes #59890 — which looks like the same underlying report as #59960) implements this same missing leg, and it already covers the three items in the sweeper review, verifiable in the diff:
8 TUI kanban regression tests total in |
|
Fixed on main via PR #72177 — a salvage of #66435, the current-main cherry-pick of @falkoro's #60085, which implemented the same missing TUI consumer this PR targeted. #60085 was submitted five days before this one and was ultimately the branch taken, with its authorship preserved in git log (badb240, 6247712). Thanks for the independent root-cause and the focused implementation here — the diagnosis (gateway watcher has no "tui" adapter, TUI poller only drains the process completion queue) matched exactly. Closing since the delivery path is now on main; if you spot gaps in the landed version, a fresh PR on top is very welcome. |
Summary
Fixes #59960
Problem
Kanban task event notifications are never delivered to TUI (Desktop/TUI) sessions. The root cause is a delivery-path gap:
_kanban_notifier_watcherreadskanban_notify_subscorrectly but has no adapter fortuiplatform subscriptions — TUI is not a gateway messaging channel_notification_poller_looponly watchesprocess_registry.completion_queuefor background process completions, never readingkanban_notify_subsResult:
kanban_tools._maybe_auto_subscribe()correctly creates subscriptions withplatform="tui", but no code path ever delivers them. All TUI kanban subscriptions havelast_event_id=0forever.Fix
Add
_poll_kanban_task_events()— a new helper that mirrors the gateway watcher's subscription-polling pattern:kanban_notify_subsfor the TUI session (filtered byplatform="tui"+chat_id=HERMES_SESSION_KEY)kanban_db.claim_unseen_events_for_sub()status.updatemessages withkind="kanban"to the TUI sessionPolled every ~5 seconds on the existing
completion_queue.get(timeout=0.5)path — no additional thread or timer needed.Changes
tui_gateway/server.py: add_poll_kanban_task_events()helper + integrate into_notification_poller_looptimeout path