@tanstack/ai-svelte 0.13.15 → 0.14.1
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/dist/create-audio-recorder.svelte.d.ts +37 -0
- package/dist/create-audio-recorder.svelte.js +36 -0
- package/dist/create-generate-audio.svelte.d.ts +4 -4
- package/dist/create-generate-image.svelte.d.ts +4 -4
- package/dist/create-generate-speech.svelte.d.ts +4 -4
- package/dist/create-generate-video.svelte.d.ts +4 -4
- package/dist/create-generate-video.svelte.js +7 -1
- package/dist/create-generation.svelte.d.ts +4 -4
- package/dist/create-generation.svelte.js +10 -1
- package/dist/create-summarize.svelte.d.ts +4 -4
- package/dist/create-transcription.svelte.d.ts +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +4 -4
- package/src/create-audio-recorder.svelte.ts +93 -0
- package/src/create-generate-audio.svelte.ts +5 -8
- package/src/create-generate-image.svelte.ts +5 -8
- package/src/create-generate-speech.svelte.ts +7 -7
- package/src/create-generate-video.svelte.ts +17 -9
- package/src/create-generation.svelte.ts +19 -6
- package/src/create-summarize.svelte.ts +5 -8
- package/src/create-transcription.svelte.ts +5 -8
- package/src/index.ts +6 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { AudioRecorderOptions, AudioRecording, InferAudioRecordingOutput } from '@tanstack/ai-client';
|
|
2
|
+
export type CreateAudioRecorderOptions<TOnComplete> = AudioRecorderOptions & {
|
|
3
|
+
/**
|
|
4
|
+
* Optional transform applied to the recording when `stop()` resolves. Its
|
|
5
|
+
* (awaited) return value becomes `recording` and the resolved value of
|
|
6
|
+
* `stop()`. Return nothing to keep the raw `AudioRecording`.
|
|
7
|
+
*/
|
|
8
|
+
onComplete?: TOnComplete;
|
|
9
|
+
};
|
|
10
|
+
export interface CreateAudioRecorderReturn<TOutput> {
|
|
11
|
+
/** Reactive: latest recording (transformed if `onComplete` provided), or null. */
|
|
12
|
+
readonly recording: TOutput | null;
|
|
13
|
+
/** Reactive: true while actively capturing audio. */
|
|
14
|
+
readonly isRecording: boolean;
|
|
15
|
+
/** Whether the browser supports recording. */
|
|
16
|
+
readonly isSupported: boolean;
|
|
17
|
+
start: () => Promise<void>;
|
|
18
|
+
/** Stop and resolve with the completed recording (transformed if `onComplete` provided). */
|
|
19
|
+
stop: () => Promise<TOutput>;
|
|
20
|
+
/**
|
|
21
|
+
* Discard the in-progress recording and release the mic. Svelte 5 runes
|
|
22
|
+
* can't register automatic teardown here (matching `createChat`), so call
|
|
23
|
+
* this from your component's cleanup if a recording may still be active.
|
|
24
|
+
*/
|
|
25
|
+
cancel: () => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Svelte 5 factory for recording an audio message. The resolved recording
|
|
29
|
+
* carries `.part` (for `createChat.sendMessage`) and `.base64` (for the
|
|
30
|
+
* generation factories).
|
|
31
|
+
*
|
|
32
|
+
* Errors are delivered via `onError`. `start()` and `stop()` also reject on
|
|
33
|
+
* failure (and `stop()` rejects with `Recording cancelled` if `cancel()` runs
|
|
34
|
+
* while a stop is in flight) — handle one channel, not both.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createAudioRecorder<TOnComplete extends (recording: AudioRecording) => unknown>(options: CreateAudioRecorderOptions<TOnComplete>): CreateAudioRecorderReturn<InferAudioRecordingOutput<TOnComplete>>;
|
|
37
|
+
export declare function createAudioRecorder(options?: CreateAudioRecorderOptions<undefined>): CreateAudioRecorderReturn<AudioRecording>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AudioRecorder } from '@tanstack/ai-client';
|
|
2
|
+
export function createAudioRecorder(options = {}) {
|
|
3
|
+
const recorder = new AudioRecorder({
|
|
4
|
+
...(options.audio !== undefined && { audio: options.audio }),
|
|
5
|
+
...(options.mimeType !== undefined && { mimeType: options.mimeType }),
|
|
6
|
+
...(options.onError !== undefined && { onError: options.onError }),
|
|
7
|
+
});
|
|
8
|
+
let isRecording = $state(false);
|
|
9
|
+
let recording = $state(null);
|
|
10
|
+
recorder.subscribe((state) => {
|
|
11
|
+
isRecording = state === 'recording';
|
|
12
|
+
});
|
|
13
|
+
const stop = async () => {
|
|
14
|
+
const rawRecording = await recorder.stop();
|
|
15
|
+
const transformed = await options.onComplete?.(rawRecording);
|
|
16
|
+
// Only `undefined` (returning nothing) keeps the raw recording; a returned
|
|
17
|
+
// null is a real value, matching the inferred output type.
|
|
18
|
+
const output = transformed === undefined ? rawRecording : transformed;
|
|
19
|
+
recording = output;
|
|
20
|
+
return output;
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
get recording() {
|
|
24
|
+
return recording;
|
|
25
|
+
},
|
|
26
|
+
get isRecording() {
|
|
27
|
+
return isRecording;
|
|
28
|
+
},
|
|
29
|
+
get isSupported() {
|
|
30
|
+
return AudioRecorder.isSupported();
|
|
31
|
+
},
|
|
32
|
+
start: () => recorder.start(),
|
|
33
|
+
stop,
|
|
34
|
+
cancel: () => recorder.cancel(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AudioGenerationResult, StreamChunk } from '@tanstack/ai';
|
|
2
|
-
import type { AIDevtoolsDisplayOptions, AudioGenerateInput, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher,
|
|
2
|
+
import type { AIDevtoolsDisplayOptions, AudioGenerateInput, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutputFromReturn } from '@tanstack/ai-client';
|
|
3
3
|
/**
|
|
4
4
|
* Options for the createGenerateAudio function.
|
|
5
5
|
*
|
|
@@ -80,6 +80,6 @@ export interface CreateGenerateAudioReturn<TOutput = AudioGenerationResult> {
|
|
|
80
80
|
* </div>
|
|
81
81
|
* ```
|
|
82
82
|
*/
|
|
83
|
-
export declare function createGenerateAudio<
|
|
84
|
-
onResult?:
|
|
85
|
-
}): CreateGenerateAudioReturn<
|
|
83
|
+
export declare function createGenerateAudio<TTransformed = void>(options: Omit<CreateGenerateAudioOptions, 'onResult'> & {
|
|
84
|
+
onResult?: (result: AudioGenerationResult) => TTransformed;
|
|
85
|
+
}): CreateGenerateAudioReturn<InferGenerationOutputFromReturn<AudioGenerationResult, TTransformed>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ImageGenerationResult, StreamChunk } from '@tanstack/ai';
|
|
2
|
-
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, ImageGenerateInput,
|
|
2
|
+
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, ImageGenerateInput, InferGenerationOutputFromReturn } from '@tanstack/ai-client';
|
|
3
3
|
/**
|
|
4
4
|
* Options for the createGenerateImage function.
|
|
5
5
|
*
|
|
@@ -89,6 +89,6 @@ export interface CreateGenerateImageReturn<TOutput = ImageGenerationResult> {
|
|
|
89
89
|
* </div>
|
|
90
90
|
* ```
|
|
91
91
|
*/
|
|
92
|
-
export declare function createGenerateImage<
|
|
93
|
-
onResult?:
|
|
94
|
-
}): CreateGenerateImageReturn<
|
|
92
|
+
export declare function createGenerateImage<TTransformed = void>(options: Omit<CreateGenerateImageOptions, 'onResult'> & {
|
|
93
|
+
onResult?: (result: ImageGenerationResult) => TTransformed;
|
|
94
|
+
}): CreateGenerateImageReturn<InferGenerationOutputFromReturn<ImageGenerationResult, TTransformed>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StreamChunk, TTSResult } from '@tanstack/ai';
|
|
2
|
-
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher,
|
|
2
|
+
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutputFromReturn, SpeechGenerateInput } from '@tanstack/ai-client';
|
|
3
3
|
/**
|
|
4
4
|
* Options for the createGenerateSpeech function.
|
|
5
5
|
*
|
|
@@ -80,6 +80,6 @@ export interface CreateGenerateSpeechReturn<TOutput = TTSResult> {
|
|
|
80
80
|
* </div>
|
|
81
81
|
* ```
|
|
82
82
|
*/
|
|
83
|
-
export declare function createGenerateSpeech<
|
|
84
|
-
onResult?:
|
|
85
|
-
}): CreateGenerateSpeechReturn<
|
|
83
|
+
export declare function createGenerateSpeech<TTransformed = void>(options: Omit<CreateGenerateSpeechOptions, 'onResult'> & {
|
|
84
|
+
onResult?: (result: TTSResult) => TTransformed;
|
|
85
|
+
}): CreateGenerateSpeechReturn<InferGenerationOutputFromReturn<TTSResult, TTransformed>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StreamChunk } from '@tanstack/ai';
|
|
2
|
-
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher,
|
|
2
|
+
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutputFromReturn, VideoGenerateInput, VideoGenerateResult, VideoStatusInfo } from '@tanstack/ai-client';
|
|
3
3
|
/**
|
|
4
4
|
* Options for the createGenerateVideo function.
|
|
5
5
|
*
|
|
@@ -94,6 +94,6 @@ export interface CreateGenerateVideoReturn<TOutput = VideoGenerateResult> {
|
|
|
94
94
|
* </div>
|
|
95
95
|
* ```
|
|
96
96
|
*/
|
|
97
|
-
export declare function createGenerateVideo<
|
|
98
|
-
onResult?:
|
|
99
|
-
}): CreateGenerateVideoReturn<
|
|
97
|
+
export declare function createGenerateVideo<TTransformed = void>(options: Omit<CreateGenerateVideoOptions, 'onResult'> & {
|
|
98
|
+
onResult?: (result: VideoGenerateResult) => TTransformed;
|
|
99
|
+
}): CreateGenerateVideoReturn<InferGenerationOutputFromReturn<VideoGenerateResult, TTransformed>>;
|
|
@@ -30,6 +30,9 @@ import { createVideoDevtoolsBridge } from '@tanstack/ai-client/devtools';
|
|
|
30
30
|
* </div>
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
|
+
// `TTransformed` infers from the `onResult` return position so the callback
|
|
34
|
+
// parameter is typed as `VideoGenerateResult` and `result` narrows to the
|
|
35
|
+
// transform's return. See issue #848.
|
|
33
36
|
export function createGenerateVideo(options) {
|
|
34
37
|
const clientId = options.id ||
|
|
35
38
|
`video-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
@@ -54,7 +57,10 @@ export function createGenerateVideo(options) {
|
|
|
54
57
|
hookName: 'createGenerateVideo',
|
|
55
58
|
outputKind: 'video',
|
|
56
59
|
},
|
|
57
|
-
|
|
60
|
+
// The transform's raw return type (`TTransformed`) and the stored output
|
|
61
|
+
// (`TOutput`, with null/void/undefined stripped) are identical at runtime;
|
|
62
|
+
// the cast bridges the relationship that the conditional type hides.
|
|
63
|
+
onResult: ((r) => options.onResult?.(r)),
|
|
58
64
|
onError: (e) => options.onError?.(e),
|
|
59
65
|
onProgress: (p, m) => options.onProgress?.(p, m),
|
|
60
66
|
onChunk: (c) => options.onChunk?.(c),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StreamChunk } from '@tanstack/ai';
|
|
2
|
-
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher,
|
|
2
|
+
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutputFromReturn } from '@tanstack/ai-client';
|
|
3
3
|
/**
|
|
4
4
|
* Options for the createGeneration function.
|
|
5
5
|
*
|
|
@@ -91,6 +91,6 @@ export interface CreateGenerationReturn<TOutput> {
|
|
|
91
91
|
* </div>
|
|
92
92
|
* ```
|
|
93
93
|
*/
|
|
94
|
-
export declare function createGeneration<TInput extends Record<string, any>, TResult,
|
|
95
|
-
onResult?:
|
|
96
|
-
}): CreateGenerationReturn<
|
|
94
|
+
export declare function createGeneration<TInput extends Record<string, any>, TResult, TTransformed = void>(options: Omit<CreateGenerationOptions<TInput, TResult>, 'onResult'> & {
|
|
95
|
+
onResult?: (result: TResult) => TTransformed;
|
|
96
|
+
}): CreateGenerationReturn<InferGenerationOutputFromReturn<TResult, TTransformed>>;
|
|
@@ -31,6 +31,12 @@ import { createGenerationDevtoolsBridge } from '@tanstack/ai-client/devtools';
|
|
|
31
31
|
* </div>
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
|
+
// `TTransformed` infers from the `onResult` return position (a covariant
|
|
35
|
+
// inference site that works even for an optional nested property), which types
|
|
36
|
+
// the callback parameter as `TResult` and narrows `result`. Inferring the
|
|
37
|
+
// whole callback as a defaulted type parameter instead collapses to the
|
|
38
|
+
// default, leaving the parameter `any` — a hard error under `strict`. See
|
|
39
|
+
// issue #848.
|
|
34
40
|
export function createGeneration(options) {
|
|
35
41
|
const clientId = options.id || `gen-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
36
42
|
// Create reactive state using Svelte 5 runes
|
|
@@ -52,7 +58,10 @@ export function createGeneration(options) {
|
|
|
52
58
|
framework: 'svelte',
|
|
53
59
|
hookName: 'createGeneration',
|
|
54
60
|
},
|
|
55
|
-
|
|
61
|
+
// The transform's raw return type (`TTransformed`) and the stored output
|
|
62
|
+
// (`TOutput`, with null/void/undefined stripped) are identical at runtime;
|
|
63
|
+
// the cast bridges the relationship that the conditional type hides.
|
|
64
|
+
onResult: ((r) => options.onResult?.(r)),
|
|
56
65
|
onError: (e) => options.onError?.(e),
|
|
57
66
|
onProgress: (p, m) => options.onProgress?.(p, m),
|
|
58
67
|
onChunk: (c) => options.onChunk?.(c),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StreamChunk, SummarizationResult } from '@tanstack/ai';
|
|
2
|
-
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher,
|
|
2
|
+
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutputFromReturn, SummarizeGenerateInput } from '@tanstack/ai-client';
|
|
3
3
|
/**
|
|
4
4
|
* Options for the createSummarize function.
|
|
5
5
|
*
|
|
@@ -84,6 +84,6 @@ export interface CreateSummarizeReturn<TOutput = SummarizationResult> {
|
|
|
84
84
|
* </div>
|
|
85
85
|
* ```
|
|
86
86
|
*/
|
|
87
|
-
export declare function createSummarize<
|
|
88
|
-
onResult?:
|
|
89
|
-
}): CreateSummarizeReturn<
|
|
87
|
+
export declare function createSummarize<TTransformed = void>(options: Omit<CreateSummarizeOptions, 'onResult'> & {
|
|
88
|
+
onResult?: (result: SummarizationResult) => TTransformed;
|
|
89
|
+
}): CreateSummarizeReturn<InferGenerationOutputFromReturn<SummarizationResult, TTransformed>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StreamChunk, TranscriptionResult } from '@tanstack/ai';
|
|
2
|
-
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher,
|
|
2
|
+
import type { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutputFromReturn, TranscriptionGenerateInput } from '@tanstack/ai-client';
|
|
3
3
|
/**
|
|
4
4
|
* Options for the createTranscription function.
|
|
5
5
|
*
|
|
@@ -89,6 +89,6 @@ export interface CreateTranscriptionReturn<TOutput = TranscriptionResult> {
|
|
|
89
89
|
* </div>
|
|
90
90
|
* ```
|
|
91
91
|
*/
|
|
92
|
-
export declare function createTranscription<
|
|
93
|
-
onResult?:
|
|
94
|
-
}): CreateTranscriptionReturn<
|
|
92
|
+
export declare function createTranscription<TTransformed = void>(options: Omit<CreateTranscriptionOptions, 'onResult'> & {
|
|
93
|
+
onResult?: (result: TranscriptionResult) => TTransformed;
|
|
94
|
+
}): CreateTranscriptionReturn<InferGenerationOutputFromReturn<TranscriptionResult, TTransformed>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -14,4 +14,6 @@ export { createSummarize } from './create-summarize.svelte';
|
|
|
14
14
|
export type { CreateSummarizeOptions, CreateSummarizeReturn, } from './create-summarize.svelte';
|
|
15
15
|
export { createGenerateVideo } from './create-generate-video.svelte';
|
|
16
16
|
export type { CreateGenerateVideoOptions, CreateGenerateVideoReturn, } from './create-generate-video.svelte';
|
|
17
|
+
export { createAudioRecorder } from './create-audio-recorder.svelte';
|
|
18
|
+
export type { CreateAudioRecorderOptions, CreateAudioRecorderReturn, } from './create-audio-recorder.svelte';
|
|
17
19
|
export { fetchServerSentEvents, fetchHttpStream, xhrServerSentEvents, xhrHttpStream, stream, rpcStream, createChatClientOptions, clientTools, type ConnectionAdapter, type ConnectConnectionAdapter, type SubscribeConnectionAdapter, type RunAgentInputContext, type FetchConnectionOptions, type XhrConnectionOptions, type InferChatMessages, type GenerationClientState, type ImageGenerateInput, type AudioGenerateInput, type SpeechGenerateInput, type TranscriptionGenerateInput, type SummarizeGenerateInput, type VideoGenerateInput, type VideoGenerateResult, type VideoStatusInfo, } from '@tanstack/ai-client';
|
package/dist/index.js
CHANGED
|
@@ -7,5 +7,6 @@ export { createGenerateSpeech } from './create-generate-speech.svelte';
|
|
|
7
7
|
export { createTranscription } from './create-transcription.svelte';
|
|
8
8
|
export { createSummarize } from './create-summarize.svelte';
|
|
9
9
|
export { createGenerateVideo } from './create-generate-video.svelte';
|
|
10
|
+
export { createAudioRecorder } from './create-audio-recorder.svelte';
|
|
10
11
|
// Re-export from ai-client for convenience
|
|
11
12
|
export { fetchServerSentEvents, fetchHttpStream, xhrServerSentEvents, xhrHttpStream, stream, rpcStream, createChatClientOptions, clientTools, } from '@tanstack/ai-client';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Svelte 5 bindings for TanStack AI streaming chat, structured outputs, and media generation.",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"media-generation"
|
|
47
47
|
],
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@tanstack/ai-client": "0.
|
|
49
|
+
"@tanstack/ai-client": "0.19.1"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"svelte": "^5.0.0",
|
|
53
|
-
"@tanstack/ai": "^0.
|
|
53
|
+
"@tanstack/ai": "^0.39.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@standard-schema/spec": "^1.1.0",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"svelte-check": "^4.2.0",
|
|
64
64
|
"typescript": "5.9.3",
|
|
65
65
|
"vite": "^7.3.3",
|
|
66
|
-
"@tanstack/ai": "0.
|
|
66
|
+
"@tanstack/ai": "0.39.0"
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
69
|
"clean": "rm -rf ./dist",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { AudioRecorder } from '@tanstack/ai-client'
|
|
2
|
+
import type {
|
|
3
|
+
AudioRecorderOptions,
|
|
4
|
+
AudioRecording,
|
|
5
|
+
InferAudioRecordingOutput,
|
|
6
|
+
} from '@tanstack/ai-client'
|
|
7
|
+
|
|
8
|
+
export type CreateAudioRecorderOptions<TOnComplete> = AudioRecorderOptions & {
|
|
9
|
+
/**
|
|
10
|
+
* Optional transform applied to the recording when `stop()` resolves. Its
|
|
11
|
+
* (awaited) return value becomes `recording` and the resolved value of
|
|
12
|
+
* `stop()`. Return nothing to keep the raw `AudioRecording`.
|
|
13
|
+
*/
|
|
14
|
+
onComplete?: TOnComplete
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface CreateAudioRecorderReturn<TOutput> {
|
|
18
|
+
/** Reactive: latest recording (transformed if `onComplete` provided), or null. */
|
|
19
|
+
readonly recording: TOutput | null
|
|
20
|
+
/** Reactive: true while actively capturing audio. */
|
|
21
|
+
readonly isRecording: boolean
|
|
22
|
+
/** Whether the browser supports recording. */
|
|
23
|
+
readonly isSupported: boolean
|
|
24
|
+
start: () => Promise<void>
|
|
25
|
+
/** Stop and resolve with the completed recording (transformed if `onComplete` provided). */
|
|
26
|
+
stop: () => Promise<TOutput>
|
|
27
|
+
/**
|
|
28
|
+
* Discard the in-progress recording and release the mic. Svelte 5 runes
|
|
29
|
+
* can't register automatic teardown here (matching `createChat`), so call
|
|
30
|
+
* this from your component's cleanup if a recording may still be active.
|
|
31
|
+
*/
|
|
32
|
+
cancel: () => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Svelte 5 factory for recording an audio message. The resolved recording
|
|
37
|
+
* carries `.part` (for `createChat.sendMessage`) and `.base64` (for the
|
|
38
|
+
* generation factories).
|
|
39
|
+
*
|
|
40
|
+
* Errors are delivered via `onError`. `start()` and `stop()` also reject on
|
|
41
|
+
* failure (and `stop()` rejects with `Recording cancelled` if `cancel()` runs
|
|
42
|
+
* while a stop is in flight) — handle one channel, not both.
|
|
43
|
+
*/
|
|
44
|
+
export function createAudioRecorder<
|
|
45
|
+
TOnComplete extends (recording: AudioRecording) => unknown,
|
|
46
|
+
>(
|
|
47
|
+
options: CreateAudioRecorderOptions<TOnComplete>,
|
|
48
|
+
): CreateAudioRecorderReturn<InferAudioRecordingOutput<TOnComplete>>
|
|
49
|
+
export function createAudioRecorder(
|
|
50
|
+
options?: CreateAudioRecorderOptions<undefined>,
|
|
51
|
+
): CreateAudioRecorderReturn<AudioRecording>
|
|
52
|
+
export function createAudioRecorder(
|
|
53
|
+
options: CreateAudioRecorderOptions<
|
|
54
|
+
(recording: AudioRecording) => unknown
|
|
55
|
+
> = {},
|
|
56
|
+
): CreateAudioRecorderReturn<unknown> {
|
|
57
|
+
const recorder = new AudioRecorder({
|
|
58
|
+
...(options.audio !== undefined && { audio: options.audio }),
|
|
59
|
+
...(options.mimeType !== undefined && { mimeType: options.mimeType }),
|
|
60
|
+
...(options.onError !== undefined && { onError: options.onError }),
|
|
61
|
+
})
|
|
62
|
+
let isRecording = $state(false)
|
|
63
|
+
let recording = $state<unknown>(null)
|
|
64
|
+
|
|
65
|
+
recorder.subscribe((state) => {
|
|
66
|
+
isRecording = state === 'recording'
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const stop = async (): Promise<unknown> => {
|
|
70
|
+
const rawRecording = await recorder.stop()
|
|
71
|
+
const transformed = await options.onComplete?.(rawRecording)
|
|
72
|
+
// Only `undefined` (returning nothing) keeps the raw recording; a returned
|
|
73
|
+
// null is a real value, matching the inferred output type.
|
|
74
|
+
const output = transformed === undefined ? rawRecording : transformed
|
|
75
|
+
recording = output
|
|
76
|
+
return output
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
get recording() {
|
|
81
|
+
return recording
|
|
82
|
+
},
|
|
83
|
+
get isRecording() {
|
|
84
|
+
return isRecording
|
|
85
|
+
},
|
|
86
|
+
get isSupported() {
|
|
87
|
+
return AudioRecorder.isSupported()
|
|
88
|
+
},
|
|
89
|
+
start: () => recorder.start(),
|
|
90
|
+
stop,
|
|
91
|
+
cancel: () => recorder.cancel(),
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
ConnectConnectionAdapter,
|
|
7
7
|
GenerationClientState,
|
|
8
8
|
GenerationFetcher,
|
|
9
|
-
|
|
9
|
+
InferGenerationOutputFromReturn,
|
|
10
10
|
} from '@tanstack/ai-client'
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -91,15 +91,12 @@ export interface CreateGenerateAudioReturn<TOutput = AudioGenerationResult> {
|
|
|
91
91
|
* </div>
|
|
92
92
|
* ```
|
|
93
93
|
*/
|
|
94
|
-
export function createGenerateAudio<
|
|
95
|
-
TOnResult extends ((result: AudioGenerationResult) => any) | undefined =
|
|
96
|
-
undefined,
|
|
97
|
-
>(
|
|
94
|
+
export function createGenerateAudio<TTransformed = void>(
|
|
98
95
|
options: Omit<CreateGenerateAudioOptions, 'onResult'> & {
|
|
99
|
-
onResult?:
|
|
96
|
+
onResult?: (result: AudioGenerationResult) => TTransformed
|
|
100
97
|
},
|
|
101
98
|
): CreateGenerateAudioReturn<
|
|
102
|
-
|
|
99
|
+
InferGenerationOutputFromReturn<AudioGenerationResult, TTransformed>
|
|
103
100
|
> {
|
|
104
101
|
const devtools = {
|
|
105
102
|
...options.devtools,
|
|
@@ -110,7 +107,7 @@ export function createGenerateAudio<
|
|
|
110
107
|
const gen = createGeneration<
|
|
111
108
|
AudioGenerateInput,
|
|
112
109
|
AudioGenerationResult,
|
|
113
|
-
|
|
110
|
+
TTransformed
|
|
114
111
|
>({
|
|
115
112
|
...options,
|
|
116
113
|
devtools,
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
GenerationClientState,
|
|
7
7
|
GenerationFetcher,
|
|
8
8
|
ImageGenerateInput,
|
|
9
|
-
|
|
9
|
+
InferGenerationOutputFromReturn,
|
|
10
10
|
} from '@tanstack/ai-client'
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -100,15 +100,12 @@ export interface CreateGenerateImageReturn<TOutput = ImageGenerationResult> {
|
|
|
100
100
|
* </div>
|
|
101
101
|
* ```
|
|
102
102
|
*/
|
|
103
|
-
export function createGenerateImage<
|
|
104
|
-
TOnResult extends ((result: ImageGenerationResult) => any) | undefined =
|
|
105
|
-
undefined,
|
|
106
|
-
>(
|
|
103
|
+
export function createGenerateImage<TTransformed = void>(
|
|
107
104
|
options: Omit<CreateGenerateImageOptions, 'onResult'> & {
|
|
108
|
-
onResult?:
|
|
105
|
+
onResult?: (result: ImageGenerationResult) => TTransformed
|
|
109
106
|
},
|
|
110
107
|
): CreateGenerateImageReturn<
|
|
111
|
-
|
|
108
|
+
InferGenerationOutputFromReturn<ImageGenerationResult, TTransformed>
|
|
112
109
|
> {
|
|
113
110
|
const devtools = {
|
|
114
111
|
...options.devtools,
|
|
@@ -119,7 +116,7 @@ export function createGenerateImage<
|
|
|
119
116
|
const gen = createGeneration<
|
|
120
117
|
ImageGenerateInput,
|
|
121
118
|
ImageGenerationResult,
|
|
122
|
-
|
|
119
|
+
TTransformed
|
|
123
120
|
>({
|
|
124
121
|
...options,
|
|
125
122
|
devtools,
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
ConnectConnectionAdapter,
|
|
6
6
|
GenerationClientState,
|
|
7
7
|
GenerationFetcher,
|
|
8
|
-
|
|
8
|
+
InferGenerationOutputFromReturn,
|
|
9
9
|
SpeechGenerateInput,
|
|
10
10
|
} from '@tanstack/ai-client'
|
|
11
11
|
|
|
@@ -91,20 +91,20 @@ export interface CreateGenerateSpeechReturn<TOutput = TTSResult> {
|
|
|
91
91
|
* </div>
|
|
92
92
|
* ```
|
|
93
93
|
*/
|
|
94
|
-
export function createGenerateSpeech<
|
|
95
|
-
TOnResult extends ((result: TTSResult) => any) | undefined = undefined,
|
|
96
|
-
>(
|
|
94
|
+
export function createGenerateSpeech<TTransformed = void>(
|
|
97
95
|
options: Omit<CreateGenerateSpeechOptions, 'onResult'> & {
|
|
98
|
-
onResult?:
|
|
96
|
+
onResult?: (result: TTSResult) => TTransformed
|
|
99
97
|
},
|
|
100
|
-
): CreateGenerateSpeechReturn<
|
|
98
|
+
): CreateGenerateSpeechReturn<
|
|
99
|
+
InferGenerationOutputFromReturn<TTSResult, TTransformed>
|
|
100
|
+
> {
|
|
101
101
|
const devtools = {
|
|
102
102
|
...options.devtools,
|
|
103
103
|
framework: 'svelte',
|
|
104
104
|
hookName: 'createGenerateSpeech',
|
|
105
105
|
outputKind: 'audio' as const,
|
|
106
106
|
}
|
|
107
|
-
const gen = createGeneration<SpeechGenerateInput, TTSResult,
|
|
107
|
+
const gen = createGeneration<SpeechGenerateInput, TTSResult, TTransformed>({
|
|
108
108
|
...options,
|
|
109
109
|
devtools,
|
|
110
110
|
})
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
ConnectConnectionAdapter,
|
|
7
7
|
GenerationClientState,
|
|
8
8
|
GenerationFetcher,
|
|
9
|
-
|
|
9
|
+
InferGenerationOutputFromReturn,
|
|
10
10
|
VideoGenerateInput,
|
|
11
11
|
VideoGenerateResult,
|
|
12
12
|
VideoStatusInfo,
|
|
@@ -108,17 +108,20 @@ export interface CreateGenerateVideoReturn<TOutput = VideoGenerateResult> {
|
|
|
108
108
|
* </div>
|
|
109
109
|
* ```
|
|
110
110
|
*/
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
>(
|
|
111
|
+
// `TTransformed` infers from the `onResult` return position so the callback
|
|
112
|
+
// parameter is typed as `VideoGenerateResult` and `result` narrows to the
|
|
113
|
+
// transform's return. See issue #848.
|
|
114
|
+
export function createGenerateVideo<TTransformed = void>(
|
|
115
115
|
options: Omit<CreateGenerateVideoOptions, 'onResult'> & {
|
|
116
|
-
onResult?:
|
|
116
|
+
onResult?: (result: VideoGenerateResult) => TTransformed
|
|
117
117
|
},
|
|
118
118
|
): CreateGenerateVideoReturn<
|
|
119
|
-
|
|
119
|
+
InferGenerationOutputFromReturn<VideoGenerateResult, TTransformed>
|
|
120
120
|
> {
|
|
121
|
-
type TOutput =
|
|
121
|
+
type TOutput = InferGenerationOutputFromReturn<
|
|
122
|
+
VideoGenerateResult,
|
|
123
|
+
TTransformed
|
|
124
|
+
>
|
|
122
125
|
const clientId =
|
|
123
126
|
options.id ||
|
|
124
127
|
`video-${Date.now()}-${Math.random().toString(36).substring(7)}`
|
|
@@ -145,7 +148,12 @@ export function createGenerateVideo<
|
|
|
145
148
|
hookName: 'createGenerateVideo',
|
|
146
149
|
outputKind: 'video' as const,
|
|
147
150
|
},
|
|
148
|
-
|
|
151
|
+
// The transform's raw return type (`TTransformed`) and the stored output
|
|
152
|
+
// (`TOutput`, with null/void/undefined stripped) are identical at runtime;
|
|
153
|
+
// the cast bridges the relationship that the conditional type hides.
|
|
154
|
+
onResult: ((r: VideoGenerateResult) => options.onResult?.(r)) as (
|
|
155
|
+
result: VideoGenerateResult,
|
|
156
|
+
) => TOutput | null | void,
|
|
149
157
|
onError: (e: Error) => options.onError?.(e),
|
|
150
158
|
onProgress: (p: number, m?: string) => options.onProgress?.(p, m),
|
|
151
159
|
onChunk: (c: StreamChunk) => options.onChunk?.(c),
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
GenerationClientOptions,
|
|
8
8
|
GenerationClientState,
|
|
9
9
|
GenerationFetcher,
|
|
10
|
-
|
|
10
|
+
InferGenerationOutputFromReturn,
|
|
11
11
|
} from '@tanstack/ai-client'
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -103,16 +103,24 @@ export interface CreateGenerationReturn<TOutput> {
|
|
|
103
103
|
* </div>
|
|
104
104
|
* ```
|
|
105
105
|
*/
|
|
106
|
+
// `TTransformed` infers from the `onResult` return position (a covariant
|
|
107
|
+
// inference site that works even for an optional nested property), which types
|
|
108
|
+
// the callback parameter as `TResult` and narrows `result`. Inferring the
|
|
109
|
+
// whole callback as a defaulted type parameter instead collapses to the
|
|
110
|
+
// default, leaving the parameter `any` — a hard error under `strict`. See
|
|
111
|
+
// issue #848.
|
|
106
112
|
export function createGeneration<
|
|
107
113
|
TInput extends Record<string, any>,
|
|
108
114
|
TResult,
|
|
109
|
-
|
|
115
|
+
TTransformed = void,
|
|
110
116
|
>(
|
|
111
117
|
options: Omit<CreateGenerationOptions<TInput, TResult>, 'onResult'> & {
|
|
112
|
-
onResult?:
|
|
118
|
+
onResult?: (result: TResult) => TTransformed
|
|
113
119
|
},
|
|
114
|
-
): CreateGenerationReturn<
|
|
115
|
-
|
|
120
|
+
): CreateGenerationReturn<
|
|
121
|
+
InferGenerationOutputFromReturn<TResult, TTransformed>
|
|
122
|
+
> {
|
|
123
|
+
type TOutput = InferGenerationOutputFromReturn<TResult, TTransformed>
|
|
116
124
|
const clientId =
|
|
117
125
|
options.id || `gen-${Date.now()}-${Math.random().toString(36).substring(7)}`
|
|
118
126
|
|
|
@@ -136,7 +144,12 @@ export function createGeneration<
|
|
|
136
144
|
framework: 'svelte',
|
|
137
145
|
hookName: 'createGeneration',
|
|
138
146
|
},
|
|
139
|
-
|
|
147
|
+
// The transform's raw return type (`TTransformed`) and the stored output
|
|
148
|
+
// (`TOutput`, with null/void/undefined stripped) are identical at runtime;
|
|
149
|
+
// the cast bridges the relationship that the conditional type hides.
|
|
150
|
+
onResult: ((r: TResult) => options.onResult?.(r)) as (
|
|
151
|
+
result: TResult,
|
|
152
|
+
) => TOutput | null | void,
|
|
140
153
|
onError: (e: Error) => options.onError?.(e),
|
|
141
154
|
onProgress: (p: number, m?: string) => options.onProgress?.(p, m),
|
|
142
155
|
onChunk: (c: StreamChunk) => options.onChunk?.(c),
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
ConnectConnectionAdapter,
|
|
6
6
|
GenerationClientState,
|
|
7
7
|
GenerationFetcher,
|
|
8
|
-
|
|
8
|
+
InferGenerationOutputFromReturn,
|
|
9
9
|
SummarizeGenerateInput,
|
|
10
10
|
} from '@tanstack/ai-client'
|
|
11
11
|
|
|
@@ -95,15 +95,12 @@ export interface CreateSummarizeReturn<TOutput = SummarizationResult> {
|
|
|
95
95
|
* </div>
|
|
96
96
|
* ```
|
|
97
97
|
*/
|
|
98
|
-
export function createSummarize<
|
|
99
|
-
TOnResult extends ((result: SummarizationResult) => any) | undefined =
|
|
100
|
-
undefined,
|
|
101
|
-
>(
|
|
98
|
+
export function createSummarize<TTransformed = void>(
|
|
102
99
|
options: Omit<CreateSummarizeOptions, 'onResult'> & {
|
|
103
|
-
onResult?:
|
|
100
|
+
onResult?: (result: SummarizationResult) => TTransformed
|
|
104
101
|
},
|
|
105
102
|
): CreateSummarizeReturn<
|
|
106
|
-
|
|
103
|
+
InferGenerationOutputFromReturn<SummarizationResult, TTransformed>
|
|
107
104
|
> {
|
|
108
105
|
const devtools = {
|
|
109
106
|
...options.devtools,
|
|
@@ -114,7 +111,7 @@ export function createSummarize<
|
|
|
114
111
|
const gen = createGeneration<
|
|
115
112
|
SummarizeGenerateInput,
|
|
116
113
|
SummarizationResult,
|
|
117
|
-
|
|
114
|
+
TTransformed
|
|
118
115
|
>({
|
|
119
116
|
...options,
|
|
120
117
|
devtools,
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
ConnectConnectionAdapter,
|
|
6
6
|
GenerationClientState,
|
|
7
7
|
GenerationFetcher,
|
|
8
|
-
|
|
8
|
+
InferGenerationOutputFromReturn,
|
|
9
9
|
TranscriptionGenerateInput,
|
|
10
10
|
} from '@tanstack/ai-client'
|
|
11
11
|
|
|
@@ -100,15 +100,12 @@ export interface CreateTranscriptionReturn<TOutput = TranscriptionResult> {
|
|
|
100
100
|
* </div>
|
|
101
101
|
* ```
|
|
102
102
|
*/
|
|
103
|
-
export function createTranscription<
|
|
104
|
-
TOnResult extends ((result: TranscriptionResult) => any) | undefined =
|
|
105
|
-
undefined,
|
|
106
|
-
>(
|
|
103
|
+
export function createTranscription<TTransformed = void>(
|
|
107
104
|
options: Omit<CreateTranscriptionOptions, 'onResult'> & {
|
|
108
|
-
onResult?:
|
|
105
|
+
onResult?: (result: TranscriptionResult) => TTransformed
|
|
109
106
|
},
|
|
110
107
|
): CreateTranscriptionReturn<
|
|
111
|
-
|
|
108
|
+
InferGenerationOutputFromReturn<TranscriptionResult, TTransformed>
|
|
112
109
|
> {
|
|
113
110
|
const devtools = {
|
|
114
111
|
...options.devtools,
|
|
@@ -119,7 +116,7 @@ export function createTranscription<
|
|
|
119
116
|
const gen = createGeneration<
|
|
120
117
|
TranscriptionGenerateInput,
|
|
121
118
|
TranscriptionResult,
|
|
122
|
-
|
|
119
|
+
TTransformed
|
|
123
120
|
>({
|
|
124
121
|
...options,
|
|
125
122
|
devtools,
|
package/src/index.ts
CHANGED
|
@@ -50,6 +50,12 @@ export type {
|
|
|
50
50
|
CreateGenerateVideoReturn,
|
|
51
51
|
} from './create-generate-video.svelte'
|
|
52
52
|
|
|
53
|
+
export { createAudioRecorder } from './create-audio-recorder.svelte'
|
|
54
|
+
export type {
|
|
55
|
+
CreateAudioRecorderOptions,
|
|
56
|
+
CreateAudioRecorderReturn,
|
|
57
|
+
} from './create-audio-recorder.svelte'
|
|
58
|
+
|
|
53
59
|
// Re-export from ai-client for convenience
|
|
54
60
|
export {
|
|
55
61
|
fetchServerSentEvents,
|