arcane-os 0.2.2 → 0.2.3
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.
- package/CHANGELOG.md +12 -0
- package/README.md +8 -8
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +1 -1
- package/docs/architecture.md +2 -2
- package/docs/reference/README.md +24 -24
- package/docs/reference/ai/browser-speech.md +1 -1
- package/docs/reference/ai/browser-wasm.md +1 -1
- package/docs/reference/availability-and-normalization.md +6 -3
- package/docs/reference/behavioral-testing.md +1 -1
- package/docs/reference/cli.md +3 -3
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/inventory/package-api.json +1 -1
- package/docs/reference/inventory/runtime-components.json +25 -10
- package/docs/reference/inventory/runtime-modules.json +8 -7
- package/docs/reference/protocols.md +27 -23
- package/docs/reference/runtime-components.md +70 -7
- package/docs/reference/runtime-modules.md +33 -11
- package/docs/reference/sdk-api.md +8 -8
- package/package.json +1 -1
- package/runtime/ARCANE_RUNTIME_RELEASE.json +9 -9
- package/runtime/arcane/components/speech.html +9 -253
- package/runtime/arcane/components/voice-transcription.html +437 -68
- package/runtime/arcane/modules/ComponentContracts.js +272 -0
- package/schemas/arcane-lock.schema.json +2 -2
|
@@ -61,7 +61,7 @@ A component file does not register its own custom element. The `<html-import>` h
|
|
|
61
61
|
| [`theme-editor.html`](#theme-editorhtml) | Edits, previews, saves, and resets semantic custom theme tokens. | `configure()`<br>`getTheme()`<br>`setTheme()`<br>`setBusy()`<br>`setStatus()` | `theme-editor-ready`<br>`theme-preview`<br>`theme-save`<br>`theme-reset` | Fully normalized Theme values |
|
|
62
62
|
| [`theme-switcher.html`](#theme-switcherhtml) | Selects and refreshes system, light, dark, or custom theme mode. | `setMode()`<br>`refresh()` | No component-specific event | Preference/native appearance behavior mixed; no component-ready contract |
|
|
63
63
|
| [`unified-inbox.html`](#unified-inboxhtml) | Displays provider-neutral communication threads with active/loading state. | `configure()`<br>`setThreads()`<br>`setActive()`<br>`setLoading()` | `unified-inbox-ready`<br>`inbox-refresh`<br>`thread-select` | DOM-normalized |
|
|
64
|
-
| [`voice-transcription.html`](#voice-transcriptionhtml) | Records segmented microphone audio, transcribes, persists, and completes a combined transcript. | `configure()`<br>`startRecording()`<br>`stopRecording()`<br>`save()`<br>`completeTranscription()/complete()`<br>`clear()`<br>`reset()`<br>`destroy()` | `voice-transcription-ready`<br>`voice-transcription-state`<br>`voice-transcription-segment`<br>`voice-transcription-change`<br>`voice-transcription-complete`<br>`speech-transcription-complete` |
|
|
64
|
+
| [`voice-transcription.html`](#voice-transcriptionhtml) | Records segmented microphone audio only after authoritative STT admission, exposes explicit selected-STT activation, transcribes with cancellation, persists, and completes a combined transcript. | `configure()`<br>`requestSTTActivation()`<br>`startRecording()`<br>`stopRecording()`<br>`save()`<br>`completeTranscription()/complete()`<br>`clear()`<br>`reset()`<br>`destroy()` | `voice-transcription-ready`<br>`voice-transcription-state`<br>`voice-transcription-segment`<br>`voice-transcription-change`<br>`voice-transcription-complete`<br>`speech-transcription-complete`<br>`speech-transcription-cancelled`<br>`speech-stt-activation-request`<br>`speech-stt-activation-error` | Sticky runtime STT readiness, explicit activation, request cancellation, and state/text are normalized; media/provider behavior remains external |
|
|
65
65
|
| [`weather-widget.html`](#weather-widgethtml) | Displays normalized current and daily weather with refresh intent. | `setWeather()`<br>`clear()` | `weather-widget-ready`<br>`weather-refresh` | Display normalized; provider supplied externally |
|
|
66
66
|
| [`web-navigator.html`](#web-navigatorhtml) | Guards embedded/external navigation and surfaces allow/block/open intents. | `configure()`<br>`navigate()`<br>`currentUrl()` | `web-navigator-ready`<br>`web-navigate`<br>`web-navigation-blocked`<br>`web-open-external` | Navigation intent/decision normalized; browser navigation result platform-native |
|
|
67
67
|
|
|
@@ -866,7 +866,8 @@ Events: `speech-ready`, `speech-transcription-complete`,
|
|
|
866
866
|
`speech-stt-activation-error`, and `speech-tts-lifecycle-error`.
|
|
867
867
|
|
|
868
868
|
Shared dependencies: [`AI.js`](runtime-modules.md#aijs),
|
|
869
|
-
[`AIRuntimeState.js`](runtime-modules.md#airuntimestatejs),
|
|
869
|
+
[`AIRuntimeState.js`](runtime-modules.md#airuntimestatejs),
|
|
870
|
+
[`ComponentContracts.js`](runtime-modules.md#componentcontractsjs), and
|
|
870
871
|
[`DBLS.js`](runtime-modules.md#dblsjs).
|
|
871
872
|
|
|
872
873
|
The Hold to talk control remains disabled unless sticky STT state is `ready`,
|
|
@@ -1113,19 +1114,81 @@ Events: `unified-inbox-ready`, `inbox-refresh`, `thread-select`.
|
|
|
1113
1114
|
|
|
1114
1115
|
### Overview
|
|
1115
1116
|
|
|
1116
|
-
Records segmented microphone audio
|
|
1117
|
+
Records segmented microphone audio only after authoritative STT admission,
|
|
1118
|
+
exposes explicit selected-STT activation, transcribes with cancellation,
|
|
1119
|
+
persists, and completes a combined transcript.
|
|
1117
1120
|
|
|
1118
1121
|
### Public surface
|
|
1119
1122
|
|
|
1120
|
-
Methods/properties: `configure()`, `
|
|
1123
|
+
Methods/properties: `configure()`, `requestSTTActivation()`, `startRecording()`,
|
|
1124
|
+
`stopRecording()`, `save()`, `completeTranscription()/complete()`, `clear()`,
|
|
1125
|
+
`reset()`, `destroy()`.
|
|
1121
1126
|
|
|
1122
|
-
Events: `voice-transcription-ready`, `voice-transcription-state`,
|
|
1127
|
+
Events: `voice-transcription-ready`, `voice-transcription-state`,
|
|
1128
|
+
`voice-transcription-segment`, `voice-transcription-change`,
|
|
1129
|
+
`voice-transcription-complete`, `speech-transcription-complete`,
|
|
1130
|
+
`speech-transcription-cancelled`, `speech-stt-activation-request`, and
|
|
1131
|
+
`speech-stt-activation-error`.
|
|
1123
1132
|
|
|
1124
|
-
Shared dependencies: [`MD.js`](runtime-modules.md#mdjs),
|
|
1133
|
+
Shared dependencies: [`MD.js`](runtime-modules.md#mdjs),
|
|
1134
|
+
[`ComponentContracts.js`](runtime-modules.md#componentcontractsjs),
|
|
1135
|
+
[`AIRuntimeState.js`](runtime-modules.md#airuntimestatejs), and
|
|
1136
|
+
[`AI.js`](runtime-modules.md#aijs).
|
|
1125
1137
|
|
|
1126
1138
|
### Availability and normalization
|
|
1127
1139
|
|
|
1128
|
-
**Browser and supported native WebViews.**
|
|
1140
|
+
**Browser and supported native WebViews.** The component subscribes
|
|
1141
|
+
synchronously to sticky `AIRuntimeState.roles.stt`; its recording Start button
|
|
1142
|
+
and public `startRecording()` both fail closed unless that role is exactly
|
|
1143
|
+
`ready` and not busy. A configured `transcribe(file,context)` callback remains
|
|
1144
|
+
request plumbing rather than readiness authority. Its context now includes the
|
|
1145
|
+
owned `signal` additively. The default route calls
|
|
1146
|
+
`AI.fetchSTT(file,undefined,signal)` so the callback position remains valid and
|
|
1147
|
+
readiness loss or destruction can abort delivery.
|
|
1148
|
+
|
|
1149
|
+
For a selected `unloaded`, `loading`, `unloading`, or `error` role, the component
|
|
1150
|
+
keeps recording Start disabled and presents the same keyboard-operable Start
|
|
1151
|
+
transcription/Try again or Cancel loading control as `speech.html`. Both use the
|
|
1152
|
+
shared `createSTTActivationController()` contract. User operation emits the
|
|
1153
|
+
cancelable `speech-stt-activation-request` event with frozen `{intent,state}`;
|
|
1154
|
+
`preventDefault()` suppresses the callback. The default
|
|
1155
|
+
`requestSTTActivation(intent)` publishes the frozen
|
|
1156
|
+
`{role:'stt',action:'load'|'unload',reason:'user'}` intent. Callback failure emits
|
|
1157
|
+
`speech-stt-activation-error` with frozen `{request,error,message}`. Import and
|
|
1158
|
+
state observation emit no activation request and never begin a model download.
|
|
1159
|
+
|
|
1160
|
+
If sticky readiness is lost during microphone acquisition, capture, or the STT
|
|
1161
|
+
request, the component invalidates the session, aborts the owned request signal,
|
|
1162
|
+
releases media, discards late completion, and emits
|
|
1163
|
+
`speech-transcription-cancelled` with frozen `{reason:'runtime-unready'}`. A
|
|
1164
|
+
current provider cancellation returns the component workflow to `idle` and
|
|
1165
|
+
emits the same event with `reason:'stt-provider-request-cancelled'`; destroying
|
|
1166
|
+
an active capture or transcription emits `reason:'component-destroyed'`.
|
|
1167
|
+
Stale teardown results remain suppressed. A
|
|
1168
|
+
current save failure, including `AbortError`, enters the visible `error` state.
|
|
1169
|
+
Readiness loss after transcription has finished does not invalidate an already
|
|
1170
|
+
pending application save or completion callback: its settlement remains
|
|
1171
|
+
observable, while any new recording remains gated by current sticky readiness.
|
|
1172
|
+
Assigning `value` or calling `configure({initialValue})` explicitly supersedes
|
|
1173
|
+
an in-flight microphone start, STT request, save, or completion. The component
|
|
1174
|
+
advances its generation, aborts owned STT delivery, releases owned media, emits
|
|
1175
|
+
`speech-transcription-cancelled` with
|
|
1176
|
+
`reason:'transcript-replaced'`, and suppresses
|
|
1177
|
+
late settlement before publishing the assigned transcript. Assigning transcript
|
|
1178
|
+
text during active recording preserves that recording and changes the transcript
|
|
1179
|
+
to which the captured segment will be appended.
|
|
1180
|
+
`destroy()` aborts the state subscription, cancels active work, removes the
|
|
1181
|
+
activation listener, sets component `ready` to `false`, and returns `true`;
|
|
1182
|
+
repeated destruction is
|
|
1183
|
+
idempotent. Destruction is terminal: Start, activation, and Complete remain
|
|
1184
|
+
disabled and status remains unavailable. `voice-transcription-state` detail is
|
|
1185
|
+
the frozen `{message,state,stt}` record, where `state` remains the component
|
|
1186
|
+
workflow and `stt` is the authoritative immutable role record. Transcript
|
|
1187
|
+
completion stays available when STT is unavailable before destruction.
|
|
1188
|
+
State/text, explicit activation, and request cancellation are normalized;
|
|
1189
|
+
provider/model authority and media behavior remain external. HTMLImport + DOM;
|
|
1190
|
+
injected Arcane/provider modules where listed.
|
|
1191
|
+
Native methods remain subject to the bound app's capabilities. [Deep protocol details](protocols.md).
|
|
1129
1192
|
|
|
1130
1193
|
### Example
|
|
1131
1194
|
|
|
@@ -41,7 +41,7 @@ Apps import renderer ESM from `/arcane/modules/<file>`. Classic scripts, the OPF
|
|
|
41
41
|
| [`CommunicationHub.js`](#communicationhubjs) | esm | Fans out provider refresh/send operations and aggregates normalized threads/messages. | Cross-host with injected providers | Normalized aggregates; refresh contains per-provider failures. |
|
|
42
42
|
| [`CommunicationPreferences.js`](#communicationpreferencesjs) | esm | Stores app-scoped, non-secret communication provider preferences. | Browser / native WebView hybrid | Normalized preference record; storage failures mixed. |
|
|
43
43
|
| [`CommunicationProviderRegistry.js`](#communicationproviderregistryjs) | esm | Registers and queries validated provider definitions, channels, and required methods. | Cross-host | Strict normalized registry. |
|
|
44
|
-
| [`ComponentContracts.js`](#componentcontractsjs) | esm | Owns normalized configuration/value contracts shared
|
|
44
|
+
| [`ComponentContracts.js`](#componentcontractsjs) | esm | Owns normalized configuration/value contracts and shared explicit STT activation behavior for chart, dashboard, Markdown, and voice components. | Cross-host | Fully normalized labels, rows, definitions, visibility, formats, editor and voice options, plus capability-neutral STT activation intent and presentation state. |
|
|
45
45
|
| [`ConfiguredAIChatSession.js`](#configuredaichatsessionjs) | esm | Owns bounded in-memory AI turns, context construction, response-length instruction, and atomic history commit. | Native bridge by default; cross-host with injected chat | Normalized session/result; provider rejection preserved. |
|
|
46
46
|
| [`ConversationActionItems.js`](#conversationactionitemsjs) | esm | Normalizes, creates, updates, remembers, selects, and formats bounded conversation action items. | Cross-host | Fully normalized status/base/presentation contract. |
|
|
47
47
|
| [`ConversationClosingReport.js`](#conversationclosingreportjs) | esm | Defines the closing-report tool, instruction, result normalizer, call classifier, and formatter. | Cross-host | Fully normalized report contract. |
|
|
@@ -259,11 +259,10 @@ request ownership is active.
|
|
|
259
259
|
|
|
260
260
|
### Availability and normalization
|
|
261
261
|
|
|
262
|
-
**Cross-host runtime with provider-specific execution.** Published SDK `0.2.
|
|
263
|
-
ships the browser-WASM LLM and browser Whisper/Kokoro adapters
|
|
264
|
-
legacy speech adapters
|
|
265
|
-
|
|
266
|
-
adapters may be supplied externally only when they implement the same
|
|
262
|
+
**Cross-host runtime with provider-specific execution.** Published SDK `0.2.2`
|
|
263
|
+
ships the browser-WASM LLM and browser Whisper/Kokoro adapters and supplies the
|
|
264
|
+
narrow AI.js legacy OpenAI/Ollama/Core-speech adapters; other native, Core, or
|
|
265
|
+
cloud adapters may be supplied externally only when they implement the same
|
|
267
266
|
`arcane-ai-provider/2` boundary. A
|
|
268
267
|
provider must prove a matching `arcane-ai-model-authority/1` inspection before load.
|
|
269
268
|
`localOnly` routing fails closed; it never selects a cloud or non-local route as
|
|
@@ -792,17 +791,40 @@ console.log(Object.keys(module));
|
|
|
792
791
|
|
|
793
792
|
### Overview
|
|
794
793
|
|
|
795
|
-
Owns normalized configuration/value contracts shared
|
|
794
|
+
Owns normalized configuration/value contracts and shared explicit STT activation
|
|
795
|
+
behavior for chart, dashboard, Markdown, and voice components.
|
|
796
796
|
|
|
797
797
|
### Public surface
|
|
798
798
|
|
|
799
|
-
|
|
799
|
+
Constant sets plus normalization, formatting, and explicit STT activation
|
|
800
|
+
helpers. `createSTTActivationController({host,button,onChange,EventClass=CustomEvent})`
|
|
801
|
+
consumes only normalized
|
|
802
|
+
[`AIRuntimeState`](#airuntimestatejs) `stt` role records. Its frozen controller
|
|
803
|
+
exposes `action`, `error`, `label`, `pending`, `selected`, `status`, `title`, and
|
|
804
|
+
`visible` getters plus `request(action)`, `synchronize(role)`, and `destroy()`.
|
|
805
|
+
`host` supplies `dispatchEvent(event)` and `requestSTTActivation(intent)`;
|
|
806
|
+
`button` supplies `addEventListener()` and `removeEventListener()`; and
|
|
807
|
+
`onChange()` is called whenever presentation should be rendered again. Browser
|
|
808
|
+
callers use the default `CustomEvent`; non-DOM callers must inject a compatible
|
|
809
|
+
`EventClass` constructor.
|
|
800
810
|
|
|
801
|
-
|
|
811
|
+
`request('load'|'unload')` emits the cancelable
|
|
812
|
+
`speech-stt-activation-request` event with frozen `{intent,state}` before it
|
|
813
|
+
invokes `host.requestSTTActivation(intent)`. Callback failure emits
|
|
814
|
+
`speech-stt-activation-error` with frozen `{request,error,message}`. Syncing
|
|
815
|
+
sticky state only changes the controller's observation and presentation; it
|
|
816
|
+
never emits a lifecycle intent, chooses a provider, or starts a download.
|
|
817
|
+
`destroy()` removes its button listener and suppresses late callback effects.
|
|
818
|
+
|
|
819
|
+
Exact exports: `CHART_LABELS`, `DASHBOARD_LABELS`, `MARKDOWN_FORMATS`, `MARKDOWN_LABELS`, `VOICE_LABELS`, `VOICE_MESSAGES`, `appendTranscription`, `applyMarkdownFormat`, `createSTTActivationController`, `effectiveDashboardVisibility`, `normalizeChartOptions`, `normalizeChartRows`, `normalizeDashboardDefinitions`, `normalizeDashboardOptions`, `normalizeDashboardVisibility`, `normalizeMarkdownFormats`, `normalizeMarkdownOptions`, `normalizeVoiceOptions`.
|
|
802
820
|
|
|
803
821
|
### Availability and normalization
|
|
804
822
|
|
|
805
|
-
**Cross-host
|
|
823
|
+
**Cross-host with an injected event constructor outside DOM hosts.** Fully
|
|
824
|
+
normalized labels, rows, definitions, visibility, formats, editor and voice
|
|
825
|
+
options, plus capability-neutral STT activation intent and presentation state.
|
|
826
|
+
Provider authority and lifecycle execution remain with the configured runtime
|
|
827
|
+
owner. Transport: In-process only. [Deep protocol details](protocols.md).
|
|
806
828
|
|
|
807
829
|
### Example
|
|
808
830
|
|
|
@@ -1083,7 +1105,7 @@ source body as implicit authority, and never persists a caller-owned body.
|
|
|
1083
1105
|
**Browser or compatible host with an injected DBOPFS adapter.** The adapter
|
|
1084
1106
|
keeps the existing `get`, `set`, `getAllKeys`, and `delete` method names; Node
|
|
1085
1107
|
can use the same class only through an explicitly imported runtime module and a
|
|
1086
|
-
compatible storage adapter; SDK `0.2.
|
|
1108
|
+
compatible storage adapter; SDK `0.2.2` publishes no Node package subpath or
|
|
1087
1109
|
Node storage implementation for it. Bootstrap uses a bounded concurrent
|
|
1088
1110
|
generation, commits its manifest last, cleans partial data on failure, and
|
|
1089
1111
|
rejects case-colliding IDs. Search
|
|
@@ -17,7 +17,7 @@ This table is the Node `package.json#exports` map: it defines package
|
|
|
17
17
|
entrypoints for SDK/tooling code. It is distinct from the generated browser
|
|
18
18
|
import map that resolves application-facing `arcane/*` modules and the focused
|
|
19
19
|
EventManager entry. See [browser runtime delivery](protocols.md#browser-runtime-delivery)
|
|
20
|
-
for that 91-entry physical-runtime contract in SDK `0.2.
|
|
20
|
+
for that 91-entry physical-runtime contract in SDK `0.2.2`.
|
|
21
21
|
|
|
22
22
|
| Specifier | Purpose |
|
|
23
23
|
| --- | --- |
|
|
@@ -47,7 +47,7 @@ Protocol mechanics are intentionally kept in the [deep protocol guide](protocols
|
|
|
47
47
|
|
|
48
48
|
## Canonical member inventory
|
|
49
49
|
|
|
50
|
-
SDK `0.2.
|
|
50
|
+
SDK `0.2.2` exports exactly 169 distinct JavaScript members across 13
|
|
51
51
|
JavaScript entrypoints. The complete export map has 23 subpaths: the other 10
|
|
52
52
|
are the runtime manifest, eight JSON Schemas, and package metadata. Runtime
|
|
53
53
|
projection modules in the managed browser map are cataloged separately in
|
|
@@ -814,7 +814,7 @@ same deterministic map. The package root also contains the public
|
|
|
814
814
|
{
|
|
815
815
|
schemaVersion: 1,
|
|
816
816
|
kind: 'arcane-app-runtime-projection',
|
|
817
|
-
sdkVersion: '0.2.
|
|
817
|
+
sdkVersion: '0.2.2',
|
|
818
818
|
pathPrefix: 'arcane/',
|
|
819
819
|
fileCount,
|
|
820
820
|
totalBytes,
|
|
@@ -2698,7 +2698,7 @@ The import-map operation also reports the stable operation-specific strings
|
|
|
2698
2698
|
`ARCANE_IMPORT_MAP_COLLISION`; package assembly can additionally report
|
|
2699
2699
|
`ARCANE_IMPORT_MAP_CLEANUP_FAILED`. They are normalized `ArcaneError.code`
|
|
2700
2700
|
values, but are not properties added to this frozen general registry in SDK
|
|
2701
|
-
`0.2.
|
|
2701
|
+
`0.2.2`.
|
|
2702
2702
|
|
|
2703
2703
|
### Value and import
|
|
2704
2704
|
|
|
@@ -3364,7 +3364,7 @@ workspace it additionally returns the exact installed package authority:
|
|
|
3364
3364
|
packageSource,
|
|
3365
3365
|
canonicalPackageRoot,
|
|
3366
3366
|
packageName: 'arcane-os',
|
|
3367
|
-
packageVersion: '0.2.
|
|
3367
|
+
packageVersion: '0.2.2',
|
|
3368
3368
|
runtimeRoot,
|
|
3369
3369
|
browserRuntimeRoot,
|
|
3370
3370
|
runtimeManifest,
|
|
@@ -3374,9 +3374,9 @@ workspace it additionally returns the exact installed package authority:
|
|
|
3374
3374
|
```
|
|
3375
3375
|
|
|
3376
3376
|
The dependency can be named `arcane-os` or be one exact npm alias for
|
|
3377
|
-
`npm:arcane-os@0.2.
|
|
3377
|
+
`npm:arcane-os@0.2.2`. The selected installation must still be one direct,
|
|
3378
3378
|
physical, non-link package directory whose manifest identifies exactly as
|
|
3379
|
-
`arcane-os@0.2.
|
|
3379
|
+
`arcane-os@0.2.2`; duplicate canonical/alias declarations fail closed.
|
|
3380
3380
|
`allowMissingManagedImportMap` is an internal packaging/development seam. An
|
|
3381
3381
|
ordinary caller should leave it `false`.
|
|
3382
3382
|
|
|
@@ -3553,7 +3553,7 @@ const toolchain = createToolchain({
|
|
|
3553
3553
|
|
|
3554
3554
|
// Only this explicit call refreshes the managed map and configured HTML entry.
|
|
3555
3555
|
const result = await toolchain.importMap();
|
|
3556
|
-
console.log(result.importMap.entryCount); // 91 in SDK 0.2.
|
|
3556
|
+
console.log(result.importMap.entryCount); // 91 in SDK 0.2.2
|
|
3557
3557
|
console.log(result.importMap.documentPaths, result.importMap.documentCount);
|
|
3558
3558
|
```
|
|
3559
3559
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"builder": "arcane-sdk-runtime-v1",
|
|
4
|
-
"sdkVersion": "0.2.
|
|
4
|
+
"sdkVersion": "0.2.3",
|
|
5
5
|
"source": {
|
|
6
6
|
"authority": "sdk-canonical",
|
|
7
7
|
"repository": "https://github.com/TheWizardNexus/arcane-os-sdk.git",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"fileCount": 160,
|
|
17
|
-
"totalBytes":
|
|
18
|
-
"contentSha256": "
|
|
17
|
+
"totalBytes": 3655536,
|
|
18
|
+
"contentSha256": "f96a27bd79a809201708f73ca729bc60ab02696daf619365f77267a28b47b4b3",
|
|
19
19
|
"files": [
|
|
20
20
|
{
|
|
21
21
|
"path": "arcane/components/app-bar.html",
|
|
@@ -159,8 +159,8 @@
|
|
|
159
159
|
},
|
|
160
160
|
{
|
|
161
161
|
"path": "arcane/components/speech.html",
|
|
162
|
-
"bytes":
|
|
163
|
-
"sha256": "
|
|
162
|
+
"bytes": 41300,
|
|
163
|
+
"sha256": "0ed5dd29c37747702f114114ad66bedd419fd39bed35fc12362c63c6357a41d9"
|
|
164
164
|
},
|
|
165
165
|
{
|
|
166
166
|
"path": "arcane/components/summary-strip.html",
|
|
@@ -199,8 +199,8 @@
|
|
|
199
199
|
},
|
|
200
200
|
{
|
|
201
201
|
"path": "arcane/components/voice-transcription.html",
|
|
202
|
-
"bytes":
|
|
203
|
-
"sha256": "
|
|
202
|
+
"bytes": 26991,
|
|
203
|
+
"sha256": "8140b918791df5043be9254d52bf7864fe91759ab6e5e60af2364d6b4a8fcb7b"
|
|
204
204
|
},
|
|
205
205
|
{
|
|
206
206
|
"path": "arcane/components/weather-widget.html",
|
|
@@ -494,8 +494,8 @@
|
|
|
494
494
|
},
|
|
495
495
|
{
|
|
496
496
|
"path": "arcane/modules/ComponentContracts.js",
|
|
497
|
-
"bytes":
|
|
498
|
-
"sha256": "
|
|
497
|
+
"bytes": 28736,
|
|
498
|
+
"sha256": "f5ba011094835b45258ee833a90bfa17980e860ef9ceac88aa56ecad3abe9d53"
|
|
499
499
|
},
|
|
500
500
|
{
|
|
501
501
|
"path": "arcane/modules/ConfiguredAIChatSession.js",
|
|
@@ -156,6 +156,9 @@
|
|
|
156
156
|
requestAIRuntimeIntent,
|
|
157
157
|
subscribeAIRuntimeState
|
|
158
158
|
} = await import('../modules/AIRuntimeState.js');
|
|
159
|
+
const {
|
|
160
|
+
createSTTActivationController
|
|
161
|
+
} = await import('../modules/ComponentContracts.js');
|
|
159
162
|
|
|
160
163
|
const host = this;
|
|
161
164
|
const shadowRoot = host.shadowRoot;
|
|
@@ -254,191 +257,6 @@
|
|
|
254
257
|
)
|
|
255
258
|
);
|
|
256
259
|
|
|
257
|
-
function createSTTActivationController({
|
|
258
|
-
host,
|
|
259
|
-
button,
|
|
260
|
-
onChange,
|
|
261
|
-
EventClass = CustomEvent
|
|
262
|
-
}) {
|
|
263
|
-
let role = null;
|
|
264
|
-
let requestPending = false;
|
|
265
|
-
let requestError = '';
|
|
266
|
-
let requestGeneration = 0;
|
|
267
|
-
let destroyed = false;
|
|
268
|
-
|
|
269
|
-
function visibleError(error, fallback) {
|
|
270
|
-
const message = typeof error?.message === 'string'
|
|
271
|
-
? error.message.trim()
|
|
272
|
-
: '';
|
|
273
|
-
return (message || fallback).slice(0, 240);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function cancellation(error) {
|
|
277
|
-
return error?.name === 'AbortError'
|
|
278
|
-
|| [
|
|
279
|
-
'ARCANE_AI_REQUEST_ABORTED',
|
|
280
|
-
'ARCANE_AI_OPERATION_SUPERSEDED'
|
|
281
|
-
]
|
|
282
|
-
.includes(error?.code);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function selected() {
|
|
286
|
-
return typeof role?.providerId === 'string'
|
|
287
|
-
&& role.providerId.length > 0
|
|
288
|
-
&& typeof role?.modelId === 'string'
|
|
289
|
-
&& role.modelId.length > 0;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function action() {
|
|
293
|
-
if (!selected()) {
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
if (role.state === 'loading') {
|
|
297
|
-
return 'unload';
|
|
298
|
-
}
|
|
299
|
-
if (!role.busy && ['unloaded', 'error'].includes(role.state)) {
|
|
300
|
-
return 'load';
|
|
301
|
-
}
|
|
302
|
-
return null;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
async function request(nextAction) {
|
|
306
|
-
if (destroyed || requestPending || action() !== nextAction) {
|
|
307
|
-
return false;
|
|
308
|
-
}
|
|
309
|
-
const generation = ++requestGeneration;
|
|
310
|
-
requestError = '';
|
|
311
|
-
const intent = Object.freeze(
|
|
312
|
-
{
|
|
313
|
-
role: 'stt',
|
|
314
|
-
action: nextAction,
|
|
315
|
-
reason: 'user'
|
|
316
|
-
}
|
|
317
|
-
);
|
|
318
|
-
const activationRequest = Object.freeze({intent, state: role});
|
|
319
|
-
const activationEvent = new EventClass(
|
|
320
|
-
'speech-stt-activation-request',
|
|
321
|
-
{
|
|
322
|
-
bubbles: true,
|
|
323
|
-
composed: true,
|
|
324
|
-
cancelable: true,
|
|
325
|
-
detail: activationRequest
|
|
326
|
-
}
|
|
327
|
-
);
|
|
328
|
-
requestPending = true;
|
|
329
|
-
const accepted = host.dispatchEvent(activationEvent);
|
|
330
|
-
if (!accepted
|
|
331
|
-
|| destroyed
|
|
332
|
-
|| generation !== requestGeneration
|
|
333
|
-
|| action() !== nextAction) {
|
|
334
|
-
if (!destroyed && generation === requestGeneration) {
|
|
335
|
-
requestPending = false;
|
|
336
|
-
onChange();
|
|
337
|
-
}
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
onChange();
|
|
341
|
-
try {
|
|
342
|
-
await host.requestSTTActivation(intent);
|
|
343
|
-
if (destroyed || generation !== requestGeneration) {
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
return true;
|
|
347
|
-
} catch (error) {
|
|
348
|
-
if (destroyed || generation !== requestGeneration) {
|
|
349
|
-
return false;
|
|
350
|
-
}
|
|
351
|
-
if (nextAction === 'load'
|
|
352
|
-
&& cancellation(error)
|
|
353
|
-
&& ['unloaded', 'unloading'].includes(role?.state)) {
|
|
354
|
-
return false;
|
|
355
|
-
}
|
|
356
|
-
const message = visibleError(
|
|
357
|
-
error,
|
|
358
|
-
`The transcription ${nextAction} request failed.`
|
|
359
|
-
);
|
|
360
|
-
requestError = message;
|
|
361
|
-
host.dispatchEvent(
|
|
362
|
-
new EventClass(
|
|
363
|
-
'speech-stt-activation-error',
|
|
364
|
-
{
|
|
365
|
-
bubbles: true,
|
|
366
|
-
composed: true,
|
|
367
|
-
detail: Object.freeze(
|
|
368
|
-
{
|
|
369
|
-
request: activationRequest,
|
|
370
|
-
error,
|
|
371
|
-
message
|
|
372
|
-
}
|
|
373
|
-
)
|
|
374
|
-
}
|
|
375
|
-
)
|
|
376
|
-
);
|
|
377
|
-
return false;
|
|
378
|
-
} finally {
|
|
379
|
-
if (!destroyed && generation === requestGeneration) {
|
|
380
|
-
requestPending = false;
|
|
381
|
-
onChange();
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
function activateSelectedSTT() {
|
|
387
|
-
const nextAction = action();
|
|
388
|
-
if (nextAction) {
|
|
389
|
-
void request(nextAction);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
function synchronize(nextRole) {
|
|
394
|
-
if (destroyed) {
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
if (role?.state !== nextRole.state
|
|
398
|
-
|| role?.providerId !== nextRole.providerId
|
|
399
|
-
|| role?.modelId !== nextRole.modelId
|
|
400
|
-
|| role?.loaded !== nextRole.loaded
|
|
401
|
-
|| role?.busy !== nextRole.busy
|
|
402
|
-
|| role?.operationId !== nextRole.operationId) {
|
|
403
|
-
requestGeneration += 1;
|
|
404
|
-
requestError = '';
|
|
405
|
-
requestPending = false;
|
|
406
|
-
}
|
|
407
|
-
role = nextRole;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
function destroy() {
|
|
411
|
-
if (destroyed) {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
destroyed = true;
|
|
415
|
-
requestGeneration += 1;
|
|
416
|
-
requestPending = false;
|
|
417
|
-
button.removeEventListener('click', activateSelectedSTT);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
button.addEventListener('click', activateSelectedSTT);
|
|
421
|
-
return Object.freeze(
|
|
422
|
-
{
|
|
423
|
-
get action() {
|
|
424
|
-
return action();
|
|
425
|
-
},
|
|
426
|
-
get error() {
|
|
427
|
-
return requestError;
|
|
428
|
-
},
|
|
429
|
-
get pending() {
|
|
430
|
-
return requestPending;
|
|
431
|
-
},
|
|
432
|
-
get selected() {
|
|
433
|
-
return selected();
|
|
434
|
-
},
|
|
435
|
-
request,
|
|
436
|
-
synchronize,
|
|
437
|
-
destroy
|
|
438
|
-
}
|
|
439
|
-
);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
260
|
function unavailableRole(role) {
|
|
443
261
|
return Object.freeze(
|
|
444
262
|
{
|
|
@@ -598,10 +416,7 @@
|
|
|
598
416
|
function renderControls() {
|
|
599
417
|
const transcriptionReady = sttRole.state === 'ready';
|
|
600
418
|
const microphoneReady = host.availability.microphone;
|
|
601
|
-
const activationVisible = sttActivationController.
|
|
602
|
-
&& sttRole.state !== 'ready'
|
|
603
|
-
&& ['unloaded', 'loading', 'unloading', 'error']
|
|
604
|
-
.includes(sttRole.state);
|
|
419
|
+
const activationVisible = sttActivationController.visible;
|
|
605
420
|
recordButton.hidden = activationVisible;
|
|
606
421
|
recordButton.disabled = !transcriptionReady
|
|
607
422
|
|| !microphoneReady
|
|
@@ -620,8 +435,8 @@
|
|
|
620
435
|
|| sttActivationController.pending
|
|
621
436
|
|| sttRole.state === 'unloading'
|
|
622
437
|
|| sttActivationController.action === null;
|
|
623
|
-
sttActivationButton.textContent =
|
|
624
|
-
sttActivationButton.title =
|
|
438
|
+
sttActivationButton.textContent = sttActivationController.label;
|
|
439
|
+
sttActivationButton.title = sttActivationController.title;
|
|
625
440
|
sttActivationButton.setAttribute(
|
|
626
441
|
'aria-label',
|
|
627
442
|
sttActivationButton.title
|
|
@@ -636,41 +451,6 @@
|
|
|
636
451
|
renderTTSControl();
|
|
637
452
|
}
|
|
638
453
|
|
|
639
|
-
function transcriptionActivationLabel() {
|
|
640
|
-
if (sttActivationController.pending) {
|
|
641
|
-
return 'Requesting…';
|
|
642
|
-
}
|
|
643
|
-
if (sttRole.state === 'loading') {
|
|
644
|
-
return 'Cancel loading';
|
|
645
|
-
}
|
|
646
|
-
if (sttRole.state === 'unloading') {
|
|
647
|
-
return 'Canceling…';
|
|
648
|
-
}
|
|
649
|
-
if (sttRole.state === 'error') {
|
|
650
|
-
return 'Try again';
|
|
651
|
-
}
|
|
652
|
-
return 'Start transcription';
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
function transcriptionActivationTitle() {
|
|
656
|
-
if (sttActivationController.pending) {
|
|
657
|
-
return 'Requesting transcription activation.';
|
|
658
|
-
}
|
|
659
|
-
if (sttRole.state === 'loading') {
|
|
660
|
-
return 'Cancel loading the selected transcription service.';
|
|
661
|
-
}
|
|
662
|
-
if (sttRole.state === 'unloading') {
|
|
663
|
-
return 'The selected transcription service is being released.';
|
|
664
|
-
}
|
|
665
|
-
if (sttRole.state === 'error') {
|
|
666
|
-
return sttActivationController.error || visibleErrorMessage(
|
|
667
|
-
sttRole.error,
|
|
668
|
-
'Retry loading the selected transcription service.'
|
|
669
|
-
);
|
|
670
|
-
}
|
|
671
|
-
return 'Start the selected transcription service.';
|
|
672
|
-
}
|
|
673
|
-
|
|
674
454
|
function transcriptionButtonTitle() {
|
|
675
455
|
if (destroyed || sttRole.state === 'disposed') {
|
|
676
456
|
return 'Transcription is unavailable.';
|
|
@@ -776,34 +556,10 @@
|
|
|
776
556
|
}
|
|
777
557
|
|
|
778
558
|
function describeSTTRole() {
|
|
779
|
-
if (
|
|
780
|
-
return
|
|
781
|
-
}
|
|
782
|
-
if (sttActivationController.pending) {
|
|
783
|
-
return 'Transcription activation requested.';
|
|
784
|
-
}
|
|
785
|
-
if (sttRole.state === 'ready') {
|
|
786
|
-
if (!host.availability.microphone) {
|
|
787
|
-
return 'Microphone unavailable.';
|
|
788
|
-
}
|
|
789
|
-
return sttRole.busy ? 'Transcription busy.' : 'Transcription ready.';
|
|
790
|
-
}
|
|
791
|
-
if (sttRole.state === 'loading') {
|
|
792
|
-
return `Transcription ${formatRoleProgress(sttRole.progress, 'loading')}; Cancel is available.`;
|
|
793
|
-
}
|
|
794
|
-
if (sttRole.state === 'unloading') {
|
|
795
|
-
return `Transcription ${formatRoleProgress(sttRole.progress, 'releasing')}.`;
|
|
796
|
-
}
|
|
797
|
-
if (sttRole.state === 'error') {
|
|
798
|
-
return `Transcription error: ${visibleErrorMessage(sttRole.error, 'Unknown error')}.`;
|
|
799
|
-
}
|
|
800
|
-
if (sttRole.state === 'disposed') {
|
|
801
|
-
return 'Transcription disposed.';
|
|
802
|
-
}
|
|
803
|
-
if (sttRole.state === 'unloaded' && sttActivationController.selected) {
|
|
804
|
-
return 'Transcription selected and waiting to load.';
|
|
559
|
+
if (sttRole.state === 'ready' && !host.availability.microphone) {
|
|
560
|
+
return 'Microphone unavailable.';
|
|
805
561
|
}
|
|
806
|
-
return
|
|
562
|
+
return sttActivationController.status;
|
|
807
563
|
}
|
|
808
564
|
|
|
809
565
|
function describeTTSRole() {
|