Skip to content

Commit 3e88109

Browse files
committed
fix: resolve type errors from @ag-ui/core Zod passthrough types
Zod passthrough adds `& { [k: string]: unknown }` to inferred types, preventing TypeScript from narrowing the `type` discriminant in switch statements. Add explicit casts where needed. Also fix toolCallName -> toolName rename in realtime types to match consumer code.
1 parent af99dde commit 3e88109

5 files changed

Lines changed: 27 additions & 22 deletions

File tree

packages/typescript/ai-openai/src/realtime/adapter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,11 @@ async function createWebRTCConnection(
284284
}
285285
try {
286286
const input = JSON.parse(args)
287-
emit('tool_call', { toolCallId: callId, toolCallName: name, input })
287+
emit('tool_call', { toolCallId: callId, toolName: name, input })
288288
} catch {
289289
emit('tool_call', {
290290
toolCallId: callId,
291-
toolCallName: name,
291+
toolName: name,
292292
input: args,
293293
})
294294
}

packages/typescript/ai/src/activities/chat/middleware/compose.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,16 @@ export class MiddlewareRunner {
132132

133133
const nextChunks: Array<StreamChunk> = []
134134
for (const c of chunks) {
135+
// Cast: @ag-ui/core Zod passthrough types prevent direct `.type` access
136+
const chunkType = (c as StreamChunk & { type: string }).type
135137
const result = await mw.onChunk(ctx, c)
136138
if (result === null) {
137139
// Drop this chunk
138140
if (!skip) {
139141
aiEventClient.emit('middleware:chunk:transformed', {
140142
...instrumentCtx(ctx),
141143
middlewareName: mw.name || 'unnamed',
142-
originalChunkType: c.type,
144+
originalChunkType: chunkType,
143145
resultCount: 0,
144146
wasDropped: true,
145147
})
@@ -155,7 +157,7 @@ export class MiddlewareRunner {
155157
aiEventClient.emit('middleware:chunk:transformed', {
156158
...instrumentCtx(ctx),
157159
middlewareName: mw.name || 'unnamed',
158-
originalChunkType: c.type,
160+
originalChunkType: chunkType,
159161
resultCount: result.length,
160162
wasDropped: false,
161163
})
@@ -167,7 +169,7 @@ export class MiddlewareRunner {
167169
aiEventClient.emit('middleware:chunk:transformed', {
168170
...instrumentCtx(ctx),
169171
middlewareName: mw.name || 'unnamed',
170-
originalChunkType: c.type,
172+
originalChunkType: chunkType,
171173
resultCount: 1,
172174
wasDropped: false,
173175
})

packages/typescript/ai/src/activities/chat/stream/processor.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -445,54 +445,57 @@ export class StreamProcessor {
445445
})
446446
}
447447

448-
switch (chunk.type) {
448+
// Cast needed: @ag-ui/core Zod passthrough types add `& { [k: string]: unknown }`
449+
// which prevents TypeScript from narrowing the `type` discriminant in switch.
450+
const c = chunk as StreamChunk & { type: string }
451+
switch (c.type) {
449452
// AG-UI Events
450453
case 'TEXT_MESSAGE_START':
451-
this.handleTextMessageStartEvent(chunk)
454+
this.handleTextMessageStartEvent(chunk as Extract<StreamChunk, { type: 'TEXT_MESSAGE_START' }>)
452455
break
453456

454457
case 'TEXT_MESSAGE_CONTENT':
455-
this.handleTextMessageContentEvent(chunk)
458+
this.handleTextMessageContentEvent(chunk as Extract<StreamChunk, { type: 'TEXT_MESSAGE_CONTENT' }>)
456459
break
457460

458461
case 'TEXT_MESSAGE_END':
459-
this.handleTextMessageEndEvent(chunk)
462+
this.handleTextMessageEndEvent(chunk as Extract<StreamChunk, { type: 'TEXT_MESSAGE_END' }>)
460463
break
461464

462465
case 'TOOL_CALL_START':
463-
this.handleToolCallStartEvent(chunk)
466+
this.handleToolCallStartEvent(chunk as Extract<StreamChunk, { type: 'TOOL_CALL_START' }>)
464467
break
465468

466469
case 'TOOL_CALL_ARGS':
467-
this.handleToolCallArgsEvent(chunk)
470+
this.handleToolCallArgsEvent(chunk as Extract<StreamChunk, { type: 'TOOL_CALL_ARGS' }>)
468471
break
469472

470473
case 'TOOL_CALL_END':
471-
this.handleToolCallEndEvent(chunk)
474+
this.handleToolCallEndEvent(chunk as Extract<StreamChunk, { type: 'TOOL_CALL_END' }>)
472475
break
473476

474477
case 'RUN_FINISHED':
475-
this.handleRunFinishedEvent(chunk)
478+
this.handleRunFinishedEvent(chunk as Extract<StreamChunk, { type: 'RUN_FINISHED' }>)
476479
break
477480

478481
case 'RUN_ERROR':
479-
this.handleRunErrorEvent(chunk)
482+
this.handleRunErrorEvent(chunk as Extract<StreamChunk, { type: 'RUN_ERROR' }>)
480483
break
481484

482485
case 'STEP_FINISHED':
483-
this.handleStepFinishedEvent(chunk)
486+
this.handleStepFinishedEvent(chunk as Extract<StreamChunk, { type: 'STEP_FINISHED' }>)
484487
break
485488

486489
case 'MESSAGES_SNAPSHOT':
487-
this.handleMessagesSnapshotEvent(chunk)
490+
this.handleMessagesSnapshotEvent(chunk as Extract<StreamChunk, { type: 'MESSAGES_SNAPSHOT' }>)
488491
break
489492

490493
case 'CUSTOM':
491-
this.handleCustomEvent(chunk)
494+
this.handleCustomEvent(chunk as Extract<StreamChunk, { type: 'CUSTOM' }>)
492495
break
493496

494497
case 'RUN_STARTED':
495-
this.handleRunStartedEvent(chunk)
498+
this.handleRunStartedEvent(chunk as Extract<StreamChunk, { type: 'RUN_STARTED' }>)
496499
break
497500

498501
case 'REASONING_START':
@@ -503,11 +506,11 @@ export class StreamProcessor {
503506
break
504507

505508
case 'REASONING_MESSAGE_CONTENT':
506-
this.handleReasoningMessageContentEvent(chunk)
509+
this.handleReasoningMessageContentEvent(chunk as Extract<StreamChunk, { type: 'REASONING_MESSAGE_CONTENT' }>)
507510
break
508511

509512
case 'TOOL_CALL_RESULT':
510-
this.handleToolCallResultEvent(chunk)
513+
this.handleToolCallResultEvent(chunk as Extract<StreamChunk, { type: 'TOOL_CALL_RESULT' }>)
511514
break
512515

513516
default:

packages/typescript/ai/src/realtime/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export interface RealtimeEventPayloads {
257257
isFinal: boolean
258258
}
259259
audio_chunk: { data: ArrayBuffer; sampleRate: number }
260-
tool_call: { toolCallId: string; toolCallName: string; input: unknown }
260+
tool_call: { toolCallId: string; toolName: string; input: unknown }
261261
message_complete: { message: RealtimeMessage }
262262
interrupted: { messageId?: string }
263263
error: { error: Error }

packages/typescript/ai/src/strip-to-spec-middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type { StreamChunk } from './types'
1212
*/
1313
export function stripToSpec(chunk: StreamChunk): StreamChunk {
1414
// Only strip the deprecated nested error object from RUN_ERROR
15-
if (chunk.type === 'RUN_ERROR' && 'error' in chunk) {
15+
if ((chunk as StreamChunk & { type: string }).type === 'RUN_ERROR' && 'error' in chunk) {
1616
const { error: _deprecated, ...rest } = chunk as Record<string, unknown>
1717
return rest as StreamChunk
1818
}

0 commit comments

Comments
 (0)