Skip to content

Commit c46a009

Browse files
committed
fix(openai-base): align with main's event type + adapter signature changes
After merging main's PR #466 and related work into the openai-base extraction: - Cast AG-UI stream events through an asChunk helper so they satisfy the EventType-enum-typed StreamChunk union that main introduced. - Update BaseImage/TTS/Transcription super() calls to match main's (model, config) constructor signature (was (config, model)). - Fix GeneratedImage transform to produce the new discriminated url-xor-b64Json shape from main. - Propagate options.logger through summarize -> chatStream so the required InternalLogger field is present. - Recreate ai-grok/src/tools/index.ts (vite entry expects it); it now re-exports the Chat Completions tool converters from openai-base.
1 parent 8d5121e commit c46a009

8 files changed

Lines changed: 172 additions & 76 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export {
2+
type ChatCompletionFunctionTool as FunctionTool,
3+
convertFunctionToolToChatCompletionsFormat as convertFunctionToolToAdapterFormat,
4+
convertToolsToChatCompletionsFormat as convertToolsToProviderFormat,
5+
} from '@tanstack/openai-base'

packages/typescript/openai-base/src/adapters/chat-completions-text.ts

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ import type {
1818
} from '@tanstack/ai'
1919
import type { OpenAICompatibleClientConfig } from '../types/config'
2020

21+
/** Cast an event object to StreamChunk. Adapters construct events with string
22+
* literal types which are structurally compatible with the EventType enum. */
23+
const asChunk = (chunk: Record<string, unknown>) =>
24+
chunk as unknown as StreamChunk
25+
2126
/**
2227
* OpenAI-compatible Chat Completions Text Adapter
2328
*
@@ -96,16 +101,16 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
96101
// Emit RUN_STARTED if not yet emitted
97102
if (!aguiState.hasEmittedRunStarted) {
98103
aguiState.hasEmittedRunStarted = true
99-
yield {
104+
yield asChunk({
100105
type: 'RUN_STARTED',
101106
runId: aguiState.runId,
102107
model: options.model,
103108
timestamp,
104-
}
109+
})
105110
}
106111

107112
// Emit AG-UI RUN_ERROR
108-
yield {
113+
yield asChunk({
109114
type: 'RUN_ERROR',
110115
runId: aguiState.runId,
111116
model: options.model,
@@ -114,7 +119,7 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
114119
message: err.message || 'Unknown error',
115120
code: err.code,
116121
},
117-
}
122+
})
118123

119124
console.error(
120125
`>>> [${this.name}] chatStream: Fatal error during response creation <<<`,
@@ -256,12 +261,12 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
256261
// Emit RUN_STARTED on first chunk
257262
if (!aguiState.hasEmittedRunStarted) {
258263
aguiState.hasEmittedRunStarted = true
259-
yield {
264+
yield asChunk({
260265
type: 'RUN_STARTED',
261266
runId: aguiState.runId,
262267
model: chunk.model || options.model,
263268
timestamp,
264-
}
269+
})
265270
}
266271

267272
const delta = choice.delta
@@ -273,26 +278,26 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
273278
// Emit TEXT_MESSAGE_START on first text content
274279
if (!hasEmittedTextMessageStart) {
275280
hasEmittedTextMessageStart = true
276-
yield {
281+
yield asChunk({
277282
type: 'TEXT_MESSAGE_START',
278283
messageId: aguiState.messageId,
279284
model: chunk.model || options.model,
280285
timestamp,
281286
role: 'assistant',
282-
}
287+
})
283288
}
284289

285290
accumulatedContent += deltaContent
286291

287292
// Emit AG-UI TEXT_MESSAGE_CONTENT
288-
yield {
293+
yield asChunk({
289294
type: 'TEXT_MESSAGE_CONTENT',
290295
messageId: aguiState.messageId,
291296
model: chunk.model || options.model,
292297
timestamp,
293298
delta: deltaContent,
294299
content: accumulatedContent,
295-
}
300+
})
296301
}
297302

298303
// Handle tool calls - they come in as deltas
@@ -326,25 +331,25 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
326331
// Emit TOOL_CALL_START when we have id and name
327332
if (toolCall.id && toolCall.name && !toolCall.started) {
328333
toolCall.started = true
329-
yield {
334+
yield asChunk({
330335
type: 'TOOL_CALL_START',
331336
toolCallId: toolCall.id,
332337
toolName: toolCall.name,
333338
model: chunk.model || options.model,
334339
timestamp,
335340
index,
336-
}
341+
})
337342
}
338343

339344
// Emit TOOL_CALL_ARGS for argument deltas
340345
if (toolCallDelta.function?.arguments && toolCall.started) {
341-
yield {
346+
yield asChunk({
342347
type: 'TOOL_CALL_ARGS',
343348
toolCallId: toolCall.id,
344349
model: chunk.model || options.model,
345350
timestamp,
346351
delta: toolCallDelta.function.arguments,
347-
}
352+
})
348353
}
349354
}
350355
}
@@ -368,14 +373,14 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
368373
}
369374

370375
// Emit AG-UI TOOL_CALL_END
371-
yield {
376+
yield asChunk({
372377
type: 'TOOL_CALL_END',
373378
toolCallId: toolCall.id,
374379
toolName: toolCall.name,
375380
model: chunk.model || options.model,
376381
timestamp,
377382
input: parsedInput,
378-
}
383+
})
379384
}
380385
}
381386

@@ -387,16 +392,16 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
387392

388393
// Emit TEXT_MESSAGE_END if we had text content
389394
if (hasEmittedTextMessageStart) {
390-
yield {
395+
yield asChunk({
391396
type: 'TEXT_MESSAGE_END',
392397
messageId: aguiState.messageId,
393398
model: chunk.model || options.model,
394399
timestamp,
395-
}
400+
})
396401
}
397402

398403
// Emit AG-UI RUN_FINISHED
399-
yield {
404+
yield asChunk({
400405
type: 'RUN_FINISHED',
401406
runId: aguiState.runId,
402407
model: chunk.model || options.model,
@@ -409,15 +414,15 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
409414
}
410415
: undefined,
411416
finishReason: computedFinishReason,
412-
}
417+
})
413418
}
414419
}
415420
} catch (error: unknown) {
416421
const err = error as Error & { code?: string }
417422
console.error(`[${this.name}] Stream ended with error:`, err.message)
418423

419424
// Emit AG-UI RUN_ERROR
420-
yield {
425+
yield asChunk({
421426
type: 'RUN_ERROR',
422427
runId: aguiState.runId,
423428
model: options.model,
@@ -426,7 +431,7 @@ export class OpenAICompatibleChatCompletionsTextAdapter<
426431
message: err.message || 'Unknown error occurred',
427432
code: err.code,
428433
},
429-
}
434+
})
430435
}
431436
}
432437

packages/typescript/openai-base/src/adapters/image.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class OpenAICompatibleImageAdapter<
4343
model: TModel,
4444
name: string = 'openai-compatible',
4545
) {
46-
super({}, model)
46+
super(model, {})
4747
this.name = name
4848
this.client = createOpenAICompatibleClient(config)
4949
}
@@ -87,11 +87,18 @@ export class OpenAICompatibleImageAdapter<
8787
model: string,
8888
response: OpenAI_SDK.Images.ImagesResponse,
8989
): ImageGenerationResult {
90-
const images: Array<GeneratedImage> = (response.data ?? []).map((item) => ({
91-
b64Json: item.b64_json,
92-
url: item.url,
93-
revisedPrompt: item.revised_prompt,
94-
}))
90+
const images: Array<GeneratedImage> = (response.data ?? []).flatMap(
91+
(item): Array<GeneratedImage> => {
92+
const revisedPrompt = item.revised_prompt
93+
if (item.b64_json) {
94+
return [{ b64Json: item.b64_json, revisedPrompt }]
95+
}
96+
if (item.url) {
97+
return [{ url: item.url, revisedPrompt }]
98+
}
99+
return []
100+
},
101+
)
95102

96103
return {
97104
id: generateId(this.name),

0 commit comments

Comments
 (0)