arcane-os 0.2.0 → 0.2.2
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 +35 -0
- package/README.md +8 -8
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +5 -5
- package/browser-runtime/ai/browser-speech-providers.mjs +331 -25
- package/docs/architecture.md +2 -2
- package/docs/reference/README.md +79 -13
- package/docs/reference/ai/browser-speech.md +336 -0
- package/docs/reference/ai/browser-wasm.md +207 -82
- package/docs/reference/availability-and-normalization.md +30 -4
- package/docs/reference/behavioral-testing.md +4 -1
- package/docs/reference/cli.md +29 -10
- package/docs/reference/core/arcane-ai-contracts.md +43 -9
- package/docs/reference/inventory/package-api.json +110 -14
- package/docs/reference/inventory/runtime-components.json +19 -6
- package/docs/reference/inventory/runtime-modules.json +113 -9
- package/docs/reference/protocols.md +260 -38
- package/docs/reference/runtime-components.md +108 -15
- package/docs/reference/runtime-modules.md +422 -8
- package/docs/reference/sdk-api.md +626 -85
- package/package.json +1 -1
- package/runtime/ARCANE_RUNTIME_RELEASE.json +19 -19
- package/runtime/arcane/components/chat.html +288 -52
- package/runtime/arcane/components/speech.html +339 -15
- package/runtime/arcane/modules/AI.js +1245 -136
- package/runtime/arcane/modules/AIProviderRuntime.js +299 -30
- package/runtime/arcane/modules/AIRuntimeState.js +23 -4
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +93 -8
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +448 -24
- package/runtime/arcane/modules/LocalAIReadinessController.js +1 -1
- package/schemas/arcane-lock.schema.json +6 -4
- package/src/dev-server.mjs +29 -13
- package/src/doctor.mjs +1 -3
- package/src/import-map.mjs +134 -83
- package/src/packager/core.mjs +311 -39
- package/src/scaffold.mjs +45 -17
- package/src/templates/workspace-template.mjs +23 -4
- package/src/toolchain.mjs +10 -2
- package/src/workspace.mjs +177 -24
|
@@ -20,8 +20,10 @@ Apps import renderer ESM from `/arcane/modules/<file>`. Classic scripts, the OPF
|
|
|
20
20
|
| [`AI.js`](#aijs) | esm | Provider-selectable chat, speech-to-text, text-to-speech, tool calling, structured output, streaming, and queued audio playback. | Browser + native bridge + cloud | High-level chat/speech behavior is normalized; provider diagnostics and media errors remain mixed. |
|
|
21
21
|
| [`AIPreferenceRuntime.js`](#aipreferenceruntimejs) | esm | Applies and reads non-persistent per-user AI preference overrides. | Cross-host | Normalized six-slot preference state. |
|
|
22
22
|
| [`AIPreferenceTuple.js`](#aipreferencetuplejs) | esm | Normalizes and compares the six provider/model preference slots. | Cross-host | Fully normalized frozen tuple. |
|
|
23
|
+
| [`AIProviderRuntime.js`](#aiproviderruntimejs) | esm | Owns provider-neutral selection, lifecycle, routing, startup, requests, streaming, cancellation, and independent LLM/STT/TTS state. | Cross-host runtime; provider-specific availability | Normalized required provider members plus closed route/status contracts, with fail-closed local-only selection and no implicit fallback. |
|
|
23
24
|
| [`AIResponseLength.js`](#airesponselengthjs) | esm | Normalizes concise/short/medium/long response preferences and applies the matching system instruction. | Cross-host | Fully normalized string/instruction contract. |
|
|
24
25
|
| [`AIResponseURLPolicy.js`](#airesponseurlpolicyjs) | esm | Extracts and audits links from AI Markdown, rendered HTML, CSS, srcset, bare URLs, and email text. | Cross-host | Normalized frozen allowlist audit. |
|
|
26
|
+
| [`AIRuntimeState.js`](#airuntimestatejs) | esm | Publishes sticky immutable role snapshots, lifecycle intents, and startup-settlement barriers. | Cross-host state contract | Closed monotonic state records; events report state but grant no authority. |
|
|
25
27
|
| [`AnsiText.js`](#ansitextjs) | esm | Parses terminal ANSI sequences into display spans or strips them to plain text. | Cross-host | Normalized text/span output. |
|
|
26
28
|
| [`ApiModelDatabase.js`](#apimodeldatabasejs) | esm | Fetches an injectable HTTP JSON model with parser, cache, redacted public endpoint records, and request lifecycle events. | Browser / native WebView / server with fetch | Request records are normalized; fetch/provider failures remain mixed. |
|
|
27
29
|
| [`AppDataScope.js`](#appdatascopejs) | esm | Reconciles declared and native application identity and scopes OPFS/localStorage ownership fail-closed. | Browser / native WebView hybrid | Strict normalized identifiers and coded mismatch failures. |
|
|
@@ -48,9 +50,11 @@ Apps import renderer ESM from `/arcane/modules/<file>`. Classic scripts, the OPF
|
|
|
48
50
|
| [`DataMaintenance.js`](#datamaintenancejs) | esm | Deletes empty chats and associated/empty memory records inside the current app data scope. | Browser / native WebView | Normalized counts; destructive storage failures preserved. |
|
|
49
51
|
| [`DBLS.js`](#dblsjs) | esm | Provides app-scoped localStorage tables, batch reads/writes, filtering, deletion, and counts. | Browser / native WebView | Scoped keys and values normalized; storage failures mixed. |
|
|
50
52
|
| [`DBOPFS.js`](#dbopfsjs) | esm | Provides app-scoped OPFS tables, worker I/O, backup/restore, compression, and CRUD/batch APIs. | Browser / native WebView | App scope normalized; DOM/storage errors preserved. |
|
|
53
|
+
| [`DBOPFSDocumentLibrary.js`](#dbopfsdocumentlibraryjs) | esm | Bootstraps and searches an app-defined DBOPFS corpus and builds explicitly untrusted chat context. | Browser or compatible DBOPFS host | Existing DBOPFS semantics; manifest-last generations and bounded search only after the app calls it or wires its context builder. |
|
|
51
54
|
| [`DBOPFSWorker.js`](#dbopfsworkerjs) | worker | Serializes OPFS sync-handle read/write requests from a MessagePort. | Dedicated worker | Responses normalize to `{success,fileData?}` or `{error:{name,message}}`. |
|
|
52
55
|
| [`DevelopmentWorkspace.js`](#developmentworkspacejs) | esm | Provides bounded workspace inspection, context, setup task, and Node installer clients without arbitrary command execution. | Native bridge | Inputs normalized; provider result/error preserved. |
|
|
53
56
|
| [`DirectoryPicker.js`](#directorypickerjs) | esm | Wraps the provider-owned native directory chooser and normalizes selected/cancelled/error results. | Native bridge | Strict normalized selection and coded errors. |
|
|
57
|
+
| [`DocumentLexicalSearch.js`](#documentlexicalsearchjs) | esm | Provides dependency-free deterministic metadata/body ranking and bounded excerpts. | Cross-host | Frozen stable results with no storage, provider, or network side effects. |
|
|
54
58
|
| [`DocumentNavigation.js`](#documentnavigationjs) | esm | Binds document navigation, filtering, history, current-item reveal, and load initialization. | Browser / native WebView | Normalized filter/navigation state; DOM effects preserved. |
|
|
55
59
|
| [`Errors.js`](#errorsjs) | esm | Normalizes global errors/rejections, fingerprints and deduplicates incidents, persists a ledger, and performs bounded delivery. | Browser / native WebView hybrid | Incident records normalized; storage/mail failures isolated. |
|
|
56
60
|
| [`GifEncoder.js`](#gifencoderjs) | esm | Encodes indexed frames into a bounded animated GIF using palette mapping and LZW. | Cross-host | Normalized byte output and bounds. |
|
|
@@ -70,6 +74,7 @@ Apps import renderer ESM from `/arcane/modules/<file>`. Classic scripts, the OPF
|
|
|
70
74
|
| [`OllamaModelIdentifier.js`](#ollamamodelidentifierjs) | esm | Validates and canonicalizes the syntax of Ollama model identifiers without granting model admission. | Cross-host | Fully normalized string/boolean result. |
|
|
71
75
|
| [`OllamaSettings.js`](#ollamasettingsjs) | esm | Defines bounded runtime/service preference schemas and deterministic Arcane brain alias names. | Cross-host | Fully normalized settings/name contract. |
|
|
72
76
|
| [`OpenMeteoWeatherProvider.js`](#openmeteoweatherproviderjs) | esm | Searches and loads Open-Meteo data into frozen Arcane weather entities. | Browser / native WebView / server with fetch + cloud | Provider data normalized to entities; transport errors mixed. |
|
|
77
|
+
| [`PersistentAIChatSession.js`](#persistentaichatsessionjs) | esm | Adds explicit durable history/memory policy to bounded configured chat without changing DBOPFS or ChatEntity semantics. | Browser / native WebView with DBOPFS and configured chat | Live context commits atomically; persistence stays coherent across user/assistant/tool turns. |
|
|
73
78
|
| [`PreferenceStore.js`](#preferencestorejs) | esm | Loads and updates schema-defined app preferences through native storage with a narrow browser fallback. | Browser/native hybrid | Values normalized; only exact unsupported capability falls back. |
|
|
74
79
|
| [`QRCode.min.js`](#qrcodeminjs) | classic-script | Vendored QRCode generator for DOM, canvas, SVG, and image output. | Browser vendor script | Vendor-native. |
|
|
75
80
|
| [`Questionnaire.js`](#questionnairejs) | esm | Evaluates whether a one-time questionnaire prompt is due without performing the prompt. | Cross-host | Normalized fail-closed boolean. |
|
|
@@ -106,13 +111,52 @@ Provider-selectable chat, speech-to-text, text-to-speech, tool calling, structur
|
|
|
106
111
|
|
|
107
112
|
### Public surface
|
|
108
113
|
|
|
109
|
-
default `AI`;
|
|
114
|
+
default `AI`; read-only `providerRuntime`; `setAI()`, `configureProviders()`, `transitionAI()`,
|
|
115
|
+
`transitionProviders()`, `startProviders()`, `setSpeechMuted()`,
|
|
116
|
+
`streamRequest()`, `streamMessage()`, `fetchRequest()`, `fetch()`,
|
|
117
|
+
`streamTTS()`, `finishTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`,
|
|
118
|
+
`playAudio()`; consumes `user-entity-loaded` and `arcane-ollama-ready`,
|
|
119
|
+
installs `window.ai`, and emits `ai-ready`.
|
|
120
|
+
|
|
121
|
+
The provider-runtime methods keep LLM, STT, and TTS selection explicit. They do
|
|
122
|
+
not reinterpret one provider's failure as permission to select another
|
|
123
|
+
provider. `transitionAI()` and `transitionProviders()` are deliberate
|
|
124
|
+
cross-role transitions: each stops queued audio, unloads the current LLM, STT,
|
|
125
|
+
and TTS roles, then applies the replacement configuration. `transitionAI()`
|
|
126
|
+
returns aggregate runtime status; `transitionProviders()` returns the admitted
|
|
127
|
+
three-role route configuration. Selected `OPENAI` LLM/STT/TTS, `OLLAMA` LLM,
|
|
128
|
+
and admitted Core `LOCAL_SPEACH` STT/TTS legacy routes expose truthful
|
|
129
|
+
capability-only readiness through internal provider/2 adapters without probing,
|
|
130
|
+
downloading, or hiding a load. Cloud speech admission requires the selected
|
|
131
|
+
route, its model, a credential, and `fetch`; Core speech admission requires the
|
|
132
|
+
exact selected `Arcane.speech.transcribe` or `synthesize` method. `fetchRequest()`
|
|
133
|
+
keeps the selected provider's public response shape. Browser speech routes
|
|
134
|
+
translate the existing AI.js STT `{audio:Blob|File,mimeType,model}` and TTS
|
|
135
|
+
`{model,input,responseFormat,voice?,speed?}` requests at the provider boundary;
|
|
136
|
+
only WAV is accepted for the shared TTS result. TTS voice selection comes from
|
|
137
|
+
the exact selected provider/model catalog `defaultVoice`; a saved OpenAI voice
|
|
138
|
+
is used only by the selected OpenAI adapter and is never forwarded to another
|
|
139
|
+
provider route.
|
|
140
|
+
|
|
141
|
+
`startProviders({startMuted=true,startTranscription=false,signal=null}={})`
|
|
142
|
+
starts text chat without requesting an STT load by default; it does not undo an
|
|
143
|
+
already ready or independently loading role. Callers must opt into eager STT
|
|
144
|
+
startup with `startTranscription:true` or publish the explicit user activation
|
|
145
|
+
intent exposed by the shared speech component. `setSpeechMuted(false)` records
|
|
146
|
+
the shared unmuted lifecycle preference before loading TTS, while
|
|
147
|
+
`setSpeechMuted(true)` cancels active TTS work and unloads that role.
|
|
148
|
+
`fetchSTT(audioFile,responseHandler,signal)` propagates the caller-owned signal;
|
|
149
|
+
delivery suppression is guaranteed after abort, while underlying provider-stop
|
|
150
|
+
claims remain limited to that provider's cancellation contract.
|
|
110
151
|
|
|
111
152
|
Exact exports: `default`.
|
|
112
153
|
|
|
113
154
|
### Availability and normalization
|
|
114
155
|
|
|
115
|
-
**Browser + native bridge + cloud.** High-level chat/speech behavior is
|
|
156
|
+
**Browser + native bridge + cloud.** High-level chat/speech behavior is
|
|
157
|
+
normalized; provider diagnostics and media errors remain mixed. Transport:
|
|
158
|
+
AIProviderRuntime `arcane-ai-provider/2` routes, OpenAI HTTPS, Arcane.ollama,
|
|
159
|
+
Arcane.speech, and the Android WebView bridge. [Deep protocol details](protocols.md).
|
|
116
160
|
|
|
117
161
|
### Example
|
|
118
162
|
|
|
@@ -170,6 +214,72 @@ import * as module from '/arcane/modules/AIPreferenceTuple.js';
|
|
|
170
214
|
console.log(Object.keys(module));
|
|
171
215
|
```
|
|
172
216
|
|
|
217
|
+
## AIProviderRuntime.js
|
|
218
|
+
|
|
219
|
+
### Overview
|
|
220
|
+
|
|
221
|
+
Owns the portable provider-neutral runtime for independently selected LLM,
|
|
222
|
+
speech-to-text, and text-to-speech providers. The exported class documents the
|
|
223
|
+
shape, but application code uses the exported singleton returned by
|
|
224
|
+
`getAIProviderRuntime()`; direct construction fails with
|
|
225
|
+
`ARCANE_AI_RUNTIME_SINGLETON_REQUIRED`.
|
|
226
|
+
|
|
227
|
+
### Public surface
|
|
228
|
+
|
|
229
|
+
Exact exports: `AI_PROVIDER_PROTOCOL`, `AI_PROVIDER_RUNTIME_PROTOCOL`,
|
|
230
|
+
`AI_MODEL_AUTHORITY_PROTOCOL`, `AIProviderRuntime`, `aiProviderRuntime`, and
|
|
231
|
+
`getAIProviderRuntime`.
|
|
232
|
+
|
|
233
|
+
The singleton exposes provider registration, closed three-role configuration,
|
|
234
|
+
catalog and status inspection, `start()`, independent `load()`, `unload()`,
|
|
235
|
+
`dispose()`, and `cancel()` operations, plus `chat()`, `stream()`,
|
|
236
|
+
`transcribe()`, `synthesize()`, and `setSpeechMuted()`. Provider payloads must
|
|
237
|
+
be data-only; callbacks, accessors, symbols, cycles, and excessive nesting are
|
|
238
|
+
rejected at the provider boundary.
|
|
239
|
+
|
|
240
|
+
`start({startMuted=true,startTranscription=false,signal=null}={})` waits for
|
|
241
|
+
prior speech-state and role unload work, applies the requested initial mute
|
|
242
|
+
state, and returns the `startAIRuntime()` control handle
|
|
243
|
+
`{barrier,settled,cancel}`. Startup does not request selected STT unless the
|
|
244
|
+
caller explicitly opts in; it does not force an independently active STT role
|
|
245
|
+
back to unloaded. The barrier and settled promises describe provider-startup
|
|
246
|
+
readiness; cancellation remains cooperative through the supplied signal and
|
|
247
|
+
returned control.
|
|
248
|
+
|
|
249
|
+
Interactive requests are latest-request-wins per role. A newer valid request
|
|
250
|
+
that reaches admission aborts the active request, waits for its provider promise
|
|
251
|
+
to settle (or for bounded stream cleanup to be confirmed), and revalidates
|
|
252
|
+
ready/loaded/not-busy state before it starts. Rapid intermediate requests are
|
|
253
|
+
superseded, and their late results cannot restore or overwrite newer role state.
|
|
254
|
+
Promise settlement proves only that the provider's exposed request promise
|
|
255
|
+
completed; it does not by itself prove that underlying provider work stopped.
|
|
256
|
+
Provider-specific positive cancellation acknowledgement remains
|
|
257
|
+
provider-specific. Load and reconfiguration guards stay fail-closed while
|
|
258
|
+
request ownership is active.
|
|
259
|
+
|
|
260
|
+
### Availability and normalization
|
|
261
|
+
|
|
262
|
+
**Cross-host runtime with provider-specific execution.** Published SDK `0.2.1`
|
|
263
|
+
ships the browser-WASM LLM and browser Whisper/Kokoro adapters but predates the
|
|
264
|
+
legacy speech adapters described above. Current source also supplies the narrow
|
|
265
|
+
AI.js legacy OpenAI/Ollama/Core-speech adapters; other native, Core, or cloud
|
|
266
|
+
adapters may be supplied externally only when they implement the same
|
|
267
|
+
`arcane-ai-provider/2` boundary. A
|
|
268
|
+
provider must prove a matching `arcane-ai-model-authority/1` inspection before load.
|
|
269
|
+
`localOnly` routing fails closed; it never selects a cloud or non-local route as
|
|
270
|
+
a fallback. Role lifecycle and stream cleanup are normalized, while the
|
|
271
|
+
selected provider retains its own capability, permission, download, and model
|
|
272
|
+
requirements. [Deep protocol details](protocols.md#portable-ai-provider-runtime).
|
|
273
|
+
|
|
274
|
+
### Example
|
|
275
|
+
|
|
276
|
+
```javascript
|
|
277
|
+
import {getAIProviderRuntime} from '/arcane/modules/AIProviderRuntime.js';
|
|
278
|
+
|
|
279
|
+
const runtime = getAIProviderRuntime();
|
|
280
|
+
console.log(runtime.protocol, runtime.status());
|
|
281
|
+
```
|
|
282
|
+
|
|
173
283
|
## AIResponseLength.js
|
|
174
284
|
|
|
175
285
|
### Overview
|
|
@@ -218,6 +328,57 @@ import * as module from '/arcane/modules/AIResponseURLPolicy.js';
|
|
|
218
328
|
console.log(Object.keys(module));
|
|
219
329
|
```
|
|
220
330
|
|
|
331
|
+
## AIRuntimeState.js
|
|
332
|
+
|
|
333
|
+
### Overview
|
|
334
|
+
|
|
335
|
+
Publishes one sticky immutable state tree for `llm`, `stt`, and `tts`, transient
|
|
336
|
+
load/unload/dispose intents, and a startup-settlement report. It makes lifecycle
|
|
337
|
+
observable without exposing provider transports in application code.
|
|
338
|
+
|
|
339
|
+
### Public surface
|
|
340
|
+
|
|
341
|
+
Exact exports: `AI_RUNTIME_PROTOCOL`, `AI_RUNTIME_STATE_EVENT`,
|
|
342
|
+
`AI_RUNTIME_INTENT_EVENT`, `AI_RUNTIME_STARTUP_EVENT`, `AI_RUNTIME_ROLES`,
|
|
343
|
+
`AI_RUNTIME_STATES`, `aiRuntimeEvents`, `getAIRuntimeState()`,
|
|
344
|
+
`subscribeAIRuntimeState()`, `publishAIRuntimeRoleState()`,
|
|
345
|
+
`publishAIRuntimeRolesState()`, `requestAIRuntimeIntent()`,
|
|
346
|
+
`subscribeAIRuntimeIntents()`, and `startAIRuntime()`.
|
|
347
|
+
|
|
348
|
+
Each role record is exactly `{role,state,providerId,modelId,localOnly,loaded,
|
|
349
|
+
busy,operationId,progress,error}`.
|
|
350
|
+
`startAIRuntime({startMuted=true,startTranscription=false,signal})` returns
|
|
351
|
+
`{barrier,settled,cancel}`: `barrier` settles for text chat, while `settled`
|
|
352
|
+
covers every requested role. Muted startup does not request TTS, and STT startup
|
|
353
|
+
is opt-in so selection and state observation do not begin a transcription-model
|
|
354
|
+
load.
|
|
355
|
+
|
|
356
|
+
### Availability and normalization
|
|
357
|
+
|
|
358
|
+
**Cross-host state contract.** States are `unavailable`, `unloaded`, `loading`,
|
|
359
|
+
`ready`, `unloading`, `error`, and `disposed`. Revisions increase monotonically.
|
|
360
|
+
The events `arcane-ai-runtime-state`, `arcane-ai-runtime-intent`, and
|
|
361
|
+
`arcane-ai-runtime-startup-settled` normalize observation only: receiving one
|
|
362
|
+
does not grant a native capability, prove browser support, or load a provider.
|
|
363
|
+
`arcane-ai-runtime-startup-settled` reports the LLM/text-chat `barrier`.
|
|
364
|
+
Await the returned `handle.settled` promise for every role requested by that
|
|
365
|
+
startup; the all-role settlement has no separate public event.
|
|
366
|
+
|
|
367
|
+
### Example
|
|
368
|
+
|
|
369
|
+
```javascript
|
|
370
|
+
import {
|
|
371
|
+
getAIRuntimeState,
|
|
372
|
+
subscribeAIRuntimeState
|
|
373
|
+
} from '/arcane/modules/AIRuntimeState.js';
|
|
374
|
+
|
|
375
|
+
const unsubscribe = subscribeAIRuntimeState(snapshot => {
|
|
376
|
+
console.log(snapshot.roles.llm.state);
|
|
377
|
+
});
|
|
378
|
+
console.log(getAIRuntimeState().protocol);
|
|
379
|
+
unsubscribe();
|
|
380
|
+
```
|
|
381
|
+
|
|
221
382
|
## AnsiText.js
|
|
222
383
|
|
|
223
384
|
### Overview
|
|
@@ -659,7 +820,40 @@ Owns bounded in-memory AI turns, context construction, response-length instructi
|
|
|
659
820
|
|
|
660
821
|
### Public surface
|
|
661
822
|
|
|
662
|
-
default `ConfiguredAIChatSession`; `history()`, `clear()`, `send()`.
|
|
823
|
+
default `ConfiguredAIChatSession`; `history()`, `clear()`, `prepare()`, `send()`.
|
|
824
|
+
|
|
825
|
+
`new ConfiguredAIChatSession(options={})` admits exactly `chat`,
|
|
826
|
+
`contextBuilder`, `initialMessages`, `maxContextCharacters`,
|
|
827
|
+
`maxMessageCharacters`, `maxMessages`, `request`, `responseLength`, and
|
|
828
|
+
`systemPrompt`. `initialMessages` is an array of closed `user`, `assistant`, or
|
|
829
|
+
`tool` messages under the same message/context bounds. It excludes `system`,
|
|
830
|
+
allows exactly one structural assistant tool call, and requires a matching tool
|
|
831
|
+
result before another user turn or tool-call sequence; `systemPrompt` owns the
|
|
832
|
+
separate system message.
|
|
833
|
+
|
|
834
|
+
`prepare(input,{signal})` performs the complete bounded request but does not
|
|
835
|
+
commit history immediately. It returns frozen `{response,commit,rollback}`;
|
|
836
|
+
exactly one terminal settlement is permitted. `send()` is the convenience path
|
|
837
|
+
that prepares and then commits the turn.
|
|
838
|
+
|
|
839
|
+
An optional async `contextBuilder({input,history,signal})` receives a frozen
|
|
840
|
+
request snapshot and the same cancellation signal. Its returned context is
|
|
841
|
+
framed as untrusted data for only the current request and is never committed to
|
|
842
|
+
history.
|
|
843
|
+
|
|
844
|
+
An injected `chat(request)` may return the prior normalized session result or
|
|
845
|
+
exactly one non-stream OpenAI-compatible choice. The prior form preserves its
|
|
846
|
+
explicit `done` boolean; OpenAI-compatible choice normalization sets
|
|
847
|
+
`done:true`. Both return frozen
|
|
848
|
+
`{provider,model,message:{role:'assistant',content,tool_calls?},done,
|
|
849
|
+
doneReason,promptEvalCount,evalCount}`. Tool calls remain structural data and
|
|
850
|
+
are never executed. When `tool_calls` is present it must contain exactly one
|
|
851
|
+
valid structural call. A malformed response fails `AI_CHAT_INVALID_RESPONSE`;
|
|
852
|
+
caller cancellation is `AbortError` with code `AI_CHAT_ABORTED`. A new user
|
|
853
|
+
turn cannot bypass a pending structural tool call
|
|
854
|
+
(`AI_CHAT_TOOL_RESULT_REQUIRED`), a mismatched tool result fails
|
|
855
|
+
`AI_CHAT_INVALID_TOOL_MESSAGE`, and a second terminal settlement of one
|
|
856
|
+
prepared transaction fails `AI_CHAT_TRANSACTION_SETTLED`.
|
|
663
857
|
|
|
664
858
|
Exact exports: `default`.
|
|
665
859
|
|
|
@@ -670,9 +864,19 @@ Exact exports: `default`.
|
|
|
670
864
|
### Example
|
|
671
865
|
|
|
672
866
|
```javascript
|
|
673
|
-
import
|
|
867
|
+
import ConfiguredAIChatSession from '/arcane/modules/ConfiguredAIChatSession.js';
|
|
674
868
|
|
|
675
|
-
|
|
869
|
+
const session = new ConfiguredAIChatSession({
|
|
870
|
+
chat: async request => ({
|
|
871
|
+
provider: 'demo',
|
|
872
|
+
model: 'echo',
|
|
873
|
+
message: {
|
|
874
|
+
role: 'assistant',
|
|
875
|
+
content: `Received ${request.messages.length} messages.`
|
|
876
|
+
}
|
|
877
|
+
})
|
|
878
|
+
});
|
|
879
|
+
console.log(await session.send('Hello'));
|
|
676
880
|
```
|
|
677
881
|
|
|
678
882
|
## ConversationActionItems.js
|
|
@@ -843,6 +1047,96 @@ import * as module from '/arcane/modules/DBOPFS.js';
|
|
|
843
1047
|
console.log(Object.keys(module));
|
|
844
1048
|
```
|
|
845
1049
|
|
|
1050
|
+
## DBOPFSDocumentLibrary.js
|
|
1051
|
+
|
|
1052
|
+
### Overview
|
|
1053
|
+
|
|
1054
|
+
Stores one application-defined document corpus through an existing DBOPFS-style
|
|
1055
|
+
adapter, searches only a completed generation, and builds bounded context that
|
|
1056
|
+
is explicitly labeled untrusted. Construction performs no read, write, fetch,
|
|
1057
|
+
or search; applications call `bootstrap()` deliberately.
|
|
1058
|
+
|
|
1059
|
+
### Public surface
|
|
1060
|
+
|
|
1061
|
+
Exact exports: default and named `DBOPFSDocumentLibrary`,
|
|
1062
|
+
`createDBOPFSDocumentLibrary()`, and `normalizeDBOPFSDocumentSchema()`.
|
|
1063
|
+
|
|
1064
|
+
`new DBOPFSDocumentLibrary({concurrency,db,maxCorpusCharacters,
|
|
1065
|
+
maxDocumentCharacters,maxSearchCharacters,schema})` exposes `schema`,
|
|
1066
|
+
`bootstrap({files,onProgress,read,readFailurePolicy,signal})`,
|
|
1067
|
+
`search(query,{kinds,limit,signal,tags})`,
|
|
1068
|
+
`evaluate(query,{sources,read,maxCharacters,maxCorpusCharacters,
|
|
1069
|
+
maxScoringCharacters,maxDocumentCharacters?,kinds?,tags?,readFailurePolicy?,
|
|
1070
|
+
onProgress?,signal?})`,
|
|
1071
|
+
`buildContext(query,{limit,maxCharacters,maxDocumentCharacters,signal})`, and
|
|
1072
|
+
`createContextBuilder({limit,maxCharacters,maxDocumentCharacters})`.
|
|
1073
|
+
|
|
1074
|
+
`evaluate()` requires `sources`, `read`, `maxCharacters`,
|
|
1075
|
+
`maxCorpusCharacters`, and `maxScoringCharacters`. It filters source metadata
|
|
1076
|
+
before calling
|
|
1077
|
+
`read(source,{maxCharacters,maxCorpusCharacters,ordinal,signal})`, never accepts a
|
|
1078
|
+
source body as implicit authority, and never persists a caller-owned body.
|
|
1079
|
+
`maxDocumentCharacters` defaults to the smaller instance/output bound.
|
|
1080
|
+
|
|
1081
|
+
### Availability and normalization
|
|
1082
|
+
|
|
1083
|
+
**Browser or compatible host with an injected DBOPFS adapter.** The adapter
|
|
1084
|
+
keeps the existing `get`, `set`, `getAllKeys`, and `delete` method names; Node
|
|
1085
|
+
can use the same class only through an explicitly imported runtime module and a
|
|
1086
|
+
compatible storage adapter; SDK `0.2.1` publishes no Node package subpath or
|
|
1087
|
+
Node storage implementation for it. Bootstrap uses a bounded concurrent
|
|
1088
|
+
generation, commits its manifest last, cleans partial data on failure, and
|
|
1089
|
+
rejects case-colliding IDs. Search
|
|
1090
|
+
returns `{failures,matches,total}` so one corrupt record does not become a false
|
|
1091
|
+
complete result. `bootstrap()` defaults to rejecting read failure; the explicit
|
|
1092
|
+
`readFailurePolicy:'preserve-readable'` mode returns partial-success
|
|
1093
|
+
`readCoverage`. `evaluate()` also defaults to rejecting a source-read failure;
|
|
1094
|
+
its explicit `preserve-readable` mode instead ranks the readable records and
|
|
1095
|
+
returns partial `failures` plus `coverage` in the evaluation result (not
|
|
1096
|
+
bootstrap's `readCoverage`). It reads a caller-owned source list without
|
|
1097
|
+
persisting its bodies and returns frozen `{authority:'sources',characters,
|
|
1098
|
+
coverage,documents,failures,limits,query,scoringTruncated,text,truncated}`.
|
|
1099
|
+
Read failure remains `DBOPFS_DOCUMENT_READ_FAILED`; invalid public input uses
|
|
1100
|
+
`DBOPFS_DOCUMENT_INVALID`, invalid integer budgets use
|
|
1101
|
+
`DBOPFS_DOCUMENT_INVALID_LIMIT`, and a preserved read failure without a usable
|
|
1102
|
+
source code is reported as `failures[].code:'DBOPFS_DOCUMENT_ERROR'`.
|
|
1103
|
+
Cancellation is `AbortError` with code `DBOPFS_DOCUMENT_ABORTED`. Construction
|
|
1104
|
+
does not search.
|
|
1105
|
+
When an application explicitly supplies the library's context builder, each
|
|
1106
|
+
prepared chat send performs that bounded retrieval.
|
|
1107
|
+
|
|
1108
|
+
### Example
|
|
1109
|
+
|
|
1110
|
+
```javascript
|
|
1111
|
+
import {
|
|
1112
|
+
createDBOPFSDocumentLibrary
|
|
1113
|
+
} from '/arcane/modules/DBOPFSDocumentLibrary.js';
|
|
1114
|
+
|
|
1115
|
+
const documents = createDBOPFSDocumentLibrary({
|
|
1116
|
+
db: globalThis.dbopfs,
|
|
1117
|
+
schema: {id: 'help', version: '1', table: 'help_documents'}
|
|
1118
|
+
});
|
|
1119
|
+
async function replaceHelpCorpusAfterUserChoice() {
|
|
1120
|
+
await documents.bootstrap({files: [{
|
|
1121
|
+
id: 'welcome',
|
|
1122
|
+
path: 'welcome.md',
|
|
1123
|
+
title: 'Welcome',
|
|
1124
|
+
body: 'Arcane applications are portable.'
|
|
1125
|
+
}]});
|
|
1126
|
+
console.log(await documents.search('portable'));
|
|
1127
|
+
|
|
1128
|
+
const preview = await documents.evaluate('portable', {
|
|
1129
|
+
sources: [{id:'draft', path:'draft.md', title:'Draft'}],
|
|
1130
|
+
read: async source => source.id === 'draft' ? 'Portable app notes.' : '',
|
|
1131
|
+
maxCharacters: 2048,
|
|
1132
|
+
maxCorpusCharacters: 4096,
|
|
1133
|
+
maxDocumentCharacters: 512,
|
|
1134
|
+
maxScoringCharacters: 512
|
|
1135
|
+
});
|
|
1136
|
+
console.log(preview.coverage, preview.text);
|
|
1137
|
+
}
|
|
1138
|
+
```
|
|
1139
|
+
|
|
846
1140
|
## DBOPFSWorker.js
|
|
847
1141
|
|
|
848
1142
|
### Overview
|
|
@@ -913,6 +1207,48 @@ import * as module from '/arcane/modules/DirectoryPicker.js';
|
|
|
913
1207
|
console.log(Object.keys(module));
|
|
914
1208
|
```
|
|
915
1209
|
|
|
1210
|
+
## DocumentLexicalSearch.js
|
|
1211
|
+
|
|
1212
|
+
### Overview
|
|
1213
|
+
|
|
1214
|
+
Provides deterministic, dependency-free metadata/body ranking and bounded
|
|
1215
|
+
context excerpts for caller-owned document records.
|
|
1216
|
+
|
|
1217
|
+
### Public surface
|
|
1218
|
+
|
|
1219
|
+
Exact exports: `DOCUMENT_SEARCH_FIELD_ORDER`, default and named
|
|
1220
|
+
`DocumentLexicalSearch`, `createDocumentLexicalIndex()`,
|
|
1221
|
+
`documentContextExcerpt()`, `documentSearchTokens()`,
|
|
1222
|
+
`normalizedDocumentSearchText()`, `scoreDocumentBody()`, and
|
|
1223
|
+
`scoreDocumentLexicalIndex()`.
|
|
1224
|
+
|
|
1225
|
+
`new DocumentLexicalSearch(records,{maxResults=20})` exposes
|
|
1226
|
+
`rank(query,{kinds,tags})` and `search(query,{kinds,limit,tags})`.
|
|
1227
|
+
|
|
1228
|
+
### Availability and normalization
|
|
1229
|
+
|
|
1230
|
+
**Cross-host.** Indexing and search are in-process only. Text, tags, kinds,
|
|
1231
|
+
scores, field ordering, truncation, and tie-breaking are normalized into frozen
|
|
1232
|
+
records. This module performs no storage, network, model, Core, or DOM action.
|
|
1233
|
+
The caller decides whether a result is merely displayed or explicitly injected
|
|
1234
|
+
as untrusted AI context.
|
|
1235
|
+
|
|
1236
|
+
### Example
|
|
1237
|
+
|
|
1238
|
+
```javascript
|
|
1239
|
+
import DocumentLexicalSearch from '/arcane/modules/DocumentLexicalSearch.js';
|
|
1240
|
+
|
|
1241
|
+
const search = new DocumentLexicalSearch([{
|
|
1242
|
+
id: 'welcome',
|
|
1243
|
+
path: 'welcome.md',
|
|
1244
|
+
title: 'Welcome',
|
|
1245
|
+
body: 'Arcane applications are portable.',
|
|
1246
|
+
kind: 'guide',
|
|
1247
|
+
tags: ['intro']
|
|
1248
|
+
}]);
|
|
1249
|
+
console.log(search.search('portable', {limit: 5}));
|
|
1250
|
+
```
|
|
1251
|
+
|
|
916
1252
|
## DocumentNavigation.js
|
|
917
1253
|
|
|
918
1254
|
### Overview
|
|
@@ -1095,7 +1431,15 @@ Exact exports: `availabilityFromReport`, `createLocalAIReadinessController`.
|
|
|
1095
1431
|
|
|
1096
1432
|
### Availability and normalization
|
|
1097
1433
|
|
|
1098
|
-
|
|
1434
|
+
`availabilityFromReport()` returns `true` only for a slot whose local
|
|
1435
|
+
requirement is explicitly `required:true` and whose report is explicitly
|
|
1436
|
+
`ready:true`. Missing and non-local-required slots remain false: this projection
|
|
1437
|
+
does not attest provider registration, selection, credentials, browser speech
|
|
1438
|
+
authority, or model load state. Components must preserve selected sticky
|
|
1439
|
+
`AIRuntimeState` roles as the readiness authority.
|
|
1440
|
+
|
|
1441
|
+
**Browser/native hybrid.** Normalized controller state and change events.
|
|
1442
|
+
Transport: LocalAIReadiness + component events. [Deep protocol details](protocols.md).
|
|
1099
1443
|
|
|
1100
1444
|
### Example
|
|
1101
1445
|
|
|
@@ -1369,6 +1713,64 @@ import * as module from '/arcane/modules/OpenMeteoWeatherProvider.js';
|
|
|
1369
1713
|
console.log(Object.keys(module));
|
|
1370
1714
|
```
|
|
1371
1715
|
|
|
1716
|
+
## PersistentAIChatSession.js
|
|
1717
|
+
|
|
1718
|
+
### Overview
|
|
1719
|
+
|
|
1720
|
+
Composes `ConfiguredAIChatSession` with one `ChatEntity` so every user,
|
|
1721
|
+
assistant, and structural tool-result turn has an explicit durable-persistence
|
|
1722
|
+
choice. It preserves the existing DBOPFS method names and ChatEntity memory
|
|
1723
|
+
semantics; it does not define a new storage protocol.
|
|
1724
|
+
|
|
1725
|
+
### Public surface
|
|
1726
|
+
|
|
1727
|
+
Exact exports: default and named `PersistentAIChatSession` plus
|
|
1728
|
+
`createPersistentAIChatSession()`.
|
|
1729
|
+
|
|
1730
|
+
Constructor and factory options are `{chat,chatEntity,chatFileName,
|
|
1731
|
+
contextBuilder,loadExisting,maxContextCharacters,maxMessageCharacters,
|
|
1732
|
+
maxMessages,memory,request,responseLength,systemPrompt}`. Public members are
|
|
1733
|
+
static `create()`, getters `chatEntity` and `fileName`, and `ready()`,
|
|
1734
|
+
`history()`, `settleMemory()`, and `send(input)`.
|
|
1735
|
+
`ready()` waits for initialization and resolves the same session instance.
|
|
1736
|
+
|
|
1737
|
+
`send()` accepts `{message:{content,role:'user'|'tool',tool_call_id?,persist},
|
|
1738
|
+
response:{persist},signal?}`. Message and response persistence must match.
|
|
1739
|
+
`persist:false` still commits the coherent turn to live bounded model context,
|
|
1740
|
+
but not to durable ChatEntity history or memory. A structural tool result must
|
|
1741
|
+
use the persistence choice captured by its matching assistant tool call.
|
|
1742
|
+
|
|
1743
|
+
### Availability and normalization
|
|
1744
|
+
|
|
1745
|
+
**Browser or native WebView with ChatEntity/DBOPFS and a configured chat
|
|
1746
|
+
function.** The default chat calls normalized `Arcane.ai.chat()`; callers can
|
|
1747
|
+
inject the browser-WASM controller, another provider-neutral adapter, or a
|
|
1748
|
+
cloud chat function. There is no automatic provider or storage fallback.
|
|
1749
|
+
Context builders are request-only, and document context remains explicitly
|
|
1750
|
+
untrusted. Errors include `AI_CHAT_BUSY`, `AI_CHAT_TOOL_RESULT_REQUIRED`,
|
|
1751
|
+
`AI_CHAT_INVALID_TOOL_MESSAGE`, and `AI_CHAT_INCOHERENT_PERSISTENCE`.
|
|
1752
|
+
|
|
1753
|
+
### Example
|
|
1754
|
+
|
|
1755
|
+
```javascript
|
|
1756
|
+
import {
|
|
1757
|
+
createPersistentAIChatSession
|
|
1758
|
+
} from '/arcane/modules/PersistentAIChatSession.js';
|
|
1759
|
+
|
|
1760
|
+
async function sendPersistentSupportTurnAfterUserChoice(documents) {
|
|
1761
|
+
const session = await createPersistentAIChatSession({
|
|
1762
|
+
chatFileName: 'support.jsonl',
|
|
1763
|
+
loadExisting: true,
|
|
1764
|
+
contextBuilder: documents.createContextBuilder()
|
|
1765
|
+
});
|
|
1766
|
+
const response = await session.send({
|
|
1767
|
+
message: {role: 'user', content: 'Summarize the documents.', persist: true},
|
|
1768
|
+
response: {persist: true}
|
|
1769
|
+
});
|
|
1770
|
+
console.log(response.message.content);
|
|
1771
|
+
}
|
|
1772
|
+
```
|
|
1773
|
+
|
|
1372
1774
|
## PreferenceStore.js
|
|
1373
1775
|
|
|
1374
1776
|
### Overview
|
|
@@ -1650,9 +2052,21 @@ Exact exports: `MAX_SPEECH_CHARACTERS`, `MAX_SPEECH_CHUNKS`, `MAX_SPEECH_INPUT`,
|
|
|
1650
2052
|
### Example
|
|
1651
2053
|
|
|
1652
2054
|
```javascript
|
|
1653
|
-
import
|
|
2055
|
+
import SpeechPlayback from '/arcane/modules/SpeechPlayback.js';
|
|
1654
2056
|
|
|
1655
|
-
|
|
2057
|
+
const audio = document.body.appendChild(document.createElement('audio'));
|
|
2058
|
+
audio.controls = true;
|
|
2059
|
+
const speech = new SpeechPlayback({audio});
|
|
2060
|
+
const speakButton = document.body.appendChild(document.createElement('button'));
|
|
2061
|
+
speakButton.type = 'button';
|
|
2062
|
+
speakButton.textContent = 'Speak';
|
|
2063
|
+
speakButton.addEventListener('click', async () => {
|
|
2064
|
+
await speech.prepare({
|
|
2065
|
+
key: 'ready',
|
|
2066
|
+
parts: ['Arcane is ready.'],
|
|
2067
|
+
autoplay: true
|
|
2068
|
+
});
|
|
2069
|
+
});
|
|
1656
2070
|
```
|
|
1657
2071
|
|
|
1658
2072
|
## StaticDocumentCatalog.js
|