Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,32 @@ All notable changes follow Keep a Changelog. Versions follow Semantic Versioning

## [Unreleased]

### Added

- Provider-backed `run` and `chat` CLI commands that compose the existing Agent runtime,
OpenAI-compatible or Anthropic adapters, bounded Workspace, and governed built-in tools.
- SiliconFlow configuration through `provider`, `model`, `base_url`, and the existing
`MINI_CODE_AGENT_OPENAI_API_KEY` secret environment variable.
- Rich terminal lifecycle output and explicit action previews for file writes and local argv
commands.

### Security

- Read-only tools remain allowed by default. Writes and CLI-enabled command execution require an
interactive approval; non-interactive mode denies both without prompting.
- CLI output uses normalized public errors and never renders API key values. Live provider calls
remain outside CI.
- Approval previews render model-controlled text literally and quote argv using platform-specific
display rules so Rich markup or whitespace cannot obscure argument boundaries.

### Verification

- Local uv-managed Python 3.13.14 passed 1201 tests with 13 Windows privilege/platform skips and
88.56% branch-aware package coverage. Ruff format/check and strict Pyright passed.
- MockTransport verified the SiliconFlow-compatible
`https://api.siliconflow.cn/v1/chat/completions` request path and bearer header without a live
credential. A live SiliconFlow request was not run.

## [0.16.0-alpha.0] - 2026-07-02

### Added
Expand Down
42 changes: 40 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

A framework-light, provider-neutral coding agent built from first principles.

> Status: pre-alpha. M6b provides a provider-neutral Agent Core, Anthropic/OpenAI-compatible
> Status: pre-alpha. M7 provides a provider-neutral Agent Core, Anthropic/OpenAI-compatible
> adapters, a schema-validating Tool Registry, a cross-platform Workspace boundary, bounded
> Read/Search, conflict-aware Write/Edit, policy-governed argv command execution, and deterministic
> context admission, hardened read-only Git evidence, governed Pytest diagnostics, versioned SQLite
> Session/Trace persistence, fail-closed Checkpoint/Resume, and a host-controlled bounded Repair
> loop, provenance-aware lazy Skills, deterministic host-registered Tool Hooks, and host-pinned
> local MCP stdio Tools, bounded host-profiled read-only analysis Subagents, and host-managed
> Worktree implementation candidates with separately approved adoption. OS sandboxing,
> Worktree implementation candidates with separately approved adoption, plus provider-backed
> `run` and `chat` terminal commands with governed action previews. OS sandboxing,
> shell-string execution, project-provided executable Hooks, automatic Repair resume, remote
> HTTP/OAuth MCP, automatic commit/merge/push, and live-provider CI are not implemented.

Expand Down Expand Up @@ -46,6 +47,41 @@ Default config paths follow the operating system conventions provided by Platfor
Secrets are accepted from environment variables but are never printed by `doctor`.
See `config.example.toml` for supported inputs.

## Run with SiliconFlow

Create a local config file from the example and set the API key only in the current shell:

```powershell
Copy-Item .\config.example.toml .\config.toml
$env:MINI_CODE_AGENT_OPENAI_API_KEY = "your-siliconflow-api-key"
```

Use the exact model identifier available in your SiliconFlow account. The example uses
`Pro/zai-org/GLM-4.7` with the OpenAI-compatible endpoint
`https://api.siliconflow.cn/v1`.

Run one coding task against the current workspace:

```powershell
mini-code-agent run "Inspect this project and summarize its architecture." `
--config .\config.toml `
--workspace .
```

Start an interactive task loop:

```powershell
mini-code-agent chat --config .\config.toml --workspace .
```

Each `chat` prompt starts an independent bounded Agent run against the same workspace; durable
conversation memory is not implied. Read-only tools run automatically. File writes and local argv
commands display an action preview and require explicit confirmation. Use `--non-interactive` with
`run` to deny writes and commands instead of prompting.

These commands call the configured live model API and consume provider quota. CI uses mocked HTTP
transports and never requires a real API key.

## Provider Adapters

Both adapters implement the same `ModelProvider` protocol:
Expand Down Expand Up @@ -290,7 +326,9 @@ claim token/latency improvements. See
- Product design: `docs/superpowers/specs/2026-06-29-mini-code-agent-design.md`
- Learning map: `docs/learning/knowledge-map.md`
- Learning evidence: `docs/learning/progress.md`
- M7 CLI learning notes: `docs/learning/m7-cli-provider-runtime.md`
- Resume evidence: `docs/resume/project-profile.md`
- M7 resume and interview profile: `docs/resume/m7-cli-project-profile.md`
- Agent Core: `docs/architecture/agent-core.md`
- Provider adapters: `docs/architecture/provider-adapters.md`
- Read-only tools: `docs/architecture/readonly-tools.md`
Expand Down
6 changes: 6 additions & 0 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
log_level = "info"
data_dir = ".mini-code-agent"
trace_enabled = true
provider = "openai_compatible"
model = "Pro/zai-org/GLM-4.7"
base_url = "https://api.siliconflow.cn/v1"

# Keep API keys out of this file. For SiliconFlow, set:
# MINI_CODE_AGENT_OPENAI_API_KEY
119 changes: 119 additions & 0 deletions docs/learning/m7-cli-provider-runtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# M7 学习笔记:把 Agent SDK 组装成可使用的 CLI 产品

## 1. 这一阶段解决什么问题

M6b 之前,项目已经有 Agent Loop、Provider、Tool、Policy、Workspace 等核心模块,但用户
需要自己写 Python 代码才能把它们组装起来。M7 增加应用组合根和 `run/chat` 命令,让真实
模型、工作区和受治理工具形成一个可以直接体验的闭环。

关键链路是:

```text
CLI 参数/配置
-> Provider Factory
-> Workspace + Tool Registry
-> Policy + Approval
-> AgentRuntime
-> OpenAI-compatible API
-> ToolCall / ToolResult
-> 最终回答
```

## 2. 需要掌握的知识点

### 2.1 Composition Root

`application.py` 是组合根。它不实现新的 Agent 算法,只负责创建并连接已有模块:

- 根据 `AppSettings` 创建 Provider;
- 根据工作区创建文件、Git 和命令工具;
- 用 `GovernedToolExecutor` 包装有副作用的工具;
- 创建 `AgentRuntime` 并执行任务;
- 在 `finally` 中关闭 Provider HTTP Client。

这和 Spring Boot 的配置类/Bean 装配类似。区别是 Python 项目没有依赖注入容器,依赖关系
由普通函数显式构造,因此调用顺序、所有权和测试替身更加直接。

### 2.2 OpenAI-compatible API

硅基流动使用 OpenAI-compatible Chat Completions 协议。项目只需要配置:

```text
provider = openai_compatible
model = 账户中实际可用的模型 ID
base_url = https://api.siliconflow.cn/v1
```

`OpenAICompatibleProvider` 会在 base URL 后追加 `chat/completions`。模型返回的
`tool_calls` 被规范化为项目内部 `ToolCall`,工具执行结果再转换回兼容协议消息。

### 2.3 配置与密钥边界

配置优先级仍然是:

```text
默认值 < TOML < MINI_CODE_AGENT_* 环境变量 < 显式 overrides
```

`provider/model/base_url` 可以进入 TOML;API Key 只建议使用环境变量。`SecretStr` 和
`safe_dict()` 防止 `doctor`、错误日志或诊断输出直接显示密钥。

### 2.4 同步 CLI 与异步 Agent

Typer 命令是同步函数,而 Provider、Tool 和 Agent Runtime 是异步接口。CLI 使用
`asyncio.run()` 建立每次任务的 event loop。这适合普通终端进程,但不能直接复制到已经拥有
event loop 的 Jupyter、FastAPI 请求处理或异步测试中;这些场景应直接 `await run_task()`。

### 2.5 Capability 与 Approval

CLI 注册工具不代表模型自动获得执行授权:

- Read/Search/Git status/diff 是只读能力,默认允许;
- Write/Edit 默认进入 `ASK`;
- Execute 默认是 `DENY`,M7 只为 `run_command` 增加明确的 `ASK` 规则;
- `--non-interactive` 不弹审批,而是拒绝所有 `ASK` 操作。

审批器展示工具名、风险、理由、资源、argv 和 bounded diff。模型只能提出动作,不能替用户
批准动作。

### 2.6 资源所有权

Provider 内部创建的 `httpx.AsyncClient` 必须关闭。`run_task()` 在成功、Provider 错误和
Runtime 失败时都进入 `finally`。测试通过可关闭的 `ScriptedProvider` 验证这一点。

## 3. Java / Flink / Spark SQL 经验映射

| 现有经验 | M7 对应概念 | 关键差异 |
|---|---|---|
| Spring `@Configuration` | `application.py` composition root | 依赖由普通函数显式创建,没有容器生命周期 |
| Spring `@ConfigurationProperties` | Pydantic `AppSettings` | 字段校验与环境变量合并由 Pydantic Settings 完成 |
| Feign/WebClient | `OpenAICompatibleProvider` + `httpx` | 响应不仅是 DTO,还可能驱动 ToolCall 状态机 |
| Java `try/finally` / `AutoCloseable` | Provider `aclose()` in `finally` | HTTP Client 是异步资源,需要 `await` |
| RBAC/接口鉴权 | Tool Policy allow/ask/deny | 授权对象是一次具体的模型动作,不是用户页面权限 |
| Flink operator graph | Provider -> Runtime -> Tool pipeline | Agent 路径由模型响应动态决定,不是预先固定 DAG |
| SQL dry-run / execution plan | `ActionPreview` | 预览只用于人工决策,不能替代执行前重验证 |

## 4. 建议练习

1. 用 `httpx.MockTransport` 抓取请求,确认 SiliconFlow URL、Authorization 和 model 字段。
2. 让模拟 Provider 先调用 `read_file`,再返回最终答案,画出完整消息序列。
3. 让模拟 Provider 请求 `write_file`,分别验证批准、拒绝和 non-interactive 三条路径。
4. 修改模型 ID 或 base URL,观察错误发生在配置期、网络期还是协议解析期。
5. 阅读 `tests/unit/test_application.py`,解释为什么真实 API 不应进入默认 CI。

## 5. 当前边界

- `chat` 是同一工作区上的交互任务循环,每条输入是独立 Agent run,不是持久对话。
- Runtime 当前使用非流式 `complete()`,终端展示生命周期事件,但不逐 Token 输出。
- CLI 尚未组合 SQLite Trace/Checkpoint、Skills、MCP、Subagent 和 Worktree candidate。
- 真实 SiliconFlow 调用需要用户本地 API Key,并会消耗账户额度。
- 命令治理和 Workspace boundary 不是 OS sandbox。

## 6. 当前验证证据

- uv 管理的 Python 3.13.14:1201 passed、13 个 Windows 权限/平台条件 skip。
- branch-aware package coverage:88.56%,高于 85% 门槛。
- Ruff format/check:通过。
- strict Pyright:0 errors。
- `httpx.MockTransport`:验证 SiliconFlow-compatible URL 和 Bearer Header。
- 真实 SiliconFlow API:未执行,因为验证环境没有配置用户 API Key。
105 changes: 105 additions & 0 deletions docs/resume/m7-cli-project-profile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Mini CodeAgent M7 简历与面试说明

## 项目介绍

Mini CodeAgent 是一个从零实现、Framework-light、Provider-neutral 的 Python Coding Agent。
项目将大模型 Tool Calling、受限工作区、工具权限、人工审批、上下文预算、Trace/Checkpoint、
MCP、Subagent 和 Worktree candidate 拆成可测试模块。M7 在此基础上增加 Provider-backed
CLI,使用户可以通过 SiliconFlow 等 OpenAI-compatible 服务直接执行代码分析和修改任务。

## 技术栈

- Python 3.12/3.13、asyncio、强类型 Protocol
- Pydantic、Pydantic Settings
- Typer、Rich
- httpx、OpenAI-compatible Chat Completions、Anthropic Messages
- JSON Schema Draft 2020-12
- Pytest、pytest-asyncio、httpx MockTransport
- Ruff、Pyright、GitHub Actions

## 面试介绍版本

“我做了一个 Python Mini Coding Agent。核心不是简单调用一次大模型,而是实现
Model -> ToolCall -> ToolResult -> Model 的有界执行循环,并把文件、Git 和本地命令封装成
受治理工具。M7 增加了应用组合根和 Typer CLI,可以切换 OpenAI-compatible 或 Anthropic
Provider,也可以直接接硅基流动。读操作默认允许,写文件和执行命令必须先展示资源、argv 或
diff,再由用户批准;非交互模式全部 fail closed。真实密钥只从环境变量读取,测试使用
MockTransport 和 ScriptedProvider,不消耗线上额度。”

## 项目亮点

### 1. Provider-neutral 的真实模型接入

**为什么使用:** 避免 Agent 核心绑定某一家模型厂商,也便于利用不同平台的额度和模型能力。

**技术实现:** 通过统一 `ModelProvider` 协议隔离内部消息模型与厂商 wire protocol;
`build_provider()` 根据强类型配置创建 OpenAI-compatible 或 Anthropic Adapter。硅基流动只需
配置 model、base URL 和环境变量 API Key。

**实现功能:** 同一套 Agent Runtime 可以调用不同 Provider,并支持 Tool Calling。

**解决问题:** 消除业务循环中的厂商条件分支,降低更换模型服务时的修改范围。

**证据:** `src/mini_code_agent/application.py`、
`tests/unit/test_application.py::test_openai_compatible_provider_uses_siliconflow_endpoint`。

### 2. 显式 Composition Root

**为什么使用:** SDK 模块齐全不等于产品可运行;必须有一个地方明确管理依赖、资源和安全策略。

**技术实现:** `application.py` 统一创建 Provider、Workspace、Tool Registry、Policy、
Approval 和 AgentRuntime,并在 `finally` 中关闭 Provider Client。

**实现功能:** `run` 和 `chat` 不需要重复装配代码,测试可以注入 ScriptedProvider。

**解决问题:** 避免 CLI、Web 或测试各自复制装配逻辑,减少策略不一致和资源泄漏。

**证据:** `run_task()` 及成功/失败关闭资源测试。

### 3. 模型不可自授权的工具治理

**为什么使用:** Coding Agent 会修改文件和执行命令,模型输出不能直接等价为用户授权。

**技术实现:** Tool Definition 标记 side effect;Policy 产生 allow/ask/deny;写入沿用默认
ASK,命令执行从默认 DENY 提升为 CLI 明确 ASK;`TerminalApprovalHandler` 展示 ActionPreview
后才返回决定。

**实现功能:** 只读分析自动执行,写文件和 argv 命令逐次审批,non-interactive 模式自动拒绝。

**解决问题:** 阻止模型静默落盘或执行本地进程,并为用户提供可判断的资源和 diff 信息。

**证据:** `build_tool_executor()`、`TerminalApprovalHandler` 及审批测试。

### 4. 密钥安全与可测试的线上协议

**为什么使用:** API Key 泄漏和 CI 消耗真实 Token 都是 Agent 项目的常见工程风险。

**技术实现:** Key 使用 `SecretStr` 和环境变量;诊断只输出 configured 布尔值;HTTP 测试使用
`httpx.MockTransport` 验证真实 URL/Header/Response parsing,不连接公网。

**实现功能:** 能验证 SiliconFlow 接口兼容性,同时保持默认测试确定性。

**解决问题:** 防止密钥进入仓库、日志和测试报告,也避免 CI 受网络、额度和模型漂移影响。

**证据:** `AppSettings.safe_dict()`、配置测试和 SiliconFlow endpoint 测试。

### 5. 稳定的 CLI 错误与退出码

**为什么使用:** Agent 可能因配置、鉴权、限流或工具边界停止,脚本和用户需要区分失败类型。

**技术实现:** 配置/组合错误返回退出码 2;Agent 未完成返回 1;完成返回 0;终端只显示 bounded
public error 和运行摘要。

**实现功能:** 既适合人工使用,也可被 PowerShell、CI 或其他进程可靠调用。

**解决问题:** 避免所有错误都变成 Traceback 或模糊的非零状态。

**证据:** `tests/cli/test_cli.py` 中 run 成功、配置错误和 Provider 错误测试。

## 诚实边界

- 不描述为 Claude Code 的完整替代品;当前没有全屏 TUI 或 Web UI。
- 不声称 `chat` 已有跨 run 的持久对话记忆。
- 不声称默认 CI 已验证真实 SiliconFlow 服务;真实 smoke 需要本地凭证。
- 不把 Workspace/Policy 描述为 OS sandbox。
- 不编造 Token、准确率、开发效率等百分比提升;没有 benchmark 就不写量化结果。
Loading
Loading