@happyvertical/smrt-svelte 0.53.1 → 0.53.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +15 -15
- package/dist/__tests__/app-state.test.js +0 -156
- package/dist/__tests__/data-surface-bridge.test.js +0 -351
- package/dist/__tests__/provider-mode-harness.svelte +0 -14
- package/dist/__tests__/provider-mode-harness.svelte.d.ts +0 -11
- package/dist/__tests__/provider-mode-harness.svelte.d.ts.map +0 -1
- package/dist/__tests__/provider-mode-probe.svelte +0 -13
- package/dist/__tests__/provider-mode-probe.svelte.d.ts +0 -8
- package/dist/__tests__/provider-mode-probe.svelte.d.ts.map +0 -1
- package/dist/__tests__/provider-webmcp-harness.svelte +0 -14
- package/dist/__tests__/provider-webmcp-harness.svelte.d.ts +0 -8
- package/dist/__tests__/provider-webmcp-harness.svelte.d.ts.map +0 -1
- package/dist/__tests__/success-never-text.test.js +0 -100
- package/dist/__tests__/warm-clients.test.js +0 -186
- package/dist/browser-ai/adapters/llm/bitgpu-inference-backend.test.js +0 -464
- package/dist/browser-ai/adapters/llm/webllm-inference-backend.test.js +0 -646
- package/dist/browser-ai/adapters/stt/browser-speech.test.js +0 -113
- package/dist/browser-ai/adapters/stt/dictation-source.test.js +0 -52
- package/dist/browser-ai/svelte/components/__tests__/ModelStatusControl.test.js +0 -172
- package/dist/components/board/__tests__/Board.test.js +0 -498
- package/dist/components/board/__tests__/BoardSsrHarness.svelte +0 -30
- package/dist/components/board/__tests__/BoardSsrHarness.svelte.d.ts +0 -19
- package/dist/components/board/__tests__/BoardSsrHarness.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/AddressInput.behavior.test.js +0 -216
- package/dist/components/forms/__tests__/CheckboxInput.test.js +0 -92
- package/dist/components/forms/__tests__/DateRangeInput.behavior.test.js +0 -135
- package/dist/components/forms/__tests__/DateTimeInput.behavior.test.js +0 -113
- package/dist/components/forms/__tests__/FileUpload.error-alert.test.js +0 -37
- package/dist/components/forms/__tests__/FileUpload.native-form.test.js +0 -249
- package/dist/components/forms/__tests__/FileUpload.test.js +0 -90
- package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte +0 -24
- package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte.d.ts +0 -10
- package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/Form.behavior.test.js +0 -137
- package/dist/components/forms/__tests__/Form.extraction.test.js +0 -68
- package/dist/components/forms/__tests__/Form.stt-error.test.js +0 -57
- package/dist/components/forms/__tests__/Form.test.js +0 -86
- package/dist/components/forms/__tests__/Form.ui-controls.test.js +0 -119
- package/dist/components/forms/__tests__/Form.webmcp.test.js +0 -2336
- package/dist/components/forms/__tests__/FormMicButton.test.js +0 -92
- package/dist/components/forms/__tests__/FormScope.test.js +0 -39
- package/dist/components/forms/__tests__/MeasurementInput.behavior.test.js +0 -129
- package/dist/components/forms/__tests__/MoneyInput.behavior.test.js +0 -124
- package/dist/components/forms/__tests__/NumberInput.behavior.test.js +0 -151
- package/dist/components/forms/__tests__/PhoneInput.behavior.test.js +0 -96
- package/dist/components/forms/__tests__/SearchInput.test.js +0 -79
- package/dist/components/forms/__tests__/SelectInput.behavior.test.js +0 -132
- package/dist/components/forms/__tests__/TextInput.behavior.test.js +0 -131
- package/dist/components/forms/__tests__/TextareaInput.behavior.test.js +0 -96
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte +0 -30
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte.d.ts +0 -7
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte +0 -19
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte.d.ts +0 -9
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte +0 -21
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte.d.ts +0 -8
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/composite-inputs-a11y.test.js +0 -69
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte +0 -27
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte.d.ts +0 -9
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte +0 -48
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte.d.ts +0 -10
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte +0 -26
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte.d.ts +0 -13
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte +0 -52
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte.d.ts +0 -16
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-scope.fixture.svelte +0 -30
- package/dist/components/forms/__tests__/form-scope.fixture.svelte.d.ts +0 -10
- package/dist/components/forms/__tests__/form-scope.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +0 -158
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +0 -51
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte +0 -24
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte.d.ts +0 -11
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte +0 -105
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts +0 -42
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte +0 -84
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte.d.ts +0 -14
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte +0 -44
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte.d.ts +0 -9
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/mic-keyboard-a11y.test.js +0 -74
- package/dist/components/forms/__tests__/policy-field.fixture.svelte +0 -35
- package/dist/components/forms/__tests__/policy-field.fixture.svelte.d.ts +0 -8
- package/dist/components/forms/__tests__/policy-field.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/rich-inputs-a11y.test.js +0 -87
- package/dist/components/settings/__tests__/SettingsCatalog.test.js +0 -69
- package/dist/components/settings/__tests__/catalog.test.js +0 -46
- package/dist/components/workspace/__tests__/AdminShell.responsive.test.js +0 -597
- package/dist/components/workspace/__tests__/AdminShell.test.js +0 -572
- package/dist/components/workspace/__tests__/RoleShell.test.js +0 -772
- package/dist/components/workspace/__tests__/TenantNav.test.js +0 -208
- package/dist/components/workspace/__tests__/WorkspaceAccountMenu.test.js +0 -79
- package/dist/components/workspace/__tests__/WorkspaceShell.test.js +0 -630
- package/dist/components/workspace/__tests__/admin-shell-header-overflow.test.js +0 -25
- package/dist/components/workspace/__tests__/admin-shell-hotkeys.test.js +0 -34
- package/dist/components/workspace/__tests__/admin-shell-mobile.test.js +0 -217
- package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte +0 -52
- package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte.d.ts +0 -23
- package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/admin-shell-page-contracts.test.js +0 -30
- package/dist/components/workspace/__tests__/admin-shell-responsive-state.test.js +0 -184
- package/dist/components/workspace/__tests__/admin-shell-settings.test.js +0 -25
- package/dist/components/workspace/__tests__/admin-shell-state.test.js +0 -286
- package/dist/components/workspace/__tests__/admin-shell-theme-hooks.test.js +0 -36
- package/dist/components/workspace/__tests__/breadcrumbs-helpers.test.js +0 -141
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte +0 -45
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts +0 -21
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/define-tools-dock.test.js +0 -1188
- package/dist/components/workspace/__tests__/harness.svelte +0 -25
- package/dist/components/workspace/__tests__/harness.svelte.d.ts +0 -14
- package/dist/components/workspace/__tests__/harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/index.test.js +0 -28
- package/dist/components/workspace/__tests__/legacy-index.test.js +0 -9
- package/dist/components/workspace/__tests__/manifest-nav-helpers.test.js +0 -24
- package/dist/components/workspace/__tests__/manifest-nav.test.js +0 -599
- package/dist/components/workspace/__tests__/nav-helpers.test.js +0 -95
- package/dist/components/workspace/__tests__/render-harness.svelte +0 -66
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts +0 -32
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/render-tools-dock.test.js +0 -260
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte +0 -58
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts +0 -16
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte +0 -41
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts +0 -13
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/shell-chrome-components.test.js +0 -108
- package/dist/components/workspace/__tests__/system-feed.test.js +0 -327
- package/dist/components/workspace/__tests__/test-icon.svelte +0 -17
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts +0 -19
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte +0 -38
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts +0 -22
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts +0 -66
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.js +0 -115
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts +0 -15
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.js +0 -7
- package/dist/components/workspace/__tests__/typed-tool-fixture.test.js +0 -115
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte +0 -9
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts +0 -19
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/use-harness.svelte +0 -23
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts +0 -8
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/use-tools-dock.test.js +0 -33
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte +0 -43
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts +0 -11
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/server/__tests__/compose-availability.test.js +0 -383
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts +0 -78
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts.map +0 -1
- package/dist/components/workspace/server/__tests__/typed-context-fixture.js +0 -104
- package/dist/hooks/__tests__/stt-consumer.fixture.svelte +0 -25
- package/dist/hooks/__tests__/stt-consumer.fixture.svelte.d.ts +0 -15
- package/dist/hooks/__tests__/stt-consumer.fixture.svelte.d.ts.map +0 -1
- package/dist/hooks/__tests__/stt-ownership-harness.svelte +0 -42
- package/dist/hooks/__tests__/stt-ownership-harness.svelte.d.ts +0 -20
- package/dist/hooks/__tests__/stt-ownership-harness.svelte.d.ts.map +0 -1
- package/dist/hooks/__tests__/useSTT-ownership.test.js +0 -102
- package/dist/i18n/__tests__/server.spec.js +0 -57
- package/dist/internal/logger.test.js +0 -54
- package/dist/provider-mode.test.js +0 -86
- package/dist/provider-webmcp.test.js +0 -244
- package/dist/state/__tests__/app-state-ai-lifecycle.test.js +0 -240
- package/dist/state/__tests__/warm-clients.test.js +0 -40
- package/dist/web/__tests__/activity-feed-harness.svelte +0 -32
- package/dist/web/__tests__/activity-feed-harness.svelte.d.ts +0 -18
- package/dist/web/__tests__/activity-feed-harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/activity-feed.integration.svelte.test.js +0 -190
- package/dist/web/__tests__/activity-feed.svelte.test.js +0 -235
- package/dist/web/__tests__/assistant-dock.integration.svelte.test.js +0 -204
- package/dist/web/__tests__/data-surface-conformance.integration.svelte.test.js +0 -1392
- package/dist/web/__tests__/harness.svelte +0 -25
- package/dist/web/__tests__/harness.svelte.d.ts +0 -15
- package/dist/web/__tests__/harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/list-data-surface.fixture.svelte +0 -59
- package/dist/web/__tests__/list-data-surface.fixture.svelte.d.ts +0 -14
- package/dist/web/__tests__/list-data-surface.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/list-data-surface.svelte.test.js +0 -106
- package/dist/web/__tests__/list-data-surface.test.js +0 -651
- package/dist/web/__tests__/list-sort-surface.fixture.svelte +0 -41
- package/dist/web/__tests__/list-sort-surface.fixture.svelte.d.ts +0 -15
- package/dist/web/__tests__/list-sort-surface.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/list-sort-surface.svelte.test.js +0 -59
- package/dist/web/__tests__/live-collection.svelte.test.js +0 -185
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte +0 -43
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte.d.ts +0 -13
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/provider-ui-registry.test.js +0 -235
- package/dist/web/__tests__/remote-query-harness.svelte +0 -27
- package/dist/web/__tests__/remote-query-harness.svelte.d.ts +0 -11
- package/dist/web/__tests__/remote-query-harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/remote-query.svelte.test.js +0 -101
- package/dist/web/__tests__/surfaces.child.fixture.svelte +0 -69
- package/dist/web/__tests__/surfaces.child.fixture.svelte.d.ts +0 -16
- package/dist/web/__tests__/surfaces.child.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/surfaces.fixture.svelte +0 -26
- package/dist/web/__tests__/surfaces.fixture.svelte.d.ts +0 -18
- package/dist/web/__tests__/surfaces.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/surfaces.svelte.test.js +0 -140
- package/dist/web/__tests__/update-available-harness.svelte +0 -46
- package/dist/web/__tests__/update-available-harness.svelte.d.ts +0 -22
- package/dist/web/__tests__/update-available-harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/update-available.svelte.test.js +0 -137
- package/dist/web/__tests__/view-intent-provider.fixture.svelte +0 -28
- package/dist/web/__tests__/view-intent-provider.fixture.svelte.d.ts +0 -13
- package/dist/web/__tests__/view-intent-provider.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/view-intent.fixture.svelte +0 -33
- package/dist/web/__tests__/view-intent.fixture.svelte.d.ts +0 -15
- package/dist/web/__tests__/view-intent.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/view-intent.intents.d.ts +0 -14
- package/dist/web/__tests__/view-intent.intents.d.ts.map +0 -1
- package/dist/web/__tests__/view-intent.intents.js +0 -38
- package/dist/web/__tests__/view-intent.svelte.test.js +0 -244
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte +0 -73
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts +0 -8
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-composed.fixture.svelte +0 -52
- package/dist/web/__tests__/webmcp-composed.fixture.svelte.d.ts +0 -12
- package/dist/web/__tests__/webmcp-composed.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-composed.integration.svelte.test.js +0 -251
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte +0 -16
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte.d.ts +0 -19
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte +0 -11
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte.d.ts +0 -8
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte +0 -20
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte.d.ts +0 -7
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte +0 -14
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte.d.ts +0 -19
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-harness.svelte +0 -18
- package/dist/web/__tests__/webmcp-harness.svelte.d.ts +0 -7
- package/dist/web/__tests__/webmcp-harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte +0 -13
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte.d.ts +0 -19
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-ui.test.js +0 -723
- package/dist/web/__tests__/webmcp.test.js +0 -234
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `bitgpu` inference backend.
|
|
3
|
-
*
|
|
4
|
-
* Beyond the sibling WebLLM suite's invariants, these three are what make this
|
|
5
|
-
* backend worth having:
|
|
6
|
-
*
|
|
7
|
-
* 1. **`signal` is forwarded.** bitgpu is the only backend in this package that
|
|
8
|
-
* can abort a live generation, so losing the option would make the one
|
|
9
|
-
* cancellation-capable path behave like the ones that cannot cancel.
|
|
10
|
-
* 2. **A turn before `load()` fails with a named reason.** These weights run from
|
|
11
|
-
* hundreds of MB to multiple GB; an implicit download behind the first turn is
|
|
12
|
-
* the failure this refuses to have.
|
|
13
|
-
* 3. **Progress maps onto the mirrored shape**, so `DownloadProgress` renders it
|
|
14
|
-
* without acquiring a second vocabulary.
|
|
15
|
-
*/
|
|
16
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
17
|
-
import { createBitGpuInferenceBackend, } from './bitgpu-inference-backend.js';
|
|
18
|
-
const originalNavigator = Object.getOwnPropertyDescriptor(globalThis, 'navigator');
|
|
19
|
-
/** jsdom has no `navigator.gpu`; detectCapabilities keys off `'gpu' in navigator`. */
|
|
20
|
-
function withWebGpu() {
|
|
21
|
-
Object.defineProperty(globalThis, 'navigator', {
|
|
22
|
-
value: { ...globalThis.navigator, gpu: {} },
|
|
23
|
-
configurable: true,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
function makeModules() {
|
|
27
|
-
let onProgress;
|
|
28
|
-
let engineFailure = null;
|
|
29
|
-
let markEngineReady = () => { };
|
|
30
|
-
const whenEngineReady = new Promise((resolve) => {
|
|
31
|
-
markEngineReady = resolve;
|
|
32
|
-
});
|
|
33
|
-
const d = {
|
|
34
|
-
engineCalls: 0,
|
|
35
|
-
chatCalls: 0,
|
|
36
|
-
sends: [],
|
|
37
|
-
streams: [],
|
|
38
|
-
disposed: 0,
|
|
39
|
-
emitProgress: (report) => onProgress?.(report),
|
|
40
|
-
failEngine: (error) => {
|
|
41
|
-
engineFailure = error;
|
|
42
|
-
},
|
|
43
|
-
streamDeltas: ['Hel', 'lo'],
|
|
44
|
-
finishReason: 'stop',
|
|
45
|
-
whenEngineReady,
|
|
46
|
-
};
|
|
47
|
-
const engine = {
|
|
48
|
-
dispose() {
|
|
49
|
-
d.disposed += 1;
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
// Typed as the interfaces the backend declares, so the compiler checks the
|
|
53
|
-
// double rather than a cast asserting it.
|
|
54
|
-
const bitgpu = {
|
|
55
|
-
async createEngine(options) {
|
|
56
|
-
d.engineCalls += 1;
|
|
57
|
-
if (engineFailure)
|
|
58
|
-
throw engineFailure;
|
|
59
|
-
onProgress = typeof options === 'string' ? undefined : options.onProgress;
|
|
60
|
-
markEngineReady();
|
|
61
|
-
return engine;
|
|
62
|
-
},
|
|
63
|
-
WebGPUUnavailableError: class extends Error {
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
const chatModule = {
|
|
67
|
-
async createChat() {
|
|
68
|
-
d.chatCalls += 1;
|
|
69
|
-
return {
|
|
70
|
-
async send(messages, options) {
|
|
71
|
-
d.sends.push({ messages, options });
|
|
72
|
-
return { text: 'reply', finishReason: d.finishReason };
|
|
73
|
-
},
|
|
74
|
-
async *stream(messages, options) {
|
|
75
|
-
d.streams.push({ messages, options });
|
|
76
|
-
for (const delta of d.streamDeltas)
|
|
77
|
-
yield delta;
|
|
78
|
-
return {
|
|
79
|
-
text: d.streamDeltas.join(''),
|
|
80
|
-
finishReason: d.finishReason,
|
|
81
|
-
};
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
return {
|
|
87
|
-
options: {
|
|
88
|
-
loadBitGpu: async () => bitgpu,
|
|
89
|
-
loadChat: async () => chatModule,
|
|
90
|
-
},
|
|
91
|
-
d,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
async function expectPathError(run, code) {
|
|
95
|
-
const error = await run().then(() => undefined, (thrown) => thrown);
|
|
96
|
-
expect(error).toMatchObject({ name: 'InferencePathError', code });
|
|
97
|
-
}
|
|
98
|
-
const USER = [{ role: 'user', content: 'hi' }];
|
|
99
|
-
describe('createBitGpuInferenceBackend', () => {
|
|
100
|
-
beforeEach(() => {
|
|
101
|
-
Object.defineProperty(globalThis, 'navigator', {
|
|
102
|
-
value: { ...globalThis.navigator },
|
|
103
|
-
configurable: true,
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
afterEach(() => {
|
|
107
|
-
if (originalNavigator) {
|
|
108
|
-
Object.defineProperty(globalThis, 'navigator', originalNavigator);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
it('reports unavailable without WebGPU', () => {
|
|
112
|
-
const { options } = makeModules();
|
|
113
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
114
|
-
expect(backend.status).toBe('unavailable');
|
|
115
|
-
expect(backend.kind).toBe('local');
|
|
116
|
-
});
|
|
117
|
-
it('refuses to load without WebGPU rather than starting a doomed download', async () => {
|
|
118
|
-
const { options, d } = makeModules();
|
|
119
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
120
|
-
await expectPathError(() => backend.load(), 'no_usable_backend');
|
|
121
|
-
expect(d.engineCalls).toBe(0);
|
|
122
|
-
});
|
|
123
|
-
it('reports idle before load and ready after', async () => {
|
|
124
|
-
withWebGpu();
|
|
125
|
-
const { options } = makeModules();
|
|
126
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
127
|
-
expect(backend.status).toBe('idle');
|
|
128
|
-
await backend.load();
|
|
129
|
-
expect(backend.status).toBe('ready');
|
|
130
|
-
});
|
|
131
|
-
it('reports loading before the first await resolves', () => {
|
|
132
|
-
withWebGpu();
|
|
133
|
-
const { options } = makeModules();
|
|
134
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
135
|
-
// `idle` is the state auto-selection is told to skip, so the window between
|
|
136
|
-
// clicking Load and the engine resolving must not report it.
|
|
137
|
-
void backend.load();
|
|
138
|
-
expect(backend.status).toBe('loading');
|
|
139
|
-
});
|
|
140
|
-
it('maps a bytes report onto the mirrored progress shape', async () => {
|
|
141
|
-
withWebGpu();
|
|
142
|
-
const { options, d } = makeModules();
|
|
143
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
144
|
-
const seen = [];
|
|
145
|
-
const load = backend.load((p) => seen.push(p));
|
|
146
|
-
await d.whenEngineReady;
|
|
147
|
-
d.emitProgress({ phase: 'weights', loaded: 50, total: 200 });
|
|
148
|
-
expect(backend.progress).toMatchObject({
|
|
149
|
-
state: 'downloading',
|
|
150
|
-
bytesLoaded: 50,
|
|
151
|
-
bytesTotal: 200,
|
|
152
|
-
percent: 25,
|
|
153
|
-
currentFile: 'weights',
|
|
154
|
-
});
|
|
155
|
-
await load;
|
|
156
|
-
expect(seen[0]).toMatchObject({ percent: 25 });
|
|
157
|
-
// Cleared once the model is usable.
|
|
158
|
-
expect(backend.progress).toBeUndefined();
|
|
159
|
-
});
|
|
160
|
-
it('reports the pipeline phase as unpacking, without inventing a percent', async () => {
|
|
161
|
-
withWebGpu();
|
|
162
|
-
const { options, d } = makeModules();
|
|
163
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
164
|
-
const load = backend.load();
|
|
165
|
-
await d.whenEngineReady;
|
|
166
|
-
d.emitProgress({ phase: 'pipelines' });
|
|
167
|
-
expect(backend.progress).toMatchObject({ state: 'extracting', percent: 0 });
|
|
168
|
-
await load;
|
|
169
|
-
});
|
|
170
|
-
it('reports error status and the failure when a load rejects', async () => {
|
|
171
|
-
withWebGpu();
|
|
172
|
-
const { options, d } = makeModules();
|
|
173
|
-
d.failEngine(new Error('out of GPU memory'));
|
|
174
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
175
|
-
await expect(backend.load()).rejects.toThrow('out of GPU memory');
|
|
176
|
-
expect(backend.status).toBe('error');
|
|
177
|
-
expect(backend.progress).toMatchObject({
|
|
178
|
-
state: 'error',
|
|
179
|
-
error: 'out of GPU memory',
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
it('re-enters on a retry after a failed load', async () => {
|
|
183
|
-
withWebGpu();
|
|
184
|
-
const { options, d } = makeModules();
|
|
185
|
-
d.failEngine(new Error('transient'));
|
|
186
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
187
|
-
await expect(backend.load()).rejects.toThrow('transient');
|
|
188
|
-
d.failEngine(null);
|
|
189
|
-
await backend.load();
|
|
190
|
-
// The second attempt must start a new engine, not replay the rejection.
|
|
191
|
-
expect(d.engineCalls).toBe(2);
|
|
192
|
-
expect(backend.status).toBe('ready');
|
|
193
|
-
});
|
|
194
|
-
it('shares one load between concurrent callers', async () => {
|
|
195
|
-
withWebGpu();
|
|
196
|
-
const { options, d } = makeModules();
|
|
197
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
198
|
-
await Promise.all([backend.load(), backend.load(), backend.load()]);
|
|
199
|
-
expect(d.engineCalls).toBe(1);
|
|
200
|
-
});
|
|
201
|
-
it('is a no-op when the engine is already ready', async () => {
|
|
202
|
-
withWebGpu();
|
|
203
|
-
const { options, d } = makeModules();
|
|
204
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
205
|
-
await backend.load();
|
|
206
|
-
expect(d.engineCalls).toBe(1);
|
|
207
|
-
// `load` is documented as a no-op when already ready. A second call that
|
|
208
|
-
// re-entered would fetch the weights again and orphan the live engine,
|
|
209
|
-
// since nothing disposes the reference it replaces.
|
|
210
|
-
await backend.load();
|
|
211
|
-
expect(d.engineCalls).toBe(1);
|
|
212
|
-
expect(d.chatCalls).toBe(1);
|
|
213
|
-
expect(d.disposed).toBe(0);
|
|
214
|
-
expect(backend.status).toBe('ready');
|
|
215
|
-
});
|
|
216
|
-
it('retries after a loader that throws synchronously', async () => {
|
|
217
|
-
withWebGpu();
|
|
218
|
-
const { options } = makeModules();
|
|
219
|
-
let failing = true;
|
|
220
|
-
const backend = createBitGpuInferenceBackend({
|
|
221
|
-
...options,
|
|
222
|
-
loadBitGpu: () => {
|
|
223
|
-
// Synchronous, not a rejected promise: legal for the declared
|
|
224
|
-
// `() => Promise<BitGpuModule>` and what an absent module shim does.
|
|
225
|
-
if (failing)
|
|
226
|
-
throw new Error('bitgpu is not installed');
|
|
227
|
-
return options.loadBitGpu();
|
|
228
|
-
},
|
|
229
|
-
});
|
|
230
|
-
await expect(backend.load()).rejects.toThrow('bitgpu is not installed');
|
|
231
|
-
expect(backend.status).toBe('error');
|
|
232
|
-
failing = false;
|
|
233
|
-
await backend.load();
|
|
234
|
-
// A synchronous throw settles the load body before it is stored, so a
|
|
235
|
-
// cached rejection here would replay on every later attempt.
|
|
236
|
-
expect(backend.status).toBe('ready');
|
|
237
|
-
});
|
|
238
|
-
it('discards a load that overlaps an unload', async () => {
|
|
239
|
-
withWebGpu();
|
|
240
|
-
const { options, d } = makeModules();
|
|
241
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
242
|
-
const pending = backend.load();
|
|
243
|
-
await backend.unload();
|
|
244
|
-
await pending;
|
|
245
|
-
// Publishing the engine here would report `ready` with a live GPU device
|
|
246
|
-
// nothing disposes, and a later `load()` would no-op on it.
|
|
247
|
-
expect(backend.status).toBe('idle');
|
|
248
|
-
expect(d.disposed).toBe(1);
|
|
249
|
-
});
|
|
250
|
-
it('stays idle when a load rejects after an unload', async () => {
|
|
251
|
-
withWebGpu();
|
|
252
|
-
const { options, d } = makeModules();
|
|
253
|
-
d.failEngine(new Error('out of GPU memory'));
|
|
254
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
255
|
-
const pending = backend.load();
|
|
256
|
-
await backend.unload();
|
|
257
|
-
await expect(pending).rejects.toThrow('out of GPU memory');
|
|
258
|
-
// The caller cancelled the work, so the backend must not report an error
|
|
259
|
-
// for it — and `unload()` already cleared any prior failure.
|
|
260
|
-
expect(backend.status).toBe('idle');
|
|
261
|
-
expect(backend.progress).toBeUndefined();
|
|
262
|
-
});
|
|
263
|
-
it('starts real work when load() follows an unload', async () => {
|
|
264
|
-
withWebGpu();
|
|
265
|
-
const { options, d } = makeModules();
|
|
266
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
267
|
-
const discarded = backend.load();
|
|
268
|
-
await backend.unload();
|
|
269
|
-
// Issued while the discarded attempt is still pending: handing back that
|
|
270
|
-
// attempt's promise would resolve this call without loading anything.
|
|
271
|
-
const second = backend.load();
|
|
272
|
-
await Promise.all([discarded, second]);
|
|
273
|
-
expect(d.engineCalls).toBe(2);
|
|
274
|
-
expect(backend.status).toBe('ready');
|
|
275
|
-
});
|
|
276
|
-
it('disposes the engine it created when createChat fails', async () => {
|
|
277
|
-
withWebGpu();
|
|
278
|
-
const { options, d } = makeModules();
|
|
279
|
-
const backend = createBitGpuInferenceBackend({
|
|
280
|
-
...options,
|
|
281
|
-
// The tokenizer comes from a different host than the manifest, so a
|
|
282
|
-
// failing `createChat` is the documented real failure after the engine
|
|
283
|
-
// already exists.
|
|
284
|
-
loadChat: async () => ({
|
|
285
|
-
async createChat() {
|
|
286
|
-
throw new Error('tokenizer 404');
|
|
287
|
-
},
|
|
288
|
-
}),
|
|
289
|
-
});
|
|
290
|
-
await expect(backend.load()).rejects.toThrow('tokenizer 404');
|
|
291
|
-
// Nothing else holds the engine, so the abandoned attempt must release it —
|
|
292
|
-
// otherwise every retry allocates another GPU device over the leaked one.
|
|
293
|
-
expect(d.disposed).toBe(1);
|
|
294
|
-
expect(backend.status).toBe('error');
|
|
295
|
-
});
|
|
296
|
-
it('keeps the load failure when the teardown throws', async () => {
|
|
297
|
-
withWebGpu();
|
|
298
|
-
const { options } = makeModules();
|
|
299
|
-
const backend = createBitGpuInferenceBackend({
|
|
300
|
-
...options,
|
|
301
|
-
loadBitGpu: async () => ({
|
|
302
|
-
async createEngine() {
|
|
303
|
-
return {
|
|
304
|
-
dispose() {
|
|
305
|
-
throw new Error('device lost');
|
|
306
|
-
},
|
|
307
|
-
};
|
|
308
|
-
},
|
|
309
|
-
WebGPUUnavailableError: class extends Error {
|
|
310
|
-
},
|
|
311
|
-
}),
|
|
312
|
-
loadChat: async () => ({
|
|
313
|
-
async createChat() {
|
|
314
|
-
throw new Error('tokenizer 404');
|
|
315
|
-
},
|
|
316
|
-
}),
|
|
317
|
-
});
|
|
318
|
-
// The teardown runs while abandoning the attempt; its own error must not
|
|
319
|
-
// replace the failure the caller is owed, nor skip recording it.
|
|
320
|
-
await expect(backend.load()).rejects.toThrow('tokenizer 404');
|
|
321
|
-
expect(backend.status).toBe('error');
|
|
322
|
-
});
|
|
323
|
-
it('refuses a turn before load, naming what is missing', async () => {
|
|
324
|
-
withWebGpu();
|
|
325
|
-
const { options, d } = makeModules();
|
|
326
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
327
|
-
await expectPathError(() => backend.chat([...USER]), 'no_usable_backend');
|
|
328
|
-
expect(d.sends).toEqual([]);
|
|
329
|
-
});
|
|
330
|
-
it('forwards messages and options, and maps the result', async () => {
|
|
331
|
-
withWebGpu();
|
|
332
|
-
const { options, d } = makeModules();
|
|
333
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
334
|
-
await backend.load();
|
|
335
|
-
const response = await backend.chat([...USER], {
|
|
336
|
-
maxTokens: 64,
|
|
337
|
-
temperature: 0.4,
|
|
338
|
-
topP: 0.9,
|
|
339
|
-
stop: 'END',
|
|
340
|
-
});
|
|
341
|
-
expect(d.sends[0].messages).toEqual([{ role: 'user', content: 'hi' }]);
|
|
342
|
-
expect(d.sends[0].options).toMatchObject({
|
|
343
|
-
maxTokens: 64,
|
|
344
|
-
temperature: 0.4,
|
|
345
|
-
topP: 0.9,
|
|
346
|
-
// bitgpu takes an array of stop sequences; a scalar is normalized.
|
|
347
|
-
stopSequences: ['END'],
|
|
348
|
-
});
|
|
349
|
-
expect(response).toEqual({ content: 'reply', finishReason: 'stop' });
|
|
350
|
-
});
|
|
351
|
-
it('omits an abort finish reason the mirrored response has no member for', async () => {
|
|
352
|
-
withWebGpu();
|
|
353
|
-
const { options, d } = makeModules();
|
|
354
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
355
|
-
await backend.load();
|
|
356
|
-
d.finishReason = 'abort';
|
|
357
|
-
// `AIResponse.finishReason` has no `'abort'` member — a completed response
|
|
358
|
-
// simply carries none rather than inventing one.
|
|
359
|
-
await expect(backend.chat([...USER])).resolves.toEqual({
|
|
360
|
-
content: 'reply',
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
it('forwards the caller signal — the one thing WebLLM cannot do', async () => {
|
|
364
|
-
withWebGpu();
|
|
365
|
-
const { options, d } = makeModules();
|
|
366
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
367
|
-
await backend.load();
|
|
368
|
-
const controller = new AbortController();
|
|
369
|
-
for await (const _chunk of backend.stream([...USER], {
|
|
370
|
-
signal: controller.signal,
|
|
371
|
-
})) {
|
|
372
|
-
/* drain */
|
|
373
|
-
}
|
|
374
|
-
expect(d.streams[0].options).toMatchObject({ signal: controller.signal });
|
|
375
|
-
});
|
|
376
|
-
it('turns a timeout into a signal the engine can abort on', async () => {
|
|
377
|
-
withWebGpu();
|
|
378
|
-
const { options, d } = makeModules();
|
|
379
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
380
|
-
await backend.load();
|
|
381
|
-
// bitgpu is the only local backend that can cancel, so a deadline must
|
|
382
|
-
// reach the engine rather than being silently dropped.
|
|
383
|
-
await backend.chat([...USER], { timeout: 5_000 });
|
|
384
|
-
const sent = d.sends.at(-1)?.options;
|
|
385
|
-
expect(sent?.signal).toBeInstanceOf(AbortSignal);
|
|
386
|
-
});
|
|
387
|
-
it('streams deltas in order and reports each to onProgress', async () => {
|
|
388
|
-
withWebGpu();
|
|
389
|
-
const { options } = makeModules();
|
|
390
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
391
|
-
await backend.load();
|
|
392
|
-
const onProgress = vi.fn();
|
|
393
|
-
const chunks = [];
|
|
394
|
-
for await (const chunk of backend.stream([...USER], { onProgress })) {
|
|
395
|
-
chunks.push(chunk);
|
|
396
|
-
}
|
|
397
|
-
expect(chunks).toEqual(['Hel', 'lo']);
|
|
398
|
-
expect(onProgress.mock.calls).toEqual([['Hel'], ['lo']]);
|
|
399
|
-
});
|
|
400
|
-
it('refuses tool definitions and tool turns, like every other backend', async () => {
|
|
401
|
-
withWebGpu();
|
|
402
|
-
const { options, d } = makeModules();
|
|
403
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
404
|
-
await backend.load();
|
|
405
|
-
// bitgpu supports tools, but exposing them here would mean a per-call switch
|
|
406
|
-
// changes what a turn means: the other backends refuse these.
|
|
407
|
-
await expectPathError(() => backend.chat([...USER], {
|
|
408
|
-
tools: [{ type: 'function', function: { name: 'product_list' } }],
|
|
409
|
-
}), 'unsupported_message');
|
|
410
|
-
await expectPathError(() => backend.chat([
|
|
411
|
-
{
|
|
412
|
-
role: 'assistant',
|
|
413
|
-
content: '',
|
|
414
|
-
tool_calls: [
|
|
415
|
-
{
|
|
416
|
-
id: 'c1',
|
|
417
|
-
type: 'function',
|
|
418
|
-
function: { name: 'x', arguments: '{}' },
|
|
419
|
-
},
|
|
420
|
-
],
|
|
421
|
-
},
|
|
422
|
-
]), 'unsupported_message');
|
|
423
|
-
expect(d.sends).toEqual([]);
|
|
424
|
-
});
|
|
425
|
-
it('disposes the engine and returns to idle on unload', async () => {
|
|
426
|
-
withWebGpu();
|
|
427
|
-
const { options, d } = makeModules();
|
|
428
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
429
|
-
await backend.load();
|
|
430
|
-
await backend.unload();
|
|
431
|
-
expect(d.disposed).toBe(1);
|
|
432
|
-
expect(backend.status).toBe('idle');
|
|
433
|
-
expect(backend.progress).toBeUndefined();
|
|
434
|
-
});
|
|
435
|
-
it('refuses a turn after unload', async () => {
|
|
436
|
-
withWebGpu();
|
|
437
|
-
const { options } = makeModules();
|
|
438
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
439
|
-
await backend.load();
|
|
440
|
-
await backend.unload();
|
|
441
|
-
await expectPathError(() => backend.chat([...USER]), 'no_usable_backend');
|
|
442
|
-
});
|
|
443
|
-
it('notifies subscribers on each status change', async () => {
|
|
444
|
-
withWebGpu();
|
|
445
|
-
const { options } = makeModules();
|
|
446
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
447
|
-
const listener = vi.fn();
|
|
448
|
-
const unsubscribe = backend.subscribe(listener);
|
|
449
|
-
await backend.load();
|
|
450
|
-
await backend.unload();
|
|
451
|
-
// Three status changes: idle→loading, loading→ready, ready→idle.
|
|
452
|
-
expect(listener).toHaveBeenCalledTimes(3);
|
|
453
|
-
unsubscribe();
|
|
454
|
-
});
|
|
455
|
-
it('stops notifying after unsubscribe', async () => {
|
|
456
|
-
withWebGpu();
|
|
457
|
-
const { options } = makeModules();
|
|
458
|
-
const backend = createBitGpuInferenceBackend(options);
|
|
459
|
-
const listener = vi.fn();
|
|
460
|
-
backend.subscribe(listener)();
|
|
461
|
-
await backend.load();
|
|
462
|
-
expect(listener).not.toHaveBeenCalled();
|
|
463
|
-
});
|
|
464
|
-
});
|