-
-
Notifications
You must be signed in to change notification settings - Fork 110
feat: add Grok support #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Important Review skippedReview was skipped due to path filters β Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including You can disable this status message by setting the π WalkthroughWalkthroughThis PR introduces comprehensive support for xAI's Grok models by adding a new Changes
Sequence DiagramssequenceDiagram
actor User
participant App as Chat Application
participant TextAdapter as GrokTextAdapter
participant Client as OpenAI SDK Client
participant GrokAPI as xAI Grok API
User->>App: Send chat message
App->>TextAdapter: chatStream(options)
TextAdapter->>TextAdapter: mapTextOptionsToGrok()
TextAdapter->>TextAdapter: convertMessageToGrok()
TextAdapter->>Client: createChatCompletion(stream: true)
Client->>GrokAPI: POST /chat/completions
rect rgb(200, 220, 240)
Note over GrokAPI,TextAdapter: Streaming Response Loop
GrokAPI-->>Client: stream chunk (content/tool_call/done)
Client-->>TextAdapter: raw chunk
TextAdapter->>TextAdapter: processGrokStreamChunks()
TextAdapter-->>App: emit StreamChunk (content/tool_call)
end
App-->>User: Display streamed response
sequenceDiagram
actor User
participant App as Image Generation App
participant ImageAdapter as GrokImageAdapter
participant Validator as Validation Layer
participant Client as OpenAI SDK Client
participant GrokAPI as xAI Grok API
User->>App: Request image generation
App->>ImageAdapter: generateImages(options)
rect rgb(240, 220, 200)
Note over Validator,ImageAdapter: Input Validation
ImageAdapter->>Validator: validatePrompt()
ImageAdapter->>Validator: validateImageSize()
ImageAdapter->>Validator: validateNumberOfImages()
Validator-->>ImageAdapter: β Valid
end
ImageAdapter->>ImageAdapter: buildRequest()
ImageAdapter->>Client: images.generate()
Client->>GrokAPI: POST /images/generations
GrokAPI-->>Client: image URLs + usage tokens
Client-->>ImageAdapter: response
ImageAdapter->>ImageAdapter: transformResponse()
ImageAdapter-->>App: GeneratedImage[] + usage
App-->>User: Display generated images
Estimated code review effortπ― 4 (Complex) | β±οΈ ~65 minutes This PR introduces a substantial new package with interconnected adapters, dense type system logic for model metadata and conditional type resolution, complex schema transformation utilities, and integration across multiple example applications. The effort is elevated by the density of new type definitions, streaming logic in the text adapter, recursive schema conversion, and the need to verify consistency across the adapter hierarchy and factory function patterns. Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touchesβ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
View your CI Pipeline Execution β for commit 12fa430
βοΈ Nx Cloud last updated this comment at |
@tanstack/ai
@tanstack/ai-anthropic
@tanstack/ai-client
@tanstack/ai-devtools-core
@tanstack/ai-gemini
@tanstack/ai-grok
@tanstack/ai-ollama
@tanstack/ai-openai
@tanstack/ai-preact
@tanstack/ai-react
@tanstack/ai-react-ui
@tanstack/ai-solid
@tanstack/ai-solid-ui
@tanstack/ai-svelte
@tanstack/ai-vue
@tanstack/ai-vue-ui
@tanstack/react-ai-devtools
@tanstack/solid-ai-devtools
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
π€ Fix all issues with AI agents
In @packages/typescript/ai-grok/package.json:
- Around line 49-51: The peer dependency for "@tanstack/ai" in package.json uses
the incorrect specifier "workspace:^"; update the version specifier to
"workspace:*" so it follows monorepo convention. Locate the "peerDependencies"
block in packages/typescript/ai-grok/package.json and replace the
"@tanstack/ai": "workspace:^" entry with "@tanstack/ai": "workspace:*".
- Around line 45-48: The package.json is missing vitest in devDependencies even
though the "test:lib" script runs "vitest run"; add "vitest": "^4.0.14" to the
"devDependencies" object in packages/typescript/ai-grok/package.json so the test
tool is installed consistently with other adapter packages (match the version
used by ai-vue, ai, ai-solid, ai-gemini, ai-anthropic, ai-client).
In @packages/typescript/ai-grok/README.md:
- Around line 27-42: The example uses the old pattern of passing model to
generate(); update it so the model is passed into the adapter factory (grokText)
instead and remove the model field from generate() call: call grokText('grok-3')
(or equivalent factory signature) to create the adapter and then call generate({
adapter, messages }) without a separate model parameter, ensuring the adapter
instance carries the model info.
- Around line 62-79: The example uses the old pattern of passing model to
generateImages; update it to pass the model into the adapter factory instead:
call grokImage with the model option (e.g., grokImage({ model:
'grok-2-image-1212' })) and remove the model property from the generateImages()
call so generateImages is invoked with adapter, prompt, numberOfImages, size,
etc.; update the README example to reflect grokImage(...) and generateImages({
adapter, prompt, numberOfImages, size }).
- Around line 44-60: The README example uses the old pattern of passing model to
summarize(); update it to the new adapter architecture by creating the adapter
with the model (call grokSummarize with the model name, e.g.
grokSummarize('grok-3')) and then call summarize() without the model option,
keeping text and style as before; locate grokSummarize and summarize in the
snippet and move the model argument into the grokSummarize(...) adapter factory
call and remove the model property from the summarize(...) invocation.
- Around line 81-87: The README example for createGrokText is missing the
required model positional parameter; update the example call to pass the model
name as the first argument and the API key as the second argument (e.g., call
createGrokText with a model identifier like "grok-1" followed by the API key) so
the function signature (createGrokText(model, apiKey)) is satisfied.
In @packages/typescript/ai-grok/src/adapters/text.ts:
- Around line 397-406: The image branch only treats part.source.value as a URL;
update the block that builds the Grok image part (the code that pushes { type:
'image_url', image_url: { url: ..., detail: ... } }) to handle both
ContentPartSource types by checking part.source.type: if 'url' use
part.source.value directly, if 'data' convert the base64 payload into a data URI
(e.g., "data:<mime>;base64,<value>") before assigning to image_url.url; derive
the MIME from part.metadata or part.source (fall back to "image/jpeg") and
preserve the existing GrokImageMetadata.detail logic when creating the final
parts entry.
π§Ή Nitpick comments (13)
docs/adapters/grok.md (1)
1-232: Documentation looks comprehensive and well-structured.The documentation covers all essential aspects including installation, usage patterns, configuration, API reference, and limitations. The implementation notes section explaining the Chat Completions vs Responses API choice is particularly helpful.
Minor grammar note: On line 163, consider hyphenating "tool-calling" for consistency with standard technical writing conventions (per static analysis hint).
packages/typescript/ai-grok/src/tools/function-tool.ts (1)
19-44: Implementation looks correct for Grok strict mode compatibility.The conversion logic properly handles schema transformations for Grok's strict mode requirements. The default empty schema fallback is a good defensive pattern.
Minor note:
additionalProperties = falseon line 34 is redundant sincemakeGrokStructuredOutputCompatiblealready sets this property (line 98 in schema-converter.ts). Consider removing for clarity, though it doesn't cause harm.packages/typescript/ai-grok/src/utils/client.ts (1)
40-45: Consider usingslice(2)for more consistent random suffix length.
substring(7)onMath.random().toString(36)can occasionally produce short strings. Usingslice(2)would skip the "0." prefix and give a more consistent length.π Proposed fix
export function generateId(prefix: string): string { - return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}` + return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}` }testing/panel/src/lib/model-selection.ts (1)
1-1: Consider extracting the Provider type to eliminate duplication.The
Providertype is duplicated inexamples/ts-react-chat/src/lib/model-selection.ts(line 1). Consider extracting this to a shared location to maintain a single source of truth and prevent the types from diverging during future updates.testing/panel/src/routes/api.chat.ts (1)
55-55: Consider extracting the Provider type to eliminate duplication.The
Providertype is defined in multiple locations (testing/panel/src/lib/model-selection.tsandexamples/ts-react-chat/src/lib/model-selection.ts). Extracting this to a shared type definition would ensure consistency across the codebase and reduce maintenance burden.packages/typescript/ai-grok/src/message-types.ts (1)
43-55: Consider using type aliases for empty metadata types.Biome flags these empty interfaces. Since they currently have no properties and TypeScript interfaces with no members are equivalent to
{}, consider converting to type aliases. However, if you anticipate extending these via declaration merging in the future, keeping them as interfaces is reasonable.π Proposed fix using type aliases
-/** - * Metadata for Grok video content parts. - * Note: Video support in Grok is limited; check current API capabilities. - */ -export interface GrokVideoMetadata {} +/** + * Metadata for Grok video content parts. + * Note: Video support in Grok is limited; check current API capabilities. + */ +export type GrokVideoMetadata = Record<string, never> -/** - * Metadata for Grok document content parts. - * Note: Direct document support may vary; PDFs often need to be converted to images. - */ -export interface GrokDocumentMetadata {} +/** + * Metadata for Grok document content parts. + * Note: Direct document support may vary; PDFs often need to be converted to images. + */ +export type GrokDocumentMetadata = Record<string, never> -/** - * Metadata for Grok text content parts. - * Currently no specific metadata options for text in Grok. - */ -export interface GrokTextMetadata {} +/** + * Metadata for Grok text content parts. + * Currently no specific metadata options for text in Grok. + */ +export type GrokTextMetadata = Record<string, never>packages/typescript/ai-grok/src/image/image-provider-options.ts (1)
94-106: Consider removing or documenting the unused_modelparameter.The
_modelparameter is unused. If it's reserved for future model-specific validation, consider adding a brief comment. Otherwise, it could be removed.π Option: Add documentation comment
/** * Validates that the number of images is within bounds for the model. + * @param _model - Reserved for future model-specific validation */ export function validateNumberOfImages( _model: string,packages/typescript/ai-grok/src/model-meta.ts (1)
216-226: Consider maintaining model order consistency.The array includes
GROK_3.namebeforeGROK_3_MINI.name(lines 223-224), but the constants are defined in reverse order (GROK_3_MINI at line 140, GROK_3 at line 159). While functionally correct, aligning the array order with the constant definitions or sorting by capability/release date would improve maintainability.packages/typescript/ai-grok/src/adapters/text.ts (5)
80-87: Replace console.error with structured logging or remove verbose error output.The error handling logs the full error details including stack traces to
console.error. In production, this could expose sensitive information and creates noise. Consider using a structured logger or removing the verbose logging since the error is re-thrown anyway.π Proposed fix
} catch (error: unknown) { - const err = error as Error - console.error('>>> chatStream: Fatal error during response creation <<<') - console.error('>>> Error message:', err.message) - console.error('>>> Error stack:', err.stack) - console.error('>>> Full error:', err) throw error }
129-139: Consider handling empty response content gracefully.If
response.choices[0]?.message.contentisnullor empty,rawTextbecomes an empty string, which will fail JSON parsing with a less informative error. Consider adding explicit validation.π Proposed fix
// Extract text content from the response const rawText = response.choices[0]?.message.content || '' + if (!rawText) { + throw new Error('Structured output response contained no content') + } + // Parse the JSON response let parsed: unknown try { parsed = JSON.parse(rawText) } catch {
149-154: Inconsistent error logging verbosity.The
structuredOutputmethod logs less detail thanchatStream(only message, not stack/full error). Consider making error handling consistent across methods, preferably by removing the console.error calls entirely as suggested earlier.
267-272: Minor: finishReason logic could be simplified.The condition
toolCallsInProgress.size > 0is checked twice (lines 234 and 269). Consider extracting to a variable for clarity.π Proposed fix
// Handle finish reason if (choice.finish_reason) { + const hasToolCalls = choice.finish_reason === 'tool_calls' || toolCallsInProgress.size > 0 + // Emit all completed tool calls - if ( - choice.finish_reason === 'tool_calls' || - toolCallsInProgress.size > 0 - ) { + if (hasToolCalls) { for (const [index, toolCall] of toolCallsInProgress) { // ... existing code ... } } yield { type: 'done', // ... - finishReason: - choice.finish_reason === 'tool_calls' || - toolCallsInProgress.size > 0 - ? 'tool_calls' - : 'stop', + finishReason: hasToolCalls ? 'tool_calls' : 'stop', } }
275-288: Stream error handling uses console.log instead of console.error.Line 277 uses
console.logfor error output while the catch blocks inchatStreamandstructuredOutputuseconsole.error. For consistency and proper log levels, errors should useconsole.erroror be removed entirely.π Proposed fix
} catch (error: unknown) { const err = error as Error & { code?: string } - console.log('[Grok Adapter] Stream ended with error:', err.message) yield { type: 'error',
π Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
β Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
π Files selected for processing (31)
.changeset/add-grok-adapter.mddocs/adapters/grok.mddocs/guides/migration.mdexamples/ts-react-chat/package.jsonexamples/ts-react-chat/src/lib/model-selection.tsexamples/ts-react-chat/src/routes/api.tanchat.tspackages/typescript/ai-grok/CHANGELOG.mdpackages/typescript/ai-grok/README.mdpackages/typescript/ai-grok/package.jsonpackages/typescript/ai-grok/src/adapters/image.tspackages/typescript/ai-grok/src/adapters/summarize.tspackages/typescript/ai-grok/src/adapters/text.tspackages/typescript/ai-grok/src/image/image-provider-options.tspackages/typescript/ai-grok/src/index.tspackages/typescript/ai-grok/src/message-types.tspackages/typescript/ai-grok/src/model-meta.tspackages/typescript/ai-grok/src/text/text-provider-options.tspackages/typescript/ai-grok/src/tools/function-tool.tspackages/typescript/ai-grok/src/tools/index.tspackages/typescript/ai-grok/src/tools/tool-converter.tspackages/typescript/ai-grok/src/utils/client.tspackages/typescript/ai-grok/src/utils/index.tspackages/typescript/ai-grok/src/utils/schema-converter.tspackages/typescript/ai-grok/tests/grok-adapter.test.tspackages/typescript/ai-grok/tsconfig.jsonpackages/typescript/ai-grok/vite.config.tspackages/typescript/smoke-tests/adapters/package.jsonpackages/typescript/smoke-tests/adapters/src/adapters/index.tstesting/panel/package.jsontesting/panel/src/lib/model-selection.tstesting/panel/src/routes/api.chat.ts
π§° Additional context used
π Path-based instructions (7)
**/*.{ts,tsx}
π CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use tree-shakeable adapter architecture for provider implementations - export specialized adapters (text, embedding, summarize, image) as separate imports from/adapterssubpath rather than monolithic adapters
Use Zod for runtime schema validation and type inference, particularly for tool input/output definitions withtoolDefinition()and Zod schema inference
Implement isomorphic tool system usingtoolDefinition()with.server()and.client()implementations for dual-environment execution
Use type-safe per-model configuration with provider options typed based on selected model to ensure compile-time safety
Implement stream processing with StreamProcessor for handling chunked responses and support partial JSON parsing for streaming AI responses
Files:
packages/typescript/ai-grok/src/tools/index.tstesting/panel/src/routes/api.chat.tspackages/typescript/ai-grok/src/text/text-provider-options.tspackages/typescript/ai-grok/src/utils/client.tspackages/typescript/ai-grok/src/utils/schema-converter.tsexamples/ts-react-chat/src/lib/model-selection.tsexamples/ts-react-chat/src/routes/api.tanchat.tspackages/typescript/ai-grok/tests/grok-adapter.test.tspackages/typescript/ai-grok/src/message-types.tspackages/typescript/ai-grok/src/tools/function-tool.tspackages/typescript/ai-grok/src/utils/index.tspackages/typescript/ai-grok/src/tools/tool-converter.tspackages/typescript/ai-grok/src/adapters/image.tspackages/typescript/ai-grok/src/adapters/summarize.tspackages/typescript/ai-grok/vite.config.tspackages/typescript/smoke-tests/adapters/src/adapters/index.tspackages/typescript/ai-grok/src/model-meta.tspackages/typescript/ai-grok/src/index.tstesting/panel/src/lib/model-selection.tspackages/typescript/ai-grok/src/adapters/text.tspackages/typescript/ai-grok/src/image/image-provider-options.ts
**/*.{ts,tsx,js,jsx}
π CodeRabbit inference engine (CLAUDE.md)
Use camelCase for function and variable names throughout the codebase
Files:
packages/typescript/ai-grok/src/tools/index.tstesting/panel/src/routes/api.chat.tspackages/typescript/ai-grok/src/text/text-provider-options.tspackages/typescript/ai-grok/src/utils/client.tspackages/typescript/ai-grok/src/utils/schema-converter.tsexamples/ts-react-chat/src/lib/model-selection.tsexamples/ts-react-chat/src/routes/api.tanchat.tspackages/typescript/ai-grok/tests/grok-adapter.test.tspackages/typescript/ai-grok/src/message-types.tspackages/typescript/ai-grok/src/tools/function-tool.tspackages/typescript/ai-grok/src/utils/index.tspackages/typescript/ai-grok/src/tools/tool-converter.tspackages/typescript/ai-grok/src/adapters/image.tspackages/typescript/ai-grok/src/adapters/summarize.tspackages/typescript/ai-grok/vite.config.tspackages/typescript/smoke-tests/adapters/src/adapters/index.tspackages/typescript/ai-grok/src/model-meta.tspackages/typescript/ai-grok/src/index.tstesting/panel/src/lib/model-selection.tspackages/typescript/ai-grok/src/adapters/text.tspackages/typescript/ai-grok/src/image/image-provider-options.ts
examples/**
π CodeRabbit inference engine (CLAUDE.md)
Examples are not built by Nx and should be run independently from their directories with
pnpm devorpnpm install && pnpm dev
Files:
examples/ts-react-chat/package.jsonexamples/ts-react-chat/src/lib/model-selection.tsexamples/ts-react-chat/src/routes/api.tanchat.ts
**/*.test.ts
π CodeRabbit inference engine (CLAUDE.md)
Write unit tests using Vitest alongside source files with
.test.tsnaming convention
Files:
packages/typescript/ai-grok/tests/grok-adapter.test.ts
packages/typescript/*/src/adapters/*.ts
π CodeRabbit inference engine (CLAUDE.md)
Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shaking
Files:
packages/typescript/ai-grok/src/adapters/image.tspackages/typescript/ai-grok/src/adapters/summarize.tspackages/typescript/ai-grok/src/adapters/text.ts
packages/typescript/*/src/model-meta.ts
π CodeRabbit inference engine (CLAUDE.md)
Maintain model metadata files that define provider options and capabilities per model for per-model type safety
Files:
packages/typescript/ai-grok/src/model-meta.ts
packages/typescript/*/src/index.ts
π CodeRabbit inference engine (CLAUDE.md)
Export tree-shakeable adapters with clear subpath exports in package.json (e.g.,
@tanstack/ai/adapters,@tanstack/ai-openai/adapters) to minimize bundle size
Files:
packages/typescript/ai-grok/src/index.ts
π§ Learnings (17)
π Common learnings
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Implement framework integrations using the headless `tanstack/ai-client` for state management with framework-specific hooks (useChat) on top
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/index.ts : Export tree-shakeable adapters with clear subpath exports in package.json (e.g., `tanstack/ai/adapters`, `tanstack/ai-openai/adapters`) to minimize bundle size
Applied to files:
.changeset/add-grok-adapter.mdpackages/typescript/ai-grok/src/tools/index.tstesting/panel/src/routes/api.chat.tsexamples/ts-react-chat/package.jsonexamples/ts-react-chat/src/routes/api.tanchat.tspackages/typescript/ai-grok/tests/grok-adapter.test.tspackages/typescript/ai-grok/README.mdpackages/typescript/ai-grok/src/tools/function-tool.tspackages/typescript/ai-grok/src/utils/index.tspackages/typescript/smoke-tests/adapters/package.jsonpackages/typescript/ai-grok/CHANGELOG.mdpackages/typescript/ai-grok/package.jsonpackages/typescript/ai-grok/src/adapters/image.tspackages/typescript/ai-grok/tsconfig.jsonpackages/typescript/ai-grok/vite.config.tspackages/typescript/smoke-tests/adapters/src/adapters/index.tspackages/typescript/ai-grok/src/index.tspackages/typescript/ai-grok/src/adapters/text.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/adapters/*.ts : Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shaking
Applied to files:
.changeset/add-grok-adapter.mdpackages/typescript/ai-grok/src/tools/index.tsdocs/adapters/grok.mdtesting/panel/src/routes/api.chat.tspackages/typescript/ai-grok/src/text/text-provider-options.tsexamples/ts-react-chat/src/lib/model-selection.tsexamples/ts-react-chat/src/routes/api.tanchat.tspackages/typescript/ai-grok/tests/grok-adapter.test.tspackages/typescript/ai-grok/README.mdpackages/typescript/ai-grok/src/tools/function-tool.tspackages/typescript/ai-grok/src/utils/index.tspackages/typescript/smoke-tests/adapters/package.jsonpackages/typescript/ai-grok/src/tools/tool-converter.tspackages/typescript/ai-grok/package.jsonpackages/typescript/ai-grok/src/adapters/image.tspackages/typescript/ai-grok/tsconfig.jsonpackages/typescript/ai-grok/src/adapters/summarize.tspackages/typescript/smoke-tests/adapters/src/adapters/index.tspackages/typescript/ai-grok/src/index.tstesting/panel/src/lib/model-selection.tspackages/typescript/ai-grok/src/adapters/text.tspackages/typescript/ai-grok/src/image/image-provider-options.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use tree-shakeable adapter architecture for provider implementations - export specialized adapters (text, embedding, summarize, image) as separate imports from `/adapters` subpath rather than monolithic adapters
Applied to files:
packages/typescript/ai-grok/src/tools/index.tstesting/panel/src/routes/api.chat.tsexamples/ts-react-chat/src/routes/api.tanchat.tspackages/typescript/ai-grok/tests/grok-adapter.test.tspackages/typescript/ai-grok/README.mdpackages/typescript/ai-grok/package.jsonpackages/typescript/ai-grok/src/adapters/image.tspackages/typescript/ai-grok/src/adapters/summarize.tspackages/typescript/smoke-tests/adapters/src/adapters/index.tspackages/typescript/ai-grok/src/index.tspackages/typescript/ai-grok/src/adapters/text.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Implement isomorphic tool system using `toolDefinition()` with `.server()` and `.client()` implementations for dual-environment execution
Applied to files:
packages/typescript/ai-grok/src/tools/index.tspackages/typescript/ai-grok/src/tools/function-tool.tspackages/typescript/ai-grok/src/tools/tool-converter.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/model-meta.ts : Maintain model metadata files that define provider options and capabilities per model for per-model type safety
Applied to files:
testing/panel/src/routes/api.chat.tspackages/typescript/ai-grok/src/text/text-provider-options.tsexamples/ts-react-chat/src/lib/model-selection.tspackages/typescript/ai-grok/src/message-types.tspackages/typescript/ai-grok/package.jsonpackages/typescript/ai-grok/src/adapters/image.tspackages/typescript/ai-grok/tsconfig.jsonpackages/typescript/ai-grok/src/model-meta.tspackages/typescript/ai-grok/src/index.tstesting/panel/src/lib/model-selection.tspackages/typescript/ai-grok/src/adapters/text.tspackages/typescript/ai-grok/src/image/image-provider-options.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Implement stream processing with StreamProcessor for handling chunked responses and support partial JSON parsing for streaming AI responses
Applied to files:
testing/panel/src/routes/api.chat.tspackages/typescript/ai-grok/src/adapters/text.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use type-safe per-model configuration with provider options typed based on selected model to ensure compile-time safety
Applied to files:
packages/typescript/ai-grok/src/text/text-provider-options.tsexamples/ts-react-chat/src/lib/model-selection.tspackages/typescript/ai-grok/src/model-meta.tstesting/panel/src/lib/model-selection.tspackages/typescript/ai-grok/src/image/image-provider-options.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/*/package.json : Use `workspace:*` protocol for internal package dependencies in package.json (e.g., `"tanstack/ai": "workspace:*"`)
Applied to files:
examples/ts-react-chat/package.jsonpackages/typescript/smoke-tests/adapters/package.jsonpackages/typescript/ai-grok/package.jsontesting/panel/package.json
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use Zod for runtime schema validation and type inference, particularly for tool input/output definitions with `toolDefinition()` and Zod schema inference
Applied to files:
packages/typescript/ai-grok/src/utils/schema-converter.tspackages/typescript/ai-grok/src/tools/function-tool.tspackages/typescript/ai-grok/tsconfig.json
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.test.ts : Write unit tests using Vitest alongside source files with `.test.ts` naming convention
Applied to files:
packages/typescript/ai-grok/tests/grok-adapter.test.tspackages/typescript/ai-grok/tsconfig.jsonpackages/typescript/ai-grok/vite.config.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Maintain type safety through multimodal content support (image, audio, video, document) with model capability awareness
Applied to files:
packages/typescript/ai-grok/src/message-types.ts
π Learning: 2025-12-27T20:22:51.232Z
Learnt from: harry-whorlow
Repo: TanStack/ai PR: 117
File: packages/typescript/ai-ollama/src/meta/model-meta-gpt-oss.ts:92-97
Timestamp: 2025-12-27T20:22:51.232Z
Learning: In the ai-ollama package's model-meta files (packages/typescript/ai-ollama/src/meta/model-meta-*.ts), capability-related comments follow a standard template format across all files for consistency, even if the comment text doesn't precisely match individual model capabilities. This is an intentional design choice to maintain uniformity across the codebase.
Applied to files:
packages/typescript/ai-grok/README.mdpackages/typescript/ai-grok/src/model-meta.tstesting/panel/src/lib/model-selection.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Implement framework integrations using the headless `tanstack/ai-client` for state management with framework-specific hooks (useChat) on top
Applied to files:
packages/typescript/ai-grok/README.md
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to .eslintrc* : Use ESLint with custom TanStack config for linting all TypeScript and JavaScript files
Applied to files:
packages/typescript/ai-grok/package.jsonpackages/typescript/ai-grok/tsconfig.jsonpackages/typescript/ai-grok/vite.config.ts
π Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Use Nx workspace with affected commands to optimize testing and building only changed packages and their dependents
Applied to files:
testing/panel/package.json
π Learning: 2025-12-27T21:39:29.563Z
Learnt from: harry-whorlow
Repo: TanStack/ai PR: 117
File: packages/typescript/ai-ollama/src/meta/model-meta-llama-guard3.ts:70-75
Timestamp: 2025-12-27T21:39:29.563Z
Learning: The standard template comments in ai-ollama model-meta files (like "Models with text, image, audio, video (no document)") should not be modified to match individual model capabilities, as they are intentionally kept uniform across all model-meta-*.ts files for consistency, regardless of what each specific model actually supports.
Applied to files:
packages/typescript/ai-grok/src/model-meta.ts
𧬠Code graph analysis (4)
examples/ts-react-chat/src/lib/model-selection.ts (1)
testing/panel/src/lib/model-selection.ts (1)
Provider(1-1)
packages/typescript/ai-grok/tests/grok-adapter.test.ts (4)
packages/typescript/ai-grok/src/adapters/text.ts (2)
createGrokText(466-474)grokText(500-506)packages/typescript/ai-grok/src/index.ts (6)
createGrokText(8-8)grokText(9-9)createGrokImage(27-27)grokImage(28-28)createGrokSummarize(17-17)grokSummarize(18-18)packages/typescript/ai-grok/src/adapters/image.ts (2)
createGrokImage(138-144)grokImage(170-176)packages/typescript/ai-grok/src/adapters/summarize.ts (2)
createGrokSummarize(136-142)grokSummarize(168-174)
testing/panel/src/lib/model-selection.ts (1)
examples/ts-react-chat/src/lib/model-selection.ts (1)
Provider(1-1)
packages/typescript/ai-grok/src/image/image-provider-options.ts (1)
packages/typescript/ai-grok/src/index.ts (2)
GrokImageProviderOptions(33-33)GrokImageModelProviderOptionsByName(34-34)
πͺ Biome (2.1.2)
packages/typescript/ai-grok/src/message-types.ts
[error] 43-43: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
[error] 49-49: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
[error] 55-55: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
πͺ LanguageTool
docs/adapters/grok.md
[grammar] ~163-~163: Use a hyphen to join words.
Context: ...hich is essential for TanStack AI's tool calling functionality. The Responses API...
(QB_NEW_EN_HYPHEN)
π Additional comments (59)
docs/guides/migration.md (1)
438-438: LGTM!Adding a trailing blank line is a standard formatting convention.
packages/typescript/smoke-tests/adapters/package.json (1)
17-17: LGTM!The dependency addition follows the correct
workspace:*protocol and maintains alphabetical ordering.packages/typescript/ai-grok/tsconfig.json (1)
1-9: LGTM!The TypeScript configuration follows the standard pattern for TanStack packages and correctly extends the root configuration.
packages/typescript/ai-grok/CHANGELOG.md (1)
1-7: The changelog correctly documents version 0.0.3 as shown in package.json. While 0.0.3 is unconventional for a typical initial release, it's the intentional version for this package and is consistent across all configuration files.packages/typescript/ai-grok/vite.config.ts (1)
1-36: LGTM!The Vite/Vitest configuration follows TanStack conventions with appropriate test setup, coverage configuration, and ESM-only build output.
packages/typescript/ai-grok/src/utils/schema-converter.ts (1)
12-35:transformNullsToUndefinedimplementation looks correct.The recursive null-to-undefined transformation with key omission handles the Grok structured output response normalization appropriately.
packages/typescript/ai-grok/src/utils/client.ts (2)
11-16: LGTM!The client creation correctly uses the OpenAI SDK with xAI's base URL, providing a clean abstraction for Grok API access.
22-38: Environment detection looks correct for isomorphic usage.The implementation properly handles both browser (
globalThis.window.env) and Node.js (process.env) environments, with a clear error message when the key is missing.packages/typescript/ai-grok/src/text/text-provider-options.ts (2)
13-52: Well-documented provider options types.The interfaces are cleanly structured with appropriate JSDoc documentation explaining each option's purpose and valid ranges.
72-77: Placeholder validation is acceptable for initial implementation.The no-op validation function is fine for now since Grok API will handle validation. Consider adding client-side validation for common errors (e.g., temperature range) in a follow-up to provide faster feedback.
testing/panel/package.json (1)
16-16: LGTM!The Grok package dependency follows the
workspace:*protocol consistently with other internal packages. Based on learnings, this is the correct approach for internal package dependencies.packages/typescript/ai-grok/src/tools/index.ts (1)
1-5: LGTM!The barrel export pattern enables tree-shaking by re-exporting individual utilities. This aligns with the tree-shakeable adapter architecture as per coding guidelines.
examples/ts-react-chat/package.json (1)
17-17: LGTM!The Grok package dependency correctly uses the
workspace:*protocol, consistent with other internal dependencies. Based on learnings, this is the correct approach.examples/ts-react-chat/src/lib/model-selection.ts (2)
1-1: LGTM!The Provider union type extension follows the established pattern and correctly includes 'grok' as a new provider option.
70-86: No changes required β Grok model identifiers are correct.All three model names (
grok-3,grok-3-mini,grok-2-vision-1212) match xAI's official API documentation as of 2025..changeset/add-grok-adapter.md (1)
5-5: Update changeset description and implementation to reflect actual available Grok models as of the PR date.The changeset claims "Grok 4.1, Grok 4, Grok 3" support, but as of January 2025, xAI's official API only provides Grok 2 family models. Grok 3 had not been released and missed its end-of-2024 deadline. The implementation references
grok-3andgrok-3-minimodel IDs that do not exist in the actual xAI API, which will cause failures when users attempt to use them. Either remove references to unreleased models or ensure the changeset and implementation match what is actually available in xAI's current API.β Skipped due to learnings
Learnt from: CR Repo: TanStack/ai PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T17:09:09.794Z Learning: Implement framework integrations using the headless `tanstack/ai-client` for state management with framework-specific hooks (useChat) on topLearnt from: CR Repo: TanStack/ai PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T17:09:09.794Z Learning: Applies to packages/typescript/*/src/adapters/*.ts : Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shakingpackages/typescript/ai-grok/src/tools/tool-converter.ts (1)
1-17: LGTM!The tool conversion logic is clean and straightforward. The function correctly maps standard Tools to Grok's OpenAI-compatible function tool format using the delegated converter.
packages/typescript/ai-grok/tests/grok-adapter.test.ts (1)
1-99: LGTM!The test coverage appropriately validates adapter creation for all three Grok adapter types. Each test suite confirms:
- Explicit API key configuration works correctly
- Environment variable-based API key resolution functions as expected
- Proper error handling when API keys are missing
- Adapter properties (kind, name, model) are set correctly
The cleanup via
afterEachensures test isolation.testing/panel/src/lib/model-selection.ts (1)
71-86: LGTM!The Grok model options follow the existing pattern and provide a reasonable selection of Grok models (standard, mini, and vision variants).
testing/panel/src/routes/api.chat.ts (1)
176-179: LGTM!The Grok adapter configuration follows the established pattern used by other providers (Anthropic, Gemini, Ollama, OpenAI) and correctly uses
createChatOptionswith thegrokTextadapter.packages/typescript/ai-grok/src/utils/index.ts (1)
1-10: LGTM!The utility exports are well-organized and follow the tree-shakeable architecture. Grouping client utilities and schema converters separately makes the module structure clear and maintainable.
packages/typescript/smoke-tests/adapters/src/adapters/index.ts (4)
8-8: LGTM!The import follows the established tree-shakeable pattern, importing individual adapters (
grokImage,grokSummarize,grokText) rather than a monolithic adapter. This aligns with the coding guidelines.
81-84: LGTM!The Grok model constants follow the same pattern as other providers with environment variable overrides and sensible defaults.
168-186: LGTM!The
createGrokAdaptersfunction follows the established factory pattern used by other providers, correctly checking for theXAI_API_KEYand returningnullwhen unavailable.
217-222: LGTM!The Grok adapter registration is consistent with other providers in the registry.
examples/ts-react-chat/src/routes/api.tanchat.ts (3)
12-12: LGTM!The import follows the tree-shakeable pattern for the Grok text adapter.
22-22: LGTM!The
Providertype correctly extended to include'grok'.
94-97: LGTM!The Grok adapter configuration follows the established pattern. The simpler config (without additional
modelOptionsortemperature) is appropriate for the "thin shim approach" mentioned in the PR commits.packages/typescript/ai-grok/src/message-types.ts (3)
14-24: LGTM!The
GrokImageMetadatainterface properly defines thedetailoption for image processing control, consistent with the OpenAI-compatible API approach.
30-37: LGTM!The
GrokAudioMetadatainterface correctly defines supported audio formats.
61-67: LGTM!The composite
GrokMessageMetadataByModalityinterface properly maps modality types to their metadata types for type inference.packages/typescript/ai-grok/src/adapters/image.ts (5)
41-57: LGTM!The
GrokImageAdapterclass properly extendsBaseImageAdapterwith correct type parameters. The constructor correctly initializes the OpenAI-compatible client.
59-78: LGTM!The
generateImagesmethod follows a good pattern: validate inputs first, then build and execute the request. The validation calls ensure early failure with descriptive errors.
80-92: LGTM!The
buildRequestmethod correctly constructs the API payload, spreadingmodelOptionslast to allow user overrides of default values.
94-116: LGTM!The
transformResponsemethod properly handles the response transformation, including optional usage data with null-safe access.
138-176: LGTM!Both factory functions follow the established pattern:
createGrokImagefor explicit API key andgrokImagefor environment-based key detection. The JSDoc examples are helpful.packages/typescript/ai-grok/src/adapters/summarize.ts (5)
36-47: LGTM!The thin wrapper approach delegating to
GrokTextAdapteris a clean design that maximizes code reuse.
78-91: LGTM!The
summarizeStreammethod correctly delegates to the text adapter's streaming interface.
93-119: LGTM!The
buildSummarizationPromptmethod properly handles all summarization style options and builds a well-structured system prompt.
136-174: LGTM!Both factory functions follow the established pattern for explicit and environment-based API key handling.
49-76: The code is correct as written βchunk.contentprovides cumulative text, not deltas.The text adapter accumulates content deltas internally (line 188 in
processGrokStreamChunks:accumulatedContent += deltaContent) and yields chunks with the full accumulated text in thecontentfield (line 195). Thedeltafield is also available for reference if needed. Assigningsummary = chunk.contenton each iteration is the correct approach.packages/typescript/ai-grok/src/index.ts (1)
1-55: LGTM!The index barrel properly exports all public API surface with tree-shakeable structure. Types are correctly exported with the
typekeyword, and runtime constants are exported separately. This follows the coding guidelines for clear subpath exports.packages/typescript/ai-grok/src/image/image-provider-options.ts (3)
11-54: LGTM!The type definitions are well-structured with clear JSDoc documentation. The type maps enable per-model type safety as recommended in the coding guidelines.
68-89: LGTM!The
validateImageSizefunction properly validates sizes against model-specific constraints with descriptive error messages.
108-117: LGTM!The
validatePromptfunction properly validates prompt constraints with clear error messages.packages/typescript/ai-grok/src/model-meta.ts (6)
1-24: LGTM! Well-structured interface for model metadata.The
ModelMetainterface provides comprehensive type safety for model definitions with appropriate optional fields for capabilities that vary across models.
237-247: Type mapping follows the established pattern correctly.The
GrokModelInputModalitiesByNametype properly maps each model name to its input modalities using computed property types, enabling type-safe multimodal message construction. Based on learnings, this aligns with the standard template approach for model metadata files.
253-255: Consider extending provider options for models with unique capabilities.Currently all chat models map to the same
GrokProviderOptionstype. If any Grok models support unique parameters (e.g., reasoning-specific options for reasoning models), you may want to differentiate the options per model for stricter type safety. This is a future consideration as xAI's API evolves.
261-276: LGTM! Provider options follow OpenAI-compatible conventions.The
GrokProviderOptionsinterface correctly documents the OpenAI-compatible parameters with appropriate JSDoc comments for developer guidance.
286-298: LGTM! Type resolution helpers are well-designed.The
ResolveProviderOptionsandResolveInputModalitiesconditional types provide proper fallback behavior for unknown models while maintaining type safety for known models. This enables both strict typing for known models and graceful handling of custom/new models.
26-211: Grok model metadata is accurate and verified against current xAI documentation.All model constants, context windows, pricing, and capabilities match the current xAI API specifications as of January 2026. The structured approach with
as const satisfies ModelMetais appropriate for maintainability.packages/typescript/ai-grok/src/adapters/text.ts (8)
1-32: LGTM! Imports are well-organized and tree-shakeable.The imports correctly separate type-only imports (using
import type) from value imports, enabling proper tree-shaking. This follows the coding guidelines for tree-shakeable adapter architecture.
50-66: LGTM! Class structure follows the adapter pattern correctly.The
GrokTextAdapterclass properly extendsBaseTextAdapterwith correct generic type parameters for model-specific type safety. Thekindandnameproperties useas constfor literal typing.
157-289: Stream chunk processing implementation is thorough.The
processGrokStreamChunksmethod correctly handles:
- Content delta accumulation
- Tool call streaming with argument chunking
- Finish reason handling with proper tool_calls detection
- Error recovery with graceful error chunk emission
The use of a Map to track in-progress tool calls by index is appropriate for handling interleaved tool call deltas.
294-342: LGTM! Options mapping is well-implemented.The
mapTextOptionsToGrokmethod correctly:
- Validates provider options
- Converts tools to provider format
- Handles system prompts by joining them
- Maps common options (temperature, max_tokens, top_p) to OpenAI-compatible format
- Enables usage reporting via
stream_options
344-413: LGTM! Message conversion handles all message types correctly.The
convertMessageToGrokmethod properly handles:
- Tool messages with
tool_call_id- Assistant messages with optional
tool_calls- User messages with multimodal content (text and image)
- Content serialization for non-string tool results
The optimization to use simple string format for text-only user messages is a good practice.
415-448: LGTM! Content normalization helpers are clean and correct.Both
normalizeContentandextractTextContentproperly handle all three content variants (null, string, ContentPart array) with appropriate type narrowing.
466-506: LGTM! Factory functions provide good DX with proper type inference.The
createGrokTextandgrokTextfactory functions:
- Preserve generic type parameter for model-specific typing
- Provide clear JSDoc documentation with examples
- Support both explicit API key and environment variable patterns
This follows the tree-shakeable adapter architecture guidelines.
109-112: Potential issue:outputSchema.requiredmay be undefined.The code passes
outputSchema.required || []butmakeGrokStructuredOutputCompatiblereceives it as the second parameter. IfoutputSchemadoesn't have arequiredproperty defined, the fallback to empty array[]will make all properties optional in the transformed schema, which may not match the intended behavior.#!/bin/bash # Check the signature and implementation of makeGrokStructuredOutputCompatible ast-grep --pattern 'function makeGrokStructuredOutputCompatible($_) { $$$ }' # Also search with export rg -n "makeGrokStructuredOutputCompatible" --type ts -A 10
| "devDependencies": { | ||
| "@vitest/coverage-v8": "4.0.14", | ||
| "vite": "^7.2.7" | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
# Read the full package.json for ai-grok to see the test:lib script
cat packages/typescript/ai-grok/package.jsonRepository: TanStack/ai
Length of output: 1187
π Script executed:
# Check if vitest is listed as a devDependency in other packages in typescript folder
fd -t f 'package.json' packages/typescript --exec grep -l '"vitest"' {} \;
# Check root package.json
grep '"vitest"' package.json | head -3Repository: TanStack/ai
Length of output: 328
π Script executed:
# Check the actual structure - is there a monorepo setup with hoisted dependencies?
head -30 package.jsonRepository: TanStack/ai
Length of output: 1366
Add vitest to devDependencies.
The test:lib script runs vitest run, but vitest is not listed in devDependencies. All other adapter packages in the workspace (ai-vue, ai, ai-solid, ai-gemini, ai-anthropic, ai-client) explicitly include vitest (^4.0.14). Add it to maintain consistency and ensure reliable tooling availability during local development.
π€ Prompt for AI Agents
In @packages/typescript/ai-grok/package.json around lines 45 - 48, The
package.json is missing vitest in devDependencies even though the "test:lib"
script runs "vitest run"; add "vitest": "^4.0.14" to the "devDependencies"
object in packages/typescript/ai-grok/package.json so the test tool is installed
consistently with other adapter packages (match the version used by ai-vue, ai,
ai-solid, ai-gemini, ai-anthropic, ai-client).
| "peerDependencies": { | ||
| "@tanstack/ai": "workspace:^", | ||
| "zod": "^4.0.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
#!/bin/bash
# Check peer dependency patterns in all ai-* packages
echo "=== Checking @tanstack/ai peer dependencies across ai-* packages ==="
fd -t f 'package.json' packages/typescript -x grep -H '@tanstack/ai' {} \; | grep -E 'workspace:' | sort
echo -e "\n=== Checking all workspace: patterns across packages/typescript ==="
fd -t f 'package.json' packages/typescript -x grep -H 'workspace:' {} \; | sortRepository: TanStack/ai
Length of output: 166
Change workspace:^ to workspace:* for the @tanstack/ai peer dependency.
Per project convention, internal package dependencies in the monorepo use workspace:* (not workspace:^). Update the peer dependency version specifier to match the pattern used across the monorepo.
π€ Prompt for AI Agents
In @packages/typescript/ai-grok/package.json around lines 49 - 51, The peer
dependency for "@tanstack/ai" in package.json uses the incorrect specifier
"workspace:^"; update the version specifier to "workspace:*" so it follows
monorepo convention. Locate the "peerDependencies" block in
packages/typescript/ai-grok/package.json and replace the "@tanstack/ai":
"workspace:^" entry with "@tanstack/ai": "workspace:*".
| ```typescript | ||
| import { grokText } from '@tanstack/ai-grok' | ||
| import { generate } from '@tanstack/ai' | ||
|
|
||
| const adapter = grokText() | ||
|
|
||
| const result = await generate({ | ||
| adapter, | ||
| model: 'grok-3', | ||
| messages: [ | ||
| { role: 'user', content: 'Explain quantum computing in simple terms' }, | ||
| ], | ||
| }) | ||
|
|
||
| console.log(result.text) | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct the API usage pattern to match the new adapter architecture.
The example shows the old API pattern where the model is passed separately to generate(). According to the migration guide, the model should be passed to the adapter factory function, not as a separate parameter.
π Corrected example
import { grokText } from '@tanstack/ai-grok'
import { generate } from '@tanstack/ai'
-const adapter = grokText()
+const adapter = grokText('grok-3')
const result = await generate({
adapter,
- model: 'grok-3',
messages: [
{ role: 'user', content: 'Explain quantum computing in simple terms' },
],
})Based on the migration guide: "Model is passed to adapter factory - The model name is now passed directly to the adapter function" and "No separate model parameter - The model is stored on the adapter, so you don't need to pass it separately."
π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```typescript | |
| import { grokText } from '@tanstack/ai-grok' | |
| import { generate } from '@tanstack/ai' | |
| const adapter = grokText() | |
| const result = await generate({ | |
| adapter, | |
| model: 'grok-3', | |
| messages: [ | |
| { role: 'user', content: 'Explain quantum computing in simple terms' }, | |
| ], | |
| }) | |
| console.log(result.text) | |
| ``` | |
| import { grokText } from '@tanstack/ai-grok' | |
| import { generate } from '@tanstack/ai' | |
| const adapter = grokText('grok-3') | |
| const result = await generate({ | |
| adapter, | |
| messages: [ | |
| { role: 'user', content: 'Explain quantum computing in simple terms' }, | |
| ], | |
| }) | |
| console.log(result.text) |
π€ Prompt for AI Agents
In @packages/typescript/ai-grok/README.md around lines 27 - 42, The example uses
the old pattern of passing model to generate(); update it so the model is passed
into the adapter factory (grokText) instead and remove the model field from
generate() call: call grokText('grok-3') (or equivalent factory signature) to
create the adapter and then call generate({ adapter, messages }) without a
separate model parameter, ensuring the adapter instance carries the model info.
| ### Summarization Adapter | ||
|
|
||
| ```typescript | ||
| import { grokSummarize } from '@tanstack/ai-grok' | ||
| import { summarize } from '@tanstack/ai' | ||
|
|
||
| const adapter = grokSummarize() | ||
|
|
||
| const result = await summarize({ | ||
| adapter, | ||
| model: 'grok-3', | ||
| text: 'Long article text...', | ||
| style: 'bullet-points', | ||
| }) | ||
|
|
||
| console.log(result.summary) | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct the API usage pattern to match the new adapter architecture.
The example shows the old API pattern where the model is passed separately to summarize(). The model should be passed to the adapter factory function.
π Corrected example
import { grokSummarize } from '@tanstack/ai-grok'
import { summarize } from '@tanstack/ai'
-const adapter = grokSummarize()
+const adapter = grokSummarize('grok-3')
const result = await summarize({
adapter,
- model: 'grok-3',
text: 'Long article text...',
style: 'bullet-points',
})π€ Prompt for AI Agents
In @packages/typescript/ai-grok/README.md around lines 44 - 60, The README
example uses the old pattern of passing model to summarize(); update it to the
new adapter architecture by creating the adapter with the model (call
grokSummarize with the model name, e.g. grokSummarize('grok-3')) and then call
summarize() without the model option, keeping text and style as before; locate
grokSummarize and summarize in the snippet and move the model argument into the
grokSummarize(...) adapter factory call and remove the model property from the
summarize(...) invocation.
| ### Image Generation Adapter | ||
|
|
||
| ```typescript | ||
| import { grokImage } from '@tanstack/ai-grok' | ||
| import { generateImages } from '@tanstack/ai' | ||
|
|
||
| const adapter = grokImage() | ||
|
|
||
| const result = await generateImages({ | ||
| adapter, | ||
| model: 'grok-2-image-1212', | ||
| prompt: 'A beautiful sunset over mountains', | ||
| numberOfImages: 1, | ||
| size: '1024x1024', | ||
| }) | ||
|
|
||
| console.log(result.images[0].url) | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct the API usage pattern to match the new adapter architecture.
The example shows the old API pattern where the model is passed separately to generateImages(). The model should be passed to the adapter factory function.
π Corrected example
import { grokImage } from '@tanstack/ai-grok'
import { generateImages } from '@tanstack/ai'
-const adapter = grokImage()
+const adapter = grokImage('grok-2-image-1212')
const result = await generateImages({
adapter,
- model: 'grok-2-image-1212',
prompt: 'A beautiful sunset over mountains',
numberOfImages: 1,
size: '1024x1024',
})π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ### Image Generation Adapter | |
| ```typescript | |
| import { grokImage } from '@tanstack/ai-grok' | |
| import { generateImages } from '@tanstack/ai' | |
| const adapter = grokImage() | |
| const result = await generateImages({ | |
| adapter, | |
| model: 'grok-2-image-1212', | |
| prompt: 'A beautiful sunset over mountains', | |
| numberOfImages: 1, | |
| size: '1024x1024', | |
| }) | |
| console.log(result.images[0].url) | |
| ``` | |
| import { grokImage } from '@tanstack/ai-grok' | |
| import { generateImages } from '@tanstack/ai' | |
| const adapter = grokImage('grok-2-image-1212') | |
| const result = await generateImages({ | |
| adapter, | |
| prompt: 'A beautiful sunset over mountains', | |
| numberOfImages: 1, | |
| size: '1024x1024', | |
| }) | |
| console.log(result.images[0].url) |
π€ Prompt for AI Agents
In @packages/typescript/ai-grok/README.md around lines 62 - 79, The example uses
the old pattern of passing model to generateImages; update it to pass the model
into the adapter factory instead: call grokImage with the model option (e.g.,
grokImage({ model: 'grok-2-image-1212' })) and remove the model property from
the generateImages() call so generateImages is invoked with adapter, prompt,
numberOfImages, size, etc.; update the README example to reflect grokImage(...)
and generateImages({ adapter, prompt, numberOfImages, size }).
| ### With Explicit API Key | ||
|
|
||
| ```typescript | ||
| import { createGrokText } from '@tanstack/ai-grok' | ||
|
|
||
| const adapter = createGrokText('xai-your-api-key-here') | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
#!/bin/bash
# Search for createGrokText function definition
ast-grep --pattern 'export function createGrokText($$$) {
$$$
}'Repository: TanStack/ai
Length of output: 166
π Script executed:
#!/bin/bash
# Also search for any export of createGrokText with different patterns
rg -A 10 'createGrokText' packages/typescript/ai-grok --type ts --type tsx -B 2Repository: TanStack/ai
Length of output: 82
π Script executed:
#!/bin/bash
# Check the README file to see the full context and other examples
cat -n packages/typescript/ai-grok/README.md | sed -n '70,100p'Repository: TanStack/ai
Length of output: 964
π Script executed:
#!/bin/bash
# Find TypeScript files in ai-grok package
fd -e ts -e js packages/typescript/ai-grok/src --type fRepository: TanStack/ai
Length of output: 484
π Script executed:
#!/bin/bash
# Search for createGrokText in the codebase
rg 'createGrokText' packages/typescript/ai-grok --type ts --type js -B 3 -A 10Repository: TanStack/ai
Length of output: 5897
π Script executed:
#!/bin/bash
# Look for index or main export files
find packages/typescript/ai-grok -name 'index.ts' -o -name 'index.js' -o -name '*.ts' | head -20Repository: TanStack/ai
Length of output: 878
π Script executed:
#!/bin/bash
# Read the createGrokText function implementation
cat -n packages/typescript/ai-grok/src/adapters/text.ts | sed -n '30,80p'Repository: TanStack/ai
Length of output: 1817
π Script executed:
#!/bin/bash
# Find the createGrokText function definition - search further down
cat -n packages/typescript/ai-grok/src/adapters/text.ts | sed -n '100,160p'Repository: TanStack/ai
Length of output: 2474
π Script executed:
#!/bin/bash
# Find the createGrokText export function - search further down in the file
cat -n packages/typescript/ai-grok/src/adapters/text.ts | sed -n '220,280p'Repository: TanStack/ai
Length of output: 2423
π Script executed:
#!/bin/bash
# Find the createGrokText export function - search near the end of the file
wc -l packages/typescript/ai-grok/src/adapters/text.tsRepository: TanStack/ai
Length of output: 107
π Script executed:
#!/bin/bash
# Read the last part of the file where createGrokText should be defined
tail -100 packages/typescript/ai-grok/src/adapters/text.ts | head -80Repository: TanStack/ai
Length of output: 2230
Correct the incomplete API key example by adding the required model parameter.
The example passes only the API key when the function requires both a model and an API key as positional parameters.
π Corrected example
import { createGrokText } from '@tanstack/ai-grok'
-const adapter = createGrokText('xai-your-api-key-here')
+const adapter = createGrokText('grok-3', 'xai-your-api-key-here')π€ Prompt for AI Agents
In @packages/typescript/ai-grok/README.md around lines 81 - 87, The README
example for createGrokText is missing the required model positional parameter;
update the example call to pass the model name as the first argument and the API
key as the second argument (e.g., call createGrokText with a model identifier
like "grok-1" followed by the API key) so the function signature
(createGrokText(model, apiKey)) is satisfied.
| } else if (part.type === 'image') { | ||
| const imageMetadata = part.metadata as GrokImageMetadata | undefined | ||
| parts.push({ | ||
| type: 'image_url', | ||
| image_url: { | ||
| url: part.source.value, | ||
| detail: imageMetadata?.detail || 'auto', | ||
| }, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
#!/bin/bash
# Search for ContentPart type definition
rg -n "type ContentPart\|interface ContentPart" --type ts -A 20Repository: TanStack/ai
Length of output: 37
π Script executed:
#!/bin/bash
# Search for image source type definitions
rg -n "type.*Source\|interface.*Source" --type ts -B 2 -A 10 | head -100Repository: TanStack/ai
Length of output: 37
π Script executed:
#!/bin/bash
# Check the text.ts file to understand context better
cat -n packages/typescript/ai-grok/src/adapters/text.ts | sed -n '390,415p'Repository: TanStack/ai
Length of output: 922
π Script executed:
#!/bin/bash
# Search for GrokImageMetadata and related types
rg -n "GrokImageMetadata\|ImageMetadata" --type ts -B 2 -A 10Repository: TanStack/ai
Length of output: 37
π Script executed:
#!/bin/bash
# Look for imports in text.ts to see where ContentPart comes from
head -50 packages/typescript/ai-grok/src/adapters/text.tsRepository: TanStack/ai
Length of output: 1443
π Script executed:
#!/bin/bash
# Search for ContentPart in the codebase (case-insensitive, broader search)
rg "ContentPart" --type ts | head -20Repository: TanStack/ai
Length of output: 1824
π Script executed:
#!/bin/bash
# Look for source type definitions in the codebase
rg "type.*Source\|source.*:" --type ts -A 3 | head -50Repository: TanStack/ai
Length of output: 37
π Script executed:
#!/bin/bash
# Check if there are other image handling patterns in other adapters
find packages/typescript -name "*.ts" -path "*/adapters/*" -type f | head -10Repository: TanStack/ai
Length of output: 591
π Script executed:
#!/bin/bash
# Find and display ContentPartSource type definition
rg -n "export interface ContentPartSource|export type ContentPartSource" --type ts -A 15 packages/typescript/ai/src/types.tsRepository: TanStack/ai
Length of output: 461
π Script executed:
#!/bin/bash
# Find and display ContentPart type definition for image
rg -n "source: ContentPartSource" --type ts -B 5 -A 2 packages/typescript/ai/src/types.tsRepository: TanStack/ai
Length of output: 1399
π Script executed:
#!/bin/bash
# Get more context around ContentPart type definitions
sed -n '1,500p' packages/typescript/ai/src/types.ts | tail -200Repository: TanStack/ai
Length of output: 6817
π Script executed:
#!/bin/bash
# Check OpenAI adapter's image handling for comparison
find packages/typescript -name "text.ts" -path "*/adapters/*" -exec grep -l "image" {} \;Repository: TanStack/ai
Length of output: 310
π Script executed:
#!/bin/bash
# Look at OpenAI adapter's text handling for images
rg -n "part.type === 'image'" --type ts -B 3 -A 10 packages/typescript/ai-openai/src/adapters/text.tsRepository: TanStack/ai
Length of output: 37
π Script executed:
#!/bin/bash
# Search for image_url handling in OpenAI adapter
rg -n "image_url\|image" --type ts -A 5 -B 2 packages/typescript/ai-openai/src/adapters/text.ts | head -60Repository: TanStack/ai
Length of output: 37
π Script executed:
#!/bin/bash
# Check if there's any base64 or data URI handling in the codebase
rg -n "base64\|data:" --type ts | grep -i imageRepository: TanStack/ai
Length of output: 37
π Script executed:
#!/bin/bash
# Look for ContentPartSource handling patterns
rg -n "source.type" --type ts -B 2 -A 5 | head -80Repository: TanStack/ai
Length of output: 5181
Add support for base64 image sources in addition to URL sources.
The ContentPartSource interface supports both type: 'data' (base64-encoded) and type: 'url'. The current implementation only handles URL sources directly. When part.source.type === 'data', the value is base64-encoded and must be converted to a data URI (e.g., data:image/jpeg;base64,<value>) before passing to OpenAI's image_url field.
See how Anthropic and Gemini adapters handle this by checking part.source.type and converting accordingly.
π€ Prompt for AI Agents
In @packages/typescript/ai-grok/src/adapters/text.ts around lines 397 - 406, The
image branch only treats part.source.value as a URL; update the block that
builds the Grok image part (the code that pushes { type: 'image_url', image_url:
{ url: ..., detail: ... } }) to handle both ContentPartSource types by checking
part.source.type: if 'url' use part.source.value directly, if 'data' convert the
base64 payload into a data URI (e.g., "data:<mime>;base64,<value>") before
assigning to image_url.url; derive the MIME from part.metadata or part.source
(fall back to "image/jpeg") and preserve the existing GrokImageMetadata.detail
logic when creating the final parts entry.
| // Recursively transform nested objects/arrays | ||
| if (prop.type === 'object' && prop.properties) { | ||
| properties[propName] = makeGrokStructuredOutputCompatible( | ||
| prop, | ||
| prop.required || [], | ||
| ) | ||
| } else if (prop.type === 'array' && prop.items) { | ||
| properties[propName] = { | ||
| ...prop, | ||
| items: makeGrokStructuredOutputCompatible( | ||
| prop.items, | ||
| prop.items.required || [], | ||
| ), | ||
| } | ||
| } else if (wasOptional) { | ||
| // Make optional fields nullable by adding null to the type | ||
| if (prop.type && !Array.isArray(prop.type)) { | ||
| properties[propName] = { | ||
| ...prop, | ||
| type: [prop.type, 'null'], | ||
| } | ||
| } else if (Array.isArray(prop.type) && !prop.type.includes('null')) { | ||
| properties[propName] = { | ||
| ...prop, | ||
| type: [...prop.type, 'null'], | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional nested objects/arrays won't be made nullable.
The else if chain means that if a property is an object or array, the wasOptional check on line 78 is never reached. This results in optional nested objects/arrays not having null added to their type union, which could cause issues when Grok returns null for an optional nested field.
π Proposed fix to handle nullable nested types
// Recursively transform nested objects/arrays
if (prop.type === 'object' && prop.properties) {
- properties[propName] = makeGrokStructuredOutputCompatible(
+ let transformed = makeGrokStructuredOutputCompatible(
prop,
prop.required || [],
)
+ if (wasOptional) {
+ transformed = { ...transformed, type: ['object', 'null'] }
+ }
+ properties[propName] = transformed
} else if (prop.type === 'array' && prop.items) {
- properties[propName] = {
+ let transformed = {
...prop,
items: makeGrokStructuredOutputCompatible(
prop.items,
prop.items.required || [],
),
}
+ if (wasOptional) {
+ transformed = { ...transformed, type: ['array', 'null'] }
+ }
+ properties[propName] = transformed
} else if (wasOptional) {
π― Changes
Adding Grok to the adapter set.
β Checklist
pnpm run test:pr.π Release Impact
Summary by CodeRabbit
New Features
Documentation
βοΈ Tip: You can customize this high-level summary in your review settings.