All notable changes to this package are documented in this file. The format follows Keep a Changelog, and versions follow Semantic Versioning.
Compatibility promise: the public API is additive-only. Anything public is deprecated before it is removed, and every pull request is compared with the latest release by swift package diagnose-api-breaking-changes in CI. See the API stability section of CONTRIBUTING.md.
Model.gpt_image_1_5forgpt-image-1.5andModel.omniModerationLatestforomni-moderation-latest(#485).
- CI: the API Breakage allowlist is emptied, because the 0.6.0 release is now the comparison baseline for the breaks it listed.
Components.Schemas.ResponseOutputTextAnnotationAddedEvent.descriptionprinted a presentannotationasOptional(...); it now prints the annotation itself, ornil.Demo: an error from a request made while polling an assistant run in Chats was silently ignored and the request repeated every second. It now stops the polling and is shown in the conversation. Link preview failures are logged instead of discarded.- JSON requests never checked the HTTP status, so an HTML gateway body surfaced as a
DecodingError, and withParsingOptions.relaxeda status of 400 or above whose body was missing required fields could decode as a successful result. Completion-handler, async, and Combine JSON calls now throw for a status of 400 or above, as raw and streaming calls already did: the decodedAPIErrorResponseorGeminiAPIErrorResponse, orOpenAIError.statusErrorwhen the body isn't an API error (#471).
0.6.0 - 2026-10-27
openAI.files(FilesEndpointProtocol) for the Files API:create(query:),retrieve(id:),list(query:)andlist(),delete(id:)andcontent(id:), in callback, async and Combine variants. The names match the official Java and Python SDKs'files.create/retrieve/list/delete/content.ListFilesQuerycarries thepurpose,limit,orderandafterparameters,content(id:)returns the file's contents asData, anddelete(id:)returns the generatedComponents.Schemas.DeleteFileResponse(#401).CreateFileQuery.expiresAfter, sent asexpires_after, to set a file's expiration policy (#401).OpenAIFileandListFilesResponse, hand-written replacements for the generated schemas of the same names. The spec'spurposeenum on the file object omitsevals, althoughevalsis a valid upload purpose, so the generated type would fail to decode a file uploaded for evals;OpenAIFile.Purposeis an open type that decodes any value.ListFilesResponse.firstIdandlastIdare optional, because the API returnsnullfor both on an empty page although the spec marks them required (#401).Demo: a Files screen (Misc → Files) that lists, uploads, retrieves, downloads and deletes files throughopenAI.files(#470).
- Breaking:
OpenAIProtocolgained afilesrequirement. Code that only callsopenAI.filesis unaffected, but custom conformances (e.g. test doubles) need to implement it (#401). FilesQuerywas renamed toCreateFileQuery, matchingfiles.create(query:).FilesQueryremains as a deprecated typealias, so existing code compiles unchanged. The API breakage check still reports thatfiles(query:)changed its parameter type fromFilesQuerytoCreateFileQuery, because it compares type names; these reports are allowlisted (#401).
files(query:)onOpenAIProtocol,OpenAIAsyncandOpenAICombine; useopenAI.files.create(query:), which returns the fullOpenAIFilerather than aFilesResultwith only anidand anamethe API doesn't return (#401).
audioCreateSpeechandfiles.content(id:)returned an API error response's JSON body as if it were the audio or file content, because responses read as raw data never had their HTTP status checked. They now throw for a status of 400 or above: the decodedAPIErrorResponse, orOpenAIError.statusErrorwhen the body isn't an API error, as streaming requests already did (#401).Demo: streamed chat replies kept updating long after the stream had ended; with a web search reply in Responses, the last update came 15.5 s later. ExyteChat'sChatViewapplies each change to its messages as a separate animated update of about half a second, while the stores published a change every 100 ms. The Chats and Responses screens now pass on at most one update every 500 ms, always with the latest messages (#475).Demo: deleting a conversation in Chats didn't remove it fromChatStore, so it came back the next time the conversations changed. It's now deleted, except while a reply is in progress, when an alert explains that it can't be (#475).
0.5.3 - 2026-10-08
Model.gpt_audio_1_5,Model.gpt_audioandModel.gpt_audio_mini, the audio-in, audio-out models for Chat Completions, also returned byModel.allModels(satisfying:). The README gained an Audio input and output with Chat Completions section coveringmodalities,audioOptions, audio input parts and streaming (#397).
Model.gpt_4o_audio_previewis deprecated, since OpenAI shut the model down on May 7th, 2026; useModel.gpt_audio_1_5. It is no longer returned byModel.allModels(satisfying:)(#397).- swift-openapi-runtime 1.12.0 → 1.12.2, which also moves swift-http-types from 1.3.1 to 1.8.0 (#439, #459).
- CI: the API Breakage allowlist is emptied, because the 0.5.2 release is now the comparison baseline for the breaks it listed.
Demo:ResponsesStore.replyFunctionCallincluded the completed.functionToolCallin the next request along with its.functionCallOutputItemParamwhileprevious_response_idwas already set, so the Responses API rejected the follow-up withDuplicate item found with id fc_.... The follow-up now sends only the function-call output, and the pending call stays available if that request fails (#457).
0.5.2 - 2026-10-07
ModelSpec, describing a model's capabilities as its OpenAI docs page lists them: endpoints, features, Responses API tools, supported reasoning efforts, and limitations the docs note, such as Chat Completions function calling being unsupported or requiringreasoning_effort: none(ModelSpec.Endpoint,.Feature,.Tool,.ReasoningEffortand.Limitation).ModelSpec.allcurrently covers the GPT-6 models;Model.allModels(satisfying:)filters them by their spec.Model.Filter.Endpoint,.Featureand.Toolare now typealiases for theModelSpectypes.ModelSpec.ReasoningEffortconverts toComponents.Schemas.ReasoningEffortandChatQuery.ReasoningEffort(xhighandmaxbecome.customValue, asChatQuery.ReasoningEfforthas no cases for them).Model.gpt6_astra,Model.gpt6_solandModel.gpt6_luna, also returned byModel.allModels(satisfying:)for the Chat Completions and Responses endpoints and the MCP tool.Model.Filter.Tool.mcpandModel.Filter.requiredTools, soModel.allModels(satisfying:)can narrow results to models that support remote MCP servers in the Responses API.ResponseStreamEvent.shellCall, covering the new shell-call streaming events (response.shell_call_command.added/delta/done,response.shell_call_output_content.delta/done) added by the latest OpenAPI spec.Tool.programmaticToolCallingTool, the tool case paired with theOutputItem.program/.programOutputresponse items; without it, decoding a response whosetoolsarray contains aprogrammatic_tool_callingtool would throw.ResponseStreamEvent.customToolCallInput, covering the previously unhandledresponse.custom_tool_call_input.delta/donestreaming events; without it, a custom-tool streaming response would fail the whole stream with anunknownEventTypeerror.InputItem.compactionTriggerItemParam,.programItemParam, and.programOutputItemParam, the item cases added by the latest OpenAPI spec; without them, decoding an input item withtype: "compaction_trigger","program", or"program_output"would throwunknownOneOfDiscriminator.ResponsesEndpoint.retrieveResponse(query:)andcancelResponse(id:), in callback, async and Combine variants, forGET /responses/{response_id}andPOST /responses/{response_id}/cancel.RetrieveModelResponseQuery.includeis sent asinclude[]query parameters. Cancelling takes just the response ID, matching the official Python SDK'sclient.responses.cancel(response_id), and only applies to responses created withbackground: true.CreateModelResponseQuery.contextManagement, encoded ascontext_management, for configuring server-side context compaction.- CI: an API Breakage workflow fails a pull request that changes the public API compared with the latest release tag. Consciously accepted breaks are listed in
.github/api-breakage-allowlist.txtwith a matching changelog entry. - CI: the Swift Build workflow now builds and tests on Linux with Swift 5.10, 6.0 and 6.3 containers, tests on macOS and the iOS Simulator, and builds for tvOS, watchOS and visionOS with Xcode. Tests written with Swift Testing only exist on toolchains that ship it (Swift 6); the XCTest suite runs everywhere.
- CONTRIBUTING.md: API stability policy, including how new endpoint groups are added as namespaces and how generated
Components.Schemastypes are treated. - This changelog.
- Breaking:
ResponsesEndpointProtocol,ResponsesEndpointAsyncandResponsesEndpointCombinegainedretrieveResponseandcancelResponserequirements. Code that only callsopenAI.responsesis unaffected, but custom conformances (e.g. test doubles) need to implement them. - Breaking:
GetModelResponseQuerywas renamed toRetrieveModelResponseQueryto matchretrieveResponse(query:). It had no public initializer before, so it couldn't be constructed outside the package. CreateModelResponseQuery.initgained acontextManagementparameter (defaulting tonil). Existing call sites compile unchanged; only code referring to the initializer by its full name, such asCreateModelResponseQuery.init(input:model:...)used as a function value, needs updating.- Breaking: Regenerated
Components.Schemasfrom the latest OpenAPI spec. Most of the reported breaks are mechanical (new cases added to generated enums, and generated memberwise initializers gaining parameters for new optional fields) and are allowlisted in.github/api-breakage-allowlist.txtwithout individual call-outs, matching how the0.5.1regeneration was documented. The changes worth knowing about if you read or construct these types directly:ResponseObject.instructionschanged fromString?toResponseObject.Instructions?, lettinginstructionsbe either a plain string or a list of input items.Instructionsis a generated two-case enum (.case1(String)for the string form,.case2([InputItem])for the list form); code that readinstructionsas aStringneeds to switch over it instead. This mirrors how the official Python SDK models the same field (Union[str, List[ResponseInputItem], None]) rather than adding a second property under a new name.Components.Schemas.ServiceTierwas renamed toServiceTierResponses.Components.Schemas.Conversation2was removed;Response.conversationandResponseProperties-derived types now useResponseConversationinstead.MCPToolCall.errorchanged fromString?toMCPToolCallError?.ResponseOutputTextAnnotationAddedEvent.annotationchanged fromOpenAPIObjectContainertoAnnotation?, matching the stricterAnnotationschema.FunctionToolCallOutput.callIdandFunctionCallOutputItemParam.callIdchanged fromStringtoString?.ResponseStreamEvent.reasoningwas renamed to.reasoningText, with its payload changing fromReasoningEventtoReasoningTextEvent.ResponseObject.toolChoicechanged fromSchemas.ToolChoiceParam?toSchemas.ToolChoiceParam. The generatedResponseProperties.toolChoiceis optional only because that schema is shared with request bodies, wheretool_choicemay be omitted; an actualResponsealways includes it, which we verified against the API docs and the official Python SDK (Response.tool_choice: ToolChoice, non-optional). This corrects a facade type that didn't match the real response shape, but is still a source-breaking type change for callers who readtoolChoiceas optional.OutputItem.webSearchToolCall's payload changed fromComponents.Schemas.WebSearchToolCallto a new hand-writtenWebSearchToolCalltype whoseactionis optional. The spec marksactionrequired, but the live API can emit aweb_search_calloutput item without one (e.g. aresponse.output_item.addedevent whilestatusis stillin_progress), and decoding threw akeyNotFounderror foractionwhenever that happened. This is an acknowledged upstream spec bug (openai/openai-openapi#572), not something specific to any one status. Callers that read.webSearchToolCall(let call)need to unwrapcall.actioninstead of accessing it directly.
Demo: a non-streaming Responses request to a reasoning model (e.g.gpt-5) always includes a.reasoningoutput item, andResponsesStore.createResponse(query:)didn't handle it (or the MCP output item cases), so it threwunhandledOutputIteminstead of completing.Components.Schemas.InputItemand theInputItemfacade failed to decode a valid{ "type": "item_reference", "id": "..." }payload withunknownOneOfDiscriminator. The generator only matched discriminator values declared as a plain string enum, butItemReferenceParam.typeis declared as a nullableanyOf: [<string enum>, {type: null}], which it didn't unwrap; theInputItemfacade also fixed the same bug independently, plus a stale"ItemReference"discriminator string (missing theParamsuffix) and a missing"message"match forEasyInputMessage.ResponseStreamEventandOutputItemdidn't round-trip throughJSONEncoder/JSONDecoder: both have a hand-writteninit(from:)that decodes the API'stypediscriminator, but noencode(to:), so the compiler-synthesized one wrapped values by enum case name instead of matching the API's shape; the hand-writtenResponseOutputItemAddedEvent/ResponseOutputItemDoneEventalso gained asequenceNumberfield they were missing, since re-encoding through them droppedsequence_number.ResponseStreamEvent.reasoningTextstreaming events never decoded:ModelResponseStreamEventTypelistened forresponse.reasoning.delta/.done, but the API sendsresponse.reasoning_text.delta/.done, so reasoning-text deltas always failed with anunknownEventTypeerror.make download-speccould leave the trackedopenapi.yamltruncated ifcurlwas interrupted mid-transfer; it now downloads to a temp file and moves it into place only on success.- Build warning in
ModelResponseEventsStreamInterpreterwhen logging a failed stream event decode in debug builds. - The test target compiles for the package's minimum iOS deployment target again; it used
Regex, which requires iOS 16. - Building on Linux with Swift 5.10 works again. swift-corelibs-foundation gained the async
URLSessionAPIs only in Swift 6, so the async client now bridges the completion-handler API on older Linux toolchains.
0.5.1 - 2026-07-21
refusalfield on the streaming chat completion delta (#408).reasoningContenton assistant chat messages for providers that return reasoning (#402).annotationsonChatStreamResult(#399).
- Regenerated
Components.Schemasfrom the updated OpenAPI spec (#433). This changed public generated types: transcription segment and word timestamps moved fromFloattoDouble,ImageGenTool.SizePayloadlost its fixed cases,responseIdwas removed from the response audio events, andChatResult.Choice.Message.Annotationmoved to a top-levelAnnotationtype. TwoChatCompletionMessageParaminitializers were removed. - swift-openapi-runtime 1.11.0 → 1.12.0 (#424).
0.5.0 - 2026-06-05
modelis optional inCreateModelResponseQueryfor the stored-prompt (prompt_id) flow (#419).
- Regenerated
Components.Schemasfrom the fresh OpenAPI spec (#423); the release notes flagged possible breaking changes. - swift-openapi-runtime 1.8.2 → 1.11.0 (#416).
- Missing
namefield onResponseFunctionCallArgumentsDoneEvent(#420).
0.4.9 - 2026-04-30
completion_tokens_detailsonCompletionUsage(#411).prompt_cache_keyonCreateModelResponseQuery(#412).- Dependabot configuration for GitHub Actions and Swift dependencies (#414).
ChoiceDeltaToolCall.indexis required again (#388).ChatQuerydescription output is easier to read (#394).- Documentation:
response_formatversustextfor structured outputs (#413); security policy points to the private reporting channel (#410).
Older releases are documented on the GitHub Releases page.