Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
daa62dc
feat(translation): cut stream tail chunks at sentence boundaries in a…
yunsheng111 Sep 5, 2026
e8db5b4
feat(translation): fill streaming batches to the char ceiling and pac…
yunsheng111 Sep 5, 2026
8ff37ef
fix(translation): normalize number formats in the display-side number…
yunsheng111 Sep 5, 2026
48dedd1
feat(translation): recover AIMD rate at 2 RPM per 5 clean successes
yunsheng111 Sep 5, 2026
2507da0
feat(translation): carry-context toggle in settings (default on), wir…
yunsheng111 Sep 5, 2026
c10a2ee
feat(translation): prepend previous segment as a consistency referenc…
yunsheng111 Sep 5, 2026
3bcaa77
feat(translation): record dropped-number gate rejections as a soft ev…
yunsheng111 Sep 5, 2026
dd86379
test(translation): align pool notification test with 5-success AIMD step
yunsheng111 Sep 5, 2026
bbd3840
fix(translation): health score needs 8 samples, maps rejections to 40…
yunsheng111 Sep 5, 2026
dcd4a80
fix(translation): normalize number formats and require half the runs …
yunsheng111 Sep 5, 2026
205cdef
fix(translation): carry carry_context through the command fixture (ta…
yunsheng111 Sep 5, 2026
64fcb18
fix(translation): dedupe number runs and correct reference-block docs
yunsheng111 Sep 5, 2026
5312606
fix(translation): strip the context reference block from local judgments
yunsheng111 Sep 5, 2026
a0647b7
fix(build): embed the comctl32-v6 manifest into integration test exes…
yunsheng111 Sep 6, 2026
8a96079
feat: translation middleware WIP
yunsheng111 Sep 6, 2026
a83a6fb
chore: untrack tool session state and scratch files
yunsheng111 Sep 6, 2026
938bc9f
feat(translation): XML envelope, retry-shape escalation, and gap iden…
yunsheng111 Sep 6, 2026
758b005
feat(translation): judge the envelope's inner body on the backend
yunsheng111 Sep 6, 2026
d987c7f
feat(translation): survive instance death between a failed chunk and …
yunsheng111 Sep 6, 2026
a05db30
feat(translation): refuse a verbatim echo of code-heavy chunks
yunsheng111 Sep 6, 2026
b50d055
feat(translation): learn a provider is slow while its requests are in…
yunsheng111 Sep 6, 2026
cef3800
feat(translation): retry an invented wide chunk as two halves
yunsheng111 Sep 6, 2026
3d9b26e
feat(translation): tag every dispatch log with the calling block's id
yunsheng111 Sep 6, 2026
99db90b
fix(translation): split-retry the rejection path the invention actual…
yunsheng111 Sep 6, 2026
4b6019d
feat(translation): skip untranslatable segments and give up dead gaps
yunsheng111 Sep 6, 2026
a076133
fix(translation): persist landings before the instance-liveness gate
yunsheng111 Sep 6, 2026
5178a8c
fix(translation): keep the display chain whole across given-up gaps
yunsheng111 Sep 7, 2026
a394598
docs: add translation call-flow diagrams
yunsheng111 Sep 7, 2026
a2bb097
feat(logging): truncate the day's log at the budget ceiling
yunsheng111 Sep 7, 2026
f2c3295
feat(translation): let users disable, cool down, and reset providers
yunsheng111 Sep 9, 2026
419cd96
Merge branch 'main' into feat/translation-middleware
yunsheng111 Sep 9, 2026
b51b881
Merge remote-tracking branch 'upstream/main' into feat/translation-mi…
yunsheng111 Sep 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,16 @@ src-tauri/binaries/
# executable then sits untracked in the repo root — which is enough to fail a
# work task's "worktree is clean" check at delivery.
/rust_out

# Agent/tool session state and scratch outputs
.ccg/
.zcode/
src-tauri/runtest.*
src-tauri/translation_out.txt
src/probe.test.ts

# security-scan and tooling artifacts (regenerated on every scan)
.mimosa/
src-tauri/.mimosa/
.magi/
bash.exe.stackdump
191 changes: 133 additions & 58 deletions CLAUDE.md

Large diffs are not rendered by default.

156 changes: 156 additions & 0 deletions docs/translation-call-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# 翻译功能调用过程图

> 依据 `feat/translation-middleware` 分支实际代码绘制(2026-09-07)。

## 1. 端到端调用链

```mermaid
flowchart TB
subgraph FE["前端 (React)"]
direction TB
R1["content-parts-renderer.tsx<br/>TextPart (正文, priority=true)<br/>ReasoningPart (思考块, translateThinking)"]
R2["use-streaming-translated-text (流式机)<br/>segmentsFor → splitStableUnits/tailChunksFor<br/>dispatchBatch / flushSettled / replayGaps"]
R3["use-translated-text (共用核心)<br/>requestNumberedGroup / requestTranslationDetailed<br/>judgeChunkTranslation (前端门禁)"]
R4["lib/api.ts translateTexts<br/>invoke() / fetch()"]
end

subgraph BE["后端 (Rust)"]
direction TB
B1["translation_translate_core<br/>commands/translation.rs + web/handlers"]
B2["translate_with_cache (LRU 2000)<br/>mod.rs"]
B3["pool.pick() 三门<br/>retire / fallback partition / probe"]
B4["translate_batch → translate_one<br/>client.rs"]
B5["Provider 池<br/>健康分 quality/stability/speed<br/>AIMD 自适应限速"]
B6["远端端点<br/>OpenAI 兼容 /chat/completions"]
end

R1 -->|"块挂载 + viewport 门"| R2
R2 -->|"numbered 组 / 单段<br/>variant 重试升级"| R3
R3 -->|"XML envelope<br/>&lt;translate&gt; 包裹 + 参考块"| R4
R4 -->|"Tauri invoke / HTTP fetch<br/>priority → lane 标记"| B1
B1 --> B2
B2 -->|"缓存未命中"| B3
B2 -->|"缓存命中"| R3
B3 --> B4
B4 -->|"Priority lane 4并发 /<br/>Background lane 3并发"| B5
B5 -->|"软超时 30s = AIMD 半速<br/>慢成功降健康分"| B6
```

## 2. 流式分段与显示链(正文/思考块共用)

```mermaid
flowchart TB
S0["流式文本 (append-only)"] --> S1
S1{"splitStableUnits<br/>切分"}
S1 -->|"空行/ATX 标题封印<br/>= 永不变字节"| S2["sealed units"]
S1 -->|"尾部按 1500 字符定宽切块<br/>open fence 处停刀"| S3["tail chunks"]

S2 --> D{"dispatchBatch<br/>每 3s / 800 新字符"}
S3 --> D
D -->|"段无字母 (符号/分隔线)"| P1["identity piece 直接落地<br/>(零请求)"]
D -->|"段已是目标语言 (中文→中文)"| P1
D -->|其余| Q1["numbered 组请求<br/>≤3000 字符/组"]
Q1 -->|"3/2 段全部成功"| L1["land(): piece 入链"]
Q1 -->|"部分失败"| L2["游标回滚至首个失败段<br/>变体升级重试"]

L1 --> C1["显示链拼接 display<br/>从 offset 0 连续走 piece"]
L2 -->|"仍失败"| G1["recordGap 挂账<br/>4s→12s→36s 退避重试"]
G1 -->|"3 次失败 → 放弃"| P2["原文 stitch 为 identity piece<br/>链条保持完整 (不再全块回原文)"]
G1 -->|"成功"| L1

C1 -->|"gap 补漏落地<br/>(gate 前先 mergePiecesIntoStore)"| C1
```

## 3. 质量门禁与重试升级

```mermaid
flowchart TB
subgraph 前端判卷["requestTranslationDetailed 返回后 (前端)"]
J1{"echoVerbatimError<br/>逐字回显? (CJK 目标)"}
J2{"missingTargetScript<br/>无目标语言字符? (≥30 拉丁字母)"}
J3{"missingSourceNumbers<br/>数字丢失过半?"}
J4{"长度门<br/>2.5×+200 = 编造?"}
RJ["拒 → variant+1 重试"]
SP{"splitChunkForHalfRetry<br/>≥800 字符?"}
HS["两半分别送翻<br/>句界中点 + 占位符不跨界"]
GIVE["gap 挂账 → 放弃 → 原文 stitch"]

J1 -->|是| RJ
J2 -->|是| RJ
J3 -->|是| RJ
J4 -->|"是 (INVENTED_CONTENT)"| SP
SP -->|能拆| HS
SP -->|不能拆| RJ
RJ -->|3 次后| GIVE
end

subgraph 后端判卷["translate_one 返回后 (后端)"]
K1{"strip_translate_envelope<br/>剥壳后判卷"}
BAD["记 ProviderEvent<br/>健康分 stability 扣分"]
OK["返回 + 记 cache"]
RATE{"失败率超阈值?"}
PEN["AIMD penalize 半速"]

K1 -->|"回显/编造/缺脚本"| BAD
K1 -->|合格| OK
BAD --> RATE
RATE -->|是| PEN
end

subgraph 慢请求["在途软超时 (30s)"]
T1["tokio::select! biased<br/>sleep_until vs pending"]
T2["SlowInFlight 事件<br/>provider 限速减半<br/>继续等待不放弃"]

T1 -->|"30s 未返回"| T2
end
```

## 4. 一条正文的完整生命周期(时序)

```mermaid
sequenceDiagram
participant U as 用户
participant FE as 前端 hook
participant BE as Rust 后端
participant P as Provider 池

U->>FE: 消息流式到达 (正文/思考块)
FE->>FE: 封印单元切分 + 节流门 (3s/800字符)
FE->>FE: 预检: 符号段/已是中文段 → identity piece (不请求)
FE->>BE: translateTexts(priority, trace=[块ID])
BE->>BE: LRU 缓存查询 (内容寻址)
alt 缓存未命中
BE->>P: pool.pick() (健康分排序 + 三门)
P->>BE: PickedProvider
BE->>P: lane 信号量 (Priority 4 / Background 3)
Note over BE,P: 30s 软超时看护: AIMD 半速不放弃
P-->>BE: 译文
BE->>BE: 剥 envelope + 门禁判卷
alt 判卷拒绝
BE->>P: 记事件 / penalize
BE-->>FE: 失败原因 (error 字符串)
FE->>FE: variant+1 升级重试 / 半拆 / gap 挂账
else 通过
BE-->>FE: 译文 (入 LRU)
FE->>FE: mergePiecesIntoStore (先落库后判活)
FE-->>U: 显示链更新 (piece 接续)
end
else 缓存命中
BE-->>FE: fromCache 译文
end
U->>FE: 流结束 (settle)
FE->>FE: flushSettled 补尾 (在途子段重叠则等待)
FE->>FE: gap replay (3 次放弃 → 原文 stitch)
FE-->>U: 完整译文 + 译/原切换按钮
```

## 关键文件对照

| 环节 | 文件 |
|---|---|
| 分段/门禁/重试判据 | `src/lib/translation.ts` |
| 流式翻译机 (dispatch/flush/replay) | `src/hooks/use-streaming-translated-text.ts` |
| 请求构造/判卷/缓存键 | `src/hooks/use-translated-text.ts` |
| Provider 池/健康分/AIMD | `src-tauri/src/translation/pool.rs`, `health.rs` |
| 请求执行/软超时/lane | `src-tauri/src/translation/client.rs` |
| 缓存与后端门禁 | `src-tauri/src/translation/mod.rs` |
130 changes: 130 additions & 0 deletions src-tauri/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
[根目录](../CLAUDE.md) > **src-tauri**

# src-tauri — Rust 后端模块

## 模块职责

Codeg 全部后端能力:代理会话文件解析(19 种 CLI)、Agent Client Protocol(ACP)连接管理与多智能体异步委托、Axum HTTP/WebSocket 服务、SeaORM+SQLite 持久化、PTY 终端、聊天通道桥接、定时自动化、备份加密、原地自升级。同一份代码按 Cargo feature 编译出三种二进制。

## 入口与启动(三个二进制)

| 二进制 | 入口 | Feature 要求 | 说明 |
|--------|------|--------------|------|
| `codeg` | `src/main.rs` | `tauri-runtime`(默认) | 桌面应用:窗口管理、通知、托盘、自动更新、开机自启 |
| `codeg-server` | `src/bin/codeg_server.rs` | 无(`--no-default-features`) | Axum HTTP API + WebSocket;附属模式:`--version`、`--supervise`(Docker PID 1 进程监督,原地升级后重启 worker)、`--credential-helper`(git 凭据协议子进程) |
| `codeg-mcp` | `src/bin/codeg_mcp.rs` | 无 | per-launch stdio MCP 伴生进程;必需参数 `--parent-connection-id`、`--socket-path`、`--token`;工具:`delegate_to_agent`、`check_user_feedback`、`ask_user_question`、`get_session_info`、`create_automation`、`create_work_task`(按 `--features` 分组开关) |

本地命令:`pnpm server:dev` / `pnpm server:build`(根目录代理执行);Tauri 开发用 `pnpm tauri:before-dev`(先跑 `scripts/prepare-sidecars.mjs`)。

## 对外接口

- **Tauri 命令**(桌面):`commands/` 下 40+ 文件,`#[cfg_attr(feature = "tauri-runtime", tauri::command)]` 标记;`commands/mod.rs` 汇总注册
- **HTTP API**(服务器/远程桌面):`web/router.rs` 注册,`web/handlers/` 45 个 handler 文件,统一 `Extension<Arc<AppState>>` 取状态;`web/auth.rs` token 认证,`web/compression.rs` gzip/brotli
- **WebSocket 事件**:`web/ws.rs` + `web/ws_attach.rs`;事件经 `EventEmitter::WebOnly(Arc<WebEventBroadcaster>)` 广播
- **MCP 工具**(给代理 LLM):`codeg-mcp` stdio JSON-RPC,经 UDS 与父进程往返,重逻辑在 `acp/delegation/{companion,transport}`(`tool_schema.json` 定义 schema)

### sidecar 准备(`scripts/prepare-sidecars.mjs`)

`pnpm tauri:prepare-sidecars`(被 `tauri:before-dev` / `tauri:before-build` 调用)执行三步:解析 target triple(`--target` 参数 → `TAURI_TARGET_TRIPLE` 环境变量 → 宿主 `rustc -vV`)→ `cargo build --release --bin codeg-mcp --no-default-features` → 拷贝产物为 `src-tauri/binaries/codeg-mcp-<triple>{.exe}`,供 Tauri `externalBin` 以裸名 `codeg-mcp` 打包。纯 Node 实现(无 shell),跨平台一致;CI 交叉编译时 release.yml 传 `--target`。本地只改前端迭代时可用 `CODEG_SKIP_SIDECAR=1` 跳过。

## 内部结构(lib.rs 声明的模块)

```
src-tauri/src/
├── main.rs / lib.rs # 桌面入口 / 模块声明
├── bin/ # codeg_server.rs、codeg_mcp.rs
├── app_state.rs # AppState 共享状态(db、连接管理器、终端管理器、EventEmitter)
├── parsers/ # 19 个会话解析器:claude、codex(+code_mode)、gemini、opencode、
│ # openclaw、cline、cursor、kimi_code、qoder、grok、hermes、pi、
│ # codebuddy、deepseek、antigravity、acp_native…+ summary_cache
├── acp/ # ACP 连接管理:manager、connection、event_stream、registry、
│ └── delegation/ # session_state、plan_approval、question、fork…;多智能体异步委托
│ # (broker/companion/spawner/transport,UDS 通信)
├── web/ # Axum 服务:router、handlers/(45)、auth、ws、event_bridge、
│ # compression、port_probe、socket_inherit、shutdown
├── commands/ # Tauri 命令层(40+ 文件);backup/ 子模块(AES-GCM+Argon2 加密备份)
├── db/ # SeaORM:entities/(21)、migration/(按日期 m2026MMDD_*)、service/、test_helpers
├── models/ # 共享数据结构(与前端 lib/types.ts 镜像)
├── automation/ # cron 自动化引擎
├── chat_channel/ # 聊天通道:backends/{telegram,lark,weixin}、scheduler、command_dispatcher、webhook、session_bridge
├── forge/ # GitHub/GitLab 集成(auth、deliver、envelope)
├── work_task/ # 工作任务看板
├── pets/ # 桌宠市场、codex_import;pet_sessions.rs / pet_state_mapper.rs
├── backgrounds/ office_watch/ network/ terminal/ # 后台任务、Office 监视、网络、PTY(portable-pty)
├── update/ + supervise.rs # 原地自升级 + 进程监督
└── git_repo.rs git_credential.rs folder_links.rs workspace_transfer.rs …
```

## 关键依赖与配置

- **ACP 栈**:`sacp` / `sacp-tokio` 11.0(`sacp-tokio` 被 `[patch.crates-io]` 指向 `vendor/sacp-tokio` 本地补丁)、`agent-client-protocol-schema` 0.11(启用多个 unstable feature:usage/fork/resume/elicitation/boolean_config)
- **Web**:`axum` 0.8(ws+multipart)、`tower-http`(fs/cors/compression)、`reqwest` 0.12(gzip/brotli 透传)
- **存储**:`sea-orm` 1.1(sqlx-sqlite)、`sea-orm-migration`、`rusqlite` 0.32(同步只读访问 Cursor 的 store.db;**libsqlite3-sys 版本已与 sqlx 对齐**,勿单独升级)
- **桌面**:`tauri` 2(可选,macos-private-api + tray-icon)+ 7 个 tauri-plugin
- **格式解析**:`toml`/`toml_edit`(保格式 TOML 手术式合并)、`serde_yaml`、`zstd`(DeepSeek `session.jsonl.zstd`)、`tar`/`zip`/`async_zip`/`flate2`/`bzip2`
- **安全**:`aes-gcm`(流式)、`argon2`、`keyring`(可选,桌面凭据存储)、`minisign-verify`、`sha2`
- **其他**:`tokio`(process/io-util/net…)、`portable-pty`、`kill_tree`、`notify`、`prost`、`qrcode`、`tracing` + `tracing-appender`
- **资源内嵌**:`include_dir` 打包 `experts/`(专家技能)与 `science/`(科研技能)、`resources/codex`、`resources/opencode` 目录
- **Tauri 配置**:`tauri.conf.json`;权限在 `capabilities/{default,desktop}.json`

## 数据模型

- `db/entities/` 21 个实体:conversation、folder、folder_link、folder_command、agent_setting、custom_agent、model_provider、automation(+run)、chat_channel(+message_log/sender_context/thread_binding)、opened_tab、quick_message、remote_workspace_connection、token_usage_(turn/sync)、work_task(+event/settings/template)、app_metadata
- 迁移按日期命名(`m20260211_000001_init.rs` 起),新增变更在 `db/migration/` 建新文件并登记到 `migration/mod.rs`
- `models/` 为 API/前端共享 DTO;`db/service/` 为各实体 CRUD 服务层

## 条件编译约定

- `#[cfg(feature = "tauri-runtime")]` — 仅桌面编译(窗口、通知、`tauri::State` 参数)
- `#[cfg_attr(feature = "tauri-runtime", tauri::command)]` — 函数始终编译,桌面模式额外注册为命令
- `#[cfg(feature = "test-utils")]` — 测试脚手架(`AppState::new_for_test`、`EventEmitter::test_web_only`、parser `with_base_dir`、`db::test_helpers`),release 物理不编译
- `_core` 后缀函数 — 接受 `&AppDatabase`/`&EventEmitter` 普通引用,供 Web handler 与 Tauri 命令共用

## 测试与质量

- 单元测试:各模块 `#[cfg(test)]`;运行 `cargo test --features test-utils`
- 集成测试 `tests/`(13 个):api_integration、backup_api、parsers_snapshot(insta 快照)、codex_corpus_differential、delegation_columns、delegation_e2e_uds、delegation_e2e_windows、ws_attach、antigravity_trajectory、credential_helper_subprocess、office_watch_proxy、log_file_budget、sanity
- dev-dependencies:`insta`(JSON+redactions)、`axum-test`(含 ws)、`temp-env`、`tempfile`
- Lint:`cargo clippy --all-targets --features test-utils -- -D warnings`;服务器模式用 `--no-default-features --bin codeg-server`
- 快照更新:`cargo insta review` 或 `INSTA_UPDATE=auto`

## 常见问题 (FAQ)

- **为什么 sacp-tokio 要 vendor?** 上游 crate 需本地补丁,`[patch.crates-io]` 指向 `vendor/sacp-tokio`;升级依赖时保留该段
- **`src-tauri/binaries/` 是什么?** sidecar 二进制的按平台暂存目录(`prepare-sidecars.mjs` 生成),gitignore 产物,通过 release.yml 分发,勿提交
- **rusqlite 为什么钉在 0.32?** 其 `libsqlite3-sys`(0.30)需与 sqlx-sqlite 链接同一份 SQLite,避免符号冲突
- **新增一种代理支持?** `parsers/` 加解析器 + 更新 `parsers/mod.rs` + 补 insta 快照测试
- **HTTP 端点与桌面命令如何共存?** 业务逻辑写 `_core` 函数,`web/handlers/` 与 `commands/` 各自薄封装调用

## 资源内嵌:experts / science 技能包

随二进制内嵌(`include_dir`),运行时只读:

| 目录 | 规模 | 内容 |
|------|------|------|
| `experts/` | 14 个技能 + `experts.toml` | 编码工作流技能(brainstorming、test-driven-development、systematic-debugging、writing-plans 等 superpowers 系列) |
| `science/` | 13 个技能 + `science.toml` + `NOTICE.md` | 科研技能(experimental-design、statistical-analysis、paper-lookup、peer-review 等) |

- 注册表约定:`experts.toml` 的 `category` 必须匹配 `commands/experts.rs` 的 `ExpertCategory` 枚举;`icon` 为 lucide-react 图标名;`display_name`/`description` 按 10 语言 locale 提供(缺失回退 en),locale 集合与前端 i18n 一致。
- 同步脚本:`scripts/sync-science-skills.sh` 负责同步 science 技能资源。

## 相关文件清单(高信号)

- `Cargo.toml`(feature/二进制定义)、`tauri.conf.json`、`build.rs`、`capabilities/*.json`
- `src/lib.rs`(模块声明)、`src/app_state.rs`、`src/main.rs`、`src/bin/*.rs`
- `src/web/router.rs`、`src/web/event_bridge.rs`、`src/commands/mod.rs`
- `src/acp/mod.rs`、`src/acp/manager.rs`、`src/acp/delegation/mod.rs`
- `src/db/mod.rs`、`src/db/migration/mod.rs`、`src/models/mod.rs`
- `experts/experts.toml`、`science/science.toml`

## HTTP API 端点概览(web/router.rs 实测)

- 挂载点:全部 API 经 `.nest("/api", api)` 挂载于 `/api` 前缀下;另有 `/ws/events` WebSocket 事件流。
- 规模:约 348 条 `.route()` 注册,几乎全部为 `POST`(JSON-RPC 风格,动词式路径如 `/acp_prompt`、`/git_commit`)。
- 域分布(按 handler 模块 → 路由数):acp 67(含 agent 下载/注册表/登录/诊断)、git 51、folders 32、work_task 31、chat_channel 22、conversations 21、pet 19、forge 17、office_tools 14、files 12、version_control 11、automation 11、custom_skills 10、web_server 8、system_settings 8、science 8、mcp 8、experts 8、backup 7、folder_links 6、folder_commands 6、workspace_files 5、terminal 5、quick_messages 5、project_boot 5、logging 5、token_usage 4、model_provider 4、app_update 4 等。
- 约定:新增端点 = `web/handlers/<域>.rs` 加 handler(`Extension<Arc<AppState>>` 取状态)→ `web/router.rs` 注册一条 `.route()`,路径保持下划线动词式命名。

## 变更记录 (Changelog)

- **2026-08-31 18:10:49 — 初始化架构师生成**:基于全仓扫描创建本模块文档(329 个 Rust 源文件清点;lib.rs mod 声明、Cargo.toml 三二进制与 feature、19 解析器、21 实体、13 集成测试均经源码核实)。
- **2026-08-31 18:50 — 补扫**:补入 experts/science 技能包结构与注册表约定、`web/router.rs` HTTP API 端点概览(348 路由实测统计)、`scripts/prepare-sidecars.mjs` sidecar 机制说明。
Loading
Loading