Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.5.1 - 2026-09-18
Fixed
- Chat and Responses APIs: after a tool result was sent back, the model often ignored it and answered something unrelated, such as "I am a foundation model created by Apple." Past tool calls went into the transcript as raw OpenAI JSON, which the model sometimes echoed back, and the tool result reached the model as a bare user turn with no question. Tool calls are now described in plain text, and the prompt restates the request that led to the call. In 15 runs of the tool-calling integration test, the first attempt succeeded 15/15 times, up from 6/15.
- Chat and Responses APIs: when one tool was called more than once, the model could not tell which result belonged to which call. Asked for the weather in Tokyo and Paris, it swapped the cities every time. Results from a repeated tool are now labeled with the call's arguments, for example
[Tool result for get_weather {"city":"Paris"}].
Changed
- TypeScript
targetandlibraised from ES2022 to ES2025, matching the Node 24 minimum. Emitted JavaScript is unchanged.
0.5.0 - 2026-09-18
Added
- Official support for macOS 27. The SDK is tested on macOS 27, and the full unit and integration suites pass there. macOS 26 is still supported, and the native library's minimum deployment target stays at macOS 26.0.
- Prompt attachments now work on macOS 27 with the bundled library. It is built against the macOS 27 SDK and still loads on macOS 26, where each attachment is rejected with
PromptAttachmentError(reason: "unsupported-os").
Fixed
- Building from source with the macOS 27 SDK did not enable prompt attachments.
scripts/build-native.shnever definedFM_HAS_MACOS_27_SDK, so the bridge compiled attachments out and every attachment was rejected withunsupported-sdk. The script now defines it when the active SDK is macOS 27 or later, as upstream's build does, and rebuilds an existing dylib that lacks attachment support instead of skipping it.
Changed
koffiupgraded from^3.1.5to^3.3.0. This is the runtime FFI dependency.- The published package is now built on the
xcode-27runner instead ofmacos-26. A newscripts/verify-native.shcheck fails the publish if the library's deployment target is not macOS 26.0, or if any macOS 27 attachment symbol is strongly linked. - Development toolchain moved to Vitest 5 (
vitestand@vitest/coverage-v85.0.1).openai,eslint,typescript-eslint,@types/node,prettier, andtsxalso moved to their latest versions.
Security
- Development dependencies no longer include vulnerable versions of
vitest(GHSA-82fw-gwwq-j7x9) or@humanfs/node(GHSA-p498-v437-472g). None of these packages ship in the published package.
0.4.0 - 2026-08-14
Added
generable()— declarative typed schema builder for structured output with full TypeScript type inference, the equivalent of the Python SDK's@generabledecoratorSystemLanguageModel.contextSize— read the model's context window size (back-deployed from macOS 26.4 SDK)SystemLanguageModel.tokenCount()— count the tokens a prompt, instruction set, tool list, schema, or transcript consumes against the context window. Asynchronous, requires a macOS 26.4+ runtime.- Prompt attachments — every method taking a prompt now accepts
{ text, attachments }as well as a string. Requires macOS 27 and a native library built against the macOS 27 SDK; until then each attachment is refused with aPromptAttachmentErrornaming the reason. SystemLanguageModel.supportedLanguages— list supported language codesSystemLanguageModel.supportsLocale()— check if a specific locale is supportedLanguageModelSession.prewarm()— preload model resources and optionally cache a prompt prefix to reduce first-response latencyGeneratedContent.dispose()/Symbol.dispose— explicit resource cleanup for structured output results, withFinalizationRegistryauto-cleanup as a safety netTranscript.dispose()/Symbol.dispose— release the C object behind a standalone transcript fromfromJson()/fromDict(), withFinalizationRegistryauto-cleanup as a safety net. No-op for the transcript reached throughsession.transcript, which the session frees.GeneratedContent.toObject<T>()— pass the shape the schema guarantees instead of asserting at the call site. Defaults toJsonObject, so existing calls are unaffected.NativeTypeNametype export — compound array type names ("array<string>","array<integer>", etc.) for use withGenerationSchema.property()decodeString()— decode a C string pointer without freeing it, for use in callbacks where the C side owns the memoryTool.onCallnow receives parsed arguments as a second parameter:(toolName, args)instead of(toolName)- Input validation:
temperaturemust be ≥ 0,maximumResponseTokensmust be a positive integer — both throw immediately on invalid values - Explicit FFI type casts (
as NativePointer,as boolean, etc.) at all C call sites - 3 new examples:
contact-card(nested generable schemas),email-triage(JSON Schema + streaming + tools),journal(tools + transcript persistence) - ESLint:
no-floating-promisesandno-consoleforsrc/,no-evalandno-debuggerglobally - Unit tests for
generable(), streaming edge cases, compatreorderJsonwith array items, disposed session guards, stream queue-stall recovery, and all 3 new examples
Fixed
Transcript.fromJson()andfromDict()leaked their native object. Each allocated a C object with no way to release it, since the class had nodispose(), noSymbol.dispose, and noFinalizationRegistry.Building from source validated the wrong toolchain: the Xcode version check ran before
DEVELOPER_DIRwas repointed at an installedXcode-beta.app, so the build could use an SDK that was never checked.Streaming no longer discards a response whose text is exactly
null. The callback treated that string as a koffi coercion artifact, so such a response streamed as nothing at all. koffi marshals the end-of-stream signal to JSnull, never to the string, so there was no artifact to filter.Upstream C bridge moved to apple/python-apple-fm-sdk@e868e608, which changed the prompt parameter of all four response entry points from
const char *to an opaque composed-prompt object. The build now pins that revision, since koffi binds by symbol name and cannot see a changed parameter type.Stream setup failures no longer stall the request queue permanently (native init moved inside try/finally)
Stream idle timeout (30s) prevents permanent hangs when native callbacks stop firing. Armed between snapshots rather than after a tool-call snapshot, since the artifact it originally keyed on does not occur.
Disposed session methods (
respond,respondWithSchema,respondWithJsonSchema,streamResponse) now throwFoundationModelsErrorimmediately instead of calling into freed native memoryFinalizationRegistrycallbacks across all classes now log warnings viaconsole.warninstead of silently swallowing errorsBetter error message when
libFoundationModels.dylibis not found — lists all searched paths and suggestsnpm run buildStreaming iterator now resets the session (
FMLanguageModelSessionReset) on earlybreakto prevent stalled subsequent calls
Changed
- Declare
generable()property maps withsatisfies Record<string, PropertyDef>(or inline them at the call). Assigning them to a plainconstfirst widensoptional: truetoboolean, andInferSchemathen marks every property required. The bundled examples show the pattern. - Breaking:
engines.noderaised from>=20to>=24. Installing on Node 20 or 22 no longer works. koffiupgraded from^2.15.1to^3.1.5. This is the runtime FFI dependency, and its marshalling of null C strings differs from 2.x — see the streaming fix above.- Development toolchain moved to TypeScript 7 (
@typescript/native, with 6.0.2 available astsc6),openai7,@types/node26, and ESLint 10. - Building the dylib from source now requires Xcode 26.4+, the first SDK that declares
SystemLanguageModel.contextSize. The bundled prebuilt library is unaffected. generable()array properties now use compound type names ("array<string>","array<Name>") matching the Python SDK's C bridge conventionGenerationSchema.property()rejects bare"array"type — use compound form like"array<string>"or usegenerable()for automatic type resolution- Prettier scope widened from
src/to entire repo (excluding*.md); added.prettierignore - Standardized "Apple Foundation Models" terminology (dropped possessive "'s") across docs and config
- README license section rewritten with copyright notice and Apple trademark disclaimer
docs/tsconfig.jsonadded for VitePress theme type checking- CSS: added
.VPHero .taglinemax-width constraints for responsive layout
0.3.1 - 2026-03-12
Added
Tool.onCall— optional callback that fires at the start of each tool invocation, beforecall()runs. Useful for showing UI indicators while the model waits for tool results.
0.3.0 - 2026-03-11
Added
- Chat & Responses API layer (
tsfm-sdk/chat) — industry-standard Chat-style and Responses-style APIs- Chat Completions API (
client.chat.completions.create()) with full message history, streaming, structured output (json_schema), and tool calling - Responses API (
client.responses.create()) — string or structured input, function tools, and streaming viaResponseStream - Parameter mapping:
temperature,max_tokens/max_completion_tokens,top_p,seed→ nativeGenerationOptions; unsupported params warned at runtime - Error mapping:
ExceededContextWindowSizeError→finish_reason: "length",GuardrailViolationError→finish_reason: "content_filter",RefusalError→message.refusal,RateLimitedError→ HTTP 429 StreamandResponseStreamasync iterables withtoReadableStream(),close(),Symbol.dispose, andFinalizationRegistrycleanup- Tool calling via structured output with
$defs/$refschemas to prevent parameter name collisions - JSON key reordering utility to match schema-defined property order
- Chat Completions API (
ServiceCrashedError— detects crashedgenerativeexperiencesdservice and provides recovery instructionsSymbol.disposesupport onSystemLanguageModel,LanguageModelSession,Tool, andClientfor TC39 Explicit Resource Management- Typed transcript entries:
TranscriptEntry,TranscriptContent,TranscriptTextContent,TranscriptStructuredContent,TranscriptToolCall,TranscriptEntryRoletypes andtranscript.entries()method JsonSchemaandJsonObjectexported types- Automatic session cleanup on
process.exit,SIGINT, andSIGTERMvia global session tracking - Enhanced
afmSchemaFormat()with recursive normalization for nested objects,$defs/$refsupport, andx-orderfields respondWithJsonSchema()now accepts typedJsonSchemainstead ofRecord<string, unknown>- Tool callback error handling: synchronous errors in
call()now invokeFMBridgedToolFinishCall()with error message to prevent session hang - Enhanced
statusToError(): mapsModelManagerError Code=1041toInvalidGenerationSchemaErrorwith descriptive message - Integration tests for Chat & Responses API layer (chat completions and Responses API)
- Unit tests for all compat modules (~4,300 lines of new test coverage)
- 6 new examples in
examples/compat/demonstrating Chat Completions and Responses API - Retry helper for integration tests (
retryAttempts()) for flaky on-device model responses
Changed
- Renamed model class from internal name to
SystemLanguageModelacross all public APIs and documentation Transcript.toDict()andfromDict()now useJsonObjecttype instead ofRecord<string, unknown>GeneratedContent.toObject()now returnsJsonObjectinstead ofRecord<string, unknown>serializeOptions()uses typedSerializedSamplingandSerializedOptionsinterfaces internally- Integration tests now use
waitUntilAvailable()instead of synchronousisAvailable()
Documentation
- Complete Chat & Responses API guide (505 lines), API reference (568 lines), and examples page (321 lines)
- Docs site visual overhaul: brand colors shifted to teal, Apple-style typography and font rendering, WCAG AA contrast fixes
- Landing page redesigned with code examples and Chat API showcase
- Swift-equivalent references extracted into caption-style info boxes across all guide pages
- Code blocks now word-wrap; inline code uses inherited text color with subtle background
- All guide pages updated with Apple conventions terminology alignment
0.2.3 - 2026-03-10
Fixed
NOTICEfile now included in published npm package
0.2.2 - 2026-03-10
Changed
- Renamed package from
afm-ts-sdktotsfm-sdk - Renamed GitHub repository from
codybrom/afm-ts-sdktocodybrom/tsfm
0.2.1 - 2026-03-09
Added
- Branded
NativePointertype for compile-time C pointer type safety unregisterCallback()utility to centralize callback cleanup logic- Discriminated union for
GenerationGuidedata, enabling exhaustive type checking - Comprehensive JSDoc comments on public APIs (
SystemLanguageModel,LanguageModelSession,Tool,Transcript,SamplingMode) stripInternalin tsconfig to exclude@internalsymbols from.d.tsoutput- Unit tests for error hierarchy and
statusToError()mapping - Integration test suite covering basic responses, streaming, structured output, tools, and transcripts
- GitHub Actions CI workflow (macOS, Node.js 20/22, lint + format + unit tests)
- Organized examples directory with individual READMEs for each example
Changed
- Renamed all internal pointer variables from abbreviations (
ptr,cbPtr) to full names (pointer,callbackPointer,_nativeSession,_nativeTool,_nativeSchema, etc.) InvalidGenerationSchemaErrornow extendsGenerationErrorinstead ofFoundationModelsError- All error-throwing paths now use
FoundationModelsErrororGenerationErrorsubclasses instead of genericError - Replaced
GenerationGuideseparateguideType/valuefields with a singledatadiscriminated union
Removed
- Monolithic
example.tsfile (replaced by organizedexamples/directory)
0.2.0 - 2026-03-08
Added
decodeAndFreeString()utility in bindings to safely decode C string pointers and free memory viaFMFreeString- ESLint (flat config) and Prettier for code linting and formatting
tsxdev dependency for TypeScript execution
Changed
- C function signatures for string-returning functions now declare return type as
void *instead ofstrto retain the pointer for proper memory management - Tool callback error handling now wraps errors in
ToolCallErrorwith proper context - Updated README import paths
Fixed
- Critical memory leak in all string-returning C functions —
koffi'sstrreturn type was copying strings but discarding the original pointer before it could be freed
Removed
- Unused
FMLanguageModelSessionCreateDefaultbinding (sessions always route throughCreateFromSystemLanguageModel) - Unused
FMRetainbinding (all Swift-to-JS transfers usepassRetained, onlyFMReleaseis needed)
0.1.0 - 2026-03-08
Added
- TypeScript/Node.js bindings for Apple Foundation Models framework via koffi FFI
SystemLanguageModelclass with availability checks andwaitUntilAvailable()LanguageModelSessionwithrespond(),streamResponse(), andrespondWithJsonSchema()for text, streaming, and structured generationGenerationSchemaandGenerationSchemaPropertyfor typed structured output with generation guidesGenerationOptionsandSamplingModefor controlling temperature, token limits, and sampling strategies- Abstract
Toolbase class for function calling with schema-driven arguments Transcriptclass for session history export and import- Error hierarchy matching Python SDK status codes (11 specific error types)
- Prebuilt
libFoundationModels.dylibbundled for npm distribution (no Xcode required) build-native.shscript for building the dylib from vendored Swift sourceverify-native.jspostinstall script for SHA256 verification with automatic rebuild