diff --git a/core/llm/llms/OpenAI.test.ts b/core/llm/llms/OpenAI.test.ts index 46c8b4e23fc..8daf9385223 100644 --- a/core/llm/llms/OpenAI.test.ts +++ b/core/llm/llms/OpenAI.test.ts @@ -5,30 +5,30 @@ describe("OpenAI", () => { const openai = new OpenAI({ model: "o3-mini", }); - expect(openai.isOSeriesModel("o4-mini")).toBeTruthy(); - expect(openai.isOSeriesModel("o3-mini")).toBeTruthy(); - expect(openai.isOSeriesModel("o1-mini")).toBeTruthy(); - expect(openai.isOSeriesModel("o1")).toBeTruthy(); - expect(openai.isOSeriesModel("o3")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o4-mini")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o3-mini")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o1-mini")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o1")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o3")).toBeTruthy(); // artificially correct samples for future models - expect(openai.isOSeriesModel("o5-mini")).toBeTruthy(); - expect(openai.isOSeriesModel("o6")).toBeTruthy(); - expect(openai.isOSeriesModel("o77")).toBeTruthy(); - expect(openai.isOSeriesModel("o54-mini")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o5-mini")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o6")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o77")).toBeTruthy(); + expect(openai.isOSeriesOrGpt5Model("o54-mini")).toBeTruthy(); }); test("should identify incorrect o-series models", () => { const openai = new OpenAI({ model: "o3-mini", }); - expect(openai.isOSeriesModel("gpt-o4-mini")).toBeFalsy(); - expect(openai.isOSeriesModel("gpt-4.5")).toBeFalsy(); - expect(openai.isOSeriesModel("gpt-4.1")).toBeFalsy(); + expect(openai.isOSeriesOrGpt5Model("gpt-o4-mini")).toBeFalsy(); + expect(openai.isOSeriesOrGpt5Model("gpt-4.5")).toBeFalsy(); + expect(openai.isOSeriesOrGpt5Model("gpt-4.1")).toBeFalsy(); // artificially wrong samples - expect(openai.isOSeriesModel("os1")).toBeFalsy(); - expect(openai.isOSeriesModel("so1")).toBeFalsy(); - expect(openai.isOSeriesModel("ao31")).toBeFalsy(); - expect(openai.isOSeriesModel("1os")).toBeFalsy(); + expect(openai.isOSeriesOrGpt5Model("os1")).toBeFalsy(); + expect(openai.isOSeriesOrGpt5Model("so1")).toBeFalsy(); + expect(openai.isOSeriesOrGpt5Model("ao31")).toBeFalsy(); + expect(openai.isOSeriesOrGpt5Model("1os")).toBeFalsy(); }); }); diff --git a/core/llm/llms/OpenAI.ts b/core/llm/llms/OpenAI.ts index c48349f83f0..27006aea117 100644 --- a/core/llm/llms/OpenAI.ts +++ b/core/llm/llms/OpenAI.ts @@ -36,12 +36,12 @@ function isChatOnlyModel(model: string): boolean { return model.startsWith("gpt") || model.startsWith("o"); } -const formatMessageForO1 = (messages: ChatCompletionMessageParam[]) => { +const formatMessageForO1OrGpt5 = (messages: ChatCompletionMessageParam[]) => { return messages?.map((message: any) => { if (message?.role === "system") { return { ...message, - role: "user", + role: "developer", }; } @@ -77,8 +77,8 @@ class OpenAI extends BaseLLM { return model; } - public isOSeriesModel(model?: string): boolean { - return !!model && !!model.match(/^o[0-9]+/); + public isOSeriesOrGpt5Model(model?: string): boolean { + return !!model && (!!model.match(/^o[0-9]+/) || model.includes("gpt-5")); } private isFireworksAiModel(model?: string): boolean { @@ -139,13 +139,13 @@ class OpenAI extends BaseLLM { finalOptions.stop = options.stop?.slice(0, this.getMaxStopWords()); // OpenAI o1-preview and o1-mini or o3-mini: - if (this.isOSeriesModel(options.model)) { + if (this.isOSeriesOrGpt5Model(options.model)) { // a) use max_completion_tokens instead of max_tokens finalOptions.max_completion_tokens = options.maxTokens; finalOptions.max_tokens = undefined; // b) don't support system message - finalOptions.messages = formatMessageForO1(finalOptions.messages); + finalOptions.messages = formatMessageForO1OrGpt5(finalOptions.messages); } if (options.model === "o1") { @@ -241,13 +241,13 @@ class OpenAI extends BaseLLM { body.stop = body.stop?.slice(0, this.getMaxStopWords()); // OpenAI o1-preview and o1-mini or o3-mini: - if (this.isOSeriesModel(body.model)) { + if (this.isOSeriesOrGpt5Model(body.model)) { // a) use max_completion_tokens instead of max_tokens body.max_completion_tokens = body.max_tokens; body.max_tokens = undefined; // b) don't support system message - body.messages = formatMessageForO1(body.messages); + body.messages = formatMessageForO1OrGpt5(body.messages); } if (body.model === "o1") { diff --git a/core/llm/toolSupport.ts b/core/llm/toolSupport.ts index 2700361cc91..1417d8307e3 100644 --- a/core/llm/toolSupport.ts +++ b/core/llm/toolSupport.ts @@ -54,18 +54,20 @@ export const PROVIDER_TOOL_SUPPORT: Record boolean> = return false; }, openai: (model) => { + const lower = model.toLowerCase(); // https://platform.openai.com/docs/guides/function-calling#models-supporting-function-calling if ( - model.toLowerCase().startsWith("gpt-4") || - model.toLowerCase().startsWith("o3") + lower.startsWith("gpt-4") || + lower.startsWith("gpt-5") || + lower.startsWith("o3") ) { return true; } - if (model.toLowerCase().includes("gpt-oss")) { + if (lower.includes("gpt-oss")) { return true; } // https://ai.google.dev/gemma/docs/capabilities/function-calling - if (model.toLowerCase().startsWith("gemma")) { + if (lower.startsWith("gemma")) { return true; } // firworks-ai https://docs.fireworks.ai/guides/function-calling diff --git a/gui/src/pages/AddNewModel/configs/models.ts b/gui/src/pages/AddNewModel/configs/models.ts index d0857d7db6e..b5c4bbae526 100644 --- a/gui/src/pages/AddNewModel/configs/models.ts +++ b/gui/src/pages/AddNewModel/configs/models.ts @@ -1095,6 +1095,18 @@ export const models: { [key: string]: ModelPackage } = { icon: "cohere.png", isOpenSource: false, }, + gpt5: { + title: "GPT-5", + description: "OpenAI's next-generation, high-intelligence flagship model", + params: { + model: "gpt-5", + contextLength: 400_000, + title: "GPT-5", + }, + providerOptions: ["openai"], + icon: "openai.png", + isOpenSource: false, + }, gpt4turbo: { title: "GPT-4 Turbo", description: diff --git a/gui/src/pages/AddNewModel/configs/providers.ts b/gui/src/pages/AddNewModel/configs/providers.ts index d210da9d662..071f96be9d3 100644 --- a/gui/src/pages/AddNewModel/configs/providers.ts +++ b/gui/src/pages/AddNewModel/configs/providers.ts @@ -52,12 +52,13 @@ export const providers: Partial> = { openai: { title: "OpenAI", provider: "openai", - description: "Use gpt-4, gpt-3.5-turbo, or any other OpenAI model", + description: "Use gpt-5, gpt-4, or any other OpenAI model", longDescription: - "Use gpt-4, gpt-3.5-turbo, or any other OpenAI model. See [here](https://openai.com/product#made-for-developers) to obtain an API key.", + "Use gpt-5, gpt-4, or any other OpenAI model. See [here](https://openai.com/product#made-for-developers) to obtain an API key.", icon: "openai.png", tags: [ModelProviderTags.RequiresApiKey], packages: [ + models.gpt5, models.gpt4o, models.gpt4omini, models.gpt4turbo, diff --git a/packages/llm-info/src/providers/openai.ts b/packages/llm-info/src/providers/openai.ts index a15dd3089e2..82055930869 100644 --- a/packages/llm-info/src/providers/openai.ts +++ b/packages/llm-info/src/providers/openai.ts @@ -75,6 +75,15 @@ export const OpenAi: ModelProvider = { contextLength: 128000, maxCompletionTokens: 4096, }, + // gpt-5 + { + model: "gpt-5", + displayName: "GPT-5", + contextLength: 400000, + maxCompletionTokens: 128000, + regex: /gpt-5/, + recommendedFor: ["chat"], + }, // gpt-4o { model: "gpt-4o", diff --git a/packages/openai-adapters/src/apis/OpenAI.ts b/packages/openai-adapters/src/apis/OpenAI.ts index c1e356fa5c9..714ce67fd34 100644 --- a/packages/openai-adapters/src/apis/OpenAI.ts +++ b/packages/openai-adapters/src/apis/OpenAI.ts @@ -38,7 +38,7 @@ export class OpenAIApi implements BaseLlmApi { // o-series models - only apply for official OpenAI API const isOfficialOpenAIAPI = this.apiBase === "https://api.openai.com/v1/"; if (isOfficialOpenAIAPI) { - if (body.model.startsWith("o")) { + if (body.model.startsWith("o") || body.model.includes("gpt-5")) { // a) use max_completion_tokens instead of max_tokens body.max_completion_tokens = body.max_tokens; body.max_tokens = undefined;