Releases: no-problem-dev/swift-llm-local
Release list
7.0.0
Added
- Tests for the MLX → canonical tool call bridge, which had none. They pin the payload contract:
ToolCall.argumentsis always a valid JSON object,{}for a call with no arguments rather
than empty bytes, and everyJSONValueshape MLX can hand over — nested objects, arrays, nulls,
quotes, escapes, non-ASCII — survives the round trip unchanged.
6.0.0
Removed
- BREAKING — the calls that answer "what is on disk" and "how much memory is there" now throw
instead of guessing.LocalModelInventory,ModelRegistry,AdapterRegistry,MLXBackend,
DestinationHubDownloaderandLLMLocalServicegained throwing initializers;
MemoryProvider.availableMemoryBytes()throws;DownloadState.pausedcarriesData?;
DownloadedModel.sizeInBytesis no longer optional. StubDownloadDelegateandStubAdapterNetworkDelegateare gone. They were the injected
defaults, and they reported a completed 1 MB download of a model that was never fetched and
recorded a 13-byte text file as a cached adapter. A caller who forgot to wire a delegate was told
the work succeeded. The delegates are now optional, and the two calls that actually need bytes
moved —downloadWithProgressand a remoteAdapterRegistry.resolve— fail without one. The uses
that never needed a delegate keep working.
Fixed
- An unreadable model directory reported as "not downloaded".
isDownloadedused
try? contentsOfDirectory, so a permission error looked like an absent model — and
DestinationHubDownloaderresponded by re-fetching a multi-gigabyte model already on disk.
snapshotState(at:)now distinguishes complete, incomplete and absent, and throws when it cannot
tell. - Storage size understated without saying so. The directory walk used
errorHandler: niland
try?per file, so an unreadable subtree silently contributed zero — producing a plausible short
number that a user acts on when deciding what to delete. - The backup-exclusion flag dropped silently.
try?onsetResourceValuesmeant multi-gigabyte
weights could end up in iCloud backup with no signal, contradicting the doc comment directly
above it. - A fabricated memory measurement.
host_page_size's return code was discarded, and a failed
host_statistics64returnedphysicalMemory / 2— a made-up number indistinguishable from a
real one. - A download that could not be cancelled reported as stopped.
try?on the delegate call, then
bookkeeping torn down regardless, so the transfer kept running whileisDownloadingsaid false.
A pause with no resume data storedData(), sohasResumeDatasaid true andresumerestarted
from byte 0. - Eviction reported storage freed when the files were still there.
deleteCachedropped the entry
whether or not the delete succeeded — and that entry was the last thing pointing at the
gigabytes, so nothing could find them to try again. The entry is now kept and the failure
reported;clearAllCachesaves what it did manage to free. - Application Support resolution had two opposite policies in three files —
.first!in two
(a crash the caller cannot catch) and?? temporaryDirectoryin the third (a purgeable directory,
so "downloaded" quietly stops being true). One throwing helper now serves all three.
5.0.0
Changed
-
BREAKING —
ModelRegistryandAdapterRegistryno longer report a registry file they could
not read as an empty registry. A file that exists but will not read or decode now throws
LLMLocalError.registryUnreadable(reason:); only a registry that was never written still reads
as empty.ModelRegistry.cachedModels()andisCached(_:), andAdapterRegistry's
cachedAdapters(),isCached(_:)andisUpdateAvailable(for:latestTag:), gainedthrowsto
carry it.The two states called for opposite responses and were being given the same answer. Downwards,
every mutating method is a load-mutate-save over the whole file, so treating an unreadable
registry as empty wrote that emptiness back over a file that was still recoverable by hand and
orphaned the model directories the lost entries pointed at —deleteCache(for:)could never free
them again. Upwards, a caller that heard "nothing is downloaded" re-fetched gigabytes the device
was already holding, andAdapterRegistry.resolve(_:)downloaded over the adapter files already
sitting at those paths. Nothing is cached from a failed read, so the next call reads again and
succeeds once the file is repaired or removed. -
Raised the swift-persistence pin to 3.0.0, whose
RegistryStore.load()throws rather than
returning a default. This package had been swallowing that distinction one layer further up.
Added
LLMLocalError.registryUnreadable(reason:).
4.0.0
Removed
- BREAKING —
LocalAgentClient.generateWithUsagetakes aGenerationOptionsvalue instead of
separatesystemPrompt,temperatureandmaxTokensarguments, following swift-llm-client
4.0.0. The requirement's signature now differs from the convenience method beside it, which is
what stops a conformance that forgets the requirement from calling the convenience back into
itself forever. Call sites that pass the arguments individually keep working — llm-client still
ships those as defaulted convenience overloads.
Changed
- Raised the swift-llm-client pin to 4.0.0.
Nothing.
3.0.0
1.5.0
chore: swift-llm-client を URL 参照に変更
1.4.0
chore: Examples・specs を削除、Package.resolved を gitignore に追加
1.3.0
feat: LocalAgentClient 追加、swift-persistence 導入、Manager → Registry リネーム