Skip to content

refactor(session): remove message content mutation API - #48043

Merged
rekram1-node merged 1 commit into
v2from
drop-message-update
Sep 9, 2026
Merged

rekram1-node merged 1 commit into
v2from
drop-message-update

Conversation

@rekram1-node

Copy link
Copy Markdown
Collaborator

Summary

Remove the completed-assistant-message content mutation introduced by #45015 for #44984.

  • Remove PATCH /api/session/:sessionID/message/:messageID (session.messageUpdate), its generated client methods, and Core Session.updateMessage/session-handle operation and dedicated errors.
  • Remove the replacement event from the public event surface and client live-state handling; regenerate clients and OpenAPI documents.
  • Retain the existing durable event definition and projector solely to decode/replay records written by older releases. No database migration is required.
  • Remove mutation-specific tests and adjust existing expectations; add no new tests.

Context and rationale

The original issue requested V1-style part deletion so clients could prune stored tool/reasoning payloads from long sessions, citing database growth. #45015 implemented a broader operation that replaced all content of a completed assistant message in an idle session.

Following maintainer discussion, arbitrary editing of persisted assistant history should not be part of the session API. Plugins that want to exclude tool/reasoning content from model input should use ctx.session.hook("context", ...) to transform the outgoing messages instead. The hook changes model context without rewriting stored history.

That distinction matters for the original report: context filtering does not reclaim disk space or remove content from stored/UI history. Storage retention is a separate concern; this PR does not claim that the context hook solves database growth.

Compatibility

This intentionally breaks callers of session.messageUpdate / Session.updateMessage and removes the corresponding public event. Existing session reads, prompts, execution, and other session operations remain available. Historical replacement events remain replayable, including for users who used the removed API before upgrading.

Created in a separate worktree from latest origin/v2 at d24f8b0810. Follow-up explanation on #44984 can happen after review.

Verification

  • Existing Core session-owned and session-projector suites: 34 passing.
  • Existing Server session-import and session-instances suites: 4 passing.
  • Existing Client solid-data suite: 23 passing.
  • Protocol and Schema event-manifest suites pass.
  • Package typechecks pass: Core, Server, Client, Protocol, Schema, SDK, Plugin.
  • Client and Protocol generated-output checks pass.
  • Website typecheck, generated-output check, production build, and link validation pass.
  • Formatting and git diff --check pass.

Remove session.messageUpdate and Session.updateMessage. Context filtering belongs in the session context hook rather than persisted history edits. Keep historical content-update events available only for durable replay.
@rekram1-node
rekram1-node merged commit 6ee2ed7 into v2 Sep 9, 2026
9 of 10 checks passed
@rekram1-node
rekram1-node deleted the drop-message-update branch September 9, 2026 01:27
@pascalandr

pascalandr commented Sep 9, 2026 •

Copy link
Copy Markdown

@rekram1-node Could you reconsider this removal and revert it until a narrower replacement is available?

OpenCode owns the database and session consistency, so it is precisely where safe cleanup should happen, not through direct SQL in downstream clients.

I think two different concerns are being conflated here: arbitrary history rewriting and selective removal of stored technical payloads. If messageUpdate is too permissive, could we constrain it or replace it with a dedicated prune operation, rather than remove the capability entirely?

An append-only history could record that content was pruned while preserving the necessary structure. Is there a concrete invariant that makes this unsafe, even for completed tool/reasoning blocks in idle sessions?

Given the immediate impact on CodeNomad 0.20.0, a temporary revert followed by a constrained replacement would let us address your concern without breaking adopted workflow in the meantime.

pascalandr added a commit to NeuralNomadsAI/CodeNomad that referenced this pull request Sep 10, 2026
…n RPC (#686)

## Summary

Restore selective deletion of completed assistant tool/reasoning content
after OpenCode removed `session.messageUpdate`, without forking OpenCode
or opening a generic RPC proxy.

The original draft's unconditional `maintenance_required` stub is
replaced by a working **experimental, explicit opt-in** plugin path for
the audited `0.0.0-beta-19419` runtime. The default remains read-only.
Unknown runtimes/storage and active native execution fail closed.
Nothing is installed or enabled on app startup.

## Implementation

- Keep individual/message/group/session cleanup entry points. Send
selected technical indices and a canonical SHA-256 revision, never
arbitrary replacement content, SQL, database filenames or
caller-selected locations.
- Use an ownership-checked CodeNomad broker with a fixed RPC
ID/method/location and worktree-deletion fence. Keep the removed PATCH
and generic RPC routes blocked.
- Bind the plugin's explicitly configured database connection to the
actual daemon DB with a fresh `ctx.storage` challenge. Inside a
synchronous SQLite write transaction, recheck
directory/project/workspace ownership, native durable execution claim,
staged revert/compaction state, event ownership and retained payloads.
- Rely on the audited native **write-ahead execution claim before runner
history reads**, not an `idle` check, plugin mutex or `BEGIN IMMEDIATE`
alone. Never set or release the native claim ourselves.
- CAS only the completed assistant's content array. Preserve IDs,
ordering, text, snapshots, usage and metadata. Commit a content-free
idempotency receipt atomically with the change; identical retries cannot
delete a second shifted block.
- Emit the custom invalidation after commit. Re-read via the native API,
invalidate the SDK transcript and pending rotations, and fence late
reads against newer invalidations. Add a public-API TUI cache companion
and reconnect handling.
- Correct native Windows path encoding; support more than 4,096 selected
parts within explicit request/message budgets.
- Provide an independently packable plugin with main and `./tui`
entrypoints, deployment/safety docs, and a Windows/Linux/macOS native
package CI matrix. Plugin installation remains manual and separately
approved.

## Validation performed locally

| Check | Result |
|---|---|
| Server/plugin/SQLite/broker/proxy tests | 72 passed |
| UI actions, events, SDK projection and stale-read tests | 60 passed |
| Plugin/SQLite/TUI-companion tests under Node 22 | 30 passed |
| Server and UI TypeScript checks | Passed |
| Production UI build | Passed; existing large-chunk warnings |
| Official Windows x64 beta-19419 executable | Passed on a private
daemon and generated DB |
| Independently packed and installed plugin | Same native test passed,
outside the checkout |

The native integration test uses the real beta-19271 network client
against the official beta-19419 runtime, with a local synthetic provider
and no credentials. It verifies actual preview/prune RPC, refusal while
a primary generation holds the native claim, both prompt/transaction
orderings, idempotent retry, two event subscribers, native re-reading,
the subsequent primary model payload, fork isolation, pre-compaction
history without summary changes, and persistence after server restart.

The new three-OS native CI matrix must pass on this head before merge.
No CI result is inferred from the local Windows run.

## Boundaries and remaining validation

- This is a reviewable opt-in implementation, **not general availability
across OpenCode versions/providers/platforms**. Exact runtime gating is
intentional; don't widen it without re-auditing/testing.
- Interactive official TUI, two native CodeNomad windows/scroll
behavior, WSL, provider-specific continuation state and budget/token
estimates are not claimed as validated. TUI companion tests use its
cache contract, not an interactive terminal. Two HTTP subscribers are
not two GUI windows.
- Existing bulk cleanup is per-message and reports failure counts;
dedicated installation/capability and bulk progress/cancel UI are not
added here.
- Existing summaries/native checkpoints, fork copies and already
assembled/sent requests are not retroactively scrubbed. Historical usage
remains historical usage; mock token values are not a token-savings
measurement.
- This changes persisted V2 content, not only visibility. It frees
reusable SQLite pages but does **not** promise a smaller physical file.
No VACUUM, V1 cleanup, durable-event rewriting, automatic backup
restoration or universal repair is included.
- No active user DB was changed, no shared-daemon plugin installed, no
shared OpenCode service stopped/upgraded, and no native desktop
executable/profile rebuilt or replaced. Tests use isolated synthetic
data only.

## Documentation

- [Request flow and validation](dev-docs/SESSION_PRUNING_RPC.md)
- [Audited safety boundary](dev-docs/SESSION_PRUNING_SAFETY.md)
- [Explicit deployment and
recovery](dev-docs/SESSION_PRUNING_DEPLOYMENT.md)

References: anomalyco/opencode#44984, anomalyco/opencode#48043,
anomalyco/opencode#48090 and the maintainer's plugin/RPC direction. No
upstream API or distribution fork is introduced.
jinhuang712 pushed a commit to jinhuang712/opencode that referenced this pull request Sep 26, 2026
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.

2 participants