arcane-os 0.7.0 → 0.7.1

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.
@@ -1592,6 +1592,52 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
1592
1592
  if (engine) return status();
1593
1593
  lifecycleReason = `${role}-load-started`;
1594
1594
  let loadFailureReason = `${role}-worker-runtime-configuration-rejected`;
1595
+ let reporting = true;
1596
+ const completedFiles = new Set();
1597
+ const loadingFiles = new Set();
1598
+ function publishProgress(progress) {
1599
+ if (!reporting || signal?.aborted) return;
1600
+ send(
1601
+ {
1602
+ protocol: SPEECH_WORKER_PROTOCOL,
1603
+ id: request.id,
1604
+ type: 'progress',
1605
+ progress,
1606
+ }
1607
+ );
1608
+ }
1609
+ function reportModelProgress(detail) {
1610
+ if (!reporting || signal?.aborted) return;
1611
+ const file = detail?.file ?? null;
1612
+ if (file !== null) {
1613
+ const fileKey = `${detail.name ?? ''}/${file}`;
1614
+ if (detail?.status === 'done') {
1615
+ completedFiles.add(fileKey);
1616
+ loadingFiles.delete(fileKey);
1617
+ } else {
1618
+ loadingFiles.add(fileKey);
1619
+ }
1620
+ }
1621
+ const initializing = detail?.status === 'ready'
1622
+ || (detail?.status === 'done' && loadingFiles.size === 0);
1623
+ const message = initializing
1624
+ ? 'Preparing the speech model session'
1625
+ : detail?.status === 'done'
1626
+ ? 'Loaded model file'
1627
+ : 'Loading model file';
1628
+ publishProgress(
1629
+ {
1630
+ phase: initializing ? 'initialize' : 'download',
1631
+ stage: 'model',
1632
+ message,
1633
+ file,
1634
+ completed: completedFiles.size,
1635
+ total: null,
1636
+ unit: 'files',
1637
+ detail,
1638
+ }
1639
+ );
1640
+ }
1595
1641
  try {
1596
1642
  configuration = validateConfiguration(request.payload?.configuration, role);
1597
1643
  const entry = configuration.runtime.files.find((file) =>
@@ -1605,6 +1651,15 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
1605
1651
  });
1606
1652
  }
1607
1653
  loadFailureReason = `${role}-worker-runtime-import-rejected`;
1654
+ publishProgress(
1655
+ {
1656
+ phase: 'initialize',
1657
+ stage: 'runtime',
1658
+ message: 'Opening the speech runtime',
1659
+ file: entry.path,
1660
+ total: null,
1661
+ }
1662
+ );
1608
1663
  const namespace = await import(entry.moduleUrl);
1609
1664
  throwIfAborted(signal, `${role}-load-cancelled`);
1610
1665
  restoreNamespace = configureRuntimeNamespace(
@@ -1614,10 +1669,17 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
1614
1669
  environment.cache,
1615
1670
  );
1616
1671
  loadFailureReason = `${role}-worker-model-load-rejected`;
1617
- const report = () => undefined;
1672
+ publishProgress(
1673
+ {
1674
+ phase: 'initialize',
1675
+ stage: 'model',
1676
+ message: `Initializing the speech model on ${configuration.execution?.device ?? 'wasm'}`,
1677
+ total: null,
1678
+ }
1679
+ );
1618
1680
  engine = role === "stt"
1619
- ? await createWhisperEngine(namespace, configuration, signal, report)
1620
- : await createKokoroEngine(namespace, configuration, signal, report);
1681
+ ? await createWhisperEngine(namespace, configuration, signal, reportModelProgress)
1682
+ : await createKokoroEngine(namespace, configuration, signal, reportModelProgress);
1621
1683
  lifecycleReason = `${role}-load-completed`;
1622
1684
  return status();
1623
1685
  } catch (error) {
@@ -1645,6 +1707,8 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
1645
1707
  configuration = null;
1646
1708
  lifecycleReason = failure.reason;
1647
1709
  throw failure;
1710
+ } finally {
1711
+ reporting = false;
1648
1712
  }
1649
1713
  }
1650
1714
 
@@ -3490,7 +3490,9 @@ var Wllama = class {
3490
3490
  }
3491
3491
 
3492
3492
  const adapterAnchor = "if(adapter){WebGPU.Internals.jsObjectInsert(adapterPtr,adapter)";
3493
- const adapterProjection = `if(adapter){(function arcaneRecordSelectedWebgpuAdapter(){const key="__arcaneWllamaWebgpuTelemetry";const previous=globalThis[key]??${emptyWorkerTelemetry};const info=adapter.info??{};const text=value=>typeof value==="string"?value.slice(0,256):"";const next={selected:true,vendorId:null,vendor:text(info.vendor),architecture:text(info.architecture),deviceId:null,name:text(info.device),description:text(info.description)};const conflicts=previous.adapter!==null&&JSON.stringify(previous.adapter)!==JSON.stringify(next);globalThis[key]={protocol:"${protocol}",adapter:previous.adapter??next,bufferCount:previous.bufferCount,bufferBytes:previous.bufferBytes,queueSubmissions:previous.queueSubmissions,commandBuffers:previous.commandBuffers,queueFenceRequests:previous.queueFenceRequests,queueFenceCompletions:previous.queueFenceCompletions,invalid:previous.invalid||conflicts}})();WebGPU.Internals.jsObjectInsert(adapterPtr,adapter)`;
3493
+ const adapterProjection = `if(adapter){(function arcaneRecordSelectedWebgpuAdapter(){const key="__arcaneWllamaWebgpuTelemetry";const previous=globalThis[key]??${emptyWorkerTelemetry};const info=adapter.info??{};const text = function preserveAdapterText(value) {
3494
+ return typeof value === 'string' ? value : '';
3495
+ };const next={selected:true,vendorId:null,vendor:text(info.vendor),architecture:text(info.architecture),deviceId:null,name:text(info.device),description:text(info.description),type:typeof info.type==="string"&&info.type?info.type:null,isFallbackAdapter:typeof info.isFallbackAdapter==="boolean"?info.isFallbackAdapter:typeof adapter.isFallbackAdapter==="boolean"?adapter.isFallbackAdapter:null};const conflicts=previous.adapter!==null&&JSON.stringify(previous.adapter)!==JSON.stringify(next);globalThis[key]={protocol:"${protocol}",adapter:previous.adapter??next,bufferCount:previous.bufferCount,bufferBytes:previous.bufferBytes,queueSubmissions:previous.queueSubmissions,commandBuffers:previous.commandBuffers,queueFenceRequests:previous.queueFenceRequests,queueFenceCompletions:previous.queueFenceCompletions,invalid:previous.invalid||conflicts}})();WebGPU.Internals.jsObjectInsert(adapterPtr,adapter)`;
3494
3496
  WLLAMA_EMSCRIPTEN_CODE = replaceSingle(
3495
3497
  WLLAMA_EMSCRIPTEN_CODE,
3496
3498
  adapterAnchor,
@@ -3526,7 +3528,7 @@ var Wllama = class {
3526
3528
  );
3527
3529
 
3528
3530
  const workerAnchor = " if (verb === 'module.init') {";
3529
- const workerProjection = ` if (verb === 'arcane.telemetry') {\n const observed = globalThis.__arcaneWllamaWebgpuTelemetry;\n const adapter = observed?.adapter?.selected === true ? {\n selected: true,\n vendorId: null,\n vendor: typeof observed.adapter.vendor === 'string' ? observed.adapter.vendor.slice(0, 256) : '',\n architecture: typeof observed.adapter.architecture === 'string' ? observed.adapter.architecture.slice(0, 256) : '',\n deviceId: null,\n name: typeof observed.adapter.name === 'string' ? observed.adapter.name.slice(0, 256) : '',\n description: typeof observed.adapter.description === 'string' ? observed.adapter.description.slice(0, 256) : '',\n } : null;\n msg({\n callbackId,\n result: {\n protocol: '${protocol}',\n adapter,\n bufferCount: Number.isSafeInteger(observed?.bufferCount) ? observed.bufferCount : 0,\n bufferBytes: Number.isSafeInteger(observed?.bufferBytes) ? observed.bufferBytes : 0,\n queueSubmissions: Number.isSafeInteger(observed?.queueSubmissions) ? observed.queueSubmissions : 0,\n commandBuffers: Number.isSafeInteger(observed?.commandBuffers) ? observed.commandBuffers : 0,\n queueFenceRequests: Number.isSafeInteger(observed?.queueFenceRequests) ? observed.queueFenceRequests : 0,\n queueFenceCompletions: Number.isSafeInteger(observed?.queueFenceCompletions) ? observed.queueFenceCompletions : 0,\n invalid: observed?.invalid === true,\n },\n });\n return;\n }\n\n${workerAnchor}`;
3531
+ const workerProjection = ` if (verb === 'arcane.telemetry') {\n const observed = globalThis.__arcaneWllamaWebgpuTelemetry;\n const adapter = observed?.adapter?.selected === true ? {\n selected: true,\n vendorId: null,\n vendor: typeof observed.adapter.vendor === 'string' ? observed.adapter.vendor : '',\n architecture: typeof observed.adapter.architecture === 'string' ? observed.adapter.architecture : '',\n deviceId: null,\n name: typeof observed.adapter.name === 'string' ? observed.adapter.name : '',\n description: typeof observed.adapter.description === 'string' ? observed.adapter.description : '',\n type: typeof observed.adapter.type === 'string' ? observed.adapter.type : null,\n isFallbackAdapter: typeof observed.adapter.isFallbackAdapter === 'boolean' ? observed.adapter.isFallbackAdapter : null,\n } : null;\n msg({\n callbackId,\n result: {\n protocol: '${protocol}',\n adapter,\n bufferCount: Number.isSafeInteger(observed?.bufferCount) ? observed.bufferCount : 0,\n bufferBytes: Number.isSafeInteger(observed?.bufferBytes) ? observed.bufferBytes : 0,\n queueSubmissions: Number.isSafeInteger(observed?.queueSubmissions) ? observed.queueSubmissions : 0,\n commandBuffers: Number.isSafeInteger(observed?.commandBuffers) ? observed.commandBuffers : 0,\n queueFenceRequests: Number.isSafeInteger(observed?.queueFenceRequests) ? observed.queueFenceRequests : 0,\n queueFenceCompletions: Number.isSafeInteger(observed?.queueFenceCompletions) ? observed.queueFenceCompletions : 0,\n invalid: observed?.invalid === true,\n },\n });\n return;\n }\n\n${workerAnchor}`;
3530
3532
  LLAMA_CPP_WORKER_CODE = replaceSingle(
3531
3533
  LLAMA_CPP_WORKER_CODE,
3532
3534
  workerAnchor,
@@ -3539,7 +3541,7 @@ var Wllama = class {
3539
3541
  return Number.isSafeInteger(candidate) && candidate >= 0 ? candidate : 0;
3540
3542
  }
3541
3543
  function adapterText(candidate) {
3542
- return typeof candidate === "string" && candidate.length <= 256 ? candidate : "";
3544
+ return typeof candidate === "string" ? candidate : "";
3543
3545
  }
3544
3546
  const rawAdapter = value?.adapter;
3545
3547
  const adapterInvalid = rawAdapter !== undefined && rawAdapter !== null && (
@@ -3547,16 +3549,12 @@ var Wllama = class {
3547
3549
  || rawAdapter.selected !== true
3548
3550
  || rawAdapter.vendorId !== null
3549
3551
  || typeof rawAdapter.vendor !== "string"
3550
- || rawAdapter.vendor.length > 256
3551
3552
  || typeof rawAdapter.architecture !== "string"
3552
- || rawAdapter.architecture.length > 256
3553
3553
  || rawAdapter.deviceId !== null
3554
3554
  || typeof rawAdapter.name !== "string"
3555
- || rawAdapter.name.length > 256
3556
3555
  || typeof rawAdapter.description !== "string"
3557
- || rawAdapter.description.length > 256
3558
3556
  );
3559
- const adapter = rawAdapter?.selected === true ? Object.freeze({
3557
+ const adapter = rawAdapter?.selected === true ? {
3560
3558
  selected: true,
3561
3559
  vendorId: null,
3562
3560
  vendor: adapterText(rawAdapter.vendor),
@@ -3564,7 +3562,9 @@ var Wllama = class {
3564
3562
  deviceId: null,
3565
3563
  name: adapterText(rawAdapter.name),
3566
3564
  description: adapterText(rawAdapter.description),
3567
- }) : null;
3565
+ type: typeof rawAdapter.type === "string" ? rawAdapter.type : null,
3566
+ isFallbackAdapter: typeof rawAdapter.isFallbackAdapter === "boolean" ? rawAdapter.isFallbackAdapter : null,
3567
+ } : null;
3568
3568
  return Object.freeze({
3569
3569
  protocol,
3570
3570
  adapter,
@@ -279,7 +279,7 @@ paths are withheld from the native provider. The provider copies the complete
279
279
  selected release rather than accepting an unrelated source path. Verification
280
280
  is a separate explicit operation for a selected release artifact.
281
281
 
282
- The SDK `0.7.0` runtime requires Arcane `0.8.12` or newer. Compatibility
282
+ The SDK `0.7.1` runtime requires Arcane `0.8.12` or newer. Compatibility
283
283
  is contractual rather than exact-version pinning: the prepared Core must meet
284
284
  the highest minimum declared by the runtime, selected app, and bundled app
285
285
  dependencies; keep each app's Arcane protocol generation; and provide every
@@ -144,28 +144,33 @@ name. It does not load a model or create a GPU device or WebNN context:
144
144
  </html-import>
145
145
  ```
146
146
 
147
- The **NPU setup** section provides real browser-specific flags links. Chrome uses
147
+ When WebNN is unavailable, **NPU setup** provides a **Copy NPU flag address**
148
+ button and a short enable/relaunch instruction. Chrome uses
148
149
  `chrome://flags/#web-machine-learning-neural-network`; Edge uses
149
150
  `edge://flags/#web-machine-learning-neural-network`. Unrecognized browsers
150
- receive explicit Chrome and Edge choices. Full addresses and copy controls
151
- remain available if the browser blocks internal-page links.
151
+ receive explicit Chrome and Edge choices. A failed copy shows the complete
152
+ address as selectable text; the component does not open internal browser pages.
152
153
  The [ONNX Runtime WebNN guide](https://onnxruntime.ai/docs/tutorials/web/ep-webnn.html)
153
154
  documents the **Enables WebNN API** flag and model/operator requirements.
154
155
 
155
- The **GPU performance** section shows adapter detection and, on desktop Windows
156
- Chromium browsers, the matching Force High Performance GPU flags link. Identified
156
+ The **GPU performance** section shows a short adapter status. Only an explicitly
157
+ reported integrated or software adapter receives setup guidance on desktop
158
+ Windows Chromium browsers. Identified
157
159
  Chrome uses `chrome://flags/#force-high-performance-gpu`; other recognized
158
- Chromium browsers use their corresponding internal scheme. **Detect GPU** or
159
- **Refresh browser availability** requests a new availability result; concurrent
160
+ Chromium browsers use their corresponding internal scheme. **Refresh**
161
+ requests a new availability result; concurrent
160
162
  requests share the pending operation. The public `checkGpu()` method provides
161
163
  the same promise, while `refresh()` remains a synchronous API-presence and
162
164
  settings update. Component readiness does not wait for adapter detection.
163
165
 
164
166
  Adapter selection uses `powerPreference: "high-performance"` as a hint, not proof
165
- of the selected GPU's performance or the flag's current state. A returned
166
- adapter establishes availability only; its fallback classification is reported
167
- when exposed. The component cannot read the browser flag or prove that a model
168
- is executing on the adapter. See the
167
+ of the selected GPU's performance or the flag's current state. When the browser
168
+ explicitly reports a discrete GPU, Profile says **Already using the performance
169
+ GPU.** and hides setup instructions. Explicit integrated or software/fallback
170
+ metadata is reported as such. Missing type metadata shows **GPU available.**
171
+ without flag advice and leaves performance selection unconfirmed; a vendor name is not a GPU
172
+ classification. The component cannot read the browser flag or prove that a
173
+ model is executing on the adapter. See the
169
174
  [component contract](../runtime-components.md#browser-ai-setuphtml) for result
170
175
  fields, failure handling, and disposal behavior.
171
176
 
@@ -1204,10 +1209,22 @@ that accelerator kernels overlap, or that generated speech is correct. WebNN
1204
1209
  may execute unsupported operations through WASM. A security field is absent
1205
1210
  in ordinary mode.
1206
1211
 
1207
- The provider/2 load context accepts an optional progress callback for interface
1208
- compatibility, but the current browser-speech artifact and Worker transport
1209
- publishes no progress records. Consumers present the explicit lifecycle states
1210
- instead of inventing a numeric total.
1212
+ The provider/2 load context accepts an optional `progress` callback. Speech
1213
+ artifact preparation and upstream model loading publish records through that
1214
+ callback and the shared sticky AI runtime state. Records include `phase`,
1215
+ `stage`, `message`, the current `file` when available, and `elapsedMs`.
1216
+ Known artifact inventories report `completed`, `total`, and `unit:'files'`.
1217
+ Upstream model files are discovered during loading, so their total remains
1218
+ `null` while completed files are counted. Remaining TTS pool initialization
1219
+ reports completed model sessions. Consumers use an indeterminate progress bar
1220
+ when no final total is known; transfer quantities do not determine this display.
1221
+
1222
+ The Worker sends intermediate `{protocol,id,type:'progress',progress}` messages
1223
+ for its active load request. They do not settle the request; the ordinary final
1224
+ response still owns completion or failure. Complete upstream callback content
1225
+ remains in the adjacent `detail` field for diagnostics. Compatible observers
1226
+ receive the latest progress when joining an active load, and cancelled,
1227
+ superseded, or settled loads stop publishing progress.
1211
1228
 
1212
1229
  Compatible concurrent loads share one underlying preparation and pool load
1213
1230
  while each caller retains its own cancellation signal. One observer cannot
@@ -187,34 +187,42 @@ Applications remain responsible for model selection and license compliance.
187
187
  cannot download. Source downloads use CORS, omit credentials and referrer,
188
188
  disable HTTP caching, and honor `AbortSignal`.
189
189
 
190
- On Windows desktop Chromium browsers, observing a WebGPU adapter may open one
191
- flags page and show one advisory per page session. The notice names only
192
- **Force High Performance GPU** (`#force-high-performance-gpu`), conditional on
193
- the computer having multiple GPUs, and asks the user to completely close and
194
- reopen their browser after enabling it. It applies to any observed GPU vendor;
195
- an Intel identity alone does not establish that an adapter is integrated or
196
- slower, and the browser does not expose a reliable machine-wide GPU count.
197
-
198
- An identified Microsoft Edge, Brave, Opera, or Vivaldi receives its own
199
- `edge://`, `brave://`, `opera://`, or `vivaldi://` flags address. Chrome,
200
- Chromium, and browsers that conceal their brand receive
201
- `about://flags/#force-high-performance-gpu`, which the browser rewrites to its
202
- own flags page, with neutral browser wording. Only the current browser's one
203
- address appears. Firefox, Safari, non-Windows platforms, and mobile browsers
204
- receive no flag notice. The notice does not suggest unrelated WebGPU, ANGLE,
205
- Vulkan, rasterization, or blocklist flags.
206
-
207
- The Windows selection workaround is documented by
208
- [Chrome](https://developer.chrome.com/docs/web-platform/webgpu/troubleshooting-tips#Windows-specific_limitations).
209
- Other Chromium browsers inherit that flag; the per-vendor addresses and generic
210
- `about://` rewrite follow the
211
- [Chromium browser-flags guide](https://developer.chrome.com/blog/browser-flags/).
212
- [Vivaldi masks its browser identity by default](https://help.vivaldi.com/developers/web/vivaldi-user-agent-and-client-hints-user-agent/),
213
- so a Chrome user-agent token is not proof that the current browser is Chrome.
214
- This source-based guidance is not a live GPU-selection test of every browser
215
- release. The advisory does not change settings, prove another or faster adapter
216
- exists, inspect the flag's current value, or make a failed load succeed. If the
217
- browser blocks opening an internal page, the alert retains the copyable address.
190
+ After a model loads, its existing Worker reports the adapter it selected.
191
+ The runtime retains that adapter in `evidence().webgpu.adapter`, including
192
+ optional browser-reported `type` and `isFallbackAdapter` fields. This reads
193
+ the loaded Worker's metadata once; it does not request another adapter.
194
+ Missing fields remain unknown. Cancellation also cancels the metadata wait;
195
+ an unavailable observation is logged without rejecting an otherwise loaded model.
196
+
197
+ On Windows desktop Chromium browsers, an explicitly reported integrated GPU,
198
+ CPU, or fallback adapter triggers one GPU-only browser alert per page session.
199
+ The alert names the selected adapter and **Force High Performance GPU**
200
+ (`#force-high-performance-gpu`), conditional on the computer also having a
201
+ discrete GPU. It contains the address to paste manually and asks the user to
202
+ save their work and completely close and reopen the browser after changing
203
+ the flag. It does not open a window or navigate to an internal browser page.
204
+ Discrete adapters and unknown adapter classes do not trigger the alert.
205
+
206
+ An identified Chrome, Microsoft Edge, Brave, Opera, or Vivaldi receives its own
207
+ `chrome://`, `edge://`, `brave://`, `opera://`, or `vivaldi://` flags address.
208
+ Other detected Chromium browsers receive
209
+ `about://flags/#force-high-performance-gpu` with neutral browser wording.
210
+ Only the current browser's address appears. Firefox, Safari, non-Windows
211
+ platforms, and mobile browsers receive no flag notice. The alert contains no
212
+ NPU guidance or unrelated flags. The Profile `browser-ai-setup` component
213
+ provides Copy controls for its browser addresses.
214
+
215
+ An adapter vendor or name does not establish its GPU class, and
216
+ `powerPreference: "high-performance"` is a request hint rather than proof of
217
+ the selected hardware. Chromium's optional adapter `type` is a
218
+ [developer feature](https://developer.chrome.com/docs/web-platform/webgpu/developer-features);
219
+ the standard API does not always expose integrated or discrete classification.
220
+ The Profile says **Already using the performance GPU.** for an explicitly
221
+ reported discrete GPU and hides performance flag advice. Missing classification
222
+ shows **GPU available.** without flag advice and remains unconfirmed.
223
+ The browser does not expose the flag's current value or a reliable machine-wide
224
+ GPU count, and a discrete adapter does not prove it is the fastest available.
225
+ See [Chrome's GPU selection guidance](https://developer.chrome.com/docs/web-platform/webgpu/troubleshooting-tips#webgpu_is_slower_than_webgl).
218
226
 
219
227
  ## Streaming, cancellation, and tools
220
228
 
@@ -5,7 +5,7 @@
5
5
  "repository": "https://github.com/TheWizardNexus/arcane-os-sdk.git",
6
6
  "branch": "main",
7
7
  "path": "runtime/arcane/components",
8
- "sdkVersion": "0.6.2"
8
+ "sdkVersion": "0.7.1"
9
9
  },
10
10
  "componentCount": 40,
11
11
  "loader": "/arcane/modules/HTMLImport.js",
@@ -79,7 +79,7 @@
79
79
  {
80
80
  "file": "runtime/arcane/components/browser-ai-setup.html",
81
81
  "name": "browser-ai-setup.html",
82
- "purpose": "Displays browser API and WebGPU adapter availability with browser-specific NPU and GPU flags links.",
82
+ "purpose": "Displays browser API availability, browser-reported GPU class, and copyable NPU/GPU flags addresses.",
83
83
  "methods": [
84
84
  "refresh()",
85
85
  "checkGpu()",
@@ -97,8 +97,8 @@
97
97
  "arcane-os/event-manager"
98
98
  ],
99
99
  "availability": "Browser and supported native WebViews",
100
- "transport": "HTMLImport + DOM; browser flags links, Clipboard API, WebGPU adapter request, and preserved open() navigation attempt with alert",
101
- "normalization": "API presence, adapter availability, and setup instructions normalized. Mounting starts one adapter request; checkGpu() coalesces concurrent calls, while refresh() remains synchronous. No GPU device, model, or WebNN context is created. Adapter availability does not establish browser flag state, high-performance selection, or model execution."
100
+ "transport": "HTMLImport + DOM; Clipboard API and WebGPU adapter request. Settings addresses use Copy controls and appear as text if copying fails; open() copies the NPU address without navigation or an alert.",
101
+ "normalization": "API presence, adapter availability, explicit browser GPU class, and copy instructions normalized. A reported discrete GPU shows Already using the performance GPU. Only explicitly reported integrated/software adapters show flag instructions. Absent type metadata shows GPU available and leaves performance selection unconfirmed. Mounting starts one adapter request; checkGpu() coalesces concurrent calls, while refresh() remains synchronous. No GPU device, model, or WebNN context is created. Adapter metadata does not establish browser flag state, the fastest physical GPU, or another page's model execution."
102
102
  },
103
103
  {
104
104
  "file": "runtime/arcane/components/calculator.html",
@@ -380,8 +380,13 @@ the module declares a shadowing binding with the same name. Explicit
380
380
  `globalThis` or `self` calls continue through the materialized-file router.
381
381
 
382
382
  The speech Worker uses its ordinary global Worker message boundary directly for
383
- requests, results, errors, and cancellation. It creates no private
384
- `MessageChannel` and publishes no Worker progress transport.
383
+ requests, progress, results, errors, and cancellation. It creates no private
384
+ `MessageChannel`. During loading, `{protocol,id,type:'progress',progress}`
385
+ messages retain the active request id without settling its pending result.
386
+ Progress records describe the current phase, stage, message, file, and completed
387
+ file count with `total:null` for dynamically discovered model files. Complete
388
+ upstream callback content remains in the adjacent `detail` field. The ordinary
389
+ final success or failure envelope ends the request and its progress stream.
385
390
 
386
391
  Worker operations use `arcane-ai-speech-worker/1`. The public Worker client
387
392
  supports `load`, `use`, `status`, `unload`, and `dispose`; the transport host
@@ -459,9 +464,11 @@ while the loaded provider remains ready.
459
464
  Speech failure neither disables text chat nor retries through another local,
460
465
  native, or cloud provider. The provider/Worker layer is event-neutral: it
461
466
  exposes promises, `AbortSignal`, and precise lifecycle/status records, but owns
462
- no event bus or listener registry. The provider/2 load context accepts an
463
- optional progress callback for interface compatibility; the current
464
- browser-speech artifact and Worker transport publishes no progress records.
467
+ no event bus. The provider/2 load context accepts an optional `progress`
468
+ callback that receives artifact preparation, upstream model loading, and session
469
+ initialization records. Compatible concurrent observers share one load and
470
+ receive its current progress; cancelling one observer leaves the others active.
471
+ The shared AI runtime projects those records into sticky role state.
465
472
 
466
473
  ### Persistent chat and document context
467
474
 
@@ -60,7 +60,7 @@ appropriate.
60
60
  | --- | --- | --- | --- | --- |
61
61
  | [`app-bar.html`](#app-barhtml) | Responsive application navigation, route state, status, and trailing actions. | `setNavigation()`<br>`setActiveRoute()`<br>`setStatus()`<br>`refresh()`<br>`destroy()` | `app-bar-ready` | DOM-normalized |
62
62
  | [`assistant-panel.html`](#assistant-panelhtml) | Reusable assistant drawer, message area, composer, pending/streaming/empty/error state, and actions. | `open()`<br>`close()`<br>`toggle()`<br>`send()`<br>`clear()`<br>`setState()`<br>`focusComposer()`<br>`scrollToEnd()`<br>`destroy()` | `assistant-ready`<br>`assistant-opened`<br>`assistant-closed`<br>`assistant-send`<br>`assistant-clear` | DOM-normalized; caller/provider results remain external |
63
- | [`browser-ai-setup.html`](#browser-ai-setuphtml) | Browser API and WebGPU adapter availability, with browser-specific NPU and GPU flags links. | `refresh()`<br>`checkGpu()`<br>`open()`<br>`destroy()`<br>`ready` | `browser-ai-setup-ready` | API and adapter availability; browser flag state and model execution remain browser-owned |
63
+ | [`browser-ai-setup.html`](#browser-ai-setuphtml) | Browser API availability, reported GPU class, and copyable NPU/GPU settings addresses. | `refresh()`<br>`checkGpu()`<br>`open()`<br>`destroy()`<br>`ready` | `browser-ai-setup-ready` | Browser-reported adapter class; browser flag state and model execution remain browser-owned |
64
64
  | [`calculator.html`](#calculatorhtml) | Calculator keypad and result/error event surface backed by CalculatorEngine. | `calculate()`<br>`destroy()` | `calculator-ready`<br>`calculation-complete`<br>`calculation-error` | Normalized Calculation/error events |
65
65
  | [`chart.html`](#charthtml) | Accessible uPlot line, area, or point chart with normalized options and rows. | `configure()`<br>`populate()`<br>`setData()`<br>`addData()`<br>`update()`<br>`destroy()` | `chart-ready`<br>`chart-remove` | Options/rows normalized; uPlot rendering is vendor-native |
66
66
  | [`chat.html`](#chathtml) | Shared chat, visible selected-model activation request, file upload, streaming, structural tool settlement, speech, language, availability, and conversation-timebox surface. | `streamMessage()`<br>`setMessageProgress()`<br>`setAIAvailability()`<br>`setInitialSpeechMuted()`<br>`setConversationComplete()`<br>`bindConversationTimebox()`<br>`bindSession()`<br>`submitMessage()`<br>`submitToolResult()`<br>`submitToolResults()`<br>`sendMessage()`<br>`languageChanged()`<br>`requestAIActivation()`<br>`destroy()` | `chat-ready`<br>`chat-session-bound`<br>`chat-session-message`<br>`chat-session-error`<br>`chat-send-message`<br>`chat-send-error`<br>`chat-file-uploaded`<br>`chat-file-upload-error`<br>`chat-language-changed`<br>`chat-language-change-error`<br>`chat-ai-activation-request`<br>`chat-ai-activation-error`<br>`chat-speech-synthesis-error`<br>`conversation-timebox-error` | UI/runtime state, explicit user activation intent, and honest structural-call settlement normalized; AI/storage/media behavior mixed |
@@ -158,14 +158,14 @@ Slots: `title`, `subtitle`, `identity`, `messages/message`, `composer`, `actions
158
158
 
159
159
  ### Overview
160
160
 
161
- Displays WebNN and WebGPU API availability for the current page, detects an
162
- available WebGPU adapter, and provides browser-specific NPU and GPU flags links.
163
- The WebNN addresses are real links: Chrome and Edge receive their own addresses;
164
- other or unidentified browsers show both explicit choices. Desktop Windows
165
- Chromium browsers also receive the matching Force High Performance GPU link,
161
+ Displays a short WebNN availability status and the detected WebGPU adapter.
162
+ When WebNN is unavailable, Chrome and Edge receive a **Copy NPU flag address**
163
+ button for their own browser; unidentified browsers show both choices. Desktop Windows
164
+ Chromium browsers receive the matching Force High Performance GPU address only
165
+ when an integrated or software adapter is explicitly reported,
166
166
  including `chrome://flags/#force-high-performance-gpu` for identified Chrome.
167
- Copy controls and complete addresses remain available when the browser blocks
168
- navigation to an internal page.
167
+ Settings addresses use Copy controls and appear as selectable text if copying
168
+ fails. The component does not attempt navigation to internal browser pages.
169
169
 
170
170
  ### Public surface
171
171
 
@@ -184,26 +184,32 @@ calls share the pending promise. The component requests an adapter with the
184
184
  `"high-performance"` power-preference hint; it does not create a GPU device or
185
185
  load a model. An unavailable result contains `available: false` and a `reason`
186
186
  of `"api-unavailable"` or `"adapter-unavailable"`. An available result contains
187
- `available: true`, the reported adapter `name`, and `isFallbackAdapter` as a
188
- boolean or `null` when the browser exposes no classification. Adapter selection
189
- does not prove that a browser flag is enabled, that the fastest GPU was selected,
190
- or that a model is using it. Failure is displayed and logged, and the promise
187
+ `available: true`, the reported adapter `name`, `isFallbackAdapter` as a boolean
188
+ or `null`, `adapterType` as the browser's string or `null`, and
189
+ `performanceStatus`: `"discrete"`, `"integrated"`, `"fallback"`, or `"unknown"`.
190
+ Only the explicit browser type or fallback field establishes that status;
191
+ vendor names and the requested power preference do not. A discrete result
192
+ shows **Already using the performance GPU.** and hides flag instructions.
193
+ An unknown class shows **GPU available.** without recommending flag changes;
194
+ performance selection remains unconfirmed in the result. Adapter selection does not
195
+ prove that a browser flag is enabled, that the fastest GPU was selected, or that
196
+ a model is using it. Failure is displayed and logged, and the promise
191
197
  resolves to `false`; destruction also yields `false` and suppresses late UI
192
198
  updates.
193
199
 
194
- Mounting starts one `checkGpu()` operation. **Detect GPU** repeats it explicitly;
195
- **Refresh browser availability** calls both `refresh()` and `checkGpu()`. Calling
200
+ Mounting starts one `checkGpu()` operation. **Refresh** calls both `refresh()`
201
+ and `checkGpu()`. Calling
196
202
  `refresh()` directly remains synchronous and does not request an adapter.
197
203
  `ready` and `browser-ai-setup-ready` describe component setup, which can complete
198
204
  while adapter detection is still pending.
199
205
 
200
- `open()` refreshes the display, attempts to open the detected Chrome or Edge flags
201
- page, and presents an alert containing the full address and enable/relaunch
202
- instructions. Pass `"chrome"` or `"edge"` to choose explicitly. Invoke it from a
203
- user action. It returns `false` when destroyed or when no supported target is
204
- selected, and otherwise returns `undefined`; it never reports that navigation
205
- succeeded. Browsers may block internal-page navigation, so the full addresses
206
- also remain visible and copyable in the component.
206
+ The retained `open(browserId?)` method now copies the matching NPU flags address
207
+ instead of navigating or showing an alert. Pass `"chrome"` or `"edge"` to choose
208
+ explicitly and invoke it from a user action. It returns a promise resolving to
209
+ `true` only after clipboard success, or `false` for destruction, an unsupported
210
+ target, or copy failure. The complete address remains selectable if clipboard
211
+ access fails. On-screen instructions explain pasting it into the address bar,
212
+ enabling WebNN, and relaunching.
207
213
 
208
214
  `destroy()` aborts owned listeners, disposes the event source, marks `ready`
209
215
  false, and suppresses UI updates from pending clipboard and adapter operations.
@@ -1497,7 +1503,11 @@ For a selected `unloaded`, `loading`, `unloading`, or `error` role, the componen
1497
1503
  keeps recording Start disabled and presents the same keyboard-operable Start
1498
1504
  transcription/Try again or Cancel loading control as `speech.html`. Both use the
1499
1505
  shared `createSTTActivationController()` contract. User operation emits the
1500
- cancelable `speech-stt-activation-request` event with mutable complete `{intent,state}`;
1506
+ cancelable `speech-stt-activation-request` event with mutable complete `{intent,state}`.
1507
+ During loading, both controls show a native progress bar and the current
1508
+ preparation, download, or initialization message with the current file and
1509
+ reported elapsed time. Unknown totals remain indeterminate. In `speech.html`,
1510
+ prior local status stays visible alongside the loading status. The activation event's
1501
1511
  `preventDefault()` suppresses the callback. The default
1502
1512
  `requestSTTActivation(intent)` publishes the mutable
1503
1513
  `{role:'stt',action:'load'|'unload',reason:'user'}` intent. Callback failure emits
@@ -1417,7 +1417,7 @@ behavior for chart, dashboard, Markdown, and voice components.
1417
1417
  ### Public surface
1418
1418
 
1419
1419
  Constant sets plus normalization, formatting, and explicit STT activation
1420
- helpers. `createSTTActivationController({host,button,onChange,EventClass=CustomEvent})`
1420
+ helpers. `createSTTActivationController({host,button,progress=null,onChange,EventClass=CustomEvent})`
1421
1421
  consumes only normalized
1422
1422
  [`AIRuntimeState`](#airuntimestatejs) `stt` role records. Its mutable controller
1423
1423
  exposes `action`, `error`, `label`, `pending`, `selected`, `status`, `title`, and
@@ -1428,6 +1428,12 @@ exposes `action`, `error`, `label`, `pending`, `selected`, `status`, `title`, an
1428
1428
  callers use the default `CustomEvent`; non-DOM callers must inject a compatible
1429
1429
  `EventClass` constructor.
1430
1430
 
1431
+ An optional native `progress` element presents the active loading phase. Known
1432
+ file or session totals produce determinate progress; an unknown total remains
1433
+ indeterminate. The shared status includes the complete loading message, current
1434
+ file, completion count, and reported elapsed time. Terminal state and destruction
1435
+ clear the loading display without starting any provider work.
1436
+
1431
1437
  `request('load'|'unload')` emits the cancelable
1432
1438
  `speech-stt-activation-request` event with mutable `{intent,state}` before it
1433
1439
  invokes `host.requestSTTActivation(intent)`. Callback failure emits
@@ -6395,9 +6395,11 @@ and materializes object URLs, then returns
6395
6395
  `{cache,runtime,model,release}`. Call `release()` when the Worker no longer
6396
6396
  needs those URLs. `offline:true` never fetches and rejects a miss with
6397
6397
  `ARCANE_AI_ARTIFACT_OFFLINE_MISS`. `remove(authority)` deletes that exact
6398
- authority's files and selection metadata. `onProgress` remains an optional
6399
- provider-interface callback, but the current store publishes no progress
6400
- records.
6398
+ authority's files and selection metadata. Optional `onProgress` receives
6399
+ preparation and download records with `phase`, `stage`, `message`, and the
6400
+ current `file` when available. File operations report actual `completed` and
6401
+ `total` inventory counts with `unit:'files'`; module preparation uses
6402
+ `total:null`. Cancellation stops progress along with the owning operation.
6401
6403
 
6402
6404
  ### Availability and normalization
6403
6405
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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",