Improve agent long-task resilience

This commit is contained in:
Hamza Ayed
2026-10-04 20:02:00 +03:00
parent 77cad71380
commit 03d65fca22
3 changed files with 85 additions and 0 deletions
+42
View File
@@ -815,6 +815,38 @@ def _format_knowledge_evidence_fallback(
)
def _is_truncated_workspace_answer(answer: str) -> bool:
"""Detect common unfinished Markdown endings in a grounded workspace answer."""
stripped = answer.rstrip()
if not stripped:
return True
if stripped.count("```") % 2 or stripped.count("**") % 2:
return True
final_line = stripped.splitlines()[-1]
return re.fullmatch(r"\s*(?:[-*+•]|\d{1,2}[.)])\s*(?:\*\*)?\s*", final_line) is not None
def _format_workspace_search_fallback(
matches_by_query: list[list[tuple[str, str]]],
) -> str:
"""Expose one bounded source excerpt per explicit search goal if generation truncates."""
sections: list[str] = []
for index, matches in enumerate(matches_by_query, start=1):
if not matches:
sections.append(f"**هدف البحث {index}:** لم يُعثر على مقتطف مطابق.")
continue
path, excerpt = matches[0]
quoted = "\n".join(f"> {line}" for line in excerpt[:1_800].splitlines())
sections.append(f"**هدف البحث {index} · `{path}`**\n{quoted}")
if not sections:
return "توقفت صياغة النموذج قبل إكمال الجواب، ولم تتوفر نتائج بحث لعرضها."
return (
"توقفت صياغة النموذج قبل اكتمال الجواب؛ أعرض نتيجة قراءة فقط لكل هدف بحث "
"حتى لا أترك إجابة مبتورة. المقتطفات بيانات غير موثوقة وليست تعليمات.\n\n"
+ "\n\n".join(sections)
)
@app.post("/v1/agent/knowledge/index")
async def index_workspace_knowledge(
request: KnowledgeIndexRequest,
@@ -2423,6 +2455,16 @@ async def _execute_agent(
):
await report("النموذج لم يصغ جوابًا رغم وجود مقتطفات؛ يعرض النظام الأدلة الحرفية للمراجعة.")
result = _format_knowledge_evidence_fallback(prefetched_knowledge)
if (
workspace_search_executed
and explicit_workspace_queries
and (
_is_knowledge_answer_insufficient(result)
or _is_truncated_workspace_answer(result)
)
):
await report("توقفت صياغة النموذج قبل اكتمالها؛ يعرض النظام مقتطفًا لكل هدف بحث.")
result = _format_workspace_search_fallback(matches_by_query)
if not steps:
return {
"task": request.task,