@tanstack/ai 0.45.0 → 0.46.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 +10 -1
- package/dist/esm/activities/chat/index.js +55 -5
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/tools/unique-tool-names.d.ts +20 -0
- package/dist/esm/activities/chat/tools/unique-tool-names.js +57 -0
- package/dist/esm/activities/chat/tools/unique-tool-names.js.map +1 -0
- package/dist/esm/adapter-internals.d.ts +1 -0
- package/dist/esm/adapter-internals.js +2 -1
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/middlewares/usage-attributes.d.ts +2 -2
- package/dist/esm/middlewares/usage-attributes.js +9 -2
- package/dist/esm/middlewares/usage-attributes.js.map +1 -1
- package/dist/esm/stream-to-response.d.ts +26 -0
- package/dist/esm/stream-to-response.js +1 -1
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/stream-to-websocket.d.ts +123 -0
- package/dist/esm/stream-to-websocket.js +249 -0
- package/dist/esm/stream-to-websocket.js.map +1 -0
- package/dist/esm/types.d.ts +8 -7
- package/package.json +2 -2
- package/skills/ai-core/media-generation/SKILL.md +9 -8
- package/src/activities/chat/index.ts +96 -13
- package/src/activities/chat/tools/unique-tool-names.ts +73 -0
- package/src/adapter-internals.ts +4 -0
- package/src/index.ts +17 -0
- package/src/middlewares/usage-attributes.ts +12 -2
- package/src/stream-to-response.ts +2 -2
- package/src/stream-to-websocket.ts +418 -0
- package/src/types.ts +10 -5
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
import { normalizeToolResult } from '../../utilities/tool-result'
|
|
26
26
|
import { isProviderExecutedToolCall } from '../../utilities/provider-executed'
|
|
27
27
|
import { LazyToolManager } from './tools/lazy-tool-manager'
|
|
28
|
+
import { assertUniqueToolNames } from './tools/unique-tool-names'
|
|
28
29
|
import {
|
|
29
30
|
MiddlewareAbortError,
|
|
30
31
|
ToolCallManager,
|
|
@@ -42,7 +43,11 @@ import {
|
|
|
42
43
|
} from './tools/approval-schema'
|
|
43
44
|
import { maxIterations as maxIterationsStrategy } from './agent-loop-strategies'
|
|
44
45
|
import { isCancelRequestedReason } from './cancel'
|
|
45
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
convertMessagesToModelMessages,
|
|
48
|
+
generateMessageId,
|
|
49
|
+
modelMessageToUIMessage,
|
|
50
|
+
} from './messages'
|
|
46
51
|
import { MiddlewareRunner } from './middleware/compose'
|
|
47
52
|
import { getRunDetached } from './middleware/run-store'
|
|
48
53
|
import { publishRunDetachedSignal } from '../../delivery-detach'
|
|
@@ -738,9 +743,11 @@ class TextEngine<
|
|
|
738
743
|
[]
|
|
739
744
|
private currentThinkingContent = ''
|
|
740
745
|
private currentThinkingSignature = ''
|
|
746
|
+
private hasSeenReasoningEvents = false
|
|
741
747
|
private eventOptions?: Record<string, unknown> | undefined
|
|
742
748
|
private eventToolNames?: Array<string>
|
|
743
749
|
private finishedEvent: RunFinishedEvent | null = null
|
|
750
|
+
private readonly streamedToolErrorResults = new Map<string, ToolResult>()
|
|
744
751
|
private deferredToolCallRunFinishedChunks: Array<StreamChunk> = []
|
|
745
752
|
private earlyTermination = false
|
|
746
753
|
private toolPhase: ToolPhaseResult = 'continue'
|
|
@@ -840,6 +847,7 @@ class TextEngine<
|
|
|
840
847
|
this.messages = convertMessagesToModelMessages(config.params.messages)
|
|
841
848
|
|
|
842
849
|
// Initialize lazy tool manager after messages are converted (needs message history for scanning)
|
|
850
|
+
assertUniqueToolNames(config.params.tools || [])
|
|
843
851
|
this.lazyToolManager = new LazyToolManager(
|
|
844
852
|
config.params.tools || [],
|
|
845
853
|
this.messages,
|
|
@@ -1151,6 +1159,7 @@ class TextEngine<
|
|
|
1151
1159
|
duration: Date.now() - this.streamStartTime,
|
|
1152
1160
|
})
|
|
1153
1161
|
} else {
|
|
1162
|
+
this.addTerminalReasoningMessage()
|
|
1154
1163
|
this.terminalHookCalled = true
|
|
1155
1164
|
await this.middlewareRunner.runOnFinish(this.middlewareCtx, {
|
|
1156
1165
|
finishReason: this.lastFinishReason,
|
|
@@ -1281,7 +1290,9 @@ class TextEngine<
|
|
|
1281
1290
|
this.accumulatedThinking = []
|
|
1282
1291
|
this.currentThinkingContent = ''
|
|
1283
1292
|
this.currentThinkingSignature = ''
|
|
1293
|
+
this.hasSeenReasoningEvents = false
|
|
1284
1294
|
this.finishedEvent = null
|
|
1295
|
+
this.streamedToolErrorResults.clear()
|
|
1285
1296
|
|
|
1286
1297
|
// Update mutable context fields
|
|
1287
1298
|
this.middlewareCtx.currentMessageId = this.currentMessageId
|
|
@@ -1531,16 +1542,19 @@ class TextEngine<
|
|
|
1531
1542
|
this.handleStepFinishedEvent(chunk)
|
|
1532
1543
|
break
|
|
1533
1544
|
|
|
1545
|
+
case 'REASONING_MESSAGE_CONTENT':
|
|
1546
|
+
this.handleReasoningMessageContentEvent(chunk)
|
|
1547
|
+
break
|
|
1548
|
+
|
|
1534
1549
|
case 'TOOL_CALL_RESULT':
|
|
1535
1550
|
// Tool result is already added to messages in buildToolResultChunks
|
|
1536
1551
|
break
|
|
1537
1552
|
|
|
1538
1553
|
case 'REASONING_START':
|
|
1539
1554
|
case 'REASONING_MESSAGE_START':
|
|
1540
|
-
case 'REASONING_MESSAGE_CONTENT':
|
|
1541
1555
|
case 'REASONING_MESSAGE_END':
|
|
1542
1556
|
case 'REASONING_END':
|
|
1543
|
-
//
|
|
1557
|
+
// No special handling needed
|
|
1544
1558
|
break
|
|
1545
1559
|
|
|
1546
1560
|
default:
|
|
@@ -1588,6 +1602,20 @@ class TextEngine<
|
|
|
1588
1602
|
|
|
1589
1603
|
private handleToolCallEndEvent(chunk: ToolCallEndEvent): void {
|
|
1590
1604
|
this.toolCallManager.completeToolCall(chunk)
|
|
1605
|
+
if (chunk.state !== 'output-error' || chunk.result === undefined) return
|
|
1606
|
+
|
|
1607
|
+
const toolCall = this.toolCallManager
|
|
1608
|
+
.getToolCalls()
|
|
1609
|
+
.find((candidate) => candidate.id === chunk.toolCallId)
|
|
1610
|
+
if (!toolCall) return
|
|
1611
|
+
|
|
1612
|
+
this.streamedToolErrorResults.set(chunk.toolCallId, {
|
|
1613
|
+
toolCallId: chunk.toolCallId,
|
|
1614
|
+
toolName: toolCall.function.name,
|
|
1615
|
+
result: chunk.result,
|
|
1616
|
+
...(chunk.input !== undefined && { input: chunk.input }),
|
|
1617
|
+
state: 'output-error',
|
|
1618
|
+
})
|
|
1591
1619
|
}
|
|
1592
1620
|
|
|
1593
1621
|
private handleRunFinishedEvent(chunk: RunFinishedEvent): void {
|
|
@@ -1635,14 +1663,29 @@ class TextEngine<
|
|
|
1635
1663
|
private handleStepFinishedEvent(
|
|
1636
1664
|
chunk: Extract<StreamChunk, { type: 'STEP_FINISHED' }>,
|
|
1637
1665
|
): void {
|
|
1638
|
-
if (
|
|
1639
|
-
|
|
1666
|
+
if (!this.hasSeenReasoningEvents) {
|
|
1667
|
+
if (chunk.delta) {
|
|
1668
|
+
this.currentThinkingContent += chunk.delta
|
|
1669
|
+
} else if (chunk.content) {
|
|
1670
|
+
if (chunk.content.startsWith(this.currentThinkingContent)) {
|
|
1671
|
+
this.currentThinkingContent = chunk.content
|
|
1672
|
+
} else if (!this.currentThinkingContent.startsWith(chunk.content)) {
|
|
1673
|
+
this.currentThinkingContent += chunk.content
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1640
1676
|
}
|
|
1641
1677
|
if (chunk.signature) {
|
|
1642
1678
|
this.currentThinkingSignature = chunk.signature
|
|
1643
1679
|
}
|
|
1644
1680
|
}
|
|
1645
1681
|
|
|
1682
|
+
private handleReasoningMessageContentEvent(
|
|
1683
|
+
chunk: Extract<StreamChunk, { type: 'REASONING_MESSAGE_CONTENT' }>,
|
|
1684
|
+
): void {
|
|
1685
|
+
this.hasSeenReasoningEvents = true
|
|
1686
|
+
this.currentThinkingContent += chunk.delta
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1646
1689
|
/**
|
|
1647
1690
|
* Tools available for execution this turn. The discovery tool is dropped
|
|
1648
1691
|
* from the advertised set (`this.tools`) once every lazy tool is discovered,
|
|
@@ -1843,6 +1886,9 @@ class TextEngine<
|
|
|
1843
1886
|
// Handle undiscovered lazy tool calls with self-correcting error messages
|
|
1844
1887
|
const undiscoveredLazyResults: Array<ToolResult> = []
|
|
1845
1888
|
const executableToolCalls = toolCalls.filter((tc) => {
|
|
1889
|
+
if (this.streamedToolErrorResults.has(tc.id)) {
|
|
1890
|
+
return false
|
|
1891
|
+
}
|
|
1846
1892
|
if (this.lazyToolManager.isUndiscoveredLazyTool(tc.function.name)) {
|
|
1847
1893
|
undiscoveredLazyResults.push({
|
|
1848
1894
|
toolCallId: tc.id,
|
|
@@ -1859,14 +1905,17 @@ class TextEngine<
|
|
|
1859
1905
|
return true
|
|
1860
1906
|
})
|
|
1861
1907
|
|
|
1862
|
-
// Non-executed outcomes
|
|
1863
|
-
//
|
|
1864
|
-
const deferredErrorResults = [
|
|
1908
|
+
// Non-executed outcomes. Per-turn skips come from middleware and appear in
|
|
1909
|
+
// execution results.
|
|
1910
|
+
const deferredErrorResults = [
|
|
1911
|
+
...this.streamedToolErrorResults.values(),
|
|
1912
|
+
...undiscoveredLazyResults,
|
|
1913
|
+
]
|
|
1865
1914
|
|
|
1866
1915
|
if (executableToolCalls.length === 0) {
|
|
1867
1916
|
yield* this.flushDeferredToolCallRunFinishedChunks()
|
|
1868
|
-
// All tool calls
|
|
1869
|
-
// loop (strategy / onShouldContinue may stop).
|
|
1917
|
+
// All tool calls already have error results — emit them, then continue
|
|
1918
|
+
// the loop (strategy / onShouldContinue may stop).
|
|
1870
1919
|
if (deferredErrorResults.length > 0) {
|
|
1871
1920
|
for (const chunk of this.buildToolResultChunks(
|
|
1872
1921
|
deferredErrorResults,
|
|
@@ -2043,6 +2092,30 @@ class TextEngine<
|
|
|
2043
2092
|
this.middlewareCtx.messages = this.messages
|
|
2044
2093
|
}
|
|
2045
2094
|
|
|
2095
|
+
private addTerminalReasoningMessage(): void {
|
|
2096
|
+
this.finalizeCurrentThinkingStep()
|
|
2097
|
+
if (this.accumulatedThinking.length === 0) return
|
|
2098
|
+
|
|
2099
|
+
const messages = this.middlewareCtx.messages
|
|
2100
|
+
const alreadyPresent = messages.some(
|
|
2101
|
+
(message) =>
|
|
2102
|
+
message.role === 'assistant' && message.id === this.currentMessageId,
|
|
2103
|
+
)
|
|
2104
|
+
if (alreadyPresent) return
|
|
2105
|
+
|
|
2106
|
+
this.messages = [
|
|
2107
|
+
...messages,
|
|
2108
|
+
{
|
|
2109
|
+
role: 'assistant',
|
|
2110
|
+
content: this.accumulatedContent || null,
|
|
2111
|
+
id: this.currentMessageId ?? undefined,
|
|
2112
|
+
createdAt: this.currentMessageCreatedAt ?? undefined,
|
|
2113
|
+
thinking: this.accumulatedThinking,
|
|
2114
|
+
},
|
|
2115
|
+
]
|
|
2116
|
+
this.middlewareCtx.messages = this.messages
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2046
2119
|
/**
|
|
2047
2120
|
* Extract client state (approvals and client tool results) from original messages.
|
|
2048
2121
|
* This is called in the constructor BEFORE converting to ModelMessage format,
|
|
@@ -2232,12 +2305,18 @@ class TextEngine<
|
|
|
2232
2305
|
: message.content === null
|
|
2233
2306
|
? undefined
|
|
2234
2307
|
: JSON.stringify(message.content)
|
|
2308
|
+
const id =
|
|
2309
|
+
message.id ||
|
|
2310
|
+
`snapshot_${this.runIdOverride ?? this.requestId}_${index}`
|
|
2311
|
+
const parts =
|
|
2312
|
+
message.role === 'assistant' && message.thinking?.length
|
|
2313
|
+
? modelMessageToUIMessage(message, id).parts
|
|
2314
|
+
: undefined
|
|
2235
2315
|
return {
|
|
2236
|
-
id
|
|
2237
|
-
message.id ||
|
|
2238
|
-
`snapshot_${this.runIdOverride ?? this.requestId}_${index}`,
|
|
2316
|
+
id,
|
|
2239
2317
|
role: message.role,
|
|
2240
2318
|
...(content !== undefined ? { content } : {}),
|
|
2319
|
+
...(parts ? { parts } : {}),
|
|
2241
2320
|
...('toolCalls' in message && message.toolCalls
|
|
2242
2321
|
? { toolCalls: message.toolCalls }
|
|
2243
2322
|
: {}),
|
|
@@ -3551,6 +3630,7 @@ class TextEngine<
|
|
|
3551
3630
|
this.applyResumeToolState(config.resumeToolState)
|
|
3552
3631
|
this.messages = config.messages
|
|
3553
3632
|
this.systemPrompts = config.systemPrompts
|
|
3633
|
+
assertUniqueToolNames(config.tools)
|
|
3554
3634
|
this.tools = config.tools
|
|
3555
3635
|
this.params = {
|
|
3556
3636
|
...this.params,
|
|
@@ -3743,6 +3823,9 @@ export function chat<
|
|
|
3743
3823
|
>,
|
|
3744
3824
|
): TextActivityResult<TSchema, TStream, TTools> {
|
|
3745
3825
|
validateCapabilities(options.middleware ?? [], options.adapter)
|
|
3826
|
+
if (options.tools) {
|
|
3827
|
+
assertUniqueToolNames(options.tools)
|
|
3828
|
+
}
|
|
3746
3829
|
|
|
3747
3830
|
const { outputSchema, stream } = options
|
|
3748
3831
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Tool } from '../../../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Thrown when `chat({ tools })` (or a provider converter) receives two tools
|
|
5
|
+
* with the same public `name`.
|
|
6
|
+
*
|
|
7
|
+
* The common case is a provider-native factory (`webSearchTool()`) next to an
|
|
8
|
+
* ordinary function that reused the reserved name (`web_search`). Providers
|
|
9
|
+
* reject that pair, so we fail before the request is built.
|
|
10
|
+
*/
|
|
11
|
+
export class DuplicateToolNameError extends Error {
|
|
12
|
+
readonly toolName: string
|
|
13
|
+
|
|
14
|
+
constructor(toolName: string, message: string) {
|
|
15
|
+
super(message)
|
|
16
|
+
this.name = 'DuplicateToolNameError'
|
|
17
|
+
this.toolName = toolName
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isProviderNativeTool(tool: Tool): boolean {
|
|
22
|
+
const kind = tool.metadata?.['__kind']
|
|
23
|
+
return typeof kind === 'string' && kind.length > 0
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function nativeAndCustomMessage(toolName: string) {
|
|
27
|
+
return [
|
|
28
|
+
`Cannot pass two tools named "${toolName}" in the same chat() call.`,
|
|
29
|
+
`One is the provider-native tool from a factory (for example webSearchTool()).`,
|
|
30
|
+
`The other is your own function with the same public name.`,
|
|
31
|
+
`Tool names in one tools array must be unique.`,
|
|
32
|
+
`Keep the factory for hosted search, or keep your function and give it a different name.`,
|
|
33
|
+
].join(' ')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function duplicateNameMessage(toolName: string) {
|
|
37
|
+
return [
|
|
38
|
+
`Cannot pass two tools named "${toolName}" in the same chat() call.`,
|
|
39
|
+
`Tool names in one tools array must be unique.`,
|
|
40
|
+
].join(' ')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Throws {@link DuplicateToolNameError} when two tools share a public name.
|
|
45
|
+
*
|
|
46
|
+
* The native-vs-custom message fires when one of the colliding tools carries
|
|
47
|
+
* adapter `metadata.__kind` (set by a provider factory) and another does not.
|
|
48
|
+
*/
|
|
49
|
+
export function assertUniqueToolNames(tools: ReadonlyArray<Tool>): void {
|
|
50
|
+
const byName = new Map<string, Array<Tool>>()
|
|
51
|
+
for (const tool of tools) {
|
|
52
|
+
const group = byName.get(tool.name)
|
|
53
|
+
if (group) {
|
|
54
|
+
group.push(tool)
|
|
55
|
+
} else {
|
|
56
|
+
byName.set(tool.name, [tool])
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const [name, group] of byName) {
|
|
61
|
+
if (group.length < 2) {
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
const hasNative = group.some(isProviderNativeTool)
|
|
65
|
+
const hasCustom = group.some((tool) => !isProviderNativeTool(tool))
|
|
66
|
+
throw new DuplicateToolNameError(
|
|
67
|
+
name,
|
|
68
|
+
hasNative && hasCustom
|
|
69
|
+
? nativeAndCustomMessage(name)
|
|
70
|
+
: duplicateNameMessage(name),
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
}
|
package/src/adapter-internals.ts
CHANGED
|
@@ -25,6 +25,10 @@ export {
|
|
|
25
25
|
PendingTurnCapability,
|
|
26
26
|
providePendingTurn,
|
|
27
27
|
} from './activities/chat/middleware/pending-turn'
|
|
28
|
+
export {
|
|
29
|
+
assertUniqueToolNames,
|
|
30
|
+
DuplicateToolNameError,
|
|
31
|
+
} from './activities/chat/tools/unique-tool-names'
|
|
28
32
|
export {
|
|
29
33
|
appendOutputSchemaInstruction,
|
|
30
34
|
parseJsonFromAssistantText,
|
package/src/index.ts
CHANGED
|
@@ -103,6 +103,7 @@ export type {
|
|
|
103
103
|
|
|
104
104
|
// MCP error classes (value exports — usable with instanceof)
|
|
105
105
|
export { MCPDuplicateToolNameError } from './activities/chat/mcp/manager'
|
|
106
|
+
export { DuplicateToolNameError } from './activities/chat/tools/unique-tool-names'
|
|
106
107
|
|
|
107
108
|
// Schema conversion (Standard JSON Schema compliant)
|
|
108
109
|
export {
|
|
@@ -138,6 +139,22 @@ export type {
|
|
|
138
139
|
UpsertableStreamDurability,
|
|
139
140
|
} from './stream-durability'
|
|
140
141
|
|
|
142
|
+
// WebSocket transport utilities
|
|
143
|
+
export {
|
|
144
|
+
toWebSocketStream,
|
|
145
|
+
toWebSocketResponse,
|
|
146
|
+
resumeWebSocketStream,
|
|
147
|
+
resumeWebSocketResponse,
|
|
148
|
+
encodeWsFrame,
|
|
149
|
+
decodeWsFrame,
|
|
150
|
+
} from './stream-to-websocket'
|
|
151
|
+
export type {
|
|
152
|
+
WebSocketLike,
|
|
153
|
+
WsRunContext,
|
|
154
|
+
WebSocketStreamInit,
|
|
155
|
+
InboundFrame,
|
|
156
|
+
} from './stream-to-websocket'
|
|
157
|
+
|
|
141
158
|
// Tool call management
|
|
142
159
|
export { ToolCallManager } from './activities/chat/tools/tool-calls'
|
|
143
160
|
|
|
@@ -12,8 +12,8 @@ import type { TokenUsage } from '../types'
|
|
|
12
12
|
* `gen_ai.usage.cost` and `gen_ai.usage.total_tokens` are de-facto extensions
|
|
13
13
|
* consumed by backends like PostHog (which otherwise re-derive cost from their
|
|
14
14
|
* own price tables, losing cache discounts and gateway markup). Fields with no
|
|
15
|
-
* semconv or de-facto convention (`
|
|
16
|
-
* `unitsBilled`) are TanStack-namespaced.
|
|
15
|
+
* semconv or de-facto convention (`billed`, `costDetails`, and the deprecated
|
|
16
|
+
* `durationSeconds`/`unitsBilled`) are TanStack-namespaced.
|
|
17
17
|
*
|
|
18
18
|
* Shared by `otelMiddleware` across every activity (chat and the media
|
|
19
19
|
* activities) so usage lands identically whichever activity produced the span.
|
|
@@ -30,6 +30,16 @@ export function usageAttributes(
|
|
|
30
30
|
'gen_ai.usage.input_tokens': usage.promptTokens,
|
|
31
31
|
'gen_ai.usage.output_tokens': usage.completionTokens,
|
|
32
32
|
}
|
|
33
|
+
// The self-describing billed quantity: the unit rides along as a string
|
|
34
|
+
// attribute so backends can label/aggregate non-token usage without
|
|
35
|
+
// out-of-band knowledge of the provider.
|
|
36
|
+
if (usage.billed !== undefined) {
|
|
37
|
+
const quantity = firstNumber(usage.billed.quantity)
|
|
38
|
+
if (quantity !== undefined) {
|
|
39
|
+
attrs['tanstack.ai.usage.billed_quantity'] = quantity
|
|
40
|
+
attrs['tanstack.ai.usage.billed_unit'] = usage.billed.unit
|
|
41
|
+
}
|
|
42
|
+
}
|
|
33
43
|
const optional: Array<[key: string, value: unknown]> = [
|
|
34
44
|
['gen_ai.usage.total_tokens', usage.totalTokens],
|
|
35
45
|
['gen_ai.usage.cost', usage.cost],
|
|
@@ -78,7 +78,7 @@ function combineFailures(
|
|
|
78
78
|
)
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
function runErrorChunk(
|
|
81
|
+
export function runErrorChunk(
|
|
82
82
|
error: unknown,
|
|
83
83
|
): Extract<StreamChunk, { type: 'RUN_ERROR' }> {
|
|
84
84
|
const payload = toRunErrorPayload(error)
|
|
@@ -366,7 +366,7 @@ export const RUN_ACCEPTED_EVENT = 'run.accepted'
|
|
|
366
366
|
* The returned `getId` maps each forwarded chunk to the exact opaque offset
|
|
367
367
|
* returned by the durability adapter for the SSE `id:` line.
|
|
368
368
|
*/
|
|
369
|
-
function durableStreamSource<TOffset extends string>(
|
|
369
|
+
export function durableStreamSource<TOffset extends string>(
|
|
370
370
|
stream: AsyncIterable<StreamChunk>,
|
|
371
371
|
durability: StreamDurability<TOffset>,
|
|
372
372
|
options: {
|