arcane-os 0.60.0 → 0.62.0

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.
@@ -2,9 +2,48 @@ import {readFile, writeFile} from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import Is from 'strong-type';
4
4
  import {ArcaneError, ERROR_CODES, throwIfAborted} from '../errors.mjs';
5
+ import {SD14_MODEL} from './image-models/sd14.mjs';
5
6
 
6
7
  const is = new Is(false);
7
- export const LOCAL_AI_RUNTIME_IDS = ['llama.cpp', 'ollama', 'onnx'];
8
+ export const LOCAL_AI_RUNTIME_IDS = ['llama.cpp', 'ollama', 'onnx', 'stable-diffusion.cpp'];
9
+
10
+ /** Image requirements describe assets without acquiring or loading a model. */
11
+ export function normalizeImageRuntimeRequirement(record) {
12
+ const backend = record.backend ?? 'auto';
13
+ if (!['auto', 'metal', 'cpu'].includes(backend)) {
14
+ throw new ArcaneError(ERROR_CODES.usage, `Unknown stable-diffusion.cpp backend: ${String(backend)}.`);
15
+ }
16
+ if (record.models !== undefined && !is.array(record.models)) {
17
+ throw new ArcaneError(ERROR_CODES.usage, 'stable-diffusion.cpp models must be an array of model IDs or descriptors.');
18
+ }
19
+ const models = (record.models ?? []).map(
20
+ function selectedImageModel(value) {
21
+ const model = value === 'sd14' ? SD14_MODEL : value;
22
+ if (!model || !is.object(model) || is.array(model) || !is.string(model.id) || !model.id) {
23
+ throw new ArcaneError(ERROR_CODES.usage, 'An image model needs a descriptor with an id, or the built-in sd14 ID.');
24
+ }
25
+ if (!model.resources || !is.object(model.resources) || is.array(model.resources)) {
26
+ throw new ArcaneError(ERROR_CODES.usage, `Image model ${model.id} needs resources keyed by model role.`);
27
+ }
28
+ if (model.operations !== undefined && !is.array(model.operations)) {
29
+ throw new ArcaneError(ERROR_CODES.usage, `Image model ${model.id} operations must be an array.`);
30
+ }
31
+ return {
32
+ ...model,
33
+ resources: {...model.resources},
34
+ context: {...model.context},
35
+ defaults: {...model.defaults},
36
+ operations: [...(model.operations ?? [])]
37
+ };
38
+ }
39
+ );
40
+ return {
41
+ ...record,
42
+ version: record.version ?? 'master-929-3f8527a',
43
+ backend,
44
+ models
45
+ };
46
+ }
8
47
 
9
48
  /** Runtime requirements are application configuration, separate from models. */
10
49
  export function normalizeLocalAIConfig(value) {
@@ -17,6 +56,7 @@ export function normalizeLocalAIConfig(value) {
17
56
  if (!record || !LOCAL_AI_RUNTIME_IDS.includes(record.id)) {
18
57
  throw new ArcaneError(ERROR_CODES.usage, `Unknown local AI runtime: ${String(record?.id ?? item)}.`);
19
58
  }
59
+ if (record.id === 'stable-diffusion.cpp') return normalizeImageRuntimeRequirement(record);
20
60
  return {...record};
21
61
  });
22
62
  return {...value, runtimes};
@@ -1,6 +1,8 @@
1
1
  import Is from 'strong-type';
2
2
  import {createCoreRuntime} from '../core/runtime.mjs';
3
3
  import {createLocalAIService} from '../core/services/local-ai.mjs';
4
+ import {createLocalImageService} from '../core/services/image.mjs';
5
+ import {createModelAssetService} from '../core/services/model-assets.mjs';
4
6
  import {CORE_PROTOCOL, CoreError, serializeCoreError} from '../../browser-runtime/core/contracts.mjs';
5
7
  import {normalizeLocalAIConfig} from './config.mjs';
6
8
  import {discoverLocalAIRuntimes} from './discover.mjs';
@@ -81,6 +83,8 @@ export function createDevelopmentLocalAI({config, appRoot, directory, applicatio
81
83
  const incoming = new Set();
82
84
  let runtime;
83
85
  let service;
86
+ let imageService;
87
+ let modelAssets;
84
88
  let stopFrames;
85
89
  let preparationError = null;
86
90
  let closing = null;
@@ -157,17 +161,49 @@ export function createDevelopmentLocalAI({config, appRoot, directory, applicatio
157
161
  writeFrame(connection, event('core.state', current));
158
162
  for (const record of current.services) writeFrame(connection, event('core.service.state', record));
159
163
  writeFrame(connection, event('localai.state', service.current()));
164
+ if (imageService) writeFrame(connection, event('image.state', imageService.current()));
165
+ if (modelAssets) writeFrame(connection, event('modelAssets.state', modelAssets.current()));
160
166
  }
161
167
 
162
- const ready = Promise.resolve().then(async function prepareLocalAI() {
168
+ const ready = Promise.resolve().then(function prepareLocalAI() {
163
169
  operationSignal.throwIfAborted();
164
- const discovered = await discoverLocalAIRuntimes({config: selected, appRoot, signal: operationSignal});
165
- operationSignal.throwIfAborted();
166
- const installed = await ensureLocalAIRuntimes({runtimes: discovered.missing, directory, signal: operationSignal, onEvent});
167
- const runtimes = [...discovered.available, ...installed];
168
- operationSignal.throwIfAborted();
169
- service = createLocalAIService(selected, {appRoot, runtimes, signal: operationSignal, onEvent});
170
- runtime = createCoreRuntime({application, version, services: [service]});
170
+ const localConfig = {
171
+ ...selected,
172
+ runtimes: selected.runtimes.filter(function selectedChatRuntime(requirement) {
173
+ return requirement.id !== 'stable-diffusion.cpp';
174
+ })
175
+ };
176
+ service = createLocalAIService(
177
+ localConfig,
178
+ {
179
+ appRoot, signal: operationSignal, onEvent,
180
+ async prepare({signal, onEvent: report}) {
181
+ const discovered = await discoverLocalAIRuntimes({config: localConfig, appRoot, signal});
182
+ const installed = await ensureLocalAIRuntimes({runtimes: discovered.missing, directory, signal, onEvent: report});
183
+ return [...discovered.available, ...installed];
184
+ }
185
+ }
186
+ );
187
+ const services = [service];
188
+ if (selected.runtimes.some(function selectedImageRuntime(requirement) {
189
+ return requirement.id === 'stable-diffusion.cpp';
190
+ })) {
191
+ modelAssets = createModelAssetService({appRoot});
192
+ imageService = createLocalImageService(
193
+ selected,
194
+ {
195
+ appRoot, modelAssets, signal: operationSignal, onEvent,
196
+ async prepare({requirement, signal, onEvent: report}) {
197
+ const installed = await ensureLocalAIRuntimes(
198
+ {runtimes: [requirement], directory, signal, onEvent: report}
199
+ );
200
+ return installed[0];
201
+ }
202
+ }
203
+ );
204
+ services.push(modelAssets, imageService);
205
+ }
206
+ runtime = createCoreRuntime({application, version, services});
171
207
  stopFrames = runtime.onFrame(routeFrame);
172
208
  runtime.start();
173
209
  return runtime;
@@ -350,7 +386,8 @@ export function createDevelopmentLocalAI({config, appRoot, directory, applicatio
350
386
  function current() {
351
387
  return {state: closed ? 'closed' : preparationError ? 'error' : runtime ? 'ready' : 'preparing',
352
388
  error: preparationError ? serializeCoreError(preparationError) : null,
353
- core: runtime?.current() ?? null, localAI: service?.current() ?? null};
389
+ core: runtime?.current() ?? null, localAI: service?.current() ?? null,
390
+ image: imageService?.current() ?? null};
354
391
  }
355
392
 
356
393
  function close() {