arcane-os 0.5.17 → 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 +24 -0
- 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 +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 +5 -1
- package/docs/reference/ai/browser-speech.md +198 -5
- 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 +117 -138
- 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
|
createBrowserSpeechAuthority,
|
|
3
4
|
isBrowserSpeechArtifactGraph,
|
|
@@ -7,6 +8,8 @@ import {
|
|
|
7
8
|
} from "./browser-speech-artifacts.mjs";
|
|
8
9
|
import { stripSpeechFormatting } from "../speech-text.mjs";
|
|
9
10
|
|
|
11
|
+
const is = new Is(false);
|
|
12
|
+
|
|
10
13
|
const completeValue = (value) => value;
|
|
11
14
|
import {
|
|
12
15
|
createSpeechWorkerClient,
|
|
@@ -46,7 +49,7 @@ function providerError(code, message, cause, reason) {
|
|
|
46
49
|
? "AbortError"
|
|
47
50
|
: "ArcaneBrowserSpeechProviderError";
|
|
48
51
|
error.code = code;
|
|
49
|
-
error.reason =
|
|
52
|
+
error.reason = is.string(reason) && reason
|
|
50
53
|
? reason
|
|
51
54
|
: UNMAPPED_PROVIDER_REASON;
|
|
52
55
|
PROVIDER_ERRORS.add(error);
|
|
@@ -54,7 +57,7 @@ function providerError(code, message, cause, reason) {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
function isBrowserSpeechProviderError(value) {
|
|
57
|
-
return
|
|
60
|
+
return is.object(value)
|
|
58
61
|
&& value !== null
|
|
59
62
|
&& PROVIDER_ERRORS.has(value);
|
|
60
63
|
}
|
|
@@ -69,7 +72,7 @@ function trustedLoadFailure(error, role) {
|
|
|
69
72
|
if (isTrustedSpeechError(error)) return error;
|
|
70
73
|
return providerError(
|
|
71
74
|
"ARCANE_AI_PROVIDER_LOAD_FAILED",
|
|
72
|
-
|
|
75
|
+
is.string(error?.message) && error.message
|
|
73
76
|
? error.message
|
|
74
77
|
: `The browser ${role} provider load was rejected.`,
|
|
75
78
|
error,
|
|
@@ -81,7 +84,7 @@ function trustedRequestFailure(error, role) {
|
|
|
81
84
|
if (isTrustedSpeechError(error)) return error;
|
|
82
85
|
return providerError(
|
|
83
86
|
"ARCANE_AI_PROVIDER_REQUEST_FAILED",
|
|
84
|
-
|
|
87
|
+
is.string(error?.message) && error.message
|
|
85
88
|
? error.message
|
|
86
89
|
: `The browser ${role} engine operation was rejected.`,
|
|
87
90
|
error,
|
|
@@ -95,7 +98,7 @@ function trustedWorkerFailure(error, role) {
|
|
|
95
98
|
if (isTrustedSpeechError(error)) return error;
|
|
96
99
|
return providerError(
|
|
97
100
|
"ARCANE_AI_WORKER_MESSAGE_REJECTED",
|
|
98
|
-
|
|
101
|
+
is.string(error?.message) && error.message
|
|
99
102
|
? error.message
|
|
100
103
|
: `The browser ${role} Worker returned an unreadable error envelope.`,
|
|
101
104
|
error,
|
|
@@ -107,7 +110,7 @@ function trustedLifecycleFailure(error, role, operation) {
|
|
|
107
110
|
if (isTrustedSpeechError(error)) return error;
|
|
108
111
|
return providerError(
|
|
109
112
|
"ARCANE_AI_INVALID_REQUEST",
|
|
110
|
-
|
|
113
|
+
is.string(error?.message) && error.message
|
|
111
114
|
? error.message
|
|
112
115
|
: `The browser ${role} ${operation} context could not be read.`,
|
|
113
116
|
error,
|
|
@@ -116,8 +119,8 @@ function trustedLifecycleFailure(error, role, operation) {
|
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
function resolveReason(reason, fallback = UNMAPPED_PROVIDER_REASON) {
|
|
119
|
-
const resolved =
|
|
120
|
-
return
|
|
122
|
+
const resolved = is.function(reason) ? reason() : reason;
|
|
123
|
+
return is.string(resolved) && resolved ? resolved : fallback;
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
function abortError(signal, reason = UNMAPPED_PROVIDER_REASON) {
|
|
@@ -140,7 +143,7 @@ function workerFailureCode(error) {
|
|
|
140
143
|
}
|
|
141
144
|
|
|
142
145
|
function requiredIdentifier(value, label) {
|
|
143
|
-
if (
|
|
146
|
+
if (!is.string(value) || !value.trim()) {
|
|
144
147
|
throw new TypeError(`${label} must be a nonempty trimmed string.`);
|
|
145
148
|
}
|
|
146
149
|
return value.trim();
|
|
@@ -159,7 +162,7 @@ function normalizeSpeechExecution(role, execution) {
|
|
|
159
162
|
maxConcurrentRequests: DEFAULT_TTS_MAX_CONCURRENT_REQUESTS,
|
|
160
163
|
});
|
|
161
164
|
}
|
|
162
|
-
if (!execution ||
|
|
165
|
+
if (!execution || !is.object(execution) || is.array(execution)) {
|
|
163
166
|
throw new TypeError("Browser Kokoro execution must be a plain data record.");
|
|
164
167
|
}
|
|
165
168
|
const prototype = Object.getPrototypeOf(execution);
|
|
@@ -185,7 +188,7 @@ function normalizeSpeechExecution(role, execution) {
|
|
|
185
188
|
throw new TypeError('Browser Kokoro execution.device must be "auto", "webgpu", or "wasm".');
|
|
186
189
|
}
|
|
187
190
|
if (
|
|
188
|
-
!
|
|
191
|
+
!is.safeInteger(maxConcurrentRequests)
|
|
189
192
|
|| maxConcurrentRequests < 1
|
|
190
193
|
|| maxConcurrentRequests > MAX_TTS_CONCURRENT_REQUESTS
|
|
191
194
|
) {
|
|
@@ -320,15 +323,15 @@ function linkedAbortFailure(linked, fallbackReason) {
|
|
|
320
323
|
function isAbortSignal(value) {
|
|
321
324
|
return value === null
|
|
322
325
|
|| value === undefined
|
|
323
|
-
|| (
|
|
324
|
-
&&
|
|
325
|
-
&&
|
|
326
|
-
&&
|
|
326
|
+
|| (is.object(value)
|
|
327
|
+
&& is.boolean(value.aborted)
|
|
328
|
+
&& is.function(value.addEventListener)
|
|
329
|
+
&& is.function(value.removeEventListener));
|
|
327
330
|
}
|
|
328
331
|
|
|
329
332
|
function providerContext(context, role, operation) {
|
|
330
333
|
if (context === undefined) return completeValue({ signal: null });
|
|
331
|
-
if (!context ||
|
|
334
|
+
if (!context || !is.object(context) || is.array(context)) {
|
|
332
335
|
throw providerError(
|
|
333
336
|
"ARCANE_AI_INVALID_REQUEST",
|
|
334
337
|
`Browser ${role} ${operation} context must be an object.`,
|
|
@@ -471,7 +474,7 @@ function genericPayloadDescriptors(
|
|
|
471
474
|
}
|
|
472
475
|
const descriptors = Object.getOwnPropertyDescriptors(payload);
|
|
473
476
|
for (const key of Reflect.ownKeys(descriptors)) {
|
|
474
|
-
if (
|
|
477
|
+
if (is.symbol(key) || !allowedKeys.includes(key)) {
|
|
475
478
|
throw providerError(
|
|
476
479
|
"ARCANE_AI_INVALID_REQUEST",
|
|
477
480
|
`${label} contains an unknown field.`,
|
|
@@ -502,7 +505,7 @@ function genericPayloadDescriptors(
|
|
|
502
505
|
}
|
|
503
506
|
|
|
504
507
|
function audioMimeEssence(value, label, reasonPrefix) {
|
|
505
|
-
if (
|
|
508
|
+
if (!is.string(value)) {
|
|
506
509
|
throw providerError(
|
|
507
510
|
"ARCANE_AI_INVALID_REQUEST",
|
|
508
511
|
`${label} must be an audio MIME type.`,
|
|
@@ -586,7 +589,7 @@ function observeLoadOperation(record, { signal, progress }, role) {
|
|
|
586
589
|
};
|
|
587
590
|
const observer = completeValue({
|
|
588
591
|
progress(value) {
|
|
589
|
-
if (settled ||
|
|
592
|
+
if (settled || !is.function(progress)) return;
|
|
590
593
|
try {
|
|
591
594
|
progress(value);
|
|
592
595
|
} catch (error) {
|
|
@@ -642,7 +645,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
642
645
|
operationSubject: "stt-transcription",
|
|
643
646
|
});
|
|
644
647
|
const audio = descriptors.audio.value;
|
|
645
|
-
if (
|
|
648
|
+
if (!is.function(globalThis.Blob)) {
|
|
646
649
|
throw providerError(
|
|
647
650
|
"ARCANE_AI_INVALID_REQUEST",
|
|
648
651
|
"Shared speech transcription requires the browser Blob constructor.",
|
|
@@ -650,7 +653,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
650
653
|
"stt-transcription-blob-constructor-unavailable",
|
|
651
654
|
);
|
|
652
655
|
}
|
|
653
|
-
if (!(audio
|
|
656
|
+
if (!is.instanceCheck(audio, Blob)) {
|
|
654
657
|
throw providerError(
|
|
655
658
|
"ARCANE_AI_INVALID_REQUEST",
|
|
656
659
|
"Shared speech transcription audio must be a Blob or File.",
|
|
@@ -685,7 +688,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
685
688
|
}
|
|
686
689
|
const OfflineAudioContext = globalThis.OfflineAudioContext
|
|
687
690
|
?? globalThis.webkitOfflineAudioContext;
|
|
688
|
-
if (
|
|
691
|
+
if (!is.function(OfflineAudioContext)) {
|
|
689
692
|
throw providerError(
|
|
690
693
|
"ARCANE_AI_AUDIO_DECODE_UNAVAILABLE",
|
|
691
694
|
`Shared Blob transcription requires OfflineAudioContext decoding at ${sampleRate} Hz.`,
|
|
@@ -704,7 +707,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
704
707
|
"stt-browser-offline-audio-context-construction-rejected",
|
|
705
708
|
);
|
|
706
709
|
}
|
|
707
|
-
if (
|
|
710
|
+
if (!is.function(decoder.decodeAudioData)) {
|
|
708
711
|
throw providerError(
|
|
709
712
|
"ARCANE_AI_AUDIO_DECODE_UNAVAILABLE",
|
|
710
713
|
"Shared Blob transcription requires browser audio decoding.",
|
|
@@ -735,7 +738,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
735
738
|
"stt-browser-audio-decode-operation-rejected",
|
|
736
739
|
);
|
|
737
740
|
}
|
|
738
|
-
if (!decoded ||
|
|
741
|
+
if (!decoded || !is.object(decoded)) {
|
|
739
742
|
throw providerError(
|
|
740
743
|
"ARCANE_AI_AUDIO_DECODE_FAILED",
|
|
741
744
|
"Decoded speech audio must be an AudioBuffer-like object.",
|
|
@@ -751,7 +754,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
751
754
|
"stt-browser-decoded-audio-sample-rate-mismatch",
|
|
752
755
|
);
|
|
753
756
|
}
|
|
754
|
-
if (!
|
|
757
|
+
if (!is.safeInteger(decoded.length)) {
|
|
755
758
|
throw providerError(
|
|
756
759
|
"ARCANE_AI_AUDIO_DECODE_FAILED",
|
|
757
760
|
"Decoded speech audio frame length must be a safe integer.",
|
|
@@ -767,7 +770,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
767
770
|
"stt-browser-decoded-audio-empty",
|
|
768
771
|
);
|
|
769
772
|
}
|
|
770
|
-
if (!
|
|
773
|
+
if (!is.safeInteger(decoded.numberOfChannels)) {
|
|
771
774
|
throw providerError(
|
|
772
775
|
"ARCANE_AI_AUDIO_DECODE_FAILED",
|
|
773
776
|
"Decoded speech audio channel count must be a safe integer.",
|
|
@@ -783,7 +786,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
783
786
|
"stt-browser-decoded-audio-channel-count-zero",
|
|
784
787
|
);
|
|
785
788
|
}
|
|
786
|
-
if (
|
|
789
|
+
if (!is.function(decoded.getChannelData)) {
|
|
787
790
|
throw providerError(
|
|
788
791
|
"ARCANE_AI_AUDIO_DECODE_FAILED",
|
|
789
792
|
"Decoded speech audio must expose getChannelData().",
|
|
@@ -804,7 +807,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
804
807
|
"stt-browser-decoded-audio-channel-read-rejected",
|
|
805
808
|
);
|
|
806
809
|
}
|
|
807
|
-
if (!(channel
|
|
810
|
+
if (!is.instanceCheck(channel, Float32Array)) {
|
|
808
811
|
throw providerError(
|
|
809
812
|
"ARCANE_AI_AUDIO_DECODE_FAILED",
|
|
810
813
|
"Decoded speech audio channels must be Float32Array values.",
|
|
@@ -827,7 +830,7 @@ async function decodeSharedTranscriptionPayload(
|
|
|
827
830
|
let sample = 0;
|
|
828
831
|
for (const channel of channels) sample += channel[index];
|
|
829
832
|
sample /= channels.length;
|
|
830
|
-
if (!
|
|
833
|
+
if (!is.finite(sample)) {
|
|
831
834
|
throw providerError(
|
|
832
835
|
"ARCANE_AI_AUDIO_DECODE_FAILED",
|
|
833
836
|
"Decoded speech audio contains a non-finite sample.",
|
|
@@ -854,7 +857,7 @@ function cloneNativeTranscriptionPayload(payload, authority) {
|
|
|
854
857
|
);
|
|
855
858
|
assertPayloadModel(payload, authority, { operationSubject: "stt-transcription" });
|
|
856
859
|
const sampleRate = inputSampleRate(authority);
|
|
857
|
-
if (!(descriptors.audio.value
|
|
860
|
+
if (!is.instanceCheck(descriptors.audio.value, Float32Array)) {
|
|
858
861
|
throw providerError(
|
|
859
862
|
"ARCANE_AI_INVALID_REQUEST",
|
|
860
863
|
"Whisper requires Float32Array audio.",
|
|
@@ -879,7 +882,7 @@ function cloneNativeTranscriptionPayload(payload, authority) {
|
|
|
879
882
|
);
|
|
880
883
|
}
|
|
881
884
|
for (const sample of descriptors.audio.value) {
|
|
882
|
-
if (!
|
|
885
|
+
if (!is.finite(sample)) {
|
|
883
886
|
throw providerError(
|
|
884
887
|
"ARCANE_AI_INVALID_REQUEST",
|
|
885
888
|
"Whisper audio must contain only finite Float32 PCM samples.",
|
|
@@ -933,12 +936,12 @@ function normalizeSynthesisPayload(payload, authority, speechInputPrepared) {
|
|
|
933
936
|
assertPayloadModel(payload, authority, { operationSubject: "tts-synthesis" });
|
|
934
937
|
textValue = descriptors.text.value;
|
|
935
938
|
}
|
|
936
|
-
const suppliedText =
|
|
939
|
+
const suppliedText = is.string(textValue) ? textValue : "";
|
|
937
940
|
const text = speechInputPrepared === true ? suppliedText : stripSpeechFormatting(suppliedText);
|
|
938
941
|
const voiceValue = Object.hasOwn(descriptors, "voice")
|
|
939
942
|
? descriptors.voice.value
|
|
940
943
|
: authority.defaultVoice;
|
|
941
|
-
const voice =
|
|
944
|
+
const voice = is.string(voiceValue) ? voiceValue : "";
|
|
942
945
|
const speed = Object.hasOwn(descriptors, "speed") ? descriptors.speed.value : 1;
|
|
943
946
|
if (!text.trim()) {
|
|
944
947
|
throw providerError(
|
|
@@ -956,7 +959,7 @@ function normalizeSynthesisPayload(payload, authority, speechInputPrepared) {
|
|
|
956
959
|
"tts-synthesis-voice-empty",
|
|
957
960
|
);
|
|
958
961
|
}
|
|
959
|
-
if (!
|
|
962
|
+
if (!is.finite(speed) || speed <= 0) {
|
|
960
963
|
throw providerError(
|
|
961
964
|
"ARCANE_AI_INVALID_REQUEST",
|
|
962
965
|
"Kokoro speed must be greater than 0.",
|
|
@@ -987,7 +990,7 @@ async function normalizeRequestPayload(
|
|
|
987
990
|
cancellationReason,
|
|
988
991
|
speechInputPrepared,
|
|
989
992
|
) {
|
|
990
|
-
if (!payload ||
|
|
993
|
+
if (!payload || !is.object(payload) || is.array(payload)) {
|
|
991
994
|
throw providerError(
|
|
992
995
|
"ARCANE_AI_INVALID_REQUEST",
|
|
993
996
|
"Speech request payload must be an object.",
|
|
@@ -1001,8 +1004,8 @@ async function normalizeRequestPayload(
|
|
|
1001
1004
|
const audio = Object.getOwnPropertyDescriptor(payload, "audio");
|
|
1002
1005
|
if (Object.hasOwn(payload, "mimeType")
|
|
1003
1006
|
|| (Object.hasOwn(audio ?? {}, "value")
|
|
1004
|
-
&&
|
|
1005
|
-
&& audio.value
|
|
1007
|
+
&& is.function(globalThis.Blob)
|
|
1008
|
+
&& is.instanceCheck(audio.value, Blob))) {
|
|
1006
1009
|
return decodeSharedTranscriptionPayload(
|
|
1007
1010
|
payload,
|
|
1008
1011
|
authority,
|
|
@@ -1017,7 +1020,7 @@ async function normalizeRequestPayload(
|
|
|
1017
1020
|
|
|
1018
1021
|
function encodeSharedSynthesisResult(result, authority) {
|
|
1019
1022
|
const sampleRate = outputSampleRate(authority);
|
|
1020
|
-
if (!result ||
|
|
1023
|
+
if (!result || !is.object(result)) {
|
|
1021
1024
|
throw providerError(
|
|
1022
1025
|
"ARCANE_AI_INVALID_PROVIDER_RESULT",
|
|
1023
1026
|
"Browser Kokoro must return a synthesis result object.",
|
|
@@ -1025,7 +1028,7 @@ function encodeSharedSynthesisResult(result, authority) {
|
|
|
1025
1028
|
"tts-synthesis-result-not-object",
|
|
1026
1029
|
);
|
|
1027
1030
|
}
|
|
1028
|
-
if (!(result.audio
|
|
1031
|
+
if (!is.instanceCheck(result.audio, Float32Array)) {
|
|
1029
1032
|
throw providerError(
|
|
1030
1033
|
"ARCANE_AI_INVALID_PROVIDER_RESULT",
|
|
1031
1034
|
"Browser Kokoro must return Float32 PCM audio.",
|
|
@@ -1080,7 +1083,7 @@ function encodeSharedSynthesisResult(result, authority) {
|
|
|
1080
1083
|
view.setUint32(40, result.audio.length * 2, true);
|
|
1081
1084
|
for (let index = 0; index < result.audio.length; index += 1) {
|
|
1082
1085
|
const sample = result.audio[index];
|
|
1083
|
-
if (!
|
|
1086
|
+
if (!is.finite(sample)) {
|
|
1084
1087
|
throw providerError(
|
|
1085
1088
|
"ARCANE_AI_INVALID_PROVIDER_RESULT",
|
|
1086
1089
|
"Browser Kokoro returned a non-finite PCM sample.",
|
|
@@ -1115,7 +1118,7 @@ function createBrowserSpeechProvider({
|
|
|
1115
1118
|
if (localOnly !== true) {
|
|
1116
1119
|
throw new TypeError("Browser speech providers are localOnly.");
|
|
1117
1120
|
}
|
|
1118
|
-
if (
|
|
1121
|
+
if (!is.boolean(offline)) {
|
|
1119
1122
|
throw new TypeError("Browser speech offline must be a boolean.");
|
|
1120
1123
|
}
|
|
1121
1124
|
if (!isDbopfsSpeechArtifactStore(store)) {
|
|
@@ -1446,7 +1449,7 @@ function createBrowserSpeechProvider({
|
|
|
1446
1449
|
} catch (error) {
|
|
1447
1450
|
return Promise.reject(trustedLoadFailure(error, role));
|
|
1448
1451
|
}
|
|
1449
|
-
if (loadProgress !== undefined &&
|
|
1452
|
+
if (loadProgress !== undefined && !is.function(loadProgress)) {
|
|
1450
1453
|
return Promise.reject(providerError(
|
|
1451
1454
|
"ARCANE_AI_INVALID_REQUEST",
|
|
1452
1455
|
"Browser speech load progress must be a function when supplied.",
|
|
@@ -1514,7 +1517,7 @@ function createBrowserSpeechProvider({
|
|
|
1514
1517
|
prepared,
|
|
1515
1518
|
released: false,
|
|
1516
1519
|
};
|
|
1517
|
-
record.warnings =
|
|
1520
|
+
record.warnings = is.array(prepared.warnings)
|
|
1518
1521
|
? completeValue([...prepared.warnings])
|
|
1519
1522
|
: NO_PROVIDER_WARNINGS;
|
|
1520
1523
|
lastWarnings = record.warnings;
|