fix(memory): reject ambiguous multi-object outputs during skill extraction (#3985)

This commit is contained in:
Vishnu
2026-06-15 16:14:43 +05:30
committed by GitHub
parent 8fe98cf471
commit 933ec8fec9
3 changed files with 87 additions and 26 deletions
+15
View File
@@ -41,3 +41,18 @@ def test_non_object_json_returns_none():
def test_empty_input_returns_none():
assert skill_extractor._extract_json_object("") is None
def test_multiple_objects_returns_none():
# Two complete valid non-overlapping JSON objects should return None (fail closed).
resp = '{"title": "Restart", "steps": []} and {"title": "Stop", "steps": []}'
assert skill_extractor._extract_json_object(resp) is None
def test_trailing_stray_brace_is_recovered():
# A single valid JSON object followed by trailing text containing a stray brace should be recovered.
resp = '{"title": "Restart the service", "steps": ["a"]} }'
data = skill_extractor._extract_json_object(resp)
assert isinstance(data, dict)
assert data["title"] == "Restart the service"
+30
View File
@@ -115,3 +115,33 @@ async def test_maybe_extract_skill_drops_when_no_candidate_parses(monkeypatch):
assert entry is None
assert not skills_manager.added
async def test_maybe_extract_skill_drops_on_multiple_json_objects(monkeypatch):
# Two valid JSON objects should be rejected by maybe_extract_skill.
resp = (
'{"title": "Deploy runbook", "problem": "manual", "solution": "script", '
'"steps": ["build"], "tags": ["deploy"], "confidence": 0.9}\n'
'{"title": "Unrelated skill", "problem": "manual", "solution": "script", '
'"steps": ["build"], "tags": ["deploy"], "confidence": 0.9}'
)
async def fake_llm_call_async(*args, **kwargs):
return resp
monkeypatch.setattr("src.llm_core.llm_call_async", fake_llm_call_async)
skills_manager = _FakeSkillsManager()
entry = await skill_extractor.maybe_extract_skill(
_FakeSession(),
skills_manager,
endpoint_url="http://endpoint",
model="test-model",
headers={},
round_count=3,
tool_count=3,
owner="alice",
)
assert entry is None
assert not skills_manager.added