mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
fix(context): preserve missing-key compression history
This commit is contained in:
parent
202ad1b8c9
commit
577beeb9b9
8 changed files with 251 additions and 17 deletions
|
|
@ -47,6 +47,11 @@ _SUMMARY_PERMANENT_QUOTA_MARKERS: tuple[str, ...] = (
|
|||
"out of extra usage",
|
||||
)
|
||||
|
||||
_SUMMARY_MISSING_CREDENTIAL_MARKERS: tuple[str, ...] = (
|
||||
"no api key was found",
|
||||
"no api key found",
|
||||
)
|
||||
|
||||
|
||||
def _is_summary_access_or_quota_error(exc: Exception) -> bool:
|
||||
"""Return True for non-retryable summary auth, permission, or quota errors."""
|
||||
|
|
@ -57,13 +62,16 @@ def _is_summary_access_or_quota_error(exc: Exception) -> bool:
|
|||
if classified.reason in {FailoverReason.auth, FailoverReason.auth_permanent}:
|
||||
return True
|
||||
|
||||
err_text = str(exc).lower()
|
||||
if any(marker in err_text for marker in _SUMMARY_MISSING_CREDENTIAL_MARKERS):
|
||||
return True
|
||||
|
||||
status = getattr(exc, "status_code", None) or getattr(
|
||||
getattr(exc, "response", None), "status_code", None
|
||||
)
|
||||
if status in {401, 402, 403}:
|
||||
return True
|
||||
|
||||
err_text = str(exc).lower()
|
||||
if classified.reason is FailoverReason.billing:
|
||||
return any(marker in err_text for marker in _SUMMARY_PERMANENT_QUOTA_MARKERS)
|
||||
return any(marker in err_text for marker in _SUMMARY_PERMANENT_QUOTA_MARKERS)
|
||||
|
|
|
|||
|
|
@ -4,45 +4,83 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any, Sequence
|
||||
|
||||
from agent.redact import redact_sensitive_text
|
||||
|
||||
|
||||
def summarize_manual_compression(
|
||||
before_messages: Sequence[dict[str, Any]],
|
||||
after_messages: Sequence[dict[str, Any]],
|
||||
before_tokens: int,
|
||||
after_tokens: int,
|
||||
*,
|
||||
compression_state: Any = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Return consistent user-facing feedback for manual compression."""
|
||||
before_count = len(before_messages)
|
||||
after_count = len(after_messages)
|
||||
noop = list(after_messages) == list(before_messages)
|
||||
aborted = (
|
||||
compression_state is not None
|
||||
and getattr(compression_state, "_last_compress_aborted", False) is True
|
||||
)
|
||||
fallback_used = (
|
||||
compression_state is not None
|
||||
and getattr(compression_state, "_last_summary_fallback_used", False) is True
|
||||
)
|
||||
failure_reason = (
|
||||
getattr(compression_state, "_last_summary_error", None)
|
||||
if compression_state is not None
|
||||
else None
|
||||
)
|
||||
if not isinstance(failure_reason, str) or not failure_reason.strip():
|
||||
failure_reason = None
|
||||
|
||||
if noop:
|
||||
if aborted:
|
||||
headline = f"Compression aborted: {before_count} messages preserved"
|
||||
elif fallback_used:
|
||||
headline = (
|
||||
f"Compressed with fallback: {before_count} → {after_count} messages"
|
||||
)
|
||||
elif noop:
|
||||
headline = f"No changes from compression: {before_count} messages"
|
||||
if after_tokens == before_tokens:
|
||||
token_line = (
|
||||
f"Approx request size: ~{before_tokens:,} tokens (unchanged)"
|
||||
)
|
||||
else:
|
||||
token_line = (
|
||||
f"Approx request size: ~{before_tokens:,} → "
|
||||
f"~{after_tokens:,} tokens"
|
||||
)
|
||||
else:
|
||||
headline = f"Compressed: {before_count} → {after_count} messages"
|
||||
|
||||
if noop and after_tokens == before_tokens:
|
||||
token_line = f"Approx request size: ~{before_tokens:,} tokens (unchanged)"
|
||||
else:
|
||||
token_line = (
|
||||
f"Approx request size: ~{before_tokens:,} → "
|
||||
f"~{after_tokens:,} tokens"
|
||||
)
|
||||
|
||||
note = None
|
||||
if not noop and after_count < before_count and after_tokens > before_tokens:
|
||||
if aborted:
|
||||
note = "Summary generation failed; no messages were removed."
|
||||
elif fallback_used:
|
||||
dropped_count = getattr(
|
||||
compression_state, "_last_summary_dropped_count", None
|
||||
)
|
||||
if not isinstance(dropped_count, int) or isinstance(dropped_count, bool):
|
||||
dropped_count = max(before_count - after_count, 0)
|
||||
note = (
|
||||
"Summary generation failed; Hermes used limited fallback context "
|
||||
f"and removed {dropped_count} message(s)."
|
||||
)
|
||||
elif not noop and after_count < before_count and after_tokens > before_tokens:
|
||||
note = (
|
||||
"Note: fewer messages can still raise this estimate when "
|
||||
"compression rewrites the transcript into denser summaries."
|
||||
)
|
||||
|
||||
if failure_reason and (aborted or fallback_used):
|
||||
safe_reason = redact_sensitive_text(failure_reason.strip())
|
||||
note = f"{note} Reason: {safe_reason}"
|
||||
|
||||
return {
|
||||
"noop": noop,
|
||||
"aborted": aborted,
|
||||
"fallback_used": fallback_used,
|
||||
"headline": headline,
|
||||
"token_line": token_line,
|
||||
"note": note,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue