Skip to content

feat(advisor) 1/4: helpers + settings field + orphan tool_use guard - #176

Merged
ericleepi314 merged 1 commit into
mainfrom
advisor/01-foundation
May 19, 2026
Merged

feat(advisor) 1/4: helpers + settings field + orphan tool_use guard#176
ericleepi314 merged 1 commit into
mainfrom
advisor/01-foundation

Conversation

@ericleepi314

Copy link
Copy Markdown
Collaborator

First in a 4-PR stack porting /advisor from TypeScript at server-side parity. This PR lands the runtime-inert foundation; activation lands in PR 3.

Summary

  • src/utils/advisor.py (NEW) — constants (ADVISOR_BETA_HEADER, ADVISOR_TOOL_TYPE, ADVISOR_TOOL_INSTRUCTIONS), provider/env gates, block predicates, schema builder, strip_advisor_blocks, and extract_advisor_{result_text,error_code}. ADVISOR_TOOL_INSTRUCTIONS is byte-for-byte from typescript/src/utils/advisor.ts:130-145; a SHA pin plus live cross-check catch drift.
  • src/settings/types.py — adds advisor_model: str = "" to SettingsSchema. Empty string = unset; future layers read at request time.
  • src/types/messages.py — extends ensure_tool_result_pairing to strip orphan server_tool_use and mcp_tool_use blocks whose matching *_tool_result never landed in the same assistant message (interrupted stream). Mirrors TS messages.ts:5217-5255. Prevents the API from 400-ing the next turn after a mid-advisor ESC.

Stack

  • PR 1 (this PR) → main
  • PR 2 (provider preservation) → this branch
  • PR 3 (query wiring) → PR 2
  • PR 4 (slash command + TUI) → PR 3

Test plan

  • tests/test_advisor_helpers.py — 32 tests: constants, all gates, block detection (dict + attribute-style), strip pass shapes including the empty/thinking-only placeholder fallback, schema shape, SHA + live TS byte-equality.
  • tests/test_advisor_orphan_pairing.py — 6 tests: advisor orphan stripped; pair retained; mcp orphan stripped; empty-content placeholder; regular client tool_use unaffected; multi-message independence.
  • No regressions in 92 adjacent tests (settings, messages utility, command system, tool normalization).

🤖 Generated with Claude Code

Foundation layer for the /advisor port from typescript/src. Three
independent pieces, all read-only at runtime until the rest of the
stack lands:

- `src/utils/advisor.py` (NEW): constants (ADVISOR_BETA_HEADER,
  ADVISOR_TOOL_TYPE, ADVISOR_TOOL_INSTRUCTIONS), provider/env gates,
  block predicates, schema builder, strip_advisor_blocks, and
  extract_advisor_{result_text,error_code}. ADVISOR_TOOL_INSTRUCTIONS
  is a byte-for-byte copy of typescript/src/utils/advisor.ts:130-145;
  a SHA pin plus a live cross-check against the TS source catch drift.

- `src/settings/types.py`: adds `advisor_model: str = ""` to
  SettingsSchema. Empty string = unset; future layers read it via
  `get_settings().advisor_model` at request time.

- `src/types/messages.py`: extends `ensure_tool_result_pairing` to
  strip orphan `server_tool_use` and `mcp_tool_use` blocks whose
  matching `*_tool_result` never landed in the same assistant message
  (interrupted stream). Mirrors TS messages.ts:5217-5255. Prevents
  the API from 400-ing the next turn after a mid-advisor ESC.

## Test plan
- [x] `tests/test_advisor_helpers.py` (32 tests): constants, all gates,
      block detection (dict + attribute-style), strip pass shapes
      including the empty/thinking-only placeholder fallback, schema
      shape, SHA + live TS byte-equality.
- [x] `tests/test_advisor_orphan_pairing.py` (6 tests): advisor orphan
      stripped; pair retained; mcp orphan stripped; empty-content
      placeholder; regular client tool_use unaffected; multi-message
      independence.
- [x] No regressions in adjacent suites (settings, messages utility,
      command system, tool normalization, transcript, tui).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant