[GH-ISSUE #199] bug: native-agent sessions start with no prior chat history when a chat is switched to a workspace model #118

Closed
opened 2026-10-18 14:03:06 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @penradioGables on GitHub (Jul 28, 2026).
Original GitHub issue: https://github.com/open-webui/computer/issues/199

Summary

Hold a conversation in a chat using a stateless API model, then switch that same chat to a Claude Code / Codex workspace model. The agent starts with no knowledge of anything discussed earlier, and nothing indicates this to the user.

This is a follow-up to #152 (closed). Moving native-session adapters onto the backend's own session continuity — rather than replaying a flattened transcript every turn — was the right call and fixed the runaway behaviour there. This issue is the gap that remains on the first turn, before any session exists to continue.

Verified still present in v0.9.15 — both cptr/utils/agents/prompts.py and cptr/routers/gateway.py are byte-identical between the v0.9.10 and v0.9.15 tags.

Root cause — two layers, both needed for a complete fix

Layer 1 — the adapter. Native-session adapters intentionally send only the current turn (prompts.py::latest_user_text, L17–23), relying on the agent's own resumable session for continuity:

def latest_user_text(messages: list[dict[str, Any]]) -> str:
    """Return only the current user turn for native-session agents."""

    for message in reversed(messages):
        if message.get("role") == "user":
            return message_text(message).strip()
    return ""

That is correct once a session exists. But on the first turn after a switch there is no session_id in chat.meta["agent_sessions"] yet, so the agent starts cold and never sees anything earlier in the chat.

Layer 2 — the gateway. Open WebUI does send the full conversation as body.messages on every request, but gateway.py::_resolve_messages extracts only the latest user turn from it and otherwise reconstructs history from cptr's own persisted ChatMessage rows. For a chat whose earlier turns were answered through a different OWUI connection, cptr has no rows at all — so fixing Layer 1 alone leaves it with nothing to render. The data has to be captured here, at the moment OWUI hands it over, or it is gone.

Suggested fix

  1. When a chat is first routed through cptr (no current_message_id) and messages contains prior turns, persist them as plain ChatMessage rows before creating the new user/assistant pair.
  2. When an adapter has no session_id to resume, seed that first prompt with a rendered transcript of the prior turns (capped, oldest-truncated) instead of only the latest message.

Worth being deliberate about the seeding format given #152 — the failure there was an in-band [role] transcript with no turn-boundary stop, replayed every turn. Seeding only on the first turn of a session, and only when there is no session to resume, avoids that: it is a one-time cold-start payload rather than a per-turn replay.

Happy to open a PR if the two-layer split above matches how you'd want it structured.

Originally created by @penradioGables on GitHub (Jul 28, 2026). Original GitHub issue: https://github.com/open-webui/computer/issues/199 ### Summary Hold a conversation in a chat using a stateless API model, then switch that same chat to a Claude Code / Codex workspace model. The agent starts with no knowledge of anything discussed earlier, and nothing indicates this to the user. This is a follow-up to #152 (closed). Moving native-session adapters onto the backend's own session continuity — rather than replaying a flattened transcript every turn — was the right call and fixed the runaway behaviour there. This issue is the gap that remains on the *first* turn, before any session exists to continue. **Verified still present in v0.9.15** — both `cptr/utils/agents/prompts.py` and `cptr/routers/gateway.py` are byte-identical between the `v0.9.10` and `v0.9.15` tags. ### Root cause — two layers, both needed for a complete fix **Layer 1 — the adapter.** Native-session adapters intentionally send only the current turn (`prompts.py::latest_user_text`, L17–23), relying on the agent's own resumable session for continuity: ```python def latest_user_text(messages: list[dict[str, Any]]) -> str: """Return only the current user turn for native-session agents.""" for message in reversed(messages): if message.get("role") == "user": return message_text(message).strip() return "" ``` That is correct once a session exists. But on the first turn after a switch there is no `session_id` in `chat.meta["agent_sessions"]` yet, so the agent starts cold and never sees anything earlier in the chat. **Layer 2 — the gateway.** Open WebUI does send the full conversation as `body.messages` on every request, but `gateway.py::_resolve_messages` extracts only the latest user turn from it and otherwise reconstructs history from cptr's own persisted `ChatMessage` rows. For a chat whose earlier turns were answered through a *different* OWUI connection, cptr has no rows at all — so fixing Layer 1 alone leaves it with nothing to render. The data has to be captured here, at the moment OWUI hands it over, or it is gone. ### Suggested fix 1. When a chat is first routed through cptr (no `current_message_id`) and `messages` contains prior turns, persist them as plain `ChatMessage` rows before creating the new user/assistant pair. 2. When an adapter has no `session_id` to resume, seed that first prompt with a rendered transcript of the prior turns (capped, oldest-truncated) instead of only the latest message. Worth being deliberate about the seeding format given #152 — the failure there was an in-band `[role]` transcript with no turn-boundary stop, replayed *every* turn. Seeding only on the first turn of a session, and only when there is no session to resume, avoids that: it is a one-time cold-start payload rather than a per-turn replay. Happy to open a PR if the two-layer split above matches how you'd want it structured.
Author
Owner

@tjbck commented on GitHub (Jul 31, 2026):

Should be addressed!

<!-- gh-comment-id:5147845311 --> @tjbck commented on GitHub (Jul 31, 2026): Should be addressed!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
open-webui/computer#118
No description provided.