Commit Graph

365 Commits

Author SHA1 Message Date
Teknium 0d27aaa247 refactor(agent/context_compressor): fold cooldown/pressure/handoff-strip branches; drop lazy-import blank lines 2026-09-02 23:19:04 -07:00
Teknium e43eb87b4e refactor(agent/context_compressor): template-driven tool-result summarizers; compact docstrings/comments (every rule kept) 2026-09-02 23:16:11 -07:00
Teknium 72bbbf8f75 refactor(agent/context_compressor): fold gate/backoff loops, content-shape helpers, echo/bridge index math 2026-09-02 23:09:25 -07:00
Teknium 2539771553 refactor(agent/context_compressor): AST-identical bracket hug pass 2026-09-02 23:01:55 -07:00
Teknium ef34ee566b refactor(agent/context_compressor): extract compress() summary/assembly phases; flatten boundary, handoff-strip, and placement helpers 2026-09-02 22:58:16 -07:00
Teknium 45a4672428 refactor(agent/context_compressor): split _build_summary_prompt into template/temporal helpers (prompt text byte-identical) 2026-09-02 22:35:45 -07:00
Teknium 29aa1bdf3d refactor(agent/context_compressor): share micro-cursor reset, breaker predicate, real-usage verdict; collapse session-state boilerplate 2026-09-02 22:34:33 -07:00
Teknium 081484e259 refactor(agent/context_compressor): unify tool-call field access, JSON-arg parsing, content rewrite; compact module helpers 2026-09-02 22:27:25 -07:00
Teknium c14ae92fea refactor(agent/context_compressor): fold derived-budget cache resets 2026-09-02 20:44:33 -07:00
Teknium bed463381f refactor(agent/context_compressor): class-qualify helper calls in _clear_compression_failure_cooldown (bare-stub binding) 2026-09-02 20:31:31 -07:00
Teknium 71bfa94ff9 refactor(agent/context_compressor): use the failure-kind dataclass directly; compact threshold/arg helpers 2026-09-02 20:23:47 -07:00
Teknium 932f7532ca refactor(agent/context_compressor): third AST-identical reflow pass at 118 cols 2026-09-02 20:19:10 -07:00
Teknium 5f7284e86e refactor(agent/context_compressor): repack historical-prefix and abort-message literals (values byte-identical) 2026-09-02 20:15:48 -07:00
Teknium 684fa87ad4 refactor(agent/context_compressor): fold parent-row rotation reads 2026-09-02 20:10:37 -07:00
Teknium 91cf271093 refactor(agent/context_compressor): second AST-identical reflow pass 2026-09-02 20:08:10 -07:00
Teknium 322f04f8fb refactor(agent/context_compressor): reflow docstrings/comments to width (every word preserved) 2026-09-02 20:04:00 -07:00
Teknium 321e8a79b0 refactor(agent/context_compressor): one newest-first token walk shared by tail-cut and prune boundary 2026-09-02 19:53:45 -07:00
Teknium d3b93c45c9 refactor(agent/context_compressor): flatten historical-media strip, summarizer part/tool-call rendering, orphan sanitizer 2026-09-02 19:49:48 -07:00
Teknium adbac330c7 refactor(agent/context_compressor): repack implicitly-concatenated string literals (values byte-identical) 2026-09-02 19:46:07 -07:00
Teknium 7b8d547ffc refactor(agent/context_compressor): normalize blank lines (ruff E302/E303/E305) 2026-09-02 19:43:18 -07:00
Teknium 939305f186 refactor(agent/context_compressor): pack multi-line def signatures (AST-identical) 2026-09-02 19:42:06 -07:00
Teknium b233420b3d refactor(agent/context_compressor): shared real-user index helper, folded guard ladders, telemetry loop cleanup 2026-09-02 19:39:24 -07:00
Teknium 1d7fb737cd refactor(agent/context_compressor): prompt scaffolding helpers, shared real-usage reset, compact text/length helpers 2026-09-02 19:25:44 -07:00
Teknium 5f716407b9 refactor(agent/context_compressor): move per-section summarizer instructions into a keyed table (text byte-identical) 2026-09-02 19:21:58 -07:00
Teknium a7e616ee5f refactor(agent/context_compressor): flatten _scan_window_handoffs around an early return 2026-09-02 19:17:16 -07:00
Teknium e468577b13 refactor(agent/context_compressor): shared content-part text helpers for handoff projection/unwrapping 2026-09-02 19:13:23 -07:00
Teknium 9a89ce5548 refactor(agent/context_compressor): pack short literal collections and call arguments (AST-identical) 2026-09-02 19:08:33 -07:00
Teknium 34f96ff29c refactor(agent/context_compressor): reflow short multi-line call statements 2026-09-02 19:01:32 -07:00
Teknium 6fe54ec6d7 refactor(agent/context_compressor): AST-identical reflow of short multi-line statements and headers 2026-09-02 19:00:02 -07:00
Teknium 6549a8bfb6 refactor(agent/context_compressor): extract _call_summary_llm and a summary-failure classifier dataclass 2026-09-02 18:51:31 -07:00
Teknium f00024ecc8 refactor(agent/context_compressor): lift static-fallback helpers to module level, extract anchor collection 2026-09-02 18:48:29 -07:00
Teknium 83168ff4e4 refactor(agent/context_compressor): split _prune_old_tool_results into boundary/dedupe/demote/pressure helpers 2026-09-02 18:45:36 -07:00
Teknium 608e8560fe refactor(agent/context_compressor): split compress() into phase helpers (494 -> ~130 LOC) 2026-09-02 18:33:40 -07:00
Teknium 6bbdb45df1 refactor(agent/context_compressor): unify durable read/write/load helpers and cooldown persistence paths 2026-09-02 18:27:34 -07:00
Teknium 806d2c3274 refactor(agent/context_compressor): dedupe image-part stripping, summarizer one-liners into dispatch table, alias coerce helper 2026-09-02 18:24:29 -07:00
Teknium b3e41128ff refactor(agent): share predicates, truncation and the timeout ladder
- User-turn predicates reuse _is_context_summary_message (single detection path).
- _serialize_for_summary hoists the shared head/tail truncation.
- __init__ initialises per-session state via _reset_session_compaction_state.
- Timeout cooldown ladder (60/300/900s) is one module helper used by both
  record_timeout_failure and the summary failure path; module-level so a real
  method bound onto a stub compressor still exercises it.
2026-09-02 13:29:38 -07:00
Teknium b2717f4f4c refactor(agent): restore rationale comments lost in the docstring compaction
Hunk-by-hunk audit of the compaction commit found 14 dropped WHY/invariant
statements (route-pin scope, persistence-marker sweep failure mode, stamp
asymmetry, reasoning-replay boundary, size-class parity with preflight,
small-context floor cap, tail-anchor ordering rules, defer-baseline backstops).
Each is restored as a compact 1-3 line comment at its anchor.
2026-09-02 13:29:38 -07:00
Teknium ea090ccb62 refactor(agent): unify durable-state helpers, session reset and tail-cut walks
- Nine near-identical durable-row getters/setters -> _durable_read/_durable_write
  (also used for parent-lineage lookups in on_session_start).
- on_session_reset/on_session_end share _reset_session_compaction_state.
- _find_tail_cut_by_tokens: the two backward token walks become one _walk_back
  (randomized parity vs. the previous version: 1500 transcripts identical).
- _strip_context_summary_handoff_message: one _unwrapped() helper for all paths
  (parity: 1296 content shapes identical).
- ruff SIM102/SIM108/SIM114 collapses.
2026-09-02 13:29:38 -07:00
Teknium 4a64d42f9b refactor(agent): extract micro-compaction into agent/micro_compaction.py
The 15 rolling micro-compaction methods (cursor resolution, exchange
serialization, one-exchange summarization, defrag, splice, DB sync, telemetry)
move verbatim into MicroCompactionMixin, mixed into ContextCompressor
(MRO: ContextCompressor -> MicroCompactionMixin -> ContextEngine). Origin
constants and call_llm are imported lazily so tests patching
agent.context_compressor.X still apply; logger name parity is kept.
2026-09-02 13:29:38 -07:00
Teknium 64576a34f8 refactor(agent): decompose _generate_summary and the compress() abort path
- _generate_summary(): prompt assembly lifted into _build_summary_prompt, the
  exception path into _on_summary_failure; the two identical main-model retry
  branches are merged behind a reason lookup.
- compress(): terminal summary-failure abort classes are table-driven via
  _TERMINAL_SUMMARY_FAILURES (same precedence, log text and telemetry class;
  flag reads stay lazy so __new__-built test doubles keep working).
2026-09-02 13:29:38 -07:00
Teknium 8b84f8debe refactor(agent): dispatch-table the tool-result summarizer
_summarize_tool_result_unguarded routed on tool_name through ~20 if-branches; each
branch is now a small _sum_* function in _TOOL_RESULT_SUMMARIZERS with the generic
fallback unchanged. Output verified byte-identical against the previous version
across 1288 name/args/content combinations.
2026-09-02 13:29:38 -07:00
Teknium cfb234c54c refactor(agent): extract _scan_window_handoffs from compress(); drop unused imports
The in-transcript handoff rehydration scan (previous-summary rebuild, zero-user
provenance, merged-handoff unwrap, tail_start advance) moves into
ContextCompressor._scan_window_handoffs returning a _HandoffScan dataclass;
compress() keeps the rollback snapshot semantics unchanged.
2026-09-02 13:29:38 -07:00
Teknium 12be763de0 refactor(agent): compact context_compressor comments/docstrings to invariants
Hand-reviewed compaction: non-obvious rules, ordering constraints, invariants,
failure modes and WHY are kept in 1-3 line form; narrative, issue-number history
and code restatements are dropped.
2026-09-02 13:29:37 -07:00
Teknium d1efa0d78d fix(compression): provider-proven overflow gets one real compaction attempt while the failure cooldown is armed
After one failed/stalled summary attempt arms the 60/300/900s compression-
failure cooldown, a provider context_length_exceeded rejection entered the
reactive overflow branch in conversation_loop, which called _compress_context
without force. Since #97488 the cooldown gate returns the soft "temporarily
paused, retry in a moment" deferral instead of exhaustion, so every turn
deferred until the cooldown lapsed, and the next failure extended the ladder:
long-running sessions wedged with no automatic recovery (#100661, four sessions
lost).

Thread a narrow `bypass_cooldown` kwarg from the three provider-proven overflow
call sites (generic overflow, 413, output-cap recovery) through
AIAgent._compress_context -> compress_context -> ContextCompressor.compress ->
_generate_summary. It skips ONLY the summary-failure cooldown check at each gate.
Unlike force=True it does not clear the cooldown, does not skip the feasibility /
anti-thrash breakers, and a failed attempt records its cooldown normally. The
attempt is bounded by the existing compression_attempts/max_compression_attempts
budget, so there is no retry loop. The preflight threshold gate is unchanged:
ordinary over-threshold pressure still honors the cooldown (#11529).

Engines whose _automatic_compression_blocked()/compress() predate the kwarg
(plugins, test doubles) are called with the legacy signature.

Tests: cooldown armed + bypass_cooldown -> summarizer invoked and transcript
compacted; ordinary pass still deferred. Docs note the cooldown/overflow
contract in the developer guide.

Fixes #100661
Closes #97766 (overflow-force idea; the bundled continuation changes were not taken)

Co-authored-by: sgtworkman <178342791+sgtworkman@users.noreply.github.com>
2026-09-02 05:33:22 -07:00
Teknium 238b6c1ab9 fix(compression): persist the anti-thrash recovery deadline so gateway agent rebuilds cannot block a session forever
The #14694 recovery clock (`_anti_thrash_recovery_deadline`) was a
process-local `time.monotonic()` value zeroed in `bind_session_state()`.
The gateway rebuilds the AIAgent (and its ContextCompressor) on every
cache eviction, so each fresh compressor bound to a durably tripped
session row (#69872) re-armed a full 300s window and the half-open probe
never fired — a long messaging conversation above the threshold stayed
blocked permanently.

Persist the deadline as a wall-clock epoch in a new
`sessions.compression_recovery_deadline REAL` column (declarative column
reconciliation; SCHEMA_VERSION 26 -> 27) with
`SessionDB.get/set_compression_recovery_deadline`. The compressor loads it
in `bind_session_state()` and writes it on change only via
`_set_anti_thrash_recovery_deadline()`. A fresh compressor with no stored
deadline still starts a full window blocked (#54923 restart contract); one
that loads an armed deadline resumes that window. Backward clock jumps are
bounded to one window. The 300s window is unchanged.

Minimal salvage of #100185 (the probe-lease/fencing state machine and
model_config-blob storage were not carried).

Refs #100185
Co-authored-by: Komzpa <me@komzpa.net>
2026-09-02 04:14:10 -07:00
Teknium c5c9aa8d44 fix(gateway): hygiene compaction keeps the profile secret scope under multiplexing
Session-hygiene compaction ran _compress_context on a bare
loop.run_in_executor(None, ...) worker. Under gateway.multiplex_profiles the
profile secret scope and HERMES_HOME override are ContextVars installed by
the per-turn _profile_runtime_scope, and a bare worker starts with an empty
Context — so the summary model's get_secret(<PROVIDER>_API_KEY) failed
closed with UnscopedSecretError on EVERY hygiene pass and compaction
silently degraded to a lossy truncation (#100849 debug bundle:
'Failed to generate context summary: get_secret(SURPLUS_API_KEY) called
with no profile secret scope active').

- gateway/run.py: run both hygiene executor hops (detached-agent path and
  codex app-server path) inside copy_context().run, keeping the default
  executor so a fence-cancelled hung summary never occupies a gateway
  agent-work slot.
- agent/context_compressor.py: UnscopedSecretError is a missing-credential
  class failure — abort and preserve the session instead of dropping the
  middle window for a placeholder summary (same carve-out as 401/402/403).
- tools/daemon_pool.py: correct the salvaged docstrings — stdlib
  ThreadPoolExecutor only propagates contextvars from 3.14; nothing is
  stripped from the bundled runtime.
- tests: hygiene worker inherits caller ContextVars (fails on bare
  run_in_executor); UnscopedSecretError classified as access failure.

Live A/B (real get_secret in a run_in_executor worker, multiplex on, profile
.env scope installed): main -> UnscopedSecretError; fixed -> scoped value.
2026-09-01 22:28:52 -07:00
Teknium bd7cdd7c53 Merge origin/main into core-tool-deferral (resolve show_tip test seam onto the check_tips_enabled gate) 2026-09-01 21:49:14 -07:00
kshitijk4poor 29d4c0ebfd refactor(compression): extract preflight seed predicate onto ContextCompressor
Address review follow-ups on the seed fix:

- Move the 'seed only from the 0 state' guard from an inline block in
  build_turn_context() into
  ContextCompressor.maybe_seed_preflight_display_tokens(), co-locating
  the predicate with the rest of the speculative-seed lifecycle
  (snapshot_preflight_display_tokens /
  rollback_interrupted_preflight_display_tokens). Callers now use the
  method via a getattr guard so test doubles and external context
  engines without it are unaffected.
- Rewrite the TestPreflightSentinelGuard docstring, which still
  described the old >=0 guard ('treats any negative value as no real
  usage yet'); the ==0 policy protects ALL non-zero readings.
- Drop the _seed mirror-helper: the tests now call the real production
  method on the compressor fixture, eliminating mirror-drift risk (the
  helper comment had already drifted once).
- Note the accepted trade-off (partial-usage providers pin the meter
  low until their next report) in the method docstring.
2026-09-01 14:33:23 +05:30
Brooklyn Nicholson 5c6dbe22c3 fix(compression): take reasoning_content when the summarizer leaves content empty
Local and thinking backends (DeepSeek, Qwen, Kimi) often return a usable
summary in reasoning fields. Treat that as the summary instead of burning
another 100s+ empty-content retry. Leave the wire max_tokens omit intact.

Co-authored-by: Chris DePuy <chris@650group.com>
Co-authored-by: chenhm <chenhm@yuancheng.local>
2026-08-31 20:43:00 -05:00
theo 8207862212 fix(compression): stop timeout paths from blocking retries 2026-08-31 13:00:33 -07:00