@tanstack/ai-solid 0.15.1 → 0.16.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/README.md +17 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/types.d.ts +29 -3
- package/dist/use-chat.js +81 -5
- package/dist/use-chat.js.map +1 -1
- package/dist/use-generate-audio.d.ts +9 -10
- package/dist/use-generate-audio.js +4 -11
- package/dist/use-generate-audio.js.map +1 -1
- package/dist/use-generate-image.d.ts +9 -10
- package/dist/use-generate-image.js +4 -11
- package/dist/use-generate-image.js.map +1 -1
- package/dist/use-generate-speech.d.ts +9 -10
- package/dist/use-generate-speech.js +4 -11
- package/dist/use-generate-speech.js.map +1 -1
- package/dist/use-generate-video.d.ts +50 -4
- package/dist/use-generate-video.js +54 -23
- package/dist/use-generate-video.js.map +1 -1
- package/dist/use-generation.d.ts +59 -6
- package/dist/use-generation.js +43 -19
- package/dist/use-generation.js.map +1 -1
- package/dist/use-summarize.d.ts +9 -10
- package/dist/use-summarize.js +4 -11
- package/dist/use-summarize.js.map +1 -1
- package/dist/use-transcription.d.ts +9 -10
- package/dist/use-transcription.js +4 -11
- package/dist/use-transcription.js.map +1 -1
- package/package.json +6 -6
- package/src/index.ts +10 -0
- package/src/types.ts +44 -0
- package/src/use-chat.ts +123 -6
- package/src/use-generate-audio.ts +33 -23
- package/src/use-generate-image.ts +33 -23
- package/src/use-generate-speech.ts +32 -23
- package/src/use-generate-video.ts +120 -25
- package/src/use-generation.ts +129 -25
- package/src/use-summarize.ts +34 -23
- package/src/use-transcription.ts +33 -24
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { useGeneration } from './use-generation'
|
|
2
|
+
import { reconstructAudioResult } from '@tanstack/ai-client'
|
|
3
|
+
import type {
|
|
4
|
+
UseGenerationOptions,
|
|
5
|
+
UseGenerationReturn,
|
|
6
|
+
} from './use-generation'
|
|
2
7
|
import type { AudioGenerationResult, StreamChunk } from '@tanstack/ai'
|
|
3
8
|
import type {
|
|
4
9
|
AIDevtoolsDisplayOptions,
|
|
@@ -6,6 +11,7 @@ import type {
|
|
|
6
11
|
ConnectConnectionAdapter,
|
|
7
12
|
GenerationClientState,
|
|
8
13
|
GenerationFetcher,
|
|
14
|
+
GenerationPersistenceOptions,
|
|
9
15
|
InferGenerationOutputFromReturn,
|
|
10
16
|
} from '@tanstack/ai-client'
|
|
11
17
|
import type { Accessor } from 'solid-js'
|
|
@@ -15,12 +21,19 @@ import type { Accessor } from 'solid-js'
|
|
|
15
21
|
*
|
|
16
22
|
* @template TOutput - The transformed output type (defaults to AudioGenerationResult)
|
|
17
23
|
*/
|
|
18
|
-
export interface UseGenerateAudioOptions<
|
|
24
|
+
export interface UseGenerateAudioOptions<
|
|
25
|
+
TOutput = AudioGenerationResult,
|
|
26
|
+
> extends Pick<
|
|
27
|
+
UseGenerationOptions<AudioGenerateInput, AudioGenerationResult, TOutput>,
|
|
28
|
+
'persistence' | 'threadId' | 'hydrateGeneration' | 'joinRun'
|
|
29
|
+
> {
|
|
19
30
|
/** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
|
|
20
31
|
connection?: ConnectConnectionAdapter
|
|
21
32
|
/** Direct async function for audio generation */
|
|
22
33
|
fetcher?: GenerationFetcher<AudioGenerateInput, AudioGenerationResult>
|
|
23
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
|
|
36
|
+
*/
|
|
24
37
|
id?: string
|
|
25
38
|
/** Additional body parameters to send with connect-based adapter requests */
|
|
26
39
|
body?: Record<string, any>
|
|
@@ -47,7 +60,9 @@ export interface UseGenerateAudioOptions<TOutput = AudioGenerationResult> {
|
|
|
47
60
|
*
|
|
48
61
|
* @template TOutput - The transformed output type (defaults to AudioGenerationResult)
|
|
49
62
|
*/
|
|
50
|
-
export interface UseGenerateAudioReturn<
|
|
63
|
+
export interface UseGenerateAudioReturn<
|
|
64
|
+
TOutput = AudioGenerationResult,
|
|
65
|
+
> extends Omit<UseGenerationReturn<TOutput>, 'generate'> {
|
|
51
66
|
/** Trigger audio generation */
|
|
52
67
|
generate: (input: AudioGenerateInput) => Promise<void>
|
|
53
68
|
/** The generation result containing audio, or null */
|
|
@@ -58,10 +73,6 @@ export interface UseGenerateAudioReturn<TOutput = AudioGenerationResult> {
|
|
|
58
73
|
error: Accessor<Error | undefined>
|
|
59
74
|
/** Current state of the generation */
|
|
60
75
|
status: Accessor<GenerationClientState>
|
|
61
|
-
/** Abort the current generation */
|
|
62
|
-
stop: () => void
|
|
63
|
-
/** Clear result, error, and return to idle */
|
|
64
|
-
reset: () => void
|
|
65
76
|
}
|
|
66
77
|
|
|
67
78
|
/**
|
|
@@ -89,9 +100,12 @@ export interface UseGenerateAudioReturn<TOutput = AudioGenerationResult> {
|
|
|
89
100
|
* ```
|
|
90
101
|
*/
|
|
91
102
|
export function useGenerateAudio<TTransformed = void>(
|
|
92
|
-
options: Omit<
|
|
103
|
+
options: Omit<
|
|
104
|
+
UseGenerateAudioOptions,
|
|
105
|
+
'onResult' | 'persistence' | 'threadId' | 'id'
|
|
106
|
+
> & {
|
|
93
107
|
onResult?: (result: AudioGenerationResult) => TTransformed
|
|
94
|
-
},
|
|
108
|
+
} & GenerationPersistenceOptions,
|
|
95
109
|
): UseGenerateAudioReturn<
|
|
96
110
|
InferGenerationOutputFromReturn<AudioGenerationResult, TTransformed>
|
|
97
111
|
> {
|
|
@@ -101,19 +115,15 @@ export function useGenerateAudio<TTransformed = void>(
|
|
|
101
115
|
hookName: 'useGenerateAudio',
|
|
102
116
|
outputKind: 'audio' as const,
|
|
103
117
|
}
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
const generation = useGeneration<
|
|
119
|
+
AudioGenerateInput,
|
|
120
|
+
AudioGenerationResult,
|
|
121
|
+
TTransformed
|
|
122
|
+
>({
|
|
123
|
+
...options,
|
|
124
|
+
devtools,
|
|
125
|
+
reconstructResult: reconstructAudioResult,
|
|
126
|
+
})
|
|
109
127
|
|
|
110
|
-
return
|
|
111
|
-
generate: generate as (input: AudioGenerateInput) => Promise<void>,
|
|
112
|
-
result,
|
|
113
|
-
isLoading,
|
|
114
|
-
error,
|
|
115
|
-
status,
|
|
116
|
-
stop,
|
|
117
|
-
reset,
|
|
118
|
-
}
|
|
128
|
+
return generation
|
|
119
129
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { useGeneration } from './use-generation'
|
|
2
|
+
import { reconstructImageResult } from '@tanstack/ai-client'
|
|
3
|
+
import type {
|
|
4
|
+
UseGenerationOptions,
|
|
5
|
+
UseGenerationReturn,
|
|
6
|
+
} from './use-generation'
|
|
2
7
|
import type { ImageGenerationResult, StreamChunk } from '@tanstack/ai'
|
|
3
8
|
import type {
|
|
4
9
|
AIDevtoolsDisplayOptions,
|
|
5
10
|
ConnectConnectionAdapter,
|
|
6
11
|
GenerationClientState,
|
|
7
12
|
GenerationFetcher,
|
|
13
|
+
GenerationPersistenceOptions,
|
|
8
14
|
ImageGenerateInput,
|
|
9
15
|
InferGenerationOutputFromReturn,
|
|
10
16
|
} from '@tanstack/ai-client'
|
|
@@ -15,12 +21,19 @@ import type { Accessor } from 'solid-js'
|
|
|
15
21
|
*
|
|
16
22
|
* @template TOutput - The transformed output type (defaults to ImageGenerationResult)
|
|
17
23
|
*/
|
|
18
|
-
export interface UseGenerateImageOptions<
|
|
24
|
+
export interface UseGenerateImageOptions<
|
|
25
|
+
TOutput = ImageGenerationResult,
|
|
26
|
+
> extends Pick<
|
|
27
|
+
UseGenerationOptions<ImageGenerateInput, ImageGenerationResult, TOutput>,
|
|
28
|
+
'persistence' | 'threadId' | 'hydrateGeneration' | 'joinRun'
|
|
29
|
+
> {
|
|
19
30
|
/** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
|
|
20
31
|
connection?: ConnectConnectionAdapter
|
|
21
32
|
/** Direct async function for image generation */
|
|
22
33
|
fetcher?: GenerationFetcher<ImageGenerateInput, ImageGenerationResult>
|
|
23
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
|
|
36
|
+
*/
|
|
24
37
|
id?: string
|
|
25
38
|
/** Additional body parameters to send with connect-based adapter requests */
|
|
26
39
|
body?: Record<string, any>
|
|
@@ -47,7 +60,9 @@ export interface UseGenerateImageOptions<TOutput = ImageGenerationResult> {
|
|
|
47
60
|
*
|
|
48
61
|
* @template TOutput - The transformed output type (defaults to ImageGenerationResult)
|
|
49
62
|
*/
|
|
50
|
-
export interface UseGenerateImageReturn<
|
|
63
|
+
export interface UseGenerateImageReturn<
|
|
64
|
+
TOutput = ImageGenerationResult,
|
|
65
|
+
> extends Omit<UseGenerationReturn<TOutput>, 'generate'> {
|
|
51
66
|
/** Trigger image generation */
|
|
52
67
|
generate: (input: ImageGenerateInput) => Promise<void>
|
|
53
68
|
/** The generation result containing images, or null */
|
|
@@ -58,10 +73,6 @@ export interface UseGenerateImageReturn<TOutput = ImageGenerationResult> {
|
|
|
58
73
|
error: Accessor<Error | undefined>
|
|
59
74
|
/** Current state of the generation */
|
|
60
75
|
status: Accessor<GenerationClientState>
|
|
61
|
-
/** Abort the current generation */
|
|
62
|
-
stop: () => void
|
|
63
|
-
/** Clear result, error, and return to idle */
|
|
64
|
-
reset: () => void
|
|
65
76
|
}
|
|
66
77
|
|
|
67
78
|
/**
|
|
@@ -97,9 +108,12 @@ export interface UseGenerateImageReturn<TOutput = ImageGenerationResult> {
|
|
|
97
108
|
* ```
|
|
98
109
|
*/
|
|
99
110
|
export function useGenerateImage<TTransformed = void>(
|
|
100
|
-
options: Omit<
|
|
111
|
+
options: Omit<
|
|
112
|
+
UseGenerateImageOptions,
|
|
113
|
+
'onResult' | 'persistence' | 'threadId' | 'id'
|
|
114
|
+
> & {
|
|
101
115
|
onResult?: (result: ImageGenerationResult) => TTransformed
|
|
102
|
-
},
|
|
116
|
+
} & GenerationPersistenceOptions,
|
|
103
117
|
): UseGenerateImageReturn<
|
|
104
118
|
InferGenerationOutputFromReturn<ImageGenerationResult, TTransformed>
|
|
105
119
|
> {
|
|
@@ -109,19 +123,15 @@ export function useGenerateImage<TTransformed = void>(
|
|
|
109
123
|
hookName: 'useGenerateImage',
|
|
110
124
|
outputKind: 'image' as const,
|
|
111
125
|
}
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
126
|
+
const generation = useGeneration<
|
|
127
|
+
ImageGenerateInput,
|
|
128
|
+
ImageGenerationResult,
|
|
129
|
+
TTransformed
|
|
130
|
+
>({
|
|
131
|
+
...options,
|
|
132
|
+
devtools,
|
|
133
|
+
reconstructResult: reconstructImageResult,
|
|
134
|
+
})
|
|
117
135
|
|
|
118
|
-
return
|
|
119
|
-
generate: generate as (input: ImageGenerateInput) => Promise<void>,
|
|
120
|
-
result,
|
|
121
|
-
isLoading,
|
|
122
|
-
error,
|
|
123
|
-
status,
|
|
124
|
-
stop,
|
|
125
|
-
reset,
|
|
126
|
-
}
|
|
136
|
+
return generation
|
|
127
137
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { useGeneration } from './use-generation'
|
|
2
|
+
import { reconstructSpeechResult } from '@tanstack/ai-client'
|
|
3
|
+
import type {
|
|
4
|
+
UseGenerationOptions,
|
|
5
|
+
UseGenerationReturn,
|
|
6
|
+
} from './use-generation'
|
|
2
7
|
import type { StreamChunk, TTSResult } from '@tanstack/ai'
|
|
3
8
|
import type {
|
|
4
9
|
AIDevtoolsDisplayOptions,
|
|
5
10
|
ConnectConnectionAdapter,
|
|
6
11
|
GenerationClientState,
|
|
7
12
|
GenerationFetcher,
|
|
13
|
+
GenerationPersistenceOptions,
|
|
8
14
|
InferGenerationOutputFromReturn,
|
|
9
15
|
SpeechGenerateInput,
|
|
10
16
|
} from '@tanstack/ai-client'
|
|
@@ -15,12 +21,17 @@ import type { Accessor } from 'solid-js'
|
|
|
15
21
|
*
|
|
16
22
|
* @template TOutput - The transformed output type (defaults to TTSResult)
|
|
17
23
|
*/
|
|
18
|
-
export interface UseGenerateSpeechOptions<TOutput = TTSResult>
|
|
24
|
+
export interface UseGenerateSpeechOptions<TOutput = TTSResult> extends Pick<
|
|
25
|
+
UseGenerationOptions<SpeechGenerateInput, TTSResult, TOutput>,
|
|
26
|
+
'persistence' | 'threadId' | 'hydrateGeneration' | 'joinRun'
|
|
27
|
+
> {
|
|
19
28
|
/** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
|
|
20
29
|
connection?: ConnectConnectionAdapter
|
|
21
30
|
/** Direct async function for speech generation */
|
|
22
31
|
fetcher?: GenerationFetcher<SpeechGenerateInput, TTSResult>
|
|
23
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
|
|
34
|
+
*/
|
|
24
35
|
id?: string
|
|
25
36
|
/** Additional body parameters to send with connect-based adapter requests */
|
|
26
37
|
body?: Record<string, any>
|
|
@@ -47,7 +58,10 @@ export interface UseGenerateSpeechOptions<TOutput = TTSResult> {
|
|
|
47
58
|
*
|
|
48
59
|
* @template TOutput - The transformed output type (defaults to TTSResult)
|
|
49
60
|
*/
|
|
50
|
-
export interface UseGenerateSpeechReturn<TOutput = TTSResult>
|
|
61
|
+
export interface UseGenerateSpeechReturn<TOutput = TTSResult> extends Omit<
|
|
62
|
+
UseGenerationReturn<TOutput>,
|
|
63
|
+
'generate'
|
|
64
|
+
> {
|
|
51
65
|
/** Trigger speech generation */
|
|
52
66
|
generate: (input: SpeechGenerateInput) => Promise<void>
|
|
53
67
|
/** The TTS result containing audio data, or null */
|
|
@@ -58,10 +72,6 @@ export interface UseGenerateSpeechReturn<TOutput = TTSResult> {
|
|
|
58
72
|
error: Accessor<Error | undefined>
|
|
59
73
|
/** Current state of the generation */
|
|
60
74
|
status: Accessor<GenerationClientState>
|
|
61
|
-
/** Abort the current generation */
|
|
62
|
-
stop: () => void
|
|
63
|
-
/** Clear result, error, and return to idle */
|
|
64
|
-
reset: () => void
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
/**
|
|
@@ -91,9 +101,12 @@ export interface UseGenerateSpeechReturn<TOutput = TTSResult> {
|
|
|
91
101
|
* ```
|
|
92
102
|
*/
|
|
93
103
|
export function useGenerateSpeech<TTransformed = void>(
|
|
94
|
-
options: Omit<
|
|
104
|
+
options: Omit<
|
|
105
|
+
UseGenerateSpeechOptions,
|
|
106
|
+
'onResult' | 'persistence' | 'threadId' | 'id'
|
|
107
|
+
> & {
|
|
95
108
|
onResult?: (result: TTSResult) => TTransformed
|
|
96
|
-
},
|
|
109
|
+
} & GenerationPersistenceOptions,
|
|
97
110
|
): UseGenerateSpeechReturn<
|
|
98
111
|
InferGenerationOutputFromReturn<TTSResult, TTransformed>
|
|
99
112
|
> {
|
|
@@ -103,19 +116,15 @@ export function useGenerateSpeech<TTransformed = void>(
|
|
|
103
116
|
hookName: 'useGenerateSpeech',
|
|
104
117
|
outputKind: 'audio' as const,
|
|
105
118
|
}
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
const generation = useGeneration<
|
|
120
|
+
SpeechGenerateInput,
|
|
121
|
+
TTSResult,
|
|
122
|
+
TTransformed
|
|
123
|
+
>({
|
|
124
|
+
...options,
|
|
125
|
+
devtools,
|
|
126
|
+
reconstructResult: reconstructSpeechResult,
|
|
127
|
+
})
|
|
111
128
|
|
|
112
|
-
return
|
|
113
|
-
generate: generate as (input: SpeechGenerateInput) => Promise<void>,
|
|
114
|
-
result,
|
|
115
|
-
isLoading,
|
|
116
|
-
error,
|
|
117
|
-
status,
|
|
118
|
-
stop,
|
|
119
|
-
reset,
|
|
120
|
-
}
|
|
129
|
+
return generation
|
|
121
130
|
}
|
|
@@ -2,11 +2,11 @@ import { VideoGenerationClient } from '@tanstack/ai-client'
|
|
|
2
2
|
import { createVideoDevtoolsBridge } from '@tanstack/ai-client/devtools'
|
|
3
3
|
import {
|
|
4
4
|
createEffect,
|
|
5
|
-
createMemo,
|
|
6
5
|
createSignal,
|
|
7
6
|
createUniqueId,
|
|
8
7
|
onCleanup,
|
|
9
8
|
onMount,
|
|
9
|
+
untrack,
|
|
10
10
|
} from 'solid-js'
|
|
11
11
|
import type { StreamChunk } from '@tanstack/ai'
|
|
12
12
|
import type {
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
ConnectConnectionAdapter,
|
|
15
15
|
GenerationClientState,
|
|
16
16
|
GenerationFetcher,
|
|
17
|
+
GenerationPersistenceOptions,
|
|
17
18
|
InferGenerationOutputFromReturn,
|
|
18
19
|
VideoGenerateInput,
|
|
19
20
|
VideoGenerateResult,
|
|
@@ -31,12 +32,51 @@ export interface UseGenerateVideoOptions<TOutput = VideoGenerateResult> {
|
|
|
31
32
|
connection?: ConnectConnectionAdapter
|
|
32
33
|
/** Direct async function that returns a completed video result */
|
|
33
34
|
fetcher?: GenerationFetcher<VideoGenerateInput, VideoGenerateResult>
|
|
34
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
|
|
37
|
+
*/
|
|
35
38
|
id?: string
|
|
36
39
|
/** Additional body parameters to send with connect-based adapter requests */
|
|
37
40
|
body?: Record<string, any>
|
|
38
41
|
/** Display options for TanStack AI Devtools. */
|
|
39
42
|
devtools?: AIDevtoolsDisplayOptions
|
|
43
|
+
/**
|
|
44
|
+
* How this generation persists across reloads.
|
|
45
|
+
* - Omit / `false`: ephemeral, in-memory only.
|
|
46
|
+
* - `true`: server-driven — on mount the client hydrates the last generation
|
|
47
|
+
* for its `threadId` from the server (needs a connection with a
|
|
48
|
+
* `hydrateGeneration` handler) and repaints it; it never auto-starts a run.
|
|
49
|
+
*/
|
|
50
|
+
persistence?: boolean
|
|
51
|
+
/**
|
|
52
|
+
* The **scope** this generation belongs to: a stable, app-chosen name for the
|
|
53
|
+
* slot successive runs fill — not a link to a chat conversation.
|
|
54
|
+
*
|
|
55
|
+
* The hook starts empty and produces many runs over its life; each gets its
|
|
56
|
+
* own `runId`, but all belong to one scope. Persistence keys on this, so
|
|
57
|
+
* derive it from your own domain and keep it identical across reloads (e.g.
|
|
58
|
+
* `` `video-${videoId}-start-frame` ``). It is also sent as the AG-UI thread
|
|
59
|
+
* id on the wire, which the protocol requires.
|
|
60
|
+
*
|
|
61
|
+
* **Required whenever `persistence` is set** — an app that cannot name the
|
|
62
|
+
* scope has nothing to restore to. Optional for ephemeral generations, where
|
|
63
|
+
* it falls back to `id` purely to satisfy the wire.
|
|
64
|
+
*/
|
|
65
|
+
threadId?: string
|
|
66
|
+
/**
|
|
67
|
+
* Server-driven hydration handler for `persistence: true` when the
|
|
68
|
+
* connection doesn't carry one (e.g. alongside `fetcher`, or a `stream()` /
|
|
69
|
+
* `rpcStream()` adapter built without handlers) — typically a one-line
|
|
70
|
+
* server-function call. The connection's own handler takes precedence.
|
|
71
|
+
*/
|
|
72
|
+
hydrateGeneration?: ConnectConnectionAdapter['hydrateGeneration']
|
|
73
|
+
/**
|
|
74
|
+
* Re-attach handler that replays a run still generating to completion on
|
|
75
|
+
* mount, when the connection doesn't carry one. Without it, a restored
|
|
76
|
+
* `running` snapshot surfaces as an (interrupted) error. The connection's
|
|
77
|
+
* own handler takes precedence.
|
|
78
|
+
*/
|
|
79
|
+
joinRun?: ConnectConnectionAdapter['joinRun']
|
|
40
80
|
/**
|
|
41
81
|
* Callback when video generation completes. Can optionally return a transformed value.
|
|
42
82
|
*
|
|
@@ -81,6 +121,13 @@ export interface UseGenerateVideoReturn<TOutput = VideoGenerateResult> {
|
|
|
81
121
|
stop: () => void
|
|
82
122
|
/** Clear all state and return to idle */
|
|
83
123
|
reset: () => void
|
|
124
|
+
/**
|
|
125
|
+
* The id of the generation job currently running, or `null` when nothing is in
|
|
126
|
+
* flight. Each call to `generate` is one job with its own id. Pass it to your
|
|
127
|
+
* own endpoint to cancel or poll the provider job — `stop()` only aborts the
|
|
128
|
+
* local stream, it does not stop work already running on the provider.
|
|
129
|
+
*/
|
|
130
|
+
runId: Accessor<string | null>
|
|
84
131
|
}
|
|
85
132
|
|
|
86
133
|
/**
|
|
@@ -118,9 +165,12 @@ export interface UseGenerateVideoReturn<TOutput = VideoGenerateResult> {
|
|
|
118
165
|
// parameter is typed as `VideoGenerateResult` and `result` narrows to the
|
|
119
166
|
// transform's return. See issue #848.
|
|
120
167
|
export function useGenerateVideo<TTransformed = void>(
|
|
121
|
-
options: Omit<
|
|
168
|
+
options: Omit<
|
|
169
|
+
UseGenerateVideoOptions,
|
|
170
|
+
'onResult' | 'persistence' | 'threadId' | 'id'
|
|
171
|
+
> & {
|
|
122
172
|
onResult?: (result: VideoGenerateResult) => TTransformed
|
|
123
|
-
},
|
|
173
|
+
} & GenerationPersistenceOptions,
|
|
124
174
|
): UseGenerateVideoReturn<
|
|
125
175
|
InferGenerationOutputFromReturn<VideoGenerateResult, TTransformed>
|
|
126
176
|
> {
|
|
@@ -129,7 +179,6 @@ export function useGenerateVideo<TTransformed = void>(
|
|
|
129
179
|
TTransformed
|
|
130
180
|
>
|
|
131
181
|
const hookId = createUniqueId()
|
|
132
|
-
const clientId = options.id || hookId
|
|
133
182
|
|
|
134
183
|
const [result, setResult] = createSignal<TOutput | null>(null)
|
|
135
184
|
const [jobId, setJobId] = createSignal<string | null>(null)
|
|
@@ -139,13 +188,30 @@ export function useGenerateVideo<TTransformed = void>(
|
|
|
139
188
|
const [isLoading, setIsLoading] = createSignal(false)
|
|
140
189
|
const [error, setError] = createSignal<Error | undefined>(undefined)
|
|
141
190
|
const [status, setStatus] = createSignal<GenerationClientState>('idle')
|
|
191
|
+
const [runId, setRunId] = createSignal<string | null>(null)
|
|
192
|
+
let disposed = false
|
|
142
193
|
|
|
143
|
-
|
|
194
|
+
// Built once. `untrack` keeps the option reads below from subscribing
|
|
195
|
+
// construction to `options.persistence` / `options.devtools` /
|
|
196
|
+
// `options.body`: a re-run would build a second client
|
|
197
|
+
// and orphan the first (only the live one is disposed on cleanup). Later
|
|
198
|
+
// `options.body` changes are pushed through `updateOptions` instead.
|
|
199
|
+
const client = untrack((): VideoGenerationClient<TOutput> => {
|
|
144
200
|
// Conditional spread on `body`: VideoGenerationClientOptions.body
|
|
145
201
|
// is a strict optional; EOPT forbids passing `T | undefined`.
|
|
146
202
|
const baseOptions = {
|
|
147
|
-
id: clientId,
|
|
148
203
|
body: options.body,
|
|
204
|
+
// Identity: pass `threadId` alone when set (never also pass deprecated `id`).
|
|
205
|
+
...(options.threadId !== undefined
|
|
206
|
+
? { threadId: options.threadId }
|
|
207
|
+
: { id: options.id ?? hookId }),
|
|
208
|
+
...(options.persistence !== undefined && {
|
|
209
|
+
persistence: options.persistence,
|
|
210
|
+
}),
|
|
211
|
+
...(options.hydrateGeneration !== undefined && {
|
|
212
|
+
hydrateGeneration: options.hydrateGeneration,
|
|
213
|
+
}),
|
|
214
|
+
...(options.joinRun !== undefined && { joinRun: options.joinRun }),
|
|
149
215
|
devtoolsBridgeFactory: createVideoDevtoolsBridge,
|
|
150
216
|
devtools: {
|
|
151
217
|
...options.devtools,
|
|
@@ -159,17 +225,42 @@ export function useGenerateVideo<TTransformed = void>(
|
|
|
159
225
|
onResult: ((r: VideoGenerateResult) => options.onResult?.(r)) as (
|
|
160
226
|
result: VideoGenerateResult,
|
|
161
227
|
) => TOutput | null | void,
|
|
162
|
-
onError: (e: Error) =>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
228
|
+
onError: (e: Error) => {
|
|
229
|
+
if (!disposed) options.onError?.(e)
|
|
230
|
+
},
|
|
231
|
+
onProgress: (p: number, m?: string) => {
|
|
232
|
+
if (!disposed) options.onProgress?.(p, m)
|
|
233
|
+
},
|
|
234
|
+
onChunk: (c: StreamChunk) => {
|
|
235
|
+
if (!disposed) options.onChunk?.(c)
|
|
236
|
+
},
|
|
237
|
+
onJobCreated: (id: string) => {
|
|
238
|
+
if (!disposed) options.onJobCreated?.(id)
|
|
239
|
+
},
|
|
240
|
+
onStatusUpdate: (s: VideoStatusInfo) => {
|
|
241
|
+
if (!disposed) options.onStatusUpdate?.(s)
|
|
242
|
+
},
|
|
243
|
+
onResultChange: (r: TOutput | null) => {
|
|
244
|
+
if (!disposed) setResult(() => r)
|
|
245
|
+
},
|
|
246
|
+
onLoadingChange: (l: boolean) => {
|
|
247
|
+
if (!disposed) setIsLoading(l)
|
|
248
|
+
},
|
|
249
|
+
onErrorChange: (e: Error | undefined) => {
|
|
250
|
+
if (!disposed) setError(e)
|
|
251
|
+
},
|
|
252
|
+
onStatusChange: (s: GenerationClientState) => {
|
|
253
|
+
if (!disposed) setStatus(s)
|
|
254
|
+
},
|
|
255
|
+
onJobIdChange: (id: string | null) => {
|
|
256
|
+
if (!disposed) setJobId(id)
|
|
257
|
+
},
|
|
258
|
+
onVideoStatusChange: (s: VideoStatusInfo | null) => {
|
|
259
|
+
if (!disposed) setVideoStatus(s)
|
|
260
|
+
},
|
|
261
|
+
onResumeStateChange: (rs: { runId: string } | null) => {
|
|
262
|
+
if (!disposed) setRunId(rs?.runId ?? null)
|
|
263
|
+
},
|
|
173
264
|
}
|
|
174
265
|
|
|
175
266
|
if (options.connection) {
|
|
@@ -189,35 +280,38 @@ export function useGenerateVideo<TTransformed = void>(
|
|
|
189
280
|
throw new Error(
|
|
190
281
|
'useGenerateVideo requires either a connection or fetcher option',
|
|
191
282
|
)
|
|
192
|
-
}
|
|
283
|
+
})
|
|
193
284
|
|
|
194
285
|
// Sync body changes without recreating client
|
|
195
286
|
createEffect(() => {
|
|
196
287
|
const currentBody = options.body
|
|
197
|
-
client
|
|
288
|
+
client.updateOptions({
|
|
198
289
|
...(currentBody !== undefined && { body: currentBody }),
|
|
199
290
|
})
|
|
200
291
|
})
|
|
201
292
|
|
|
293
|
+
// Mount devtools only. Generation runs are never auto-started on mount — a
|
|
294
|
+
// persisted snapshot is hydrated for display, never replayed.
|
|
202
295
|
onMount(() => {
|
|
203
|
-
client
|
|
296
|
+
client.mountDevtools()
|
|
204
297
|
})
|
|
205
298
|
|
|
206
299
|
// Cleanup on unmount: stop any in-flight requests and unregister devtools
|
|
207
300
|
onCleanup(() => {
|
|
208
|
-
|
|
301
|
+
disposed = true
|
|
302
|
+
client.dispose()
|
|
209
303
|
})
|
|
210
304
|
|
|
211
305
|
const generate = async (input: VideoGenerateInput) => {
|
|
212
|
-
await client
|
|
306
|
+
await client.generate(input)
|
|
213
307
|
}
|
|
214
308
|
|
|
215
309
|
const stop = () => {
|
|
216
|
-
client
|
|
310
|
+
client.stop()
|
|
217
311
|
}
|
|
218
312
|
|
|
219
313
|
const reset = () => {
|
|
220
|
-
client
|
|
314
|
+
client.reset()
|
|
221
315
|
}
|
|
222
316
|
|
|
223
317
|
return {
|
|
@@ -230,5 +324,6 @@ export function useGenerateVideo<TTransformed = void>(
|
|
|
230
324
|
status,
|
|
231
325
|
stop,
|
|
232
326
|
reset,
|
|
327
|
+
runId,
|
|
233
328
|
}
|
|
234
329
|
}
|