@tanstack/ai-client 0.25.2 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/esm/byok/client.d.ts +52 -0
- package/dist/esm/byok/client.js +300 -0
- package/dist/esm/byok/client.js.map +1 -0
- package/dist/esm/byok/passkey.d.ts +43 -0
- package/dist/esm/byok/passkey.js +251 -0
- package/dist/esm/byok/passkey.js.map +1 -0
- package/dist/esm/byok/resolve.d.ts +8 -0
- package/dist/esm/byok/resolve.js +20 -0
- package/dist/esm/byok/resolve.js.map +1 -0
- package/dist/esm/byok/storage.d.ts +15 -0
- package/dist/esm/byok/storage.js +16 -0
- package/dist/esm/byok/storage.js.map +1 -0
- package/dist/esm/byok.d.ts +8 -0
- package/dist/esm/byok.js +5 -0
- package/dist/esm/chat-client.d.ts +18 -5
- package/dist/esm/chat-client.js +96 -59
- package/dist/esm/chat-client.js.map +1 -1
- package/dist/esm/connection-adapters.d.ts +2 -0
- package/dist/esm/connection-adapters.js +70 -30
- package/dist/esm/connection-adapters.js.map +1 -1
- package/dist/esm/generation-client.d.ts +3 -1
- package/dist/esm/generation-client.js +27 -6
- package/dist/esm/generation-client.js.map +1 -1
- package/dist/esm/generation-types.d.ts +14 -0
- package/dist/esm/generation-types.js +4 -2
- package/dist/esm/generation-types.js.map +1 -1
- package/dist/esm/interrupt-manager.d.ts +1 -0
- package/dist/esm/interrupt-manager.js +15 -6
- package/dist/esm/interrupt-manager.js.map +1 -1
- package/dist/esm/sse-parser.js +8 -1
- package/dist/esm/sse-parser.js.map +1 -1
- package/dist/esm/types.d.ts +46 -3
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/video-generation-client.d.ts +3 -1
- package/dist/esm/video-generation-client.js +29 -8
- package/dist/esm/video-generation-client.js.map +1 -1
- package/package.json +7 -3
- package/src/byok/client.ts +360 -0
- package/src/byok/passkey.ts +399 -0
- package/src/byok/resolve.ts +30 -0
- package/src/byok/storage.ts +29 -0
- package/src/byok.ts +20 -0
- package/src/chat-client.ts +138 -77
- package/src/connection-adapters.ts +108 -53
- package/src/generation-client.ts +53 -9
- package/src/generation-types.ts +24 -2
- package/src/interrupt-manager.ts +20 -6
- package/src/sse-parser.ts +10 -0
- package/src/types.ts +48 -3
- package/src/video-generation-client.ts +50 -9
package/src/chat-client.ts
CHANGED
|
@@ -3,9 +3,21 @@ import {
|
|
|
3
3
|
convertSchemaToJsonSchema,
|
|
4
4
|
generateMessageId,
|
|
5
5
|
isStandardSchema,
|
|
6
|
+
mergeMetadata,
|
|
6
7
|
normalizeToUIMessage,
|
|
7
8
|
parseWithStandardSchema,
|
|
9
|
+
restoreInboundChunk,
|
|
10
|
+
tanstackMetadata,
|
|
8
11
|
} from '@tanstack/ai/client'
|
|
12
|
+
import {
|
|
13
|
+
ByokBlockedError,
|
|
14
|
+
ByokMissingError,
|
|
15
|
+
ByokUnresolvedProviderError,
|
|
16
|
+
} from '@tanstack/ai/byok'
|
|
17
|
+
import {
|
|
18
|
+
prepareResolvedByokHeaders,
|
|
19
|
+
resolveByokProviderId,
|
|
20
|
+
} from './byok/resolve'
|
|
9
21
|
import { createNoOpChatDevtoolsBridge } from './devtools-noop'
|
|
10
22
|
import {
|
|
11
23
|
fetcherToConnectionAdapter,
|
|
@@ -24,6 +36,7 @@ import type {
|
|
|
24
36
|
RunAgentResumeItem,
|
|
25
37
|
StreamChunk,
|
|
26
38
|
} from '@tanstack/ai/client'
|
|
39
|
+
import type { ByokClient } from './byok'
|
|
27
40
|
import type {
|
|
28
41
|
ChatHydrationResult,
|
|
29
42
|
ConnectionAdapter,
|
|
@@ -94,6 +107,8 @@ type ChatClientUpdateOptionsWithoutContext<
|
|
|
94
107
|
/** @deprecated Use `forwardedProps` instead. */
|
|
95
108
|
body?: Record<string, any>
|
|
96
109
|
forwardedProps?: Record<string, any>
|
|
110
|
+
byok?: ByokClient
|
|
111
|
+
byokProvider?: () => string | undefined
|
|
97
112
|
tools?: TTools
|
|
98
113
|
interrupts?: TInterrupts
|
|
99
114
|
queue?: QueueOption
|
|
@@ -189,6 +204,7 @@ export function normalizeQueueOption(
|
|
|
189
204
|
* Merge a run of queued messages into a single send for `drain: 'batch'`.
|
|
190
205
|
* All-string content is joined with newlines; mixed/multimodal content is
|
|
191
206
|
* flattened into a single `ContentPart` array. The last item's `body` wins.
|
|
207
|
+
* Object-form metadata is merged last-write-wins per key.
|
|
192
208
|
*/
|
|
193
209
|
function mergeQueuedMessages(items: Array<InternalQueuedMessage>): {
|
|
194
210
|
content: string | MultimodalContent
|
|
@@ -209,17 +225,24 @@ function mergeQueuedMessages(items: Array<InternalQueuedMessage>): {
|
|
|
209
225
|
}
|
|
210
226
|
}
|
|
211
227
|
const parts: Array<ContentPart> = []
|
|
228
|
+
let metadata: Record<string, any> | undefined
|
|
212
229
|
for (const item of items) {
|
|
213
230
|
if (typeof item.content === 'string') {
|
|
214
231
|
parts.push({ type: 'text', content: item.content })
|
|
215
|
-
|
|
232
|
+
continue
|
|
233
|
+
}
|
|
234
|
+
if (typeof item.content.content === 'string') {
|
|
216
235
|
parts.push({ type: 'text', content: item.content.content })
|
|
217
236
|
} else {
|
|
218
237
|
parts.push(...item.content.content)
|
|
219
238
|
}
|
|
239
|
+
metadata = mergeMetadata(metadata, item.content.metadata)
|
|
220
240
|
}
|
|
221
241
|
return {
|
|
222
|
-
content: {
|
|
242
|
+
content: {
|
|
243
|
+
content: parts,
|
|
244
|
+
...(metadata !== undefined ? { metadata } : {}),
|
|
245
|
+
},
|
|
223
246
|
...(body !== undefined ? { body } : {}),
|
|
224
247
|
}
|
|
225
248
|
}
|
|
@@ -337,6 +360,8 @@ export class ChatClient<
|
|
|
337
360
|
// merged on every send, with `forwardedProps` winning on key collision.
|
|
338
361
|
private bodyOption: Record<string, any> = {}
|
|
339
362
|
private forwardedPropsOption: Record<string, any> = {}
|
|
363
|
+
private byok: ByokClient | undefined
|
|
364
|
+
private byokProvider: (() => string | undefined) | undefined
|
|
340
365
|
private context: TContext | undefined = undefined
|
|
341
366
|
private pendingMessageBody: Record<string, any> | undefined = undefined
|
|
342
367
|
private queueConfig: NormalizedQueueConfig
|
|
@@ -483,6 +508,8 @@ export class ChatClient<
|
|
|
483
508
|
// winning on key collision.
|
|
484
509
|
this.bodyOption = options.body || {}
|
|
485
510
|
this.forwardedPropsOption = options.forwardedProps || {}
|
|
511
|
+
this.byok = options.byok
|
|
512
|
+
this.byokProvider = options.byokProvider
|
|
486
513
|
this.context = options.context
|
|
487
514
|
this.queueConfig = normalizeQueueOption(options.queue)
|
|
488
515
|
this.connection = normalizeConnectionAdapter(resolveTransport(options))
|
|
@@ -1747,12 +1774,14 @@ export class ChatClient<
|
|
|
1747
1774
|
chunk: StreamChunk,
|
|
1748
1775
|
options?: { defer?: boolean },
|
|
1749
1776
|
): Promise<void> {
|
|
1777
|
+
chunk = restoreInboundChunk(chunk)
|
|
1750
1778
|
if (
|
|
1751
1779
|
chunk.type === 'RUN_ERROR' &&
|
|
1752
1780
|
this.isActiveInterruptSubmissionFailure(chunk)
|
|
1753
1781
|
) {
|
|
1782
|
+
const interruptErrors = tanstackMetadata(chunk)?.interruptErrors
|
|
1754
1783
|
this.interruptSubmissionFailure = {
|
|
1755
|
-
errors:
|
|
1784
|
+
errors: Array.isArray(interruptErrors) ? interruptErrors : [],
|
|
1756
1785
|
}
|
|
1757
1786
|
}
|
|
1758
1787
|
if (this.connectionStatus === 'connecting') {
|
|
@@ -1792,8 +1821,10 @@ export class ChatClient<
|
|
|
1792
1821
|
chunk: Extract<StreamChunk, { type: 'RUN_ERROR' }>,
|
|
1793
1822
|
): boolean {
|
|
1794
1823
|
const submission = this.activeInterruptSubmission
|
|
1795
|
-
const errors = chunk
|
|
1796
|
-
if (!submission || !errors || errors.length === 0)
|
|
1824
|
+
const errors = tanstackMetadata(chunk)?.interruptErrors
|
|
1825
|
+
if (!submission || !Array.isArray(errors) || errors.length === 0) {
|
|
1826
|
+
return false
|
|
1827
|
+
}
|
|
1797
1828
|
const runId = getChunkRunId(chunk)
|
|
1798
1829
|
if (runId !== undefined && runId !== this.currentRunId) return false
|
|
1799
1830
|
if (
|
|
@@ -1802,12 +1833,22 @@ export class ChatClient<
|
|
|
1802
1833
|
) {
|
|
1803
1834
|
return false
|
|
1804
1835
|
}
|
|
1805
|
-
return errors.every(
|
|
1806
|
-
(
|
|
1836
|
+
return errors.every((error) => {
|
|
1837
|
+
if (
|
|
1838
|
+
error == null ||
|
|
1839
|
+
typeof error !== 'object' ||
|
|
1840
|
+
typeof error.threadId !== 'string' ||
|
|
1841
|
+
typeof error.interruptedRunId !== 'string' ||
|
|
1842
|
+
typeof error.generation !== 'number'
|
|
1843
|
+
) {
|
|
1844
|
+
return false
|
|
1845
|
+
}
|
|
1846
|
+
return (
|
|
1807
1847
|
error.threadId === submission.threadId &&
|
|
1808
1848
|
error.interruptedRunId === submission.interruptedRunId &&
|
|
1809
|
-
error.generation === submission.generation
|
|
1810
|
-
|
|
1849
|
+
error.generation === submission.generation
|
|
1850
|
+
)
|
|
1851
|
+
})
|
|
1811
1852
|
}
|
|
1812
1853
|
|
|
1813
1854
|
private resolveJoinedRun(chunk: StreamChunk): void {
|
|
@@ -1857,8 +1898,12 @@ export class ChatClient<
|
|
|
1857
1898
|
* - A MultimodalContent object with content array and optional custom ID
|
|
1858
1899
|
* @param body - Optional body parameters to merge with the client's base body for this request.
|
|
1859
1900
|
* Uses shallow merge with per-message body taking priority.
|
|
1860
|
-
* @param sendOptions - Per-call overrides
|
|
1861
|
-
*
|
|
1901
|
+
* @param sendOptions - Per-call overrides. `{ whenBusy }` overrides the
|
|
1902
|
+
* queue policy for this one send. `{ body }`
|
|
1903
|
+
* shallow-merges with `body` and with the chat-level
|
|
1904
|
+
* `body` / `forwardedProps`. `sendOptions.body` wins
|
|
1905
|
+
* on key collisions. Framework hooks forward this
|
|
1906
|
+
* object as their second argument.
|
|
1862
1907
|
*
|
|
1863
1908
|
* @example
|
|
1864
1909
|
* ```ts
|
|
@@ -1868,9 +1913,13 @@ export class ChatClient<
|
|
|
1868
1913
|
* // Text message with custom body params
|
|
1869
1914
|
* await client.sendMessage('Hello!', { temperature: 0.7 })
|
|
1870
1915
|
*
|
|
1871
|
-
* // Per-call whenBusy override
|
|
1916
|
+
* // Per-call whenBusy override
|
|
1872
1917
|
* await client.sendMessage('Urgent', undefined, { whenBusy: 'interrupt' })
|
|
1873
1918
|
*
|
|
1919
|
+
* // Per-call body via options. Same effect as the positional arg.
|
|
1920
|
+
* // This is the shape the framework hooks (`useChat`, `injectChat`) forward.
|
|
1921
|
+
* await client.sendMessage('Hello!', undefined, { body: { temperature: 0.7 } })
|
|
1922
|
+
*
|
|
1874
1923
|
* // Multimodal message with image
|
|
1875
1924
|
* await client.sendMessage({
|
|
1876
1925
|
* content: [
|
|
@@ -1908,13 +1957,15 @@ export class ChatClient<
|
|
|
1908
1957
|
)
|
|
1909
1958
|
}
|
|
1910
1959
|
|
|
1960
|
+
const resolvedBody = { ...body, ...sendOptions?.body }
|
|
1961
|
+
|
|
1911
1962
|
if (this.isSendBusy()) {
|
|
1912
1963
|
const { action, id } = this.decideWhenBusy(content, sendOptions)
|
|
1913
1964
|
if (action === 'drop') {
|
|
1914
1965
|
return
|
|
1915
1966
|
}
|
|
1916
1967
|
if (action === 'queue') {
|
|
1917
|
-
this.enqueueMessage(content,
|
|
1968
|
+
this.enqueueMessage(content, resolvedBody, id)
|
|
1918
1969
|
return
|
|
1919
1970
|
}
|
|
1920
1971
|
// 'interrupt': abort the current stream, then send now.
|
|
@@ -1931,7 +1982,7 @@ export class ChatClient<
|
|
|
1931
1982
|
}
|
|
1932
1983
|
|
|
1933
1984
|
try {
|
|
1934
|
-
await this.deliverMessage(content,
|
|
1985
|
+
await this.deliverMessage(content, resolvedBody)
|
|
1935
1986
|
} finally {
|
|
1936
1987
|
this.sendInFlight = false
|
|
1937
1988
|
}
|
|
@@ -1982,6 +2033,7 @@ export class ChatClient<
|
|
|
1982
2033
|
const userMessage = this.processor.addUserMessage(
|
|
1983
2034
|
normalizedContent.content,
|
|
1984
2035
|
normalizedContent.id,
|
|
2036
|
+
normalizedContent.metadata,
|
|
1985
2037
|
)
|
|
1986
2038
|
this.events.messageSent(userMessage.id, normalizedContent.content)
|
|
1987
2039
|
return await this.streamResponse()
|
|
@@ -2041,17 +2093,22 @@ export class ChatClient<
|
|
|
2041
2093
|
}
|
|
2042
2094
|
|
|
2043
2095
|
/**
|
|
2044
|
-
* Normalize the message input to extract content
|
|
2045
|
-
* Trims string content
|
|
2096
|
+
* Normalize the message input to extract content, optional id, and
|
|
2097
|
+
* optional metadata. String form has no metadata. Trims string content.
|
|
2046
2098
|
*/
|
|
2047
2099
|
private normalizeMessageInput(input: string | MultimodalContent): {
|
|
2048
2100
|
content: string | Array<ContentPart>
|
|
2049
2101
|
id?: string
|
|
2102
|
+
metadata?: Record<string, any>
|
|
2050
2103
|
} {
|
|
2051
2104
|
if (typeof input === 'string') {
|
|
2052
2105
|
return { content: input.trim() }
|
|
2053
2106
|
}
|
|
2054
|
-
return {
|
|
2107
|
+
return {
|
|
2108
|
+
content: input.content,
|
|
2109
|
+
id: input.id,
|
|
2110
|
+
...(input.metadata !== undefined ? { metadata: input.metadata } : {}),
|
|
2111
|
+
}
|
|
2055
2112
|
}
|
|
2056
2113
|
|
|
2057
2114
|
/**
|
|
@@ -2160,7 +2217,7 @@ export class ChatClient<
|
|
|
2160
2217
|
// order (later spreads win):
|
|
2161
2218
|
// 1. Legacy `body` option (deprecated).
|
|
2162
2219
|
// 2. Canonical `forwardedProps` option (wins over `body`).
|
|
2163
|
-
// 3. Per-
|
|
2220
|
+
// 3. Per-call body (`pendingMessageBody`: positional + sendOptions.body).
|
|
2164
2221
|
// The AG-UI standard `threadId` is sent at the wire's top level for
|
|
2165
2222
|
// run/conversation correlation, so we no longer auto-emit a separate
|
|
2166
2223
|
// `conversationId` here — `chat({ threadId })` server-side covers the
|
|
@@ -2200,6 +2257,15 @@ export class ChatClient<
|
|
|
2200
2257
|
// AG-UI servers consuming `RunAgentInput.tools[].parameters` expect
|
|
2201
2258
|
// JSON Schema; sending a Standard Schema instance directly would
|
|
2202
2259
|
// serialize to an unusable shape.
|
|
2260
|
+
let byokHeaders: Record<string, string> | undefined
|
|
2261
|
+
if (this.byok) {
|
|
2262
|
+
const provider = resolveByokProviderId(
|
|
2263
|
+
this.byokProvider,
|
|
2264
|
+
mergedBody.provider,
|
|
2265
|
+
)
|
|
2266
|
+
byokHeaders = await prepareResolvedByokHeaders(this.byok, provider)
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2203
2269
|
const runContext = {
|
|
2204
2270
|
threadId: resumeThreadId ?? this.threadId,
|
|
2205
2271
|
runId,
|
|
@@ -2215,6 +2281,7 @@ export class ChatClient<
|
|
|
2215
2281
|
})),
|
|
2216
2282
|
forwardedProps: { ...mergedBody },
|
|
2217
2283
|
...(resumeItems ? { resume: resumeItems } : {}),
|
|
2284
|
+
...(byokHeaders ? { headers: byokHeaders } : {}),
|
|
2218
2285
|
}
|
|
2219
2286
|
this.devtoolsBridge.beginRun(runContext.runId, runContext.threadId)
|
|
2220
2287
|
activeDevtoolsRunId = runContext.runId
|
|
@@ -2270,32 +2337,45 @@ export class ChatClient<
|
|
|
2270
2337
|
// Finalize (idempotent — may already be done by RUN_FINISHED handler)
|
|
2271
2338
|
this.processor.finalizeStream()
|
|
2272
2339
|
streamCompletedSuccessfully = true
|
|
2273
|
-
} catch (err) {
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
}
|
|
2284
|
-
return false
|
|
2340
|
+
} catch (err: unknown) {
|
|
2341
|
+
const error = err instanceof Error ? err : new Error(String(err))
|
|
2342
|
+
if (error.name === 'AbortError') {
|
|
2343
|
+
if (activeDevtoolsRunId) {
|
|
2344
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
2345
|
+
'run:cancelled',
|
|
2346
|
+
activeDevtoolsRunId,
|
|
2347
|
+
'cancelled',
|
|
2348
|
+
)
|
|
2349
|
+
runTerminalEventEmitted = true
|
|
2285
2350
|
}
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2351
|
+
return false
|
|
2352
|
+
}
|
|
2353
|
+
if (error instanceof ByokMissingError) {
|
|
2354
|
+
this.byok?.request(error.provider, 'missing')
|
|
2355
|
+
}
|
|
2356
|
+
if (error instanceof ByokBlockedError && error.reason === 'locked') {
|
|
2357
|
+
this.byok?.request(error.provider, 'locked')
|
|
2358
|
+
}
|
|
2359
|
+
if (generation === this.streamGeneration) {
|
|
2360
|
+
this.reportStreamError(error)
|
|
2361
|
+
if (activeDevtoolsRunId) {
|
|
2362
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
2363
|
+
'run:errored',
|
|
2364
|
+
activeDevtoolsRunId,
|
|
2365
|
+
'errored',
|
|
2366
|
+
{ error: error.message },
|
|
2367
|
+
)
|
|
2368
|
+
runTerminalEventEmitted = true
|
|
2297
2369
|
}
|
|
2298
2370
|
}
|
|
2371
|
+
if (
|
|
2372
|
+
generation === this.streamGeneration &&
|
|
2373
|
+
(error instanceof ByokMissingError ||
|
|
2374
|
+
error instanceof ByokBlockedError ||
|
|
2375
|
+
error instanceof ByokUnresolvedProviderError)
|
|
2376
|
+
) {
|
|
2377
|
+
throw error
|
|
2378
|
+
}
|
|
2299
2379
|
} finally {
|
|
2300
2380
|
// Only clean up if this is still the active stream.
|
|
2301
2381
|
// A superseded stream (e.g. reload() started a new one) must not
|
|
@@ -2330,43 +2410,18 @@ export class ChatClient<
|
|
|
2330
2410
|
// Drain any actions that were queued while the stream was in progress
|
|
2331
2411
|
await this.drainPostStreamActions()
|
|
2332
2412
|
|
|
2333
|
-
// Continue conversation if the stream ended with a tool result (server tool completed)
|
|
2334
|
-
// but ONLY if the model indicated it wants to continue (finishReason !== 'stop').
|
|
2335
|
-
// When finishReason is 'stop', the model is done — don't re-send.
|
|
2336
2413
|
if (streamCompletedSuccessfully) {
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
)
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
} catch (error) {
|
|
2349
|
-
console.error('Failed to continue flow after tool result:', error)
|
|
2350
|
-
// Continuation failed without starting a new stream — don't
|
|
2351
|
-
// leave queued user messages stranded forever. (isLoading is
|
|
2352
|
-
// already false in this finally block.)
|
|
2353
|
-
await this.drainQueue()
|
|
2354
|
-
}
|
|
2355
|
-
} else {
|
|
2356
|
-
if (this.status !== 'ready') {
|
|
2357
|
-
// Terminal run, but onStreamEnd never fired: the processor had
|
|
2358
|
-
// no assistant message to emit it for (e.g. a bare
|
|
2359
|
-
// RUN_FINISHED{stop}, #421). The normal path already set
|
|
2360
|
-
// 'ready', so this is a no-op.
|
|
2361
|
-
this.setStatus('ready')
|
|
2362
|
-
}
|
|
2363
|
-
// Auto-send queued messages once the run fully settles. When a
|
|
2364
|
-
// continuation runs instead (tool-result branch above), that
|
|
2365
|
-
// continuation's own finally drains the queue. Skip if a drain
|
|
2366
|
-
// loop is already walking the queue (avoids nested re-entry).
|
|
2367
|
-
if (!this.messageQueueDraining) {
|
|
2368
|
-
await this.drainQueue()
|
|
2369
|
-
}
|
|
2414
|
+
if (this.status !== 'ready') {
|
|
2415
|
+
// Terminal run, but onStreamEnd never fired: the processor had
|
|
2416
|
+
// no assistant message to emit it for (e.g. a bare
|
|
2417
|
+
// RUN_FINISHED{stop}, #421). The normal path already set
|
|
2418
|
+
// 'ready', so this is a no-op.
|
|
2419
|
+
this.setStatus('ready')
|
|
2420
|
+
}
|
|
2421
|
+
// Auto-send queued messages once the run fully settles. Skip if a
|
|
2422
|
+
// drain loop is already walking the queue (avoids nested re-entry).
|
|
2423
|
+
if (!this.messageQueueDraining) {
|
|
2424
|
+
await this.drainQueue()
|
|
2370
2425
|
}
|
|
2371
2426
|
} else {
|
|
2372
2427
|
// Error/abort settle for the active generation: don't strand or
|
|
@@ -2948,6 +3003,12 @@ export class ChatClient<
|
|
|
2948
3003
|
if (options.forwardedProps !== undefined) {
|
|
2949
3004
|
this.forwardedPropsOption = options.forwardedProps
|
|
2950
3005
|
}
|
|
3006
|
+
if (options.byok !== undefined) {
|
|
3007
|
+
this.byok = options.byok
|
|
3008
|
+
}
|
|
3009
|
+
if (options.byokProvider !== undefined) {
|
|
3010
|
+
this.byokProvider = options.byokProvider
|
|
3011
|
+
}
|
|
2951
3012
|
if ('context' in options) {
|
|
2952
3013
|
this.context = options.context
|
|
2953
3014
|
}
|