Skip to content

refactor: sever the agentic-mode imports from the classic handlers - #237

Open
claude[bot] wants to merge 3 commits into
mainfrom
claude/sever-agentic-classic-imports-72q9g8
Open

claude[bot] wants to merge 3 commits into
mainfrom
claude/sever-agentic-classic-imports-72q9g8

Conversation

@claude

@claude claude Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Richard · project thread

Description

Before: agentic mode depended on classic mode. src/bot/orchestrator.py had nine from .handlers lines: _format_error_message imported inline at four error sites, _update_working_directory_from_claude_response at three success sites, and from .handlers import command to register /restart and /sync_threads. Deleting src/bot/handlers/ would have broken every agentic reply path.

After: the orchestrator imports nothing from src/bot/handlers/ except the classic registration inside _register_classic_handlers. Nothing changes for a user in either mode; every moved function is byte-for-byte the same code at a new path.

This is step 1 of the classic-mode removal (roadmap item 4.1). It ships in 1.x and is non-breaking.

How

Two shared helpers leave src/bot/handlers/message.py:

  • _format_error_message (with its _format_process_error companion) → src/bot/utils/error_messages.py
  • _update_working_directory_from_claude_response → src/bot/utils/working_directory.py

Two commands leave src/bot/handlers/command.py, because agentic mode registers them too, so they were never classic-mode code:

  • restart_command and sync_threads → src/bot/commands.py, together with the _is_private_chat predicate sync_threads needs. Classic start_command imports _is_private_chat from there.

orchestrator.py binds all four at module level instead of importing them inside each function. The three tests that patched src.bot.handlers.message.<helper> now patch src.bot.orchestrator.<helper>, and the /restart and /sync_threads tests import from src.bot.commands.

A new test, tests/unit/test_bot/test_agentic_imports.py, parses the orchestrator's AST and asserts the only from .handlers import is the classic registration; it also checks the three new shared modules do not reach back into handlers/. That is the "done when" condition of this step, kept enforced.

CLAUDE.md gains the two new modules under Key Directories and a note that agentic code must not import from src/bot/handlers/.

Merged with main after #236 and #239 landed. The #236 merge had one conflict, two adjacent import lines in src/bot/handlers/message.py, and both imports are kept. #236's own guard test (every format_claude_response() call goes through with_stop_reason()) passes on the merged head.

Related issue

Groundwork for roadmap item 4.1 (classic-mode removal), docs/ROADMAP-v2.md. No issue closes.

Type of change

  • Bug fix
  • New feature
  • Breaking change (documented in CHANGELOG under "Changed" or "Removed")
  • Documentation or tooling only — refactor with no behaviour change

How it was tested

  • Tests added or updated: tests/unit/test_bot/test_agentic_imports.py (2 tests); patch targets updated in test_stop_button.py, test_orchestrator.py, test_thread_mode_handlers.py
  • poetry run pytest on the merged head: 691 passed (689 on main after fix: say why a run stopped instead of reporting success #236, plus the 2 new). black --check, isort --check-only and flake8 pass. mypy is not a gate and was not run.
  • Tested by hand against a running bot: not done. No bot token or Claude session here. The change moves code without editing it, and the existing /restart, /sync_threads and agentic reply tests cover the new import paths.

Checklist

  • One concern per PR; unrelated changes are split out
  • CHANGELOG.md has an entry under [Unreleased]
  • No pyproject.toml dependency changes
  • Documentation updated: CLAUDE.md. No settings or commands changed, so no .env.example or docs/ change
  • New settings default to current behaviour — no new settings
  • If AI tools helped write this change, I reviewed every line — written by Claude Code; the hand-testing row above is honest about what was not run

🤖 Generated with Claude Code

https://claude.ai/code/session_01Uta5V6wHoXYU3muwEpvaDt

Agentic mode pulled _format_error_message and
_update_working_directory_from_claude_response out of
src/bot/handlers/message.py at seven call sites, and registered
restart_command and sync_threads from src/bot/handlers/command.py. That
is what made classic mode undeletable.

The two helpers move to src/bot/utils/error_messages.py and
src/bot/utils/working_directory.py. The two commands, which both modes
register, move to src/bot/commands.py together with the _is_private_chat
predicate sync_threads needs. Classic mode imports all of them from the
new homes, so behaviour is unchanged in either mode.

The only `from .handlers` import left in orchestrator.py is the classic
registration inside _register_classic_handlers. A new test parses the
orchestrator's AST and fails if another one appears, and checks that the
three new shared modules do not reach back into handlers/.

Tests that patched the helpers on handlers.message now patch the names
the orchestrator binds at module level.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uta5V6wHoXYU3muwEpvaDt
@claude
claude Bot requested a review from RichardAtCT as a code owner September 22, 2026 15:31
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

No findings meet the merge-blocking bar at this head.

Resolves the CHANGELOG.md conflict under [Unreleased]: this branch's
Changed entry and main's Fixed entries from #239 are both kept.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uta5V6wHoXYU3muwEpvaDt
…q9g8

Resolves one conflict in src/bot/handlers/message.py: both sides added an
import on adjacent lines (_format_error_message from its new home in
src/bot/utils/error_messages.py, and with_stop_reason from #236). Both
are kept.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uta5V6wHoXYU3muwEpvaDt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants