* docs: add SDK v1.17.12 migration plan — phase 4 (session.permission) * feat(permissions): verify pending permission before auto-accept via SDK v1.17.12 Adds createPermission() and fetchPermission() wrappers on OpencodeService for the new v2.session.permission endpoints (OpenCode SDK 1.17.12). fetchPermission() is used by the auto-accept sweep in resyncBlockingRequestsForDirectory to verify a permission is still pending before replying. The auto-accept flow now skips permissions that are already resolved, returning a null from fetchPermission() rather than blindly calling respondToPermission on a stale entry. createPermission() is exposed for future programmatic permission creation; the V1 list/reply path used by the UI is unchanged. The plan doc at plans/opencode-v1.17.12-sdk/ was rebased onto origin/main in the prior commit to keep the PR diff focused on this change. Closes #1972 * fix(permissions): drop confirmed-resolved permissions from auto-accept resync fetchPermission() now returns a tagged FetchPermissionResult so the auto-accept loop can distinguish a server-confirmed 404 (the permission is no longer pending) from a fetch failure (network error or pre-v1.17.12 server). Previously both cases collapsed to null, so a permission the server had already answered would still appear in the resync output and trigger a spurious 'Permission needed' toast. The auto-accept loop in resyncBlockingRequestsForDirectory now tracks both accepted and resolved permissions, then drops both from the 'grouped' map before it falls through to the toast path. On a pre-v1.17.12 server (no V2 endpoint) the call still returns 'unknown' and the permission stays in the resync output so the user can answer manually — fail-closed, no false-resolved signals. Adds a focused unit test for fetchPermission (4 cases: 200 ok, 404 resolved, 500 unknown, network throw) mocking the V2 SDK client shape. --------- Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com>
89 lines
6.0 KiB
Markdown
89 lines
6.0 KiB
Markdown
# OpenCode v1.17.12 SDK Migration
|
|
|
|
## Why this matters
|
|
|
|
OpenChamber currently runs on SDK v1.17.9. Version 1.17.12 adds several methods that directly fix real user-facing problems. Plus there are methods already in the SDK that we simply aren't using — and we should.
|
|
|
|
In short: **this is not a "bump the version" chore. It's concrete fixes for hangs, lag, and wasted tokens.**
|
|
|
|
## What actually improves for the user
|
|
|
|
### 1. The STOP button will actually stop generation
|
|
|
|
**Today:** when the user presses STOP, OpenChamber sends `session.abort()` to the server. The server marks the session as idle, but **does not cancel the HTTP request to the LLM provider** (OpenAI, Anthropic, etc.). The provider keeps generating, tokens keep burning, and the user thinks everything stopped. Worse — sometimes the abort itself hangs and never reaches the server (known OpenCode bug #29975).
|
|
|
|
**After the update:** `session.interrupt()` — new in v1.17.12 — doesn't just mark the session idle. It **actually tears down the HTTP request to the provider**. The provider stops generating, tokens stop burning, the session frees up immediately. This is the direct fix from OpenCode PR #34467.
|
|
|
|
**Where it gets better:** no more "I pressed STOP but it's still thinking for 10 more seconds."
|
|
|
|
### 2. Chat stops lagging when switching sessions
|
|
|
|
**Today:** all events from all sessions flow into a single global stream (`global.event()`). OpenChamber has to manually parse this firehose — 300+ lines of code in `sync-context.tsx` exist solely to figure out "which chat gets which event." This is slow, complex, and events occasionally leak into the wrong chat.
|
|
|
|
**After the update:** `session.events()` — new in v1.17.12 — lets us subscribe to events for **a single session**. The chat listens only to its own session. No global firehose parsing, no guessing "whose event is this."
|
|
|
|
**Where it gets better:**
|
|
- Session switching is instant, no lag
|
|
- Events don't "leak" between chats
|
|
- Lower CPU from event parsing (especially noticeable with 5+ open sessions)
|
|
|
|
### 3. Long sessions load without freezing; revert/fork without full history load
|
|
|
|
**Today (pagination):** when loading message history, OpenChamber requests "the last N messages" via `session.messages({ limit: 50 })`. To load older messages, it requests "everything before message X" via `before`. No cursor — the server rescans history from the beginning every time.
|
|
|
|
**Today (message lookup):** when revert or fork needs one specific message, the code searches the already-loaded history. If the message isn't cached — the entire session history is loaded just to find one message.
|
|
|
|
**After the update:** `Session3.messages({ cursor })` — the V2 API with cursor-based pagination (already in the SDK, but we use the old `Session2`). Works like flipping pages: load page 1 → get a cursor → request page 2 by cursor → server returns the continuation without rescanning. Plus `Session3.message({ messageID })` for targeted single-message fetch.
|
|
|
|
**Where it gets better:**
|
|
- Long sessions open faster
|
|
- Scrolling up for history — smooth, no jank or redundant loads
|
|
- Less server load (no rescanning from scratch)
|
|
- Revert and fork complete instantly, even when session is evicted from cache
|
|
|
|
### 4. Permissions — programmatic create and fetch
|
|
|
|
**Today:** permissions are handled reactively — an SSE event `permission.asked` arrives, the UI shows a dialog, the user responds. Auto-accept works by iterating all pending permissions and calling `reply()` without checking if the permission is still valid.
|
|
|
|
**After the update:** `session.permission.create` and `session.permission.fetch` — new in v1.17.12. Enables programmatic permission creation and status checks before responding. Useful for auto-accept: before auto-approving, we can verify the permission is still relevant.
|
|
|
|
**Where it gets better:** fewer false auto-accepts on already-answered permissions.
|
|
|
|
## What will NOT change (and why)
|
|
|
|
### Tool timeout hangs (issue #1950) — not fixable via SDK
|
|
|
|
The problem "tool hangs for 5 minutes → session silently dies → UI stuck on thinking" is an **OpenCode server bug**, not an SDK issue. No SDK method can force the server to emit `session.idle` when it doesn't. This can only be fixed in OpenCode itself (default timeout, stream watchdog, correct `session.idle` emission).
|
|
|
|
**What the SDK does help with:** `session.interrupt()` lets the user **manually** kill a hung tool via STOP. Previously STOP didn't guarantee provider cancellation — now it does.
|
|
|
|
## Phase plan
|
|
|
|
| # | What | Priority | Effort | User impact |
|
|
|---|------|----------|--------|-------------|
|
|
| 1 | `session.interrupt()` replaces `session.abort()` | 🔴 High | Small | STOP actually stops generation |
|
|
| 2 | `session.events()` — per-session event subscription | 🟡 Medium | Medium | No lag on session switch, no event leaks |
|
|
| 3 | Migrate all message ops to Session3 API (cursor pagination + targeted message lookup) | 🟡 Medium | Medium | Long sessions load without freezing; revert/fork without full history load |
|
|
| 4 | `session.permission` — programmatic endpoints | 🟢 Low | Small | More reliable auto-accept |
|
|
|
|
## What already works — don't touch
|
|
|
|
- `global.event()` — global event stream. Used, works, no changes needed.
|
|
- Custom WebSocket/SSE in `event-pipeline.ts` — this is OpenChamber-specific wrapping (coalescing, routing, backpressure), not an SDK replacement. Stays as-is.
|
|
|
|
## Validation
|
|
|
|
| Phase | Command |
|
|
|-------|---------|
|
|
| 1-4 | `bun run type-check` in affected packages |
|
|
| 1 | `bun test packages/ui/src/sync/session-actions.test.ts` |
|
|
| 2 | Manual: open a session, send a message, switch sessions — events don't leak |
|
|
| 3 | Manual: load a session with 100+ messages, scroll up — smooth, no jank; revert an evicted session — works without full history load |
|
|
| 4 | Manual: verify auto-accept permissions |
|
|
|
|
## References
|
|
|
|
- OpenCode v1.17.12 release: https://github.com/anomalyco/opencode/releases/tag/v1.17.12
|
|
- OpenChamber issue #1950: https://github.com/openchamber/openchamber/issues/1950
|
|
- SDK types: `node_modules/@opencode-ai/sdk/dist/v2/gen/sdk.gen.d.ts`
|