mirror of
https://github.com/logancyang/obsidian-copilot.git
synced 2026-07-22 07:50:24 +00:00
Add GPT5 models (#1698)
* Add GPT5 models * Refactor BUILTIN_CHAT_MODELS: remove some models * Fix temperature again
This commit is contained in:
parent
2292a0a6fd
commit
8c532ecbdc
8 changed files with 346 additions and 111 deletions
90
package-lock.json
generated
90
package-lock.json
generated
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
38
src/utils.ts
38
src/utils.ts
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in a new issue