Skip to content

Commit f7095ab

Browse files
mergify[bot]eoinfennessyclaude
authored
fix!: default vector_stores_config to VectorStoresConfig() to prevent file_search crash (backport #5949) (#5951)
When `vector_stores_config` was not set in the responses provider config, `file_search` tool calls crashed with "'NoneType' object has no attribute 'file_search_params'" because the config defaulted to `None`. Since `VectorStoresConfig` has sensible defaults for all fields, default it to `VectorStoresConfig()` in the config. Coerce `None` to `VectorStoresConfig()` in the `ToolExecutor` constructor so that tests do not have to explicitly pass it. Minor breaking change: users that previously set an explicit null value for vector stores config (`vector_stores_config: null`) will now encounter validation errors. This is unlikely to affect anyone. Signed-off-by: Eoin Fennessy <efenness@redhat.com> --- <a href="https://app.devin.ai/review/ogx-ai/ogx/pull/5949" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review"> </picture> </a> <hr>This is an automatic backport of pull request #5949 done by [Mergify](https://mergify.com). <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/ogx-ai/ogx/pull/5951" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review"> </picture> </a> <!-- devin-review-badge-end --> Signed-off-by: Eoin Fennessy <efenness@redhat.com> Co-authored-by: Eoin Fennessy <efenness@redhat.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7bf2d46 commit f7095ab

5 files changed

Lines changed: 45 additions & 20 deletions

File tree

docs/docs/providers/responses/inline_builtin.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Meta's reference implementation of an agent system that can use tools, access ve
2020
| `persistence.responses.backend` | `str` | No | | Name of backend from storage.backends |
2121
| `persistence.responses.max_write_queue_size` | `int` | No | 10000 | Max queued writes for inference store |
2222
| `persistence.responses.num_writers` | `int` | No | 4 | Number of concurrent background writers |
23-
| `vector_stores_config` | `VectorStoresConfig \| None` | No | | Configuration for vector store prompt templates and behavior |
23+
| `vector_stores_config` | `VectorStoresConfig` | No | default_provider_id=None default_embedding_model=None default_reranker_model=None rewrite_query_params=None file_search_params=FileSearchParams(header_template='file_search tool found &#123;num_chunks&#125; chunks:\nBEGIN of file_search tool results.\n', footer_template='END of file_search tool results.\n') context_prompt_params=ContextPromptParams(chunk_annotation_template='Result &#123;index&#125;\nContent: &#123;chunk.content&#125;\nMetadata: &#123;metadata&#125;\n', context_template='The above results were retrieved to help answer the user\'s query: "&#123;query&#125;". Use them as supporting information only in answering this query. &#123;annotation_instruction&#125;\n') annotation_prompt_params=AnnotationPromptParams(enable_annotations=True, annotation_instruction_template="Cite sources immediately at the end of sentences before punctuation, using `&lt;|file-id|&gt;` format like 'This is a fact &lt;|file-Cn3MSNn72ENTiiq11Qda4A|&gt;.'. Do not add extra punctuation. Use only the file IDs provided, do not invent new ones.", chunk_annotation_template='[&#123;index&#125;] &#123;metadata_text&#125; cite as &lt;|&#123;file_id&#125;|&gt;\n&#123;chunk_text&#125;\n') file_ingestion_params=FileIngestionParams(default_chunk_size_tokens=512, default_chunk_overlap_tokens=128) chunk_retrieval_params=ChunkRetrievalParams(chunk_multiplier=5, max_tokens_in_context=4000, default_reranker_strategy='rrf', rrf_impact_factor=60.0, weighted_search_alpha=0.5, default_search_mode='vector') file_batch_params=FileBatchParams(max_concurrent_files_per_batch=3, file_batch_chunk_size=10, cleanup_interval_seconds=86400) contextual_retrieval_params=ContextualRetrievalParams(model=None, default_timeout_seconds=120, default_max_concurrency=3, max_document_tokens=100000) | Configuration for vector store prompt templates and behavior |
2424
| `vector_stores_config.default_provider_id` | `str \| None` | No | | ID of the vector_io provider to use as default when multiple providers are available and none is specified. |
2525
| `vector_stores_config.default_embedding_model` | `QualifiedModel \| None` | No | | Default embedding model configuration for vector stores. |
2626
| `vector_stores_config.default_embedding_model.provider_id` | `str` | No | | |

src/ogx/providers/inline/responses/builtin/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ class BuiltinResponsesImplConfig(BaseModel):
6767

6868
persistence: ResponsesPersistenceConfig
6969

70-
vector_stores_config: VectorStoresConfig | None = Field(
71-
default=None,
70+
vector_stores_config: VectorStoresConfig = Field(
71+
default_factory=VectorStoresConfig,
7272
description="Configuration for vector store prompt templates and behavior",
7373
)
7474

src/ogx/providers/inline/responses/builtin/responses/openai_responses.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from pydantic import TypeAdapter
1616

1717
from ogx.core.conversations.validation import CONVERSATION_ID_PATTERN
18+
from ogx.core.datatypes import VectorStoresConfig
1819
from ogx.core.task import (
1920
RequestContext,
2021
activate_request_context,
@@ -117,7 +118,7 @@ def __init__(
117118
prompts_api: Prompts,
118119
files_api: Files,
119120
connectors_api: Connectors,
120-
vector_stores_config=None,
121+
vector_stores_config: VectorStoresConfig | None = None,
121122
compaction_config=None,
122123
):
123124
self.inference_api = inference_api

src/ogx/providers/inline/responses/builtin/responses/tool_executor.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ def __init__(
5656
tool_groups_api: ToolGroups,
5757
tool_runtime_api: ToolRuntime,
5858
vector_io_api: VectorIO,
59-
vector_stores_config=None,
59+
vector_stores_config: VectorStoresConfig | None = None,
6060
mcp_session_manager=None,
6161
):
6262
self.tool_groups_api = tool_groups_api
6363
self.tool_runtime_api = tool_runtime_api
6464
self.vector_io_api = vector_io_api
65-
self.vector_stores_config = vector_stores_config
65+
self.vector_stores_config = vector_stores_config or VectorStoresConfig()
6666
# Optional MCPSessionManager for session reuse within a request (fix for #4452)
6767
self.mcp_session_manager = mcp_session_manager
6868

@@ -136,14 +136,7 @@ async def _execute_file_search_via_vector_store(
136136
# Create search tasks for all vector stores
137137
async def search_single_store(vector_store_id):
138138
try:
139-
# Use default_search_mode from config if available
140-
search_mode = "vector"
141-
if (
142-
self.vector_stores_config
143-
and hasattr(self.vector_stores_config, "chunk_retrieval_params")
144-
and hasattr(self.vector_stores_config.chunk_retrieval_params, "default_search_mode")
145-
):
146-
search_mode = self.vector_stores_config.chunk_retrieval_params.default_search_mode
139+
search_mode = self.vector_stores_config.chunk_retrieval_params.default_search_mode
147140

148141
search_response = await self.vector_io_api.openai_search_vector_store(
149142
vector_store_id=vector_store_id,
@@ -171,12 +164,7 @@ async def search_single_store(vector_store_id):
171164

172165
# Get templates from vector stores config, fallback to constants
173166

174-
# Check if annotations are enabled
175-
enable_annotations = (
176-
self.vector_stores_config
177-
and self.vector_stores_config.annotation_prompt_params
178-
and self.vector_stores_config.annotation_prompt_params.enable_annotations
179-
)
167+
enable_annotations = self.vector_stores_config.annotation_prompt_params.enable_annotations
180168

181169
# Get templates
182170
header_template = self.vector_stores_config.file_search_params.header_template

tests/unit/providers/responses/builtin/test_openai_responses_tools.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,42 @@ async def test_file_search_results_include_chunk_metadata_attributes(mock_vector
558558
]
559559

560560

561+
async def test_file_search_works_without_explicit_vector_stores_config(mock_vector_io_api):
562+
"""Test that file_search works when vector_stores_config is not passed to ToolExecutor."""
563+
query = "What is machine learning?"
564+
vector_store_id = "test_vector_store"
565+
566+
mock_vector_io_api.openai_search_vector_store.return_value = VectorStoreSearchResponsePage(
567+
search_query=[query],
568+
has_more=False,
569+
data=[
570+
VectorStoreSearchResponse(
571+
file_id="doc-123",
572+
filename="ml-intro.md",
573+
content=[VectorStoreContent(type="text", text="Machine learning is a subset of AI")],
574+
score=0.95,
575+
attributes={},
576+
),
577+
],
578+
)
579+
580+
tool_executor = ToolExecutor(
581+
tool_groups_api=None, # type: ignore
582+
tool_runtime_api=None, # type: ignore
583+
vector_io_api=mock_vector_io_api,
584+
mcp_session_manager=None,
585+
)
586+
587+
file_search_tool = OpenAIResponseInputToolFileSearch(vector_store_ids=[vector_store_id])
588+
result = await tool_executor._execute_file_search_via_vector_store(
589+
query=query,
590+
response_file_search_tool=file_search_tool,
591+
)
592+
593+
mock_vector_io_api.openai_search_vector_store.assert_called_once()
594+
assert result.content is not None
595+
596+
561597
async def test_tool_call_arguments_arrive_in_subsequent_delta(openai_responses_impl, mock_inference_api):
562598
"""Test that tool call arguments are correctly accumulated when the model streams
563599
arguments=None in the first delta and actual arguments in a subsequent delta.

0 commit comments

Comments
 (0)