mindagent 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.
- mindagent-0.1.0/PKG-INFO +309 -0
- mindagent-0.1.0/README.md +290 -0
- mindagent-0.1.0/pyproject.toml +17 -0
- mindagent-0.1.0/src/mindagent/__init__.py +1 -0
- mindagent-0.1.0/src/mindagent/context/__init__.py +25 -0
- mindagent-0.1.0/src/mindagent/context/manager.py +376 -0
- mindagent-0.1.0/src/mindagent/context/models.py +63 -0
- mindagent-0.1.0/src/mindagent/context/packer.py +217 -0
- mindagent-0.1.0/src/mindagent/context/store.py +53 -0
- mindagent-0.1.0/src/mindagent/core/__init__.py +54 -0
- mindagent-0.1.0/src/mindagent/core/context.py +86 -0
- mindagent-0.1.0/src/mindagent/core/contracts.py +53 -0
- mindagent-0.1.0/src/mindagent/core/event.py +46 -0
- mindagent-0.1.0/src/mindagent/core/heartbeat.py +39 -0
- mindagent-0.1.0/src/mindagent/core/react_loop.py +321 -0
- mindagent-0.1.0/src/mindagent/core/runtime.py +284 -0
- mindagent-0.1.0/src/mindagent/core/state_machine.py +84 -0
- mindagent-0.1.0/src/mindagent/core/trace.py +72 -0
- mindagent-0.1.0/src/mindagent/providers/__init__.py +18 -0
- mindagent-0.1.0/src/mindagent/providers/base.py +81 -0
- mindagent-0.1.0/src/mindagent/providers/openai/__init__.py +4 -0
- mindagent-0.1.0/src/mindagent/providers/openai/param.py +65 -0
- mindagent-0.1.0/src/mindagent/providers/openai/provider.py +262 -0
- mindagent-0.1.0/src/mindagent/providers/param.py +14 -0
- mindagent-0.1.0/src/mindagent/providers/reasoner.py +89 -0
- mindagent-0.1.0/src/mindagent/providers/router.py +77 -0
- mindagent-0.1.0/src/mindagent/tools/__init__.py +38 -0
- mindagent-0.1.0/src/mindagent/tools/base.py +86 -0
- mindagent-0.1.0/src/mindagent/tools/builtin/__init__.py +13 -0
- mindagent-0.1.0/src/mindagent/tools/builtin/calculator.py +87 -0
- mindagent-0.1.0/src/mindagent/tools/builtin/context_query.py +41 -0
- mindagent-0.1.0/src/mindagent/tools/builtin/image_understanding.py +69 -0
- mindagent-0.1.0/src/mindagent/tools/builtin/memory.py +51 -0
- mindagent-0.1.0/src/mindagent/tools/builtin/time_now.py +44 -0
- mindagent-0.1.0/src/mindagent/tools/executor.py +86 -0
- mindagent-0.1.0/src/mindagent/tools/registry.py +125 -0
mindagent-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mindagent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MindAgent 是一个基于 Python 和 `asyncio` 的 Agent Runtime。它使用状态机约束生命周期,通过 ReAct 循环驱动模型决策,并将 Provider、Tool 和上下文管理分离。
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: runkezhong
|
|
7
|
+
Author-email: jarvisshangye@gmail.com
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# MindAgent
|
|
20
|
+
|
|
21
|
+
MindAgent 是一个基于 Python 和 `asyncio` 的 Agent Runtime。它使用状态机约束生命周期,通过 ReAct 循环驱动模型决策,并将 Provider、Tool 和上下文管理分离。
|
|
22
|
+
|
|
23
|
+
当前版本聚焦单 Agent、单 Action、串行 Tool Calling 的核心闭环。
|
|
24
|
+
|
|
25
|
+
## 当前能力
|
|
26
|
+
|
|
27
|
+
- 状态机控制 Agent 生命周期
|
|
28
|
+
- ReAct:Think → Validate → Execute → Observe → Update
|
|
29
|
+
- OpenAI-compatible Provider
|
|
30
|
+
- Provider 能力路由
|
|
31
|
+
- Tool 注册、JSON Schema 和参数校验
|
|
32
|
+
- 普通工具与流式工具
|
|
33
|
+
- ContextManager 文本、图像和 Tool Observation 管理
|
|
34
|
+
- 上下文长度估算与旧轮次裁剪
|
|
35
|
+
- 事件、heartbeat、超时、取消和人工审批
|
|
36
|
+
- JSONL 执行轨迹与离线回放
|
|
37
|
+
- 内置时间、计算器、上下文查询、进程内记忆和图像理解工具
|
|
38
|
+
|
|
39
|
+
MCP、Skill、长期记忆和并行 ToolCall 尚未实现。
|
|
40
|
+
|
|
41
|
+
## 架构
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
AgentRuntime
|
|
45
|
+
├── ReActLoop
|
|
46
|
+
│ ├── ProviderReasoner
|
|
47
|
+
│ │ └── ProviderRouter → LLM/VLM Provider
|
|
48
|
+
│ ├── PolicyEngine
|
|
49
|
+
│ ├── ToolExecutor → ToolRegistry → Tool
|
|
50
|
+
│ └── ContextManager
|
|
51
|
+
├── EventHandler
|
|
52
|
+
├── Heartbeat
|
|
53
|
+
└── Timeout / Cancel
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
核心边界:
|
|
57
|
+
|
|
58
|
+
- `core` 只负责编排和协议,不依赖具体模型或工具。
|
|
59
|
+
- `providers` 将不同模型接口统一为 `ProviderResponse`。
|
|
60
|
+
- `tools` 不感知 Agent 推理,只接收参数和 `ToolContext`。
|
|
61
|
+
- 所有外部动作通过 `ActionRequest` 表达。
|
|
62
|
+
- 每次 ToolCall 最终只生成一个 `Observation`。
|
|
63
|
+
|
|
64
|
+
## 环境要求
|
|
65
|
+
|
|
66
|
+
- Python 3.12+
|
|
67
|
+
- 项目虚拟环境 `.venv`
|
|
68
|
+
- OpenAI-compatible API
|
|
69
|
+
|
|
70
|
+
安装依赖:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
uv pip install --python .venv/bin/python -r requirements.txt
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
也可以使用已激活虚拟环境中的 `pip`:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install -r requirements.txt
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## API 配置
|
|
83
|
+
|
|
84
|
+
在项目根目录创建 `.env`:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
MINDAGENT_API_KEY="your-api-key"
|
|
88
|
+
MINDAGENT_BASE_URL="https://your-provider.example/v1"
|
|
89
|
+
MINDAGENT_MODELS="your-model-name"
|
|
90
|
+
MINDAGENT_PLATFORM="openai-compatible"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`OpenAIProviderParam.from_env()` 会自动读取该文件。`MINDAGENT_MODELS` 支持逗号分隔,当前默认使用第一个模型。
|
|
94
|
+
|
|
95
|
+
不要提交包含真实密钥的 `.env`。
|
|
96
|
+
|
|
97
|
+
## 快速开始
|
|
98
|
+
|
|
99
|
+
运行完整 Tool Calling 示例:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
PYTHONPATH=src .venv/bin/python examples/tool_agent.py
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
示例包含:
|
|
106
|
+
|
|
107
|
+
1. 定义一个 `AddTool`
|
|
108
|
+
2. 注册到 `ToolRegistry`
|
|
109
|
+
3. 将工具 Schema 提供给模型
|
|
110
|
+
4. 创建 Provider、ContextManager 和 Runtime
|
|
111
|
+
5. 模型自主调用工具
|
|
112
|
+
6. Observation 写回上下文
|
|
113
|
+
7. 模型生成最终答案
|
|
114
|
+
|
|
115
|
+
核心代码:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
registry = ToolRegistry([AddTool()])
|
|
119
|
+
provider = OpenAIProvider(OpenAIProviderParam.from_env())
|
|
120
|
+
|
|
121
|
+
reasoner = ProviderReasoner(
|
|
122
|
+
ProviderRouter([provider]),
|
|
123
|
+
tools=registry.provider_schemas(),
|
|
124
|
+
action_risks=registry.action_risks(),
|
|
125
|
+
approval_required=registry.approval_required(),
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
runtime = AgentRuntime(
|
|
129
|
+
reasoner,
|
|
130
|
+
ToolExecutor(registry),
|
|
131
|
+
context_manager=ContextManager(
|
|
132
|
+
ContextConfig(system_prompt="Use tools when required.")
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
result = await runtime.run("Use the add tool to calculate 17 + 25.")
|
|
137
|
+
print(result.final_answer)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
完整代码见 [`examples/tool_agent.py`](examples/tool_agent.py)。
|
|
141
|
+
|
|
142
|
+
## 内置工具
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from mindagent.tools import (
|
|
146
|
+
CalculatorTool,
|
|
147
|
+
ContextQueryTool,
|
|
148
|
+
ImageUnderstandingTool,
|
|
149
|
+
MemoryTool,
|
|
150
|
+
TimeNowTool,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
registry = ToolRegistry(
|
|
154
|
+
[TimeNowTool(), CalculatorTool(), ContextQueryTool(), MemoryTool()]
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- `time_now`:获取指定 IANA 时区的当前时间
|
|
159
|
+
- `calculator`:基于受限 AST 计算算术表达式
|
|
160
|
+
- `context_query`:读取当前 run 的 metadata 或 artifacts
|
|
161
|
+
- `memory`:按 run 隔离的进程内 key/value 存储
|
|
162
|
+
- `image_understanding`:通过 `ProviderRouter` 选择多模态 provider 分析图像
|
|
163
|
+
|
|
164
|
+
`ImageUnderstandingTool` 需要显式传入 router:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
image_tool = ImageUnderstandingTool(
|
|
168
|
+
ProviderRouter([vision_provider])
|
|
169
|
+
)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
它支持 HTTP 图片 URL 和 base64 data URL。默认 `api="auto"`,优先使用
|
|
173
|
+
Chat Completions 的 `text` / `image_url` 格式;当兼容服务明确返回端点或
|
|
174
|
+
图像能力不支持的 4xx 时,再回退 Responses API 的
|
|
175
|
+
`input_text` / `input_image` 格式。也可以显式设置:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
arguments = {
|
|
179
|
+
"image_url": image_data_url,
|
|
180
|
+
"prompt": "请描述图片。",
|
|
181
|
+
"api": "chat_completions", # 或 "responses"
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## 定义工具
|
|
186
|
+
|
|
187
|
+
普通工具继承 `BaseTool`:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
class AddTool(BaseTool):
|
|
191
|
+
definition = ToolDefinition(
|
|
192
|
+
name="add",
|
|
193
|
+
description="Add two integers.",
|
|
194
|
+
parameters={
|
|
195
|
+
"type": "object",
|
|
196
|
+
"properties": {
|
|
197
|
+
"a": {"type": "integer"},
|
|
198
|
+
"b": {"type": "integer"},
|
|
199
|
+
},
|
|
200
|
+
"required": ["a", "b"],
|
|
201
|
+
"additionalProperties": False,
|
|
202
|
+
},
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
async def execute(self, arguments, context):
|
|
206
|
+
return arguments["a"] + arguments["b"]
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
流式工具继承 `StreamingTool`,并产生 `ToolProgress`:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
async def stream(self, arguments, context):
|
|
213
|
+
yield ToolProgress(message="working", progress=0.5)
|
|
214
|
+
yield ToolProgress(message="done", data=result, progress=1.0)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
进度通过 `ACTION_PROGRESS` 事件发送。所有 chunk 会由 `ToolExecutor` 聚合,ReAct 循环只接收一个最终 `Observation`。
|
|
218
|
+
|
|
219
|
+
## ContextManager
|
|
220
|
+
|
|
221
|
+
`ContextManager` 当前负责:
|
|
222
|
+
|
|
223
|
+
- 以只追加 `ContextStore` 保存原始执行记录
|
|
224
|
+
- 将 tool call 与 tool result 组成不可拆分的原子 Bundle
|
|
225
|
+
- 注入 system、user 和多模态图片内容
|
|
226
|
+
- 每次 THINK 前动态编译 Provider 消息视图
|
|
227
|
+
- 计算稳定前缀指纹,保持 system 与工具 schema 顺序稳定
|
|
228
|
+
- 使用 NORMAL / WARNING / CRITICAL 压力水位决定是否压缩
|
|
229
|
+
- 通过 Context Epoch 避免 ReAct iteration 内反复重写历史
|
|
230
|
+
- 通过 `CONTEXT_PACKED` 事件记录预算和压缩决策
|
|
231
|
+
|
|
232
|
+
示例:
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
result = await runtime.run(
|
|
236
|
+
"Describe this image.",
|
|
237
|
+
artifacts={
|
|
238
|
+
"images": ["https://example.com/image.png"],
|
|
239
|
+
},
|
|
240
|
+
)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Context 不使用固定分块预算。默认使用离线字符估算,避免初始化时下载
|
|
244
|
+
tokenizer;需要精确估算时可设置 `ContextConfig(use_tiktoken=True)`。
|
|
245
|
+
|
|
246
|
+
## 事件
|
|
247
|
+
|
|
248
|
+
通过 `event_handler` 观察执行过程:
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
async def handle_event(event):
|
|
252
|
+
print(event.event_type.value, event.payload)
|
|
253
|
+
|
|
254
|
+
runtime = AgentRuntime(
|
|
255
|
+
reasoner,
|
|
256
|
+
executor,
|
|
257
|
+
event_handler=handle_event,
|
|
258
|
+
)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
主要事件包括:
|
|
262
|
+
|
|
263
|
+
- `STATE_CHANGED`
|
|
264
|
+
- `DECISION_CREATED`
|
|
265
|
+
- `ACTION_VALIDATED`
|
|
266
|
+
- `ACTION_STARTED`
|
|
267
|
+
- `ACTION_PROGRESS`
|
|
268
|
+
- `ACTION_FINISHED`
|
|
269
|
+
- `OBSERVATION_CREATED`
|
|
270
|
+
- `FINAL_CREATED`
|
|
271
|
+
- `ERROR_CREATED`
|
|
272
|
+
- `HEARTBEAT`
|
|
273
|
+
|
|
274
|
+
使用 `TraceRecorder` 将全部事件记录为 JSONL:
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
from mindagent.core import TraceRecorder
|
|
278
|
+
|
|
279
|
+
recorder = TraceRecorder("traces")
|
|
280
|
+
runtime = AgentRuntime(
|
|
281
|
+
reasoner,
|
|
282
|
+
executor,
|
|
283
|
+
event_handler=recorder,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
events = TraceRecorder.replay("traces/<run_id>.jsonl")
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
`runtime.cancel(run_id)` 会直接中断当前 LLM 或工具 await,并返回
|
|
290
|
+
`CANCELLED` 状态;它不依赖 `step_timeout_s`。
|
|
291
|
+
|
|
292
|
+
## 测试
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests -v
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## 目录
|
|
299
|
+
|
|
300
|
+
```text
|
|
301
|
+
src/mindagent/
|
|
302
|
+
core/ 状态机、ReActLoop、Runtime 和核心协议
|
|
303
|
+
context/ 上下文构造、图像注入和裁剪
|
|
304
|
+
providers/ Provider、Router 和 Reasoner
|
|
305
|
+
tools/ Tool、Registry、Executor 和内置工具
|
|
306
|
+
examples/ 可运行示例
|
|
307
|
+
tests/ 单元测试
|
|
308
|
+
```
|
|
309
|
+
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# MindAgent
|
|
2
|
+
|
|
3
|
+
MindAgent 是一个基于 Python 和 `asyncio` 的 Agent Runtime。它使用状态机约束生命周期,通过 ReAct 循环驱动模型决策,并将 Provider、Tool 和上下文管理分离。
|
|
4
|
+
|
|
5
|
+
当前版本聚焦单 Agent、单 Action、串行 Tool Calling 的核心闭环。
|
|
6
|
+
|
|
7
|
+
## 当前能力
|
|
8
|
+
|
|
9
|
+
- 状态机控制 Agent 生命周期
|
|
10
|
+
- ReAct:Think → Validate → Execute → Observe → Update
|
|
11
|
+
- OpenAI-compatible Provider
|
|
12
|
+
- Provider 能力路由
|
|
13
|
+
- Tool 注册、JSON Schema 和参数校验
|
|
14
|
+
- 普通工具与流式工具
|
|
15
|
+
- ContextManager 文本、图像和 Tool Observation 管理
|
|
16
|
+
- 上下文长度估算与旧轮次裁剪
|
|
17
|
+
- 事件、heartbeat、超时、取消和人工审批
|
|
18
|
+
- JSONL 执行轨迹与离线回放
|
|
19
|
+
- 内置时间、计算器、上下文查询、进程内记忆和图像理解工具
|
|
20
|
+
|
|
21
|
+
MCP、Skill、长期记忆和并行 ToolCall 尚未实现。
|
|
22
|
+
|
|
23
|
+
## 架构
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
AgentRuntime
|
|
27
|
+
├── ReActLoop
|
|
28
|
+
│ ├── ProviderReasoner
|
|
29
|
+
│ │ └── ProviderRouter → LLM/VLM Provider
|
|
30
|
+
│ ├── PolicyEngine
|
|
31
|
+
│ ├── ToolExecutor → ToolRegistry → Tool
|
|
32
|
+
│ └── ContextManager
|
|
33
|
+
├── EventHandler
|
|
34
|
+
├── Heartbeat
|
|
35
|
+
└── Timeout / Cancel
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
核心边界:
|
|
39
|
+
|
|
40
|
+
- `core` 只负责编排和协议,不依赖具体模型或工具。
|
|
41
|
+
- `providers` 将不同模型接口统一为 `ProviderResponse`。
|
|
42
|
+
- `tools` 不感知 Agent 推理,只接收参数和 `ToolContext`。
|
|
43
|
+
- 所有外部动作通过 `ActionRequest` 表达。
|
|
44
|
+
- 每次 ToolCall 最终只生成一个 `Observation`。
|
|
45
|
+
|
|
46
|
+
## 环境要求
|
|
47
|
+
|
|
48
|
+
- Python 3.12+
|
|
49
|
+
- 项目虚拟环境 `.venv`
|
|
50
|
+
- OpenAI-compatible API
|
|
51
|
+
|
|
52
|
+
安装依赖:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uv pip install --python .venv/bin/python -r requirements.txt
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
也可以使用已激活虚拟环境中的 `pip`:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install -r requirements.txt
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## API 配置
|
|
65
|
+
|
|
66
|
+
在项目根目录创建 `.env`:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
MINDAGENT_API_KEY="your-api-key"
|
|
70
|
+
MINDAGENT_BASE_URL="https://your-provider.example/v1"
|
|
71
|
+
MINDAGENT_MODELS="your-model-name"
|
|
72
|
+
MINDAGENT_PLATFORM="openai-compatible"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`OpenAIProviderParam.from_env()` 会自动读取该文件。`MINDAGENT_MODELS` 支持逗号分隔,当前默认使用第一个模型。
|
|
76
|
+
|
|
77
|
+
不要提交包含真实密钥的 `.env`。
|
|
78
|
+
|
|
79
|
+
## 快速开始
|
|
80
|
+
|
|
81
|
+
运行完整 Tool Calling 示例:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
PYTHONPATH=src .venv/bin/python examples/tool_agent.py
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
示例包含:
|
|
88
|
+
|
|
89
|
+
1. 定义一个 `AddTool`
|
|
90
|
+
2. 注册到 `ToolRegistry`
|
|
91
|
+
3. 将工具 Schema 提供给模型
|
|
92
|
+
4. 创建 Provider、ContextManager 和 Runtime
|
|
93
|
+
5. 模型自主调用工具
|
|
94
|
+
6. Observation 写回上下文
|
|
95
|
+
7. 模型生成最终答案
|
|
96
|
+
|
|
97
|
+
核心代码:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
registry = ToolRegistry([AddTool()])
|
|
101
|
+
provider = OpenAIProvider(OpenAIProviderParam.from_env())
|
|
102
|
+
|
|
103
|
+
reasoner = ProviderReasoner(
|
|
104
|
+
ProviderRouter([provider]),
|
|
105
|
+
tools=registry.provider_schemas(),
|
|
106
|
+
action_risks=registry.action_risks(),
|
|
107
|
+
approval_required=registry.approval_required(),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
runtime = AgentRuntime(
|
|
111
|
+
reasoner,
|
|
112
|
+
ToolExecutor(registry),
|
|
113
|
+
context_manager=ContextManager(
|
|
114
|
+
ContextConfig(system_prompt="Use tools when required.")
|
|
115
|
+
),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
result = await runtime.run("Use the add tool to calculate 17 + 25.")
|
|
119
|
+
print(result.final_answer)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
完整代码见 [`examples/tool_agent.py`](examples/tool_agent.py)。
|
|
123
|
+
|
|
124
|
+
## 内置工具
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from mindagent.tools import (
|
|
128
|
+
CalculatorTool,
|
|
129
|
+
ContextQueryTool,
|
|
130
|
+
ImageUnderstandingTool,
|
|
131
|
+
MemoryTool,
|
|
132
|
+
TimeNowTool,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
registry = ToolRegistry(
|
|
136
|
+
[TimeNowTool(), CalculatorTool(), ContextQueryTool(), MemoryTool()]
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
- `time_now`:获取指定 IANA 时区的当前时间
|
|
141
|
+
- `calculator`:基于受限 AST 计算算术表达式
|
|
142
|
+
- `context_query`:读取当前 run 的 metadata 或 artifacts
|
|
143
|
+
- `memory`:按 run 隔离的进程内 key/value 存储
|
|
144
|
+
- `image_understanding`:通过 `ProviderRouter` 选择多模态 provider 分析图像
|
|
145
|
+
|
|
146
|
+
`ImageUnderstandingTool` 需要显式传入 router:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
image_tool = ImageUnderstandingTool(
|
|
150
|
+
ProviderRouter([vision_provider])
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
它支持 HTTP 图片 URL 和 base64 data URL。默认 `api="auto"`,优先使用
|
|
155
|
+
Chat Completions 的 `text` / `image_url` 格式;当兼容服务明确返回端点或
|
|
156
|
+
图像能力不支持的 4xx 时,再回退 Responses API 的
|
|
157
|
+
`input_text` / `input_image` 格式。也可以显式设置:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
arguments = {
|
|
161
|
+
"image_url": image_data_url,
|
|
162
|
+
"prompt": "请描述图片。",
|
|
163
|
+
"api": "chat_completions", # 或 "responses"
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 定义工具
|
|
168
|
+
|
|
169
|
+
普通工具继承 `BaseTool`:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
class AddTool(BaseTool):
|
|
173
|
+
definition = ToolDefinition(
|
|
174
|
+
name="add",
|
|
175
|
+
description="Add two integers.",
|
|
176
|
+
parameters={
|
|
177
|
+
"type": "object",
|
|
178
|
+
"properties": {
|
|
179
|
+
"a": {"type": "integer"},
|
|
180
|
+
"b": {"type": "integer"},
|
|
181
|
+
},
|
|
182
|
+
"required": ["a", "b"],
|
|
183
|
+
"additionalProperties": False,
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
async def execute(self, arguments, context):
|
|
188
|
+
return arguments["a"] + arguments["b"]
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
流式工具继承 `StreamingTool`,并产生 `ToolProgress`:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
async def stream(self, arguments, context):
|
|
195
|
+
yield ToolProgress(message="working", progress=0.5)
|
|
196
|
+
yield ToolProgress(message="done", data=result, progress=1.0)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
进度通过 `ACTION_PROGRESS` 事件发送。所有 chunk 会由 `ToolExecutor` 聚合,ReAct 循环只接收一个最终 `Observation`。
|
|
200
|
+
|
|
201
|
+
## ContextManager
|
|
202
|
+
|
|
203
|
+
`ContextManager` 当前负责:
|
|
204
|
+
|
|
205
|
+
- 以只追加 `ContextStore` 保存原始执行记录
|
|
206
|
+
- 将 tool call 与 tool result 组成不可拆分的原子 Bundle
|
|
207
|
+
- 注入 system、user 和多模态图片内容
|
|
208
|
+
- 每次 THINK 前动态编译 Provider 消息视图
|
|
209
|
+
- 计算稳定前缀指纹,保持 system 与工具 schema 顺序稳定
|
|
210
|
+
- 使用 NORMAL / WARNING / CRITICAL 压力水位决定是否压缩
|
|
211
|
+
- 通过 Context Epoch 避免 ReAct iteration 内反复重写历史
|
|
212
|
+
- 通过 `CONTEXT_PACKED` 事件记录预算和压缩决策
|
|
213
|
+
|
|
214
|
+
示例:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
result = await runtime.run(
|
|
218
|
+
"Describe this image.",
|
|
219
|
+
artifacts={
|
|
220
|
+
"images": ["https://example.com/image.png"],
|
|
221
|
+
},
|
|
222
|
+
)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Context 不使用固定分块预算。默认使用离线字符估算,避免初始化时下载
|
|
226
|
+
tokenizer;需要精确估算时可设置 `ContextConfig(use_tiktoken=True)`。
|
|
227
|
+
|
|
228
|
+
## 事件
|
|
229
|
+
|
|
230
|
+
通过 `event_handler` 观察执行过程:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
async def handle_event(event):
|
|
234
|
+
print(event.event_type.value, event.payload)
|
|
235
|
+
|
|
236
|
+
runtime = AgentRuntime(
|
|
237
|
+
reasoner,
|
|
238
|
+
executor,
|
|
239
|
+
event_handler=handle_event,
|
|
240
|
+
)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
主要事件包括:
|
|
244
|
+
|
|
245
|
+
- `STATE_CHANGED`
|
|
246
|
+
- `DECISION_CREATED`
|
|
247
|
+
- `ACTION_VALIDATED`
|
|
248
|
+
- `ACTION_STARTED`
|
|
249
|
+
- `ACTION_PROGRESS`
|
|
250
|
+
- `ACTION_FINISHED`
|
|
251
|
+
- `OBSERVATION_CREATED`
|
|
252
|
+
- `FINAL_CREATED`
|
|
253
|
+
- `ERROR_CREATED`
|
|
254
|
+
- `HEARTBEAT`
|
|
255
|
+
|
|
256
|
+
使用 `TraceRecorder` 将全部事件记录为 JSONL:
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
from mindagent.core import TraceRecorder
|
|
260
|
+
|
|
261
|
+
recorder = TraceRecorder("traces")
|
|
262
|
+
runtime = AgentRuntime(
|
|
263
|
+
reasoner,
|
|
264
|
+
executor,
|
|
265
|
+
event_handler=recorder,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
events = TraceRecorder.replay("traces/<run_id>.jsonl")
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`runtime.cancel(run_id)` 会直接中断当前 LLM 或工具 await,并返回
|
|
272
|
+
`CANCELLED` 状态;它不依赖 `step_timeout_s`。
|
|
273
|
+
|
|
274
|
+
## 测试
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests -v
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## 目录
|
|
281
|
+
|
|
282
|
+
```text
|
|
283
|
+
src/mindagent/
|
|
284
|
+
core/ 状态机、ReActLoop、Runtime 和核心协议
|
|
285
|
+
context/ 上下文构造、图像注入和裁剪
|
|
286
|
+
providers/ Provider、Router 和 Reasoner
|
|
287
|
+
tools/ Tool、Registry、Executor 和内置工具
|
|
288
|
+
examples/ 可运行示例
|
|
289
|
+
tests/ 单元测试
|
|
290
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mindagent"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MindAgent 是一个基于 Python 和 `asyncio` 的 Agent Runtime。它使用状态机约束生命周期,通过 ReAct 循环驱动模型决策,并将 Provider、Tool 和上下文管理分离。"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "runkezhong",email = "jarvisshangye@gmail.com"}
|
|
7
|
+
]
|
|
8
|
+
license = {text = "MIT"}
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
dependencies = [
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
[build-system]
|
|
16
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
17
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""mindagent public package."""
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .manager import ContextConfig, ContextManager
|
|
2
|
+
from .models import (
|
|
3
|
+
ContextBundle,
|
|
4
|
+
ContextPackResult,
|
|
5
|
+
ContextPressure,
|
|
6
|
+
ContextPressureLevel,
|
|
7
|
+
ContextRecord,
|
|
8
|
+
ContextScope,
|
|
9
|
+
)
|
|
10
|
+
from .packer import CacheAwarePacker, ContextOverflowError
|
|
11
|
+
from .store import ContextStore
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"CacheAwarePacker",
|
|
15
|
+
"ContextBundle",
|
|
16
|
+
"ContextConfig",
|
|
17
|
+
"ContextManager",
|
|
18
|
+
"ContextOverflowError",
|
|
19
|
+
"ContextPackResult",
|
|
20
|
+
"ContextPressure",
|
|
21
|
+
"ContextPressureLevel",
|
|
22
|
+
"ContextRecord",
|
|
23
|
+
"ContextScope",
|
|
24
|
+
"ContextStore",
|
|
25
|
+
]
|