From 8239268dc28123142c1d1fbcc239078c7a6f6613 Mon Sep 17 00:00:00 2001 From: Vapi Tasker Date: Sat, 31 Jan 2026 07:42:49 +0000 Subject: [PATCH] feat(openai): align client SDK with OpenAI spec updates (VAP-11729) - Add 'developer' role to OpenAIMessage for GPT-5.x and o-series models - Add GPT-5.2 and GPT-5.2-chat-latest models to all OpenAI model lists - Add new optional API parameters: seed, topP, frequencyPenalty, presencePenalty, logprobs, topLogprobs, parallelToolCalls, reasoningEffort - Add JSDoc deprecation notice for 'function' role (use 'tool' instead) - Add comprehensive tests for all new features Co-Authored-By: Claude --- __tests__/openai-spec.test.ts | 322 ++++++++++++++++++++++++++++++++++ api.ts | 78 +++++++- 2 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 __tests__/openai-spec.test.ts diff --git a/__tests__/openai-spec.test.ts b/__tests__/openai-spec.test.ts new file mode 100644 index 000000000..ecb1d86e4 --- /dev/null +++ b/__tests__/openai-spec.test.ts @@ -0,0 +1,322 @@ +/** + * Tests for OpenAI spec alignment updates (VAP-11729) + * + * This test file validates: + * 1. Developer role support in OpenAIMessage + * 2. GPT-5.2 model availability + * 3. New optional API parameters + * 4. Function role deprecation notice (documented) + */ + +import { + OpenAIMessage, + OpenAIModel, + WorkflowOpenAIModel, + EvalOpenAIModel, +} from "../api"; + +describe("OpenAI Spec Updates (VAP-11729)", () => { + describe("OpenAIMessage role types", () => { + it("should support the developer role for GPT-5.x and o-series models", () => { + const developerMessage: OpenAIMessage = { + content: "You are a helpful assistant for software development tasks.", + role: "developer", + }; + expect(developerMessage.role).toBe("developer"); + expect(developerMessage.content).toBeDefined(); + }); + + it("should support the system role", () => { + const systemMessage: OpenAIMessage = { + content: "You are a helpful assistant.", + role: "system", + }; + expect(systemMessage.role).toBe("system"); + }); + + it("should support the user role", () => { + const userMessage: OpenAIMessage = { + content: "Hello, how are you?", + role: "user", + }; + expect(userMessage.role).toBe("user"); + }); + + it("should support the assistant role", () => { + const assistantMessage: OpenAIMessage = { + content: "I am doing well, thank you!", + role: "assistant", + }; + expect(assistantMessage.role).toBe("assistant"); + }); + + it("should support the tool role", () => { + const toolMessage: OpenAIMessage = { + content: '{"result": "success"}', + role: "tool", + }; + expect(toolMessage.role).toBe("tool"); + }); + + it("should support the deprecated function role for backward compatibility", () => { + // Note: The function role is deprecated in favor of tool role + const functionMessage: OpenAIMessage = { + content: '{"result": "success"}', + role: "function", + }; + expect(functionMessage.role).toBe("function"); + }); + + it("should support null content in messages", () => { + const messageWithNullContent: OpenAIMessage = { + content: null, + role: "assistant", + }; + expect(messageWithNullContent.content).toBeNull(); + }); + }); + + describe("GPT-5.2 model support", () => { + it("should allow gpt-5.2 as a valid model option", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + }; + expect(model.model).toBe("gpt-5.2"); + }); + + it("should allow gpt-5.2-chat-latest as a valid model option", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2-chat-latest", + }; + expect(model.model).toBe("gpt-5.2-chat-latest"); + }); + + it("should still support gpt-5.1 models", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.1", + }; + expect(model.model).toBe("gpt-5.1"); + }); + + it("should still support gpt-5 models", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5", + }; + expect(model.model).toBe("gpt-5"); + }); + + it("should support gpt-5.2 in WorkflowOpenAIModel", () => { + const workflowModel: WorkflowOpenAIModel = { + provider: "openai", + model: "gpt-5.2", + }; + expect(workflowModel.model).toBe("gpt-5.2"); + }); + + it("should support gpt-5.2 in EvalOpenAIModel", () => { + const evalModel: EvalOpenAIModel = { + provider: "openai", + model: "gpt-5.2", + messages: [], + }; + expect(evalModel.model).toBe("gpt-5.2"); + }); + }); + + describe("New optional API parameters", () => { + it("should support seed parameter for deterministic sampling", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + seed: 12345, + }; + expect(model.seed).toBe(12345); + }); + + it("should support topP parameter for nucleus sampling", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + topP: 0.9, + }; + expect(model.topP).toBe(0.9); + }); + + it("should support frequencyPenalty parameter", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + frequencyPenalty: 0.5, + }; + expect(model.frequencyPenalty).toBe(0.5); + }); + + it("should support presencePenalty parameter", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + presencePenalty: 0.5, + }; + expect(model.presencePenalty).toBe(0.5); + }); + + it("should support logprobs parameter", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + logprobs: true, + }; + expect(model.logprobs).toBe(true); + }); + + it("should support topLogprobs parameter", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + logprobs: true, + topLogprobs: 5, + }; + expect(model.topLogprobs).toBe(5); + }); + + it("should support parallelToolCalls parameter", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + parallelToolCalls: true, + }; + expect(model.parallelToolCalls).toBe(true); + }); + + it("should support reasoningEffort parameter for o-series models", () => { + const modelLow: OpenAIModel = { + provider: "openai", + model: "o3", + reasoningEffort: "low", + }; + expect(modelLow.reasoningEffort).toBe("low"); + + const modelMedium: OpenAIModel = { + provider: "openai", + model: "o3", + reasoningEffort: "medium", + }; + expect(modelMedium.reasoningEffort).toBe("medium"); + + const modelHigh: OpenAIModel = { + provider: "openai", + model: "o3", + reasoningEffort: "high", + }; + expect(modelHigh.reasoningEffort).toBe("high"); + }); + + it("should allow combining multiple new parameters", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + temperature: 0.7, + maxTokens: 1000, + seed: 42, + topP: 0.95, + frequencyPenalty: 0.3, + presencePenalty: 0.2, + logprobs: true, + topLogprobs: 10, + parallelToolCalls: true, + }; + + expect(model.seed).toBe(42); + expect(model.topP).toBe(0.95); + expect(model.frequencyPenalty).toBe(0.3); + expect(model.presencePenalty).toBe(0.2); + expect(model.logprobs).toBe(true); + expect(model.topLogprobs).toBe(10); + expect(model.parallelToolCalls).toBe(true); + }); + + it("should maintain backward compatibility with existing parameters", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-4o", + temperature: 0.5, + maxTokens: 500, + emotionRecognitionEnabled: true, + numFastTurns: 2, + }; + + expect(model.temperature).toBe(0.5); + expect(model.maxTokens).toBe(500); + expect(model.emotionRecognitionEnabled).toBe(true); + expect(model.numFastTurns).toBe(2); + }); + }); + + describe("Model fallbacks with GPT-5.2", () => { + it("should support gpt-5.2 in fallback models", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + fallbackModels: "gpt-5.1", + }; + expect(model.fallbackModels).toBe("gpt-5.1"); + }); + + it("should support gpt-5.2-chat-latest in fallback models", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2-chat-latest", + fallbackModels: "gpt-5.2", + }; + expect(model.fallbackModels).toBe("gpt-5.2"); + }); + }); + + describe("Messages with developer role", () => { + it("should support developer messages in OpenAIModel messages array", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + messages: [ + { + content: "You are a code review assistant.", + role: "developer", + }, + { + content: "Hello!", + role: "user", + }, + ], + }; + + expect(model.messages).toHaveLength(2); + expect(model.messages?.[0].role).toBe("developer"); + expect(model.messages?.[1].role).toBe("user"); + }); + + it("should allow mixing developer and system roles in messages", () => { + const model: OpenAIModel = { + provider: "openai", + model: "gpt-5.2", + messages: [ + { + content: "Developer instructions take precedence.", + role: "developer", + }, + { + content: "System fallback instructions.", + role: "system", + }, + ], + }; + + expect(model.messages).toHaveLength(2); + expect(model.messages?.[0].role).toBe("developer"); + expect(model.messages?.[1].role).toBe("system"); + }); + }); +}); diff --git a/api.ts b/api.ts index e5c3f47a9..3ca2a540e 100644 --- a/api.ts +++ b/api.ts @@ -7342,7 +7342,17 @@ export interface CreateGoHighLevelContactGetToolDTO { export interface OpenAIMessage { /** @maxLength 100000000 */ content: string | null; - role: "assistant" | "function" | "user" | "system" | "tool"; + /** + * The role of the message author. + * - `system`: System messages that set behavior + * - `user`: Messages from the user + * - `assistant`: Messages from the AI assistant + * - `developer`: Developer messages for GPT-5.x and o-series models (takes precedence over system) + * - `tool`: Tool/function response messages + * - `function`: Function response messages + * @deprecated The `function` role is deprecated. Use `tool` role instead for function responses. + */ + role: "assistant" | "function" | "user" | "system" | "tool" | "developer"; } export interface AnyscaleModel { @@ -8177,6 +8187,8 @@ export interface OpenAIModel { * @default undefined */ model: + | "gpt-5.2" + | "gpt-5.2-chat-latest" | "gpt-5.1" | "gpt-5.1-chat-latest" | "gpt-5" @@ -8281,6 +8293,8 @@ export interface OpenAIModel { * @example ["gpt-4-0125-preview","gpt-4-0613"] */ fallbackModels?: + | "gpt-5.2" + | "gpt-5.2-chat-latest" | "gpt-5.1" | "gpt-5.1-chat-latest" | "gpt-5" @@ -8420,6 +8434,58 @@ export interface OpenAIModel { * @min 0 */ numFastTurns?: number; + /** + * This is the seed for deterministic sampling. If specified, the model will make a best effort to sample deterministically. + * Using the same seed with the same parameters should return the same result. + */ + seed?: number; + /** + * An alternative to sampling with temperature, called nucleus sampling. + * The model considers the results of the tokens with top_p probability mass. + * So 0.1 means only the tokens comprising the top 10% probability mass are considered. + * We generally recommend altering this or temperature but not both. + * @min 0 + * @max 1 + */ + topP?: number; + /** + * Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, + * decreasing the model's likelihood to repeat the same line verbatim. + * @min -2 + * @max 2 + */ + frequencyPenalty?: number; + /** + * Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, + * increasing the model's likelihood to talk about new topics. + * @min -2 + * @max 2 + */ + presencePenalty?: number; + /** + * Whether to return log probabilities of the output tokens. + * If true, returns the log probabilities of each output token returned in the content of message. + */ + logprobs?: boolean; + /** + * An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, + * each with an associated log probability. logprobs must be set to true if this parameter is used. + * @min 0 + * @max 20 + */ + topLogprobs?: number; + /** + * Whether to enable parallel function calling during tool use. + * When set to true, the model may call multiple functions in parallel. + * @default true + */ + parallelToolCalls?: boolean; + /** + * Constrains effort on reasoning for reasoning models (o-series). + * Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + * Possible values: 'low', 'medium', 'high'. Default varies by model. + */ + reasoningEffort?: "low" | "medium" | "high"; } export interface OpenRouterModel { @@ -8659,6 +8725,8 @@ export interface WorkflowOpenAIModel { * @maxLength 100 */ model: + | "gpt-5.2" + | "gpt-5.2-chat-latest" | "gpt-5.1" | "gpt-5.1-chat-latest" | "gpt-5" @@ -13896,6 +13964,8 @@ export interface CreateAzureOpenAICredentialDTO { | "westus3"; /** @example ["gpt-4-0125-preview","gpt-4-0613"] */ models: + | "gpt-5.2" + | "gpt-5.1" | "gpt-5" | "gpt-5-mini" | "gpt-5-nano" @@ -30527,6 +30597,8 @@ export interface EvalOpenAIModel { * @maxLength 100 */ model: + | "gpt-5.2" + | "gpt-5.2-chat-latest" | "gpt-5.1" | "gpt-5.1-chat-latest" | "gpt-5" @@ -31970,6 +32042,8 @@ export interface AzureOpenAICredential { | "westus3"; /** @example ["gpt-4-0125-preview","gpt-4-0613"] */ models: + | "gpt-5.2" + | "gpt-5.1" | "gpt-5" | "gpt-5-mini" | "gpt-5-nano" @@ -33620,6 +33694,8 @@ export interface UpdateAzureOpenAICredentialDTO { | "westus3"; /** @example ["gpt-4-0125-preview","gpt-4-0613"] */ models?: + | "gpt-5.2" + | "gpt-5.1" | "gpt-5" | "gpt-5-mini" | "gpt-5-nano"