Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/grok-summarize-adapter-assignability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@tanstack/ai-grok': patch
---

Fix `grokSummarize`/`createGrokSummarize` not being assignable to `summarize()`'s
`adapter` param for any current Grok model (`grok-4.3`, `grok-build-0.1`).

`GrokTextProviderOptions` was declared as an `interface` extending
`Record<string, unknown>`, giving it an explicit index signature. Under
`strictFunctionTypes`, the `SummarizeAdapter` constraint is checked
contravariantly, which requires `object` to be assignable to the provider
options β€” but `object` is not assignable to an index-signature type, so the
check failed (Grok-only; OpenAI's all-optional, no-index-signature options
passed). The options are now a type-alias intersection matching the OpenAI
shape, and the text adapter's provider-options constraint is widened to
`Record<string, any>` to mirror `OpenAITextAdapter`.
Comment on lines +2 to +16

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ—„οΈ Data Integrity & Integration | 🟠 Major | ⚑ Quick win

Ship this as a minor changeset instead of patch.

GrokTextProviderOptions is part of the published provider-options surface via GrokProviderOptions, and this PR changes it from an augmentable interface with an index signature to a closed type-alias intersection. That is a semver-visible shape tightening for downstream TypeScript consumers, so patch undersells the compatibility impact.

Suggested changeset fix
-'`@tanstack/ai-grok`': patch
+'`@tanstack/ai-grok`': minor

Based on learnings, "breaking changes and breaking/shape changes documented in Changesets must use a minor version bump (not major)."

πŸ“ 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.

Suggested change
'@tanstack/ai-grok': patch
---
Fix `grokSummarize`/`createGrokSummarize` not being assignable to `summarize()`'s
`adapter` param for any current Grok model (`grok-4.3`, `grok-build-0.1`).
`GrokTextProviderOptions` was declared as an `interface` extending
`Record<string, unknown>`, giving it an explicit index signature. Under
`strictFunctionTypes`, the `SummarizeAdapter` constraint is checked
contravariantly, which requires `object` to be assignable to the provider
options β€” but `object` is not assignable to an index-signature type, so the
check failed (Grok-only; OpenAI's all-optional, no-index-signature options
passed). The options are now a type-alias intersection matching the OpenAI
shape, and the text adapter's provider-options constraint is widened to
`Record<string, any>` to mirror `OpenAITextAdapter`.
'`@tanstack/ai-grok`': minor
---
Fix `grokSummarize`/`createGrokSummarize` not being assignable to `summarize()`'s
`adapter` param for any current Grok model (`grok-4.3`, `grok-build-0.1`).
`GrokTextProviderOptions` was declared as an `interface` extending
`Record<string, unknown>`, giving it an explicit index signature. Under
`strictFunctionTypes`, the `SummarizeAdapter` constraint is checked
contravariantly, which requires `object` to be assignable to the provider
options β€” but `object` is not assignable to an index-signature type, so the
check failed (Grok-only; OpenAI's all-optional, no-index-signature options
passed). The options are now a type-alias intersection matching the OpenAI
shape, and the text adapter's provider-options constraint is widened to
`Record<string, any>` to mirror `OpenAITextAdapter`.
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/grok-summarize-adapter-assignability.md around lines 2 - 16, The
changeset currently marks the Grok provider-options shape change as a patch
release, but this is a semver-visible TypeScript surface change through
GrokProviderOptions and GrokTextProviderOptions. Update the changeset in
grok-summarize-adapter-assignability.md to use a minor release entry instead of
patch, keeping the rest of the rationale intact.

Source: Learnings

7 changes: 5 additions & 2 deletions packages/ai-grok/src/adapters/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ export type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../
*/
export class GrokTextAdapter<
TModel extends (typeof GROK_CHAT_MODELS)[number],
TProviderOptions extends Record<string, unknown> =
ResolveProviderOptions<TModel>,
// Use `Record<string, any>` (not `unknown`) to match the OpenAI text
// adapter: the resolved Grok provider options are a type-alias intersection
// with no explicit index signature, which is assignable to
// `Record<string, any>` but not `Record<string, unknown>`. See issue #821.
TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,
TInputModalities extends ReadonlyArray<Modality> =
ResolveInputModalities<TModel>,
TToolCapabilities extends ReadonlyArray<string> =
Expand Down
21 changes: 17 additions & 4 deletions packages/ai-grok/src/text/text-provider-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ export interface GrokBaseOptions {
}

/**
* Grok-specific provider options for text/chat
* Based on xAI Responses API options
* Sampling and response controls for Grok text/chat models.
*/
export interface GrokTextProviderOptions
extends GrokBaseOptions, Record<string, unknown> {
export interface GrokSamplingOptions {
/**
* Temperature for response generation (0-2)
* Higher values make output more random, lower values more focused
Expand Down Expand Up @@ -62,6 +60,21 @@ export interface GrokTextProviderOptions
reasoning?: GrokReasoning
}

/**
* Grok-specific provider options for text/chat
* Based on xAI Responses API options.
*
* Declared as a type-alias intersection of interfaces with all-optional props
* (matching the OpenAI text adapter), NOT an `interface ... extends
* Record<string, unknown>`. An explicit index signature makes `object`
* un-assignable to these options, which breaks the contravariantly-checked
* `summarize()` adapter constraint (`SummarizeAdapter<string, object>`); see
* issue #821. Without the index signature these options no longer satisfy a
* `Record<string, unknown>` constraint, so the text adapter's provider-options
* generic is widened to `Record<string, any>` to match OpenAI.
*/
export type GrokTextProviderOptions = GrokBaseOptions & GrokSamplingOptions

export type GrokBuildProviderOptions = Omit<
GrokTextProviderOptions,
'reasoning'
Expand Down
15 changes: 14 additions & 1 deletion packages/ai-grok/tests/grok-adapter.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { resolveDebugOption } from '@tanstack/ai/adapter-internals'
import { EventType } from '@tanstack/ai'
import { EventType, summarize } from '@tanstack/ai'
import { createGrokText, grokText } from '../src/adapters/text'
import { createGrokImage, grokImage } from '../src/adapters/image'
import { createGrokSummarize, grokSummarize } from '../src/adapters/summarize'
Expand Down Expand Up @@ -498,5 +498,18 @@ describe('Grok adapters', () => {
'XAI_API_KEY is required',
)
})

it('grokSummarize is assignable to summarize() adapter param for every model (#821)', () => {
// Type-level regression guard: the SummarizeAdapter constraint only
// instantiates at the summarize() call site, so constructing the adapter
// (covered above) is not enough. This closure is type-checked but never
// executed β€” passing CI's test:types is the assertion.
const _typeCheck = () => {
void summarize({ adapter: grokSummarize('grok-4.3'), text: '' })
void summarize({ adapter: grokSummarize('grok-build-0.1'), text: '' })
}

expect(_typeCheck).toBeInstanceOf(Function)
})
})
})
Loading