Commit 2f4d001
authored
fix(proxy): keep prefixed core tools resident (#3046)
## Description
Headroom's Tool Search deferral lowercased core tool names but did not
account for client namespace prefixes. Oh My Pi sends built-ins such as
`_read`, `_edit`, `_write`, and `_bash`, so those core tools were
incorrectly marked `defer_loading=True`.
This change centralizes resident-name normalization for both the
Anthropic and OpenAI paths. It lowercases names and removes only leading
underscores, preserving internal separators such as `mcp__server__read`
so unrelated tools do not become resident.
Closes #3031
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)
## Changes Made
- Added a shared resident-tool name normalizer in
`headroom/proxy/helpers.py`.
- Applied the same normalization to Anthropic and OpenAI Tool Search
deferral.
- Added a regression test for Oh My Pi's exact 12-tool surface at the
deferral threshold.
- Added OpenAI coverage for prefixed resident tools and negative
namespace cases.
## Testing
<!-- Check what you actually ran, then paste the real command output
below. -->
- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [x] Manual testing performed
### Test Output
```text
$ uv run --no-sync pytest --noconftest -q tests/test_openai_tool_search_deferral.py tests/test_issue_746_tool_search.py -k 'not normalize_tool_search_mode and not configure_'
72 passed, 23 deselected in 0.25s
$ uv run --no-sync ruff check .
All checks passed!
$ uv run --no-sync ruff format --check .
1499 files already formatted
$ UV_CACHE_DIR=/tmp/headroom-uv-cache uv run --no-sync mypy headroom
Success: no issues found in 520 source files
```
## Real Behavior Proof
- Environment: Linux x86_64 sandbox; Python 3.12.13; uv 0.11.33; no
provider credentials.
- Exact command / steps: Exercised the exact 12-tool Oh My Pi fixture
through the Anthropic deferral helper and prefixed resident plus
negative names through the OpenAI helper.
- Observed result: Anthropic kept `_edit`, `_task`, `_read`, `_bash`,
`_glob`, `_grep`, `_write`, `computer`, and `web_search` resident while
deferring `_hub`, `_todo`, and `_eval`. OpenAI kept prefixed core tools
resident while `mcp__server__read` and `terminal_helper` remained
deferred.
- Not tested: Live Oh My Pi traffic against Anthropic, provider E2E
tests, and the full native-backed pytest suite.
## Runtime Rollout Safety
- Rollout-managed feature(s): Existing server-side Tool Search deferral
for Anthropic and OpenAI.
- Minimum rollout channel: N/A; targeted bug fix to existing behavior.
- Stable/default behavior changed: Yes. Leading-underscore names that
normalize to known resident names now remain resident.
- Kill switch / disable path: Set `HEADROOM_TOOL_SEARCH=0`.
- Unsafe override required: No.
- Qualification impact: Prefixed core tools remain immediately
available; non-core and MCP namespace behavior is unchanged.
- Rollback path: Revert this commit or disable Tool Search with
`HEADROOM_TOOL_SEARCH=0`.
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [x] I did **not** edit `CHANGELOG.md` — it is generated by
release-please from my Conventional Commit PR title (a CI guard enforces
this)
## Screenshots (if applicable)
N/A
## Additional Notes1 parent 322425c commit 2f4d001
3 files changed
Lines changed: 68 additions & 11 deletions
File tree
- headroom/proxy
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2811 | 2811 | | |
2812 | 2812 | | |
2813 | 2813 | | |
| 2814 | + | |
| 2815 | + | |
| 2816 | + | |
| 2817 | + | |
| 2818 | + | |
| 2819 | + | |
| 2820 | + | |
2814 | 2821 | | |
2815 | 2822 | | |
2816 | 2823 | | |
| |||
2872 | 2879 | | |
2873 | 2880 | | |
2874 | 2881 | | |
2875 | | - | |
2876 | | - | |
2877 | | - | |
2878 | | - | |
2879 | | - | |
| 2882 | + | |
| 2883 | + | |
| 2884 | + | |
| 2885 | + | |
| 2886 | + | |
2880 | 2887 | | |
2881 | 2888 | | |
2882 | 2889 | | |
2883 | 2890 | | |
2884 | 2891 | | |
2885 | | - | |
| 2892 | + | |
2886 | 2893 | | |
2887 | 2894 | | |
2888 | 2895 | | |
| |||
3259 | 3266 | | |
3260 | 3267 | | |
3261 | 3268 | | |
3262 | | - | |
3263 | | - | |
3264 | | - | |
3265 | | - | |
| 3269 | + | |
| 3270 | + | |
| 3271 | + | |
| 3272 | + | |
3266 | 3273 | | |
3267 | 3274 | | |
3268 | 3275 | | |
| |||
3273 | 3280 | | |
3274 | 3281 | | |
3275 | 3282 | | |
3276 | | - | |
| 3283 | + | |
3277 | 3284 | | |
3278 | 3285 | | |
3279 | 3286 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
350 | 350 | | |
351 | 351 | | |
352 | 352 | | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
353 | 389 | | |
354 | 390 | | |
355 | 391 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
123 | 123 | | |
124 | 124 | | |
125 | 125 | | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
126 | 140 | | |
127 | 141 | | |
128 | 142 | | |
| |||
0 commit comments