arcane-os 0.5.17 → 0.5.19
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 +34 -1
- package/README.md +9 -9
- package/bin/arcane-test.mjs +16 -13
- package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
- package/browser-runtime/ai/browser-speech-providers.mjs +46 -43
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +158 -135
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +104 -23
- package/browser-runtime/ai/model-controller.mjs +94 -91
- package/browser-runtime/ai/speech-worker-client.mjs +12 -9
- package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
- package/browser-runtime/dependencies/strong-type/index.js +207 -82
- package/browser-runtime/dependencies/strong-type/package.json +15 -6
- package/browser-runtime/dom-event-instrumentation.mjs +24 -20
- package/browser-runtime/event-manager.mjs +111 -108
- package/browser-runtime/speech-text.mjs +5 -1
- package/docs/architecture.md +1 -1
- package/docs/publishing.md +10 -4
- package/docs/reference/ai/browser-speech.md +198 -5
- package/docs/reference/ai/browser-wasm.md +29 -6
- package/docs/reference/availability-and-normalization.md +40 -0
- package/docs/reference/inventory/package-api.json +1 -1
- package/docs/reference/inventory/runtime-components.json +1 -1
- package/docs/reference/inventory/runtime-modules.json +20 -24
- package/docs/reference/protocols.md +1 -1
- package/docs/reference/runtime-modules.md +125 -35
- package/docs/reference/sdk-api.md +23 -7
- package/examples/wasm-ai-demo/index.html +1 -0
- package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
- package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
- package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
- package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
- package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
- package/node_modules/strong-type/README.md +42 -24
- package/node_modules/strong-type/benchmark/core.js +324 -0
- package/node_modules/strong-type/index.js +207 -82
- package/node_modules/strong-type/package.json +14 -6
- package/package.json +3 -3
- package/runtime/arcane/components/app-bar.html +5 -2
- package/runtime/arcane/components/assistant-panel.html +5 -2
- package/runtime/arcane/components/chart.html +15 -12
- package/runtime/arcane/components/chat.html +170 -148
- package/runtime/arcane/components/dashboard-config.html +6 -3
- package/runtime/arcane/components/data-view.html +4 -1
- package/runtime/arcane/components/directory-picker.html +5 -2
- package/runtime/arcane/components/document-inspector.html +6 -3
- package/runtime/arcane/components/file-drop.html +5 -2
- package/runtime/arcane/components/file-inspector.html +9 -6
- package/runtime/arcane/components/file-manager.html +16 -13
- package/runtime/arcane/components/local-ai-status.html +5 -2
- package/runtime/arcane/components/markdown-document.html +14 -11
- package/runtime/arcane/components/markdown-editor.html +4 -1
- package/runtime/arcane/components/modal.html +4 -1
- package/runtime/arcane/components/output-panel.html +6 -3
- package/runtime/arcane/components/preferences-form.html +4 -1
- package/runtime/arcane/components/record-timeline.html +8 -5
- package/runtime/arcane/components/relationship-board.html +9 -6
- package/runtime/arcane/components/source-code-viewer.html +12 -9
- package/runtime/arcane/components/source-explanation.html +8 -5
- package/runtime/arcane/components/speech.html +24 -21
- package/runtime/arcane/components/summary-strip.html +4 -1
- package/runtime/arcane/components/task-progress.html +6 -3
- package/runtime/arcane/components/terminal-workspace.html +4 -1
- package/runtime/arcane/components/voice-transcription.html +11 -8
- package/runtime/arcane/components/web-navigator.html +5 -2
- package/runtime/arcane/entities/ApiModelRecord.js +5 -2
- package/runtime/arcane/entities/Calculation.js +5 -2
- package/runtime/arcane/entities/Chat.js +33 -33
- package/runtime/arcane/entities/CommunicationMessage.js +4 -1
- package/runtime/arcane/entities/CommunicationThread.js +4 -1
- package/runtime/arcane/entities/File.js +1 -1
- package/runtime/arcane/entities/Image.js +8 -5
- package/runtime/arcane/entities/IntentEnvelope.js +20 -17
- package/runtime/arcane/entities/Preference.js +9 -6
- package/runtime/arcane/entities/Theme.js +5 -2
- package/runtime/arcane/entities/User.js +11 -11
- package/runtime/arcane/entities/Weather.js +5 -2
- package/runtime/arcane/modules/AI.js +491 -165
- package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
- package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
- package/runtime/arcane/modules/AIProviderRuntime.js +88 -85
- package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
- package/runtime/arcane/modules/AIRuntimeState.js +29 -26
- package/runtime/arcane/modules/AnsiText.js +4 -1
- package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
- package/runtime/arcane/modules/AppDataScope.js +8 -5
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
- package/runtime/arcane/modules/AsyncBoundary.js +13 -10
- package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
- package/runtime/arcane/modules/CalculatorEngine.js +5 -2
- package/runtime/arcane/modules/ChatRecords.js +18 -15
- package/runtime/arcane/modules/CommunicationAppController.js +9 -6
- package/runtime/arcane/modules/CommunicationHub.js +9 -6
- package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
- package/runtime/arcane/modules/ComponentContracts.js +56 -53
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
- package/runtime/arcane/modules/ConversationActionItems.js +15 -12
- package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
- package/runtime/arcane/modules/ConversationTimebox.js +28 -25
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
- package/runtime/arcane/modules/DBLS.js +7 -4
- package/runtime/arcane/modules/DBOPFS.js +7 -7
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
- package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
- package/runtime/arcane/modules/DirectoryPicker.js +8 -5
- package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
- package/runtime/arcane/modules/DocumentNavigation.js +7 -4
- package/runtime/arcane/modules/Errors.js +28 -25
- package/runtime/arcane/modules/HTMLImport.js +7 -4
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
- package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
- package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
- package/runtime/arcane/modules/MD.js +1 -1
- package/runtime/arcane/modules/Mail.js +46 -43
- package/runtime/arcane/modules/MailOutbox.mjs +48 -45
- package/runtime/arcane/modules/MailTransport.mjs +29 -26
- package/runtime/arcane/modules/MemoryRecords.js +7 -4
- package/runtime/arcane/modules/MessageAdvisory.js +6 -3
- package/runtime/arcane/modules/ModelDefinition.js +7 -4
- package/runtime/arcane/modules/Ollama.js +6 -3
- package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
- package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
- package/runtime/arcane/modules/PreferenceStore.js +20 -17
- package/runtime/arcane/modules/PreparedSpeech.js +485 -0
- package/runtime/arcane/modules/Questionnaire.js +6 -3
- package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
- package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
- package/runtime/arcane/modules/RecordReviewStore.js +12 -9
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
- package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
- package/runtime/arcane/modules/ScreenCapture.js +20 -17
- package/runtime/arcane/modules/SpeechPlayback.js +29 -26
- package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
- package/runtime/arcane/modules/SystemAppearance.js +5 -2
- package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
- package/runtime/arcane/modules/TerminalClient.js +14 -11
- package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
- package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
- package/runtime/arcane/modules/ThemeManager.js +5 -2
- package/runtime/arcane/modules/TimeGuard.js +1 -1
- package/runtime/arcane/modules/ToolCallRouter.js +11 -8
- package/runtime/arcane/modules/WaitForComponent.js +19 -16
- package/runtime/arcane/modules/YouTubeMedia.js +4 -1
- package/runtime/strong-type/index.js +1276 -352
- package/runtime/strong-type/package.json +69 -45
- package/src/app-descriptor.mjs +17 -14
- package/src/application-tests.mjs +4 -1
- package/src/cli/main.mjs +8 -5
- package/src/constants.mjs +4 -1
- package/src/dev-server.mjs +8 -5
- package/src/doctor.mjs +5 -2
- package/src/dom-event-instrumentation.mjs +24 -20
- package/src/errors.mjs +7 -3
- package/src/event-manager.mjs +111 -108
- package/src/event-queue.mjs +8 -5
- package/src/events.mjs +12 -9
- package/src/import-map.mjs +35 -27
- package/src/installed-sdk-runtime.mjs +4 -1
- package/src/integrated-provider-loader.mjs +9 -6
- package/src/mail-credentials.mjs +16 -13
- package/src/mail-server.mjs +53 -50
- package/src/mail.mjs +18 -15
- package/src/native-plan.mjs +12 -9
- package/src/native-provider-loader.mjs +7 -4
- package/src/packager/core.mjs +18 -15
- package/src/process.mjs +6 -3
- package/src/release-bundle.mjs +14 -11
- package/src/runtime.mjs +4 -1
- package/src/scaffold.mjs +9 -6
- package/src/sdk-browser-runtime.mjs +4 -1
- package/src/source-server.mjs +17 -14
- package/src/targets/index.mjs +5 -2
- package/src/templates/workspace-template.mjs +13 -6
- package/src/testing-loader.mjs +7 -4
- package/src/testing.mjs +10 -7
- package/src/toolchain.mjs +13 -10
- package/src/update-check.mjs +9 -6
- package/src/workspace-operation-lock.mjs +14 -11
- package/src/workspace-runtime.mjs +4 -1
- package/src/workspace.mjs +17 -14
- package/runtime/arcane/modules/AIResponseLength.js +0 -32
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from "../dependencies/strong-type/index.js";
|
|
1
2
|
import {
|
|
2
3
|
completeValueText,
|
|
3
4
|
createModelController,
|
|
@@ -11,6 +12,8 @@ import {
|
|
|
11
12
|
} from "./browser-wasm-llm-provider.mjs";
|
|
12
13
|
import { BROWSER_WASM_RUNTIME_AUTHORITY } from "./browser-wllama-runtime.mjs";
|
|
13
14
|
|
|
15
|
+
const is = new Is(false);
|
|
16
|
+
|
|
14
17
|
/**
|
|
15
18
|
* Creates the public Arcane browser-local AI API module. The SDK owns lifecycle,
|
|
16
19
|
* cache, streaming, complete response projection, and structural tool visibility; applications
|
|
@@ -24,12 +27,12 @@ function createArcaneAI({
|
|
|
24
27
|
} = {}) {
|
|
25
28
|
const selected = llm ?? provider;
|
|
26
29
|
if (!selected) throw new TypeError("createArcaneAI requires an llm provider.");
|
|
27
|
-
if (selected
|
|
30
|
+
if (is.instanceCheck(selected, ModelController) && security !== undefined) {
|
|
28
31
|
throw new TypeError(
|
|
29
32
|
"createArcaneAI security must be configured when the existing ModelController is created.",
|
|
30
33
|
);
|
|
31
34
|
}
|
|
32
|
-
const controller = selected
|
|
35
|
+
const controller = is.instanceCheck(selected, ModelController)
|
|
33
36
|
? selected
|
|
34
37
|
: createModelController({ provider: selected, loadPolicy, security });
|
|
35
38
|
const api = {
|
|
@@ -46,7 +49,7 @@ function createArcaneAI({
|
|
|
46
49
|
};
|
|
47
50
|
|
|
48
51
|
async function createChatSession(options = {}) {
|
|
49
|
-
if (!options ||
|
|
52
|
+
if (!options || !is.object(options) || is.array(options)) {
|
|
50
53
|
throw new TypeError("createChatSession options must be a plain object.");
|
|
51
54
|
}
|
|
52
55
|
if (Object.getPrototypeOf(options) !== Object.prototype) {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import Is from "../dependencies/strong-type/index.js";
|
|
1
2
|
import { arcaneLogging } from '../logging.mjs';
|
|
2
3
|
import { Wllama } from "./wllama/index.mjs";
|
|
3
4
|
|
|
5
|
+
const is = new Is(false);
|
|
6
|
+
|
|
4
7
|
const completeValue = (value) => value;
|
|
5
8
|
|
|
6
9
|
const MODULE_URL = new URL("./wllama/index.mjs", import.meta.url).href;
|
|
@@ -63,15 +66,15 @@ function runtimeCapabilitySnapshot(evidence) {
|
|
|
63
66
|
const navigatorObject = globalThis.navigator;
|
|
64
67
|
const webgpuOperational = evidence?.state === "ready" && evidence?.webgpu?.observed === true;
|
|
65
68
|
return completeValue({
|
|
66
|
-
webAssembly:
|
|
67
|
-
opfs:
|
|
69
|
+
webAssembly: is.object(globalThis.WebAssembly),
|
|
70
|
+
opfs: is.function(navigatorObject?.storage?.getDirectory),
|
|
68
71
|
webgpu: webgpuOperational,
|
|
69
72
|
webgpuApiPresent: Boolean(navigatorObject?.gpu),
|
|
70
73
|
webgpuOperational,
|
|
71
74
|
webgpuEvidenceProtocol: RUNTIME_EVIDENCE_PROTOCOL,
|
|
72
75
|
crossOriginIsolated: globalThis.crossOriginIsolated === true,
|
|
73
76
|
secureContext: globalThis.isSecureContext === true,
|
|
74
|
-
hardwareConcurrency:
|
|
77
|
+
hardwareConcurrency: is.safeInteger(navigatorObject?.hardwareConcurrency)
|
|
75
78
|
? navigatorObject.hardwareConcurrency
|
|
76
79
|
: null,
|
|
77
80
|
});
|
|
@@ -80,7 +83,7 @@ function runtimeCapabilitySnapshot(evidence) {
|
|
|
80
83
|
function normalizePositiveInteger(value, fallback) {
|
|
81
84
|
if (value === undefined || value === null) return fallback;
|
|
82
85
|
const number = Number(value);
|
|
83
|
-
if (!
|
|
86
|
+
if (!is.safeInteger(number) || number < 1) {
|
|
84
87
|
throw new RangeError("Expected a positive safe integer.");
|
|
85
88
|
}
|
|
86
89
|
return number;
|
|
@@ -91,6 +94,59 @@ function createEvidenceLogger(logger) {
|
|
|
91
94
|
let offload = null;
|
|
92
95
|
let invalid = false;
|
|
93
96
|
let completionCapture = null;
|
|
97
|
+
let loadProgress = null;
|
|
98
|
+
let tensorCount = null;
|
|
99
|
+
|
|
100
|
+
function observeLoadLine(line) {
|
|
101
|
+
if (!loadProgress) return;
|
|
102
|
+
let stage;
|
|
103
|
+
let message;
|
|
104
|
+
const metadata = line.match(/^llama_model_loader: loaded meta data with \d+ key-value pairs and (\d+) tensors from /u);
|
|
105
|
+
const layers = line.match(GPU_OFFLOAD_PATTERN);
|
|
106
|
+
if (line.startsWith('Loading "wllama.wasm" from ')) {
|
|
107
|
+
stage = "runtime";
|
|
108
|
+
message = "Loading the WebAssembly runtime";
|
|
109
|
+
} else if (line === "Calling wllamaStart...") {
|
|
110
|
+
stage = "backend";
|
|
111
|
+
message = "Starting the inference engine";
|
|
112
|
+
} else if (line === "Loading model...") {
|
|
113
|
+
stage = "metadata";
|
|
114
|
+
message = "Reading model metadata";
|
|
115
|
+
} else if (WEBGPU_ADAPTER_PATTERN.test(line)) {
|
|
116
|
+
stage = "gpu";
|
|
117
|
+
message = "Graphics device initialized; preparing the model";
|
|
118
|
+
} else if (metadata) {
|
|
119
|
+
tensorCount = Number(metadata[1]);
|
|
120
|
+
stage = "metadata";
|
|
121
|
+
message = `Model metadata read: ${tensorCount} tensors`;
|
|
122
|
+
} else if (line.startsWith("load_tensors: loading model tensors,")) {
|
|
123
|
+
stage = "weights";
|
|
124
|
+
message = tensorCount === null
|
|
125
|
+
? "Loading model weights"
|
|
126
|
+
: `Loading model weights for ${tensorCount} tensors`;
|
|
127
|
+
} else if (layers) {
|
|
128
|
+
// Upstream reports layer assignment before the weight reads finish.
|
|
129
|
+
stage = "weights";
|
|
130
|
+
message = `Loading model weights; ${layers[1]} of ${layers[2]} layers assigned to the GPU`;
|
|
131
|
+
} else if (line === "llama_context: constructing llama_context") {
|
|
132
|
+
stage = "context";
|
|
133
|
+
message = "Preparing the inference context";
|
|
134
|
+
} else if (/^[^:]+:\s+graph (?:nodes|splits)\s+=\s+\d+/u.test(line)) {
|
|
135
|
+
stage = "graph";
|
|
136
|
+
message = "Preparing the inference graph";
|
|
137
|
+
} else if (/^cmn\s+common_init_:\s+warming up the model with an empty run\b/u.test(line)) {
|
|
138
|
+
stage = "warmup";
|
|
139
|
+
message = "Warming up the model with an empty run";
|
|
140
|
+
}
|
|
141
|
+
if (stage) {
|
|
142
|
+
loadProgress({
|
|
143
|
+
phase: "initialize",
|
|
144
|
+
stage,
|
|
145
|
+
message,
|
|
146
|
+
total: null,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
94
150
|
|
|
95
151
|
function same(left, right) {
|
|
96
152
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
@@ -116,6 +172,7 @@ function createEvidenceLogger(logger) {
|
|
|
116
172
|
observeCompletionLine(level, value);
|
|
117
173
|
const line = String(value).trim();
|
|
118
174
|
if (!line) return;
|
|
175
|
+
observeLoadLine(line);
|
|
119
176
|
const adapterMatch = line.match(WEBGPU_ADAPTER_PATTERN);
|
|
120
177
|
if (adapterMatch) {
|
|
121
178
|
const next = completeValue({
|
|
@@ -141,8 +198,10 @@ function createEvidenceLogger(logger) {
|
|
|
141
198
|
}
|
|
142
199
|
|
|
143
200
|
function observe(level, args) {
|
|
201
|
+
// Activity without a new stage updates its age without repainting the UI.
|
|
202
|
+
loadProgress?.(null);
|
|
144
203
|
for (const value of args) {
|
|
145
|
-
if (
|
|
204
|
+
if (!is.string(value)) continue;
|
|
146
205
|
for (const line of value.split(/\r?\n/u)) observeLine(level, line);
|
|
147
206
|
}
|
|
148
207
|
}
|
|
@@ -151,12 +210,19 @@ function createEvidenceLogger(logger) {
|
|
|
151
210
|
for (const level of ["debug", "log", "warn", "error"]) {
|
|
152
211
|
wrapped[level] = (...args) => {
|
|
153
212
|
observe(level, args);
|
|
154
|
-
if (
|
|
213
|
+
if (is.function(logger?.[level])) logger[level](...args);
|
|
155
214
|
};
|
|
156
215
|
}
|
|
157
216
|
|
|
158
217
|
return completeValue({
|
|
159
218
|
logger: completeValue(wrapped),
|
|
219
|
+
beginLoadProgress(report) {
|
|
220
|
+
loadProgress = report;
|
|
221
|
+
tensorCount = null;
|
|
222
|
+
return function releaseLoadProgress() {
|
|
223
|
+
loadProgress = null;
|
|
224
|
+
};
|
|
225
|
+
},
|
|
160
226
|
beginCompletionCapture() {
|
|
161
227
|
if (completionCapture) {
|
|
162
228
|
throw runtimeFailure(
|
|
@@ -214,7 +280,7 @@ function createStructuredStreamCapture() {
|
|
|
214
280
|
|
|
215
281
|
function observe(value) {
|
|
216
282
|
chunks += 1;
|
|
217
|
-
if (!value ||
|
|
283
|
+
if (!value || !is.object(value) || !is.array(value.choices)) {
|
|
218
284
|
invalid = true;
|
|
219
285
|
return;
|
|
220
286
|
}
|
|
@@ -227,8 +293,8 @@ function createStructuredStreamCapture() {
|
|
|
227
293
|
if (
|
|
228
294
|
choice?.index !== 0
|
|
229
295
|
|| !delta
|
|
230
|
-
||
|
|
231
|
-
||
|
|
296
|
+
|| !is.object(delta)
|
|
297
|
+
|| is.array(delta)
|
|
232
298
|
|| (delta.role !== undefined && delta.role !== "assistant")
|
|
233
299
|
|| (choice.finish_reason !== undefined && choice.finish_reason !== null)
|
|
234
300
|
|| delta.tool_calls !== undefined
|
|
@@ -239,7 +305,7 @@ function createStructuredStreamCapture() {
|
|
|
239
305
|
return;
|
|
240
306
|
}
|
|
241
307
|
if (delta.content === undefined || delta.content === null) return;
|
|
242
|
-
if (
|
|
308
|
+
if (!is.string(delta.content)) {
|
|
243
309
|
invalid = true;
|
|
244
310
|
return;
|
|
245
311
|
}
|
|
@@ -296,7 +362,7 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
296
362
|
}
|
|
297
363
|
|
|
298
364
|
function cancellationError(reason, fallback = "The Wllama operation was cancelled.") {
|
|
299
|
-
return reason
|
|
365
|
+
return is.error(reason) ? reason : new Error(reason ? String(reason) : fallback);
|
|
300
366
|
}
|
|
301
367
|
|
|
302
368
|
function trackOperation(rawOperation) {
|
|
@@ -380,7 +446,7 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
380
446
|
});
|
|
381
447
|
next.setCompat(null);
|
|
382
448
|
for (const method of ["arcaneLoadModel", "arcaneTelemetry", "arcaneTerminate"]) {
|
|
383
|
-
if (
|
|
449
|
+
if (!is.function(next[method])) {
|
|
384
450
|
throw new Error(`The packaged Wllama projection is missing public ${method}().`);
|
|
385
451
|
}
|
|
386
452
|
}
|
|
@@ -401,10 +467,10 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
401
467
|
}
|
|
402
468
|
|
|
403
469
|
async function load(files, options = {}) {
|
|
404
|
-
if (!
|
|
470
|
+
if (!is.array(files) || files.length === 0) {
|
|
405
471
|
throw new TypeError("Wllama load() requires at least one File or Blob.");
|
|
406
472
|
}
|
|
407
|
-
if (
|
|
473
|
+
if (!is.object(globalThis.WebAssembly)) {
|
|
408
474
|
throw new Error("WebAssembly is unavailable in this browser.");
|
|
409
475
|
}
|
|
410
476
|
if (!globalThis.navigator?.gpu) {
|
|
@@ -435,25 +501,25 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
435
501
|
loadOptions.n_ubatch = normalizePositiveInteger(options.microBatchTokens, 128);
|
|
436
502
|
}
|
|
437
503
|
if (options.reasoning !== undefined) {
|
|
438
|
-
if (
|
|
504
|
+
if (!is.boolean(options.reasoning)) {
|
|
439
505
|
throw new TypeError("reasoning must be a boolean when provided.");
|
|
440
506
|
}
|
|
441
507
|
loadOptions.reasoning = options.reasoning;
|
|
442
508
|
}
|
|
443
509
|
if (options.chatTemplate !== undefined) {
|
|
444
|
-
if (
|
|
510
|
+
if (!is.string(options.chatTemplate)) {
|
|
445
511
|
throw new TypeError("chatTemplate must be a string when provided.");
|
|
446
512
|
}
|
|
447
513
|
loadOptions.chat_template = options.chatTemplate;
|
|
448
514
|
}
|
|
449
515
|
if (options.jinja !== undefined) {
|
|
450
|
-
if (
|
|
516
|
+
if (!is.boolean(options.jinja)) {
|
|
451
517
|
throw new TypeError("jinja must be a boolean when provided.");
|
|
452
518
|
}
|
|
453
519
|
loadOptions.jinja = options.jinja;
|
|
454
520
|
}
|
|
455
521
|
if (options.templateDefaults !== undefined) {
|
|
456
|
-
if (!options.templateDefaults ||
|
|
522
|
+
if (!options.templateDefaults || !is.object(options.templateDefaults) || is.array(options.templateDefaults)) {
|
|
457
523
|
throw new TypeError("templateDefaults must be a plain object when provided.");
|
|
458
524
|
}
|
|
459
525
|
loadOptions.default_template_kwargs = { ...options.templateDefaults };
|
|
@@ -466,6 +532,18 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
466
532
|
cleanup: null,
|
|
467
533
|
});
|
|
468
534
|
const loadController = new AbortController();
|
|
535
|
+
let progressFailure = null;
|
|
536
|
+
const releaseLoadProgress = sessionObservers.get(next).beginLoadProgress(
|
|
537
|
+
function reportRuntimeLoadProgress(progress) {
|
|
538
|
+
if (loadController.signal.aborted || !is.function(options.onProgress)) return;
|
|
539
|
+
try {
|
|
540
|
+
options.onProgress(progress);
|
|
541
|
+
} catch (error) {
|
|
542
|
+
progressFailure = error;
|
|
543
|
+
loadController.abort(error);
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
);
|
|
469
547
|
const loadOperation = Promise.resolve().then(() => (
|
|
470
548
|
next.arcaneLoadModel(files, loadOptions, loadController.signal)
|
|
471
549
|
));
|
|
@@ -481,8 +559,9 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
481
559
|
else signal?.addEventListener?.("abort", onAbort, { once: true });
|
|
482
560
|
try {
|
|
483
561
|
await loadOperation;
|
|
562
|
+
if (progressFailure) throw progressFailure;
|
|
484
563
|
if (pending?.engine !== next) throw new Error("Wllama load was cancelled.");
|
|
485
|
-
if (
|
|
564
|
+
if (!is.function(next.isModelLoaded) || next.isModelLoaded() !== true) {
|
|
486
565
|
throw runtimeFailure(
|
|
487
566
|
"ARCANE_AI_LOAD_FAILED",
|
|
488
567
|
"Wllama did not confirm a successfully loaded model.",
|
|
@@ -493,6 +572,7 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
493
572
|
engine = next;
|
|
494
573
|
publishEvidence({ state: "ready", webgpu, cancellation: null, cleanup: null });
|
|
495
574
|
} catch (error) {
|
|
575
|
+
releaseLoadProgress();
|
|
496
576
|
let cleanupFailure = null;
|
|
497
577
|
try {
|
|
498
578
|
await exitSession(next);
|
|
@@ -510,6 +590,7 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
510
590
|
if (cleanupFailure) throw cleanupFailure;
|
|
511
591
|
throw error;
|
|
512
592
|
} finally {
|
|
593
|
+
releaseLoadProgress();
|
|
513
594
|
signal?.removeEventListener?.("abort", onAbort);
|
|
514
595
|
}
|
|
515
596
|
|
|
@@ -553,13 +634,13 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
553
634
|
lastObservedOperational: evidenceState.webgpu?.lastObservedOperational === true,
|
|
554
635
|
},
|
|
555
636
|
failure: completeValue({
|
|
556
|
-
code:
|
|
637
|
+
code: is.string(error?.code) ? error.code : "ARCANE_AI_RUNTIME_FAILED",
|
|
557
638
|
}),
|
|
558
639
|
});
|
|
559
640
|
}
|
|
560
641
|
|
|
561
642
|
async function inference(options, onData = null) {
|
|
562
|
-
if (!options ||
|
|
643
|
+
if (!options || !is.object(options) || is.array(options)) {
|
|
563
644
|
throw new TypeError("Wllama inference options must be an object.");
|
|
564
645
|
}
|
|
565
646
|
if (Object.hasOwn(options, "signal")) {
|
|
@@ -629,7 +710,7 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
629
710
|
}
|
|
630
711
|
|
|
631
712
|
function stream(options, onData) {
|
|
632
|
-
if (
|
|
713
|
+
if (!is.function(onData)) {
|
|
633
714
|
throw new TypeError("Wllama stream() requires an onData callback.");
|
|
634
715
|
}
|
|
635
716
|
return inference({ ...options, stream: true }, onData);
|
|
@@ -653,7 +734,7 @@ export function createPackagedWllamaRuntime({ logger = arcaneLogging } = {}) {
|
|
|
653
734
|
|
|
654
735
|
async function probe({ args = ["-o", "ADD"] } = {}) {
|
|
655
736
|
if (engine) throw new Error("The no-model Wllama probe cannot run while a model is loaded.");
|
|
656
|
-
if (!
|
|
737
|
+
if (!is.array(args) || args.some((value) => !is.string(value))) {
|
|
657
738
|
throw new TypeError("Wllama probe args must be an array of strings.");
|
|
658
739
|
}
|
|
659
740
|
const temporary = newEngine();
|