Skip to content

Commit 3474ae3

Browse files
lesebclaudemergify[bot]
authored
refactor: decouple file_search from legacy knowledge_search tool_groups (#5175)
## Summary Decouples the Responses API's `file_search` tool from the legacy `knowledge_search` tool_groups infrastructure. **Before**: When a user passed `{"type": "file_search"}`, the code looked up `knowledge_search` from the `builtin::rag` tool group registry and presented it to the LLM under that name. This required `builtin::rag` to be registered at startup and showed `knowledge_search` in tracing spans. **After**: The Responses API creates an inline tool definition with the name `file_search` — matching the OpenAI convention. No dependency on `builtin::rag` for the Responses API path. Backward compatibility preserved: `knowledge_search` still works if used directly. ### Changes **`streaming.py`**: - `file_search` tool type now creates an inline `ChatCompletionToolParam` with name `"file_search"` instead of looking up `knowledge_search` from tool_groups - Added `"file_search"` to `_SERVER_SIDE_BUILTIN_TOOL_NAMES` - Output item events match both `"knowledge_search"` and `"file_search"` **`tool_executor.py`**: - All 6 places that checked `== "knowledge_search"` now use `in ("knowledge_search", "file_search")` - Tracer span uses `function_name` dynamically instead of hardcoded `"knowledge_search"` **Recordings**: 44 new recordings for file_search tests with the updated tool name. ### Why - Removes unnecessary coupling to `builtin::rag` tool group registration - LLM now sees `file_search` (matching OpenAI convention) instead of the non-standard `knowledge_search` - Tracing spans correctly show `file_search` - Related to #3901 (closed without merge — this is a more surgical approach) ## Test Plan - All 144 unit tests in `tests/unit/providers/agents/builtin/` pass - Integration test recordings re-generated against OpenAI --------- Signed-off-by: Sébastien Han <seb@redhat.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent e516ada commit 3474ae3

File tree

91 files changed

+102671
-13
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+102671
-13
lines changed

src/llama_stack/providers/inline/agents/builtin/responses/streaming.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114

115115
# Built-in tool names that the server knows how to execute itself.
116116
# Anything else is either a registered function tool (client-side) or a hallucinated name.
117-
_SERVER_SIDE_BUILTIN_TOOL_NAMES = frozenset({"web_search", "knowledge_search"})
117+
_SERVER_SIDE_BUILTIN_TOOL_NAMES = frozenset({"web_search", "knowledge_search", "file_search"})
118118

119119
# Maps OpenAI Chat Completions error codes to Responses API error codes
120120
_RESPONSES_API_ERROR_CODES = {
@@ -1299,7 +1299,7 @@ async def _coordinate_tool_execution(
12991299
id=matching_item_id,
13001300
status="in_progress",
13011301
)
1302-
elif tool_call.function.name == "knowledge_search":
1302+
elif tool_call.function.name in ("knowledge_search", "file_search"):
13031303
item = OpenAIResponseOutputMessageFileSearchToolCall(
13041304
id=matching_item_id,
13051305
status="in_progress",
@@ -1417,11 +1417,22 @@ def make_openai_tool(tool_name: str, tool: ToolDef) -> ChatCompletionToolParam:
14171417
raise ValueError(f"Tool {tool_name} not found")
14181418
self.ctx.chat_tools.append(make_openai_tool(tool_name, tool))
14191419
elif input_tool.type == "file_search":
1420-
tool_name = "knowledge_search"
1421-
tool = await self.tool_executor.tool_groups_api.get_tool(tool_name)
1422-
if not tool:
1423-
raise ValueError(f"Tool {tool_name} not found")
1424-
self.ctx.chat_tools.append(make_openai_tool(tool_name, tool))
1420+
tool_name = "file_search"
1421+
file_search_tool_def = ToolDef(
1422+
name=tool_name,
1423+
description="Search files for relevant information",
1424+
input_schema={
1425+
"type": "object",
1426+
"properties": {
1427+
"query": {
1428+
"type": "string",
1429+
"description": "The search query",
1430+
},
1431+
},
1432+
"required": ["query"],
1433+
},
1434+
)
1435+
self.ctx.chat_tools.append(make_openai_tool(tool_name, file_search_tool_def))
14251436
elif input_tool.type == "mcp":
14261437
async for stream_event in self._process_mcp_tool(input_tool, output_messages):
14271438
yield stream_event

src/llama_stack/providers/inline/agents/builtin/responses/tool_executor.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ async def _emit_progress_events(
275275
),
276276
sequence_number=sequence_number,
277277
)
278-
elif function_name == "knowledge_search":
278+
elif function_name in ("knowledge_search", "file_search"):
279279
sequence_number += 1
280280
yield ToolExecutionResult(
281281
stream_event=OpenAIResponseObjectStreamResponseFileSearchCallInProgress(
@@ -299,7 +299,7 @@ async def _emit_progress_events(
299299
)
300300

301301
# For file search, emit searching event
302-
if function_name == "knowledge_search":
302+
if function_name in ("knowledge_search", "file_search"):
303303
sequence_number += 1
304304
yield ToolExecutionResult(
305305
stream_event=OpenAIResponseObjectStreamResponseFileSearchCallSearching(
@@ -343,7 +343,7 @@ async def _execute_tool(
343343
authorization=mcp_tool.authorization,
344344
session_manager=self.mcp_session_manager,
345345
)
346-
elif function_name == "knowledge_search":
346+
elif function_name in ("knowledge_search", "file_search"):
347347
response_file_search_tool = (
348348
next(
349349
(t for t in ctx.response_tools if isinstance(t, OpenAIResponseInputToolFileSearch)),
@@ -356,7 +356,7 @@ async def _execute_tool(
356356
# Use vector_stores.search API instead of knowledge_search tool
357357
# to support filters and ranking_options
358358
query = tool_kwargs.get("query", "")
359-
with tracer.start_as_current_span("knowledge_search"):
359+
with tracer.start_as_current_span(function_name):
360360
result = await self._execute_knowledge_search_via_vector_store(
361361
query=query,
362362
response_file_search_tool=response_file_search_tool,
@@ -408,7 +408,7 @@ async def _emit_completion_events(
408408
sequence_number=sequence_number,
409409
)
410410
yield ToolExecutionResult(stream_event=web_completion_event, sequence_number=sequence_number)
411-
elif function_name == "knowledge_search":
411+
elif function_name in ("knowledge_search", "file_search"):
412412
sequence_number += 1
413413
file_completion_event = OpenAIResponseObjectStreamResponseFileSearchCallCompleted(
414414
item_id=item_id,
@@ -465,7 +465,7 @@ async def _build_result_messages(
465465
)
466466
if has_error:
467467
message.status = "failed"
468-
elif function.name == "knowledge_search":
468+
elif function.name in ("knowledge_search", "file_search"):
469469
message = OpenAIResponseOutputMessageFileSearchToolCall(
470470
id=item_id,
471471
queries=[tool_kwargs.get("query", "")],

0 commit comments

Comments
 (0)