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,3 +1,7 @@
|
|
|
1
|
+
import Is from "../dependencies/strong-type/index.js";
|
|
2
|
+
|
|
3
|
+
const is = new Is(false);
|
|
4
|
+
|
|
1
5
|
export const SPEECH_WORKER_PROTOCOL = "arcane-ai-speech-worker/1";
|
|
2
6
|
|
|
3
7
|
const completeValue = (value) => value;
|
|
@@ -266,14 +270,14 @@ function workerError(code, message, cause, reason) {
|
|
|
266
270
|
? "AbortError"
|
|
267
271
|
: "ArcaneSpeechWorkerError";
|
|
268
272
|
error.code = code;
|
|
269
|
-
if (
|
|
273
|
+
if (is.string(reason) && reason) error.reason = reason;
|
|
270
274
|
SDK_WORKER_ERRORS.add(error);
|
|
271
275
|
return error;
|
|
272
276
|
}
|
|
273
277
|
|
|
274
278
|
function isSdkWorkerError(value) {
|
|
275
279
|
try {
|
|
276
|
-
return value
|
|
280
|
+
return is.error(value) && SDK_WORKER_ERRORS.has(value);
|
|
277
281
|
} catch {
|
|
278
282
|
return false;
|
|
279
283
|
}
|
|
@@ -307,20 +311,20 @@ export function collectSpeechTransferables(value) {
|
|
|
307
311
|
const buffers = new Set();
|
|
308
312
|
const seen = new WeakSet();
|
|
309
313
|
function visit(candidate) {
|
|
310
|
-
if (candidate
|
|
314
|
+
if (is.instanceCheck(candidate, ArrayBuffer)) {
|
|
311
315
|
if (!buffers.has(candidate)) {
|
|
312
316
|
buffers.add(candidate);
|
|
313
317
|
transfers.push(candidate);
|
|
314
318
|
}
|
|
315
319
|
return;
|
|
316
320
|
}
|
|
317
|
-
if (
|
|
321
|
+
if (is.arrayBufferView(candidate)) {
|
|
318
322
|
visit(candidate.buffer);
|
|
319
323
|
return;
|
|
320
324
|
}
|
|
321
|
-
if (!candidate ||
|
|
325
|
+
if (!candidate || !is.object(candidate) || seen.has(candidate)) return;
|
|
322
326
|
seen.add(candidate);
|
|
323
|
-
for (const child of
|
|
327
|
+
for (const child of is.array(candidate)
|
|
324
328
|
? candidate
|
|
325
329
|
: Object.values(candidate)) visit(child);
|
|
326
330
|
}
|
|
@@ -352,7 +356,7 @@ function serializedError(error, role, op) {
|
|
|
352
356
|
&& admission?.code === reportedCode;
|
|
353
357
|
const code = admittedCode ? reportedCode : "ARCANE_AI_PROVIDER_REQUEST_FAILED";
|
|
354
358
|
const reason = admittedCode ? reportedReason : operationFailureReason(role, op);
|
|
355
|
-
const message =
|
|
359
|
+
const message = is.string(reportedMessage) && reportedMessage.length > 0
|
|
356
360
|
? reportedMessage
|
|
357
361
|
: WORKER_ERROR_MESSAGES[code];
|
|
358
362
|
const envelope = completeValue({
|
|
@@ -373,7 +377,7 @@ function fallbackSerializedError(error, role, op) {
|
|
|
373
377
|
return completeValue({
|
|
374
378
|
protocol: SPEECH_WORKER_ERROR_PROTOCOL,
|
|
375
379
|
code: "ARCANE_AI_PROVIDER_REQUEST_FAILED",
|
|
376
|
-
message:
|
|
380
|
+
message: is.string(message) && message.length > 0
|
|
377
381
|
? message
|
|
378
382
|
: WORKER_ERROR_MESSAGES.ARCANE_AI_PROVIDER_REQUEST_FAILED,
|
|
379
383
|
reason: operationFailureReason(role, op),
|
|
@@ -424,9 +428,8 @@ function diagnosticType(value) {
|
|
|
424
428
|
|
|
425
429
|
function serializedDiagnosticValue(value, seen = new WeakMap()) {
|
|
426
430
|
if (value === null || value === undefined) return value;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
return type === "symbol"
|
|
431
|
+
if (is.primitive(value)) {
|
|
432
|
+
return is.symbol(value)
|
|
430
433
|
? diagnosticText(value, "[symbol could not be represented]")
|
|
431
434
|
: value;
|
|
432
435
|
}
|
|
@@ -473,7 +476,7 @@ function serializedDiagnosticValue(value, seen = new WeakMap()) {
|
|
|
473
476
|
);
|
|
474
477
|
}
|
|
475
478
|
}
|
|
476
|
-
if (
|
|
479
|
+
if (is.symbol(key)) {
|
|
477
480
|
const symbolProperty = Object.create(null);
|
|
478
481
|
defineDiagnosticProperty(
|
|
479
482
|
symbolProperty,
|
|
@@ -516,7 +519,7 @@ function serializedDiagnosticValue(value, seen = new WeakMap()) {
|
|
|
516
519
|
defineDiagnosticProperty(metadata, "symbolProperties", symbolProperties);
|
|
517
520
|
}
|
|
518
521
|
try {
|
|
519
|
-
if (
|
|
522
|
+
if (is.function(value)) {
|
|
520
523
|
defineDiagnosticProperty(
|
|
521
524
|
metadata,
|
|
522
525
|
"source",
|
|
@@ -547,7 +550,7 @@ function serializedDiagnosticValue(value, seen = new WeakMap()) {
|
|
|
547
550
|
} else {
|
|
548
551
|
let view = false;
|
|
549
552
|
try {
|
|
550
|
-
view =
|
|
553
|
+
view = is.arrayBufferView(value);
|
|
551
554
|
} catch {}
|
|
552
555
|
if (view) defineDiagnosticProperty(metadata, "value", value);
|
|
553
556
|
}
|
|
@@ -572,11 +575,11 @@ function workerErrorReasonAdmission(reason, role, op) {
|
|
|
572
575
|
}
|
|
573
576
|
|
|
574
577
|
export function normalizeSpeechWorkerErrorEnvelope(value, role, op) {
|
|
575
|
-
if (!value ||
|
|
578
|
+
if (!value || !is.object(value) || is.array(value)) return null;
|
|
576
579
|
let descriptors;
|
|
577
580
|
try {
|
|
578
581
|
const keys = Reflect.ownKeys(value);
|
|
579
|
-
if (keys.some((key) =>
|
|
582
|
+
if (keys.some((key) => !is.string(key))
|
|
580
583
|
|| ![
|
|
581
584
|
"code,message,protocol,reason",
|
|
582
585
|
"cause,code,message,protocol,reason",
|
|
@@ -594,7 +597,7 @@ export function normalizeSpeechWorkerErrorEnvelope(value, role, op) {
|
|
|
594
597
|
const reason = descriptors.reason.value;
|
|
595
598
|
if (protocol !== SPEECH_WORKER_ERROR_PROTOCOL) return null;
|
|
596
599
|
if (!Object.hasOwn(WORKER_ERROR_MESSAGES, code)) return null;
|
|
597
|
-
if (
|
|
600
|
+
if (!is.string(message) || message.length < 1) return null;
|
|
598
601
|
const admission = workerErrorReasonAdmission(reason, role, op);
|
|
599
602
|
if (admission?.code !== code) return null;
|
|
600
603
|
if (descriptors.cause && !Object.hasOwn(descriptors.cause, "value")) return null;
|
|
@@ -611,7 +614,7 @@ function requiredText(
|
|
|
611
614
|
label,
|
|
612
615
|
reason,
|
|
613
616
|
) {
|
|
614
|
-
if (
|
|
617
|
+
if (!is.string(value) || !value.trim()) {
|
|
615
618
|
throw workerError(
|
|
616
619
|
"ARCANE_AI_INVALID_REQUEST",
|
|
617
620
|
`${label} is required.`,
|
|
@@ -627,7 +630,7 @@ function requiredContent(
|
|
|
627
630
|
label,
|
|
628
631
|
reason,
|
|
629
632
|
) {
|
|
630
|
-
if (
|
|
633
|
+
if (!is.string(value) || !value.trim()) {
|
|
631
634
|
throw workerError(
|
|
632
635
|
"ARCANE_AI_INVALID_REQUEST",
|
|
633
636
|
`${label} is required.`,
|
|
@@ -640,7 +643,7 @@ function requiredContent(
|
|
|
640
643
|
|
|
641
644
|
function requiredSampleRate(value, label, fallback) {
|
|
642
645
|
const candidate = value ?? fallback;
|
|
643
|
-
if (!
|
|
646
|
+
if (!is.safeInteger(candidate) || candidate < 1) {
|
|
644
647
|
throw workerError(
|
|
645
648
|
"ARCANE_AI_INVALID_REQUEST",
|
|
646
649
|
`${label} must be a positive safe integer.`,
|
|
@@ -656,7 +659,7 @@ function graphConfiguration(configuration) {
|
|
|
656
659
|
}
|
|
657
660
|
|
|
658
661
|
function validateMaterializedFile(file, label) {
|
|
659
|
-
if (!file ||
|
|
662
|
+
if (!file || !is.object(file) || is.array(file)) {
|
|
660
663
|
throw workerError(
|
|
661
664
|
"ARCANE_AI_INVALID_REQUEST",
|
|
662
665
|
`${label} must be an object.`,
|
|
@@ -668,7 +671,7 @@ function validateMaterializedFile(file, label) {
|
|
|
668
671
|
requiredText(file.sourceUrl, `${label} sourceUrl`, "artifact-graph-materialized-source-url-empty");
|
|
669
672
|
requiredText(file.moduleUrl, `${label} moduleUrl`, "artifact-graph-materialized-module-url-empty");
|
|
670
673
|
requiredText(file.mediaType, `${label} mediaType`, "artifact-graph-materialized-media-type-empty");
|
|
671
|
-
if (file.runtimeRequestUrls !== undefined && !
|
|
674
|
+
if (file.runtimeRequestUrls !== undefined && !is.array(file.runtimeRequestUrls)) {
|
|
672
675
|
throw workerError(
|
|
673
676
|
"ARCANE_AI_INVALID_REQUEST",
|
|
674
677
|
`${label} runtimeRequestUrls must be an array.`,
|
|
@@ -680,7 +683,7 @@ function validateMaterializedFile(file, label) {
|
|
|
680
683
|
}
|
|
681
684
|
|
|
682
685
|
function validateConfiguration(configuration, role) {
|
|
683
|
-
if (!configuration ||
|
|
686
|
+
if (!configuration || !is.object(configuration) || is.array(configuration)) {
|
|
684
687
|
throw workerError(
|
|
685
688
|
"ARCANE_AI_INVALID_REQUEST",
|
|
686
689
|
"Speech worker configuration is required.",
|
|
@@ -707,7 +710,7 @@ function validateConfiguration(configuration, role) {
|
|
|
707
710
|
requiredText(configuration.runtime?.entry, "Speech runtime entry", "speech-worker-runtime-entry-empty");
|
|
708
711
|
const execution = configuration.execution;
|
|
709
712
|
if (execution !== undefined) {
|
|
710
|
-
if (!execution ||
|
|
713
|
+
if (!execution || !is.object(execution) || is.array(execution)) {
|
|
711
714
|
throw workerError(
|
|
712
715
|
"ARCANE_AI_INVALID_REQUEST",
|
|
713
716
|
"Speech worker execution must be a plain data record.",
|
|
@@ -748,7 +751,7 @@ function validateConfiguration(configuration, role) {
|
|
|
748
751
|
);
|
|
749
752
|
}
|
|
750
753
|
}
|
|
751
|
-
if (!
|
|
754
|
+
if (!is.array(configuration.runtime?.files) || !is.array(configuration.model?.files)) {
|
|
752
755
|
throw workerError(
|
|
753
756
|
"ARCANE_AI_INVALID_REQUEST",
|
|
754
757
|
"Speech runtime and model files are required.",
|
|
@@ -811,7 +814,7 @@ function validateConfiguration(configuration, role) {
|
|
|
811
814
|
}
|
|
812
815
|
if (
|
|
813
816
|
wasm.numThreads !== undefined
|
|
814
|
-
&& (!
|
|
817
|
+
&& (!is.safeInteger(wasm.numThreads) || wasm.numThreads < 1)
|
|
815
818
|
) {
|
|
816
819
|
throw workerError(
|
|
817
820
|
"ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
|
|
@@ -826,7 +829,7 @@ function validateConfiguration(configuration, role) {
|
|
|
826
829
|
} else {
|
|
827
830
|
requiredSampleRate(configuration.model.outputSampleRate, "Kokoro outputSampleRate");
|
|
828
831
|
requiredText(configuration.model.defaultVoice, "Kokoro defaultVoice", "tts-default-voice-empty");
|
|
829
|
-
if (!
|
|
832
|
+
if (!is.array(configuration.model.voices) || configuration.model.voices.length < 1) {
|
|
830
833
|
throw workerError(
|
|
831
834
|
"ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
|
|
832
835
|
"Kokoro graph configuration requires the caller-owned voice inventory.",
|
|
@@ -852,7 +855,7 @@ function nestedWorkerUrl(role) {
|
|
|
852
855
|
|
|
853
856
|
function nestedWorkerFailureEvent(scope, error) {
|
|
854
857
|
const ErrorEventConstructor = scope.ErrorEvent ?? globalThis.ErrorEvent;
|
|
855
|
-
if (
|
|
858
|
+
if (is.function(ErrorEventConstructor)) {
|
|
856
859
|
return new ErrorEventConstructor("error", {
|
|
857
860
|
error,
|
|
858
861
|
message: error.message,
|
|
@@ -869,10 +872,10 @@ function nestedWorkerFailureEvent(scope, error) {
|
|
|
869
872
|
}
|
|
870
873
|
|
|
871
874
|
function ordinaryRequestUrl(value, scope, base = scope.location?.href) {
|
|
872
|
-
const input =
|
|
875
|
+
const input = is.string(value) || is.instanceCheck(value, URL)
|
|
873
876
|
? String(value)
|
|
874
877
|
: value?.url;
|
|
875
|
-
if (
|
|
878
|
+
if (!is.string(input) || input.length < 1) return null;
|
|
876
879
|
try {
|
|
877
880
|
return new URL(input, base).href;
|
|
878
881
|
} catch {
|
|
@@ -881,7 +884,7 @@ function ordinaryRequestUrl(value, scope, base = scope.location?.href) {
|
|
|
881
884
|
}
|
|
882
885
|
|
|
883
886
|
function isBareModuleSpecifier(value) {
|
|
884
|
-
return
|
|
887
|
+
return is.string(value)
|
|
885
888
|
&& !value.startsWith("./")
|
|
886
889
|
&& !value.startsWith("../")
|
|
887
890
|
&& !value.startsWith("/")
|
|
@@ -932,7 +935,7 @@ function createOrdinaryRouteReader(
|
|
|
932
935
|
}
|
|
933
936
|
|
|
934
937
|
function nativeInput(input, modulePath) {
|
|
935
|
-
if (
|
|
938
|
+
if (!is.string(input) && !is.instanceCheck(input, URL)) return input;
|
|
936
939
|
return ordinaryRequestUrl(input, scope, sourceBase(modulePath)) ?? input;
|
|
937
940
|
}
|
|
938
941
|
|
|
@@ -943,15 +946,15 @@ function createOrdinaryRouteReader(
|
|
|
943
946
|
}
|
|
944
947
|
|
|
945
948
|
function responseFor(resolution, input, init) {
|
|
946
|
-
const mappedInput =
|
|
947
|
-
&& input
|
|
949
|
+
const mappedInput = is.function(RequestConstructor)
|
|
950
|
+
&& is.instanceCheck(input, RequestConstructor)
|
|
948
951
|
? new RequestConstructor(resolution.file.moduleUrl, input)
|
|
949
952
|
: resolution.file.moduleUrl;
|
|
950
953
|
return originalFetch(mappedInput, init);
|
|
951
954
|
}
|
|
952
955
|
|
|
953
956
|
async function nativeCache(name) {
|
|
954
|
-
if (!originalCaches ||
|
|
957
|
+
if (!originalCaches || !is.function(originalCaches.open)) return null;
|
|
955
958
|
if (!nativeCaches.has(name)) {
|
|
956
959
|
nativeCaches.set(name, Promise.resolve(originalCaches.open.call(originalCaches, name)));
|
|
957
960
|
}
|
|
@@ -1031,7 +1034,7 @@ function createOrdinaryArtifactModuleRouter(
|
|
|
1031
1034
|
},
|
|
1032
1035
|
|
|
1033
1036
|
createWorker(modulePath, specifier, options = {}) {
|
|
1034
|
-
if (
|
|
1037
|
+
if (!is.function(originalWorker)) {
|
|
1035
1038
|
throw workerError(
|
|
1036
1039
|
"ARCANE_AI_PROVIDER_UNAVAILABLE",
|
|
1037
1040
|
"Nested browser Workers are unavailable.",
|
|
@@ -1043,7 +1046,7 @@ function createOrdinaryArtifactModuleRouter(
|
|
|
1043
1046
|
if (!resolution) {
|
|
1044
1047
|
return new originalWorker(reader.nativeInput(specifier, modulePath), options);
|
|
1045
1048
|
}
|
|
1046
|
-
const workerOptions = options &&
|
|
1049
|
+
const workerOptions = options && is.object(options)
|
|
1047
1050
|
? { ...options, type: "module" }
|
|
1048
1051
|
: { type: "module" };
|
|
1049
1052
|
const worker = new originalWorker(nestedWorkerUrl(role), workerOptions);
|
|
@@ -1105,7 +1108,7 @@ function installOrdinaryArtifactModuleRouter(scope, configuration, role) {
|
|
|
1105
1108
|
const originalFetch = scope.fetch?.bind(scope);
|
|
1106
1109
|
const originalWorker = scope.Worker;
|
|
1107
1110
|
const originalCaches = scope.caches;
|
|
1108
|
-
if (
|
|
1111
|
+
if (!is.function(originalFetch)) {
|
|
1109
1112
|
throw workerError(
|
|
1110
1113
|
"ARCANE_AI_PROVIDER_UNAVAILABLE",
|
|
1111
1114
|
"Browser fetch is unavailable in the speech Worker.",
|
|
@@ -1338,20 +1341,20 @@ function configureRuntimeNamespace(namespace, configuration, role, cache) {
|
|
|
1338
1341
|
|
|
1339
1342
|
async function disposeEngine(engine) {
|
|
1340
1343
|
if (!engine) return;
|
|
1341
|
-
if (
|
|
1344
|
+
if (is.function(engine.dispose)) {
|
|
1342
1345
|
await engine.dispose();
|
|
1343
1346
|
return;
|
|
1344
1347
|
}
|
|
1345
1348
|
const disposed = new Set();
|
|
1346
1349
|
for (const part of [engine.model, engine.tokenizer, engine.processor]) {
|
|
1347
|
-
if (!part || disposed.has(part) ||
|
|
1350
|
+
if (!part || disposed.has(part) || !is.function(part.dispose)) continue;
|
|
1348
1351
|
disposed.add(part);
|
|
1349
1352
|
await part.dispose();
|
|
1350
1353
|
}
|
|
1351
1354
|
}
|
|
1352
1355
|
|
|
1353
1356
|
async function createWhisperEngine(namespace, configuration, signal, report) {
|
|
1354
|
-
if (
|
|
1357
|
+
if (!is.function(namespace?.pipeline)) {
|
|
1355
1358
|
throw workerError(
|
|
1356
1359
|
"ARCANE_AI_PROVIDER_UNAVAILABLE",
|
|
1357
1360
|
"The Whisper runtime does not export pipeline().",
|
|
@@ -1392,7 +1395,7 @@ async function createWhisperEngine(namespace, configuration, signal, report) {
|
|
|
1392
1395
|
}
|
|
1393
1396
|
|
|
1394
1397
|
async function createKokoroEngine(namespace, configuration, signal, report) {
|
|
1395
|
-
if (
|
|
1398
|
+
if (!is.function(namespace?.KokoroTTS?.from_pretrained)) {
|
|
1396
1399
|
throw workerError(
|
|
1397
1400
|
"ARCANE_AI_PROVIDER_UNAVAILABLE",
|
|
1398
1401
|
"The Kokoro runtime does not export KokoroTTS.",
|
|
@@ -1429,7 +1432,7 @@ async function createKokoroEngine(namespace, configuration, signal, report) {
|
|
|
1429
1432
|
signal: requestSignal,
|
|
1430
1433
|
});
|
|
1431
1434
|
throwIfAborted(requestSignal, "tts-synthesis-cancelled");
|
|
1432
|
-
const audio = output?.audio
|
|
1435
|
+
const audio = is.instanceCheck(output?.audio, Float32Array)
|
|
1433
1436
|
? output.audio
|
|
1434
1437
|
: new Float32Array(output?.audio ?? []);
|
|
1435
1438
|
return completeValue({
|
|
@@ -1444,7 +1447,7 @@ async function createKokoroEngine(namespace, configuration, signal, report) {
|
|
|
1444
1447
|
|
|
1445
1448
|
function callerVoiceIds(configuration) {
|
|
1446
1449
|
return new Set((configuration.model.voices ?? []).map((voice) =>
|
|
1447
|
-
|
|
1450
|
+
is.string(voice) ? voice : voice?.id));
|
|
1448
1451
|
}
|
|
1449
1452
|
|
|
1450
1453
|
function validateInput(role, payload, configuration) {
|
|
@@ -1454,7 +1457,7 @@ function validateInput(role, payload, configuration) {
|
|
|
1454
1457
|
"Whisper inputSampleRate",
|
|
1455
1458
|
16_000,
|
|
1456
1459
|
);
|
|
1457
|
-
if (!(payload?.audio
|
|
1460
|
+
if (!is.instanceCheck(payload?.audio, Float32Array)) {
|
|
1458
1461
|
throw workerError(
|
|
1459
1462
|
"ARCANE_AI_INVALID_REQUEST",
|
|
1460
1463
|
"Whisper requires Float32Array audio.",
|
|
@@ -1488,7 +1491,7 @@ function validateInput(role, payload, configuration) {
|
|
|
1488
1491
|
);
|
|
1489
1492
|
}
|
|
1490
1493
|
const speed = payload?.speed ?? 1;
|
|
1491
|
-
if (!
|
|
1494
|
+
if (!is.finite(speed) || speed <= 0) {
|
|
1492
1495
|
throw workerError(
|
|
1493
1496
|
"ARCANE_AI_INVALID_REQUEST",
|
|
1494
1497
|
"Kokoro speed must be greater than 0.",
|
|
@@ -1501,7 +1504,7 @@ function validateInput(role, payload, configuration) {
|
|
|
1501
1504
|
|
|
1502
1505
|
function validateResult(role, result, configuration) {
|
|
1503
1506
|
if (role === "stt") {
|
|
1504
|
-
if (!result ||
|
|
1507
|
+
if (!result || !is.string(result.text)) {
|
|
1505
1508
|
throw workerError(
|
|
1506
1509
|
"ARCANE_AI_INVALID_PROVIDER_RESULT",
|
|
1507
1510
|
"Whisper did not return text.",
|
|
@@ -1516,7 +1519,7 @@ function validateResult(role, result, configuration) {
|
|
|
1516
1519
|
"Kokoro outputSampleRate",
|
|
1517
1520
|
24_000,
|
|
1518
1521
|
);
|
|
1519
|
-
if (!(result?.audio
|
|
1522
|
+
if (!is.instanceCheck(result?.audio, Float32Array)) {
|
|
1520
1523
|
throw workerError(
|
|
1521
1524
|
"ARCANE_AI_INVALID_PROVIDER_RESULT",
|
|
1522
1525
|
"Kokoro must return Float32 PCM.",
|
|
@@ -1533,7 +1536,7 @@ function validateResult(role, result, configuration) {
|
|
|
1533
1536
|
);
|
|
1534
1537
|
}
|
|
1535
1538
|
for (const sample of result.audio) {
|
|
1536
|
-
if (!
|
|
1539
|
+
if (!is.finite(sample)) {
|
|
1537
1540
|
throw workerError(
|
|
1538
1541
|
"ARCANE_AI_INVALID_PROVIDER_RESULT",
|
|
1539
1542
|
"Kokoro returned non-finite PCM.",
|
|
@@ -1553,7 +1556,7 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
|
|
|
1553
1556
|
if (role !== "stt" && role !== "tts") {
|
|
1554
1557
|
throw new TypeError('Speech worker role must be "stt" or "tts".');
|
|
1555
1558
|
}
|
|
1556
|
-
if (
|
|
1559
|
+
if (!is.function(send)) {
|
|
1557
1560
|
throw new TypeError("Speech worker send() is required.");
|
|
1558
1561
|
}
|
|
1559
1562
|
let configuration = null;
|
|
@@ -1659,7 +1662,7 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
|
|
|
1659
1662
|
}
|
|
1660
1663
|
const input = validateInput(role, request.payload, configuration);
|
|
1661
1664
|
const method = role === "stt" ? engine.transcribe : engine.synthesize;
|
|
1662
|
-
if (
|
|
1665
|
+
if (!is.function(method)) {
|
|
1663
1666
|
throw workerError(
|
|
1664
1667
|
"ARCANE_AI_PROVIDER_UNAVAILABLE",
|
|
1665
1668
|
"The speech engine operation is unavailable.",
|
|
@@ -1769,7 +1772,7 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
|
|
|
1769
1772
|
|
|
1770
1773
|
function handleMessage(request) {
|
|
1771
1774
|
if (request?.protocol !== SPEECH_WORKER_PROTOCOL
|
|
1772
|
-
|| !
|
|
1775
|
+
|| !is.safeInteger(request.id)
|
|
1773
1776
|
|| request.id < 1) {
|
|
1774
1777
|
return Promise.reject(workerError(
|
|
1775
1778
|
"ARCANE_AI_INVALID_REQUEST",
|
|
@@ -1836,7 +1839,7 @@ export function installBrowserSpeechWorker(role, scope = globalThis) {
|
|
|
1836
1839
|
}
|
|
1837
1840
|
|
|
1838
1841
|
function replayWorkerMessage(scope, event) {
|
|
1839
|
-
if (
|
|
1842
|
+
if (is.function(scope.dispatchEvent)) {
|
|
1840
1843
|
scope.dispatchEvent(event);
|
|
1841
1844
|
return;
|
|
1842
1845
|
}
|