Skip to content

refactor(middleware): gut dead thinkingLevel configuration surface #2480

@alexey-pelykh

Description

@alexey-pelykh

Context

RemoteClaw is middleware that delegates LLM execution to CLI agents (Claude Code, Gemini, Codex, OpenCode). Each CLI manages its own reasoning/thinking configuration. RemoteClaw should not attempt to translate or control LLM-level thinking settings — that's platform territory and violates the middleware boundary.

Problem

The thinkingLevel config surface is user-settable but has no runtime effect. This is a broken half-implementation.

Flow analysis

  1. User sets it via CLI (--thinking high), TUI (/thinking command), ACP set_config_option thinking_level, or cron job flag
  2. Value is persisted in session entries (SessionEntry.thinkingLevel)
  3. Value is displayed back in the TUI (src/tui/tui.ts:757-759) and surfaced to ACP clients (src/acp/translator.ts:1001)
  4. No CLI subprocess invocation passes the value. The CLI agents (src/middleware/runtimes/claude.ts, codex.ts, gemini.ts, opencode.ts) consume thinking/reasoning as OUTPUT events from their subprocess streams; they do not accept a thinkingLevel input and do not forward it as a CLI flag.
  5. Merge logic in src/auto-reply/thinking.shared.ts — specifically resolveThinkingDefaultForModel — has zero callers. Dead function.
  6. src/agents/subagent-spawn.ts:279 reads params.thinking into _thinkingOverrideRaw — the leading underscore indicates intentionally unused; subagent spawning silently discards the thinking override.
  7. Tests asserting thinking-merge behavior (src/commands/agent.test.ts:840-846 "prefers per-model thinking over global thinkingDefault") are orphan: they assert against a mock of runEmbeddedPiAgent, which is not imported anywhere in production src/ code (the embedded execution path was gutted).

What reasoningLevel does (and why it stays)

reasoningLevel is a different concept and must be KEPT. It controls Telegram channel display behavior (off | on | stream — drives suppression/streaming/block-streaming of reasoning-event rendering in Telegram drafts) via resolveTelegramReasoningLevel in src/telegram/bot-message-dispatch.ts:92-112. Downstream it flows through src/auto-reply/reply/get-reply.ts, get-reply-inline-actions.ts, commands-status.ts. This is a legitimate channel-bound middleware concern.

Do not confuse the two. Gut only thinkingLevel / thinkingDefault / thinking-related helpers. Keep reasoningLevel everywhere.

Tasks

Session/state

  • Remove thinkingLevel field from SessionEntry type in src/gateway/session-utils.types.ts:36 and src/gateway/protocol/schema/sessions.ts:101
  • Remove thinkingLevel persistence in gateway server methods:
    • src/gateway/server-methods/sessions.ts:498
    • src/gateway/server-methods/agent.ts:468
    • src/gateway/server-methods/chat.ts:778-784
    • src/gateway/server-node-events.ts:167
    • src/gateway/session-utils.ts:826
  • Remove from src/auto-reply/reply/session.ts session merge logic (lines 368, 370, 384, 386, 434)

Config

  • Remove thinkingDefault field from src/config/types.agent-defaults.ts:178 and src/config/zod-schema.agent-defaults.ts:132-141
  • Remove subagents.thinking override in src/config/zod-schema.agent-defaults.ts:182
  • Regenerate src/config/schema.base.generated.ts
  • Add migration warning if loaded config contains thinkingDefault or subagents.thinking (same channel used for other legacy-field warnings)

CLI surface

  • Remove --thinking flag from src/cli/cron-cli/register.cron-add.ts:178-179 and register.cron-edit.ts:211-212
  • Remove thinking field from cron test fixtures (src/cron/normalize.test.ts:368, src/cli/cron-cli.test.ts:233,402,408,430)
  • Remove thinking: opts.thinking from src/commands/agent-via-gateway.ts:140 gateway payload
  • Remove thinking option handling from src/commands/agent.ts (search for opts.thinking and the CLI option declaration)

TUI

  • Remove thinkingLevel from src/tui/tui-types.ts:30
  • Remove thinkingLevel from src/tui/tui-session-actions.ts:165-166, 288, 292
  • Remove thinkingLevel display from src/tui/tui.ts:757-759
  • Remove /thinking command handler from src/tui/tui-command-handlers.ts (search for thinkingLevel and remove the whole command branch)
  • Remove from src/tui/gateway-chat.ts:80

ACP

  • Remove thinking_level handling in src/acp/translator.ts:
    • set_config_option write path (~line 1030)
    • Response field emit (~line 1001)
    • Session-mode param handling (~lines 93, 203, 558-562, 663)
  • Remove thinking_level from src/acp/commands.ts if exposed as a config option ID there
  • Remove thinking assertions from src/acp/translator.set-session-mode.test.ts:39, 50 and from src/acp/translator.session-rate-limit.test.ts

Subagent spawn + cron jobs

  • Remove thinking param from src/agents/tools/sessions-spawn-tool.ts:27, 91, 123
  • Remove _thinkingOverrideRaw/params.thinking discard in src/agents/subagent-spawn.ts:279
  • Remove thinking field handling from src/cron/service/jobs.ts:679-680, 763
  • Remove thinking field references from src/agents/tools/sessions-history-tool.ts:66

Thinking helpers + orphan tests

  • Delete the following from src/auto-reply/thinking.shared.ts, leaving only ReasoningLevel, VerboseLevel, and normalizeVerboseLevel (and anything else still used):
    • ThinkLevel type
    • resolveThinkingDefaultForModel
    • listThinkingLevels, listThinkingLevelLabels, formatThinkingLevels
    • formatXHighModelHint
    • isBinaryThinkingProvider
    • ThinkingCatalogEntry type
    • Any other helpers whose only consumers are being removed in this issue
  • Delete src/tui/tui-formatters.ts:181 thinking-text display (verify it's the text-output rendering, not a level — if it's level-related, delete; if it's the stream of thinking text emitted by the CLI, keep since that's the output-event rendering and still in use)
  • Delete orphan tests in src/commands/agent.test.ts:
    • expectDefaultThinkLevel helper function
    • "prefers per-model thinking over global thinkingDefault"
    • "defaults thinking to adaptive for Anthropic Claude 4.6 models"
    • Any other tests asserting getLastEmbeddedCall()?.thinkLevel

Acceptance Criteria

  • rg "thinkingLevel|thinkingDefault|ThinkLevel" src/ returns no hits (migration-warning message text aside)
  • rg "\.thinking\b|params\.thinking" src/ returns no hits, except thinking_delta and type === \"thinking\" references in src/middleware/runtimes/*.ts (those are output-event stream parsers and must stay)
  • rg "reasoningLevel" src/ still returns live hits in Telegram, channel, ACP translator paths — this is intentional, reasoningLevel is kept
  • User loading a config with thinkingDefault: "high" sees a migration warning and the config still loads
  • remoteclaw cron add --thinking high — the flag either errors with "unknown option" or the whole line is removed; state the behavior in the PR description
  • tsc --noEmit clean
  • Test suite passes with no new skips

Metadata

Metadata

Assignees

Labels

gutRemoving dead upstream subsystems

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions