fix: give final acceptance a shared retry budget and diagnostics
This commit is contained in:
1 parent
50638d4130
commit
32441e79c4
18 files changed
+779
-40
No files matched your search
@@ -13,6 +13,8 @@ from uuid import uuid4
|
||||
from PIL import Image
|
||||
|
||||
from artemis.data_engine.context_vars import CURRENT_NODE_NAME, CURRENT_TRACE_ID
|
||||
from artemis.llm.final_review import ACTIVE_FINAL_REVIEW, FinalReviewBudgetExceeded
|
||||
from artemis.llm.reliability import LLMExhaustedError
|
||||
from artemis.llm.usage import usage_from_message
|
||||
from artemis.llm.stream_guard import ToolArgumentOverflow
|
||||
|
||||
@@ -21,6 +23,8 @@ ACTIVE_ATTEMPT: ContextVar["RequestAttempt | None"] = ContextVar("llm_attempt",
|
||||
|
||||
|
||||
def error_text(error: BaseException, timeout: float | None = None) -> str:
|
||||
if isinstance(error, FinalReviewBudgetExceeded):
|
||||
return str(error)
|
||||
if isinstance(error, TimeoutError):
|
||||
return f"模型请求在 {timeout:g} 秒内未完成" if timeout else "模型请求超时"
|
||||
text = str(error).strip() or type(error).__name__
|
||||
@@ -34,6 +38,14 @@ def error_text(error: BaseException, timeout: float | None = None) -> str:
|
||||
return text[:1000]
|
||||
|
||||
|
||||
def final_review_error_text(error: Exception) -> str:
|
||||
if isinstance(error, FinalReviewBudgetExceeded):
|
||||
return str(error)
|
||||
if isinstance(error, LLMExhaustedError):
|
||||
return f"验收模型请求重试已用尽({error.failure.category.value}):{error_text(error)}"
|
||||
return f"{type(error).__name__}: {error_text(error)}"
|
||||
|
||||
|
||||
def input_images(args: tuple, kwargs: dict) -> list[dict]:
|
||||
"""Inspect only inline image headers; never fetch URLs or retain image data."""
|
||||
images = []
|
||||
@@ -76,6 +88,9 @@ class RequestAttempt:
|
||||
self.clock = time.monotonic()
|
||||
self.last_publish = self.clock
|
||||
self.tools: dict[int | str, dict] = {}
|
||||
self.review = ACTIVE_FINAL_REVIEW.get()
|
||||
if self.review:
|
||||
self.review.request_started(request_id, attempt)
|
||||
self.data = {
|
||||
"images": [],
|
||||
**metadata,
|
||||
@@ -102,6 +117,8 @@ class RequestAttempt:
|
||||
self.data["updated_at"] = time.time()
|
||||
self.data["elapsed_seconds"] = round(time.monotonic() - self.clock, 3)
|
||||
self.last_publish = time.monotonic()
|
||||
if self.review:
|
||||
self.data["final_review"] = self.review.snapshot()
|
||||
if not self.engine or not getattr(self.engine, "current_session_id", None):
|
||||
return
|
||||
try:
|
||||
@@ -203,14 +220,28 @@ class RequestAttempt:
|
||||
if (usage := usage_from_message(response)) is not None:
|
||||
self.data["usage"] = usage
|
||||
self.data.update(phase=phase, ended_at=time.time())
|
||||
if self.review:
|
||||
self.review.request_finished(phase, category)
|
||||
self.publish()
|
||||
|
||||
def retry(self, delay):
|
||||
self.data.update(
|
||||
phase="retry_wait", retry_at=time.time() + delay, retry_delay_seconds=delay
|
||||
)
|
||||
if self.review:
|
||||
self.review.request_finished("retry_wait")
|
||||
self.publish()
|
||||
|
||||
def cancel(self, error: BaseException | None = None):
|
||||
if self.review and self.review.expired and not isinstance(error, KeyboardInterrupt):
|
||||
self.finish(
|
||||
"failed",
|
||||
error=FinalReviewBudgetExceeded(self.review.total_seconds),
|
||||
category="final_review_budget_exhausted",
|
||||
)
|
||||
else:
|
||||
self.finish("cancelled", error=error, category="cancelled")
|
||||
|
||||
|
||||
async def observe_request_headers(request):
|
||||
"""Correlate a wire request and record only hashes of routing headers."""
|
||||
|
||||
Reference in new issue
Block a user