You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
6.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 02 架构与目录
源码落地:`D:\ideaProject\gcode`(本次只定结构,不建库)。
## 分层
```text
┌─────────────────────────────────────────────┐
│ ui/detect + tui / repl │
│ 探测终端、画界面、收集确认(y/N、diff) │
├─────────────────────────────────────────────┤
│ graph + session + prompt │
│ ReAct、checkpoint、静态/动态提示词 │
├─────────────────────────────────────────────┤
│ models(注册表 + openai_compatible) │
├─────────────────────────────────────────────┤
│ tools + safety + mcp │
│ 文件/命令沙箱、HITL、Playwright MCP │
└─────────────────────────────────────────────┘
```
依赖只能从上到下。工具不得 `import` 图模块去改全局 `llm` / `agent`。TUI 与 REPL 都只消费 `graph.astream(...)`。
```mermaid
flowchart LR
detect[终端探测] -->|WT 等| tui[自研TUI]
detect -->|conhost| repl[REPL回退]
tui --> graph[LangGraph ReAct]
repl --> graph
graph --> llmCall[llm_call]
llmCall -->|tool_calls| toolNode[tool_node]
toolNode --> safety[HITL]
safety --> llmCall
llmCall -->|纯文本| uiOut[TUI或REPL渲染]
```
## 目录骨架
```text
D:\ideaProject\gcode\
pyproject.toml
README.md
src/gcode/
__init__.py
cli.py # 入口:解析参数、探测、选 UI
config.py # 单一 home:%APPDATA%\gcode 与 <cwd>/.gcode
windows.py # 代码页、默认 PowerShell、Job Object / taskkill
prompt.py
graph.py # StateGraph:llm_call / tool_node
session.py # sqlite checkpointer + thread_id
safety.py # 写文件 diff、shell 确认;回调由 UI 注入
ui/
detect.py
repl.py
tui/ # 自研 Textual,不拷 Qoze CSS/logo
models/
registry.py # 读 models.yaml
openai_compatible.py
tools/
fs.py
shell.py
mcp/
client.py # 薄客户端,默认只起 @playwright/mcp
tests/
test_path_sandbox.py
test_graph_smoke.py
test_detect_terminal.py
```
项目级数据:`<cwd>/.gcode/`(checkpoints、rules、debug log)。
用户级:`%APPDATA%\gcode\`(`models.yaml`、mcp 配置、token 统计)。禁止再混用 `~\.gcode` 与 `%APPDATA%` 两套根。
## Prompt 怎么写
不要一上来写 400 行。对照 Qoze 的 [system_prompt.py](D:\ideaProject\QozeCode-main\utils\system_prompt.py) 学 **静态/动态拆分**,不要整段粘贴。G-CODE 工具清单不同,抄过来模型会去调不存在的 `dispatch_subagent`。
每次加一段之前问:
1. 模型此刻有哪些工具?没实现的一句不写
2. 最容易做错的 3 件事?只为这些写硬规则
3. 静态还是动态?每次一样 → System;会变(cwd、git、rules)→ 动态段
4. 能用代码拦住的不要只靠文字(路径沙箱在 `read_file` 里拒绝)
5. 用失败任务加规则,不用想象加规则
静态段先控制在 80~150 行:身份、工具怎么选、5~8 条硬规则、ReAct 与「连续 3 次无进展就问人」、中文推理、TUI 内避免 emoji。
动态段保持短:cwd、目录树摘要、git 摘要、`.gcode/rules`。
## 多模型
不复制 Qoze 的枚举树。`models.yaml` 示例:
```yaml
providers:
deepseek:
api: openai_compatible
base_url: https://api.deepseek.com/v1
api_key_env: DEEPSEEK_API_KEY
models:
- id: deepseek-v4-flash
vision: false
reasoning: false
- id: deepseek-v4-pro
vision: false
reasoning: true
agicto:
api: openai_compatible
base_url: https://api.agicto.cn/v1
api_key_env: GCODE_API_KEY
models:
- id: deepseek-v4-flash
vision: false
reasoning: false
```
一期只实现 `openai_compatible`。加一家模型改 yaml,不改 Python。`reasoning_content` 尽量显式解析,避免猴子补丁 LangChain。Vertex / Anthropic / Bedrock 有账号再加 adapter。
启动:`gcode --model deepseek-v4-flash` 或 TUI 内选择。
## 人在回路
`safety.py` 定义确认点,UI 注入回调(TUI 用对话框,REPL 用 y/N):
| 动作 | 展示 | 拒绝时 |
|------|------|--------|
| 写文件 / 替换 | unified diff | ToolMessage:「用户拒绝本次写入」 |
| `execute_command` | 完整命令 + 工作目录 | ToolMessage:「用户拒绝执行该命令」 |
读文件、列目录、只读 git 不必确认。安装依赖、构建、测试、`git commit` / `push` 必须走确认(prompt 硬规则 + HITL 双保险)。
## 工具
一期内置:
- `read_file` / `list_dir` / `replace_in_file`:仅 cwd 或用户级 gcode 目录;拒绝 `..`
- `execute_command`:默认 PowerShell;输出 UTF-8 失败则 GBK;超时用 Job Object 或 `taskkill /T`,不要只 `terminate()` 留孤儿
浏览器不进 `tools/` 进程内实现,见下一节。
## Playwright MCP(仅途径 A)
官方:`npx -y @playwright/mcp@latest`。
G-CODE 薄 MCP 客户端:stdio 拉起 → 把 tools 动态交给 `bind_tools`。MCP 只当 Playwright 插座,一期不接 GitHub / Postgres。不复活 Qoze 已注释的 `browser_tool.py`,不默认 `chrome-devtools-mcp`(那是 `--remote-debugging-port=9222` 附着已开 Chrome)。
硬依赖 Node.js / npx。检测不到则 TUI/REPL 提示「浏览器工具不可用,请安装 Node.js」,没有 Python Playwright 备选。
## 相对 Qoze 必须避开的结构
- 模块级全局 `llm`、`agent`、`tools_by_name` 被 MCP/TUI 到处改
- `mcp_tools` / `subagent_tool` 反向 import `qoze_code_agent`
- `qoze_tui.py` 里命令路由、拼消息、token、流式全混在一个 App 类
- 配置路径分裂:`%APPDATA%\qoze` vs `~\.qoze`
- shell 一律按 UTF-8 解码(cmd 的 `dir` 常为 GBK)