@tanstack/ai-svelte 0.6.2 → 0.6.4

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.
@@ -0,0 +1,110 @@
1
+ import { GenerationClient } from '@tanstack/ai-client';
2
+ /**
3
+ * Creates a reactive generation instance for Svelte 5.
4
+ *
5
+ * This is the base function used by `createGenerateImage`, `createGenerateSpeech`,
6
+ * `createTranscription`, and `createSummarize`. You can also use it directly
7
+ * for custom generation types.
8
+ *
9
+ * @template TInput - The input type for the generation request
10
+ * @template TResult - The result type returned by the generation
11
+ *
12
+ * @example
13
+ * ```svelte
14
+ * <script>
15
+ * import { createGeneration, fetchServerSentEvents } from '@tanstack/ai-svelte'
16
+ *
17
+ * const gen = createGeneration({
18
+ * connection: fetchServerSentEvents('/api/generate/custom'),
19
+ * })
20
+ * </script>
21
+ *
22
+ * <div>
23
+ * <button onclick={() => gen.generate({ prompt: 'Hello' })}>Generate</button>
24
+ * {#if gen.isLoading}
25
+ * <p>Generating...</p>
26
+ * {/if}
27
+ * {#if gen.result}
28
+ * <p>{JSON.stringify(gen.result)}</p>
29
+ * {/if}
30
+ * </div>
31
+ * ```
32
+ */
33
+ export function createGeneration(options) {
34
+ const clientId = options.id || `gen-${Date.now()}-${Math.random().toString(36).substring(7)}`;
35
+ // Create reactive state using Svelte 5 runes
36
+ let result = $state(null);
37
+ let isLoading = $state(false);
38
+ let error = $state(undefined);
39
+ let status = $state('idle');
40
+ const clientOptions = {
41
+ id: clientId,
42
+ body: options.body,
43
+ onResult: (r) => options.onResult?.(r),
44
+ onError: (e) => options.onError?.(e),
45
+ onProgress: (p, m) => options.onProgress?.(p, m),
46
+ onChunk: (c) => options.onChunk?.(c),
47
+ onResultChange: (r) => {
48
+ result = r;
49
+ },
50
+ onLoadingChange: (l) => {
51
+ isLoading = l;
52
+ },
53
+ onErrorChange: (e) => {
54
+ error = e;
55
+ },
56
+ onStatusChange: (s) => {
57
+ status = s;
58
+ },
59
+ };
60
+ let client;
61
+ if (options.connection) {
62
+ client = new GenerationClient({
63
+ ...clientOptions,
64
+ connection: options.connection,
65
+ });
66
+ }
67
+ else if (options.fetcher) {
68
+ client = new GenerationClient({
69
+ ...clientOptions,
70
+ fetcher: options.fetcher,
71
+ });
72
+ }
73
+ else {
74
+ throw new Error('createGeneration requires either a connection or fetcher option');
75
+ }
76
+ // Note: Cleanup is handled by calling stop() directly when needed.
77
+ // Unlike React/Vue/Solid, Svelte 5 runes like $effect can only be used
78
+ // during component initialization, so we don't add automatic cleanup here.
79
+ // Users should call gen.stop() in their component's cleanup if needed.
80
+ const generate = async (input) => {
81
+ await client.generate(input);
82
+ };
83
+ const stop = () => {
84
+ client.stop();
85
+ };
86
+ const reset = () => {
87
+ client.reset();
88
+ };
89
+ const updateBody = (newBody) => {
90
+ client.updateOptions({ body: newBody });
91
+ };
92
+ return {
93
+ get result() {
94
+ return result;
95
+ },
96
+ get isLoading() {
97
+ return isLoading;
98
+ },
99
+ get error() {
100
+ return error;
101
+ },
102
+ get status() {
103
+ return status;
104
+ },
105
+ generate: generate,
106
+ stop,
107
+ reset,
108
+ updateBody,
109
+ };
110
+ }
@@ -0,0 +1,87 @@
1
+ import type { StreamChunk, SummarizationResult } from '@tanstack/ai';
2
+ import type { ConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutput, SummarizeGenerateInput } from '@tanstack/ai-client';
3
+ /**
4
+ * Options for the createSummarize function.
5
+ *
6
+ * @template TOutput - The output type after optional transform (defaults to SummarizationResult)
7
+ */
8
+ export interface CreateSummarizeOptions<TOutput = SummarizationResult> {
9
+ /** Connection adapter for streaming transport (SSE, HTTP stream, custom) */
10
+ connection?: ConnectionAdapter;
11
+ /** Direct async function for summarization */
12
+ fetcher?: GenerationFetcher<SummarizeGenerateInput, SummarizationResult>;
13
+ /** Unique identifier for this generation instance */
14
+ id?: string;
15
+ /** Additional body parameters to send with ConnectionAdapter requests */
16
+ body?: Record<string, any>;
17
+ /**
18
+ * Callback when summarization is complete. Can optionally return a transformed value.
19
+ *
20
+ * - Return a non-null value to transform and store it as the result
21
+ * - Return `null` to keep the previous result unchanged
22
+ * - Return nothing (`void`) to store the raw result as-is
23
+ */
24
+ onResult?: (result: SummarizationResult) => TOutput | null | void;
25
+ /** Callback when an error occurs */
26
+ onError?: (error: Error) => void;
27
+ /** Callback when progress is reported (0-100) */
28
+ onProgress?: (progress: number, message?: string) => void;
29
+ /** Callback for each stream chunk (ConnectionAdapter mode only) */
30
+ onChunk?: (chunk: StreamChunk) => void;
31
+ }
32
+ /**
33
+ * Return type for the createSummarize function.
34
+ *
35
+ * @template TOutput - The output type (after optional transform)
36
+ */
37
+ export interface CreateSummarizeReturn<TOutput = SummarizationResult> {
38
+ /** The summarization result, or null */
39
+ readonly result: TOutput | null;
40
+ /** Whether summarization is in progress */
41
+ readonly isLoading: boolean;
42
+ /** Current error, if any */
43
+ readonly error: Error | undefined;
44
+ /** Current state of the generation */
45
+ readonly status: GenerationClientState;
46
+ /** Trigger summarization */
47
+ generate: (input: SummarizeGenerateInput) => Promise<void>;
48
+ /** Abort the current summarization */
49
+ stop: () => void;
50
+ /** Clear result, error, and return to idle */
51
+ reset: () => void;
52
+ /** Update additional body parameters */
53
+ updateBody: (body: Record<string, any>) => void;
54
+ }
55
+ /**
56
+ * Creates a reactive text summarization instance for Svelte 5.
57
+ *
58
+ * @example
59
+ * ```svelte
60
+ * <script>
61
+ * import { createSummarize, fetchServerSentEvents } from '@tanstack/ai-svelte'
62
+ *
63
+ * const summarizer = createSummarize({
64
+ * connection: fetchServerSentEvents('/api/summarize'),
65
+ * })
66
+ * </script>
67
+ *
68
+ * <div>
69
+ * <button onclick={() => summarizer.generate({
70
+ * text: 'Long article text...',
71
+ * style: 'bullet-points',
72
+ * maxLength: 200,
73
+ * })}>
74
+ * Summarize
75
+ * </button>
76
+ * {#if summarizer.isLoading}
77
+ * <p>Summarizing...</p>
78
+ * {/if}
79
+ * {#if summarizer.result}
80
+ * <p>{summarizer.result.summary}</p>
81
+ * {/if}
82
+ * </div>
83
+ * ```
84
+ */
85
+ export declare function createSummarize<TOnResult extends ((result: SummarizationResult) => any) | undefined = undefined>(options: Omit<CreateSummarizeOptions, 'onResult'> & {
86
+ onResult?: TOnResult;
87
+ }): CreateSummarizeReturn<InferGenerationOutput<SummarizationResult, TOnResult>>;
@@ -0,0 +1,52 @@
1
+ import { createGeneration } from './create-generation.svelte';
2
+ /**
3
+ * Creates a reactive text summarization instance for Svelte 5.
4
+ *
5
+ * @example
6
+ * ```svelte
7
+ * <script>
8
+ * import { createSummarize, fetchServerSentEvents } from '@tanstack/ai-svelte'
9
+ *
10
+ * const summarizer = createSummarize({
11
+ * connection: fetchServerSentEvents('/api/summarize'),
12
+ * })
13
+ * </script>
14
+ *
15
+ * <div>
16
+ * <button onclick={() => summarizer.generate({
17
+ * text: 'Long article text...',
18
+ * style: 'bullet-points',
19
+ * maxLength: 200,
20
+ * })}>
21
+ * Summarize
22
+ * </button>
23
+ * {#if summarizer.isLoading}
24
+ * <p>Summarizing...</p>
25
+ * {/if}
26
+ * {#if summarizer.result}
27
+ * <p>{summarizer.result.summary}</p>
28
+ * {/if}
29
+ * </div>
30
+ * ```
31
+ */
32
+ export function createSummarize(options) {
33
+ const gen = createGeneration(options);
34
+ return {
35
+ get result() {
36
+ return gen.result;
37
+ },
38
+ get isLoading() {
39
+ return gen.isLoading;
40
+ },
41
+ get error() {
42
+ return gen.error;
43
+ },
44
+ get status() {
45
+ return gen.status;
46
+ },
47
+ generate: gen.generate,
48
+ stop: gen.stop,
49
+ reset: gen.reset,
50
+ updateBody: gen.updateBody,
51
+ };
52
+ }
@@ -0,0 +1,92 @@
1
+ import type { StreamChunk, TranscriptionResult } from '@tanstack/ai';
2
+ import type { ConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutput, TranscriptionGenerateInput } from '@tanstack/ai-client';
3
+ /**
4
+ * Options for the createTranscription function.
5
+ *
6
+ * @template TOutput - The output type after optional transform (defaults to TranscriptionResult)
7
+ */
8
+ export interface CreateTranscriptionOptions<TOutput = TranscriptionResult> {
9
+ /** Connection adapter for streaming transport (SSE, HTTP stream, custom) */
10
+ connection?: ConnectionAdapter;
11
+ /** Direct async function for transcription */
12
+ fetcher?: GenerationFetcher<TranscriptionGenerateInput, TranscriptionResult>;
13
+ /** Unique identifier for this generation instance */
14
+ id?: string;
15
+ /** Additional body parameters to send with ConnectionAdapter requests */
16
+ body?: Record<string, any>;
17
+ /**
18
+ * Callback when transcription is complete. Can optionally return a transformed value.
19
+ *
20
+ * - Return a non-null value to transform and store it as the result
21
+ * - Return `null` to keep the previous result unchanged
22
+ * - Return nothing (`void`) to store the raw result as-is
23
+ */
24
+ onResult?: (result: TranscriptionResult) => TOutput | null | void;
25
+ /** Callback when an error occurs */
26
+ onError?: (error: Error) => void;
27
+ /** Callback when progress is reported (0-100) */
28
+ onProgress?: (progress: number, message?: string) => void;
29
+ /** Callback for each stream chunk (ConnectionAdapter mode only) */
30
+ onChunk?: (chunk: StreamChunk) => void;
31
+ }
32
+ /**
33
+ * Return type for the createTranscription function.
34
+ *
35
+ * @template TOutput - The output type (after optional transform)
36
+ */
37
+ export interface CreateTranscriptionReturn<TOutput = TranscriptionResult> {
38
+ /** The transcription result, or null */
39
+ readonly result: TOutput | null;
40
+ /** Whether transcription is in progress */
41
+ readonly isLoading: boolean;
42
+ /** Current error, if any */
43
+ readonly error: Error | undefined;
44
+ /** Current state of the generation */
45
+ readonly status: GenerationClientState;
46
+ /** Trigger transcription */
47
+ generate: (input: TranscriptionGenerateInput) => Promise<void>;
48
+ /** Abort the current transcription */
49
+ stop: () => void;
50
+ /** Clear result, error, and return to idle */
51
+ reset: () => void;
52
+ /** Update additional body parameters */
53
+ updateBody: (body: Record<string, any>) => void;
54
+ }
55
+ /**
56
+ * Creates a reactive audio transcription instance for Svelte 5.
57
+ *
58
+ * @example
59
+ * ```svelte
60
+ * <script>
61
+ * import { createTranscription, fetchServerSentEvents } from '@tanstack/ai-svelte'
62
+ *
63
+ * const transcription = createTranscription({
64
+ * connection: fetchServerSentEvents('/api/transcribe'),
65
+ * })
66
+ *
67
+ * function handleFile(e) {
68
+ * const file = e.target.files?.[0]
69
+ * if (file) {
70
+ * const reader = new FileReader()
71
+ * reader.onload = () => {
72
+ * transcription.generate({ audio: reader.result, language: 'en' })
73
+ * }
74
+ * reader.readAsDataURL(file)
75
+ * }
76
+ * }
77
+ * </script>
78
+ *
79
+ * <div>
80
+ * <input type="file" accept="audio/*" onchange={handleFile} />
81
+ * {#if transcription.isLoading}
82
+ * <p>Transcribing...</p>
83
+ * {/if}
84
+ * {#if transcription.result}
85
+ * <p>{transcription.result.text}</p>
86
+ * {/if}
87
+ * </div>
88
+ * ```
89
+ */
90
+ export declare function createTranscription<TOnResult extends ((result: TranscriptionResult) => any) | undefined = undefined>(options: Omit<CreateTranscriptionOptions, 'onResult'> & {
91
+ onResult?: TOnResult;
92
+ }): CreateTranscriptionReturn<InferGenerationOutput<TranscriptionResult, TOnResult>>;
@@ -0,0 +1,57 @@
1
+ import { createGeneration } from './create-generation.svelte';
2
+ /**
3
+ * Creates a reactive audio transcription instance for Svelte 5.
4
+ *
5
+ * @example
6
+ * ```svelte
7
+ * <script>
8
+ * import { createTranscription, fetchServerSentEvents } from '@tanstack/ai-svelte'
9
+ *
10
+ * const transcription = createTranscription({
11
+ * connection: fetchServerSentEvents('/api/transcribe'),
12
+ * })
13
+ *
14
+ * function handleFile(e) {
15
+ * const file = e.target.files?.[0]
16
+ * if (file) {
17
+ * const reader = new FileReader()
18
+ * reader.onload = () => {
19
+ * transcription.generate({ audio: reader.result, language: 'en' })
20
+ * }
21
+ * reader.readAsDataURL(file)
22
+ * }
23
+ * }
24
+ * </script>
25
+ *
26
+ * <div>
27
+ * <input type="file" accept="audio/*" onchange={handleFile} />
28
+ * {#if transcription.isLoading}
29
+ * <p>Transcribing...</p>
30
+ * {/if}
31
+ * {#if transcription.result}
32
+ * <p>{transcription.result.text}</p>
33
+ * {/if}
34
+ * </div>
35
+ * ```
36
+ */
37
+ export function createTranscription(options) {
38
+ const gen = createGeneration(options);
39
+ return {
40
+ get result() {
41
+ return gen.result;
42
+ },
43
+ get isLoading() {
44
+ return gen.isLoading;
45
+ },
46
+ get error() {
47
+ return gen.error;
48
+ },
49
+ get status() {
50
+ return gen.status;
51
+ },
52
+ generate: gen.generate,
53
+ stop: gen.stop,
54
+ reset: gen.reset,
55
+ updateBody: gen.updateBody,
56
+ };
57
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,15 @@
1
1
  export { createChat } from './create-chat.svelte';
2
2
  export type { CreateChatOptions, CreateChatReturn, UIMessage, ChatRequestBody, } from './types';
3
- export { fetchServerSentEvents, fetchHttpStream, stream, createChatClientOptions, clientTools, type ConnectionAdapter, type FetchConnectionOptions, type InferChatMessages, } from '@tanstack/ai-client';
3
+ export { createGeneration } from './create-generation.svelte';
4
+ export type { CreateGenerationOptions, CreateGenerationReturn, } from './create-generation.svelte';
5
+ export { createGenerateImage } from './create-generate-image.svelte';
6
+ export type { CreateGenerateImageOptions, CreateGenerateImageReturn, } from './create-generate-image.svelte';
7
+ export { createGenerateSpeech } from './create-generate-speech.svelte';
8
+ export type { CreateGenerateSpeechOptions, CreateGenerateSpeechReturn, } from './create-generate-speech.svelte';
9
+ export { createTranscription } from './create-transcription.svelte';
10
+ export type { CreateTranscriptionOptions, CreateTranscriptionReturn, } from './create-transcription.svelte';
11
+ export { createSummarize } from './create-summarize.svelte';
12
+ export type { CreateSummarizeOptions, CreateSummarizeReturn, } from './create-summarize.svelte';
13
+ export { createGenerateVideo } from './create-generate-video.svelte';
14
+ export type { CreateGenerateVideoOptions, CreateGenerateVideoReturn, } from './create-generate-video.svelte';
15
+ export { fetchServerSentEvents, fetchHttpStream, stream, createChatClientOptions, clientTools, type ConnectionAdapter, type FetchConnectionOptions, type InferChatMessages, type GenerationClientState, type ImageGenerateInput, type SpeechGenerateInput, type TranscriptionGenerateInput, type SummarizeGenerateInput, type VideoGenerateInput, type VideoGenerateResult, type VideoStatusInfo, } from '@tanstack/ai-client';
package/dist/index.js CHANGED
@@ -1,3 +1,10 @@
1
1
  export { createChat } from './create-chat.svelte';
2
+ // Generation hooks
3
+ export { createGeneration } from './create-generation.svelte';
4
+ export { createGenerateImage } from './create-generate-image.svelte';
5
+ export { createGenerateSpeech } from './create-generate-speech.svelte';
6
+ export { createTranscription } from './create-transcription.svelte';
7
+ export { createSummarize } from './create-summarize.svelte';
8
+ export { createGenerateVideo } from './create-generate-video.svelte';
2
9
  // Re-export from ai-client for convenience
3
10
  export { fetchServerSentEvents, fetchHttpStream, stream, 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.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Svelte bindings for TanStack AI",
5
5
  "author": "",
6
6
  "license": "MIT",
@@ -33,11 +33,11 @@
33
33
  "streaming"
34
34
  ],
35
35
  "dependencies": {
36
- "@tanstack/ai-client": "0.5.2"
36
+ "@tanstack/ai-client": "0.6.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "svelte": "^5.0.0",
40
- "@tanstack/ai": "^0.6.1"
40
+ "@tanstack/ai": "^0.6.3"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@sveltejs/package": "^2.3.10",
@@ -49,7 +49,7 @@
49
49
  "svelte-check": "^4.2.0",
50
50
  "typescript": "5.9.3",
51
51
  "vite": "^7.2.7",
52
- "@tanstack/ai": "0.6.1"
52
+ "@tanstack/ai": "0.6.3"
53
53
  },
54
54
  "scripts": {
55
55
  "clean": "rm -rf ./dist",
@@ -0,0 +1,134 @@
1
+ import { createGeneration } from './create-generation.svelte'
2
+ import type { ImageGenerationResult, StreamChunk } from '@tanstack/ai'
3
+ import type {
4
+ ConnectionAdapter,
5
+ GenerationClientState,
6
+ GenerationFetcher,
7
+ ImageGenerateInput,
8
+ InferGenerationOutput,
9
+ } from '@tanstack/ai-client'
10
+
11
+ /**
12
+ * Options for the createGenerateImage function.
13
+ *
14
+ * @template TOutput - The output type after optional transform (defaults to ImageGenerationResult)
15
+ */
16
+ export interface CreateGenerateImageOptions<TOutput = ImageGenerationResult> {
17
+ /** Connection adapter for streaming transport (SSE, HTTP stream, custom) */
18
+ connection?: ConnectionAdapter
19
+ /** Direct async function for image generation */
20
+ fetcher?: GenerationFetcher<ImageGenerateInput, ImageGenerationResult>
21
+ /** Unique identifier for this generation instance */
22
+ id?: string
23
+ /** Additional body parameters to send with ConnectionAdapter requests */
24
+ body?: Record<string, any>
25
+ /**
26
+ * Callback when images are generated. Can optionally return a transformed value.
27
+ *
28
+ * - Return a non-null value to transform and store it as the result
29
+ * - Return `null` to keep the previous result unchanged
30
+ * - Return nothing (`void`) to store the raw result as-is
31
+ */
32
+ onResult?: (result: ImageGenerationResult) => TOutput | null | void
33
+ /** Callback when an error occurs */
34
+ onError?: (error: Error) => void
35
+ /** Callback when progress is reported (0-100) */
36
+ onProgress?: (progress: number, message?: string) => void
37
+ /** Callback for each stream chunk (ConnectionAdapter mode only) */
38
+ onChunk?: (chunk: StreamChunk) => void
39
+ }
40
+
41
+ /**
42
+ * Return type for the createGenerateImage function.
43
+ *
44
+ * @template TOutput - The output type (after optional transform)
45
+ */
46
+ export interface CreateGenerateImageReturn<TOutput = ImageGenerationResult> {
47
+ /** The generation result containing images, or null */
48
+ readonly result: TOutput | null
49
+ /** Whether generation is in progress */
50
+ readonly isLoading: boolean
51
+ /** Current error, if any */
52
+ readonly error: Error | undefined
53
+ /** Current state of the generation */
54
+ readonly status: GenerationClientState
55
+ /** Trigger image generation */
56
+ generate: (input: ImageGenerateInput) => Promise<void>
57
+ /** Abort the current generation */
58
+ stop: () => void
59
+ /** Clear result, error, and return to idle */
60
+ reset: () => void
61
+ /** Update additional body parameters */
62
+ updateBody: (body: Record<string, any>) => void
63
+ }
64
+
65
+ /**
66
+ * Creates a reactive image generation instance for Svelte 5.
67
+ *
68
+ * Supports two transport modes:
69
+ * - **ConnectionAdapter** -- Streaming transport (SSE, HTTP stream, custom)
70
+ * - **Fetcher** -- Direct async function call
71
+ *
72
+ * @example
73
+ * ```svelte
74
+ * <script>
75
+ * import { createGenerateImage, fetchServerSentEvents } from '@tanstack/ai-svelte'
76
+ *
77
+ * const imageGen = createGenerateImage({
78
+ * connection: fetchServerSentEvents('/api/generate/image'),
79
+ * })
80
+ * </script>
81
+ *
82
+ * <div>
83
+ * <button onclick={() => imageGen.generate({ prompt: 'A sunset over mountains' })}>
84
+ * Generate
85
+ * </button>
86
+ * {#if imageGen.isLoading}
87
+ * <p>Generating...</p>
88
+ * {/if}
89
+ * {#if imageGen.error}
90
+ * <p>Error: {imageGen.error.message}</p>
91
+ * {/if}
92
+ * {#if imageGen.result}
93
+ * {#each imageGen.result.images as img}
94
+ * <img src={img.url || `data:image/png;base64,${img.b64Json}`} alt="Generated" />
95
+ * {/each}
96
+ * {/if}
97
+ * </div>
98
+ * ```
99
+ */
100
+ export function createGenerateImage<
101
+ TOnResult extends ((result: ImageGenerationResult) => any) | undefined =
102
+ undefined,
103
+ >(
104
+ options: Omit<CreateGenerateImageOptions, 'onResult'> & {
105
+ onResult?: TOnResult
106
+ },
107
+ ): CreateGenerateImageReturn<
108
+ InferGenerationOutput<ImageGenerationResult, TOnResult>
109
+ > {
110
+ const gen = createGeneration<
111
+ ImageGenerateInput,
112
+ ImageGenerationResult,
113
+ TOnResult
114
+ >(options)
115
+
116
+ return {
117
+ get result() {
118
+ return gen.result
119
+ },
120
+ get isLoading() {
121
+ return gen.isLoading
122
+ },
123
+ get error() {
124
+ return gen.error
125
+ },
126
+ get status() {
127
+ return gen.status
128
+ },
129
+ generate: gen.generate as (input: ImageGenerateInput) => Promise<void>,
130
+ stop: gen.stop,
131
+ reset: gen.reset,
132
+ updateBody: gen.updateBody,
133
+ }
134
+ }