feat: surface retrieved evidence when agent abstains

This commit is contained in:
Hamza Ayed
2026-10-04 10:43:48 +03:00
parent 472ccc41ac
commit 76567d4b47
8 changed files with 357 additions and 5 deletions
@@ -17,6 +17,7 @@ from app.main import (
AgentRequest,
_execute_agent,
_knowledge_context_for_model,
_is_knowledge_answer_insufficient,
app,
safe_arithmetic,
select_workspace_file_excerpt,
@@ -247,6 +248,44 @@ class AgentSkillTests(unittest.TestCase):
self.assertEqual(result["tool"], "search_knowledge")
self.assertEqual(result["files"], ["ROADMAP.md"])
def test_knowledge_refusal_falls_back_to_bounded_cited_evidence(self) -> None:
match = {
"path": "migration.md",
"chunk": 0,
"text": "The SQLite migration adds selected_version to old messages and preserves saved assistant answer versions.",
}
refusal = "لم يتم العثور على مقاطع تجيب مباشرة على السؤال في فهرس المعرفة المحلي."
with (
patch(
"app.main._search_local_knowledge",
new=AsyncMock(return_value=([match], "keyword")),
),
patch(
"app.main.get_completion",
new=AsyncMock(return_value={"choices": [{"message": {"content": refusal}}]}),
),
):
result = asyncio.run(
_execute_agent(
AgentRequest(
task=(
"ابحث في فهرس المعرفة المحلي عن المقاطع التي تجيب عن السؤال، "
"ثم أجب استنادًا إلى المقاطع فقط. السؤال: "
"How are old conversation answers migrated?"
),
workspace_path=self.workspace,
)
)
)
citation_only = "المقطع `routing.md`, المقطع 0."
self.assertTrue(_is_knowledge_answer_insufficient(refusal))
self.assertTrue(_is_knowledge_answer_insufficient(citation_only))
self.assertFalse(_is_knowledge_answer_insufficient("تضيف الهجرة selected_version."))
self.assertIn("لم يصغ النموذج جوابًا كافيًا رغم وجود نتائج", result["result"])
self.assertIn("migration.md · المقطع 0", result["result"])
self.assertIn("> The SQLite migration adds selected_version", result["result"])
def test_test_plan_skill_only_advertises_workspace_search(self) -> None:
completion = {"choices": [{"message": {"content": "ثلاث حالات اختبار مقترحة."}}]}
with patch("app.main.get_completion", new=AsyncMock(return_value=completion)) as model: