arcane-os 0.5.8 → 0.5.10

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +32 -27
  3. package/browser-runtime/ai/browser-speech-artifacts.mjs +23 -1683
  4. package/browser-runtime/ai/browser-speech-providers.mjs +353 -143
  5. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +95 -363
  6. package/browser-runtime/ai/speech-worker-client.mjs +51 -14
  7. package/browser-runtime/ai/speech-worker-runtime.mjs +45 -1072
  8. package/browser-runtime/dependencies/strong-type/package.json +22 -23
  9. package/browser-runtime/event-manager.mjs +27 -41
  10. package/package.json +2 -3
  11. package/runtime/arcane/components/chat.html +1 -1
  12. package/runtime/arcane/components/speech.html +8 -38
  13. package/runtime/arcane/components/voice-transcription.html +1 -1
  14. package/runtime/arcane/css/theme.css +1 -1
  15. package/runtime/arcane/entities/Chat.js +12 -7
  16. package/runtime/arcane/modules/AI.js +506 -391
  17. package/runtime/arcane/modules/AIPreferenceTuple.js +1 -1
  18. package/runtime/arcane/modules/AIProviderRuntime.js +129 -68
  19. package/runtime/arcane/modules/AIRuntimeState.js +2 -18
  20. package/runtime/arcane/modules/BrowserTestSuite.js +2 -5
  21. package/runtime/arcane/modules/CalculatorEngine.js +0 -4
  22. package/runtime/arcane/modules/ChatRecords.js +169 -1
  23. package/runtime/arcane/modules/CommunicationHub.js +0 -19
  24. package/runtime/arcane/modules/ConfiguredAIChatSession.js +28 -25
  25. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +4 -5
  26. package/runtime/arcane/modules/DocumentLexicalSearch.js +1 -1
  27. package/runtime/arcane/modules/Errors.js +6 -19
  28. package/runtime/arcane/modules/Mail.js +1 -2
  29. package/runtime/arcane/modules/MailTransport.mjs +1 -3
  30. package/runtime/arcane/modules/OllamaModelIdentifier.js +1 -1
  31. package/runtime/arcane/modules/PersistentAIChatSession.js +5 -5
  32. package/runtime/arcane/modules/ScreenCapture.js +2 -4
  33. package/runtime/arcane/modules/SpeechPlayback.js +0 -27
  34. package/runtime/arcane/modules/WaitForComponent.js +0 -1
  35. package/src/app-descriptor.mjs +1 -1
  36. package/src/doctor.mjs +1 -3
  37. package/src/event-manager.mjs +27 -41
  38. package/src/import-map.mjs +1 -1
  39. package/src/index.mjs +2 -9
  40. package/src/installed-sdk-runtime.mjs +1 -11
  41. package/src/mail-api.mjs +0 -1
  42. package/src/native-provider-loader.mjs +0 -9
  43. package/src/scaffold.mjs +9 -21
  44. package/src/toolchain.mjs +5 -28
  45. package/src/workspace-runtime.mjs +0 -4
  46. package/src/workspace.mjs +2 -23
@@ -52,8 +52,9 @@ function validateWorker(worker) {
52
52
  const WORKER_CLIENTS = new WeakSet();
53
53
 
54
54
  /**
55
- * Owns exactly one role Worker. Cancellation terminates that Worker, which is
56
- * the only reliable preemption boundary for the third-party WASM engines.
55
+ * Owns exactly one role Worker. STT and lifecycle cancellation terminate that
56
+ * Worker. TTS use cancellation targets only the active request so sibling pool
57
+ * Workers remain available.
57
58
  */
58
59
  class SpeechWorkerClient {
59
60
  #role;
@@ -194,22 +195,54 @@ class SpeechWorkerClient {
194
195
  }
195
196
  const id = this.#nextId;
196
197
  this.#nextId += 1;
197
- return new Promise((resolve, reject) => {
198
+ const client = this;
199
+ return new Promise(function requestSpeechWorkerOperation(resolve, reject) {
198
200
  let listening = true;
199
201
  const cleanup = () => {
200
202
  if (!listening) return;
201
203
  listening = false;
202
204
  signal?.removeEventListener?.("abort", onAbort);
203
205
  };
204
- const onAbort = () => {
205
- if (!this.#pending.has(id)) return;
206
- void this.terminate(
207
- abortError(signal, this.#role, op),
206
+ function onAbort() {
207
+ const pending = client.#pending.get(id);
208
+ if (!pending) return;
209
+ if (client.#role === "tts" && op === "use") {
210
+ client.#pending.delete(id);
211
+ pending.cleanup();
212
+ pending.reject(abortError(signal, client.#role, op));
213
+ const cancelId = client.#nextId;
214
+ client.#nextId += 1;
215
+ try {
216
+ client.#transport.postMessage({
217
+ protocol: SPEECH_WORKER_PROTOCOL,
218
+ id: cancelId,
219
+ op: "cancel",
220
+ payload: { targetId: id },
221
+ });
222
+ } catch (error) {
223
+ const failure = clientError(
224
+ "ARCANE_AI_WORKER_MESSAGE_ERROR",
225
+ "Unable to cancel an operation in the speech Worker.",
226
+ error,
227
+ `${operationSubject(client.#role, op)}-message-rejected`,
228
+ );
229
+ void client.terminate(failure, { intentional: false }).catch(
230
+ function ignoreCancellationTerminationFailure() {
231
+ return undefined;
232
+ },
233
+ );
234
+ }
235
+ return;
236
+ }
237
+ void client.terminate(
238
+ abortError(signal, client.#role, op),
208
239
  { intentional: true },
209
- ).catch(() => undefined);
210
- };
240
+ ).catch(function ignoreAbortTerminationFailure() {
241
+ return undefined;
242
+ });
243
+ }
211
244
  signal?.addEventListener?.("abort", onAbort, { once: true });
212
- this.#pending.set(id, { resolve, reject, cleanup, op });
245
+ client.#pending.set(id, { resolve, reject, cleanup, op });
213
246
  const message = {
214
247
  protocol: SPEECH_WORKER_PROTOCOL,
215
248
  id,
@@ -218,18 +251,22 @@ class SpeechWorkerClient {
218
251
  };
219
252
  const transfers = collectSpeechTransferables(payload);
220
253
  try {
221
- this.#transport.postMessage(message, transfers);
254
+ client.#transport.postMessage(message, transfers);
222
255
  } catch (error) {
223
- this.#pending.delete(id);
256
+ client.#pending.delete(id);
224
257
  cleanup();
225
258
  const failure = clientError(
226
259
  "ARCANE_AI_WORKER_MESSAGE_ERROR",
227
260
  "Unable to send an operation to the speech Worker.",
228
261
  error,
229
- `${operationSubject(this.#role, op)}-message-rejected`,
262
+ `${operationSubject(client.#role, op)}-message-rejected`,
230
263
  );
231
264
  reject(failure);
232
- void this.terminate(failure, { intentional: false }).catch(() => undefined);
265
+ void client.terminate(failure, { intentional: false }).catch(
266
+ function ignoreRequestTerminationFailure() {
267
+ return undefined;
268
+ },
269
+ );
233
270
  }
234
271
  });
235
272
  }