From 43665cb6499044d92d2be141303be065922d44a0 Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Tue, 7 Oct 2025 19:36:22 +0800 Subject: [PATCH] feat(gemini-web): Replace `code-mode` with flexible `gem-mode` --- README.md | 4 ++-- README_CN.md | 4 ++-- config.example.yaml | 12 +++++------- internal/config/config.go | 17 +++++++++++++---- internal/provider/gemini-web/state.go | 17 ++++++++++++++++- internal/watcher/watcher.go | 3 +++ 6 files changed, 41 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 82c0744c..736c0cb1 100644 --- a/README.md +++ b/README.md @@ -328,7 +328,7 @@ The server uses a YAML configuration file (`config.yaml`) located in the project | `openai-compatibility.*.models.*.alias` | string | "" | The alias used in the API. | | `gemini-web` | object | {} | Configuration specific to the Gemini Web client. | | `gemini-web.context` | boolean | true | Enables conversation context reuse for continuous dialogue. | -| `gemini-web.code-mode` | boolean | false | Enables code mode for optimized responses in coding-related tasks. | +| `gemini-web.gem-mode` | string | "" | Selects a predefined Gem to attach for Gemini Web requests; allowed values: `coding-partner`, `writing-editor`. When empty, no Gem is attached. | | `gemini-web.max-chars-per-request` | integer | 1,000,000 | The maximum number of characters to send to Gemini Web in a single request. | | `gemini-web.disable-continuation-hint` | boolean | false | Disables the continuation hint for split prompts. | @@ -378,7 +378,7 @@ quota-exceeded: # Gemini Web client configuration gemini-web: context: true # Enable conversation context reuse - code-mode: false # Enable code mode + gem-mode: "" # Select Gem: "coding-partner" or "writing-editor"; empty means no Gem max-chars-per-request: 1000000 # Max characters per request # API keys for official Generative Language API diff --git a/README_CN.md b/README_CN.md index 327e516c..d5af9d1b 100644 --- a/README_CN.md +++ b/README_CN.md @@ -340,7 +340,7 @@ console.log(await claudeResponse.json()); | `openai-compatibility.*.models.*.alias` | string | "" | 在API中使用的别名。 | | `gemini-web` | object | {} | Gemini Web 客户端的特定配置。 | | `gemini-web.context` | boolean | true | 是否启用会话上下文重用,以实现连续对话。 | -| `gemini-web.code-mode` | boolean | false | 是否启用代码模式,优化代码相关任务的响应。 | +| `gemini-web.gem-mode` | string | "" | 选择要附加的预设 Gem(`coding-partner` 或 `writing-editor`);为空表示不附加。 | | `gemini-web.max-chars-per-request` | integer | 1,000,000 | 单次请求发送给 Gemini Web 的最大字符数。 | | `gemini-web.disable-continuation-hint` | boolean | false | 当提示被拆分时,是否禁用连续提示的暗示。 | @@ -390,7 +390,7 @@ quota-exceeded: # Gemini Web 客户端配置 gemini-web: context: true # 启用会话上下文重用 - code-mode: false # 启用代码模式 + gem-mode: "" # 选择 Gem:"coding-partner" 或 "writing-editor";为空表示不附加 max-chars-per-request: 1000000 # 单次请求最大字符数 # AIStduio Gemini API 的 API 密钥 diff --git a/config.example.yaml b/config.example.yaml index 66cdf64c..b3dbf801 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -90,10 +90,8 @@ quota-exceeded: # # Disable the short continuation hint appended to intermediate chunks # # when splitting long prompts. Default is false (hint enabled by default). # disable-continuation-hint: false -# # Code mode: -# # - true: enable XML wrapping hint and attach the coding-partner Gem. -# # Thought merging ( into visible content) applies to STREAMING only; -# # non-stream responses keep reasoning/thought parts separate for clients -# # that expect explicit reasoning fields. -# # - false: disable XML hint and keep separate -# code-mode: false +# # Gem selection (Gem Mode): +# # - "coding-partner": attach the predefined Coding partner Gem +# # - "writing-editor": attach the predefined Writing editor Gem +# # - empty: do not attach any Gem +# gem-mode: "" diff --git a/internal/config/config.go b/internal/config/config.go index 7f8a5c0c..b69cdd2e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -62,10 +62,19 @@ type GeminiWebConfig struct { // Defaults to true if not set in YAML (see LoadConfig). Context bool `yaml:"context" json:"context"` - // CodeMode, when true, enables coding mode behaviors for Gemini Web: - // - Attach the predefined "Coding partner" Gem - // - Enable XML wrapping hint for tool markup - // - Merge content into visible content for tool-friendly output + // GemMode selects a predefined Gem to attach for Gemini Web requests. + // Allowed values: + // - "coding-partner" + // - "writing-editor" + // When empty, no Gem is attached by configuration. + // This is independent from CodeMode below, which is kept for backwards compatibility. + GemMode string `yaml:"gem-mode" json:"gem-mode"` + + // CodeMode enables legacy coding-mode behaviors for Gemini Web. + // Backwards compatibility: when true, the service behaves as before by + // attaching the predefined "Coding partner" Gem and enabling extra + // conveniences (e.g., XML wrapping hints). Prefer GemMode for selecting + // a Gem going forward. CodeMode bool `yaml:"code-mode" json:"code-mode"` // MaxCharsPerRequest caps the number of characters (runes) sent to diff --git a/internal/provider/gemini-web/state.go b/internal/provider/gemini-web/state.go index b642d2b1..4e6c6616 100644 --- a/internal/provider/gemini-web/state.go +++ b/internal/provider/gemini-web/state.go @@ -696,7 +696,22 @@ func (s *GeminiWebState) findReusableSession(modelName string, msgs []RoleText) } func (s *GeminiWebState) getConfiguredGem() *Gem { - if s.cfg != nil && s.cfg.GeminiWeb.CodeMode { + if s.cfg == nil { + return nil + } + // New behavior: attach Gem based on explicit GemMode selection. + // Only attaches the Gem; does not toggle any other behavior. + if gm := strings.ToLower(strings.TrimSpace(s.cfg.GeminiWeb.GemMode)); gm != "" { + switch gm { + case "coding-partner": + return &Gem{ID: "coding-partner", Name: "Coding partner", Predefined: true} + case "writing-editor": + return &Gem{ID: "writing-editor", Name: "Writing editor", Predefined: true} + } + } + // Backwards compatibility: legacy CodeMode still attaches Coding partner + // and may enable extra behaviors elsewhere. + if s.cfg.GeminiWeb.CodeMode { return &Gem{ID: "coding-partner", Name: "Coding partner", Predefined: true} } return nil diff --git a/internal/watcher/watcher.go b/internal/watcher/watcher.go index 0d966ae0..b4ed25a0 100644 --- a/internal/watcher/watcher.go +++ b/internal/watcher/watcher.go @@ -521,6 +521,9 @@ func (w *Watcher) reloadConfig() bool { if oldConfig.GeminiWeb.DisableContinuationHint != newConfig.GeminiWeb.DisableContinuationHint { log.Debugf(" gemini-web.disable-continuation-hint: %t -> %t", oldConfig.GeminiWeb.DisableContinuationHint, newConfig.GeminiWeb.DisableContinuationHint) } + if oldConfig.GeminiWeb.GemMode != newConfig.GeminiWeb.GemMode { + log.Debugf(" gemini-web.gem-mode: %s -> %s", oldConfig.GeminiWeb.GemMode, newConfig.GeminiWeb.GemMode) + } if oldConfig.GeminiWeb.CodeMode != newConfig.GeminiWeb.CodeMode { log.Debugf(" gemini-web.code-mode: %t -> %t", oldConfig.GeminiWeb.CodeMode, newConfig.GeminiWeb.CodeMode) }