Chore/sync latest openapi spec - #443
Conversation
- make generate now downloads the current openapi.yaml from openai/openai-openapi before preparing/generating, so it's a single command to refresh types (new `make download-spec` target). - Fix fix_recursive_reference.py: it silently no-op'd against the new spec (upstream switched to double-quoted `$recursiveRef: "#"`) and only handled a single recursive anchor; it now matches either quote style and resolves each occurrence to its own enclosing schema (CompoundFilter and the new BetaCompoundFilter). - Fix extract_components.py: dedupe repeated identical typealiases emitted in the same struct scope (ModerationPolicyParam now references ModerationConfigParam twice), which caused an invalid redeclaration build error. - Drop the WebSearchActionSearch/query required-property workaround; upstream now marks it optional. - Regenerate openapi.yaml and Components.swift from the refreshed spec. - Sync ResponseObject with the refreshed schema: renamed/relocated types (Conversation2 -> ResponseConversation, ServiceTier -> ServiceTierResponses, truncation moved off ResponseProperties), add moderation/promptCacheOptions/promptCacheDiagnostics, deprecate promptCacheRetention, and fix instructions/metadata typing to match the schema. tools and toolChoice are verified against openai-python and the API docs to stay non-optional despite the shared ResponseProperties component marking them optional for its request-body use. - Add the OutputItem facade's 3 new cases (program, programOutput, additionalTools) so its decoder switch stays exhaustive. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The OpenAPI spec sync replaced the annotation field's OpenAPIObjectContainer
type with a discriminated Annotation oneOf, so the empty {} test fixture no
longer decodes. Use a valid url_citation payload instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The critical tool-facade decoding issue and unresolved public API compatibility breaks must be addressed.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Synchronizes the project with the latest OpenAPI specification and updates related models, generation scripts, documentation, and tests.
Changes:
- Downloads the latest specification before generation.
- Updates response schemas, output items, mocks, and fixtures.
- Generalizes generation workarounds and documents the workflow.
File summaries
| File | Summary |
|---|---|
Tests/OpenAITests/ResponseObjectCodingTests.swift |
Updates response decoding fixtures. |
Tests/OpenAITests/MockServerSentEvent.swift |
Updates the annotation fixture. |
Tests/OpenAITests/Extensions/ResponseObject+Mock.swift |
Updates response mocks for new fields. |
Sources/OpenAI/Public/Schemas/Facade/OutputItem.swift |
Critical (1 vote): The Tool facade lacks the programmatic_tool_calling case, so valid responses may fail decoding. |
Sources/OpenAI/Public/Models/Responses API/ResponseObject.swift |
Moderate (1 vote each): Six existing public members are retyped or changed incompatibly without compatibility shims or documented allowlisting. |
Scripts/fix_recursive_reference.py |
Generalizes recursive-reference handling. |
Scripts/extract_components.py |
Removes duplicate generated typealiases. |
Makefile |
Moderate (3 votes): Interrupted downloads can truncate the tracked specification; use a temporary file and atomic replacement. |
CONTRIBUTING.md |
Documents the updated generation workflow. |
Review details
Suppressed comments (6)
Sources/OpenAI/Public/Models/Responses API/ResponseObject.swift:17
ResponseObject.Truncationis an existing public typealias, but this changes its underlying type fromSchemas.ResponseProperties.TruncationPayloadtoSchemas.Response.Value3Payload.TruncationPayload.CONTRIBUTING.md:34-44,71-79requires public symbols to remain additive and unavoidable breaks to be explicitly allowlisted and documented; the current allowlist and Unreleased changelog have no entry for this break. Please preserve a compatibility type where possible, or record the accepted break and migration before merging.
public typealias Truncation = Schemas.Response.Value3Payload.TruncationPayload
Sources/OpenAI/Public/Models/Responses API/ResponseObject.swift:28
- This retypes the existing public
conversationmember fromSchemas.Conversation2?toSchemas.ResponseConversation?, which is a source/API break for clients compiled against the old member. The additive-only policy inCONTRIBUTING.md:34-44,71-79requires a compatibility shim where possible or an explicit allowlist and CHANGELOG migration for an unavoidable break; neither is included here.
/// The conversation that this response belonged to. Input items and output items from this response were automatically added to this conversation.
public let conversation: Schemas.ResponseConversation?
Sources/OpenAI/Public/Models/Responses API/ResponseObject.swift:45
- This retypes the existing public
instructionsmember fromString?to the generatedInstructions?one-of. That breaks source compatibility for every caller using the old string property, contrary to the additive-only API policy inCONTRIBUTING.md:34-44,71-79; retain a deprecated compatibility surface or explicitly allowlist and document the unavoidable break.
/// A system (or developer) message inserted into the model's context, either as a plain string or a list of input items.
///
/// When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to swap out system (or developer) messages in new responses.
public let instructions: Instructions?
Sources/OpenAI/Public/Models/Responses API/ResponseObject.swift:56
- Changing
metadatafrom nonoptional[String: String]to optional is a public retype that forces existing consumers to add unwrapping, while the updated OpenAPIResponsestill listsmetadataas required (openapi.yaml:61254-61266). This conflicts with the additive-only policy inCONTRIBUTING.md:34-44; preserve the existing facade type where possible, or explicitly allowlist and document the break.
/// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard.
///
/// Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters.
public let metadata: [String: String]?
Sources/OpenAI/Public/Models/Responses API/ResponseObject.swift:133
- Making the existing public
toolChoicemember nonoptional is another public retype and changes both source compatibility and decoding behavior for payloads that omit the key. The additive-only policy inCONTRIBUTING.md:34-44,71-79requires retaining compatibility where possible or documenting/allowlisting an unavoidable break; only the test fixtures were updated here.
/// How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call.
public let toolChoice: Schemas.ToolChoiceParam
Sources/OpenAI/Public/Models/Responses API/ResponseObject.swift:119
- This retypes the existing public
serviceTiermember fromSchemas.ServiceTier?toSchemas.ServiceTierResponses?, so downstream code using the previous enum type no longer compiles.CONTRIBUTING.md:34-44,71-79requires preserving public symbols or explicitly accepting breaks through the allowlist and CHANGELOG; this PR does neither for this change.
public let serviceTier: Schemas.ServiceTierResponses?
- Files reviewed: 9/11 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The OpenAPI sync added response.shell_call_command.{added,delta,done}
and response.shell_call_output_content.{delta,done} events, but the
hand-written ResponseStreamEvent facade and its decoders weren't
updated to match, so these would have failed to decode at runtime.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Demo isn't covered by any CI workflow, so nothing else catches it when DemoChat falls behind a public API change (e.g. a Facade enum gaining a case that an exhaustive switch doesn't handle). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tool.programmaticToolCallingTool was missing, so decoding a response whose tools array contains that tool would throw. Also handle the previously unimplemented response.custom_tool_call_input.delta/done streaming events, and fix reasoning-text streaming events, which never decoded because ModelResponseStreamEventType listened for response.reasoning.delta/.done instead of the actual response.reasoning_text.delta/.done sent by the API. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
curl -o writes directly into the tracked file as it streams, so an interrupted transfer (network drop, Ctrl-C) could leave openapi.yaml truncated and require a manual git checkout to recover. Download to a temp file and move it into place only after the transfer succeeds. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Critical public API and decoding issues remain, along with a generation race and missing stream coverage.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
Makefile:49
- Both commands use the single fixed
openapi.yaml.tmppath. Concurrentmake generate/make download-specinvocations can overwrite or move each other's temporary file, causing one generation to read a partially written spec or fail onmv; use a per-invocation temporary file and remove it with a trap before the final move.
curl -fsSL "$(OPENAPI_SPEC_URL)" -o "$(PROJECT_DIR)/openapi.yaml.tmp"
mv "$(PROJECT_DIR)/openapi.yaml.tmp" "$(PROJECT_DIR)/openapi.yaml"
- Files reviewed: 18/20 changed files
- Comments generated: 9
- Review effort level: Lite
Allowlist the two api-digester messages for the String? -> Instructions? type change and explain the migration in the changelog, per the "Accepting a break" process in CONTRIBUTING.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
swift package diagnose-api-breaking-changes against 0.5.1 reports 322 breaking changes from regenerating Components.Schemas. Most are mechanical (new enum cases, memberwise inits gaining parameters for new optional fields); allowlist those without individual prose, same as the 0.5.1 regeneration. Call out the handful of real renames/type changes (ServiceTier, Conversation2, MCPToolCall.error, ResponseOutputTextAnnotationAddedEvent.annotation, the callId properties turning optional, ResponseStreamEvent.reasoning -> .reasoningText) in the changelog alongside the instructions entry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
swift-openapi-generator recommends against exposing generated code in a package's public API, since spec changes that are additive in OpenAPI can be breaking in generated Swift. Explain in CONTRIBUTING.md why we do it anyway, and that the API stability section and the API Breakage workflow exist to make that trade-off safe. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Name this one explicitly in the changelog rather than leaving it in the bulk allowlist: it fixes a facade type that didn't match the real response shape (verified against the API docs and openai-python's non-optional Response.tool_choice), but is still a breaking type change for callers that read toolChoice as optional. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cover response.shell_call_command.added/delta/done and response.shell_call_output_content.delta/done in ModelResponseEventsStreamInterpreterTests, matching the coverage the reasoning and custom-tool-call branches already had. A typo in any of the five discriminator strings or target decoders would previously only surface in a live stream. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved schema mappings, service-tier compatibility, and Demo output-item handling issues block approval.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
Sources/OpenAI/Public/Schemas/Facade/OutputItem.swift:38
- These newly decodable output-item variants are not handled by DemoChat: its non-streaming and streaming output handlers fall through to
StoreError.unhandledOutputItemfor.program,.programOutput, and.additionalTools(seeDemo/DemoChat/Sources/ResponsesStore.swift:498,672,711). A valid response using these items will therefore fail in the Demo; add explicit handling/ignoring cases in all three switches, with coverage, before exposing them here.
/// A program item generated by the model.
case program(Schemas.Program)
/// The output of a program item.
case programOutput(Schemas.ProgramOutput)
- Files reviewed: 19/21 changed files
- Comments generated: 2
- Review effort level: Lite
Components.Schemas.InputItem's decoder rejected a valid
{ "type": "item_reference", "id": "..." } payload with
unknownOneOfDiscriminator, per review on #443. ItemReferenceParam.type
is declared as a nullable anyOf (an OpenAPI 3.1 pattern), and the
generator's discriminator-value matching didn't unwrap it before
looking for a string enum; fixed in the local swift-openapi-generator
fork and regenerated.
The hand-maintained InputItem facade had the same class of bug
independently: it matched the stale "ItemReference" string (missing
the Param suffix) instead of "ItemReferenceParam"/"item_reference",
and was missing the "message" runtime value for EasyInputMessage.
While aligning it, also added the compactionTriggerItemParam,
programItemParam, and programOutputItemParam cases that this spec
sync introduced but the facade never gained, so decoding those input
items no longer throws.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
One or more issues must be addressed before approval.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (2)
Makefile:49
- If
curlis interrupted or fails after creating the fixed-name temp file,openapi.yaml.tmpis left behind because there is no cleanup. Since the root.gitignoredoes not ignore this path, a failedmake download-specleaves an untracked artifact that can be accidentally staged; use a unique temp file with anEXITtrap (or remove the temp file on failure) before moving it into place.
curl -fsSL "$(OPENAPI_SPEC_URL)" -o "$(PROJECT_DIR)/openapi.yaml.tmp"
mv "$(PROJECT_DIR)/openapi.yaml.tmp" "$(PROJECT_DIR)/openapi.yaml"
Sources/OpenAI/Public/Schemas/Facade/ResponseStreamEvent.swift:322
- These branches add a second, independent decoding dispatch table for the public
ResponseStreamEventfacade, but the new tests exercise onlyModelResponseEventsStreamInterpreter's private dispatch path. A typo here would leaveJSONDecoder().decode(ResponseStreamEvent.self, from:)broken while the interpreter tests still pass; add direct facade-decoding tests for the new reasoning-text, shell-call, and custom-tool-input events (similar toResponseFunctionCallArgumentsDoneEventTests.testResponseStreamEventFacadeExposesName).
case .responseReasoningTextDelta:
self = .reasoningText(.delta(try Schemas.ResponseReasoningTextDeltaEvent(from: decoder)))
case .responseReasoningTextDone:
self = .reasoningText(.done(try Schemas.ResponseReasoningTextDoneEvent(from: decoder)))
- Files reviewed: 21/23 changed files
- Comments generated: 3
- Review effort level: Lite
swift package diagnose-api-breaking-changes flags InputItem.compactionTriggerItemParam/.programItemParam/.programOutputItemParam as breaking, since it's a non-frozen public enum and an exhaustive switch over it won't compile against the new cases. Same class of mechanical break as Tool.programmaticToolCallingTool; allowlist it and fold the changelog entry into the existing Added bullet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
download-spec had to move above generate so generate could depend on it, but that made download-spec the first real target and therefore GNU make's default goal. A plain \`make\` silently only refreshed openapi.yaml instead of running the full pipeline. Set .DEFAULT_GOAL explicitly so target order doesn't matter. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
download-spec wrote to a fixed openapi.yaml.tmp path before the atomic mv into place. Two concurrent make download-spec/generate invocations sharing that name could interleave: one's mv could move the file out while the other's curl was still writing it, leaving openapi.yaml truncated or corrupted despite the atomic rename. Use mktemp for a unique path per invocation and a trap to remove it on any exit, so a failed or interrupted download never leaves a temp file behind either. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The Makefile cleanup trap is not POSIX-portable, and requested positive decoding and round-trip fixtures are missing.
Review details
Suppressed comments (3)
Makefile:55
makerecipes run under/bin/sh, andEXITis not a portable trap condition on POSIX shells such asdash(used by default on Linux). On those systems thistrapcommand fails, so a successful download leaves the temporaryopenapi.yaml.XXXXXXfile behind and a failed/interrupted transfer is not cleaned up as intended. Use the POSIX0condition here, or explicitly run this recipe with Bash.
trap 'rm -f "$$tmp"' EXIT; \
Sources/OpenAI/Public/Models/Responses API/ResponseObject.swift:64
- The new response fields added here are only covered by the minimal-response fixtures with those keys absent. Add at least one positive decoding fixture containing
moderation,prompt_cache_diagnostics,prompt_cache_options, the union-shapedinstructions, and a responseservice_tier; otherwise incorrect generated types, coding keys, or requiredness can pass the current tests unnoticed.
/// Moderation results or errors for the response input and output.
public let moderation: Schemas.Moderation?
Sources/OpenAI/Public/Schemas/Facade/OutputItem.swift:44
- The new facade mappings for
program,programOutput, andadditionalToolsare not exercised by any test. BecauseOutputItem.init(from:)delegates to the generated one-of and then switches over its cases, a generated case/type mismatch can compile successfully but still fail at runtime. Add decode/round-trip fixtures for these three discriminator values, followingInputItemCodingTests.
/// A program item generated by the model.
case program(Schemas.Program)
/// The output of a program item.
case programOutput(Schemas.ProgramOutput)
/// A tool search call.
case toolSearchCall(Schemas.ToolSearchCall)
/// The output of a tool search call.
case toolSearchOutput(Schemas.ToolSearchOutput)
/// The additional tools made available for a request.
case additionalTools(Schemas.AdditionalTools)
- Files reviewed: 21/23 changed files
- Comments generated: 0 new
- Review effort level: Lite
* Add GPT-5.6 models
Added new GPT-5.6 model variants:
- gpt-5.6-sol: Most capable GPT-5.6 model for frontier reasoning and agentic workloads
- gpt-5.6-terra: Balanced GPT-5.6 model for general-purpose workloads
- gpt-5.6-luna: GPT-5.6 model optimized for cost-sensitive, high-volume workloads
* ci: gate pull requests on public API breakage against the latest release
Runs swift package diagnose-api-breaking-changes against the newest semver tag on every pull request and push to main, publishes the report in the job summary, and fails on any break that is not listed in .github/api-breakage-allowlist.txt. A manual run can pass a different baseline.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* ci: build and test on Linux 5.10, 6.0, 6.3 and every declared Apple platform
Package.swift declares Swift 5.10 and macOS, iOS, tvOS, watchOS and visionOS, but CI only ran one unpinned Linux toolchain. Linux now builds and tests in swift:5.10, 6.0 and 6.3 containers; macOS and the iOS Simulator run the tests; tvOS, watchOS and visionOS are built with xcodebuild.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* ci: pin codeql-action to v4 so Dependabot can track it
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test: compile the test target for the minimum iOS deployment target
testModerationsIterable used Regex and String.replacing(_:with:), which require iOS 16 while the package declares iOS 13, so the test bundle could not be built for iOS. Foundation's replacingOccurrences(of:with:options:) does the same job on every platform.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix: avoid optional interpolation warning in the debug decode log
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs: add CHANGELOG and an API stability policy
CHANGELOG.md follows Keep a Changelog and is seeded from the 0.4.9, 0.5.0 and 0.5.1 release notes, including the public API changes 0.5.1 shipped. CONTRIBUTING.md gains an API stability section: additive-only public API, how the breakage gate works, how to accept an unavoidable break, and how regenerated Components.Schemas types are treated.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* ci: resolve like a consumer on older toolchains and pick the iOS simulator by UDID
Package.resolved pins swift-openapi-runtime 1.12.0, whose manifest needs Swift tools 6.1, so the 5.10 and 6.0 lanes failed before compiling anything. A consumer of this library never uses our Package.resolved, so those lanes now delete it and resolve fresh, which is what such a consumer gets. The iOS Simulator lane picked a device name that only exists in an older runtime; it now takes an iPhone from the newest installed iOS runtime and addresses it by UDID.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix: build on Linux with Swift 5.10 by bridging the async URLSession API
swift-corelibs-foundation gained data(for:delegate:) in Swift 6.0, so on Linux toolchains before that URLSession did not satisfy URLSessionProtocol and the package failed to compile, contradicting the declared Swift 5.10 minimum. A Linux-only, pre-Swift-6 extension now bridges dataTask(with:completionHandler:) to async/await, including cancellation.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix: disambiguate dataTask(with:completionHandler:) in the Linux 5.10 shim
The call was ambiguous between Foundation's method and the URLSessionProtocol overload that returns URLSessionDataTaskProtocol. Coerce to URLSessionDataTask, as URLSessionProtocol.swift already does.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test: compile Swift Testing suites only where the Testing module exists
Swift Testing ships with Swift 6 toolchains. The package declares Swift 5.10, and swift test on that toolchain failed with 'no such module Testing'. The eight Swift Testing files are now wrapped in #if canImport(Testing); the XCTest suite still runs on every toolchain.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs: new endpoint groups are added as namespaces
Adding methods to OpenAIProtocol, OpenAIAsync or OpenAICombine is reported as a break by the API gate because external conformers stop compiling. New endpoint groups follow the Responses API pattern instead: one namespace property on OpenAIProtocol and the methods on the endpoint protocol in all three flavours.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* ci: keep the API allowlist free of comments
swift package diagnose-api-breaking-changes matches allowlist entries literally and matches none of them when the file contains a comment or blank line. The file now starts empty and the format is documented in CONTRIBUTING.md and in the workflow summary.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Chore: Auto-download latest spec in make generate, sync generated types
- make generate now downloads the current openapi.yaml from
openai/openai-openapi before preparing/generating, so it's a single
command to refresh types (new `make download-spec` target).
- Fix fix_recursive_reference.py: it silently no-op'd against the new
spec (upstream switched to double-quoted `$recursiveRef: "#"`) and
only handled a single recursive anchor; it now matches either quote
style and resolves each occurrence to its own enclosing schema
(CompoundFilter and the new BetaCompoundFilter).
- Fix extract_components.py: dedupe repeated identical typealiases
emitted in the same struct scope (ModerationPolicyParam now
references ModerationConfigParam twice), which caused an invalid
redeclaration build error.
- Drop the WebSearchActionSearch/query required-property workaround;
upstream now marks it optional.
- Regenerate openapi.yaml and Components.swift from the refreshed
spec.
- Sync ResponseObject with the refreshed schema: renamed/relocated
types (Conversation2 -> ResponseConversation, ServiceTier ->
ServiceTierResponses, truncation moved off ResponseProperties), add
moderation/promptCacheOptions/promptCacheDiagnostics, deprecate
promptCacheRetention, and fix instructions/metadata typing to match
the schema. tools and toolChoice are verified against openai-python
and the API docs to stay non-optional despite the shared
ResponseProperties component marking them optional for its
request-body use.
- Add the OutputItem facade's 3 new cases (program, programOutput,
additionalTools) so its decoder switch stays exhaustive.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* test: fix annotation-added SSE fixture for stricter Annotation schema
The OpenAPI spec sync replaced the annotation field's OpenAPIObjectContainer
type with a discriminated Annotation oneOf, so the empty {} test fixture no
longer decodes. Use a valid url_citation payload instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat: handle new shell-call streaming events from the latest spec
The OpenAPI sync added response.shell_call_command.{added,delta,done}
and response.shell_call_output_content.{delta,done} events, but the
hand-written ResponseStreamEvent facade and its decoders weren't
updated to match, so these would have failed to decode at runtime.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: instruct agents to also build the Demo app for relevant changes
Demo isn't covered by any CI workflow, so nothing else catches it when
DemoChat falls behind a public API change (e.g. a Facade enum gaining
a case that an exhaustive switch doesn't handle).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix: add missing Tool/stream-event cases found in OpenAPI sync review
Tool.programmaticToolCallingTool was missing, so decoding a response
whose tools array contains that tool would throw. Also handle the
previously unimplemented response.custom_tool_call_input.delta/done
streaming events, and fix reasoning-text streaming events, which never
decoded because ModelResponseStreamEventType listened for
response.reasoning.delta/.done instead of the actual
response.reasoning_text.delta/.done sent by the API.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix: download openapi.yaml atomically to avoid a truncated spec
curl -o writes directly into the tracked file as it streams, so an
interrupted transfer (network drop, Ctrl-C) could leave openapi.yaml
truncated and require a manual git checkout to recover. Download to a
temp file and move it into place only after the transfer succeeds.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: accept the ResponseObject.instructions breaking type change
Allowlist the two api-digester messages for the String? -> Instructions?
type change and explain the migration in the changelog, per the
"Accepting a break" process in CONTRIBUTING.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: accept remaining API breaks from the OpenAPI spec regen
swift package diagnose-api-breaking-changes against 0.5.1 reports 322
breaking changes from regenerating Components.Schemas. Most are
mechanical (new enum cases, memberwise inits gaining parameters for
new optional fields); allowlist those without individual prose, same
as the 0.5.1 regeneration. Call out the handful of real renames/type
changes (ServiceTier, Conversation2, MCPToolCall.error,
ResponseOutputTextAnnotationAddedEvent.annotation, the callId
properties turning optional, ResponseStreamEvent.reasoning ->
.reasoningText) in the changelog alongside the instructions entry.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: note why we expose generated Components.Schemas publicly
swift-openapi-generator recommends against exposing generated code in
a package's public API, since spec changes that are additive in
OpenAPI can be breaking in generated Swift. Explain in CONTRIBUTING.md
why we do it anyway, and that the API stability section and the API
Breakage workflow exist to make that trade-off safe.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: call out ResponseObject.toolChoice becoming non-optional
Name this one explicitly in the changelog rather than leaving it in
the bulk allowlist: it fixes a facade type that didn't match the real
response shape (verified against the API docs and openai-python's
non-optional Response.tool_choice), but is still a breaking type
change for callers that read toolChoice as optional.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* test: add fixtures for the shell-call streaming events
Cover response.shell_call_command.added/delta/done and
response.shell_call_output_content.delta/done in
ModelResponseEventsStreamInterpreterTests, matching the coverage the
reasoning and custom-tool-call branches already had. A typo in any of
the five discriminator strings or target decoders would previously
only surface in a live stream.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix: match item_reference discriminator and align InputItem facade
Components.Schemas.InputItem's decoder rejected a valid
{ "type": "item_reference", "id": "..." } payload with
unknownOneOfDiscriminator, per review on MacPaw#443. ItemReferenceParam.type
is declared as a nullable anyOf (an OpenAPI 3.1 pattern), and the
generator's discriminator-value matching didn't unwrap it before
looking for a string enum; fixed in the local swift-openapi-generator
fork and regenerated.
The hand-maintained InputItem facade had the same class of bug
independently: it matched the stale "ItemReference" string (missing
the Param suffix) instead of "ItemReferenceParam"/"item_reference",
and was missing the "message" runtime value for EasyInputMessage.
While aligning it, also added the compactionTriggerItemParam,
programItemParam, and programOutputItemParam cases that this spec
sync introduced but the facade never gained, so decoding those input
items no longer throws.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* chore: allowlist the InputItem facade's new enum cases
swift package diagnose-api-breaking-changes flags
InputItem.compactionTriggerItemParam/.programItemParam/.programOutputItemParam
as breaking, since it's a non-frozen public enum and an exhaustive
switch over it won't compile against the new cases. Same class of
mechanical break as Tool.programmaticToolCallingTool; allowlist it and
fold the changelog entry into the existing Added bullet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix: keep generate as the Makefile's default goal
download-spec had to move above generate so generate could depend on
it, but that made download-spec the first real target and therefore
GNU make's default goal. A plain \`make\` silently only refreshed
openapi.yaml instead of running the full pipeline. Set
.DEFAULT_GOAL explicitly so target order doesn't matter.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix: use a unique temp file when downloading the OpenAPI spec
download-spec wrote to a fixed openapi.yaml.tmp path before the
atomic mv into place. Two concurrent make download-spec/generate
invocations sharing that name could interleave: one's mv could move
the file out while the other's curl was still writing it, leaving
openapi.yaml truncated or corrupted despite the atomic rename.
Use mktemp for a unique path per invocation and a trap to remove it
on any exit, so a failed or interrupted download never leaves a temp
file behind either.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Victor Sanahuja <piscue@gmail.com>
Co-authored-by: Krivoblotsky <krivoblotsky@macpaw.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Oleksii <am.nezhyborets@gmail.com>
What
make generatedownload the latest spec before generating.Why
Planning one working on the project. Better to do it with the updated and complete types set.
Affected Areas
More Info
Demoapp currently fails to build locally on newer Xcode toolchains (unrelated to this PR's changes — a pre-existing linker incompatibility with the pinned ExyteChat2.7.10dependency). Fixing it requires a breaking ExyteChat 2.x → 3.x migration ofDemoChat, which we'll do separately. Tracked in Demo app fails to build on newer Xcode: ExyteChat 2.x needs a 3.x migration #444.