Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions core/llm/llms/OpenAI.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});
16 changes: 8 additions & 8 deletions core/llm/llms/OpenAI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
};
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for adapting requests for specific OpenAI models (O-series and GPT-5) is duplicated in multiple locations. This same logic exists in packages/openai-adapters/src/apis/OpenAI.ts. This violates the DRY (Don't Repeat Yourself) principle and creates a maintenance burden. If the adaptation requirements change or a new model needs similar handling, the changes must be manually synchronized across different packages. This logic should be centralized into a single adapter or middleware that handles all outgoing requests to the OpenAI API, ensuring that model-specific quirks are handled consistently.

Prompt for AI agents
Address the following comment on core/llm/llms/OpenAI.ts at line 142:

<comment>The logic for adapting requests for specific OpenAI models (O-series and GPT-5) is duplicated in multiple locations. This same logic exists in `packages/openai-adapters/src/apis/OpenAI.ts`. This violates the DRY (Don&#39;t Repeat Yourself) principle and creates a maintenance burden. If the adaptation requirements change or a new model needs similar handling, the changes must be manually synchronized across different packages. This logic should be centralized into a single adapter or middleware that handles all outgoing requests to the OpenAI API, ensuring that model-specific quirks are handled consistently.</comment>

<file context>
@@ -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;
</file context>

// 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") {
Expand Down Expand Up @@ -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") {
Expand Down
10 changes: 6 additions & 4 deletions core/llm/toolSupport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,20 @@ export const PROVIDER_TOOL_SUPPORT: Record<string, (model: string) => 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
Expand Down
12 changes: 12 additions & 0 deletions gui/src/pages/AddNewModel/configs/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 3 additions & 2 deletions gui/src/pages/AddNewModel/configs/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ export const providers: Partial<Record<string, ProviderInfo>> = {
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,
Expand Down
9 changes: 9 additions & 0 deletions packages/llm-info/src/providers/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ export const OpenAi: ModelProvider = {
contextLength: 128000,
maxCompletionTokens: 4096,
},
// gpt-5
{
model: "gpt-5",
displayName: "GPT-5",
contextLength: 400000,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are multiple, conflicting sources of truth for model configuration. The context length for 'gpt-5' is defined as 400,000 here, but it is set to 128,000 in gui/src/pages/AddNewModel/configs/models.ts. This inconsistency can lead to unpredictable behavior and bugs, as different parts of the system will operate with different assumptions about the model's capabilities. Architecturally, model metadata should be centralized in a single package (like llm-info) and consumed by other parts of the application (like the GUI) to ensure consistency.

Prompt for AI agents
Address the following comment on packages/llm-info/src/providers/openai.ts at line 82:

<comment>There are multiple, conflicting sources of truth for model configuration. The context length for &#39;gpt-5&#39; is defined as 400,000 here, but it is set to 128,000 in `gui/src/pages/AddNewModel/configs/models.ts`. This inconsistency can lead to unpredictable behavior and bugs, as different parts of the system will operate with different assumptions about the model&#39;s capabilities. Architecturally, model metadata should be centralized in a single package (like `llm-info`) and consumed by other parts of the application (like the GUI) to ensure consistency.</comment>

<file context>
@@ -75,6 +75,15 @@ export const OpenAi: ModelProvider = {
       contextLength: 128000,
       maxCompletionTokens: 4096,
     },
+    // gpt-5
+    {
+      model: &quot;gpt-5&quot;,
+      displayName: &quot;GPT-5&quot;,
+      contextLength: 400000,
+      maxCompletionTokens: 128000,
</file context>

maxCompletionTokens: 128000,
regex: /gpt-5/,
recommendedFor: ["chat"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gpt-4o and gpt-4o-mini model definitions are missing the maxCompletionTokens property. While this property is optional in the LlmInfo interface, it is a critical parameter for large language models, defining the maximum number of tokens the model can generate in a completion. Without this value explicitly set, any part of the application that relies on maxCompletionTokens for these models will either use an incorrect default, infer an incorrect value, or fail to function as expected. This can lead to issues such as truncated responses, increased costs, or runtime errors.

Prompt for AI agents
Address the following comment on packages/llm-info/src/providers/openai.ts at line 85:

<comment>The `gpt-4o` and `gpt-4o-mini` model definitions are missing the `maxCompletionTokens` property. While this property is optional in the `LlmInfo` interface, it is a critical parameter for large language models, defining the maximum number of tokens the model can generate in a completion. Without this value explicitly set, any part of the application that relies on `maxCompletionTokens` for these models will either use an incorrect default, infer an incorrect value, or fail to function as expected. This can lead to issues such as truncated responses, increased costs, or runtime errors.</comment>

<file context>
@@ -75,6 +75,15 @@ export const OpenAi: ModelProvider = {
       contextLength: 128000,
       maxCompletionTokens: 4096,
     },
+    // gpt-5
+    {
+      model: &quot;gpt-5&quot;,
+      displayName: &quot;GPT-5&quot;,
+      contextLength: 400000,
+      maxCompletionTokens: 128000,
</file context>
Suggested change
recommendedFor: ["chat"],
maxCompletionTokens: 4096,

},
// gpt-4o
{
model: "gpt-4o",
Expand Down
2 changes: 1 addition & 1 deletion packages/openai-adapters/src/apis/OpenAI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading