Skip to content

v1 TUI sync hardcodes limit:100 — api.state.session.messages() returns truncated data for long sessions #31513

Closed as not planned

Description

@zhumengzhu

Description

Sessions with >100 messages silently return truncated data via api.state.session.messages(). Plugins (cache-hit, etc.) see incorrect statistics because the API only returns the last 100 messages.

The root cause is in packages/opencode/src/cli/cmd/tui/context/sync.tsx:

// line 559
sdk.client.session.messages({ sessionID, limit: 100 }),
// lines 580-581
const removed = infos.slice(0, -100)
const visible = infos.slice(-100)

This hardcoded window means any session exceeding 100 messages is silently truncated.

Concrete example — a real opus-4-6 session with 284 messages (234 assistant + 50 user):

Full (DB session table) API (messages(), last 100) Loss
tokens_cache_read 138,989,149 59,585,432 −57%
tokens_input 329 118 −64%
tokens_output 91,895 32,749 −64%
cost $80.61 $31.17 −61%

The cache-hit plugin correctly aggregates whatever the API returns — the data is simply incomplete.

Related issues:


Plugins

opencode-cache-hit


Steps to reproduce

  1. Run a long session that accumulates >100 messages
  2. Compare session table aggregate (tokens_cache_read, cost) with what api.state.session.messages() returns
  3. Cache-hit sidebar will show ~43% of actual values

OpenCode version

1.16.0


Operating System

Linux

Activity

  1. github-actions commented on Jun 9, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

  2. zhumengzhu commented on Jun 9, 2026

    @zhumengzhu
    Author

    This issue is distinct from #30587 and not fully addressed by #26861.

    #30587 is about the TUI scroll buffer — users can't scroll to old messages. A UI problem.

    This issue (#31513) is about the plugin API — api.state.session.messages() returns truncated data regardless of scroll state. Plugins call this API once and get at most 100 messages, with no way to trigger full load.

    #26861 replaces the hardcoded limit: 100 with INITIAL_PAGE_SIZE = 100 and adds lazy-scroll loading (50/page). This fixes the scroll experience in #30587, but the initial page size remains 100. For plugins consuming the messages API, they still only see 100 messages on first call — they can't scroll or paginate.

    What's needed beyond #26861: either raise/remove INITIAL_PAGE_SIZE, or provide an explicit "full load" path for programmatic consumers.

  3. zhumengzhu commented on Jun 10, 2026

    @zhumengzhu
    Author

    Confirmed this affects opencode-cache-hit — same session, same cap.

    Workaround: switched from api.state.session.messages() (capped at 100)
    to api.state.session.get() which returns database-level aggregates
    (cost, tokens.{input,output,cache.*}) computed from all messages by
    the session projector, not affected by the TUI sync limit.

    Before/after (284-message session):

    messages() session.get()
    cache read 59.6M tok 139.0M tok
    cost ~39% actual full

    Covered by opencode-cache-hit v0.2.2. This is a plugin-side workaround —
    the root cause in sync.tsx (hardcoded limit:100) still needs fixing
    for plugins that iterate per-message fields.

    Quick checklist for other plugin authors: if your Session type has
    cost? and tokens?, you can swap now without waiting for the
    pagination PR.

  4. github-actions commented on Aug 10, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions