Skip to content

Commit 0291e11

Browse files
committed
coderabbit
1 parent 12becc5 commit 0291e11

File tree

3 files changed

+49
-17
lines changed

3 files changed

+49
-17
lines changed

src/utils/metadata.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,16 @@ def process_knowledge_search_content(tool_response: Any) -> dict[str, dict[str,
128128
try:
129129
content = json.loads(content, strict=False)
130130
except (json.JSONDecodeError, TypeError):
131-
# If JSON parsing fails or content is still a string, return empty
132-
if isinstance(content, str):
133-
return metadata_map
131+
# If JSON parsing fails, try parsing as metadata text
132+
try:
133+
parsed_metadata = parse_knowledge_search_metadata(content, strict=False)
134+
metadata_map.update(parsed_metadata)
135+
except ValueError as e:
136+
logger.exception(
137+
"Error processing string content as metadata; position=%s",
138+
getattr(e, "position", "unknown"),
139+
)
140+
return metadata_map
134141

135142
# Ensure content is iterable (but not a string)
136143
if isinstance(content, str):

tests/unit/app/endpoints/test_query.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,7 +1592,7 @@ def test_evaluate_model_hints(
15921592
assert model_id == expected_model
15931593

15941594

1595-
def testprocess_knowledge_search_content_with_valid_metadata(mocker):
1595+
def test_process_knowledge_search_content_with_valid_metadata(mocker):
15961596
"""Test process_knowledge_search_content with valid metadata."""
15971597
# Mock tool response with valid metadata
15981598
text_content_item = mocker.Mock()
@@ -1613,7 +1613,7 @@ def testprocess_knowledge_search_content_with_valid_metadata(mocker):
16131613
assert metadata_map["doc-1"]["document_id"] == "doc-1"
16141614

16151615

1616-
def testprocess_knowledge_search_content_with_invalid_metadata_syntax_error(mocker):
1616+
def test_process_knowledge_search_content_with_invalid_metadata_syntax_error(mocker):
16171617
"""Test process_knowledge_search_content gracefully handles SyntaxError."""
16181618
# Mock tool response with invalid metadata (invalid Python syntax)
16191619
text_content_item = mocker.Mock()
@@ -1631,7 +1631,7 @@ def testprocess_knowledge_search_content_with_invalid_metadata_syntax_error(mock
16311631
assert len(metadata_map) == 0
16321632

16331633

1634-
def testprocess_knowledge_search_content_with_invalid_metadata_value_error(mocker):
1634+
def test_process_knowledge_search_content_with_invalid_metadata_value_error(mocker):
16351635
"""Test process_knowledge_search_content gracefully handles ValueError from invalid metadata."""
16361636
# Mock tool response with invalid metadata containing complex expressions
16371637
text_content_item = mocker.Mock()
@@ -1649,7 +1649,7 @@ def testprocess_knowledge_search_content_with_invalid_metadata_value_error(mocke
16491649
assert len(metadata_map) == 0
16501650

16511651

1652-
def testprocess_knowledge_search_content_with_non_dict_metadata(mocker):
1652+
def test_process_knowledge_search_content_with_non_dict_metadata(mocker):
16531653
"""Test process_knowledge_search_content handles non-dict metadata gracefully."""
16541654
mock_logger = mocker.patch("app.endpoints.query.logger")
16551655

@@ -1672,7 +1672,7 @@ def testprocess_knowledge_search_content_with_non_dict_metadata(mocker):
16721672
mock_logger.exception.assert_not_called()
16731673

16741674

1675-
def testprocess_knowledge_search_content_with_metadata_missing_document_id(mocker):
1675+
def test_process_knowledge_search_content_with_metadata_missing_document_id(mocker):
16761676
"""Test process_knowledge_search_content skips metadata without document_id."""
16771677
# Mock tool response with valid metadata but missing document_id
16781678
text_content_item = mocker.Mock()
@@ -1690,7 +1690,7 @@ def testprocess_knowledge_search_content_with_metadata_missing_document_id(mocke
16901690
assert len(metadata_map) == 0
16911691

16921692

1693-
def testprocess_knowledge_search_content_with_no_text_attribute(mocker):
1693+
def test_process_knowledge_search_content_with_no_text_attribute(mocker):
16941694
"""Test process_knowledge_search_content skips content items without text attribute."""
16951695
# Mock tool response with content item that has no text attribute
16961696
text_content_item = mocker.Mock(spec=[]) # spec=[] means no attributes
@@ -1704,7 +1704,7 @@ def testprocess_knowledge_search_content_with_no_text_attribute(mocker):
17041704
assert len(metadata_map) == 0
17051705

17061706

1707-
def testprocess_knowledge_search_content_with_none_content(mocker):
1707+
def test_process_knowledge_search_content_with_none_content(mocker):
17081708
"""Test process_knowledge_search_content handles tool_response with content=None."""
17091709
# Mock tool response with content = None
17101710
tool_response = mocker.Mock()
@@ -1716,7 +1716,7 @@ def testprocess_knowledge_search_content_with_none_content(mocker):
17161716
assert len(metadata_map) == 0
17171717

17181718

1719-
def testprocess_knowledge_search_content_duplicate_document_id_last_wins(mocker):
1719+
def test_process_knowledge_search_content_duplicate_document_id_last_wins(mocker):
17201720
"""The last metadata block for a given document_id should win."""
17211721
text_items = [
17221722
mocker.Mock(
@@ -1747,7 +1747,7 @@ def testprocess_knowledge_search_content_duplicate_document_id_last_wins(mocker)
17471747
assert docs[0].doc_title == "Second"
17481748

17491749

1750-
def testprocess_knowledge_search_content_with_braces_inside_strings(mocker):
1750+
def test_process_knowledge_search_content_with_braces_inside_strings(mocker):
17511751
"""Test that braces inside strings are handled correctly."""
17521752
text_content_item = mocker.Mock()
17531753
text_content_item.text = (
@@ -1766,7 +1766,7 @@ def testprocess_knowledge_search_content_with_braces_inside_strings(mocker):
17661766
assert metadata_map["doc-100"]["extra"]["note"] == "contains {braces}"
17671767

17681768

1769-
def testprocess_knowledge_search_content_with_nested_objects(mocker):
1769+
def test_process_knowledge_search_content_with_nested_objects(mocker):
17701770
"""Test that nested objects are parsed correctly."""
17711771
text_content_item = mocker.Mock()
17721772
text_content_item.text = (
@@ -1785,6 +1785,33 @@ def testprocess_knowledge_search_content_with_nested_objects(mocker):
17851785
assert metadata_map["doc-200"]["meta"]["k"]["inner"] == 1
17861786

17871787

1788+
def test_process_knowledge_search_content_with_string_fallback_parsing(mocker):
1789+
"""Test that string content uses parse_knowledge_search_metadata as fallback."""
1790+
# Create a tool response with string content containing metadata
1791+
string_content = """Result 1
1792+
Content: Test content
1793+
Metadata: {'docs_url': 'https://example.com/fallback', 'title': 'Fallback Doc', 'document_id': 'fallback-1'}
1794+
1795+
Result 2
1796+
Content: More content
1797+
Metadata: {'docs_url': 'https://example.com/fallback2', 'title': 'Fallback Doc 2', 'document_id': 'fallback-2'}
1798+
"""
1799+
1800+
tool_response = mocker.Mock()
1801+
tool_response.content = string_content # String instead of list
1802+
1803+
metadata_map = process_knowledge_search_content(tool_response)
1804+
1805+
# Verify fallback parsing worked correctly
1806+
assert len(metadata_map) == 2
1807+
assert "fallback-1" in metadata_map
1808+
assert "fallback-2" in metadata_map
1809+
assert metadata_map["fallback-1"]["title"] == "Fallback Doc"
1810+
assert metadata_map["fallback-1"]["docs_url"] == "https://example.com/fallback"
1811+
assert metadata_map["fallback-2"]["title"] == "Fallback Doc 2"
1812+
assert metadata_map["fallback-2"]["docs_url"] == "https://example.com/fallback2"
1813+
1814+
17881815
@pytest.mark.asyncio
17891816
async def test_retrieve_response_with_none_content(prepare_agent_mocks, mocker):
17901817
"""Test retrieve_response handles None content gracefully."""

tests/unit/app/endpoints/test_streaming_query.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,10 +1046,8 @@ def test_stream_build_event_knowledge_search_with_invalid_metadata(mocker):
10461046
# Verify the function still returns tool execution events
10471047
assert len(result_list) == 2 # One for tool_calls, one for tool_responses
10481048

1049-
# Verify exception logging was called
1050-
mock_logger.exception.assert_called_once()
1051-
args = mock_logger.exception.call_args[0]
1052-
assert "An exception was thrown in processing" in args[0]
1049+
# Verify no exception logging was called in non-strict mode
1050+
mock_logger.exception.assert_not_called()
10531051

10541052

10551053
def test_stream_end_event_with_referenced_documents():

0 commit comments

Comments
 (0)