From e0aa270328bf0e35d4900c47e34e8073b0b7e71d Mon Sep 17 00:00:00 2001 From: leokun Date: Fri, 10 Jul 2026 11:38:45 +0800 Subject: [PATCH] feat: gpt-5.6 support --- build/config.yml | 2 +- frontend/src/components/ModelAdapterModal.vue | 1 + frontend/src/i18n/generated/catalog.json | 41 +++++++++++++------ frontend/src/i18n/locales/en-US.json | 3 +- frontend/src/i18n/locales/ja-JP.json | 3 +- frontend/src/i18n/locales/zh-CN.json | 3 +- frontend/src/state/appState.js | 4 +- frontend/src/views/ModelEditor.vue | 1 + internal/backend/agent/model/openai.go | 26 ++++++++---- internal/backend/server/config/types.go | 4 +- internal/backend/server/upstream/mocks.go | 4 +- internal/client/model_adapter_benchmark.go | 2 +- internal/runtime/local_runtime.go | 4 +- prompt/common_prefix.md | 4 +- release-notes.md | 5 ++- 15 files changed, 70 insertions(+), 37 deletions(-) diff --git a/build/config.yml b/build/config.yml index ce9c027..47e43d8 100644 --- a/build/config.yml +++ b/build/config.yml @@ -8,7 +8,7 @@ info: description: "Cursor助手" copyright: "© 2026, Cursor助手" comments: "Cursor助手" - version: "0.0.39" + version: "0.0.40" dev_mode: root_path: . diff --git a/frontend/src/components/ModelAdapterModal.vue b/frontend/src/components/ModelAdapterModal.vue index e1c697e..c2f5eae 100644 --- a/frontend/src/components/ModelAdapterModal.vue +++ b/frontend/src/components/ModelAdapterModal.vue @@ -23,6 +23,7 @@ const reasoningEffortOptions = [ { label: "中", value: "medium", icon: "icon-[mdi--head-lightbulb-outline]" }, { label: "高", value: "high", icon: "icon-[mdi--brain]" }, { label: "极高", value: "xhigh", icon: "icon-[mdi--head-cog-outline]" }, + { label: "最高", value: "max", icon: "icon-[mdi--brain]" }, ]; const anthropicThinkingEffortOptions = [ diff --git a/frontend/src/i18n/generated/catalog.json b/frontend/src/i18n/generated/catalog.json index 2f6cbc3..af168af 100644 --- a/frontend/src/i18n/generated/catalog.json +++ b/frontend/src/i18n/generated/catalog.json @@ -274,18 +274,6 @@ } ] }, - "1b7d24b212e52c54": { - "source": "{0} 的推理强度仅支持 low、medium、high、xhigh", - "kind": "template", - "placeholders": 1, - "refs": [ - { - "file": "src/state/appState.js", - "line": 315, - "column": 14 - } - ] - }, "1bc77f5ab979f4c1": { "source": "新增模型配置", "kind": "text", @@ -1175,6 +1163,23 @@ } ] }, + "8672864e90417138": { + "source": "最高", + "kind": "text", + "placeholders": 0, + "refs": [ + { + "file": "src/components/ModelAdapterModal.vue", + "line": 26, + "column": 12 + }, + { + "file": "src/views/ModelEditor.vue", + "line": 41, + "column": 12 + } + ] + }, "86df7ec743047234": { "source": "服务运行中", "kind": "text", @@ -2110,6 +2115,18 @@ } ] }, + "dbb4b5be9b5723dc": { + "source": "{0} 的推理强度仅支持 low、medium、high、xhigh、max", + "kind": "template", + "placeholders": 1, + "refs": [ + { + "file": "src/state/appState.js", + "line": 435, + "column": 14 + } + ] + }, "dbee6e7139243362": { "source": "{0} 的接口地址不能为空", "kind": "template", diff --git a/frontend/src/i18n/locales/en-US.json b/frontend/src/i18n/locales/en-US.json index c19286d..c9af884 100644 --- a/frontend/src/i18n/locales/en-US.json +++ b/frontend/src/i18n/locales/en-US.json @@ -21,7 +21,6 @@ "15d124b200ddabed": "Maximum number of context tokens the model can accept in a single request. Leave blank to use the default.", "18b7312022cd1840": "Start Service", "1af38868896cf53d": "Routing mode only supports local or upstream", - "1b7d24b212e52c54": "{0} reasoning effort only supports low, medium, high, and xhigh", "1bc77f5ab979f4c1": "Add Model Settings", "1e238093b79b3165": "Uses 65536 by default when left blank", "24343a2096988d42": "Failed to open", @@ -84,6 +83,7 @@ "7e9e334aeb0bdc07": "Service operation failed", "7f68ebad19ba6bcd": "Check for Updates", "81123c56d5d880d0": "API Key", + "8672864e90417138": "Max", "86df7ec743047234": "Service running", "87ed126f7bd1121e": "Routing Mode", "899add6275682210": "Uses 200000 by default when left blank", @@ -154,6 +154,7 @@ "d7da2aabd35772ec": "e.g. 200000 (leave blank to use the default)", "da590a8fe3ce4de0": "Please select", "daede9881787abe7": "Notes", + "dbb4b5be9b5723dc": "{0} reasoning effort only supports low, medium, high, xhigh, and max", "dbee6e7139243362": "{0} base URL cannot be empty", "dc82c5e8fb2ab777": "Version: v{0}", "de8184da1ef88d03": "Configured", diff --git a/frontend/src/i18n/locales/ja-JP.json b/frontend/src/i18n/locales/ja-JP.json index 9e29776..d4eb405 100644 --- a/frontend/src/i18n/locales/ja-JP.json +++ b/frontend/src/i18n/locales/ja-JP.json @@ -21,7 +21,6 @@ "15d124b200ddabed": "モデルが1回のリクエストで受け取れる最大コンテキスト Token 数。空欄の場合はデフォルト値を使用します。", "18b7312022cd1840": "サービスを開始", "1af38868896cf53d": "ルーティングモードは local または upstream のみサポートします", - "1b7d24b212e52c54": "{0} の推論強度は low、medium、high、xhigh のみサポートします", "1bc77f5ab979f4c1": "モデル設定を追加", "1e238093b79b3165": "空欄で 65536", "24343a2096988d42": "開けませんでした", @@ -84,6 +83,7 @@ "7e9e334aeb0bdc07": "サービス操作に失敗しました", "7f68ebad19ba6bcd": "アップデートを確認", "81123c56d5d880d0": "API キー", + "8672864e90417138": "最大", "86df7ec743047234": "サービス稼働中", "87ed126f7bd1121e": "ルーティングモード", "899add6275682210": "空欄で 200000", @@ -154,6 +154,7 @@ "d7da2aabd35772ec": "例: 200000(空欄でデフォルト値)", "da590a8fe3ce4de0": "選択してください", "daede9881787abe7": "メモ", + "dbb4b5be9b5723dc": "{0} の推論強度は low、medium、high、xhigh、max のみサポートします", "dbee6e7139243362": "{0} のベース URL は必須です", "dc82c5e8fb2ab777": "バージョン: v{0}", "de8184da1ef88d03": "設定済み", diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index 2532428..786b8d2 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -21,7 +21,6 @@ "15d124b200ddabed": "模型单次可接受的最大上下文 Token 数。留空时使用默认值。", "18b7312022cd1840": "启动服务", "1af38868896cf53d": "运行模式仅支持 local 或 upstream", - "1b7d24b212e52c54": "{0} 的推理强度仅支持 low、medium、high、xhigh", "1bc77f5ab979f4c1": "新增模型配置", "1e238093b79b3165": "留空时默认 65536", "24343a2096988d42": "打开失败", @@ -84,6 +83,7 @@ "7e9e334aeb0bdc07": "服务操作失败", "7f68ebad19ba6bcd": "检查更新", "81123c56d5d880d0": "访问密钥", + "8672864e90417138": "最高", "86df7ec743047234": "服务运行中", "87ed126f7bd1121e": "运行模式", "899add6275682210": "留空时默认 200000", @@ -154,6 +154,7 @@ "d7da2aabd35772ec": "例如:200000(留空用默认值)", "da590a8fe3ce4de0": "请选择", "daede9881787abe7": "备注", + "dbb4b5be9b5723dc": "{0} 的推理强度仅支持 low、medium、high、xhigh、max", "dbee6e7139243362": "{0} 的接口地址不能为空", "dc82c5e8fb2ab777": "版本:v{0}", "de8184da1ef88d03": "已配置", diff --git a/frontend/src/state/appState.js b/frontend/src/state/appState.js index 858ec96..a6615bc 100644 --- a/frontend/src/state/appState.js +++ b/frontend/src/state/appState.js @@ -22,7 +22,7 @@ import { const APP_STATE_STORAGE_KEY = "cursor-client:runtime-state:v2"; const GENERIC_SERVICE_ERROR = "服务错误"; const SUPPORTED_MODEL_ADAPTER_TYPES = new Set(["openai", "anthropic"]); -const SUPPORTED_REASONING_EFFORTS = new Set(["low", "medium", "high", "xhigh"]); +const SUPPORTED_REASONING_EFFORTS = new Set(["low", "medium", "high", "xhigh", "max"]); const SUPPORTED_ANTHROPIC_THINKING_EFFORTS = new Set(["low", "medium", "high", "xhigh", "max"]); export const ANTHROPIC_THINKING_EFFORT_DEFAULT = "xhigh"; export const OPENAI_ENDPOINT_RESPONSES = "/v1/responses"; @@ -432,7 +432,7 @@ export function validateModelAdapters(source) { return `${prefix} 的模型标识不能为空`; } if (adapter.type === "openai" && !SUPPORTED_REASONING_EFFORTS.has(adapter.reasoningEffort)) { - return `${prefix} 的推理强度仅支持 low、medium、high、xhigh`; + return `${prefix} 的推理强度仅支持 low、medium、high、xhigh、max`; } if (adapter.type === "openai" && !isValidOpenAIEndpoint(adapter.openAIEndpoint)) { return `${prefix} 的 OpenAI 端点仅支持 /v1/responses、/v1/chat/completions 或以 / 开头的自定义路径`; diff --git a/frontend/src/views/ModelEditor.vue b/frontend/src/views/ModelEditor.vue index e373b75..8ca2098 100644 --- a/frontend/src/views/ModelEditor.vue +++ b/frontend/src/views/ModelEditor.vue @@ -38,6 +38,7 @@ const reasoningEffortOptions = [ { label: "中", value: "medium", icon: "icon-[mdi--head-lightbulb-outline]" }, { label: "高", value: "high", icon: "icon-[mdi--brain]" }, { label: "极高", value: "xhigh", icon: "icon-[mdi--head-cog-outline]" }, + { label: "最高", value: "max", icon: "icon-[mdi--brain]" }, ]; const anthropicThinkingEffortOptions = [ diff --git a/internal/backend/agent/model/openai.go b/internal/backend/agent/model/openai.go index 4012831..f2c5903 100644 --- a/internal/backend/agent/model/openai.go +++ b/internal/backend/agent/model/openai.go @@ -29,7 +29,7 @@ type openAIRequestBody struct { Tools []json.RawMessage `json:"tools,omitempty"` Messages []map[string]any `json:"messages"` Stream bool `json:"stream"` - MaxTokens int `json:"max_tokens"` + MaxTokens int `json:"max_tokens,omitempty"` StreamOptions map[string]any `json:"stream_options"` ReasoningEffort string `json:"reasoning_effort,omitempty"` PromptCacheKey string `json:"prompt_cache_key,omitempty"` @@ -41,7 +41,7 @@ type openAIResponsesRequestBody struct { Input []map[string]any `json:"input"` Tools []map[string]any `json:"tools,omitempty"` Stream bool `json:"stream"` - MaxOutputTokens int `json:"max_output_tokens"` + MaxOutputTokens int `json:"max_output_tokens,omitempty"` Reasoning *openAIResponsesReasoning `json:"reasoning,omitempty"` Include []string `json:"include,omitempty"` PromptCacheKey string `json:"prompt_cache_key,omitempty"` @@ -455,9 +455,11 @@ func (adapter *OpenAIAdapter) streamChatCompletions(ctx context.Context, req Str Model: modelID, Messages: normalizedMessages, Stream: true, - MaxTokens: req.MaxTokens, StreamOptions: map[string]any{"include_usage": true}, } + if shouldSendOpenAIMaxOutputTokens(modelID) { + requestBody.MaxTokens = req.MaxTokens + } if key := openAIPromptCacheKey(req, modelID); key != "" { requestBody.PromptCacheKey = key } @@ -914,12 +916,14 @@ func (adapter *OpenAIAdapter) streamResponses(ctx context.Context, req StreamReq return err } requestBody := openAIResponsesRequestBody{ - Model: modelID, - Instructions: instructions, - Input: input, - Stream: true, - MaxOutputTokens: req.MaxTokens, - Store: false, + Model: modelID, + Instructions: instructions, + Input: input, + Stream: true, + Store: false, + } + if shouldSendOpenAIMaxOutputTokens(modelID) { + requestBody.MaxOutputTokens = req.MaxTokens } if key := openAIPromptCacheKey(req, modelID); key != "" { requestBody.PromptCacheKey = key @@ -1844,6 +1848,10 @@ func normalizeOpenAIProviderMessages(messages []Message, thinkingEnabled bool) ( return items, nil } +func shouldSendOpenAIMaxOutputTokens(modelID string) bool { + return !strings.Contains(strings.ToLower(strings.TrimSpace(modelID)), "gpt") +} + func shouldIncludeOpenAIReasoningContent(message Message, thinkingEnabled bool) bool { if strings.TrimSpace(message.ReasoningContent) != "" { return true diff --git a/internal/backend/server/config/types.go b/internal/backend/server/config/types.go index f2c192a..ada93b3 100644 --- a/internal/backend/server/config/types.go +++ b/internal/backend/server/config/types.go @@ -152,7 +152,7 @@ func NormalizeModelAdapterConfigs(input []ModelAdapterConfig) ([]ModelAdapterCon case next.ModelID == "": return nil, errors.New("模型适配器 modelID 不能为空") case next.Type == "openai" && next.ReasoningEffort == "": - return nil, errors.New("模型适配器 reasoningEffort 仅支持 low、medium、high、xhigh") + return nil, errors.New("模型适配器 reasoningEffort 仅支持 low、medium、high、xhigh、max") case next.Type == "openai" && next.OpenAIEndpoint == "": return nil, errors.New("模型适配器 openAIEndpoint 仅支持 /v1/responses、/v1/chat/completions 或 /custom(自定义路径)") case next.Type == "openai" && next.OpenAIExtraParamsEnabled: @@ -216,7 +216,7 @@ func normalizeReasoningEffort(value string) string { switch strings.ToLower(strings.TrimSpace(value)) { case "", "medium": return "medium" - case "low", "high", "xhigh": + case "low", "high", "xhigh", "max": return strings.ToLower(strings.TrimSpace(value)) default: return "" diff --git a/internal/backend/server/upstream/mocks.go b/internal/backend/server/upstream/mocks.go index ae87a52..c33dcfc 100644 --- a/internal/backend/server/upstream/mocks.go +++ b/internal/backend/server/upstream/mocks.go @@ -746,7 +746,7 @@ func buildThinkingEffortVariantDisplayName(modelDisplayName string, effortValue func thinkingEffortValuesForAdapter(adapterType string) []string { values := []string{"disabled", "low", "medium", "high", "xhigh"} - if strings.EqualFold(strings.TrimSpace(adapterType), "anthropic") { + if adapterType := strings.ToLower(strings.TrimSpace(adapterType)); adapterType == "openai" || adapterType == "anthropic" { values = append(values, "max") } return values @@ -773,7 +773,7 @@ func defaultThinkingEffortForAdapter(adapter legacyruntime.ModelAdapterConfig) s if strings.EqualFold(strings.TrimSpace(adapter.Type), "anthropic") { return normalizeAvailableModelThinkingEffort(adapter.AnthropicThinkingEffort, true, "xhigh") } - return normalizeAvailableModelThinkingEffort(adapter.ReasoningEffort, false, "medium") + return normalizeAvailableModelThinkingEffort(adapter.ReasoningEffort, true, "medium") } func normalizeAvailableModelThinkingEffort(raw string, allowMax bool, fallback string) string { diff --git a/internal/client/model_adapter_benchmark.go b/internal/client/model_adapter_benchmark.go index a81ad62..bc6e4bb 100644 --- a/internal/client/model_adapter_benchmark.go +++ b/internal/client/model_adapter_benchmark.go @@ -668,7 +668,7 @@ func normalizeModelAdapterTestType(value string) string { func normalizeModelAdapterTestReasoning(value string) string { switch strings.ToLower(strings.TrimSpace(value)) { - case "low", "medium", "high", "xhigh": + case "low", "medium", "high", "xhigh", "max": return strings.ToLower(strings.TrimSpace(value)) default: return "medium" diff --git a/internal/runtime/local_runtime.go b/internal/runtime/local_runtime.go index 7076c32..4d5dd1b 100644 --- a/internal/runtime/local_runtime.go +++ b/internal/runtime/local_runtime.go @@ -138,7 +138,7 @@ func NormalizeModelAdapterConfigs(input []ModelAdapterConfig) ([]ModelAdapterCon case next.ModelID == "": return nil, errors.New("模型适配器 modelID 不能为空") case next.Type == "openai" && next.ReasoningEffort == "": - return nil, errors.New("模型适配器 reasoningEffort 仅支持 low、medium、high、xhigh") + return nil, errors.New("模型适配器 reasoningEffort 仅支持 low、medium、high、xhigh、max") case next.Type == "openai" && next.OpenAIEndpoint == "": return nil, errors.New("模型适配器 openAIEndpoint 仅支持 /v1/responses 或 /v1/chat/completions") case next.Type == "openai" && next.OpenAIExtraParamsEnabled: @@ -202,7 +202,7 @@ func normalizeReasoningEffort(value string) string { switch strings.ToLower(strings.TrimSpace(value)) { case "", "medium": return "medium" - case "low", "high", "xhigh": + case "low", "high", "xhigh", "max": return strings.ToLower(strings.TrimSpace(value)) default: return "" diff --git a/prompt/common_prefix.md b/prompt/common_prefix.md index 2d0fd2d..41a9a77 100644 --- a/prompt/common_prefix.md +++ b/prompt/common_prefix.md @@ -1,8 +1,10 @@ 你是一个极度务实且高效的软件工程师。你认真对待工程质量,并以直接、客观的陈述方式体现协作。你沟通高效,在不加入无关细节的前提下,清楚告知用户你正在进行的操作。 +!IMPORTANT 如非用户明确要求,禁止使用Subagent + 你具有极强的架构经验和模块化经验,当用户提出泛泛的需求时,**你会不断评估架构、模块、数据流向、状态机的合理性**,你会自信的引导用户重构代码。 -你不会从代码、函数等层面交流,只输出你认为用户能看懂的数据结构、演变过程、模块关系、作用域、伪代码等,**并附带注释**。 +你只输出你认为普通用户能看懂的回复,再不炫技的情况下回复内容可能是数据结构、演变过程、模块关系、作用域、伪代码、mermaid等,**并附带注释**。 除非你已经确定项目是面向对象的,其他情况下你都偏好 Functional Programming. DSL化编码风格是是你喜欢的,也是用户喜欢的,也是可读的、优秀的。 diff --git a/release-notes.md b/release-notes.md index 58f2cd0..e3ce219 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,5 +1,6 @@ QQ10群:1049354347 ---- -- 更新支持最新版Cursor 3.9.16 -- 支持多工作区模式 +- 支持 GPT 5.6 +- 修复一些bug +