arcane-os 0.5.13 → 0.5.15
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 +32 -0
- package/README.md +33 -8
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +11 -10
- package/browser-runtime/ai/browser-wllama-runtime.mjs +2 -1
- package/browser-runtime/ai/model-controller.mjs +6 -5
- package/browser-runtime/ai/speech-worker-client.mjs +45 -3
- package/browser-runtime/event-manager.mjs +2 -1
- package/browser-runtime/logging.mjs +58 -0
- package/docs/architecture.md +1 -1
- package/docs/reference/README.md +9 -7
- package/docs/reference/ai/browser-speech.md +90 -1
- package/docs/reference/ai/twin-cloud.md +1 -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 +34 -6
- package/docs/reference/inventory/runtime-components.json +1 -1
- package/docs/reference/inventory/runtime-modules.json +4 -4
- package/docs/reference/protocols.md +5 -5
- package/docs/reference/runtime-modules.md +70 -15
- package/docs/reference/sdk-api.md +120 -11
- package/package.json +4 -3
- package/runtime/arcane/components/app-bar.html +3 -1
- package/runtime/arcane/components/chat.html +22 -20
- package/runtime/arcane/components/dashboard-config.html +3 -1
- package/runtime/arcane/components/data-maintenance.html +4 -2
- package/runtime/arcane/components/data-view.html +3 -1
- package/runtime/arcane/components/directory-picker.html +3 -1
- package/runtime/arcane/components/file-manager.html +11 -9
- package/runtime/arcane/components/header.html +5 -3
- package/runtime/arcane/components/markdown-document.html +3 -1
- package/runtime/arcane/components/markdown-editor.html +4 -2
- package/runtime/arcane/components/modal.html +3 -1
- package/runtime/arcane/components/screen-capture.html +4 -2
- package/runtime/arcane/components/speech.html +10 -8
- package/runtime/arcane/components/table.html +3 -1
- package/runtime/arcane/components/voice-transcription.html +8 -6
- package/runtime/arcane/entities/Chat.js +5 -4
- package/runtime/arcane/entities/User.js +2 -1
- package/runtime/arcane/modules/AI.js +442 -292
- package/runtime/arcane/modules/AIProviderRuntime.js +359 -82
- package/runtime/arcane/modules/CommunicationAppController.js +2 -1
- package/runtime/arcane/modules/ComponentContracts.js +3 -2
- package/runtime/arcane/modules/ConversationTimebox.js +2 -1
- package/runtime/arcane/modules/DBOPFS.js +5 -4
- package/runtime/arcane/modules/Errors.js +3 -14
- package/runtime/arcane/modules/HTMLImport.js +4 -3
- package/runtime/arcane/modules/LocalAIReadinessController.js +2 -1
- package/runtime/arcane/modules/MD.js +3 -2
- package/runtime/arcane/modules/MailOutbox.mjs +2 -1
- package/runtime/arcane/modules/PersistentAIChatSession.js +2 -1
- package/runtime/arcane/modules/ScreenCapture.js +2 -1
- package/runtime/arcane/modules/SpeechPlayback.js +206 -40
- package/runtime/arcane/modules/ThemeBootstrap.js +3 -2
- package/runtime/arcane/modules/ToolCallRouter.js +2 -1
- package/src/import-map.mjs +65 -10
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {arcaneLogging} from 'arcane-os/logging';
|
|
1
2
|
import {
|
|
2
3
|
AI_RUNTIME_ROLES,
|
|
3
4
|
getAIRuntimeState,
|
|
@@ -1708,6 +1709,7 @@ export class AIProviderRuntime {
|
|
|
1708
1709
|
}
|
|
1709
1710
|
|
|
1710
1711
|
get speechMuted() {
|
|
1712
|
+
arcaneLogging.debug('[Arcane speech runtime] speechMuted', this.#speechMuted);
|
|
1711
1713
|
return this.#speechMuted;
|
|
1712
1714
|
}
|
|
1713
1715
|
|
|
@@ -1719,6 +1721,9 @@ export class AIProviderRuntime {
|
|
|
1719
1721
|
this.#assertOpen();
|
|
1720
1722
|
this.#assertNotConfiguring();
|
|
1721
1723
|
const admitted = validateProvider(provider);
|
|
1724
|
+
if (SPEECH_ROLES.includes(admitted.role)) {
|
|
1725
|
+
arcaneLogging.debug('[Arcane speech runtime] register', provider);
|
|
1726
|
+
}
|
|
1722
1727
|
const key = providerKey(admitted.role, admitted.id);
|
|
1723
1728
|
const existing = this.#providers.get(key);
|
|
1724
1729
|
if (existing && existing !== admitted) {
|
|
@@ -1785,10 +1790,17 @@ export class AIProviderRuntime {
|
|
|
1785
1790
|
}
|
|
1786
1791
|
}
|
|
1787
1792
|
|
|
1788
|
-
|
|
1793
|
+
const unregister = this.#createProviderUnregisterHandle(admitted);
|
|
1794
|
+
if (SPEECH_ROLES.includes(admitted.role)) {
|
|
1795
|
+
arcaneLogging.debug('[Arcane speech runtime] register.result', admitted.role, admitted.id, unregister);
|
|
1796
|
+
}
|
|
1797
|
+
return unregister;
|
|
1789
1798
|
}
|
|
1790
1799
|
|
|
1791
1800
|
unregister(role, providerId, expectedProvider = null) {
|
|
1801
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1802
|
+
arcaneLogging.debug('[Arcane speech runtime] unregister', role, providerId, expectedProvider);
|
|
1803
|
+
}
|
|
1792
1804
|
this.#assertOpen();
|
|
1793
1805
|
this.#assertNotConfiguring();
|
|
1794
1806
|
assertRole(role);
|
|
@@ -1796,6 +1808,9 @@ export class AIProviderRuntime {
|
|
|
1796
1808
|
const key = providerKey(role, providerId);
|
|
1797
1809
|
const provider = this.#providers.get(key);
|
|
1798
1810
|
if (!provider || (expectedProvider && provider !== expectedProvider)) {
|
|
1811
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1812
|
+
arcaneLogging.debug('[Arcane speech runtime] unregister.result', role, providerId, false);
|
|
1813
|
+
}
|
|
1799
1814
|
return false;
|
|
1800
1815
|
}
|
|
1801
1816
|
|
|
@@ -1809,16 +1824,29 @@ export class AIProviderRuntime {
|
|
|
1809
1824
|
}
|
|
1810
1825
|
this.#providers.delete(key);
|
|
1811
1826
|
this.#disposeAllCompletedProviders.delete(provider);
|
|
1827
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1828
|
+
arcaneLogging.debug('[Arcane speech runtime] unregister.result', role, providerId, true);
|
|
1829
|
+
}
|
|
1812
1830
|
return true;
|
|
1813
1831
|
}
|
|
1814
1832
|
|
|
1815
1833
|
hasProvider(role, providerId) {
|
|
1834
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1835
|
+
arcaneLogging.debug('[Arcane speech runtime] hasProvider', role, providerId);
|
|
1836
|
+
}
|
|
1816
1837
|
assertRole(role);
|
|
1817
1838
|
assertIdentifier(providerId, 'AI provider id');
|
|
1818
|
-
|
|
1839
|
+
const result = this.#providers.has(providerKey(role, providerId));
|
|
1840
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1841
|
+
arcaneLogging.debug('[Arcane speech runtime] hasProvider.result', role, providerId, result);
|
|
1842
|
+
}
|
|
1843
|
+
return result;
|
|
1819
1844
|
}
|
|
1820
1845
|
|
|
1821
1846
|
ownsProvider(role, expectedProvider) {
|
|
1847
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1848
|
+
arcaneLogging.debug('[Arcane speech runtime] ownsProvider', role, expectedProvider);
|
|
1849
|
+
}
|
|
1822
1850
|
if (!ROLE_SET.has(role)) {
|
|
1823
1851
|
throw speechProviderReplacementError(
|
|
1824
1852
|
'ARCANE_AI_PROVIDER_IDENTITY_ROLE_INVALID',
|
|
@@ -1846,17 +1874,27 @@ export class AIProviderRuntime {
|
|
|
1846
1874
|
);
|
|
1847
1875
|
}
|
|
1848
1876
|
|
|
1849
|
-
|
|
1877
|
+
const result = this.#providers.get(providerKey(role, admitted.id)) === admitted;
|
|
1878
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1879
|
+
arcaneLogging.debug('[Arcane speech runtime] ownsProvider.result', role, admitted.id, result);
|
|
1880
|
+
}
|
|
1881
|
+
return result;
|
|
1850
1882
|
}
|
|
1851
1883
|
|
|
1852
1884
|
providerIdentity(role, providerId) {
|
|
1885
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1886
|
+
arcaneLogging.debug('[Arcane speech runtime] providerIdentity', role, providerId);
|
|
1887
|
+
}
|
|
1853
1888
|
assertRole(role);
|
|
1854
1889
|
assertIdentifier(providerId, 'AI provider id');
|
|
1855
1890
|
const provider = this.#providers.get(providerKey(role, providerId)) ?? null;
|
|
1856
1891
|
if (!provider) {
|
|
1892
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1893
|
+
arcaneLogging.debug('[Arcane speech runtime] providerIdentity.result', role, providerId, null);
|
|
1894
|
+
}
|
|
1857
1895
|
return null;
|
|
1858
1896
|
}
|
|
1859
|
-
|
|
1897
|
+
const result = completeValue(
|
|
1860
1898
|
{
|
|
1861
1899
|
protocol: provider.protocol,
|
|
1862
1900
|
role: provider.role,
|
|
@@ -1864,9 +1902,16 @@ export class AIProviderRuntime {
|
|
|
1864
1902
|
localOnly: provider.localOnly
|
|
1865
1903
|
}
|
|
1866
1904
|
);
|
|
1905
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1906
|
+
arcaneLogging.debug('[Arcane speech runtime] providerIdentity.result', role, providerId, result);
|
|
1907
|
+
}
|
|
1908
|
+
return result;
|
|
1867
1909
|
}
|
|
1868
1910
|
|
|
1869
1911
|
selection(role, options = {}) {
|
|
1912
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1913
|
+
arcaneLogging.debug('[Arcane speech runtime] selection', role, options);
|
|
1914
|
+
}
|
|
1870
1915
|
assertRole(role);
|
|
1871
1916
|
assertPlainObject(options, 'AI provider route options');
|
|
1872
1917
|
for (const key of Reflect.ownKeys(options)) {
|
|
@@ -1881,16 +1926,28 @@ export class AIProviderRuntime {
|
|
|
1881
1926
|
fail('AI provider route localOnly must be a boolean.');
|
|
1882
1927
|
}
|
|
1883
1928
|
const slot = this.#slots[role];
|
|
1884
|
-
|
|
1929
|
+
const selection = localOnly ? slot.routes.localOnly : slot.routes.default;
|
|
1930
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1931
|
+
arcaneLogging.debug('[Arcane speech runtime] selection.result', role, selection);
|
|
1932
|
+
}
|
|
1933
|
+
return selection;
|
|
1885
1934
|
}
|
|
1886
1935
|
|
|
1887
1936
|
ownsSelection(role, providerId, options = {}) {
|
|
1937
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1938
|
+
arcaneLogging.debug('[Arcane speech runtime] ownsSelection', role, providerId, options);
|
|
1939
|
+
}
|
|
1888
1940
|
assertRole(role);
|
|
1889
1941
|
assertIdentifier(providerId, 'AI provider id');
|
|
1890
|
-
|
|
1942
|
+
const result = this.selection(role, options)?.providerId === providerId;
|
|
1943
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
1944
|
+
arcaneLogging.debug('[Arcane speech runtime] ownsSelection.result', role, providerId, result);
|
|
1945
|
+
}
|
|
1946
|
+
return result;
|
|
1891
1947
|
}
|
|
1892
1948
|
|
|
1893
1949
|
validateConfiguration(value) {
|
|
1950
|
+
arcaneLogging.debug('[Arcane speech runtime] validateConfiguration', value);
|
|
1894
1951
|
this.#assertOpen();
|
|
1895
1952
|
const selections = immutableSelections(value);
|
|
1896
1953
|
for (const role of AI_RUNTIME_ROLES) {
|
|
@@ -1910,10 +1967,12 @@ export class AIProviderRuntime {
|
|
|
1910
1967
|
}
|
|
1911
1968
|
}
|
|
1912
1969
|
}
|
|
1970
|
+
arcaneLogging.debug('[Arcane speech runtime] validateConfiguration.result', selections);
|
|
1913
1971
|
return selections;
|
|
1914
1972
|
}
|
|
1915
1973
|
|
|
1916
1974
|
validateSpeechConfiguration(value) {
|
|
1975
|
+
arcaneLogging.debug('[Arcane speech runtime] validateSpeechConfiguration', value);
|
|
1917
1976
|
this.#assertOpen();
|
|
1918
1977
|
const selections = immutableSpeechSelections(value);
|
|
1919
1978
|
for (const role of SPEECH_ROLES) {
|
|
@@ -1933,10 +1992,12 @@ export class AIProviderRuntime {
|
|
|
1933
1992
|
}
|
|
1934
1993
|
}
|
|
1935
1994
|
}
|
|
1995
|
+
arcaneLogging.debug('[Arcane speech runtime] validateSpeechConfiguration.result', selections);
|
|
1936
1996
|
return selections;
|
|
1937
1997
|
}
|
|
1938
1998
|
|
|
1939
1999
|
configure(value) {
|
|
2000
|
+
arcaneLogging.debug('[Arcane speech runtime] configure', value);
|
|
1940
2001
|
this.#assertOpen();
|
|
1941
2002
|
if (this.#configuring) {
|
|
1942
2003
|
throw operationError(
|
|
@@ -1977,10 +2038,12 @@ export class AIProviderRuntime {
|
|
|
1977
2038
|
} finally {
|
|
1978
2039
|
this.#configuring = false;
|
|
1979
2040
|
}
|
|
2041
|
+
arcaneLogging.debug('[Arcane speech runtime] configure.result', selections);
|
|
1980
2042
|
return selections;
|
|
1981
2043
|
}
|
|
1982
2044
|
|
|
1983
2045
|
configureSpeech(value) {
|
|
2046
|
+
arcaneLogging.debug('[Arcane speech runtime] configureSpeech', value);
|
|
1984
2047
|
this.#assertOpen();
|
|
1985
2048
|
if (this.#configuring) {
|
|
1986
2049
|
throw operationError(
|
|
@@ -2022,10 +2085,12 @@ export class AIProviderRuntime {
|
|
|
2022
2085
|
} finally {
|
|
2023
2086
|
this.#configuring = false;
|
|
2024
2087
|
}
|
|
2088
|
+
arcaneLogging.debug('[Arcane speech runtime] configureSpeech.result', selections);
|
|
2025
2089
|
return selections;
|
|
2026
2090
|
}
|
|
2027
2091
|
|
|
2028
2092
|
replaceSpeechProvider(role, value) {
|
|
2093
|
+
arcaneLogging.debug('[Arcane speech runtime] replaceSpeechProvider', role, value);
|
|
2029
2094
|
this.#assertOpen();
|
|
2030
2095
|
if (this.#configuring) {
|
|
2031
2096
|
throw speechProviderReplacementError(
|
|
@@ -2036,7 +2101,9 @@ export class AIProviderRuntime {
|
|
|
2036
2101
|
}
|
|
2037
2102
|
this.#configuring = true;
|
|
2038
2103
|
try {
|
|
2039
|
-
|
|
2104
|
+
const result = this.#commitSpeechProviderRoleReplacement(role, value);
|
|
2105
|
+
arcaneLogging.debug('[Arcane speech runtime] replaceSpeechProvider.result', role, result);
|
|
2106
|
+
return result;
|
|
2040
2107
|
} finally {
|
|
2041
2108
|
this.#configuring = false;
|
|
2042
2109
|
}
|
|
@@ -2191,6 +2258,7 @@ export class AIProviderRuntime {
|
|
|
2191
2258
|
}
|
|
2192
2259
|
|
|
2193
2260
|
replaceSpeechProviders(value) {
|
|
2261
|
+
arcaneLogging.debug('[Arcane speech runtime] replaceSpeechProviders', value);
|
|
2194
2262
|
this.#assertOpen();
|
|
2195
2263
|
if (this.#configuring) {
|
|
2196
2264
|
throw speechProviderReplacementError(
|
|
@@ -2201,7 +2269,9 @@ export class AIProviderRuntime {
|
|
|
2201
2269
|
}
|
|
2202
2270
|
this.#configuring = true;
|
|
2203
2271
|
try {
|
|
2204
|
-
|
|
2272
|
+
const result = this.#commitSpeechProviderReplacement(value);
|
|
2273
|
+
arcaneLogging.debug('[Arcane speech runtime] replaceSpeechProviders.result', result);
|
|
2274
|
+
return result;
|
|
2205
2275
|
} finally {
|
|
2206
2276
|
this.#configuring = false;
|
|
2207
2277
|
}
|
|
@@ -2366,6 +2436,7 @@ export class AIProviderRuntime {
|
|
|
2366
2436
|
}
|
|
2367
2437
|
|
|
2368
2438
|
configureFromTuple(tuple) {
|
|
2439
|
+
arcaneLogging.debug('[Arcane speech runtime] configureFromTuple', tuple);
|
|
2369
2440
|
if (!Array.isArray(tuple) || tuple.length !== 6) {
|
|
2370
2441
|
fail('AI preference tuple must contain exactly six entries.');
|
|
2371
2442
|
}
|
|
@@ -2416,12 +2487,19 @@ export class AIProviderRuntime {
|
|
|
2416
2487
|
}
|
|
2417
2488
|
|
|
2418
2489
|
status(role = null, options = {}) {
|
|
2490
|
+
if (role === null || SPEECH_ROLES.includes(role)) {
|
|
2491
|
+
arcaneLogging.debug('[Arcane speech runtime] status', role, options);
|
|
2492
|
+
}
|
|
2419
2493
|
if (role !== null) {
|
|
2420
2494
|
assertRole(role);
|
|
2421
2495
|
}
|
|
2422
2496
|
const snapshot = getAIRuntimeState();
|
|
2423
2497
|
if (options?.execution !== true) {
|
|
2424
|
-
|
|
2498
|
+
const result = role === null ? snapshot : snapshot.roles[role];
|
|
2499
|
+
if (role === null || SPEECH_ROLES.includes(role)) {
|
|
2500
|
+
arcaneLogging.debug('[Arcane speech runtime] status.result', role, result);
|
|
2501
|
+
}
|
|
2502
|
+
return result;
|
|
2425
2503
|
}
|
|
2426
2504
|
|
|
2427
2505
|
// Live provider inspection is explicit so ordinary lifecycle reads
|
|
@@ -2433,6 +2511,9 @@ export class AIProviderRuntime {
|
|
|
2433
2511
|
continue;
|
|
2434
2512
|
}
|
|
2435
2513
|
const providerStatus = validateProviderStatus(provider.status());
|
|
2514
|
+
if (SPEECH_ROLES.includes(selectedRole)) {
|
|
2515
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.status.result', selectedRole, providerStatus);
|
|
2516
|
+
}
|
|
2436
2517
|
if (providerStatus.execution == null) {
|
|
2437
2518
|
continue;
|
|
2438
2519
|
}
|
|
@@ -2441,10 +2522,17 @@ export class AIProviderRuntime {
|
|
|
2441
2522
|
execution: {...providerStatus.execution}
|
|
2442
2523
|
};
|
|
2443
2524
|
}
|
|
2444
|
-
|
|
2525
|
+
const result = role === null ? {...snapshot, roles} : roles[role];
|
|
2526
|
+
if (role === null || SPEECH_ROLES.includes(role)) {
|
|
2527
|
+
arcaneLogging.debug('[Arcane speech runtime] status.result', role, result);
|
|
2528
|
+
}
|
|
2529
|
+
return result;
|
|
2445
2530
|
}
|
|
2446
2531
|
|
|
2447
2532
|
catalog(role) {
|
|
2533
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2534
|
+
arcaneLogging.debug('[Arcane speech runtime] catalog', role);
|
|
2535
|
+
}
|
|
2448
2536
|
assertRole(role);
|
|
2449
2537
|
const entries = [];
|
|
2450
2538
|
for (const provider of this.#providers.values()) {
|
|
@@ -2452,6 +2540,9 @@ export class AIProviderRuntime {
|
|
|
2452
2540
|
continue;
|
|
2453
2541
|
}
|
|
2454
2542
|
const providerCatalog = provider.catalog();
|
|
2543
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2544
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.catalog.result', role, provider.id, providerCatalog);
|
|
2545
|
+
}
|
|
2455
2546
|
if (!Array.isArray(providerCatalog)) {
|
|
2456
2547
|
fail('AI provider.catalog() must synchronously return an array.');
|
|
2457
2548
|
}
|
|
@@ -2465,10 +2556,16 @@ export class AIProviderRuntime {
|
|
|
2465
2556
|
)
|
|
2466
2557
|
);
|
|
2467
2558
|
}
|
|
2559
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2560
|
+
arcaneLogging.debug('[Arcane speech runtime] catalog.result', role, entries);
|
|
2561
|
+
}
|
|
2468
2562
|
return completeValue(entries);
|
|
2469
2563
|
}
|
|
2470
2564
|
|
|
2471
2565
|
async inspect(role, options = {}) {
|
|
2566
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2567
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect', role, options);
|
|
2568
|
+
}
|
|
2472
2569
|
this.#assertOpen();
|
|
2473
2570
|
this.#assertNotConfiguring();
|
|
2474
2571
|
assertRole(role);
|
|
@@ -2482,25 +2579,29 @@ export class AIProviderRuntime {
|
|
|
2482
2579
|
const generation = slot.generation;
|
|
2483
2580
|
const selection = this.selection(role, {localOnly});
|
|
2484
2581
|
if (!selection) {
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2582
|
+
const result = completeValue({
|
|
2583
|
+
available: false,
|
|
2584
|
+
code: 'ARCANE_AI_ROLE_NOT_SELECTED',
|
|
2585
|
+
message: `No ${role} provider and model are selected.`
|
|
2586
|
+
});
|
|
2587
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2588
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect.result', role, result);
|
|
2589
|
+
}
|
|
2590
|
+
return result;
|
|
2492
2591
|
}
|
|
2493
2592
|
const provider = this.#providers.get(
|
|
2494
2593
|
providerKey(role, selection.providerId)
|
|
2495
2594
|
) ?? null;
|
|
2496
2595
|
if (!provider) {
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2596
|
+
const result = completeValue({
|
|
2597
|
+
available: false,
|
|
2598
|
+
code: 'ARCANE_AI_PROVIDER_UNAVAILABLE',
|
|
2599
|
+
message: `The selected ${role} provider is not registered.`
|
|
2600
|
+
});
|
|
2601
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2602
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect.result', role, result);
|
|
2603
|
+
}
|
|
2604
|
+
return result;
|
|
2504
2605
|
}
|
|
2505
2606
|
|
|
2506
2607
|
let inspection;
|
|
@@ -2512,11 +2613,20 @@ export class AIProviderRuntime {
|
|
|
2512
2613
|
selection,
|
|
2513
2614
|
{role, signal}
|
|
2514
2615
|
);
|
|
2616
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2617
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.inspect.result', role, selection, inspection);
|
|
2618
|
+
}
|
|
2515
2619
|
if (signal?.aborted) {
|
|
2516
2620
|
throw normalizedAbort();
|
|
2517
2621
|
}
|
|
2518
2622
|
} catch (error) {
|
|
2623
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2624
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect.error', role, error);
|
|
2625
|
+
}
|
|
2519
2626
|
if (isAbort(error, signal)) {
|
|
2627
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2628
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect.cancelled', role, error);
|
|
2629
|
+
}
|
|
2520
2630
|
throw normalizedAbort(error);
|
|
2521
2631
|
}
|
|
2522
2632
|
this.#assertOpen();
|
|
@@ -2526,36 +2636,47 @@ export class AIProviderRuntime {
|
|
|
2526
2636
|
error,
|
|
2527
2637
|
'ARCANE_AI_PROVIDER_AUTHORITY_BLOCKED'
|
|
2528
2638
|
);
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2639
|
+
const result = completeValue({
|
|
2640
|
+
available: false,
|
|
2641
|
+
code: unavailable.code,
|
|
2642
|
+
message: unavailable.message
|
|
2643
|
+
});
|
|
2644
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2645
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect.result', role, result);
|
|
2646
|
+
}
|
|
2647
|
+
return result;
|
|
2536
2648
|
}
|
|
2537
2649
|
this.#assertOpen();
|
|
2538
2650
|
this.#assertNotConfiguring();
|
|
2539
2651
|
this.#assertCurrentOperation(slot, generation, signal);
|
|
2540
2652
|
try {
|
|
2541
2653
|
validateInspection(inspection, selection);
|
|
2654
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2655
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect.result', role, inspection);
|
|
2656
|
+
}
|
|
2542
2657
|
return inspection;
|
|
2543
2658
|
} catch (error) {
|
|
2659
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2660
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect.error', role, error);
|
|
2661
|
+
}
|
|
2544
2662
|
const unavailable = stateError(
|
|
2545
2663
|
error,
|
|
2546
2664
|
'ARCANE_AI_PROVIDER_AUTHORITY_BLOCKED'
|
|
2547
2665
|
);
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2666
|
+
const result = completeValue({
|
|
2667
|
+
available: false,
|
|
2668
|
+
code: unavailable.code,
|
|
2669
|
+
message: unavailable.message
|
|
2670
|
+
});
|
|
2671
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2672
|
+
arcaneLogging.debug('[Arcane speech runtime] inspect.result', role, result);
|
|
2673
|
+
}
|
|
2674
|
+
return result;
|
|
2555
2675
|
}
|
|
2556
2676
|
}
|
|
2557
2677
|
|
|
2558
2678
|
async start(options) {
|
|
2679
|
+
arcaneLogging.debug('[Arcane speech runtime] start', options);
|
|
2559
2680
|
this.#assertOpen();
|
|
2560
2681
|
this.#assertNotConfiguring();
|
|
2561
2682
|
if (!this.#configured) {
|
|
@@ -2589,6 +2710,9 @@ export class AIProviderRuntime {
|
|
|
2589
2710
|
}
|
|
2590
2711
|
|
|
2591
2712
|
load(role, options = {}) {
|
|
2713
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2714
|
+
arcaneLogging.debug('[Arcane speech runtime] load', role, options);
|
|
2715
|
+
}
|
|
2592
2716
|
this.#assertOpen();
|
|
2593
2717
|
this.#assertNotConfiguring();
|
|
2594
2718
|
assertRole(role);
|
|
@@ -2747,25 +2871,36 @@ export class AIProviderRuntime {
|
|
|
2747
2871
|
slot.selection,
|
|
2748
2872
|
{role, signal: controller.signal}
|
|
2749
2873
|
);
|
|
2874
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2875
|
+
arcaneLogging.debug('[Arcane speech runtime] load.inspection', role, slot.selection, inspection);
|
|
2876
|
+
}
|
|
2750
2877
|
validateInspection(inspection, slot.selection);
|
|
2751
2878
|
runtime.#assertCurrentOperation(slot, generation, controller.signal);
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
);
|
|
2764
|
-
}
|
|
2879
|
+
const loadRequest = {
|
|
2880
|
+
role,
|
|
2881
|
+
selection: slot.selection,
|
|
2882
|
+
signal: controller.signal,
|
|
2883
|
+
progress: function publishAIProviderLoadProgress(progress) {
|
|
2884
|
+
runtime.#publishLoadProgress(
|
|
2885
|
+
slot,
|
|
2886
|
+
generation,
|
|
2887
|
+
operationId,
|
|
2888
|
+
progress
|
|
2889
|
+
);
|
|
2765
2890
|
}
|
|
2766
|
-
|
|
2891
|
+
};
|
|
2892
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2893
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.load', {generation, operationId}, loadRequest);
|
|
2894
|
+
}
|
|
2895
|
+
const loadResult = await provider.load(loadRequest);
|
|
2896
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2897
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.load.result', {role, generation, operationId}, loadResult);
|
|
2898
|
+
}
|
|
2767
2899
|
runtime.#assertCurrentOperation(slot, generation, controller.signal);
|
|
2768
2900
|
const providerStatus = validateProviderStatus(provider.status());
|
|
2901
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2902
|
+
arcaneLogging.debug('[Arcane speech runtime] load.status', {role, generation, operationId}, providerStatus);
|
|
2903
|
+
}
|
|
2769
2904
|
if (providerStatus.state !== 'ready'
|
|
2770
2905
|
|| providerStatus.loaded !== true
|
|
2771
2906
|
|| providerStatus.busy !== false) {
|
|
@@ -2794,6 +2929,9 @@ export class AIProviderRuntime {
|
|
|
2794
2929
|
const normalized = isAbort(error, controller.signal)
|
|
2795
2930
|
? normalizedAbort(error)
|
|
2796
2931
|
: error;
|
|
2932
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2933
|
+
arcaneLogging.debug('[Arcane speech runtime] load.error', {role, generation, operationId}, error);
|
|
2934
|
+
}
|
|
2797
2935
|
if (slot.generation === generation && !slot.unloadPromise) {
|
|
2798
2936
|
slot.ready = false;
|
|
2799
2937
|
if (role === 'tts') {
|
|
@@ -2834,6 +2972,9 @@ export class AIProviderRuntime {
|
|
|
2834
2972
|
}
|
|
2835
2973
|
|
|
2836
2974
|
unload(role, options = {}) {
|
|
2975
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
2976
|
+
arcaneLogging.debug('[Arcane speech runtime] unload', role, options);
|
|
2977
|
+
}
|
|
2837
2978
|
this.#assertNotConfiguring();
|
|
2838
2979
|
assertRole(role);
|
|
2839
2980
|
assertPlainObject(options, 'AI provider unload options');
|
|
@@ -2931,14 +3072,18 @@ export class AIProviderRuntime {
|
|
|
2931
3072
|
throw normalizedAbort();
|
|
2932
3073
|
}
|
|
2933
3074
|
if (provider) {
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
3075
|
+
const unloadRequest = {role, selection: slot.selection, signal};
|
|
3076
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3077
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.unload', {generation, operationId: unloadOperationId}, unloadRequest);
|
|
3078
|
+
}
|
|
3079
|
+
const unloadResult = await provider.unload(unloadRequest);
|
|
3080
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3081
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.unload.result', {role, generation, operationId: unloadOperationId}, unloadResult);
|
|
3082
|
+
}
|
|
2941
3083
|
const unloadedStatus = validateProviderStatus(provider.status());
|
|
3084
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3085
|
+
arcaneLogging.debug('[Arcane speech runtime] unload.status', role, unloadedStatus);
|
|
3086
|
+
}
|
|
2942
3087
|
if (unloadedStatus.loaded || unloadedStatus.busy) {
|
|
2943
3088
|
throw operationError(
|
|
2944
3089
|
`The selected ${role} provider remained loaded after unload.`,
|
|
@@ -2954,6 +3099,9 @@ export class AIProviderRuntime {
|
|
|
2954
3099
|
}
|
|
2955
3100
|
return runtime.status(role);
|
|
2956
3101
|
} catch (error) {
|
|
3102
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3103
|
+
arcaneLogging.debug('[Arcane speech runtime] unload.error', {role, generation, operationId: unloadOperationId}, error);
|
|
3104
|
+
}
|
|
2957
3105
|
if (slot.generation === generation) {
|
|
2958
3106
|
runtime.#publishRoleError(slot, error, providerOwned);
|
|
2959
3107
|
}
|
|
@@ -2982,6 +3130,9 @@ export class AIProviderRuntime {
|
|
|
2982
3130
|
}
|
|
2983
3131
|
|
|
2984
3132
|
dispose(role, options = {}) {
|
|
3133
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3134
|
+
arcaneLogging.debug('[Arcane speech runtime] dispose', role, options);
|
|
3135
|
+
}
|
|
2985
3136
|
this.#assertNotConfiguring();
|
|
2986
3137
|
assertRole(role);
|
|
2987
3138
|
assertPlainObject(options, 'AI provider dispose options');
|
|
@@ -3006,14 +3157,18 @@ export class AIProviderRuntime {
|
|
|
3006
3157
|
try {
|
|
3007
3158
|
await runtime.unload(role, {signal});
|
|
3008
3159
|
if (provider) {
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3160
|
+
const disposeRequest = {role, selection: slot.selection, signal};
|
|
3161
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3162
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.dispose', disposeRequest);
|
|
3163
|
+
}
|
|
3164
|
+
const disposeResult = await provider.dispose(disposeRequest);
|
|
3165
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3166
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.dispose.result', role, disposeResult);
|
|
3167
|
+
}
|
|
3016
3168
|
const disposedStatus = validateProviderStatus(provider.status());
|
|
3169
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3170
|
+
arcaneLogging.debug('[Arcane speech runtime] dispose.status', role, disposedStatus);
|
|
3171
|
+
}
|
|
3017
3172
|
if (disposedStatus.loaded || disposedStatus.busy) {
|
|
3018
3173
|
throw operationError(
|
|
3019
3174
|
`The selected ${role} provider remained active after disposal.`,
|
|
@@ -3035,6 +3190,9 @@ export class AIProviderRuntime {
|
|
|
3035
3190
|
);
|
|
3036
3191
|
return runtime.status(role);
|
|
3037
3192
|
} catch (error) {
|
|
3193
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3194
|
+
arcaneLogging.debug('[Arcane speech runtime] dispose.error', role, error);
|
|
3195
|
+
}
|
|
3038
3196
|
runtime.#publishRoleError(slot, error, runtime.status(role).loaded);
|
|
3039
3197
|
throw error;
|
|
3040
3198
|
} finally {
|
|
@@ -3046,6 +3204,7 @@ export class AIProviderRuntime {
|
|
|
3046
3204
|
}
|
|
3047
3205
|
|
|
3048
3206
|
disposeAll(options = {}) {
|
|
3207
|
+
arcaneLogging.debug('[Arcane speech runtime] disposeAll', options);
|
|
3049
3208
|
this.#assertNotConfiguring();
|
|
3050
3209
|
assertPlainObject(options, 'AI provider dispose-all options');
|
|
3051
3210
|
for (const key of Reflect.ownKeys(options)) {
|
|
@@ -3171,10 +3330,12 @@ export class AIProviderRuntime {
|
|
|
3171
3330
|
})();
|
|
3172
3331
|
this.#disposeAllPromise = disposing.then(
|
|
3173
3332
|
function releaseCompletedAIProviderRuntimeDisposal(result) {
|
|
3333
|
+
arcaneLogging.debug('[Arcane speech runtime] disposeAll.result', result);
|
|
3174
3334
|
runtime.#disposeAllPromise = null;
|
|
3175
3335
|
return result;
|
|
3176
3336
|
},
|
|
3177
3337
|
function releaseFailedAIProviderRuntimeDisposal(error) {
|
|
3338
|
+
arcaneLogging.debug('[Arcane speech runtime] disposeAll.error', error);
|
|
3178
3339
|
runtime.#disposeAllPromise = null;
|
|
3179
3340
|
throw error;
|
|
3180
3341
|
}
|
|
@@ -3183,6 +3344,9 @@ export class AIProviderRuntime {
|
|
|
3183
3344
|
}
|
|
3184
3345
|
|
|
3185
3346
|
request(role, options = {}) {
|
|
3347
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3348
|
+
arcaneLogging.debug('[Arcane speech runtime] request', role, options);
|
|
3349
|
+
}
|
|
3186
3350
|
return this.#requestRole(role, options, false);
|
|
3187
3351
|
}
|
|
3188
3352
|
|
|
@@ -3286,6 +3450,18 @@ export class AIProviderRuntime {
|
|
|
3286
3450
|
);
|
|
3287
3451
|
}
|
|
3288
3452
|
const maxConcurrentRequests = this.#providerRequestCapacity(provider);
|
|
3453
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3454
|
+
arcaneLogging.debug('[Arcane speech runtime] request.state', {
|
|
3455
|
+
role,
|
|
3456
|
+
generation: slot.generation,
|
|
3457
|
+
selection: slot.selection,
|
|
3458
|
+
ready: slot.ready,
|
|
3459
|
+
activeRequests: slot.activeRequests.size,
|
|
3460
|
+
queuedRequests: slot.requestQueue.length,
|
|
3461
|
+
maxConcurrentRequests,
|
|
3462
|
+
queued
|
|
3463
|
+
}, providerStatus);
|
|
3464
|
+
}
|
|
3289
3465
|
if ((!queued && slot.requestQueue.length)
|
|
3290
3466
|
|| slot.activeRequests.size >= maxConcurrentRequests) {
|
|
3291
3467
|
return this.#enqueueRoleRequest(slot, options);
|
|
@@ -3369,6 +3545,7 @@ export class AIProviderRuntime {
|
|
|
3369
3545
|
const projectedStreamChunks = [];
|
|
3370
3546
|
const projectedStreamReaders = [];
|
|
3371
3547
|
let projectedStreamClosed = false;
|
|
3548
|
+
let projectedStreamFailed = false;
|
|
3372
3549
|
let projectedStreamError = null;
|
|
3373
3550
|
let terminalSettled = false;
|
|
3374
3551
|
let resolveTerminal;
|
|
@@ -3394,7 +3571,7 @@ export class AIProviderRuntime {
|
|
|
3394
3571
|
}
|
|
3395
3572
|
while (projectedStreamReaders.length) {
|
|
3396
3573
|
const reader = projectedStreamReaders.shift();
|
|
3397
|
-
if (
|
|
3574
|
+
if (projectedStreamFailed) {
|
|
3398
3575
|
reader.reject(projectedStreamError);
|
|
3399
3576
|
} else {
|
|
3400
3577
|
reader.resolve({value: undefined, done: true});
|
|
@@ -3407,11 +3584,12 @@ export class AIProviderRuntime {
|
|
|
3407
3584
|
drainProjectedAIProviderStreamReaders();
|
|
3408
3585
|
}
|
|
3409
3586
|
|
|
3410
|
-
function closeProjectedAIProviderStream(error
|
|
3587
|
+
function closeProjectedAIProviderStream(error) {
|
|
3411
3588
|
if (projectedStreamClosed) {
|
|
3412
3589
|
return;
|
|
3413
3590
|
}
|
|
3414
3591
|
projectedStreamClosed = true;
|
|
3592
|
+
projectedStreamFailed = arguments.length > 0;
|
|
3415
3593
|
projectedStreamError = error;
|
|
3416
3594
|
drainProjectedAIProviderStreamReaders();
|
|
3417
3595
|
}
|
|
@@ -3424,7 +3602,7 @@ export class AIProviderRuntime {
|
|
|
3424
3602
|
});
|
|
3425
3603
|
}
|
|
3426
3604
|
if (projectedStreamClosed) {
|
|
3427
|
-
return
|
|
3605
|
+
return projectedStreamFailed
|
|
3428
3606
|
? Promise.reject(projectedStreamError)
|
|
3429
3607
|
: Promise.resolve({value: undefined, done: true});
|
|
3430
3608
|
}
|
|
@@ -3449,7 +3627,7 @@ export class AIProviderRuntime {
|
|
|
3449
3627
|
slot.activeRequests.delete(requestSequence);
|
|
3450
3628
|
}
|
|
3451
3629
|
runtime.#drainRoleRequestQueue(slot);
|
|
3452
|
-
if (
|
|
3630
|
+
if (arguments.length === 1) {
|
|
3453
3631
|
closeProjectedAIProviderStream(error);
|
|
3454
3632
|
restoreAIProviderRoleAfterRequest(error);
|
|
3455
3633
|
rejectTerminal(error);
|
|
@@ -3527,8 +3705,8 @@ export class AIProviderRuntime {
|
|
|
3527
3705
|
);
|
|
3528
3706
|
}
|
|
3529
3707
|
|
|
3530
|
-
async function cancelAIProviderStream(reason, terminalError
|
|
3531
|
-
const terminalOutcome = terminalError
|
|
3708
|
+
async function cancelAIProviderStream(reason, terminalError) {
|
|
3709
|
+
const terminalOutcome = arguments.length > 1 ? terminalError : normalizedAbort(
|
|
3532
3710
|
reason instanceof Error
|
|
3533
3711
|
? reason
|
|
3534
3712
|
: operationError(
|
|
@@ -3744,7 +3922,7 @@ export class AIProviderRuntime {
|
|
|
3744
3922
|
)
|
|
3745
3923
|
).catch(
|
|
3746
3924
|
function reportReturnedAIProviderStreamCancellationFailure(error) {
|
|
3747
|
-
|
|
3925
|
+
arcaneLogging.error(
|
|
3748
3926
|
'Arcane AI provider stream early-return cancellation failed.',
|
|
3749
3927
|
error
|
|
3750
3928
|
);
|
|
@@ -3799,6 +3977,9 @@ export class AIProviderRuntime {
|
|
|
3799
3977
|
}
|
|
3800
3978
|
|
|
3801
3979
|
requestRecord.cancel = async function cancelAIProviderRequest(reason) {
|
|
3980
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
3981
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.request.cancel', {role, generation, requestSequence, operationId}, reason);
|
|
3982
|
+
}
|
|
3802
3983
|
controller.abort(reason);
|
|
3803
3984
|
await requestRecord.promise?.catch(
|
|
3804
3985
|
function retainCancelledAIProviderRequest() {}
|
|
@@ -3810,15 +3991,20 @@ export class AIProviderRuntime {
|
|
|
3810
3991
|
if (controller.signal.aborted) {
|
|
3811
3992
|
throw normalizedAbort();
|
|
3812
3993
|
}
|
|
3813
|
-
const
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3994
|
+
const providerRequest = {
|
|
3995
|
+
role,
|
|
3996
|
+
selection: slot.selection,
|
|
3997
|
+
operation: options.operation,
|
|
3998
|
+
payload: options.payload,
|
|
3999
|
+
signal: controller.signal
|
|
4000
|
+
};
|
|
4001
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
4002
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.request', {generation, requestSequence, operationId}, providerRequest);
|
|
4003
|
+
}
|
|
4004
|
+
const result = await provider.request(providerRequest);
|
|
4005
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
4006
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.request.result', {role, generation, requestSequence, operationId}, result);
|
|
4007
|
+
}
|
|
3822
4008
|
runtime.#assertCurrentRequest(
|
|
3823
4009
|
slot,
|
|
3824
4010
|
generation,
|
|
@@ -3836,6 +4022,9 @@ export class AIProviderRuntime {
|
|
|
3836
4022
|
const normalized = isAbort(error, controller.signal)
|
|
3837
4023
|
? normalizedAbort(error)
|
|
3838
4024
|
: error;
|
|
4025
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
4026
|
+
arcaneLogging.debug('[Arcane speech runtime] provider.request.error', {role, generation, requestSequence, operationId}, error);
|
|
4027
|
+
}
|
|
3839
4028
|
requestError = normalized;
|
|
3840
4029
|
throw normalized;
|
|
3841
4030
|
} finally {
|
|
@@ -3843,6 +4032,17 @@ export class AIProviderRuntime {
|
|
|
3843
4032
|
if (slot.activeRequests.get(requestSequence) === requestRecord) {
|
|
3844
4033
|
slot.activeRequests.delete(requestSequence);
|
|
3845
4034
|
}
|
|
4035
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
4036
|
+
arcaneLogging.debug('[Arcane speech runtime] request.settled', {
|
|
4037
|
+
role,
|
|
4038
|
+
generation,
|
|
4039
|
+
currentGeneration: slot.generation,
|
|
4040
|
+
requestSequence,
|
|
4041
|
+
operationId,
|
|
4042
|
+
activeRequests: slot.activeRequests.size,
|
|
4043
|
+
queuedRequests: slot.requestQueue.length
|
|
4044
|
+
}, requestError);
|
|
4045
|
+
}
|
|
3846
4046
|
runtime.#drainRoleRequestQueue(slot);
|
|
3847
4047
|
if (slot.generation === generation && !slot.unloadPromise) {
|
|
3848
4048
|
restoreAIProviderRoleAfterRequest(requestError);
|
|
@@ -3861,18 +4061,26 @@ export class AIProviderRuntime {
|
|
|
3861
4061
|
}
|
|
3862
4062
|
|
|
3863
4063
|
transcribe(payload, options = {}) {
|
|
4064
|
+
arcaneLogging.debug('[Arcane speech runtime] transcribe', payload, options);
|
|
3864
4065
|
return this.#roleRequestAlias('stt', 'transcribe', payload, options);
|
|
3865
4066
|
}
|
|
3866
4067
|
|
|
3867
4068
|
synthesize(payload, options = {}) {
|
|
4069
|
+
arcaneLogging.debug('[Arcane speech runtime] synthesize', payload, options);
|
|
3868
4070
|
return this.#roleRequestAlias('tts', 'synthesize', payload, options);
|
|
3869
4071
|
}
|
|
3870
4072
|
|
|
3871
4073
|
cancel(role) {
|
|
4074
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
4075
|
+
arcaneLogging.debug('[Arcane speech runtime] cancel', role);
|
|
4076
|
+
}
|
|
3872
4077
|
assertRole(role);
|
|
3873
4078
|
const slot = this.#slots[role];
|
|
3874
4079
|
const requestRecord = slot.activeRequests.values().next().value ?? null;
|
|
3875
4080
|
if (!requestRecord) {
|
|
4081
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
4082
|
+
arcaneLogging.debug('[Arcane speech runtime] cancel.result', role, false);
|
|
4083
|
+
}
|
|
3876
4084
|
return false;
|
|
3877
4085
|
}
|
|
3878
4086
|
const reason = operationError(
|
|
@@ -3882,10 +4090,14 @@ export class AIProviderRuntime {
|
|
|
3882
4090
|
requestRecord?.controller.abort(reason);
|
|
3883
4091
|
const cancellation = requestRecord?.cancel?.(reason);
|
|
3884
4092
|
cancellation?.catch(function retainAIProviderCancelFailureInState() {});
|
|
4093
|
+
if (SPEECH_ROLES.includes(role)) {
|
|
4094
|
+
arcaneLogging.debug('[Arcane speech runtime] cancel.result', role, true, requestRecord.operationId);
|
|
4095
|
+
}
|
|
3885
4096
|
return true;
|
|
3886
4097
|
}
|
|
3887
4098
|
|
|
3888
4099
|
async setSpeechMuted(muted) {
|
|
4100
|
+
arcaneLogging.debug('[Arcane speech runtime] setSpeechMuted', muted);
|
|
3889
4101
|
this.#assertOpen();
|
|
3890
4102
|
this.#assertNotConfiguring();
|
|
3891
4103
|
if (typeof muted !== 'boolean') {
|
|
@@ -3924,6 +4136,7 @@ export class AIProviderRuntime {
|
|
|
3924
4136
|
}
|
|
3925
4137
|
if (runtime.#speechDesiredMuted === desiredMuted) {
|
|
3926
4138
|
runtime.#speechMuted = desiredMuted;
|
|
4139
|
+
arcaneLogging.debug('[Arcane speech runtime] setSpeechMuted.settled', desiredMuted);
|
|
3927
4140
|
return runtime.status('tts');
|
|
3928
4141
|
}
|
|
3929
4142
|
}
|
|
@@ -3971,6 +4184,15 @@ export class AIProviderRuntime {
|
|
|
3971
4184
|
}
|
|
3972
4185
|
|
|
3973
4186
|
#enqueueRoleRequest(slot, options) {
|
|
4187
|
+
if (SPEECH_ROLES.includes(slot.role)) {
|
|
4188
|
+
arcaneLogging.debug('[Arcane speech runtime] queue.enqueue', {
|
|
4189
|
+
role: slot.role,
|
|
4190
|
+
generation: slot.generation,
|
|
4191
|
+
selection: slot.selection,
|
|
4192
|
+
activeRequests: slot.activeRequests.size,
|
|
4193
|
+
queuedRequests: slot.requestQueue.length
|
|
4194
|
+
}, options);
|
|
4195
|
+
}
|
|
3974
4196
|
const runtime = this;
|
|
3975
4197
|
return new Promise(function queueAIProviderRoleRequest(resolve, reject) {
|
|
3976
4198
|
const entry = {
|
|
@@ -3986,6 +4208,13 @@ export class AIProviderRuntime {
|
|
|
3986
4208
|
}
|
|
3987
4209
|
slot.requestQueue.splice(index, 1);
|
|
3988
4210
|
entry.detachSignal?.();
|
|
4211
|
+
if (SPEECH_ROLES.includes(slot.role)) {
|
|
4212
|
+
arcaneLogging.debug('[Arcane speech runtime] queue.cancelled', {
|
|
4213
|
+
role: slot.role,
|
|
4214
|
+
generation: slot.generation,
|
|
4215
|
+
queuedRequests: slot.requestQueue.length
|
|
4216
|
+
}, options, options.signal?.reason);
|
|
4217
|
+
}
|
|
3989
4218
|
reject(normalizedAbort(options.signal?.reason));
|
|
3990
4219
|
}
|
|
3991
4220
|
if (options.signal) {
|
|
@@ -4024,6 +4253,15 @@ export class AIProviderRuntime {
|
|
|
4024
4253
|
&& slot.activeRequests.size < maxConcurrentRequests) {
|
|
4025
4254
|
const entry = slot.requestQueue.shift();
|
|
4026
4255
|
entry.detachSignal?.();
|
|
4256
|
+
if (SPEECH_ROLES.includes(slot.role)) {
|
|
4257
|
+
arcaneLogging.debug('[Arcane speech runtime] queue.dispatch', {
|
|
4258
|
+
role: slot.role,
|
|
4259
|
+
generation: slot.generation,
|
|
4260
|
+
activeRequests: slot.activeRequests.size,
|
|
4261
|
+
queuedRequests: slot.requestQueue.length,
|
|
4262
|
+
maxConcurrentRequests
|
|
4263
|
+
}, entry.options);
|
|
4264
|
+
}
|
|
4027
4265
|
if (entry.options.signal?.aborted) {
|
|
4028
4266
|
entry.reject(normalizedAbort(entry.options.signal.reason));
|
|
4029
4267
|
continue;
|
|
@@ -4032,6 +4270,9 @@ export class AIProviderRuntime {
|
|
|
4032
4270
|
try {
|
|
4033
4271
|
operation = runtime.#requestRole(slot.role, entry.options, true);
|
|
4034
4272
|
} catch (error) {
|
|
4273
|
+
if (SPEECH_ROLES.includes(slot.role)) {
|
|
4274
|
+
arcaneLogging.debug('[Arcane speech runtime] queue.error', slot.role, entry.options, error);
|
|
4275
|
+
}
|
|
4035
4276
|
entry.reject(error);
|
|
4036
4277
|
continue;
|
|
4037
4278
|
}
|
|
@@ -4043,6 +4284,9 @@ export class AIProviderRuntime {
|
|
|
4043
4284
|
const queued = slot.requestQueue.splice(0);
|
|
4044
4285
|
for (const entry of queued) {
|
|
4045
4286
|
entry.detachSignal?.();
|
|
4287
|
+
if (SPEECH_ROLES.includes(slot.role)) {
|
|
4288
|
+
arcaneLogging.debug('[Arcane speech runtime] queue.rejected', slot.role, entry.options, error);
|
|
4289
|
+
}
|
|
4046
4290
|
entry.reject(error);
|
|
4047
4291
|
}
|
|
4048
4292
|
}
|
|
@@ -4156,6 +4400,16 @@ export class AIProviderRuntime {
|
|
|
4156
4400
|
|
|
4157
4401
|
#publishRoleRequestState(slot) {
|
|
4158
4402
|
const requestRecord = slot.activeRequests.values().next().value ?? null;
|
|
4403
|
+
if (SPEECH_ROLES.includes(slot.role)) {
|
|
4404
|
+
arcaneLogging.debug('[Arcane speech runtime] queue.state', {
|
|
4405
|
+
role: slot.role,
|
|
4406
|
+
generation: slot.generation,
|
|
4407
|
+
selection: slot.selection,
|
|
4408
|
+
operationId: requestRecord?.operationId ?? null,
|
|
4409
|
+
activeRequests: slot.activeRequests.size,
|
|
4410
|
+
queuedRequests: slot.requestQueue.length
|
|
4411
|
+
});
|
|
4412
|
+
}
|
|
4159
4413
|
if (!requestRecord && slot.requestQueue.length === 0) {
|
|
4160
4414
|
return false;
|
|
4161
4415
|
}
|
|
@@ -4193,6 +4447,15 @@ export class AIProviderRuntime {
|
|
|
4193
4447
|
}
|
|
4194
4448
|
|
|
4195
4449
|
#publishLoadProgress(slot, generation, operationId, progress) {
|
|
4450
|
+
if (SPEECH_ROLES.includes(slot.role)) {
|
|
4451
|
+
arcaneLogging.debug('[Arcane speech runtime] load.progress', {
|
|
4452
|
+
role: slot.role,
|
|
4453
|
+
generation,
|
|
4454
|
+
currentGeneration: slot.generation,
|
|
4455
|
+
operationId,
|
|
4456
|
+
aborted: slot.loadController?.signal.aborted
|
|
4457
|
+
}, progress);
|
|
4458
|
+
}
|
|
4196
4459
|
if (slot.generation !== generation || slot.loadController?.signal.aborted) {
|
|
4197
4460
|
return false;
|
|
4198
4461
|
}
|
|
@@ -4213,6 +4476,17 @@ export class AIProviderRuntime {
|
|
|
4213
4476
|
|
|
4214
4477
|
#publishRoleError(slot, error, loaded) {
|
|
4215
4478
|
const requestRecord = slot.activeRequests.values().next().value ?? null;
|
|
4479
|
+
if (SPEECH_ROLES.includes(slot.role)) {
|
|
4480
|
+
arcaneLogging.debug('[Arcane speech runtime] role.error', {
|
|
4481
|
+
role: slot.role,
|
|
4482
|
+
generation: slot.generation,
|
|
4483
|
+
selection: slot.selection,
|
|
4484
|
+
operationId: requestRecord?.operationId ?? null,
|
|
4485
|
+
loaded,
|
|
4486
|
+
activeRequests: slot.activeRequests.size,
|
|
4487
|
+
queuedRequests: slot.requestQueue.length
|
|
4488
|
+
}, error);
|
|
4489
|
+
}
|
|
4216
4490
|
publishAIRuntimeRoleState(
|
|
4217
4491
|
slot.role,
|
|
4218
4492
|
roleRecord(
|
|
@@ -4237,6 +4511,9 @@ export class AIProviderRuntime {
|
|
|
4237
4511
|
return;
|
|
4238
4512
|
}
|
|
4239
4513
|
const slot = this.#slots[intent.role];
|
|
4514
|
+
if (SPEECH_ROLES.includes(intent.role)) {
|
|
4515
|
+
arcaneLogging.debug('[Arcane speech runtime] intent', intent);
|
|
4516
|
+
}
|
|
4240
4517
|
if (!slot.selection) {
|
|
4241
4518
|
return;
|
|
4242
4519
|
}
|