@kitn.ai/ui 0.28.0 → 0.29.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/README.md +1 -1
- package/dist/agent-tooling/construct/public.d.ts +15 -0
- package/dist/agent-tooling/construct/schema.d.ts +111 -0
- package/dist/construct-cli.es.js +3 -3
- package/dist/construct.d.ts +5 -0
- package/dist/construct.js +327 -0
- package/dist/core-C8fzo39E.js +1 -12
- package/dist/engine-javascript-C1x7zo1_.js +1 -141
- package/dist/mcp.es.js +1 -1
- package/package.json +16 -16
- package/bin/route.test.js +0 -58
- package/src/agent-tooling/README.md +0 -192
- package/src/agent-tooling/archetypes.ts +0 -205
- package/src/agent-tooling/catalog/README.md +0 -676
- package/src/agent-tooling/catalog/catalog-types.ts +0 -231
- package/src/agent-tooling/catalog/fabrications.ts +0 -96
- package/src/agent-tooling/catalog/invariants.ts +0 -284
- package/src/agent-tooling/catalog/labs-titles.ts +0 -114
- package/src/agent-tooling/catalog/scenarios.ts +0 -87
- package/src/agent-tooling/catalog/surfaces.ts +0 -347
- package/src/agent-tooling/construct/cli-entry.ts +0 -8
- package/src/agent-tooling/construct/cli.ts +0 -147
- package/src/agent-tooling/construct/codegen.ts +0 -1635
- package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
- package/src/agent-tooling/construct/dev.ts +0 -148
- package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
- package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
- package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
- package/src/agent-tooling/construct/schema.ts +0 -452
- package/src/agent-tooling/integrations/anthropic.ts +0 -442
- package/src/agent-tooling/integrations/cloudflare.ts +0 -218
- package/src/agent-tooling/integrations/langgraph.ts +0 -133
- package/src/agent-tooling/integrations/mastra.ts +0 -182
- package/src/agent-tooling/integrations/mock.ts +0 -148
- package/src/agent-tooling/integrations/ollama.ts +0 -97
- package/src/agent-tooling/integrations/openai.ts +0 -95
- package/src/agent-tooling/integrations/openrouter.ts +0 -82
- package/src/agent-tooling/integrations/pi.ts +0 -176
- package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
- package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
- package/src/agent-tooling/mcp/manifest.ts +0 -422
- package/src/agent-tooling/mcp/server.ts +0 -116
- package/src/agent-tooling/mcp/stdio.ts +0 -18
- package/src/agent-tooling/mcp/tools/construct.ts +0 -130
- package/src/agent-tooling/mcp/tools/debug.ts +0 -621
- package/src/agent-tooling/mcp/tools/reference.ts +0 -980
- package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
- package/src/agent-tooling/mcp/tools/theme.ts +0 -456
- package/src/agent-tooling/mcp/tools/types.ts +0 -14
- package/src/agent-tooling/mcp/validate-args.ts +0 -141
- package/src/agent-tooling/recipes/composed-thread.ts +0 -714
- package/src/agent-tooling/recipes/index.ts +0 -22
- package/src/agent-tooling/recipes/types.ts +0 -32
- package/src/agent-tooling/registry.ts +0 -132
- package/src/agent-tooling/route-emit.ts +0 -305
- package/src/agent-tooling/types.ts +0 -390
- package/src/components/artifact-card.tsx +0 -120
- package/src/components/artifact.tsx +0 -914
- package/src/components/attachment-types.ts +0 -66
- package/src/components/attachments.tsx +0 -536
- package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
- package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
- package/src/components/audio-visualizer/fit-scale.ts +0 -112
- package/src/components/audio-visualizer/index.tsx +0 -528
- package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
- package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
- package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
- package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
- package/src/components/audio-visualizer/sizes.ts +0 -54
- package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
- package/src/components/audio-visualizer/variant-bar.tsx +0 -175
- package/src/components/audio-visualizer/variant-custom.tsx +0 -344
- package/src/components/audio-visualizer/variant-grid.tsx +0 -175
- package/src/components/audio-visualizer/variant-radial.tsx +0 -163
- package/src/components/audio-visualizer/variant-wave.tsx +0 -130
- package/src/components/audio-visualizer/wave.glsl.ts +0 -130
- package/src/components/card-fallback.tsx +0 -60
- package/src/components/card-renderer.tsx +0 -220
- package/src/components/card.tsx +0 -212
- package/src/components/chain-of-thought.tsx +0 -348
- package/src/components/chat-container.tsx +0 -89
- package/src/components/chat-scope-picker.tsx +0 -57
- package/src/components/chat-thread.tsx +0 -1014
- package/src/components/checkpoint.tsx +0 -88
- package/src/components/choice-card.tsx +0 -743
- package/src/components/coachmark.tsx +0 -249
- package/src/components/code-block.tsx +0 -181
- package/src/components/composer-dom.ts +0 -159
- package/src/components/composer-highlight.ts +0 -242
- package/src/components/composer-history.ts +0 -82
- package/src/components/composer.tsx +0 -1075
- package/src/components/confirm-card.tsx +0 -402
- package/src/components/context.tsx +0 -377
- package/src/components/conversation-item.tsx +0 -241
- package/src/components/conversation-list.tsx +0 -429
- package/src/components/conversation-panel.tsx +0 -118
- package/src/components/dismissed-stub.tsx +0 -80
- package/src/components/embed.tsx +0 -200
- package/src/components/empty.tsx +0 -177
- package/src/components/feedback-bar.tsx +0 -166
- package/src/components/file-tree.tsx +0 -530
- package/src/components/file-upload.tsx +0 -167
- package/src/components/form-widgets.tsx +0 -525
- package/src/components/form.tsx +0 -1296
- package/src/components/home-panel.tsx +0 -159
- package/src/components/image.tsx +0 -65
- package/src/components/link-preview.tsx +0 -195
- package/src/components/loader.tsx +0 -367
- package/src/components/markdown.tsx +0 -162
- package/src/components/message-skills.tsx +0 -40
- package/src/components/message.tsx +0 -765
- package/src/components/model-switcher.tsx +0 -132
- package/src/components/prompt-input.tsx +0 -188
- package/src/components/prompt-suggestion.tsx +0 -150
- package/src/components/reasoning.tsx +0 -293
- package/src/components/response-compare-types.ts +0 -152
- package/src/components/response-compare.tsx +0 -455
- package/src/components/response-stream.tsx +0 -109
- package/src/components/screen.tsx +0 -181
- package/src/components/scroll-button.tsx +0 -93
- package/src/components/source.tsx +0 -192
- package/src/components/tasks-card.tsx +0 -801
- package/src/components/text-shimmer.tsx +0 -37
- package/src/components/thinking-bar.tsx +0 -50
- package/src/components/thread.tsx +0 -228
- package/src/components/toast.tsx +0 -503
- package/src/components/tool-classify.ts +0 -26
- package/src/components/tool-types.ts +0 -49
- package/src/components/tool.tsx +0 -190
- package/src/components/use-card-resolution.ts +0 -44
- package/src/components/voice-input.tsx +0 -222
- package/src/components/voice-output.tsx +0 -242
- package/src/components/widget-tab-bar.tsx +0 -73
- package/src/components/workspace-shell.tsx +0 -285
- package/src/diagnostics/hook.ts +0 -352
- package/src/diagnostics/index.ts +0 -82
- package/src/diagnostics/report-request.ts +0 -296
- package/src/elements/agent-card.tsx +0 -67
- package/src/elements/artifact.tsx +0 -194
- package/src/elements/attachments.tsx +0 -140
- package/src/elements/audio-visualizer.tsx +0 -227
- package/src/elements/autoloader.ts +0 -89
- package/src/elements/avatar.tsx +0 -33
- package/src/elements/badge.tsx +0 -32
- package/src/elements/button.tsx +0 -149
- package/src/elements/card.tsx +0 -133
- package/src/elements/cards.tsx +0 -266
- package/src/elements/chain-of-thought.tsx +0 -141
- package/src/elements/chat-scope-picker.tsx +0 -65
- package/src/elements/chat-types.ts +0 -102
- package/src/elements/chat-workspace.tsx +0 -188
- package/src/elements/chat.tsx +0 -304
- package/src/elements/checkbox-group.tsx +0 -164
- package/src/elements/checkbox.tsx +0 -134
- package/src/elements/checkpoint.tsx +0 -47
- package/src/elements/choice.tsx +0 -100
- package/src/elements/coachmark.tsx +0 -90
- package/src/elements/code-block.tsx +0 -60
- package/src/elements/command.tsx +0 -197
- package/src/elements/compare.tsx +0 -111
- package/src/elements/compiled.css +0 -2
- package/src/elements/composer.tsx +0 -162
- package/src/elements/confirm-card.tsx +0 -76
- package/src/elements/context-meter.tsx +0 -107
- package/src/elements/conversation-item.tsx +0 -120
- package/src/elements/conversation-list.tsx +0 -203
- package/src/elements/css.ts +0 -5
- package/src/elements/default-input.tsx +0 -392
- package/src/elements/define-entry.ts +0 -12
- package/src/elements/define.tsx +0 -563
- package/src/elements/diagnostic-events.ts +0 -114
- package/src/elements/dialog.tsx +0 -145
- package/src/elements/disclosure.ts +0 -95
- package/src/elements/dock.tsx +0 -215
- package/src/elements/dropdown.tsx +0 -123
- package/src/elements/editable-label.tsx +0 -140
- package/src/elements/element-data-types.ts +0 -152
- package/src/elements/element-diagnostics.ts +0 -392
- package/src/elements/element-manifest.json +0 -354
- package/src/elements/element-nonscalar.json +0 -187
- package/src/elements/element-types.d.ts +0 -4353
- package/src/elements/embed.tsx +0 -35
- package/src/elements/empty.tsx +0 -29
- package/src/elements/feedback-bar.tsx +0 -66
- package/src/elements/file-tree.tsx +0 -62
- package/src/elements/file-upload.tsx +0 -44
- package/src/elements/form.tsx +0 -94
- package/src/elements/hover-card.tsx +0 -80
- package/src/elements/icon.tsx +0 -41
- package/src/elements/image.tsx +0 -32
- package/src/elements/input.tsx +0 -492
- package/src/elements/kbd.tsx +0 -45
- package/src/elements/link-preview.tsx +0 -34
- package/src/elements/loader.tsx +0 -25
- package/src/elements/markdown.tsx +0 -38
- package/src/elements/menu.tsx +0 -241
- package/src/elements/message-skills.tsx +0 -83
- package/src/elements/message.tsx +0 -361
- package/src/elements/model-switcher.tsx +0 -121
- package/src/elements/nav.tsx +0 -87
- package/src/elements/notice.tsx +0 -53
- package/src/elements/pane-grid.tsx +0 -111
- package/src/elements/pane-group.tsx +0 -119
- package/src/elements/pane.tsx +0 -129
- package/src/elements/popover.tsx +0 -81
- package/src/elements/progress-bar.tsx +0 -39
- package/src/elements/prompt-dock.tsx +0 -82
- package/src/elements/prompt-input.tsx +0 -240
- package/src/elements/prompt-suggestions.tsx +0 -113
- package/src/elements/radio-group.tsx +0 -129
- package/src/elements/reasoning.tsx +0 -71
- package/src/elements/register-impl.ts +0 -148
- package/src/elements/register.ts +0 -76
- package/src/elements/remote.tsx +0 -225
- package/src/elements/resizable.globals.d.ts +0 -36
- package/src/elements/resizable.tsx +0 -704
- package/src/elements/response-stream.tsx +0 -40
- package/src/elements/screen.tsx +0 -90
- package/src/elements/scroll-area.tsx +0 -33
- package/src/elements/scroll-button.tsx +0 -179
- package/src/elements/search.tsx +0 -185
- package/src/elements/segmented.tsx +0 -129
- package/src/elements/select.tsx +0 -165
- package/src/elements/separator.tsx +0 -36
- package/src/elements/setting-item.tsx +0 -50
- package/src/elements/settings-group.tsx +0 -37
- package/src/elements/skeleton.tsx +0 -45
- package/src/elements/slider.tsx +0 -171
- package/src/elements/slot-text.ts +0 -73
- package/src/elements/slots.ts +0 -787
- package/src/elements/source.tsx +0 -126
- package/src/elements/status.tsx +0 -42
- package/src/elements/styles.css +0 -328
- package/src/elements/switch.tsx +0 -118
- package/src/elements/tabs.tsx +0 -95
- package/src/elements/tasks.tsx +0 -103
- package/src/elements/text-shimmer.tsx +0 -28
- package/src/elements/thinking-bar.tsx +0 -43
- package/src/elements/thread.tsx +0 -139
- package/src/elements/toast.tsx +0 -106
- package/src/elements/tool.tsx +0 -78
- package/src/elements/tooltip.tsx +0 -85
- package/src/elements/validate-messages.ts +0 -76
- package/src/elements/voice-input.tsx +0 -100
- package/src/elements/voice-output.tsx +0 -82
- package/src/index.ts +0 -430
- package/src/primitives/audio-bands.ts +0 -174
- package/src/primitives/card-component-types.ts +0 -63
- package/src/primitives/card-contract.ts +0 -80
- package/src/primitives/card-data-types.ts +0 -361
- package/src/primitives/card-host.tsx +0 -37
- package/src/primitives/card-recovery.ts +0 -160
- package/src/primitives/card-registry.tsx +0 -78
- package/src/primitives/card-resolution.ts +0 -36
- package/src/primitives/card-routing.ts +0 -85
- package/src/primitives/card-schemas/artifact.schema.json +0 -92
- package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
- package/src/primitives/card-schemas/card-event.schema.json +0 -12
- package/src/primitives/card-schemas/choice.schema.json +0 -75
- package/src/primitives/card-schemas/confirm.schema.json +0 -65
- package/src/primitives/card-schemas/embed.schema.json +0 -63
- package/src/primitives/card-schemas/form.result.schema.json +0 -7
- package/src/primitives/card-schemas/form.schema.json +0 -53
- package/src/primitives/card-schemas/link.schema.json +0 -54
- package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
- package/src/primitives/card-schemas/tasks.schema.json +0 -83
- package/src/primitives/card-tags.ts +0 -61
- package/src/primitives/card-validate-cards.ts +0 -255
- package/src/primitives/card-validate-schemas.ts +0 -58
- package/src/primitives/card-validate.ts +0 -131
- package/src/primitives/chat-config.tsx +0 -103
- package/src/primitives/composer-model.ts +0 -49
- package/src/primitives/composer-triggers.ts +0 -35
- package/src/primitives/controllable.ts +0 -21
- package/src/primitives/conversation-store.ts +0 -248
- package/src/primitives/create-kai-chat.ts +0 -66
- package/src/primitives/create-tween.ts +0 -266
- package/src/primitives/embed-providers.ts +0 -254
- package/src/primitives/field-mask.ts +0 -256
- package/src/primitives/field-semantics.ts +0 -115
- package/src/primitives/highlighter.ts +0 -157
- package/src/primitives/input-mask.ts +0 -853
- package/src/primitives/link-preview.ts +0 -87
- package/src/primitives/message-feedback.ts +0 -124
- package/src/primitives/pdf-preview.ts +0 -121
- package/src/primitives/toast-store.ts +0 -338
- package/src/primitives/url-scheme-policy.ts +0 -70
- package/src/primitives/use-audio-analysis.ts +0 -340
- package/src/primitives/use-auto-resize.ts +0 -31
- package/src/primitives/use-resize-observer.ts +0 -45
- package/src/primitives/use-sequencer.ts +0 -72
- package/src/primitives/use-speech-recognition.ts +0 -146
- package/src/primitives/use-stick-to-bottom.ts +0 -75
- package/src/primitives/use-text-stream.ts +0 -143
- package/src/primitives/use-voice-recorder.ts +0 -62
- package/src/primitives/visualizer-sequences.ts +0 -350
- package/src/remote/host-embed.ts +0 -345
- package/src/remote/index.ts +0 -2
- package/src/remote/origin.ts +0 -30
- package/src/remote/provider-runtime.ts +0 -262
- package/src/remote/provider.ts +0 -2
- package/src/remote/validate.ts +0 -22
- package/src/remote/version.ts +0 -12
- package/src/remote/wire.ts +0 -48
- package/src/schemas/from-tool-call.ts +0 -151
- package/src/schemas/index.ts +0 -341
- package/src/schemas/provider-subsets.ts +0 -538
- package/src/schemas/registry.ts +0 -355
- package/src/schemas/tool-defs.ts +0 -793
- package/src/solid.ts +0 -173
- package/src/state/index.ts +0 -44
- package/src/state/messages.ts +0 -53
- package/src/state/mock.ts +0 -297
- package/src/state/parts.ts +0 -295
- package/src/state/persistence.ts +0 -180
- package/src/state/stream.ts +0 -246
- package/src/state/suggestions.ts +0 -9
- package/src/state/threads.ts +0 -142
- package/src/test-utils/fake-clock.ts +0 -88
- package/src/types.ts +0 -95
- package/src/ui/action-icons.ts +0 -53
- package/src/ui/agent-card.tsx +0 -218
- package/src/ui/avatar.tsx +0 -23
- package/src/ui/badge.tsx +0 -21
- package/src/ui/button.tsx +0 -49
- package/src/ui/card.tsx +0 -245
- package/src/ui/checkbox-group.tsx +0 -153
- package/src/ui/checkbox.tsx +0 -63
- package/src/ui/collapsible.tsx +0 -163
- package/src/ui/command.tsx +0 -103
- package/src/ui/dialog.tsx +0 -223
- package/src/ui/dock.tsx +0 -630
- package/src/ui/dropdown.tsx +0 -636
- package/src/ui/editable-label.tsx +0 -112
- package/src/ui/hover-card.tsx +0 -345
- package/src/ui/icon.tsx +0 -167
- package/src/ui/input.tsx +0 -391
- package/src/ui/kbd.tsx +0 -118
- package/src/ui/nav.tsx +0 -282
- package/src/ui/notice.tsx +0 -84
- package/src/ui/overlay.tsx +0 -277
- package/src/ui/pane-grid.tsx +0 -117
- package/src/ui/pane-group.tsx +0 -291
- package/src/ui/pane.tsx +0 -193
- package/src/ui/popover.tsx +0 -106
- package/src/ui/progress-bar.tsx +0 -83
- package/src/ui/prompt-dock.tsx +0 -145
- package/src/ui/radio.tsx +0 -150
- package/src/ui/resizable.tsx +0 -693
- package/src/ui/scroll-area.tsx +0 -26
- package/src/ui/segmented.tsx +0 -109
- package/src/ui/select.tsx +0 -168
- package/src/ui/separator.tsx +0 -10
- package/src/ui/settings-group.tsx +0 -67
- package/src/ui/skeleton.tsx +0 -73
- package/src/ui/slider.tsx +0 -178
- package/src/ui/status.tsx +0 -48
- package/src/ui/switch.tsx +0 -119
- package/src/ui/tabs.tsx +0 -168
- package/src/ui/textarea.tsx +0 -21
- package/src/ui/tooltip.tsx +0 -118
- package/src/utils/cn.ts +0 -30
- package/src/wire/chunk.ts +0 -248
- package/src/wire/consume.ts +0 -599
- package/src/wire/diagnostics.ts +0 -727
- package/src/wire/encode-probe.ts +0 -214
- package/src/wire/encode.ts +0 -947
- package/src/wire/files.ts +0 -342
- package/src/wire/formats/anthropic.ts +0 -274
- package/src/wire/formats/openai.ts +0 -228
- package/src/wire/index.ts +0 -95
- package/src/wire/media-types.ts +0 -344
- package/src/wire/read.ts +0 -396
- package/src/wire/sink-helpers.ts +0 -50
- package/src/wire/sse.ts +0 -153
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { createSignal, onCleanup } from 'solid-js';
|
|
2
|
-
|
|
3
|
-
// Minimal Web Speech API surface. The DOM lib doesn't ship these types reliably
|
|
4
|
-
// across TS versions, so we declare only what we touch. `webkitSpeechRecognition`
|
|
5
|
-
// is the Chrome/Safari-prefixed constructor; the unprefixed one is rare.
|
|
6
|
-
interface SpeechRecognitionAlternative {
|
|
7
|
-
transcript: string;
|
|
8
|
-
}
|
|
9
|
-
interface SpeechRecognitionResult {
|
|
10
|
-
readonly isFinal: boolean;
|
|
11
|
-
readonly length: number;
|
|
12
|
-
[index: number]: SpeechRecognitionAlternative;
|
|
13
|
-
}
|
|
14
|
-
interface SpeechRecognitionResultList {
|
|
15
|
-
readonly length: number;
|
|
16
|
-
[index: number]: SpeechRecognitionResult;
|
|
17
|
-
}
|
|
18
|
-
interface SpeechRecognitionEventLike {
|
|
19
|
-
readonly resultIndex: number;
|
|
20
|
-
readonly results: SpeechRecognitionResultList;
|
|
21
|
-
}
|
|
22
|
-
interface SpeechRecognitionLike {
|
|
23
|
-
lang: string;
|
|
24
|
-
continuous: boolean;
|
|
25
|
-
interimResults: boolean;
|
|
26
|
-
start(): void;
|
|
27
|
-
stop(): void;
|
|
28
|
-
abort(): void;
|
|
29
|
-
onresult: ((event: SpeechRecognitionEventLike) => void) | null;
|
|
30
|
-
onerror: ((event: { error?: string }) => void) | null;
|
|
31
|
-
onend: (() => void) | null;
|
|
32
|
-
}
|
|
33
|
-
type SpeechRecognitionCtor = new () => SpeechRecognitionLike;
|
|
34
|
-
|
|
35
|
-
function getCtor(): SpeechRecognitionCtor | undefined {
|
|
36
|
-
if (typeof window === 'undefined') return undefined;
|
|
37
|
-
const w = window as unknown as {
|
|
38
|
-
SpeechRecognition?: SpeechRecognitionCtor;
|
|
39
|
-
webkitSpeechRecognition?: SpeechRecognitionCtor;
|
|
40
|
-
};
|
|
41
|
-
return w.SpeechRecognition ?? w.webkitSpeechRecognition;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface UseSpeechRecognitionOptions {
|
|
45
|
-
/** Emit live, non-final partials via the `onInterim` callback passed to start(). */
|
|
46
|
-
interim?: boolean;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface SpeechRecognitionStartOptions {
|
|
50
|
-
/** BCP-47 language tag, e.g. `en-US`. */
|
|
51
|
-
lang?: string;
|
|
52
|
-
/** Called with each interim (non-final) transcript when `interim` is enabled. */
|
|
53
|
-
onInterim?: (text: string) => void;
|
|
54
|
-
/**
|
|
55
|
-
* Called when the recognition session hits a runtime error (`recognition.onerror`),
|
|
56
|
-
* with the platform's error code (`network`, `not-allowed`, `no-speech`, ...) and a
|
|
57
|
-
* human-readable message. The session still ends through `onend`, so `start()` still
|
|
58
|
-
* resolves (with whatever text was captured before the error). Without this callback
|
|
59
|
-
* a runtime failure is invisible: the `error` signal is state, not a notification.
|
|
60
|
-
*/
|
|
61
|
-
onError?: (error: string, message: string) => void;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Wrap the browser's Web Speech `SpeechRecognition` (Chrome/Safari; no Firefox).
|
|
66
|
-
* Mirrors `useVoiceRecorder`'s shape: an `isListening` signal, an `error` signal,
|
|
67
|
-
* and `start`/`stop` controls. `start()` resolves with the final transcript when
|
|
68
|
-
* recognition ends; `stop()` ends the in-progress session (resolving start()).
|
|
69
|
-
*
|
|
70
|
-
* Caveat (documented at the element): in Chrome this is cloud-based — audio is
|
|
71
|
-
* sent to Google — so it is "native to the browser," not on-device/private.
|
|
72
|
-
*/
|
|
73
|
-
export function useSpeechRecognition(options: UseSpeechRecognitionOptions = {}) {
|
|
74
|
-
const [isListening, setIsListening] = createSignal(false);
|
|
75
|
-
const [error, setError] = createSignal<string | null>(null);
|
|
76
|
-
|
|
77
|
-
const isSupported = getCtor() !== undefined;
|
|
78
|
-
|
|
79
|
-
let recognition: SpeechRecognitionLike | undefined;
|
|
80
|
-
let resolveText: ((text: string) => void) | undefined;
|
|
81
|
-
let finalText = '';
|
|
82
|
-
|
|
83
|
-
function start(opts: SpeechRecognitionStartOptions = {}): Promise<string> {
|
|
84
|
-
setError(null);
|
|
85
|
-
finalText = '';
|
|
86
|
-
const Ctor = getCtor();
|
|
87
|
-
if (!Ctor) {
|
|
88
|
-
const message = 'SpeechRecognition is not supported in this browser';
|
|
89
|
-
setError(message);
|
|
90
|
-
return Promise.reject(new Error(message));
|
|
91
|
-
}
|
|
92
|
-
try {
|
|
93
|
-
recognition = new Ctor();
|
|
94
|
-
if (opts.lang) recognition.lang = opts.lang;
|
|
95
|
-
recognition.interimResults = options.interim === true;
|
|
96
|
-
recognition.continuous = false;
|
|
97
|
-
|
|
98
|
-
recognition.onresult = (event) => {
|
|
99
|
-
let interim = '';
|
|
100
|
-
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
101
|
-
const result = event.results[i];
|
|
102
|
-
const transcript = result[0]?.transcript ?? '';
|
|
103
|
-
if (result.isFinal) {
|
|
104
|
-
finalText += transcript;
|
|
105
|
-
} else {
|
|
106
|
-
interim += transcript;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (interim && opts.onInterim) opts.onInterim(interim);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
recognition.onerror = (event) => {
|
|
113
|
-
const code = event.error ?? 'unknown';
|
|
114
|
-
const message = `Speech recognition error: ${code}`;
|
|
115
|
-
setError(message);
|
|
116
|
-
opts.onError?.(code, message);
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
recognition.onend = () => {
|
|
120
|
-
setIsListening(false);
|
|
121
|
-
resolveText?.(finalText);
|
|
122
|
-
recognition = undefined;
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
recognition.start();
|
|
126
|
-
setIsListening(true);
|
|
127
|
-
return new Promise<string>((resolve) => { resolveText = resolve; });
|
|
128
|
-
} catch (err) {
|
|
129
|
-
setError(err instanceof Error ? err.message : 'Speech recognition failed to start');
|
|
130
|
-
setIsListening(false);
|
|
131
|
-
throw err;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function stop() {
|
|
136
|
-
if (recognition && isListening()) {
|
|
137
|
-
recognition.stop();
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
onCleanup(() => {
|
|
142
|
-
if (recognition) recognition.abort();
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
return { isSupported, isListening, error, start, stop };
|
|
146
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { createSignal, onCleanup } from 'solid-js';
|
|
2
|
-
|
|
3
|
-
const SCROLL_THRESHOLD = 50;
|
|
4
|
-
|
|
5
|
-
export function useStickToBottom() {
|
|
6
|
-
const [isAtBottom, setIsAtBottom] = createSignal(true);
|
|
7
|
-
let containerEl: HTMLElement | undefined;
|
|
8
|
-
let shouldStick = true;
|
|
9
|
-
|
|
10
|
-
function checkIfAtBottom() {
|
|
11
|
-
if (!containerEl) return;
|
|
12
|
-
const { scrollTop, scrollHeight, clientHeight } = containerEl;
|
|
13
|
-
const atBottom = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD;
|
|
14
|
-
setIsAtBottom(atBottom);
|
|
15
|
-
shouldStick = atBottom;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function scrollToBottom(behavior: ScrollBehavior = 'smooth') {
|
|
19
|
-
if (!containerEl) return;
|
|
20
|
-
if (typeof containerEl.scrollTo === 'function') {
|
|
21
|
-
containerEl.scrollTo({ top: containerEl.scrollHeight, behavior });
|
|
22
|
-
} else {
|
|
23
|
-
containerEl.scrollTop = containerEl.scrollHeight;
|
|
24
|
-
}
|
|
25
|
-
shouldStick = true;
|
|
26
|
-
setIsAtBottom(true);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let pendingFrame: number | undefined;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* `cancelAnimationFrame`, captured at SETUP -- not called bare at cleanup.
|
|
33
|
-
*
|
|
34
|
-
* Cleanup is not guaranteed to run while the page that mounted this
|
|
35
|
-
* primitive is still standing: a host can tear its DOM globals down first
|
|
36
|
-
* (`component-register`'s `disconnectedCallback` defers a microtask; a
|
|
37
|
-
* test environment deletes the globals synchronously right after
|
|
38
|
-
* detaching). A bare `cancelAnimationFrame` there throws, surfacing as an
|
|
39
|
-
* unhandled rejection that fails a run in which every test passed --
|
|
40
|
-
* see tests/components/teardown-without-dom-globals.test.tsx, and the
|
|
41
|
-
* same pattern in create-tween.ts.
|
|
42
|
-
*
|
|
43
|
-
* Guarded because "setup" here is the component body, and a server render
|
|
44
|
-
* executes component bodies too; Node has neither global.
|
|
45
|
-
*/
|
|
46
|
-
const cancelFrame = typeof cancelAnimationFrame === 'function'
|
|
47
|
-
? cancelAnimationFrame.bind(globalThis)
|
|
48
|
-
: () => {};
|
|
49
|
-
|
|
50
|
-
function onNewContent() {
|
|
51
|
-
if (shouldStick) {
|
|
52
|
-
pendingFrame = requestAnimationFrame(() => {
|
|
53
|
-
pendingFrame = undefined;
|
|
54
|
-
scrollToBottom('instant');
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function ref(el: HTMLElement) {
|
|
60
|
-
containerEl = el;
|
|
61
|
-
el.addEventListener('scroll', checkIfAtBottom, { passive: true });
|
|
62
|
-
const observer = new MutationObserver(onNewContent);
|
|
63
|
-
observer.observe(el, { childList: true, subtree: true, characterData: true });
|
|
64
|
-
onCleanup(() => {
|
|
65
|
-
el.removeEventListener('scroll', checkIfAtBottom);
|
|
66
|
-
observer.disconnect();
|
|
67
|
-
if (pendingFrame !== undefined) {
|
|
68
|
-
cancelFrame(pendingFrame);
|
|
69
|
-
pendingFrame = undefined;
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return { ref, isAtBottom, scrollToBottom };
|
|
75
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { createSignal, onCleanup } from 'solid-js';
|
|
2
|
-
|
|
3
|
-
export interface UseTextStreamOptions {
|
|
4
|
-
mode: 'typewriter' | 'fade';
|
|
5
|
-
speed?: number;
|
|
6
|
-
characterChunkSize?: number;
|
|
7
|
-
fadeDuration?: number;
|
|
8
|
-
segmentDelay?: number;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** Default fade-in duration for a given speed (ms) — shared with ResponseStream. */
|
|
12
|
-
export function defaultFadeDuration(speed: number): number {
|
|
13
|
-
const s = Math.min(100, Math.max(1, speed));
|
|
14
|
-
return Math.round(1000 / Math.sqrt(s));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Default per-segment stagger for a given speed (ms) — shared with ResponseStream. */
|
|
18
|
-
export function defaultSegmentDelay(speed: number): number {
|
|
19
|
-
const s = Math.min(100, Math.max(1, speed));
|
|
20
|
-
return Math.max(1, Math.round(100 / Math.sqrt(s)));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface TextStreamSegment {
|
|
24
|
-
text: string;
|
|
25
|
-
index: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function useTextStream(options: UseTextStreamOptions) {
|
|
29
|
-
const speed = options.speed ?? 20;
|
|
30
|
-
const chunkSize = options.characterChunkSize ?? 3;
|
|
31
|
-
|
|
32
|
-
const [displayedText, setDisplayedText] = createSignal('');
|
|
33
|
-
const [isComplete, setIsComplete] = createSignal(true);
|
|
34
|
-
const [segments, setSegments] = createSignal<TextStreamSegment[]>([]);
|
|
35
|
-
|
|
36
|
-
let fullText = '';
|
|
37
|
-
let charIndex = 0;
|
|
38
|
-
let intervalId: ReturnType<typeof setInterval> | undefined;
|
|
39
|
-
let completeTimeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
40
|
-
let isPaused = false;
|
|
41
|
-
let asyncIterator: AsyncIterator<string> | undefined;
|
|
42
|
-
|
|
43
|
-
function clearInterval_() {
|
|
44
|
-
if (intervalId !== undefined) {
|
|
45
|
-
clearInterval(intervalId);
|
|
46
|
-
intervalId = undefined;
|
|
47
|
-
}
|
|
48
|
-
if (completeTimeoutId !== undefined) {
|
|
49
|
-
clearTimeout(completeTimeoutId);
|
|
50
|
-
completeTimeoutId = undefined;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function typewriterTick() {
|
|
55
|
-
if (isPaused) return;
|
|
56
|
-
if (charIndex >= fullText.length) {
|
|
57
|
-
if (!asyncIterator) {
|
|
58
|
-
clearInterval_();
|
|
59
|
-
setIsComplete(true);
|
|
60
|
-
}
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
const end = Math.min(charIndex + chunkSize, fullText.length);
|
|
64
|
-
charIndex = end;
|
|
65
|
-
setDisplayedText(fullText.slice(0, charIndex));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async function consumeAsyncIterable(source: AsyncIterable<string>) {
|
|
69
|
-
asyncIterator = source[Symbol.asyncIterator]();
|
|
70
|
-
try {
|
|
71
|
-
while (true) {
|
|
72
|
-
const { value, done } = await asyncIterator.next();
|
|
73
|
-
if (done) break;
|
|
74
|
-
if (value) {
|
|
75
|
-
fullText += value;
|
|
76
|
-
setSegments((prev) => [...prev, { text: value, index: prev.length }]);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
} finally {
|
|
80
|
-
asyncIterator = undefined;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function startStreaming(source: string | AsyncIterable<string>) {
|
|
85
|
-
reset();
|
|
86
|
-
setIsComplete(false);
|
|
87
|
-
|
|
88
|
-
if (typeof source === 'string') {
|
|
89
|
-
fullText = source;
|
|
90
|
-
if (options.mode === 'typewriter') {
|
|
91
|
-
intervalId = setInterval(typewriterTick, speed);
|
|
92
|
-
} else {
|
|
93
|
-
// Deliver all segments at once — CSS animation-delay handles staggered fade-in
|
|
94
|
-
const words = source.split(/(\s+)/).filter(Boolean);
|
|
95
|
-
setSegments(words.map((text, index) => ({ text, index })));
|
|
96
|
-
setDisplayedText(source);
|
|
97
|
-
// Completion announces after the staggered animation has had time to
|
|
98
|
-
// play: segments * per-segment delay + one fade duration — the promise
|
|
99
|
-
// the comment here used to make with no code behind it (nothing on this
|
|
100
|
-
// path ever called setIsComplete(true), so kai-complete never fired for
|
|
101
|
-
// a fade-mode string). A timer, not a synchronous write: the consumer
|
|
102
|
-
// attaches its kai-complete listener a beat after mount, and a
|
|
103
|
-
// same-tick fire races past it.
|
|
104
|
-
const segDelay = typeof options.segmentDelay === 'number'
|
|
105
|
-
? Math.max(0, options.segmentDelay)
|
|
106
|
-
: defaultSegmentDelay(speed);
|
|
107
|
-
const fadeDur = options.fadeDuration ?? defaultFadeDuration(speed);
|
|
108
|
-
completeTimeoutId = setTimeout(() => {
|
|
109
|
-
completeTimeoutId = undefined;
|
|
110
|
-
setIsComplete(true);
|
|
111
|
-
}, words.length * segDelay + fadeDur);
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
if (options.mode === 'typewriter') {
|
|
115
|
-
intervalId = setInterval(typewriterTick, speed);
|
|
116
|
-
}
|
|
117
|
-
consumeAsyncIterable(source).then(() => {
|
|
118
|
-
if (options.mode === 'fade') {
|
|
119
|
-
setDisplayedText(fullText);
|
|
120
|
-
setIsComplete(true);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function pause() { isPaused = true; }
|
|
127
|
-
function resume() { isPaused = false; }
|
|
128
|
-
|
|
129
|
-
function reset() {
|
|
130
|
-
clearInterval_();
|
|
131
|
-
fullText = '';
|
|
132
|
-
charIndex = 0;
|
|
133
|
-
isPaused = false;
|
|
134
|
-
asyncIterator = undefined;
|
|
135
|
-
setDisplayedText('');
|
|
136
|
-
setIsComplete(true);
|
|
137
|
-
setSegments([]);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
onCleanup(() => clearInterval_());
|
|
141
|
-
|
|
142
|
-
return { displayedText, isComplete, segments, startStreaming, pause, resume, reset };
|
|
143
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { createSignal, onCleanup } from 'solid-js';
|
|
2
|
-
|
|
3
|
-
export interface UseVoiceRecorderOptions {
|
|
4
|
-
mimeType?: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function useVoiceRecorder(options: UseVoiceRecorderOptions = {}) {
|
|
8
|
-
const mimeType = options.mimeType ?? 'audio/webm;codecs=opus';
|
|
9
|
-
const [isRecording, setIsRecording] = createSignal(false);
|
|
10
|
-
const [error, setError] = createSignal<string | null>(null);
|
|
11
|
-
const [stream, setStream] = createSignal<MediaStream | undefined>();
|
|
12
|
-
|
|
13
|
-
let mediaRecorder: MediaRecorder | undefined;
|
|
14
|
-
let chunks: Blob[] = [];
|
|
15
|
-
let resolveBlob: ((blob: Blob) => void) | undefined;
|
|
16
|
-
|
|
17
|
-
async function start(): Promise<Blob> {
|
|
18
|
-
setError(null);
|
|
19
|
-
chunks = [];
|
|
20
|
-
try {
|
|
21
|
-
const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
22
|
-
setStream(mediaStream);
|
|
23
|
-
mediaRecorder = new MediaRecorder(mediaStream, { mimeType });
|
|
24
|
-
mediaRecorder.ondataavailable = (e) => {
|
|
25
|
-
if (e.data.size > 0) chunks.push(e.data);
|
|
26
|
-
};
|
|
27
|
-
mediaRecorder.onstop = () => {
|
|
28
|
-
const blob = new Blob(chunks, { type: mimeType });
|
|
29
|
-
mediaStream.getTracks().forEach((t) => t.stop());
|
|
30
|
-
setStream(undefined);
|
|
31
|
-
setIsRecording(false);
|
|
32
|
-
resolveBlob?.(blob);
|
|
33
|
-
};
|
|
34
|
-
mediaRecorder.start();
|
|
35
|
-
setIsRecording(true);
|
|
36
|
-
return new Promise<Blob>((resolve) => { resolveBlob = resolve; });
|
|
37
|
-
} catch (err) {
|
|
38
|
-
// getUserMedia may have already succeeded (stream() is live) even
|
|
39
|
-
// though something after it threw, e.g. an unsupported mimeType
|
|
40
|
-
// rejected by `new MediaRecorder(...)`. Leaving that stream open would
|
|
41
|
-
// keep the microphone live with no indication anything is recording.
|
|
42
|
-
const liveStream = stream();
|
|
43
|
-
if (liveStream) {
|
|
44
|
-
liveStream.getTracks().forEach((t) => t.stop());
|
|
45
|
-
setStream(undefined);
|
|
46
|
-
}
|
|
47
|
-
setError(err instanceof Error ? err.message : 'Microphone access denied');
|
|
48
|
-
setIsRecording(false);
|
|
49
|
-
throw err;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function stop() {
|
|
54
|
-
if (mediaRecorder && mediaRecorder.state === 'recording') {
|
|
55
|
-
mediaRecorder.stop();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
onCleanup(() => stop());
|
|
60
|
-
|
|
61
|
-
return { isRecording, error, stream, start, stop };
|
|
62
|
-
}
|