# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [5.0.1] - 2026-10-06 ### Fixed - **A clean end of the event stream no longer finishes a turn early.** The 2.x client never reconnects `/api/event`, so a server restart or a proxy closing the connection ends the stream cleanly mid-turn. The provider finished the turn with whatever had streamed so far — a truncated (or empty) answer that looked successful, with no chance to recover in `streamText`/`doStream`. It is now treated as a dropped stream and reconciled from the session's stored messages. - **Recovering a dropped event stream now needs proof the turn concluded.** Recovery used to count any stored assistant message or observed step as success, but the server stores the message when a step starts, so a turn still running (or one that died mid-step) came back as a normal answer. Recovery now succeeds only if the last stored message finished or failed, or the session is waiting on an approval; otherwise the call ends with an error (the partial text that streamed is still delivered). - **Mixed approval continuations return the new prompt's answer.** A call that both replies to an approval and adds new user content resumes the blocked execution and queues the new content behind it. The resumed execution's end could arrive after the new prompt was enqueued and ended the call there, losing the new prompt's answer. That ending is now held back until the new prompt's own execution starts or the prompt is delivered. If the session settles first, the call reports the held failure (OpenCode can run the queued prompt inside the resumed execution and fail it before delivery) or an error, never the earlier answer; stream recovery likewise only accepts an answer stored after the new prompt. - **Transient connection failures at startup are retryable again.** The connection preflight re-threw `server.info()` failures as a plain `Error`, which was classified as permanent: a momentary "connection refused" surfaced as a non-retryable error, and an auth failure lost its `LoadAPIKeyError` type. Errors are now classified by the typed error they wrap. - **No more abort-listener leak on reused signals.** Each call left its abort listener attached to the caller's `AbortSignal` after the call finished, so a long-lived signal shared across calls retained finished turns and eventually triggered Node's listener-leak warning. The listener is now removed when the call ends. ## [5.0.0] - 2026-10-06 A rewrite for **OpenCode 2.x**: the provider now talks to OpenCode v2 through `@opencode/client` (exact pin `2.0.24`). OpenCode v2 is a new backend, not an SDK bump — client package, prompt contract, streaming events, questions, permissions, structured output, and server lifecycle all changed. This entry lists everything that changed since **4.1.0**; the setting-by-setting guide is **[docs/migrating-v4-to-v5.md](docs/migrating-v4-to-v5.md)**. The 4.x line stays available for OpenCode 1.x servers. > **Server requirement:** an OpenCode 2.x server — the published > **`@opencode/cli`** (binary `opencode`, also `opencode2`): > > ```bash > OPENCODE_PASSWORD= npx @opencode/cli@2.0.24 serve --port 4096 > ``` > > `opencode-ai` on npm is still the **v1** CLI and will not work. A server > without `/api/info` (v1, or the pre-2.0 `0.0.0-beta-*` builds) is reported > as incompatible. ### Breaking - **OpenCode 2.x backend.** `@opencode-ai/sdk@^1.18.11` → `@opencode/client@2.0.24` (`OpenCode.make`). Results are returned directly and errors are thrown as typed tagged errors; fields-style `{ data, error }` handling is gone. - **Server lifecycle.** `hostname`, `port`, `autoStartServer` and `serverTimeout` are removed. Backends are a caller `client`, a caller `clientManager`, `baseUrl`, or local-service discovery (`service` options plus opt-in `autoStart`). The provider never owns or kills a shared server, and its process signal handlers are gone. 2.x servers require Basic auth (`clientOptions.headers.Authorization`). - **Client settings retyped.** `client` is now an `OpenCode.make(...)` v2 client; `clientOptions` is collapsed to `{ headers?, fetch? }`; the `OpencodeClientManager` singleton (`createInstance` / `resetInstance`) is replaced by per-provider managers (`createClientManager`, `createClientManagerFromSettings`, `createClientManagerFromPort`). - **Session model.** Model and agent are session state. One model instance = one conversation = one pinned session (`sessionMode: "ephemeral"`, the default, or `"existing"` with `sessionId`). `cwd` is removed and `directory` is a deprecated alias: use `location: { directory }`. - **Questions → forms.** `onQuestion` / `questionPolicy` are replaced by `onForm` / `formPolicy` (`"cancel"` default, or `"wait"`): typed, keyed fields answered with a keyed record instead of positional `string[][]`. - **`tools` and `permission` settings removed.** `tools` has no v2 per-prompt equivalent; tool availability is server/agent configuration, and AI SDK `tools` / non-default `toolChoice` are ignored with a warning. The session-scoped `permission` ruleset is not exposed yet (2.x `session.create` accepts `permissions`, see Known limitations); configure rules on the server or agent. - **Structured output is prompt-engineered.** v1's native `json_schema` and the `StructuredOutput` tool do not exist in v2: `responseFormat: json` appends a JSON instruction and warns. `outputFormatRetryCount` is removed; the closest analog is the new opt-in `jsonRepair`. - **System prompts move to the session.** v2 has no per-prompt `system` field, so `systemPrompt` and AI SDK `system:` messages are written to the session instruction entry `ai-sdk.system`, which stays in effect for later turns until replaced or cleared (see Added). When both are given they are now joined, setting first; 4.x sent the AI SDK `system:` message and ignored `systemPrompt`. - **Conversation history on reused sessions.** OpenCode owns the transcript, so on a reused session only the latest user turn (and any content after it) is sent; earlier messages you pass — including edited ones — are ignored. 4.x sent the whole supplied prompt every call. On a fresh session the supplied history is serialized into a delimited transcript block; use `createNewSession: true` if each call must carry its full history. - **Low-level utilities replaced.** The v1-shaped converters are gone: `convertToOpencodeMessages`, `extractTextFromParts`, `convertEventToStreamParts`, `createStreamState`, `createFinishParts`, `isEventForSession`, `isSessionComplete`, `STRUCTURED_OUTPUT_TOOL`, `mapErrorToFinishReasonFromUnknown`, `hasToolCalls` and their v1 event / part types. v2 equivalents: `convertToOpencodePrompt`, `convertV2EventToStreamParts` / `createV2StreamState` / `finalizeV2Stream`, `mapInterruptReasonToFinishReason`, `mapStructuredErrorToFinishReason`. `mapOpencodeFinishReason` now takes a native finish string (and optional raw finish) instead of a v1 `MessageInfo`. - **Files.** Prompt attachments are sent as URIs; `data:` is the only portable scheme (bytes are converted for you). Assistant messages no longer carry standalone file parts — files surface through tool results. - **Errors.** v1 named error classes and the `isAuthenticationError` / `isTimeoutError` / `createAPICallError` / `createEmptyResponseDataError` helpers are removed, replaced by tagged-error guards (`isAbortError`, `isClientError`, `isTaggedError`, …). Retryability is phase-aware: nothing is retryable once a prompt or permission reply has been dispatched. - **`providerOptions.opencode.messageID` → `providerOptions.opencode.id`.** - **`OpencodeModels` replaced.** The Anthropic / OpenAI / Google shortcuts are gone; the map now holds three OpenCode zen free-tier IDs (`nemotron-3.5-lightning-free`, `nemotron-3-ultra-free`, `big-pickle`), which need no credentials on 2.x. - **Examples reworked.** `question-handling`, `generate-object`, `stream-object`, `image-input`, `conversation-history`, `custom-config`, `tool-observation`, `long-running-tasks` and `limitations` are gone; new `form-handling` and `tool-approval`. Examples read `OPENCODE_URL` / `OPENCODE_PASSWORD`. ### Added - **Delta-native streaming** mapped 1:1 from v2 events (text, reasoning and incremental tool-input deltas), with execution lifecycle events as the completion signal and `session.wait` and silence watchdogs that recover from a lost signal via the session's message store. - **Two-phase tool approval.** A blocked tool finishes the call with a `tool-approval-request` part; calling the same model instance with a `tool-approval-response` sends `permission.reply` and resumes the original execution without re-prompting. - **Interactive forms** (`onForm` / `formPolicy`) with client-side answer validation, verified live with OpenCode's built-in `question` tool. - **Session controls:** `sessionMode`, `location`, `delivery` (`"queue"` by default, always sent explicitly — the server default is `"steer"`), `resume`, and the per-call `providerOptions.opencode.sessionId` escape hatch. - **System prompts as session instructions.** The `ai-sdk.system` entry is rendered into the server's instruction baseline on every turn. Writes are reconciled (an unchanged value skips the request), and a turn without system content clears a stale entry. Falls back to a delimited prepend plus a warning when the route is missing, the value exceeds the server's 256 KiB cap, or the write fails. - **`jsonRepair`** (opt-in, non-streaming): client-side JSON validation with bounded repair via the server's session-less `generate.text` route. - **`resolveFileToUri`** hook; unconvertible files are warned and skipped before the prompt is sent. - **Abort handling.** Aborting before delivery cancels the queued inbox item (confirmed against the message store); after delivery it interrupts the execution. The next call on the instance waits for that cleanup to settle, and a turn ignores a previous execution's late events. Every prompt carries an id (`providerOptions.opencode.id`, else a generated `msg_` id) for exact correlation. - AI SDK per-call `headers` forwarded to every request in a generation; `includeRawChunks` emits the raw typed v2 events. - Expanded `providerMetadata.opencode`: `inboxId`, approval and form IDs, native `finish` / `rawFinish`, `outcome`, `interruptReason` (`user`, `superseded`, `shutdown`, `inactivity`), `cost`, native `tokens` (with cache), structured `error`, `retry`. - Gated live integration suite (`npm run test:integration`) that drives `@opencode/cli@2.0.24` in an isolated sandbox, plus a client-contract drift test and a packed-artifact smoke test. ### Changed - `createNewSession` still forces a fresh session per ordinary call, but tool-approval continuations always reattach to the blocked session. - A bare model ID combined with `variant` must resolve its provider from the server catalog; an empty catalog right after server startup is re-polled before failing. - OpenCode 2.x names the shell tool and its permission action `shell` (not `bash`), e.g. `permission: { shell: "ask" }`. ### Known limitations (OpenCode 2.0.24) - No schema-enforced structured output on the prompt path. - No inbox → execution correlation key, so another client's activity on a shared session can be misattributed. - `session.log` replay is not persisted by `opencode serve`; stream-drop recovery uses the message store. - Per-request headers do not reach the shared event subscription (only client-level headers reach `/api/event`). - An approval rejected without a `reason`, or a cancelled `question` form, ends the turn as `interrupted` with reason `"shutdown"` (finish `error`), the same label as a real shutdown. Reject with a `reason` to let the model continue. - `session.create` accepts a `permissions` ruleset again in 2.x; the provider does not expose it yet. See `docs/known-upstream-issues/` for details and re-check recipes. ### Upgrading from 5.0.0-beta.1 The beta targeted the pre-release `@opencode-ai/client@0.0.0-beta-18286`. Moving to 5.0.0: - Client package `@opencode-ai/client` → `@opencode/client@2.0.24`; run the server from `@opencode/cli@2.0.24` (beta servers are no longer supported). - `location.workspaceID` is removed (2.x dropped workspaces); a stale value produces a settings-validation warning. - `OpencodeModels` went from six IDs to three (`hy3-free`, `mimo-v2.5-free` and `muse-spark-1.2-contributor-free` are not served by 2.0.24). - The connection preflight uses `server.info` (`/api/info`) instead of the removed `health.get`. - The `systemPrompt` instruction cap is 256 KiB (was 8 KiB). - Fixed since the beta: aborts that resolved as normal finishes or left a delivered turn running; abort cleanup interrupting the next call; a previous execution's late events finishing the next turn; duplicated text in `doGenerate` on reasoning models; bare model ID + `variant` failing on a fresh server; a spurious "custom tools ignored" warning on every call; a repeated approval warning on later turns; and resumed tools reported as `unknown`. ## [5.0.0-beta.1] - 2026-08-26 Clean-break rewrite targeting **OpenCode v2** via `@opencode-ai/client` (exact pin `0.0.0-beta-18286`). See **[docs/migrating-v4-to-v5.md](docs/migrating-v4-to-v5.md)** for the full setting-by-setting migration. > **Server requirement:** the client is pinned to the beta-18286 contract, > and the matching server is published — as **`@opencode-ai/cli`**, binary > **`opencode2`**, at the same build number: > > ```bash > npx @opencode-ai/cli@0.0.0-beta-18286 serve --port 4096 > ``` > > `opencode-ai` on npm is the **v1** CLI and speaks an incompatible > protocol; use the 4.x line of this package for OpenCode 1.18.x servers. > Install the CLI at the same build number as the client — the two packages' > dist-tags do not pair. The provider's behavior is verified against > `opencode2` (unit suite + a gated live integration suite and spike > artifacts). ### Breaking - **New backend package**: `@opencode-ai/sdk/v2` → `@opencode-ai/client` (`OpenCode.make`); results are returned directly and errors are thrown as typed tagged errors (fields-style `{data, error}` handling is gone). - **Server lifecycle**: `hostname`/`port`/`autoStartServer`/`serverTimeout` removed. Backends are now caller `client`, caller `clientManager`, `baseUrl`, or local-service discovery (`service` options + opt-in `autoStart`); the provider never owns or kills a shared server, and process signal handlers are gone. - **Session model**: model/agent are session state, and binding is model-instance-local: one model instance = one conversation = one pinned session (`sessionMode: "ephemeral"` — the default — or `"existing"` with a `sessionId`; a planned `"persistent"` value was dropped before release as a documented no-op — see the migration guide). `directory`/`cwd` → `location: { directory, workspaceID? }`. - **Structured output**: v1's native `json_schema` and the `StructuredOutput` tool do not exist in v2. `responseFormat: json` is now a warned, prompt-engineered degradation; `outputFormatRetryCount` removed. - **Questions → forms**: `onQuestion`/`questionPolicy` removed; `onForm` receives typed keyed fields and returns keyed answers; `formPolicy: "cancel" | "wait"`. - **Per-request `tools` and per-session `permission` rulesets removed** (no v2 fields); AI SDK `tools`/`toolChoice` are ignored with a warning. - **`systemPrompt` is session-scoped, not per-prompt**: v2 has no `system` field on `session.prompt`, so the value is written to the session's `ai-sdk.system` instruction entry (see Added) instead of riding the request. It applies to every turn of the session rather than to one call. - **Files**: prompt attachments are `data:` URIs only (the one scheme verified end-to-end); assistant messages no longer carry standalone file parts (files surface via tool results). - **Errors**: v1 named error classes and `isAuthenticationError`/ `isTimeoutError`/`createAPICallError` helpers removed; new tagged-error guards and phase-aware retryability (nothing is retryable after prompt dispatch; transient-class post-dispatch failures additionally attempt internal reconciliation against the session's message store). - **`providerOptions.opencode.messageID` → `providerOptions.opencode.id`.** ### Added - Delta-native streaming mapped 1:1 from v2 events (`session.text.delta`, `session.reasoning.delta`, incremental tool-input deltas), with execution lifecycle events as the completion signal and a `session.wait`-backed watchdog plus silence watchdog for lost-signal recovery. - Two-phase tool-approval round-trip (`tool-approval-request` part → `permission.reply` continuation that resumes the original blocked execution without re-prompting). - Interactive forms (`onForm`/`formPolicy`) with keyed answers and client-side answer validation. - Session controls: `sessionMode`, `location`, explicit `delivery: "queue"` default, `resume`, per-call `providerOptions.opencode.sessionId` escape hatch. - `OpencodeModels` refreshed to six OpenCode zen free-tier IDs, each cross-checked against a live beta catalog and the upstream models.dev catalog; the v4-era Anthropic/OpenAI/Google shortcuts were dropped as unverifiable against any reachable v2 catalog. - Opt-in `jsonRepair` (non-streaming): client-side JSON validation with bounded repair via the server's session-less `generate.text` route. - `resolveFileToUri` hook; bytes are converted to `data:` URIs with the correct media type and unconvertible files are warned and skipped pre-prompt instead of failing the turn late. - AI SDK per-call `headers` forwarded to every request in a generation; `includeRawChunks` emits raw typed v2 events. - Expanded `providerMetadata.opencode`: `inboxId`, approval/form IDs, native `finish`/`rawFinish`, `outcome`, `interruptReason`, `cost`, native `tokens` (incl. cache), structured `error`, `retry`. - **System prompts are real, not degraded.** `systemPrompt` and AI SDK `system:` messages are written as a session instruction entry under the namespaced key `ai-sdk.system`, which the server renders into the instruction baseline and re-renders on every turn — so a system prompt applies to the whole session. Writes are reconciled: an unchanged value skips the request, and any turn that does not write its own value — because it carries no system content, or because the value is over the cap or the write failed — clears the entry first, so a stale system prompt can never outrank the turn that replaced it. Falls back to the delimited prepend plus an `unsupported` warning when the route is absent, the value exceeds the server's 8192-byte cap (measured on the JSON encoding), or the write fails; a clear that itself fails is reported in that warning too. - Gated live integration suite (`npm run test:integration`) driving the published `opencode2` binary in an isolated sandbox, contract-drift snapshot test, and packed-artifact smoke test. ## [4.1.0] - 2026-08-05 ### Added - **Interactive question handling** ([#15](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/issues/15)) - New `onQuestion` model setting: when OpenCode's question tool fires a `question.asked` event, the provider invokes the callback with the question request (`id`, `sessionID`, `questions`, `tool`) and forwards the returned `{ type: "answer", answers }` via `question.reply` (one `string[]` per question) or `{ type: "reject" }` via `question.reject`, passing the configured `directory` like other client calls. A new `questionPolicy` setting (`"reject"` default, `"wait"`) controls what happens when no handler is set. The `OpencodeQuestionRequest` / `OpencodeQuestionResponse` types are exported, and duplicate `question.asked` events are deduped by question id. `doGenerate` watches for questions on a temporary event subscription while `session.prompt` is in flight, so non-streaming calls no longer deadlock on questions. New example: `examples/question-handling.ts`. ### Changed - **Unanswered questions are rejected by default** (fixes [#15](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/issues/15)) - Previously a `question.asked` event only produced a stream `error` part ("cannot answer interactive questions automatically") and generation hung until the question was answered in OpenCode directly. With no `onQuestion` handler the provider now rejects the question so the session unblocks; set `questionPolicy: "wait"` to restore the legacy behavior. Callback failures fall back to rejection with a warning, reply/reject API errors (including fields-style `{ error }` results) are logged without crashing the stream, and a failed rejection is not marked as handled so a duplicate event retries it. ## [4.0.0] - 2026-08-04 ### Changed - **ESM-only package** - The package no longer ships a CommonJS build (`dist/index.cjs`, `dist/index.d.cts` are gone, and the `require` export condition was removed). `@ai-sdk/provider@4` and `ai@7` are ESM-only, so v7 consumers are already ESM; CommonJS consumers must use Node `>= 22.12` `require(esm)` or migrate to `import`. The exports map uses a flat `types`/`default` shape (matching `@ai-sdk/provider`) so `require(esm)` resolves correctly. - **AI SDK v6 maintenance line** - Version 3.x remains available for AI SDK v6 via the `ai-sdk-v6` npm tag and is maintained on the [`ai-sdk-v6`](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/tree/ai-sdk-v6) branch. - **`@opencode-ai/sdk` bumped to `^1.18.11`** - The latest SDK renames event types from `Event*` to plain names and describes events with a `data` payload envelope instead of `properties`. The provider keeps its `Event*`-styled local event interfaces but reads each event's payload from whichever envelope a server emits (`properties` or `data`, treated as optional), so it works with current and future OpenCode servers and older SDKs/servers alike. - **AI SDK v7 migration** - The provider now implements the V4 provider interfaces (`LanguageModelV4` / `ProviderV4`, `specificationVersion: "v4"`) and requires `@ai-sdk/provider ^4.0.4`, `@ai-sdk/provider-utils ^5.0.18`, and `ai ^7.0.47`. `reasoning` model call options are unsupported (warned and ignored via `logUnsupportedCallOptions`), and `reasoning-file` output parts are converted as a no-op with debug logging. - **Node.js >= 22** - The package now requires **Node.js >= 22** and is built for the `node22` target. The CI matrix covers Node 22 and 24. - **File data parts** - Per AI SDK v7, `reference` file input parts are unsupported and skipped with a warning. ### Fixed - **Silent permission reply failures** ([#35](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/35)) - `replyToPendingApprovals` never inspected the resolved value of `permission.reply`. Managed clients use `responseStyle: "fields"` without `throwOnError`, so API-level failures resolve as `{ error }` instead of throwing — a failed reply was silently recorded as replied and never retried, leaving OpenCode waiting on the permission request. The result is now checked via `extractSdkResult` (matching the question-reply handling): on error, a warning is logged and surfaced in the response `warnings`, and the approval id is not recorded as replied so the next turn retries it. ## [3.0.6] - 2026-06-11 ### Fixed - **Process hang from leaked `/event` SSE connection** ([#30](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/30)) - `doStream` passes a per-stream `AbortController` signal to `client.event.subscribe` and aborts it when the stream closes (before `iterator.return()`, which could otherwise block until the next server event). Previously the SSE iterator's `return()` only released its reader lock without cancelling the underlying fetch, so the `GET /event` connection stayed open and kept the Node event loop alive after streaming finished — `examples/abort-signal.ts` intermittently never exited after printing "Done.". The client manager tracks these controllers (`registerEventSubscription`) and aborts any still open during `dispose()`. - **Streaming `session.prompt` and `session.abort` requests cancelled on stream close** ([#31](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/31)) - The per-stream abort signal from [#30](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/30) is now also passed to the `session.prompt` and `session.abort` requests, so a prompt the server never completes (e.g. after an abort race) cannot pin the event loop, and `dispose()` tears these requests down too. Prompt results that arrive after an intentional close are ignored instead of being mis-reported as empty-response errors. - **`doGenerate` abort signal** ([#31](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/31)) - The non-streaming path now forwards `options.abortSignal` to the prompt request, so aborting `generateText` cancels the underlying HTTP request instead of leaving it pending. A caller-initiated abort now surfaces as an `AbortError` (previously a generic empty-response error) and best-effort aborts the server-side session to stop generation. - **Non-streaming native structured output (`json_schema`)** ([#32](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/32)) - `generateText` with `Output.object()` / `Output.array()` (and `generateObject`) failed deterministically with `AI_NoOutputGeneratedError: No output generated.` even though the OpenCode server returned a valid structured result. OpenCode 1.17.x ends a `format: json_schema` turn on the `StructuredOutput` tool call, so the assistant message finishes with `"tool-calls"`; the provider reported that as a non-`stop` finish reason, and the AI SDK only parses structured output when the final step finishes with `stop`. The provider already flattens the `StructuredOutput` tool call into text content, so both `doGenerate` and the streaming path now report `finishReason: "stop"` (preserving the raw `tool-calls` value) when a completed `StructuredOutput` part is present. Streaming (`streamObject` / `streamText`) was unaffected because the AI SDK parses streamed output regardless of finish reason, but its finish event now also reports `stop` for consistency. - **Hyphenated finish reasons** ([#32](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/32)) - `mapOpencodeFinishReason` now recognizes the AI SDK-style hyphenated finish values OpenCode actually stores (`"tool-calls"`, `"content-filter"`) in addition to the provider-style `tool_use`/`tool_calls`/`content_filter` values; previously they fell through to `"other"`. ## [3.0.5] - 2026-06-11 ### Added - **Exported `createEmptyResponseDataError`** - New error factory alongside the existing `createAPICallError` / `createTimeoutError` exports. ### Fixed - **CJS type declarations (FalseESM)** - Split the `exports["."]` conditions so `require` resolves the CommonJS declarations (`./dist/index.d.cts`) that the build already emitted, instead of the ESM `./dist/index.d.ts`. Previously, TypeScript consumers using `require()` under `node16`/`nodenext` module resolution got a "Masquerading as ESM" error from `@arethetypeswrong/cli`; both `publint` and `attw --pack` are now clean across all resolution modes. - **Empty response data errors** - Prompt calls that succeed but return no response data (the behavior of opencode CLI 1.17.x for invalid or unavailable `provider/model` IDs, e.g. the `github-copilot/gpt-5` repro from [#21](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/issues/21)) now throw an actionable `APICallError` that names the requested model ID, suggests checking `opencode models`, includes the server error payload when available, and carries `errorType: "EmptyResponseData"` — replacing the generic `No response data from OpenCode`. The streaming path surfaces the same error as an `error` stream part and terminates the stream instead of hanging on the event subscription. - **`wrapError` double-wrapping** - `wrapError` now returns already-wrapped AI SDK errors (`APICallError`, `LoadAPIKeyError`) unchanged instead of re-wrapping them and losing their metadata. - **Singleton client manager recovery after dispose** - `OpencodeClientManager.dispose()` now releases the singleton slot when the disposed manager is the singleton, so a later `createOpencode()` builds a fresh client manager. Previously the singleton kept pointing at the disposed instance, and every subsequent provider in the same process failed with `Client manager has been disposed`. - **client-options example** - Step 2 of `examples/client-options.ts` now genuinely demonstrates the preconfigured-client pattern by passing an isolated manager via `clientManager: OpencodeClientManager.createInstance({ client })`. Previously the preconfigured client was handed to the singleton that step 1 had already initialized, so it was ignored and step 2's requests flowed through step 1's client while the demo reported success. The example now also echoes each outgoing request's `x-demo-source` header so the output proves which client served it, drops a spurious `await` on the synchronous v2 `createOpencodeClient()`, and allows overriding the example model via `OPENCODE_MODEL`. ### Changed - **Clearer stale-options warnings** - The client manager's "already initialized" warnings now point at the escape hatches that actually work (`OpencodeClientManager.createInstance()` with the `clientManager` provider setting, or `OpencodeClientManager.resetInstance()`) instead of the previous generic advice. - **`clientOptions.responseStyle` normalization** - Managed clients are now always created with fields-style SDK results; `clientOptions.responseStyle: "data"` is ignored with a warning since the provider's response handling requires `{ data, error }` results. Session-creation and prompt result handling also tolerate data-style results from caller-supplied (preconfigured) clients. ## [3.0.4] - 2026-06-11 ### Fixed - **Empty OpenCode response errors** - Empty-body JSON parse failures from the OpenCode server (`SyntaxError: Unexpected end of JSON input`, most commonly caused by an invalid or unavailable `provider/model` ID) are now wrapped in an actionable `APICallError` that names the requested model ID and likely cause. The same wrapping is applied to the streaming prompt failure path, and `modelId` is now included in API call error metadata. (Fixes [#21](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/issues/21), PR [#24](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/24) by [@slegarraga](https://github.com/slegarraga)) - **image-input example** - Updated `examples/image-input.ts` to use `openai/gpt-5.5` instead of the no-longer-available `openai/gpt-5.3-codex`, which caused the example to fail silently (empty response, zero usage). ## [3.0.3] - 2026-06-09 ### Fixed - **Tool approval ordering** - Buffered OpenCode `permission.asked` events until the correlated tool call is registered, preventing AI SDK `ToolCallNotFoundForApprovalError` failures for provider-executed tools that require approval. Also treats early approval registration as closing the tool-input envelope so stale post-registration `running` updates cannot emit late `tool-input-delta` chunks. (Fixes [#22](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/issues/22), PR [#23](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/23) by [@JulieLorin](https://github.com/JulieLorin)) ## [3.0.2] - 2026-04-12 ### Added - **Structured output support** - OpenCode's `StructuredOutput` tool input is now re-emitted as text content so the AI SDK's `Output.object()` / `Output.array()` can parse `step.text` correctly. Previously this always threw `NoObjectGeneratedError`. (PR [#16](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/16) by [@abhijit-hota](https://github.com/abhijit-hota)) - **Exported `STRUCTURED_OUTPUT_TOOL` constant** - Shared constant for the `"StructuredOutput"` tool name. ## [3.0.1] - 2026-03-24 ### Added - **User message ID passthrough** - Added support for `providerOptions.opencode.messageID` to control the user message ID sent to OpenCode. Must start with `"msg_"`. (PR [#14](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/14) by [@abhijit-hota](https://github.com/abhijit-hota)) - **Exported `OpencodeProviderOptions` type** - New type in `src/types.ts` documenting the per-request provider options surface. ### Fixed - **Session creation error messages** - `Failed to create session` now includes the server error payload for easier debugging. ## [3.0.0] - 2026-03-17 ### Changed - **Breaking: multi-slash model ID parsing now matches OpenCode upstream** - Model IDs containing multiple `/` separators now use the first segment as `providerID` and preserve the remaining path as `modelID` (for example, `litellm/anthropic/claude-sonnet-4-6` now resolves to `providerID: "litellm"` and `modelID: "anthropic/claude-sonnet-4-6"`). This changes behavior for integrations that relied on the previous last-segment parsing, so the release is being published as `3.0.0` to avoid silently breaking consumers pinned to `^2.x`. ## [2.1.2] - 2026-03-02 ### Fixed - **Streaming delta handling** - Added support for `message.part.delta` events to enable true incremental text and reasoning streaming instead of batch delivery via `message.part.updated` only. (PR [#9](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk/pull/9) by [@abhijit-hota](https://github.com/abhijit-hota)) - **User-message filtering for deltas** - Applied user-role guard to `handlePartDelta` to prevent user prompt text from leaking into assistant stream output, matching existing filtering in `handlePartUpdated`. ### Changed - **Dependencies** - Bumped `@opencode-ai/sdk` from `^1.1.65` to `^1.2.15`. ## [2.1.1] - 2026-02-19 ### Added - **Isolated client manager instances** - Added `OpencodeClientManager.createInstance()` for creating standalone (non-singleton) client managers, enabling concurrent sessions pointing at different servers. - **Client manager injection** - Added `clientManager` option on `OpencodeProviderSettings` to use a custom client manager instead of the shared singleton. - **Validation for conflicting options** - Added warning when both `clientManager` and `client` are provided. ### Changed - **OpencodeClient type** - Aligned `OpencodeClient` type alias to the SDK-exported `OpencodeClient` type directly instead of inferring from `createOpencodeClient` return type. ## [2.1.0] - 2026-02-18 ### Added - **SDK client passthrough options** - Added `clientOptions` on `OpencodeProviderSettings` to forward OpenCode `createOpencodeClient()` configuration (headers, auth, fetch, serializers, validators, transformers, throwOnError, and RequestInit-compatible options). - **Preconfigured client support** - Added `client` on `OpencodeProviderSettings` to use a prebuilt OpenCode SDK client directly. - **Client configuration example** - Added `examples/client-options.ts` showing `clientOptions` passthrough and preconfigured `client` usage patterns. ### Changed - **Client initialization behavior** - `clientOptions` are now applied consistently across external `baseUrl`, existing-server, and auto-started-server client creation paths. - **Conflict handling** - Reserved `baseUrl` and `directory` values in `clientOptions` are ignored with warnings; `client` takes precedence over `clientOptions`. ## [2.0.0] - 2026-02-13 - **Breaking release** - OpenCode SDK v2 migration and AI SDK v6 hardening. ### Changed - **OpenCode SDK v2 cutover** - Migrated runtime client/server integration to `@opencode-ai/sdk/v2`. - **Request shape updates** - Updated session APIs to v2 parameter style (`sessionID`, top-level args) instead of legacy `path/body`. - **Structured output** - Mapped AI SDK JSON response format to OpenCode native `format: { type: \"json_schema\", schema }`. - **Dependencies** - Bumped to latest stable compatible versions: - `@opencode-ai/sdk` -> `^1.1.65` - `@ai-sdk/provider` -> `^3.0.8` - `@ai-sdk/provider-utils` -> `^4.0.15` - `ai` (dev) -> `^6.0.85` ### Added - **Permission/approval flow** - Added support for OpenCode permission events as AI SDK `tool-approval-request` stream parts. - **Approval response handling** - Applied `tool-approval-response` prompt parts through OpenCode `permission.reply()` before sending prompts. - **New model settings** - Added `permission`, `variant`, `directory`, and `outputFormatRetryCount` settings. - **File/source streaming output** - Added conversion for OpenCode file parts and source metadata into AI SDK `file` / `source` stream/content parts. - **Provider lifecycle cleanup API** - Added provider `dispose()` method for managed server/client cleanup. - **Event typing exports** - Added `EventQuestionAsked` export for SDK v2 question events. - **Approval metadata** - Added `approvalRequestId` in provider metadata for approval request correlation. ### Fixed - **Finish reason mapping** - Added `ContextOverflowError` and `StructuredOutputError` handling in finish-reason conversion. - **Output-length detection** - Treated `ContextOverflowError` as output-length overflow for AI SDK error utilities. ## [1.0.0] - 2026-01-01 ### Changed - **AI SDK v6 migration** - Updated to Language Model Specification V3 (LanguageModelV3 / ProviderV3). - **Usage/finish metadata** - Nested V3 usage shape and unified finish reasons with raw provider values. - **Streaming updates** - V3 stream parts and warnings with SharedV3Warning format. - **Dependencies** - Bumped `@ai-sdk/provider` to v3, `@ai-sdk/provider-utils` to v4, and `ai` to v6. ## [0.0.2] - 2025-12-10 ### Changed - **Updated dependencies** - Bumped to latest compatible versions: - `@ai-sdk/provider-utils`: 3.0.9 → 3.0.18 - `@opencode-ai/sdk`: ^1.0.141 → ^1.0.137 (aligned with stable release) ### Fixed - **OpenAI model names** - Updated documentation to use current GPT-5.1 series models instead of outdated GPT-4o references ## [0.0.1] - 2025-12-10 ### Added Initial release of the AI SDK Provider for OpenCode. #### Core Features - **LanguageModelV2 implementation** - Full AI SDK v5 provider interface - **Text generation** - `generateText()` support with non-streaming responses - **Streaming** - `streamText()` with real-time SSE event streaming - **Object generation** - `generateObject()` with Zod schema validation (prompt-based JSON mode) - **Object streaming** - `streamObject()` with incremental partial object updates #### Provider Configuration - **Auto-start server** - Automatically starts OpenCode server if not running - **Custom server settings** - Configure hostname, port, baseUrl, serverTimeout - **Default settings** - Apply default settings to all model instances #### Model Settings - **Session management** - Create, resume, and manage conversation sessions - **Agent selection** - Choose from `build`, `plan`, `general`, `explore` agents - **System prompts** - Override default system prompts per request - **Tool configuration** - Enable/disable specific server-side tools - **Working directory** - Set `cwd` for file operations - **Logging** - Custom logger support with verbose mode #### Streaming Features - **Text streaming** - Real-time text delta delivery - **Tool observation** - Observe server-side tool execution (Read, Write, Bash, etc.) - **Tool state tracking** - Track pending → running → completed/error states - **Usage tracking** - Token usage extracted from step-finish events - **Finish reason mapping** - Proper finish reason (stop, length, tool-calls, error) #### Multi-Provider Support - **Anthropic models** - Claude 4.5 series (opus, sonnet, haiku) - **OpenAI models** - GPT-5.1 series (gpt-5.1, gpt-5.1-codex, gpt-5.1-codex-mini, gpt-5.1-codex-max) - **Google models** - Gemini 2.0/2.5/3.0 series - Model ID format: `providerID/modelID` (e.g., `anthropic/claude-opus-4-5-20251101`) #### Image Input Support - **Base64/Data URL images** - Vision-capable models can process local images - Supported formats: PNG, JPEG, GIF, WebP - Note: Remote image URLs are not supported #### Abort Signal Support - **Request cancellation** - Cancel in-progress requests via AbortController - **Pre-abort detection** - Immediately reject pre-aborted signals - **Streaming abort** - Cancel streaming requests mid-generation - **Server-side abort** - Calls `session.abort()` to cleanly terminate server processing #### Error Handling - **Typed errors** - Authentication, timeout, and API errors - **Error utilities** - `isAuthenticationError()`, `isTimeoutError()`, etc. - **Graceful recovery** - Proper error propagation to AI SDK #### Examples - `basic-usage.ts` - Simple text generation - `streaming.ts` - Real-time streaming with usage tracking - `conversation-history.ts` - Multi-turn conversations - `generate-object.ts` - Structured output with various schema patterns - `stream-object.ts` - Streaming object generation with progress tracking - `tool-observation.ts` - Observing server-side tool execution - `image-input.ts` - Processing images with vision models - `abort-signal.ts` - Request cancellation patterns - `custom-config.ts` - Provider and model configuration - `limitations.ts` - Documenting unsupported features - `long-running-tasks.ts` - Timeout and retry patterns #### Testing - **269 unit tests** - Comprehensive test coverage - Tests for: message conversion, event streaming, error handling, validation, logging ### Known Limitations The following AI SDK parameters are **not supported** (silently ignored): - `temperature`, `topP`, `topK` - Sampling parameters - `maxOutputTokens` - Output length limits - `presencePenalty`, `frequencyPenalty` - Repetition penalties - `stopSequences` - Custom stop sequences - `seed` - Deterministic output Custom tool definitions are ignored - OpenCode executes tools server-side. ### Dependencies - `@ai-sdk/provider` ^2.0.0 - `@ai-sdk/provider-utils` ^3.0.0 - `@opencode-ai/sdk` ^0.0.21 - `zod` ^3.0.0 || ^4.0.0 (peer dependency)