bleam 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai.cjs +1872 -1182
- package/dist/ai.d.cts +267 -234
- package/dist/ai.d.ts +267 -234
- package/dist/ai.js +1859 -1167
- package/dist/cli.cjs +3 -183
- package/dist/cli.d.cts +3 -47
- package/dist/cli.d.ts +3 -47
- package/dist/cli.js +3 -183
- package/dist/config.d.cts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/{files-Ds1wT8C2.js → files-BXVkPrPN.js} +6 -1
- package/dist/{files-Bo7h9fik.cjs → files-DxaQ-Nv0.cjs} +11 -0
- package/dist/files.cjs +1 -1
- package/dist/files.js +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/platform.cjs +1 -13
- package/dist/platform.d.cts +1 -28
- package/dist/platform.d.ts +1 -28
- package/dist/platform.js +1 -10
- package/dist/schema-B5BfdswF.js +226 -0
- package/dist/schema-BnVZOXfu.cjs +286 -0
- package/dist/schema-D5eImHxu.d.cts +125 -0
- package/dist/schema-SSjokbtw.d.ts +125 -0
- package/dist/schema.cjs +10 -2
- package/dist/schema.d.cts +2 -2
- package/dist/schema.d.ts +2 -2
- package/dist/schema.js +2 -2
- package/dist/state-Dh3HLixb.js +874 -0
- package/dist/state-LssDgpff.cjs +973 -0
- package/dist/state.cjs +16 -12
- package/dist/state.d.cts +144 -140
- package/dist/state.d.ts +145 -140
- package/dist/state.js +3 -3
- package/dist/{ui-Bg11tvlc.d.ts → ui-1WepaMS4.d.cts} +1 -1
- package/dist/{ui-Dd7SXdbg.d.cts → ui-D7bRLYee.d.ts} +7 -7
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/window.d.cts +1 -1
- package/dist/window.d.ts +1 -1
- package/package.json +3 -1
- package/templates/foundation-models/app/index.tsx +77 -15
- package/templates/image-generation/app/index.tsx +4 -2
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/ModelRegistry.swift +1 -1
- package/templates/native/ios/Bleam/AI/Flux2/Pipeline/FluxImageRunner.swift +7 -2
- package/templates/native/ios/Bleam/AI/TextGeneration/Bonsai/BonsaiTextGenerator.swift +46 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Bonsai/BonsaiTextModel.swift +107 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Bonsai/BonsaiTextSnapshotValidator.swift +201 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Core/GenerationTypes.swift +85 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Core/ModelCapabilities.swift +21 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Core/TextKVCache.swift +23 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Core/TokenSampler.swift +79 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen3/Qwen3CheckpointLoader.swift +161 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen3/Qwen3Configuration.swift +119 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen3/Qwen3InferenceSession.swift +84 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen3/Qwen3Layers.swift +197 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen3/Qwen3Model.swift +130 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen35/Qwen35Checkpoint.swift +102 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen35/Qwen35Configuration.swift +140 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen35/Qwen35Model.swift +112 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/Qwen35/Qwen35Session.swift +121 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/QwenHybrid/QwenHybridCache.swift +42 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/QwenHybrid/QwenHybridFullAttention.swift +57 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/QwenHybrid/QwenHybridLayers.swift +58 -0
- package/templates/native/ios/Bleam/AI/TextGeneration/QwenHybrid/QwenHybridLinearAttention.swift +111 -0
- package/templates/native/ios/Bleam/AppDelegate.swift +0 -206
- package/templates/native/ios/Bleam.xcodeproj/project.pbxproj +135 -129
- package/templates/native/ios/GenerationService/BonsaiTextGenerationRunner.swift +103 -0
- package/templates/native/ios/GenerationService/ImageGenerationRunner.swift +19 -7
- package/templates/native/ios/GenerationService/main.swift +174 -48
- package/templates/native/ios/Podfile.lock +173 -173
- package/templates/native/ios/Shared/Generation/GenerationServiceProtocol.swift +3 -0
- package/templates/native/ios/Shared/Generation/GenerationWorkerProtocol.swift +44 -0
- package/templates/native/modules/bleam-runtime/ios/AIModule.swift +239 -341
- package/templates/native/modules/bleam-runtime/ios/GenerationContracts.swift +47 -0
- package/templates/native/modules/bleam-runtime/ios/PlatformModule.swift +0 -191
- package/templates/text-generation/app/index.tsx +124 -0
- package/templates/text-generation/app.config.ts +5 -0
- package/templates/updates/README.md +43 -199
- package/templates/updates/src/index.ts +5 -98
- package/templates/updates/src/schema.ts +18 -173
- package/dist/schema-Bo5Jvqus.js +0 -90
- package/dist/schema-DOOjfXvs.d.ts +0 -58
- package/dist/schema-ENSMX_1t.d.cts +0 -58
- package/dist/schema-rQ13mrpD.cjs +0 -102
- package/dist/state-Bx0VlTlO.cjs +0 -852
- package/dist/state-CAwe-Vw1.js +0 -767
- package/templates/native/ios/PlatformHelper/main.swift +0 -726
- /package/dist/{config-Cms0rvqg.d.ts → config-COcRnn5a.d.cts} +0 -0
- /package/dist/{config-CufOVJV3.d.cts → config-Chi-flpJ.d.ts} +0 -0
|
@@ -2,68 +2,130 @@ import Foundation
|
|
|
2
2
|
import MLX
|
|
3
3
|
|
|
4
4
|
private final class GenerationRuntime: @unchecked Sendable {
|
|
5
|
+
private enum OperationKind {
|
|
6
|
+
case image
|
|
7
|
+
case text
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
private let modelWarmTimeout: Duration = .seconds(60)
|
|
11
|
+
private let stateLock = NSLock()
|
|
12
|
+
private var activeID: String?
|
|
13
|
+
private var activeKind: OperationKind?
|
|
6
14
|
private var activeTask: Task<Void, Never>?
|
|
7
|
-
private var
|
|
15
|
+
private var activeImageRunner: ImageGenerationRunner?
|
|
16
|
+
private var activeTextRunner: BonsaiTextGenerationRunner?
|
|
8
17
|
private var trimTask: Task<Void, Never>?
|
|
9
18
|
private var isCancelled = false
|
|
19
|
+
private var operationEpoch: UInt64 = 0
|
|
20
|
+
private var isShuttingDown = false
|
|
10
21
|
|
|
11
22
|
var isRunning: Bool {
|
|
12
|
-
activeTask != nil
|
|
23
|
+
stateLock.withLock { activeTask != nil }
|
|
13
24
|
}
|
|
14
25
|
|
|
15
|
-
func
|
|
26
|
+
func startImage(
|
|
16
27
|
request: GenerationWorkerRequest,
|
|
17
28
|
emit: @escaping @Sendable (GenerationWorkerEvent) -> Void
|
|
18
29
|
) -> Bool {
|
|
19
|
-
|
|
30
|
+
stateLock.withLock {
|
|
31
|
+
guard activeTask == nil, !isShuttingDown else { return false }
|
|
32
|
+
trimTask?.cancel()
|
|
33
|
+
trimTask = nil
|
|
34
|
+
isCancelled = false
|
|
35
|
+
operationEpoch &+= 1
|
|
36
|
+
activeID = request.jobID.uuidString
|
|
37
|
+
activeKind = .image
|
|
38
|
+
let runner = ImageGenerationRunner(request: request, emit: emit)
|
|
39
|
+
activeImageRunner = runner
|
|
40
|
+
activeTask = Task { [weak self] in
|
|
41
|
+
await self?.runImage(request, runner: runner, emit: emit)
|
|
42
|
+
}
|
|
43
|
+
return true
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func startText(
|
|
48
|
+
request: BonsaiTextGenerationRequest,
|
|
49
|
+
emit: @escaping @Sendable (BonsaiTextGenerationEvent) -> Void
|
|
50
|
+
) -> Bool {
|
|
51
|
+
stateLock.withLock {
|
|
52
|
+
guard activeTask == nil, !isShuttingDown else { return false }
|
|
53
|
+
trimTask?.cancel()
|
|
54
|
+
trimTask = nil
|
|
55
|
+
isCancelled = false
|
|
56
|
+
operationEpoch &+= 1
|
|
57
|
+
activeID = request.id
|
|
58
|
+
activeKind = .text
|
|
59
|
+
let runner = BonsaiTextGenerationRunner(request: request, emit: emit)
|
|
60
|
+
activeTextRunner = runner
|
|
61
|
+
activeTask = Task { [weak self] in
|
|
62
|
+
await self?.runText(request, runner: runner)
|
|
63
|
+
}
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func cancelImage() -> Bool {
|
|
69
|
+
let operation = stateLock.withLock { () -> (Task<Void, Never>?, ImageGenerationRunner?)? in
|
|
70
|
+
guard activeKind == .image else { return nil }
|
|
71
|
+
isCancelled = true
|
|
72
|
+
trimTask?.cancel()
|
|
73
|
+
trimTask = nil
|
|
74
|
+
return (activeTask, activeImageRunner)
|
|
75
|
+
}
|
|
76
|
+
guard let operation else { return false }
|
|
77
|
+
operation.0?.cancel()
|
|
78
|
+
operation.1?.cancel()
|
|
79
|
+
return true
|
|
80
|
+
}
|
|
20
81
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
82
|
+
func cancelText(id: String) -> Bool {
|
|
83
|
+
let operation = stateLock.withLock { () -> (Task<Void, Never>?, BonsaiTextGenerationRunner?)? in
|
|
84
|
+
guard activeKind == .text, activeID == id else { return nil }
|
|
85
|
+
isCancelled = true
|
|
86
|
+
trimTask?.cancel()
|
|
87
|
+
trimTask = nil
|
|
88
|
+
return (activeTask, activeTextRunner)
|
|
26
89
|
}
|
|
90
|
+
guard let operation else { return false }
|
|
91
|
+
operation.0?.cancel()
|
|
92
|
+
operation.1?.cancel()
|
|
27
93
|
return true
|
|
28
94
|
}
|
|
29
95
|
|
|
30
|
-
func
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
96
|
+
func beginShutdown() -> Bool {
|
|
97
|
+
stateLock.withLock {
|
|
98
|
+
guard activeTask == nil, !isShuttingDown else { return false }
|
|
99
|
+
isShuttingDown = true
|
|
100
|
+
operationEpoch &+= 1
|
|
101
|
+
trimTask?.cancel()
|
|
102
|
+
trimTask = nil
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
36
105
|
}
|
|
37
106
|
|
|
38
107
|
func trimModelsNow() async {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
await Task.yield()
|
|
46
|
-
MLX.Memory.clearCache()
|
|
108
|
+
stateLock.withLock {
|
|
109
|
+
trimTask?.cancel()
|
|
110
|
+
trimTask = nil
|
|
111
|
+
MLX.Memory.clearCache()
|
|
112
|
+
MLX.Memory.clearCache()
|
|
113
|
+
}
|
|
47
114
|
print("[GenerationService] trim active=\(MLX.Memory.activeMemory / 1_048_576)MB cache=\(MLX.Memory.cacheMemory / 1_048_576)MB")
|
|
48
115
|
}
|
|
49
116
|
|
|
50
|
-
private func
|
|
117
|
+
private func runImage(
|
|
51
118
|
_ request: GenerationWorkerRequest,
|
|
119
|
+
runner: ImageGenerationRunner,
|
|
52
120
|
emit: @escaping @Sendable (GenerationWorkerEvent) -> Void
|
|
53
121
|
) async {
|
|
54
|
-
let runner = ImageGenerationRunner(request: request, emit: emit)
|
|
55
|
-
activeRunner = runner
|
|
56
122
|
defer {
|
|
57
|
-
|
|
58
|
-
activeRunner = nil
|
|
59
|
-
}
|
|
60
|
-
activeTask = nil
|
|
61
|
-
scheduleTrimAfterIdle()
|
|
123
|
+
finish(id: request.jobID.uuidString, imageRunner: runner)
|
|
62
124
|
}
|
|
63
125
|
|
|
64
126
|
do {
|
|
65
127
|
try await runner.run(isCancelled: { [weak self] in
|
|
66
|
-
Task.isCancelled || (self?.
|
|
128
|
+
Task.isCancelled || (self?.cancellationRequested ?? false)
|
|
67
129
|
})
|
|
68
130
|
} catch is CancellationError {
|
|
69
131
|
emit(.init(type: .canceled))
|
|
@@ -76,17 +138,59 @@ private final class GenerationRuntime: @unchecked Sendable {
|
|
|
76
138
|
}
|
|
77
139
|
}
|
|
78
140
|
|
|
141
|
+
private func runText(
|
|
142
|
+
_ request: BonsaiTextGenerationRequest,
|
|
143
|
+
runner: BonsaiTextGenerationRunner
|
|
144
|
+
) async {
|
|
145
|
+
defer { finish(id: request.id, textRunner: runner) }
|
|
146
|
+
await runner.run(isCancelled: { [weak self] in
|
|
147
|
+
Task.isCancelled || (self?.cancellationRequested ?? true)
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private var cancellationRequested: Bool {
|
|
152
|
+
stateLock.withLock { isCancelled }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private func finish(
|
|
156
|
+
id: String,
|
|
157
|
+
imageRunner: ImageGenerationRunner? = nil,
|
|
158
|
+
textRunner: BonsaiTextGenerationRunner? = nil
|
|
159
|
+
) {
|
|
160
|
+
let finished = stateLock.withLock {
|
|
161
|
+
guard activeID == id else { return false }
|
|
162
|
+
if let imageRunner, activeImageRunner !== imageRunner { return false }
|
|
163
|
+
if let textRunner, activeTextRunner !== textRunner { return false }
|
|
164
|
+
activeID = nil
|
|
165
|
+
activeKind = nil
|
|
166
|
+
activeImageRunner = nil
|
|
167
|
+
activeTextRunner = nil
|
|
168
|
+
activeTask = nil
|
|
169
|
+
isCancelled = false
|
|
170
|
+
return true
|
|
171
|
+
}
|
|
172
|
+
if finished { scheduleTrimAfterIdle() }
|
|
173
|
+
}
|
|
174
|
+
|
|
79
175
|
private func scheduleTrimAfterIdle() {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
176
|
+
stateLock.withLock {
|
|
177
|
+
trimTask?.cancel()
|
|
178
|
+
let scheduledEpoch = operationEpoch
|
|
179
|
+
trimTask = Task { [weak self] in
|
|
180
|
+
guard let self else { return }
|
|
181
|
+
do {
|
|
182
|
+
try await Task.sleep(for: modelWarmTimeout)
|
|
183
|
+
} catch {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
guard !Task.isCancelled else { return }
|
|
187
|
+
self.stateLock.withLock {
|
|
188
|
+
guard self.activeTask == nil, self.operationEpoch == scheduledEpoch else { return }
|
|
189
|
+
self.trimTask = nil
|
|
190
|
+
MLX.Memory.clearCache()
|
|
191
|
+
MLX.Memory.clearCache()
|
|
192
|
+
}
|
|
87
193
|
}
|
|
88
|
-
guard !Task.isCancelled else { return }
|
|
89
|
-
await self.trimModelsNow()
|
|
90
194
|
}
|
|
91
195
|
print("[GenerationService] model trim scheduled 60s")
|
|
92
196
|
}
|
|
@@ -94,10 +198,11 @@ private final class GenerationRuntime: @unchecked Sendable {
|
|
|
94
198
|
|
|
95
199
|
private final class GenerationService: NSObject, GenerationServiceProtocol {
|
|
96
200
|
private weak var connection: NSXPCConnection?
|
|
97
|
-
private let runtime
|
|
201
|
+
private let runtime: GenerationRuntime
|
|
98
202
|
|
|
99
|
-
init(connection: NSXPCConnection) {
|
|
203
|
+
init(connection: NSXPCConnection, runtime: GenerationRuntime) {
|
|
100
204
|
self.connection = connection
|
|
205
|
+
self.runtime = runtime
|
|
101
206
|
}
|
|
102
207
|
|
|
103
208
|
func startGeneration(requestData: Data, reply: @escaping (Bool) -> Void) {
|
|
@@ -107,14 +212,27 @@ private final class GenerationService: NSObject, GenerationServiceProtocol {
|
|
|
107
212
|
return
|
|
108
213
|
}
|
|
109
214
|
|
|
110
|
-
reply(runtime.
|
|
215
|
+
reply(runtime.startImage(request: request) { [weak self] event in
|
|
111
216
|
self?.emit(event)
|
|
112
217
|
})
|
|
113
218
|
}
|
|
114
219
|
|
|
115
220
|
func cancelGeneration(reply: @escaping (Bool) -> Void) {
|
|
116
|
-
runtime.
|
|
117
|
-
|
|
221
|
+
reply(runtime.cancelImage())
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
func startTextGeneration(requestData: Data, reply: @escaping (Bool) -> Void) {
|
|
225
|
+
guard let request = try? JSONDecoder().decode(BonsaiTextGenerationRequest.self, from: requestData) else {
|
|
226
|
+
reply(false)
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
reply(runtime.startText(request: request) { [weak self] event in
|
|
230
|
+
self?.emitText(event)
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
func cancelTextGeneration(id: String, reply: @escaping (Bool) -> Void) {
|
|
235
|
+
reply(runtime.cancelText(id: id))
|
|
118
236
|
}
|
|
119
237
|
|
|
120
238
|
func memoryTelemetry(reply: @escaping (Data?) -> Void) {
|
|
@@ -126,7 +244,7 @@ private final class GenerationService: NSObject, GenerationServiceProtocol {
|
|
|
126
244
|
}
|
|
127
245
|
|
|
128
246
|
func shutdown(reply: @escaping (Bool) -> Void) {
|
|
129
|
-
guard
|
|
247
|
+
guard runtime.beginShutdown() else {
|
|
130
248
|
reply(false)
|
|
131
249
|
return
|
|
132
250
|
}
|
|
@@ -142,13 +260,21 @@ private final class GenerationService: NSObject, GenerationServiceProtocol {
|
|
|
142
260
|
let client = connection?.remoteObjectProxy as? GenerationServiceClientProtocol
|
|
143
261
|
client?.generationWorkerDidEmit(eventData: data)
|
|
144
262
|
}
|
|
263
|
+
|
|
264
|
+
private func emitText(_ event: BonsaiTextGenerationEvent) {
|
|
265
|
+
guard let data = try? JSONEncoder().encode(event) else { return }
|
|
266
|
+
let client = connection?.remoteObjectProxy as? GenerationServiceClientProtocol
|
|
267
|
+
client?.textGenerationWorkerDidEmit(eventData: data)
|
|
268
|
+
}
|
|
145
269
|
}
|
|
146
270
|
|
|
147
271
|
private final class GenerationServiceDelegate: NSObject, NSXPCListenerDelegate {
|
|
272
|
+
private let runtime = GenerationRuntime()
|
|
273
|
+
|
|
148
274
|
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection connection: NSXPCConnection) -> Bool {
|
|
149
275
|
connection.exportedInterface = NSXPCInterface(with: GenerationServiceProtocol.self)
|
|
150
276
|
connection.remoteObjectInterface = NSXPCInterface(with: GenerationServiceClientProtocol.self)
|
|
151
|
-
connection.exportedObject = GenerationService(connection: connection)
|
|
277
|
+
connection.exportedObject = GenerationService(connection: connection, runtime: runtime)
|
|
152
278
|
connection.resume()
|
|
153
279
|
return true
|
|
154
280
|
}
|