fix(ai-chat): disable Responses API storage for Azure models to stop "Item with id ... not found" stream failures (#23182)
## Problem AI chat and workflow-agent turns on Azure-routed reasoning models (e.g. `azure-foundry-us/gpt-5.5`) intermittently die mid-answer with: > Failed to get response — `400 Item with id 'rs_...' not found` ## Root cause The OpenAI Responses API is stateful: each output item gets a server-side id (`rs_...` reasoning, `fc_...` function call). With `store: true` (the API default), the Vercel AI SDK replays prior assistant reasoning as `item_reference` entries that the provider must resolve from its own storage. For reasoning models the chain-of-thought is never returned in plaintext — it lives only as a stored referenced item, or as `encrypted_content` requested via `include: ['reasoning.encrypted_content']` (which the SDK only auto-adds when `store: false`). PR #20888 (June 22) switched to the safe `store: false` mode, but only for `AI_SDK_OPENAI`. `AI_SDK_AZURE` fell through to `default` and got no options, so every Azure request ran in stored-reference mode. Azure's item storage resolves those references unreliably (a server-side race — the July 21 failure could not find the exact `rs_...` id Azure itself had streamed seconds earlier in the same turn), and the failure is fatal to the stream. Retries replay the same persisted references, so they can fail again. ## Fix Add an `AI_SDK_AZURE` case in `getCallLevelProviderOptions` that passes `azure: { store: false }`. Both AI chat and workflow agents go through this helper, so both paths are covered. The provider-options key for `@ai-sdk/azure` is `azure` (its responses model is registered as `azure.responses`); I verified the `@ai-sdk/openai@3.0.54` copy nested inside `@ai-sdk/azure` has the same guards as the root `3.0.71`. With `store: false` the SDK: - auto-requests `include: ['reasoning.encrypted_content']` for reasoning models (the `gpt-5.5` deployment name passes reasoning detection), - replays reasoning as self-contained encrypted items instead of server-side references, - drops any stale unencrypted reasoning parts instead of referencing them. ### Transition safety Existing threads whose persisted reasoning has `reasoningEncryptedContent: null` simply have those parts skipped on replay. I checked prod logs for the related pairing-validation error ("was provided without its required...") and found zero occurrences since OpenAI-direct made this same switch a month ago, so the transition is safe. ## Testing - Added two Azure cases to `provider-options.util.spec.ts` — all 9 pass. - oxlint (type-aware) and oxfmt clean on the changed files. ## Post-deploy validation Inverse of the evidence: new Azure reasoning parts should persist with non-null `reasoningEncryptedContent`, and the Loki query below should go quiet. fixes : https://discord.com/channels/1130383047699738754/1526873169124659230
This commit is contained in:
+31
@@ -5,6 +5,7 @@ import {
|
||||
} from 'src/engine/metadata-modules/ai/ai-chat/utils/provider-options.util';
|
||||
import {
|
||||
AI_SDK_ANTHROPIC,
|
||||
AI_SDK_AZURE,
|
||||
AI_SDK_BEDROCK,
|
||||
AI_SDK_OPENAI,
|
||||
} from 'src/engine/metadata-modules/ai/ai-models/constants/ai-sdk-package.const';
|
||||
@@ -65,6 +66,36 @@ describe('provider-options.util', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns store false for Azure models', () => {
|
||||
expect(getCallLevelProviderOptions({ sdkPackage: AI_SDK_AZURE })).toEqual(
|
||||
{
|
||||
azure: {
|
||||
store: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('merges existing provider options with Azure store false', () => {
|
||||
expect(
|
||||
getCallLevelProviderOptions({
|
||||
sdkPackage: AI_SDK_AZURE,
|
||||
providerOptions: {
|
||||
xai: {
|
||||
searchParameters: { mode: 'auto' },
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
xai: {
|
||||
searchParameters: { mode: 'auto' },
|
||||
},
|
||||
azure: {
|
||||
store: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('omits promptCacheKey for non-OpenAI providers', () => {
|
||||
expect(
|
||||
getCallLevelProviderOptions({
|
||||
|
||||
+6
@@ -4,6 +4,7 @@ import { type AiSdkPackage } from 'twenty-shared/ai';
|
||||
|
||||
import {
|
||||
AI_SDK_ANTHROPIC,
|
||||
AI_SDK_AZURE,
|
||||
AI_SDK_BEDROCK,
|
||||
AI_SDK_OPENAI,
|
||||
} from 'src/engine/metadata-modules/ai/ai-models/constants/ai-sdk-package.const';
|
||||
@@ -38,6 +39,11 @@ export const getCallLevelProviderOptions = ({
|
||||
...(providerOptions ?? {}),
|
||||
openai: { store: false, ...(promptCacheKey ? { promptCacheKey } : {}) },
|
||||
};
|
||||
case AI_SDK_AZURE:
|
||||
return {
|
||||
...(providerOptions ?? {}),
|
||||
azure: { store: false },
|
||||
};
|
||||
default:
|
||||
return providerOptions;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user