arcane-os 0.2.0 → 0.2.2
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 +35 -0
- package/README.md +8 -8
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +5 -5
- package/browser-runtime/ai/browser-speech-providers.mjs +331 -25
- package/docs/architecture.md +2 -2
- package/docs/reference/README.md +79 -13
- package/docs/reference/ai/browser-speech.md +336 -0
- package/docs/reference/ai/browser-wasm.md +207 -82
- package/docs/reference/availability-and-normalization.md +30 -4
- package/docs/reference/behavioral-testing.md +4 -1
- package/docs/reference/cli.md +29 -10
- package/docs/reference/core/arcane-ai-contracts.md +43 -9
- package/docs/reference/inventory/package-api.json +110 -14
- package/docs/reference/inventory/runtime-components.json +19 -6
- package/docs/reference/inventory/runtime-modules.json +113 -9
- package/docs/reference/protocols.md +260 -38
- package/docs/reference/runtime-components.md +108 -15
- package/docs/reference/runtime-modules.md +422 -8
- package/docs/reference/sdk-api.md +626 -85
- package/package.json +1 -1
- package/runtime/ARCANE_RUNTIME_RELEASE.json +19 -19
- package/runtime/arcane/components/chat.html +288 -52
- package/runtime/arcane/components/speech.html +339 -15
- package/runtime/arcane/modules/AI.js +1245 -136
- package/runtime/arcane/modules/AIProviderRuntime.js +299 -30
- package/runtime/arcane/modules/AIRuntimeState.js +23 -4
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +93 -8
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +448 -24
- package/runtime/arcane/modules/LocalAIReadinessController.js +1 -1
- package/schemas/arcane-lock.schema.json +6 -4
- package/src/dev-server.mjs +29 -13
- package/src/doctor.mjs +1 -3
- package/src/import-map.mjs +134 -83
- package/src/packager/core.mjs +311 -39
- package/src/scaffold.mjs +45 -17
- package/src/templates/workspace-template.mjs +23 -4
- package/src/toolchain.mjs +10 -2
- package/src/workspace.mjs +177 -24
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"builder": "arcane-sdk-runtime-v1",
|
|
4
|
-
"sdkVersion": "0.2.
|
|
4
|
+
"sdkVersion": "0.2.2",
|
|
5
5
|
"source": {
|
|
6
6
|
"authority": "sdk-canonical",
|
|
7
7
|
"repository": "https://github.com/TheWizardNexus/arcane-os-sdk.git",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"fileCount": 160,
|
|
17
|
-
"totalBytes":
|
|
18
|
-
"contentSha256": "
|
|
17
|
+
"totalBytes": 3643083,
|
|
18
|
+
"contentSha256": "0b09b1fd548152416f583d5e117197c7886b5a9e63071e43493577b4090e4a8c",
|
|
19
19
|
"files": [
|
|
20
20
|
{
|
|
21
21
|
"path": "arcane/components/app-bar.html",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"path": "arcane/components/chat.html",
|
|
42
|
-
"bytes":
|
|
43
|
-
"sha256": "
|
|
42
|
+
"bytes": 60478,
|
|
43
|
+
"sha256": "2f3a7f454c1e3da64c9eaeedb0869d49f04636b20ff59e5116a671e0d0a17973"
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
"path": "arcane/components/conversation-view.html",
|
|
@@ -159,8 +159,8 @@
|
|
|
159
159
|
},
|
|
160
160
|
{
|
|
161
161
|
"path": "arcane/components/speech.html",
|
|
162
|
-
"bytes":
|
|
163
|
-
"sha256": "
|
|
162
|
+
"bytes": 49596,
|
|
163
|
+
"sha256": "2a8b2929d28699ab9011f358b09b5fd2d53a0703542b2fee5cda8334261c6c86"
|
|
164
164
|
},
|
|
165
165
|
{
|
|
166
166
|
"path": "arcane/components/summary-strip.html",
|
|
@@ -374,8 +374,8 @@
|
|
|
374
374
|
},
|
|
375
375
|
{
|
|
376
376
|
"path": "arcane/modules/AI.js",
|
|
377
|
-
"bytes":
|
|
378
|
-
"sha256": "
|
|
377
|
+
"bytes": 120607,
|
|
378
|
+
"sha256": "703a5342ed0c0758cccdfd8469fbae6d86e91de8c43ec01c893619daf97c2d34"
|
|
379
379
|
},
|
|
380
380
|
{
|
|
381
381
|
"path": "arcane/modules/AIPreferenceRuntime.js",
|
|
@@ -389,8 +389,8 @@
|
|
|
389
389
|
},
|
|
390
390
|
{
|
|
391
391
|
"path": "arcane/modules/AIProviderRuntime.js",
|
|
392
|
-
"bytes":
|
|
393
|
-
"sha256": "
|
|
392
|
+
"bytes": 93507,
|
|
393
|
+
"sha256": "d1b33f678431128cefe6f43daabe177794e758c770394098871cf4ac726926b8"
|
|
394
394
|
},
|
|
395
395
|
{
|
|
396
396
|
"path": "arcane/modules/AIResponseLength.js",
|
|
@@ -404,8 +404,8 @@
|
|
|
404
404
|
},
|
|
405
405
|
{
|
|
406
406
|
"path": "arcane/modules/AIRuntimeState.js",
|
|
407
|
-
"bytes":
|
|
408
|
-
"sha256": "
|
|
407
|
+
"bytes": 25379,
|
|
408
|
+
"sha256": "492162cec5e6a8b9e9b437833172905b2cb4e352ca1ef30104c65ec29cf3fa29"
|
|
409
409
|
},
|
|
410
410
|
{
|
|
411
411
|
"path": "arcane/modules/AnsiText.js",
|
|
@@ -499,8 +499,8 @@
|
|
|
499
499
|
},
|
|
500
500
|
{
|
|
501
501
|
"path": "arcane/modules/ConfiguredAIChatSession.js",
|
|
502
|
-
"bytes":
|
|
503
|
-
"sha256": "
|
|
502
|
+
"bytes": 24501,
|
|
503
|
+
"sha256": "f95c3421bf07397e987f77fc3d02166cf780059dd3d6de90ceaded990752f51b"
|
|
504
504
|
},
|
|
505
505
|
{
|
|
506
506
|
"path": "arcane/modules/ConversationActionItems.js",
|
|
@@ -534,8 +534,8 @@
|
|
|
534
534
|
},
|
|
535
535
|
{
|
|
536
536
|
"path": "arcane/modules/DBOPFSDocumentLibrary.js",
|
|
537
|
-
"bytes":
|
|
538
|
-
"sha256": "
|
|
537
|
+
"bytes": 50695,
|
|
538
|
+
"sha256": "2831470ce54c3393595bf068d60c2e774804cbd51dba7491ad734bbfbea7f32f"
|
|
539
539
|
},
|
|
540
540
|
{
|
|
541
541
|
"path": "arcane/modules/DBOPFSWorker.js",
|
|
@@ -599,8 +599,8 @@
|
|
|
599
599
|
},
|
|
600
600
|
{
|
|
601
601
|
"path": "arcane/modules/LocalAIReadinessController.js",
|
|
602
|
-
"bytes":
|
|
603
|
-
"sha256": "
|
|
602
|
+
"bytes": 4340,
|
|
603
|
+
"sha256": "f80d51d0ad499664f265b4f2d52a46ede521a78d56714fecb0e13b939b261007"
|
|
604
604
|
},
|
|
605
605
|
{
|
|
606
606
|
"path": "arcane/modules/MD.js",
|
|
@@ -100,6 +100,7 @@
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
.chat_area[data-conversation-complete="true"] .conversation_timebox,
|
|
103
|
+
.chat_area[data-conversation-complete="true"] .ai_activation,
|
|
103
104
|
.chat_area[data-conversation-complete="true"] .chat_input_area,
|
|
104
105
|
.chat_area[data-conversation-complete="true"] > #speech,
|
|
105
106
|
.chat_area[data-conversation-complete="true"] > .controls{
|
|
@@ -209,6 +210,63 @@
|
|
|
209
210
|
box-shadow: var(--arcane-shadow-small, 0 .35rem 1rem var(--shadow-color));
|
|
210
211
|
}
|
|
211
212
|
|
|
213
|
+
.ai_activation {
|
|
214
|
+
display:flex;
|
|
215
|
+
flex:0 0 auto;
|
|
216
|
+
box-sizing:border-box;
|
|
217
|
+
width:100%;
|
|
218
|
+
padding:var(--arcane-space-3, .75rem);
|
|
219
|
+
align-items:center;
|
|
220
|
+
justify-content:space-between;
|
|
221
|
+
gap:var(--arcane-space-3, .75rem);
|
|
222
|
+
border:1px solid var(--arcane-border, var(--border-color));
|
|
223
|
+
border-radius:var(--arcane-chat-radius);
|
|
224
|
+
background:var(--arcane-surface-raised, var(--modal-background));
|
|
225
|
+
color:var(--text-color);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.ai_activation[hidden] {
|
|
229
|
+
display:none;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.ai_activation_copy {
|
|
233
|
+
min-width:0;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.ai_activation_copy strong,
|
|
237
|
+
.ai_activation_copy span {
|
|
238
|
+
display:block;
|
|
239
|
+
overflow-wrap:anywhere;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.ai_activation_copy span {
|
|
243
|
+
margin-block-start:.22rem;
|
|
244
|
+
font-size:.9rem;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.ai_activation button {
|
|
248
|
+
flex:0 0 auto;
|
|
249
|
+
min-height:2.65rem;
|
|
250
|
+
padding:.55rem .8rem;
|
|
251
|
+
border:1px solid var(--arcane-action, var(--primary-color));
|
|
252
|
+
border-radius:var(--arcane-radius-medium, .7rem);
|
|
253
|
+
background:var(--arcane-action, var(--primary-color));
|
|
254
|
+
color:var(--arcane-action-text, var(--button-text-color, var(--text-color)));
|
|
255
|
+
font:inherit;
|
|
256
|
+
font-weight:600;
|
|
257
|
+
cursor:pointer;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.ai_activation button:focus-visible {
|
|
261
|
+
outline:.2rem solid var(--arcane-focus, var(--focus-color));
|
|
262
|
+
outline-offset:.18rem;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.ai_activation button:disabled {
|
|
266
|
+
cursor:not-allowed;
|
|
267
|
+
opacity:.65;
|
|
268
|
+
}
|
|
269
|
+
|
|
212
270
|
.chat_input {
|
|
213
271
|
box-sizing: border-box;
|
|
214
272
|
width: 100%;
|
|
@@ -421,6 +479,20 @@
|
|
|
421
479
|
>Starting the elapsed timer.</span>
|
|
422
480
|
</section>
|
|
423
481
|
<ul type='text' class='chat_output' id='chat_output' tabindex='-1' aria-label='Conversation transcript'></ul>
|
|
482
|
+
<section
|
|
483
|
+
id="ai_activation"
|
|
484
|
+
class="ai_activation"
|
|
485
|
+
role="status"
|
|
486
|
+
aria-live="polite"
|
|
487
|
+
aria-busy="false"
|
|
488
|
+
hidden
|
|
489
|
+
>
|
|
490
|
+
<span class="ai_activation_copy">
|
|
491
|
+
<strong id="ai_activation_title">Language model not active</strong>
|
|
492
|
+
<span id="ai_activation_status">Start the selected language model to enable chat.</span>
|
|
493
|
+
</span>
|
|
494
|
+
<button type="button" id="ai_activation_button">Start language model</button>
|
|
495
|
+
</section>
|
|
424
496
|
<div class="chat_input_area">
|
|
425
497
|
<textarea type='text' class='chat_input' id='chat_input'></textarea>
|
|
426
498
|
<button type="button" id="chat_upload" class="chat_upload" title="Upload files" aria-label="Upload files">
|
|
@@ -624,11 +696,15 @@
|
|
|
624
696
|
const conversationTimeboxPanel=shadowRoot.querySelector('#conversation_timebox');
|
|
625
697
|
const conversationTimeboxElapsed=shadowRoot.querySelector('#conversation_timebox_elapsed');
|
|
626
698
|
const conversationTimeboxStatus=shadowRoot.querySelector('#conversation_timebox_status');
|
|
699
|
+
const aiActivationPanel=shadowRoot.querySelector('#ai_activation');
|
|
700
|
+
const aiActivationTitle=shadowRoot.querySelector('#ai_activation_title');
|
|
701
|
+
const aiActivationStatus=shadowRoot.querySelector('#ai_activation_status');
|
|
702
|
+
const aiActivationButton=shadowRoot.querySelector('#ai_activation_button');
|
|
627
703
|
const [
|
|
628
704
|
{default:MD},
|
|
629
705
|
{default:FileEntity},
|
|
630
706
|
{ConversationSubmissionBarrier,requireConversationTimeboxDelivery},
|
|
631
|
-
{subscribeAIRuntimeState}
|
|
707
|
+
{requestAIRuntimeIntent,subscribeAIRuntimeState}
|
|
632
708
|
]=await Promise.all([
|
|
633
709
|
import('../modules/MD.js'),
|
|
634
710
|
import('../entities/File.js'),
|
|
@@ -643,8 +719,7 @@
|
|
|
643
719
|
?speech.initialMuted
|
|
644
720
|
:true;
|
|
645
721
|
let initialSpeechMuteListenerInstalled=false;
|
|
646
|
-
let
|
|
647
|
-
let speechAvailabilityListenerInstalled=false;
|
|
722
|
+
let latestAIRuntimeRoles=null;
|
|
648
723
|
const hostSubmissionBarrier=new ConversationSubmissionBarrier();
|
|
649
724
|
const aiRuntimeStateAbortController=new AbortController();
|
|
650
725
|
let programmaticSubmissionQueue=Promise.resolve(true);
|
|
@@ -663,6 +738,18 @@
|
|
|
663
738
|
console.warn('html-import chat.html `host.languageChanged` method not implemented.\n\nThis can also be done by listening for the "chat-language-changed" event.\n\nIt is still best practice to implement the `.languageChanged` method atleast with an empty function.\n\n')
|
|
664
739
|
}
|
|
665
740
|
|
|
741
|
+
host.requestAIActivation=host.requestAIActivation||function requestAIActivation(intent){
|
|
742
|
+
return requestAIRuntimeIntent(intent);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const aiActivationController=createAIActivationController({
|
|
746
|
+
host,
|
|
747
|
+
panel:aiActivationPanel,
|
|
748
|
+
title:aiActivationTitle,
|
|
749
|
+
status:aiActivationStatus,
|
|
750
|
+
button:aiActivationButton
|
|
751
|
+
});
|
|
752
|
+
|
|
666
753
|
host.streamMessage=streamMessage;
|
|
667
754
|
host.setMessageProgress=setMessageProgress;
|
|
668
755
|
host.setAIAvailability=setAIAvailability;
|
|
@@ -822,36 +909,32 @@
|
|
|
822
909
|
}
|
|
823
910
|
|
|
824
911
|
function setAIAvailability(input={}){
|
|
825
|
-
const explicitSpeechAvailability={};
|
|
826
912
|
const availability={
|
|
827
|
-
llm:
|
|
913
|
+
llm:hasSelectedAIRuntimeRole('llm')
|
|
914
|
+
?latestAIRuntimeRoles.llm.state==='ready'
|
|
915
|
+
:Object.prototype.hasOwnProperty.call(input,'llm')
|
|
828
916
|
?Boolean(input.llm)
|
|
829
917
|
:host.aiAvailability.llm,
|
|
830
|
-
stt:
|
|
831
|
-
?
|
|
918
|
+
stt:latestAIRuntimeRoles
|
|
919
|
+
?latestAIRuntimeRoles.stt.state==='ready'
|
|
832
920
|
:host.aiAvailability.stt,
|
|
833
|
-
tts:
|
|
834
|
-
?
|
|
921
|
+
tts:latestAIRuntimeRoles
|
|
922
|
+
?latestAIRuntimeRoles.tts.state==='ready'
|
|
835
923
|
:host.aiAvailability.tts
|
|
836
924
|
};
|
|
837
925
|
|
|
838
|
-
if(Object.prototype.hasOwnProperty.call(input,'stt')){
|
|
839
|
-
explicitSpeechAvailability.stt=availability.stt;
|
|
840
|
-
}
|
|
841
|
-
if(Object.prototype.hasOwnProperty.call(input,'tts')){
|
|
842
|
-
explicitSpeechAvailability.tts=availability.tts;
|
|
843
|
-
}
|
|
844
926
|
applyAIAvailability(availability);
|
|
845
|
-
if(Object.keys(explicitSpeechAvailability).length){
|
|
846
|
-
pendingSpeechAvailability={
|
|
847
|
-
...(pendingSpeechAvailability||{}),
|
|
848
|
-
...explicitSpeechAvailability
|
|
849
|
-
};
|
|
850
|
-
synchronizeSpeechCompatibilityAvailability();
|
|
851
|
-
}
|
|
852
927
|
return {...availability};
|
|
853
928
|
}
|
|
854
929
|
|
|
930
|
+
function hasSelectedAIRuntimeRole(role){
|
|
931
|
+
const record=latestAIRuntimeRoles?.[role];
|
|
932
|
+
return typeof record?.providerId==='string'
|
|
933
|
+
&&record.providerId.length>0
|
|
934
|
+
&&typeof record?.modelId==='string'
|
|
935
|
+
&&record.modelId.length>0;
|
|
936
|
+
}
|
|
937
|
+
|
|
855
938
|
function applyAIAvailability(availability){
|
|
856
939
|
host.aiAvailability={...availability};
|
|
857
940
|
send.disabled=host.conversationComplete||!availability.llm;
|
|
@@ -861,43 +944,195 @@
|
|
|
861
944
|
send.setAttribute('aria-label',send.title);
|
|
862
945
|
}
|
|
863
946
|
|
|
864
|
-
function
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
});
|
|
870
|
-
}
|
|
947
|
+
function createAIActivationController({host,panel,title,status,button,EventClass=CustomEvent}){
|
|
948
|
+
let role=null;
|
|
949
|
+
let requestPending=false;
|
|
950
|
+
let requestError='';
|
|
951
|
+
let destroyed=false;
|
|
871
952
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
953
|
+
function visibleError(error,fallback){
|
|
954
|
+
const message=typeof error?.message==='string'
|
|
955
|
+
?error.message.trim()
|
|
956
|
+
:'';
|
|
957
|
+
return (message||fallback).slice(0,240);
|
|
875
958
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
return;
|
|
959
|
+
|
|
960
|
+
function cancellation(error){
|
|
961
|
+
return error?.name==='AbortError'
|
|
962
|
+
||['ARCANE_AI_REQUEST_ABORTED','AI_CHAT_ABORTED'].includes(error?.code);
|
|
881
963
|
}
|
|
882
|
-
|
|
883
|
-
|
|
964
|
+
|
|
965
|
+
function selected(){
|
|
966
|
+
return typeof role?.providerId==='string'
|
|
967
|
+
&&role.providerId.length>0
|
|
968
|
+
&&typeof role?.modelId==='string'
|
|
969
|
+
&&role.modelId.length>0;
|
|
884
970
|
}
|
|
885
971
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
972
|
+
function progressMessage(){
|
|
973
|
+
if(!role?.progress){
|
|
974
|
+
return 'The selected language model is loading.';
|
|
975
|
+
}
|
|
976
|
+
const progress=role.progress;
|
|
977
|
+
const amount=progress.total===null
|
|
978
|
+
?`${progress.completed} ${progress.unit}`
|
|
979
|
+
:`${progress.completed} of ${progress.total} ${progress.unit}`;
|
|
980
|
+
return `${progress.phase}, ${amount}${progress.heartbeat?', active heartbeat':''}.`;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
function render(){
|
|
984
|
+
const visible=selected()&&role.state!=='ready';
|
|
985
|
+
panel.hidden=!visible;
|
|
986
|
+
panel.setAttribute(
|
|
987
|
+
'aria-busy',
|
|
988
|
+
String(requestPending||['loading','unloading'].includes(role?.state))
|
|
989
|
+
);
|
|
990
|
+
if(!visible){
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
if(requestPending){
|
|
994
|
+
title.textContent='Requesting language model activation';
|
|
995
|
+
status.textContent='Waiting for the selected language model runtime.';
|
|
996
|
+
button.textContent='Requesting…';
|
|
997
|
+
button.disabled=true;
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
if(role.state==='loading'){
|
|
1001
|
+
title.textContent='Starting language model';
|
|
1002
|
+
status.textContent=progressMessage();
|
|
1003
|
+
button.textContent='Cancel loading';
|
|
1004
|
+
button.disabled=false;
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
if(role.state==='unloading'){
|
|
1008
|
+
title.textContent='Canceling language model load';
|
|
1009
|
+
status.textContent='Waiting for the selected language model runtime to stop.';
|
|
1010
|
+
button.textContent='Canceling…';
|
|
1011
|
+
button.disabled=true;
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
if(role.state==='error'||requestError){
|
|
1015
|
+
title.textContent='Language model activation failed';
|
|
1016
|
+
status.textContent=requestError||visibleError(
|
|
1017
|
+
role.error,
|
|
1018
|
+
'The selected language model could not start.'
|
|
1019
|
+
);
|
|
1020
|
+
button.textContent='Try again';
|
|
1021
|
+
button.disabled=false;
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
if(role.state==='unloaded'){
|
|
1025
|
+
title.textContent='Language model not active';
|
|
1026
|
+
status.textContent='Start the selected language model to enable chat.';
|
|
1027
|
+
button.textContent='Start language model';
|
|
1028
|
+
button.disabled=false;
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
title.textContent='Language model unavailable';
|
|
1032
|
+
status.textContent='The selected language model cannot be activated in this state.';
|
|
1033
|
+
button.textContent='Unavailable';
|
|
1034
|
+
button.disabled=true;
|
|
1035
|
+
}
|
|
893
1036
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
1037
|
+
async function request(action){
|
|
1038
|
+
if(destroyed||requestPending||!selected()){
|
|
1039
|
+
return false;
|
|
1040
|
+
}
|
|
1041
|
+
const permitted=action==='load'
|
|
1042
|
+
?['unloaded','error'].includes(role.state)
|
|
1043
|
+
:action==='unload'&&role.state==='loading';
|
|
1044
|
+
if(!permitted){
|
|
1045
|
+
return false;
|
|
1046
|
+
}
|
|
1047
|
+
requestError='';
|
|
1048
|
+
const intent=Object.freeze({role:'llm',action,reason:'user'});
|
|
1049
|
+
const request=Object.freeze({intent,state:role});
|
|
1050
|
+
const activationEvent=new EventClass(
|
|
1051
|
+
'chat-ai-activation-request',
|
|
1052
|
+
{
|
|
1053
|
+
bubbles:true,
|
|
1054
|
+
composed:true,
|
|
1055
|
+
cancelable:true,
|
|
1056
|
+
detail:request
|
|
1057
|
+
}
|
|
1058
|
+
);
|
|
1059
|
+
if(!host.dispatchEvent(activationEvent)){
|
|
1060
|
+
render();
|
|
1061
|
+
return false;
|
|
1062
|
+
}
|
|
1063
|
+
requestPending=true;
|
|
1064
|
+
render();
|
|
1065
|
+
try{
|
|
1066
|
+
await host.requestAIActivation(intent);
|
|
1067
|
+
return true;
|
|
1068
|
+
}catch(error){
|
|
1069
|
+
if(action==='load'
|
|
1070
|
+
&&cancellation(error)
|
|
1071
|
+
&&['unloaded','unloading'].includes(role?.state)){
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
const message=visibleError(
|
|
1075
|
+
error,
|
|
1076
|
+
`The language model ${action} request failed.`
|
|
1077
|
+
);
|
|
1078
|
+
requestError=message;
|
|
1079
|
+
host.dispatchEvent(
|
|
1080
|
+
new EventClass(
|
|
1081
|
+
'chat-ai-activation-error',
|
|
1082
|
+
{
|
|
1083
|
+
bubbles:true,
|
|
1084
|
+
composed:true,
|
|
1085
|
+
detail:Object.freeze({request,error,message})
|
|
1086
|
+
}
|
|
1087
|
+
)
|
|
1088
|
+
);
|
|
1089
|
+
return false;
|
|
1090
|
+
}finally{
|
|
1091
|
+
requestPending=false;
|
|
1092
|
+
render();
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
function activateSelectedAI(){
|
|
1097
|
+
const action=role?.state==='loading'?'unload':'load';
|
|
1098
|
+
void request(action);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
function synchronize(nextRole){
|
|
1102
|
+
if(destroyed){
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
if(role?.state!==nextRole.state
|
|
1106
|
+
||role?.providerId!==nextRole.providerId
|
|
1107
|
+
||role?.modelId!==nextRole.modelId){
|
|
1108
|
+
requestError='';
|
|
1109
|
+
requestPending=false;
|
|
1110
|
+
}
|
|
1111
|
+
role=nextRole;
|
|
1112
|
+
render();
|
|
900
1113
|
}
|
|
1114
|
+
|
|
1115
|
+
function destroy(){
|
|
1116
|
+
if(destroyed){
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
destroyed=true;
|
|
1120
|
+
button.removeEventListener('click',activateSelectedAI);
|
|
1121
|
+
panel.hidden=true;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
button.addEventListener('click',activateSelectedAI);
|
|
1125
|
+
return Object.freeze({request,synchronize,destroy});
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
function synchronizeAIRuntimeState(snapshot){
|
|
1129
|
+
latestAIRuntimeRoles=snapshot.roles;
|
|
1130
|
+
aiActivationController.synchronize(snapshot.roles.llm);
|
|
1131
|
+
applyAIAvailability({
|
|
1132
|
+
llm:snapshot.roles.llm.state==='ready',
|
|
1133
|
+
stt:snapshot.roles.stt.state==='ready',
|
|
1134
|
+
tts:snapshot.roles.tts.state==='ready'
|
|
1135
|
+
});
|
|
901
1136
|
}
|
|
902
1137
|
|
|
903
1138
|
function formatConversationTime(milliseconds=0){
|
|
@@ -1432,6 +1667,7 @@
|
|
|
1432
1667
|
|
|
1433
1668
|
function destroy(){
|
|
1434
1669
|
aiRuntimeStateAbortController.abort();
|
|
1670
|
+
aiActivationController.destroy();
|
|
1435
1671
|
window.removeEventListener('pagehide',destroy);
|
|
1436
1672
|
speech.destroy?.();
|
|
1437
1673
|
host.ready=false;
|