mindbot 0.3.0__tar.gz → 0.3.2__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.
Files changed (172) hide show
  1. {mindbot-0.3.0/src/mindbot.egg-info → mindbot-0.3.2}/PKG-INFO +131 -6
  2. {mindbot-0.3.0 → mindbot-0.3.2}/README.md +130 -5
  3. {mindbot-0.3.0 → mindbot-0.3.2}/pyproject.toml +1 -1
  4. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/__init__.py +1 -1
  5. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/agent.py +20 -2
  6. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/core.py +5 -95
  7. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/persistence_writer.py +56 -2
  8. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/turn_engine.py +83 -14
  9. mindbot-0.3.2/src/mindbot/benchmarking/__init__.py +37 -0
  10. mindbot-0.3.2/src/mindbot/benchmarking/real_tools.py +720 -0
  11. mindbot-0.3.2/src/mindbot/benchmarking/toolcall15_adapter.py +304 -0
  12. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/bot.py +4 -0
  13. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/builders/agent_builder.py +8 -2
  14. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/cli/__init__.py +314 -10
  15. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/config/schema.py +58 -0
  16. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/context/models.py +43 -1
  17. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/openai/param.py +1 -0
  18. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/openai/provider.py +1 -1
  19. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/session/types.py +10 -0
  20. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/templates/settings.example.json +11 -0
  21. mindbot-0.3.2/src/mindbot/tools/builtin.py +57 -0
  22. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/tools/file_ops.py +41 -23
  23. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/tools/mindbot_ops.py +51 -4
  24. mindbot-0.3.2/src/mindbot/tools/path_policy.py +50 -0
  25. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/tools/shell_ops.py +53 -11
  26. mindbot-0.3.0/src/mindbot/utils.py → mindbot-0.3.2/src/mindbot/utils/__init__.py +118 -118
  27. {mindbot-0.3.0 → mindbot-0.3.2/src/mindbot.egg-info}/PKG-INFO +131 -6
  28. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot.egg-info/SOURCES.txt +5 -31
  29. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/SKILL.md +0 -235
  30. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/assets/html-template.html +0 -635
  31. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/chapter1.json +0 -137
  32. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/chapter2.json +0 -130
  33. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/chapter3.json +0 -133
  34. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/chapter4.json +0 -123
  35. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/SKILL.md +0 -235
  36. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/assets/html-template.html +0 -635
  37. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/references/chapter-generation.md +0 -526
  38. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/references/performance-optimization.md +0 -192
  39. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/references/plot-design.md +0 -583
  40. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/references/plot-template.json +0 -50
  41. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/references/time-usage.md +0 -307
  42. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/scripts/__pycache__/generate_html.cpython-313.pyc +0 -0
  43. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/scripts/build.py +0 -107
  44. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/scripts/generate_html.py +0 -896
  45. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/scripts/generate_html_from_template.py +0 -114
  46. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/scripts/get_time.py +0 -174
  47. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/interactive-fiction-learning/scripts/merge_chapters.py +0 -111
  48. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/references/chapter-generation.md +0 -526
  49. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/references/performance-optimization.md +0 -192
  50. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/references/plot-design.md +0 -583
  51. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/references/plot-template.json +0 -50
  52. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/references/time-usage.md +0 -307
  53. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/scripts/__pycache__/generate_html.cpython-313.pyc +0 -0
  54. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/scripts/build.py +0 -107
  55. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/scripts/generate_html.py +0 -896
  56. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/scripts/generate_html_from_template.py +0 -114
  57. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/scripts/get_time.py +0 -174
  58. mindbot-0.3.0/src/mindbot/templates/skills/interactive-fiction-learning/scripts/merge_chapters.py +0 -111
  59. mindbot-0.3.0/src/mindbot/tools/builtin.py +0 -36
  60. {mindbot-0.3.0 → mindbot-0.3.2}/LICENSE +0 -0
  61. {mindbot-0.3.0 → mindbot-0.3.2}/setup.cfg +0 -0
  62. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/__main__.py +0 -0
  63. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/__init__.py +0 -0
  64. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/approval.py +0 -0
  65. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/input.py +0 -0
  66. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/input_builder.py +0 -0
  67. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/interrupt.py +0 -0
  68. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/models.py +0 -0
  69. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/multi_agent.py +0 -0
  70. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/orchestrator.py +0 -0
  71. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/scheduler.py +0 -0
  72. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/agent/streaming.py +0 -0
  73. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/builders/__init__.py +0 -0
  74. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/builders/llm_builder.py +0 -0
  75. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/builders/model_ref.py +0 -0
  76. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/builders/tool_builder.py +0 -0
  77. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/bus/__init__.py +0 -0
  78. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/bus/events.py +0 -0
  79. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/bus/outbound.py +0 -0
  80. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/bus/queue.py +0 -0
  81. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/__init__.py +0 -0
  82. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/backends/__init__.py +0 -0
  83. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/backends/base.py +0 -0
  84. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/backends/tool_backend.py +0 -0
  85. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/backends/tooling/__init__.py +0 -0
  86. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/backends/tooling/executor.py +0 -0
  87. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/backends/tooling/meta_tool.py +0 -0
  88. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/backends/tooling/models.py +0 -0
  89. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/backends/tooling/registry.py +0 -0
  90. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/executor.py +0 -0
  91. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/facade.py +0 -0
  92. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/models.py +0 -0
  93. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/capability/registry.py +0 -0
  94. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/channels/__init__.py +0 -0
  95. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/channels/base.py +0 -0
  96. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/channels/cli.py +0 -0
  97. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/channels/feishu.py +0 -0
  98. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/channels/http.py +0 -0
  99. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/channels/manager.py +0 -0
  100. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/config/__init__.py +0 -0
  101. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/config/approval.py +0 -0
  102. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/config/env_subst.py +0 -0
  103. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/config/loader.py +0 -0
  104. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/config/store.py +0 -0
  105. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/config/vision.py +0 -0
  106. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/config/watcher.py +0 -0
  107. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/context/__init__.py +0 -0
  108. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/context/archiver.py +0 -0
  109. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/context/checkpoint.py +0 -0
  110. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/context/compression.py +0 -0
  111. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/context/extraction.py +0 -0
  112. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/context/manager.py +0 -0
  113. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/cron/__init__.py +0 -0
  114. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/cron/service.py +0 -0
  115. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/cron/types.py +0 -0
  116. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/__init__.py +0 -0
  117. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/dynamic_manager.py +0 -0
  118. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/events.py +0 -0
  119. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/executor.py +0 -0
  120. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/models.py +0 -0
  121. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/protocols.py +0 -0
  122. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/registry.py +0 -0
  123. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/system_prompt_builder.py +0 -0
  124. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/tool_generator.py +0 -0
  125. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/generation/validator.py +0 -0
  126. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/memory/__init__.py +0 -0
  127. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/memory/compaction.py +0 -0
  128. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/memory/indexer.py +0 -0
  129. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/memory/manager.py +0 -0
  130. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/memory/markdown.py +0 -0
  131. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/memory/searcher.py +0 -0
  132. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/memory/storage.py +0 -0
  133. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/memory/types.py +0 -0
  134. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/multimodal/__init__.py +0 -0
  135. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/multimodal/models.py +0 -0
  136. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/multimodal/processor.py +0 -0
  137. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/__init__.py +0 -0
  138. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/adapter.py +0 -0
  139. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/base.py +0 -0
  140. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/factory.py +0 -0
  141. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/ollama/__init__.py +0 -0
  142. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/ollama/param.py +0 -0
  143. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/ollama/provider.py +0 -0
  144. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/openai/__init__.py +0 -0
  145. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/param.py +0 -0
  146. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/transformers/__init__.py +0 -0
  147. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/transformers/param.py +0 -0
  148. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/providers/transformers/provider.py +0 -0
  149. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/routing/__init__.py +0 -0
  150. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/routing/adapter.py +0 -0
  151. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/routing/endpoint.py +0 -0
  152. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/routing/models.py +0 -0
  153. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/routing/router.py +0 -0
  154. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/session/__init__.py +0 -0
  155. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/session/store.py +0 -0
  156. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/skills/__init__.py +0 -0
  157. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/skills/loader.py +0 -0
  158. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/skills/models.py +0 -0
  159. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/skills/registry.py +0 -0
  160. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/skills/render.py +0 -0
  161. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/skills/selector.py +0 -0
  162. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/templates/SYSTEM.md +0 -0
  163. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/templates/skills/mindbot-runtime-inspection/SKILL.md +0 -0
  164. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/templates/skills/mindbot-self-knowledge/SKILL.md +0 -0
  165. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/templates/skills/system-basic-info/SKILL.md +0 -0
  166. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/tools/__init__.py +0 -0
  167. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/tools/web_ops.py +0 -0
  168. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot/utils/ollama_setup.py +0 -0
  169. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot.egg-info/dependency_links.txt +0 -0
  170. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot.egg-info/entry_points.txt +0 -0
  171. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot.egg-info/requires.txt +0 -0
  172. {mindbot-0.3.0 → mindbot-0.3.2}/src/mindbot.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mindbot
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: 基于 **Python + asyncio** 的模块化 AI Agent 框架,支持多 Provider、动态路由、流式响应和工具确认机制。
5
5
  Author: MindBot Team
6
6
  License: MIT
@@ -28,7 +28,7 @@ Dynamic: license-file
28
28
 
29
29
  # MindBot
30
30
 
31
- [![Version](https://img.shields.io/badge/Version-0.2.0-blue.svg)](https://github.com/your-org/mindbot)
31
+ [![Version](https://img.shields.io/badge/Version-0.3.1-blue.svg)](https://github.com/your-org/mindbot)
32
32
  [![Python](https://img.shields.io/badge/Python-3.10+-blue?logo=python)](https://www.python.org/)
33
33
  [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
34
34
 
@@ -45,12 +45,13 @@ Dynamic: license-file
45
45
  | 统一入口 | `AgentOrchestrator` 自主决策,无需预选模式 |
46
46
  | 流式响应 | 实时事件流,用户可看到 Agent 思考过程 |
47
47
  | 工具确认 | 多级安全确认机制(安全级别、白名单、危险工具检测)|
48
+ | 路径安全 | 文件工具路径策略 + Shell 执行边界控制,降低越权风险 |
48
49
  | 智能路由 | 根据内容类型/复杂度/关键词自动选择模型 |
49
50
  | 多 Provider | OpenAI / Ollama / Transformers / llama.cpp |
50
51
  | 可中断执行 | 用户可随时中止 Agent 运行 |
51
52
  | 记忆系统 | 短期/长期记忆,向量检索,自动归档 |
52
53
  | Skills 机制 | `SKILL.md` 技能包按需注入 prompt,默认摘要、命中后展开正文 |
53
- | 上下文管理 | Token 预算管理,自动压缩 |
54
+ | 上下文管理 | Token 预算管理,自动压缩,工具持久化策略(none/summary/full)|
54
55
  | 多通道支持 | CLI、HTTP、飞书、Telegram |
55
56
  | 对话追踪 | Tracer 记录完整对话日志 |
56
57
 
@@ -119,7 +120,7 @@ mindbot generate-config
119
120
  ]
120
121
  },
121
122
 
122
- // Moonshot(OpenAI 兼容)
123
+ // OpenAI 兼容
123
124
  "moonshot": {
124
125
  "type": "openai",
125
126
  "strategy": "priority",
@@ -141,7 +142,17 @@ mindbot generate-config
141
142
  "model": "local-ollama/qwen3",
142
143
  "temperature": 0.7,
143
144
  "max_tokens": 8192,
144
- "max_tool_iterations": 20
145
+ "max_tool_iterations": 20,
146
+ "workspace": "~/.mindbot/workspace",
147
+ "system_path_whitelist": ["~/.mindbot"],
148
+ "trusted_paths": [],
149
+ "restrict_to_workspace": true,
150
+ "shell_execution": {
151
+ "policy": "cwd_guard",
152
+ "sandbox_provider": "none",
153
+ "fail_if_unavailable": false
154
+ },
155
+ "tool_persistence": "none"
145
156
  },
146
157
 
147
158
  // 动态路由
@@ -204,6 +215,23 @@ mindbot generate-config
204
215
 
205
216
  > **注意**:YAML 配置格式已弃用,请使用 JSON/JSONC 格式。可使用 `mindbot config migrate` 迁移旧配置。
206
217
 
218
+ ### Agent 配置项说明
219
+
220
+ | 配置项 | 类型 | 默认值 | 说明 |
221
+ |--------|------|--------|------|
222
+ | `model` | string | `"local-ollama/qwen3.5:2b"` | 默认模型,格式 `instance/model` |
223
+ | `workspace` | string | `"~/.mindbot/workspace"` | 内置文件/Shell 工具的工作空间根目录 |
224
+ | `system_path_whitelist` | list | `["~/.mindbot"]` | 额外允许的系统路径根目录白名单,白名单目录下的子树也允许访问 |
225
+ | `trusted_paths` | list | `[]` | 用户显式信任的目录根;shell 会话可在授权后把这些目录当作默认当前目录 |
226
+ | `restrict_to_workspace` | bool | `true` | 是否将工具限制在工作空间和允许根目录内 |
227
+ | `shell_execution.policy` | string | `"cwd_guard"` | Shell 执行策略;`cwd_guard` 只校验启动目录与基础安全规则,`sandboxed` 预留给未来 OS 级沙箱 |
228
+ | `shell_execution.sandbox_provider` | string | `"none"` | 预留的 Shell 沙箱后端,v0.3 默认不启用 |
229
+ | `shell_execution.fail_if_unavailable` | bool | `false` | 未来 `sandboxed` 模式下,沙箱不可用时是否失败关闭 |
230
+ | `tool_persistence` | string | `"none"` | 工具消息持久化策略:`none`/`summary`/`full` |
231
+ | `max_tool_iterations` | int | `20` | 单轮最大工具迭代次数 |
232
+ | `temperature` | float | `0.7` | LLM 温度参数 |
233
+ | `max_tokens` | int | `8192` | 最大生成 token 数 |
234
+
207
235
  ### 3.1 Skills 机制
208
236
 
209
237
  - 内置 skill 位于 `mindbot/skills/<skill-name>/SKILL.md`
@@ -218,6 +246,48 @@ mindbot generate-config
218
246
  mindbot config validate
219
247
  ```
220
248
 
249
+ ## Benchmark
250
+
251
+ 当前推荐的 `MindBot v1 benchmark` 是 `ToolCall-15`。
252
+
253
+ 如果你想直接启动 benchmark,可按下面最短路径执行:
254
+
255
+ ```bash
256
+ # 终端 1
257
+ mindbot toolcall15-adapter --host 127.0.0.1 --port 11435 --model local-ollama/qwen3
258
+
259
+ # 终端 2
260
+ cd benchmark/ToolCall-15
261
+ cp .env.example .env
262
+ ```
263
+
264
+ `.env` 示例:
265
+
266
+ ```env
267
+ LMSTUDIO_HOST=http://127.0.0.1:11435
268
+ LLM_MODELS=lmstudio:local-ollama/qwen3
269
+ MODEL_REQUEST_TIMEOUT_SECONDS=30
270
+ ```
271
+
272
+ 然后执行:
273
+
274
+ ```bash
275
+ npm install
276
+ npm run dev
277
+ ```
278
+
279
+ 浏览器打开 `http://localhost:3000` 即可开始跑 benchmark。
280
+
281
+ 完整说明见 `docs/testing/toolcall15.md`。
282
+
283
+ 第二阶段 benchmark 是 `real-tools`,用于验证 MindBot 是否真的执行了内置文件、Shell 和本地 HTTP 工具:
284
+
285
+ ```bash
286
+ python benchmark/real-tools/runner.py --config-path ~/.mindbot/settings.json --model gpt-backup/glm-5
287
+ ```
288
+
289
+ 完整说明见 `docs/testing/real-tools.md` 和 `benchmark/real-tools/README.md`。
290
+
221
291
  ### 5. 基本使用
222
292
 
223
293
  ```python
@@ -350,6 +420,7 @@ AssistantResponse
350
420
  | Context | `context/` | 上下文管理 |
351
421
  | Memory | `memory/` | 记忆系统 |
352
422
  | Capability Tooling | `capability/backends/tooling/` | 工具注册与执行 |
423
+ | Tools | `tools/` | 内置工具(文件/Shell/运行时)|
353
424
  | Channels | `channels/` | 多通道支持 |
354
425
  | Config | `config/` | 配置管理(JSON/JSONC)|
355
426
  | Session | `session/` | 会话日志与类型 |
@@ -443,6 +514,57 @@ AssistantResponse
443
514
  }
444
515
  ```
445
516
 
517
+ ## 路径安全策略
518
+
519
+ MindBot v0.3 将“文件路径策略”和“Shell 执行边界”分开描述:
520
+
521
+ - **workspace**: 默认工作目录,所有相对路径以此解析
522
+ - **restrict_to_workspace**: 启用时,文件工具只能在 `workspace` 和 `system_path_whitelist` 定义的允许根目录内运行
523
+ - **system_path_whitelist**: 额外允许访问的系统路径根目录列表(如 `~/.mindbot`),每个根目录都会递归覆盖其子目录和文件
524
+ - **trusted_paths**: 用户显式授权过的目录根;当 `mindbot shell` 从这些目录启动时,文件工具和 shell 可优先把它们作为默认当前目录
525
+ - **shell_execution.policy**: Shell 的独立执行策略;默认 `cwd_guard` 只校验 `working_dir` 和危险命令模式,不是 OS 级沙箱
526
+
527
+ ### 路径安全示例
528
+
529
+ ```jsonc
530
+ {
531
+ "agent": {
532
+ "workspace": "~/.mindbot/workspace",
533
+ "system_path_whitelist": ["~/.mindbot", "/tmp"],
534
+ "trusted_paths": ["/root/research/mindbot"],
535
+ "restrict_to_workspace": true,
536
+ "shell_execution": {
537
+ "policy": "cwd_guard",
538
+ "sandbox_provider": "none",
539
+ "fail_if_unavailable": false
540
+ }
541
+ }
542
+ }
543
+ ```
544
+
545
+ **安全规则**:
546
+ - 绝对路径必须落在允许范围内
547
+ - 相对路径基于 workspace 解析
548
+ - 允许根目录按目录树递归生效
549
+ - `mindbot shell` 启动目录会被记录为当前会话目录;若该目录未被信任,CLI 会先要求用户授权再将其作为默认目录
550
+ - 文件工具的路径检查适用于读、写、编辑、列目录等内置文件操作
551
+ - Shell 的 `cwd_guard` 模式只校验 `working_dir` 是否落在允许根目录内,并应用轻量危险命令检查
552
+ - `cwd_guard` 不是 OS 级文件系统沙箱;shell 子进程不会自动获得像 Claude Code Bash sandbox 那样的强隔离
553
+ - 超出范围的路径返回策略错误
554
+
555
+ ## 内置工具
556
+
557
+ | 工具 | 类别 | 说明 |
558
+ |------|------|------|
559
+ | `read_file` | 文件 | 读取文件,支持 offset/limit 分页 |
560
+ | `write_file` | 文件 | 写入文件,自动创建父目录 |
561
+ | `edit_file` | 文件 | 精确文本替换,支持 replace_all |
562
+ | `list_directory` | 文件 | 列出目录内容,支持 glob 模式 |
563
+ | `file_info` | 文件 | 获取文件/目录基本信息 |
564
+ | `exec_command` | Shell | 执行命令,带超时和安全检查 |
565
+ | `get_mindbot_runtime_info` | 系统 | 获取运行时配置、内存、日志等状态 |
566
+ | `web_search` | Web | 网络搜索(需配置 Provider)|
567
+
446
568
  ## LLM Provider
447
569
 
448
570
  ### 模型格式
@@ -542,6 +664,7 @@ AssistantResponse
542
664
  ├── skills/ # 自定义技能
543
665
  ├── memory/ # Markdown 记忆存储
544
666
  ├── history/ # CLI 历史记录
667
+ ├── workspace/ # 默认工作空间
545
668
  ├── data/
546
669
  │ ├── memory.db # 记忆数据库
547
670
  │ └── journal/ # 会话记录
@@ -569,7 +692,9 @@ mindbot/
569
692
  │ ├── multimodal/ # 多模态支持
570
693
  │ ├── cron/ # 定时任务
571
694
  │ ├── config/ # 配置模型与加载(JSON/JSONC)
572
- └── cli/ # CLI 命令实现
695
+ ├── cli/ # CLI 命令实现
696
+ │ ├── tools/ # 内置工具(文件/Shell/运行时)
697
+ │ └── utils/ # 工具函数
573
698
  ├── docs/ # 文档
574
699
  ├── tests/ # 测试
575
700
  ├── examples/ # 示例代码
@@ -1,6 +1,6 @@
1
1
  # MindBot
2
2
 
3
- [![Version](https://img.shields.io/badge/Version-0.2.0-blue.svg)](https://github.com/your-org/mindbot)
3
+ [![Version](https://img.shields.io/badge/Version-0.3.1-blue.svg)](https://github.com/your-org/mindbot)
4
4
  [![Python](https://img.shields.io/badge/Python-3.10+-blue?logo=python)](https://www.python.org/)
5
5
  [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
6
6
 
@@ -17,12 +17,13 @@
17
17
  | 统一入口 | `AgentOrchestrator` 自主决策,无需预选模式 |
18
18
  | 流式响应 | 实时事件流,用户可看到 Agent 思考过程 |
19
19
  | 工具确认 | 多级安全确认机制(安全级别、白名单、危险工具检测)|
20
+ | 路径安全 | 文件工具路径策略 + Shell 执行边界控制,降低越权风险 |
20
21
  | 智能路由 | 根据内容类型/复杂度/关键词自动选择模型 |
21
22
  | 多 Provider | OpenAI / Ollama / Transformers / llama.cpp |
22
23
  | 可中断执行 | 用户可随时中止 Agent 运行 |
23
24
  | 记忆系统 | 短期/长期记忆,向量检索,自动归档 |
24
25
  | Skills 机制 | `SKILL.md` 技能包按需注入 prompt,默认摘要、命中后展开正文 |
25
- | 上下文管理 | Token 预算管理,自动压缩 |
26
+ | 上下文管理 | Token 预算管理,自动压缩,工具持久化策略(none/summary/full)|
26
27
  | 多通道支持 | CLI、HTTP、飞书、Telegram |
27
28
  | 对话追踪 | Tracer 记录完整对话日志 |
28
29
 
@@ -91,7 +92,7 @@ mindbot generate-config
91
92
  ]
92
93
  },
93
94
 
94
- // Moonshot(OpenAI 兼容)
95
+ // OpenAI 兼容
95
96
  "moonshot": {
96
97
  "type": "openai",
97
98
  "strategy": "priority",
@@ -113,7 +114,17 @@ mindbot generate-config
113
114
  "model": "local-ollama/qwen3",
114
115
  "temperature": 0.7,
115
116
  "max_tokens": 8192,
116
- "max_tool_iterations": 20
117
+ "max_tool_iterations": 20,
118
+ "workspace": "~/.mindbot/workspace",
119
+ "system_path_whitelist": ["~/.mindbot"],
120
+ "trusted_paths": [],
121
+ "restrict_to_workspace": true,
122
+ "shell_execution": {
123
+ "policy": "cwd_guard",
124
+ "sandbox_provider": "none",
125
+ "fail_if_unavailable": false
126
+ },
127
+ "tool_persistence": "none"
117
128
  },
118
129
 
119
130
  // 动态路由
@@ -176,6 +187,23 @@ mindbot generate-config
176
187
 
177
188
  > **注意**:YAML 配置格式已弃用,请使用 JSON/JSONC 格式。可使用 `mindbot config migrate` 迁移旧配置。
178
189
 
190
+ ### Agent 配置项说明
191
+
192
+ | 配置项 | 类型 | 默认值 | 说明 |
193
+ |--------|------|--------|------|
194
+ | `model` | string | `"local-ollama/qwen3.5:2b"` | 默认模型,格式 `instance/model` |
195
+ | `workspace` | string | `"~/.mindbot/workspace"` | 内置文件/Shell 工具的工作空间根目录 |
196
+ | `system_path_whitelist` | list | `["~/.mindbot"]` | 额外允许的系统路径根目录白名单,白名单目录下的子树也允许访问 |
197
+ | `trusted_paths` | list | `[]` | 用户显式信任的目录根;shell 会话可在授权后把这些目录当作默认当前目录 |
198
+ | `restrict_to_workspace` | bool | `true` | 是否将工具限制在工作空间和允许根目录内 |
199
+ | `shell_execution.policy` | string | `"cwd_guard"` | Shell 执行策略;`cwd_guard` 只校验启动目录与基础安全规则,`sandboxed` 预留给未来 OS 级沙箱 |
200
+ | `shell_execution.sandbox_provider` | string | `"none"` | 预留的 Shell 沙箱后端,v0.3 默认不启用 |
201
+ | `shell_execution.fail_if_unavailable` | bool | `false` | 未来 `sandboxed` 模式下,沙箱不可用时是否失败关闭 |
202
+ | `tool_persistence` | string | `"none"` | 工具消息持久化策略:`none`/`summary`/`full` |
203
+ | `max_tool_iterations` | int | `20` | 单轮最大工具迭代次数 |
204
+ | `temperature` | float | `0.7` | LLM 温度参数 |
205
+ | `max_tokens` | int | `8192` | 最大生成 token 数 |
206
+
179
207
  ### 3.1 Skills 机制
180
208
 
181
209
  - 内置 skill 位于 `mindbot/skills/<skill-name>/SKILL.md`
@@ -190,6 +218,48 @@ mindbot generate-config
190
218
  mindbot config validate
191
219
  ```
192
220
 
221
+ ## Benchmark
222
+
223
+ 当前推荐的 `MindBot v1 benchmark` 是 `ToolCall-15`。
224
+
225
+ 如果你想直接启动 benchmark,可按下面最短路径执行:
226
+
227
+ ```bash
228
+ # 终端 1
229
+ mindbot toolcall15-adapter --host 127.0.0.1 --port 11435 --model local-ollama/qwen3
230
+
231
+ # 终端 2
232
+ cd benchmark/ToolCall-15
233
+ cp .env.example .env
234
+ ```
235
+
236
+ `.env` 示例:
237
+
238
+ ```env
239
+ LMSTUDIO_HOST=http://127.0.0.1:11435
240
+ LLM_MODELS=lmstudio:local-ollama/qwen3
241
+ MODEL_REQUEST_TIMEOUT_SECONDS=30
242
+ ```
243
+
244
+ 然后执行:
245
+
246
+ ```bash
247
+ npm install
248
+ npm run dev
249
+ ```
250
+
251
+ 浏览器打开 `http://localhost:3000` 即可开始跑 benchmark。
252
+
253
+ 完整说明见 `docs/testing/toolcall15.md`。
254
+
255
+ 第二阶段 benchmark 是 `real-tools`,用于验证 MindBot 是否真的执行了内置文件、Shell 和本地 HTTP 工具:
256
+
257
+ ```bash
258
+ python benchmark/real-tools/runner.py --config-path ~/.mindbot/settings.json --model gpt-backup/glm-5
259
+ ```
260
+
261
+ 完整说明见 `docs/testing/real-tools.md` 和 `benchmark/real-tools/README.md`。
262
+
193
263
  ### 5. 基本使用
194
264
 
195
265
  ```python
@@ -322,6 +392,7 @@ AssistantResponse
322
392
  | Context | `context/` | 上下文管理 |
323
393
  | Memory | `memory/` | 记忆系统 |
324
394
  | Capability Tooling | `capability/backends/tooling/` | 工具注册与执行 |
395
+ | Tools | `tools/` | 内置工具(文件/Shell/运行时)|
325
396
  | Channels | `channels/` | 多通道支持 |
326
397
  | Config | `config/` | 配置管理(JSON/JSONC)|
327
398
  | Session | `session/` | 会话日志与类型 |
@@ -415,6 +486,57 @@ AssistantResponse
415
486
  }
416
487
  ```
417
488
 
489
+ ## 路径安全策略
490
+
491
+ MindBot v0.3 将“文件路径策略”和“Shell 执行边界”分开描述:
492
+
493
+ - **workspace**: 默认工作目录,所有相对路径以此解析
494
+ - **restrict_to_workspace**: 启用时,文件工具只能在 `workspace` 和 `system_path_whitelist` 定义的允许根目录内运行
495
+ - **system_path_whitelist**: 额外允许访问的系统路径根目录列表(如 `~/.mindbot`),每个根目录都会递归覆盖其子目录和文件
496
+ - **trusted_paths**: 用户显式授权过的目录根;当 `mindbot shell` 从这些目录启动时,文件工具和 shell 可优先把它们作为默认当前目录
497
+ - **shell_execution.policy**: Shell 的独立执行策略;默认 `cwd_guard` 只校验 `working_dir` 和危险命令模式,不是 OS 级沙箱
498
+
499
+ ### 路径安全示例
500
+
501
+ ```jsonc
502
+ {
503
+ "agent": {
504
+ "workspace": "~/.mindbot/workspace",
505
+ "system_path_whitelist": ["~/.mindbot", "/tmp"],
506
+ "trusted_paths": ["/root/research/mindbot"],
507
+ "restrict_to_workspace": true,
508
+ "shell_execution": {
509
+ "policy": "cwd_guard",
510
+ "sandbox_provider": "none",
511
+ "fail_if_unavailable": false
512
+ }
513
+ }
514
+ }
515
+ ```
516
+
517
+ **安全规则**:
518
+ - 绝对路径必须落在允许范围内
519
+ - 相对路径基于 workspace 解析
520
+ - 允许根目录按目录树递归生效
521
+ - `mindbot shell` 启动目录会被记录为当前会话目录;若该目录未被信任,CLI 会先要求用户授权再将其作为默认目录
522
+ - 文件工具的路径检查适用于读、写、编辑、列目录等内置文件操作
523
+ - Shell 的 `cwd_guard` 模式只校验 `working_dir` 是否落在允许根目录内,并应用轻量危险命令检查
524
+ - `cwd_guard` 不是 OS 级文件系统沙箱;shell 子进程不会自动获得像 Claude Code Bash sandbox 那样的强隔离
525
+ - 超出范围的路径返回策略错误
526
+
527
+ ## 内置工具
528
+
529
+ | 工具 | 类别 | 说明 |
530
+ |------|------|------|
531
+ | `read_file` | 文件 | 读取文件,支持 offset/limit 分页 |
532
+ | `write_file` | 文件 | 写入文件,自动创建父目录 |
533
+ | `edit_file` | 文件 | 精确文本替换,支持 replace_all |
534
+ | `list_directory` | 文件 | 列出目录内容,支持 glob 模式 |
535
+ | `file_info` | 文件 | 获取文件/目录基本信息 |
536
+ | `exec_command` | Shell | 执行命令,带超时和安全检查 |
537
+ | `get_mindbot_runtime_info` | 系统 | 获取运行时配置、内存、日志等状态 |
538
+ | `web_search` | Web | 网络搜索(需配置 Provider)|
539
+
418
540
  ## LLM Provider
419
541
 
420
542
  ### 模型格式
@@ -514,6 +636,7 @@ AssistantResponse
514
636
  ├── skills/ # 自定义技能
515
637
  ├── memory/ # Markdown 记忆存储
516
638
  ├── history/ # CLI 历史记录
639
+ ├── workspace/ # 默认工作空间
517
640
  ├── data/
518
641
  │ ├── memory.db # 记忆数据库
519
642
  │ └── journal/ # 会话记录
@@ -541,7 +664,9 @@ mindbot/
541
664
  │ ├── multimodal/ # 多模态支持
542
665
  │ ├── cron/ # 定时任务
543
666
  │ ├── config/ # 配置模型与加载(JSON/JSONC)
544
- └── cli/ # CLI 命令实现
667
+ ├── cli/ # CLI 命令实现
668
+ │ ├── tools/ # 内置工具(文件/Shell/运行时)
669
+ │ └── utils/ # 工具函数
545
670
  ├── docs/ # 文档
546
671
  ├── tests/ # 测试
547
672
  ├── examples/ # 示例代码
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mindbot"
3
- version = "0.3.0"
3
+ version = "0.3.2"
4
4
  description = "基于 **Python + asyncio** 的模块化 AI Agent 框架,支持多 Provider、动态路由、流式响应和工具确认机制。"
5
5
  authors = [
6
6
  {name = "MindBot Team"}
@@ -1,6 +1,6 @@
1
1
  """MindBot - AI Assistant (Native Implementation)."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.3.2"
4
4
 
5
5
  __logo__ = """
6
6
  ╔════════════════════════════════════╗
@@ -36,6 +36,7 @@ if TYPE_CHECKING:
36
36
  from mindbot.config.schema import SkillsConfig
37
37
  from mindbot.generation.dynamic_manager import DynamicToolManager
38
38
  from mindbot.memory.manager import MemoryManager
39
+ from mindbot.session.store import SessionJournal
39
40
  from mindbot.skills.registry import SkillRegistry
40
41
 
41
42
  logger = get_logger("agent")
@@ -144,6 +145,8 @@ class Agent:
144
145
  tuple[bool, frozenset[tuple[str, int]]],
145
146
  ] = {}
146
147
  self._capability_tool_cache: dict[str, Tool] = {}
148
+ self._journal: "SessionJournal | None" = None
149
+ self._journal_sessions: set[str] = set()
147
150
 
148
151
  # ------------------------------------------------------------------
149
152
  # Tool management
@@ -210,6 +213,12 @@ class Agent:
210
213
  """Return whether a tool is currently visible to the LLM."""
211
214
  return any(getattr(tool, "name", None) == tool_name for tool in self.list_tools())
212
215
 
216
+ def set_session_journal(self, journal: "SessionJournal | None") -> None:
217
+ """Attach or detach the shared session journal for this agent."""
218
+ self._journal = journal
219
+ if journal is None:
220
+ self._journal_sessions.clear()
221
+
213
222
  # ------------------------------------------------------------------
214
223
  # Session management (LRU)
215
224
  # ------------------------------------------------------------------
@@ -330,12 +339,15 @@ class Agent:
330
339
  def _get_persistence_writer(self, session_id: str) -> PersistenceWriter:
331
340
  """Build a :class:`PersistenceWriter` for *session_id*."""
332
341
  context = self._get_session_context(session_id)
333
- return PersistenceWriter(
342
+ writer = PersistenceWriter(
334
343
  context=context,
335
344
  memory=self.memory,
345
+ journal=self._journal,
336
346
  tool_persistence=self._tool_persistence,
337
347
  system_prompt=self.system_prompt,
338
348
  )
349
+ writer._journal_sessions = self._journal_sessions
350
+ return writer
339
351
 
340
352
  async def _run_turn(
341
353
  self,
@@ -348,6 +360,7 @@ class Agent:
348
360
  """Run one turn through the shared execution path."""
349
361
  input_builder = self._get_session_input_builder(session_id)
350
362
  messages = input_builder.build(message, session_id=session_id)
363
+ user_timestamp = messages[-1].timestamp if messages and messages[-1].role == "user" else None
351
364
  turn_engine = self._get_turn_engine(session_id, turn_context)
352
365
  response = await turn_engine.run(
353
366
  messages=messages,
@@ -355,7 +368,12 @@ class Agent:
355
368
  )
356
369
 
357
370
  writer = self._get_persistence_writer(session_id)
358
- writer.commit_turn(message, response, session_id=session_id)
371
+ writer.commit_turn(
372
+ message,
373
+ response,
374
+ session_id=session_id,
375
+ user_timestamp=user_timestamp,
376
+ )
359
377
  return response
360
378
 
361
379
  # ------------------------------------------------------------------
@@ -3,7 +3,7 @@
3
3
  MindAgent acts as a Supervisor that:
4
4
  * Creates and owns a *main Agent* which handles conversation, tools, and memory.
5
5
  * Maintains a registry of named *child Agents* for sub-task delegation.
6
- * Writes an optional append-only Session Journal after each turn.
6
+ * Wires an optional append-only Session Journal into the shared persistence path.
7
7
  * Keeps the same public API as before, so existing channels (CLI, HTTP,
8
8
  Feishu …) and the MindBot wrapper do not need changes.
9
9
  """
@@ -18,14 +18,11 @@ from mindbot.agent.models import AgentEvent, AgentResponse, StopReason, TurnResu
18
18
  from mindbot.builders import create_agent, create_llm
19
19
  from mindbot.capability.backends.tooling import ToolRegistry
20
20
  from mindbot.config.schema import Config
21
- from mindbot.context.models import Message
22
21
  from mindbot.memory import MemoryManager
23
22
  from mindbot.session import SessionJournal
24
- from mindbot.session.types import SessionMessage
25
23
  from mindbot.utils import get_logger
26
24
 
27
25
  if TYPE_CHECKING:
28
- from mindbot.agent.persistence_writer import PersistenceWriter as _PersistenceWriter
29
26
  from mindbot.capability.facade import CapabilityFacade
30
27
 
31
28
  logger = get_logger("agent.core")
@@ -69,7 +66,7 @@ class MindAgent:
69
66
  if config.session_journal.enabled:
70
67
  self._journal = SessionJournal(config.session_journal.path)
71
68
  logger.info("Session journal enabled at %s", config.session_journal.path)
72
- self._journal_sessions: set[str] = set()
69
+ self._main_agent.set_session_journal(self._journal)
73
70
 
74
71
  # ------------------------------------------------------------------
75
72
  # Internal factory
@@ -161,86 +158,10 @@ class MindAgent:
161
158
  """Return whether the main agent currently exposes *tool_name*."""
162
159
  return self._main_agent.has_tool(tool_name)
163
160
 
164
- # ------------------------------------------------------------------
165
- # Session Journal helpers
166
- # ------------------------------------------------------------------
167
-
168
- @staticmethod
169
- def _msgs_to_journal(msgs: list[Message]) -> list[SessionMessage]:
170
- result: list[SessionMessage] = []
171
- for m in msgs:
172
- tool_calls = None
173
- if m.tool_calls:
174
- tool_calls = [
175
- {"id": tc.id, "name": tc.name, "arguments": tc.arguments}
176
- for tc in m.tool_calls
177
- ]
178
- result.append(SessionMessage(
179
- role=m.role,
180
- content=m.text,
181
- timestamp=m.timestamp,
182
- tool_calls=tool_calls,
183
- tool_call_id=m.tool_call_id,
184
- reasoning_content=m.reasoning_content,
185
- ))
186
- return result
187
-
188
- def _write_journal(
189
- self,
190
- session_id: str,
191
- user_message: str,
192
- assistant_content: str,
193
- trace: list[Message] | None = None,
194
- ) -> None:
195
- """Persist the current turn to the journal (if enabled)."""
196
- if self._journal is None:
197
- return
198
-
199
- entries: list[SessionMessage] = []
200
-
201
- if session_id not in self._journal_sessions:
202
- system_prompt = self.config.agent.system_prompt
203
- if system_prompt:
204
- entries.append(SessionMessage(role="system", content=system_prompt))
205
- self._journal_sessions.add(session_id)
206
-
207
- entries.append(SessionMessage(role="user", content=user_message))
208
-
209
- if trace:
210
- entries.extend(self._msgs_to_journal(trace))
211
-
212
- # The authoritative trace already includes the final assistant
213
- # message when produced by TurnEngine. Only append an explicit
214
- # assistant entry when there is no trace (e.g. streaming mode).
215
- trace_has_final = (
216
- trace
217
- and trace[-1].role == "assistant"
218
- and not trace[-1].tool_calls
219
- )
220
- if not trace_has_final:
221
- entries.append(SessionMessage(role="assistant", content=assistant_content))
222
-
223
- self._journal.append(session_id, entries)
224
-
225
161
  # ------------------------------------------------------------------
226
162
  # Chat interfaces
227
163
  # ------------------------------------------------------------------
228
164
 
229
- def _get_journal_writer(self, session_id: str) -> "_PersistenceWriter | None":
230
- """Return a writer that handles journal-only persistence for this session."""
231
- if self._journal is None:
232
- return None
233
- from mindbot.agent.persistence_writer import PersistenceWriter
234
-
235
- ctx = self._main_agent._get_session_context(session_id)
236
- writer = PersistenceWriter(
237
- context=ctx,
238
- journal=self._journal,
239
- system_prompt=self.config.agent.system_prompt,
240
- )
241
- writer._journal_sessions = self._journal_sessions
242
- return writer
243
-
244
165
  async def chat(
245
166
  self,
246
167
  message: str,
@@ -250,7 +171,7 @@ class MindAgent:
250
171
  ) -> AgentResponse:
251
172
  """Primary async chat entry point.
252
173
 
253
- Delegates execution to the main Agent, then writes the session journal.
174
+ Delegates execution to the main Agent, which persists the full turn.
254
175
 
255
176
  Args:
256
177
  message: User message.
@@ -268,13 +189,6 @@ class MindAgent:
268
189
  tools=tools,
269
190
  )
270
191
 
271
- self._write_journal(
272
- session_id,
273
- user_message=message,
274
- assistant_content=response.content or "",
275
- trace=response.message_trace or None,
276
- )
277
-
278
192
  logger.info(
279
193
  "chat: session=%s stop_reason=%s",
280
194
  session_id,
@@ -290,23 +204,19 @@ class MindAgent:
290
204
  ) -> AsyncIterator[str]:
291
205
  """Primary async streaming chat entry point.
292
206
 
293
- Delegates to the main Agent and writes the journal after the stream
294
- completes.
207
+ Delegates to the main Agent, which persists the full turn before the
208
+ final response chunks are yielded.
295
209
 
296
210
  Yields:
297
211
  String chunks of the assistant response.
298
212
  """
299
- full_content = ""
300
213
  async for chunk in self._main_agent.chat_stream(
301
214
  message=message,
302
215
  session_id=session_id,
303
216
  tools=tools,
304
217
  ):
305
- full_content += chunk
306
218
  yield chunk
307
219
 
308
- self._write_journal(session_id, user_message=message, assistant_content=full_content)
309
-
310
220
  # ------------------------------------------------------------------
311
221
  # Memory interfaces
312
222
  # ------------------------------------------------------------------