feat(apple): add guardrails option to createAppleProvider - #228
feat(apple): add guardrails option to createAppleProvider#228robertherber wants to merge 3 commits into
Conversation
Apps transforming legitimate but sensitive content (for example health
data) hit guardrailViolation errors with the default Foundation Models
guardrails. Apple provides a permissive guardrails mode for exactly this
case; expose it as a provider-level option threaded through to the
LanguageModelSession's SystemLanguageModel:
createAppleProvider({ guardrails: 'permissiveContentTransformations' })
Defaults to the system guardrails when omitted.
https://developer.apple.com/documentation/foundationmodels/improving-the-safety-of-generative-model-output
|
@robertherber is attempting to deploy a commit to the Callstack Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-in Apple Foundation Models guardrails mode at the provider level so apps that transform legitimate but sensitive content (e.g., health data) can reduce guardrailViolation refusals while keeping the default behavior unchanged when the option is omitted.
Changes:
- Adds a
guardrailsoption tocreateAppleProvider, stores it onAppleLLMChatLanguageModel, and forwards it on each nativegenerateText/generateStreamcall. - Extends the native generation options to include an optional
guardrailsfield and uses it to create the appropriateSystemLanguageModelin Swift. - Documents the new option in the Apple “Generating” docs.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| website/src/docs/apple/generating.md | Adds documentation for the new provider-level guardrails option and links to Apple’s guidance. |
| packages/apple-llm/src/NativeAppleLLM.ts | Extends TurboModule options with a guardrails field passed across the JS↔native boundary. |
| packages/apple-llm/src/ai-sdk.ts | Adds guardrails to createAppleProvider and forwards it through AppleLLMChatLanguageModel to native calls. |
| packages/apple-llm/ios/AppleLLMImpl.swift | Creates a SystemLanguageModel based on the requested guardrails mode instead of always using .default. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
thymikee
left a comment
There was a problem hiding this comment.
There is one blocking issue in the native bridge:
[P1] Forward guardrails through AppleLLM.mm
NativeAppleLLM.ts now includes guardrails in AppleGenerationOptions, and the AI SDK passes it to both native calls, but packages/apple-llm/ios/AppleLLM.mm reconstructs the NSDictionary *opts manually in both generateText and generateStream. Neither dictionary copies options.guardrails().
As a result, AppleLLMImpl.createModel(from:) never receives a "guardrails" key and always returns SystemLanguageModel.default; selecting permissiveContentTransformations currently has no effect for either API path.
Please add the generated guardrails value to both options dictionaries (with the appropriate generated enum/string conversion), and ideally cover this bridge path with a test or native build/codegen check.
The generateText/generateStream bridge rebuilds the options dictionary manually, so the guardrails value never reached AppleLLMImpl and the option was a no-op. Copy it in both paths, mirroring schema/tools.
|
Good catch, thank you — the option was indeed a no-op through the bridge. Fixed in the latest commit: both On verification: I ran |
Summary
Apps that transform legitimate but sensitive content — health data in our case — frequently hit
guardrailViolationerrors with the default Foundation Models guardrails. Apple provides a permissive guardrails mode for exactly this scenario (Improving the safety of generative model output).This PR exposes it as a provider-level option:
Changes
createAppleProvideracceptsguardrails?: 'default' | 'permissiveContentTransformations', stored onAppleLLMChatLanguageModeland passed with everygenerateText/generateStreamnative callAppleGenerationOptionsgains an optionalguardrailsstring fieldAppleLLMImpl.swiftbuilds the session model via acreateModel(from:)helper:SystemLanguageModel(guardrails: .permissiveContentTransformations)when requested,SystemLanguageModel.defaultotherwisewebsite/src/docs/apple/generating.mdDefaults are unchanged — omitting the option keeps
SystemLanguageModel.default.Guardrails.permissiveContentTransformationsis available on all OS versions the framework supports (verified against the iOS 26.5 and 27.0 SDK swiftinterfaces), so no additional availability gating is needed.Testing
tsc --noEmitpasses for@react-native-ai/apple🤖 Generated with Claude Code