Skip to content

LCORE-1262: Resolve allowed tools filters in LCS#1412

Open
asimurka wants to merge 1 commit intolightspeed-core:mainfrom
asimurka:responses_implement_allowed_tools_filtering
Open

LCORE-1262: Resolve allowed tools filters in LCS#1412
asimurka wants to merge 1 commit intolightspeed-core:mainfrom
asimurka:responses_implement_allowed_tools_filtering

Conversation

@asimurka
Copy link
Copy Markdown
Contributor

@asimurka asimurka commented Mar 27, 2026

Description

This PR adds support for resolving allowed_tools within resolve_tool_choice instead of passing it to LLS. When allowed_tools is provided, the function now applies the allowlist directly by filtering the available tools based on the specified criteria (such as type, name, or server_label). At the same time, tool_choice is normalized so that it is always converted to a standard ToolChoiceMode, rather than keeping the original object form. As a result, allowed_tools is no longer propagated further; instead, its effect is reflected in the filtered tools set. If no tools remain after filtering, the function returns (None, None) which is consistent with Responses API behavior.

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement
  • Benchmarks improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: (e.g., Claude, CodeRabbit, Ollama, etc., N/A if not used)
  • Generated by: (e.g., tool name and version; N/A if not used)

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • Please provide detailed steps to perform tests related to this code change.
  • How were the fix/results from this change verified? Please provide relevant screenshots or results.

Summary by CodeRabbit

  • New Features

    • Added allowlist-style tool filtering in tool_choice, letting responses restrict available tools by type, server, and name, with explicit handling for file-only and web-only searches.
  • Documentation

    • Clarified how tools and tool_choice are resolved and presented in responses, and updated examples to show filtering semantics and final resolved tool lists.
  • Tests

    • Expanded unit tests to cover allowlist filtering, resolution outcomes, and edge cases for tool selection.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Implements allowlist-based tool filtering for tool_choice: adds utilities to match/filter tools by key-valued allowlist entries (including MCP-specific rules), updates resolve_tool_choice control flow to apply filtering and early-exit cases, and documents the new allowlist semantics with tests.

Changes

Cohort / File(s) Summary
Documentation
docs/responses.md
Clarified tool_choice.allowed_tools semantics: tools is now an array of key-valued filter objects matched against the request's configured tools; updated examples and response-spec text to state tools/tool_choice reflect the internally resolved, filtered configuration.
Core Implementation
src/utils/responses.py
Added allowlist filtering utilities (tool_matches_allowed_entry, group_mcp_tools_by_server, mcp_strip_name_from_allowlist_entries, mcp_project_allowed_tools_to_names, filter_tools_by_allowed_entries) and integrated AllowedTools handling into resolve_tool_choice (early return for none, mapping allowed filters, filtering prepared/explicit tools, and clearing/returning (None, None, None) when filtering excludes all tools).
Tests
tests/unit/utils/test_responses.py
Expanded unit tests to cover resolve_tool_choice and filter_tools_by_allowed_entries, including MCP server/name rules, file_search/web_search distinctions, function matching, allowed-tools OR semantics, and early-exit behaviors (many new cases added).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Resolver as resolve_tool_choice
    participant Prep as prepare_tools
    participant Filter as filter_tools_by_allowed_entries
    participant Registry as ToolsRegistry

    Client->>Resolver: call resolve_tool_choice(request, tool_choice, tools?)
    Resolver->>Prep: prepare tools (if tools omitted) / translate provided tools
    Prep-->>Resolver: prepared_tools (or None)
    Resolver->>Filter: apply allowed_filters (if present) to prepared_tools
    Filter->>Registry: match tool entries against configured tools
    Registry-->>Filter: matched tools (with MCP-name narrowing)
    Filter-->>Resolver: filtered_tools (or empty)
    alt filtered_tools empty
        Resolver-->>Client: return (None, None, None)
    else
        Resolver->>Resolver: derive vector_store_ids, set prepared_tool_choice
        Resolver-->>Client: return (prepared_tools, vector_store_ids, prepared_tool_choice)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title references the ticket ID (LCORE-1262) but lacks specificity about the main change—resolving allowed tools filters locally instead of passing to LLS. Consider revising to be more descriptive, e.g., 'Resolve allowed tools filters locally in tool choice' to clarify the core change without requiring ticket lookup.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 97.44% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/responses.md`:
- Around line 407-408: Update the responses docs to keep `tool_choice`
documented as "string or object" (not just string) so clients know handlers may
pass through specific tool-choice objects (e.g., `file_search`, `function`,
`mcp`) while only `allowed_tools` is normalized to `auto`/`required`; modify the
table row for `tool_choice` to show "string or object" and add a short note
clarifying that `allowed_tools` is collapsed but handlers can still emit
structured tool-choice objects for normal/blocked responses.

In `@src/utils/responses.py`:
- Around line 1411-1423: The condition "if tools:" conflates None with an
explicit empty list; change the logic to check for presence vs explicit disable
by using "if tools is not None:" and explicitly handle the empty list case (when
tools == [] return the disabled result: None, None, None) before calling
prepare_tools()/translate_tools_vector_store_ids/filter_tools_by_allowed_entries/extract_vector_store_ids
and setting prepared_tool_choice (tool_choice or ToolChoiceMode.auto); apply the
same fix to the other analogous block that also inspects tools (the block around
the later use at 1425-1440).
- Around line 423-463: The allowlist matcher must handle MCP server tools
specially: update _tool_matches_allowed_entry to detect MCP tools (e.g.,
isinstance(tool, OpenAIResponseInputToolMCP) or tool.type == "mcp") and, when
the allowlist entry includes a "name" key, verify the entry's server_label/type
match the tool and that the entry["name"] is present in tool.allowed_tools
(treat string attr comparison accordingly) instead of checking a non-existent
top-level name attribute; additionally, change filter_tools_by_allowed_entries
so that when an MCP tool matches an entry that narrows by name it returns a
projected copy of that tool with allowed_tools filtered to only the matching
names (preserving non-MCP behavior for other entries and tools).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3b0c82c0-73f4-4d76-8668-d74645d34708

📥 Commits

Reviewing files that changed from the base of the PR and between 409cdc2 and 88711a8.

📒 Files selected for processing (4)
  • docs/responses.md
  • src/app/endpoints/responses.py
  • src/utils/responses.py
  • tests/unit/utils/test_responses.py

@asimurka asimurka force-pushed the responses_implement_allowed_tools_filtering branch from 88711a8 to 2efc922 Compare March 27, 2026 14:13
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
docs/responses.md (1)

283-288: Grammar: Use hyphen for compound adjective.

Per static analysis, "file only search" should be "file-only search" (compound adjective).

📝 Proposed fix
-- `allowed_tools`: Restrict to a list of tool definitions; `mode` is `"auto"` or `"required"`, `tools` is a list of key-valued filters for tools configured by `tools` attribute.
-- `file_search`: Force the model to use file only search.
-- `web_search`: Force the model to use only web search.
+- `allowed_tools`: Restrict to a list of tool definitions; `mode` is `"auto"` or `"required"`, `tools` is a list of key-valued filters for tools configured by `tools` attribute.
+- `file_search`: Force the model to use file-only search.
+- `web_search`: Force the model to use web-only search.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/responses.md` around lines 283 - 288, The phrase "Force the model to use
file only search" in the `file_search` bullet is missing a hyphen; update the
`file_search` description to read "Force the model to use file-only search" so
the compound adjective is correct (locate the `file_search` entry in
docs/responses.md and apply the change).
src/utils/responses.py (1)

555-558: Fix typo in comment.

Line 555: "handler" should be "handled".

📝 Proposed fix
-        # Non-MCP tools pass through and are handler separately
+        # Non-MCP tools pass through and are handled separately
         if tool.type != "mcp":
             filtered.append(tool)
             continue
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/responses.py` around lines 555 - 558, Fix the typo in the comment
above the MCP filter: change "handler" to "handled" in the comment that reads "#
Non-MCP tools pass through and are handler separately" in src/utils/responses.py
so it correctly reads "# Non-MCP tools pass through and are handled separately"
near the conditional that checks if tool.type != "mcp" (the
filtered.append(tool); continue block).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/responses.md`:
- Around line 283-288: The phrase "Force the model to use file only search" in
the `file_search` bullet is missing a hyphen; update the `file_search`
description to read "Force the model to use file-only search" so the compound
adjective is correct (locate the `file_search` entry in docs/responses.md and
apply the change).

In `@src/utils/responses.py`:
- Around line 555-558: Fix the typo in the comment above the MCP filter: change
"handler" to "handled" in the comment that reads "# Non-MCP tools pass through
and are handler separately" in src/utils/responses.py so it correctly reads "#
Non-MCP tools pass through and are handled separately" near the conditional that
checks if tool.type != "mcp" (the filtered.append(tool); continue block).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2aa94315-b7cb-453b-b203-25b1b3cefca2

📥 Commits

Reviewing files that changed from the base of the PR and between 88711a8 and 2efc922.

📒 Files selected for processing (4)
  • docs/responses.md
  • src/app/endpoints/responses.py
  • src/utils/responses.py
  • tests/unit/utils/test_responses.py
✅ Files skipped from review due to trivial changes (1)
  • src/app/endpoints/responses.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/utils/test_responses.py

@asimurka asimurka force-pushed the responses_implement_allowed_tools_filtering branch from 2efc922 to 23b4fde Compare March 27, 2026 15:18
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/responses.md`:
- Line 284: Update the documentation line for the `file_search` modifier: change
the phrase "file only search" to the hyphenated compound modifier "file-only
search" so the entry reads "`file_search`: Force the model to use file-only
search." Reference: the `file_search` entry in docs/responses.md.

In `@src/utils/responses.py`:
- Line 555: Fix the typo in the inline comment "# Non-MCP tools pass through and
are handler separately" by changing "handler" to "handled" so the comment reads
"# Non-MCP tools pass through and are handled separately"; locate this exact
comment string in src/utils/responses.py and update it accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 69803068-2398-43aa-8f3c-2e3716705d5b

📥 Commits

Reviewing files that changed from the base of the PR and between 2efc922 and 23b4fde.

📒 Files selected for processing (4)
  • docs/responses.md
  • src/app/endpoints/responses.py
  • src/utils/responses.py
  • tests/unit/utils/test_responses.py
✅ Files skipped from review due to trivial changes (1)
  • src/app/endpoints/responses.py

@asimurka asimurka changed the title Adjust tools resolution LCORE-1262: Resolve allowed tools filters in LCS Mar 27, 2026
@asimurka asimurka force-pushed the responses_implement_allowed_tools_filtering branch 3 times, most recently from 2126ba5 to 06adfc8 Compare March 27, 2026 15:35
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
docs/responses.md (1)

408-409: ⚠️ Potential issue | 🟡 Minor

tool_choice response type is still documented too narrowly.

Line 409 says tool_choice is string, but src/utils/responses.py (resolve_tool_choice, Line 1485-1557) still returns Optional[ToolChoice], and object-shaped choices are validated in tests (tests/unit/utils/test_responses.py, Line 967-984).

Suggested doc correction
-| `tool_choice` | string | Internally resolved tool choice mode |
+| `tool_choice` | string or object | Internally resolved tool choice. `allowed_tools` is normalized to mode (`auto`/`required`), while specific tool-choice objects may still be returned. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/responses.md` around lines 408 - 409, The docs currently list
`tool_choice` as just a string, but resolve_tool_choice in
src/utils/responses.py returns Optional[ToolChoice] (and tests validate
object-shaped choices), so update the responses.md table entry for `tool_choice`
to reflect it can be an object matching the ToolChoice shape or a string (and
may be null/absent); reference the resolve_tool_choice function and the
ToolChoice type when describing the object shape so readers know the expected
fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/responses.md`:
- Line 283: The docs entry for allowed_tools is misleading: it says "list of
tool definitions" but the implementation expects key-value allowlist filter
entries rather than full tool definitions; update the wording for the
allowed_tools field to state that allowed_tools is a filter list (not full tool
definitions), explain that mode is "auto" or "required", and that tools is a
list of key-value filter objects which match configured tools via the tools
attribute (e.g., name, category, or tag filters), so callers know to supply
filter entries rather than entire tool definitions.

---

Duplicate comments:
In `@docs/responses.md`:
- Around line 408-409: The docs currently list `tool_choice` as just a string,
but resolve_tool_choice in src/utils/responses.py returns Optional[ToolChoice]
(and tests validate object-shaped choices), so update the responses.md table
entry for `tool_choice` to reflect it can be an object matching the ToolChoice
shape or a string (and may be null/absent); reference the resolve_tool_choice
function and the ToolChoice type when describing the object shape so readers
know the expected fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fb6c9d44-6d2b-4510-a66f-926499178900

📥 Commits

Reviewing files that changed from the base of the PR and between 23b4fde and 44d0d1f.

📒 Files selected for processing (3)
  • docs/responses.md
  • src/utils/responses.py
  • tests/unit/utils/test_responses.py
✅ Files skipped from review due to trivial changes (1)
  • src/utils/responses.py

@asimurka asimurka force-pushed the responses_implement_allowed_tools_filtering branch 5 times, most recently from 39929d9 to 1a288ae Compare March 30, 2026 06:40
@asimurka asimurka requested a review from tisnik March 30, 2026 06:40
@asimurka asimurka marked this pull request as draft March 30, 2026 06:45
@asimurka asimurka force-pushed the responses_implement_allowed_tools_filtering branch from 1a288ae to 7bec21f Compare March 30, 2026 08:03
@asimurka asimurka force-pushed the responses_implement_allowed_tools_filtering branch from 7bec21f to 9ef5d2e Compare March 30, 2026 08:07
@asimurka asimurka requested a review from are-ces March 30, 2026 08:07
@asimurka asimurka marked this pull request as ready for review March 30, 2026 08:07
responses_request.tool_choice,
vector_store_ids,
) = await resolve_tool_choice(
# Extract vector store IDs for Inline RAG context before resolving tool choice.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done in order to be consistent with recent changes in query endpoints. no_tools or tool_choice in this case should not affect inline RAG vector store selection. That's why tool resolution is done after.

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