Add GPT5 models (#1698)

* Add GPT5 models

* Refactor BUILTIN_CHAT_MODELS: remove some models

* Fix temperature again
This commit is contained in:
Logan Yang 2025-08-08 09:30:46 -07:00 committed by GitHub
parent 2292a0a6fd
commit 8c532ecbdc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 346 additions and 111 deletions

90
package-lock.json generated
View file

@ -23,7 +23,7 @@
"@langchain/google-genai": "^0.1.6",
"@langchain/groq": "^0.1.2",
"@langchain/mistralai": "^0.2.0",
"@langchain/openai": "^0.5.6",
"@langchain/openai": "^0.6.6",
"@langchain/xai": "^0.0.2",
"@orama/orama": "^3.0.0-rc-2",
"@radix-ui/react-checkbox": "^1.1.3",
@ -4369,9 +4369,9 @@
}
},
"node_modules/@langchain/core": {
"version": "0.3.55",
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.55.tgz",
"integrity": "sha512-SojY2ugpT6t9eYfFB9Ysvyhhyh+KJTGXs50hdHUE9tAEQWp3WAwoxe4djwJnOZ6fSpWYdpFt2UT2ksHVDy2vXA==",
"version": "0.3.68",
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.68.tgz",
"integrity": "sha512-dWPT1h9ObG1TK9uivFTk/pgBULZ6/tBmq8czGUjZjR+1xh9jB4tm/D5FY6o5FklXcEpnAI9peNq2x17Kl9wbMg==",
"license": "MIT",
"dependencies": {
"@cfworker/json-schema": "^4.0.2",
@ -4379,12 +4379,12 @@
"camelcase": "6",
"decamelize": "1.2.0",
"js-tiktoken": "^1.0.12",
"langsmith": "^0.3.16",
"langsmith": "^0.3.46",
"mustache": "^4.2.0",
"p-queue": "^6.6.2",
"p-retry": "4",
"uuid": "^10.0.0",
"zod": "^3.22.4",
"zod": "^3.25.32",
"zod-to-json-schema": "^3.22.3"
},
"engines": {
@ -4417,6 +4417,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@ -4432,6 +4433,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@ -4443,9 +4445,10 @@
}
},
"node_modules/@langchain/core/node_modules/langsmith": {
"version": "0.3.20",
"resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.3.20.tgz",
"integrity": "sha512-zwVQos6tjcksCTfdM67QKq7yyED4GmQiZw/sJ6UCMYZxlvTMMg3PeQ9tOePXAWNWoJygOnH+EwGXr7gYOOETDg==",
"version": "0.3.54",
"resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.3.54.tgz",
"integrity": "sha512-+yMM0pFU172QLq/PIUdaI0Yn+M6CjSSFEQh2R+0B1IvtmVuB72R8if8eLnQ8LdqgvN7jHTjTqJmc/EZVJqv+QA==",
"license": "MIT",
"dependencies": {
"@types/uuid": "^10.0.0",
"chalk": "^4.1.2",
@ -4456,9 +4459,21 @@
"uuid": "^10.0.0"
},
"peerDependencies": {
"@opentelemetry/api": "*",
"@opentelemetry/exporter-trace-otlp-proto": "*",
"@opentelemetry/sdk-trace-base": "*",
"openai": "*"
},
"peerDependenciesMeta": {
"@opentelemetry/api": {
"optional": true
},
"@opentelemetry/exporter-trace-otlp-proto": {
"optional": true
},
"@opentelemetry/sdk-trace-base": {
"optional": true
},
"openai": {
"optional": true
}
@ -4472,6 +4487,7 @@
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
@ -4620,20 +4636,41 @@
}
},
"node_modules/@langchain/openai": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.5.6.tgz",
"integrity": "sha512-zN0iyJthPNmcefIBVybZwcTBgcqu/ElJFov42ZntxEncK4heOMAE9lkq9LQ5CaPU/SgrduibrM1oL57+tLUtaA==",
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.6.6.tgz",
"integrity": "sha512-0fxSg290WTCTEM0PECDGfst2QYUiULKhzyydaOPLMQ5pvWHjJkzBudx+CyHkeQ8DvGXysJteSmZzAMjRCj4duQ==",
"license": "MIT",
"dependencies": {
"js-tiktoken": "^1.0.12",
"openai": "^4.93.0",
"zod": "^3.22.4",
"zod-to-json-schema": "^3.22.3"
"openai": "^5.12.1",
"zod": "^3.25.32"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@langchain/core": ">=0.3.39 <0.4.0"
"@langchain/core": ">=0.3.68 <0.4.0"
}
},
"node_modules/@langchain/openai/node_modules/openai": {
"version": "5.12.1",
"resolved": "https://registry.npmjs.org/openai/-/openai-5.12.1.tgz",
"integrity": "sha512-26s536j4Fi7P3iUma1S9H33WRrw0Qu8pJ2nYJHffrlKHPU0JK4d0r3NcMgqEcAeTdNLGYNyoFsqN4g4YE9vutg==",
"license": "Apache-2.0",
"bin": {
"openai": "bin/cli"
},
"peerDependencies": {
"ws": "^8.18.0",
"zod": "^3.23.8"
},
"peerDependenciesMeta": {
"ws": {
"optional": true
},
"zod": {
"optional": true
}
}
},
"node_modules/@langchain/textsplitters": {
@ -10719,9 +10756,10 @@
"dev": true
},
"node_modules/console-table-printer": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.12.1.tgz",
"integrity": "sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==",
"version": "2.14.6",
"resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.14.6.tgz",
"integrity": "sha512-MCBl5HNVaFuuHW6FGbL/4fB7N/ormCy+tQ+sxTrF6QtSbSNETvPuOVbkJBhzDgYhvjWGrTma4eYJa37ZuoQsPw==",
"license": "MIT",
"dependencies": {
"simple-wcswidth": "^1.0.1"
}
@ -19885,9 +19923,10 @@
"peer": true
},
"node_modules/simple-wcswidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.0.1.tgz",
"integrity": "sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz",
"integrity": "sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==",
"license": "MIT"
},
"node_modules/sisteransi": {
"version": "1.0.5",
@ -21679,9 +21718,10 @@
}
},
"node_modules/zod": {
"version": "3.24.3",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz",
"integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==",
"version": "3.25.76",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}

View file

@ -90,7 +90,7 @@
"@langchain/google-genai": "^0.1.6",
"@langchain/groq": "^0.1.2",
"@langchain/mistralai": "^0.2.0",
"@langchain/openai": "^0.5.6",
"@langchain/openai": "^0.6.6",
"@langchain/xai": "^0.0.2",
"@orama/orama": "^3.0.0-rc-2",
"@radix-ui/react-checkbox": "^1.1.3",

View file

@ -8,7 +8,13 @@ import {
import { getDecryptedKey } from "@/encryptionService";
import { logError, logInfo } from "@/logger";
import { getModelKeyFromModel, getSettings, subscribeToSettingsChange } from "@/settings/model";
import { err2String, isOSeriesModel, safeFetch, withSuppressedTokenWarnings } from "@/utils";
import {
err2String,
getModelInfo,
ModelInfo,
safeFetch,
withSuppressedTokenWarnings,
} from "@/utils";
import { HarmBlockThreshold, HarmCategory } from "@google/generative-ai";
import { ChatAnthropic } from "@langchain/anthropic";
import { ChatCohere } from "@langchain/cohere";
@ -89,43 +95,65 @@ export default class ChatModelManager {
return ChatModelManager.instance;
}
private static readonly REASONING_MODEL_TEMPERATURE = 1;
/**
* Determines the appropriate temperature for a model
* @returns temperature value or undefined if temperature should not be set
*/
private getTemperatureForModel(
modelInfo: ModelInfo,
customModel: CustomModel,
settings: any
): number | undefined {
// Thinking-enabled models don't accept temperature
if (modelInfo.isThinkingEnabled) {
return undefined;
}
// O-series and GPT-5 models require temperature = 1
if (modelInfo.isOSeries || modelInfo.isGPT5) {
return ChatModelManager.REASONING_MODEL_TEMPERATURE;
}
// All other models use configured temperature
return customModel.temperature ?? settings.temperature;
}
private async getModelConfig(customModel: CustomModel): Promise<ModelConfig> {
const settings = getSettings();
const modelName = customModel.name;
const isOSeries = isOSeriesModel(modelName);
const isThinkingEnabled =
modelName.startsWith("claude-3-7-sonnet") || modelName.startsWith("claude-sonnet-4");
const modelInfo = getModelInfo(modelName);
const { isThinkingEnabled } = modelInfo;
// Base config without temperature when thinking is enabled
const baseConfig: Omit<ModelConfig, "maxTokens" | "maxCompletionTokens" | "temperature"> = {
// Base config - temperature will be handled by provider-specific methods
const baseConfig: Omit<ModelConfig, "maxTokens" | "maxCompletionTokens"> = {
modelName: modelName,
streaming: customModel.stream ?? true,
maxRetries: 3,
maxConcurrency: 3,
enableCors: customModel.enableCors,
// Add temperature for normal models (will be overridden by special configs if needed)
...(!isThinkingEnabled && { temperature: customModel.temperature ?? settings.temperature }),
};
// Add temperature only if thinking is not enabled
if (!isThinkingEnabled) {
(baseConfig as any).temperature = customModel.temperature ?? settings.temperature;
}
const providerConfig: {
[K in keyof ChatProviderConstructMap]: ConstructorParameters<ChatProviderConstructMap[K]>[0];
} = {
[ChatModelProviders.OPENAI]: {
modelName: modelName,
openAIApiKey: await getDecryptedKey(customModel.apiKey || settings.openAIApiKey),
apiKey: await getDecryptedKey(customModel.apiKey || settings.openAIApiKey),
configuration: {
baseURL: customModel.baseUrl,
fetch: customModel.enableCors ? safeFetch : undefined,
organization: await getDecryptedKey(customModel.openAIOrgId || settings.openAIOrgId),
},
...this.handleOpenAIExtraArgs(
isOSeries,
...this.getOpenAISpecialConfig(
modelName,
customModel.maxTokens ?? settings.maxTokens,
customModel.temperature ?? settings.temperature
customModel.temperature ?? settings.temperature,
customModel
),
},
[ChatModelProviders.ANTHROPIC]: {
@ -146,7 +174,7 @@ export default class ChatModelManager {
[ChatModelProviders.AZURE_OPENAI]: {
modelName:
customModel.azureOpenAIApiDeploymentName || settings.azureOpenAIApiDeploymentName,
openAIApiKey: await getDecryptedKey(customModel.apiKey || settings.azureOpenAIApiKey),
apiKey: await getDecryptedKey(customModel.apiKey || settings.azureOpenAIApiKey),
configuration: {
baseURL:
customModel.baseUrl ||
@ -160,10 +188,11 @@ export default class ChatModelManager {
},
fetch: customModel.enableCors ? safeFetch : undefined,
},
...this.handleOpenAIExtraArgs(
isOSeries,
...this.getOpenAISpecialConfig(
modelName,
customModel.maxTokens ?? settings.maxTokens,
customModel.temperature ?? settings.temperature
customModel.temperature ?? settings.temperature,
customModel
),
},
[ChatModelProviders.COHEREAI]: {
@ -200,7 +229,7 @@ export default class ChatModelManager {
},
[ChatModelProviders.OPENROUTERAI]: {
modelName: modelName,
openAIApiKey: await getDecryptedKey(customModel.apiKey || settings.openRouterAiApiKey),
apiKey: await getDecryptedKey(customModel.apiKey || settings.openRouterAiApiKey),
configuration: {
baseURL: customModel.baseUrl || "https://openrouter.ai/api/v1",
fetch: customModel.enableCors ? safeFetch : undefined,
@ -225,7 +254,7 @@ export default class ChatModelManager {
},
[ChatModelProviders.LM_STUDIO]: {
modelName: modelName,
openAIApiKey: customModel.apiKey || "default-key",
apiKey: customModel.apiKey || "default-key",
configuration: {
baseURL: customModel.baseUrl || "http://localhost:1234/v1",
fetch: customModel.enableCors ? safeFetch : undefined,
@ -233,21 +262,22 @@ export default class ChatModelManager {
},
[ChatModelProviders.OPENAI_FORMAT]: {
modelName: modelName,
openAIApiKey: await getDecryptedKey(customModel.apiKey || settings.openAIApiKey),
apiKey: await getDecryptedKey(customModel.apiKey || settings.openAIApiKey),
configuration: {
baseURL: customModel.baseUrl,
fetch: customModel.enableCors ? safeFetch : undefined,
defaultHeaders: { "dangerously-allow-browser": "true" },
},
...this.handleOpenAIExtraArgs(
isOSeries,
...this.getOpenAISpecialConfig(
modelName,
customModel.maxTokens ?? settings.maxTokens,
customModel.temperature ?? settings.temperature
customModel.temperature ?? settings.temperature,
customModel
),
},
[ChatModelProviders.COPILOT_PLUS]: {
modelName: modelName,
openAIApiKey: await getDecryptedKey(settings.plusLicenseKey),
apiKey: await getDecryptedKey(settings.plusLicenseKey),
configuration: {
baseURL: BREVILABS_API_BASE_URL,
fetch: customModel.enableCors ? safeFetch : undefined,
@ -277,15 +307,14 @@ export default class ChatModelManager {
customModel
);
// LangChain 0.6.6 handles token configuration for special models internally
const tokenConfig = isThinkingEnabled
? {
maxTokens: customModel.maxTokens ?? settings.maxTokens,
}
: this.handleOpenAIExtraArgs(
isOSeries,
customModel.maxTokens ?? settings.maxTokens,
customModel.temperature ?? settings.temperature
);
: {
maxTokens: customModel.maxTokens ?? settings.maxTokens,
};
const finalConfig = {
...baseConfig,
@ -294,28 +323,47 @@ export default class ChatModelManager {
...tokenConfig,
};
// Final safety check to ensure no temperature when thinking is enabled
if (isThinkingEnabled) {
delete finalConfig.temperature;
}
return finalConfig as ModelConfig;
}
private handleOpenAIExtraArgs(
isOSeriesModel: boolean,
/**
* Adds special configuration for OpenAI models that support reasoning
* LangChain 0.6.6+ handles most of the token/temperature logic internally
*/
private getOpenAISpecialConfig(
modelName: string,
maxTokens: number,
temperature: number | undefined
_temperature: number | undefined,
customModel?: CustomModel
) {
const config = isOSeriesModel
? {
maxCompletionTokens: maxTokens,
temperature: temperature === undefined ? undefined : 1,
}
: {
maxTokens: maxTokens,
temperature: temperature,
};
const settings = getSettings();
const modelInfo = getModelInfo(modelName);
const resolvedTemperature = this.getTemperatureForModel(
modelInfo,
customModel || ({} as CustomModel),
settings
);
const config: any = {
maxTokens,
temperature: resolvedTemperature,
};
// Add reasoning parameters for O-series and GPT-5 models
// LangChain 0.6.6 will handle the endpoint routing and parameter conversion
if (modelInfo.isOSeries || modelInfo.isGPT5) {
config.reasoning = {
effort: customModel?.reasoningEffort || settings.reasoningEffort || "low",
};
// Add verbosity for GPT-5 models (when API supports it)
if (modelInfo.isGPT5) {
const verbosityValue = customModel?.verbosity || settings.verbosity || "medium";
config.verbosity = verbosityValue;
config.modelKwargs = { verbosity: verbosityValue };
}
}
return config;
}
@ -504,8 +552,8 @@ export default class ChatModelManager {
const modelConfig = await this.getModelConfig(modelToTest);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { streaming, maxTokens, maxCompletionTokens, ...pingConfig } = modelConfig;
const isOSeries = isOSeriesModel(modelToTest.name);
const tokenConfig = this.handleOpenAIExtraArgs(isOSeries, 30, modelConfig.temperature);
// For ping, just use minimal config
const tokenConfig = { maxTokens: 30 };
const testModel = new (this.getProviderConstructor(modelToTest))({
...pingConfig,
...tokenConfig,

View file

@ -124,6 +124,10 @@ export interface CustomModel {
azureOpenAIApiDeploymentName?: string;
azureOpenAIApiVersion?: string;
azureOpenAIApiEmbeddingDeploymentName?: string;
// OpenAI GPT-5 and O-series specific fields
reasoningEffort?: "minimal" | "low" | "medium" | "high";
verbosity?: "low" | "medium" | "high";
}
export function setModelKey(modelKey: string) {

View file

@ -122,6 +122,9 @@ export const DEFAULT_MODEL_SETTING = {
export enum ChatModels {
COPILOT_PLUS_FLASH = "copilot-plus-flash",
GPT_5 = "gpt-5",
GPT_5_mini = "gpt-5-mini",
GPT_5_nano = "gpt-5-nano",
GPT_41 = "gpt-4.1",
GPT_41_mini = "gpt-4.1-mini",
GPT_41_nano = "gpt-4.1-nano",
@ -216,6 +219,30 @@ export const BUILTIN_CHAT_MODELS: CustomModel[] = [
projectEnabled: true,
capabilities: [ModelCapability.VISION],
},
{
name: ChatModels.GPT_5,
provider: ChatModelProviders.OPENAI,
enabled: true,
isBuiltIn: true,
core: true,
capabilities: [ModelCapability.VISION],
},
{
name: ChatModels.GPT_5_mini,
provider: ChatModelProviders.OPENAI,
enabled: true,
isBuiltIn: true,
core: true,
capabilities: [ModelCapability.VISION],
},
{
name: ChatModels.GPT_5_nano,
provider: ChatModelProviders.OPENAI,
enabled: true,
isBuiltIn: true,
core: true,
capabilities: [ModelCapability.VISION],
},
{
name: ChatModels.GPT_41,
provider: ChatModelProviders.OPENAI,
@ -239,17 +266,8 @@ export const BUILTIN_CHAT_MODELS: CustomModel[] = [
provider: ChatModelProviders.OPENAI,
enabled: true,
isBuiltIn: true,
core: true,
capabilities: [ModelCapability.VISION],
},
{
name: ChatModels.O4_mini,
provider: ChatModelProviders.OPENAI,
enabled: true,
isBuiltIn: true,
core: true,
capabilities: [ModelCapability.REASONING],
},
{
name: ChatModels.CLAUDE_4_SONNET,
provider: ChatModelProviders.ANTHROPIC,
@ -264,20 +282,6 @@ export const BUILTIN_CHAT_MODELS: CustomModel[] = [
isBuiltIn: true,
capabilities: [ModelCapability.VISION, ModelCapability.REASONING],
},
{
name: ChatModels.CLAUDE_3_5_SONNET,
provider: ChatModelProviders.ANTHROPIC,
enabled: true,
isBuiltIn: true,
core: true,
capabilities: [ModelCapability.VISION],
},
{
name: ChatModels.CLAUDE_3_5_HAIKU,
provider: ChatModelProviders.ANTHROPIC,
enabled: true,
isBuiltIn: true,
},
{
name: ChatModels.GROK3,
provider: ChatModelProviders.XAI,
@ -314,18 +318,6 @@ export const BUILTIN_CHAT_MODELS: CustomModel[] = [
projectEnabled: true,
capabilities: [ModelCapability.VISION],
},
{
name: ChatModels.COMMAND_R,
provider: ChatModelProviders.COHEREAI,
enabled: true,
isBuiltIn: true,
},
{
name: ChatModels.COMMAND_R_PLUS,
provider: ChatModelProviders.COHEREAI,
enabled: true,
isBuiltIn: true,
},
{
name: ChatModels.AZURE_OPENAI,
provider: ChatModelProviders.AZURE_OPENAI,
@ -733,6 +725,8 @@ export const DEFAULT_SETTINGS: CopilotSettings = {
"writeToFile",
"replaceInFile",
],
reasoningEffort: "low",
verbosity: "medium",
};
export const EVENT_NAMES = {

View file

@ -114,6 +114,10 @@ export interface CopilotSettings {
suggestedDefaultCommands: boolean;
autonomousAgentMaxIterations: number;
autonomousAgentEnabledToolIds: string[];
/** Default reasoning effort for models that support it (GPT-5, O-series, etc.) */
reasoningEffort: "minimal" | "low" | "medium" | "high";
/** Default verbosity level for models that support it */
verbosity: "low" | "medium" | "high";
}
export const settingsStore = createStore();

View file

@ -4,6 +4,13 @@ import { FormField } from "@/components/ui/form-field";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { PasswordInput } from "@/components/ui/password-input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { SettingSlider } from "@/components/ui/setting-slider";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import {
@ -372,6 +379,106 @@ export const ModelEditModalContent: React.FC<ModelEditModalContentProps> = ({
step={0.05}
/>
</FormField>
{/* Reasoning Effort and Verbosity for GPT-5 and O-series models */}
{localModel.provider === "openai" &&
(localModel.name.startsWith("gpt-5") ||
localModel.name.startsWith("o1") ||
localModel.name.startsWith("o3") ||
localModel.name.startsWith("o4")) && (
<>
<FormField
label={
<div className="tw-flex tw-items-center tw-gap-2">
Reasoning Effort
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<HelpCircle className="tw-size-4 tw-text-muted" />
</TooltipTrigger>
<TooltipContent side="bottom">
<div className="tw-w-[300px]">
<p>
Controls the amount of reasoning effort the model uses. Higher
effort provides more thorough reasoning but takes longer. Note:
thinking tokens are not available yet!
</p>
<ul className="tw-mt-2 tw-space-y-1 tw-text-xs">
<li>
Minimal: Fastest responses, minimal reasoning (GPT-5 only)
</li>
<li>Low: Faster responses, basic reasoning (default)</li>
<li>Medium: Balanced performance</li>
<li>High: Thorough reasoning, slower responses</li>
</ul>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
}
>
<Select
value={localModel.reasoningEffort || settings.reasoningEffort || "low"}
onValueChange={(value) => handleLocalUpdate("reasoningEffort", value)}
>
<SelectTrigger className="tw-w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
{localModel.name.startsWith("gpt-5") && (
<SelectItem value="minimal">Minimal</SelectItem>
)}
<SelectItem value="low">Low</SelectItem>
<SelectItem value="medium">Medium</SelectItem>
<SelectItem value="high">High</SelectItem>
</SelectContent>
</Select>
</FormField>
{/* Verbosity only for GPT-5 models */}
{localModel.name.startsWith("gpt-5") && (
<FormField
label={
<div className="tw-flex tw-items-center tw-gap-2">
Verbosity
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<HelpCircle className="tw-size-4 tw-text-muted" />
</TooltipTrigger>
<TooltipContent side="bottom">
<div className="tw-w-[300px]">
<p>Controls the length and detail of the model responses.</p>
<ul className="tw-mt-2 tw-space-y-1 tw-text-xs">
<li>Low: Concise, brief responses</li>
<li>Medium: Balanced detail</li>
<li>High: Detailed, comprehensive responses</li>
</ul>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
}
>
<Select
value={localModel.verbosity || settings.verbosity || "medium"}
onValueChange={(value) => handleLocalUpdate("verbosity", value)}
>
<SelectTrigger className="tw-w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">Low</SelectItem>
<SelectItem value="medium">Medium</SelectItem>
<SelectItem value="high">High</SelectItem>
</SelectContent>
</Select>
</FormField>
)}
</>
)}
</>
)}
</div>

View file

@ -784,6 +784,8 @@ export async function checkLatestVersion(): Promise<{
}
}
// Note: LangChain 0.6.6+ handles O-series and GPT-5 models automatically
// These functions are kept for backward compatibility and specific checks
export function isOSeriesModel(model: BaseChatModel | string): boolean {
if (typeof model === "string") {
return model.startsWith("o1") || model.startsWith("o3") || model.startsWith("o4");
@ -794,6 +796,42 @@ export function isOSeriesModel(model: BaseChatModel | string): boolean {
return modelName.startsWith("o1") || modelName.startsWith("o3") || modelName.startsWith("o4");
}
export function isGPT5Model(model: BaseChatModel | string): boolean {
if (typeof model === "string") {
return model.startsWith("gpt-5");
}
// For BaseChatModel instances
const modelName = (model as any).modelName || (model as any).model || "";
return modelName.startsWith("gpt-5");
}
/**
* Utility for determining model characteristics
* Note: Most of this is handled by LangChain 0.6.6+ internally
*/
export interface ModelInfo {
isOSeries: boolean;
isGPT5: boolean;
isThinkingEnabled: boolean;
}
export function getModelInfo(model: BaseChatModel | string): ModelInfo {
const modelName =
typeof model === "string" ? model : (model as any).modelName || (model as any).model || "";
const isOSeries = isOSeriesModel(modelName);
const isGPT5 = isGPT5Model(modelName);
const isThinkingEnabled =
modelName.startsWith("claude-3-7-sonnet") || modelName.startsWith("claude-sonnet-4");
return {
isOSeries,
isGPT5,
isThinkingEnabled,
};
}
export function getMessageRole(
model: BaseChatModel | string,
defaultRole: "system" | "human" = "system"