Add _model_error_summary and _fallback_content_from_context functions

This commit is contained in:
2026-06-16 19:13:25 +02:00
parent ce21613905
commit abed82924b

View File

@@ -62,6 +62,48 @@ def _collect_sources(blocks: List[Any]) -> List[Any]:
return sources
def _model_error_summary(exc: Exception) -> str:
message = str(exc).strip().splitlines()[0] if str(exc).strip() else type(exc).__name__
return f"{type(exc).__name__}: {message}"
def _fallback_content_from_context(model: str, exc: Exception, context_blocks: List[Any], context_text: str) -> str:
sources = _collect_sources(context_blocks)
if not sources and not context_text.strip():
return ""
lines = [
f"The selected chat model failed before it could compose an answer ({_model_error_summary(exc)}).",
"Retrieved context is still available:",
]
if sources:
for index, source in enumerate(sources[:6], 1):
if isinstance(source, dict):
title = str(source.get("title") or source.get("url") or f"Source {index}").strip()
snippet = str(source.get("snippet") or source.get("text") or "").strip()
url = str(source.get("url") or "").strip()
lines.append(f"[{index}] {title}")
if snippet:
lines.append(snippet[:900])
if url:
lines.append(f"Source: {url}")
else:
lines.append(f"[{index}] {source}")
return "\n\n".join(lines)
cleaned_context = (
context_text
.replace("<websearch_context>", "")
.replace("</websearch_context>", "")
.replace("<chat_memory_context>", "")
.replace("</chat_memory_context>", "")
.strip()
)
if cleaned_context:
lines.append(cleaned_context[:5000])
return "\n\n".join(lines)
def _drop_superseded_trailing_user_rows(rows: List[Any]) -> List[Any]:
if not rows or getattr(rows[-1], "role", None) != "user":
return rows
@@ -85,7 +127,8 @@ def _append_context_to_last_user_message(messages: List[Dict[str, Any]], context
async def chat_handler(arguments: Dict[str, Any], context: ToolExecutionContext) -> Dict[str, Any]:
messages = [dict(item) for item in arguments.get("messages") or []]
context_text = _context_text(arguments.get("context_blocks") or [])
context_blocks = arguments.get("context_blocks") or []
context_text = _context_text(context_blocks)
context_applied = False
if context.session_id:
db = context.db_factory()
@@ -124,25 +167,32 @@ async def chat_handler(arguments: Dict[str, Any], context: ToolExecutionContext)
full_content = ""
full_thinking = ""
usage: Dict[str, int] = {}
async for chunk in chat_stream_typed(
arguments["model"],
messages,
options=arguments.get("generation_options") or {},
think=bool(arguments.get("reasoning")),
cancellation_event=context.cancellation_event,
):
if chunk.thinking:
full_thinking += chunk.thinking
if context.show_thinking:
await context.emit("model_thinking", {"text": chunk.thinking})
if chunk.content:
full_content += chunk.content
await context.emit("model_token", {"text": chunk.content})
if chunk.done:
usage = _usage_dict(chunk.usage)
try:
async for chunk in chat_stream_typed(
arguments["model"],
messages,
options=arguments.get("generation_options") or {},
think=bool(arguments.get("reasoning")),
cancellation_event=context.cancellation_event,
):
if chunk.thinking:
full_thinking += chunk.thinking
if context.show_thinking:
await context.emit("model_thinking", {"text": chunk.thinking})
if chunk.content:
full_content += chunk.content
await context.emit("model_token", {"text": chunk.content})
if chunk.done:
usage = _usage_dict(chunk.usage)
except Exception as exc:
fallback_content = _fallback_content_from_context(arguments["model"], exc, context_blocks, context_text)
if not fallback_content:
raise
full_content = fallback_content
await context.emit("model_token", {"text": full_content})
return {
"content": full_content,
"sources": _collect_sources(arguments.get("context_blocks") or []),
"sources": _collect_sources(context_blocks),
"usage": usage,
"thinking_available": bool(full_thinking),
}