Skip to content

feat(hints): remove string hints — consolidate to hints_structured with reason field#223

Merged
HumanBean17 merged 2 commits into
masterfrom
feat/hints-string-removal
May 24, 2026
Merged

feat(hints): remove string hints — consolidate to hints_structured with reason field#223
HumanBean17 merged 2 commits into
masterfrom
feat/hints-string-removal

Conversation

@HumanBean17
Copy link
Copy Markdown
Owner

Summary

Removes the redundant hints: list[str] field from all 5 MCP tool output models and replaces it with a cleaner structure:

  • Added reason: str = "" field to StructuredHint — explains why each hint was emitted
  • Added new advisories: list[str] field to all output models — pure informational text with no tool call
  • Changed generate_hints return type from tuple[list[str], list[_StructuredHint]] to tuple[list[_StructuredHint], list[str]]
  • Removed all string template constants (TPL_*) and string-only helper functions
  • Reclassified hints: tool calls → structured hints with reason; pure advisory → advisories list

Changes

mcp_hints.py

  • Added reason: str = "" to _StructuredHint NamedTuple
  • Removed MCP_HINTS_FIELD_DESCRIPTION constant and all TPL_* string template constants
  • Removed finalize_hint_list function and string-only helpers
  • Changed generate_hints return type to (structured hints, advisories)
  • Added finalize_advisories() function for deduping advisory strings

mcp_v2.py

  • Added reason: str = "" to public StructuredHint model
  • Added advisories: list[str] field to all 5 output models
  • Removed hints: list[str] field from all output models
  • Updated _to_structured_hints() to forward reason field
  • Updated all tool functions to unpack (raw_struct, raw_advisories) instead of (str_hints, raw_struct)

server.py

  • Updated tool descriptions to reference hints_structured (tool call suggestions with reason) and advisories (informational notes)

tests/test_mcp_hints.py

  • Migrated 80+ tests from out.hints to out.advisories or out.hints_structured[*].reason
  • Removed tests that referenced old template constants
  • Removed _structural_neighbors_hints helper function
  • Removed parity test and template-length tests
  • Added 7 new tests: reason content, reason char cap, no hints field, advisory content, advisory char cap, no empty args

docs/AGENT-GUIDE.md

  • Updated documentation to reflect new field structure and removed hints list references

Test plan

  • All hints tests pass (52 passed, 1 skipped)
  • Ruff check clean
  • Full test suite passes

Definition of Done

  • hints: list[str] field absent from all five output models
  • advisories: list[str] field present on all five output models
  • reason: str field present on StructuredHint and _StructuredHint
  • generate_hints returns tuple[list[_StructuredHint], list[str]]
  • MCP_HINTS_FIELD_DESCRIPTION, all TPL_* constants, finalize_hint_list removed
  • No structured hint has empty args without concrete tool call
  • server.py tool descriptions reference hints_structured and advisories
  • Test suite passes
  • Ruff clean

🤖 Generated with Claude Code

…th reason field

- Remove redundant hints: list[str] field from all 5 MCP tool output models
- Add reason: str to StructuredHint — explains why each hint was emitted
- Add advisories: list[str] to all output models — pure informational text with no tool call
- Eliminate dual-emission maintenance burden and parity test
- Preserve all currently emitted advisory information — string-only hints move to advisories, tool-call hints gain reason

Changes:
- mcp_hints.py: Added reason to _StructuredHint, removed TPL_* template constants, changed generate_hints return type to (structured, advisories), added finalize_advisories()
- mcp_v2.py: Added reason to StructuredHint, added advisories field, removed hints field from all output models
- server.py: Updated tool descriptions to reference hints_structured and advisories
- tests/test_mcp_hints.py: Migrated 80+ tests, removed template-based tests, added 7 new tests for reason and advisories
- docs/AGENT-GUIDE.md: Updated documentation to reflect new field structure

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@HumanBean17
Copy link
Copy Markdown
Owner Author

Code Review

The architecture is right and the code reduction is excellent. A few issues to address:


Bug: find success hints lost when limit=None

The old condition if results and not _find_is_page_full(payload, results) emitted success hints when lim is None (because _find_is_page_full returned False). The new condition:

if results and lim is not None and len(results) < int(lim):

requires lim is not None, so find calls without a limit get no success structured hints (handler for route, HTTP targets for client, async targets for producer). Fix:

if results and (lim is None or len(results) < int(lim)):

Missing fallback in type-level requery

_neighbors_empty_structured_hints had an else fallback trying spec.typical_traversals.get("type_subject", "") when the primary parse failed. Now removed. If the primary template format diverges from what split("'") expects, the hint silently disappears. Low risk but worth a comment explaining the intentional removal.


Long advisory strings may exceed test cap

The unresolved call sites advisory is ~280 chars with realistic values (page_n=25, unresolved=5), but test_advisories_char_cap only exercises the fuzzy-strategy path and won't catch this. Either shorten the advisory or raise/parameterize the cap.


Fragile template parser

The regex _parse_first_traversal was replaced with template.split("'") indexing. Works for the current format but silently produces wrong results if the template format changes. A comment documenting the expected format would help future maintainers.


The find regression should be fixed before merge. The rest are lower severity.

🤖 Generated with Claude Code

- Fix bug: find success hints now emit when limit=None (was missing)
- Add comment explaining intentional removal of regex fallback in neighbors hints
- Shorten unresolved call sites advisory to stay under 200 char cap
- Add comment documenting expected template format for split-based parsing

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@HumanBean17
Copy link
Copy Markdown
Owner Author

Follow-up Review

All four items from the previous review are addressed:

  1. Find success condition — Fixed: if results and (lim is None or len(results) < int(lim)) correctly handles limit=None now.
  2. Type-level requery fallback — Intentionally kept removed with a clear comment explaining the rationale (schema-controlled format is stable, silence on mismatch is acceptable).
  3. Long advisory string — Unresolved advisory shortened to ~100 chars with realistic values, with a comment referencing the char cap.
  4. Fragile template parser — Now has a 3-line comment block documenting the intentional regex removal.

LGTM — ready to merge.

🤖 Generated with Claude Code

@HumanBean17 HumanBean17 merged commit 87e673c into master May 24, 2026
1 check passed
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