Skip to content

1.2.0

Latest

Choose a tag to compare

@mattt mattt released this 06 Nov 15:54
· 2 commits to main since this release
Immutable release. Only release title and notes can be modified.
749319d

Important

If you use multi-turn sessions, tools, structured responses, or streaming, check these changes:

  • OpenAILanguageModel with apiVariant: .responses and OpenResponsesLanguageModel now send earlier assistant messages, which they used to drop, so the model sees both sides of a conversation and input tokens grow with each turn. If you set previous_response_id or conversation through extraBody, the server now gets assistant text twice, as it already did user messages (#401).
  • A stream from OpenAI, Open Responses, Anthropic, or Gemini now throws HTTPTransportError with .providerError when the provider sends an error event after a successful HTTP response. Before, the stream finished with the partial text, or threw a generic error when there was none (#379).
  • respond on AnthropicLanguageModel (#396) and OllamaLanguageModel (#348) now continues after tool calls, so it makes more requests and returns the model's answer instead of stopping after the first round. Past the tool-round limit, which defaults to 8, it throws ToolRoundLimitExceeded. With Anthropic, toolCallingMode: .required or a toolChoice of .any or .tool applies to every request, so the model can keep calling tools until that limit.
  • MLXLanguageModel and LlamaLanguageModel now call tools before a structured response, instead of going straight to constrained generation, so tools can run and the tool-round limit applies (#389).
  • HTTP models now honor includeSchemaInPrompt, which defaults to true, so a response that isn't String adds the schema instructions to the last prompt. Pass includeSchemaInPrompt: false to leave them out (#377).
  • A response of a type that can't be empty, such as Int, Bool, or a structure with required properties, now throws ToolExecutionStopped when a tool execution delegate stops it (#390, #397).
  • An image in a tool output now reaches Anthropic, Gemini, and Ollama as an image where the provider supports its type, so requests and saved transcripts can be larger, and Gemini needs version 3 or later for it. On the system model and FoundationLanguageModel, it goes as an attachment on OS 27 with Swift 6.4, and otherwise throws PromptBridgeError.attachmentsUnavailable, where it used to go as text. A local file in a tool output that isn't a readable image now throws after the tool has run (#312).
  • A String tool output now reaches Anthropic, Ollama, Gemini, MLX, and llama.cpp as plain text instead of JSON (#381), and a structured tool output reaches Gemini as plain JSON under result (#382).

This release adds dynamic profiles, which follow the Foundation Models 27 API. A profile can change a session's model, instructions, tools, generation options, and transcript projection without rebuilding the session, and @SessionProperty gives profiles, dynamic instructions, and tools isolated session state (#313, #315, #344, #345, #346, #347, #348, #349, #398). Unlike Foundation Models, a profile must set a model.

Support differs by model. onToolCall and onToolOutput run on OpenAI, Open Responses, Anthropic, Gemini, and Ollama. They don't run on MLX, llama.cpp, Private Cloud Compute, FoundationLanguageModel, or the system model, and Core ML doesn't run tools. The system model takes profiles only in apps built with Swift 6.4 or later that run on OS 27 or later. The README describes what each model does (#317, #402).

Two uses stop the process here, where Foundation Models ignores the write or returns the default: writing history from a tool or dynamic instructions, and using @SessionProperty where no session binds it, such as in a delegate. Use session.properties there. SystemLanguageModel, FoundationLanguageModel, and PrivateCloudComputeLanguageModel ignore maximumToolRounds, so .required can loop until a delegate returns .stop. When a turn is replayed, edits to a response in the transcript take precedence on OpenAI, Open Responses, and Gemini, with limits that the README states (#401).

Also: with HTTP models, cancelling during toolCallDecision no longer runs the tool (#344, #345, #346, #347, #348). SystemLanguageModel, FoundationLanguageModel, and PrivateCloudComputeLanguageModel report usage on OS 27 when built with Swift 6.4 or later (#353). The package builds on WASI, where a model needs an explicit transport: (#370), and for tvOS with Xcode 27, where SystemLanguageModel isn't available (#400). The minimum versions of EventSource and swift-http-types are now 1.6.0 and 1.5.0.

Thanks to @qoli for dynamic profiles, session properties, and images in tool outputs (#312, #313, #315, #317, #344, #345, #346, #347, #348, #349); to @akbashev for schema prompts on HTTP models (#377) and the system model's usage (#353); to @mergesort for WASI (#370); and to @jihtsan for provider errors in streams (#379).

What's Changed

  • Attach generated responses to live tests by @mattt in #371
  • Propagate known provider SSE error events by @jihtsan in #379
  • Say a response's schema after the prompt for HTTP models by @akbashev in #377
  • Report the system model's usage from Foundation Models 27 by @akbashev in #353
  • Preserve attachments in tool outputs by @qoli in #312
  • Add session properties and Foundation Models 27 HistoryView compatibility by @qoli in #313
  • Fix README dependency requirements and MLX test command by @mattt in #383
  • Give each session its own property defaults and report the caller's tool in errors by @mattt in #380
  • Restore image placeholders and plain text in tool outputs by @mattt in #381
  • Send plain JSON in Gemini structured tool outputs by @mattt in #382
  • Raise the Linux CI timeout to 15 minutes by @mattt in #386
  • Add shared profile execution behind Compatibility SPI by @qoli in #315
  • Build on WASI by @mergesort in #370
  • Call tools before structured output in MLX and llama.cpp by @mattt in #389
  • Expect final-request usage in the MLX tool tests by @mattt in #392
  • Count structured stream requests when the consumer cancels by @mattt in #391
  • Keep callback history when a profile context resolves again by @mattt in #394
  • Integrate dynamic profiles with OpenAI Tool loops by @qoli in #344
  • Integrate dynamic profiles with OpenResponses Tool loops by @qoli in #345
  • Integrate dynamic profiles with Anthropic Tool loops by @qoli in #346
  • Integrate dynamic profiles with Gemini Tool loops by @qoli in #347
  • Integrate dynamic profiles with Ollama Tool loops by @qoli in #348
  • Fix handoff usage and schema setting changes in tool loops by @mattt in #395
  • Throw ToolExecutionStopped from stopped HTTP responses by @mattt in #390
  • Continue after tool calls in Anthropic responses by @mattt in #396
  • Project profile history into native Foundation Models sessions by @qoli in #349
  • Throw ToolExecutionStopped from stopped SystemLanguageModel responses by @mattt in #397
  • Evaluate profiles again before native tool continuations by @mattt in #398
  • Correct the dynamic profile and tool round doc comments by @mattt in #399
  • Document dynamic profiles by @qoli in #317
  • Fix tvOS builds with Xcode 27 by @mattt in #400
  • Send assistant messages in Responses requests by @mattt in #401
  • Correct the README and doc comments before 1.2.0 by @mattt in #402
  • Bump README install snippets to 1.2.0 by @mattt in #403

New Contributors

Full Changelog: 1.1.1...1.2.0