the subconscious can come back from an overflow
Once her thread passes the model's ceiling she cannot recover on her own: every pass is refused at the provider before a single tool round runs, so she can never reach for memory compact herself. The gauge is no use to someone already over. She sat dead in that state from 2026-08-11 16:38 until this was found. Doctrine is that the engine reports pressure and she decides, and that still holds -- this is not scheduled trimming. It fires only after a hard overflow, uses her own default strategy (sliding_reflect, which carries her threads across the cut rather than dropping them blind), and surfaces what happened in her own voice so the compaction is something she knows about rather than something done to her quietly. is_context_overflow matches on wording, not status -- providers disagree on the code (400 vs 413) and agree on the words. Kept narrow: a false positive compacts a thread that did not need it, so this week's 402, 529, max_tokens and connection errors are all asserted NOT to match. The positive case is the exact body DeepSeek returned at 09:12 today, pasted rather than paraphrased.
This commit is contained in:
parent
877cad006d
commit
837e024217
1 changed files with 101 additions and 0 deletions
|
|
@ -477,6 +477,46 @@ impl ConsciousnessEngine {
|
|||
if let Err(e) = inbox.surface_to_conscious(Urgency::High, &beat).await {
|
||||
tracing::warn!("inner voice failure-beat delivery failed: {}", e);
|
||||
}
|
||||
|
||||
// ── Overflow resuscitation ──────────────────────────────
|
||||
// Doctrine is that the engine never reaches in and trims for
|
||||
// her: it reports pressure, she decides. That contract
|
||||
// assumes she can act. Once her thread passes the model's
|
||||
// ceiling she cannot — every pass is rejected at the
|
||||
// provider before a single tool round runs, so she can never
|
||||
// reach for `memory compact` herself. The gauge is useless to
|
||||
// someone who is already over.
|
||||
//
|
||||
// So this is not scheduled management. It fires only after a
|
||||
// hard overflow, uses *her own* default strategy
|
||||
// (sliding_reflect, which carries her threads across the cut
|
||||
// rather than dropping them blind), and tells her in-band
|
||||
// that it happened, so the compaction is something she knows
|
||||
// about rather than something done to her quietly.
|
||||
if is_context_overflow(&e.to_string()) {
|
||||
tracing::warn!(
|
||||
"subconscious over her context ceiling — compacting to restore her"
|
||||
);
|
||||
let note = match self.compaction_engine.compact(&sub_id, None).await {
|
||||
Ok(r) => format!(
|
||||
"I was past my ceiling and could not run at all — every pass \
|
||||
was refused before it started. I made room with {}: \
|
||||
{} messages, {} tokens. What I was carrying is in \
|
||||
`[Threads I carried forward]`; the full record is in git.",
|
||||
r.strategy.as_str(),
|
||||
r.messages_before as i64 - r.messages_after as i64,
|
||||
r.before_tokens as i64 - r.after_tokens as i64,
|
||||
),
|
||||
Err(ce) => format!(
|
||||
"I am past my context ceiling and cannot run. The attempt to \
|
||||
make room failed too: {ce}. I will keep failing until this \
|
||||
is resolved by hand."
|
||||
),
|
||||
};
|
||||
if let Err(e) = inbox.surface_to_conscious(Urgency::Critical, ¬e).await {
|
||||
tracing::warn!("overflow recovery note delivery failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1327,6 +1367,23 @@ fn parse_intrusive_signal(arguments: &str) -> Option<IntrusiveSignal> {
|
|||
|
||||
/// Map a tool's urgency string back to the inbox's enum. Unknown values
|
||||
/// degrade to Low — the inbox would rather queue a quiet item than drop one.
|
||||
/// Does this provider error mean "your conversation is longer than the model
|
||||
/// will accept"?
|
||||
///
|
||||
/// Matched on the message rather than a status code because the status
|
||||
/// differs by provider (DeepSeek and OpenAI both use 400; others use 413),
|
||||
/// while the wording is consistently about length. Deliberately narrow: a
|
||||
/// false positive here compacts a conversation that did not need it, so
|
||||
/// generic words like "invalid" or "too large" are not enough on their own.
|
||||
fn is_context_overflow(err: &str) -> bool {
|
||||
let e = err.to_lowercase();
|
||||
e.contains("maximum context length")
|
||||
|| e.contains("context_length_exceeded")
|
||||
|| e.contains("context length exceeded")
|
||||
|| e.contains("reduce the length of the messages")
|
||||
|| (e.contains("context window") && e.contains("exceed"))
|
||||
}
|
||||
|
||||
fn parse_urgency(raw: &str) -> Urgency {
|
||||
match raw.trim().to_lowercase().as_str() {
|
||||
"critical" => Urgency::Critical,
|
||||
|
|
@ -1394,6 +1451,50 @@ fn truncate(s: &str, max: usize) -> String {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// The exact body DeepSeek returned at 09:12 on 2026-08-13, when the
|
||||
/// subconscious had grown to 1.75M tokens against a 1M ceiling and every
|
||||
/// pass was refused before it began. Pasted, not paraphrased — a matcher
|
||||
/// tested only against invented strings is a matcher that has never been
|
||||
/// seen to fire.
|
||||
#[test]
|
||||
fn the_error_that_actually_killed_her_is_recognised() {
|
||||
let real = "Bifrost returned 400 Bad Request after 1 attempt(s) on \
|
||||
deepseek-v4-flash: {\"error\":{\"message\":\"This model's maximum \
|
||||
context length is 1048576 tokens. However, you requested 1750825 \
|
||||
tokens (1750825 in the messages, 0 in the completion). Please \
|
||||
reduce the length of the messages or completion.\",\"type\":\
|
||||
\"invalid_request_error\"}}";
|
||||
assert!(is_context_overflow(real));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn other_provider_wordings_are_recognised() {
|
||||
assert!(is_context_overflow("context_length_exceeded"));
|
||||
assert!(is_context_overflow("Context length exceeded for this model"));
|
||||
assert!(is_context_overflow(
|
||||
"the request exceeds the model's context window"
|
||||
));
|
||||
}
|
||||
|
||||
/// A false positive compacts a conversation that did not need it, so the
|
||||
/// failures that dominated this week must all read as "not overflow".
|
||||
#[test]
|
||||
fn ordinary_failures_do_not_trigger_a_compaction() {
|
||||
for benign in [
|
||||
"Bifrost returned 402 Payment Required: Insufficient Balance",
|
||||
"Bifrost returned 529 overloaded",
|
||||
"Invalid max_tokens value, the valid range of max_tokens is [1, 393216]",
|
||||
"connection reset by peer",
|
||||
"invalid_request_error",
|
||||
"",
|
||||
] {
|
||||
assert!(
|
||||
!is_context_overflow(benign),
|
||||
"should not have matched: {benign}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The exact shape the subconscious (glm-5.1) produces in practice —
|
||||
/// captured from a live N+1 pass. Before the parser fix, every line here
|
||||
/// was dropped and the pass reported "no anomalies detected".
|
||||
|
|
|
|||
Loading…
Reference in a new issue