refactor(agent/agent_runtime_helpers): flatten pool walk, steer requeue, error-context, orphan classifier

This commit is contained in:
Teknium
2026-09-02 19:51:54 -07:00
parent f9d27dfcd0
commit a2fb880d79
+49 -88
View File
@@ -2436,49 +2436,33 @@ def _classify_tool_call_orphans(messages: List[Dict[str, Any]]):
every id variant of a tool_call is registered so a result matching any alias survives, and
``orphaned_results`` are the actual dicts (filter by ``id(msg)``). ``sanitize_api_messages``
pairs positionally instead but shares the ``*_id_variants`` alias policy."""
assistant_call_variants: List[tuple[Any, frozenset[str]]] = []
surviving_call_ids: set[str] = set()
for msg in messages:
if msg.get("role") != "assistant":
continue
for tc in msg.get("tool_calls") or []:
variants = tool_call_id_variants(tc)
if variants:
assistant_call_variants.append((tc, variants))
surviving_call_ids.update(variants)
assistant_call_variants = [
(tc, variants)
for msg in messages if msg.get("role") == "assistant"
for tc in msg.get("tool_calls") or []
if (variants := tool_call_id_variants(tc))
]
surviving_call_ids: set[str] = set().union(*(v for _, v in assistant_call_variants))
result_entries = [
(msg, tool_result_id_variants(msg.get("tool_call_id")))
for msg in messages
if msg.get("role") == "tool"
]
result_call_ids: set[str] = set()
for _, variants in result_entries:
result_call_ids.update(variants)
orphaned_results = [
msg for msg, variants in result_entries if variants and not (variants & surviving_call_ids)
(msg, tool_result_id_variants(msg.get("tool_call_id"))) for msg in messages if msg.get("role") == "tool"
]
result_call_ids: set[str] = set().union(*(v for _, v in result_entries))
orphaned_results = [msg for msg, v in result_entries if v and not (v & surviving_call_ids)]
orphaned_ids = {id(msg) for msg in orphaned_results}
surviving_result_variants = [
variants for msg, variants in result_entries if variants and id(msg) not in orphaned_ids
]
surviving_result_variants = [v for msg, v in result_entries if v and id(msg) not in orphaned_ids]
missing_tool_calls = [
tc
for tc, variants in assistant_call_variants
if not any(variants & rv for rv in surviving_result_variants)
tc for tc, v in assistant_call_variants if not any(v & rv for rv in surviving_result_variants)
]
return surviving_call_ids, result_call_ids, orphaned_results, missing_tool_calls
def _drop_invalid_roles(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""Drop messages whose role the API won't accept."""
filtered = []
valid = _ra().AIAgent._VALID_API_ROLES
for msg in messages:
role = msg.get("role")
if role not in _ra().AIAgent._VALID_API_ROLES:
_ra().logger.debug("Pre-call sanitizer: dropping message with invalid role %r", role)
continue
filtered.append(msg)
return filtered
if msg.get("role") not in valid:
_ra().logger.debug("Pre-call sanitizer: dropping message with invalid role %r", msg.get("role"))
return [m for m in messages if m.get("role") in valid]
def _drop_empty_tool_calls_arrays(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
@@ -2807,23 +2791,20 @@ def _iter_httpx_pool_objects(http_client: Any):
keepalive and proxy configs put live connections on ``client._mounts``, which a
``_transport``-only walk misses."""
seen_pools: set[int] = set()
def _pools_for_transport(transport: Any):
if transport is None:
return
# Connections live under ``_pool``; a directly mounted HTTPProxy *is* a ConnectionPool, so
# ``_connections`` may sit on the transport itself.
pool = getattr(transport, "_pool", None)
if pool is None and getattr(transport, "_connections", None) is not None:
pool = transport
if pool is not None and id(pool) not in seen_pools:
seen_pools.add(id(pool))
yield pool
try:
yield from _pools_for_transport(getattr(http_client, "_transport", None))
mounts = getattr(http_client, "_mounts", None) or {}
for _pattern, mounted in list(mounts.items()):
yield from _pools_for_transport(mounted)
transports = [getattr(http_client, "_transport", None)]
transports += list((getattr(http_client, "_mounts", None) or {}).values())
for transport in transports:
if transport is None:
continue
# Connections live under ``_pool``; a directly mounted HTTPProxy *is* a ConnectionPool,
# so ``_connections`` may sit on the transport itself.
pool = getattr(transport, "_pool", None)
if pool is None and getattr(transport, "_connections", None) is not None:
pool = transport
if pool is not None and id(pool) not in seen_pools:
seen_pools.add(id(pool))
yield pool
except Exception:
return
@@ -2949,9 +2930,7 @@ def extract_api_error_context(error: Exception) -> Dict[str, Any]:
"""Extract structured rate-limit details from provider errors."""
context: Dict[str, Any] = {}
body = getattr(error, "body", None)
payload = None
if isinstance(body, dict):
payload = body.get("error") if isinstance(body.get("error"), dict) else body
payload = (body.get("error") if isinstance(body.get("error"), dict) else body) if isinstance(body, dict) else None
if isinstance(payload, dict):
reason = payload.get("code") or payload.get("type") or payload.get("error")
if isinstance(reason, str) and reason.strip():
@@ -2962,11 +2941,9 @@ def extract_api_error_context(error: Exception) -> Dict[str, Any]:
message = payload.get("error")
if isinstance(message, str) and message.strip():
context["message"] = message.strip()
for key in ("resets_at", "reset_at"):
value = payload.get(key)
if value not in {None, ""}:
context["reset_at"] = value
break
reset = next((payload.get(k) for k in ("resets_at", "reset_at") if payload.get(k) not in {None, ""}), None)
if reset is not None:
context["reset_at"] = reset
_set_reset_from_retry_after(context, payload.get("retry_after"))
headers = getattr(getattr(error, "response", None), "headers", None)
if headers:
@@ -2974,29 +2951,20 @@ def extract_api_error_context(error: Exception) -> Dict[str, Any]:
ratelimit_reset = headers.get("x-ratelimit-reset")
if ratelimit_reset and "reset_at" not in context:
context["reset_at"] = ratelimit_reset
if "message" not in context:
raw_message = str(error).strip()
if raw_message:
context["message"] = raw_message[:500]
if "reset_at" not in context:
message = context.get("message") or ""
if isinstance(message, str):
delay = _reset_delay_from_message(message)
if delay is not None:
context["reset_at"] = time.time() + delay
if "message" not in context and str(error).strip():
context["message"] = str(error).strip()[:500]
if "reset_at" not in context and isinstance(context.get("message") or "", str):
delay = _reset_delay_from_message(context.get("message") or "")
if delay is not None:
context["reset_at"] = time.time() + delay
return context
def _requeue_pending_steer(agent, steer_text: str) -> None:
"""Put drained steer text back so the caller's fallback delivers it as a next-turn user message."""
lock = getattr(agent, "_pending_steer_lock", None)
if lock is not None:
with lock:
existing = agent._pending_steer
agent._pending_steer = (existing + "\n" + steer_text) if existing else steer_text
return
existing = getattr(agent, "_pending_steer", None)
agent._pending_steer = (existing + "\n" + steer_text) if existing else steer_text
with getattr(agent, "_pending_steer_lock", None) or contextlib.nullcontext():
existing = getattr(agent, "_pending_steer", None)
agent._pending_steer = (existing + "\n" + steer_text) if existing else steer_text
def apply_pending_steer_to_tool_results(agent, messages: list, num_tool_msgs: int) -> None:
@@ -3009,30 +2977,23 @@ def apply_pending_steer_to_tool_results(agent, messages: list, num_tool_msgs: in
if not steer_text:
return
# Skip non-tool messages in the tail in case something else is appended at the boundary.
target_idx = next(
(
j for j in range(len(messages) - 1, max(len(messages) - num_tool_msgs - 1, -1), -1)
if isinstance(messages[j], dict) and messages[j].get("role") == "tool"
),
None,
)
if target_idx is None:
tail = range(len(messages) - 1, max(len(messages) - num_tool_msgs - 1, -1), -1)
target = next((messages[j] for j in tail if isinstance(messages[j], dict) and messages[j].get("role") == "tool"), None)
if target is None:
# No tool result in this batch (e.g. all skipped by interrupt).
_requeue_pending_steer(agent, steer_text)
return
marker = format_steer_marker(steer_text)
existing_content = messages[target_idx].get("content", "")
existing_content = target.get("content", "")
if isinstance(existing_content, str):
messages[target_idx]["content"] = existing_content + marker
target["content"] = existing_content + marker
else:
# Anthropic multimodal content blocks: preserve them and append a text block.
try:
blocks = list(existing_content) if existing_content else []
blocks.append({"type": "text", "text": marker.lstrip()})
messages[target_idx]["content"] = blocks
target["content"] = [*(existing_content or []), {"type": "text", "text": marker.lstrip()}]
except Exception:
# Fall back to string replacement if content shape is unexpected.
messages[target_idx]["content"] = f"{existing_content}{marker}"
target["content"] = f"{existing_content}{marker}"
_ra().logger.info(
"Delivered /steer to agent after tool batch (%d chars): %s", len(steer_text),
steer_text[:120] + ("..." if len(steer_text) > 120 else ""),