Skip to content

Comments

Harden async context compression against new DB session alias and runtime edge cases#20

Merged
Fu-Jie merged 9 commits intomainfrom
copilot/fix-session-alias-errors
Jan 11, 2026
Merged

Harden async context compression against new DB session alias and runtime edge cases#20
Fu-Jie merged 9 commits intomainfrom
copilot/fix-session-alias-errors

Conversation

Copy link
Contributor

Copilot AI commented Jan 11, 2026

Async Context Compression failed on newer Open WebUI builds because Session is no longer a scoped, engine-bound alias; it also crashed on missing metadata and empty summary models.

  • Database compatibility
    • Discover Open WebUI engine/schema via get_db_context/get_db/engine attributes with fallbacks.
    • Introduce a context-managed session factory (prefers OWUI helpers, then SessionLocal/ScopedSession, then a local sessionmaker) and clearer errors.
  • Safety guards
    • Gracefully skip when chat_id metadata is absent, now centralized through a shared extractor.
    • Require non-empty summary model ID before LLM calls; skip save on empty summaries.
  • Diagnostics
    • Lightweight discovery debug logs and docstrings for the new discovery helpers.

Example (session usage):

with self._db_session() as session:
    existing = session.query(ChatSummary).filter_by(chat_id=chat_id).first()
Original prompt

This section details on the original issue you should resolve

<issue_title>open_webui.internal.db Session alias change breaks plugins (ChatSummary bind error) + AsyncCompression runtime failures</issue_title>
<issue_description>https://github.com/Fu-Jie/awesome-openwebui/blob/main/plugins/filters/async-context-compression/async_context_compression.py

Summary

Since Open WebUI v0.7.x, open_webui.internal.db.Session is no longer a scoped session alias. Plugins/tools built against
v0.6.x (e.g., AsyncCompression) now crash with DB bind errors. In addition, AsyncCompression has two other safe‑to‑fix
runtime failures: unsafe metadata access and empty model IDs.

Versions / Context

  • v0.6.43: Session = scoped_session(SessionLocal)
  • current: ScopedSession = scoped_session(SessionLocal) and Session is SQLAlchemy Session class

Errors Observed (3 total)

  1. CRITICAL — DB session binding mismatch

[Load] ❌ Database read failed: Could not locate a bind configured on mapper Mapper[ChatSummary(chat_summary)], SQL
expression or this Session.

Why it happens (detailed):

  • In v0.6.43, Session was an engine‑bound scoped session, so plugins importing Session worked.
  • In current versions, Session is the SQLAlchemy class, not a configured session.
  • Any plugin still doing from open_webui.internal.db import Session now gets a class with no engine/bind, so ORM
    queries fail at runtime.
    Impact: Summary load/save fails; compression pipeline breaks.
    Safe fix: Use SessionLocal or get_db_context() (current supported pattern). Optionally restore a
    backward‑compatible alias: Session = ScopedSession.
  1. MEDIUM — Unsafe metadata access (KeyError)
  • Code uses __metadata__["chat_id"] directly.
  • If metadata is missing or malformed, a KeyError occurs and the compression step crashes.
    Impact: Compression skipped for those messages.
    Safe fix: Use __metadata__.get("chat_id") and short‑circuit gracefully if absent.
  1. MEDIUM — Empty/invalid model ID
  • Summary model ID can resolve to empty string (e.g., valve unset).
  • LLM call fails with “Model not found.”
    Impact: Compression fails even though everything else is valid.
    Safe fix: Validate model ID before calling LLM; if empty, log warning and skip compression.

Expected

Plugins/tools continue working or have a clear migration path.

Actual

Legacy plugins fail at runtime without clear guidance.

Suggested Fix

  • Restore Session = ScopedSession alias for backward compatibility, or
  • Publish explicit migration guidance: use SessionLocal / get_db / get_db_context.
  • Apply the two safe guardrails above in AsyncCompression.

References

  • v0.6.43: /backend/open_webui/internal/db.py
  • current: /open_webui/internal/db.py</issue_description>

<agent_instructions>查看 rbb-dev 的方案 修复 bug。</agent_instructions>

Comments on the Issue (you are @copilot in this section)

  • Fixes Fu-Jie/awesome-openwebui#19

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI self-assigned this Jan 11, 2026
Copilot AI and others added 6 commits January 11, 2026 08:24
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
Copy link
Owner

@Fu-Jie Fu-Jie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def _extract_chat_id(self, body: dict, metadata: Optional[dict]) -> str:
    """Extract chat_id from body or metadata"""
    if isinstance(body, dict):
        chat_id = body.get("chat_id")
        if isinstance(chat_id, str) and chat_id.strip():
            return chat_id.strip()

        body_metadata = body.get("metadata", {})
        if isinstance(body_metadata, dict):
            chat_id = body_metadata.get("chat_id")
            if isinstance(chat_id, str) and chat_id.strip():
                return chat_id.strip()

    if isinstance(metadata, dict):
        chat_id = metadata.get("chat_id")
        if isinstance(chat_id, str) and chat_id.strip():
            return chat_id.strip()

    return ""

chat_id,统一改为调用这个函数

Copilot AI changed the title [WIP] Fix session alias change issues in AsyncCompression plugin Harden async context compression against new DB session alias and runtime edge cases Jan 11, 2026
Copilot AI requested a review from Fu-Jie January 11, 2026 08:34
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 11, 2026

def _extract_chat_id(self, body: dict, metadata: Optional[dict]) -> str:
    """Extract chat_id from body or metadata"""
    if isinstance(body, dict):...

Updated inlet/outlet to use a shared _extract_chat_id helper per request. Commit abbe3fb.

- Enhanced error reporting via status bar and console
- Robust model ID handling
- Open WebUI v0.7.x compatibility (dynamic DB session)
- Updated documentation and version bumps
@github-actions
Copy link
Contributor

✅ Plugin Version Check / 插件版本检查

版本更新检测通过!PR 包含版本变化和更新说明。

Version check passed! PR contains version changes and update description.


版本变化 / Version Changes

插件更新 / Plugin Updates

  • Async Context Compression: v1.1.1 → v1.1.2
  • 异步上下文压缩: v1.1.1 → v1.1.2

This comment was generated automatically. / 此评论由自动生成。

@Fu-Jie Fu-Jie marked this pull request as ready for review January 11, 2026 09:25
Copilot AI review requested due to automatic review settings January 11, 2026 09:26
@Fu-Jie Fu-Jie merged commit 06e8d30 into main Jan 11, 2026
1 check passed
@Fu-Jie Fu-Jie deleted the copilot/fix-session-alias-errors branch January 11, 2026 09:26
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request addresses critical database compatibility issues affecting the Async Context Compression filter plugin after Open WebUI upgraded from v0.6.x to v0.7.x. The primary issue is that open_webui.internal.db.Session changed from being a scoped session instance to the SQLAlchemy Session class itself, causing "Could not locate a bind configured" errors. Additionally, the PR adds safety guards for missing metadata and invalid model IDs.

Changes:

  • Database compatibility layer with dynamic engine/schema discovery and multi-level session factory fallbacks
  • Safety guards for missing chat_id metadata and empty/invalid model IDs
  • Enhanced error reporting with status bar notifications for background errors
  • Version bump from 1.1.1 to 1.1.2 with updated documentation

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
async_context_compression.py Added database discovery functions, context-managed session factory, chat_id extractor, model ID cleaner, and enhanced error handling
async_context_compression_cn.py Partially updated: Added model ID validation and error handling but missing critical database compatibility fixes
README.md Updated version to 1.1.2 and documented new compatibility features
README_CN.md Updated version to 1.1.2 with Chinese documentation of changes
docs/plugins/filters/index.md Updated version number in plugin listing
docs/plugins/filters/async-context-compression.md Updated version badge and added feature bullets
docs/plugins/filters/async-context-compression.zh.md Updated Chinese version badge and features
Comments suppressed due to low confidence (6)

plugins/filters/async-context-compression/async_context_compression.py:246

  • Import of 'model_validator' is not used.
from pydantic import BaseModel, Field, model_validator

plugins/filters/async-context-compression/async_context_compression.py:247

  • Import of 'Union' is not used.
from typing import Optional, Dict, Any, List, Union, Callable, Awaitable

plugins/filters/async-context-compression/async_context_compression_cn.py:245

  • Import of 'model_validator' is not used.
from pydantic import BaseModel, Field, model_validator

plugins/filters/async-context-compression/async_context_compression_cn.py:246

  • Import of 'Union' is not used.
from typing import Optional, Dict, Any, List, Union, Callable, Awaitable

plugins/filters/async-context-compression/async_context_compression_cn.py:249

  • Import of 'hashlib' is not used.
import hashlib

plugins/filters/async-context-compression/async_context_compression_cn.py:250

  • Import of 'time' is not used.
import time

Comment on lines +289 to +297
with db_context() as session:
try:
return session.get_bind()
except AttributeError:
return getattr(session, "bind", None) or getattr(
session, "engine", None
)
except Exception as exc:
print(f"[DB Discover] get_db_context failed: {exc}")
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _discover_owui_engine function attempts to call session.get_bind() which may not exist on all session types. While there is a fallback that uses getattr for bind and engine attributes, the initial try block could fail with an AttributeError that gets caught in the outer exception handler. This can mask the actual problem.

Consider restructuring to avoid calling potentially non-existent methods directly. The inner try-except should catch AttributeError specifically and fall through to the getattr fallback, while the outer exception handler should only catch context manager errors.

Suggested change
with db_context() as session:
try:
return session.get_bind()
except AttributeError:
return getattr(session, "bind", None) or getattr(
session, "engine", None
)
except Exception as exc:
print(f"[DB Discover] get_db_context failed: {exc}")
ctx = db_context()
except Exception as exc:
print(f"[DB Discover] get_db_context failed: {exc}")
else:
with ctx as session:
try:
return session.get_bind()
except AttributeError:
return getattr(session, "bind", None) or getattr(
session, "engine", None
)

Copilot uses AI. Check for mistakes.
Comment on lines +331 to +338
try:
from open_webui import env as owui_env

candidate = getattr(owui_env, "DATABASE_SCHEMA", None)
if isinstance(candidate, str) and candidate.strip():
return candidate.strip()
except Exception as exc:
print(f"[DB Discover] env schema lookup failed: {exc}")
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table schema discovery logic tries to import from open_webui.env, but this import may fail in environments where the module structure is different. The exception is caught and logged to print, but the error handling should be more specific.

Consider checking if the module exists before attempting the import, or using importlib for more controlled imports. Also, the fallback chain might benefit from a final check that validates the discovered schema is actually used by the database.

Copilot uses AI. Check for mistakes.
Comment on lines +409 to +412
if self._fallback_session_factory is None:
raise RuntimeError(
"Open WebUI database session is unavailable. Ensure Open WebUI's database layer is initialized."
)
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _db_session context manager has a potential issue in the fallback path. If self._fallback_session_factory is None, it raises a RuntimeError, but this check happens after attempting to use the session factories from the db_module. If the db_module factories exist but fail during session creation or usage, the error handling might not provide clear diagnostics about which factory failed.

Consider adding more specific error messages that indicate which fallback level failed (e.g., "get_db_context failed", "SessionLocal factory failed", "fallback session factory unavailable") to help with debugging.

Copilot uses AI. Check for mistakes.

# Check if table exists using SQLAlchemy inspect
inspector = inspect(self._db_engine)
if not inspector.has_table("chat_summary"):
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _init_database method checks for table existence using inspector.has_table("chat_summary"), but when a schema is configured (via owui_schema), the table might be in that schema. The has_table method may need a schema parameter to correctly check for the table in the right schema.

Verify that inspector.has_table("chat_summary") correctly finds the table when a schema is configured. You may need to pass the schema explicitly: inspector.has_table("chat_summary", schema=owui_schema).

Suggested change
if not inspector.has_table("chat_summary"):
# Try to detect the configured schema (if any) from Open WebUI's internal DB module.
# This keeps behavior identical when no schema is configured, while correctly handling
# deployments that use a dedicated schema (e.g. PostgreSQL with owui_schema set).
owui_schema = None
try:
from open_webui.internal.db import schema as owui_schema # type: ignore
except Exception:
owui_schema = None
if owui_schema:
table_exists = inspector.has_table("chat_summary", schema=owui_schema)
else:
table_exists = inspector.has_table("chat_summary")
if not table_exists:

Copilot uses AI. Check for mistakes.
Comment on lines +1006 to +1010
"""Cleans the model ID by removing whitespace and quotes."""
if not model_id:
return None
cleaned = model_id.strip().strip('"').strip("'")
return cleaned if cleaned else None
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _clean_model_id method strips both double and single quotes from model IDs, but this could potentially cause issues if a model ID legitimately contains quotes as part of its identifier. While this is unlikely, the current implementation might be too aggressive.

Consider validating that the quotes are actually wrapping the entire string rather than being part of the model ID itself. A more conservative approach would only strip quotes if they appear at both the beginning and end of the string.

Suggested change
"""Cleans the model ID by removing whitespace and quotes."""
if not model_id:
return None
cleaned = model_id.strip().strip('"').strip("'")
return cleaned if cleaned else None
"""Cleans the model ID by removing surrounding whitespace and wrapping quotes."""
if not model_id:
return None
# First trim surrounding whitespace
cleaned = model_id.strip()
# Only strip quotes if they wrap the entire string, e.g. "model-id" or 'model-id'
if len(cleaned) >= 2 and cleaned[0] == cleaned[-1] and cleaned[0] in ('"', "'"):
cleaned = cleaned[1:-1]
return cleaned or None

Copilot uses AI. Check for mistakes.
@@ -249,6 +249,7 @@
import json
import hashlib
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'hashlib' is not used.

Suggested change
import hashlib

Copilot uses AI. Check for mistakes.
@@ -249,6 +249,7 @@
import json
import hashlib
import time
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'time' is not used.

Suggested change
import time

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

open_webui.internal.db Session alias change breaks plugins (ChatSummary bind error) + AsyncCompression runtime failures

2 participants