arcane-os 0.45.0 → 0.47.0
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 +39 -0
- package/README.md +1 -1
- package/browser-runtime/ai/browser-speech-recognition.mjs +495 -0
- package/browser-runtime/ai/browser-speech.mjs +1 -0
- package/docs/reference/ai/browser-speech.md +80 -2
- package/docs/reference/availability-and-normalization.md +2 -1
- package/docs/reference/inventory/package-api.json +14 -0
- package/docs/reference/runtime-components.md +59 -4
- package/docs/reference/runtime-modules.md +78 -10
- package/docs/reference/sdk-api.md +57 -0
- package/package.json +2 -2
- package/runtime/arcane/components/file-manager.html +35 -3
- package/runtime/arcane/components/speech.html +141 -11
- package/runtime/arcane/components/voice-transcription.html +77 -8
- package/runtime/arcane/css/theme.css +41 -0
- package/runtime/arcane/modules/AI.js +15 -4
- package/runtime/arcane/modules/AIProviderRuntime.js +118 -0
- package/runtime/arcane/modules/MD.js +14 -0
- package/runtime/arcane/modules/MarkdownMedia.js +41 -13
- package/runtime/arcane/modules/PrintView.js +23 -3
|
@@ -72,6 +72,7 @@ version; WebKitGTK availability must not be generalized to macOS.
|
|
|
72
72
|
| Select and observe independent LLM/STT/TTS roles | `/arcane/modules/AIProviderRuntime.js` and `AIRuntimeState.js` | **Cross-host** controller/state; registered providers retain their own host requirements | Required/projected provider members, route/configuration records, and status fields; per-role lifecycle, cancellation, stream cleanup, sticky state, and startup barriers are normalized. `localOnly` creates no fallback. |
|
|
73
73
|
| Run a caller-selected local LLM entirely in a browser renderer | `arcane-os/ai/browser-wasm` through `createArcaneAI()` | **Browser** only; secure context, WebAssembly, and OPFS/DBOPFS; full WebGPU offload by default or explicit CPU with `gpuLayers:0` | The public AI API module normalizes multi-model lifecycle, status, complete all-choice streaming, cancellation, exact ordered structural tool-call visibility, and session persistence. Model sources are canonical ordered file descriptors; licenses and model choice remain application policy. |
|
|
74
74
|
| Run caller-selected Whisper or Kokoro in a browser renderer | `arcane-os/ai/browser-speech` registered with `AIProviderRuntime` | **Browser** only; DBOPFS, Web Locks, Workers, Fetch/object URLs, and a caller-supplied self-contained runtime/model closure are required | STT/TTS use independent provider/2 lifecycle and status. Kokoro adds bounded Worker/session concurrency and explicit `auto`, `webgpu`, or `wasm` execution. Complete model/runtime selection, offline behavior, cancellation, Worker teardown, and request/result shapes are normalized. No runtime/model content or cloud fallback is supplied. |
|
|
75
|
+
| Capture speech with the explicitly selected native browser service | `createBrowserSpeechRecognitionProvider` from `arcane-os/ai/browser-speech`, configured as STT | **Browser / native WebView**, conditional on `SpeechRecognition` or `webkitSpeechRecognition`; no SDK model, Worker, or storage required | `localOnly:false` because the browser may use a remote service. Factory/catalog remain usable without native support; inspect/load report availability. User-gesture start, exact final results, transient interim text, stop/drain and abort are owned by the provider/runtime and shared controls. No provider fallback. |
|
|
75
76
|
| Prepare ordered speech playback or reuse the speech-input formatting filter | `arcane-os/speech-playback` and `arcane-os/speech-text` | **Node** with injected media adapters, or **Browser / Native WebView** media; the text filter itself is **Cross-host** | Stored and caller-owned text stays exact. Only the outbound synthesis copy automatically loses repeated same formatting marks. A capacity-advertising provider receives complete segments immediately while retaining indexed playback; native/custom synthesis stays serialized. |
|
|
76
77
|
| Preserve complete chat history and memory | `/arcane/modules/PersistentAIChatSession.js` | **Browser / native WebView** with ChatEntity/DBOPFS and a configured chat function | Existing DBOPFS names and memory semantics are preserved. Live-context commit is atomic; durable persistence is explicit and coherent across user/assistant turns and atomic all-ID tool-result batches. |
|
|
77
78
|
| Search an app-owned document corpus for explicit chat context | `/arcane/modules/DBOPFSDocumentLibrary.js` | **Browser** or compatible injected DBOPFS adapter | Generation/manifest completion, complete lexical search, partial read failures, and untrusted context labels are normalized. Construction does not search; an explicitly wired context builder performs retrieval for each prepared chat send. |
|
|
@@ -79,7 +80,7 @@ version; WebKitGTK availability must not be generalized to macOS.
|
|
|
79
80
|
| Use local AI without coupling app code to Ollama HTTP | `Arcane.localAI`, `Arcane.ai`, or `/arcane/modules/Ollama.js` | Primarily **Native**; Android exposes a narrower admitted inference projection | Admission, errors, and managed-operation events are normalized. Direct Ollama response envelopes remain **Provider-native**. |
|
|
80
81
|
| Use TWiN Cloud from the renderer profile | `/arcane/modules/AI.js` | **Cloud** from an allowed browser/native renderer | High-level chat behavior is normalized by the module. The TWiN access key authenticates remote LLM chat; raw provider diagnostics remain provider-specific. No automatic cloud fallback is inferred from local failure. |
|
|
81
82
|
| Send one TWiN Cloud request with an explicit key and model | `fetchRequest` from `arcane-os/ai/twin-cloud` | **Node** and **Browser**, using standard Fetch and a remote HTTPS provider | Keeps complete messages and returns the full parsed provider JSON. Rejected Fetch and HTTP 529 share three retries after 3000 ms; HTTP 429 overload retains unlimited three-second retries. Optional `onRetry` reports waiting/requesting phases without blocking recovery. Shared structured-output mapping and cancellation match browser TWiN transport. No browser profile, AI/user singleton, DBOPFS, or retained request history is created. |
|
|
82
|
-
| Use speech through one application helper | `/arcane/modules/AI.js` and `Arcane.speech` | **Browser** or **Native** |
|
|
83
|
+
| Use speech through one application helper | `/arcane/modules/AI.js` and `Arcane.speech` | **Browser** or **Native** | Whisper and Kokoro keep their on-device paths; explicitly selected Web Speech STT and TWiN Cloud TTS declare their non-local behavior. The helper automatically cleans only the outbound synthesis-input copy and normalizes application-facing audio/text behavior while request/response plumbing differs below that boundary. |
|
|
83
84
|
| Inspect or manage raw Ollama models | `Arcane.ollama` or `/arcane/modules/Ollama.js` | **Native** desktop Core for management; narrower Android inference only | Wrapper method names, errors, streaming correlation, and admission are Arcane-controlled. Direct Ollama success envelopes are intentionally provider-native. |
|
|
84
85
|
| Use native terminal, installation, user, provisioning, or machine controls | matching `Arcane.*` namespace | **Native** and app/capability restricted | Calls and errors use the common bridge contract. Platform results can be host-specific and are marked in the method guide. |
|
|
85
86
|
|
|
@@ -3134,6 +3134,20 @@
|
|
|
3134
3134
|
"protocol": "arcane-ai-provider/2 tts/synthesize",
|
|
3135
3135
|
"normalization": "Construction and activation make no adapter network requests. SDK initial POSTs bypass the provider-local js-queue; follow-up status/result/audio GETs use followUpQueue capacity and cadence through complete body consumption. Retry-After affects only its job. Whole-job maxConcurrentRequests remains independent. Local Kokoro and Whisper paths are unchanged. Applications own model, voice, credentials, activation, and queue settings."
|
|
3136
3136
|
},
|
|
3137
|
+
{
|
|
3138
|
+
"id": "browser-speech:createBrowserSpeechRecognitionProvider",
|
|
3139
|
+
"name": "createBrowserSpeechRecognitionProvider",
|
|
3140
|
+
"displayName": "createBrowserSpeechRecognitionProvider()",
|
|
3141
|
+
"kind": "function",
|
|
3142
|
+
"signature": "createBrowserSpeechRecognitionProvider({id,model,language}={})",
|
|
3143
|
+
"entrypoints": ["arcane-os/ai/browser-speech"],
|
|
3144
|
+
"primaryImport": "arcane-os/ai/browser-speech",
|
|
3145
|
+
"group": "Browser speech providers",
|
|
3146
|
+
"summary": "Creates an explicitly selected native browser speech recognition provider with gesture-started live capture.",
|
|
3147
|
+
"availability": "Browser or WebView exposing SpeechRecognition or webkitSpeechRecognition; construction remains available on unsupported hosts",
|
|
3148
|
+
"protocol": "arcane-ai-provider/2 stt with optional createCapture",
|
|
3149
|
+
"normalization": "Non-local service declaration, independent STT lifecycle, exact final segments, transient interim results, graceful stop/drain and native abort. No model download, storage, microphone on activation, file-transcription emulation, or automatic fallback."
|
|
3150
|
+
},
|
|
3137
3151
|
{
|
|
3138
3152
|
"id": "browser-speech:createBrowserKokoroProvider",
|
|
3139
3153
|
"name": "createBrowserKokoroProvider",
|
|
@@ -54,6 +54,16 @@ imported component's `destroy()` through `HTMLImport`; callers that invoke
|
|
|
54
54
|
`destroy()` directly retain responsibility for removing the element when
|
|
55
55
|
appropriate.
|
|
56
56
|
|
|
57
|
+
## Shared print presentation
|
|
58
|
+
|
|
59
|
+
Applications loading the shared `theme.css` receive a print-only base light
|
|
60
|
+
palette with a white paper surface and `15mm` page margins. Root, body, and
|
|
61
|
+
scoped `data-arcane-palette` tokens override screen/custom colors during print;
|
|
62
|
+
root/body margins are reset. Saved preferences, screen presentation, scrolling,
|
|
63
|
+
media, and other layout rules remain unchanged. Registered rendered-print
|
|
64
|
+
views use the separate [`PrintView.js`](runtime-modules.md#printviewjs) snapshot
|
|
65
|
+
owner described with the editor and file preview below.
|
|
66
|
+
|
|
57
67
|
## Canonical inventory
|
|
58
68
|
|
|
59
69
|
| Component | Capability | Principal methods | Events | Normalization |
|
|
@@ -919,7 +929,16 @@ extension. Routing compares the lowercase MIME essence without its parameters;
|
|
|
919
929
|
the callback's `mimeType` and the file content remain unchanged.
|
|
920
930
|
HTML uses its complete original string in `srcdoc` without an
|
|
921
931
|
added sandbox policy; Markdown reads the complete original text before
|
|
922
|
-
rendering.
|
|
932
|
+
rendering. With no descriptor or `previewTransform`, JSON, JSONL, and NDJSON
|
|
933
|
+
files are read in full and recognized through
|
|
934
|
+
[`decodeMarkdownMediaRecord()`](runtime-modules.md#markdownmediajs). A complete
|
|
935
|
+
stored image record, including nested single-record arrays, opens as an image
|
|
936
|
+
when its decoded Blob has an `image/` media type. Untyped/non-image records,
|
|
937
|
+
multiple records, and unrecognized content keep their ordinary JSON-family
|
|
938
|
+
presentation; malformed recognized image encoding follows the existing
|
|
939
|
+
file-open failure path.
|
|
940
|
+
This recognition leaves saved content unchanged and performs no migration.
|
|
941
|
+
Untransformed JSONL/NDJSON shows its complete original text,
|
|
923
942
|
including lines that are not JSON records. Other binary files offer a download
|
|
924
943
|
of the original `File`.
|
|
925
944
|
The larger file-preview dialog reuses `--modal-width`, `--modal-max-height`,
|
|
@@ -931,6 +950,8 @@ preview ahead of the editor. Printing uses the shared
|
|
|
931
950
|
[`PrintView.js`](runtime-modules.md#printviewjs) owner; accessible HTML frames
|
|
932
951
|
are copied from their current rendered document, never substituted with source
|
|
933
952
|
text. Explicit printing waits for images/fonts and HTML frame readiness.
|
|
953
|
+
The shared print surface uses a light paper palette and `15mm` page margins
|
|
954
|
+
while preserving image/SVG colors and leaving the screen theme unchanged.
|
|
934
955
|
Native PDF and inaccessible embedded viewers require their own print command.
|
|
935
956
|
`true` means the browser print dialog was requested, not that paper or a PDF
|
|
936
957
|
was produced. Closed, destroyed, or unavailable previews return `false`;
|
|
@@ -945,6 +966,9 @@ pending media because it cannot await them. Closing or replacing a preview
|
|
|
945
966
|
cancels display readiness without waiting for storage; URLs already retained
|
|
946
967
|
by a requested print remain until `afterprint`. Original Markdown and ordinary
|
|
947
968
|
external image URLs remain unchanged.
|
|
969
|
+
Standalone IMG blocks with multiline quoted descriptions use the shared
|
|
970
|
+
[`MD.js`](runtime-modules.md#mdjs) tokenizer in both ordinary and source-mapped
|
|
971
|
+
rendering; the complete description and stored Markdown remain intact.
|
|
948
972
|
|
|
949
973
|
`await close()` cancels pending presentation work and closes delete, file, and
|
|
950
974
|
directory dialogs in that order. A settled preview keeps its rendered content,
|
|
@@ -957,7 +981,7 @@ writes complete through the storage owner without reopening closed dialogs.
|
|
|
957
981
|
|
|
958
982
|
Events: `file-manager-ready`, `file-manager-select`, `file-manager-open`, `file-manager-action`.
|
|
959
983
|
|
|
960
|
-
Shared dependencies: [`DBOPFS.js`](runtime-modules.md#dbopfsjs), [`File.js`](runtime-entities.md#filejs), [`MD.js`](runtime-modules.md#mdjs), [`WaitForComponent.js`](runtime-modules.md#waitforcomponentjs).
|
|
984
|
+
Shared dependencies: [`DBOPFS.js`](runtime-modules.md#dbopfsjs), [`File.js`](runtime-entities.md#filejs), [`MD.js`](runtime-modules.md#mdjs), [`MarkdownMedia.js`](runtime-modules.md#markdownmediajs), [`PrintView.js`](runtime-modules.md#printviewjs), [`WaitForComponent.js`](runtime-modules.md#waitforcomponentjs).
|
|
961
985
|
|
|
962
986
|
### Availability and normalization
|
|
963
987
|
|
|
@@ -1082,6 +1106,9 @@ diagnostics remain in the developer console; successful images and document
|
|
|
1082
1106
|
text remain visible. Replacing, clearing, failing, or destroying the document
|
|
1083
1107
|
releases its display resources without deleting stored media. Markdown source
|
|
1084
1108
|
and ordinary external image URLs remain unchanged.
|
|
1109
|
+
Complete standalone IMG blocks with quoted multiline descriptions render
|
|
1110
|
+
through the shared [`MD.js`](runtime-modules.md#mdjs) tokenizer without
|
|
1111
|
+
rewriting saved Markdown.
|
|
1085
1112
|
|
|
1086
1113
|
Shared dependencies: [`MD.js`](runtime-modules.md#mdjs), [`MarkdownMedia.js`](runtime-modules.md#markdownmediajs).
|
|
1087
1114
|
|
|
@@ -1125,8 +1152,10 @@ The visible **Print** control and `await print()` print the complete rendered
|
|
|
1125
1152
|
Markdown with `entryTitle`, independently of saving. Native browser Print uses
|
|
1126
1153
|
that same registered view unless an open file preview takes precedence.
|
|
1127
1154
|
The SDK copies current rendered DOM/styles into a temporary print-only view,
|
|
1128
|
-
leaving the editor's source, controls, and screen layout in place.
|
|
1129
|
-
|
|
1155
|
+
leaving the editor's source, controls, and screen layout in place. Both explicit
|
|
1156
|
+
and native print use the shared light paper palette and `15mm` page margins;
|
|
1157
|
+
image pixels and SVG artwork keep their colors. Explicit printing waits for
|
|
1158
|
+
resource readiness; native `beforeprint` is synchronous
|
|
1130
1159
|
and uses the currently rendered content. `print()` returns `false` when the
|
|
1131
1160
|
view is unavailable, rejects preparation failures, and returns `true` only
|
|
1132
1161
|
when the browser dialog was requested. Completion of physical printing or PDF
|
|
@@ -1142,6 +1171,9 @@ waits for the current image reads/decoding, follows a replacement preview, and
|
|
|
1142
1171
|
rechecks readiness before capture. Native Print reports still-pending media
|
|
1143
1172
|
synchronously; it cannot wait or cancel the native dialog. Print-owned URLs
|
|
1144
1173
|
outlive a changed or destroyed editor until `afterprint`.
|
|
1174
|
+
The shared [`MD.js`](runtime-modules.md#mdjs) tokenizer preserves complete
|
|
1175
|
+
standalone IMG blocks with quoted multiline descriptions in ordinary and
|
|
1176
|
+
source-mapped rendering. Existing saved markup needs no rewriting.
|
|
1145
1177
|
|
|
1146
1178
|
`configure({fit:true,followPreview:true})` opts into the two independent
|
|
1147
1179
|
behaviors. Both options default to `false`; omitted options retain their
|
|
@@ -1597,6 +1629,16 @@ Events: `source-explanation-ready`, `source-explanation-save`, `source-explanati
|
|
|
1597
1629
|
|
|
1598
1630
|
## speech.html
|
|
1599
1631
|
|
|
1632
|
+
An explicitly selected native Web Speech provider uses gesture-started live
|
|
1633
|
+
capture instead of MediaRecorder. The shared control retains every final
|
|
1634
|
+
result and emits its existing completion event once with the exact combined
|
|
1635
|
+
text when native capture ends. The live display retains final words alongside
|
|
1636
|
+
interim hypotheses while speaking; interim hypotheses stay transient. Release/Stop
|
|
1637
|
+
finishes native recognition; cancellation, replacement and destruction abort
|
|
1638
|
+
it and suppress late submission. A persisted page hide stops live native capture
|
|
1639
|
+
without restarting it when the page returns. Existing Whisper and TTS paths
|
|
1640
|
+
remain unchanged.
|
|
1641
|
+
|
|
1600
1642
|
### Overview
|
|
1601
1643
|
|
|
1602
1644
|
Coordinates explicit speech-to-text activation, speech controls, transcription
|
|
@@ -2051,6 +2093,19 @@ Native methods remain subject to the bound app's capabilities. [Deep protocol de
|
|
|
2051
2093
|
|
|
2052
2094
|
### Continuous capture and controls
|
|
2053
2095
|
|
|
2096
|
+
An explicitly selected native Web Speech provider uses the same ordered
|
|
2097
|
+
transcript/save queue in either capture mode. Each complete final text segment
|
|
2098
|
+
skips file transcription and enters the existing append/save stages; interim
|
|
2099
|
+
text stays in the transient `interim` part and never reaches a save or success
|
|
2100
|
+
event. Final segments waiting behind a save stay visible there until appended
|
|
2101
|
+
to the main transcript. Native `stopRecording()` returns the drain promise, including final
|
|
2102
|
+
results emitted during native stop. Browser `end` stops capture without an
|
|
2103
|
+
automatic restart. Provider replacement stops native capture while already
|
|
2104
|
+
accepted final segments retain their ordered saves. Explicit Cancel, transcript
|
|
2105
|
+
replacement and destruction retain the existing supersession behavior.
|
|
2106
|
+
This path does not require AudioWorklet or MediaRecorder. A supplied custom
|
|
2107
|
+
`transcribe(file,context)` callback keeps the existing audio-clip route.
|
|
2108
|
+
|
|
2054
2109
|
`configure({capture:{mode:'continuous'}})` opts into the SDK's
|
|
2055
2110
|
[`ContinuousVoiceCapture`](runtime-modules.md#continuousvoicecapturejs) owner.
|
|
2056
2111
|
The default capture settings are `preRollMs:1500`, `quietMs:2000`,
|
|
@@ -96,7 +96,7 @@ own asynchronous work, cancellation, and backpressure.
|
|
|
96
96
|
| [`Mail.js`](#mailjs) | esm | Builds complete reports and prefers the native mail capability with an explicit HTTP transport fallback. | Browser/native hybrid + cloud | Mail inputs/results normalized; transport failures mixed. |
|
|
97
97
|
| [`MailOutbox.mjs`](#mailoutboxmjs) | esm | Persists complete mail reports before delivery and normalizes idempotent enqueue, retry, reconciliation, and invalid-record maintenance. | Browser/native WebView or compatible injected host | Complete records, full work, cancellation, and lifecycle states normalized; storage, lock, and delivery failures coded. |
|
|
98
98
|
| [`MailTransport.mjs`](#mailtransportmjs) | esm | Sends one complete mail report to a normalized HTTP(S) endpoint. | Browser/server with fetch + cloud | Normalized endpoint and transport errors; remote detail preserved. |
|
|
99
|
-
| [`MarkdownMedia.js`](#markdownmediajs) | esm | Saves local Markdown images separately and resolves
|
|
99
|
+
| [`MarkdownMedia.js`](#markdownmediajs) | esm | Saves local Markdown images separately, decodes complete stored records, and resolves stable references in rendered views. | Browser / supported native WebView | Complete image records, concurrent display reads, cancellation, and print-owned URL lifetime. |
|
|
100
100
|
| [`MarkdownSpeech.js`](#markdownspeechjs) | esm | Removes repeated Markdown formatting marks from streamed narration. | Cross-host | Speech-only filtering; single marks and ordinary punctuation remain literal. |
|
|
101
101
|
| [`Marked.min.js`](#markedminjs) | esm | Vendored Marked 18.0.5 Markdown lexer, parser, renderer, extension, and walk-token API. | Cross-host vendor module | Vendor-native Marked contract. |
|
|
102
102
|
| [`MD.js`](#mdjs) | esm | Renders complete Markdown with Marked and optionally maps source blocks to rendered comment anchors. | Browser / native WebView | Complete raw and rendered Marked values; opt-in original-source offsets; parse errors vendor-native. |
|
|
@@ -275,8 +275,9 @@ tool declarations, emitted tool calls, or callback ordering.
|
|
|
275
275
|
`configureSpeechProviders({stt,tts})` commits only the two speech routes and
|
|
276
276
|
leaves the current LLM route and sticky lifecycle record unchanged. Both speech
|
|
277
277
|
roles must be unloaded and own no request, load, unload, or dispose operation.
|
|
278
|
-
STT remains local-only (`AI_STT_DEVICE_ONLY` for
|
|
279
|
-
|
|
278
|
+
File-based STT remains local-only (`AI_STT_DEVICE_ONLY` for an unsupported
|
|
279
|
+
remote file selection). An explicitly selected native live-capture STT provider
|
|
280
|
+
or TTS provider may declare `localOnly:false`.
|
|
280
281
|
`transitionSpeechProviders({stt,tts})` stops queued audio, explicitly unloads
|
|
281
282
|
only STT and TTS, then commits that same closed speech route record. Neither
|
|
282
283
|
method loads a model, selects a fallback, or changes caller-owned model or voice
|
|
@@ -302,6 +303,13 @@ cancels that pending unmute. The application keeps model, voice, and credential
|
|
|
302
303
|
selection. See [DigitalOcean FAL speech](ai/browser-speech.md#digitalocean-fal-text-to-speech)
|
|
303
304
|
for the public remote adapter and completed-job audio transport.
|
|
304
305
|
|
|
306
|
+
`supportsTranscriptionCapture()` reports whether the selected STT provider
|
|
307
|
+
offers native live capture. `createTranscriptionCapture(options={})` delegates
|
|
308
|
+
to the provider runtime's owned capture boundary below and returns `null` for
|
|
309
|
+
file-only providers. Shared speech controls select it automatically; apps keep
|
|
310
|
+
using their existing controls and completion/save callbacks. See
|
|
311
|
+
[native browser recognition](ai/browser-speech.md#native-browser-speech-recognition).
|
|
312
|
+
|
|
305
313
|
`startProviders({startLanguageModel=true,startMuted=true,startTranscription=false,signal=null}={})`
|
|
306
314
|
starts provider-owned text chat without requesting an STT load by default.
|
|
307
315
|
Callers selecting a browser-WASM LLM pass `startLanguageModel:false` so it
|
|
@@ -961,6 +969,8 @@ The singleton exposes read-only `protocol`, `configured`, and `speechMuted`;
|
|
|
961
969
|
`request(role,options={},preparation={})`;
|
|
962
970
|
`chat(payload,options={})`; `stream(payload,options={})`;
|
|
963
971
|
`transcribe(payload,options={})`;
|
|
972
|
+
`supportsTranscriptionCapture(providerId=null)`;
|
|
973
|
+
`createTranscriptionCapture(options={})`;
|
|
964
974
|
`synthesize(payload,options={},preparation={})`; and
|
|
965
975
|
`setSpeechMuted(muted)`. Provider payloads must be data-only; callbacks,
|
|
966
976
|
accessors, symbols, and cycles are rejected at the provider boundary.
|
|
@@ -1099,6 +1109,24 @@ cleanup are normalized, while the
|
|
|
1099
1109
|
selected provider retains its own capability, permission, download, and model
|
|
1100
1110
|
requirements. [Deep protocol details](protocols.md#portable-ai-provider-runtime).
|
|
1101
1111
|
|
|
1112
|
+
STT providers may additionally implement `createCapture(options)`. Registration
|
|
1113
|
+
retains that optional method without changing the required provider/2 methods.
|
|
1114
|
+
`supportsTranscriptionCapture(providerId=null)` checks the current selection by
|
|
1115
|
+
default or a specified registered STT provider without starting it.
|
|
1116
|
+
`createTranscriptionCapture({language,continuous,onSegment,onInterim,onState,onError})`
|
|
1117
|
+
returns `null` for a provider without that method; otherwise it returns
|
|
1118
|
+
`{start,stop,cancel,destroy,done}`. Creation has no microphone side effect.
|
|
1119
|
+
`start({signal})` requires the same selected ready provider with an idle STT
|
|
1120
|
+
lane and invokes its capture start synchronously in the caller's gesture.
|
|
1121
|
+
Capture occupies one active STT request until its `done` promise settles;
|
|
1122
|
+
ordinary file requests remain queued, and unload/dispose/cancel use the same
|
|
1123
|
+
owned request cancellation lifecycle. Stop drains native final recognition;
|
|
1124
|
+
cancel suppresses late callbacks. Provider callbacks carry exact final
|
|
1125
|
+
`{text,sequence}` segments, transient `{text}` interim results, capture state,
|
|
1126
|
+
or complete errors. The browser provider's `done` resolves a success boolean;
|
|
1127
|
+
runtime cleanup errors remain observable as rejection. No callback is inserted
|
|
1128
|
+
into a data-only transcription request payload.
|
|
1129
|
+
|
|
1102
1130
|
### Example
|
|
1103
1131
|
|
|
1104
1132
|
```javascript
|
|
@@ -2816,9 +2844,18 @@ Public package import: `arcane-os/modules/MarkdownMedia.js`.
|
|
|
2816
2844
|
- `parseMarkdownMediaReference(reference)` returns `{tableName,fileName}` for
|
|
2817
2845
|
a local reference, or `null` for an ordinary URL. Malformed local addresses
|
|
2818
2846
|
report their actual parsing error.
|
|
2847
|
+
- `decodeMarkdownMediaRecord(value)` synchronously decodes a complete
|
|
2848
|
+
`{dataUrl,mediaType?}` record or its JSON text into a `Blob`, without storage
|
|
2849
|
+
or network access. Nested single-record arrays are unwrapped; arrays with
|
|
2850
|
+
multiple records are never reduced to one image. Unrecognized content,
|
|
2851
|
+
including text that is not complete JSON, returns `null`. A recognized
|
|
2852
|
+
record with unreadable base64 data-URL content throws its decoding error.
|
|
2853
|
+
Omitted `mediaType` preserves the Blob's empty type. Input remains unchanged.
|
|
2819
2854
|
- `await readMarkdownMedia(reference)` returns the complete `Blob`, using
|
|
2820
2855
|
only local storage and data-URL decoding; stored strings are never fetched
|
|
2821
|
-
as network addresses.
|
|
2856
|
+
as network addresses. It uses the same record decoder after loading, while
|
|
2857
|
+
preserving JSON parse errors for unreadable stored JSON strings and reporting
|
|
2858
|
+
an unreadable record as an error rather than `null`.
|
|
2822
2859
|
- `hydrateMarkdownMedia(root,{signal}={})` returns `{ready,destroy,retain}`
|
|
2823
2860
|
immediately. It includes an IMG root and descendant IMG elements, removes
|
|
2824
2861
|
local-reference `src` values synchronously, starts independent reads
|
|
@@ -2841,6 +2878,9 @@ records their existing JSON backup/export includes. Reusing the same filename
|
|
|
2841
2878
|
supports an application-selected save-only retry without another generation
|
|
2842
2879
|
request. The helper performs no existing-data migration.
|
|
2843
2880
|
|
|
2881
|
+
Exact exports: `saveMarkdownMedia`, `parseMarkdownMediaReference`,
|
|
2882
|
+
`decodeMarkdownMediaRecord`, `readMarkdownMedia`, `hydrateMarkdownMedia`.
|
|
2883
|
+
|
|
2844
2884
|
### Availability and normalization
|
|
2845
2885
|
|
|
2846
2886
|
Browser or native WebView with the existing app-scoped DBOPFS owner, Blob,
|
|
@@ -2896,16 +2936,29 @@ mapping, not exact rendered glyph or caret geometry.
|
|
|
2896
2936
|
|
|
2897
2937
|
Assigning `raw` or calling `append(string)` rebuilds both the complete rendered
|
|
2898
2938
|
result and its current mapping. Without `sourceMap:true`, `sourceMap` is empty
|
|
2899
|
-
and the
|
|
2939
|
+
and the same parsing runs without comment anchors. Existing raw content, link
|
|
2900
2940
|
behavior, no-op `rendered` setter, and complete `append()` result remain.
|
|
2901
2941
|
|
|
2942
|
+
Both rendering paths first use Marked's native HTML block tokenizer. When it
|
|
2943
|
+
does not recognize a complete standalone `<img>` tag with a newline inside a
|
|
2944
|
+
quoted attribute value, MD keeps that complete tag together as one HTML block.
|
|
2945
|
+
This includes blank lines in an image's full `alt` description. The tag must
|
|
2946
|
+
start at an existing Markdown block boundary with at most three leading spaces
|
|
2947
|
+
and end on its own line or at the end of the source. Separate inserted image
|
|
2948
|
+
blocks from surrounding Markdown with blank lines. Native HTML handling,
|
|
2949
|
+
inline prose, fenced/indented/inline code, escaped examples, and incomplete
|
|
2950
|
+
tags retain their existing parsing behavior. No source is rewritten or saved
|
|
2951
|
+
data migrated. Marked's existing rendered line-ending normalization remains;
|
|
2952
|
+
mapped offsets still address the exact original source, including CRLF or CR.
|
|
2953
|
+
|
|
2902
2954
|
Exact exports: `default`.
|
|
2903
2955
|
|
|
2904
2956
|
### Availability and normalization
|
|
2905
2957
|
|
|
2906
|
-
**Browser / native WebView.**
|
|
2907
|
-
|
|
2908
|
-
scrolling belong to the
|
|
2958
|
+
**Browser / native WebView.** Marked parsing, including the shared standalone
|
|
2959
|
+
image-token correction above; parse errors remain vendor-native. Rendering and
|
|
2960
|
+
the getters are DOM-independent. DOM lookup and scrolling belong to the
|
|
2961
|
+
consuming component;
|
|
2909
2962
|
mapping performs no persistence or viewport movement. Transport: Marked.
|
|
2910
2963
|
[Deep protocol details](protocols.md).
|
|
2911
2964
|
|
|
@@ -3345,6 +3398,13 @@ Shared rendered-print owner used by Markdown Editor and File Manager. It
|
|
|
3345
3398
|
captures the current DOM and computed styles, including accessible rendered
|
|
3346
3399
|
HTML frames, complete text, selected images, and the current title. A temporary
|
|
3347
3400
|
print-only surface expands scrollable content without editing the live screen.
|
|
3401
|
+
That surface uses the shared Arcane light-theme text, paper, and border colors,
|
|
3402
|
+
with `15mm` page margins. It retains rendered fonts, emphasis, and complete
|
|
3403
|
+
content while removing screen-theme text/shadow paint from ordinary HTML and
|
|
3404
|
+
pseudo-elements. Links are underlined and table cells receive visible borders.
|
|
3405
|
+
Image pixels, canvas snapshots, and SVG artwork keep their own colors. These
|
|
3406
|
+
print rules leave the live screen theme unchanged; browser print settings still
|
|
3407
|
+
control the eventual page output.
|
|
3348
3408
|
|
|
3349
3409
|
### Public surface
|
|
3350
3410
|
|
|
@@ -4022,12 +4082,20 @@ is applied once the body is available.
|
|
|
4022
4082
|
|
|
4023
4083
|
The shared `theme.css` owns the default, warm, curious, hopeful, harmony, and
|
|
4024
4084
|
warrior palettes. Each works with explicit light/dark or system appearance.
|
|
4025
|
-
`layout.css` imports that same owner.
|
|
4026
|
-
through `data-arcane-skin="custom"` and their inline tokens.
|
|
4085
|
+
`layout.css` imports that same owner. On screen, explicit custom themes retain
|
|
4086
|
+
precedence through `data-arcane-skin="custom"` and their inline tokens.
|
|
4027
4087
|
The bare root retains the generic neutral light/dark baseline; the prior
|
|
4028
4088
|
layout default palette is selected explicitly through `data-user-skin="default"`,
|
|
4029
4089
|
`body.default` compatibility, or the default swatch.
|
|
4030
4090
|
|
|
4091
|
+
During printing, `theme.css` applies the existing base light palette, with a
|
|
4092
|
+
white paper surface and `15mm` page margins, to the root, body, and scoped
|
|
4093
|
+
`data-arcane-palette` elements. These print-only tokens override screen/custom
|
|
4094
|
+
palette tokens. It resets the root/body margin without changing saved
|
|
4095
|
+
preferences, screen presentation, scrolling, media, or other layout rules.
|
|
4096
|
+
The separate [`PrintView.js`](#printviewjs) owner uses the same light palette
|
|
4097
|
+
and margins for its expanded rendered-content snapshot.
|
|
4098
|
+
|
|
4031
4099
|
A scoped `data-arcane-palette="warm"` element exposes the same palette variables
|
|
4032
4100
|
for a chooser preview without changing the page's selection. Use any of the
|
|
4033
4101
|
six named palettes and paint the preview with ordinary shared variables such
|
|
@@ -169,6 +169,7 @@ browser map are cataloged separately in [Runtime modules](runtime-modules.md).
|
|
|
169
169
|
| `createBrowserSpeechAuthority()` | function | `arcane-os/ai/browser-speech` | Browser speech providers | Browser descriptor construction; use requires the selected storage and provider Web APIs |
|
|
170
170
|
| `createBrowserWasmLlmProvider()` | function | `arcane-os/ai/browser-wasm` | Browser-WASM local AI | Browser context with WebAssembly and OPFS/DBOPFS; WebGPU by default or explicit CPU with gpuLayers:0 |
|
|
171
171
|
| `createBrowserWhisperProvider()` | function | `arcane-os/ai/browser-speech` | Browser speech providers | Browser with Workers, object URLs, caller-selected Whisper runtime/model artifacts, and an SDK DBOPFS speech store |
|
|
172
|
+
| `createBrowserSpeechRecognitionProvider()` | function | `arcane-os/ai/browser-speech` | Browser speech providers | Browser or WebView with native SpeechRecognition; construction and catalog remain available on unsupported hosts |
|
|
172
173
|
| `createCanonicalUstarHeader()` | function | `arcane-os` | Packaging and release bundles | Node |
|
|
173
174
|
| `createDbopfsModelStore()` | function | `arcane-os/ai/browser-wasm` | Browser-WASM local AI | Browser with a ready DBOPFS instance and OPFS |
|
|
174
175
|
| `getBrowserDeviceClass()` | function | `arcane-os/browser-device` | Browser device settings | Node and Browser; synchronous identity hint with no model, storage, or GPU operation |
|
|
@@ -7185,6 +7186,62 @@ async function transcribeAfterUserChoice(audioBlob) {
|
|
|
7185
7186
|
}
|
|
7186
7187
|
```
|
|
7187
7188
|
|
|
7189
|
+
## createBrowserSpeechRecognitionProvider()
|
|
7190
|
+
|
|
7191
|
+
### Overview
|
|
7192
|
+
|
|
7193
|
+
Creates an explicitly selected provider/2 STT adapter for the browser's native
|
|
7194
|
+
`SpeechRecognition` or `webkitSpeechRecognition` service. It declares
|
|
7195
|
+
`localOnly:false` because recognition may use a remote browser service. It does
|
|
7196
|
+
not change Whisper, TTS, typing, stored preferences, or any default selection.
|
|
7197
|
+
|
|
7198
|
+
### Signature and result
|
|
7199
|
+
|
|
7200
|
+
```text
|
|
7201
|
+
createBrowserSpeechRecognitionProvider({id,model,language}={})
|
|
7202
|
+
```
|
|
7203
|
+
|
|
7204
|
+
The application supplies its provider `id` and `model:{id}`; optional `language`
|
|
7205
|
+
is passed to native recognition without changing transcript text. The provider
|
|
7206
|
+
implements the required `catalog`, `inspect`, `status`, `load`, `request`,
|
|
7207
|
+
`unload`, and `dispose` methods plus `createCapture(options)`. There is no SDK
|
|
7208
|
+
model download or storage. Construction/catalog do not require native support;
|
|
7209
|
+
inspect/load report actual browser availability without opening a microphone.
|
|
7210
|
+
File transcription requests are unsupported for this provider.
|
|
7211
|
+
|
|
7212
|
+
`createCapture({language,continuous,onSegment,onInterim,onState,onError})`
|
|
7213
|
+
returns a single-use `{start,stop,cancel,destroy,done}` handle. Start must be
|
|
7214
|
+
called directly from a user gesture and returns a promise for startup success.
|
|
7215
|
+
Final callbacks carry exact `{text,sequence}` values once per final result;
|
|
7216
|
+
interim `{text}` stays transient. Stop preserves pending native final results
|
|
7217
|
+
through `end`; cancellation aborts recognition and suppresses late text.
|
|
7218
|
+
`done` resolves `true` for normal native end and `false` for cancellation or
|
|
7219
|
+
failure. Unload/dispose cancel owned capture.
|
|
7220
|
+
The shared runtime's `createTranscriptionCapture()` additionally owns STT busy
|
|
7221
|
+
state and lifecycle replacement. See the
|
|
7222
|
+
[complete native capture contract](ai/browser-speech.md#native-browser-speech-recognition).
|
|
7223
|
+
|
|
7224
|
+
### Availability and normalization
|
|
7225
|
+
|
|
7226
|
+
Conditional browser/native-WebView support on Windows, Linux, macOS and
|
|
7227
|
+
Android, determined by the actual browser API and permission/service outcome,
|
|
7228
|
+
not by operating-system name. Missing API, denied microphone permission and
|
|
7229
|
+
service errors remain honest STT failures without disabling TTS or typing.
|
|
7230
|
+
No Core, Whisper, or cloud-provider fallback is inferred.
|
|
7231
|
+
|
|
7232
|
+
### Example
|
|
7233
|
+
|
|
7234
|
+
```javascript
|
|
7235
|
+
import {createBrowserSpeechRecognitionProvider} from 'arcane-os/ai/browser-speech';
|
|
7236
|
+
|
|
7237
|
+
async function selectNativeRecognition(ai, signal) {
|
|
7238
|
+
const provider = createBrowserSpeechRecognitionProvider(
|
|
7239
|
+
{id: 'WEB_SPEECH', model: {id: 'WEB_SPEECH'}}
|
|
7240
|
+
);
|
|
7241
|
+
return ai.configureSpeechProvider('stt', provider, {modelId: 'WEB_SPEECH', signal});
|
|
7242
|
+
}
|
|
7243
|
+
```
|
|
7244
|
+
|
|
7188
7245
|
## createTwinCloudTTSProvider()
|
|
7189
7246
|
|
|
7190
7247
|
### Overview
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arcane-os",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
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",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
|
|
87
87
|
"test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
|
|
88
88
|
"test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/conversation-closing-report.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
|
|
89
|
-
"test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.test.mjs test/modal.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
|
|
89
|
+
"test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.test.mjs test/modal.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
|
|
90
90
|
"test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-plan.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
|
|
91
91
|
"test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/html-import-registration.test.mjs test/logging-regression.test.mjs test/markdown-speech.test.mjs test/prepared-speech.test.mjs test/native-provider-generation.test.mjs test/speech-queue-regression.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
|
|
92
92
|
"check": "node tools/check-source.mjs && npm test",
|
|
@@ -2142,8 +2142,9 @@
|
|
|
2142
2142
|
const rendered=document.createElement('div');
|
|
2143
2143
|
rendered.className='file-preview';
|
|
2144
2144
|
let value=fileRef.parsed;
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2145
|
+
const jsonFile=['json','jsonl','ndjson'].includes(fileRef.ext);
|
|
2146
|
+
const transformed=jsonFile&&is.function(host.previewTransform);
|
|
2147
|
+
let completeJSON;
|
|
2147
2148
|
|
|
2148
2149
|
if(transformed){
|
|
2149
2150
|
value=await host.previewTransform(
|
|
@@ -2155,6 +2156,37 @@
|
|
|
2155
2156
|
}
|
|
2156
2157
|
);
|
|
2157
2158
|
preview.controller.signal.throwIfAborted();
|
|
2159
|
+
}else if(jsonFile){
|
|
2160
|
+
// Recognition needs the complete file: FileEntity's parsed JSONL
|
|
2161
|
+
// rows do not include every unparseable line in the original.
|
|
2162
|
+
const [{decodeMarkdownMediaRecord},text]=await Promise.all([
|
|
2163
|
+
import('../modules/MarkdownMedia.js'),
|
|
2164
|
+
fileRef.text()
|
|
2165
|
+
]);
|
|
2166
|
+
preview.controller.signal.throwIfAborted();
|
|
2167
|
+
completeJSON=text;
|
|
2168
|
+
let imageRecord;
|
|
2169
|
+
try {
|
|
2170
|
+
imageRecord = JSON.parse(completeJSON);
|
|
2171
|
+
} catch {
|
|
2172
|
+
// Mixed JSONL and ordinary text keep their complete presentation.
|
|
2173
|
+
imageRecord = null;
|
|
2174
|
+
}
|
|
2175
|
+
while (is.array(imageRecord) && imageRecord.length === 1) {
|
|
2176
|
+
imageRecord = imageRecord[0];
|
|
2177
|
+
}
|
|
2178
|
+
// A dataUrl property alone does not identify an image record.
|
|
2179
|
+
// Recognize its declared media type before attempting any decoding.
|
|
2180
|
+
if (is.string(imageRecord?.mediaType)
|
|
2181
|
+
&& imageRecord.mediaType.toLowerCase().startsWith('image/')) {
|
|
2182
|
+
const image = decodeMarkdownMediaRecord(imageRecord);
|
|
2183
|
+
if (image?.type.startsWith('image/')) {
|
|
2184
|
+
return renderDescriptor(
|
|
2185
|
+
{kind: 'image', content: image, alt: fileRef.name},
|
|
2186
|
+
preview
|
|
2187
|
+
);
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2158
2190
|
}
|
|
2159
2191
|
|
|
2160
2192
|
switch(fileRef.ext){
|
|
@@ -2168,7 +2200,7 @@
|
|
|
2168
2200
|
case 'jsonl':
|
|
2169
2201
|
case 'ndjson':{
|
|
2170
2202
|
if(!transformed){
|
|
2171
|
-
rendered.append(createPreformatted(
|
|
2203
|
+
rendered.append(createPreformatted(completeJSON));
|
|
2172
2204
|
break;
|
|
2173
2205
|
}
|
|
2174
2206
|
const records=is.array(value)?value:[];
|