From 41de4adbcf8f5732d43b6c93a9cb37f15e48a915 Mon Sep 17 00:00:00 2001 From: Harshdeep Singh Date: Sat, 10 Oct 2026 21:43:41 +0530 Subject: [PATCH 1/3] fix(ai, ai-anthropic): skip summarize temperature on no-sampling models summarize() was injecting temperature: 0.3 for every non-Ollama adapter, which 400s on Anthropic models that reject non-default sampling (e.g. claude-sonnet-5-5). Opt out via supportsSamplingTemperature, strip sampling keys on the Anthropic wire, and align opus-5-5 meta. Closes #1703 --- .../summarize-skip-temperature-no-sampling.md | 6 +++ docs/adapters/anthropic.md | 11 +++-- packages/ai-anthropic/src/adapters/text.ts | 34 +++++++++++-- packages/ai-anthropic/src/index.ts | 2 + packages/ai-anthropic/src/model-meta.ts | 35 ++++++++++++- .../tests/anthropic-adapter.test.ts | 49 +++++++++++++++++++ .../ai-anthropic/tests/auth-parity.test.ts | 5 +- .../tests/chat-per-model-type-safety.test.ts | 48 ++++++++++++++++++ .../ai-anthropic/tests/model-meta.test.ts | 36 ++++++++++++++ .../summarize/chat-stream-summarize.ts | 10 +++- .../ai/tests/summarize-max-length.test.ts | 20 ++++++++ 11 files changed, 243 insertions(+), 13 deletions(-) create mode 100644 .changeset/summarize-skip-temperature-no-sampling.md diff --git a/.changeset/summarize-skip-temperature-no-sampling.md b/.changeset/summarize-skip-temperature-no-sampling.md new file mode 100644 index 0000000000..279fd2618d --- /dev/null +++ b/.changeset/summarize-skip-temperature-no-sampling.md @@ -0,0 +1,6 @@ +--- +'@tanstack/ai': patch +'@tanstack/ai-anthropic': patch +--- + +`summarize()` no longer sends a default `temperature: 0.3` when the wrapped text adapter sets `supportsSamplingTemperature: false`. The Anthropic text adapter sets that flag for models that reject non-default sampling parameters, strips `temperature` / `top_p` / `top_k` on the wire for those models, and corrects `claude-opus-5-5` provider options so sampling knobs are not typed. diff --git a/docs/adapters/anthropic.md b/docs/adapters/anthropic.md index f0c3faf765..5eeddb163d 100644 --- a/docs/adapters/anthropic.md +++ b/docs/adapters/anthropic.md @@ -347,10 +347,13 @@ Per-model rules (enforced by the adapter's types): - **`claude-fable-5`** — thinking is always on. The only accepted explicit config is `{ type: "adaptive" }` (both `disabled` and `budget_tokens` return a 400), and sampling parameters are rejected. -- **`claude-sonnet-5-5`** — the types accept only `{ type: "adaptive" }`. - Both `disabled` and `budget_tokens` return a 400, and so do non-default - sampling values. To turn off up-front thinking, the API takes - `{ type: "between_tools" }`, which the adapter does not type yet. +- **`claude-sonnet-5-5` / `claude-opus-5-5`** — the types accept only + `{ type: "adaptive" }`. Both `disabled` and `budget_tokens` return a + 400, and so do non-default sampling values. To turn off up-front + thinking on Sonnet 5.5, the API takes `{ type: "between_tools" }`, + which the adapter does not type yet. `summarize()` also omits its + default `temperature: 0.3` on these models (and on the other + no-sampling ids above), so the request does not 400. - **`claude-haiku-5-5`** — adaptive thinking is the default, and the types accept `{ type: "adaptive" }` or `{ type: "disabled" }`. The API accepts `disabled` at `high` effort or below and returns a 400 at `xhigh` diff --git a/packages/ai-anthropic/src/adapters/text.ts b/packages/ai-anthropic/src/adapters/text.ts index 5a78fd43b0..84b9e5bd50 100644 --- a/packages/ai-anthropic/src/adapters/text.ts +++ b/packages/ai-anthropic/src/adapters/text.ts @@ -29,6 +29,7 @@ import { import { ANTHROPIC_COMBINED_TOOLS_AND_SCHEMA_MODELS, ANTHROPIC_MODEL_INPUT_MODALITIES, + anthropicModelSupportsSampling, getAnthropicDefaultMaxTokens, } from '../model-meta' import type { @@ -370,6 +371,11 @@ export class AnthropicTextAdapter< override readonly supportsFileSources = true override readonly inputModalities = ANTHROPIC_MODEL_INPUT_MODALITIES[this.model] + /** + * When `false`, `ChatStreamSummarizeAdapter` skips its default + * `temperature: 0.3` (models that reject non-default sampling). + */ + readonly supportsSamplingTemperature: boolean private readonly client: SdkAnthropicMessagesClient private readonly allowEmptySignature: boolean @@ -389,6 +395,7 @@ export class AnthropicTextAdapter< constructor(config: AnthropicTextAdapterConfig, model: TModel) { super({}, model) + this.supportsSamplingTemperature = anthropicModelSupportsSampling(model) this.provider = config.provider ?? this.name this.allowEmptySignature = config.allowEmptySignature ?? false if ('client' in config) { @@ -696,6 +703,8 @@ export class AnthropicTextAdapter< const validProviderOptions: Partial = {} if (modelOptions) { + const samplingKeys = ['top_k', 'temperature', 'top_p'] as const + const modelAllowsSampling = anthropicModelSupportsSampling(this.model) const validKeys: Array = [ 'cache_control', 'container', @@ -707,16 +716,20 @@ export class AnthropicTextAdapter< 'stop_sequences', 'thinking', 'tool_choice', - 'top_k', - 'temperature', - 'top_p', + ...(modelAllowsSampling ? samplingKeys : []), ] // `max_tokens` is a legitimate public modelOptions field, but it is read // via a dedicated path (defaultMaxTokens below) rather than copied into // validProviderOptions. Exempt it from the dropped-key warning here so a // correct `modelOptions: { max_tokens }` call doesn't log a spurious // "dropped unknown key" error, while keeping it out of the copy loop. - const droppedKeyExemptSet = new Set([...validKeys, 'max_tokens']) + const droppedKeyExemptSet = new Set([ + ...validKeys, + 'max_tokens', + // Sampling keys are stripped (not "unknown") on no-sampling models — + // warn separately below so callers who cast around types get a signal. + ...(modelAllowsSampling ? [] : samplingKeys), + ]) const droppedKeys = Object.keys(modelOptions).filter( (key) => !droppedKeyExemptSet.has(key), ) @@ -737,6 +750,19 @@ export class AnthropicTextAdapter< }, ) } + if (!modelAllowsSampling) { + const strippedSampling = samplingKeys.filter((key) => key in modelOptions) + if (strippedSampling.length > 0) { + options.logger.warn( + `anthropic.mapCommonOptionsToAnthropic omitted sampling key(s) for model=${this.model}: ${strippedSampling.join(', ')} (this model rejects non-default sampling parameters)`, + { + provider: 'anthropic', + model: this.model, + strippedSampling, + }, + ) + } + } for (const key of validKeys) { if (key in modelOptions) { const value = modelOptions[key] diff --git a/packages/ai-anthropic/src/index.ts b/packages/ai-anthropic/src/index.ts index 0c489cb14b..bf552cdf4a 100644 --- a/packages/ai-anthropic/src/index.ts +++ b/packages/ai-anthropic/src/index.ts @@ -43,8 +43,10 @@ export type { } from './model-meta' export { ANTHROPIC_MODELS, + ANTHROPIC_MODELS_WITHOUT_SAMPLING, ANTHROPIC_VERTEX_CHAT_MODELS, ANTHROPIC_COMBINED_TOOLS_AND_SCHEMA_MODELS, + anthropicModelSupportsSampling, } from './model-meta' export type { AnthropicTextMetadata, diff --git a/packages/ai-anthropic/src/model-meta.ts b/packages/ai-anthropic/src/model-meta.ts index 0201277e68..630dd7ff2c 100644 --- a/packages/ai-anthropic/src/model-meta.ts +++ b/packages/ai-anthropic/src/model-meta.ts @@ -607,6 +607,9 @@ const CLAUDE_FABLE_5_1 = { AnthropicOutputConfigOptions > +// Claude Opus 5.5: adaptive-only thinking; non-default sampling parameters +// (`temperature`, `top_p`, `top_k`) return a 400. Provider options use +// `max_tokens` without the sampling knobs (Anthropic Opus 5.5 migration guide). const CLAUDE_OPUS_5_5 = { name: 'claude-opus-5-5', id: 'claude-opus-5-5', @@ -643,7 +646,7 @@ const CLAUDE_OPUS_5_5 = { AnthropicStopSequencesOptions & AnthropicAdaptiveOnlyThinkingOptions & AnthropicToolChoiceOptions & - AnthropicSamplingOptions & + AnthropicMaxTokensOptions & AnthropicOutputConfigOptions > @@ -759,6 +762,33 @@ export const ANTHROPIC_MODELS = [ CLAUDE_SONNET_5.id, ] as const +/** + * Models whose Messages API rejects non-default `temperature` / `top_p` / + * `top_k`. Keep in sync with `AnthropicChatModelProviderOptionsByName` + * entries that use `AnthropicMaxTokensOptions` instead of + * `AnthropicSamplingOptions`. Type tests in `model-meta.test.ts` enforce both + * directions so a new model id must pick one. + */ +export const ANTHROPIC_MODELS_WITHOUT_SAMPLING = [ + CLAUDE_OPUS_4_7.id, + CLAUDE_OPUS_4_8.id, + CLAUDE_FABLE_5.id, + CLAUDE_FABLE_5_1.id, + CLAUDE_SONNET_5.id, + CLAUDE_SONNET_5_5.id, + CLAUDE_OPUS_5_5.id, + CLAUDE_HAIKU_5_5.id, +] as const + +const ANTHROPIC_MODELS_WITHOUT_SAMPLING_SET: ReadonlySet = new Set( + ANTHROPIC_MODELS_WITHOUT_SAMPLING, +) + +/** `false` when the model rejects non-default sampling parameters. */ +export function anthropicModelSupportsSampling(model: string): boolean { + return !ANTHROPIC_MODELS_WITHOUT_SAMPLING_SET.has(model) +} + /** * Claude chat models on Vertex AI / Gemini Enterprise Agent Platform. * This list is the Google partner catalog, not the full Anthropic API catalog. @@ -1030,6 +1060,7 @@ export type AnthropicChatModelProviderOptionsByName = { AnthropicToolChoiceOptions & AnthropicMaxTokensOptions & AnthropicOutputConfigOptions + // Claude Opus 5.5: adaptive-only thinking, no sampling — see constant above. [CLAUDE_OPUS_5_5.id]: AnthropicCacheControlOptions & AnthropicContainerOptions & AnthropicContextManagementOptions & @@ -1038,7 +1069,7 @@ export type AnthropicChatModelProviderOptionsByName = { AnthropicStopSequencesOptions & AnthropicAdaptiveOnlyThinkingOptions & AnthropicToolChoiceOptions & - AnthropicSamplingOptions & + AnthropicMaxTokensOptions & AnthropicOutputConfigOptions // Claude Sonnet 5.5: adaptive-only thinking config, no sampling // parameters — see the CLAUDE_SONNET_5_5 constant above. diff --git a/packages/ai-anthropic/tests/anthropic-adapter.test.ts b/packages/ai-anthropic/tests/anthropic-adapter.test.ts index 0dc0788bfb..41da9143e6 100644 --- a/packages/ai-anthropic/tests/anthropic-adapter.test.ts +++ b/packages/ai-anthropic/tests/anthropic-adapter.test.ts @@ -612,6 +612,55 @@ describe('Anthropic adapter option mapping', () => { expect(payload.max_tokens).toBe(2048) }) + it('strips sampling keys on no-sampling models even when cast in (#1703)', async () => { + mocks.betaMessagesCreate.mockResolvedValueOnce(createTextStream('ok')) + + const adapter = new AnthropicTextAdapter( + { apiKey: 'test-key' }, + 'claude-sonnet-5-5', + ) + expect(adapter.supportsSamplingTemperature).toBe(false) + + const logger = { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + } + + for await (const _ of chat({ + adapter, + messages: [{ role: 'user', content: 'Hi' }], + // Escape the per-model options type: temperature is rejected at the + // type level on this model, but the wire layer must still strip it. + modelOptions: { + temperature: 0.3, + top_p: 0.9, + top_k: 5, + max_tokens: 1024, + } as never, + debug: { logger, errors: true }, + })) { + // consume stream + } + + const [payload] = mocks.betaMessagesCreate.mock.calls[0]! + expect(payload.temperature).toBeUndefined() + expect(payload.top_p).toBeUndefined() + expect(payload.top_k).toBeUndefined() + expect(payload.max_tokens).toBe(1024) + + const stripWarning = logger.warn.mock.calls.find((call) => + String(call[0]).includes('omitted sampling key(s)'), + ) + expect(stripWarning).toBeDefined() + }) + + it('keeps supportsSamplingTemperature true on sampling models', () => { + const adapter = createAdapter('claude-opus-4-1') + expect(adapter.supportsSamplingTemperature).toBe(true) + }) + it('forwards context_management and attaches the required beta (issue #1074)', async () => { mocks.betaMessagesCreate.mockResolvedValueOnce(createTextStream('ok')) diff --git a/packages/ai-anthropic/tests/auth-parity.test.ts b/packages/ai-anthropic/tests/auth-parity.test.ts index da1f951822..70c3bcb802 100644 --- a/packages/ai-anthropic/tests/auth-parity.test.ts +++ b/packages/ai-anthropic/tests/auth-parity.test.ts @@ -390,7 +390,7 @@ describe('summarize factories', () => { expect(result.summary).toBe('Summary') }) - it('anthropicSummarize sends ANTHROPIC_API_KEY and keeps the request unchanged', async () => { + it('anthropicSummarize sends ANTHROPIC_API_KEY and omits temperature on no-sampling models', async () => { vi.stubEnv('ANTHROPIC_API_KEY', 'summarize-key') const { fetch, requests } = captureTransport() const result = await anthropicSummarize('claude-sonnet-5', { @@ -405,6 +405,8 @@ describe('summarize factories', () => { authorization: null, xApiKey: 'summarize-key', }) + // claude-sonnet-5 rejects non-default sampling — summarize must not + // inject temperature: 0.3 (#1703). expect(requests[0]!.body).toEqual({ model: 'claude-sonnet-5', max_tokens: 128, @@ -415,7 +417,6 @@ describe('summarize factories', () => { text: 'You are a professional summarizer. Provide a clear and concise summary. ', }, ], - temperature: 0.3, stream: true, }) expect(result.summary).toBe('Summary') diff --git a/packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts b/packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts index 1d48eed085..d5442a18a5 100644 --- a/packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts +++ b/packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts @@ -364,6 +364,39 @@ describe('Anthropic per-model chat modelOptions gating', () => { }) }) + describe('claude-opus-5-5 — adaptive-only thinking, no sampling', () => { + it('accepts adaptive thinking + output_config + max_tokens', () => { + chat({ + adapter: anthropicText('claude-opus-5-5'), + messages: [{ role: 'user', content: 'hi' }], + modelOptions: { + thinking: { type: 'adaptive', display: 'summarized' }, + output_config: { effort: 'high' }, + max_tokens: 2048, + }, + }) + }) + + it('rejects sampling parameters', () => { + chat({ + adapter: anthropicText('claude-opus-5-5'), + messages: [{ role: 'user', content: 'hi' }], + modelOptions: { + // @ts-expect-error - 'temperature' is not available on claude-opus-5-5 + temperature: 0.5, + }, + }) + chat({ + adapter: anthropicText('claude-opus-5-5'), + messages: [{ role: 'user', content: 'hi' }], + modelOptions: { + // @ts-expect-error - 'top_k' is not available on claude-opus-5-5 + top_k: 5, + }, + }) + }) + }) + describe('Model name type safety', () => { it('rejects unknown model names at the factory', () => { // @ts-expect-error - 'claude-fake-9000' is not a valid Anthropic chat model @@ -473,4 +506,19 @@ describe('Anthropic provider options shape assertions', () => { expectTypeOf().not.toHaveProperty('top_k') }) }) + + describe('claude-opus-5-5 — adaptive-only thinking without sampling', () => { + type Options = AnthropicChatModelProviderOptionsByName['claude-opus-5-5'] + + it('has thinking and output_config', () => { + expectTypeOf().toHaveProperty('thinking') + expectTypeOf().toHaveProperty('output_config') + }) + it('has max_tokens but NOT temperature/top_p/top_k', () => { + expectTypeOf().toHaveProperty('max_tokens') + expectTypeOf().not.toHaveProperty('temperature') + expectTypeOf().not.toHaveProperty('top_p') + expectTypeOf().not.toHaveProperty('top_k') + }) + }) }) diff --git a/packages/ai-anthropic/tests/model-meta.test.ts b/packages/ai-anthropic/tests/model-meta.test.ts index 0d973280d4..95dbe7347d 100644 --- a/packages/ai-anthropic/tests/model-meta.test.ts +++ b/packages/ai-anthropic/tests/model-meta.test.ts @@ -4,6 +4,8 @@ import { ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS, ANTHROPIC_MAX_NONSTREAMING_TOKENS, ANTHROPIC_MODELS, + ANTHROPIC_MODELS_WITHOUT_SAMPLING, + anthropicModelSupportsSampling, getAnthropicDefaultMaxTokens, } from '../src/model-meta' import type { @@ -188,6 +190,40 @@ describe('Anthropic Model Provider Options Type Assertions', () => { expectTypeOf<'claude-haiku-5-5'>().toExtend() }) }) + + describe('ANTHROPIC_MODELS_WITHOUT_SAMPLING stays in sync with provider options', () => { + type WithoutSampling = (typeof ANTHROPIC_MODELS_WITHOUT_SAMPLING)[number] + type WithSampling = Exclude<(typeof ANTHROPIC_MODELS)[number], WithoutSampling> + + it('without-sampling models have max_tokens but not temperature/top_p/top_k', () => { + type Options = AnthropicChatModelProviderOptionsByName[WithoutSampling] + expectTypeOf().toHaveProperty('max_tokens') + expectTypeOf().not.toHaveProperty('temperature') + expectTypeOf().not.toHaveProperty('top_p') + expectTypeOf().not.toHaveProperty('top_k') + }) + + it('every other registered model exposes AnthropicSamplingOptions', () => { + type Options = AnthropicChatModelProviderOptionsByName[WithSampling] + expectTypeOf().toExtend() + }) + + it('without-sampling ids are a subset of ANTHROPIC_MODELS', () => { + const registered = new Set(ANTHROPIC_MODELS) + for (const id of ANTHROPIC_MODELS_WITHOUT_SAMPLING) { + expect(registered.has(id)).toBe(true) + } + }) + + it('anthropicModelSupportsSampling matches the const list', () => { + for (const id of ANTHROPIC_MODELS) { + const expected = !( + ANTHROPIC_MODELS_WITHOUT_SAMPLING as ReadonlyArray + ).includes(id) + expect(anthropicModelSupportsSampling(id)).toBe(expected) + } + }) + }) }) /** diff --git a/packages/ai/src/activities/summarize/chat-stream-summarize.ts b/packages/ai/src/activities/summarize/chat-stream-summarize.ts index fdb522f867..af0439f6fb 100644 --- a/packages/ai/src/activities/summarize/chat-stream-summarize.ts +++ b/packages/ai/src/activities/summarize/chat-stream-summarize.ts @@ -67,6 +67,12 @@ function throwRunError( export interface ChatStreamCapable { /** Native token-limit option for adapters whose provider name is user-defined. */ readonly maxTokensKey?: string + /** + * When `false`, summarize skips the default `temperature: 0.3`. + * `undefined` / `true` keep today's default. Use for models that reject + * non-default sampling parameters (e.g. Anthropic Claude Sonnet 5.5). + */ + readonly supportsSamplingTemperature?: boolean chatStream: (options: TextOptions) => AsyncIterable } @@ -372,7 +378,9 @@ export class ChatStreamSummarizeAdapter< let working: Record = { ...(options.modelOptions as Record | undefined), } - working = applyDefaultTemperature(this.name, 0.3, working) + if (this.textAdapter.supportsSamplingTemperature !== false) { + working = applyDefaultTemperature(this.name, 0.3, working) + } // `maxLength` must reach the wire under the provider-native token key (it // differs per provider, and no adapter reads a generic `maxTokens`). // Prefer the wrapped adapter's explicit key, then this wrapper's name, diff --git a/packages/ai/tests/summarize-max-length.test.ts b/packages/ai/tests/summarize-max-length.test.ts index 6dc2c5c629..da9635ea6b 100644 --- a/packages/ai/tests/summarize-max-length.test.ts +++ b/packages/ai/tests/summarize-max-length.test.ts @@ -143,6 +143,26 @@ describe('ChatStreamSummarizeAdapter — maxLength reaches the wrapped adapter u expect(opts?.['temperature']).toBe(0.9) }) + it('skips the temperature default when supportsSamplingTemperature is false', async () => { + const { textAdapter, lastModelOptions } = createRecordingTextAdapter() + const adapter = new ChatStreamSummarizeAdapter( + { ...textAdapter, supportsSamplingTemperature: false }, + 'claude-sonnet-5-5', + 'anthropic', + ) + + await adapter.summarize({ + model: 'claude-sonnet-5-5', + text: 'hi', + maxLength: 200, + logger, + }) + + const opts = lastModelOptions() + expect(opts?.['temperature']).toBeUndefined() + expect(opts?.['max_tokens']).toBe(200) + }) + it('unknown adapter name sets no token key and warns instead of silently dropping maxLength', async () => { const { textAdapter, lastModelOptions } = createRecordingTextAdapter() // Default name is 'chat-stream-summarize' — not a recognised provider. From 455be12b166b61e9081d2f0feb9c8f71765726d2 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 12:04:29 +0000 Subject: [PATCH 2/3] ci: apply automated fixes --- packages/ai-anthropic/src/adapters/text.ts | 4 +++- packages/ai-anthropic/tests/model-meta.test.ts | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/ai-anthropic/src/adapters/text.ts b/packages/ai-anthropic/src/adapters/text.ts index 84b9e5bd50..bd5e12ff69 100644 --- a/packages/ai-anthropic/src/adapters/text.ts +++ b/packages/ai-anthropic/src/adapters/text.ts @@ -751,7 +751,9 @@ export class AnthropicTextAdapter< ) } if (!modelAllowsSampling) { - const strippedSampling = samplingKeys.filter((key) => key in modelOptions) + const strippedSampling = samplingKeys.filter( + (key) => key in modelOptions, + ) if (strippedSampling.length > 0) { options.logger.warn( `anthropic.mapCommonOptionsToAnthropic omitted sampling key(s) for model=${this.model}: ${strippedSampling.join(', ')} (this model rejects non-default sampling parameters)`, diff --git a/packages/ai-anthropic/tests/model-meta.test.ts b/packages/ai-anthropic/tests/model-meta.test.ts index 95dbe7347d..cc2be3df0f 100644 --- a/packages/ai-anthropic/tests/model-meta.test.ts +++ b/packages/ai-anthropic/tests/model-meta.test.ts @@ -193,7 +193,10 @@ describe('Anthropic Model Provider Options Type Assertions', () => { describe('ANTHROPIC_MODELS_WITHOUT_SAMPLING stays in sync with provider options', () => { type WithoutSampling = (typeof ANTHROPIC_MODELS_WITHOUT_SAMPLING)[number] - type WithSampling = Exclude<(typeof ANTHROPIC_MODELS)[number], WithoutSampling> + type WithSampling = Exclude< + (typeof ANTHROPIC_MODELS)[number], + WithoutSampling + > it('without-sampling models have max_tokens but not temperature/top_p/top_k', () => { type Options = AnthropicChatModelProviderOptionsByName[WithoutSampling] From 8afd5f9c1726e7388c65ac5ddd855be44eaa79d4 Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Thu, 22 Oct 2026 14:57:48 +0200 Subject: [PATCH 3/3] test: pass threadId and use a current model, as main now requires --- packages/ai-anthropic/tests/anthropic-adapter.test.ts | 3 ++- packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts | 1 + packages/ai/tests/summarize-max-length.test.ts | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/ai-anthropic/tests/anthropic-adapter.test.ts b/packages/ai-anthropic/tests/anthropic-adapter.test.ts index 1c58110bdb..eb3d367f42 100644 --- a/packages/ai-anthropic/tests/anthropic-adapter.test.ts +++ b/packages/ai-anthropic/tests/anthropic-adapter.test.ts @@ -639,6 +639,7 @@ describe('Anthropic adapter option mapping', () => { for await (const _ of chat({ adapter, + threadId: 'thread-1', messages: [{ role: 'user', content: 'Hi' }], // Escape the per-model options type: temperature is rejected at the // type level on this model, but the wire layer must still strip it. @@ -666,7 +667,7 @@ describe('Anthropic adapter option mapping', () => { }) it('keeps supportsSamplingTemperature true on sampling models', () => { - const adapter = createAdapter('claude-opus-4-1') + const adapter = createAdapter('claude-sonnet-4-5') expect(adapter.supportsSamplingTemperature).toBe(true) }) diff --git a/packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts b/packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts index ec9c7a64cc..bc7d0498b1 100644 --- a/packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts +++ b/packages/ai-anthropic/tests/chat-per-model-type-safety.test.ts @@ -265,6 +265,7 @@ describe('Anthropic per-model chat modelOptions gating', () => { it('accepts max_tokens and the base options', () => { chat({ adapter: anthropicText('claude-opus-5-5'), + threadId: 'thread-1', messages: [{ role: 'user', content: 'hi' }], modelOptions: { service_tier: 'auto', diff --git a/packages/ai/tests/summarize-max-length.test.ts b/packages/ai/tests/summarize-max-length.test.ts index 0921cd5928..a81bfb257a 100644 --- a/packages/ai/tests/summarize-max-length.test.ts +++ b/packages/ai/tests/summarize-max-length.test.ts @@ -158,6 +158,7 @@ describe('ChatStreamSummarizeAdapter — maxLength reaches the wrapped adapter u await adapter.summarize({ model: 'claude-sonnet-5-5', + threadId: 'thread-1', text: 'hi', maxLength: 200, logger,