Repository navigation
Releases
0.4.0
A minor release: the tool outcome log changes shape, so .upToNextMinor(from: "0.3.1") pins don't pick it up.
.package(url: "https://github.com/airowe/syrup-ai-kit", .upToNextMinor(from: "0.4.0"))Changed
ToolOutcomeLogkeeps every call in a run, not only the last one.callsandsummaryare new,laststill works, and the log keeps at most 20 calls (callLimit). SyrupAIEvalKit launches the app with--siri-ai-eval-clear-outcomes, so each run starts empty. The label is now "Tool calls: …", and the old "Last tool call: …" label is still read. Before, a tool called after a failure replaced the failure in the log. (#42)- Storage key is now
syrupAIKit.toolOutcomes. Outcomes stored by 0.3.x aren't carried over.
New
- Expo plugin: generated tools honour the
bad-hostEvalSwitch. With it on, every generated request goes tohttps://siri-ai-eval-bad-host.invalid, so a generated tool can now have a negative control. (#43) - Expo plugin: pass
SIRI_AI_EVAL_SWITCHES=YEStoxcodebuildto compileEvalSwitchchecks into a Release build. Guard them with#if DEBUG || SIRI_AI_EVAL_SWITCHES. Builds without that setting, such aseas buildand archives, leave the checks out. (#43)
Checked on a phone
The checks used a Release Expo app with SIRI_AI_EVAL_SWITCHES=YES:
- A generated value-only tool passed 5 of 5 runs.
- Its
bad-hostnegative control failed the reply check in 4 of 4 complete runs, as intended. - A failed call followed by a second one showed both calls in the outcome.
- The bad-host URL isn't in a Release build made without the setting.
Docs
- Results of the 0.3.1 device run: value-only tools, an enum parameter, a failure, and a write action with confirmation. (#41)
- A reply check can miss because Siri writes typographic apostrophes ("couldn’t"). Match a word without one.
0.3.1
A small release. Everything is additive, so .upToNextMinor(from: "0.3.0") pins pick it up.
.package(url: "https://github.com/airowe/syrup-ai-kit", .upToNextMinor(from: "0.3.1"))New
- Expo plugin: a tool in
siri-tools.jsoncan set"returns": "value". The generated tool returns only.result(value:), so Siri can chain it with other tools, for example in an App Skill."dialog"stays the default: Siri says the reply and ends its turn. Any other value stops prebuild with an error. (#34) - siri-ai-discover sets
"returns": "value"on every tool an App Skill names.
Fixed
syrup-ai-eval summarizereads every turn of a multi-turn evaluation. Before, it read only the first turn, so calls made in later turns showed as "no tool calls". (#37)
Docs
- When a tool should speak its answer and when it should hand the value to Siri. On a phone, Siri chained value-only tools 5 of 5 times and dialog tools 0 of 5. (#34)
- Siri's one-time consent prompt for requests that don't name the app. After one yes, that phone sends such requests straight to the tool. (#35)
- "Sample App" replaces "My App" as the placeholder app name. (#33)
Not yet tried on a phone
A generated tool with "returns": "value". The chaining result above came from Swift tools written by hand.
0.3.0
SiriAIKit is now Syrup AI Kit. 0.3.0 is the first release under the new name. The Swift API is the same as 0.2.0, apart from the module names.
Breaking changes: the rename
- Repository:
https://github.com/airowe/syrup-ai-kit. The old URL redirects. - Swift products:
SyrupAIKit,SyrupAIEvalKit,SyrupAIEvalSummary. Changeimport SiriAIKittoimport SyrupAIKit. - CLI:
swift run syrup-ai-eval summarize <result>.xcresult. - Expo plugin: the npm package is now
expo-syrup-ai-kit;expo-siri-ai-kitis deprecated. Change the name inapp.jsonplugins andpackage.json. - Claude Code plugin:
/plugin marketplace add airowe/syrup-ai-kit, then/plugin install syrup-ai-kit@syrup-ai-kit.
Unchanged: the types (SiriTool, ToolFailure, SiriToolOutcome), SIRI_AI_PREVIEW, the evaluation ids, and the skill names siri-ai, siri-ai-tool, siri-ai-eval, siri-ai-discover. The Expo skill is now expo-syrup-ai-kit.
.package(url: "https://github.com/airowe/syrup-ai-kit", .upToNextMinor(from: "0.3.0"))New since 0.2.0
- Expo plugin
evalsadds a Siri Evaluations UI test target at prebuild.skillsadds Apple App Skills (a skills bundle) to the app target, checked against Apple's rules.tools(experimental) generates Siri tools fromsiri-tools.json, with parameter descriptions.- The auth helpers are gone from the plugin and the example, matching the kit.
- SyrupAIEvalKit: negative-control and app-not-named evaluation helpers.
- Agent skills, as a Claude Code plugin and for the skills CLI:
siri-aiis the entry skill: it finds the app's stack and picks the next skill.siri-ai-discoverchooses an app's tools and drafts App Skills.siri-ai-toolcovers writing a tool, andsiri-ai-evalcovers evaluations.expo-syrup-ai-kitcovers using the kit in an Expo app.
- Docs:
INSTALL.md,docs/implementing-tools.md, and who can use tools during the preview. - Fix: the example app builds in Release without the debug-only outcome view (#6).
0.2.0
SiriAIKit no longer does auth. Keep your app's own networking and token storage, and wrap your existing API call in a Siri tool.
Breaking changes
- Removed:
ToolHTTPClient,HTTPMethod,TokenAuthenticator,KeychainTokenStore,TokenStore,Tokens,KeychainAccessibility. ToolErroris nowToolFailure:signedOut,timedOut,unreachable,failed..rejectedand.invalidResponsebecame.failed, and.keychainis gone.- Outcomes: "used saved token" and "refreshed after 401" are no longer recorded automatically.
Upgrading from 0.1.0
- Wrap your existing API call:
await tool.answer { … }ortry await tool.run { … }on aSiriTool. - Keep tokens in your own store, saved with
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. Check it at launch withKeychainLockCheck.warnIfLockedOut(service:)in debug builds. - Add details to outcomes from your code with
ToolOutcomeLog.standard.note("refreshed after 401").
The example app's DemoAPI.swift shows refreshing inside a Siri call: one refresh at a time, and sign out only on a rejected refresh.
New
SiriTool: keeps to Siri's time budget (10 seconds by default, or when Siri cancels), turns failures into sentences Siri can say, and records each call's outcome. It stops waiting at the deadline without cancelling your code, so a token refresh still saves.ToolOutcomeLog.note(_:): details per call, as in "succeeded (refreshed after 401)".KeychainLockCheck(debug only): warns when a Keychain item can't be read while the phone is locked.siri-ai-eval summarize: flags runs where Siri gave the right answer without calling your tool, which usually means it answered from the Spotlight index.expo-siri-ai-kit: an Expo config plugin (inexpo-plugin/) that adds SiriAIKit to your app target during prebuild and turns on the preview flag. Its npm release follows separately.
Verified on a device
iPhone 16 Pro, iOS 27.3 beta, Xcode 27.3 beta (27C5020n), using the example app:
| Evaluation | Real pass rate |
|---|---|
| Cart from the demo API | 5 of 5 |
| Cart after the one-minute token expires | 4 of 4 complete runs, refreshed in all 5 |
| Negative control, refresh off | 0 of 1, as it should |
In an Expo SDK 58 app using the plugin, a SiriAIKit tool passed 3 of 3 runs.
APIs may change before 1.0 while Apple's APIs are in beta.
0.1.0
First release, for Apple's Siri AI Developer Preview (iOS 27.3 beta, Xcode 27.3 beta).
- SiriAIKit: Keychain token storage that works on a locked phone, a single shared refresh of expired tokens, an HTTP client with a 10-second timeout, and errors Siri can speak.
- SiriAIEvalKit: launches your app, waits until it's ready, repeats scenarios, and records each tool outcome. Runs on iOS devices only.
- siri-ai-eval: a CLI that summarizes
.xcresultbundles and separates runs that were cut short from real failures.
Verified on an iPhone 16 Pro running iOS 27.3 beta. See the README for results. APIs may change before 1.0 while Apple's APIs are in beta.