arcane-os 0.5.7 → 0.5.9

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 +39 -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 +32 -324
  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 +569 -402
  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
@@ -1,7 +1,7 @@
1
- {
2
- "name": "strong-type",
1
+ {
2
+ "name": "strong-type",
3
3
  "version": "2.0.0",
4
- "type": "module",
4
+ "type": "module",
5
5
  "description": "Dependency-free native ESM type enforcement for JavaScript values, objects, classes, browsers, and Node.",
6
6
  "main": "index.js",
7
7
  "exports": {
@@ -19,30 +19,29 @@
19
19
  "licence"
20
20
  ],
21
21
  "sideEffects": false,
22
- "directories": {
23
- "example": "example"
24
- },
25
- "engines": {
26
- "node": ">=12.21.0"
27
- },
22
+ "directories": {
23
+ "example": "example"
24
+ },
25
+ "engines": {
26
+ "node": ">=12.21.0"
27
+ },
28
28
  "scripts": {
29
29
  "test": "node scripts/test.js",
30
30
  "test:core": "node scripts/test.js core",
31
31
  "test:node": "node scripts/test.js node",
32
32
  "test:docs": "node scripts/test.js docs",
33
- "test:legacy": "node scripts/test.js legacy",
34
33
  "coverage": "node --test --experimental-test-coverage --test-coverage-include=index.js --test-coverage-include=node.js --test-coverage-lines=95 --test-coverage-branches=90 --test-coverage-functions=95 test/CI.js test/node.js test/docs.js",
35
34
  "start": "node scripts/serve.js",
36
35
  "nodeExample": "node ./example/node/typecheck.js",
37
36
  "check": "npm test"
38
- },
39
- "repository": {
40
- "type": "git",
41
- "url": "git+https://github.com/RIAEvangelist/strong-type.git"
42
- },
43
- "keywords": [
44
- "strong",
45
- "type",
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/RIAEvangelist/strong-type.git"
41
+ },
42
+ "keywords": [
43
+ "strong",
44
+ "type",
46
45
  "validation",
47
46
  "validate",
48
47
  "check",
@@ -51,11 +50,11 @@
51
50
  "isomorphic",
52
51
  "browser",
53
52
  "node"
54
- ],
53
+ ],
55
54
  "author": "Roshi _ _",
56
- "license": "MIT",
57
- "bugs": {
58
- "url": "https://github.com/RIAEvangelist/strong-type/issues"
59
- },
55
+ "license": "MIT",
56
+ "bugs": {
57
+ "url": "https://github.com/RIAEvangelist/strong-type/issues"
58
+ },
60
59
  "homepage": "https://riaevangelist.github.io/strong-type/"
61
60
  }
@@ -28,7 +28,6 @@ export const ARCANE_EVENT_AUTHORITY_KIND='arcane-event-authority';
28
28
  export const ARCANE_EVENT_SOURCE_KIND='arcane-event-source';
29
29
  export const ARCANE_EVENT_LISTENER_ERROR_EVENT='arcane.event.listener.error';
30
30
  export const ARCANE_EVENT_SOURCE_DISPOSED_EVENT='arcane.event.source.disposed';
31
- const ARCANE_EVENT_TARGET_COMPATIBILITY_SOURCE='event-target-compatibility';
32
31
  const ARCANE_EVENT_NAME_PATTERN=/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/u;
33
32
  const ARCANE_EVENT_CHANNEL_PREFIX='arcane.event.authority.internal:';
34
33
  const ARCANE_EVENT_PROJECTION_KEYS=[
@@ -36,23 +35,13 @@ const ARCANE_EVENT_PROJECTION_KEYS=[
36
35
  ];
37
36
  const ARCANE_EVENT_REQUIRED_AUTHORITY_API=[
38
37
  'on','once','off','reset','emit','instrument','forward','subscribe','createSource',
39
- 'projectDOMEvent','isOccurrence','addEventListener','removeEventListener','dispatchEvent'
38
+ 'projectDOMEvent','isOccurrence','addEventListener','removeEventListener'
40
39
  ];
41
40
  const EVENT_MANAGER_BUS_ON=Symbol('EventManager.busOn');
42
41
  const EVENT_MANAGER_BUS_OFF=Symbol('EventManager.busOff');
43
42
  const EVENT_MANAGER_DISPATCH=Symbol('EventManager.dispatch');
44
43
 
45
44
  const ARCANE_EVENT_ERRORS={
46
- ARCANE_EVENT_AUTHORITY_ACCESSOR_COLLISION:
47
- 'globalThis.arcaneEvents must be an own data property.',
48
- ARCANE_EVENT_AUTHORITY_VALUE_COLLISION:
49
- 'globalThis.arcaneEvents is occupied by an unbranded value.',
50
- ARCANE_EVENT_AUTHORITY_DESCRIPTOR_MISMATCH:
51
- 'The globalThis.arcaneEvents property, authority brand, or protocol descriptor is incompatible.',
52
- ARCANE_EVENT_AUTHORITY_PROTOCOL_MISMATCH:
53
- 'globalThis.arcaneEvents uses an incompatible authority protocol.',
54
- ARCANE_EVENT_AUTHORITY_API_MISMATCH:
55
- 'globalThis.arcaneEvents does not expose the required authority API.',
56
45
  ARCANE_EVENT_AUTHORITY_INSTALL_FAILED:
57
46
  'The Arcane event authority could not be installed on globalThis.',
58
47
  ARCANE_EVENT_SOURCE_INVALID:
@@ -63,8 +52,6 @@ const ARCANE_EVENT_ERRORS={
63
52
  'The Arcane event source is disposed.',
64
53
  ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED:
65
54
  'The Arcane event source cannot publish an undeclared event type.',
66
- ARCANE_EVENT_COMPATIBILITY_DETAIL_INVALID:
67
- 'Arcane event compatibility detail must be safely shallow-copyable.',
68
55
  ARCANE_EVENT_OCCURRENCE_INVALID:
69
56
  'The Arcane event occurrence value or creation options are invalid.',
70
57
  ARCANE_EVENT_OCCURRENCE_SEQUENCE_EXHAUSTED:
@@ -74,7 +61,7 @@ const ARCANE_EVENT_ERRORS={
74
61
  ARCANE_EVENT_LISTENER_CALLBACK_FAILED:
75
62
  'An Arcane event listener threw during observational delivery.',
76
63
  ARCANE_EVENT_DOM_DETAIL_COLLISION:
77
- 'Arcane DOM projection metadata conflicts with compatibility detail.',
64
+ 'Arcane DOM projection metadata conflicts with source detail.',
78
65
  ARCANE_EVENT_DOM_TARGET_INVALID:
79
66
  'Arcane DOM projection requires a target with dispatchEvent and CustomEvent support.',
80
67
  ARCANE_EVENT_DOM_OPTIONS_INVALID:
@@ -88,7 +75,7 @@ const ARCANE_EVENT_ERRORS={
88
75
  ARCANE_EVENT_SUBSCRIPTION_SIGNAL_INVALID:
89
76
  'Arcane event subscription signal must be an AbortSignal.',
90
77
  ARCANE_EVENT_DISPATCH_EVENT_INVALID:
91
- 'arcaneEvents.dispatchEvent requires an Event-like object with a valid type and data detail.'
78
+ 'dispatchEvent requires an Event-like object with a valid type and data detail.'
92
79
  };
93
80
  export const ARCANE_EVENT_ERROR_CODES=Object.fromEntries(
94
81
  Object.keys(ARCANE_EVENT_ERRORS).map(code=>[code,code])
@@ -1345,7 +1332,7 @@ function createArcaneEventAuthority(){
1345
1332
  const compatibilityByOccurrence=new WeakMap();
1346
1333
  const sourceRecordByOccurrence=new WeakMap();
1347
1334
  const authorityTargetListeners=[];
1348
- const legacyListeners=[];
1335
+ const directListeners=[];
1349
1336
  let occurrenceSequence=0;
1350
1337
  let sourceSequence=0;
1351
1338
  let reportingListenerError=false;
@@ -1664,9 +1651,9 @@ function createArcaneEventAuthority(){
1664
1651
  record.unsubscribe();
1665
1652
  }
1666
1653
 
1667
- function dispatchEventLike(value,sourceRecord=null){
1654
+ function dispatchEventLike(value,sourceRecord){
1668
1655
  const admitted=eventLikeRecord(value);
1669
- if(sourceRecord&&!sourceRecord.eventTypes.has(admitted.type)){
1656
+ if(!sourceRecord.eventTypes.has(admitted.type)){
1670
1657
  throw eventAuthorityError('ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED');
1671
1658
  }
1672
1659
  const detail=compatibilityDetail(admitted.detail);
@@ -1679,8 +1666,8 @@ function createArcaneEventAuthority(){
1679
1666
  const publication=dispatchOccurrence({
1680
1667
  type:admitted.type,
1681
1668
  sourceRecord,
1682
- source:sourceRecord?.source??ARCANE_EVENT_TARGET_COMPATIBILITY_SOURCE,
1683
- instanceId:sourceRecord?.instanceId??'arcane-source-compatibility',
1669
+ source:sourceRecord.source,
1670
+ instanceId:sourceRecord.instanceId,
1684
1671
  compatibility:detail,
1685
1672
  publicDetail:detail,
1686
1673
  operationId,
@@ -1943,43 +1930,43 @@ function createArcaneEventAuthority(){
1943
1930
  return accepted&&!occurrence.defaultPrevented;
1944
1931
  }
1945
1932
 
1946
- function safeLegacyOn(type,handler,once=false){
1933
+ function safeDirectOn(type,handler,once=false){
1947
1934
  const admittedType=type==='*'?'*':eventName(type);
1948
1935
  const admitted=eventListener(handler);
1949
1936
  if(typeof once!=='boolean'){
1950
1937
  throw eventAuthorityError('ARCANE_EVENT_SUBSCRIPTION_OPTIONS_INVALID',undefined,TypeError);
1951
1938
  }
1952
1939
  const record={type:admittedType,identity:admitted.identity,wrapper:null};
1953
- function safeLegacyListener(value,...rest){
1954
- if(once)removeLegacyRecord(record);
1940
+ function safeDirectListener(value,...rest){
1941
+ if(once)removeDirectRecord(record);
1955
1942
  try{admitted.invoke(value,manager,...rest);}
1956
1943
  catch(error){reportListenerFailure(error,null,null);}
1957
1944
  }
1958
- record.wrapper=safeLegacyListener;
1959
- legacyListeners.push(record);
1960
- manager[EVENT_MANAGER_BUS_ON](admittedType,safeLegacyListener);
1945
+ record.wrapper=safeDirectListener;
1946
+ directListeners.push(record);
1947
+ manager[EVENT_MANAGER_BUS_ON](admittedType,safeDirectListener);
1961
1948
  return manager;
1962
1949
  }
1963
1950
 
1964
- function removeLegacyRecord(record){
1965
- const index=legacyListeners.indexOf(record);
1951
+ function removeDirectRecord(record){
1952
+ const index=directListeners.indexOf(record);
1966
1953
  if(index<0)return false;
1967
- legacyListeners.splice(index,1);
1954
+ directListeners.splice(index,1);
1968
1955
  manager[EVENT_MANAGER_BUS_OFF](record.type,record.wrapper);
1969
1956
  return true;
1970
1957
  }
1971
1958
 
1972
- function safeLegacyOff(type='*',handler='*'){
1959
+ function safeDirectOff(type='*',handler='*'){
1973
1960
  const admittedType=type==='*'?'*':eventName(type);
1974
- const selected=legacyListeners.filter(record=>(admittedType==='*'||record.type===admittedType)
1961
+ const selected=directListeners.filter(record=>(admittedType==='*'||record.type===admittedType)
1975
1962
  &&(handler==='*'||record.identity===handler));
1976
1963
  if(handler!=='*')eventListener(handler);
1977
- for(const record of selected)removeLegacyRecord(record);
1964
+ for(const record of selected)removeDirectRecord(record);
1978
1965
  return manager;
1979
1966
  }
1980
1967
 
1981
- function safeLegacyReset(){
1982
- for(const record of [...legacyListeners])removeLegacyRecord(record);
1968
+ function safeDirectReset(){
1969
+ for(const record of [...directListeners])removeDirectRecord(record);
1983
1970
  return manager;
1984
1971
  }
1985
1972
 
@@ -1987,10 +1974,10 @@ function createArcaneEventAuthority(){
1987
1974
  [ARCANE_EVENT_AUTHORITY_BRAND]:ARCANE_EVENT_AUTHORITY_PROTOCOL,
1988
1975
  protocol:ARCANE_EVENT_AUTHORITY_PROTOCOL,
1989
1976
  descriptor,
1990
- on:safeLegacyOn,
1991
- once:(type,handler)=>safeLegacyOn(type,handler,true),
1992
- off:safeLegacyOff,
1993
- reset:safeLegacyReset,
1977
+ on:safeDirectOn,
1978
+ once:(type,handler)=>safeDirectOn(type,handler,true),
1979
+ off:safeDirectOff,
1980
+ reset:safeDirectReset,
1994
1981
  subscribe,
1995
1982
  createSource,
1996
1983
  projectDOMEvent,
@@ -2007,8 +1994,7 @@ function createArcaneEventAuthority(){
2007
1994
  },
2008
1995
  removeEventListener(type,handler,options){
2009
1996
  removeEventTargetListener(authorityTargetListeners,type,handler,options);
2010
- },
2011
- dispatchEvent:value=>dispatchEventLike(value)
1997
+ }
2012
1998
  });
2013
1999
  return manager;
2014
2000
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -54,12 +54,11 @@
54
54
  "test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
55
55
  "test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
56
56
  "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/contracts.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
57
- "test:functional": "node ./bin/arcane-test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-download-resume.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dev-server.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/packaging.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime-sync.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/site.test.mjs test/update-check.test.mjs",
57
+ "test:functional": "node ./bin/arcane-test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-download-resume.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dev-server.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/packaging.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/site.test.mjs test/update-check.test.mjs",
58
58
  "test:integration": "node ./bin/arcane-test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-plan.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/wllama-webgpu-runtime.test.mjs",
59
59
  "test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/native-provider-generation.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
60
60
  "check": "node tools/check-source.mjs && npm test",
61
61
  "check:release": "node tools/check-source.mjs --package-only && npm run test:release",
62
- "runtime:sync": "node tools/sync-runtime.mjs",
63
62
  "pack:local": "npm pack --ignore-scripts",
64
63
  "pack:inspect": "npm pack --dry-run --json",
65
64
  "release:pack": "node tools/build-npm-release.mjs",
@@ -3406,7 +3406,7 @@
3406
3406
  &&result.disposition!==undefined
3407
3407
  &&result.status!==result.disposition
3408
3408
  ){
3409
- throw new TypeError('Tool-result status and legacy disposition must match.');
3409
+ throw new TypeError('Tool-result status and disposition must match.');
3410
3410
  }
3411
3411
  const status=result.status??result.disposition;
3412
3412
  if(!statuses.has(status)){
@@ -301,7 +301,6 @@
301
301
  || function requestSTTActivation(intent) {
302
302
  return requestAIRuntimeIntent(intent);
303
303
  };
304
- host.setAvailability = setAvailability;
305
304
  host.setMuted = setMuted;
306
305
  host.availability = {
307
306
  microphone: Boolean(
@@ -417,40 +416,15 @@
417
416
  applyConfiguredMutedState(configuredMuted);
418
417
  }
419
418
 
420
- if (
421
- Object.prototype.hasOwnProperty.call(options, 'stt')
422
- || Object.prototype.hasOwnProperty.call(options, 'tts')
423
- || Object.prototype.hasOwnProperty.call(options, 'microphone')
424
- ) {
425
- setAvailability(options);
426
- }
427
-
428
419
  return host;
429
420
  }
430
421
 
431
- function setAvailability(input = {}) {
422
+ function updateMicrophoneAvailability(available) {
432
423
  if (destroyed) {
433
- return { ...host.availability };
424
+ return;
434
425
  }
435
- // Compatibility-only explicit adapter report. Canonical consumers use
436
- // the sticky AIRuntimeState role records instead of this wrapper.
437
- const previousSTTRole = sttRole;
438
- const previousTTSRole = ttsRole;
439
426
  const microphoneWasAvailable = host.availability.microphone;
440
-
441
- if (Object.prototype.hasOwnProperty.call(input, 'microphone')) {
442
- host.availability.microphone = Boolean(input.microphone);
443
- }
444
- if (Object.prototype.hasOwnProperty.call(input, 'stt')
445
- && !Boolean(input.stt)
446
- && !selectedRole(sttRole)) {
447
- sttRole = unavailableRole('stt');
448
- }
449
- if (Object.prototype.hasOwnProperty.call(input, 'tts')
450
- && !Boolean(input.tts)
451
- && !selectedRole(ttsRole)) {
452
- ttsRole = unavailableRole('tts');
453
- }
427
+ host.availability.microphone = Boolean(available);
454
428
 
455
429
  if (microphoneWasAvailable && !host.availability.microphone) {
456
430
  cancelSTTOperation('microphone-unavailable');
@@ -462,8 +436,7 @@
462
436
  ) {
463
437
  localStatus = null;
464
438
  }
465
- applyRoleTransitions(previousSTTRole, previousTTSRole);
466
- return { ...host.availability };
439
+ applyRoleTransitions(sttRole, ttsRole);
467
440
  }
468
441
 
469
442
  function setMuted(muted) {
@@ -796,10 +769,8 @@
796
769
  if (destroyed) {
797
770
  return;
798
771
  }
799
- setAvailability(
800
- {
801
- microphone: microphonePermissionStatus?.state !== 'denied'
802
- }
772
+ updateMicrophoneAvailability(
773
+ microphonePermissionStatus?.state !== 'denied'
803
774
  );
804
775
  }
805
776
 
@@ -1265,7 +1236,7 @@
1265
1236
  owner: 'microphone'
1266
1237
  };
1267
1238
  if (microphonePermissionStatus?.state === 'denied') {
1268
- setAvailability({ microphone: false });
1239
+ updateMicrophoneAvailability(false);
1269
1240
  }
1270
1241
  dispatchSpeechEvent(
1271
1242
  'speech-microphone-unavailable',
@@ -1323,7 +1294,7 @@
1323
1294
  const audioContext = new AudioContext();
1324
1295
  const source = audioContext.createMediaStreamSource(stream);
1325
1296
 
1326
- // ScriptProcessor remains the visible compatibility capture path
1297
+ // ScriptProcessor remains the active silence-detection capture path
1327
1298
  // in this increment. AudioWorklet needs its own reviewed protocol.
1328
1299
  const processor = audioContext.createScriptProcessor(4096, 1, 1);
1329
1300
  session = {
@@ -1508,7 +1479,6 @@
1508
1479
 
1509
1480
  const transcription = await aiRuntime.fetchSTT(
1510
1481
  audioFile,
1511
- undefined,
1512
1482
  controller.signal
1513
1483
  );
1514
1484
  if (
@@ -605,7 +605,7 @@
605
605
  error.code='ARCANE_VOICE_TRANSCRIPTION_STT_RUNTIME_METHOD_UNAVAILABLE';
606
606
  throw error;
607
607
  }
608
- return globalThis.ai.fetchSTT(file,undefined,signal);
608
+ return globalThis.ai.fetchSTT(file,signal);
609
609
  }
610
610
 
611
611
  function isTranscriptionCancellation(error,controller){
@@ -1,5 +1,5 @@
1
1
  /* Arcane OS shared appearance layer.
2
- * Load after legacy layout.css (when used) and before primitives or app CSS.
2
+ * Load after the shared layout.css (when used) and before primitives or app CSS.
3
3
  * Explicit user preferences use data-color-scheme; otherwise the device
4
4
  * preference selects the light or dark base.
5
5
  */
@@ -1,7 +1,11 @@
1
1
  import Is from '../../node_modules/strong-type/index.js';
2
2
  import '../modules/DBOPFS.js';
3
3
  import '../modules/AI.js';
4
- import {hasConversationEntry,hasUserEntry} from '../modules/ChatRecords.js';
4
+ import {
5
+ hasConversationEntry,
6
+ hasUserEntry,
7
+ recurringChatMessages
8
+ } from '../modules/ChatRecords.js';
5
9
  import {normalizeMemoryContent} from '../modules/MemoryRecords.js';
6
10
 
7
11
  const is = new Is(false);
@@ -454,15 +458,16 @@ class ChatEntity{
454
458
  /**
455
459
  * Returns the current chat message array.
456
460
  *
457
- * This is intended to be passed directly into
458
- * the AI request pipeline.
461
+ * This is intended to be passed directly into the AI request pipeline.
462
+ * Unresolved structural protocol remains available for its one matching
463
+ * continuation; settled exchanges recur only as ordinary visible content.
459
464
  *
460
465
  * @returns {Array<*>}
461
466
  */
462
467
  get messages(){
463
468
  const retainedMessages=retainedChatMessages(this.#messages);
464
469
  pendingToolCalls(retainedMessages);
465
- return retainedMessages
470
+ return recurringChatMessages(retainedMessages)
466
471
  .map(function publicChatMessage(message){
467
472
  const copy={...message};
468
473
  if(copy.tool_calls){
@@ -548,7 +553,7 @@ class ChatEntity{
548
553
  * @param {string} text
549
554
  * Message content from the user.
550
555
  * @param {{hidden?:boolean,persist?:boolean}} options
551
- * The legacy hidden option excludes the message from memory extraction without
556
+ * The hidden option excludes the message from memory extraction without
552
557
  * removing it from the complete saved or UI transcript.
553
558
  */
554
559
  addUserMessage(text='',{hidden=false,persist=true}={}){
@@ -633,8 +638,8 @@ class ChatEntity{
633
638
 
634
639
  /**
635
640
  * Adds an assistant tool call and its result as one hidden, atomic log exchange.
636
- * The active provider context keeps the complete exchange. New durable history
637
- * retains only the call's required user-facing arguments.message record.
641
+ * The immediate provider continuation receives the complete exchange. Recurring
642
+ * context and new durable history retain only ordinary user-facing content.
638
643
  */
639
644
  addToolExchange({id='',name='',arguments:argumentValue='',result='',persist=true}={}){
640
645
  const toolCallId=id;