Skip to content

Branch-aware summary never applied at inlet for reasoning models (idless body ≠ DB branch via process_messages_with_output) #98

Description

@Tuxie

Branch-aware summary never applied at inlet for reasoning models (idless body ≠ DB branch via process_messages_with_output)

Summary

With branch-aware compression (v1.7.0+), a saved summary is never applied on the inlet for chats whose model is a reasoning model (assistant turns persisted with an output array plus a rendered <details type="reasoning">…</details> block in content). The outlet validates the snapshot against the DB branch and accepts it (so it stops rebuilding), but the inlet validates against the idless request body and always rejects it → the full uncompressed history is sent on every request, while the UI still reports a summary exists.

Environment

  • Function: Async Context Compression v1.7.2 (commit 439b9f4)
  • Open WebUI: 0.9.6
  • DB: PostgreSQL
  • Model: a reasoning model over an OpenAI-compatible endpoint with function_calling: native. Assistant turns are stored with an output array and a <details type="reasoning"> block inside content.

Symptom

  • Every chat request sends the full history (verified via the upstream proxy's prompt_tokens), despite a valid chat_summary row covering the older turns.
  • The summary row is correct and current-branch-anchored — replaying the stored covered refs against the live DB history nodes matches 100%.
  • With debug_mode enabled, the inlet logs:
    [Summary Snapshot] Rejecting snapshot because current messages do not expose stable refs through covered prefix count=<N>.
    [Summary Snapshot] DB active branch fallback skipped: request body is not a compatible idless view (body_count=<N>, db_count=<N>).
    
    Note body_count == db_count, yet the idless view is judged incompatible.

Root cause

The request-body messages carry no Open WebUI ids, so _select_applicable_summary_snapshot_current_branch_refs returns None and the code falls back to _compatible_db_branch_for_body_ref_fallback. That fallback fails for reasoning models:

  • Open WebUI rebuilds each assistant message from its output array before sending, via process_messages_with_output()convert_output_to_messages(output, ...), which skips reasoning by default (reasoning_format=None). So the model-visible assistant content is regenerated from output (reasoning excluded) and does not equal the stored content (which contains the <details type="reasoning"> fold).
  • _body_message_matches_db_branch_message compares stored content (folded, with reasoning) against body content (output-derived, no reasoning). Even via the include_output=False path, the content differs, so the folded match fails.
  • _unfold_db_branch_for_body_ref_fallback calls convert_output_to_messages(output, raw=True), but that does not reproduce the installed OWUI build's process_messages_with_output result (the raw flag / reasoning_format / message-collapsing differ), so the unfolded comparison also fails.

Net: neither the folded nor unfolded comparison matches → snapshot rejected on every inlet → full context sent. The outlet, which validates against DB-reconstructed messages, accepts the snapshot and skips rebuild, so the stale-but-valid summary persists unused.

Reproduction

  1. Use a reasoning model with function_calling: native so assistant turns are stored with an output array and a <details type="reasoning"> block in content.
  2. Let a long chat exceed the compression threshold so a summary is generated and saved.
  3. Observe subsequent requests: the summary is never applied on the inlet (full history sent), while the outlet keeps the existing snapshot and skips rebuild.

Suggested fix

Reconcile the idless body↔DB comparison with how Open WebUI actually builds the model payload for reasoning models:

  • Mirror process_messages_with_output() exactly in _unfold_db_branch_for_body_ref_fallback (use the same convert_output_to_messages arguments — raw and reasoning_format — as the installed OWUI version), or
  • When the body is idless and 1:1 in count/role with the DB active branch, validate the snapshot against the DB branch (as the outlet does) and inject the summary by position, rather than requiring a content-level match of reasoning-stripped bodies.

Happy to provide more detail or test a patch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions