On this page
Use this browser-only entrypoint when an application deliberately owns a local
GGUF model authority and wants provider-neutral LLM lifecycle, chat, streaming,
cancellation, and structural tool-call results without an Arcane Core host.
For a remote request with an explicit model and key, use
TWiN Cloud. Applications using an Arcane Core host can use
the native AI contracts through
globalThis.Arcane.ai. This page covers local inference in the browser.
The wiring example assumes a scaffolded or materialized Arcane application
using its installed SDK and managed browser import map. Browser modules use
the published arcane-os exports below; DBOPFS still requires a browser host.
See browser runtime delivery before
using the example in a custom host or bundler.
import DBOPFS from 'arcane-os/modules/DBOPFS.js';
import {
createArcaneAI,
createBrowserModelSource,
createBrowserWasmLlmProvider,
createDbopfsModelStore
} from 'arcane-os/ai/browser-wasm';
const MODEL = {
id:'my-reviewed-model',
files:[{
name:'model-q4-00001-of-00002.gguf',
url:'https://models.example/revisions/4f7c/model-q4-00001-of-00002.gguf'
},{
name:'model-q4-00002-of-00002.gguf',
url:'https://models.example/revisions/4f7c/model-q4-00002-of-00002.gguf'
}]
};
const dbopfs = globalThis.dbopfs || new DBOPFS({applicationId:'my-app'});
await dbopfs.readyPromise;
const source = createBrowserModelSource(MODEL);
const store = createDbopfsModelStore({dbopfs});
const provider = createBrowserWasmLlmProvider({sources:[source], store});
const ai = createArcaneAI({
provider,
loadPolicy:'manual'
});
// Put this behind an explicit user action: it can download every declared file.
async function loadReviewedModel() {
return ai.load({threads:1, contextTokens:4096});
}
The browser-WASM runtime closure packages the upstream
@wllama/wllama 3.6.0 ESM and WebAssembly runtime plus the Wllama and
llama.cpp MIT license texts. It
packages no model weights, default model catalog, CDN fallback, native
provider, speech synthesis, or transcription. The sibling
arcane-os/ai/browser-speech entrypoint supplies speech
provider mechanisms but still no runtime/model content. Callers supply every
model source. Each file needs only a name and HTTPS URL. A positive optional
bytes value supplies observational progress and transport-planning metadata;
it never validates, admits, identifies, or decides cache reuse for content.
Mobile and desktop settings
getBrowserDeviceClass(navigatorObject = globalThis.navigator), exported from
arcane-os/browser-device, returns mobile or desktop for choosing
application-owned settings. Mobile includes a positive mobile client hint,
Android or iOS platform information, mobile user-agent identifiers, and iPadOS
reporting a Mac platform with multiple touch points. Missing or unrecognized
identity defaults to desktop; a browser hiding all mobile hints may therefore
receive that profile. This classification is a settings hint, not evidence of
GPU capability, available memory, or model readiness.
Keep complete mobile and desktop load profiles at the application owner and
pass the selected profile as createBrowserWasmLlmProvider({loadDefaults}).
Choose it once before provider creation so catalog inspection and model loading
use the same settings. The helper reads identity synchronously and starts no
GPU request, model operation, listener, or viewport-dependent reload. Its
dependency-free entrypoint does not import the inference runtime. Profile
selection does not alter prompts, documents, history, or output limits.
CPU selection
Set loadDefaults:{gpuLayers:0} when creating the provider, or pass
gpuLayers:0 to ai.load() or provider.load(), to run the selected model on
CPU through the packaged Wllama WebAssembly runtime. CPU selection skips
WebGPU capability checks, adapter initialization, and GPU execution reporting.
It uses the same complete model sources, cache, request, streaming, and
cancellation contracts. Existing context, batch, micro-batch, and thread
settings remain independently configurable.
Omitting gpuLayers preserves full GPU offload (99999). CPU is an explicit
selection; a failed GPU load does not silently switch to CPU.
Lifecycle at a glance
createArcaneAI() owns one LLM controller. Its default loadPolicy is
on-demand; the first request may download and initialize the model. Use
manual when a user action, resource review, or progress UI must precede load.
| Operation | Result |
|---|---|
ai.status() |
Mutable {llm: status} snapshot. |
ai.load(options) |
Flat LLM status after load. |
ai.llm.chat(request) / ai.fetchRequest(request) |
Validated OpenAI-like completion. |
ai.llm.stream(request) |
Mutable async-iterator handle with result and cancel(reason). |
ai.streamRequest(request) |
Consumes the stream, publishes every choice's ordinary content/reasoning in provider order, and returns complete JSON text for a multi-choice terminal completion, one structural-call array for selected tool output, or ordinary single-choice text. |
ai.createChatSession(options) |
Asynchronously resolves Promise<PersistentAIChatSession> bound to this exact controller; caller-supplied ai and chat are rejected. |
ai.unload() |
Cancels active work, releases the Wllama session, and returns flat unloaded status; the DBOPFS cache remains. |
ai.dispose() |
Permanently disposes the controller; explicit store.remove(source) is required to delete cached model content. |
The controller emits statechange and progress through
addEventListener(), removeEventListener(), or on(). Event detail is the
current mutable status snapshot. Provider states are unloaded, loading, ready,
unloading, and error.
Browser-WASM model loads report cache-check, load, download, and initialize
phases. Cache-read and download records preserve the ordered model-file fields completed,
total, and unit:'files'. Their ordered members records contain each file's
name, committed-part completed, total, and unit:'shards'. A streaming
response has total:null until its end is observed; completion then supplies
the actual committed-part count. Reading saved parts reports phase:'load',
cached:true, and the known saved-part total before the first read and after
each part is opened. An existing HTTP Range plan likewise supplies its actual
shard total. Previously complete members identify state:'cached'; their
per-member records remain cache reads even if another member is downloading.
A fully cached activation emits no download phase. activeTransfers is the current transfer-worker count,
transferLimit is the selected concurrency, and transferMode identifies
probing, files, ranges, or single. No byte progress, rate, or estimated
completion time is produced. Closed-part and lifecycle changes publish promptly;
the existing 250 ms heartbeat retains the current semantic state.
Initialization keeps phase:'initialize' and reports a stage and a readable
message from the packaged runtime's existing log signals: runtime startup,
engine startup, model metadata, graphics-device initialization, model weights,
inference context, and inference graph. Warmup is shown only if the runtime
actually reports it; the default upstream log level may omit that signal.
These messages do not change the runtime's log level or replace its complete
diagnostic output.
Initialization has total:null and omits completed and unit, so its progress
bar is indeterminate. Cached or downloaded file completion is not activation completion.
The metadata tensor count and GPU layer assignment are descriptive only:
upstream reports assigned layers before model-weight loading has finished.
The pinned runtime does not expose a measured overall initialization fraction
or a shader-compilation completion count. Readiness requires the load operation
to resolve, Wllama to report the model loaded, and its public
getLoadedContextInfo() result to report success:true. A failed model context
rejects loading with ARCANE_AI_LOAD_FAILED, releases the owned session, and
leaves the provider in error with loaded:false before inference can begin.
While a load remains active, the provider repeats its current record every five
seconds with heartbeat:true and an updated elapsedMs. During initialization,
phaseElapsedMs measures time in the current stage and activityElapsedMs
measures time since the most recent runtime log signal. A signal without a
recognized stage updates activity time without triggering another UI render.
The shared chat loading panel shows the observed stage and those timings. A
heartbeat only shows that the provider's timer ran; it does not establish
runtime advancement, estimate a completion time, or advance the progress bar.
Late runtime progress is ignored after cancellation or supersession.
The DBOPFS store uses one bounded transfer axis. Ordered multi-file GGUF sets
download several members concurrently and preserve completed shards across a
retry. Each active member negotiates HTTP Range support. A split member uses at
most one Range worker while a single-member source may use up to
downloadConcurrency Range workers (four by default), so file and Range
workers are never multiplied. A usable total from Content-Range or the
optional descriptor bytes divides that member into deterministic contiguous
parts of roughly 4 MB each, up to 4,096 parts. Each exact completed part is
committed separately in OPFS, so retry or refresh fetches only the small
in-flight parts plus any other missing parts; the ordered parts are exposed to
Wllama as one logical model Blob. Ordinary full responses, including unknown
content lengths and single-file models, also stream directly into ordered OPFS
parts. Model data is not accumulated in one JavaScript buffer. Range offsets
and physical part framing remain storage/transport-local; progress describes
completed files and parts.
Model selection, optional hardening, and cache
The canonical model descriptor is
{id, files:[{name?,url,bytes?},...]}. The ordered files array is nonempty;
names and URLs are unique. Each URL must be absolute HTTPS without credentials
or a fragment. An optional positive safe-integer bytes value is used only for
HTTP Range planning. Missing or unusable metadata never blocks a
download, and a declared value is not a content-length check.
Fetch follows HTTPS redirects and records the requested and final HTTPS URL. A redirect that leaves HTTPS is rejected as an unavoidable transport-safety boundary.
App, provider/model-binding, and load-operation options may use the same plain-JavaScript shape:
const result = {security:{secure:true}};
The SDK default is secure:false. Omitted security leaves ordinary model
loading fully functional. secure:true records only an
application-selected hardening intent in this development contract. It does
not activate the historical checking machinery; that implementation remains
disabled and requires a separate review with the user before it can run.
Neither path performs byte-limit, hash, digest, content-identity, freeze, or
admission work. Observational byte counting and exact HTTP Range framing remain
transport-local. A load succeeds only after Wllama reports that the model is
loaded.
The DBOPFS adapter commits ordered parts independently and exposes only a
complete ordered model set as a cache hit. Existing whole-file and Range-part
caches remain readable without migration. Closed parts survive interrupted
writes; a source without supported resume starts that member's next transfer
from its beginning. Complete peer members remain cached.
load({offline:true}) never performs a model request; it uses a compatible
cached entry or rejects with ARCANE_AI_MODEL_OFFLINE_MISS.
The same store exposes fetchResource(input, options) for SDK-owned browser
model loaders. It returns {file,status,statusText,headers,url,redirected}
after storing the complete response through the shared part owner. Ordinary
Fetch request options, signal, and semantic onProgress are supported.
The browser decision model accepts this store through its additive store
option; resource acquisition stays with the SDK while model selection stays
with the application. See browser decisions.
const {security, cache} = ai.status().llm;
console.log(security?.secure === true); // false when the optional field is absent
console.log(cache);
Applications remain responsible for model selection and license compliance.
localOnly:true describes inference after load. It does not mean a cache miss
cannot download. Source downloads use CORS, omit credentials and referrer,
disable HTTP caching, and honor AbortSignal.
After a GPU model loads, its existing Worker reports the adapter it selected.
The runtime retains that adapter in evidence().webgpu.adapter, including
optional browser-reported type and isFallbackAdapter fields. This reads
the loaded Worker's metadata once; it does not request another adapter.
Missing fields remain unknown. Cancellation also cancels the metadata wait;
an unavailable observation is logged without rejecting an otherwise loaded model.
For GPU loads on Windows desktop Chromium browsers, an explicitly reported
integrated GPU, CPU, or fallback adapter triggers one GPU-only browser alert
per page session.
The alert names the selected adapter and Force High Performance GPU
(#force-high-performance-gpu), conditional on the computer also having a
discrete GPU. It contains the address to paste manually and asks the user to
save their work and completely close and reopen the browser after changing
the flag. It does not open a window or navigate to an internal browser page.
Discrete adapters and unknown adapter classes do not trigger the alert.
An identified Chrome, Microsoft Edge, Brave, Opera, or Vivaldi receives its own
chrome://, edge://, brave://, opera://, or vivaldi:// flags address.
Other detected Chromium browsers receive
about://flags/#force-high-performance-gpu with neutral browser wording.
Only the current browser's address appears. Firefox, Safari, non-Windows
platforms, and mobile browsers receive no flag notice. The alert contains no
NPU guidance or unrelated flags. The Profile browser-ai-setup component
provides Copy controls for its browser addresses.
An adapter vendor or name does not establish its GPU class, and
powerPreference: "high-performance" is a request hint rather than proof of
the selected hardware. Chromium's optional adapter type is a
developer feature;
the standard API does not always expose integrated or discrete classification.
The Profile says Already using the performance GPU. for an explicitly
reported discrete GPU. Missing classification shows GPU available. and
remains unconfirmed. On supported Windows desktop Chromium browsers, Profile
keeps its Copy GPU flag address control available regardless of adapter
classification or detection outcome. This Profile control is separate from
the provider's conditional one-time alert described above.
The browser does not expose the flag's current value or a reliable machine-wide
GPU count, and a discrete adapter does not prove it is the fastest available.
See Chrome's GPU selection guidance.
Streaming, cancellation, and tools
async function streamLocalSummaryAfterUserChoice(cancelButton) {
// The selected browser-WASM model must already be ready.
if (!cancelButton?.addEventListener) {
throw new TypeError('A cancel button is required.');
}
const abort = new AbortController();
const stream = ai.llm.stream({
localOnly:true,
signal:abort.signal,
messages:[{role:'user', content:'Summarize this text.'}]
});
const cancel = () => abort.abort('user cancelled');
cancelButton.addEventListener('click', cancel, {once:true});
try {
for await (const chunk of stream) renderChunk(chunk);
const completion = await stream.result;
renderCompletion(completion);
} catch (error) {
if (error?.code !== 'ARCANE_AI_REQUEST_ABORTED') throw error;
renderCancelled();
} finally {
cancelButton.removeEventListener('click', cancel);
}
}
An active cancellation rejects as ARCANE_AI_REQUEST_ABORTED. Requests are
serialized; provider status exposes busy and queued. Supported request
generation fields include temperature, top-K, top-P, min-P, repeat penalty,
and seed. Load settings separately include
contextTokens, batchTokens, microBatchTokens, threads, and GPU-layer
count. The shipped runtime defaults to gpuLayers:99999 for full GPU offload;
gpuLayers:0 explicitly selects CPU. WebGPU/full-offload availability applies
only to the GPU route, which has no automatic CPU fallback. Secure context
remains a browser platform requirement;
cross-origin isolation and coarse hardware fields remain observations.
Tool definitions, tool choice, parallel-tool-call preference, and JSON or JSON
Schema structured-output requests are passed to Wllama. Returned tool calls are
validated and surfaced as structural data. Every function declaration requires
parameters.properties.message with {type:'string',minLength:1} and includes
message in its required list. Every emitted argument JSON object contains
that nonempty user-facing progress or next-step text; exact IDs, names, and
argument strings remain intact. The SDK never invokes a handler or executes a
tool. Application code chooses whether to execute, then records the exact
matching executed, declined, cancelled, or not-executed role:'tool' result
with nonblank user-facing content before another user turn. High-level sessions accept per-turn request options,
so visibility-only consumers can select toolChoice:'none' for the continuation
after a not-executed result without calling Wllama directly. Streaming sessions
buffer a structural call until its exact ID, type, name, and argument string
match the terminal response; omission or divergence rejects with
AI_CHAT_STREAM_TOOL_CALL_MISMATCH before the call is published or persisted.
Ordinary iteration exposes only text/reasoning chunks; raw structural deltas
remain internal until the complete terminal result validates. Explicit
onResponse or inspection consumers retain the complete raw terminal response.
Stream selected tool text
Both AI.streamRequest() and this browser controller's streamRequest() accept
toolText:{name,field} with onToolText(text,call,displayId). Select the exact
tool name and one root-level string argument. The callback receives newly
decoded text in arrival order, preserving whitespace and JSON string escapes as
their original characters. Its call record is
{id,name,field,index,choiceIndex}: the actual normalized tool-call ID, matching
tool name, selected field, call index within the response choice, and choice
index. Delivery waits until the matching name and ID are known. displayId is
the request's existing M-${id} display ID.
This callback is distinct from ordinary onChunk; display the text in the
corresponding tool turn and keep ordinary prose in its own existing turn.
onToolCall still receives only the complete normalized call after terminal
settlement. The text callback does not execute a tool, rewrite arguments, or
retain a transcript. The application owns the completed call's execution and
stores its complete visible result once through its normal history path.
If a provider supplies arguments only at completion, the callback runs only
when that actual complete response arrives. Repeated terminal snapshots do not
replay text already emitted. Callback errors reach the request owner, and a
cancelled or superseded request stops further text delivery.
For example, an application that already supplies a closing-report tool can connect its existing display operations without parsing provider protocol:
import {
formatConversationClosingReportText
} from 'arcane-os/conversation-closing-report';
async function streamClosingReport(ai, messages, closingTool, view, signal) {
return ai.streamRequest(
{
messages,
tools:[closingTool],
signal,
toolText:{name:closingTool.function.name, field:'final_message'},
onChunk:function appendOrdinaryText(text, displayId, thinking) {
return view.appendAssistantText(text, displayId, thinking);
},
onToolText:function appendClosingText(text, call, displayId) {
return view.appendToolText(
formatConversationClosingReportText(text),
call.id,
displayId
);
}
}
);
}
The application supplies view and the existing closingTool; those are not
SDK exports. The formatter applies the same existing &, <, and > escaping
used for the complete closing report, including whitespace-only chunks. The
returned terminal call remains available to the application's normal tool
execution and persistence path. These options do not change the tool schema,
tool choice, or authored request content. Omitting toolText creates no text
observer. Invalid selection or callback input throws TypeError; malformed
selected argument text reports ARCANE_AI_TOOL_TEXT_INVALID.
Errors and unavailable states
Invalid configuration can throw TypeError or RangeError. Operational
failures expose a stable .code; the internal error class is not exported.
Handle the narrow code needed by the current operation and treat other failures
as unavailable.
| Area | Stable codes |
|---|---|
| Source and download | ARCANE_AI_MODEL_SOURCE_INVALID, ARCANE_AI_MODEL_SOURCE_UNAVAILABLE, ARCANE_AI_MODEL_DOWNLOAD_FAILED, ARCANE_AI_MODEL_REDIRECT_BLOCKED |
| Cache and storage | ARCANE_AI_MODEL_CACHE_REJECTED, ARCANE_AI_MODEL_OFFLINE_MISS, ARCANE_AI_STORAGE_UNAVAILABLE, ARCANE_AI_STORAGE_READ_FAILED, ARCANE_AI_STORAGE_DELETE_FAILED |
| Lifecycle | ARCANE_AI_UNAVAILABLE, ARCANE_AI_NOT_READY, ARCANE_AI_MODEL_NOT_READY, ARCANE_AI_LOAD_FAILED, ARCANE_AI_UNLOAD_FAILED, ARCANE_AI_DISPOSE_FAILED, ARCANE_AI_DISPOSED, ARCANE_AI_OPERATION_SUPERSEDED |
| Requests | ARCANE_AI_REQUEST_ABORTED, ARCANE_AI_REQUEST_FAILED, ARCANE_AI_RUNTIME_BUSY, ARCANE_AI_INVALID_PROVIDER_RESULT, ARCANE_AI_TOOL_CALL_INVALID, ARCANE_AI_TOOL_MESSAGE_REQUIRED, ARCANE_AI_INVALID_TOOL_MESSAGE, ARCANE_AI_TOOL_RESULT_REQUIRED, ARCANE_AI_LOCAL_ONLY_UNAVAILABLE, ARCANE_AI_ADAPTER_PROTOCOL_MISMATCH |
| Persistent sessions | AI_CHAT_INVALID_TOOL_CALL, AI_CHAT_INVALID_TOOL_MESSAGE, AI_CHAT_TOOL_MESSAGE_REQUIRED, AI_CHAT_TOOL_RESULT_REQUIRED, AI_CHAT_INCOHERENT_PERSISTENCE, AI_CHAT_STREAM_TOOL_CALL_MISMATCH, AI_CHAT_TRANSACTION_SETTLED |
| Provider/2 adapter | ARCANE_AI_MODEL_AUTHORITY_REQUIRED, ARCANE_AI_PROVIDER_ROLE_MISMATCH, ARCANE_AI_PROVIDER_PROGRESS_INVALID, ARCANE_AI_PROVIDER_STATUS_INVALID, ARCANE_AI_PROVIDER_OPERATION_UNAVAILABLE |
| WebGPU and model availability | ARCANE_AI_WEBGPU_REQUIRED, ARCANE_AI_WEBGPU_API_UNAVAILABLE, ARCANE_AI_WEBGPU_EVIDENCE_INVALID, ARCANE_AI_MODEL_FULL_OFFLOAD_UNPROVEN, ARCANE_AI_MODEL_WEBGPU_REQUIREMENT_FAILED, ARCANE_AI_MODEL_GPU_MEMORY_INSUFFICIENT, ARCANE_AI_MODEL_RELOAD_REQUIRED, ARCANE_AI_LOAD_PLAN_RELOAD_REQUIRED |
| Worker cleanup and recovery | ARCANE_AI_WORKER_TERMINATION_UNCONFIRMED, ARCANE_AI_COMPLETION_RECOVERY_UNCONFIRMED |
| Diagnostics | ARCANE_AI_PROBE_FAILED |
Capability and status records also carry stable reason codes. These observations are not all thrown errors: positive and unknown states let an application explain why load is available, blocked, or not yet measured without guessing.
| Observation | Status/reason codes |
|---|---|
| Browser prerequisites | ARCANE_AI_WEBASSEMBLY_UNAVAILABLE, ARCANE_AI_OPFS_UNAVAILABLE, ARCANE_AI_SECURE_CONTEXT_REQUIRED |
| Positive cache/storage state | ARCANE_AI_MODEL_CACHE_COMPLETE, ARCANE_AI_STORAGE_CAPACITY_AVAILABLE |
| WebGPU execution evidence | ARCANE_AI_WEBGPU_EXECUTION_OBSERVED, ARCANE_AI_WEBGPU_EXECUTION_UNOBSERVED |
| Provider and runtime failure state | ARCANE_AI_PROVIDER_UNAVAILABLE, ARCANE_AI_RUNTIME_FAILED |
capabilities() reports browser observations such as WebAssembly, OPFS,
WebGPU API presence, WebGPU operation, secure context, cross-origin
isolation, and hardware concurrency. navigator.gpu alone is not operational
evidence. The authoritative runtime can operate without cross-origin isolation.
Secure context remains required; WebGPU/full-offload support applies to the
GPU route, while explicit gpuLayers:0 uses CPU. probe() exercises packaged
Wllama backend operations only while unloaded; it does not download a model.
BROWSERWASMRUNTIME_AUTHORITY
Overview
Mutable metadata for the shipped browser runtime. Its protocol is
arcane-ai-browser-wasm/2; the direct provider uses
arcane-ai-adapter/1 and adaptV1LlmProvider() projects it into
arcane-ai-provider/2. It records Wllama 3.6.0, upstream license metadata,
packaged runtime asset URLs, execution policy, and the disabled
compatibility-runtime and remote-model-helper policy.
Value and import
const BROWSER_WASM_RUNTIME_AUTHORITY
Availability and normalization
Browser metadata; safely inspectable without loading a model. The value is metadata, not a provider instance, model catalog, or capability grant.
Example
import {BROWSER_WASM_RUNTIME_AUTHORITY} from 'arcane-os/ai/browser-wasm';
console.log(BROWSER_WASM_RUNTIME_AUTHORITY.protocol);
console.log(BROWSER_WASM_RUNTIME_AUTHORITY.package.version); // 3.6.0
completeValueText()
Overview
Returns complete caller content as text. Strings are returned unchanged;
supported non-string values become readable JSON text. Cycles use $ref
records, and special primitives, maps, sets, dates, regular expressions,
functions, symbols, typed views, array buffers, and accessors retain explicit
representations.
Signature and result
completeValueText(value)
The function returns one complete string. It reads ordinary data descriptors without invoking accessors and records repeated object references by their first traversal location.
Availability and normalization
Compatible JavaScript module host. This is a pure value-to-text helper. It does not require a provider, model, cache, storage, WebAssembly, or browser capability.
Example
import {completeValueText} from 'arcane-os/ai/browser-wasm';
const status = new Map([
['state','ready'],
['roles',new Set(['llm'])]
]);
console.log(completeValueText(status));
createArcaneAI()
Overview
Creates the application-facing AI API module around a provider or an existing LLM controller. Use this as the primary browser-local API; construct the source, store, and Wllama provider beneath it.
Signature and result
createArcaneAI({ llm=null, provider=null, loadPolicy='on-demand', security }={})
At least one llm or provider is required; when both are supplied, llm
takes precedence. loadPolicy is on-demand or manual. The mutable result
contains llm, runtime, createChatSession, status, load,
unload, probe, fetchRequest, streamRequest, and dispose.
security carries only the app-level boolean secure intent inherited by
provider loads. The SDK default is secure:false; ai.load({security}) can
override that intent for the operation, but no checking implementation runs
until a separately authorized review enables one.
When llm is an existing ModelController, that controller keeps the security
and load policy with which it was created. This function
does not reapply its loadPolicy argument in that case, and supplying security alongside the
existing controller throws TypeError. Passing a provider instead creates a
new controller with the requested policy and security.
Availability and normalization
Browser. It normalizes provider lifecycle and request observation without selecting a model, changing browser permissions, contacting Arcane Core, or creating a fallback provider.
Example
const ai = createArcaneAI({provider, loadPolicy:'manual'});
async function loadCachedModelAfterUserChoice() {
const off = ai.llm.on('statechange', event => renderStatus(event.detail));
try {
return await ai.load({offline:true});
} finally {
off();
}
}
await ai.createChatSession(options) dynamically creates a
PersistentAIChatSession
whose AI API is permanently bound to this controller. options must
be a plain object and must not contain ai or chat; this prevents a session
from claiming the controller's lifecycle while sending its turns through
another provider.
createBrowserModelSource()
Overview
Validates a caller-owned canonical ordered multi-file descriptor and creates the cancellable HTTPS download source accepted by this provider.
Signature and result
createBrowserModelSource(descriptor, { fetchImpl=null }={})
The mutable source includes kind, the canonical descriptor fields,
descriptor, and open(memberIndex=0,{signal}). An omitted index selects the
first member. The method returns the complete readable response body,
requested/final URLs, nullable observed contentLength, and cancel(); caching
and the store's private per-member Range negotiation remain store-owned.
Availability and normalization
Browser Fetch with CORS. URL and optional metadata syntax are normalized. Declared and observed lengths feed only progress and transport planning. Ordinary source loading performs no expected-length, hash, digest, receipt, freeze, content-identity, admission, or cache-reuse checks.
Example
const source = createBrowserModelSource(MODEL);
console.log(source.id, source.files);
createBrowserWasmLlmProvider()
Overview
Creates the local-only Wllama provider from genuine source and store objects created by this module. Structural lookalikes are rejected.
Signature and result
createBrowserWasmLlmProvider({ sources, store, loadDefaults={}, security, logger=console }={})
sources is a nonempty array of unique SDK-created model sources. Its first
entry is the default model. The mutable result exposes protocol and provider
identity, default model metadata,
catalog, capabilities, status, load, unload, chat, stream,
streamChat, use, probe, and dispose. Direct provider load() selects a
catalog model and returns {model,status};
the public AI API module's ai.load() returns the flat controller status.
Direct load({onProgress}) forwards the same download progress and observed
initialization-stage/activity records used by the controller and provider/2
adapter. Initialization has no completion percentage unless the runtime reports
a meaningful completion total.
Provider security carries the provider/model-binding secure intent. Direct
provider.load({security}) and ai.load({security}) supply the operation
intent. They do not activate checking in the ordinary development contract.
Availability and normalization
Browser secure context with WebAssembly and OPFS/DBOPFS. The default GPU
route additionally requires WebGPU and full-offload support; gpuLayers:0
selects CPU without those GPU requirements. Inference is local after a
successful Wllama load. Status discloses the optional secure intent,
capability state, storage/model compatibility, and lifecycle state; it does not claim that
hardening ran.
Example
const provider = createBrowserWasmLlmProvider({
sources:[source],
store,
loadDefaults:{threads:1, contextTokens:4096}
});
console.log(provider.status().state); // unloaded
createDbopfsModelStore()
Overview
Adapts an existing DBOPFS instance without renaming or replacing its public methods. The adapter owns model-file caching and complete-set exposure.
Signature and result
createDbopfsModelStore({ dbopfs, tableName='arcane_ai_browser_models', estimateStorage=null, downloadConcurrency=4 }={})
The optional estimateStorage() function supplies browser storage availability
when the default estimator is unavailable or an application owns a more precise
quota view. downloadConcurrency must be a positive safe integer and bounds
the selected file or Range worker pool; the default is four. The mutable result
contains kind, tableName, downloadConcurrency, the original adapter,
and ready, install, ensure, remove, and fetchResource. ensure() preserves the complete
ordered model set and reports whether it was cached or installed.
install(source,{signal,onProgress}) and
ensure(source,{signal,onProgress,offline}) publish cache-check, cache-reading
load, and actual network download records using ordered file counts and per-member closed-part progress
when onProgress is supplied. Each member reports completed, total, and
unit:'shards'; streaming totals remain null until completion. Cache reads
publish the known stored-part plan from zero through each opened part, with
cached:true; the existing Range plan supplies known totals during resume.
No model length is converted into product progress. Records retain
activeTransfers, transferLimit, and transferMode, with prompt part/lifecycle
updates and an existing 250 ms heartbeat. They contain no transfer rate or ETA.
Multi-file sources use up to that many concurrent member workers
while retaining descriptor order, preserve completed members and completed
Range parts within members across an interrupted attempt, and fetch only
missing work on retry. Each missing source member first requests the HTTP
Range bytes=0-0. If a followed
redirect turns that probe into a full 200, the source probes the final URL directly;
confirmed support cancels the original body and starts parallel Range workers,
while refusal keeps the original full response as the single-fetch fallback. A
valid Content-Range, or optional descriptor bytes when that header is not
exposed, supplies the total for deterministic resumable Range parts of roughly
4 MB each, up to 4,096 parts. These values belong only to HTTP Range framing,
not product progress or content admission. Without an observable or declared
total, one full fetch streams into ordered persistent parts without requiring
a response length. Existing complete whole files remain readable without
migration. A later non-206,
contradictory exposed Range response, or incorrectly framed Range body fails
rather than silently assembling a partial model. A transfer failure lets peer
transfers settle; explicit cancellation stops active transfers. Both preserve
completed members and exact Range parts for retry, while unfinished active
parts restart after refresh. A complete whole member supersedes its current
Range fragments.
Cleanup failure is warned without replacing a usable model.
fetchResource(input,{signal,onProgress,...requestOptions}) returns the complete
stored response as {file,status,statusText,headers,url,redirected}. SDK model
loaders share this owner for actual configuration, tokenizer, graph,
external-data and support-file requests. Complete successful GET resources may
be reused. Cancellation joins reader/writer cleanup and preserves closed parts
for supported HTTP resume; a full response restarts that resource without
duplicating its saved prefix. Resource progress uses unit:'shards'. A network
response without a known shard plan retains total:null until completion;
opening a saved complete or partial resource reports phase:'load',
cached:true, and the known number of stored parts before and during the read.
The resource URL accompanies every update. These counts describe resource
preparation, never engine activation. Independent resource requests remain concurrent.
Availability and normalization
Browser with a ready DBOPFS instance and OPFS. Cache metadata is not a transferable capability token or proof of model license rights.
Example
const store = createDbopfsModelStore({dbopfs});
async function loadCachedModelAfterUserChoice() {
await store.ready();
const cached = await store.ensure(source,{offline:true});
console.log(cached ? 'cached model' : 'cache miss');
}
adaptV1LlmProvider()
Overview
Projects one compatible v1 browser-WASM provider into the same provider/2 LLM
role used by AIProviderRuntime.js. It checks the v1 protocol, required methods,
and local-only capability. The adapter does
not change the wrapped provider, download a model, execute a tool, or create a
fallback.
Signature and result
adaptV1LlmProvider(provider)
The mutable result exposes {protocol:'arcane-ai-provider/2',role:'llm',id, localOnly:true,catalog,inspect,status,load,request,unload,dispose}. Inspection
returns arcane-ai-model-authority/1 only for an exact catalog selection.
request() supports chat and stream and preserves structural tool data.
Both operations validate request history and tool declarations before provider
dispatch, then validate every terminal choice and required nonempty
arguments.message. The adapter drains the private provider stream regardless
of whether the consumer iterates first or awaits result first. Its ordinary
iterator receives complete nonstructural content/reasoning projections from
every choice in FIFO order, while structural deltas remain private until the
complete terminal result validates. A terminal-only structural call is valid;
any call observed during streaming must preserve its choice, ordered position,
ID, type, name, exact argument string, and extension fields in the terminal
envelope. Consumer return() starts observed provider cancellation immediately
and completes the iterator return without waiting for provider cleanup. The
terminal result retains provider settlement, and a later
cancellation/iterator-return failure is reported completely to the developer
console.
Availability and normalization
The adapter is available anywhere the caller can supply a compatible
arcane-ai-adapter/1 provider object. It performs only the versioned
provider-shape normalization into arcane-ai-provider/2. The v1 ingress,
terminal result, cancellation, and ordinary iterator projection use the same
structural-message contract; the wrapper does not create a
runtime, choose or download a model, grant host capability, change local-only
behavior, or make an arbitrary provider authoritative. Provider lifecycle,
cancellation, catalog selection, and failures remain owned by the wrapped
provider and are forwarded through the normalized role contract.
Example
import {adaptV1LlmProvider} from 'arcane-os/ai/browser-wasm';
import {getAIProviderRuntime} from 'arcane-os/ai-provider-runtime';
const runtime = getAIProviderRuntime();
const release = runtime.register(adaptV1LlmProvider(provider));
// Configure an exact llm route before load/use. Release registration at teardown.
release();
Related reference
- Canonical
createArcaneAI()entry and the siblingBROWSER_WASM_RUNTIME_AUTHORITY,adaptV1LlmProvider(),completeValueText(),createBrowserModelSource(),createBrowserWasmLlmProvider(), andcreateDbopfsModelStore()entries - Browser-local normalization boundary
- Browser runtime delivery
- Browser-WASM behavior evidence
- DBOPFS runtime module
- Browser speech providers
- Provider-neutral AI runtime
- Persistent chat