diff --git a/packages/ai/src/protocols/open-responses.ts b/packages/ai/src/protocols/open-responses.ts index 92c822682e..3ec5575f89 100644 --- a/packages/ai/src/protocols/open-responses.ts +++ b/packages/ai/src/protocols/open-responses.ts @@ -154,6 +154,7 @@ export const coreFields = { tools: optionalArray(Tool), tool_choice: Schema.optional(ToolChoice), store: Schema.optional(Schema.Boolean), + truncation: Schema.optional(OpenResponsesOptions.TruncationSchema), service_tier: Schema.optional(OpenResponsesOptions.ServiceTierSchema), prompt_cache_key: Schema.optional(Schema.String), include: optionalArray(OpenResponsesOptions.ResponseIncludableSchema), @@ -577,6 +578,7 @@ const lowerOptions = (request: LLMRequest) => { : {}), ...(options.textVerbosity ? { text: { verbosity: options.textVerbosity } } : {}), ...(options.serviceTier ? { service_tier: options.serviceTier } : {}), + ...(options.truncation ? { truncation: options.truncation } : {}), } } diff --git a/packages/ai/src/protocols/utils/open-responses-options.ts b/packages/ai/src/protocols/utils/open-responses-options.ts index 834606817e..ff148fc1fd 100644 --- a/packages/ai/src/protocols/utils/open-responses-options.ts +++ b/packages/ai/src/protocols/utils/open-responses-options.ts @@ -16,19 +16,25 @@ export type ResponseIncludable = (typeof ResponseIncludables)[number] export const ServiceTiers = ["auto", "default", "flex", "priority"] as const export type ServiceTier = (typeof ServiceTiers)[number] +export const Truncations = ["auto", "disabled"] as const +export type Truncation = (typeof Truncations)[number] + const TEXT_VERBOSITY = new Set(["low", "medium", "high"]) const INCLUDABLES = new Set(ResponseIncludables) const SERVICE_TIERS = new Set(ServiceTiers) +const TRUNCATIONS = new Set(Truncations) const isTextVerbosity = (value: unknown): value is Schema.Schema.Type => typeof value === "string" && TEXT_VERBOSITY.has(value) const isServiceTier = (value: unknown): value is ServiceTier => typeof value === "string" && SERVICE_TIERS.has(value) +const isTruncation = (value: unknown): value is Truncation => typeof value === "string" && TRUNCATIONS.has(value) export const ReasoningEffort = Schema.String export const TextVerbositySchema = TextVerbosity export const ResponseIncludableSchema = Schema.Literals(ResponseIncludables) export const ServiceTierSchema = Schema.Literals(ServiceTiers) +export const TruncationSchema = Schema.Literals(Truncations) export interface Resolved { readonly instructions?: string @@ -38,6 +44,7 @@ export interface Resolved { readonly include?: ReadonlyArray readonly textVerbosity?: Schema.Schema.Type readonly serviceTier?: ServiceTier + readonly truncation?: Truncation } export const resolve = (request: LLMRequest): Resolved => { @@ -57,6 +64,7 @@ export const resolve = (request: LLMRequest): Resolved => { include: include.length > 0 ? include : undefined, textVerbosity: isTextVerbosity(input?.textVerbosity) ? input.textVerbosity : undefined, serviceTier: isServiceTier(input?.serviceTier) ? input.serviceTier : undefined, + truncation: isTruncation(input?.truncation) ? input.truncation : undefined, } } diff --git a/packages/ai/src/providers/open-responses-options.ts b/packages/ai/src/providers/open-responses-options.ts index 7f8cff95d2..1a844e2732 100644 --- a/packages/ai/src/providers/open-responses-options.ts +++ b/packages/ai/src/providers/open-responses-options.ts @@ -1,4 +1,4 @@ -import type { ResponseIncludable, ServiceTier } from "../protocols/utils/open-responses-options.js" +import type { ResponseIncludable, ServiceTier, Truncation } from "../protocols/utils/open-responses-options.js" import type { ProviderOptions, ReasoningEffort, TextVerbosity } from "../schema/index.js" export interface OpenResponsesOptionsInput { @@ -10,6 +10,7 @@ export interface OpenResponsesOptionsInput { readonly include?: ReadonlyArray readonly textVerbosity?: TextVerbosity readonly serviceTier?: ServiceTier + readonly truncation?: Truncation } export type OpenResponsesProviderOptionsInput = ProviderOptions & { diff --git a/packages/ai/test/provider/openai-compatible-responses.test.ts b/packages/ai/test/provider/openai-compatible-responses.test.ts index e5f8024d34..0ca953ee22 100644 --- a/packages/ai/test/provider/openai-compatible-responses.test.ts +++ b/packages/ai/test/provider/openai-compatible-responses.test.ts @@ -123,13 +123,14 @@ describe("Open Responses-compatible route", () => { const model = configure({ apiKey: "test-key", baseURL: "https://responses.example.test/v1", - providerOptions: { openresponses: { reasoningEffort: "low", store: true } }, + providerOptions: { openresponses: { reasoningEffort: "low", store: true, truncation: "auto" } }, }).model("example-model") const prepared = yield* compileRequest(LLM.request({ model, prompt: "Think." })) expect(prepared.body).toMatchObject({ reasoning: { effort: "low" }, store: true, + truncation: "auto", }) }), ) diff --git a/packages/ai/test/provider/openai-responses.test.ts b/packages/ai/test/provider/openai-responses.test.ts index 0cc08c6bd7..dd97982baa 100644 --- a/packages/ai/test/provider/openai-responses.test.ts +++ b/packages/ai/test/provider/openai-responses.test.ts @@ -1283,6 +1283,7 @@ describe("OpenAI Responses route", () => { reasoningEffort: "high", reasoningSummary: "auto", include: ["reasoning.encrypted_content"], + truncation: "disabled", }, }, }), @@ -1293,6 +1294,7 @@ describe("OpenAI Responses route", () => { expect(prepared.body.include).toEqual(["reasoning.encrypted_content"]) expect(prepared.body.reasoning).toEqual({ effort: "high", summary: "auto" }) expect(prepared.body.text).toEqual({ verbosity: "low" }) + expect(prepared.body.truncation).toBe("disabled") }), )