Repository navigation
0.9.0-preview.12
Pre-releaseStreams and automatic traversals take per-call options, and the public surface sheds its last
loose names before 1.0. SubscribeAsync, ReadLogAsync (formerly GetLogAsync),
EnumerateMessagesAsync and EnumerateSessionsAsync accept OpenCodeRequestOptions, so a
per-call Location reaches every connection attempt and page request, and
EventStreamIdleTimeout sets the event bus's idle window. Query parameters take the types the
server reads (bool?, int?, long?), generated enums work in switch and patterns through
their Values constants, assistant content has one union type, PTY sizes share PtySize, and
OpenCodeRoutes is internal. Cancellation reports your own token at every public async door,
disposing the root client interrupts calls and streams with ObjectDisposedException, readiness
timeouts keep an outcome recorded before them, IntelliSense states only what the API declares, and
on .NET Framework and netstandard2.0 response bodies up to 16 MiB are pooled.
💥 Breaking changes
-
Streams and automatic cursor traversals take per-call options before cancellation.
These four virtual method signatures change; recompile consumers and update overrides.
Name a token ascancellationToken: tokenwhen omitting the new options argument.
Calls that omit options keep their behavior. Streams and traversals refuseNoThrow;
the event bus also refuses a per-callNetworkTimeout, includingTimeout.InfiniteTimeSpan.Door Was Now EventsClient.SubscribeAsync(CancellationToken cancellationToken = default)(OpenCodeRequestOptions? requestOptions = null, CancellationToken cancellationToken = default)SessionClient.ReadLogAsync(SessionLogRequest? request = null, CancellationToken cancellationToken = default)(SessionLogRequest? request = null, OpenCodeRequestOptions? requestOptions = null, CancellationToken cancellationToken = default)SessionClient.EnumerateMessagesAsync(SessionMessageListRequest? request = null, CancellationToken cancellationToken = default)(SessionMessageListRequest? request = null, OpenCodeRequestOptions? requestOptions = null, CancellationToken cancellationToken = default)SessionsClient.EnumerateSessionsAsync(SessionListRequest? request = null, CancellationToken cancellationToken = default)(SessionListRequest? request = null, OpenCodeRequestOptions? requestOptions = null, CancellationToken cancellationToken = default) -
Invalid per-call options name
requestOptionsin exceptions. An undefinedErrorBehavior
on a one-shot call now reportsArgumentOutOfRangeException.ParamNameas"requestOptions"
rather than"options", and the new stream and traversal refusals name"requestOptions"too. -
IOpenCodeStreamFailureCauseexposesTag. Every cause in
OpenCodeStreamFailureException.Causesexposes its wire tag without a cast, including an
unknown cause. Custom test implementations must supply the property.IStreamFailureCause
inherits it rather than redeclaring it; concrete causes and their wire representation are unchanged. -
Instruction-entry DTO names retain
Put.
ExperimentalSessionInstructionsEntryRequestis now
ExperimentalSessionInstructionsEntryPutRequest, and
ExperimentalSessionInstructionsEntryResponseis now
ExperimentalSessionInstructionsEntryPutResponse.
ExperimentalClient.SetSessionInstructionsEntryAsynckeeps its method name. -
The instruction-entry list method names its subject in the plural.
ExperimentalClient.ListSessionInstructionsEntryAsyncis now
ListSessionInstructionsEntriesAsync, and
ExperimentalSessionInstructionsEntryListResponse.SessionInstructionsEntryis now
SessionInstructionsEntries. -
The session log uses stream-reading terminology.
SessionClient.GetLogAsyncis nowReadLogAsync; its request and stream item types and
its behavior are unchanged. -
OpenCodeRoutesis no longer public. Call the typed clients to build and send request
paths instead of using route constants or builders directly. Request paths on the wire are
unchanged. -
Assistant content has one union type. Message content and content-updated events use
ISessionMessageAssistantContent; the encoded duplicate and its unknown carrier are removed.
Existing text, reasoning, and tool records implement the surviving interface. The wire is unchanged.Surface Was Now SessionMessageContentUpdatedData.ContentitemISessionMessageAssistantContentEncodedISessionMessageAssistantContentUnknown assistant-content record UnknownSessionMessageAssistantContentEncodedUnknownSessionMessageAssistantContent -
PTY requests share
PtySize. Replace the three old size names withPtySize.
ItsColsandRowsmembers remain requiredlongvalues. The persistent requests remain experimental.
Thepty.updatebody now writescolsbeforerows, which the server does not observe.Property Was Now PtyUpdateRequest.SizePtyUpdateSize?PtySize?PersistentPtyCreateRequest.SizePersistentPtyCreateInputSize?PtySize?PersistentPtyUpdateRequest.SizePersistentPtyUpdateInputSizePtySize -
Boolean query parameters use
bool?.QueryBooleanis removed. Passtrueorfalse,
notQueryBoolean.TrueorQueryBoolean.False; leave the member null to omit it.
The query text remains lowercasetrueorfalse.Property Was Now SessionLogRequest.FollowQueryBoolean?bool?SessionInterruptRequest.ResumeQueryBoolean?bool?ProjectListRequest.ArchivedQueryBoolean?bool?ExperimentalSessionExportRequest.SanitizeQueryBoolean?bool? -
Numeric query parameters are numbers. The API description declares them as strings, but the
server reads each one as a number and upstream's own client takes a number, so the request
records now do too. PassLimit = 50, notLimit = "50". The value still goes out as query text,
and the server still enforces its range.Property Was Now ListRequest.Limit(SessionListRequest,SessionMessageListRequest)string?int?FsFindRequest.Limitstring?int?VcsBranchListRequest.Limitstring?int?ShellOutputRequest.Limitstring?int?ShellOutputRequest.Cursorstring?long?PersistentPtyReadRequest.Linesstring?int?SessionLogRequest.Afterstring?long?SessionDiffRequest.Contextstring?int?VcsDiffRequest.Contextstring?int?ExperimentalSessionStatsRequest.From,.To(milliseconds since the Unix epoch)string?long? -
OpenCodeApiExceptionandOpenCodeServerExceptionare sealed. They can no longer be used
as base classes; their constructors and error data are unchanged. -
SessionParentFilteris a record with value equality. Filters for the same parent compare
equal and have the same hash code, soSessionListRequestrecords built with equal filters
compare equal too.ToString()identifiesRootOnlyorOfand includes the parent id forOf.
✨ Added
-
Per-call
Locationapplies to streams and automatic cursor traversals. Pass
OpenCodeRequestOptionsto override the ambient directory on every stream connection attempt
or every page request. The server still ignores the header on routes that resolve a session's
location or need no location; it does not filter the global event bus. A per-call
NetworkTimeoutbounds only opening the session log, and bounds each page request separately
on a traversal, not the whole walk. -
OpenCodeClientOptions.EventStreamIdleTimeoutsets the event bus's idle window, as
upstream's own client allows. A connection that receives nothing for that long is replaced; the
default stays 45 seconds. Keep it above the server's 15-second keepalive. Any window above zero
and at mostint.MaxValuemilliseconds is accepted, but notTimeout.InfiniteTimeSpan: a bus
that never times out would hang on a half-open connection. The 2-second connect bound and the
1-second delay before a new attempt stay fixed. -
Enum values work in
switchand in patterns. Every generated enum carries its pinned wire
spellings asconst stringmembers of a nestedValuesclass, and aValueproperty that
returns a value's spelling. Match one against the other in acaselabel or a property pattern;
a value a newer server sends matches none of them:switch (mode.Value) { case VcsMode.Values.Committed: /* … */ break; } if (rule is { Effect.Value: PermissionEffect.Values.Allow }) { /* … */ }
Nothing else changes: the static properties,
==,IsKnownand the wire format stay as they
were.
🔧 Changes
- On .NET Framework and netstandard2.0, response bodies between 1 and 16 MiB are pooled instead
of allocated on every call. The SDK then typically keeps one buffer per size class it has used,
at most about 60 MiB after large responses; bodies above 16 MiB still allocate.
🐛 Fixes
- IntelliSense documents declared units, defaults and family roles. Documentation inferred only
from server implementation is removed; SDK types and runtime behavior are unchanged. - Generated XML summaries use grammatical prose. Articles and brand spellings are corrected,
digits stay attached to their words, and members namedValueread "Gets the value." - A background-service start failure no longer carries part of the PTY handoff ticket. The
contender's stderr tail redacts the ticket even where the 8 KiB cut or the end of the pipe splits
it, so no fragment of it reachesOpenCodeServerExceptionmessages. - Caller cancellation preserves your token across public async doors: HTTP, SSE, cursor
traversal, both terminal families, andOpenCodeServer.StartAsync,DiscoverAsync,EnsureAsync,
andStopAsync.OperationCanceledException.CancellationTokenis the
token you supplied at either entry point, including the same token at both enumeration entry
points; two distinct cancellable tokens are observed without an identity guarantee. - A caller token already canceled at the launch boundary prevents the server process from starting.
- Readiness timeouts preserve recorded outcomes: a readiness line, root exit, or stdout end
recorded before timeout arbitration is reported instead of a timeout. Cancellation arriving only
during teardown does not replace the selected failure. - POSIX pipe-creation failures throw
OpenCodeServerExceptionnaming the command, with the
underlyingIOExceptionretained. - Malformed PTY-handoff sidecar and ticket documents are refused, including trailing garbage
or a second JSON value; trailing whitespace remains valid. - Endpoints with a query, fragment, or user info no longer escape best-effort service shutdown
and handoff paths, so endpoint refusal does not prevent termination or replacement. - Disposing the root client interrupts HTTP calls and SSE streams with
ObjectDisposedException,
rather than misreporting a transport timeout. Caller cancellation already observed takes precedence;
terminal sessions keep their separate ownership and disposal rules. - SSE releases its live response on cancellation or client disposal on every target, even while
your code holds an event. A suspended enumeration reports the exception on its next pull. - A stream positioned past its end uploads zero bytes, with a zero
Content-Lengthwhen it can
seek, without rewinding or disposing the caller's stream. - Malformed PTY cursor control documents are refused, including truncation after the cursor
value, trailing garbage, or a second JSON value. Trailing whitespace remains valid. AddOpenCodekeeps existing client registrations. Calling it again does not add another
OpenCodeClientor sub-client registration. A consumer's earlier registration of the root client
or any sub-client wins; missing sub-clients are resolved from the registered root client.