@tanstack/ai-octane 0.0.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.
@@ -0,0 +1,245 @@
1
+ import { VideoGenerationClient } from '@tanstack/ai-client'
2
+ import { createVideoDevtoolsBridge } from '@tanstack/ai-client/devtools'
3
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'octane'
4
+ import type { StreamChunk } from '@tanstack/ai'
5
+ import type {
6
+ AIDevtoolsDisplayOptions,
7
+ ConnectConnectionAdapter,
8
+ GenerationClientState,
9
+ GenerationFetcher,
10
+ InferGenerationOutputFromReturn,
11
+ VideoGenerateInput,
12
+ VideoGenerateResult,
13
+ VideoStatusInfo,
14
+ } from '@tanstack/ai-client'
15
+
16
+ /**
17
+ * Options for the useGenerateVideo hook.
18
+ */
19
+ export interface UseGenerateVideoOptions<TOutput = VideoGenerateResult> {
20
+ /** Connect-based adapter for streaming transport (server handles polling) */
21
+ connection?: ConnectConnectionAdapter
22
+ /** Direct async function that returns a completed video result */
23
+ fetcher?: GenerationFetcher<VideoGenerateInput, VideoGenerateResult>
24
+ /** Unique identifier for this generation instance */
25
+ id?: string
26
+ /** Additional body parameters to send with connect-based adapter requests */
27
+ body?: Record<string, any>
28
+ /** Display options for TanStack AI Devtools. */
29
+ devtools?: AIDevtoolsDisplayOptions
30
+ /**
31
+ * Callback when video generation completes. Can optionally return a transformed value.
32
+ *
33
+ * - Return a non-null value to transform and store it as the result
34
+ * - Return `null` to keep the previous result unchanged
35
+ * - Return nothing (`void`) to store the raw result as-is
36
+ */
37
+ onResult?: (result: VideoGenerateResult) => TOutput | null | void
38
+ /** Callback when an error occurs */
39
+ onError?: (error: Error) => void
40
+ /** Callback when progress is reported (0-100) */
41
+ onProgress?: (progress: number, message?: string) => void
42
+ /** Callback when a video job is created */
43
+ onJobCreated?: (jobId: string) => void
44
+ /** Callback on each status update */
45
+ onStatusUpdate?: (status: VideoStatusInfo) => void
46
+ /** Callback for each stream chunk (connect-based adapter mode only) */
47
+ onChunk?: (chunk: StreamChunk) => void
48
+ }
49
+
50
+ /**
51
+ * Return type for the useGenerateVideo hook.
52
+ *
53
+ * @template TOutput - The output type (after optional transform)
54
+ */
55
+ export interface UseGenerateVideoReturn<TOutput = VideoGenerateResult> {
56
+ /** Trigger video generation */
57
+ generate: (input: VideoGenerateInput) => Promise<void>
58
+ /** The final video result (with URL), or null */
59
+ result: TOutput | null
60
+ /** The current job ID, or null */
61
+ jobId: string | null
62
+ /** Current video generation status info, or null */
63
+ videoStatus: VideoStatusInfo | null
64
+ /** Whether generation/polling is in progress */
65
+ isLoading: boolean
66
+ /** Current error, if any */
67
+ error: Error | undefined
68
+ /** Current state of the generation */
69
+ status: GenerationClientState
70
+ /** Abort the current generation/polling */
71
+ stop: () => void
72
+ /** Clear all state and return to idle */
73
+ reset: () => void
74
+ }
75
+
76
+ /**
77
+ * Octane hook for generating videos using AI models.
78
+ *
79
+ * Video generation is asynchronous: a job is created, then polled for status
80
+ * until completion. This hook handles the full lifecycle.
81
+ *
82
+ * @example
83
+ * ```tsx
84
+ * import { useGenerateVideo } from '@tanstack/ai-octane'
85
+ * import { fetchServerSentEvents } from '@tanstack/ai-client'
86
+ *
87
+ * function VideoGenerator() {
88
+ * const { generate, result, videoStatus, isLoading } = useGenerateVideo({
89
+ * connection: fetchServerSentEvents('/api/generate/video'),
90
+ * onStatusUpdate: (status) => console.log(`Progress: ${status.progress}%`),
91
+ * })
92
+ *
93
+ * return (
94
+ * <div>
95
+ * <button onClick={() => generate({ prompt: 'A flying car over a city' })}>
96
+ * Generate Video
97
+ * </button>
98
+ * {isLoading && videoStatus && (
99
+ * <p>Status: {videoStatus.status} ({videoStatus.progress}%)</p>
100
+ * )}
101
+ * {result && <video src={result.url} controls />}
102
+ * </div>
103
+ * )
104
+ * }
105
+ * ```
106
+ */
107
+ // `TTransformed` infers from the `onResult` return position so the callback
108
+ // parameter is typed as `VideoGenerateResult` and `result` narrows to the
109
+ // transform's return. See issue #848.
110
+ export function useGenerateVideo<TTransformed = void>(
111
+ options: Omit<UseGenerateVideoOptions, 'onResult'> & {
112
+ onResult?: (result: VideoGenerateResult) => TTransformed
113
+ },
114
+ ): UseGenerateVideoReturn<
115
+ InferGenerationOutputFromReturn<VideoGenerateResult, TTransformed>
116
+ > {
117
+ type TOutput = InferGenerationOutputFromReturn<
118
+ VideoGenerateResult,
119
+ TTransformed
120
+ >
121
+ const hookId = useId()
122
+ const clientId = options.id || hookId
123
+
124
+ const [result, setResult] = useState<TOutput | null>(null)
125
+ const [jobId, setJobId] = useState<string | null>(null)
126
+ const [videoStatus, setVideoStatus] = useState<VideoStatusInfo | null>(null)
127
+ const [isLoading, setIsLoading] = useState(false)
128
+ const [error, setError] = useState<Error | undefined>(undefined)
129
+ const [status, setStatus] = useState<GenerationClientState>('idle')
130
+
131
+ const optionsRef = useRef(options)
132
+ optionsRef.current = options
133
+
134
+ const client = useMemo(() => {
135
+ const opts = optionsRef.current
136
+
137
+ // Conditional spread for `body` (strict-optional in target).
138
+ // Optional callbacks are wrapped in non-returning bodies so
139
+ // `?.()`'s implicit `undefined` doesn't widen the function
140
+ // return type (which `exactOptionalPropertyTypes` rejects
141
+ // against the strict-optional target).
142
+ const baseOptions = {
143
+ id: clientId,
144
+ body: opts.body,
145
+ devtoolsBridgeFactory: createVideoDevtoolsBridge,
146
+ devtools: {
147
+ ...opts.devtools,
148
+ // OCTANE DIVERGENCE: identify this binding as Octane (not 'react') in TanStack AI Devtools.
149
+ framework: 'octane',
150
+ hookName: 'useGenerateVideo',
151
+ outputKind: 'video' as const,
152
+ },
153
+ // The transform's raw return type (`TTransformed`) and the stored output
154
+ // (`TOutput`, with null/void/undefined stripped) are identical at runtime;
155
+ // the cast bridges the relationship that the conditional type hides.
156
+ onResult: ((r: VideoGenerateResult) =>
157
+ optionsRef.current.onResult?.(r)) as (
158
+ result: VideoGenerateResult,
159
+ ) => TOutput | null | void,
160
+ onError: (e: Error) => {
161
+ optionsRef.current.onError?.(e)
162
+ },
163
+ onProgress: (p: number, m?: string) => {
164
+ optionsRef.current.onProgress?.(p, m)
165
+ },
166
+ onChunk: (c: StreamChunk) => {
167
+ optionsRef.current.onChunk?.(c)
168
+ },
169
+ onJobCreated: (id: string) => {
170
+ optionsRef.current.onJobCreated?.(id)
171
+ },
172
+ onStatusUpdate: (s: VideoStatusInfo) => {
173
+ optionsRef.current.onStatusUpdate?.(s)
174
+ },
175
+ onResultChange: setResult,
176
+ onLoadingChange: setIsLoading,
177
+ onErrorChange: setError,
178
+ onStatusChange: setStatus,
179
+ onJobIdChange: setJobId,
180
+ onVideoStatusChange: setVideoStatus,
181
+ }
182
+
183
+ if (opts.connection) {
184
+ return new VideoGenerationClient<TOutput>({
185
+ ...baseOptions,
186
+ connection: opts.connection,
187
+ })
188
+ }
189
+
190
+ if (opts.fetcher) {
191
+ return new VideoGenerationClient<TOutput>({
192
+ ...baseOptions,
193
+ fetcher: opts.fetcher,
194
+ })
195
+ }
196
+
197
+ throw new Error(
198
+ 'useGenerateVideo requires either a connection or fetcher option',
199
+ )
200
+ }, [clientId])
201
+
202
+ // Sync body changes without recreating client
203
+ useEffect(() => {
204
+ // Conditional spread: target uses strict-optional `body?: T`.
205
+ client.updateOptions({
206
+ ...(options.body !== undefined && { body: options.body }),
207
+ })
208
+ }, [client, options.body])
209
+
210
+ // Cleanup on unmount
211
+ useEffect(() => {
212
+ client.mountDevtools()
213
+
214
+ return () => {
215
+ client.dispose()
216
+ }
217
+ }, [client])
218
+
219
+ const generate = useCallback(
220
+ async (input: VideoGenerateInput) => {
221
+ await client.generate(input)
222
+ },
223
+ [client],
224
+ )
225
+
226
+ const stop = useCallback(() => {
227
+ client.stop()
228
+ }, [client])
229
+
230
+ const reset = useCallback(() => {
231
+ client.reset()
232
+ }, [client])
233
+
234
+ return {
235
+ generate,
236
+ result,
237
+ jobId,
238
+ videoStatus,
239
+ isLoading,
240
+ error,
241
+ status,
242
+ stop,
243
+ reset,
244
+ }
245
+ }
@@ -0,0 +1,108 @@
1
+ // Declaration companion generated from use-generate-video.tsrx.
2
+ import type { StreamChunk } from '@tanstack/ai'
3
+ import type {
4
+ AIDevtoolsDisplayOptions,
5
+ ConnectConnectionAdapter,
6
+ GenerationClientState,
7
+ GenerationFetcher,
8
+ InferGenerationOutputFromReturn,
9
+ VideoGenerateInput,
10
+ VideoGenerateResult,
11
+ VideoStatusInfo,
12
+ } from '@tanstack/ai-client'
13
+ /**
14
+ * Options for the useGenerateVideo hook.
15
+ */
16
+ export interface UseGenerateVideoOptions<TOutput = VideoGenerateResult> {
17
+ /** Connect-based adapter for streaming transport (server handles polling) */
18
+ connection?: ConnectConnectionAdapter
19
+ /** Direct async function that returns a completed video result */
20
+ fetcher?: GenerationFetcher<VideoGenerateInput, VideoGenerateResult>
21
+ /** Unique identifier for this generation instance */
22
+ id?: string
23
+ /** Additional body parameters to send with connect-based adapter requests */
24
+ body?: Record<string, any>
25
+ /** Display options for TanStack AI Devtools. */
26
+ devtools?: AIDevtoolsDisplayOptions
27
+ /**
28
+ * Callback when video generation completes. Can optionally return a transformed value.
29
+ *
30
+ * - Return a non-null value to transform and store it as the result
31
+ * - Return `null` to keep the previous result unchanged
32
+ * - Return nothing (`void`) to store the raw result as-is
33
+ */
34
+ onResult?: (result: VideoGenerateResult) => TOutput | null | void
35
+ /** Callback when an error occurs */
36
+ onError?: (error: Error) => void
37
+ /** Callback when progress is reported (0-100) */
38
+ onProgress?: (progress: number, message?: string) => void
39
+ /** Callback when a video job is created */
40
+ onJobCreated?: (jobId: string) => void
41
+ /** Callback on each status update */
42
+ onStatusUpdate?: (status: VideoStatusInfo) => void
43
+ /** Callback for each stream chunk (connect-based adapter mode only) */
44
+ onChunk?: (chunk: StreamChunk) => void
45
+ }
46
+ /**
47
+ * Return type for the useGenerateVideo hook.
48
+ *
49
+ * @template TOutput - The output type (after optional transform)
50
+ */
51
+ export interface UseGenerateVideoReturn<TOutput = VideoGenerateResult> {
52
+ /** Trigger video generation */
53
+ generate: (input: VideoGenerateInput) => Promise<void>
54
+ /** The final video result (with URL), or null */
55
+ result: TOutput | null
56
+ /** The current job ID, or null */
57
+ jobId: string | null
58
+ /** Current video generation status info, or null */
59
+ videoStatus: VideoStatusInfo | null
60
+ /** Whether generation/polling is in progress */
61
+ isLoading: boolean
62
+ /** Current error, if any */
63
+ error: Error | undefined
64
+ /** Current state of the generation */
65
+ status: GenerationClientState
66
+ /** Abort the current generation/polling */
67
+ stop: () => void
68
+ /** Clear all state and return to idle */
69
+ reset: () => void
70
+ }
71
+ /**
72
+ * Octane hook for generating videos using AI models.
73
+ *
74
+ * Video generation is asynchronous: a job is created, then polled for status
75
+ * until completion. This hook handles the full lifecycle.
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * import { useGenerateVideo } from '@tanstack/ai-octane'
80
+ * import { fetchServerSentEvents } from '@tanstack/ai-client'
81
+ *
82
+ * function VideoGenerator() {
83
+ * const { generate, result, videoStatus, isLoading } = useGenerateVideo({
84
+ * connection: fetchServerSentEvents('/api/generate/video'),
85
+ * onStatusUpdate: (status) => console.log(`Progress: ${status.progress}%`),
86
+ * })
87
+ *
88
+ * return (
89
+ * <div>
90
+ * <button onClick={() => generate({ prompt: 'A flying car over a city' })}>
91
+ * Generate Video
92
+ * </button>
93
+ * {isLoading && videoStatus && (
94
+ * <p>Status: {videoStatus.status} ({videoStatus.progress}%)</p>
95
+ * )}
96
+ * {result && <video src={result.url} controls />}
97
+ * </div>
98
+ * )
99
+ * }
100
+ * ```
101
+ */
102
+ export declare function useGenerateVideo<TTransformed = void>(
103
+ options: Omit<UseGenerateVideoOptions, 'onResult'> & {
104
+ onResult?: (result: VideoGenerateResult) => TTransformed
105
+ },
106
+ ): UseGenerateVideoReturn<
107
+ InferGenerationOutputFromReturn<VideoGenerateResult, TTransformed>
108
+ >
@@ -0,0 +1,229 @@
1
+ import { GenerationClient } from '@tanstack/ai-client'
2
+ import { createGenerationDevtoolsBridge } from '@tanstack/ai-client/devtools'
3
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'octane'
4
+ import type { StreamChunk } from '@tanstack/ai'
5
+ import type {
6
+ AIDevtoolsDisplayOptions,
7
+ ConnectConnectionAdapter,
8
+ GenerationClientOptions,
9
+ GenerationClientState,
10
+ GenerationFetcher,
11
+ InferGenerationOutputFromReturn,
12
+ } from '@tanstack/ai-client'
13
+
14
+ /**
15
+ * Options for the useGeneration hook.
16
+ *
17
+ * Accepts either a `connection` (streaming transport) or a `fetcher` (direct async call).
18
+ *
19
+ * @template TInput - The input type for the generation request
20
+ * @template TResult - The result type returned by the generation
21
+ * @template TOutput - The output type after optional transform (defaults to TResult)
22
+ */
23
+ export interface UseGenerationOptions<TInput, TResult, TOutput = TResult> {
24
+ /** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
25
+ connection?: ConnectConnectionAdapter
26
+ /** Direct async function for one-shot generation (no streaming protocol needed) */
27
+ fetcher?: GenerationFetcher<TInput, TResult>
28
+ /** Unique identifier for this generation instance */
29
+ id?: string
30
+ /** Additional body parameters to send with connect-based adapter requests */
31
+ body?: Record<string, any>
32
+ /** Display options for TanStack AI Devtools. */
33
+ devtools?: AIDevtoolsDisplayOptions
34
+ /**
35
+ * Callback when a result is received. Can optionally return a transformed value.
36
+ *
37
+ * - Return a non-null value to transform and store it as the result
38
+ * - Return `null` to keep the previous result unchanged
39
+ * - Return nothing (`void`) to store the raw result as-is
40
+ */
41
+ onResult?: (result: TResult) => TOutput | null | void
42
+ /** Callback when an error occurs */
43
+ onError?: (error: Error) => void
44
+ /** Callback when progress is reported (0-100) */
45
+ onProgress?: (progress: number, message?: string) => void
46
+ /** Callback for each stream chunk (connect-based adapter mode only) */
47
+ onChunk?: (chunk: StreamChunk) => void
48
+ }
49
+
50
+ /**
51
+ * Return type for the useGeneration hook.
52
+ *
53
+ * @template TInput - The input type accepted by `generate`
54
+ * @template TOutput - The output type (after optional transform)
55
+ */
56
+ export interface UseGenerationReturn<TInput, TOutput> {
57
+ /**
58
+ * Trigger a generation request.
59
+ *
60
+ * Typed as `TInput` rather than `Record<string, any>` so required and narrow
61
+ * input fields are actually checked at the call site. (Upstream
62
+ * `@tanstack/ai-react` widens this; see status.json.)
63
+ */
64
+ generate: (input: TInput) => Promise<void>
65
+ /** The generation result, or null if not yet generated */
66
+ result: TOutput | null
67
+ /** Whether a generation is currently in progress */
68
+ isLoading: boolean
69
+ /** Current error, if any */
70
+ error: Error | undefined
71
+ /** Current state of the generation client */
72
+ status: GenerationClientState
73
+ /** Abort the current generation */
74
+ stop: () => void
75
+ /** Clear result, error, and return to idle */
76
+ reset: () => void
77
+ }
78
+
79
+ /**
80
+ * Generic Octane hook for one-shot generation tasks.
81
+ *
82
+ * This is the base hook used by `useGenerateImage`, `useGenerateSpeech`,
83
+ * `useTranscription`, and `useSummarize`. You can also use it directly
84
+ * for custom generation types.
85
+ *
86
+ * @template TInput - The input type for the generation request
87
+ * @template TResult - The result type returned by the generation
88
+ *
89
+ * @example
90
+ * ```tsx
91
+ * const { generate, result, isLoading } = useGeneration<MyInput, MyResult>({
92
+ * connection: fetchServerSentEvents('/api/generate/custom'),
93
+ * })
94
+ *
95
+ * await generate({ prompt: 'Hello' })
96
+ * ```
97
+ */
98
+ // `TTransformed` infers from the `onResult` return position (a covariant
99
+ // inference site that works even for an optional nested property), which types
100
+ // the callback parameter as `TResult` and narrows `result`. Inferring the
101
+ // whole callback as a defaulted type parameter instead collapses to the
102
+ // default, leaving the parameter `any` — a hard error under `strict`. See
103
+ // issue #848.
104
+ export function useGeneration<
105
+ TInput extends Record<string, any>,
106
+ TResult,
107
+ TTransformed = void,
108
+ >(
109
+ options: Omit<UseGenerationOptions<TInput, TResult>, 'onResult'> & {
110
+ onResult?: (result: TResult) => TTransformed
111
+ },
112
+ ): UseGenerationReturn<
113
+ TInput,
114
+ InferGenerationOutputFromReturn<TResult, TTransformed>
115
+ > {
116
+ type TOutput = InferGenerationOutputFromReturn<TResult, TTransformed>
117
+ const hookId = useId()
118
+ const clientId = options.id || hookId
119
+
120
+ const [result, setResult] = useState<TOutput | null>(null)
121
+ const [isLoading, setIsLoading] = useState(false)
122
+ const [error, setError] = useState<Error | undefined>(undefined)
123
+ const [status, setStatus] = useState<GenerationClientState>('idle')
124
+
125
+ const optionsRef = useRef(options)
126
+ optionsRef.current = options
127
+
128
+ const client = useMemo(() => {
129
+ const opts = optionsRef.current
130
+
131
+ // Conditional spread for `body` (strict-optional in target;
132
+ // local source is `Record<string, any> | undefined`). Callbacks
133
+ // wrap optional ones in non-returning bodies so `?.()`'s
134
+ // implicit `undefined` doesn't pollute the function return type.
135
+ const clientOptions: GenerationClientOptions<TInput, TResult, TOutput> = {
136
+ id: clientId,
137
+ body: opts.body,
138
+ devtoolsBridgeFactory: createGenerationDevtoolsBridge,
139
+ devtools: {
140
+ ...opts.devtools,
141
+ // OCTANE DIVERGENCE: identify this binding as Octane (not 'react') in TanStack AI Devtools.
142
+ // The spread comes first so a caller-supplied `devtools.framework` can't
143
+ // silently misidentify the binding — `useGeneration` is public API, and
144
+ // the sibling hooks (useChat, useGenerateVideo) already order it this way.
145
+ framework: 'octane',
146
+ hookName: 'useGeneration',
147
+ },
148
+ // The transform's raw return type (`TTransformed`) and the stored output
149
+ // (`TOutput`, with null/void/undefined stripped) are identical at runtime;
150
+ // the cast bridges the relationship that the conditional type hides.
151
+ onResult: ((r: TResult) => optionsRef.current.onResult?.(r)) as (
152
+ result: TResult,
153
+ ) => TOutput | null | void,
154
+ onError: (e: Error) => {
155
+ optionsRef.current.onError?.(e)
156
+ },
157
+ onProgress: (p: number, m?: string) => {
158
+ optionsRef.current.onProgress?.(p, m)
159
+ },
160
+ onChunk: (c: StreamChunk) => {
161
+ optionsRef.current.onChunk?.(c)
162
+ },
163
+ onResultChange: setResult,
164
+ onLoadingChange: setIsLoading,
165
+ onErrorChange: setError,
166
+ onStatusChange: setStatus,
167
+ }
168
+
169
+ if (opts.connection) {
170
+ return new GenerationClient<TInput, TResult, TOutput>({
171
+ ...clientOptions,
172
+ connection: opts.connection,
173
+ })
174
+ }
175
+
176
+ if (opts.fetcher) {
177
+ return new GenerationClient<TInput, TResult, TOutput>({
178
+ ...clientOptions,
179
+ fetcher: opts.fetcher,
180
+ })
181
+ }
182
+
183
+ throw new Error(
184
+ 'useGeneration requires either a connection or fetcher option',
185
+ )
186
+ }, [clientId])
187
+
188
+ // Sync body changes without recreating client
189
+ useEffect(() => {
190
+ // Conditional spread: target uses strict-optional `body?: T`.
191
+ client.updateOptions({
192
+ ...(options.body !== undefined && { body: options.body }),
193
+ })
194
+ }, [client, options.body])
195
+
196
+ // Cleanup on unmount
197
+ useEffect(() => {
198
+ client.mountDevtools()
199
+
200
+ return () => {
201
+ client.dispose()
202
+ }
203
+ }, [client])
204
+
205
+ const generate = useCallback(
206
+ async (input: TInput) => {
207
+ await client.generate(input)
208
+ },
209
+ [client],
210
+ )
211
+
212
+ const stop = useCallback(() => {
213
+ client.stop()
214
+ }, [client])
215
+
216
+ const reset = useCallback(() => {
217
+ client.reset()
218
+ }, [client])
219
+
220
+ return {
221
+ generate,
222
+ result,
223
+ isLoading,
224
+ error,
225
+ status,
226
+ stop,
227
+ reset,
228
+ }
229
+ }
@@ -0,0 +1,103 @@
1
+ // Declaration companion generated from use-generation.tsrx.
2
+ import type { StreamChunk } from '@tanstack/ai'
3
+ import type {
4
+ AIDevtoolsDisplayOptions,
5
+ ConnectConnectionAdapter,
6
+ GenerationClientState,
7
+ GenerationFetcher,
8
+ InferGenerationOutputFromReturn,
9
+ } from '@tanstack/ai-client'
10
+ /**
11
+ * Options for the useGeneration hook.
12
+ *
13
+ * Accepts either a `connection` (streaming transport) or a `fetcher` (direct async call).
14
+ *
15
+ * @template TInput - The input type for the generation request
16
+ * @template TResult - The result type returned by the generation
17
+ * @template TOutput - The output type after optional transform (defaults to TResult)
18
+ */
19
+ export interface UseGenerationOptions<TInput, TResult, TOutput = TResult> {
20
+ /** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
21
+ connection?: ConnectConnectionAdapter
22
+ /** Direct async function for one-shot generation (no streaming protocol needed) */
23
+ fetcher?: GenerationFetcher<TInput, TResult>
24
+ /** Unique identifier for this generation instance */
25
+ id?: string
26
+ /** Additional body parameters to send with connect-based adapter requests */
27
+ body?: Record<string, any>
28
+ /** Display options for TanStack AI Devtools. */
29
+ devtools?: AIDevtoolsDisplayOptions
30
+ /**
31
+ * Callback when a result is received. Can optionally return a transformed value.
32
+ *
33
+ * - Return a non-null value to transform and store it as the result
34
+ * - Return `null` to keep the previous result unchanged
35
+ * - Return nothing (`void`) to store the raw result as-is
36
+ */
37
+ onResult?: (result: TResult) => TOutput | null | void
38
+ /** Callback when an error occurs */
39
+ onError?: (error: Error) => void
40
+ /** Callback when progress is reported (0-100) */
41
+ onProgress?: (progress: number, message?: string) => void
42
+ /** Callback for each stream chunk (connect-based adapter mode only) */
43
+ onChunk?: (chunk: StreamChunk) => void
44
+ }
45
+ /**
46
+ * Return type for the useGeneration hook.
47
+ *
48
+ * @template TInput - The input type accepted by `generate`
49
+ * @template TOutput - The output type (after optional transform)
50
+ */
51
+ export interface UseGenerationReturn<TInput, TOutput> {
52
+ /**
53
+ * Trigger a generation request.
54
+ *
55
+ * Typed as `TInput` rather than `Record<string, any>` so required and narrow
56
+ * input fields are actually checked at the call site. (Upstream
57
+ * `@tanstack/ai-react` widens this; see status.json.)
58
+ */
59
+ generate: (input: TInput) => Promise<void>
60
+ /** The generation result, or null if not yet generated */
61
+ result: TOutput | null
62
+ /** Whether a generation is currently in progress */
63
+ isLoading: boolean
64
+ /** Current error, if any */
65
+ error: Error | undefined
66
+ /** Current state of the generation client */
67
+ status: GenerationClientState
68
+ /** Abort the current generation */
69
+ stop: () => void
70
+ /** Clear result, error, and return to idle */
71
+ reset: () => void
72
+ }
73
+ /**
74
+ * Generic Octane hook for one-shot generation tasks.
75
+ *
76
+ * This is the base hook used by `useGenerateImage`, `useGenerateSpeech`,
77
+ * `useTranscription`, and `useSummarize`. You can also use it directly
78
+ * for custom generation types.
79
+ *
80
+ * @template TInput - The input type for the generation request
81
+ * @template TResult - The result type returned by the generation
82
+ *
83
+ * @example
84
+ * ```tsx
85
+ * const { generate, result, isLoading } = useGeneration<MyInput, MyResult>({
86
+ * connection: fetchServerSentEvents('/api/generate/custom'),
87
+ * })
88
+ *
89
+ * await generate({ prompt: 'Hello' })
90
+ * ```
91
+ */
92
+ export declare function useGeneration<
93
+ TInput extends Record<string, any>,
94
+ TResult,
95
+ TTransformed = void,
96
+ >(
97
+ options: Omit<UseGenerationOptions<TInput, TResult>, 'onResult'> & {
98
+ onResult?: (result: TResult) => TTransformed
99
+ },
100
+ ): UseGenerationReturn<
101
+ TInput,
102
+ InferGenerationOutputFromReturn<TResult, TTransformed>
103
+ >