min-agent 0.1.4 → 0.1.6
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.
- package/README.md +95 -194
- package/bin/min-agent.js +0 -0
- package/dist/agent.js +431 -28
- package/dist/cli.js +177 -27
- package/dist/clipboard.js +106 -0
- package/dist/code-mode.js +166 -0
- package/dist/compaction.js +243 -48
- package/dist/config.js +34 -7
- package/dist/context-window.js +185 -0
- package/dist/doom-loop.js +36 -0
- package/dist/instructions.js +42 -0
- package/dist/mcp.js +82 -28
- package/dist/output.js +15 -2
- package/dist/paste-handler.js +41 -0
- package/dist/serve.js +351 -3
- package/dist/sessions.js +13 -4
- package/dist/skills.js +15 -7
- package/dist/structured-output.js +29 -0
- package/dist/title-gen.js +48 -0
- package/dist/tools/bash.js +85 -74
- package/dist/tools/code_search.js +91 -0
- package/dist/tools/explore.js +104 -0
- package/dist/tools/index.js +10 -1
- package/dist/tools/question.js +53 -0
- package/dist/tools/read.js +14 -3
- package/dist/tools/task.js +98 -0
- package/dist/tools/todo.js +88 -0
- package/docs/API.md +219 -123
- package/package.json +1 -1
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { tool, jsonSchema, streamText, stepCountIs } from "ai";
|
|
2
|
+
import { resolveModel } from "../provider.js";
|
|
3
|
+
import { createTools } from "./index.js";
|
|
4
|
+
import { getMcpTools } from "../mcp.js";
|
|
5
|
+
import { getSkillsTool, getSkills } from "../skills.js";
|
|
6
|
+
import { loadPluginTools } from "../plugins.js";
|
|
7
|
+
import { DoomLoopDetector } from "../doom-loop.js";
|
|
8
|
+
import { stripThinkingFromAssistantText } from "../assistant-stream.js";
|
|
9
|
+
import { truncateToolOutput } from "../tool-output.js";
|
|
10
|
+
const SUB_AGENT_MAX_STEPS = 15;
|
|
11
|
+
const SUB_AGENT_SYSTEM = `You are a focused sub-agent executing a specific task. Complete the task thoroughly and return a clear result.
|
|
12
|
+
|
|
13
|
+
Rules:
|
|
14
|
+
- Focus only on the assigned task
|
|
15
|
+
- Be thorough but concise
|
|
16
|
+
- Use tools as needed to complete the task
|
|
17
|
+
- Return a clear summary of what you did and the result
|
|
18
|
+
|
|
19
|
+
Working directory: ${process.cwd()}
|
|
20
|
+
Platform: ${process.platform}
|
|
21
|
+
Date: ${new Date().toDateString()}`;
|
|
22
|
+
export function createTaskTool(modelId) {
|
|
23
|
+
return tool({
|
|
24
|
+
description: `Launch a sub-agent to execute a task independently. The sub-agent has its own context and tools. Use this for:
|
|
25
|
+
- Parallel execution: call multiple tasks at once for independent work
|
|
26
|
+
- Context isolation: keep the main conversation clean while the sub-agent explores
|
|
27
|
+
- Delegation: hand off well-defined subtasks (search, analysis, file operations)
|
|
28
|
+
|
|
29
|
+
The sub-agent can read/write files, run commands, search, and use all available tools.
|
|
30
|
+
Call multiple tasks in parallel when the work is independent.`,
|
|
31
|
+
inputSchema: jsonSchema({
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
description: { type: "string", description: "Short description of the task (shown to user)" },
|
|
35
|
+
prompt: { type: "string", description: "Detailed instructions for the sub-agent" },
|
|
36
|
+
},
|
|
37
|
+
required: ["description", "prompt"],
|
|
38
|
+
}),
|
|
39
|
+
execute: async ({ description, prompt }) => {
|
|
40
|
+
console.log(`\x1b[90m ┌─ Sub-agent: ${description}\x1b[0m`);
|
|
41
|
+
try {
|
|
42
|
+
const result = await runSubAgent(prompt, modelId);
|
|
43
|
+
console.log(`\x1b[90m └─ ✓ Done\x1b[0m`);
|
|
44
|
+
return truncateToolOutput(result, { direction: "head" }).content;
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
console.log(`\x1b[90m └─ ✗ Failed: ${err.message}\x1b[0m`);
|
|
48
|
+
return `Sub-agent error: ${err.message}`;
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async function runSubAgent(prompt, modelId) {
|
|
54
|
+
const model = resolveModel(modelId);
|
|
55
|
+
// Build tools for sub-agent (no task tool to prevent recursion)
|
|
56
|
+
const builtinTools = createTools();
|
|
57
|
+
const mcpTools = getMcpTools();
|
|
58
|
+
const pluginTools = await loadPluginTools();
|
|
59
|
+
const skills = getSkills();
|
|
60
|
+
const allTools = { ...builtinTools, ...pluginTools };
|
|
61
|
+
for (const [id, t] of Object.entries(mcpTools))
|
|
62
|
+
allTools[id] = t;
|
|
63
|
+
if (skills.length > 0)
|
|
64
|
+
allTools["skill"] = getSkillsTool();
|
|
65
|
+
// Remove task tool from sub-agent to prevent infinite recursion
|
|
66
|
+
delete allTools["task"];
|
|
67
|
+
const messages = [{ role: "user", content: prompt }];
|
|
68
|
+
const doomLoop = new DoomLoopDetector();
|
|
69
|
+
const result = streamText({
|
|
70
|
+
model,
|
|
71
|
+
system: SUB_AGENT_SYSTEM,
|
|
72
|
+
messages,
|
|
73
|
+
tools: allTools,
|
|
74
|
+
stopWhen: stepCountIs(SUB_AGENT_MAX_STEPS),
|
|
75
|
+
maxRetries: 2,
|
|
76
|
+
onError() { },
|
|
77
|
+
});
|
|
78
|
+
let assistantText = "";
|
|
79
|
+
for await (const event of result.fullStream) {
|
|
80
|
+
switch (event.type) {
|
|
81
|
+
case "text-delta":
|
|
82
|
+
assistantText += event.text;
|
|
83
|
+
break;
|
|
84
|
+
case "tool-call":
|
|
85
|
+
if (doomLoop.record(event.toolName, event.input)) {
|
|
86
|
+
return assistantText + "\n\n[Sub-agent stopped: doom loop detected]";
|
|
87
|
+
}
|
|
88
|
+
console.log(`\x1b[90m │ ⚡ ${event.toolName}\x1b[0m`);
|
|
89
|
+
break;
|
|
90
|
+
case "tool-result":
|
|
91
|
+
break;
|
|
92
|
+
case "error":
|
|
93
|
+
return assistantText + `\n\n[Sub-agent error: ${event.error}]`;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const cleaned = stripThinkingFromAssistantText(assistantText);
|
|
97
|
+
return cleaned || "(sub-agent produced no output)";
|
|
98
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { tool, jsonSchema } from "ai";
|
|
2
|
+
let todos = [];
|
|
3
|
+
let nextId = 1;
|
|
4
|
+
export function getTodos() {
|
|
5
|
+
return todos;
|
|
6
|
+
}
|
|
7
|
+
export function resetTodos() {
|
|
8
|
+
todos = [];
|
|
9
|
+
nextId = 1;
|
|
10
|
+
}
|
|
11
|
+
function formatTodos() {
|
|
12
|
+
if (todos.length === 0)
|
|
13
|
+
return "No tasks.";
|
|
14
|
+
const icons = {
|
|
15
|
+
pending: "○",
|
|
16
|
+
in_progress: "◐",
|
|
17
|
+
done: "●",
|
|
18
|
+
cancelled: "✕",
|
|
19
|
+
};
|
|
20
|
+
return todos
|
|
21
|
+
.map((t) => ` ${icons[t.status]} #${t.id} ${t.text}`)
|
|
22
|
+
.join("\n");
|
|
23
|
+
}
|
|
24
|
+
function printTodos() {
|
|
25
|
+
if (todos.length === 0)
|
|
26
|
+
return;
|
|
27
|
+
console.log(`\x1b[90m ┌─ Tasks${"─".repeat(36)}\x1b[0m`);
|
|
28
|
+
for (const t of todos) {
|
|
29
|
+
const icon = t.status === "done" ? "\x1b[32m●\x1b[0m"
|
|
30
|
+
: t.status === "in_progress" ? "\x1b[33m◐\x1b[0m"
|
|
31
|
+
: t.status === "cancelled" ? "\x1b[90m✕\x1b[0m"
|
|
32
|
+
: "\x1b[90m○\x1b[0m";
|
|
33
|
+
const dim = t.status === "done" || t.status === "cancelled" ? "\x1b[90m" : "";
|
|
34
|
+
const reset = dim ? "\x1b[0m" : "";
|
|
35
|
+
console.log(`\x1b[90m │\x1b[0m ${icon} ${dim}#${t.id} ${t.text}${reset}`);
|
|
36
|
+
}
|
|
37
|
+
console.log(`\x1b[90m └${"─".repeat(44)}\x1b[0m`);
|
|
38
|
+
}
|
|
39
|
+
export const todoTool = tool({
|
|
40
|
+
description: `Create or update tasks to track progress. Use this FREQUENTLY to:
|
|
41
|
+
- Plan multi-step work by creating tasks upfront
|
|
42
|
+
- Mark tasks as in_progress when starting them
|
|
43
|
+
- Mark tasks as done when completed
|
|
44
|
+
- Give the user visibility into your progress
|
|
45
|
+
|
|
46
|
+
To create new tasks: provide items with "text" and optionally "status" (defaults to "pending").
|
|
47
|
+
To update existing tasks: provide items with "id" and "status".
|
|
48
|
+
You can mix creates and updates in one call.`,
|
|
49
|
+
inputSchema: jsonSchema({
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
todos: {
|
|
53
|
+
type: "array",
|
|
54
|
+
description: "List of tasks to create or update",
|
|
55
|
+
items: {
|
|
56
|
+
type: "object",
|
|
57
|
+
properties: {
|
|
58
|
+
text: { type: "string", description: "Task description (for new tasks)" },
|
|
59
|
+
status: { type: "string", description: "Status: pending, in_progress, done, cancelled" },
|
|
60
|
+
id: { type: "number", description: "Task ID (for updating existing tasks)" },
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
required: ["todos"],
|
|
66
|
+
}),
|
|
67
|
+
execute: async ({ todos: items }) => {
|
|
68
|
+
for (const item of items) {
|
|
69
|
+
if (item.id) {
|
|
70
|
+
// Update existing
|
|
71
|
+
const existing = todos.find((t) => t.id === item.id);
|
|
72
|
+
if (existing && item.status) {
|
|
73
|
+
existing.status = item.status;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (item.text) {
|
|
77
|
+
// Create new
|
|
78
|
+
todos.push({
|
|
79
|
+
id: nextId++,
|
|
80
|
+
text: item.text,
|
|
81
|
+
status: item.status ?? "pending",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
printTodos();
|
|
86
|
+
return formatTodos();
|
|
87
|
+
},
|
|
88
|
+
});
|
package/docs/API.md
CHANGED
|
@@ -1,216 +1,312 @@
|
|
|
1
1
|
# min-agent HTTP API
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`min-agent serve` 启动本地 HTTP 服务,以编程方式调用代理能力。
|
|
4
4
|
|
|
5
5
|
## 启动
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
min-agent serve
|
|
9
|
-
min-agent serve --host
|
|
10
|
-
min-agent serve -p 3030
|
|
9
|
+
min-agent serve --host 0.0.0.0 --port 3000
|
|
11
10
|
```
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
|
16
|
-
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `MIN_AGENT_SERVE_TOKEN` | 若设置,则所有除 `OPTIONS` 外的请求须带 `Authorization: Bearer <token>` |
|
|
20
|
-
| `MIN_AGENT_SERVE_CORS` | 设为 `1` 或 `true` 时添加 `Access-Control-Allow-Origin: *`(仅开发跨域时使用) |
|
|
21
|
-
|
|
22
|
-
启动后进程内 **`--yes` 等效**:危险 shell 等确认会自动通过,请勿把未鉴权服务暴露到公网。
|
|
12
|
+
| 环境变量 | 说明 |
|
|
13
|
+
|----------|------|
|
|
14
|
+
| `MIN_AGENT_SERVE_HOST` | 监听地址(默认 `127.0.0.1`) |
|
|
15
|
+
| `MIN_AGENT_SERVE_PORT` | 端口(默认 `8787`) |
|
|
16
|
+
| `MIN_AGENT_SERVE_TOKEN` | Bearer token 鉴权 |
|
|
17
|
+
| `MIN_AGENT_SERVE_CORS` | 设为 `1` 启用 CORS |
|
|
23
18
|
|
|
24
19
|
---
|
|
25
20
|
|
|
26
|
-
##
|
|
21
|
+
## 端点一览
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
| 方法 | 路径 | 说明 |
|
|
24
|
+
|------|------|------|
|
|
25
|
+
| GET | `/health` | 存活检查 |
|
|
26
|
+
| GET | `/v1/meta` | 运行环境 |
|
|
27
|
+
| GET | `/v1/models` | 模型列表 |
|
|
28
|
+
| GET | `/v1/context` | 上下文窗口信息 |
|
|
29
|
+
| GET | `/v1/project` | 项目扫描 |
|
|
30
|
+
| POST | `/v1/chat` | 对话 |
|
|
31
|
+
| POST | `/v1/code` | Code 模式对话 |
|
|
32
|
+
| POST | `/v1/paste` | 图片+文本对话 |
|
|
33
|
+
| POST | `/v1/chat/compact` | 手动压缩会话 |
|
|
34
|
+
| POST | `/v1/chat/reload-instructions` | 重载规则 |
|
|
35
|
+
| GET | `/v1/sessions` | 列出会话 |
|
|
36
|
+
| DELETE | `/v1/sessions/:id` | 删除会话 |
|
|
37
|
+
| GET | `/v1/memory` | 列出记忆 |
|
|
38
|
+
| POST | `/v1/memory` | 添加记忆 |
|
|
39
|
+
| GET | `/v1/memory/search?q=xxx` | 搜索记忆 |
|
|
40
|
+
| DELETE | `/v1/memory/:index` | 删除记忆 |
|
|
41
|
+
| GET | `/v1/mcp` | MCP 状态 |
|
|
42
|
+
| POST | `/v1/mcp` | 添加 MCP 服务器 |
|
|
43
|
+
| DELETE | `/v1/mcp/:name` | 删除 MCP 服务器 |
|
|
44
|
+
| GET | `/v1/skills` | 技能列表 |
|
|
45
|
+
| GET | `/v1/rules` | 已加载规则 |
|
|
33
46
|
|
|
34
47
|
---
|
|
35
48
|
|
|
36
49
|
## `GET /health`
|
|
37
50
|
|
|
38
|
-
|
|
51
|
+
```json
|
|
52
|
+
{ "ok": true, "service": "min-agent", "version": "0.1.0" }
|
|
53
|
+
```
|
|
39
54
|
|
|
40
|
-
|
|
55
|
+
## `GET /v1/meta`
|
|
41
56
|
|
|
42
57
|
```json
|
|
43
|
-
{
|
|
44
|
-
"ok": true,
|
|
45
|
-
"service": "min-agent",
|
|
46
|
-
"version": "0.1.0"
|
|
47
|
-
}
|
|
58
|
+
{ "version": "0.1.0", "cwd": "/path/to/project", "instructions_chars": 1234 }
|
|
48
59
|
```
|
|
49
60
|
|
|
50
|
-
|
|
61
|
+
## `GET /v1/models`
|
|
51
62
|
|
|
52
|
-
|
|
63
|
+
```json
|
|
64
|
+
{ "default_model": "gpt-4o", "models": ["gpt-4o", "gpt-4o-mini"] }
|
|
65
|
+
```
|
|
53
66
|
|
|
54
|
-
|
|
67
|
+
## `GET /v1/context`
|
|
55
68
|
|
|
56
|
-
|
|
69
|
+
```json
|
|
70
|
+
{ "context_window": 128000, "model": "gpt-4o" }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## `GET /v1/project`
|
|
57
74
|
|
|
58
75
|
```json
|
|
59
76
|
{
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
"project": {
|
|
78
|
+
"directory": "/path",
|
|
79
|
+
"isGitRepo": true,
|
|
80
|
+
"branch": "main",
|
|
81
|
+
"languages": ["TypeScript"],
|
|
82
|
+
"framework": "Next.js",
|
|
83
|
+
"packageManager": "bun",
|
|
84
|
+
"entryFiles": ["src/index.ts"],
|
|
85
|
+
"configFiles": ["package.json", "tsconfig.json"],
|
|
86
|
+
"summary": "..."
|
|
87
|
+
}
|
|
63
88
|
}
|
|
64
89
|
```
|
|
65
90
|
|
|
66
91
|
---
|
|
67
92
|
|
|
68
|
-
## `
|
|
93
|
+
## `POST /v1/chat`
|
|
69
94
|
|
|
70
|
-
|
|
95
|
+
| 字段 | 类型 | 说明 |
|
|
96
|
+
|------|------|------|
|
|
97
|
+
| `message` | string | 用户消息(与 `messages` 二选一) |
|
|
98
|
+
| `messages` | array | 完整 ModelMessage[] |
|
|
99
|
+
| `model` | string | 覆盖模型 |
|
|
100
|
+
| `stream` | boolean | SSE 流式 |
|
|
101
|
+
| `session_id` | string | 恢复会话 |
|
|
102
|
+
| `images` | string[] | 本地图片路径 |
|
|
71
103
|
|
|
72
|
-
|
|
104
|
+
### 非流式响应
|
|
73
105
|
|
|
74
106
|
```json
|
|
75
107
|
{
|
|
76
|
-
"
|
|
77
|
-
"
|
|
108
|
+
"messages": [...],
|
|
109
|
+
"assistant": { "role": "assistant", "content": "..." },
|
|
110
|
+
"tool_calls": [{ "name": "bash", "input": {...} }],
|
|
111
|
+
"tool_results": [{ "name": "bash", "output": "..." }],
|
|
112
|
+
"session_id": "abc123",
|
|
113
|
+
"step_count": 2,
|
|
114
|
+
"usage": { "inputTokens": 1200, "outputTokens": 300 },
|
|
115
|
+
"has_error": false,
|
|
116
|
+
"aborted": false
|
|
78
117
|
}
|
|
79
118
|
```
|
|
80
119
|
|
|
81
|
-
|
|
120
|
+
### 流式 SSE 事件
|
|
82
121
|
|
|
83
|
-
|
|
122
|
+
| type | 字段 | 说明 |
|
|
123
|
+
|------|------|------|
|
|
124
|
+
| `assistant` | text | 正文增量 |
|
|
125
|
+
| `thinking` | text | 思考片段 |
|
|
126
|
+
| `tool_call` | name, input | 工具调用 |
|
|
127
|
+
| `tool_result` | name, output | 工具返回 |
|
|
128
|
+
| `compaction` | line | 压缩进度 |
|
|
129
|
+
| `error` | message | 错误 |
|
|
130
|
+
| `done` | step_count, usage, messages, session_id | 结束 |
|
|
131
|
+
| `fatal` | message | 致命错误 |
|
|
84
132
|
|
|
85
|
-
|
|
133
|
+
---
|
|
86
134
|
|
|
87
|
-
|
|
135
|
+
## `POST /v1/code`
|
|
88
136
|
|
|
137
|
+
Code 模式对话(项目感知 prompt + explore 工具)。请求体与 `/v1/chat` 相同。
|
|
138
|
+
|
|
139
|
+
响应额外包含:
|
|
89
140
|
```json
|
|
90
|
-
{
|
|
91
|
-
"ok": true,
|
|
92
|
-
"instructions_chars": 1234
|
|
93
|
-
}
|
|
141
|
+
{ "mode": "code", "project": { "languages": [...], ... }, ... }
|
|
94
142
|
```
|
|
95
143
|
|
|
96
144
|
---
|
|
97
145
|
|
|
98
|
-
## `POST /v1/
|
|
99
|
-
|
|
100
|
-
执行一轮或多轮对话(与 CLI 使用相同的 `streamText` + 工具集)。
|
|
146
|
+
## `POST /v1/paste`
|
|
101
147
|
|
|
102
|
-
|
|
148
|
+
图片 + 文本多模态对话。
|
|
103
149
|
|
|
104
150
|
| 字段 | 类型 | 说明 |
|
|
105
151
|
|------|------|------|
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `session_id` |
|
|
111
|
-
| `
|
|
152
|
+
| `image_base64` | string | **必填** Base64 图片数据 |
|
|
153
|
+
| `mime_type` | string | MIME 类型(默认 `image/png`) |
|
|
154
|
+
| `message` | string | 文本 prompt |
|
|
155
|
+
| `model` | string | 覆盖模型 |
|
|
156
|
+
| `session_id` | string | 追加到会话 |
|
|
157
|
+
| `stream` | boolean | SSE 流式 |
|
|
112
158
|
|
|
113
|
-
|
|
159
|
+
---
|
|
114
160
|
|
|
115
|
-
|
|
116
|
-
- 服务端加载该会话已有 `messages`,追加新用户消息后调用模型,并在本轮结束后 **写回同一 `session_id`**
|
|
161
|
+
## `POST /v1/chat/compact`
|
|
117
162
|
|
|
118
|
-
|
|
163
|
+
```json
|
|
164
|
+
// 请求
|
|
165
|
+
{ "session_id": "abc123" }
|
|
166
|
+
// 响应
|
|
167
|
+
{ "ok": true, "compacted": true, "message_count": 5 }
|
|
168
|
+
```
|
|
119
169
|
|
|
120
|
-
|
|
170
|
+
## `POST /v1/chat/reload-instructions`
|
|
121
171
|
|
|
122
172
|
```json
|
|
123
|
-
{
|
|
124
|
-
"messages": [ ... ],
|
|
125
|
-
"assistant": { "role": "assistant", "content": "..." },
|
|
126
|
-
"tool_calls": [{ "name": "bash", "input": { "command": "ls" } }],
|
|
127
|
-
"tool_results": [{ "name": "bash", "output": "..." }],
|
|
128
|
-
"session_id": "abc123",
|
|
129
|
-
"step_count": 2,
|
|
130
|
-
"usage": { "inputTokens": 1200, "outputTokens": 300, "totalTokens": 1500 },
|
|
131
|
-
"has_error": false,
|
|
132
|
-
"aborted": false
|
|
133
|
-
}
|
|
173
|
+
{ "ok": true, "instructions_chars": 1234 }
|
|
134
174
|
```
|
|
135
175
|
|
|
136
|
-
|
|
137
|
-
- `tool_results` 中单条输出过长时会被截断并附带说明后缀
|
|
138
|
-
- 未使用 `session_id` 时 `session_id` 字段为 `undefined`/省略
|
|
176
|
+
---
|
|
139
177
|
|
|
140
|
-
|
|
178
|
+
## `GET /v1/sessions`
|
|
141
179
|
|
|
142
|
-
|
|
143
|
-
|
|
180
|
+
```json
|
|
181
|
+
{ "sessions": [{ "id": "abc", "title": "Fix bug", "updated": "...", "messageCount": 12 }] }
|
|
182
|
+
```
|
|
144
183
|
|
|
145
|
-
|
|
184
|
+
## `DELETE /v1/sessions/:id`
|
|
146
185
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
| `thinking` | `text` | 模型泄漏的思考片段(若存在) |
|
|
151
|
-
| `tool_call` | `name`, `input` | 工具调用开始 |
|
|
152
|
-
| `tool_result` | `name`, `output` | 工具返回(可能截断) |
|
|
153
|
-
| `compaction` | `line` | 上下文压缩进度说明 |
|
|
154
|
-
| `error` | `message` | 流内模型/鉴权类错误事件 |
|
|
155
|
-
| `done` | `step_count`, `usage`, `has_error`, `aborted`, `messages`, `session_id?` | 本轮结束;之后连接关闭 |
|
|
156
|
-
| `fatal` | `message` | 服务异常,随后关闭 |
|
|
186
|
+
```json
|
|
187
|
+
{ "ok": true, "deleted": "abc123" }
|
|
188
|
+
```
|
|
157
189
|
|
|
158
|
-
|
|
190
|
+
---
|
|
159
191
|
|
|
160
|
-
|
|
192
|
+
## `GET /v1/memory`
|
|
161
193
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
| `401` | 配置了 `MIN_AGENT_SERVE_TOKEN` 但未携带合法 Bearer |
|
|
166
|
-
| `404` | `session_id` 不存在 |
|
|
167
|
-
| `413` | 请求体超过约 2MB |
|
|
168
|
-
| `415` | 非 `application/json` |
|
|
169
|
-
| `500` | 未配置提供商等内部错误 |
|
|
194
|
+
```json
|
|
195
|
+
{ "memories": [{ "content": "...", "tags": [...], "created": "..." }] }
|
|
196
|
+
```
|
|
170
197
|
|
|
171
|
-
|
|
198
|
+
## `POST /v1/memory`
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
// 请求
|
|
202
|
+
{ "content": "prefer TypeScript", "tags": ["preference"] }
|
|
203
|
+
// 响应
|
|
204
|
+
{ "ok": true, "memory": {...} }
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## `GET /v1/memory/search?q=typescript`
|
|
172
208
|
|
|
173
|
-
|
|
209
|
+
```json
|
|
210
|
+
{ "results": [{ "content": "...", "tags": [...], "index": 0 }] }
|
|
211
|
+
```
|
|
174
212
|
|
|
175
|
-
|
|
213
|
+
## `DELETE /v1/memory/:index`
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{ "ok": true, "deleted": 1 }
|
|
217
|
+
```
|
|
176
218
|
|
|
177
219
|
---
|
|
178
220
|
|
|
179
|
-
##
|
|
221
|
+
## `GET /v1/mcp`
|
|
180
222
|
|
|
181
|
-
|
|
223
|
+
```json
|
|
224
|
+
{ "servers": { "filesystem": { "connected": true, "tools": ["read_file", "write_file"] } } }
|
|
225
|
+
```
|
|
182
226
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
227
|
+
## `POST /v1/mcp`
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
// 本地 stdio
|
|
231
|
+
{ "name": "fs", "command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }
|
|
232
|
+
// 远程
|
|
233
|
+
{ "name": "remote", "url": "https://mcp.example.com", "token": "xxx" }
|
|
187
234
|
```
|
|
188
235
|
|
|
189
|
-
|
|
236
|
+
```json
|
|
237
|
+
{ "ok": true, "name": "fs" }
|
|
238
|
+
```
|
|
190
239
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
240
|
+
## `DELETE /v1/mcp/:name`
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{ "ok": true, "deleted": "fs" }
|
|
195
244
|
```
|
|
196
245
|
|
|
197
|
-
|
|
246
|
+
---
|
|
198
247
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
248
|
+
## `GET /v1/skills`
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{ "skills": [{ "name": "git-workflow", "description": "...", "location": "..." }] }
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## `GET /v1/rules`
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{ "count": 2, "rules": [{ "source": "~/.min-agent/rules.md", "chars": 456 }] }
|
|
204
258
|
```
|
|
205
259
|
|
|
206
260
|
---
|
|
207
261
|
|
|
208
|
-
##
|
|
262
|
+
## 错误码
|
|
209
263
|
|
|
210
|
-
|
|
264
|
+
| 状态 | 说明 |
|
|
265
|
+
|------|------|
|
|
266
|
+
| 400 | 请求参数错误 |
|
|
267
|
+
| 401 | 未授权 |
|
|
268
|
+
| 404 | 资源不存在 |
|
|
269
|
+
| 413 | 请求体过大(>2MB) |
|
|
270
|
+
| 415 | Content-Type 不是 JSON |
|
|
271
|
+
| 500 | 内部错误 |
|
|
211
272
|
|
|
212
273
|
---
|
|
213
274
|
|
|
214
|
-
##
|
|
275
|
+
## 示例
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# 对话
|
|
279
|
+
curl http://127.0.0.1:8787/v1/chat \
|
|
280
|
+
-H "Content-Type: application/json" \
|
|
281
|
+
-d '{"message":"list files"}'
|
|
282
|
+
|
|
283
|
+
# 流式
|
|
284
|
+
curl -N http://127.0.0.1:8787/v1/chat \
|
|
285
|
+
-H "Content-Type: application/json" \
|
|
286
|
+
-d '{"message":"say hi","stream":true}'
|
|
287
|
+
|
|
288
|
+
# Code 模式
|
|
289
|
+
curl http://127.0.0.1:8787/v1/code \
|
|
290
|
+
-H "Content-Type: application/json" \
|
|
291
|
+
-d '{"message":"add error handling to login"}'
|
|
292
|
+
|
|
293
|
+
# 图片
|
|
294
|
+
curl http://127.0.0.1:8787/v1/paste \
|
|
295
|
+
-H "Content-Type: application/json" \
|
|
296
|
+
-d '{"image_base64":"iVBOR...","message":"分析这张图"}'
|
|
215
297
|
|
|
216
|
-
|
|
298
|
+
# 添加 MCP
|
|
299
|
+
curl -X POST http://127.0.0.1:8787/v1/mcp \
|
|
300
|
+
-H "Content-Type: application/json" \
|
|
301
|
+
-d '{"name":"fs","command":["npx","-y","@modelcontextprotocol/server-filesystem","/tmp"]}'
|
|
302
|
+
|
|
303
|
+
# 添加记忆
|
|
304
|
+
curl -X POST http://127.0.0.1:8787/v1/memory \
|
|
305
|
+
-H "Content-Type: application/json" \
|
|
306
|
+
-d '{"content":"prefer TypeScript","tags":["preference"]}'
|
|
307
|
+
|
|
308
|
+
# 压缩会话
|
|
309
|
+
curl -X POST http://127.0.0.1:8787/v1/chat/compact \
|
|
310
|
+
-H "Content-Type: application/json" \
|
|
311
|
+
-d '{"session_id":"abc123"}'
|
|
312
|
+
```
|