From 6d3b9524f028a8c155666e40ecffba99ad72fb83 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Sat, 25 Jul 2026 08:00:05 +0800 Subject: [PATCH 1/3] style(tests): satisfy prettier in the tool-call grouping test The context-compaction assertion in the ai-elements adapter test was wrapped in a shape prettier rejects, failing `eslint .` in CI. --- src/lib/adapters/ai-elements-adapter.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/adapters/ai-elements-adapter.test.ts b/src/lib/adapters/ai-elements-adapter.test.ts index ef776ac44..c8c71bee3 100644 --- a/src/lib/adapters/ai-elements-adapter.test.ts +++ b/src/lib/adapters/ai-elements-adapter.test.ts @@ -170,9 +170,9 @@ describe("groupConsecutiveToolCalls", () => { state: "output-available", meta: { contextCompaction: true, tokensBefore: 51777, tokensAfter: 4616 }, } - expect( - groupConsecutiveToolCalls([compaction]).map((p) => p.type) - ).toEqual(["tool-call"]) + expect(groupConsecutiveToolCalls([compaction]).map((p) => p.type)).toEqual([ + "tool-call", + ]) // It also breaks a surrounding run instead of folding in. expect( groupConsecutiveToolCalls([poll("read"), compaction, poll("read")]).map( From 7f829c82e610b8527ad97c04ea63f1a87498d8f4 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Sat, 25 Jul 2026 08:58:35 +0800 Subject: [PATCH 2/3] chore(claude): update claude-agent-acp to 0.62.0 and refresh model handling - Pin @agentclientprotocol/claude-agent-acp 0.61.0 -> 0.62.0, which carries @anthropic-ai/claude-agent-sdk 0.3.217 -> 0.3.219 (Claude Code engine 2.1.217 -> 2.1.219). No ACP protocol, client capability, or Node engine change comes with it. - Refresh stale Claude model placeholders in the agent and model-provider settings inputs: claude-opus-4-8 -> claude-opus-5, and Pi's claude-sonnet-4-20250514 -> claude-sonnet-5. - Share one capacity-suffix parser between the Claude Code parser and the generic model inference, which had byte-identical private copies whose Claude defaults had drifted apart. The generic inference now also recognizes the SDK's id spelling of the 1M lane (claude-opus-4-6-1m), which previously fell through to the 200K default. The remaining 1M-vs-200K difference between the two paths is intentional and now documented at both sites: Claude Code strips the 1M marker when it writes a transcript -- a session run as claude-opus-5[1m] is recorded as plain claude-opus-5 -- so that parser cannot tell which lane a session used and assumes the extended one; other agents record the resolved id verbatim, so their path detects the marker and defaults to 200K. --- src-tauri/src/acp/registry.rs | 8 +-- src-tauri/src/parsers/claude.rs | 68 ++++++++----------- src-tauri/src/parsers/mod.rs | 40 +++++++++++ .../settings/acp-agent-settings.tsx | 6 +- .../settings/add-model-provider-dialog.tsx | 6 +- .../settings/edit-model-provider-dialog.tsx | 6 +- src/components/settings/pi-config-panel.tsx | 2 +- 7 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src-tauri/src/acp/registry.rs b/src-tauri/src/acp/registry.rs index 353a6c07b..f22f84509 100644 --- a/src-tauri/src/acp/registry.rs +++ b/src-tauri/src/acp/registry.rs @@ -194,8 +194,8 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta { name: "Claude Code", description: "ACP wrapper for Anthropic's Claude", distribution: AgentDistribution::Npx { - version: "0.61.0", - package: "@agentclientprotocol/claude-agent-acp@0.61.0", + version: "0.62.0", + package: "@agentclientprotocol/claude-agent-acp@0.62.0", cmd: "claude-agent-acp", args: &[], env: &[], @@ -628,8 +628,8 @@ mod tests { fn registry_pins_current_acp_agent_versions() { assert_npx_version( AgentType::ClaudeCode, - "0.61.0", - "@agentclientprotocol/claude-agent-acp@0.61.0", + "0.62.0", + "@agentclientprotocol/claude-agent-acp@0.62.0", Some("22.0.0"), ); assert_npx_version( diff --git a/src-tauri/src/parsers/claude.rs b/src-tauri/src/parsers/claude.rs index bc1699430..5b0469aac 100644 --- a/src-tauri/src/parsers/claude.rs +++ b/src-tauri/src/parsers/claude.rs @@ -34,15 +34,6 @@ fn system_tag_regex() -> &'static Regex { }) } -/// Regex that matches an optional model capacity suffix like `[1M]` / `[500k]`. -fn model_capacity_suffix_regex() -> &'static Regex { - static RE: OnceLock = OnceLock::new(); - RE.get_or_init(|| { - Regex::new(r"(?i)\[\s*([0-9]+(?:\.[0-9]+)?)\s*([km])\s*\]\s*$") - .expect("valid model capacity regex") - }) -} - /// Sentinel prefixing the structured lifecycle payload the parser writes into /// an async-launch ack's `output_preview` (see /// `ClaudeRecordAccumulator::finalize_background_lifecycle`). The frontend @@ -275,38 +266,34 @@ fn is_synthetic_assistant(value: &serde_json::Value) -> bool { .unwrap_or(false) } -fn parse_model_capacity_suffix(model: &str) -> Option { - let captures = model_capacity_suffix_regex().captures(model.trim())?; - let value = captures.get(1)?.as_str().parse::().ok()?; - if !value.is_finite() || value <= 0.0 { - return None; - } - - let unit = captures - .get(2) - .map(|m| m.as_str().to_ascii_lowercase()) - .unwrap_or_default(); - let multiplier = match unit.as_str() { - "m" => 1_000_000.0, - "k" => 1_000.0, - _ => return None, - }; - - Some((value * multiplier) as u64) -} - +/// Context window to display for a *file-parsed* Claude Code session, which +/// carries no authoritative window of its own (live sessions get one from the +/// ACP `usage_update.size` and never reach here). +/// +/// Deliberately defaults higher than [`super::infer_context_window_max_tokens`] +/// does for the same `claude-*` model, because the two read different inputs: +/// Claude Code's transcripts record the *resolved* model with the 1M marker +/// stripped — a session launched as `claude-opus-5[1m]` is written to the +/// JSONL as plain `claude-opus-5` — so neither the bracket spelling nor the +/// `-1m` id spelling survives to be detected, and any per-session guess is +/// unavoidable. Assuming the 1M lane keeps the meter from over-reporting +/// pressure ~5x on the extended-context models most sessions run; the cost is +/// under-reporting for a session that really was on the 200K lane. Other +/// agents' transcripts keep the id verbatim, so that path can detect the lane +/// and defaults to 200K instead. Change one of these without the other and +/// they silently disagree again. fn claude_context_window_max_tokens_for_model(model: Option<&str>) -> Option { let model = model?.trim(); if model.is_empty() { return None; } - // If user/model config contains an explicit capacity suffix, prefer it. - if let Some(suffixed_limit) = parse_model_capacity_suffix(model) { + // A capacity suffix that did survive (hand-written config, non-CLI writer) + // is authoritative. + if let Some(suffixed_limit) = super::parse_model_capacity_suffix(model) { return Some(suffixed_limit); } - // Claude models default to 1M when no explicit capacity is provided. if model.to_ascii_lowercase().starts_with("claude") { return Some(1_000_000); } @@ -1996,24 +1983,27 @@ mod tests { } #[test] - fn parses_model_capacity_suffix() { + fn honours_surviving_capacity_suffix() { assert_eq!( - parse_model_capacity_suffix("claude-sonnet-4-6[1.5M]"), - Some(1_500_000) - ); - assert_eq!( - parse_model_capacity_suffix("claude-opus-4-6 [500k]"), + claude_context_window_max_tokens_for_model(Some("claude-opus-4-6 [500k]")), Some(500_000) ); - assert_eq!(parse_model_capacity_suffix("claude-sonnet-4-6"), None); } #[test] fn defaults_context_limit_for_claude_models() { + // Claude Code strips the 1M marker when it writes the transcript, so a + // bare id has to be assumed to be the extended lane here — unlike the + // shared inference other agents' parsers use. See the doc comment on + // `claude_context_window_max_tokens_for_model`. assert_eq!( claude_context_window_max_tokens_for_model(Some("claude-sonnet-4-6")), Some(1_000_000) ); + assert_eq!( + super::super::infer_context_window_max_tokens(Some("claude-sonnet-4-6")), + Some(200_000) + ); assert_eq!( claude_context_window_max_tokens_for_model(Some("custom-model-x")), None diff --git a/src-tauri/src/parsers/mod.rs b/src-tauri/src/parsers/mod.rs index d6ae02756..354156ef2 100644 --- a/src-tauri/src/parsers/mod.rs +++ b/src-tauri/src/parsers/mod.rs @@ -449,6 +449,23 @@ fn model_capacity_suffix_regex() -> &'static Regex { }) } +/// Matches the SDK's *id* spelling of Anthropic's 1M-context lane, where `1m` +/// is its own delimited token (`claude-opus-4-6-1m`). `\b1m\b` is the same +/// test claude-agent-acp's `inferContextWindowFromModel` applies, and it +/// deliberately does not match embedded runs like `10m`. +fn claude_one_million_id_regex() -> &'static Regex { + static RE: OnceLock = OnceLock::new(); + RE.get_or_init(|| Regex::new(r"(?i)\b1m\b").expect("valid claude 1m id regex")) +} + +/// Whether `model` names Anthropic's 1M-context lane through the SDK's id +/// spelling (`claude-opus-4-6-1m`). The CLI's *display* spelling +/// (`claude-sonnet-5[1m]`) carries the same meaning but is handled by +/// [`parse_model_capacity_suffix`], which reads the bracketed number directly. +fn is_claude_one_million_context_id(model: &str) -> bool { + claude_one_million_id_regex().is_match(model) +} + fn parse_model_capacity_suffix(model: &str) -> Option { let captures = model_capacity_suffix_regex().captures(model.trim())?; let value = captures.get(1)?.as_str().parse::().ok()?; @@ -489,7 +506,15 @@ pub fn infer_context_window_max_tokens(model: Option<&str>) -> Option { .trim() .to_ascii_lowercase(); + // Anthropic's default lane is 200K; the 1M lane is opt-in and shows up in + // the model id itself. Agents other than Claude Code record the id the way + // their backend named it, so the marker survives here — unlike Claude + // Code's own transcripts, where it is stripped (see + // `claude::claude_context_window_max_tokens_for_model`). if normalized.starts_with("claude") { + if is_claude_one_million_context_id(&normalized) { + return Some(1_000_000); + } return Some(200_000); } if normalized.starts_with("gemini") { @@ -1208,6 +1233,21 @@ mod tests { infer_context_window_max_tokens(Some("claude-sonnet-4-6 [1.5M]")), Some(1_500_000) ); + // The 1M lane also travels as a bare id token (`-1m`), which is how the + // SDK — and therefore every agent that records the resolved id — spells + // it. `\b1m\b` must not fire on an embedded run like `10m`. + assert_eq!( + infer_context_window_max_tokens(Some("claude-opus-4-6-1m")), + Some(1_000_000) + ); + assert_eq!( + infer_context_window_max_tokens(Some("my-gateway/claude-opus-4-6-1m")), + Some(1_000_000) + ); + assert_eq!( + infer_context_window_max_tokens(Some("claude-opus-4-6-10m-preview")), + Some(200_000) + ); // Grok context windows per x.ai docs: grok-4.5 = 500K, grok-4.3 / // grok-4.20 = 1M, the coding/build models = 256K (grok-code-fast-1 // despite "fast"), the general -fast variants = 2M, and any unknown diff --git a/src/components/settings/acp-agent-settings.tsx b/src/components/settings/acp-agent-settings.tsx index ce29468b0..b5d500f26 100644 --- a/src/components/settings/acp-agent-settings.tsx +++ b/src/components/settings/acp-agent-settings.tsx @@ -10693,7 +10693,7 @@ supports_websockets = true`} event.target.value ) }} - placeholder="claude-opus-4-8" + placeholder="claude-opus-5" />
@@ -10750,7 +10750,7 @@ supports_websockets = true`} event.target.value ) }} - placeholder="claude-opus-4-8" + placeholder="claude-opus-5" />
@@ -10775,7 +10775,7 @@ supports_websockets = true`} event.target.value ) }} - placeholder="my-gateway/claude-opus-4-8" + placeholder="my-gateway/claude-opus-5" />
diff --git a/src/components/settings/add-model-provider-dialog.tsx b/src/components/settings/add-model-provider-dialog.tsx index 0f4defdd8..ffd96f204 100644 --- a/src/components/settings/add-model-provider-dialog.tsx +++ b/src/components/settings/add-model-provider-dialog.tsx @@ -250,7 +250,7 @@ export function AddModelProviderDialog({ reasoning: e.target.value, })) } - placeholder="claude-opus-4-8" + placeholder="claude-opus-5" />
@@ -295,7 +295,7 @@ export function AddModelProviderDialog({ opus: e.target.value, })) } - placeholder="claude-opus-4-8" + placeholder="claude-opus-5" />
@@ -310,7 +310,7 @@ export function AddModelProviderDialog({ customOption: e.target.value, })) } - placeholder="my-gateway/claude-opus-4-8" + placeholder="my-gateway/claude-opus-5" />
diff --git a/src/components/settings/edit-model-provider-dialog.tsx b/src/components/settings/edit-model-provider-dialog.tsx index 459928da6..9798dd256 100644 --- a/src/components/settings/edit-model-provider-dialog.tsx +++ b/src/components/settings/edit-model-provider-dialog.tsx @@ -269,7 +269,7 @@ export function EditModelProviderDialog({ reasoning: e.target.value, })) } - placeholder="claude-opus-4-8" + placeholder="claude-opus-5" />
@@ -314,7 +314,7 @@ export function EditModelProviderDialog({ opus: e.target.value, })) } - placeholder="claude-opus-4-8" + placeholder="claude-opus-5" />
@@ -329,7 +329,7 @@ export function EditModelProviderDialog({ customOption: e.target.value, })) } - placeholder="my-gateway/claude-opus-4-8" + placeholder="my-gateway/claude-opus-5" />
diff --git a/src/components/settings/pi-config-panel.tsx b/src/components/settings/pi-config-panel.tsx index b48b9cfdf..5094fcbfc 100644 --- a/src/components/settings/pi-config-panel.tsx +++ b/src/components/settings/pi-config-panel.tsx @@ -911,7 +911,7 @@ export function PiConfigPanel({ setModel(event.target.value)} - placeholder="claude-sonnet-4-20250514" + placeholder="claude-sonnet-5" spellCheck={false} disabled={savingCreds || loadingCreds} /> From c181c56b974f944b6d1fe7277135a2c3d6c15579 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Sat, 25 Jul 2026 09:07:54 +0800 Subject: [PATCH 3/3] # Release version 0.21.7 & 0.21.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - feat(claude): **Opus 5 support.** Claude Code and the model-provider settings now default to `claude-opus-5` (and `claude-sonnet-5` for Pi), so new sessions target Anthropic's latest models out of the box. - chore(claude): **Updated the Claude Code engine.** Bundled Claude Code moves to engine 2.1.219 (claude-agent-acp 0.62.0). Context-window detection now also recognizes the SDK's 1M-lane model id, so those sessions stop falling back to the 200K estimate. - feat(codex): **Answer Codex's prompts with codeg's own cards.** Plan-mode questions, MCP forms, and tool-call approvals from Codex now surface as codeg's interactive ask and permission cards — synthesized live and preserved on reload — and its plans render as a proper markdown card. (Codex updated to 1.1.7) - feat(codex): **Pause or clear an active goal.** The goal card gains Pause and Clear buttons; resuming is just re-sending your `/goal`. The controls hide on history reload, for viewers, and in the read-only sub-agent dialog. - feat(codex): **A clearer live sub-agent card.** It now shows the sub-agent's model and reasoning effort as it runs, no longer draws an empty white box when there's nothing to report, and picks up Codex's new retry banner and context-compaction card. - feat(codex): **Plan mode moved to the mode selector.** The redundant `/plan` slash command is gone — toggle plan mode from the collaboration-mode selector instead. - feat(grok): **Grok plan mode, end to end.** Leaving plan mode now shows an approval card (approve / request changes / abandon) in both the main conversation and the sub-agent dialog, and survives a mid-turn reconnect. "Approve & build" is honored correctly, request-changes notes go back as a follow-up so Grok revises, and plan calls render in the dedicated plan-mode card. - fix(grok): **Long file writes no longer fail.** When a command line is too long to run directly, Grok now falls back to the shell instead of erroring with "File name too long." - feat(grok): **Context compaction shown inline.** Auto-compaction now appears as a centered divider between turns with the token delta, in both the live stream and history. - feat(sidebar): **A more focused sidebar.** Finished conversations are now hidden by default — flip on "Show completed" to see them. Imported local sessions arrive as pending review so they stay visible. - feat(settings): **New Claude Code privacy toggles.** Two switches now control Claude Code's attribution/billing header (off by default) and non-essential network traffic (disabled by default), written straight to your native config. - fix(settings): **A cleaner skill import picker.** Built-in expert, office, and science skills no longer clutter the agent skill-import list. - fix(pet): **Pet marketplace images load everywhere.** Thumbnails and previews are now fetched through the backend, so they show up even where the marketplace host is unreachable from the webview. - fix(chat): **Snappier session switching.** The outgoing tab hides immediately, and the new-session welcome controls no longer linger and animate over the conversation you just opened. - fix(messages): **Right-sized message bubbles.** Your messages and ask-question results now hug their content instead of stretching to full width. - feat(layout): **Smarter branch search.** The branch selector now ranks matches by relevance, with exact matches first. - chore(experts): **Updated expert skills to superpowers 6.2.0.** Brings a rules-based "writing good tests" guide, a plan-scoped subagent workspace whose review-fix loop routes back to the original implementer, and forge-agnostic PR creation, among other refinements. - chore(acp): **Refreshed the bundled agents.** CodeBuddy 2.127.0, Kimi Code 0.29.1, Pi 0.0.32, Cursor 2026.07.23, and Codex 1.1.7. ----------------------------- # 发布版本 0.21.7 & 0.21.8 - 功能(Claude):**支持 Opus 5。** Claude Code 与模型提供方设置现在默认使用 `claude-opus-5`(Pi 则为 `claude-sonnet-5`),新会话开箱即用 Anthropic 最新模型。 - 维护(Claude):**升级 Claude Code 引擎。** 内置 Claude Code 升级至引擎 2.1.219(claude-agent-acp 0.62.0)。上下文窗口识别现在也能认出 SDK 的百万上下文(1M)模型 id,这类会话不再回退到 20 万(200K)的估算。 - 功能(Codex):**用 codeg 自己的卡片回应 Codex 的提问。** Codex 的计划模式提问、MCP 表单与工具调用授权,现在都以 codeg 的交互式提问卡与授权卡呈现——实时合成、重载后仍保留——其计划也渲染为规范的 markdown 卡片。(Codex 升级至 1.1.7) - 功能(Codex):**暂停或清除进行中的目标。** 目标卡片新增「暂停」与「清除」按钮;重新发送 `/goal` 即可恢复。这些按钮在历史重载、旁观者视角以及只读子智能体对话中会自动隐藏。 - 功能(Codex):**更清晰的实时子智能体卡片。** 运行时即显示子智能体的模型与推理强度;无内容可展示时不再画出空白「白框」;并接入 Codex 新的重试提示与上下文压缩卡片。 - 功能(Codex):**计划模式移至模式选择器。** 移除多余的 `/plan` 斜杠命令,改从协作模式选择器切换计划模式。 - 功能(Grok):**Grok 计划模式,端到端可用。** 离开计划模式时,主对话与子智能体对话中都会弹出审批卡(批准 / 请求修改 / 放弃),并可在回合中途重连后恢复。「批准并构建」被正确执行,「请求修改」的意见会作为后续提示回传让 Grok 修订,计划调用也渲染进专属的计划模式卡片。 - 修复(Grok):**长文件写入不再失败。** 当命令行过长无法直接执行时,Grok 现在会回退到 shell 运行,而不再报「文件名过长」。 - 功能(Grok):**上下文压缩内联显示。** 自动压缩现在以居中分隔线的形式显示在两回合之间,并标注 token 变化,实时流与历史均可见。 - 功能(侧边栏):**更专注的侧边栏。** 已完成的会话现在默认隐藏,需要时打开「显示已完成」即可查看。导入的本地会话以「待评审」状态进入,保持可见。 - 功能(设置):**新增 Claude Code 隐私开关。** 两个开关分别控制 Claude Code 的归属/计费标头(默认关闭)与非必要网络请求(默认禁用),直接写入原生配置。 - 修复(设置):**更清爽的技能导入选择器。** 内置的专家、办公与科研技能不再出现在智能体的技能导入列表中。 - 修复(宠物):**宠物市场图片处处可加载。** 缩略图与预览现在改由后端代理拉取,即便 webview 直连市场主机不通也能正常显示。 - 修复(聊天):**切换会话更利落。** 切出的标签立即隐藏,新会话的欢迎控件不再滞留、也不再在你刚打开的会话上继续动画。 - 修复(消息):**大小合适的消息气泡。** 你的消息与提问结果现在按内容自适应宽度,不再撑满整行。 - 功能(布局):**更聪明的分支搜索。** 分支选择器现在按相关度排序,精确匹配优先。 - 维护(专家):**专家技能升级至 superpowers 6.2.0。** 带来基于规则的「编写优质测试」指南、按计划隔离且将「评审—修复」环路回交给原实现者的子智能体工作区,以及不依赖特定托管平台的 PR 创建等改进。 - 维护(智能体):**刷新内置智能体版本。** CodeBuddy 2.127.0、Kimi Code 0.29.1、Pi 0.0.32、Cursor 2026.07.23、Codex 1.1.7。 --- package.json | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index f6338f992..dc34c3358 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "codeg", "private": true, - "version": "0.21.7", + "version": "0.21.8", "packageManager": "pnpm@11.9.0", "scripts": { "dev": "next dev --turbopack", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index fac8069b3..ee01c432f 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1014,7 +1014,7 @@ checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "codeg" -version = "0.21.7" +version = "0.21.8" dependencies = [ "aes-gcm", "agent-client-protocol-schema", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index d0db85d19..a68821f79 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "codeg" -version = "0.21.7" +version = "0.21.8" description = "Agent Code Generation App" authors = ["feitao"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 5dee830e4..e7a47ebc4 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "codeg", - "version": "0.21.7", + "version": "0.21.8", "identifier": "app.codeg", "build": { "beforeDevCommand": "pnpm tauri:before-dev",