arcane-os 0.5.16 → 0.5.18
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 +44 -0
- package/README.md +42 -19
- 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 +53 -46
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -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 +35 -0
- package/docs/architecture.md +1 -1
- package/docs/reference/README.md +8 -8
- package/docs/reference/ai/browser-speech.md +230 -16
- package/docs/reference/ai/twin-cloud.md +1 -1
- package/docs/reference/availability-and-normalization.md +42 -1
- package/docs/reference/cli.md +1 -1
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/inventory/package-api.json +60 -4
- package/docs/reference/inventory/runtime-components.json +2 -2
- package/docs/reference/inventory/runtime-modules.json +29 -31
- package/docs/reference/protocols.md +17 -13
- package/docs/reference/runtime-components.md +6 -5
- package/docs/reference/runtime-modules.md +212 -70
- package/docs/reference/sdk-api.md +197 -11
- 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 +4 -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 +118 -141
- 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 +503 -187
- package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
- package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
- package/runtime/arcane/modules/AIProviderRuntime.js +117 -92
- 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/MarkdownSpeech.js +1 -50
- 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 +61 -28
- 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 +36 -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,6 +1,9 @@
|
|
|
1
|
+
import Is from "../dependencies/strong-type/index.js";
|
|
1
2
|
import { arcaneLogging } from '../logging.mjs';
|
|
2
3
|
import { createArcaneEventSource } from "arcane-os/event-manager";
|
|
3
4
|
|
|
5
|
+
const is = new Is(false);
|
|
6
|
+
|
|
4
7
|
export const ARCANE_AI_ADAPTER_PROTOCOL = "arcane-ai-adapter/1";
|
|
5
8
|
|
|
6
9
|
const MODEL_CONTROLLER_EVENT_TYPES = ["statechange", "progress"];
|
|
@@ -65,18 +68,18 @@ export function normalizeArcaneAIError(error, {
|
|
|
65
68
|
{ cause: error ?? signal?.reason, kind, operation },
|
|
66
69
|
);
|
|
67
70
|
}
|
|
68
|
-
if (error
|
|
69
|
-
const code =
|
|
71
|
+
if (is.instanceCheck(error, ArcaneAIError)) return error;
|
|
72
|
+
const code = is.string(error?.code) && error.code.startsWith("ARCANE_AI_")
|
|
70
73
|
? error.code
|
|
71
74
|
: ERROR_CODES[operation] ?? ERROR_CODES.request;
|
|
72
|
-
const message =
|
|
75
|
+
const message = is.string(error?.message) && error.message.trim()
|
|
73
76
|
? error.message
|
|
74
77
|
: `The Arcane AI ${operation} operation failed.`;
|
|
75
78
|
return new ArcaneAIError(code, message, { cause: error, kind, operation });
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
function providerMethod(provider, name) {
|
|
79
|
-
return
|
|
82
|
+
return is.function(provider?.[name]) ? provider[name].bind(provider) : null;
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
function invalidStatus(cause) {
|
|
@@ -91,7 +94,7 @@ function copyError(error) {
|
|
|
91
94
|
if (!error) return null;
|
|
92
95
|
let code;
|
|
93
96
|
let message;
|
|
94
|
-
if (
|
|
97
|
+
if (is.object(error) || is.function(error)) {
|
|
95
98
|
try {
|
|
96
99
|
const codeDescriptor = Object.getOwnPropertyDescriptor(error, "code");
|
|
97
100
|
const messageDescriptor = Object.getOwnPropertyDescriptor(error, "message");
|
|
@@ -102,7 +105,7 @@ function copyError(error) {
|
|
|
102
105
|
code = codeDescriptor?.value;
|
|
103
106
|
message = messageDescriptor?.value;
|
|
104
107
|
} catch (copyErrorFailure) {
|
|
105
|
-
if (copyErrorFailure
|
|
108
|
+
if (is.instanceCheck(copyErrorFailure, ArcaneAIError)) throw copyErrorFailure;
|
|
106
109
|
throw invalidStatus(copyErrorFailure);
|
|
107
110
|
}
|
|
108
111
|
}
|
|
@@ -113,17 +116,17 @@ function copyError(error) {
|
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
function isModelControllerListener(value) {
|
|
116
|
-
return
|
|
117
|
-
|| Boolean(value &&
|
|
119
|
+
return is.function(value)
|
|
120
|
+
|| Boolean(value && is.object(value) && is.function(value.handleEvent));
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
function copyProviderStatus(value) {
|
|
121
124
|
if (value === undefined || value === null) return {};
|
|
122
|
-
if (
|
|
125
|
+
if (!is.object(value) || is.array(value)) throw invalidStatus();
|
|
123
126
|
try {
|
|
124
127
|
const copy = {};
|
|
125
128
|
for (const key of Reflect.ownKeys(value)) {
|
|
126
|
-
if (
|
|
129
|
+
if (!is.string(key)) throw invalidStatus();
|
|
127
130
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
128
131
|
if (!descriptor || !("value" in descriptor)) throw invalidStatus();
|
|
129
132
|
Object.defineProperty(copy, key, {
|
|
@@ -135,7 +138,7 @@ function copyProviderStatus(value) {
|
|
|
135
138
|
}
|
|
136
139
|
return copy;
|
|
137
140
|
} catch (error) {
|
|
138
|
-
if (error
|
|
141
|
+
if (is.instanceCheck(error, ArcaneAIError)) throw error;
|
|
139
142
|
throw invalidStatus(error);
|
|
140
143
|
}
|
|
141
144
|
}
|
|
@@ -149,20 +152,20 @@ function invalidProgress(cause) {
|
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
function copyProgressValue(value, state) {
|
|
152
|
-
if (value === null ||
|
|
155
|
+
if (value === null || !is.object(value)) return value;
|
|
153
156
|
if (state.seen.has(value)) {
|
|
154
157
|
throw invalidProgress();
|
|
155
158
|
}
|
|
156
159
|
const prototype = Object.getPrototypeOf(value);
|
|
157
|
-
if (!
|
|
160
|
+
if (!is.array(value) && prototype !== Object.prototype && prototype !== null) {
|
|
158
161
|
throw invalidProgress();
|
|
159
162
|
}
|
|
160
163
|
state.seen.add(value);
|
|
161
|
-
const copy =
|
|
164
|
+
const copy = is.array(value) ? [] : prototype === null ? Object.create(null) : {};
|
|
162
165
|
try {
|
|
163
166
|
for (const key of Reflect.ownKeys(value)) {
|
|
164
|
-
if (
|
|
165
|
-
if (
|
|
167
|
+
if (is.array(value) && key === "length") continue;
|
|
168
|
+
if (!is.string(key)) {
|
|
166
169
|
throw invalidProgress();
|
|
167
170
|
}
|
|
168
171
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
@@ -182,23 +185,23 @@ function copyProgressValue(value, state) {
|
|
|
182
185
|
|
|
183
186
|
function copyProgress(progress) {
|
|
184
187
|
if (progress === undefined || progress === null) return null;
|
|
185
|
-
if (
|
|
188
|
+
if (!is.object(progress) || is.array(progress)) {
|
|
186
189
|
throw invalidProgress();
|
|
187
190
|
}
|
|
188
191
|
try {
|
|
189
192
|
return copyProgressValue(progress, { seen: new WeakSet() });
|
|
190
193
|
} catch (error) {
|
|
191
|
-
if (error
|
|
194
|
+
if (is.instanceCheck(error, ArcaneAIError)) throw error;
|
|
192
195
|
throw invalidProgress(error);
|
|
193
196
|
}
|
|
194
197
|
}
|
|
195
198
|
|
|
196
199
|
function publicProgress(progress) {
|
|
197
|
-
return progress &&
|
|
200
|
+
return progress && is.object(progress) ? copyProgress(progress) : null;
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
function localRequirement(options, provider) {
|
|
201
|
-
if (options?.localOnly !== undefined &&
|
|
204
|
+
if (options?.localOnly !== undefined && !is.boolean(options.localOnly)) {
|
|
202
205
|
throw new TypeError("localOnly must be a boolean when provided.");
|
|
203
206
|
}
|
|
204
207
|
if (options?.localOnly === true && provider.capabilities?.().localOnly !== true) {
|
|
@@ -222,7 +225,7 @@ function linkedAbortSignal(externalSignal) {
|
|
|
222
225
|
}
|
|
223
226
|
|
|
224
227
|
function fireAndForget(callback, ...args) {
|
|
225
|
-
if (
|
|
228
|
+
if (!is.function(callback)) return;
|
|
226
229
|
try {
|
|
227
230
|
Promise.resolve(callback(...args)).catch(() => undefined);
|
|
228
231
|
} catch {
|
|
@@ -245,20 +248,20 @@ function displayRequestId(value) {
|
|
|
245
248
|
function completeTextValue(value, seen, location) {
|
|
246
249
|
if (value === null) return null;
|
|
247
250
|
if (value === undefined) return { $type: "undefined" };
|
|
248
|
-
if (
|
|
249
|
-
if (
|
|
251
|
+
if (is.bigint(value)) return { $type: "bigint", value: value.toString() };
|
|
252
|
+
if (is.number(value) && !is.finite(value)) {
|
|
250
253
|
return { $type: "number", value: String(value) };
|
|
251
254
|
}
|
|
252
|
-
if (
|
|
253
|
-
if (
|
|
255
|
+
if (is.symbol(value)) return { $type: "symbol", value: String(value) };
|
|
256
|
+
if (is.function(value)) {
|
|
254
257
|
return { $type: "function", value: Function.prototype.toString.call(value) };
|
|
255
258
|
}
|
|
256
|
-
if (
|
|
259
|
+
if (!is.object(value)) return value;
|
|
257
260
|
if (seen.has(value)) return { $ref: seen.get(value) };
|
|
258
261
|
seen.set(value, location);
|
|
259
|
-
if (value
|
|
260
|
-
if (value
|
|
261
|
-
if (value
|
|
262
|
+
if (is.instanceCheck(value, Date)) return { $type: "date", value: value.toISOString() };
|
|
263
|
+
if (is.instanceCheck(value, RegExp)) return { $type: "regexp", value: String(value) };
|
|
264
|
+
if (is.instanceCheck(value, Map)) {
|
|
262
265
|
return {
|
|
263
266
|
$type: "map",
|
|
264
267
|
entries: [...value.entries()].map(([key, entry], index) => [
|
|
@@ -267,7 +270,7 @@ function completeTextValue(value, seen, location) {
|
|
|
267
270
|
]),
|
|
268
271
|
};
|
|
269
272
|
}
|
|
270
|
-
if (value
|
|
273
|
+
if (is.instanceCheck(value, Set)) {
|
|
271
274
|
return {
|
|
272
275
|
$type: "set",
|
|
273
276
|
values: [...value].map((entry, index) => completeTextValue(
|
|
@@ -277,25 +280,25 @@ function completeTextValue(value, seen, location) {
|
|
|
277
280
|
)),
|
|
278
281
|
};
|
|
279
282
|
}
|
|
280
|
-
if (
|
|
283
|
+
if (is.arrayBufferView(value)) {
|
|
281
284
|
return {
|
|
282
285
|
$type: value.constructor?.name ?? "ArrayBufferView",
|
|
283
286
|
values: Array.from(
|
|
284
|
-
value
|
|
287
|
+
is.instanceCheck(value, DataView)
|
|
285
288
|
? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)
|
|
286
289
|
: value,
|
|
287
290
|
(entry, index) => completeTextValue(entry, seen, `${location}.values[${index}]`),
|
|
288
291
|
),
|
|
289
292
|
};
|
|
290
293
|
}
|
|
291
|
-
if (value
|
|
294
|
+
if (is.instanceCheck(value, ArrayBuffer)) {
|
|
292
295
|
return { $type: "ArrayBuffer", values: Array.from(new Uint8Array(value)) };
|
|
293
296
|
}
|
|
294
|
-
const copy =
|
|
297
|
+
const copy = is.array(value) ? [] : {};
|
|
295
298
|
for (const key of Reflect.ownKeys(value)) {
|
|
296
|
-
if (
|
|
299
|
+
if (is.array(value) && key === "length") continue;
|
|
297
300
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
298
|
-
const renderedKey =
|
|
301
|
+
const renderedKey = is.symbol(key) ? `[${String(key)}]` : key;
|
|
299
302
|
copy[renderedKey] = descriptor && "value" in descriptor
|
|
300
303
|
? completeTextValue(descriptor.value, seen, `${location}.${renderedKey}`)
|
|
301
304
|
: {
|
|
@@ -308,12 +311,12 @@ function completeTextValue(value, seen, location) {
|
|
|
308
311
|
}
|
|
309
312
|
|
|
310
313
|
export function completeValueText(value) {
|
|
311
|
-
if (
|
|
314
|
+
if (is.string(value)) return value;
|
|
312
315
|
return JSON.stringify(completeTextValue(value, new WeakMap(), "$"), null, 2);
|
|
313
316
|
}
|
|
314
317
|
|
|
315
318
|
function textFromCompletion(completion) {
|
|
316
|
-
if (!
|
|
319
|
+
if (!is.array(completion?.choices)) return completeValueText(completion);
|
|
317
320
|
if(completion.choices.length>1)return completeValueText(completion);
|
|
318
321
|
const choice=completion.choices[0];
|
|
319
322
|
const content=choice?.message?.content;
|
|
@@ -323,17 +326,17 @@ function textFromCompletion(completion) {
|
|
|
323
326
|
function structuralToolCall(call,location){
|
|
324
327
|
if(
|
|
325
328
|
!call
|
|
326
|
-
|
|
327
|
-
||
|
|
329
|
+
||!is.object(call)
|
|
330
|
+
||is.array(call)
|
|
328
331
|
||call.type!=="function"
|
|
329
|
-
|
|
332
|
+
||!is.string(call.id)
|
|
330
333
|
||!call.id.trim()
|
|
331
334
|
||!call.function
|
|
332
|
-
|
|
333
|
-
||
|
|
334
|
-
|
|
335
|
+
||!is.object(call.function)
|
|
336
|
+
||is.array(call.function)
|
|
337
|
+
||!is.string(call.function.name)
|
|
335
338
|
||!call.function.name.trim()
|
|
336
|
-
|
|
339
|
+
||!is.string(call.function.arguments)
|
|
337
340
|
){
|
|
338
341
|
throw new ArcaneAIError(
|
|
339
342
|
"ARCANE_AI_TOOL_CALL_INVALID",
|
|
@@ -353,8 +356,8 @@ function structuralToolCall(call,location){
|
|
|
353
356
|
}
|
|
354
357
|
if(
|
|
355
358
|
!argumentsRecord
|
|
356
|
-
|
|
357
|
-
||
|
|
359
|
+
||!is.object(argumentsRecord)
|
|
360
|
+
||is.array(argumentsRecord)
|
|
358
361
|
){
|
|
359
362
|
throw new ArcaneAIError(
|
|
360
363
|
"ARCANE_AI_TOOL_CALL_INVALID",
|
|
@@ -362,7 +365,7 @@ function structuralToolCall(call,location){
|
|
|
362
365
|
{operation:"request"},
|
|
363
366
|
);
|
|
364
367
|
}
|
|
365
|
-
if(
|
|
368
|
+
if(!is.string(argumentsRecord.message)||!argumentsRecord.message.trim()){
|
|
366
369
|
throw new ArcaneAIError(
|
|
367
370
|
"ARCANE_AI_TOOL_MESSAGE_REQUIRED",
|
|
368
371
|
`${location} arguments must include a nonempty user-facing message.`,
|
|
@@ -382,14 +385,14 @@ function structuralToolCall(call,location){
|
|
|
382
385
|
}
|
|
383
386
|
|
|
384
387
|
function plainStructuralRecord(value){
|
|
385
|
-
if(!value
|
|
388
|
+
if(!value||!is.object(value)||is.array(value)) return false;
|
|
386
389
|
const prototype=Object.getPrototypeOf(value);
|
|
387
390
|
return prototype===Object.prototype||prototype===null;
|
|
388
391
|
}
|
|
389
392
|
|
|
390
393
|
function requireToolMessageSchemas(value,location){
|
|
391
394
|
if(value===undefined) return;
|
|
392
|
-
if(!
|
|
395
|
+
if(!is.array(value)){
|
|
393
396
|
throw new ArcaneAIError(
|
|
394
397
|
"ARCANE_AI_TOOL_CALL_INVALID",
|
|
395
398
|
`${location} must be an array.`,
|
|
@@ -408,9 +411,9 @@ function requireToolMessageSchemas(value,location){
|
|
|
408
411
|
||!plainStructuralRecord(parameters.properties)
|
|
409
412
|
||!plainStructuralRecord(messageSchema)
|
|
410
413
|
||messageSchema.type!=="string"
|
|
411
|
-
||!
|
|
414
|
+
||!is.integer(messageSchema.minLength)
|
|
412
415
|
||messageSchema.minLength<1
|
|
413
|
-
||!
|
|
416
|
+
||!is.array(parameters.required)
|
|
414
417
|
||!parameters.required.includes("message")
|
|
415
418
|
){
|
|
416
419
|
throw new ArcaneAIError(
|
|
@@ -448,7 +451,7 @@ function structuralCallsFromMessage(message,location){
|
|
|
448
451
|
if(
|
|
449
452
|
!descriptor
|
|
450
453
|
||!Object.hasOwn(descriptor,"value")
|
|
451
|
-
||!
|
|
454
|
+
||!is.array(descriptor.value)
|
|
452
455
|
){
|
|
453
456
|
throw new ArcaneAIError(
|
|
454
457
|
"ARCANE_AI_TOOL_CALL_INVALID",
|
|
@@ -463,12 +466,12 @@ function structuralRequest(value){
|
|
|
463
466
|
if(!plainStructuralRecord(value)){
|
|
464
467
|
throw new TypeError("AI request options must be a plain object.");
|
|
465
468
|
}
|
|
466
|
-
if(value.messages!==undefined&&!
|
|
469
|
+
if(value.messages!==undefined&&!is.array(value.messages)){
|
|
467
470
|
throw new TypeError("AI request messages must be an array.");
|
|
468
471
|
}
|
|
469
472
|
requireToolMessageSchemas(value.tools,"AI request tools");
|
|
470
473
|
for(const key of ["parallelToolCalls","parallel_tool_calls"]){
|
|
471
|
-
if(Object.hasOwn(value,key)
|
|
474
|
+
if(Object.hasOwn(value,key)&&!is.boolean(value[key])){
|
|
472
475
|
throw new TypeError(`AI request ${key} must be a boolean when provided.`);
|
|
473
476
|
}
|
|
474
477
|
}
|
|
@@ -481,7 +484,7 @@ function structuralRequest(value){
|
|
|
481
484
|
);
|
|
482
485
|
let openedToolCall=false;
|
|
483
486
|
if(Object.hasOwn(message,"tool_calls")){
|
|
484
|
-
if(message?.role!=="assistant"||!
|
|
487
|
+
if(message?.role!=="assistant"||!is.array(calls)){
|
|
485
488
|
throw new ArcaneAIError(
|
|
486
489
|
"ARCANE_AI_TOOL_CALL_INVALID",
|
|
487
490
|
`AI request messages[${String(messageIndex)}].tool_calls is invalid.`,
|
|
@@ -515,7 +518,7 @@ function structuralRequest(value){
|
|
|
515
518
|
}
|
|
516
519
|
if(message?.role==="tool"){
|
|
517
520
|
if(
|
|
518
|
-
|
|
521
|
+
!is.string(message.content)
|
|
519
522
|
||!message.content.trim()
|
|
520
523
|
){
|
|
521
524
|
throw new ArcaneAIError(
|
|
@@ -526,7 +529,7 @@ function structuralRequest(value){
|
|
|
526
529
|
}
|
|
527
530
|
if(
|
|
528
531
|
!pendingToolCallIds.size
|
|
529
|
-
|
|
532
|
+
||!is.string(message.tool_call_id)
|
|
530
533
|
||!pendingToolCallIds.has(message.tool_call_id)
|
|
531
534
|
){
|
|
532
535
|
throw new ArcaneAIError(
|
|
@@ -556,7 +559,7 @@ function structuralRequest(value){
|
|
|
556
559
|
}
|
|
557
560
|
|
|
558
561
|
function toolRecordFromCompletion(completion) {
|
|
559
|
-
if(
|
|
562
|
+
if(is.string(completion))return null;
|
|
560
563
|
if(!plainStructuralRecord(completion)){
|
|
561
564
|
throw new ArcaneAIError(
|
|
562
565
|
"ARCANE_AI_INVALID_PROVIDER_RESULT",
|
|
@@ -595,7 +598,7 @@ function toolRecordFromCompletion(completion) {
|
|
|
595
598
|
if(
|
|
596
599
|
!descriptor
|
|
597
600
|
||!Object.hasOwn(descriptor,"value")
|
|
598
|
-
||!
|
|
601
|
+
||!is.array(descriptor.value)
|
|
599
602
|
||!descriptor.value.length
|
|
600
603
|
){
|
|
601
604
|
throw new ArcaneAIError(
|
|
@@ -611,7 +614,7 @@ function toolRecordFromCompletion(completion) {
|
|
|
611
614
|
:null;
|
|
612
615
|
if(
|
|
613
616
|
!plainStructuralRecord(choice)
|
|
614
|
-
||!
|
|
617
|
+
||!is.safeInteger(choice.index)
|
|
615
618
|
||choice.index<0
|
|
616
619
|
||indexes.has(choice.index)
|
|
617
620
|
||!messageDescriptor
|
|
@@ -669,9 +672,9 @@ function sameCompleteStreamValue(left,right,leftToRight=new Map(),rightToLeft=ne
|
|
|
669
672
|
if(
|
|
670
673
|
!left
|
|
671
674
|
||!right
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
||
|
|
675
|
+
||!is.object(left)
|
|
676
|
+
||!is.object(right)
|
|
677
|
+
||is.array(left)!==is.array(right)
|
|
675
678
|
)return false;
|
|
676
679
|
if(leftToRight.has(left)||rightToLeft.has(right)){
|
|
677
680
|
return leftToRight.get(left)===right&&rightToLeft.get(right)===left;
|
|
@@ -768,13 +771,13 @@ function createStreamedToolCallAccumulator(){
|
|
|
768
771
|
}
|
|
769
772
|
if(!Object.hasOwn(delta,"tool_calls"))return;
|
|
770
773
|
const descriptor=Object.getOwnPropertyDescriptor(delta,"tool_calls");
|
|
771
|
-
if(!descriptor||!Object.hasOwn(descriptor,"value")||!
|
|
774
|
+
if(!descriptor||!Object.hasOwn(descriptor,"value")||!is.array(descriptor.value)){
|
|
772
775
|
throw mismatch(`${location}.tool_calls must be an array data property.`);
|
|
773
776
|
}
|
|
774
777
|
for(const [fragmentPosition,fragment] of descriptor.value.entries()){
|
|
775
778
|
if(
|
|
776
779
|
!plainStructuralRecord(fragment)
|
|
777
|
-
||!
|
|
780
|
+
||!is.safeInteger(fragment.index)
|
|
778
781
|
||fragment.index<0
|
|
779
782
|
){
|
|
780
783
|
throw mismatch(
|
|
@@ -790,7 +793,7 @@ function createStreamedToolCallAccumulator(){
|
|
|
790
793
|
};
|
|
791
794
|
if(Object.hasOwn(fragment,"id")){
|
|
792
795
|
if(
|
|
793
|
-
|
|
796
|
+
!is.string(fragment.id)
|
|
794
797
|
||!fragment.id
|
|
795
798
|
||current.id&¤t.id!==fragment.id
|
|
796
799
|
){
|
|
@@ -800,7 +803,7 @@ function createStreamedToolCallAccumulator(){
|
|
|
800
803
|
}
|
|
801
804
|
if(Object.hasOwn(fragment,"type")){
|
|
802
805
|
if(
|
|
803
|
-
|
|
806
|
+
!is.string(fragment.type)
|
|
804
807
|
||!fragment.type
|
|
805
808
|
||current.type&¤t.type!==fragment.type
|
|
806
809
|
){
|
|
@@ -813,13 +816,13 @@ function createStreamedToolCallAccumulator(){
|
|
|
813
816
|
throw mismatch("A streamed structural tool call has an invalid function fragment.");
|
|
814
817
|
}
|
|
815
818
|
if(Object.hasOwn(fragment.function,"name")){
|
|
816
|
-
if(
|
|
819
|
+
if(!is.string(fragment.function.name)){
|
|
817
820
|
throw mismatch("A streamed structural tool call has an invalid function-name fragment.");
|
|
818
821
|
}
|
|
819
822
|
current.name+=fragment.function.name;
|
|
820
823
|
}
|
|
821
824
|
if(Object.hasOwn(fragment.function,"arguments")){
|
|
822
|
-
if(
|
|
825
|
+
if(!is.string(fragment.function.arguments)){
|
|
823
826
|
throw mismatch("A streamed structural tool call has an invalid arguments fragment.");
|
|
824
827
|
}
|
|
825
828
|
current.arguments+=fragment.function.arguments;
|
|
@@ -837,13 +840,13 @@ function createStreamedToolCallAccumulator(){
|
|
|
837
840
|
rememberDelta(state,chunk.delta,"The streamed model delta");
|
|
838
841
|
rememberCompleteMessage(state,chunk.message,"The streamed model message");
|
|
839
842
|
}
|
|
840
|
-
if(!
|
|
843
|
+
if(!is.array(chunk.choices)||!chunk.choices.length)return;
|
|
841
844
|
for(const [position,choice] of chunk.choices.entries()){
|
|
842
845
|
if(
|
|
843
846
|
!plainStructuralRecord(choice)
|
|
844
847
|
||(!structuralRecord(choice.delta)&&!structuralRecord(choice.message))
|
|
845
848
|
)continue;
|
|
846
|
-
if(!
|
|
849
|
+
if(!is.safeInteger(choice.index)||choice.index<0){
|
|
847
850
|
throw mismatch(
|
|
848
851
|
`The streamed model choice ${String(position)} has no valid choice index.`,
|
|
849
852
|
);
|
|
@@ -889,7 +892,7 @@ function createStreamedToolCallAccumulator(){
|
|
|
889
892
|
|
|
890
893
|
function terminalChoices(completion){
|
|
891
894
|
const result=new Map();
|
|
892
|
-
if(
|
|
895
|
+
if(is.string(completion))return result;
|
|
893
896
|
if(Object.hasOwn(completion,"message")){
|
|
894
897
|
result.set(
|
|
895
898
|
directChoice,
|
|
@@ -949,9 +952,9 @@ function isPublicStreamStructuralKey(key){
|
|
|
949
952
|
const OMITTED_PUBLIC_STREAM_DATA=Symbol("omitted-public-stream-data");
|
|
950
953
|
|
|
951
954
|
function projectPublicStreamData(value,seen=new Map()){
|
|
952
|
-
if(value===null||value===undefined
|
|
955
|
+
if(value===null||value===undefined||!is.object(value))return value;
|
|
953
956
|
if(seen.has(value))return seen.get(value);
|
|
954
|
-
if(
|
|
957
|
+
if(is.array(value)){
|
|
955
958
|
const result=[];
|
|
956
959
|
seen.set(value,result);
|
|
957
960
|
for(const item of value){
|
|
@@ -998,7 +1001,7 @@ export class ModelController {
|
|
|
998
1001
|
#error = null;
|
|
999
1002
|
|
|
1000
1003
|
constructor({ provider, loadPolicy = "on-demand", security } = {}) {
|
|
1001
|
-
if (!provider ||
|
|
1004
|
+
if (!provider || !is.object(provider)) {
|
|
1002
1005
|
throw new TypeError("ModelController requires an LLM provider.");
|
|
1003
1006
|
}
|
|
1004
1007
|
if (
|
|
@@ -1074,9 +1077,9 @@ export class ModelController {
|
|
|
1074
1077
|
this.#events.dispatch(type, status, {
|
|
1075
1078
|
operationId,
|
|
1076
1079
|
publicDetail: {
|
|
1077
|
-
...(
|
|
1080
|
+
...(is.string(status.state) ? { state: status.state } : {}),
|
|
1078
1081
|
...(progress ? { progress } : {}),
|
|
1079
|
-
...(
|
|
1082
|
+
...(is.string(status.error?.code) ? { code: status.error.code } : {}),
|
|
1080
1083
|
},
|
|
1081
1084
|
});
|
|
1082
1085
|
}
|
|
@@ -1364,12 +1367,12 @@ export class ModelController {
|
|
|
1364
1367
|
);
|
|
1365
1368
|
if (
|
|
1366
1369
|
!value
|
|
1367
|
-
|
|
1368
|
-
|
|
1370
|
+
||!is.function(value[Symbol.asyncIterator])
|
|
1371
|
+
||!is.function(value.cancel)
|
|
1369
1372
|
||!value.result
|
|
1370
|
-
|
|
1373
|
+
||!is.function(value.result.then)
|
|
1371
1374
|
) {
|
|
1372
|
-
if(
|
|
1375
|
+
if(is.function(value?.cancel)){
|
|
1373
1376
|
Promise.resolve().then(()=>value.cancel(
|
|
1374
1377
|
"The provider returned an invalid stream handle.",
|
|
1375
1378
|
)).catch(function reportInvalidModelStreamCleanupFailure(error){
|
|
@@ -1392,7 +1395,7 @@ export class ModelController {
|
|
|
1392
1395
|
);
|
|
1393
1396
|
throw error;
|
|
1394
1397
|
}
|
|
1395
|
-
if(!iterator
|
|
1398
|
+
if(!iterator||!is.function(iterator.next)){
|
|
1396
1399
|
Promise.resolve().then(()=>value.cancel(
|
|
1397
1400
|
"The provider returned an invalid stream iterator.",
|
|
1398
1401
|
)).catch(function reportInvalidModelIteratorCleanupFailure(error){
|
|
@@ -1520,7 +1523,7 @@ export class ModelController {
|
|
|
1520
1523
|
throw normalizeArcaneAIError(null, { operation: "request", signal: options.signal });
|
|
1521
1524
|
}
|
|
1522
1525
|
toolRecordFromCompletion(response);
|
|
1523
|
-
if (
|
|
1526
|
+
if (is.function(options.onResponse)) {
|
|
1524
1527
|
await options.onResponse(response, id, false);
|
|
1525
1528
|
}
|
|
1526
1529
|
return response;
|
|
@@ -1539,21 +1542,21 @@ export class ModelController {
|
|
|
1539
1542
|
for await (const chunk of handle) {
|
|
1540
1543
|
if (options.signal?.aborted) break;
|
|
1541
1544
|
await options.onDataChunk?.(chunk, id);
|
|
1542
|
-
if(
|
|
1545
|
+
if(is.string(chunk)){
|
|
1543
1546
|
if(chunk)await options.onChunk?.(chunk, displayId, false);
|
|
1544
1547
|
continue;
|
|
1545
1548
|
}
|
|
1546
|
-
const streamedChoices=
|
|
1549
|
+
const streamedChoices=is.array(chunk?.choices)?chunk.choices:[];
|
|
1547
1550
|
for(const choice of streamedChoices){
|
|
1548
1551
|
const delta = choice?.delta ?? {};
|
|
1549
1552
|
if (
|
|
1550
|
-
|
|
1553
|
+
is.string(delta.reasoning_content)
|
|
1551
1554
|
&&delta.reasoning_content
|
|
1552
1555
|
&&options.seeThinking === true
|
|
1553
1556
|
) {
|
|
1554
1557
|
await options.onChunk?.(delta.reasoning_content, displayId, true);
|
|
1555
1558
|
}
|
|
1556
|
-
if (
|
|
1559
|
+
if (is.string(delta.content)&&delta.content) {
|
|
1557
1560
|
await options.onChunk?.(delta.content, displayId, false);
|
|
1558
1561
|
}
|
|
1559
1562
|
}
|
|
@@ -1564,17 +1567,17 @@ export class ModelController {
|
|
|
1564
1567
|
}
|
|
1565
1568
|
const tools = toolRecordFromCompletion(completion);
|
|
1566
1569
|
await options.onDataResult?.(completion, id);
|
|
1567
|
-
if (
|
|
1570
|
+
if (is.function(options.onResponse)) {
|
|
1568
1571
|
await options.onResponse(completion, id, false);
|
|
1569
1572
|
}
|
|
1570
1573
|
for (const call of tools ?? []) {
|
|
1571
1574
|
await options.onToolCall?.(call, displayId);
|
|
1572
1575
|
}
|
|
1573
|
-
const multipleChoices=
|
|
1576
|
+
const multipleChoices=is.array(completion?.choices)&&completion.choices.length>1;
|
|
1574
1577
|
const output = multipleChoices
|
|
1575
1578
|
?textFromCompletion(completion)
|
|
1576
1579
|
:tools??textFromCompletion(completion);
|
|
1577
|
-
if (
|
|
1580
|
+
if (is.function(options.onComplete)) {
|
|
1578
1581
|
await options.onComplete(output, displayId, false);
|
|
1579
1582
|
}
|
|
1580
1583
|
return output;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from "../dependencies/strong-type/index.js";
|
|
1
2
|
import {
|
|
2
3
|
collectSpeechTransferables,
|
|
3
4
|
normalizeSpeechWorkerErrorEnvelope,
|
|
@@ -5,6 +6,8 @@ import {
|
|
|
5
6
|
} from "./speech-worker-runtime.mjs";
|
|
6
7
|
import { arcaneLogging } from "../logging.mjs";
|
|
7
8
|
|
|
9
|
+
const is = new Is(false);
|
|
10
|
+
|
|
8
11
|
const completeValue = (value) => value;
|
|
9
12
|
let nextSpeechWorkerClientId = 0;
|
|
10
13
|
|
|
@@ -25,7 +28,7 @@ function clientError(code, message, cause, reason) {
|
|
|
25
28
|
? "AbortError"
|
|
26
29
|
: "ArcaneSpeechWorkerError";
|
|
27
30
|
error.code = code;
|
|
28
|
-
if (
|
|
31
|
+
if (is.string(reason) && reason) error.reason = reason;
|
|
29
32
|
WORKER_CLIENT_ERRORS.add(error);
|
|
30
33
|
return error;
|
|
31
34
|
}
|
|
@@ -45,7 +48,7 @@ function abortError(signal, role, op) {
|
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
function validateWorker(worker) {
|
|
48
|
-
if (!worker ||
|
|
51
|
+
if (!worker || !is.function(worker.postMessage) || !is.function(worker.terminate)) {
|
|
49
52
|
throw new TypeError("The packaged speech worker did not create a Worker.");
|
|
50
53
|
}
|
|
51
54
|
return worker;
|
|
@@ -74,7 +77,7 @@ class SpeechWorkerClient {
|
|
|
74
77
|
if (role !== "stt" && role !== "tts") {
|
|
75
78
|
throw new TypeError('SpeechWorkerClient role must be "stt" or "tts".');
|
|
76
79
|
}
|
|
77
|
-
if (
|
|
80
|
+
if (!is.function(onTermination)) {
|
|
78
81
|
throw new TypeError("SpeechWorkerClient onTermination must be a function.");
|
|
79
82
|
}
|
|
80
83
|
const workerUrl = role === "stt"
|
|
@@ -163,7 +166,7 @@ class SpeechWorkerClient {
|
|
|
163
166
|
), { intentional: false }).catch(() => undefined);
|
|
164
167
|
return;
|
|
165
168
|
}
|
|
166
|
-
if (!
|
|
169
|
+
if (!is.safeInteger(message.id) || !is.boolean(message.ok)) {
|
|
167
170
|
void this.terminate(clientError(
|
|
168
171
|
"ARCANE_AI_WORKER_MESSAGE_ERROR",
|
|
169
172
|
"The speech Worker response envelope shape was rejected.",
|
|
@@ -313,16 +316,16 @@ class SpeechWorkerClient {
|
|
|
313
316
|
|
|
314
317
|
async terminate(reason = null, { intentional = true } = {}) {
|
|
315
318
|
this.#trace("terminate.call", { reason, intentional });
|
|
316
|
-
if (
|
|
319
|
+
if (!is.boolean(intentional)) {
|
|
317
320
|
throw new TypeError("Speech Worker termination intent must be a boolean.");
|
|
318
321
|
}
|
|
319
322
|
if (this.#terminated) return;
|
|
320
|
-
const terminationReason = reason
|
|
323
|
+
const terminationReason = is.error(reason) && WORKER_CLIENT_ERRORS.has(reason)
|
|
321
324
|
? reason
|
|
322
325
|
: clientError(
|
|
323
326
|
"ARCANE_AI_OPERATION_SUPERSEDED",
|
|
324
327
|
"The speech Worker was terminated.",
|
|
325
|
-
reason
|
|
328
|
+
is.error(reason) ? reason : undefined,
|
|
326
329
|
`${this.#role}-worker-terminated`,
|
|
327
330
|
);
|
|
328
331
|
this.#terminated = true;
|
|
@@ -341,7 +344,7 @@ class SpeechWorkerClient {
|
|
|
341
344
|
try {
|
|
342
345
|
this.#transport = null;
|
|
343
346
|
const termination = worker?.terminate();
|
|
344
|
-
if (termination &&
|
|
347
|
+
if (termination && is.function(termination.then)) await termination;
|
|
345
348
|
} finally {
|
|
346
349
|
for (const pending of pendingOperations) pending.reject(terminationReason);
|
|
347
350
|
this.#trace("terminated", { reason: terminationReason, intentional });
|
|
@@ -359,5 +362,5 @@ export function isSpeechWorkerClient(value) {
|
|
|
359
362
|
}
|
|
360
363
|
|
|
361
364
|
export function isSpeechWorkerClientError(value) {
|
|
362
|
-
return value
|
|
365
|
+
return is.error(value) && WORKER_CLIENT_ERRORS.has(value);
|
|
363
366
|
}
|