|
22 | 22 | store_transcript, |
23 | 23 | get_rag_toolgroups, |
24 | 24 | evaluate_model_hints, |
| 25 | +) |
| 26 | +from utils.metadata import ( |
| 27 | + process_knowledge_search_content, |
25 | 28 | extract_referenced_documents_from_steps, |
26 | 29 | ) |
27 | | -from utils.metadata import process_knowledge_search_content |
28 | 30 |
|
29 | 31 | from models.requests import QueryRequest, Attachment |
30 | 32 | from models.config import ModelContextProtocolServer |
@@ -270,6 +272,10 @@ async def test_query_endpoint_handler_with_referenced_documents(mocker): |
270 | 272 | ] |
271 | 273 | assert all(isinstance(d, ReferencedDocument) for d in response.referenced_documents) |
272 | 274 | assert len(response.referenced_documents) == 2 |
| 275 | + # Titles should be sorted deterministically by doc_title |
| 276 | + assert [d.doc_title for d in response.referenced_documents] == sorted( |
| 277 | + [d.doc_title for d in response.referenced_documents] |
| 278 | + ) |
273 | 279 |
|
274 | 280 | # Assert the metric for successful LLM calls is incremented |
275 | 281 | mock_metric.labels("fake_provider_id", "fake_model_id").inc.assert_called_once() |
@@ -1317,7 +1323,6 @@ async def test_query_endpoint_handler_no_tools_true(mocker): |
1317 | 1323 | ] |
1318 | 1324 |
|
1319 | 1325 | mock_config = mocker.Mock() |
1320 | | - mock_config.user_data_collection_configuration.transcripts_disabled = True |
1321 | 1326 | mocker.patch("app.endpoints.query.configuration", mock_config) |
1322 | 1327 |
|
1323 | 1328 | llm_response = "LLM answer without tools" |
@@ -1356,7 +1361,6 @@ async def test_query_endpoint_handler_no_tools_false(mocker): |
1356 | 1361 | ] |
1357 | 1362 |
|
1358 | 1363 | mock_config = mocker.Mock() |
1359 | | - mock_config.user_data_collection_configuration.transcripts_disabled = True |
1360 | 1364 | mocker.patch("app.endpoints.query.configuration", mock_config) |
1361 | 1365 |
|
1362 | 1366 | llm_response = "LLM answer with tools" |
@@ -1651,7 +1655,7 @@ def test_process_knowledge_search_content_with_invalid_metadata_value_error(mock |
1651 | 1655 |
|
1652 | 1656 | def test_process_knowledge_search_content_with_non_dict_metadata(mocker): |
1653 | 1657 | """Test process_knowledge_search_content handles non-dict metadata gracefully.""" |
1654 | | - mock_logger = mocker.patch("app.endpoints.query.logger") |
| 1658 | + mock_logger = mocker.patch("utils.metadata.logger") |
1655 | 1659 |
|
1656 | 1660 | # Mock tool response with metadata that's not a dict |
1657 | 1661 | text_content_item = mocker.Mock() |
@@ -1812,6 +1816,24 @@ def test_process_knowledge_search_content_with_string_fallback_parsing(mocker): |
1812 | 1816 | assert metadata_map["fallback-2"]["docs_url"] == "https://example.com/fallback2" |
1813 | 1817 |
|
1814 | 1818 |
|
| 1819 | +def test_process_knowledge_search_content_metadata_label_case_insensitive(mocker): |
| 1820 | + """Test that metadata labels are detected case-insensitively.""" |
| 1821 | + text_content_item = mocker.Mock() |
| 1822 | + text_content_item.text = ( |
| 1823 | + "Result 1\n" |
| 1824 | + "Content: Test content\n" |
| 1825 | + "metadata: {'document_id': 'doc-ci', 'title': 'Case Insensitive', 'docs_url': 'https://example.com/ci'}\n" |
| 1826 | + ) |
| 1827 | + tool_response = mocker.Mock() |
| 1828 | + tool_response.content = [text_content_item] |
| 1829 | + |
| 1830 | + metadata_map = process_knowledge_search_content(tool_response) |
| 1831 | + |
| 1832 | + assert "doc-ci" in metadata_map |
| 1833 | + assert metadata_map["doc-ci"]["title"] == "Case Insensitive" |
| 1834 | + assert metadata_map["doc-ci"]["docs_url"] == "https://example.com/ci" |
| 1835 | + |
| 1836 | + |
1815 | 1837 | @pytest.mark.asyncio |
1816 | 1838 | async def test_retrieve_response_with_none_content(prepare_agent_mocks, mocker): |
1817 | 1839 | """Test retrieve_response handles None content gracefully.""" |
@@ -1994,7 +2016,7 @@ async def test_retrieve_response_skips_invalid_docs_url(prepare_agent_mocks, moc |
1994 | 2016 | mock_tool_response.call_id = "c1" |
1995 | 2017 | mock_tool_response.tool_name = "knowledge_search" |
1996 | 2018 | mock_tool_response.content = [ |
1997 | | - mocker.Mock(text=s, type="text") for s in invalid_docs_url_results |
| 2019 | + TextContentItem(text=s, type="text") for s in invalid_docs_url_results |
1998 | 2020 | ] |
1999 | 2021 |
|
2000 | 2022 | mock_tool_execution_step = mocker.Mock() |
|
0 commit comments