arcane-os 0.5.17 → 0.5.19
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 +34 -1
- 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 +158 -135
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +104 -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/architecture.md +1 -1
- package/docs/publishing.md +10 -4
- package/docs/reference/ai/browser-speech.md +198 -5
- package/docs/reference/ai/browser-wasm.md +29 -6
- 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 +170 -148
- 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
|
@@ -538,59 +538,35 @@
|
|
|
538
538
|
}
|
|
539
539
|
}
|
|
540
540
|
|
|
541
|
-
table
|
|
542
|
-
|
|
543
|
-
|
|
541
|
+
/* Native table layout shares columns across rows and grows with complete cell content. */
|
|
542
|
+
.chat_output table {
|
|
543
|
+
width: 100%;
|
|
544
|
+
margin: .75em 0;
|
|
544
545
|
border-collapse: collapse;
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
box-shadow: 0 0 0.7em var(--border-color);
|
|
549
|
-
border-radius: 0.5em 0.5em 0.5em 0.5em;
|
|
550
|
-
border-spacing: unset;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
thead, tbody {
|
|
554
|
-
display: table; /* These elements behave like table rows */
|
|
555
|
-
width: 100%; /* Table rows take full available space */
|
|
556
|
-
table-layout: fixed; /* Ensures the table layout respects the width settings */
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
tbody tr{
|
|
560
|
-
height: 130px;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
thead tr{
|
|
564
|
-
background: var(--background);
|
|
565
|
-
color: var(--platinum);
|
|
566
|
-
border-radius: .5em .5em 0 0;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
tr{
|
|
570
|
-
display: grid;
|
|
571
|
-
grid-template-columns:
|
|
572
|
-
6em 1fr 1fr 1fr;
|
|
546
|
+
border-spacing: 0;
|
|
547
|
+
background: var(--arcane-surface, var(--background));
|
|
548
|
+
color: var(--text-color);
|
|
573
549
|
}
|
|
574
550
|
|
|
575
|
-
|
|
576
|
-
|
|
551
|
+
.chat_output th,
|
|
552
|
+
.chat_output td {
|
|
553
|
+
padding: .6em .75em;
|
|
554
|
+
border: 1px solid var(--arcane-border, var(--border-color));
|
|
555
|
+
vertical-align: top;
|
|
556
|
+
overflow-wrap: anywhere;
|
|
577
557
|
}
|
|
578
558
|
|
|
579
|
-
th,
|
|
580
|
-
|
|
581
|
-
|
|
559
|
+
.chat_output th:not([align]),
|
|
560
|
+
.chat_output td:not([align]) {
|
|
561
|
+
text-align: start;
|
|
582
562
|
}
|
|
583
563
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
padding:.4em;
|
|
564
|
+
.chat_output thead {
|
|
565
|
+
background: var(--arcane-surface-muted, var(--secondary-color));
|
|
587
566
|
}
|
|
588
567
|
|
|
589
|
-
|
|
590
|
-
background: var(--
|
|
591
|
-
padding:.4em;
|
|
592
|
-
border: 1px solid var(--accent-color);
|
|
593
|
-
overflow: visible;
|
|
568
|
+
.chat_output tbody tr:hover {
|
|
569
|
+
background: var(--arcane-surface-muted, var(--secondary-color));
|
|
594
570
|
}
|
|
595
571
|
</style>
|
|
596
572
|
|
|
@@ -833,6 +809,9 @@
|
|
|
833
809
|
</section>
|
|
834
810
|
|
|
835
811
|
<script type="module">
|
|
812
|
+
const {default:Is}=await import('strong-type');
|
|
813
|
+
const is=new Is(false);
|
|
814
|
+
|
|
836
815
|
const {arcaneLogging}=await import('arcane-os/logging');
|
|
837
816
|
|
|
838
817
|
const {
|
|
@@ -909,7 +888,7 @@
|
|
|
909
888
|
host.language=host.language||'English';
|
|
910
889
|
host.name = host.name||'User';
|
|
911
890
|
host.aiName='AI';
|
|
912
|
-
let requestedInitialSpeechMuted=
|
|
891
|
+
let requestedInitialSpeechMuted=is.boolean(speech.initialMuted)
|
|
913
892
|
?speech.initialMuted
|
|
914
893
|
:true;
|
|
915
894
|
let initialSpeechMuteListenerInstalled=false;
|
|
@@ -1017,8 +996,8 @@
|
|
|
1017
996
|
let causeCode='';
|
|
1018
997
|
let message='';
|
|
1019
998
|
try{
|
|
1020
|
-
causeCode=
|
|
1021
|
-
message=
|
|
999
|
+
causeCode=is.string(error?.code)?error.code:'';
|
|
1000
|
+
message=is.string(error?.message)?error.message:'';
|
|
1022
1001
|
}catch{}
|
|
1023
1002
|
return {
|
|
1024
1003
|
error,
|
|
@@ -1035,7 +1014,7 @@
|
|
|
1035
1014
|
}
|
|
1036
1015
|
|
|
1037
1016
|
function isPlainRecord(value){
|
|
1038
|
-
if(!value
|
|
1017
|
+
if(!value||!is.object(value)||is.array(value))return false;
|
|
1039
1018
|
const prototype=Object.getPrototypeOf(value);
|
|
1040
1019
|
return prototype===Object.prototype||prototype===null;
|
|
1041
1020
|
}
|
|
@@ -1045,10 +1024,10 @@
|
|
|
1045
1024
|
// Only errors deliberately classified by their owner may provide UI copy.
|
|
1046
1025
|
// Provider and protocol diagnostics remain complete in console/events.
|
|
1047
1026
|
if(error?.userSafe===true){
|
|
1048
|
-
const message=
|
|
1027
|
+
const message=is.string(error.userMessage)
|
|
1049
1028
|
?error.userMessage
|
|
1050
1029
|
:error.message;
|
|
1051
|
-
if(
|
|
1030
|
+
if(is.string(message)&&message.trim()){
|
|
1052
1031
|
return message;
|
|
1053
1032
|
}
|
|
1054
1033
|
}
|
|
@@ -1057,10 +1036,10 @@
|
|
|
1057
1036
|
}
|
|
1058
1037
|
|
|
1059
1038
|
function visibleProgressText(value,fallback,field){
|
|
1060
|
-
if(
|
|
1039
|
+
if(is.string(value)){
|
|
1061
1040
|
return value||fallback;
|
|
1062
1041
|
}
|
|
1063
|
-
if(value&&
|
|
1042
|
+
if(value&&is.object(value)){
|
|
1064
1043
|
arcaneLogging.error(`Arcane chat progress ${field} is not text.`,value);
|
|
1065
1044
|
return visibleErrorMessage(value,fallback);
|
|
1066
1045
|
}
|
|
@@ -1085,10 +1064,10 @@
|
|
|
1085
1064
|
|
|
1086
1065
|
function compatibleChatSession(session){
|
|
1087
1066
|
return Boolean(session)
|
|
1088
|
-
&&
|
|
1089
|
-
&&
|
|
1090
|
-
&&
|
|
1091
|
-
&&
|
|
1067
|
+
&&is.object(session)
|
|
1068
|
+
&&is.function(session.ready)
|
|
1069
|
+
&&is.function(session.history)
|
|
1070
|
+
&&is.function(session.send);
|
|
1092
1071
|
}
|
|
1093
1072
|
|
|
1094
1073
|
function scrollTranscriptToBottom(){
|
|
@@ -1102,7 +1081,7 @@
|
|
|
1102
1081
|
const value=timestamp instanceof Date
|
|
1103
1082
|
?timestamp
|
|
1104
1083
|
:new Date(timestamp);
|
|
1105
|
-
if(timestamp!==undefined&×tamp!==null&&
|
|
1084
|
+
if(timestamp!==undefined&×tamp!==null&&is.finite(value.getTime())){
|
|
1106
1085
|
time.dateTime=value.toISOString();
|
|
1107
1086
|
time.textContent=value.toLocaleTimeString([],{
|
|
1108
1087
|
hour:'2-digit',
|
|
@@ -1119,7 +1098,7 @@
|
|
|
1119
1098
|
|
|
1120
1099
|
function normalizeVisibleToolCalls(value){
|
|
1121
1100
|
if(value===undefined) return [];
|
|
1122
|
-
if(!
|
|
1101
|
+
if(!is.array(value)){
|
|
1123
1102
|
const failure=new TypeError('Chat session tool calls must be an array.');
|
|
1124
1103
|
failure.code='AI_CHAT_INVALID_TOOL_CALL';
|
|
1125
1104
|
throw failure;
|
|
@@ -1128,18 +1107,18 @@
|
|
|
1128
1107
|
return value.map((call,index)=>{
|
|
1129
1108
|
if(
|
|
1130
1109
|
!call
|
|
1131
|
-
|
|
1132
|
-
||
|
|
1110
|
+
||!is.object(call)
|
|
1111
|
+
||is.array(call)
|
|
1133
1112
|
||call.type!=='function'
|
|
1134
1113
|
||!call.function
|
|
1135
|
-
|
|
1136
|
-
||
|
|
1137
|
-
|
|
1114
|
+
||!is.object(call.function)
|
|
1115
|
+
||is.array(call.function)
|
|
1116
|
+
||!is.string(call.id)
|
|
1138
1117
|
||!call.id.trim()
|
|
1139
1118
|
||ids.has(call.id)
|
|
1140
|
-
|
|
1119
|
+
||!is.string(call.function.name)
|
|
1141
1120
|
||!call.function.name.trim()
|
|
1142
|
-
|
|
1121
|
+
||!is.string(call.function.arguments)
|
|
1143
1122
|
){
|
|
1144
1123
|
const failure=new TypeError(`Chat session tool call ${index+1} is invalid.`);
|
|
1145
1124
|
failure.code='AI_CHAT_INVALID_TOOL_CALL';
|
|
@@ -1157,9 +1136,9 @@
|
|
|
1157
1136
|
}
|
|
1158
1137
|
|
|
1159
1138
|
function copyCompleteChatData(value,seen=new Map()){
|
|
1160
|
-
if(value===null
|
|
1139
|
+
if(value===null||!is.object(value)) return value;
|
|
1161
1140
|
if(seen.has(value)) return seen.get(value);
|
|
1162
|
-
if(
|
|
1141
|
+
if(is.array(value)){
|
|
1163
1142
|
const result=[];
|
|
1164
1143
|
seen.set(value,result);
|
|
1165
1144
|
for(const item of value) result.push(copyCompleteChatData(item,seen));
|
|
@@ -1177,12 +1156,12 @@
|
|
|
1177
1156
|
|
|
1178
1157
|
function sameCompleteChatData(left,right,seen=new Map()){
|
|
1179
1158
|
if(Object.is(left,right)) return true;
|
|
1180
|
-
if(!left||!right
|
|
1181
|
-
if(
|
|
1159
|
+
if(!left||!right||!is.object(left)||!is.object(right)) return false;
|
|
1160
|
+
if(is.array(left)!==is.array(right)) return false;
|
|
1182
1161
|
const matched=seen.get(left);
|
|
1183
1162
|
if(matched!==undefined) return matched===right;
|
|
1184
1163
|
seen.set(left,right);
|
|
1185
|
-
if(
|
|
1164
|
+
if(is.array(left)){
|
|
1186
1165
|
return left.length===right.length
|
|
1187
1166
|
&&left.every((value,index)=>sameCompleteChatData(value,right[index],seen));
|
|
1188
1167
|
}
|
|
@@ -1216,7 +1195,7 @@
|
|
|
1216
1195
|
failure.code='AI_CHAT_INVALID_TOOL_CALL';
|
|
1217
1196
|
throw failure;
|
|
1218
1197
|
}
|
|
1219
|
-
if(
|
|
1198
|
+
if(!is.string(argumentsRecord.message)||!argumentsRecord.message.trim()){
|
|
1220
1199
|
const failure=new TypeError(
|
|
1221
1200
|
'Structural tool call arguments must include a nonempty user-facing message.'
|
|
1222
1201
|
);
|
|
@@ -1227,7 +1206,7 @@
|
|
|
1227
1206
|
}
|
|
1228
1207
|
|
|
1229
1208
|
function setPendingStructuralToolCalls(calls=[]){
|
|
1230
|
-
if(!
|
|
1209
|
+
if(!is.array(calls)||calls.length===0){
|
|
1231
1210
|
pendingStructuralToolCalls=[];
|
|
1232
1211
|
pendingStructuralToolMessage='';
|
|
1233
1212
|
return [];
|
|
@@ -1244,8 +1223,8 @@
|
|
|
1244
1223
|
}
|
|
1245
1224
|
|
|
1246
1225
|
function sameStructuralToolCalls(left,right){
|
|
1247
|
-
return
|
|
1248
|
-
&&
|
|
1226
|
+
return is.array(left)
|
|
1227
|
+
&&is.array(right)
|
|
1249
1228
|
&&left.length===right.length
|
|
1250
1229
|
&&left.every((call,index)=>sameStructuralToolCall(call,right[index]));
|
|
1251
1230
|
}
|
|
@@ -1308,7 +1287,7 @@
|
|
|
1308
1287
|
}
|
|
1309
1288
|
|
|
1310
1289
|
function setTranscriptMessageContent(item,content,timestamp){
|
|
1311
|
-
if(
|
|
1290
|
+
if(!is.string(content)){
|
|
1312
1291
|
throw new TypeError('Chat session message content must be a string.');
|
|
1313
1292
|
}
|
|
1314
1293
|
item.querySelector('.thinking')?.remove();
|
|
@@ -1345,8 +1324,8 @@
|
|
|
1345
1324
|
}
|
|
1346
1325
|
|
|
1347
1326
|
function latestCommittedTranscriptTurn(transcript,requestMessages){
|
|
1348
|
-
if(!
|
|
1349
|
-
const expected=
|
|
1327
|
+
if(!is.array(transcript)) return null;
|
|
1328
|
+
const expected=is.array(requestMessages)
|
|
1350
1329
|
?requestMessages
|
|
1351
1330
|
:[requestMessages];
|
|
1352
1331
|
if(!expected.length) return null;
|
|
@@ -1362,7 +1341,7 @@
|
|
|
1362
1341
|
}
|
|
1363
1342
|
|
|
1364
1343
|
function createTranscriptMessage(role,content,name,{timestamp,toolCalls}={}){
|
|
1365
|
-
if(
|
|
1344
|
+
if(!is.string(content)){
|
|
1366
1345
|
throw new TypeError('Chat session message content must be a string.');
|
|
1367
1346
|
}
|
|
1368
1347
|
const item=chatOutput.ownerDocument.createElement('li');
|
|
@@ -1402,7 +1381,7 @@
|
|
|
1402
1381
|
}
|
|
1403
1382
|
|
|
1404
1383
|
function createSavedRecordFallback(message,index){
|
|
1405
|
-
const content=isPlainRecord(message)&&
|
|
1384
|
+
const content=isPlainRecord(message)&&is.string(message.content)
|
|
1406
1385
|
?message.content
|
|
1407
1386
|
:'Saved record content is available in details.';
|
|
1408
1387
|
const item=createTranscriptMessage(
|
|
@@ -1425,7 +1404,7 @@
|
|
|
1425
1404
|
}
|
|
1426
1405
|
|
|
1427
1406
|
function renderSessionHistory(history){
|
|
1428
|
-
if(!
|
|
1407
|
+
if(!is.array(history)){
|
|
1429
1408
|
throw new TypeError('Chat session history must be an array.');
|
|
1430
1409
|
}
|
|
1431
1410
|
const fragment=chatOutput.ownerDocument.createDocumentFragment();
|
|
@@ -1442,7 +1421,7 @@
|
|
|
1442
1421
|
'AI_CHAT_INCOHERENT_PERSISTENCE'
|
|
1443
1422
|
);
|
|
1444
1423
|
}
|
|
1445
|
-
if(
|
|
1424
|
+
if(!is.string(message.content)){
|
|
1446
1425
|
throw chatError(
|
|
1447
1426
|
'Saved chat contains a record without text content.',
|
|
1448
1427
|
'AI_CHAT_INCOHERENT_PERSISTENCE'
|
|
@@ -1465,7 +1444,7 @@
|
|
|
1465
1444
|
if(message.role==='tool'){
|
|
1466
1445
|
if(message.tool_call_id!==undefined){
|
|
1467
1446
|
if(
|
|
1468
|
-
|
|
1447
|
+
!is.string(message.tool_call_id)
|
|
1469
1448
|
||!message.tool_call_id.trim()
|
|
1470
1449
|
||!message.content.trim()
|
|
1471
1450
|
||!restoredPendingToolCalls.has(message.tool_call_id)
|
|
@@ -1494,7 +1473,7 @@
|
|
|
1494
1473
|
const name=message.role==='user'
|
|
1495
1474
|
?host.name
|
|
1496
1475
|
:message.role==='tool'
|
|
1497
|
-
?
|
|
1476
|
+
?is.string(message.name)&&message.name.trim()
|
|
1498
1477
|
?`Tool · ${message.name}`
|
|
1499
1478
|
:'Tool'
|
|
1500
1479
|
:message.role==='system'
|
|
@@ -1573,7 +1552,7 @@
|
|
|
1573
1552
|
ai
|
|
1574
1553
|
});
|
|
1575
1554
|
await session.ready();
|
|
1576
|
-
const history=
|
|
1555
|
+
const history=is.function(session.transcript)
|
|
1577
1556
|
?await session.transcript()
|
|
1578
1557
|
:await session.history();
|
|
1579
1558
|
if(destroyed||generation!==sessionBindingGeneration){
|
|
@@ -1653,10 +1632,10 @@
|
|
|
1653
1632
|
|
|
1654
1633
|
function isAbortSignal(value){
|
|
1655
1634
|
return value!==null
|
|
1656
|
-
&&
|
|
1657
|
-
&&
|
|
1658
|
-
&&
|
|
1659
|
-
&&
|
|
1635
|
+
&&is.object(value)
|
|
1636
|
+
&&is.boolean(value.aborted)
|
|
1637
|
+
&&is.function(value.addEventListener)
|
|
1638
|
+
&&is.function(value.removeEventListener);
|
|
1660
1639
|
}
|
|
1661
1640
|
|
|
1662
1641
|
function createChatSubmissionAbort(reason,message){
|
|
@@ -1793,7 +1772,7 @@
|
|
|
1793
1772
|
host.destroy=destroy;
|
|
1794
1773
|
host.session=null;
|
|
1795
1774
|
host.sessionStatus={state:'idle',message:'Chat session is not connected.'};
|
|
1796
|
-
host.modelName=
|
|
1775
|
+
host.modelName=is.string(host.modelName)?host.modelName:'';
|
|
1797
1776
|
host.aiAvailability={llm:false,stt:false,tts:false};
|
|
1798
1777
|
host.conversationComplete=false;
|
|
1799
1778
|
applyAIAvailability(host.aiAvailability);
|
|
@@ -1826,7 +1805,7 @@
|
|
|
1826
1805
|
);
|
|
1827
1806
|
|
|
1828
1807
|
function setConversationComplete(complete=true){
|
|
1829
|
-
if(
|
|
1808
|
+
if(!is.boolean(complete)){
|
|
1830
1809
|
throw new TypeError('Conversation completion state must be boolean.');
|
|
1831
1810
|
}
|
|
1832
1811
|
|
|
@@ -1847,7 +1826,7 @@
|
|
|
1847
1826
|
}
|
|
1848
1827
|
|
|
1849
1828
|
function setInitialSpeechMuted(initialMuted){
|
|
1850
|
-
if(
|
|
1829
|
+
if(!is.boolean(initialMuted)){
|
|
1851
1830
|
throw new TypeError('initialMuted must be boolean');
|
|
1852
1831
|
}
|
|
1853
1832
|
|
|
@@ -1883,13 +1862,13 @@
|
|
|
1883
1862
|
}={}
|
|
1884
1863
|
){
|
|
1885
1864
|
const messageId=String(id);
|
|
1886
|
-
const normalizedTotal=
|
|
1865
|
+
const normalizedTotal=is.finite(Number(total))
|
|
1887
1866
|
?Number(total)
|
|
1888
1867
|
:0;
|
|
1889
|
-
const normalizedCurrent=
|
|
1868
|
+
const normalizedCurrent=is.finite(Number(current))
|
|
1890
1869
|
?Number(current)
|
|
1891
1870
|
:0;
|
|
1892
|
-
const normalizedFailed=
|
|
1871
|
+
const normalizedFailed=is.finite(Number(failed))
|
|
1893
1872
|
?Number(failed)
|
|
1894
1873
|
:0;
|
|
1895
1874
|
const message=messageId
|
|
@@ -1998,9 +1977,9 @@
|
|
|
1998
1977
|
|
|
1999
1978
|
function hasSelectedAIRuntimeRole(role){
|
|
2000
1979
|
const record=latestAIRuntimeRoles?.[role];
|
|
2001
|
-
return
|
|
1980
|
+
return is.string(record?.providerId)
|
|
2002
1981
|
&&record.providerId.length>0
|
|
2003
|
-
&&
|
|
1982
|
+
&&is.string(record?.modelId)
|
|
2004
1983
|
&&record.modelId.length>0;
|
|
2005
1984
|
}
|
|
2006
1985
|
|
|
@@ -2046,26 +2025,40 @@
|
|
|
2046
2025
|
}
|
|
2047
2026
|
|
|
2048
2027
|
function selected(){
|
|
2049
|
-
return
|
|
2028
|
+
return is.string(role?.providerId)
|
|
2050
2029
|
&&role.providerId.length>0
|
|
2051
|
-
&&
|
|
2030
|
+
&&is.string(role?.modelId)
|
|
2052
2031
|
&&role.modelId.length>0;
|
|
2053
2032
|
}
|
|
2054
2033
|
|
|
2055
2034
|
function modelDisplayName(){
|
|
2056
|
-
const configured=
|
|
2035
|
+
const configured=is.string(host.modelName)
|
|
2057
2036
|
?host.modelName.trim()
|
|
2058
2037
|
:'';
|
|
2059
2038
|
return configured||role?.modelId||'the selected language model';
|
|
2060
2039
|
}
|
|
2061
2040
|
|
|
2062
2041
|
function determinateProgress(){
|
|
2042
|
+
if(role?.progress?.phase==='initialize'){
|
|
2043
|
+
const {completed,total,unit}=role.progress;
|
|
2044
|
+
if(
|
|
2045
|
+
!is.finite(total)
|
|
2046
|
+
||total<=0
|
|
2047
|
+
||!is.finite(completed)
|
|
2048
|
+
||completed<0
|
|
2049
|
+
||!is.string(unit)
|
|
2050
|
+
||!unit
|
|
2051
|
+
){
|
|
2052
|
+
return null;
|
|
2053
|
+
}
|
|
2054
|
+
return {completed,total,unit,byteTelemetry:false};
|
|
2055
|
+
}
|
|
2063
2056
|
const totalBytes=role?.progress?.totalBytes;
|
|
2064
2057
|
const loadedBytes=role?.progress?.loadedBytes;
|
|
2065
2058
|
if(
|
|
2066
|
-
|
|
2059
|
+
is.finite(totalBytes)
|
|
2067
2060
|
&&totalBytes>0
|
|
2068
|
-
&&
|
|
2061
|
+
&&is.finite(loadedBytes)
|
|
2069
2062
|
&&loadedBytes>=0
|
|
2070
2063
|
){
|
|
2071
2064
|
return {
|
|
@@ -2077,13 +2070,13 @@
|
|
|
2077
2070
|
}
|
|
2078
2071
|
const total=Number(role?.progress?.total);
|
|
2079
2072
|
const completed=Number(role?.progress?.completed);
|
|
2080
|
-
const unit=
|
|
2073
|
+
const unit=is.string(role?.progress?.unit)&&role.progress.unit
|
|
2081
2074
|
?role.progress.unit
|
|
2082
2075
|
:'items';
|
|
2083
2076
|
if(
|
|
2084
|
-
!
|
|
2077
|
+
!is.finite(total)
|
|
2085
2078
|
||total<=0
|
|
2086
|
-
||!
|
|
2079
|
+
||!is.finite(completed)
|
|
2087
2080
|
){
|
|
2088
2081
|
return null;
|
|
2089
2082
|
}
|
|
@@ -2096,7 +2089,7 @@
|
|
|
2096
2089
|
}
|
|
2097
2090
|
|
|
2098
2091
|
function formatBytes(value){
|
|
2099
|
-
if(!
|
|
2092
|
+
if(!is.finite(value)||value<0){
|
|
2100
2093
|
return '';
|
|
2101
2094
|
}
|
|
2102
2095
|
const bytes=value;
|
|
@@ -2127,7 +2120,7 @@
|
|
|
2127
2120
|
}
|
|
2128
2121
|
|
|
2129
2122
|
function approximateDuration(value){
|
|
2130
|
-
if(!
|
|
2123
|
+
if(!is.finite(value)||value<0){
|
|
2131
2124
|
return '';
|
|
2132
2125
|
}
|
|
2133
2126
|
const suppliedSeconds=value;
|
|
@@ -2151,13 +2144,13 @@
|
|
|
2151
2144
|
function activeTransferText(){
|
|
2152
2145
|
const active=role?.progress?.activeTransfers;
|
|
2153
2146
|
const limit=role?.progress?.transferLimit;
|
|
2154
|
-
const mode=
|
|
2147
|
+
const mode=is.string(role?.progress?.transferMode)
|
|
2155
2148
|
?role.progress.transferMode.trim().toLowerCase()
|
|
2156
2149
|
:'';
|
|
2157
2150
|
if(
|
|
2158
|
-
!
|
|
2151
|
+
!is.safeInteger(active)
|
|
2159
2152
|
||active<0
|
|
2160
|
-
||!
|
|
2153
|
+
||!is.safeInteger(limit)
|
|
2161
2154
|
||limit<1
|
|
2162
2155
|
||!mode
|
|
2163
2156
|
){
|
|
@@ -2181,9 +2174,11 @@
|
|
|
2181
2174
|
return `${active} of ${limit} ${noun}${limit===1?'':'s'} active`;
|
|
2182
2175
|
}
|
|
2183
2176
|
|
|
2184
|
-
function progressElapsedText(
|
|
2185
|
-
|
|
2186
|
-
|
|
2177
|
+
function progressElapsedText(
|
|
2178
|
+
elapsedMilliseconds,
|
|
2179
|
+
suffix='elapsed'
|
|
2180
|
+
){
|
|
2181
|
+
if(!is.finite(elapsedMilliseconds)||elapsedMilliseconds<0){
|
|
2187
2182
|
return '';
|
|
2188
2183
|
}
|
|
2189
2184
|
const elapsedSeconds=Math.floor(elapsedMilliseconds/1000);
|
|
@@ -2191,20 +2186,27 @@
|
|
|
2191
2186
|
const minutes=Math.floor(elapsedSeconds%3600/60);
|
|
2192
2187
|
const seconds=elapsedSeconds%60;
|
|
2193
2188
|
if(hours>0){
|
|
2194
|
-
return `${hours}h ${minutes}m
|
|
2189
|
+
return `${hours}h ${minutes}m ${suffix}`;
|
|
2195
2190
|
}
|
|
2196
2191
|
if(minutes>0){
|
|
2197
|
-
return `${minutes}m ${String(seconds).padStart(2,'0')}s
|
|
2192
|
+
return `${minutes}m ${String(seconds).padStart(2,'0')}s ${suffix}`;
|
|
2198
2193
|
}
|
|
2199
|
-
return `${seconds}s
|
|
2194
|
+
return `${seconds}s ${suffix}`;
|
|
2200
2195
|
}
|
|
2201
2196
|
|
|
2202
2197
|
function progressMessage(){
|
|
2203
2198
|
const measured=determinateProgress();
|
|
2204
|
-
const phaseValue=
|
|
2199
|
+
const phaseValue=is.string(role?.progress?.phase)&&role.progress.phase
|
|
2205
2200
|
?role.progress.phase
|
|
2206
2201
|
:'loading';
|
|
2207
|
-
const
|
|
2202
|
+
const initializing=phaseValue==='initialize';
|
|
2203
|
+
const phase=initializing
|
|
2204
|
+
?is.string(role?.progress?.message)&&role.progress.message
|
|
2205
|
+
?role.progress.message
|
|
2206
|
+
:is.string(role?.progress?.stage)&&role.progress.stage
|
|
2207
|
+
?role.progress.stage.replaceAll('-',' ')
|
|
2208
|
+
:'Initializing the selected model'
|
|
2209
|
+
:phaseValue.replaceAll('-',' ');
|
|
2208
2210
|
const parts=[
|
|
2209
2211
|
`Loading ${modelDisplayName()} through the Arcane SDK`,
|
|
2210
2212
|
phase
|
|
@@ -2217,7 +2219,7 @@
|
|
|
2217
2219
|
);
|
|
2218
2220
|
parts.push(`${formatBytes(remainingBytes)} remaining`);
|
|
2219
2221
|
const bytesPerSecond=role?.progress?.bytesPerSecond;
|
|
2220
|
-
if(
|
|
2222
|
+
if(is.finite(bytesPerSecond)&&bytesPerSecond>=0){
|
|
2221
2223
|
parts.push(`${formatBytes(bytesPerSecond)}/s`);
|
|
2222
2224
|
}else{
|
|
2223
2225
|
parts.push('Calculating speed');
|
|
@@ -2232,18 +2234,38 @@
|
|
|
2232
2234
|
:measured.unit;
|
|
2233
2235
|
parts.push(`${measured.completed} of ${measured.total} ${suffix}`);
|
|
2234
2236
|
}
|
|
2235
|
-
const transfers=activeTransferText();
|
|
2237
|
+
const transfers=initializing?'':activeTransferText();
|
|
2236
2238
|
if(transfers){
|
|
2237
2239
|
parts.push(transfers);
|
|
2238
2240
|
}
|
|
2239
|
-
const elapsed=progressElapsedText();
|
|
2241
|
+
const elapsed=progressElapsedText(Number(role?.progress?.elapsedMs));
|
|
2240
2242
|
if(elapsed){
|
|
2241
2243
|
parts.push(elapsed);
|
|
2242
|
-
if(role?.progress?.heartbeat===true){
|
|
2244
|
+
if(!initializing&&role?.progress?.heartbeat===true){
|
|
2243
2245
|
parts.push('Still working');
|
|
2244
2246
|
}
|
|
2245
2247
|
}
|
|
2246
|
-
if(
|
|
2248
|
+
if(initializing){
|
|
2249
|
+
const phaseElapsed=progressElapsedText(
|
|
2250
|
+
role.progress.phaseElapsedMs,
|
|
2251
|
+
'in this stage'
|
|
2252
|
+
);
|
|
2253
|
+
if(phaseElapsed){
|
|
2254
|
+
parts.push(phaseElapsed);
|
|
2255
|
+
}
|
|
2256
|
+
if(role.progress.heartbeat===true){
|
|
2257
|
+
const activityElapsed=progressElapsedText(
|
|
2258
|
+
role.progress.activityElapsedMs,
|
|
2259
|
+
'ago'
|
|
2260
|
+
);
|
|
2261
|
+
if(activityElapsed){
|
|
2262
|
+
parts.push(`Last runtime activity ${activityElapsed}`);
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
parts.push(measured
|
|
2266
|
+
?'Keep this tab open'
|
|
2267
|
+
:'Completion percentage unavailable; keep this tab open');
|
|
2268
|
+
}else if(!measured?.byteTelemetry){
|
|
2247
2269
|
parts.push('The first activation can take several minutes; keep this tab open');
|
|
2248
2270
|
}
|
|
2249
2271
|
return parts.join(' · ');
|
|
@@ -2342,7 +2364,7 @@
|
|
|
2342
2364
|
requestError='';
|
|
2343
2365
|
const intent={role:'llm',action,reason:'user'};
|
|
2344
2366
|
const request={intent,state:role};
|
|
2345
|
-
const operationId=
|
|
2367
|
+
const operationId=is.string(role?.operationId)&&role.operationId
|
|
2346
2368
|
?role.operationId
|
|
2347
2369
|
:createOperationId('llm-activation');
|
|
2348
2370
|
const generation=++requestGeneration;
|
|
@@ -2480,9 +2502,9 @@
|
|
|
2480
2502
|
if(
|
|
2481
2503
|
!controller
|
|
2482
2504
|
||requiredMethods.some(function missingConversationTimeboxMethod(name){
|
|
2483
|
-
return
|
|
2505
|
+
return !is.function(controller[name]);
|
|
2484
2506
|
})
|
|
2485
|
-
|
|
2507
|
+
||!is.string(controller.limitReachedMessage)
|
|
2486
2508
|
){
|
|
2487
2509
|
throw new TypeError('A compatible conversation timebox controller is required.');
|
|
2488
2510
|
}
|
|
@@ -2583,7 +2605,7 @@
|
|
|
2583
2605
|
}
|
|
2584
2606
|
|
|
2585
2607
|
function queueConversationTimeboxMessage(message,context,guard){
|
|
2586
|
-
const operationId=
|
|
2608
|
+
const operationId=is.string(context?.operationId)&&context.operationId
|
|
2587
2609
|
?context.operationId
|
|
2588
2610
|
:nextChatOperationId('conversation-timebox');
|
|
2589
2611
|
const deliveryContext={...context,operationId};
|
|
@@ -2597,7 +2619,7 @@
|
|
|
2597
2619
|
if(destroyed||aiRuntimeStateAbortController.signal.aborted){
|
|
2598
2620
|
return false;
|
|
2599
2621
|
}
|
|
2600
|
-
if(
|
|
2622
|
+
if(is.function(guard)&&!guard()){
|
|
2601
2623
|
return false;
|
|
2602
2624
|
}
|
|
2603
2625
|
let lastError;
|
|
@@ -2615,7 +2637,7 @@
|
|
|
2615
2637
|
if(destroyed||aiRuntimeStateAbortController.signal.aborted){
|
|
2616
2638
|
return false;
|
|
2617
2639
|
}
|
|
2618
|
-
if(
|
|
2640
|
+
if(is.function(guard)&&!guard()){
|
|
2619
2641
|
return false;
|
|
2620
2642
|
}
|
|
2621
2643
|
if(
|
|
@@ -2638,7 +2660,7 @@
|
|
|
2638
2660
|
if(destroyed||aiRuntimeStateAbortController.signal.aborted){
|
|
2639
2661
|
return false;
|
|
2640
2662
|
}
|
|
2641
|
-
if(
|
|
2663
|
+
if(is.function(guard)&&!guard()){
|
|
2642
2664
|
return false;
|
|
2643
2665
|
}
|
|
2644
2666
|
return requireConversationTimeboxDelivery(delivered);
|
|
@@ -2657,7 +2679,7 @@
|
|
|
2657
2679
|
if(destroyed||aiRuntimeStateAbortController.signal.aborted){
|
|
2658
2680
|
return false;
|
|
2659
2681
|
}
|
|
2660
|
-
if(
|
|
2682
|
+
if(is.function(guard)&&!guard()){
|
|
2661
2683
|
return false;
|
|
2662
2684
|
}
|
|
2663
2685
|
if(result!==false){
|
|
@@ -2673,7 +2695,7 @@
|
|
|
2673
2695
|
if(destroyed||aiRuntimeStateAbortController.signal.aborted){
|
|
2674
2696
|
return false;
|
|
2675
2697
|
}
|
|
2676
|
-
if(
|
|
2698
|
+
if(is.function(guard)&&!guard()){
|
|
2677
2699
|
return false;
|
|
2678
2700
|
}
|
|
2679
2701
|
setConversationTimeboxError(
|
|
@@ -2746,7 +2768,7 @@
|
|
|
2746
2768
|
);
|
|
2747
2769
|
|
|
2748
2770
|
async function streamMessage(text='', id='', isThinking){
|
|
2749
|
-
if(
|
|
2771
|
+
if(!is.string(text)){
|
|
2750
2772
|
if(text instanceof Error){
|
|
2751
2773
|
arcaneLogging.error('Arcane chat stream delivered an Error as content.',text);
|
|
2752
2774
|
throw text;
|
|
@@ -2816,7 +2838,7 @@
|
|
|
2816
2838
|
&&speech.muted===false
|
|
2817
2839
|
){
|
|
2818
2840
|
const aiRuntime=boundChatAI??globalThis.ai;
|
|
2819
|
-
if(
|
|
2841
|
+
if(is.function(aiRuntime?.streamTTS)){
|
|
2820
2842
|
void Promise.resolve(aiRuntime.streamTTS(text)).catch(
|
|
2821
2843
|
reportTTSError
|
|
2822
2844
|
);
|
|
@@ -3070,7 +3092,7 @@
|
|
|
3070
3092
|
);
|
|
3071
3093
|
}
|
|
3072
3094
|
|
|
3073
|
-
const sessionRequestMessages=
|
|
3095
|
+
const sessionRequestMessages=is.array(sessionRequest)
|
|
3074
3096
|
?sessionRequest
|
|
3075
3097
|
:[sessionRequest];
|
|
3076
3098
|
if(!sessionRequestMessages.length){
|
|
@@ -3103,7 +3125,7 @@
|
|
|
3103
3125
|
status:'Working'
|
|
3104
3126
|
}
|
|
3105
3127
|
);
|
|
3106
|
-
const result=
|
|
3128
|
+
const result=is.function(session.stream)
|
|
3107
3129
|
?await session.stream(
|
|
3108
3130
|
request,
|
|
3109
3131
|
{
|
|
@@ -3154,13 +3176,13 @@
|
|
|
3154
3176
|
){
|
|
3155
3177
|
return false;
|
|
3156
3178
|
}
|
|
3157
|
-
if(!result
|
|
3179
|
+
if(!result||!is.object(result)||is.array(result)){
|
|
3158
3180
|
throw new TypeError('The chat session returned an invalid result.');
|
|
3159
3181
|
}
|
|
3160
|
-
if(!result.message
|
|
3182
|
+
if(!result.message||!is.string(result.message.content)){
|
|
3161
3183
|
throw new TypeError('The chat session result must contain assistant message content.');
|
|
3162
3184
|
}
|
|
3163
|
-
const committedTurn=
|
|
3185
|
+
const committedTurn=is.function(session.transcript)
|
|
3164
3186
|
?latestCommittedTranscriptTurn(
|
|
3165
3187
|
await session.transcript(),
|
|
3166
3188
|
sessionRequestMessages
|
|
@@ -3351,7 +3373,7 @@
|
|
|
3351
3373
|
error.code='AI_CHAT_TOOL_RESULT_NOT_PENDING';
|
|
3352
3374
|
throw error;
|
|
3353
3375
|
}
|
|
3354
|
-
if(!
|
|
3376
|
+
if(!is.array(options.results)||options.results.length===0){
|
|
3355
3377
|
throw new TypeError('Tool results must be a nonempty array.');
|
|
3356
3378
|
}
|
|
3357
3379
|
const statuses=new Map([
|
|
@@ -3393,7 +3415,7 @@
|
|
|
3393
3415
|
}
|
|
3394
3416
|
const toolCallId=result.toolCallId;
|
|
3395
3417
|
if(
|
|
3396
|
-
|
|
3418
|
+
!is.string(toolCallId)
|
|
3397
3419
|
||!pendingById.has(toolCallId)
|
|
3398
3420
|
||resultsById.has(toolCallId)
|
|
3399
3421
|
){
|
|
@@ -3416,11 +3438,11 @@
|
|
|
3416
3438
|
'Tool-result status must be executed, declined, cancelled, or not-executed.'
|
|
3417
3439
|
);
|
|
3418
3440
|
}
|
|
3419
|
-
if(
|
|
3441
|
+
if(!is.string(result.message)||!result.message.trim()){
|
|
3420
3442
|
throw new TypeError('Tool-result message must contain user-facing text.');
|
|
3421
3443
|
}
|
|
3422
3444
|
const persist=result.persist??true;
|
|
3423
|
-
if(
|
|
3445
|
+
if(!is.boolean(persist)){
|
|
3424
3446
|
throw new TypeError('Tool-result persist must be boolean.');
|
|
3425
3447
|
}
|
|
3426
3448
|
resultsById.set(toolCallId,{
|
|
@@ -3450,7 +3472,7 @@
|
|
|
3450
3472
|
error.code='AI_CHAT_INCOHERENT_PERSISTENCE';
|
|
3451
3473
|
throw error;
|
|
3452
3474
|
}
|
|
3453
|
-
const operationId=
|
|
3475
|
+
const operationId=is.string(context.operationId)&&context.operationId
|
|
3454
3476
|
?context.operationId
|
|
3455
3477
|
:nextChatOperationId('tool-results');
|
|
3456
3478
|
const ownership=createChatSubmissionOwnership(context.signal??null);
|
|
@@ -3580,10 +3602,10 @@
|
|
|
3580
3602
|
if(destroyed){
|
|
3581
3603
|
return false;
|
|
3582
3604
|
}
|
|
3583
|
-
if(
|
|
3605
|
+
if(!is.string(textOverride)){
|
|
3584
3606
|
throw new TypeError('Programmatic chat messages must be strings.');
|
|
3585
3607
|
}
|
|
3586
|
-
if(!context
|
|
3608
|
+
if(!context||!is.object(context)||is.array(context)){
|
|
3587
3609
|
throw new TypeError('Chat submission context must be an object.');
|
|
3588
3610
|
}
|
|
3589
3611
|
if(host.conversationComplete){
|
|
@@ -3610,7 +3632,7 @@
|
|
|
3610
3632
|
if(!text.trim()){
|
|
3611
3633
|
return false;
|
|
3612
3634
|
}
|
|
3613
|
-
const operationId=
|
|
3635
|
+
const operationId=is.string(submissionContext.operationId)
|
|
3614
3636
|
&&submissionContext.operationId
|
|
3615
3637
|
?submissionContext.operationId
|
|
3616
3638
|
:nextChatOperationId('message');
|
|
@@ -3680,7 +3702,7 @@
|
|
|
3680
3702
|
if(host.aiAvailability.tts&&speech.muted===false){
|
|
3681
3703
|
const aiRuntime=boundChatAI??globalThis.ai;
|
|
3682
3704
|
aiRuntime?.stopAudio?.();
|
|
3683
|
-
if(
|
|
3705
|
+
if(is.function(aiRuntime?.resumeAudio)){
|
|
3684
3706
|
void Promise.resolve(aiRuntime.resumeAudio()).catch(
|
|
3685
3707
|
function reportPlaybackResumeFailure(error){
|
|
3686
3708
|
reportTTSError(error,'playback-resume');
|
|
@@ -3717,7 +3739,7 @@
|
|
|
3717
3739
|
if(destroyed){
|
|
3718
3740
|
return false;
|
|
3719
3741
|
}
|
|
3720
|
-
if(
|
|
3742
|
+
if(is.function(speech.reportTTSError)){
|
|
3721
3743
|
try{
|
|
3722
3744
|
speech.reportTTSError(error,boundary);
|
|
3723
3745
|
return true;
|