Skip to content

gateway/session-utils: honor per-agent thinkingDefault in buildGatewaySessionRow#70302

Closed
cholaolu-boop wants to merge 1 commit intoopenclaw:mainfrom
cholaolu-boop:fix/session-utils-agent-thinking-fallback
Closed

gateway/session-utils: honor per-agent thinkingDefault in buildGatewaySessionRow#70302
cholaolu-boop wants to merge 1 commit intoopenclaw:mainfrom
cholaolu-boop:fix/session-utils-agent-thinking-fallback

Conversation

@cholaolu-boop
Copy link
Copy Markdown

Summary

  • Fix a TUI display drift that is adjacent to, but not covered by, PR gateway/chat: honor per-agent thinkingDefault in chat.history fallback #70259. The TUI footer's state.sessionInfo.thinkingLevel is fed through sessions.list / sessions.changed, which flow through buildGatewaySessionRow(...) in src/gateway/session-utils.ts. That builder currently reads only entry?.thinkingLevel, with no fallback. When a session has no persisted thinkingLevel (fresh session, post-restart, new webchat connection), the row's thinkingLevel is undefined, the TUI picks up whatever it defaults to (typically the model-centric default from resolveThinkingDefaultForModel, which for openai-codex/gpt-5.4 is "low"), and drifts below the configured agent level.
  • Honor the same three-step fallback chain the chat.history RPC handler uses (PR gateway/chat: honor per-agent thinkingDefault in chat.history fallback #70259):
    1. entry.thinkingLevel — persisted session value (unchanged priority).
    2. cfg.agents.list[].thinkingDefault via resolveAgentConfig — per-agent override.
    3. resolveThinkingDefault(...) — which internally covers per-model override, cfg.agents.defaults.thinkingDefault, anthropic heuristics, and the model-centric fallback.

Scope

  • Single-call-site change in src/gateway/session-utils.ts inside buildGatewaySessionRow(...). Both RPC paths that feed the TUI — sessions.list (listSessionsFromStore) and sessions.changed broadcasts (loadGatewaySessionRowbuildGatewaySessionRow) — benefit from the one edit.
  • Uses the existing normalized resolveAgentConfig helper from src/agents/agent-scope.ts (same one PR gateway/chat: honor per-agent thinkingDefault in chat.history fallback #70259 uses in the chat.history handler), so agent id normalization is shared.
  • The /think command path, auto-reply/reply/model-selection, agent-command, cron/isolated-agent, and plugin runtime callers are untouched — this is strictly the TUI-effective SessionRow fallback.

Deliberate design notes

  • No model catalog in the sync row-builder. buildGatewaySessionRow is synchronous and is called from many places (including hot paths). resolveThinkingDefault accepts catalog? as optional. This PR intentionally calls it without a model catalog, which means the Claude-4.6 "adaptive" heuristic that depends on catalogCandidate.name does not fire in this sync row-builder. The opus-4-7 / per-model / global / model-centric branches continue to work because they do not require the catalog. Introducing async + catalog plumbing into buildGatewaySessionRow would be a broader refactor outside this PR's scope; it can be added later if the Claude-4.6 sonnet-adaptive case turns out to matter for the TUI footer in practice.
  • No redundancy with PR gateway/chat: honor per-agent thinkingDefault in chat.history fallback #70259. The chat.history RPC handler still independently returns a correctly-resolved thinkingLevel (including the catalog-aware heuristic, because it is async and has catalog access). When the TUI issues both sessions.list and chat.history for the same session, the two paths now produce consistent values (and PR gateway/chat: honor per-agent thinkingDefault in chat.history fallback #70259 remains the authoritative, catalog-aware one for chat.history).

Rollout / verification note

Because the TUI footer caches state.sessionInfo.thinkingLevel locally after the initial handshake, a live client that was already connected before this change may continue to show the stale value for its existing session. A reconnect / TUI restart is the expected verification step after rollout — the new SessionRow values take effect on the next sessions.list / sessions.changed delivery.

Tests

New focused suite src/gateway/session-utils.thinking-fallback.test.ts — 6 tests, all passing locally:

  • entry.thinkingLevel wins over per-agent default (regression guard).
  • Per-agent thinkingDefault fills the gap when the entry has no thinkingLevel.
  • Global agents.defaults.thinkingDefault fills the gap when per-agent is unset.
  • Model-centric fallback still produces a concrete ThinkLevel string (never undefined).
  • sessions.list and loadGatewaySessionRow stay consistent on thinkingLevel (covers both TUI-feeding paths).
  • Canonical webchat sessionKey: "agent:main:main" resolves via the normalized agent lookup.

Test plan

  • pnpm test src/gateway/session-utils.thinking-fallback.test.ts — 6/6 PASS
  • Regression: pnpm test src/gateway/session-utils.test.ts src/gateway/session-utils.fs.test.ts src/gateway/session-utils.search.test.ts src/gateway/session-utils.subagent.test.ts — 139/139 PASS
  • pnpm check (tsgo core + core:test + extensions + extensions:test, oxlint, import-cycle + madge checks all green; ran via scripts/committer)

Related

🤖 Generated with Claude Code

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: S labels Apr 22, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 22, 2026

Greptile Summary

Adds the same three-step thinkingLevel fallback chain to buildGatewaySessionRow that PR #70259 introduced for the chat.history RPC handler, preventing TUI footer drift when a session has no persisted thinkingLevel. The change is minimal and well-reasoned: per-agent thinkingDefault is resolved via the existing resolveAgentConfig helper, then resolveThinkingDefault covers the global/model/heuristic chain, intentionally without catalog to keep the builder synchronous.

Confidence Score: 5/5

Safe to merge — single call-site change with thorough test coverage and no P0/P1 issues found.

The implementation is correct: resolveThinkingDefault does not already cover per-agent thinkingDefault (it only reads cfg.agents.defaults.thinkingDefault), so step 2 adds the missing level without redundancy. sessionAgentId is normalized before use, optional-chaining is correct, and the 6-test suite covers all fallback branches plus both TUI-feeding code paths.

No files require special attention.

Reviews (1): Last reviewed commit: "gateway/session-utils: honor per-agent t..." | Re-trigger Greptile

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 26, 2026

Closing this as duplicate or superseded after Codex automated review.

PR #70302 identifies a real gateway session-row thinking-default gap, but the remaining work is now superseded by the open maintainer replacement PR #72324, which explicitly carries forward #70302 and preserves contributor credit. Current main has not shipped the fix, so this should close as superseded rather than implemented.

Best possible solution:

Close #70302 as superseded by the maintainer-owned #72324. Continue the fix there, preserving #70302 attribution, and make the final implementation keep explicit persisted session overrides in thinkingLevel while exposing inherited per-agent/per-model/global defaults through thinkingDefault with correct precedence and regression coverage.

What I checked:

So I’m closing this here and keeping the remaining discussion on the canonical linked item.

Codex Review notes: model gpt-5.5, reasoning high; reviewed against edf40ab6c944.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant