arcane-os 0.3.4 → 0.3.6

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 (35) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +7 -7
  3. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +315 -119
  4. package/browser-runtime/ai/model-controller.mjs +439 -95
  5. package/package.json +1 -1
  6. package/runtime/arcane/components/assistant-panel.html +2 -1
  7. package/runtime/arcane/components/chat.html +469 -220
  8. package/runtime/arcane/components/speech.html +33 -13
  9. package/runtime/arcane/components/voice-transcription.html +27 -3
  10. package/runtime/arcane/entities/Chat.js +165 -97
  11. package/runtime/arcane/entities/IntentEnvelope.js +52 -118
  12. package/runtime/arcane/entities/TWiNPolicyDecision.js +33 -130
  13. package/runtime/arcane/entities/User.js +38 -44
  14. package/runtime/arcane/modules/AI.js +569 -302
  15. package/runtime/arcane/modules/AIProviderRuntime.js +776 -151
  16. package/runtime/arcane/modules/AIRuntimeState.js +22 -24
  17. package/runtime/arcane/modules/ApiModelDatabase.js +54 -48
  18. package/runtime/arcane/modules/CaseEvidenceIndexer.js +6 -10
  19. package/runtime/arcane/modules/CommunicationHub.js +90 -94
  20. package/runtime/arcane/modules/ComponentContracts.js +23 -9
  21. package/runtime/arcane/modules/ConfiguredAIChatSession.js +77 -77
  22. package/runtime/arcane/modules/ConversationTimebox.js +76 -104
  23. package/runtime/arcane/modules/DBLS.js +14 -12
  24. package/runtime/arcane/modules/DBOPFS.js +20 -15
  25. package/runtime/arcane/modules/Errors.js +196 -436
  26. package/runtime/arcane/modules/HTMLImport.js +49 -32
  27. package/runtime/arcane/modules/Ollama.js +16 -14
  28. package/runtime/arcane/modules/PersistentAIChatSession.js +174 -93
  29. package/runtime/arcane/modules/RecordReviewStore.js +40 -35
  30. package/runtime/arcane/modules/TerminalClient.js +12 -14
  31. package/runtime/arcane/modules/ThemeBootstrap.js +7 -7
  32. package/runtime/arcane/modules/ThemeManager.js +5 -5
  33. package/runtime/arcane/modules/TimeGuard.js +5 -65
  34. package/runtime/arcane/modules/WaitForComponent.js +43 -40
  35. package/src/installed-sdk-runtime.mjs +11 -1
@@ -1,16 +1,4 @@
1
- const AGGREGATE_MAXIMUM_BYTES = 64 * 1024;
2
- const AMBIGUITY_MAXIMUM = 32;
3
- const CONSTRAINT_MAXIMUM = 64;
4
- const DESCRIPTION_MAXIMUM_BYTES = 2048;
5
- const EXPRESSION_MAXIMUM_BYTES = 32 * 1024;
6
- const GOAL_MAXIMUM_BYTES = 8 * 1024;
7
1
  const IDENTIFIER_MAXIMUM_CHARACTERS = 128;
8
- const LABEL_MAXIMUM_BYTES = 256;
9
- const OPTION_MAXIMUM = 16;
10
- const OPTION_MAXIMUM_BYTES = 512;
11
- const RESOURCE_LOCATOR_MAXIMUM_BYTES = 4096;
12
- const RESOURCE_MAXIMUM = 64;
13
- const SENSITIVITY_LABEL_MAXIMUM = 32;
14
2
 
15
3
  const SCHEMA = 'arcane.intent-envelope';
16
4
  const VERSION = 1;
@@ -45,18 +33,18 @@ const RESOURCE_KEY_VALUES = ['id', 'type', 'locator', 'description'];
45
33
  const AMBIGUITY_KEY_VALUES = ['id', 'kind', 'description', 'options'];
46
34
  const SENSITIVITY_KEY_VALUES = ['level', 'labels'];
47
35
  const PROVENANCE_KEY_VALUES = ['source', 'channel', 'actorId', 'applicationId', 'sessionId'];
48
- const ROOT_KEYS = Object.freeze(ROOT_KEY_VALUES);
49
- const PAYLOAD_KEYS = Object.freeze(PAYLOAD_KEY_VALUES);
50
- const TRUSTED_CONTEXT_KEYS = Object.freeze(TRUSTED_CONTEXT_KEY_VALUES);
51
- const GOAL_KEYS = Object.freeze(GOAL_KEY_VALUES);
52
- const CONSTRAINT_KEYS = Object.freeze(CONSTRAINT_KEY_VALUES);
53
- const RESOURCE_KEYS = Object.freeze(RESOURCE_KEY_VALUES);
54
- const AMBIGUITY_KEYS = Object.freeze(AMBIGUITY_KEY_VALUES);
55
- const SENSITIVITY_KEYS = Object.freeze(SENSITIVITY_KEY_VALUES);
56
- const PROVENANCE_KEYS = Object.freeze(PROVENANCE_KEY_VALUES);
57
-
58
- const encoder = new TextEncoder();
36
+ const ROOT_KEYS = ROOT_KEY_VALUES;
37
+ const PAYLOAD_KEYS = PAYLOAD_KEY_VALUES;
38
+ const TRUSTED_CONTEXT_KEYS = TRUSTED_CONTEXT_KEY_VALUES;
39
+ const GOAL_KEYS = GOAL_KEY_VALUES;
40
+ const CONSTRAINT_KEYS = CONSTRAINT_KEY_VALUES;
41
+ const RESOURCE_KEYS = RESOURCE_KEY_VALUES;
42
+ const AMBIGUITY_KEYS = AMBIGUITY_KEY_VALUES;
43
+ const SENSITIVITY_KEYS = SENSITIVITY_KEY_VALUES;
44
+ const PROVENANCE_KEYS = PROVENANCE_KEY_VALUES;
45
+
59
46
  const constructionToken = Symbol('IntentEnvelope construction');
47
+ const intentEnvelopeInstances = new WeakSet();
60
48
 
61
49
  export class IntentEnvelopeValidationError extends TypeError {
62
50
  constructor(code, path, message, options) {
@@ -91,11 +79,7 @@ function validateUnicode(value, path) {
91
79
  return value;
92
80
  }
93
81
 
94
- function byteLength(value) {
95
- return encoder.encode(value).byteLength;
96
- }
97
-
98
- function boundedString(value, path, maximum, options = {}) {
82
+ function normalizedString(value, path, options = {}) {
99
83
  const nullable = options.nullable === true;
100
84
  const nonempty = options.nonempty !== false;
101
85
 
@@ -109,9 +93,6 @@ function boundedString(value, path, maximum, options = {}) {
109
93
  if (nonempty && !value.trim()) {
110
94
  fail('INTENT_ENVELOPE_INVALID', path, 'Intent envelope field must contain text.');
111
95
  }
112
- if (byteLength(value) > maximum) {
113
- fail('INTENT_ENVELOPE_LIMIT_EXCEEDED', path, 'Intent envelope field exceeds its size limit.');
114
- }
115
96
  return value;
116
97
  }
117
98
 
@@ -143,7 +124,11 @@ function plainRecord(value, path, allowedKeys, active) {
143
124
  fail('INTENT_ENVELOPE_INVALID', path, 'Intent envelope field must be a plain record.');
144
125
  }
145
126
  const prototype = Object.getPrototypeOf(value);
146
- if (prototype !== Object.prototype && prototype !== null) {
127
+ if (
128
+ prototype !== Object.prototype
129
+ && prototype !== null
130
+ && !intentEnvelopeInstances.has(value)
131
+ ) {
147
132
  fail('INTENT_ENVELOPE_INVALID', path, 'Intent envelope record prototype is invalid.');
148
133
  }
149
134
  if (active.has(value)) {
@@ -186,16 +171,13 @@ function ownValue(record, key, path, options = {}) {
186
171
  return descriptor.value;
187
172
  }
188
173
 
189
- function denseArray(value, path, maximum, active) {
174
+ function denseArray(value, path, active) {
190
175
  if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) {
191
176
  fail('INTENT_ENVELOPE_INVALID', path, 'Intent envelope field must be an array.');
192
177
  }
193
178
  if (active.has(value)) {
194
179
  fail('INTENT_ENVELOPE_INVALID', path, 'Intent envelope data must not contain cycles.');
195
180
  }
196
- if (value.length > maximum) {
197
- fail('INTENT_ENVELOPE_LIMIT_EXCEEDED', path, 'Intent envelope array exceeds its item limit.');
198
- }
199
181
  active.add(value);
200
182
  const keys = Reflect.ownKeys(value);
201
183
  for (const key of keys) {
@@ -258,7 +240,7 @@ function normalizeGoal(value, path, active) {
258
240
  const textValue = ownValue(record, 'text', path);
259
241
  const producerValue = ownValue(record, 'producer', path);
260
242
  const versionValue = ownValue(record, 'version', path);
261
- const text = boundedString(textValue, `${path}.text`, GOAL_MAXIMUM_BYTES);
243
+ const text = normalizedString(textValue, `${path}.text`);
262
244
  const producer = identifier(producerValue, `${path}.producer`);
263
245
  const version = identifier(versionValue, `${path}.version`);
264
246
  const confidenceValue = ownValue(record, 'confidence', path);
@@ -270,7 +252,7 @@ function normalizeGoal(value, path, active) {
270
252
  }
271
253
  finishRecord(record, active);
272
254
  const goal = { text, producer, version, confidence: confidenceValue };
273
- return Object.freeze(goal);
255
+ return goal;
274
256
  }
275
257
 
276
258
  function normalizeScalar(value, path) {
@@ -298,7 +280,7 @@ function normalizeConstraint(value, index, active) {
298
280
  const id = identifier(idValue, `${path}.id`);
299
281
  const kind = enumeration(kindValue, `${path}.kind`, CONSTRAINT_KINDS);
300
282
  const scalar = normalizeScalar(scalarValue, `${path}.value`);
301
- const description = boundedString(
283
+ const description = normalizedString(
302
284
  ownValue(
303
285
  record,
304
286
  'description',
@@ -309,14 +291,13 @@ function normalizeConstraint(value, index, active) {
309
291
  }
310
292
  ),
311
293
  `${path}.description`,
312
- DESCRIPTION_MAXIMUM_BYTES,
313
294
  {
314
295
  nullable: true
315
296
  }
316
297
  );
317
298
  finishRecord(record, active);
318
299
  const constraint = { id, kind, value: scalar, description };
319
- return Object.freeze(constraint);
300
+ return constraint;
320
301
  }
321
302
 
322
303
  function normalizeResource(value, index, active) {
@@ -327,8 +308,8 @@ function normalizeResource(value, index, active) {
327
308
  const locatorValue = ownValue(record, 'locator', path);
328
309
  const id = identifier(idValue, `${path}.id`);
329
310
  const type = enumeration(typeValue, `${path}.type`, RESOURCE_TYPES);
330
- const locator = boundedString(locatorValue, `${path}.locator`, RESOURCE_LOCATOR_MAXIMUM_BYTES);
331
- const description = boundedString(
311
+ const locator = normalizedString(locatorValue, `${path}.locator`);
312
+ const description = normalizedString(
332
313
  ownValue(
333
314
  record,
334
315
  'description',
@@ -339,26 +320,25 @@ function normalizeResource(value, index, active) {
339
320
  }
340
321
  ),
341
322
  `${path}.description`,
342
- DESCRIPTION_MAXIMUM_BYTES,
343
323
  {
344
324
  nullable: true
345
325
  }
346
326
  );
347
327
  finishRecord(record, active);
348
328
  const resource = { id, type, locator, description };
349
- return Object.freeze(resource);
329
+ return resource;
350
330
  }
351
331
 
352
332
  function normalizeOptions(value, path, active) {
353
- const options = denseArray(value, path, OPTION_MAXIMUM, active);
333
+ const options = denseArray(value, path, active);
354
334
  const normalized = [];
355
335
  for (let index = 0; index < options.length; index += 1) {
356
336
  const descriptor = Object.getOwnPropertyDescriptor(options, String(index));
357
- const normalizedOption = boundedString(descriptor.value, `${path}[${index}]`, OPTION_MAXIMUM_BYTES);
337
+ const normalizedOption = normalizedString(descriptor.value, `${path}[${index}]`);
358
338
  normalized.push(normalizedOption);
359
339
  }
360
340
  finishArray(options, active);
361
- return Object.freeze(normalized);
341
+ return normalized;
362
342
  }
363
343
 
364
344
  function normalizeAmbiguity(value, index, active) {
@@ -368,10 +348,9 @@ function normalizeAmbiguity(value, index, active) {
368
348
  const kindValue = ownValue(record, 'kind', path);
369
349
  const id = identifier(idValue, `${path}.id`);
370
350
  const kind = enumeration(kindValue, `${path}.kind`, AMBIGUITY_KINDS);
371
- const description = boundedString(
351
+ const description = normalizedString(
372
352
  ownValue(record, 'description', path),
373
353
  `${path}.description`,
374
- DESCRIPTION_MAXIMUM_BYTES,
375
354
  );
376
355
  const options = normalizeOptions(
377
356
  ownValue(
@@ -388,11 +367,11 @@ function normalizeAmbiguity(value, index, active) {
388
367
  );
389
368
  finishRecord(record, active);
390
369
  const ambiguity = { id, kind, description, options };
391
- return Object.freeze(ambiguity);
370
+ return ambiguity;
392
371
  }
393
372
 
394
- function normalizeList(value, path, maximum, normalizer, active) {
395
- const list = denseArray(value, path, maximum, active);
373
+ function normalizeList(value, path, normalizer, active) {
374
+ const list = denseArray(value, path, active);
396
375
  const normalized = [];
397
376
  const ids = new Set();
398
377
  for (let index = 0; index < list.length; index += 1) {
@@ -406,7 +385,7 @@ function normalizeList(value, path, maximum, normalizer, active) {
406
385
  normalized.push(item);
407
386
  }
408
387
  finishArray(list, active);
409
- return Object.freeze(normalized);
388
+ return normalized;
410
389
  }
411
390
 
412
391
  function normalizeSensitivity(value, path, active) {
@@ -422,16 +401,15 @@ function normalizeSensitivity(value, path, active) {
422
401
  defaultValue: []
423
402
  }
424
403
  );
425
- const labels = denseArray(labelsValue, `${path}.labels`, SENSITIVITY_LABEL_MAXIMUM, active);
404
+ const labels = denseArray(labelsValue, `${path}.labels`, active);
426
405
  const normalized = [];
427
406
  const seen = new Set();
428
407
  for (let index = 0; index < labels.length; index += 1) {
429
408
  const descriptor = Object.getOwnPropertyDescriptor(labels, String(index));
430
- const label = boundedString(
409
+ const label = normalizedString(
431
410
  descriptor.value,
432
411
  `${path}.labels[${index}]`,
433
- LABEL_MAXIMUM_BYTES,
434
- ).trim();
412
+ );
435
413
  if (seen.has(label)) {
436
414
  finishArray(labels, active);
437
415
  finishRecord(record, active);
@@ -445,9 +423,9 @@ function normalizeSensitivity(value, path, active) {
445
423
  finishRecord(record, active);
446
424
  const sensitivity = {
447
425
  level,
448
- labels: Object.freeze(normalized)
426
+ labels: normalized
449
427
  };
450
- return Object.freeze(sensitivity);
428
+ return sensitivity;
451
429
  }
452
430
 
453
431
  function normalizeProvenance(value, path, active) {
@@ -467,7 +445,7 @@ function normalizeProvenance(value, path, active) {
467
445
  const sessionId = identifier(sessionIdValue, `${path}.sessionId`, nullableIdentifierOptions);
468
446
  finishRecord(record, active);
469
447
  const provenance = { source, channel, actorId, applicationId, sessionId };
470
- return Object.freeze(provenance);
448
+ return provenance;
471
449
  }
472
450
 
473
451
  function cloneGoal(value) {
@@ -542,14 +520,6 @@ function canonicalRecord(values) {
542
520
  };
543
521
  }
544
522
 
545
- function validateAggregate(values) {
546
- const canonical = canonicalRecord(values);
547
- const serialized = JSON.stringify(canonical);
548
- if (byteLength(serialized) > AGGREGATE_MAXIMUM_BYTES) {
549
- fail('INTENT_ENVELOPE_LIMIT_EXCEEDED', '$', 'Intent envelope exceeds its aggregate size limit.');
550
- }
551
- }
552
-
553
523
  function normalizeValues(input) {
554
524
  const active = new WeakSet();
555
525
  const record = plainRecord(input, '$', ROOT_KEYS, active);
@@ -571,30 +541,26 @@ function normalizeValues(input) {
571
541
  const values = {
572
542
  id: identifier(idValue, 'id'),
573
543
  createdAt: normalizeTimestamp(createdAtValue, 'createdAt'),
574
- originalExpression: boundedString(
544
+ originalExpression: normalizedString(
575
545
  ownValue(record, 'originalExpression', '$'),
576
546
  'originalExpression',
577
- EXPRESSION_MAXIMUM_BYTES,
578
547
  ),
579
548
  normalizedGoal: normalizeGoal(normalizedGoalValue, 'normalizedGoal', active),
580
549
  constraints: normalizeList(
581
550
  ownValue(record, 'constraints', '$'),
582
551
  'constraints',
583
- CONSTRAINT_MAXIMUM,
584
552
  normalizeConstraint,
585
553
  active,
586
554
  ),
587
555
  resources: normalizeList(
588
556
  ownValue(record, 'resources', '$'),
589
557
  'resources',
590
- RESOURCE_MAXIMUM,
591
558
  normalizeResource,
592
559
  active,
593
560
  ),
594
561
  ambiguities: normalizeList(
595
562
  ownValue(record, 'ambiguities', '$'),
596
563
  'ambiguities',
597
- AMBIGUITY_MAXIMUM,
598
564
  normalizeAmbiguity,
599
565
  active,
600
566
  ),
@@ -602,7 +568,6 @@ function normalizeValues(input) {
602
568
  provenance: normalizeProvenance(provenanceValue, 'provenance', active)
603
569
  };
604
570
  finishRecord(record, active);
605
- validateAggregate(values);
606
571
  return values;
607
572
  }
608
573
 
@@ -720,11 +685,11 @@ class IntentEnvelope {
720
685
  this.ambiguities = values.ambiguities;
721
686
  this.sensitivity = values.sensitivity;
722
687
  this.provenance = values.provenance;
723
- Object.freeze(this);
688
+ intentEnvelopeInstances.add(this);
724
689
  }
725
690
 
726
691
  toJSON() {
727
- return canonicalRecord(this);
692
+ return canonicalRecord(normalizeValues(this));
728
693
  }
729
694
  }
730
695
 
@@ -739,10 +704,6 @@ export function createIntentEnvelope(payload, trustedContext) {
739
704
  }
740
705
 
741
706
  export function rehydrateIntentEnvelope(canonical) {
742
- if (canonical instanceof IntentEnvelope) {
743
- return canonical;
744
- }
745
-
746
707
  if (typeof canonical === 'string') {
747
708
  try {
748
709
  const parsed = JSON.parse(canonical);
@@ -780,38 +741,11 @@ export function intentEnvelopeAuditProjection(envelope) {
780
741
  sensitivity: cloneSensitivity(value.sensitivity),
781
742
  provenance: cloneProvenance(value.provenance),
782
743
  };
783
- const frozenConstraints = projection.constraints.map(Object.freeze);
784
- const frozenResources = projection.resources.map(Object.freeze);
785
- const frozenAmbiguities = projection.ambiguities.map(Object.freeze);
786
- const frozenSensitivity = {
787
- ...projection.sensitivity,
788
- labels: Object.freeze(projection.sensitivity.labels)
789
- };
790
- const frozenProjection = {
791
- ...projection,
792
- constraints: Object.freeze(frozenConstraints),
793
- resources: Object.freeze(frozenResources),
794
- ambiguities: Object.freeze(frozenAmbiguities),
795
- sensitivity: Object.freeze(frozenSensitivity),
796
- provenance: Object.freeze(projection.provenance)
797
- };
798
- return Object.freeze(frozenProjection);
744
+ return projection;
799
745
  }
800
746
 
801
747
  const intentEnvelopeLimits = {
802
- aggregateBytes: AGGREGATE_MAXIMUM_BYTES,
803
- ambiguityCount: AMBIGUITY_MAXIMUM,
804
- constraintCount: CONSTRAINT_MAXIMUM,
805
- descriptionBytes: DESCRIPTION_MAXIMUM_BYTES,
806
- expressionBytes: EXPRESSION_MAXIMUM_BYTES,
807
- goalBytes: GOAL_MAXIMUM_BYTES,
808
- identifierCharacters: IDENTIFIER_MAXIMUM_CHARACTERS,
809
- labelBytes: LABEL_MAXIMUM_BYTES,
810
- optionBytes: OPTION_MAXIMUM_BYTES,
811
- optionCount: OPTION_MAXIMUM,
812
- resourceCount: RESOURCE_MAXIMUM,
813
- resourceLocatorBytes: RESOURCE_LOCATOR_MAXIMUM_BYTES,
814
- sensitivityLabelCount: SENSITIVITY_LABEL_MAXIMUM
748
+ identifierCharacters: IDENTIFIER_MAXIMUM_CHARACTERS
815
749
  };
816
750
  const ambiguityKinds = [...AMBIGUITY_KINDS];
817
751
  const constraintKinds = [...CONSTRAINT_KINDS];
@@ -822,13 +756,13 @@ const sensitivityLevels = [...SENSITIVITY_LEVELS];
822
756
  const intentEnvelopeContractValue = {
823
757
  schema: SCHEMA,
824
758
  version: VERSION,
825
- limits: Object.freeze(intentEnvelopeLimits),
826
- ambiguityKinds: Object.freeze(ambiguityKinds),
827
- constraintKinds: Object.freeze(constraintKinds),
828
- provenanceChannels: Object.freeze(provenanceChannels),
829
- provenanceSources: Object.freeze(provenanceSources),
830
- resourceTypes: Object.freeze(resourceTypes),
831
- sensitivityLevels: Object.freeze(sensitivityLevels)
759
+ limits: intentEnvelopeLimits,
760
+ ambiguityKinds,
761
+ constraintKinds,
762
+ provenanceChannels,
763
+ provenanceSources,
764
+ resourceTypes,
765
+ sensitivityLevels
832
766
  };
833
767
 
834
- export const intentEnvelopeContract = Object.freeze(intentEnvelopeContractValue);
768
+ export const intentEnvelopeContract = intentEnvelopeContractValue;