@happyvertical/smrt-svelte 0.30.0
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/AGENTS.md +317 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +185 -0
- package/dist/Provider.svelte +204 -0
- package/dist/Provider.svelte.d.ts +73 -0
- package/dist/Provider.svelte.d.ts.map +1 -0
- package/dist/__tests__/app-state.test.js +156 -0
- package/dist/__tests__/warm-clients.test.js +186 -0
- package/dist/browser-ai/adapters/llm/factory.d.ts +38 -0
- package/dist/browser-ai/adapters/llm/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/factory.js +91 -0
- package/dist/browser-ai/adapters/llm/index.d.ts +7 -0
- package/dist/browser-ai/adapters/llm/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/index.js +6 -0
- package/dist/browser-ai/adapters/llm/types.d.ts +182 -0
- package/dist/browser-ai/adapters/llm/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/types.js +43 -0
- package/dist/browser-ai/adapters/llm/webllm.d.ts +33 -0
- package/dist/browser-ai/adapters/llm/webllm.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/webllm.js +225 -0
- package/dist/browser-ai/adapters/stt/browser-speech.d.ts +31 -0
- package/dist/browser-ai/adapters/stt/browser-speech.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/browser-speech.js +217 -0
- package/dist/browser-ai/adapters/stt/factory.d.ts +49 -0
- package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/factory.js +110 -0
- package/dist/browser-ai/adapters/stt/index.d.ts +9 -0
- package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/index.js +8 -0
- package/dist/browser-ai/adapters/stt/types.d.ts +154 -0
- package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/types.js +4 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.d.ts +46 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.js +348 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +51 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.js +380 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +42 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.js +235 -0
- package/dist/browser-ai/adapters/tts/factory.d.ts +53 -0
- package/dist/browser-ai/adapters/tts/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/factory.js +92 -0
- package/dist/browser-ai/adapters/tts/index.d.ts +7 -0
- package/dist/browser-ai/adapters/tts/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/index.js +6 -0
- package/dist/browser-ai/adapters/tts/types.d.ts +140 -0
- package/dist/browser-ai/adapters/tts/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/types.js +4 -0
- package/dist/browser-ai/capabilities/detector.d.ts +38 -0
- package/dist/browser-ai/capabilities/detector.d.ts.map +1 -0
- package/dist/browser-ai/capabilities/detector.js +211 -0
- package/dist/browser-ai/core/errors.d.ts +62 -0
- package/dist/browser-ai/core/errors.d.ts.map +1 -0
- package/dist/browser-ai/core/errors.js +92 -0
- package/dist/browser-ai/core/index.d.ts +6 -0
- package/dist/browser-ai/core/index.d.ts.map +1 -0
- package/dist/browser-ai/core/index.js +5 -0
- package/dist/browser-ai/core/types.d.ts +115 -0
- package/dist/browser-ai/core/types.d.ts.map +1 -0
- package/dist/browser-ai/core/types.js +34 -0
- package/dist/browser-ai/index.d.ts +12 -0
- package/dist/browser-ai/index.d.ts.map +1 -0
- package/dist/browser-ai/index.js +16 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte +77 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte.d.ts +16 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte +57 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte.d.ts +15 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte +141 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte.d.ts +15 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte +379 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte.d.ts +9 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte +200 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte.d.ts +16 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/index.d.ts +15 -0
- package/dist/browser-ai/svelte/index.d.ts.map +1 -0
- package/dist/browser-ai/svelte/index.js +28 -0
- package/dist/browser-ai/ui.d.ts +16 -0
- package/dist/browser-ai/ui.d.ts.map +1 -0
- package/dist/browser-ai/ui.js +67 -0
- package/dist/components/admin/AgentAdminPanel.svelte +111 -0
- package/dist/components/admin/AgentAdminPanel.svelte.d.ts +25 -0
- package/dist/components/admin/AgentAdminPanel.svelte.d.ts.map +1 -0
- package/dist/components/admin/AgentAdminTabs.svelte +280 -0
- package/dist/components/admin/AgentAdminTabs.svelte.d.ts +23 -0
- package/dist/components/admin/AgentAdminTabs.svelte.d.ts.map +1 -0
- package/dist/components/admin/AgentSettingsShell.svelte +257 -0
- package/dist/components/admin/AgentSettingsShell.svelte.d.ts +33 -0
- package/dist/components/admin/AgentSettingsShell.svelte.d.ts.map +1 -0
- package/dist/components/admin/index.d.ts +5 -0
- package/dist/components/admin/index.d.ts.map +1 -0
- package/dist/components/admin/index.js +6 -0
- package/dist/components/forms/AddressInput.svelte +500 -0
- package/dist/components/forms/AddressInput.svelte.d.ts +36 -0
- package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/CheckboxInput.svelte +208 -0
- package/dist/components/forms/CheckboxInput.svelte.d.ts +20 -0
- package/dist/components/forms/CheckboxInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/DateRangeInput.svelte +628 -0
- package/dist/components/forms/DateRangeInput.svelte.d.ts +33 -0
- package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/DateTimeInput.svelte +521 -0
- package/dist/components/forms/DateTimeInput.svelte.d.ts +24 -0
- package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/FileUpload.svelte +358 -0
- package/dist/components/forms/FileUpload.svelte.d.ts +22 -0
- package/dist/components/forms/FileUpload.svelte.d.ts.map +1 -0
- package/dist/components/forms/Form.svelte +771 -0
- package/dist/components/forms/Form.svelte.d.ts +26 -0
- package/dist/components/forms/Form.svelte.d.ts.map +1 -0
- package/dist/components/forms/FormGroup.svelte +86 -0
- package/dist/components/forms/FormGroup.svelte.d.ts +13 -0
- package/dist/components/forms/FormGroup.svelte.d.ts.map +1 -0
- package/dist/components/forms/FormMicButton.svelte +179 -0
- package/dist/components/forms/FormMicButton.svelte.d.ts +10 -0
- package/dist/components/forms/FormMicButton.svelte.d.ts.map +1 -0
- package/dist/components/forms/Input.svelte +83 -0
- package/dist/components/forms/Input.svelte.d.ts +9 -0
- package/dist/components/forms/Input.svelte.d.ts.map +1 -0
- package/dist/components/forms/MeasurementInput.svelte +505 -0
- package/dist/components/forms/MeasurementInput.svelte.d.ts +35 -0
- package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/MoneyInput.svelte +412 -0
- package/dist/components/forms/MoneyInput.svelte.d.ts +30 -0
- package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/NumberInput.svelte +310 -0
- package/dist/components/forms/NumberInput.svelte.d.ts +28 -0
- package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/PhoneInput.svelte +530 -0
- package/dist/components/forms/PhoneInput.svelte.d.ts +22 -0
- package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/SearchInput.svelte +358 -0
- package/dist/components/forms/SearchInput.svelte.d.ts +33 -0
- package/dist/components/forms/SearchInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Select.svelte +83 -0
- package/dist/components/forms/Select.svelte.d.ts +11 -0
- package/dist/components/forms/Select.svelte.d.ts.map +1 -0
- package/dist/components/forms/SelectInput.svelte +254 -0
- package/dist/components/forms/SelectInput.svelte.d.ts +25 -0
- package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/TextInput.svelte +415 -0
- package/dist/components/forms/TextInput.svelte.d.ts +26 -0
- package/dist/components/forms/TextInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Textarea.svelte +85 -0
- package/dist/components/forms/Textarea.svelte.d.ts +10 -0
- package/dist/components/forms/Textarea.svelte.d.ts.map +1 -0
- package/dist/components/forms/TextareaInput.svelte +386 -0
- package/dist/components/forms/TextareaInput.svelte.d.ts +26 -0
- package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Toggle.svelte +217 -0
- package/dist/components/forms/Toggle.svelte.d.ts +37 -0
- package/dist/components/forms/Toggle.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/AddressInput.behavior.test.js +122 -0
- package/dist/components/forms/__tests__/CheckboxInput.test.js +92 -0
- package/dist/components/forms/__tests__/DateRangeInput.behavior.test.js +135 -0
- package/dist/components/forms/__tests__/DateTimeInput.behavior.test.js +103 -0
- package/dist/components/forms/__tests__/FileUpload.test.js +90 -0
- package/dist/components/forms/__tests__/Form.behavior.test.js +137 -0
- package/dist/components/forms/__tests__/Form.test.js +58 -0
- package/dist/components/forms/__tests__/FormGroup.test.js +48 -0
- package/dist/components/forms/__tests__/FormMicButton.test.js +86 -0
- package/dist/components/forms/__tests__/Input.test.js +49 -0
- package/dist/components/forms/__tests__/MeasurementInput.behavior.test.js +129 -0
- package/dist/components/forms/__tests__/MoneyInput.behavior.test.js +124 -0
- package/dist/components/forms/__tests__/NumberInput.behavior.test.js +141 -0
- package/dist/components/forms/__tests__/PhoneInput.behavior.test.js +96 -0
- package/dist/components/forms/__tests__/SearchInput.test.js +79 -0
- package/dist/components/forms/__tests__/Select.test.js +37 -0
- package/dist/components/forms/__tests__/SelectInput.behavior.test.js +132 -0
- package/dist/components/forms/__tests__/TextInput.behavior.test.js +131 -0
- package/dist/components/forms/__tests__/Textarea.test.js +39 -0
- package/dist/components/forms/__tests__/TextareaInput.behavior.test.js +96 -0
- package/dist/components/forms/__tests__/Toggle.test.js +87 -0
- package/dist/components/forms/__tests__/composite-inputs-a11y.test.js +69 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte +16 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +33 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +12 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/rich-inputs-a11y.test.js +87 -0
- package/dist/components/forms/index.d.ts +25 -0
- package/dist/components/forms/index.d.ts.map +1 -0
- package/dist/components/forms/index.js +25 -0
- package/dist/components/forms/types.d.ts +33 -0
- package/dist/components/forms/types.d.ts.map +1 -0
- package/dist/components/forms/types.js +4 -0
- package/dist/components/module/ModulePanel.svelte +134 -0
- package/dist/components/module/ModulePanel.svelte.d.ts +22 -0
- package/dist/components/module/ModulePanel.svelte.d.ts.map +1 -0
- package/dist/components/module/index.d.ts +5 -0
- package/dist/components/module/index.d.ts.map +1 -0
- package/dist/components/module/index.js +4 -0
- package/dist/components/workspace/Breadcrumbs.svelte +141 -0
- package/dist/components/workspace/Breadcrumbs.svelte.d.ts +21 -0
- package/dist/components/workspace/Breadcrumbs.svelte.d.ts.map +1 -0
- package/dist/components/workspace/NavTree.svelte +354 -0
- package/dist/components/workspace/NavTree.svelte.d.ts +45 -0
- package/dist/components/workspace/NavTree.svelte.d.ts.map +1 -0
- package/dist/components/workspace/README.md +34 -0
- package/dist/components/workspace/RoleShell.svelte +309 -0
- package/dist/components/workspace/RoleShell.svelte.d.ts +91 -0
- package/dist/components/workspace/RoleShell.svelte.d.ts.map +1 -0
- package/dist/components/workspace/WorkspaceShell.svelte +951 -0
- package/dist/components/workspace/WorkspaceShell.svelte.d.ts +112 -0
- package/dist/components/workspace/WorkspaceShell.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/RoleShell.test.js +772 -0
- package/dist/components/workspace/__tests__/WorkspaceShell.test.js +630 -0
- package/dist/components/workspace/__tests__/breadcrumbs-helpers.test.js +141 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte +45 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts +21 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/define-tools-dock.test.js +1010 -0
- package/dist/components/workspace/__tests__/harness.svelte +25 -0
- package/dist/components/workspace/__tests__/harness.svelte.d.ts +14 -0
- package/dist/components/workspace/__tests__/harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/index.test.js +37 -0
- package/dist/components/workspace/__tests__/manifest-nav-helpers.test.js +24 -0
- package/dist/components/workspace/__tests__/manifest-nav.test.js +599 -0
- package/dist/components/workspace/__tests__/nav-helpers.test.js +95 -0
- package/dist/components/workspace/__tests__/render-harness.svelte +66 -0
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts +32 -0
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/render-tools-dock.test.js +243 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte +58 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts +16 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte +41 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts +13 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/test-icon.svelte +17 -0
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts +19 -0
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte +38 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts +22 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts +65 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.js +115 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts +15 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.js +7 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture.test.js +115 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte +9 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts +19 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/use-harness.svelte +23 -0
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts +8 -0
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/use-tools-dock.test.js +33 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte +43 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts +11 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/breadcrumbs-helpers.d.ts +44 -0
- package/dist/components/workspace/breadcrumbs-helpers.d.ts.map +1 -0
- package/dist/components/workspace/breadcrumbs-helpers.js +88 -0
- package/dist/components/workspace/index.d.ts +16 -0
- package/dist/components/workspace/index.d.ts.map +1 -0
- package/dist/components/workspace/index.js +14 -0
- package/dist/components/workspace/manifest-nav.d.ts +200 -0
- package/dist/components/workspace/manifest-nav.d.ts.map +1 -0
- package/dist/components/workspace/manifest-nav.js +408 -0
- package/dist/components/workspace/nav-helpers.d.ts +36 -0
- package/dist/components/workspace/nav-helpers.d.ts.map +1 -0
- package/dist/components/workspace/nav-helpers.js +60 -0
- package/dist/components/workspace/server/__tests__/compose-availability.test.js +383 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts +78 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts.map +1 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.js +104 -0
- package/dist/components/workspace/server/compose-availability.d.ts +73 -0
- package/dist/components/workspace/server/compose-availability.d.ts.map +1 -0
- package/dist/components/workspace/server/compose-availability.js +114 -0
- package/dist/components/workspace/server/index.d.ts +13 -0
- package/dist/components/workspace/server/index.d.ts.map +1 -0
- package/dist/components/workspace/server/index.js +11 -0
- package/dist/components/workspace/server/types.d.ts +108 -0
- package/dist/components/workspace/server/types.d.ts.map +1 -0
- package/dist/components/workspace/server/types.js +11 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte +565 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte.d.ts +14 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.d.ts +143 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.js +487 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.d.ts +41 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.js +50 -0
- package/dist/components/workspace/types.d.ts +372 -0
- package/dist/components/workspace/types.d.ts.map +1 -0
- package/dist/components/workspace/types.js +6 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +10 -0
- package/dist/hooks/useAppState.svelte.d.ts +46 -0
- package/dist/hooks/useAppState.svelte.d.ts.map +1 -0
- package/dist/hooks/useAppState.svelte.js +59 -0
- package/dist/hooks/useAuth.svelte.d.ts +41 -0
- package/dist/hooks/useAuth.svelte.d.ts.map +1 -0
- package/dist/hooks/useAuth.svelte.js +43 -0
- package/dist/hooks/useLLM.svelte.d.ts +69 -0
- package/dist/hooks/useLLM.svelte.d.ts.map +1 -0
- package/dist/hooks/useLLM.svelte.js +85 -0
- package/dist/hooks/useSTT.svelte.d.ts +68 -0
- package/dist/hooks/useSTT.svelte.d.ts.map +1 -0
- package/dist/hooks/useSTT.svelte.js +97 -0
- package/dist/hooks/useSocket.svelte.d.ts +45 -0
- package/dist/hooks/useSocket.svelte.d.ts.map +1 -0
- package/dist/hooks/useSocket.svelte.js +54 -0
- package/dist/hooks/useTTS.svelte.d.ts +65 -0
- package/dist/hooks/useTTS.svelte.d.ts.map +1 -0
- package/dist/hooks/useTTS.svelte.js +93 -0
- package/dist/hooks/useTheme.d.ts +13 -0
- package/dist/hooks/useTheme.d.ts.map +1 -0
- package/dist/hooks/useTheme.js +16 -0
- package/dist/i18n/__tests__/server.spec.js +50 -0
- package/dist/i18n/server.d.ts +47 -0
- package/dist/i18n/server.d.ts.map +1 -0
- package/dist/i18n/server.js +58 -0
- package/dist/i18n/strings.forms.d.ts +33 -0
- package/dist/i18n/strings.forms.d.ts.map +1 -0
- package/dist/i18n/strings.forms.js +54 -0
- package/dist/i18n/strings.workspace.d.ts +34 -0
- package/dist/i18n/strings.workspace.d.ts.map +1 -0
- package/dist/i18n/strings.workspace.js +40 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/state/__tests__/warm-clients.test.js +40 -0
- package/dist/state/app-state.d.ts +308 -0
- package/dist/state/app-state.d.ts.map +1 -0
- package/dist/state/app-state.js +64 -0
- package/dist/state/app-state.svelte.d.ts +196 -0
- package/dist/state/app-state.svelte.d.ts.map +1 -0
- package/dist/state/app-state.svelte.js +774 -0
- package/dist/state/context.d.ts +23 -0
- package/dist/state/context.d.ts.map +1 -0
- package/dist/state/context.js +32 -0
- package/dist/state/form-context.d.ts +59 -0
- package/dist/state/form-context.d.ts.map +1 -0
- package/dist/state/form-context.js +31 -0
- package/dist/state/form-group-context.d.ts +13 -0
- package/dist/state/form-group-context.d.ts.map +1 -0
- package/dist/state/form-group-context.js +28 -0
- package/dist/state/index.d.ts +9 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +8 -0
- package/dist/state/warm-clients.d.ts +136 -0
- package/dist/state/warm-clients.d.ts.map +1 -0
- package/dist/state/warm-clients.js +231 -0
- package/package.json +137 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
createI18nContext,
|
|
4
|
+
type I18nSnapshot,
|
|
5
|
+
setI18nContext,
|
|
6
|
+
} from '@happyvertical/smrt-ui/i18n';
|
|
7
|
+
import type { Snippet } from 'svelte';
|
|
8
|
+
import { onDestroy, untrack } from 'svelte';
|
|
9
|
+
import AILoadingOverlay from './browser-ai/svelte/components/AILoadingOverlay.svelte';
|
|
10
|
+
import type {
|
|
11
|
+
AIConfig,
|
|
12
|
+
AILoadingState,
|
|
13
|
+
AppMode,
|
|
14
|
+
SocketConfig,
|
|
15
|
+
User,
|
|
16
|
+
} from './state/app-state.js';
|
|
17
|
+
import { createAppState } from './state/app-state.svelte.js';
|
|
18
|
+
import { setAppStateContext } from './state/context.js';
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
/**
|
|
22
|
+
* Initial mode: 'default' | 'smrt'
|
|
23
|
+
* If not provided, mode is auto-detected based on capabilities
|
|
24
|
+
*/
|
|
25
|
+
mode?: AppMode;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to auto-enable smrt mode when capabilities are available
|
|
28
|
+
* @default true
|
|
29
|
+
*/
|
|
30
|
+
autoEnableSmrt?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* User object from smrt-users (from your load function)
|
|
33
|
+
* Pass null when not authenticated
|
|
34
|
+
*/
|
|
35
|
+
user?: User | null;
|
|
36
|
+
/**
|
|
37
|
+
* Resolved permissions (from PermissionResolver in your load function)
|
|
38
|
+
*/
|
|
39
|
+
permissions?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* WebSocket configuration
|
|
42
|
+
* If provided, connects on mount and disconnects on unmount
|
|
43
|
+
*/
|
|
44
|
+
socket?: SocketConfig;
|
|
45
|
+
/**
|
|
46
|
+
* AI configuration for preloading and warm clients
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```svelte
|
|
50
|
+
* <Provider
|
|
51
|
+
* ai={{
|
|
52
|
+
* preload: 'idle',
|
|
53
|
+
* stt: { type: 'whisper-cpp' },
|
|
54
|
+
* showLoadingOverlay: true
|
|
55
|
+
* }}
|
|
56
|
+
* >
|
|
57
|
+
* ...
|
|
58
|
+
* </Provider>
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
ai?: AIConfig;
|
|
62
|
+
/**
|
|
63
|
+
* Callback when capabilities are detected
|
|
64
|
+
*/
|
|
65
|
+
onReady?: () => void;
|
|
66
|
+
/**
|
|
67
|
+
* Callback when mode changes
|
|
68
|
+
*/
|
|
69
|
+
onModeChange?: (mode: AppMode) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Callback when AI loading state changes
|
|
72
|
+
*/
|
|
73
|
+
onAILoadingChange?: (state: AILoadingState) => void;
|
|
74
|
+
/**
|
|
75
|
+
* i18n snapshot from your load function (`buildI18nSnapshot` on
|
|
76
|
+
* `@happyvertical/smrt-svelte/i18n/server`). Provides the active locale +
|
|
77
|
+
* resolved message templates to `useI18n()` / `<Trans>`. Omit for
|
|
78
|
+
* English-default-only rendering.
|
|
79
|
+
*/
|
|
80
|
+
i18n?: I18nSnapshot;
|
|
81
|
+
/**
|
|
82
|
+
* Children to render
|
|
83
|
+
*/
|
|
84
|
+
children: Snippet;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const {
|
|
88
|
+
mode,
|
|
89
|
+
autoEnableSmrt = true,
|
|
90
|
+
user = null,
|
|
91
|
+
permissions = [],
|
|
92
|
+
socket,
|
|
93
|
+
ai,
|
|
94
|
+
onReady,
|
|
95
|
+
onModeChange,
|
|
96
|
+
onAILoadingChange,
|
|
97
|
+
i18n,
|
|
98
|
+
children,
|
|
99
|
+
}: Props = $props();
|
|
100
|
+
|
|
101
|
+
// Determine if we should show the loading overlay
|
|
102
|
+
const showLoadingOverlay = $derived(ai?.showLoadingOverlay ?? true);
|
|
103
|
+
|
|
104
|
+
// Create app state
|
|
105
|
+
const appState = createAppState({
|
|
106
|
+
onCapabilitiesDetected: () => {
|
|
107
|
+
onReady?.();
|
|
108
|
+
},
|
|
109
|
+
onModeChange: (newMode) => {
|
|
110
|
+
onModeChange?.(newMode);
|
|
111
|
+
},
|
|
112
|
+
onAILoadingChange: (state) => {
|
|
113
|
+
onAILoadingChange?.(state);
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
$effect(() => {
|
|
118
|
+
const currentPreferences = untrack(() => appState.state.session.preferences);
|
|
119
|
+
if (currentPreferences.autoEnableSmrt === autoEnableSmrt) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
appState.updateSession({
|
|
124
|
+
preferences: {
|
|
125
|
+
...currentPreferences,
|
|
126
|
+
autoEnableSmrt,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
$effect(() => {
|
|
132
|
+
if (mode) {
|
|
133
|
+
appState.setMode(mode, 'explicit');
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Provide context
|
|
138
|
+
setAppStateContext(appState);
|
|
139
|
+
|
|
140
|
+
// i18n: seed the store from the initial snapshot synchronously (untrack — this
|
|
141
|
+
// MUST run during SSR, where $effect does not, so translated strings render on
|
|
142
|
+
// the server), then keep it in sync when the `i18n` prop changes (locale
|
|
143
|
+
// switch). Reads stay synchronous on the client; all async resolution happened
|
|
144
|
+
// server-side in buildI18nSnapshot.
|
|
145
|
+
const i18nStore = untrack(() => createI18nContext(i18n));
|
|
146
|
+
setI18nContext(i18nStore);
|
|
147
|
+
$effect(() => {
|
|
148
|
+
if (i18n) {
|
|
149
|
+
i18nStore.snapshot = i18n;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Initialize on mount (untrack to prevent infinite loop)
|
|
154
|
+
// Skip during SSR - browser-ai APIs require browser environment
|
|
155
|
+
$effect(() => {
|
|
156
|
+
if (typeof window === 'undefined') return;
|
|
157
|
+
untrack(() => {
|
|
158
|
+
appState.initialize();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Sync user and permissions when they change
|
|
163
|
+
$effect(() => {
|
|
164
|
+
appState.setUser(user, permissions);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Manage socket lifecycle (browser-only)
|
|
168
|
+
$effect(() => {
|
|
169
|
+
if (typeof window === 'undefined') return;
|
|
170
|
+
if (socket) {
|
|
171
|
+
// connectSocket already handles disconnecting any existing socket
|
|
172
|
+
appState.connectSocket(socket);
|
|
173
|
+
|
|
174
|
+
// Cleanup when socket prop changes or component unmounts
|
|
175
|
+
return () => {
|
|
176
|
+
appState.disconnectSocket();
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Update AI config when it changes (for dynamic config updates, browser-only)
|
|
182
|
+
$effect(() => {
|
|
183
|
+
if (typeof window === 'undefined') return;
|
|
184
|
+
if (ai) {
|
|
185
|
+
untrack(() => {
|
|
186
|
+
appState.setAIConfig(ai);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Cleanup on destroy
|
|
192
|
+
onDestroy(() => {
|
|
193
|
+
appState.disconnectSocket();
|
|
194
|
+
});
|
|
195
|
+
</script>
|
|
196
|
+
|
|
197
|
+
{#if ai && showLoadingOverlay}
|
|
198
|
+
<AILoadingOverlay
|
|
199
|
+
message={ai.loadingMessage}
|
|
200
|
+
dismissible={true}
|
|
201
|
+
/>
|
|
202
|
+
{/if}
|
|
203
|
+
|
|
204
|
+
{@render children()}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type I18nSnapshot } from '@happyvertical/smrt-ui/i18n';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { AIConfig, AILoadingState, AppMode, SocketConfig, User } from './state/app-state.js';
|
|
4
|
+
interface Props {
|
|
5
|
+
/**
|
|
6
|
+
* Initial mode: 'default' | 'smrt'
|
|
7
|
+
* If not provided, mode is auto-detected based on capabilities
|
|
8
|
+
*/
|
|
9
|
+
mode?: AppMode;
|
|
10
|
+
/**
|
|
11
|
+
* Whether to auto-enable smrt mode when capabilities are available
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
autoEnableSmrt?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* User object from smrt-users (from your load function)
|
|
17
|
+
* Pass null when not authenticated
|
|
18
|
+
*/
|
|
19
|
+
user?: User | null;
|
|
20
|
+
/**
|
|
21
|
+
* Resolved permissions (from PermissionResolver in your load function)
|
|
22
|
+
*/
|
|
23
|
+
permissions?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* WebSocket configuration
|
|
26
|
+
* If provided, connects on mount and disconnects on unmount
|
|
27
|
+
*/
|
|
28
|
+
socket?: SocketConfig;
|
|
29
|
+
/**
|
|
30
|
+
* AI configuration for preloading and warm clients
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```svelte
|
|
34
|
+
* <Provider
|
|
35
|
+
* ai={{
|
|
36
|
+
* preload: 'idle',
|
|
37
|
+
* stt: { type: 'whisper-cpp' },
|
|
38
|
+
* showLoadingOverlay: true
|
|
39
|
+
* }}
|
|
40
|
+
* >
|
|
41
|
+
* ...
|
|
42
|
+
* </Provider>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
ai?: AIConfig;
|
|
46
|
+
/**
|
|
47
|
+
* Callback when capabilities are detected
|
|
48
|
+
*/
|
|
49
|
+
onReady?: () => void;
|
|
50
|
+
/**
|
|
51
|
+
* Callback when mode changes
|
|
52
|
+
*/
|
|
53
|
+
onModeChange?: (mode: AppMode) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Callback when AI loading state changes
|
|
56
|
+
*/
|
|
57
|
+
onAILoadingChange?: (state: AILoadingState) => void;
|
|
58
|
+
/**
|
|
59
|
+
* i18n snapshot from your load function (`buildI18nSnapshot` on
|
|
60
|
+
* `@happyvertical/smrt-svelte/i18n/server`). Provides the active locale +
|
|
61
|
+
* resolved message templates to `useI18n()` / `<Trans>`. Omit for
|
|
62
|
+
* English-default-only rendering.
|
|
63
|
+
*/
|
|
64
|
+
i18n?: I18nSnapshot;
|
|
65
|
+
/**
|
|
66
|
+
* Children to render
|
|
67
|
+
*/
|
|
68
|
+
children: Snippet;
|
|
69
|
+
}
|
|
70
|
+
declare const Provider: import("svelte").Component<Props, {}, "">;
|
|
71
|
+
type Provider = ReturnType<typeof Provider>;
|
|
72
|
+
export default Provider;
|
|
73
|
+
//# sourceMappingURL=Provider.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Provider.svelte.d.ts","sourceRoot":"","sources":["../src/Provider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,OAAO,EACP,YAAY,EACZ,IAAI,EACL,MAAM,sBAAsB,CAAC;AAK9B,UAAU,KAAK;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;;;;;;;;;;;;OAeG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD;;;;;OAKG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAiID,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for app state types and initial state
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { createInitialState, } from '../state/app-state.js';
|
|
6
|
+
describe('createInitialState', () => {
|
|
7
|
+
it('creates initial state with correct defaults', () => {
|
|
8
|
+
const state = createInitialState();
|
|
9
|
+
expect(state.mode).toBe('default');
|
|
10
|
+
expect(state.modeSource).toBe('auto');
|
|
11
|
+
expect(state.initialized).toBe(false);
|
|
12
|
+
expect(state.error).toBeNull();
|
|
13
|
+
});
|
|
14
|
+
it('creates initial session with null user', () => {
|
|
15
|
+
const state = createInitialState();
|
|
16
|
+
expect(state.session.user).toBeNull();
|
|
17
|
+
expect(state.session.isAuthenticated).toBe(false);
|
|
18
|
+
expect(state.session.permissions).toEqual([]);
|
|
19
|
+
expect(state.session.preferences).toEqual({});
|
|
20
|
+
});
|
|
21
|
+
it('creates initial socket state as disconnected', () => {
|
|
22
|
+
const state = createInitialState();
|
|
23
|
+
expect(state.socket.status).toBe('disconnected');
|
|
24
|
+
expect(state.socket.reconnectAttempts).toBe(0);
|
|
25
|
+
expect(state.socket.lastError).toBeNull();
|
|
26
|
+
});
|
|
27
|
+
it('creates initial AI state as uninitialized', () => {
|
|
28
|
+
const state = createInitialState();
|
|
29
|
+
expect(state.ai.stt.initState).toBe('uninitialized');
|
|
30
|
+
expect(state.ai.tts.initState).toBe('uninitialized');
|
|
31
|
+
expect(state.ai.llm.initState).toBe('uninitialized');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('UserSession type', () => {
|
|
35
|
+
it('allows null user', () => {
|
|
36
|
+
const session = {
|
|
37
|
+
user: null,
|
|
38
|
+
isAuthenticated: false,
|
|
39
|
+
permissions: [],
|
|
40
|
+
preferences: {},
|
|
41
|
+
};
|
|
42
|
+
expect(session.user).toBeNull();
|
|
43
|
+
expect(session.isAuthenticated).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
it('allows user with permissions', () => {
|
|
46
|
+
const session = {
|
|
47
|
+
user: {
|
|
48
|
+
id: 'user-123',
|
|
49
|
+
profileId: 'profile-456',
|
|
50
|
+
email: 'test@example.com',
|
|
51
|
+
status: 'active',
|
|
52
|
+
lastLoginAt: null,
|
|
53
|
+
},
|
|
54
|
+
isAuthenticated: true,
|
|
55
|
+
permissions: ['articles.create', 'articles.read'],
|
|
56
|
+
preferences: {
|
|
57
|
+
preferredSTT: 'whisper-cpp',
|
|
58
|
+
autoEnableSmrt: true,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
expect(session.user?.email).toBe('test@example.com');
|
|
62
|
+
expect(session.isAuthenticated).toBe(true);
|
|
63
|
+
expect(session.permissions).toContain('articles.create');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('SocketState type', () => {
|
|
67
|
+
it('allows all socket statuses', () => {
|
|
68
|
+
const statuses = [
|
|
69
|
+
'disconnected',
|
|
70
|
+
'connecting',
|
|
71
|
+
'connected',
|
|
72
|
+
'reconnecting',
|
|
73
|
+
];
|
|
74
|
+
statuses.forEach((status) => {
|
|
75
|
+
const state = {
|
|
76
|
+
status,
|
|
77
|
+
reconnectAttempts: 0,
|
|
78
|
+
lastError: null,
|
|
79
|
+
};
|
|
80
|
+
expect(state.status).toBe(status);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe('SocketConfig type', () => {
|
|
85
|
+
it('allows minimal config with just url', () => {
|
|
86
|
+
const config = {
|
|
87
|
+
url: 'wss://example.com/ws',
|
|
88
|
+
};
|
|
89
|
+
expect(config.url).toBe('wss://example.com/ws');
|
|
90
|
+
expect(config.reconnect).toBeUndefined();
|
|
91
|
+
expect(config.onMessage).toBeUndefined();
|
|
92
|
+
});
|
|
93
|
+
it('allows full config with all options', () => {
|
|
94
|
+
const config = {
|
|
95
|
+
url: 'wss://example.com/ws',
|
|
96
|
+
reconnect: {
|
|
97
|
+
enabled: true,
|
|
98
|
+
maxAttempts: 10,
|
|
99
|
+
baseDelay: 2000,
|
|
100
|
+
},
|
|
101
|
+
onOpen: () => { },
|
|
102
|
+
onMessage: (data) => console.log(data),
|
|
103
|
+
onClose: (event) => console.log(event),
|
|
104
|
+
onError: (event) => console.log(event),
|
|
105
|
+
};
|
|
106
|
+
expect(config.url).toBe('wss://example.com/ws');
|
|
107
|
+
expect(config.reconnect?.enabled).toBe(true);
|
|
108
|
+
expect(config.reconnect?.maxAttempts).toBe(10);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe('AIConfig type', () => {
|
|
112
|
+
it('creates initial AI loading state', () => {
|
|
113
|
+
const state = createInitialState();
|
|
114
|
+
expect(state.aiLoading.phase).toBe('idle');
|
|
115
|
+
expect(state.aiLoading.currentAdapter).toBeNull();
|
|
116
|
+
expect(state.aiLoading.overallProgress).toBe(0);
|
|
117
|
+
expect(state.aiLoading.message).toBe('');
|
|
118
|
+
expect(state.aiLoading.loaded).toEqual([]);
|
|
119
|
+
expect(state.aiLoading.failed).toEqual([]);
|
|
120
|
+
expect(state.aiLoading.error).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
describe('AIConfig types', () => {
|
|
124
|
+
it('allows preload strategies', () => {
|
|
125
|
+
const strategies = ['none', 'eager', 'idle', 'on-visible'];
|
|
126
|
+
strategies.forEach((strategy) => {
|
|
127
|
+
expect(strategy).toBeDefined();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
it('allows STT config', () => {
|
|
131
|
+
const sttConfig = {
|
|
132
|
+
type: 'whisper-cpp',
|
|
133
|
+
model: 'tiny.en',
|
|
134
|
+
enabled: true,
|
|
135
|
+
};
|
|
136
|
+
expect(sttConfig.type).toBe('whisper-cpp');
|
|
137
|
+
expect(sttConfig.model).toBe('tiny.en');
|
|
138
|
+
});
|
|
139
|
+
it('allows TTS config', () => {
|
|
140
|
+
const ttsConfig = {
|
|
141
|
+
type: 'browser-synthesis',
|
|
142
|
+
voice: 'Google UK English Female',
|
|
143
|
+
enabled: true,
|
|
144
|
+
};
|
|
145
|
+
expect(ttsConfig.type).toBe('browser-synthesis');
|
|
146
|
+
});
|
|
147
|
+
it('allows LLM config', () => {
|
|
148
|
+
const llmConfig = {
|
|
149
|
+
type: 'webllm',
|
|
150
|
+
model: 'Llama-3.1-8B-Instruct',
|
|
151
|
+
enabled: true,
|
|
152
|
+
};
|
|
153
|
+
expect(llmConfig.type).toBe('webllm');
|
|
154
|
+
expect(llmConfig.model).toBe('Llama-3.1-8B-Instruct');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for warm client cache
|
|
3
|
+
*/
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { clearAllCaches, getCachedLLM, getCachedSTT, getCachedTTS, getCacheStats, removeCachedLLM, removeCachedSTT, removeCachedTTS, setCachedLLM, setCachedSTT, setCachedTTS, updateLLMCacheState, updateSTTCacheState, updateTTSCacheState, } from '../state/warm-clients.js';
|
|
6
|
+
// Mock adapters for testing
|
|
7
|
+
const createMockSTTAdapter = () => ({
|
|
8
|
+
type: 'whisper-cpp',
|
|
9
|
+
dispose: () => Promise.resolve(),
|
|
10
|
+
ensureInitialized: () => Promise.resolve(),
|
|
11
|
+
start: () => Promise.resolve(),
|
|
12
|
+
stop: () => Promise.resolve(),
|
|
13
|
+
onResult: () => { },
|
|
14
|
+
onStart: () => { },
|
|
15
|
+
onEnd: () => { },
|
|
16
|
+
onError: () => { },
|
|
17
|
+
});
|
|
18
|
+
const createMockTTSAdapter = () => ({
|
|
19
|
+
type: 'browser-synthesis',
|
|
20
|
+
dispose: () => Promise.resolve(),
|
|
21
|
+
ensureInitialized: () => Promise.resolve(),
|
|
22
|
+
speak: () => Promise.resolve(),
|
|
23
|
+
stop: () => { },
|
|
24
|
+
pause: () => { },
|
|
25
|
+
resume: () => { },
|
|
26
|
+
getVoices: () => [],
|
|
27
|
+
onStart: () => { },
|
|
28
|
+
onEnd: () => { },
|
|
29
|
+
onError: () => { },
|
|
30
|
+
});
|
|
31
|
+
const createMockLLMAdapter = () => ({
|
|
32
|
+
type: 'webllm',
|
|
33
|
+
currentModel: 'test-model',
|
|
34
|
+
dispose: () => Promise.resolve(),
|
|
35
|
+
ensureInitialized: () => Promise.resolve(),
|
|
36
|
+
message: () => Promise.resolve('response'),
|
|
37
|
+
unloadModel: () => Promise.resolve(),
|
|
38
|
+
});
|
|
39
|
+
describe('warm-clients', () => {
|
|
40
|
+
afterEach(async () => {
|
|
41
|
+
await clearAllCaches();
|
|
42
|
+
});
|
|
43
|
+
describe('STT cache', () => {
|
|
44
|
+
it('caches STT adapter', () => {
|
|
45
|
+
const adapter = createMockSTTAdapter();
|
|
46
|
+
setCachedSTT('whisper-cpp', adapter);
|
|
47
|
+
const cached = getCachedSTT('whisper-cpp');
|
|
48
|
+
expect(cached).toBeDefined();
|
|
49
|
+
expect(cached?.adapter).toBe(adapter);
|
|
50
|
+
expect(cached?.initState).toBe('ready');
|
|
51
|
+
expect(cached?.type).toBe('whisper-cpp');
|
|
52
|
+
});
|
|
53
|
+
it('returns undefined for uncached adapter', () => {
|
|
54
|
+
const cached = getCachedSTT('browser-speech');
|
|
55
|
+
expect(cached).toBeUndefined();
|
|
56
|
+
});
|
|
57
|
+
it('updates cache state', () => {
|
|
58
|
+
const adapter = createMockSTTAdapter();
|
|
59
|
+
setCachedSTT('whisper-cpp', adapter);
|
|
60
|
+
updateSTTCacheState('whisper-cpp', {
|
|
61
|
+
initState: 'initializing',
|
|
62
|
+
downloadProgress: {
|
|
63
|
+
state: 'downloading',
|
|
64
|
+
percent: 50,
|
|
65
|
+
bytesLoaded: 50,
|
|
66
|
+
bytesTotal: 100,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
const cached = getCachedSTT('whisper-cpp');
|
|
70
|
+
expect(cached?.initState).toBe('initializing');
|
|
71
|
+
expect(cached?.downloadProgress?.percent).toBe(50);
|
|
72
|
+
});
|
|
73
|
+
it('removes cached adapter', () => {
|
|
74
|
+
const adapter = createMockSTTAdapter();
|
|
75
|
+
setCachedSTT('whisper-cpp', adapter);
|
|
76
|
+
removeCachedSTT('whisper-cpp');
|
|
77
|
+
const cached = getCachedSTT('whisper-cpp');
|
|
78
|
+
expect(cached).toBeUndefined();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('TTS cache', () => {
|
|
82
|
+
it('caches TTS adapter', () => {
|
|
83
|
+
const adapter = createMockTTSAdapter();
|
|
84
|
+
setCachedTTS('browser-synthesis', adapter);
|
|
85
|
+
const cached = getCachedTTS('browser-synthesis');
|
|
86
|
+
expect(cached).toBeDefined();
|
|
87
|
+
expect(cached?.adapter).toBe(adapter);
|
|
88
|
+
expect(cached?.initState).toBe('ready');
|
|
89
|
+
});
|
|
90
|
+
it('updates cache state', () => {
|
|
91
|
+
const adapter = createMockTTSAdapter();
|
|
92
|
+
setCachedTTS('browser-synthesis', adapter);
|
|
93
|
+
updateTTSCacheState('browser-synthesis', {
|
|
94
|
+
initState: 'error',
|
|
95
|
+
error: new Error('test error'),
|
|
96
|
+
});
|
|
97
|
+
const cached = getCachedTTS('browser-synthesis');
|
|
98
|
+
expect(cached?.initState).toBe('error');
|
|
99
|
+
expect(cached?.error?.message).toBe('test error');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe('LLM cache', () => {
|
|
103
|
+
it('caches LLM adapter with model ID', () => {
|
|
104
|
+
const adapter = createMockLLMAdapter();
|
|
105
|
+
setCachedLLM('webllm', adapter, 'test-model');
|
|
106
|
+
const cached = getCachedLLM('webllm', 'test-model');
|
|
107
|
+
expect(cached).toBeDefined();
|
|
108
|
+
expect(cached?.adapter).toBe(adapter);
|
|
109
|
+
expect(cached?.initState).toBe('ready');
|
|
110
|
+
});
|
|
111
|
+
it('caches LLM adapter without model ID', () => {
|
|
112
|
+
const adapter = createMockLLMAdapter();
|
|
113
|
+
setCachedLLM('webllm', adapter);
|
|
114
|
+
const cached = getCachedLLM('webllm');
|
|
115
|
+
expect(cached).toBeDefined();
|
|
116
|
+
expect(cached?.adapter).toBe(adapter);
|
|
117
|
+
});
|
|
118
|
+
it('distinguishes between models', () => {
|
|
119
|
+
const adapter1 = createMockLLMAdapter();
|
|
120
|
+
const adapter2 = {
|
|
121
|
+
...createMockLLMAdapter(),
|
|
122
|
+
currentModel: 'other-model',
|
|
123
|
+
};
|
|
124
|
+
setCachedLLM('webllm', adapter1, 'model-1');
|
|
125
|
+
setCachedLLM('webllm', adapter2, 'model-2');
|
|
126
|
+
expect(getCachedLLM('webllm', 'model-1')?.adapter).toBe(adapter1);
|
|
127
|
+
expect(getCachedLLM('webllm', 'model-2')?.adapter).toBe(adapter2);
|
|
128
|
+
});
|
|
129
|
+
it('updates cache state', () => {
|
|
130
|
+
const adapter = createMockLLMAdapter();
|
|
131
|
+
setCachedLLM('webllm', adapter, 'test-model');
|
|
132
|
+
updateLLMCacheState('webllm', 'test-model', {
|
|
133
|
+
initState: 'initializing',
|
|
134
|
+
downloadProgress: {
|
|
135
|
+
state: 'downloading',
|
|
136
|
+
percent: 75,
|
|
137
|
+
bytesLoaded: 75,
|
|
138
|
+
bytesTotal: 100,
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
const cached = getCachedLLM('webllm', 'test-model');
|
|
142
|
+
expect(cached?.initState).toBe('initializing');
|
|
143
|
+
expect(cached?.downloadProgress?.percent).toBe(75);
|
|
144
|
+
});
|
|
145
|
+
it('removes cached adapter', () => {
|
|
146
|
+
const adapter = createMockLLMAdapter();
|
|
147
|
+
setCachedLLM('webllm', adapter, 'test-model');
|
|
148
|
+
removeCachedLLM('webllm', 'test-model');
|
|
149
|
+
const cached = getCachedLLM('webllm', 'test-model');
|
|
150
|
+
expect(cached).toBeUndefined();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('getCacheStats', () => {
|
|
154
|
+
it('returns empty stats initially', async () => {
|
|
155
|
+
const stats = getCacheStats();
|
|
156
|
+
expect(stats.stt.count).toBe(0);
|
|
157
|
+
expect(stats.tts.count).toBe(0);
|
|
158
|
+
expect(stats.llm.count).toBe(0);
|
|
159
|
+
});
|
|
160
|
+
it('returns correct counts after caching', () => {
|
|
161
|
+
setCachedSTT('whisper-cpp', createMockSTTAdapter());
|
|
162
|
+
setCachedSTT('browser-speech', createMockSTTAdapter());
|
|
163
|
+
setCachedTTS('browser-synthesis', createMockTTSAdapter());
|
|
164
|
+
setCachedLLM('webllm', createMockLLMAdapter(), 'model-1');
|
|
165
|
+
const stats = getCacheStats();
|
|
166
|
+
expect(stats.stt.count).toBe(2);
|
|
167
|
+
expect(stats.stt.types).toContain('whisper-cpp');
|
|
168
|
+
expect(stats.stt.types).toContain('browser-speech');
|
|
169
|
+
expect(stats.tts.count).toBe(1);
|
|
170
|
+
expect(stats.llm.count).toBe(1);
|
|
171
|
+
expect(stats.llm.keys).toContain('webllm:model-1');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
describe('clearAllCaches', () => {
|
|
175
|
+
it('clears all cached adapters', async () => {
|
|
176
|
+
setCachedSTT('whisper-cpp', createMockSTTAdapter());
|
|
177
|
+
setCachedTTS('browser-synthesis', createMockTTSAdapter());
|
|
178
|
+
setCachedLLM('webllm', createMockLLMAdapter());
|
|
179
|
+
await clearAllCaches();
|
|
180
|
+
const stats = getCacheStats();
|
|
181
|
+
expect(stats.stt.count).toBe(0);
|
|
182
|
+
expect(stats.tts.count).toBe(0);
|
|
183
|
+
expect(stats.llm.count).toBe(0);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM adapter factory with type guards
|
|
3
|
+
*/
|
|
4
|
+
import type { GetLLMOptions, LLMAdapter } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Create an LLM adapter
|
|
7
|
+
*
|
|
8
|
+
* Uses lazy loading to only import the requested adapter.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* // WebLLM (default)
|
|
13
|
+
* const llm = await getLLM();
|
|
14
|
+
*
|
|
15
|
+
* // With specific model
|
|
16
|
+
* const llm = await getLLM({ defaultModel: 'Llama-3.2-1B-Instruct-q4f16_1-MLC' });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function getLLM(options?: GetLLMOptions): Promise<LLMAdapter>;
|
|
20
|
+
/**
|
|
21
|
+
* Auto-detect and create the best available LLM adapter
|
|
22
|
+
*
|
|
23
|
+
* Selection priority:
|
|
24
|
+
* 1. WebLLM with WebGPU (best performance)
|
|
25
|
+
* 2. Transformers.js as fallback
|
|
26
|
+
*
|
|
27
|
+
* @throws If no LLM adapter is available
|
|
28
|
+
*/
|
|
29
|
+
export declare function getLLMAuto(options?: Partial<Omit<GetLLMOptions, 'type'>>): Promise<LLMAdapter>;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a specific LLM backend is available
|
|
32
|
+
*/
|
|
33
|
+
export declare function isLLMAvailable(type: 'webllm' | 'transformers-llm'): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Check if WebGPU is available for accelerated inference
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasWebGPU(): boolean;
|
|
38
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/browser-ai/adapters/llm/factory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EAGX,MAAM,YAAY,CAAC;AAkBpB;;;;;;;;;;;;;GAaG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAe7E;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,OAAO,GAAE,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAM,GACjD,OAAO,CAAC,UAAU,CAAC,CAoBrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,kBAAkB,GAAG,OAAO,CAY3E;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC"}
|