arcane-os 0.5.16 → 0.5.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/README.md +42 -19
- package/bin/arcane-test.mjs +16 -13
- package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
- package/browser-runtime/ai/browser-speech-providers.mjs +53 -46
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -23
- package/browser-runtime/ai/model-controller.mjs +94 -91
- package/browser-runtime/ai/speech-worker-client.mjs +12 -9
- package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
- package/browser-runtime/dependencies/strong-type/index.js +207 -82
- package/browser-runtime/dependencies/strong-type/package.json +15 -6
- package/browser-runtime/dom-event-instrumentation.mjs +24 -20
- package/browser-runtime/event-manager.mjs +111 -108
- package/browser-runtime/speech-text.mjs +35 -0
- package/docs/architecture.md +1 -1
- package/docs/reference/README.md +8 -8
- package/docs/reference/ai/browser-speech.md +230 -16
- package/docs/reference/ai/twin-cloud.md +1 -1
- package/docs/reference/availability-and-normalization.md +42 -1
- package/docs/reference/cli.md +1 -1
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/inventory/package-api.json +60 -4
- package/docs/reference/inventory/runtime-components.json +2 -2
- package/docs/reference/inventory/runtime-modules.json +29 -31
- package/docs/reference/protocols.md +17 -13
- package/docs/reference/runtime-components.md +6 -5
- package/docs/reference/runtime-modules.md +212 -70
- package/docs/reference/sdk-api.md +197 -11
- package/examples/wasm-ai-demo/index.html +1 -0
- package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
- package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
- package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
- package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
- package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
- package/node_modules/strong-type/README.md +42 -24
- package/node_modules/strong-type/benchmark/core.js +324 -0
- package/node_modules/strong-type/index.js +207 -82
- package/node_modules/strong-type/package.json +14 -6
- package/package.json +4 -3
- package/runtime/arcane/components/app-bar.html +5 -2
- package/runtime/arcane/components/assistant-panel.html +5 -2
- package/runtime/arcane/components/chart.html +15 -12
- package/runtime/arcane/components/chat.html +118 -141
- package/runtime/arcane/components/dashboard-config.html +6 -3
- package/runtime/arcane/components/data-view.html +4 -1
- package/runtime/arcane/components/directory-picker.html +5 -2
- package/runtime/arcane/components/document-inspector.html +6 -3
- package/runtime/arcane/components/file-drop.html +5 -2
- package/runtime/arcane/components/file-inspector.html +9 -6
- package/runtime/arcane/components/file-manager.html +16 -13
- package/runtime/arcane/components/local-ai-status.html +5 -2
- package/runtime/arcane/components/markdown-document.html +14 -11
- package/runtime/arcane/components/markdown-editor.html +4 -1
- package/runtime/arcane/components/modal.html +4 -1
- package/runtime/arcane/components/output-panel.html +6 -3
- package/runtime/arcane/components/preferences-form.html +4 -1
- package/runtime/arcane/components/record-timeline.html +8 -5
- package/runtime/arcane/components/relationship-board.html +9 -6
- package/runtime/arcane/components/source-code-viewer.html +12 -9
- package/runtime/arcane/components/source-explanation.html +8 -5
- package/runtime/arcane/components/speech.html +24 -21
- package/runtime/arcane/components/summary-strip.html +4 -1
- package/runtime/arcane/components/task-progress.html +6 -3
- package/runtime/arcane/components/terminal-workspace.html +4 -1
- package/runtime/arcane/components/voice-transcription.html +11 -8
- package/runtime/arcane/components/web-navigator.html +5 -2
- package/runtime/arcane/entities/ApiModelRecord.js +5 -2
- package/runtime/arcane/entities/Calculation.js +5 -2
- package/runtime/arcane/entities/Chat.js +33 -33
- package/runtime/arcane/entities/CommunicationMessage.js +4 -1
- package/runtime/arcane/entities/CommunicationThread.js +4 -1
- package/runtime/arcane/entities/File.js +1 -1
- package/runtime/arcane/entities/Image.js +8 -5
- package/runtime/arcane/entities/IntentEnvelope.js +20 -17
- package/runtime/arcane/entities/Preference.js +9 -6
- package/runtime/arcane/entities/Theme.js +5 -2
- package/runtime/arcane/entities/User.js +11 -11
- package/runtime/arcane/entities/Weather.js +5 -2
- package/runtime/arcane/modules/AI.js +503 -187
- package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
- package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
- package/runtime/arcane/modules/AIProviderRuntime.js +117 -92
- package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
- package/runtime/arcane/modules/AIRuntimeState.js +29 -26
- package/runtime/arcane/modules/AnsiText.js +4 -1
- package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
- package/runtime/arcane/modules/AppDataScope.js +8 -5
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
- package/runtime/arcane/modules/AsyncBoundary.js +13 -10
- package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
- package/runtime/arcane/modules/CalculatorEngine.js +5 -2
- package/runtime/arcane/modules/ChatRecords.js +18 -15
- package/runtime/arcane/modules/CommunicationAppController.js +9 -6
- package/runtime/arcane/modules/CommunicationHub.js +9 -6
- package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
- package/runtime/arcane/modules/ComponentContracts.js +56 -53
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
- package/runtime/arcane/modules/ConversationActionItems.js +15 -12
- package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
- package/runtime/arcane/modules/ConversationTimebox.js +28 -25
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
- package/runtime/arcane/modules/DBLS.js +7 -4
- package/runtime/arcane/modules/DBOPFS.js +7 -7
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
- package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
- package/runtime/arcane/modules/DirectoryPicker.js +8 -5
- package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
- package/runtime/arcane/modules/DocumentNavigation.js +7 -4
- package/runtime/arcane/modules/Errors.js +28 -25
- package/runtime/arcane/modules/HTMLImport.js +7 -4
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
- package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
- package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
- package/runtime/arcane/modules/MD.js +1 -1
- package/runtime/arcane/modules/Mail.js +46 -43
- package/runtime/arcane/modules/MailOutbox.mjs +48 -45
- package/runtime/arcane/modules/MailTransport.mjs +29 -26
- package/runtime/arcane/modules/MarkdownSpeech.js +1 -50
- package/runtime/arcane/modules/MemoryRecords.js +7 -4
- package/runtime/arcane/modules/MessageAdvisory.js +6 -3
- package/runtime/arcane/modules/ModelDefinition.js +7 -4
- package/runtime/arcane/modules/Ollama.js +6 -3
- package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
- package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
- package/runtime/arcane/modules/PreferenceStore.js +20 -17
- package/runtime/arcane/modules/PreparedSpeech.js +485 -0
- package/runtime/arcane/modules/Questionnaire.js +6 -3
- package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
- package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
- package/runtime/arcane/modules/RecordReviewStore.js +12 -9
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
- package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
- package/runtime/arcane/modules/ScreenCapture.js +20 -17
- package/runtime/arcane/modules/SpeechPlayback.js +61 -28
- package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
- package/runtime/arcane/modules/SystemAppearance.js +5 -2
- package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
- package/runtime/arcane/modules/TerminalClient.js +14 -11
- package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
- package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
- package/runtime/arcane/modules/ThemeManager.js +5 -2
- package/runtime/arcane/modules/TimeGuard.js +1 -1
- package/runtime/arcane/modules/ToolCallRouter.js +11 -8
- package/runtime/arcane/modules/WaitForComponent.js +19 -16
- package/runtime/arcane/modules/YouTubeMedia.js +4 -1
- package/runtime/strong-type/index.js +1276 -352
- package/runtime/strong-type/package.json +69 -45
- package/src/app-descriptor.mjs +17 -14
- package/src/application-tests.mjs +4 -1
- package/src/cli/main.mjs +8 -5
- package/src/constants.mjs +4 -1
- package/src/dev-server.mjs +8 -5
- package/src/doctor.mjs +5 -2
- package/src/dom-event-instrumentation.mjs +24 -20
- package/src/errors.mjs +7 -3
- package/src/event-manager.mjs +111 -108
- package/src/event-queue.mjs +8 -5
- package/src/events.mjs +12 -9
- package/src/import-map.mjs +36 -27
- package/src/installed-sdk-runtime.mjs +4 -1
- package/src/integrated-provider-loader.mjs +9 -6
- package/src/mail-credentials.mjs +16 -13
- package/src/mail-server.mjs +53 -50
- package/src/mail.mjs +18 -15
- package/src/native-plan.mjs +12 -9
- package/src/native-provider-loader.mjs +7 -4
- package/src/packager/core.mjs +18 -15
- package/src/process.mjs +6 -3
- package/src/release-bundle.mjs +14 -11
- package/src/runtime.mjs +4 -1
- package/src/scaffold.mjs +9 -6
- package/src/sdk-browser-runtime.mjs +4 -1
- package/src/source-server.mjs +17 -14
- package/src/targets/index.mjs +5 -2
- package/src/templates/workspace-template.mjs +13 -6
- package/src/testing-loader.mjs +7 -4
- package/src/testing.mjs +10 -7
- package/src/toolchain.mjs +13 -10
- package/src/update-check.mjs +9 -6
- package/src/workspace-operation-lock.mjs +14 -11
- package/src/workspace-runtime.mjs +4 -1
- package/src/workspace.mjs +17 -14
- package/runtime/arcane/modules/AIResponseLength.js +0 -32
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
const ACTION_ITEM_STATUSES=['open','completed'];
|
|
2
5
|
const ACTION_ITEM_BASES=['user_commitment','optional_homework'];
|
|
3
6
|
const DEFAULT_PRESENTATION_COOLDOWN_MS=7*24*60*60*1000;
|
|
@@ -12,7 +15,7 @@ function invalid(message){
|
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
function isPlainRecord(value){
|
|
15
|
-
if(!value
|
|
18
|
+
if(!value||!is.object(value)||is.array(value)){
|
|
16
19
|
return false;
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -21,7 +24,7 @@ function isPlainRecord(value){
|
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
function normalizedText(value,label='Action item'){
|
|
24
|
-
if(
|
|
27
|
+
if(!is.string(value)){
|
|
25
28
|
throw invalid(`${label} must be a string.`);
|
|
26
29
|
}
|
|
27
30
|
if(UNSAFE_TEXT_CONTROL_PATTERN.test(value)){
|
|
@@ -35,7 +38,7 @@ function normalizedText(value,label='Action item'){
|
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
function normalizedId(value,label='Action item id'){
|
|
38
|
-
if(
|
|
41
|
+
if(!is.string(value)||!ACTION_ITEM_ID_PATTERN.test(value)){
|
|
39
42
|
throw invalid(`${label} is invalid.`);
|
|
40
43
|
}
|
|
41
44
|
|
|
@@ -47,7 +50,7 @@ function normalizedOptionalId(value,label){
|
|
|
47
50
|
return null;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
if(
|
|
53
|
+
if(!is.string(value)||!CONVERSATION_ID_PATTERN.test(value)){
|
|
51
54
|
throw invalid(`${label} is invalid.`);
|
|
52
55
|
}
|
|
53
56
|
|
|
@@ -58,7 +61,7 @@ function normalizedTimestamp(value,label,{nullable=false}={}){
|
|
|
58
61
|
if(nullable&&(value===undefined||value===null)){
|
|
59
62
|
return null;
|
|
60
63
|
}
|
|
61
|
-
if(!
|
|
64
|
+
if(!is.safeInteger(value)||value<0){
|
|
62
65
|
throw invalid(`${label} must be a non-negative integer timestamp.`);
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -70,7 +73,7 @@ function normalizedNow(value){
|
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
function normalizedRevision(value){
|
|
73
|
-
if(!
|
|
76
|
+
if(!is.safeInteger(value)||value<1){
|
|
74
77
|
throw invalid('revision must be a positive integer.');
|
|
75
78
|
}
|
|
76
79
|
|
|
@@ -98,7 +101,7 @@ function nextRevision(item){
|
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
function defaultActionItemId(){
|
|
101
|
-
if(
|
|
104
|
+
if(is.function(globalThis.crypto?.randomUUID)){
|
|
102
105
|
return globalThis.crypto.randomUUID();
|
|
103
106
|
}
|
|
104
107
|
|
|
@@ -110,7 +113,7 @@ function completeItems(items){
|
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
export function normalizeRememberedConversationActions(value=[]){
|
|
113
|
-
if(!
|
|
116
|
+
if(!is.array(value))throw invalid('Remembered actions must be an array.');
|
|
114
117
|
|
|
115
118
|
return completeItems(value.map(function normalizeRememberedAction(action){
|
|
116
119
|
if(!isPlainRecord(action)){
|
|
@@ -186,7 +189,7 @@ export function normalizeConversationActionItem(value){
|
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
export function normalizeConversationActionItems(value=[]){
|
|
189
|
-
if(!
|
|
192
|
+
if(!is.array(value))throw invalid('Action items must be an array.');
|
|
190
193
|
|
|
191
194
|
const ids=new Set();
|
|
192
195
|
const items=value.map(function normalizeActionItemRecord(item){
|
|
@@ -231,7 +234,7 @@ export function rememberConversationActionItems(current=[],actions=[],{
|
|
|
231
234
|
}={}){
|
|
232
235
|
const items=[...normalizeConversationActionItems(current)];
|
|
233
236
|
const remembered=normalizeRememberedConversationActions(actions);
|
|
234
|
-
if(
|
|
237
|
+
if(!is.function(idFactory)){
|
|
235
238
|
throw invalid('idFactory must be a function.');
|
|
236
239
|
}
|
|
237
240
|
|
|
@@ -353,7 +356,7 @@ export function selectConversationActionItemsForPresentation(current=[],{
|
|
|
353
356
|
throw invalid('conversationId is required.');
|
|
354
357
|
}
|
|
355
358
|
const timestamp=normalizedNow(now);
|
|
356
|
-
if(!
|
|
359
|
+
if(!is.safeInteger(cooldownMs)||cooldownMs<0){
|
|
357
360
|
throw invalid('cooldownMs must be a non-negative integer.');
|
|
358
361
|
}
|
|
359
362
|
const selected=outstandingConversationActionItems(current)
|
|
@@ -390,7 +393,7 @@ export function markConversationActionItemsPresented(current=[],ids=[],{
|
|
|
390
393
|
throw invalid('conversationId is required.');
|
|
391
394
|
}
|
|
392
395
|
const timestamp=normalizedNow(now);
|
|
393
|
-
if(!
|
|
396
|
+
if(!is.array(ids))throw invalid('Presented ids must be an array.');
|
|
394
397
|
const requested=new Set(ids.map(id=>normalizedId(id)));
|
|
395
398
|
|
|
396
399
|
let matched=0;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
import {
|
|
2
5
|
CONVERSATION_ACTION_ITEM_BASES,
|
|
3
6
|
normalizeRememberedConversationActions
|
|
@@ -18,7 +21,7 @@ function invalid(message){
|
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
function isPlainRecord(value){
|
|
21
|
-
if(!value
|
|
24
|
+
if(!value||!is.object(value)||is.array(value)){
|
|
22
25
|
return false;
|
|
23
26
|
}
|
|
24
27
|
|
|
@@ -33,7 +36,7 @@ function normalizedText(value,label,{required=false}={}){
|
|
|
33
36
|
}
|
|
34
37
|
return '';
|
|
35
38
|
}
|
|
36
|
-
if(
|
|
39
|
+
if(!is.string(value)){
|
|
37
40
|
throw invalid(`${label} must be a string.`);
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -44,7 +47,7 @@ function normalizedText(value,label,{required=false}={}){
|
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
function normalizedFinalMessage(value){
|
|
47
|
-
if(
|
|
50
|
+
if(!is.string(value)){
|
|
48
51
|
throw invalid('final_message must be a string.');
|
|
49
52
|
}
|
|
50
53
|
|
|
@@ -55,7 +58,7 @@ function normalizedFinalMessage(value){
|
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
function parseArguments(value){
|
|
58
|
-
if(
|
|
61
|
+
if(is.string(value)){
|
|
59
62
|
if(!value)throw invalid('The closing-report arguments are required.');
|
|
60
63
|
|
|
61
64
|
try{
|
|
@@ -91,10 +94,10 @@ export function createConversationClosingReportTool({
|
|
|
91
94
|
name=DEFAULT_TOOL_NAME,
|
|
92
95
|
description='Prepare a complete closing report when the user clearly ends a conversation.'
|
|
93
96
|
}={}){
|
|
94
|
-
if(
|
|
97
|
+
if(!is.string(name)||!TOOL_NAME_PATTERN.test(name)){
|
|
95
98
|
throw invalid('The closing-report tool name is invalid.');
|
|
96
99
|
}
|
|
97
|
-
if(
|
|
100
|
+
if(!is.string(description)||!description.trim()){
|
|
98
101
|
throw invalid('The closing-report tool description is invalid.');
|
|
99
102
|
}
|
|
100
103
|
|
|
@@ -157,7 +160,7 @@ export function conversationClosingReportInstruction({
|
|
|
157
160
|
if(enabled!==true){
|
|
158
161
|
return '';
|
|
159
162
|
}
|
|
160
|
-
if(
|
|
163
|
+
if(!is.string(toolName)||!TOOL_NAME_PATTERN.test(toolName)){
|
|
161
164
|
throw invalid('The closing-report tool name is invalid.');
|
|
162
165
|
}
|
|
163
166
|
|
|
@@ -195,7 +198,7 @@ export function normalizeConversationClosingReport(value){
|
|
|
195
198
|
export function classifyConversationClosingReportCalls(calls={}, {
|
|
196
199
|
toolName=DEFAULT_TOOL_NAME
|
|
197
200
|
}={}){
|
|
198
|
-
if(
|
|
201
|
+
if(!is.string(toolName)||!TOOL_NAME_PATTERN.test(toolName)){
|
|
199
202
|
throw invalid('The closing-report tool name is invalid.');
|
|
200
203
|
}
|
|
201
204
|
if(!isPlainRecord(calls)){
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
import { arcaneLogging } from 'arcane-os/logging';
|
|
2
5
|
import {createArcaneEventSource} from 'arcane-os/event-manager';
|
|
3
6
|
|
|
@@ -64,7 +67,7 @@ const conversationTimeboxTool={
|
|
|
64
67
|
};
|
|
65
68
|
|
|
66
69
|
function isPlainRecord(value){
|
|
67
|
-
if(!value
|
|
70
|
+
if(!value||!is.object(value)||is.array(value))return false;
|
|
68
71
|
const prototype=Object.getPrototypeOf(value);
|
|
69
72
|
return prototype===Object.prototype||prototype===null;
|
|
70
73
|
}
|
|
@@ -73,7 +76,7 @@ function parseToolArguments(value){
|
|
|
73
76
|
if(isPlainRecord(value)){
|
|
74
77
|
return value;
|
|
75
78
|
}
|
|
76
|
-
if(
|
|
79
|
+
if(!is.string(value)){
|
|
77
80
|
throw new TypeError('The conversation timebox tool requires JSON object arguments.');
|
|
78
81
|
}
|
|
79
82
|
try{
|
|
@@ -95,13 +98,13 @@ function normalizeConversationTimeboxCommand(value){
|
|
|
95
98
|
if(!['set','adjust','clear'].includes(input.action)){
|
|
96
99
|
throw new TypeError('Conversation timebox action must be "set", "adjust", or "clear".');
|
|
97
100
|
}
|
|
98
|
-
if(
|
|
101
|
+
if(!is.string(input.message)||!input.message.trim()){
|
|
99
102
|
throw new TypeError('Conversation timebox message must contain user-facing text.');
|
|
100
103
|
}
|
|
101
104
|
if(input.action==='clear'){
|
|
102
105
|
return {...input,action:'clear',message:input.message};
|
|
103
106
|
}
|
|
104
|
-
if(!
|
|
107
|
+
if(!is.safeInteger(input.duration_milliseconds)||input.duration_milliseconds<=0){
|
|
105
108
|
throw new TypeError('duration_milliseconds must be an explicit positive whole number.');
|
|
106
109
|
}
|
|
107
110
|
return {
|
|
@@ -113,7 +116,7 @@ function normalizeConversationTimeboxCommand(value){
|
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
function appendConversationTimeboxOpeningInstruction(message=''){
|
|
116
|
-
if(
|
|
119
|
+
if(!is.string(message)){
|
|
117
120
|
throw new TypeError('The opening message must be a string.');
|
|
118
121
|
}
|
|
119
122
|
const base=message.trim();
|
|
@@ -123,7 +126,7 @@ function appendConversationTimeboxOpeningInstruction(message=''){
|
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
function formatConversationElapsed(milliseconds=0){
|
|
126
|
-
if(!
|
|
129
|
+
if(!is.finite(milliseconds)||milliseconds<0){
|
|
127
130
|
throw new TypeError('Elapsed time must be a non-negative finite number.');
|
|
128
131
|
}
|
|
129
132
|
const totalSeconds=Math.floor(milliseconds/1000);
|
|
@@ -141,7 +144,7 @@ function createConversationTimeboxControlMessage(action,milliseconds){
|
|
|
141
144
|
}
|
|
142
145
|
if(
|
|
143
146
|
!['set','adjust'].includes(action)
|
|
144
|
-
||!
|
|
147
|
+
||!is.safeInteger(milliseconds)
|
|
145
148
|
||milliseconds<=0
|
|
146
149
|
){
|
|
147
150
|
throw new TypeError('A timebox control message requires an explicit positive whole-millisecond duration.');
|
|
@@ -160,7 +163,7 @@ function conversationTimeboxSubmissionKey(context={}){
|
|
|
160
163
|
const revision=context.timeboxRevision;
|
|
161
164
|
if(
|
|
162
165
|
!source.startsWith('conversation-timebox')
|
|
163
|
-
||!
|
|
166
|
+
||!is.safeInteger(revision)
|
|
164
167
|
||revision<1
|
|
165
168
|
){
|
|
166
169
|
return '';
|
|
@@ -181,10 +184,10 @@ function conversationTimeboxError(message,code,reason,ErrorType=Error){
|
|
|
181
184
|
|
|
182
185
|
function isAbortSignal(value){
|
|
183
186
|
return Boolean(value)
|
|
184
|
-
&&
|
|
185
|
-
&&
|
|
186
|
-
&&
|
|
187
|
-
&&
|
|
187
|
+
&&is.object(value)
|
|
188
|
+
&&is.boolean(value.aborted)
|
|
189
|
+
&&is.function(value.addEventListener)
|
|
190
|
+
&&is.function(value.removeEventListener);
|
|
188
191
|
}
|
|
189
192
|
|
|
190
193
|
function normalizeSubscriptionOptions(value={}){
|
|
@@ -197,7 +200,7 @@ function normalizeSubscriptionOptions(value={}){
|
|
|
197
200
|
);
|
|
198
201
|
}
|
|
199
202
|
if((value.once!==undefined
|
|
200
|
-
|
|
203
|
+
&&!is.boolean(value.once)
|
|
201
204
|
)||(
|
|
202
205
|
value.signal!==undefined
|
|
203
206
|
&&value.signal!==null
|
|
@@ -289,11 +292,11 @@ class ConversationTimebox{
|
|
|
289
292
|
['cancel',this.#cancel],
|
|
290
293
|
['onListenerError',onListenerError]
|
|
291
294
|
]){
|
|
292
|
-
if(
|
|
295
|
+
if(!is.function(value)){
|
|
293
296
|
throw new TypeError(`${name} must be a function.`);
|
|
294
297
|
}
|
|
295
298
|
}
|
|
296
|
-
if(!
|
|
299
|
+
if(!is.finite(this.#tickMs)||this.#tickMs<=0){
|
|
297
300
|
throw new RangeError('tickMs must be a positive finite number.');
|
|
298
301
|
}
|
|
299
302
|
this.#events=createArcaneEventSource(this,{
|
|
@@ -323,16 +326,16 @@ class ConversationTimebox{
|
|
|
323
326
|
|
|
324
327
|
setLimitMilliseconds(milliseconds,{source='user'}={}){
|
|
325
328
|
this.#assertActive();
|
|
326
|
-
if(!
|
|
329
|
+
if(!is.safeInteger(milliseconds)||milliseconds<=0){
|
|
327
330
|
throw new TypeError('Conversation time must be an explicit positive whole number of milliseconds.');
|
|
328
331
|
}
|
|
329
|
-
if(
|
|
332
|
+
if(!is.string(source)||!source.trim()){
|
|
330
333
|
throw new TypeError('Conversation timebox source must contain text.');
|
|
331
334
|
}
|
|
332
335
|
const commandSource=source.trim();
|
|
333
336
|
const now=this.#readClock();
|
|
334
337
|
const dueAtMs=now+milliseconds;
|
|
335
|
-
if(!
|
|
338
|
+
if(!is.safeInteger(dueAtMs)||dueAtMs>MAX_DATE_MILLISECONDS){
|
|
336
339
|
throw new RangeError('The requested conversation duration exceeds the supported date range.');
|
|
337
340
|
}
|
|
338
341
|
if(this.#startedAtMs===null){
|
|
@@ -351,10 +354,10 @@ class ConversationTimebox{
|
|
|
351
354
|
|
|
352
355
|
adjustLimitMilliseconds(milliseconds,{source='user'}={}){
|
|
353
356
|
this.#assertActive();
|
|
354
|
-
if(!
|
|
357
|
+
if(!is.safeInteger(milliseconds)||milliseconds<=0){
|
|
355
358
|
throw new TypeError('Conversation adjustment must be an explicit positive whole number of milliseconds.');
|
|
356
359
|
}
|
|
357
|
-
if(
|
|
360
|
+
if(!is.string(source)||!source.trim()){
|
|
358
361
|
throw new TypeError('Conversation timebox source must contain text.');
|
|
359
362
|
}
|
|
360
363
|
const commandSource=source.trim();
|
|
@@ -364,7 +367,7 @@ class ConversationTimebox{
|
|
|
364
367
|
|
|
365
368
|
const now=this.#readClock();
|
|
366
369
|
const dueAtMs=Math.max(now,this.#dueAtMs)+milliseconds;
|
|
367
|
-
if(!
|
|
370
|
+
if(!is.safeInteger(dueAtMs)||dueAtMs>MAX_DATE_MILLISECONDS){
|
|
368
371
|
throw new RangeError('The requested conversation adjustment exceeds the supported date range.');
|
|
369
372
|
}
|
|
370
373
|
|
|
@@ -380,7 +383,7 @@ class ConversationTimebox{
|
|
|
380
383
|
|
|
381
384
|
clearLimit({source='user'}={}){
|
|
382
385
|
this.#assertActive();
|
|
383
|
-
if(
|
|
386
|
+
if(!is.string(source)||!source.trim()){
|
|
384
387
|
throw new TypeError('Conversation timebox source must contain text.');
|
|
385
388
|
}
|
|
386
389
|
const commandSource=source.trim();
|
|
@@ -417,7 +420,7 @@ class ConversationTimebox{
|
|
|
417
420
|
}
|
|
418
421
|
|
|
419
422
|
subscribe(listener,options={}){
|
|
420
|
-
if(
|
|
423
|
+
if(!is.function(listener)){
|
|
421
424
|
throw conversationTimeboxError(
|
|
422
425
|
'Conversation timebox listener must be a function.',
|
|
423
426
|
conversationTimeboxErrorCodes.subscriptionHandlerInvalid,
|
|
@@ -511,7 +514,7 @@ class ConversationTimebox{
|
|
|
511
514
|
|
|
512
515
|
#readClock(){
|
|
513
516
|
const now=this.#clock();
|
|
514
|
-
if(!
|
|
517
|
+
if(!is.safeInteger(now)||now<0||now>MAX_DATE_MILLISECONDS){
|
|
515
518
|
throw new TypeError('Conversation timebox clock must return a supported non-negative integer timestamp.');
|
|
516
519
|
}
|
|
517
520
|
return this.#nowMs===null?now:Math.max(now,this.#nowMs);
|
|
@@ -581,7 +584,7 @@ function consumeConversationTimeboxCall(calls,controller){
|
|
|
581
584
|
if(!isPlainRecord(calls)){
|
|
582
585
|
throw new TypeError('Streamed conversation tool calls must be a plain object.');
|
|
583
586
|
}
|
|
584
|
-
if(!controller
|
|
587
|
+
if(!controller||!is.function(controller.applyCommand)){
|
|
585
588
|
throw new TypeError('A conversation timebox controller is required.');
|
|
586
589
|
}
|
|
587
590
|
const remainingCalls={...calls};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
import {normalizeOllamaModelIdentifier} from './OllamaModelIdentifier.js';
|
|
2
5
|
|
|
3
6
|
const MAX_CORE_LOCAL_SPEECH_MODELS=8;
|
|
@@ -48,7 +51,7 @@ function modelDescriptor(model){
|
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
function boundedParallelRequests(value,{allowZero=false}={}){
|
|
51
|
-
return
|
|
54
|
+
return is.safeInteger(value)
|
|
52
55
|
&&(allowZero?value>=0:value>=1)
|
|
53
56
|
?value
|
|
54
57
|
:null;
|
|
@@ -57,7 +60,7 @@ function boundedParallelRequests(value,{allowZero=false}={}){
|
|
|
57
60
|
function admissionCode(compatibility){
|
|
58
61
|
const code=compatibility?.code;
|
|
59
62
|
|
|
60
|
-
return
|
|
63
|
+
return is.string(code)&&/^[A-Z][A-Z0-9_]{0,95}$/.test(code)
|
|
61
64
|
?code
|
|
62
65
|
:null;
|
|
63
66
|
}
|
|
@@ -91,8 +94,8 @@ function admissionAwareModelDescriptor(model,{rejected=false,activeFallback=null
|
|
|
91
94
|
throw new TypeError('Arcane Core returned an invalid local-model identifier.');
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
const compatibility=model?.compatibility&&
|
|
95
|
-
&&!
|
|
97
|
+
const compatibility=model?.compatibility&&is.object(model.compatibility)
|
|
98
|
+
&&!is.array(model.compatibility)
|
|
96
99
|
?model.compatibility
|
|
97
100
|
:null;
|
|
98
101
|
const activeParallelRequests=boundedParallelRequests(
|
|
@@ -103,7 +106,7 @@ function admissionAwareModelDescriptor(model,{rejected=false,activeFallback=null
|
|
|
103
106
|
{allowZero:true}
|
|
104
107
|
);
|
|
105
108
|
const activeParallelRequestsAllowed=
|
|
106
|
-
|
|
109
|
+
is.boolean(compatibility?.activeParallelRequestsAllowed)
|
|
107
110
|
?compatibility.activeParallelRequestsAllowed
|
|
108
111
|
:null;
|
|
109
112
|
const repairRequired=compatibility?.creationRequired===true
|
|
@@ -160,7 +163,7 @@ function admissionAwareModelDescriptor(model,{rejected=false,activeFallback=null
|
|
|
160
163
|
export function getCoreLocalModelCatalog(status){
|
|
161
164
|
const models=status?.models?.ollama;
|
|
162
165
|
|
|
163
|
-
if(!
|
|
166
|
+
if(!is.array(models)){
|
|
164
167
|
return Object.freeze([]);
|
|
165
168
|
}
|
|
166
169
|
return Object.freeze(models.map(modelDescriptor));
|
|
@@ -172,10 +175,10 @@ export function getCoreLocalModelCatalog(status){
|
|
|
172
175
|
* diagnostic messages in the application UI.
|
|
173
176
|
*/
|
|
174
177
|
export function getCoreLocalModelCatalogWithAdmissionFailures(status){
|
|
175
|
-
const admitted=
|
|
178
|
+
const admitted=is.array(status?.models?.ollama)
|
|
176
179
|
?status.models.ollama
|
|
177
180
|
:[];
|
|
178
|
-
const rejected=
|
|
181
|
+
const rejected=is.array(status?.admission?.rejected)
|
|
179
182
|
?status.admission.rejected
|
|
180
183
|
:[];
|
|
181
184
|
|
|
@@ -207,7 +210,7 @@ export function getCoreLocalModelCatalogWithAdmissionFailures(status){
|
|
|
207
210
|
}
|
|
208
211
|
|
|
209
212
|
function hasAvailableSpeechRole(models,role){
|
|
210
|
-
if(!
|
|
213
|
+
if(!is.array(models)){
|
|
211
214
|
return false;
|
|
212
215
|
}
|
|
213
216
|
if(models.length>MAX_CORE_LOCAL_SPEECH_MODELS){
|
|
@@ -218,16 +221,16 @@ function hasAvailableSpeechRole(models,role){
|
|
|
218
221
|
for(const model of models){
|
|
219
222
|
if(
|
|
220
223
|
!model
|
|
221
|
-
|
|
222
|
-
||
|
|
223
|
-
|
|
224
|
+
||!is.object(model)
|
|
225
|
+
||is.array(model)
|
|
226
|
+
||!is.string(model.id)
|
|
224
227
|
||!model.id
|
|
225
228
|
||model.id.length>128
|
|
226
|
-
|
|
229
|
+
||!is.string(model.name)
|
|
227
230
|
||!model.name
|
|
228
231
|
||model.name.length>128
|
|
229
232
|
||model.provider!=='speech'
|
|
230
|
-
||!
|
|
233
|
+
||!is.array(model.roles)
|
|
231
234
|
||model.roles.length<1
|
|
232
235
|
||model.roles.length>2
|
|
233
236
|
||!model.roles.every(candidate=>candidate==='stt'||candidate==='tts')
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
import {
|
|
2
5
|
APP_LOCAL_STORAGE_PREFIX,
|
|
3
6
|
resolveBrowserApplicationId
|
|
@@ -30,8 +33,8 @@ class DBLS {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
if(!storage
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
||!is.function(storage.getItem)
|
|
37
|
+
||!is.function(storage.setItem)){
|
|
35
38
|
const error=new Error('Local storage is unavailable in this browser.');
|
|
36
39
|
error.code='APP_DATA_STORAGE_UNAVAILABLE';
|
|
37
40
|
throw error;
|
|
@@ -68,7 +71,7 @@ class DBLS {
|
|
|
68
71
|
|
|
69
72
|
// Set an item
|
|
70
73
|
set(key='', value) {
|
|
71
|
-
if(
|
|
74
|
+
if(!is.string(value) && !is.number(value)){
|
|
72
75
|
value=JSON.stringify(value);
|
|
73
76
|
}
|
|
74
77
|
this.storage.setItem(this.storageKey(key), value);
|
|
@@ -196,7 +199,7 @@ class DBLS {
|
|
|
196
199
|
}
|
|
197
200
|
}
|
|
198
201
|
|
|
199
|
-
if(
|
|
202
|
+
if(!is.function(window.dbls?.get)){
|
|
200
203
|
window.dbls=new DBLS();
|
|
201
204
|
window.dbls.ready=true;
|
|
202
205
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { arcaneLogging } from 'arcane-os/logging';
|
|
2
|
-
import Is from
|
|
2
|
+
import Is from 'strong-type';
|
|
3
3
|
import {openApplicationDataDirectory} from './AppDataScope.js';
|
|
4
4
|
import {
|
|
5
5
|
createArcaneEventSource,
|
|
@@ -208,7 +208,7 @@ class DBOPFS {
|
|
|
208
208
|
*/
|
|
209
209
|
async #requestFileWorker(data={},transfer=[]){
|
|
210
210
|
|
|
211
|
-
if(
|
|
211
|
+
if(!is.function(this.#writeWorker?.postMessage)){
|
|
212
212
|
this.#writeWorker=new Worker(
|
|
213
213
|
new URL('./DBOPFSWorker.js',import.meta.url)
|
|
214
214
|
);
|
|
@@ -438,7 +438,7 @@ class DBOPFS {
|
|
|
438
438
|
|
|
439
439
|
let dataToWrite=value
|
|
440
440
|
|
|
441
|
-
if(
|
|
441
|
+
if(!is.string(value)){
|
|
442
442
|
dataToWrite=JSON.stringify(dataToWrite)
|
|
443
443
|
}
|
|
444
444
|
|
|
@@ -499,7 +499,7 @@ class DBOPFS {
|
|
|
499
499
|
{create:true}
|
|
500
500
|
);
|
|
501
501
|
|
|
502
|
-
if(
|
|
502
|
+
if(!is.function(handle.createWritable)){
|
|
503
503
|
return this.#writeFileWithWorker(
|
|
504
504
|
table.name,
|
|
505
505
|
fileName,
|
|
@@ -542,7 +542,7 @@ class DBOPFS {
|
|
|
542
542
|
const table=await this.getTableHandle(tableName)
|
|
543
543
|
const handle=await table.getFileHandle(fileName,{create:false})
|
|
544
544
|
|
|
545
|
-
if(
|
|
545
|
+
if(is.function(handle.getFile)){
|
|
546
546
|
return handle.getFile()
|
|
547
547
|
}
|
|
548
548
|
|
|
@@ -564,7 +564,7 @@ class DBOPFS {
|
|
|
564
564
|
const table=await this.getTableHandle(tableName)
|
|
565
565
|
const handle=await table.getFileHandle(fileName,{create:false})
|
|
566
566
|
|
|
567
|
-
if(
|
|
567
|
+
if(!is.function(handle.getFile)){
|
|
568
568
|
return {
|
|
569
569
|
lastModified:null,
|
|
570
570
|
size:null,
|
|
@@ -1177,7 +1177,7 @@ class DBOPFS {
|
|
|
1177
1177
|
}
|
|
1178
1178
|
}
|
|
1179
1179
|
|
|
1180
|
-
if(
|
|
1180
|
+
if(!is.function(window.dbopfs?.get)){
|
|
1181
1181
|
window.dbopfs=new DBOPFS();
|
|
1182
1182
|
}
|
|
1183
1183
|
|