All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Interactive question handling (#15) - New
onQuestionmodel setting: when OpenCode's question tool fires aquestion.askedevent, the provider invokes the callback with the question request (id,sessionID,questions,tool) and forwards the returned{ type: "answer", answers }viaquestion.reply(onestring[]per question) or{ type: "reject" }viaquestion.reject, passing the configureddirectorylike other client calls. A newquestionPolicysetting ("reject"default,"wait") controls what happens when no handler is set. TheOpencodeQuestionRequest/OpencodeQuestionResponsetypes are exported, and duplicatequestion.askedevents are deduped by question id.doGeneratewatches for questions on a temporary event subscription whilesession.promptis in flight, so non-streaming calls no longer deadlock on questions. New example:examples/question-handling.ts.
- Unanswered questions are rejected by default (fixes #15) - Previously a
question.askedevent only produced a streamerrorpart ("cannot answer interactive questions automatically") and generation hung until the question was answered in OpenCode directly. With noonQuestionhandler the provider now rejects the question so the session unblocks; setquestionPolicy: "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.
- ESM-only package - The package no longer ships a CommonJS build (
dist/index.cjs,dist/index.d.ctsare gone, and therequireexport condition was removed).@ai-sdk/provider@4andai@7are ESM-only, so v7 consumers are already ESM; CommonJS consumers must use Node>= 22.12require(esm)or migrate toimport. The exports map uses a flattypes/defaultshape (matching@ai-sdk/provider) sorequire(esm)resolves correctly. - AI SDK v6 maintenance line - Version 3.x remains available for AI SDK v6 via the
ai-sdk-v6npm tag and is maintained on theai-sdk-v6branch. @opencode-ai/sdkbumped to^1.18.11- The latest SDK renames event types fromEvent*to plain names and describes events with adatapayload envelope instead ofproperties. The provider keeps itsEvent*-styled local event interfaces but reads each event's payload from whichever envelope a server emits (propertiesordata, 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, andai ^7.0.47.reasoningmodel call options are unsupported (warned and ignored vialogUnsupportedCallOptions), andreasoning-fileoutput 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
node22target. The CI matrix covers Node 22 and 24. - File data parts - Per AI SDK v7,
referencefile input parts are unsupported and skipped with a warning.
- Silent permission reply failures (#35) -
replyToPendingApprovalsnever inspected the resolved value ofpermission.reply. Managed clients useresponseStyle: "fields"withoutthrowOnError, 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 viaextractSdkResult(matching the question-reply handling): on error, a warning is logged and surfaced in the responsewarnings, and the approval id is not recorded as replied so the next turn retries it.
- Process hang from leaked
/eventSSE connection (#30) -doStreampasses a per-streamAbortControllersignal toclient.event.subscribeand aborts it when the stream closes (beforeiterator.return(), which could otherwise block until the next server event). Previously the SSE iterator'sreturn()only released its reader lock without cancelling the underlying fetch, so theGET /eventconnection stayed open and kept the Node event loop alive after streaming finished —examples/abort-signal.tsintermittently never exited after printing "Done.". The client manager tracks these controllers (registerEventSubscription) and aborts any still open duringdispose(). - Streaming
session.promptandsession.abortrequests cancelled on stream close (#31) - The per-stream abort signal from #30 is now also passed to thesession.promptandsession.abortrequests, so a prompt the server never completes (e.g. after an abort race) cannot pin the event loop, anddispose()tears these requests down too. Prompt results that arrive after an intentional close are ignored instead of being mis-reported as empty-response errors. doGenerateabort signal (#31) - The non-streaming path now forwardsoptions.abortSignalto the prompt request, so abortinggenerateTextcancels the underlying HTTP request instead of leaving it pending. A caller-initiated abort now surfaces as anAbortError(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) -generateTextwithOutput.object()/Output.array()(andgenerateObject) failed deterministically withAI_NoOutputGeneratedError: No output generated.even though the OpenCode server returned a valid structured result. OpenCode 1.17.x ends aformat: json_schematurn on theStructuredOutputtool call, so the assistant message finishes with"tool-calls"; the provider reported that as a non-stopfinish reason, and the AI SDK only parses structured output when the final step finishes withstop. The provider already flattens theStructuredOutputtool call into text content, so bothdoGenerateand the streaming path now reportfinishReason: "stop"(preserving the rawtool-callsvalue) when a completedStructuredOutputpart is present. Streaming (streamObject/streamText) was unaffected because the AI SDK parses streamed output regardless of finish reason, but its finish event now also reportsstopfor consistency. - Hyphenated finish reasons (#32) -
mapOpencodeFinishReasonnow recognizes the AI SDK-style hyphenated finish values OpenCode actually stores ("tool-calls","content-filter") in addition to the provider-styletool_use/tool_calls/content_filtervalues; previously they fell through to"other".
- Exported
createEmptyResponseDataError- New error factory alongside the existingcreateAPICallError/createTimeoutErrorexports.
- CJS type declarations (FalseESM) - Split the
exports["."]conditions sorequireresolves the CommonJS declarations (./dist/index.d.cts) that the build already emitted, instead of the ESM./dist/index.d.ts. Previously, TypeScript consumers usingrequire()undernode16/nodenextmodule resolution got a "Masquerading as ESM" error from@arethetypeswrong/cli; bothpublintandattw --packare 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/modelIDs, e.g. thegithub-copilot/gpt-5repro from #21) now throw an actionableAPICallErrorthat names the requested model ID, suggests checkingopencode models, includes the server error payload when available, and carrieserrorType: "EmptyResponseData"— replacing the genericNo response data from OpenCode. The streaming path surfaces the same error as anerrorstream part and terminates the stream instead of hanging on the event subscription. wrapErrordouble-wrapping -wrapErrornow 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 latercreateOpencode()builds a fresh client manager. Previously the singleton kept pointing at the disposed instance, and every subsequent provider in the same process failed withClient manager has been disposed. - client-options example - Step 2 of
examples/client-options.tsnow genuinely demonstrates the preconfigured-client pattern by passing an isolated manager viaclientManager: 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'sx-demo-sourceheader so the output proves which client served it, drops a spuriousawaiton the synchronous v2createOpencodeClient(), and allows overriding the example model viaOPENCODE_MODEL.
- Clearer stale-options warnings - The client manager's "already initialized" warnings now point at the escape hatches that actually work (
OpencodeClientManager.createInstance()with theclientManagerprovider setting, orOpencodeClientManager.resetInstance()) instead of the previous generic advice. clientOptions.responseStylenormalization - 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.
- 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 unavailableprovider/modelID) are now wrapped in an actionableAPICallErrorthat names the requested model ID and likely cause. The same wrapping is applied to the streaming prompt failure path, andmodelIdis now included in API call error metadata. (Fixes #21, PR #24 by @slegarraga) - image-input example - Updated
examples/image-input.tsto useopenai/gpt-5.5instead of the no-longer-availableopenai/gpt-5.3-codex, which caused the example to fail silently (empty response, zero usage).
- Tool approval ordering - Buffered OpenCode
permission.askedevents until the correlated tool call is registered, preventing AI SDKToolCallNotFoundForApprovalErrorfailures for provider-executed tools that require approval. Also treats early approval registration as closing the tool-input envelope so stale post-registrationrunningupdates cannot emit latetool-input-deltachunks. (Fixes #22, PR #23 by @JulieLorin)
- Structured output support - OpenCode's
StructuredOutputtool input is now re-emitted as text content so the AI SDK'sOutput.object()/Output.array()can parsestep.textcorrectly. Previously this always threwNoObjectGeneratedError. (PR #16 by @abhijit-hota) - Exported
STRUCTURED_OUTPUT_TOOLconstant - Shared constant for the"StructuredOutput"tool name.
- User message ID passthrough - Added support for
providerOptions.opencode.messageIDto control the user message ID sent to OpenCode. Must start with"msg_". (PR #14 by @abhijit-hota) - Exported
OpencodeProviderOptionstype - New type insrc/types.tsdocumenting the per-request provider options surface.
- Session creation error messages -
Failed to create sessionnow includes the server error payload for easier debugging.
- Breaking: multi-slash model ID parsing now matches OpenCode upstream - Model IDs containing multiple
/separators now use the first segment asproviderIDand preserve the remaining path asmodelID(for example,litellm/anthropic/claude-sonnet-4-6now resolves toproviderID: "litellm"andmodelID: "anthropic/claude-sonnet-4-6"). This changes behavior for integrations that relied on the previous last-segment parsing, so the release is being published as3.0.0to avoid silently breaking consumers pinned to^2.x.
- Streaming delta handling - Added support for
message.part.deltaevents to enable true incremental text and reasoning streaming instead of batch delivery viamessage.part.updatedonly. (PR #9 by @abhijit-hota) - User-message filtering for deltas - Applied user-role guard to
handlePartDeltato prevent user prompt text from leaking into assistant stream output, matching existing filtering inhandlePartUpdated.
- Dependencies - Bumped
@opencode-ai/sdkfrom^1.1.65to^1.2.15.
- 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
clientManageroption onOpencodeProviderSettingsto use a custom client manager instead of the shared singleton. - Validation for conflicting options - Added warning when both
clientManagerandclientare provided.
- OpencodeClient type - Aligned
OpencodeClienttype alias to the SDK-exportedOpencodeClienttype directly instead of inferring fromcreateOpencodeClientreturn type.
- SDK client passthrough options - Added
clientOptionsonOpencodeProviderSettingsto forward OpenCodecreateOpencodeClient()configuration (headers, auth, fetch, serializers, validators, transformers, throwOnError, and RequestInit-compatible options). - Preconfigured client support - Added
clientonOpencodeProviderSettingsto use a prebuilt OpenCode SDK client directly. - Client configuration example - Added
examples/client-options.tsshowingclientOptionspassthrough and preconfiguredclientusage patterns.
- Client initialization behavior -
clientOptionsare now applied consistently across externalbaseUrl, existing-server, and auto-started-server client creation paths. - Conflict handling - Reserved
baseUrlanddirectoryvalues inclientOptionsare ignored with warnings;clienttakes precedence overclientOptions.
- Breaking release - OpenCode SDK v2 migration and AI SDK v6 hardening.
- 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 legacypath/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.15ai(dev) ->^6.0.85
- Permission/approval flow - Added support for OpenCode permission events as AI SDK
tool-approval-requeststream parts. - Approval response handling - Applied
tool-approval-responseprompt parts through OpenCodepermission.reply()before sending prompts. - New model settings - Added
permission,variant,directory, andoutputFormatRetryCountsettings. - File/source streaming output - Added conversion for OpenCode file parts and source metadata into AI SDK
file/sourcestream/content parts. - Provider lifecycle cleanup API - Added provider
dispose()method for managed server/client cleanup. - Event typing exports - Added
EventQuestionAskedexport for SDK v2 question events. - Approval metadata - Added
approvalRequestIdin provider metadata for approval request correlation.
- Finish reason mapping - Added
ContextOverflowErrorandStructuredOutputErrorhandling in finish-reason conversion. - Output-length detection - Treated
ContextOverflowErroras output-length overflow for AI SDK error utilities.
- 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/providerto v3,@ai-sdk/provider-utilsto v4, andaito v6.
- 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)
- OpenAI model names - Updated documentation to use current GPT-5.1 series models instead of outdated GPT-4o references
Initial release of the AI SDK Provider for OpenCode.
- 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
- 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
- Session management - Create, resume, and manage conversation sessions
- Agent selection - Choose from
build,plan,general,exploreagents - System prompts - Override default system prompts per request
- Tool configuration - Enable/disable specific server-side tools
- Working directory - Set
cwdfor file operations - Logging - Custom logger support with verbose mode
- 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)
- 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)
- Base64/Data URL images - Vision-capable models can process local images
- Supported formats: PNG, JPEG, GIF, WebP
- Note: Remote image URLs are not supported
- 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
- Typed errors - Authentication, timeout, and API errors
- Error utilities -
isAuthenticationError(),isTimeoutError(), etc. - Graceful recovery - Proper error propagation to AI SDK
basic-usage.ts- Simple text generationstreaming.ts- Real-time streaming with usage trackingconversation-history.ts- Multi-turn conversationsgenerate-object.ts- Structured output with various schema patternsstream-object.ts- Streaming object generation with progress trackingtool-observation.ts- Observing server-side tool executionimage-input.ts- Processing images with vision modelsabort-signal.ts- Request cancellation patternscustom-config.ts- Provider and model configurationlimitations.ts- Documenting unsupported featureslong-running-tasks.ts- Timeout and retry patterns
- 269 unit tests - Comprehensive test coverage
- Tests for: message conversion, event streaming, error handling, validation, logging
The following AI SDK parameters are not supported (silently ignored):
temperature,topP,topK- Sampling parametersmaxOutputTokens- Output length limitspresencePenalty,frequencyPenalty- Repetition penaltiesstopSequences- Custom stop sequencesseed- Deterministic output
Custom tool definitions are ignored - OpenCode executes tools server-side.
@ai-sdk/provider^2.0.0@ai-sdk/provider-utils^3.0.0@opencode-ai/sdk^0.0.21zod^3.0.0 || ^4.0.0 (peer dependency)