@tanstack/ai-grok 0.7.1 → 0.7.3

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.
Files changed (45) hide show
  1. package/dist/esm/adapters/image.d.ts +8 -7
  2. package/dist/esm/adapters/image.js +10 -60
  3. package/dist/esm/adapters/image.js.map +1 -1
  4. package/dist/esm/adapters/summarize.d.ts +2 -7
  5. package/dist/esm/adapters/summarize.js +11 -95
  6. package/dist/esm/adapters/summarize.js.map +1 -1
  7. package/dist/esm/adapters/text.d.ts +10 -34
  8. package/dist/esm/adapters/text.js +4 -381
  9. package/dist/esm/adapters/text.js.map +1 -1
  10. package/dist/esm/adapters/transcription.js +3 -1
  11. package/dist/esm/adapters/transcription.js.map +1 -1
  12. package/dist/esm/adapters/tts.js +3 -1
  13. package/dist/esm/adapters/tts.js.map +1 -1
  14. package/dist/esm/realtime/token.js +2 -0
  15. package/dist/esm/realtime/token.js.map +1 -1
  16. package/dist/esm/text/text-provider-options.d.ts +0 -14
  17. package/dist/esm/tools/index.d.ts +1 -2
  18. package/dist/esm/tools/index.js +3 -4
  19. package/dist/esm/tools/index.js.map +1 -1
  20. package/dist/esm/utils/client.d.ts +5 -9
  21. package/dist/esm/utils/client.js +11 -17
  22. package/dist/esm/utils/client.js.map +1 -1
  23. package/dist/esm/utils/index.d.ts +2 -1
  24. package/dist/esm/utils/schema-converter.d.ts +2 -24
  25. package/package.json +6 -6
  26. package/src/adapters/image.ts +18 -87
  27. package/src/adapters/summarize.ts +16 -121
  28. package/src/adapters/text.ts +13 -562
  29. package/src/text/text-provider-options.ts +0 -22
  30. package/src/tools/index.ts +4 -4
  31. package/src/utils/client.ts +15 -30
  32. package/src/utils/index.ts +2 -2
  33. package/src/utils/schema-converter.ts +2 -110
  34. package/dist/esm/text/text-provider-options.js +0 -6
  35. package/dist/esm/text/text-provider-options.js.map +0 -1
  36. package/dist/esm/tools/function-tool.d.ts +0 -15
  37. package/dist/esm/tools/function-tool.js +0 -27
  38. package/dist/esm/tools/function-tool.js.map +0 -1
  39. package/dist/esm/tools/tool-converter.d.ts +0 -7
  40. package/dist/esm/tools/tool-converter.js +0 -10
  41. package/dist/esm/tools/tool-converter.js.map +0 -1
  42. package/dist/esm/utils/schema-converter.js +0 -71
  43. package/dist/esm/utils/schema-converter.js.map +0 -1
  44. package/src/tools/function-tool.ts +0 -45
  45. package/src/tools/tool-converter.ts +0 -17
@@ -1,52 +1,23 @@
1
- import { BaseTextAdapter } from '@tanstack/ai/adapters'
2
- import { validateTextProviderOptions } from '../text/text-provider-options'
3
- import { convertToolsToProviderFormat } from '../tools'
4
- import {
5
- createGrokClient,
6
- generateId,
7
- getGrokApiKeyFromEnv,
8
- makeGrokStructuredOutputCompatible,
9
- transformNullsToUndefined,
10
- } from '../utils'
1
+ import { OpenAICompatibleChatCompletionsTextAdapter } from '@tanstack/openai-base'
2
+ import { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'
11
3
  import type {
12
4
  GROK_CHAT_MODELS,
13
5
  GrokChatModelToolCapabilitiesByName,
14
6
  ResolveInputModalities,
15
7
  ResolveProviderOptions,
16
8
  } from '../model-meta'
17
- import type {
18
- StructuredOutputOptions,
19
- StructuredOutputResult,
20
- } from '@tanstack/ai/adapters'
21
- import type { InternalLogger } from '@tanstack/ai/adapter-internals'
22
- import type OpenAI_SDK from 'openai'
23
- import type {
24
- ContentPart,
25
- Modality,
26
- ModelMessage,
27
- StreamChunk,
28
- TextOptions,
29
- } from '@tanstack/ai'
30
- import type {
31
- ExternalTextProviderOptions as GrokTextProviderOptions,
32
- InternalTextProviderOptions,
33
- } from '../text/text-provider-options'
34
- import type {
35
- GrokImageMetadata,
36
- GrokMessageMetadataByModality,
37
- } from '../message-types'
9
+ import type { Modality } from '@tanstack/ai'
10
+ import type { GrokMessageMetadataByModality } from '../message-types'
38
11
  import type { GrokClientConfig } from '../utils'
39
12
 
13
+ /**
14
+ * Resolve tool capabilities for a specific Grok model.
15
+ */
40
16
  type ResolveToolCapabilities<TModel extends string> =
41
17
  TModel extends keyof GrokChatModelToolCapabilitiesByName
42
18
  ? NonNullable<GrokChatModelToolCapabilitiesByName[TModel]>
43
19
  : readonly []
44
20
 
45
- /** Cast an event object to StreamChunk. Adapters construct events with string
46
- * literal types which are structurally compatible with the EventType enum. */
47
- const asChunk = (chunk: Record<string, unknown>) =>
48
- chunk as unknown as StreamChunk
49
-
50
21
  /**
51
22
  * Configuration for Grok text adapter
52
23
  */
@@ -62,6 +33,10 @@ export type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../
62
33
  *
63
34
  * Tree-shakeable adapter for Grok chat/text completion functionality.
64
35
  * Uses OpenAI-compatible Chat Completions API (not Responses API).
36
+ *
37
+ * Delegates implementation to {@link OpenAICompatibleChatCompletionsTextAdapter}
38
+ * from `@tanstack/openai-base` and threads Grok-specific tool-capability typing
39
+ * through the 5th generic of the base class.
65
40
  */
66
41
  export class GrokTextAdapter<
67
42
  TModel extends (typeof GROK_CHAT_MODELS)[number],
@@ -70,7 +45,7 @@ export class GrokTextAdapter<
70
45
  ResolveInputModalities<TModel>,
71
46
  TToolCapabilities extends ReadonlyArray<string> =
72
47
  ResolveToolCapabilities<TModel>,
73
- > extends BaseTextAdapter<
48
+ > extends OpenAICompatibleChatCompletionsTextAdapter<
74
49
  TModel,
75
50
  TProviderOptions,
76
51
  TInputModalities,
@@ -80,532 +55,8 @@ export class GrokTextAdapter<
80
55
  readonly kind = 'text' as const
81
56
  readonly name = 'grok' as const
82
57
 
83
- private client: OpenAI_SDK
84
-
85
58
  constructor(config: GrokTextConfig, model: TModel) {
86
- super({}, model)
87
- this.client = createGrokClient(config)
88
- }
89
-
90
- async *chatStream(
91
- options: TextOptions<GrokTextProviderOptions>,
92
- ): AsyncIterable<StreamChunk> {
93
- const requestParams = this.mapTextOptionsToGrok(options)
94
- const timestamp = Date.now()
95
- const { logger } = options
96
-
97
- // AG-UI lifecycle tracking (mutable state object for ESLint compatibility)
98
- const aguiState = {
99
- runId: options.runId ?? generateId(this.name),
100
- threadId: options.threadId ?? generateId(this.name),
101
- messageId: generateId(this.name),
102
- timestamp,
103
- hasEmittedRunStarted: false,
104
- }
105
-
106
- try {
107
- logger.request(
108
- `activity=chat provider=grok model=${this.model} messages=${options.messages.length} tools=${options.tools?.length ?? 0} stream=true`,
109
- { provider: 'grok', model: this.model },
110
- )
111
- const stream = await this.client.chat.completions.create({
112
- ...requestParams,
113
- stream: true,
114
- })
115
-
116
- yield* this.processGrokStreamChunks(stream, options, aguiState, logger)
117
- } catch (error: unknown) {
118
- const err = error as Error & { code?: string }
119
-
120
- // Emit RUN_STARTED if not yet emitted
121
- if (!aguiState.hasEmittedRunStarted) {
122
- aguiState.hasEmittedRunStarted = true
123
- yield asChunk({
124
- type: 'RUN_STARTED',
125
- runId: aguiState.runId,
126
- threadId: aguiState.threadId,
127
- model: options.model,
128
- timestamp,
129
- })
130
- }
131
-
132
- // Emit AG-UI RUN_ERROR
133
- yield asChunk({
134
- type: 'RUN_ERROR',
135
- runId: aguiState.runId,
136
- model: options.model,
137
- timestamp,
138
- message: err.message || 'Unknown error',
139
- code: err.code,
140
- error: {
141
- message: err.message || 'Unknown error',
142
- code: err.code,
143
- },
144
- })
145
-
146
- logger.errors('grok.chatStream fatal', {
147
- error,
148
- source: 'grok.chatStream',
149
- })
150
- }
151
- }
152
-
153
- /**
154
- * Generate structured output using Grok's JSON Schema response format.
155
- * Uses stream: false to get the complete response in one call.
156
- *
157
- * Grok has strict requirements for structured output (via OpenAI-compatible API):
158
- * - All properties must be in the `required` array
159
- * - Optional fields should have null added to their type union
160
- * - additionalProperties must be false for all objects
161
- *
162
- * The outputSchema is already JSON Schema (converted in the ai layer).
163
- * We apply Grok-specific transformations for structured output compatibility.
164
- */
165
- async structuredOutput(
166
- options: StructuredOutputOptions<GrokTextProviderOptions>,
167
- ): Promise<StructuredOutputResult<unknown>> {
168
- const { chatOptions, outputSchema } = options
169
- const requestParams = this.mapTextOptionsToGrok(chatOptions)
170
- const { logger } = chatOptions
171
-
172
- // Apply Grok-specific transformations for structured output compatibility
173
- const jsonSchema = makeGrokStructuredOutputCompatible(
174
- outputSchema,
175
- outputSchema.required || [],
176
- )
177
-
178
- try {
179
- logger.request(
180
- `activity=chat provider=grok model=${this.model} messages=${chatOptions.messages.length} tools=${chatOptions.tools?.length ?? 0} stream=false`,
181
- { provider: 'grok', model: this.model },
182
- )
183
- const response = await this.client.chat.completions.create({
184
- ...requestParams,
185
- stream: false,
186
- response_format: {
187
- type: 'json_schema',
188
- json_schema: {
189
- name: 'structured_output',
190
- schema: jsonSchema,
191
- strict: true,
192
- },
193
- },
194
- })
195
-
196
- // Extract text content from the response
197
- const rawText = response.choices[0]?.message.content || ''
198
-
199
- // Parse the JSON response
200
- let parsed: unknown
201
- try {
202
- parsed = JSON.parse(rawText)
203
- } catch {
204
- throw new Error(
205
- `Failed to parse structured output as JSON. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,
206
- )
207
- }
208
-
209
- // Transform null values to undefined to match original Zod schema expectations
210
- // Grok returns null for optional fields we made nullable in the schema
211
- const transformed = transformNullsToUndefined(parsed)
212
-
213
- return {
214
- data: transformed,
215
- rawText,
216
- }
217
- } catch (error: unknown) {
218
- logger.errors('grok.structuredOutput fatal', {
219
- error,
220
- source: 'grok.structuredOutput',
221
- })
222
- throw error
223
- }
224
- }
225
-
226
- private async *processGrokStreamChunks(
227
- stream: AsyncIterable<OpenAI_SDK.Chat.Completions.ChatCompletionChunk>,
228
- options: TextOptions,
229
- aguiState: {
230
- runId: string
231
- threadId: string
232
- messageId: string
233
- timestamp: number
234
- hasEmittedRunStarted: boolean
235
- },
236
- logger: InternalLogger,
237
- ): AsyncIterable<StreamChunk> {
238
- let accumulatedContent = ''
239
- const timestamp = aguiState.timestamp
240
- let hasEmittedTextMessageStart = false
241
-
242
- // Track tool calls being streamed (arguments come in chunks)
243
- const toolCallsInProgress = new Map<
244
- number,
245
- {
246
- id: string
247
- name: string
248
- arguments: string
249
- started: boolean // Track if TOOL_CALL_START has been emitted
250
- }
251
- >()
252
-
253
- try {
254
- for await (const chunk of stream) {
255
- logger.provider(`provider=grok`, { chunk })
256
- const choice = chunk.choices[0]
257
-
258
- if (!choice) continue
259
-
260
- // Emit RUN_STARTED on first chunk
261
- if (!aguiState.hasEmittedRunStarted) {
262
- aguiState.hasEmittedRunStarted = true
263
- yield asChunk({
264
- type: 'RUN_STARTED',
265
- runId: aguiState.runId,
266
- threadId: aguiState.threadId,
267
- model: chunk.model || options.model,
268
- timestamp,
269
- })
270
- }
271
-
272
- const delta = choice.delta
273
- const deltaContent = delta.content
274
- const deltaToolCalls = delta.tool_calls
275
-
276
- // Handle content delta
277
- if (deltaContent) {
278
- // Emit TEXT_MESSAGE_START on first text content
279
- if (!hasEmittedTextMessageStart) {
280
- hasEmittedTextMessageStart = true
281
- yield asChunk({
282
- type: 'TEXT_MESSAGE_START',
283
- messageId: aguiState.messageId,
284
- model: chunk.model || options.model,
285
- timestamp,
286
- role: 'assistant',
287
- })
288
- }
289
-
290
- accumulatedContent += deltaContent
291
-
292
- // Emit AG-UI TEXT_MESSAGE_CONTENT
293
- yield asChunk({
294
- type: 'TEXT_MESSAGE_CONTENT',
295
- messageId: aguiState.messageId,
296
- model: chunk.model || options.model,
297
- timestamp,
298
- delta: deltaContent,
299
- content: accumulatedContent,
300
- })
301
- }
302
-
303
- // Handle tool calls - they come in as deltas
304
- if (deltaToolCalls) {
305
- for (const toolCallDelta of deltaToolCalls) {
306
- const index = toolCallDelta.index
307
-
308
- // Initialize or update the tool call in progress
309
- if (!toolCallsInProgress.has(index)) {
310
- toolCallsInProgress.set(index, {
311
- id: toolCallDelta.id || '',
312
- name: toolCallDelta.function?.name || '',
313
- arguments: '',
314
- started: false,
315
- })
316
- }
317
-
318
- const toolCall = toolCallsInProgress.get(index)!
319
-
320
- // Update with any new data from the delta
321
- if (toolCallDelta.id) {
322
- toolCall.id = toolCallDelta.id
323
- }
324
- if (toolCallDelta.function?.name) {
325
- toolCall.name = toolCallDelta.function.name
326
- }
327
- if (toolCallDelta.function?.arguments) {
328
- toolCall.arguments += toolCallDelta.function.arguments
329
- }
330
-
331
- // Emit TOOL_CALL_START when we have id and name
332
- if (toolCall.id && toolCall.name && !toolCall.started) {
333
- toolCall.started = true
334
- yield asChunk({
335
- type: 'TOOL_CALL_START',
336
- toolCallId: toolCall.id,
337
- toolCallName: toolCall.name,
338
- toolName: toolCall.name,
339
- model: chunk.model || options.model,
340
- timestamp,
341
- index,
342
- })
343
- }
344
-
345
- // Emit TOOL_CALL_ARGS for argument deltas
346
- if (toolCallDelta.function?.arguments && toolCall.started) {
347
- yield asChunk({
348
- type: 'TOOL_CALL_ARGS',
349
- toolCallId: toolCall.id,
350
- model: chunk.model || options.model,
351
- timestamp,
352
- delta: toolCallDelta.function.arguments,
353
- })
354
- }
355
- }
356
- }
357
-
358
- // Handle finish reason
359
- if (choice.finish_reason) {
360
- // Emit all completed tool calls
361
- if (
362
- choice.finish_reason === 'tool_calls' ||
363
- toolCallsInProgress.size > 0
364
- ) {
365
- for (const [, toolCall] of toolCallsInProgress) {
366
- // Parse arguments for TOOL_CALL_END
367
- let parsedInput: unknown = {}
368
- try {
369
- parsedInput = toolCall.arguments
370
- ? JSON.parse(toolCall.arguments)
371
- : {}
372
- } catch {
373
- parsedInput = {}
374
- }
375
-
376
- // Emit AG-UI TOOL_CALL_END
377
- yield asChunk({
378
- type: 'TOOL_CALL_END',
379
- toolCallId: toolCall.id,
380
- toolCallName: toolCall.name,
381
- toolName: toolCall.name,
382
- model: chunk.model || options.model,
383
- timestamp,
384
- input: parsedInput,
385
- })
386
- }
387
- }
388
-
389
- const computedFinishReason =
390
- choice.finish_reason === 'tool_calls' ||
391
- toolCallsInProgress.size > 0
392
- ? 'tool_calls'
393
- : 'stop'
394
-
395
- // Emit TEXT_MESSAGE_END if we had text content
396
- if (hasEmittedTextMessageStart) {
397
- yield asChunk({
398
- type: 'TEXT_MESSAGE_END',
399
- messageId: aguiState.messageId,
400
- model: chunk.model || options.model,
401
- timestamp,
402
- })
403
- }
404
-
405
- // Emit AG-UI RUN_FINISHED
406
- yield asChunk({
407
- type: 'RUN_FINISHED',
408
- runId: aguiState.runId,
409
- threadId: aguiState.threadId,
410
- model: chunk.model || options.model,
411
- timestamp,
412
- usage: chunk.usage
413
- ? {
414
- promptTokens: chunk.usage.prompt_tokens || 0,
415
- completionTokens: chunk.usage.completion_tokens || 0,
416
- totalTokens: chunk.usage.total_tokens || 0,
417
- }
418
- : undefined,
419
- finishReason: computedFinishReason,
420
- })
421
- }
422
- }
423
- } catch (error: unknown) {
424
- const err = error as Error & { code?: string }
425
- logger.errors('grok stream ended with error', {
426
- error,
427
- source: 'grok.processGrokStreamChunks',
428
- })
429
-
430
- // Emit AG-UI RUN_ERROR
431
- yield asChunk({
432
- type: 'RUN_ERROR',
433
- runId: aguiState.runId,
434
- model: options.model,
435
- timestamp,
436
- message: err.message || 'Unknown error occurred',
437
- code: err.code,
438
- error: {
439
- message: err.message || 'Unknown error occurred',
440
- code: err.code,
441
- },
442
- })
443
- }
444
- }
445
-
446
- /**
447
- * Maps common options to Grok-specific Chat Completions format
448
- */
449
- private mapTextOptionsToGrok(
450
- options: TextOptions,
451
- ): OpenAI_SDK.Chat.Completions.ChatCompletionCreateParamsStreaming {
452
- const modelOptions = options.modelOptions as
453
- | Omit<
454
- InternalTextProviderOptions,
455
- 'max_tokens' | 'tools' | 'temperature' | 'input' | 'top_p'
456
- >
457
- | undefined
458
-
459
- if (modelOptions) {
460
- validateTextProviderOptions({
461
- ...modelOptions,
462
- model: options.model,
463
- })
464
- }
465
-
466
- const tools = options.tools
467
- ? convertToolsToProviderFormat(options.tools)
468
- : undefined
469
-
470
- // Build messages array with system prompts
471
- const messages: Array<OpenAI_SDK.Chat.Completions.ChatCompletionMessageParam> =
472
- []
473
-
474
- // Add system prompts first
475
- if (options.systemPrompts && options.systemPrompts.length > 0) {
476
- messages.push({
477
- role: 'system',
478
- content: options.systemPrompts.join('\n'),
479
- })
480
- }
481
-
482
- // Convert messages
483
- for (const message of options.messages) {
484
- messages.push(this.convertMessageToGrok(message))
485
- }
486
-
487
- return {
488
- model: options.model,
489
- messages,
490
- temperature: options.temperature,
491
- max_tokens: options.maxTokens,
492
- top_p: options.topP,
493
- tools: tools as Array<OpenAI_SDK.Chat.Completions.ChatCompletionTool>,
494
- stream: true,
495
- stream_options: { include_usage: true },
496
- }
497
- }
498
-
499
- private convertMessageToGrok(
500
- message: ModelMessage,
501
- ): OpenAI_SDK.Chat.Completions.ChatCompletionMessageParam {
502
- // Handle tool messages
503
- if (message.role === 'tool') {
504
- return {
505
- role: 'tool',
506
- tool_call_id: message.toolCallId || '',
507
- content:
508
- typeof message.content === 'string'
509
- ? message.content
510
- : JSON.stringify(message.content),
511
- }
512
- }
513
-
514
- // Handle assistant messages
515
- if (message.role === 'assistant') {
516
- const toolCalls = message.toolCalls?.map((tc) => ({
517
- id: tc.id,
518
- type: 'function' as const,
519
- function: {
520
- name: tc.function.name,
521
- arguments:
522
- typeof tc.function.arguments === 'string'
523
- ? tc.function.arguments
524
- : JSON.stringify(tc.function.arguments),
525
- },
526
- }))
527
-
528
- return {
529
- role: 'assistant',
530
- content: this.extractTextContent(message.content),
531
- ...(toolCalls && toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
532
- }
533
- }
534
-
535
- // Handle user messages - support multimodal content
536
- const contentParts = this.normalizeContent(message.content)
537
-
538
- // If only text, use simple string format
539
- if (contentParts.length === 1 && contentParts[0]?.type === 'text') {
540
- return {
541
- role: 'user',
542
- content: contentParts[0].content,
543
- }
544
- }
545
-
546
- // Otherwise, use array format for multimodal
547
- const parts: Array<OpenAI_SDK.Chat.Completions.ChatCompletionContentPart> =
548
- []
549
- for (const part of contentParts) {
550
- if (part.type === 'text') {
551
- parts.push({ type: 'text', text: part.content })
552
- } else if (part.type === 'image') {
553
- const imageMetadata = part.metadata as GrokImageMetadata | undefined
554
- // For base64 data, construct a data URI using the mimeType from source
555
- const imageValue = part.source.value
556
- const imageUrl =
557
- part.source.type === 'data' && !imageValue.startsWith('data:')
558
- ? `data:${part.source.mimeType};base64,${imageValue}`
559
- : imageValue
560
- parts.push({
561
- type: 'image_url',
562
- image_url: {
563
- url: imageUrl,
564
- detail: imageMetadata?.detail || 'auto',
565
- },
566
- })
567
- }
568
- }
569
-
570
- return {
571
- role: 'user',
572
- content: parts.length > 0 ? parts : '',
573
- }
574
- }
575
-
576
- /**
577
- * Normalizes message content to an array of ContentPart.
578
- * Handles backward compatibility with string content.
579
- */
580
- private normalizeContent(
581
- content: string | null | Array<ContentPart>,
582
- ): Array<ContentPart> {
583
- if (content === null) {
584
- return []
585
- }
586
- if (typeof content === 'string') {
587
- return [{ type: 'text', content: content }]
588
- }
589
- return content
590
- }
591
-
592
- /**
593
- * Extracts text content from a content value that may be string, null, or ContentPart array.
594
- */
595
- private extractTextContent(
596
- content: string | null | Array<ContentPart>,
597
- ): string {
598
- if (content === null) {
599
- return ''
600
- }
601
- if (typeof content === 'string') {
602
- return content
603
- }
604
- // It's an array of ContentPart
605
- return content
606
- .filter((p) => p.type === 'text')
607
- .map((p) => p.content)
608
- .join('')
59
+ super(withGrokDefaults(config), model, 'grok')
609
60
  }
610
61
  }
611
62
 
@@ -1,5 +1,3 @@
1
- import type { FunctionTool } from '../tools/function-tool'
2
-
3
1
  /**
4
2
  * Grok Text Provider Options
5
3
  *
@@ -51,27 +49,7 @@ export interface GrokTextProviderOptions extends GrokBaseOptions {
51
49
  stop?: string | Array<string>
52
50
  }
53
51
 
54
- /**
55
- * Internal options interface for validation
56
- * Used internally by the adapter
57
- */
58
- export interface InternalTextProviderOptions extends GrokTextProviderOptions {
59
- model: string
60
- stream?: boolean
61
- tools?: Array<FunctionTool>
62
- }
63
-
64
52
  /**
65
53
  * External provider options (what users pass in)
66
54
  */
67
55
  export type ExternalTextProviderOptions = GrokTextProviderOptions
68
-
69
- /**
70
- * Validates text provider options
71
- */
72
- export function validateTextProviderOptions(
73
- _options: InternalTextProviderOptions,
74
- ): void {
75
- // Basic validation can be added here if needed
76
- // For now, Grok API will handle validation
77
- }
@@ -1,5 +1,5 @@
1
1
  export {
2
- convertFunctionToolToAdapterFormat,
3
- type FunctionTool,
4
- } from './function-tool'
5
- export { convertToolsToProviderFormat } from './tool-converter'
2
+ type ChatCompletionFunctionTool as FunctionTool,
3
+ convertFunctionToolToChatCompletionsFormat as convertFunctionToolToAdapterFormat,
4
+ convertToolsToChatCompletionsFormat as convertToolsToProviderFormat,
5
+ } from '@tanstack/openai-base'