pyminicode 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyminicode-0.1.0/PKG-INFO +265 -0
- pyminicode-0.1.0/README.md +240 -0
- pyminicode-0.1.0/pyminicode.egg-info/PKG-INFO +265 -0
- pyminicode-0.1.0/pyminicode.egg-info/SOURCES.txt +46 -0
- pyminicode-0.1.0/pyminicode.egg-info/dependency_links.txt +1 -0
- pyminicode-0.1.0/pyminicode.egg-info/entry_points.txt +2 -0
- pyminicode-0.1.0/pyminicode.egg-info/requires.txt +9 -0
- pyminicode-0.1.0/pyminicode.egg-info/top_level.txt +1 -0
- pyminicode-0.1.0/pyproject.toml +46 -0
- pyminicode-0.1.0/setup.cfg +4 -0
- pyminicode-0.1.0/tests/test_agent.py +435 -0
- pyminicode-0.1.0/tests/test_agent_loader.py +112 -0
- pyminicode-0.1.0/tests/test_agent_runtime.py +219 -0
- pyminicode-0.1.0/tests/test_anthropic.py +89 -0
- pyminicode-0.1.0/tests/test_base.py +76 -0
- pyminicode-0.1.0/tests/test_bus.py +250 -0
- pyminicode-0.1.0/tests/test_chat_cli.py +210 -0
- pyminicode-0.1.0/tests/test_chatbridge_adapter.py +152 -0
- pyminicode-0.1.0/tests/test_chatbridge_manager.py +332 -0
- pyminicode-0.1.0/tests/test_chatbridge_stdio.py +109 -0
- pyminicode-0.1.0/tests/test_chatbridge_webhook.py +140 -0
- pyminicode-0.1.0/tests/test_cli_input.py +86 -0
- pyminicode-0.1.0/tests/test_config.py +337 -0
- pyminicode-0.1.0/tests/test_context_view.py +102 -0
- pyminicode-0.1.0/tests/test_demo.py +30 -0
- pyminicode-0.1.0/tests/test_display.py +301 -0
- pyminicode-0.1.0/tests/test_e2e_mcp.py +66 -0
- pyminicode-0.1.0/tests/test_goal_cli.py +294 -0
- pyminicode-0.1.0/tests/test_goal_judge.py +281 -0
- pyminicode-0.1.0/tests/test_goal_service.py +148 -0
- pyminicode-0.1.0/tests/test_goal_types.py +96 -0
- pyminicode-0.1.0/tests/test_hooks_dispatcher.py +213 -0
- pyminicode-0.1.0/tests/test_hooks_python.py +181 -0
- pyminicode-0.1.0/tests/test_hooks_shell.py +267 -0
- pyminicode-0.1.0/tests/test_hooks_types.py +108 -0
- pyminicode-0.1.0/tests/test_memory_budget.py +89 -0
- pyminicode-0.1.0/tests/test_memory_compact.py +56 -0
- pyminicode-0.1.0/tests/test_memory_context.py +63 -0
- pyminicode-0.1.0/tests/test_memory_history.py +121 -0
- pyminicode-0.1.0/tests/test_memory_loaders.py +54 -0
- pyminicode-0.1.0/tests/test_memory_status.py +44 -0
- pyminicode-0.1.0/tests/test_memory_truncation.py +131 -0
- pyminicode-0.1.0/tests/test_model_registry.py +120 -0
- pyminicode-0.1.0/tests/test_openai_compat.py +271 -0
- pyminicode-0.1.0/tests/test_permission.py +425 -0
- pyminicode-0.1.0/tests/test_registry.py +116 -0
- pyminicode-0.1.0/tests/test_skill_loader.py +72 -0
- pyminicode-0.1.0/tests/test_subagent_tool.py +126 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyminicode
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Terminal-native AI coding assistant (Python)
|
|
5
|
+
Author: Wangzheng Yuan
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: pydantic>=2.6
|
|
18
|
+
Requires-Dist: httpx>=0.27
|
|
19
|
+
Requires-Dist: anyio>=4.3
|
|
20
|
+
Requires-Dist: PyYAML>=6.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
24
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
25
|
+
|
|
26
|
+
# minicode
|
|
27
|
+
|
|
28
|
+
Terminal-native AI coding assistant, implemented in Python.
|
|
29
|
+
|
|
30
|
+
> **当前状态**:已完成**工具层**([v0])和**模型层**([v1])。能加载 LLM、切换 provider、流式测试连通性。
|
|
31
|
+
> 下一版([v2])会接入 ReAct 循环(输入 → LLM → 工具调用 → 回灌 → 循环)。
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# 1. install
|
|
37
|
+
pip install -e .
|
|
38
|
+
|
|
39
|
+
# 2. 跑起来(首次会自动建 .minicode/)
|
|
40
|
+
minicode
|
|
41
|
+
|
|
42
|
+
# 一次性命令
|
|
43
|
+
minicode --version
|
|
44
|
+
minicode --paths
|
|
45
|
+
minicode --print-tools # 列工具
|
|
46
|
+
minicode --print-models # 列 model provider
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Layout
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
minicode/
|
|
53
|
+
├── pyproject.toml
|
|
54
|
+
├── README.md
|
|
55
|
+
├── .minicode/ # per-project config dir
|
|
56
|
+
│ ├── skills/ # skill files
|
|
57
|
+
│ │ ├── code-review/SKILL.md
|
|
58
|
+
│ │ ├── refactor/SKILL.md
|
|
59
|
+
│ │ └── test-gen/SKILL.md
|
|
60
|
+
│ ├── mcp.json # MCP server config (stdio / http)
|
|
61
|
+
│ └── config.yaml # LLM provider 配置
|
|
62
|
+
├── minicode/ # source
|
|
63
|
+
│ ├── __init__.py
|
|
64
|
+
│ ├── __main__.py
|
|
65
|
+
│ ├── paths.py # .minicode 路径解析
|
|
66
|
+
│ ├── config.py # config.yaml 加载
|
|
67
|
+
│ ├── tool/ # 工具层
|
|
68
|
+
│ │ ├── base.py # Tool 抽象基类 + ToolContext + ToolResult
|
|
69
|
+
│ │ ├── registry.py # ToolRegistry
|
|
70
|
+
│ │ ├── skill.py # SkillLoader
|
|
71
|
+
│ │ ├── mcp.py # McpClient + McpToolAdapter
|
|
72
|
+
│ │ └── builtin/ # 7 个内置工具
|
|
73
|
+
│ ├── model/ # 模型层
|
|
74
|
+
│ │ ├── base.py # Model 抽象基类 + ModelResponse/Event
|
|
75
|
+
│ │ ├── message.py # Message / Part / ToolSchema
|
|
76
|
+
│ │ ├── openai_compat.py # OpenAI Chat Completions (覆盖 ollama/vllm/DeepSeek/OpenAI)
|
|
77
|
+
│ │ ├── anthropic.py # Anthropic Messages API
|
|
78
|
+
│ │ ├── demo.py # 假 provider(echo),无需 apikey
|
|
79
|
+
│ │ └── registry.py # ModelRegistry
|
|
80
|
+
│ └── cli/
|
|
81
|
+
│ └── app.py # REPL + /tools /skills /mcp /models /model /call
|
|
82
|
+
└── tests/ # 单测 + 端到端冒烟
|
|
83
|
+
├── test_base.py
|
|
84
|
+
├── test_skill_loader.py
|
|
85
|
+
├── test_registry.py # 工具层端到端
|
|
86
|
+
├── test_config.py # config.yaml 加载
|
|
87
|
+
├── test_model_registry.py # ModelRegistry
|
|
88
|
+
├── test_openai_compat.py # 用 httpx MockTransport 模拟 SSE
|
|
89
|
+
├── test_anthropic.py
|
|
90
|
+
├── test_demo.py
|
|
91
|
+
├── demo_mcp_server.py
|
|
92
|
+
└── test_e2e_mcp.py
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## config.yaml 格式
|
|
96
|
+
|
|
97
|
+
`.minicode/config.yaml`:
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
default: openai # 可选:默认 provider id
|
|
101
|
+
|
|
102
|
+
providers:
|
|
103
|
+
openai:
|
|
104
|
+
type: openai-compat # openai-compat | anthropic | demo
|
|
105
|
+
api_key: ${OPENAI_API_KEY} # ${ENV_VAR} 自动展开
|
|
106
|
+
base_url: https://api.openai.com/v1
|
|
107
|
+
model: gpt-4o
|
|
108
|
+
extra: # 透传给 provider
|
|
109
|
+
timeout: 60
|
|
110
|
+
temperature: 0.7
|
|
111
|
+
max_tokens: 4096
|
|
112
|
+
|
|
113
|
+
anthropic:
|
|
114
|
+
type: anthropic
|
|
115
|
+
api_key: ${ANTHROPIC_API_KEY}
|
|
116
|
+
base_url: https://api.anthropic.com
|
|
117
|
+
model: claude-3-5-sonnet-20241022
|
|
118
|
+
extra:
|
|
119
|
+
max_tokens: 4096
|
|
120
|
+
|
|
121
|
+
demo: # 假 provider(开箱即用)
|
|
122
|
+
type: demo
|
|
123
|
+
base_url: "(in-process)"
|
|
124
|
+
model: demo-echo
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`type` 字段:
|
|
128
|
+
- `openai-compat` — 任何实现 OpenAI Chat Completions 的服务(OpenAI/DeepSeek/Moonshot/ollama/vllm/...)
|
|
129
|
+
- `anthropic` — Anthropic Messages API
|
|
130
|
+
- `demo` — 进程内回显,无需网络
|
|
131
|
+
|
|
132
|
+
`extra` 字段透传给 provider 实现(OpenAI:`temperature`/`top_p`/`presence_penalty`;Anthropic:`max_tokens` 必填/`temperature`/`top_k`)。
|
|
133
|
+
|
|
134
|
+
## CLI 命令
|
|
135
|
+
|
|
136
|
+
| 命令 | 作用 |
|
|
137
|
+
| --- | --- |
|
|
138
|
+
| `/tools` | 列出所有工具(builtin + skill + mcp) |
|
|
139
|
+
| `/skills` | 列出 skill |
|
|
140
|
+
| `/mcp` | 列出 MCP server + 工具 |
|
|
141
|
+
| `/models` | 列出 `config.yaml` 中所有 LLM provider,标 current |
|
|
142
|
+
| `/model` | 显示当前 model 详情 |
|
|
143
|
+
| `/model <id>` | 切换到指定 provider |
|
|
144
|
+
| `/model test` | 流式发 "ping" 测试当前 model 的连通性 |
|
|
145
|
+
| `/paths` | 路径解析 |
|
|
146
|
+
| `/call <id> [json]` | 手动调用一个工具 |
|
|
147
|
+
| `/reload` | 重新 build registry |
|
|
148
|
+
| `/help` | 帮助 |
|
|
149
|
+
| `/exit` | 退出 |
|
|
150
|
+
|
|
151
|
+
## 工具协议
|
|
152
|
+
|
|
153
|
+
所有工具实现同一接口([minicode/tool/base.py](minicode/tool/base.py)):
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
class Tool(ABC):
|
|
157
|
+
kind: ToolKind = ToolKind.BUILTIN
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def id(self) -> str: ...
|
|
161
|
+
@property
|
|
162
|
+
def description(self) -> str: ...
|
|
163
|
+
@property
|
|
164
|
+
def parameters(self) -> type[BaseModel]: ...
|
|
165
|
+
@abstractmethod
|
|
166
|
+
async def execute(self, args: BaseModel, ctx: ToolContext) -> ToolResult: ...
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
- `parameters` 是 Pydantic BaseModel,自动生成 JSON Schema 给 LLM
|
|
170
|
+
- `ToolKind`: BUILTIN / SKILL / MCP / CUSTOM
|
|
171
|
+
|
|
172
|
+
## Model 协议
|
|
173
|
+
|
|
174
|
+
所有 Model 实现同一接口([minicode/model/base.py](minicode/model/base.py)):
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
class Model(ABC):
|
|
178
|
+
@property
|
|
179
|
+
def info(self) -> ModelInfo: ... # id / type / base_url / model
|
|
180
|
+
@property
|
|
181
|
+
def api_key(self) -> str: ...
|
|
182
|
+
@property
|
|
183
|
+
def extra(self) -> dict: ...
|
|
184
|
+
|
|
185
|
+
@abstractmethod
|
|
186
|
+
async def stream(
|
|
187
|
+
self,
|
|
188
|
+
messages: List[Message],
|
|
189
|
+
tools: Optional[List[ToolSchema]] = None,
|
|
190
|
+
system: Optional[str] = None,
|
|
191
|
+
) -> AsyncIterator[ModelEvent]: ... # 流式产出 text_delta / tool_call_delta / usage / finish / error
|
|
192
|
+
|
|
193
|
+
async def complete(...) -> ModelResponse: # 基类默认实现:把 stream 攒起来
|
|
194
|
+
...
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
- 协议不感知 Tool/MCP,只接收 `ToolSchema`(与 `ToolDef` 解耦)
|
|
198
|
+
- HTTP 错误用 `yield ModelEvent(type="error", error=...)` 表达,不抛
|
|
199
|
+
|
|
200
|
+
## 架构
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
.minicode/skills/ .minicode/mcp.json .minicode/config.yaml
|
|
204
|
+
│ │ │
|
|
205
|
+
scan ▼ load ▼ load ▼
|
|
206
|
+
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
207
|
+
│SkillLoader │ │ McpClient │ │ ModelRegistry │
|
|
208
|
+
│ │ │ (stdio+http) │ │ (openai/anthropic/demo) │
|
|
209
|
+
└──────┬──────┘ └────────┬────────┘ └────────┬────────┘
|
|
210
|
+
│ │ │
|
|
211
|
+
│ inject │ tools/list │ build
|
|
212
|
+
▼ ▼ ▼
|
|
213
|
+
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
214
|
+
│ SkillTool │ │ McpToolAdapter │ │ OpenAICompat │
|
|
215
|
+
│ (builtin) │ │ (kind=MCP) │ │ Anthropic │
|
|
216
|
+
└─────────────┘ └─────────────────┘ │ Demo │
|
|
217
|
+
└─────────────────┘
|
|
218
|
+
│ │ │
|
|
219
|
+
│ ┌────────────────────┴────────────────────────┐ │
|
|
220
|
+
└───────▶│ ToolRegistry │ │
|
|
221
|
+
│ id → ToolDef (all kinds) │ │
|
|
222
|
+
└────────────────────┬────────────────────────┘ │
|
|
223
|
+
│ │
|
|
224
|
+
│ tools │ model
|
|
225
|
+
▼ ▼
|
|
226
|
+
┌──────────────────────────┐ ┌────────────────┐
|
|
227
|
+
│ ReAct 循环(v2 待做) │ │ /model test │
|
|
228
|
+
└──────────────────────────┘ └────────────────┘
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## 与原 mimo code 的差异
|
|
232
|
+
|
|
233
|
+
| 维度 | mimo code (TS) | minicode (Py) |
|
|
234
|
+
| --- | --- | --- |
|
|
235
|
+
| 语言 | TypeScript + Effect | Python 3.10+ + Pydantic |
|
|
236
|
+
| 异步模型 | Effect.gen | async/await |
|
|
237
|
+
| 工具 schema | zod | Pydantic BaseModel |
|
|
238
|
+
| MCP SDK | 官方 @modelcontextprotocol/sdk | 自研最小 JSON-RPC over stdio/http |
|
|
239
|
+
| 内置工具数 | 21 | 7(保留核心) |
|
|
240
|
+
| Skill 协议 | 完整(嵌套 + 外部目录 + 远程拉取) | 简化(`<name>/SKILL.md` + frontmatter) |
|
|
241
|
+
| Model 协议 | Vercel AI SDK | 自研(`stream()` + `complete()`) |
|
|
242
|
+
| provider | 11 种 | 2 种(openai-compat + anthropic)+ 1 demo |
|
|
243
|
+
| LLM 循环 | 接好 | **未接**(v2) |
|
|
244
|
+
|
|
245
|
+
## 下一步
|
|
246
|
+
|
|
247
|
+
1. **ReAct 循环**(v2):把 `ToolRegistry` 的工具转成 `ToolSchema` 给 LLM,处理 `tool_call_delta` → 调 `ToolRegistry.execute` → 灌回 `Message.tool_result` → 下一轮
|
|
248
|
+
2. **权限系统**:完善 `ctx.ask` 的实际行为(allow/deny/ask)
|
|
249
|
+
3. **truncate 服务**:超过阈值的输出写入临时文件,原始位置放占位
|
|
250
|
+
4. **plugin / hooks**:参照 mimo code 的 plugin system
|
|
251
|
+
5. **Google provider**(v3):Gemini generateContent
|
|
252
|
+
|
|
253
|
+
## 测试
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
pip install pytest pytest-asyncio
|
|
257
|
+
python -m pytest tests/ -v
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
应该看到 39 个测试全过。
|
|
261
|
+
|
|
262
|
+
## 已知问题
|
|
263
|
+
|
|
264
|
+
- Windows 终端默认 GBK 编码会乱码。在自己的终端跑前请先 `chcp 65001` 或换 Windows Terminal + Cascadia Code。
|
|
265
|
+
- v2 才接 LLM 循环。/model test 用来单点测试连通性。
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# minicode
|
|
2
|
+
|
|
3
|
+
Terminal-native AI coding assistant, implemented in Python.
|
|
4
|
+
|
|
5
|
+
> **当前状态**:已完成**工具层**([v0])和**模型层**([v1])。能加载 LLM、切换 provider、流式测试连通性。
|
|
6
|
+
> 下一版([v2])会接入 ReAct 循环(输入 → LLM → 工具调用 → 回灌 → 循环)。
|
|
7
|
+
|
|
8
|
+
## Quick start
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# 1. install
|
|
12
|
+
pip install -e .
|
|
13
|
+
|
|
14
|
+
# 2. 跑起来(首次会自动建 .minicode/)
|
|
15
|
+
minicode
|
|
16
|
+
|
|
17
|
+
# 一次性命令
|
|
18
|
+
minicode --version
|
|
19
|
+
minicode --paths
|
|
20
|
+
minicode --print-tools # 列工具
|
|
21
|
+
minicode --print-models # 列 model provider
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Layout
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
minicode/
|
|
28
|
+
├── pyproject.toml
|
|
29
|
+
├── README.md
|
|
30
|
+
├── .minicode/ # per-project config dir
|
|
31
|
+
│ ├── skills/ # skill files
|
|
32
|
+
│ │ ├── code-review/SKILL.md
|
|
33
|
+
│ │ ├── refactor/SKILL.md
|
|
34
|
+
│ │ └── test-gen/SKILL.md
|
|
35
|
+
│ ├── mcp.json # MCP server config (stdio / http)
|
|
36
|
+
│ └── config.yaml # LLM provider 配置
|
|
37
|
+
├── minicode/ # source
|
|
38
|
+
│ ├── __init__.py
|
|
39
|
+
│ ├── __main__.py
|
|
40
|
+
│ ├── paths.py # .minicode 路径解析
|
|
41
|
+
│ ├── config.py # config.yaml 加载
|
|
42
|
+
│ ├── tool/ # 工具层
|
|
43
|
+
│ │ ├── base.py # Tool 抽象基类 + ToolContext + ToolResult
|
|
44
|
+
│ │ ├── registry.py # ToolRegistry
|
|
45
|
+
│ │ ├── skill.py # SkillLoader
|
|
46
|
+
│ │ ├── mcp.py # McpClient + McpToolAdapter
|
|
47
|
+
│ │ └── builtin/ # 7 个内置工具
|
|
48
|
+
│ ├── model/ # 模型层
|
|
49
|
+
│ │ ├── base.py # Model 抽象基类 + ModelResponse/Event
|
|
50
|
+
│ │ ├── message.py # Message / Part / ToolSchema
|
|
51
|
+
│ │ ├── openai_compat.py # OpenAI Chat Completions (覆盖 ollama/vllm/DeepSeek/OpenAI)
|
|
52
|
+
│ │ ├── anthropic.py # Anthropic Messages API
|
|
53
|
+
│ │ ├── demo.py # 假 provider(echo),无需 apikey
|
|
54
|
+
│ │ └── registry.py # ModelRegistry
|
|
55
|
+
│ └── cli/
|
|
56
|
+
│ └── app.py # REPL + /tools /skills /mcp /models /model /call
|
|
57
|
+
└── tests/ # 单测 + 端到端冒烟
|
|
58
|
+
├── test_base.py
|
|
59
|
+
├── test_skill_loader.py
|
|
60
|
+
├── test_registry.py # 工具层端到端
|
|
61
|
+
├── test_config.py # config.yaml 加载
|
|
62
|
+
├── test_model_registry.py # ModelRegistry
|
|
63
|
+
├── test_openai_compat.py # 用 httpx MockTransport 模拟 SSE
|
|
64
|
+
├── test_anthropic.py
|
|
65
|
+
├── test_demo.py
|
|
66
|
+
├── demo_mcp_server.py
|
|
67
|
+
└── test_e2e_mcp.py
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## config.yaml 格式
|
|
71
|
+
|
|
72
|
+
`.minicode/config.yaml`:
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
default: openai # 可选:默认 provider id
|
|
76
|
+
|
|
77
|
+
providers:
|
|
78
|
+
openai:
|
|
79
|
+
type: openai-compat # openai-compat | anthropic | demo
|
|
80
|
+
api_key: ${OPENAI_API_KEY} # ${ENV_VAR} 自动展开
|
|
81
|
+
base_url: https://api.openai.com/v1
|
|
82
|
+
model: gpt-4o
|
|
83
|
+
extra: # 透传给 provider
|
|
84
|
+
timeout: 60
|
|
85
|
+
temperature: 0.7
|
|
86
|
+
max_tokens: 4096
|
|
87
|
+
|
|
88
|
+
anthropic:
|
|
89
|
+
type: anthropic
|
|
90
|
+
api_key: ${ANTHROPIC_API_KEY}
|
|
91
|
+
base_url: https://api.anthropic.com
|
|
92
|
+
model: claude-3-5-sonnet-20241022
|
|
93
|
+
extra:
|
|
94
|
+
max_tokens: 4096
|
|
95
|
+
|
|
96
|
+
demo: # 假 provider(开箱即用)
|
|
97
|
+
type: demo
|
|
98
|
+
base_url: "(in-process)"
|
|
99
|
+
model: demo-echo
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`type` 字段:
|
|
103
|
+
- `openai-compat` — 任何实现 OpenAI Chat Completions 的服务(OpenAI/DeepSeek/Moonshot/ollama/vllm/...)
|
|
104
|
+
- `anthropic` — Anthropic Messages API
|
|
105
|
+
- `demo` — 进程内回显,无需网络
|
|
106
|
+
|
|
107
|
+
`extra` 字段透传给 provider 实现(OpenAI:`temperature`/`top_p`/`presence_penalty`;Anthropic:`max_tokens` 必填/`temperature`/`top_k`)。
|
|
108
|
+
|
|
109
|
+
## CLI 命令
|
|
110
|
+
|
|
111
|
+
| 命令 | 作用 |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `/tools` | 列出所有工具(builtin + skill + mcp) |
|
|
114
|
+
| `/skills` | 列出 skill |
|
|
115
|
+
| `/mcp` | 列出 MCP server + 工具 |
|
|
116
|
+
| `/models` | 列出 `config.yaml` 中所有 LLM provider,标 current |
|
|
117
|
+
| `/model` | 显示当前 model 详情 |
|
|
118
|
+
| `/model <id>` | 切换到指定 provider |
|
|
119
|
+
| `/model test` | 流式发 "ping" 测试当前 model 的连通性 |
|
|
120
|
+
| `/paths` | 路径解析 |
|
|
121
|
+
| `/call <id> [json]` | 手动调用一个工具 |
|
|
122
|
+
| `/reload` | 重新 build registry |
|
|
123
|
+
| `/help` | 帮助 |
|
|
124
|
+
| `/exit` | 退出 |
|
|
125
|
+
|
|
126
|
+
## 工具协议
|
|
127
|
+
|
|
128
|
+
所有工具实现同一接口([minicode/tool/base.py](minicode/tool/base.py)):
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
class Tool(ABC):
|
|
132
|
+
kind: ToolKind = ToolKind.BUILTIN
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def id(self) -> str: ...
|
|
136
|
+
@property
|
|
137
|
+
def description(self) -> str: ...
|
|
138
|
+
@property
|
|
139
|
+
def parameters(self) -> type[BaseModel]: ...
|
|
140
|
+
@abstractmethod
|
|
141
|
+
async def execute(self, args: BaseModel, ctx: ToolContext) -> ToolResult: ...
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- `parameters` 是 Pydantic BaseModel,自动生成 JSON Schema 给 LLM
|
|
145
|
+
- `ToolKind`: BUILTIN / SKILL / MCP / CUSTOM
|
|
146
|
+
|
|
147
|
+
## Model 协议
|
|
148
|
+
|
|
149
|
+
所有 Model 实现同一接口([minicode/model/base.py](minicode/model/base.py)):
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
class Model(ABC):
|
|
153
|
+
@property
|
|
154
|
+
def info(self) -> ModelInfo: ... # id / type / base_url / model
|
|
155
|
+
@property
|
|
156
|
+
def api_key(self) -> str: ...
|
|
157
|
+
@property
|
|
158
|
+
def extra(self) -> dict: ...
|
|
159
|
+
|
|
160
|
+
@abstractmethod
|
|
161
|
+
async def stream(
|
|
162
|
+
self,
|
|
163
|
+
messages: List[Message],
|
|
164
|
+
tools: Optional[List[ToolSchema]] = None,
|
|
165
|
+
system: Optional[str] = None,
|
|
166
|
+
) -> AsyncIterator[ModelEvent]: ... # 流式产出 text_delta / tool_call_delta / usage / finish / error
|
|
167
|
+
|
|
168
|
+
async def complete(...) -> ModelResponse: # 基类默认实现:把 stream 攒起来
|
|
169
|
+
...
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- 协议不感知 Tool/MCP,只接收 `ToolSchema`(与 `ToolDef` 解耦)
|
|
173
|
+
- HTTP 错误用 `yield ModelEvent(type="error", error=...)` 表达,不抛
|
|
174
|
+
|
|
175
|
+
## 架构
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
.minicode/skills/ .minicode/mcp.json .minicode/config.yaml
|
|
179
|
+
│ │ │
|
|
180
|
+
scan ▼ load ▼ load ▼
|
|
181
|
+
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
182
|
+
│SkillLoader │ │ McpClient │ │ ModelRegistry │
|
|
183
|
+
│ │ │ (stdio+http) │ │ (openai/anthropic/demo) │
|
|
184
|
+
└──────┬──────┘ └────────┬────────┘ └────────┬────────┘
|
|
185
|
+
│ │ │
|
|
186
|
+
│ inject │ tools/list │ build
|
|
187
|
+
▼ ▼ ▼
|
|
188
|
+
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
189
|
+
│ SkillTool │ │ McpToolAdapter │ │ OpenAICompat │
|
|
190
|
+
│ (builtin) │ │ (kind=MCP) │ │ Anthropic │
|
|
191
|
+
└─────────────┘ └─────────────────┘ │ Demo │
|
|
192
|
+
└─────────────────┘
|
|
193
|
+
│ │ │
|
|
194
|
+
│ ┌────────────────────┴────────────────────────┐ │
|
|
195
|
+
└───────▶│ ToolRegistry │ │
|
|
196
|
+
│ id → ToolDef (all kinds) │ │
|
|
197
|
+
└────────────────────┬────────────────────────┘ │
|
|
198
|
+
│ │
|
|
199
|
+
│ tools │ model
|
|
200
|
+
▼ ▼
|
|
201
|
+
┌──────────────────────────┐ ┌────────────────┐
|
|
202
|
+
│ ReAct 循环(v2 待做) │ │ /model test │
|
|
203
|
+
└──────────────────────────┘ └────────────────┘
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 与原 mimo code 的差异
|
|
207
|
+
|
|
208
|
+
| 维度 | mimo code (TS) | minicode (Py) |
|
|
209
|
+
| --- | --- | --- |
|
|
210
|
+
| 语言 | TypeScript + Effect | Python 3.10+ + Pydantic |
|
|
211
|
+
| 异步模型 | Effect.gen | async/await |
|
|
212
|
+
| 工具 schema | zod | Pydantic BaseModel |
|
|
213
|
+
| MCP SDK | 官方 @modelcontextprotocol/sdk | 自研最小 JSON-RPC over stdio/http |
|
|
214
|
+
| 内置工具数 | 21 | 7(保留核心) |
|
|
215
|
+
| Skill 协议 | 完整(嵌套 + 外部目录 + 远程拉取) | 简化(`<name>/SKILL.md` + frontmatter) |
|
|
216
|
+
| Model 协议 | Vercel AI SDK | 自研(`stream()` + `complete()`) |
|
|
217
|
+
| provider | 11 种 | 2 种(openai-compat + anthropic)+ 1 demo |
|
|
218
|
+
| LLM 循环 | 接好 | **未接**(v2) |
|
|
219
|
+
|
|
220
|
+
## 下一步
|
|
221
|
+
|
|
222
|
+
1. **ReAct 循环**(v2):把 `ToolRegistry` 的工具转成 `ToolSchema` 给 LLM,处理 `tool_call_delta` → 调 `ToolRegistry.execute` → 灌回 `Message.tool_result` → 下一轮
|
|
223
|
+
2. **权限系统**:完善 `ctx.ask` 的实际行为(allow/deny/ask)
|
|
224
|
+
3. **truncate 服务**:超过阈值的输出写入临时文件,原始位置放占位
|
|
225
|
+
4. **plugin / hooks**:参照 mimo code 的 plugin system
|
|
226
|
+
5. **Google provider**(v3):Gemini generateContent
|
|
227
|
+
|
|
228
|
+
## 测试
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
pip install pytest pytest-asyncio
|
|
232
|
+
python -m pytest tests/ -v
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
应该看到 39 个测试全过。
|
|
236
|
+
|
|
237
|
+
## 已知问题
|
|
238
|
+
|
|
239
|
+
- Windows 终端默认 GBK 编码会乱码。在自己的终端跑前请先 `chcp 65001` 或换 Windows Terminal + Cascadia Code。
|
|
240
|
+
- v2 才接 LLM 循环。/model test 用来单点测试连通性。
|