fix(memory): 将项目记忆文件从 .agents/memory 迁移到 .astrion/memory 并更新提示词路径

This commit is contained in:
JOJO 2026-07-10 01:28:13 +08:00
parent e3c897947f
commit b7a535fc8f
21 changed files with 1306 additions and 1 deletions

View File

@ -0,0 +1,153 @@
---
name: agent_hooks_design
description: 当需要继续讨论或实现本项目的 hooks / 生命周期钩子功能时,应该索引本记忆
---
# Hooks / 生命周期钩子功能设计讨论(进行中)
## 调研结论
### 主流实现
- **Claude Code**最完整20+ 事件、5 种 handlercommand/http/mcp_tool/prompt/agent、多层配置全局/项目/本地/组织/插件/SDK
- **OpenAI Codex**11 个事件、command 回调为主、有信任审查机制和企业托管 hooks。
- **Cursor**`.cursor/hooks.json`Betacommand 回调,项目/用户/企业三级。
- **GitHub Copilot**`.github/hooks/*.json`command/http/prompt 三种回调Cloud Agent 也支持。
- **Windsurf/Cascade**`.windsurf/hooks.json`exit 2 阻断12 个事件。
- **Aider / Continue.dev / Kimi Code / Devin**:无原生 hooks 或资料有限。
### 共性模式
```
Agent 事件发生
stdin 发送 JSON 事件载荷 → Hook 脚本 / HTTP 端点
返回决策allow/deny/ask/modify/injectMessage
Agent 根据决策继续执行
```
## 用户(项目 owner对 hooks 的理解
> 钩子 = 发生一件事件之前/中/后 → 自动触发另一个事件。用 JSON 格式写条件和行为,分为全局/项目级,放在数据存储目录下/工作区内。
用户认可的核心:**事件驱动 + JSON 配置 + 全局/项目两级 + before/after 拦截**。
## 已达成的设计共识
### 1. 配置位置
- 全局:`~/.astrion/astrion/config/hooks.json`
- 项目级:`<project>/.astrion/hooks.json`
- 未来可扩展:`.astrion/hooks.local.json`、企业策略级。
- 多层配置**合并执行**,不是覆盖(更安全)。
### 2. 优先事件MVP 范围建议)
- `PreToolUse`:工具执行前拦截/修改
- `PostToolUse`:工具执行后触发后续动作
- `Stop`:模型/turn 结束时注入反馈
- `PreCompact`:上下文压缩前备份
### 3. 优先回调类型
- MVP 只做 `command`shell/python/任意可执行文件)。
- 后续可扩展 `http`、`prompt`、`agent`、`mcp_tool`。
### 4. 通信协议(对齐 Claude Code/Codex
- stdin 输入 JSON 事件载荷
- stdout 返回 JSON 决策
- exit code0=通过1=非阻断错误2=阻断
### 5. JSON 结构草案
```json
{
"version": 1,
"disabled": false,
"hooks": {
"PreToolUse": [
{
"name": "block-dangerous-rm",
"matcher": "run_command",
"if": "command contains 'rm -rf /'",
"enabled": true,
"max_repeats": null,
"hooks": [
{
"type": "command",
"command": "python3 ~/.astrion/astrion/hooks/block_dangerous.py",
"timeout": 5,
"statusMessage": "检查危险命令...",
"fail_policy": "continue",
"on_error": "log"
}
]
}
],
"Stop": [
{
"name": "remind-check-completion",
"max_repeats": 3,
"hooks": [
{
"type": "command",
"command": "python3 ~/.astrion/astrion/hooks/remind_check.py",
"timeout": 5
}
]
}
]
}
}
```
## 已讨论的具体例子
### 例子 1拦截危险命令
- 事件:`PreToolUse`
- 条件:`matcher=run_command` + `if=command contains 'rm -rf /'`
- 行为:调用脚本,返回 `permissionDecision: deny`
### 例子 2edit_file 单行全替换触发审核
- 事件:`PreToolUse`
- 条件:`matcher=edit_file` + `old_string` 只有一行 + `replace_all=true`
- 行为:返回 `permissionDecision: ask`
### 例子 3Stop 时自动插入 user 消息,最多 3 次
- 事件:`Stop`
- 行为:返回 `injectMessage: {role: "user", content: "请仔细检查是否真的完成了所有工作"}`
- "最多 3 次"可用 `max_repeats` 或由脚本自己维护状态文件。
## 尚未决定的决策点
1. **`if` 条件表达式语法**
- 选项 A简单规则 DSL`command contains '...'`
- 选项 B结构化 JSON`{"field": "...", "op": "contains", "value": "..."}`
- 选项 C交给 hook 脚本自己判断,`if` 只保留工具名匹配
2. **"最多 N 次"由谁负责**
- 框架负责 `max_repeats`(简单,但状态语义固定)
- 脚本自己维护状态文件(灵活,框架更轻量)
3. **注入消息语义**
- `injectMessage.user`:会触发模型再回复一轮
- `addContext.system`:只是给下一轮加提示,不立刻触发回复
4. **hook 失败时的主流程策略**
- 默认 `continue`(用户配置错误不瘫痪智能体)
- 或提供 `fail_policy: block` 让管理员强制策略
5. **工具名匹配**
- 是否同时支持内部工具名(`run_command`/`edit_file`)和 Claude Code 风格别名(`Bash`/`Edit|Write`
## 推荐后续路线
1. 先定 JSON schema 和 `if` 语法。
2. MVP 实现 `command` 回调 + `PreToolUse`/`PostToolUse`/`Stop`。
3. 新增 `modules/hook_manager.py`
4. 在 `core/main_terminal_parts/tools_execution.py``core/web_terminal.py` 插入 hook 调用。
5. 确保 API task 模式也走 hooks。
6. 补文档 `docs/hooks.md`
## 参考资料位置
- 调研报告:`research/claudecode_hooks/claudecode_hooks.md`
- 调研报告:`research/codex_hooks/codex_hooks.md`
- 调研报告:`research/other_agents_hooks/other_agents_hooks.md`

View File

@ -0,0 +1,68 @@
---
name: ai_avatar_demo
description: 当需要了解或继续开发/修改 agents 项目的 AI 形象头像 demo 时,应该索引本记忆
---
---
name: ai_avatar_demo
description: 当需要了解或继续开发/修改 agents 项目的 AI 形象头像 demo 时,应该索引本记忆
---
# AI 形象头像 Demo
## 文件位置
`/Users/jojo/Desktop/agents/正在修复中/agents/demo/ai-avatar/index.html`
## 设计目标
为项目设计一个独特、动态的 AI 形象,替代之前从网上找的通用小机器人 SVG。
## 当前设计
### 视觉构成
- **外框**flat-top 圆角正六边形(上下边水平,底部是一条横线),中心 `(100,100)`,外接圆半径 80圆角半径 14。
- **内部符号**:由两条等粗白色线段组成:
- 空闲态:两条竖线作为眼睛,长度 22间距 32位于 `y ≈ 84`(面部上半区域略偏上)。
- 工作态:`>` 终端提示符(无下横线),尖端朝右,开角 60°单条线长度 34。
### 状态与动画
- **空闲**:六边形停到最近的 60° 正位,显示眼睛,眼睛跟随鼠标移动。
- **工作**:六边形开始持续旋转,显示 `>` 符号。
- 状态切换时内部符号立即变形,不等待外框停稳;外框则从当前角度平滑过渡到目标角度或开始旋转。
- 内部符号在空闲/工作之间通过**同两条 `<line>`** 进行 morph
- `transform`(位置 + 旋转)使用 CSS `transition: transform 0.55s cubic-bezier(0.22, 1, 0.36, 1)`
- `x2`线段长度使用同节奏0.55s,相同 cubic-bezier`requestAnimationFrame` 插值,避免长度跳变。
- 提供一个独立的"停止追踪 / 开始追踪"按钮:停止追踪时眼睛平滑回到默认居中位置。
### 技术实现
- **纯 SVG**:外框用 `<path>`,眼睛 / `>``<line>`,整体用 `<svg>` + `<g>`
- **动画方式**
- 六边形旋转CSS `@keyframes spin` + CSS `transition`
- 符号变形CSS `transition` 改变 `transform`JS `requestAnimationFrame` 插值改变 `x2`
- 眼睛追踪JS `requestAnimationFrame` 实时更新 SVG `<g>``transform`
- **无 Canvas / WebGL / GIF / Lottie / 图片序列帧**
- 整体缩放不会导致比例或长度失调(矢量 SVG
## 设计约束
### 不可改动的核心动画
`demo/ai-avatar/index.html`**空闲idle****工作work** 两个核心状态的切换动画不可改动:
- 六边形外框:空闲时从当前角度滑到最近的 60° 正位后停住;工作时从当前角度开始持续旋转。
- 内部图标:空闲为眼睛,工作为 `>` 符号,二者通过同两条 `<line>` 元素进行 morphing 变形。
- 变形节奏统一为 0.55s cubic-bezier(0.22, 1, 0.36, 1)
- `transform` 由 CSS transition 处理。
- `x2` 长度由 JS `requestAnimationFrame` 插值处理CSS transition 不直接支持 SVG `x2` 属性)。
### 设计原则
- 只允许 SVG 的**微动 / 线条 / 点**之间的**优雅细微动化**。
- 禁止花哨特效:脉冲波纹、光标闪烁、发光、强烈缩放、大幅度弹跳等。
- 新增工作状态时,应保持通用切换容器,避免为每个 SVG 单独适配位置。
- 内部图标线条应比外框稍细,保持视觉层次感。
## 关键调整历史
- 外框从 pointy-top 改为 flat-top横线在底部
- 边角从锐利直线改为 Q 贝塞尔圆角。
- 状态含义反转:空闲 = 静止 + 眼睛 + 追踪;工作 = 旋转 + `>`
- 眼睛长度缩短,位置上移至 `y=84`
- 鼠标追踪范围水平/垂直均为 ±10px。
- 2026-07-01`x2` 长度变化增加与 `transform` 同节奏的 JS 插值动画,解决工作/休息切换时长度跳变问题。

View File

@ -0,0 +1,30 @@
---
name: app_initialization_flow
description: 当需要适配桌面 App 初始化流程或理解项目首次启动配置时,应该索引本记忆
---
## 项目初始化流程(首次启动 / 桌面 App 适配必读)
### 关键文件
- `_bootstrap.sh` — 共享引导(定位项目根、准备 Python venv + Node 依赖)
- `setup.sh` — 首次初始化入口:调 `_bootstrap.sh` 后运行 `python -m scripts.setup`
- `scripts/setup.py`**交互式配置向导**终端5 步生成 `.env` + `custom_models.json`
### setup.py 向导步骤
1. **运行模式**`host`(单机本地沙箱)/ `web`(多用户 Docker决定 `TERMINAL_SANDBOX_MODE`
2. **Web 监听** — 端口 (`WEB_SERVER_PORT`) + 地址 (`WEB_SERVER_HOST`)host 模式默认 127.0.0.1
3. **数据目录**`~/.astrion/astrion/<mode>/`,可自定义(设 `ASTRION_DATA_ROOT`
4. **管理员账户**`AGENT_ADMIN_USERNAME` + `AGENT_ADMIN_PASSWORD_HASH`werkzeug hash
5. **模型配置** — 写入部署级 `custom_models.json`~/.astrion/astrion/config/model_name / url / apikey / model_id / thinking 支持
6. **自动生成**`WEB_SECRET_KEY` + `API_TOKEN_SECRET`secrets.token_hex(32)
### 设计要点
- 向导**刻意不 import config**,以免在 `.env` 写之前过早锁定路径
- 以 `.env.example` 为模板,仅替换被接管键,其余原样保留(含注释)
- `.env` 写完后 chmod 600
### 桌面 App 适配要点
- 桌面 App 应固定 `TERMINAL_SANDBOX_MODE=host`
- 端口应自动找可用端口
- 模型配置可在 Web UI 中后续修改,但首次启动至少需要一个模型
- `_deploy_config_dir()` 推导逻辑必须与 `config/paths.py` 保持一致

View File

@ -0,0 +1,109 @@
---
name: background_notification_pool
description: 当需要讨论或修复后台子智能体/后台 run_command 完成通知机制时,应该索引本记忆
---
# 后台子智能体 / 后台 run_command 通知机制问题(待修复)
## 问题描述
后台子智能体和后台 `run_command` 在“主智能体停止输出后完成”的场景下,通知机制存在串行化问题:
- 若同时有多个后台任务在运行,它们不会随完成逐个通知。
- 而是在所有后台任务全部完成后,按时间顺序一条一条地发送 user 消息。
- 且每发送一条 user 消息就要触发一次“工作 → 停止 → 再工作”的循环,导致通知被拆成多次停止输出。
## 当前机制
运行期间inline和停止输出后polling是两条链路
### 1. 运行期间inline当前正常
- 位置:`server/chat_flow_tool_loop.py` 中 `execute_tool_calls` 末尾。
- 调用:
- `process_sub_agent_updates(..., inline=True)`
- `process_background_command_updates(..., inline=True)`
- 行为:每次工具循环结束时,把**当前所有已完成且未通知**的任务一次性插入 `messages`,不触发新任务。
- 结论:运行期间的批量通知已经是“池化”的,暂无问题。
### 2. 停止输出后polling问题所在
- 位置:`server/chat_flow_task_main.py` 中 `handle_task_with_sender` 结尾。
- 调用:
- `poll_sub_agent_completion(...)`
- `poll_background_command_completion(...)`
- 行为:
- 两个轮询器各自由 `socketio.start_background_task(...)` 启动。
- 每轮循环只处理**一个**完成的通知。
- 处理完一个通知后,创建一个新的 chat task然后 `return`
- 下一个通知必须等待这个新 chat task 跑完,并再次走到 `handle_task_with_sender` 结尾重新 spawn 轮询器时才会发出。
## 根因
后台任务管理器本身已经扮演了“后台池 + 通知池”的角色(任务完成但 `notified=False` 就是待通知状态)。
但轮询器是 **one-shot** 的:每次只消费一条通知就退出,导致通知被串行化到多次“工作 → 停止 → 再工作”循环中。
## 讨论中的设计方案
统一为“通知池轮询器”:
1. 合并 `poll_sub_agent_completion``poll_background_command_completion` 为一个统一的 `poll_completion_notifications`
2. 每次轮询时,同时从以下两处取出**所有**待通知项:
- `sub_agent_manager.poll_updates()`
- `background_command_manager.poll_updates(conversation_id=...)`
3. 把所有待通知项作为 user 消息插入对话历史(倾向保留为多条消息,而非合并成一条)。
4. 只创建 **一个**后续 chat task 来触发继续工作。
5. 轮询器返回,由这个新任务在结束时继续下一轮轮询。
### 期望行为示例
- 3 个后台子智能体运行中,主智能体停止输出。
- 第 1 个完成 → 通知池有 1 条 → 插入 1 条 user 消息 → 触发 1 个新任务。
- 新任务处理期间,第 2、3 个完成 → 进入通知池。
- 新任务停止输出 → 轮询器发现通知池还有 2 条 → 一次性插入 2 条 user 消息 → 再触发 1 个新任务。
- 不再有后台任务时,轮询器直接退出。
## 涉及文件
| 文件 | 角色 |
|---|---|
| `server/chat_flow_task_support.py` | 新增统一轮询器 `poll_completion_notifications`;可废弃旧的两个轮询函数。 |
| `server/chat_flow_task_main.py` | 在 `handle_task_with_sender` 结尾,把分别 spawn 两个轮询器的逻辑替换为 spawn 一个统一轮询器。 |
| `modules/sub_agent/manager.py` | 提供 `poll_updates()`,基于 `notified` 标志表示待通知状态。 |
| `modules/background_command_manager.py` | 提供 `poll_updates()``has_pending_for_conversation()`。 |
## 待决策点
- 是否坚持把通知拆成多条 user 消息插入历史(推荐),还是合并为一条。
- 统一轮询器是否做成“持久单例”还是保持 one-shot batch当前讨论倾向 one-shot batch由新任务继续轮询
## 状态
已实施2026-06-24方案 A + one-shot batch
### 落地实现
- `server/chat_flow_task_support.py` 未改;新增逻辑集中在 `server/chat_flow_task_main.py`
- 新增统一轮询器 `poll_completion_notifications`,替换并删除旧的 `poll_sub_agent_completion` / `poll_background_command_completion`
- 新增 `_collect_pending_completion_notices`:每轮一次性从子智能体 + 后台命令两路取出所有待通知项(取出即就地标记 `notified` / `_announced_sub_agent_tasks`),按 `updated_at` 跨两路排序。
- 新增 `_has_pending_completion_work`:判断是否还有运行中/待通知的后台工作,决定轮询是否继续。
- 新增 `_build_sub_agent_notice_text`:抽出子智能体通知文本构建。
- `handle_task_with_sender` 结尾:保留 `sub_agent_waiting` 事件探测,但把「分别 spawn 两个轮询器」改为只 spawn **一个** `run_completion_poll`。**这也顺带消除了两个轮询器同时 `create_chat_task``create_chat_task` 单工作区互斥(`models.py` RuntimeError的隐患。**
### 方案 A 的「多条 + 单 task」如何落地
`create_chat_task` 只收单条 message`handle_task_with_sender` 开头无条件 `add_conversation`。因此:
- 一批取出 N 条:前 N-1 条为「前置通知」,最后 1 条作为后续 chat task 的触发消息。
- `_dispatch_completion_user_notice` 新增 `preceding_notices` 参数:
- 通过 `_persist_and_echo_preceding_notice` 把前 N-1 条**写入对话历史**`add_conversation`,落盘)+ **socketio 回显**(在线客户端即时可见),`starts_work=False`(渲染为完成态气泡,不起独立计时器)。
- 把 `preceding_user_notices` 塞进 `session_data`,传给后续任务。
- `server/tasks/models.py``_run_chat_task`:在补发触发 user_message 事件**之前**,先按顺序把 `preceding_user_notices` 逐条 `_append_event("user_message", ...)` 注入任务事件流——保证 REST 轮询客户端按时间顺序看到所有完成通知。
- 触发消息(最后 1 条)走原有 `auto_user_message_event` 链路,正常 `starts_work=True` 启动一轮工作。
### 验证
- `python3 -m py_compile server/chat_flow_task_main.py server/tasks/models.py` 通过(注意本机 pycache 目录无写权限,需 `PYTHONPYCACHEPREFIX=$TMPDIR/pycache`)。
- `python3 -m unittest test.test_server_refactor_smoke` 6 用例通过。
- 前端未改:复用既有 `user_message` / `sub_agent_notice` 渲染链路(`messaging.ts` handleUserMessage + socketio `user_message`dedup 与单通知场景一致。

View File

@ -0,0 +1,49 @@
---
name: chat_block_scroll_anchor
description: 当需要优化聊天区域块展开/折叠滚动行为,或排查向上滚动后瞬间跳回问题时,应该索引本记忆
---
# 聊天区域块展开/折叠滚动行为优化记录
## 背景
聊天区域默认使用 `vue-stick-to-bottom` 保持底部锁定。块thinking/tool展开/折叠时,`stick-to-bottom` 的弹簧追底动画和 CSS 高度过渡不同步,会产生「向下展开一点、向上滚动一点」的顿挫感。
## 已尝试方案
### 1. 块展开锚定useBlockExpansionAnchor
- 在 `static/src/composables/useBlockExpansionAnchor.ts` 中实现
- 块展开/折叠的 CSS 过渡期间(约 260300ms`requestAnimationFrame` 持续覆盖 `scrollTop`
- 目标:让被操作块的底边或顶边保持在原来视口位置
- 方向判断:
- 用**底边**判断比顶边更准确。高块即使顶边位于上半,底边仍可能在下半;用顶边判断会把高块误判为 `down` 模式
- `up` 模式:底边不动,头部向上展开
- `down` 模式:顶边不动,内容向下展开
- 方向在单次展开-收起周期内记忆(`preferredModes`),保证收起是展开的倒放;收起动画结束后清除记录
### 2. 运行期间策略
- 运行中的 thinking/tool 块(带 `.processing`/`.running`/`.thinking-animation`)保持旧逻辑,由 `stick-to-bottom` 追底,避免被输入栏遮挡
- 非运行中的块(包括运行期间的历史块)走锚定逻辑
- 已实现 commit`f43b5ea7 fix(chat): 运行期间恢复旧滚动逻辑,堆叠块更多按钮也接入锚定`
### 3. 堆叠块「更多」按钮
- `StackedBlocks.vue` 在 toggleMore 时 emit `more-toggle``ChatArea.vue` 监听后对 more-block 元素启动锚定
- 注意:事件 payload 里的展开状态应使用 `payload.expanded`,避免 `ReferenceError`
## 未解决的向上滚动跳回问题
### 现象
- 在块较多的对话中,**向上滚动**后页面会瞬间跳回滚动前的位置
- 向下滚动不会出现
- 禁用 `anchorBlockElement` 调用、禁用 wheel-up 时的 `stopScroll()` 后问题依然存在
### 调试结论
- 不是 `anchorBlockElement` 直接导致
- 不是 `stopScroll()` 直接导致
- `heightDelta` 可能为负(内容高度减小),但 large-growth 检测未触发
- `escapedFromLock` 已为 `true``stick-state-change` 未出现异常变化
- 原因未最终定位,可能与 `vue-stick-to-bottom` 内部状态、浏览器原生滚动行为或内容高度变化后的布局抖动有关
## 当前代码状态
- 当前 HEAD`f43b5ea7 fix(chat): 运行期间恢复旧滚动逻辑,堆叠块更多按钮也接入锚定`
- 工作区干净所有调试和临时修改已撤回stash 已清空
- 后续若继续优化,建议从 `f43b5ea7` 开始,并优先定位向上滚动跳回的根本原因

View File

@ -0,0 +1,148 @@
---
name: cloud_server_disk_usage
description: 当需要了解云服务器磁盘使用现状、规划Docker镜像构建空间、或决定清理哪些文件释放空间时应该索引本记忆
---
# 云服务器磁盘使用现状
> 记录时间2026-06-25
> 服务器59.110.19.30Ubuntu 24.04.2 LTS, x86_64
## 总体情况
```text
Filesystem Size Used Avail Use%
/dev/vda3 49G 43G 4.0G 92%
```
- 总磁盘:约 49 GB
- 已用:约 43 GB92%
- 可用:约 4 GB
**结论:磁盘非常紧张,不足以直接本地构建方案 B 的 2.9GB Docker 镜像。**
## 占用大户(按大小排序)
| 路径 | 大小 | 说明 |
|------|------|------|
| `/var/lib/docker` | **18 GB** | Docker 镜像、容器、volume |
| `/var/log/journal` | **4.1 GB** | systemd journal 日志 |
| `/opt/agent` | **5.0 GB** | agents 项目源码、运行时、备份、镜像 |
| `/opt/openwebui` | **3.6 GB** | OpenWebUI 部署目录 |
| `/var/lib/filebrowser` | **3.0 GB** | filebrowser 数据 |
| `/swapfile` | **2.1 GB** | swap 文件 |
| `/home/git/data` | **856 MB** | gitea 数据 |
| `/home/admin/go` | **770 MB** | Go 相关文件/缓存 |
| `/var/www` | **1.4 GB** | nginx web 目录 |
| `/var/lib/clamav` | **1.2 GB** | 病毒库 |
| `/usr` | **4.2 GB** | 系统软件 |
## Docker 详细占用
```text
Images: 4 5.284 GB
- ghcr.io/open-webui/open-webui <none> 4.32 GB
- my-agent-shell amd64 913 MB
- my-agent-shell latest 913 MB与 amd64 同 image id
- python 3.11-slim 124 MB
- ghcr.io/corentinth/it-tools latest 56.2 MB
Volumes: 1 7.966 GB
- open-webui: 7.966 GB
Containers: 3
- agent-term-jojo-default my-agent-shell:latest Up
- openwebui-new open-webui image Up (healthy)
- it-tools it-tools image Exited (7 months ago)
Build Cache: 10 / 2.182 kB可忽略
```
## `/opt/agent` 详细占用
| 路径 | 大小 | 说明 |
|------|------|------|
| `/opt/agent/backup` | **1.5 GB** | 6 个压缩备份包runtime_backup_* ×3, users_data_backup_* ×3 |
| `/opt/agent/dockerimage` | **894 MB** | `my-agent-shell_amd64.tar` 旧镜像 tar |
| `/opt/agent/agents` | **883 MB** | 当前源码目录 |
| `/opt/agent/agents_old_20260614` | **540 MB** | 旧版本源码备份 |
| `/opt/agent/runtime` | **520 MB** | 运行时数据(对话、用户工作区等) |
| `/opt/agent/voice_models` | **230 MB** | 语音模型文件 |
| `/opt/agent/agents_old_20260612_012026` | **190 MB** | 旧版本源码备份 |
| `/opt/agent/agents_old_20260614_190527` | **190 MB** | 旧版本源码备份 |
| `/opt/agent/venv` | **96 MB** | Python 虚拟环境 |
| `/opt/agent/agents.zip` | **42 MB** | 源码 zip 包 |
## 建议清理清单
### 低风险(约可释放 6.5 GB
| 操作 | 可释放 | 命令/路径 |
|------|--------|-----------|
| 清理 systemd journal 旧日志 | ~4 GB | `journalctl --vacuum-time=7d``--vacuum-size=500M` |
| 删除 `/opt/agent/backup` 旧备份,只留最新各 1 个 | ~1 GB | 手动删除旧的 `runtime_backup_*``users_data_backup_*` |
| 删除 `/opt/agent/dockerimage/my-agent-shell_amd64.tar` | 894 MB | `rm /opt/agent/dockerimage/my-agent-shell_amd64.tar` |
| 删除 `/opt/agent/agents_old_*` 旧版本目录 | ~920 MB | `rm -rf /opt/agent/agents_old_*` |
| 删除 `/opt/agent/agents.zip` | 42 MB | `rm /opt/agent/agents.zip` |
| 删除已退出容器 `it-tools` | ~514 kB | `docker rm it-tools` |
### 中风险(需先确认是否仍在使用)
| 操作 | 可释放 | 说明 |
|------|--------|------|
| 清理 `/var/lib/filebrowser` | 3 GB | 需确认 filebrowser 中是否还有需要保留的文件 |
| 清理 `/home/admin/go` 缓存 | ~770 MB | `go clean -cache` |
| 删除 `/var/lib/clamav` | 1.2 GB | 如果系统不使用 clamav 扫描 |
### 不建议动
- `/opt/agent/runtime`:用户运行时数据(对话、项目文件等)
- `/opt/agent/agents`:当前项目源码
- `/opt/openwebui`:如果 OpenWebUI 服务仍在使用
- `/home/git/data`gitea 数据
- Docker volume `open-webui`OpenWebUI 用户数据
## 关键命令(下次快速查看)
```bash
# 总体磁盘
ssh 59.110.19.30
df -h
# 根目录一级占用
sudo du -sh /* 2>/dev/null | sort -h | tail -20
# /var 明细
sudo du -sh /var/lib/* /var/log/* 2>/dev/null | sort -h | tail -20
# /opt/agent 明细
sudo du -sh /opt/agent/* 2>/dev/null | sort -h | tail -20
# Docker 占用
docker system df
docker images --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}'
docker volume ls
# 清理 journal
sudo journalctl --vacuum-time=7d
# 清理 Docker
# docker image prune -a # 谨慎:会删除所有未使用镜像
# docker volume prune # 谨慎:会删除未使用 volume
```
## 与本次 Docker 改造的关系
- 当前 `my-agent-shell` 镜像913 MB
- 方案 B 目标镜像:约 2.9 GB本地 arm64 实测)
- 构建过程需下载 586 MB apt 包,解压后约 2.2 GB
- 当前可用空间仅 4 GB**不足以安全构建方案 B**
- 建议先执行低风险清理释放 6-8 GB再考虑构建
- 云端构建建议分阶段:先只加 LibreOffice + 字体 + Node + Python 必要包(约 1.5 GB 镜像),验证稳定后再决定是否加 chromium/ffmpeg
## 注意事项
- 服务器架构为 x86_64本地为 arm64**禁止将本地构建的镜像上传到云端**
- 云端网络环境较差,大文件下载可能超时
- 云端内存 2 GB构建/运行大镜像需警惕 OOM
- 清理前务必确认文件是否仍在使用,尤其是 `/var/lib/filebrowser``/opt/openwebui`

View File

@ -0,0 +1,75 @@
---
name: cloud_server_ssh_and_directories
description: 当需要SSH登录云服务器排查部署问题、查看日志、或操作服务器文件时应该索引本记忆
---
# 云服务器 SSH 与目录指南
## SSH 登录
```bash
ssh 59.110.19.30
# 使用与本地相同的 id_ed25519 密钥
```
## 关键目录
| 用途 | 路径 |
|------|------|
| **源码根目录** | `/opt/agent/agents/` |
| **运行时数据根** | `/opt/agent/runtime/``ASTRION_DATA_ROOT` |
| **部署级配置** | `/opt/agent/runtime/config/` |
| **子智能体模型配置** | `/opt/agent/runtime/config/sub_agent_models.json` |
| **子智能体代码** | `/opt/agent/agents/modules/sub_agent/`Python 主进程内协程) |
| **虚拟环境** | `/opt/agent/venv/` |
## 用户数据
```
/opt/agent/runtime/web/users/<用户名>/projects/<项目名>/
├── project/ # 用户工作区文件
└── data/
└── conversations/
└── default/
└── conv_xxx.json # 对话记录
```
## 子智能体相关
| 用途 | 路径 |
|------|------|
| **子智能体任务目录** | `/opt/agent/runtime/web/data/sub_agent_tasks/<task_id>/` |
| **任务文件** | `task.txt`、`system_prompt.txt` |
| **子智能体交付目录** | 在用户 project 下的 `sub_agent_results/` |
## 服务管理
| 操作 | 命令/路径 |
|------|----------|
| **启动服务** | `bash /opt/agent/start_webapp_new.sh`(端口 8091 |
| **更新服务** | `bash /opt/agent/refresh_agents.sh`git pull + 重启 + nginx reload |
| **数据迁移脚本** | `python3 /opt/agent/agents/scripts/migrate_runtime_data.py`(执行前务必 `--dry-run` |
| **Nginx 配置** | `/etc/nginx/sites-enabled/agent.cyjai.com` |
| **本地部署脚本** | `deploy_agents.sh`git push → npm build → scp dist/ → 触发远程 refresh |
## 日志
| 用途 | 路径 |
|------|------|
| **Web 日志** | `/opt/agent/runtime/web/logs/` |
| **主机调试日志** | `/opt/agent/runtime/web/logs/host_workspace_debug.log` |
## 常见排查流程
1. SSH 登录服务器
2. 查看对话 JSON`cat /opt/agent/runtime/web/users/<user>/projects/<project>/data/conversations/default/conv_xxx.json`
3. 查看子智能体任务:`ls /opt/agent/runtime/web/data/sub_agent_tasks/`
4. 查看日志:`tail -100 /opt/agent/runtime/web/logs/host_workspace_debug.log`
5. 查看子智能体任务文件:`ls /opt/agent/runtime/web/data/sub_agent_tasks/<task_id>/`
## 已知坑
- **前端构建不能服务器执行**2G 内存会 OOM必须本地 build 后 scp 上传 `static/dist/`
- **venv 符号链接问题**:从 macOS 复制来的 venv启动脚本 `fix_venv()` 会自动检测重建
- **子智能体现为 Python 协程**`easyagent/` 目录已废弃,不再作为子智能体入口
- **数据迁移后路径变更**:运行态数据根的环境变量由 `AGENTS_DATA_ROOT` 改为 `ASTRION_DATA_ROOT`,工作区内部目录由 `.agents/` 改为 `.astrion/`

View File

@ -0,0 +1,13 @@
---
name: config_system_and_deployment
description: 当修改配置加载逻辑、服务器部署流程、skill 归档路径或理解 settings.json 结构时,应该索引本记忆
---
## Skill 归档路径约定2026-07-09 更新)
- **内置 skill 库**`AGENT_SKILLS_DIR`(源码树 `agentskills/`),只放通用、自带、适用于项目的 skill。
- **用户自定义 skill 归档目录**`CUSTOM_SKILLS_DIR = <RUNTIME_ROOT>/<mode>/agentskills`
- host 模式:`~/.astrion/astrion/host/agentskills/`(全局,不按用户拆分)
- web/docker 模式:`~/.astrion/astrion/web/agentskills/`(可与 per-user `personal/agentskills` 并存)
- **create_skill 行为**:统一通过 `infer_private_skills_dir(data_dir)` 解析目标目录host 模式不再特殊处理为源码树 `agentskills/`
- **实验/测试 skill**:如 `test` 应从源码树 `agentskills/` 移出,归档到 `CUSTOM_SKILLS_DIR`,不作为内置 skill 发布。

View File

@ -0,0 +1,210 @@
---
name: docker_toolbox_enhancement_plan
description: 当需要继续推进 my-agent-shell 容器镜像增强改造、查看本地实验结果、或在云端构建新版镜像时,应该索引本记忆
---
# my-agent-shell 容器镜像增强改造计划与本地实验进度
> 记录时间2026-06-25
> 相关记忆:`cloud_server_disk_usage`(服务器磁盘现状)
## 背景
当前运行在云端的 `my-agent-shell` 容器(镜像 `my-agent-shell:latest`,基于 `python:3.11-slim`)依赖不足:
- docx/pptx skill 缺少 `defusedxml`
- pptx skill 推荐的 `markitdown` 未安装
- 完全缺少 LibreOffice / soffice
- 完全缺少 pandoc、pdftoppmpoppler-utils
- 完全缺少 Node.js / npm
- 完全缺少中文字体(`fc-list` 为 0
导致用户常见的 Office 转换、图片处理、OCR、网页截图等需求无法跑通。
## 改造方案
### 方案 B已选定
在最小方案基础上扩展常见业务能力:
**系统 apt 包:**
- Officelibreoffice、pandoc、poppler-utils
- 图片/视频imagemagick、ffmpeg
- OCRtesseract-ocr、tesseract-ocr-chi-sim、tesseract-ocr-chi-tra
- 网页chromium
- 字体fonts-noto-cjk、fonts-noto-color-emoji、fonts-liberation
- 开发工具jq、ripgrep、fd-find、tree
**Python pip 包(加入 `docker/toolbox-requirements.txt`**
- defusedxml
- markitdown[docx]
- pytesseract
- pdf2image
**Node 全局包:**
- docx
- pptxgenjs
**特殊处理:**
- 用 NodeSource 安装 Node 20 LTS避免 Debian 源版本过老
- 修改 ImageMagick policy.xml 允许读写 PDF
- 设置 `NODE_PATH=/usr/lib/node_modules`
## 已修改文件
### 1. `docker/terminal.Dockerfile`
主要变更:
- apt 安装段加入 libreoffice、pandoc、poppler-utils、imagemagick、ffmpeg、tesseract、chromium、中文字体、开发工具
- 增加 ImageMagick PDF 策略调整 RUN 层
- 增加 NodeSource Node 20 安装
- 增加 `npm install -g docx pptxgenjs`
- 末尾添加 `ENV NODE_PATH="/usr/lib/node_modules"`
### 2. `docker/toolbox-requirements.txt`
新增:
- `defusedxml`
- `markitdown[docx]`
- `pytesseract`
- `pdf2image`
## 本地实验进度
### 实验环境
- 本地 macOS 15.6.1, arm64
- Docker Desktop
- 构建命令:
```bash
cd /Users/jojo/Desktop/agents/正在修复中/agents
docker build -f docker/terminal.Dockerfile -t my-agent-shell:local .
```
### 实验结果
| 指标 | 结果 |
|------|------|
| 构建成功 | ✅ 是 |
| 新镜像大小 | **2.9 GB**(原镜像 913 MB |
| 镜像增加 | 约 **2 GB** |
| 空闲内存 | ~10 MB |
| 单任务峰值内存 | ~40 MB |
| 并发 5×soffice + 1×chromium 峰值内存 | **~237 MB** |
### 功能验证(全部通过)
| 测试项 | 结果 |
|--------|------|
| `soffice --headless --convert-to pdf` docx→pdf | ✅ |
| `pandoc docx -o md` | ✅ |
| `pdftoppm` pdf→png | ✅ |
| `markitdown` 读取 docx/pptx | ✅ |
| `python-docx` / `python-pptx` | ✅ |
| Node `docx-js` 生成 docx | ✅ |
| Node `pptxgenjs` 生成 pptx | ✅ |
| ImageMagick 图片裁剪 | ✅ |
| matplotlib 生成中文字体表格图片 | ✅ |
| tesseract OCR 中英文 | ✅(可运行,中文识别准确度一般) |
| chromium 网页截图 | ✅ |
| `pdf2image` PDF 转图片 | ✅ |
| docx/pptx skill 脚本 import | ✅ |
### 遇到的问题与解决
1. **markitdown 读 docx 报 MissingDependencyException**
- 原因:默认 `markitdown` 不包含 docx converter 的 `mammoth` 依赖
- 解决:改成 `markitdown[docx]`
2. **Node 全局安装的 `docx`/`pptxgenjs` require 不到**
- 原因node 默认不搜索 `/usr/lib/node_modules`
- 解决Dockerfile 添加 `ENV NODE_PATH="/usr/lib/node_modules"`
3. **chromium 运行时有 dbus 报错**
- 不影响截图结果,属于 headless 环境下的常见警告
4. **ImageMagick 默认禁止 PDF 处理**
- 解决:修改 `/etc/ImageMagick-6/policy.xml` 中 PDF 的 rights 为 `read|write`
5. **onnxruntime 启动警告**
- 警告:`Unknown CPU vendor. cpuinfo_vendor value: 0`
- 不影响功能arm64 容器中的常见提示
## 尚未完成的工作
1. **云端构建验证**
- 当前只在本地 arm64 构建验证
- 需要在云端 x86_64 上实际构建
- 云端磁盘紧张(只剩 4GB需先清理或分阶段构建
2. **精简镜像体积(可选)**
- 2.9GB 较大,可考虑去掉 chromium/ffmpeg 做成"最小方案 B"(约 1.5GB
- 或保留完整方案 B但需确保云端有足够空间
3. **react-icons / react / react-dom / sharp**
- pptxgenjs skill 文档中提到图标生成需要这几个包
- 当前未预装,需要时可在运行时安装或后续加入镜像
- `sharp` 涉及原生编译,构建时间和失败风险较高
4. **更详细的内存压力测试**
- 当前只做了简单并发测试
- 未测试大文件转换、长时间运行场景
5. **ImageMagick 安全策略复核**
- 当前为支持 PDF 放宽了限制,需确认是否符合安全要求
## 下一步建议
### 推荐路径:分阶段上云端
1. **阶段一:精简必要包**
- 去掉 chromium、ffmpeg、imagemagick、tesseract
- 保留libreoffice、pandoc、poppler-utils、node、npm、docx、pptxgenjs、字体、defusedxml、markitdown[docx]
- 目标镜像约 1.3-1.5GB
- 先验证 Office skill 能跑通
2. **阶段二:按需加回媒体能力**
- 根据实际使用频率,决定是否加回 imagemagick、ffmpeg、chromium、tesseract
3. **阶段三:优化构建缓存**
- 考虑把 apt 层拆成多个 RUN便于失败后重试
- 云端构建时加 `--progress=plain` 便于排查
## 关键命令
```bash
# 本地构建
cd /Users/jojo/Desktop/agents/正在修复中/agents
docker build -f docker/terminal.Dockerfile -t my-agent-shell:local .
# 本地测试容器
docker run -d --name agent-test-local my-agent-shell:local tail -f /dev/null
# 验证基础依赖
docker exec agent-test-local bash -c "which soffice pandoc pdftoppm node npm convert ffmpeg chromium tesseract jq rg fdfind tree"
# 验证 Python 包
docker exec agent-test-local bash -c "/opt/agent-venv/bin/python -c 'import defusedxml, markitdown, pytesseract, pdf2image'"
# 验证 Node 包
docker exec agent-test-local bash -c "node -e 'require(\"docx\"); require(\"pptxgenjs\"); console.log(\"OK\")'"
# 查看镜像大小
docker images my-agent-shell:local
# 监控运行时内存
docker stats agent-test-local --no-stream
```
## 重要约束
- **本地 arm64云端 x86_64禁止把本地构建的镜像上传到云端**
- 云端磁盘只剩 4GB必须清理或分阶段构建
- 云端内存 2GB构建/运行需警惕 OOM
- 云端网络差,大文件下载可能超时
## 相关文件
- `docker/terminal.Dockerfile`
- `docker/toolbox-requirements.txt`
- 项目记忆:`cloud_server_disk_usage`(服务器磁盘现状)

View File

@ -17,7 +17,7 @@ description: 当需要把前端日志输出到后端文件(如调试目标模
- 端点:`POST /api/client_debug_log`
- 写入函数:`log_goal_mode_debug_entry(data: Dict[str, Any])`
- 日志文件:`{LOGS_DIR}/goal_mode_debug.log`
- 宿主机模式示例:`/Users/jojo/.agents/agents/host/logs/goal_mode_debug.log`
- 宿主机模式示例:`/Users/jojo/.astrion/astrion/host/logs/goal_mode_debug.log`
### 前端函数

View File

@ -0,0 +1,41 @@
---
name: ocr_client_initialization
description: 当 OCRClient/OpenAI 初始化报错、WebTerminal 创建失败、或升级 openai 包时,应该索引本记忆
---
# OCRClient 初始化与 OpenAI 包兼容性
## 问题
`modules/ocr_client.py``__init__` 中直接创建 `OpenAI(api_key=OCR_API_KEY)`
- `openai` 包较新版本(>= 2.40)在 `api_key` 为空时会抛出 `openai.OpenAIError: Missing credentials`
- 服务器 settings.json 通常未配置 `OCR_API_KEY`
- 这会导致 `WebTerminal`/`MainTerminal` 初始化失败,所有依赖 terminal 的 API 都返回 500
## 修复
`OCRClient.__init__` 中,仅在 `OCR_API_KEY` 存在时才创建 `OpenAI` 客户端:
```python
self.client = None
if OCR_API_KEY:
self.client = OpenAI(
api_key=OCR_API_KEY,
base_url=base_url or None,
http_client=self.http_client,
)
```
`vlm_analyze` 中同时检查 `self.client`
```python
if not self.client or not OCR_API_KEY or not OCR_API_BASE_URL or not self.model:
return {"success": False, "error": "VLM 配置缺失,请设置 OCR_API_BASE_URL / OCR_API_KEY / OCR_MODEL_ID", "warnings": warnings}
```
## 教训
- 升级依赖包后要检查破坏性变更
- 可选功能OCR/VLM的客户端初始化不应阻塞主终端启动
- 服务器环境缺少某个 API key 时,应优雅降级而不是直接崩溃

View File

@ -0,0 +1,100 @@
---
name: opencode_key_replacement_script
description: 当需要批量替换 ~/.astrion/astrion、~/.astrion/astrion-clone 和服务器 /opt/agent/runtime 中的 OpenCode API key 时,应该索引本记忆
---
---
name: opencode_key_replacement_script
description: 当需要批量替换 ~/.astrion/astrion、~/.astrion/astrion-clone 和服务器 /opt/agent/runtime 中的 OpenCode API key 时,应该索引本记忆
---
# OpenCode API key 批量替换脚本
## 脚本位置
项目根目录下的 `replace_opencode_keys.py`
## 作用
一次性批量替换以下目录中所有 OpenCode 相关的 API key
- 本地:`/Users/jojo/.astrion/astrion`
- 本地:`/Users/jojo/.astrion/astrion-clone`
- 服务器:`/opt/agent/runtime/`(或服务器上 `ASTRION_DATA_ROOT` 指向的目录)
## 扫描范围
仅扫描配置文件,自动跳过运行时数据:
- `settings.json`
- `config/*.json`
- 跳过 `data/`、`logs/`、对话历史等目录
- 跳过已有的 `.bak_` / `.bak` 备份文件
## 替换规则
脚本会查找已知的旧 OpenCode key 值(被多个 OpenCode Go 相关环境变量共用的同一串 key并将其替换为新的 OpenCode key。
实际会改到的键名通常包括:
- `settings.json``env_vars` 下的:
- `API_KEY_OPENCODE`
- `AGENT_API_KEY`
- `AGENT_THINKING_API_KEY`
- `AGENT_TITLE_API_KEY`
- 指向 `opencode.ai``API_KEY_KIMI`、`API_KEY_DEEPSEEK`、`API_KEY_QWEN`、`API_KEY_MINIMAX` 等
- `config/sub_agent_models.json``url``https://opencode.ai/zen/go/v1` 的模型条目的 `apikey`
`config/custom_models.json` 中一般使用 `${API_KEY_OPENCODE}` 变量引用key 本身存在 `settings.json`,脚本不会直接修改它。
## 用法
```bash
# 只预览,不写入(循环轮换模式)
python3 replace_opencode_keys.py --dry-run
# 正式执行循环轮换默认key1→key2, key2→key3, key3→key1
python3 replace_opencode_keys.py
# 单次指定替换(覆盖默认循环模式)
python3 replace_opencode_keys.py --old-key <旧key> --new-key <新key>
```
## 服务器替换流程
1. 确保脚本已上传至 `/opt/agent/agents/replace_opencode_keys.py`
2. 在服务器上修改脚本,把 `Path("/opt/agent/runtime")` 加入 `TARGET_DIRS`
3. 先执行 `--dry-run` 预览影响范围
4. 去掉 `--dry-run` 正式执行
5. 执行 `bash /opt/agent/refresh_agents.sh` 重启 webapp 服务使配置生效
6. 删除生成的 `.bak_时间戳` 备份文件
## 服务器执行方式建议
- **推荐**:通过 `terminal_session` 打开一个 SSH 会话,在会话里直接运行 `python3 replace_opencode_keys.py ...`
- **次选**:使用服务器虚拟环境的完整路径,例如 `/opt/agent/venv/bin/python3 replace_opencode_keys.py ...`
- **注意**:在旧版本或未重启前,通过 `run_command` 直接执行 `ssh host "python3 ..."` 时,`run_command` 可能把命令中的 `python3` 重写为本地 macOS 的 Python 绝对路径,导致远程服务器找不到解释器。该问题已在 `modules/terminal_ops/run.py` 中修复:当命令通过 `ssh` 在远程执行时,跳过 `python3`/`pip` 重写。
## 注意事项
- 执行前会自动在同级目录生成 `.bak_时间戳` 备份。
- 如果在沙箱/受限执行环境下运行,原目录不可写时脚本会把备份和修改后的文件写到项目工作区的 `opencode_key_replacement_backup/` 目录下,需要手动复制覆盖。
- 建议执行后删除生成的 `.bak_时间戳` 备份文件。
- 服务器上配置文件修改后,需要重启 webapp 服务才能生效。
## 历史记录
- 2026-06-19使用脚本将本地两个目录的配置从主 key 替换为备用 key并删除备份。
- 2026-06-19将服务器 `/opt/agent/runtime/` 下的 `settings.json``config/sub_agent_models.json` 也从主 key 替换为备用 key并删除备份。
- 2026-06-24将服务器 `/opt/agent/runtime/` 下的 `settings.json`9 处)和 `config/sub_agent_models.json`1 处)从备用 key 替换回主 key随后执行 `bash /opt/agent/refresh_agents.sh` 重启 webapp 服务,并删除备份。期间发现 `run_command` 执行 `ssh host "python3 ..."` 会错误重写 `python3` 为本地 macOS 路径,已修复 `modules/terminal_ops/run.py`
- 2026-06-25重构脚本为三 key 循环轮换模式key1/key2/key3去掉主/备用命名)。将本地 `~/.astrion/astrion``~/.astrion/astrion-clone` 的配置从 key2 替换为 key34 文件 20 处)。服务器尚未操作,当前仍为 key1。
- 2026-06-25将本地 `~/.astrion/astrion``~/.astrion/astrion-clone` 的配置从 key2 替换为 key34 文件 20 处),删除备份。服务器仍为 key1。
## 相关 key 记录
| 说明 | Key |
|---|---|
| key1 | `sk-zNU867TGGXNKxoM0H6Pg6Jq4PYUPUOPDgMlzrOl3SS6jECRMWK5nNi6YMSsHzoZ` |
| key2 | `sk-sgt4ERgERPx2axU18PSfmenHv9zNDD3y8M5yr0p4ryhcNSm04CZsCxDHftJ9AkFD` |
| key3 | `sk-Jhvi76vJdCEQzvEdl8cAS5MIwBxBS4iTrJYSru2zCAXVnDVQpiZIvrcn9hBwkdZ4` |
| legacy已停用等同 key1 轮换到 key2 | `sk-j0NdTvEDoqqkKCHEAFXXYneEsuXEiOXNCgLeZARJmfYUBf2Riym7KPFWq1amkB6z` |

View File

@ -0,0 +1,94 @@
---
name: pywebview_macos_packaging
description: 当打包 PyWebview macOS App、调试 "The string did not match" 错误、修改 _packaging/ 目录时,应该索引本记忆
---
# PyWebview macOS 打包项目记忆
## 目标
将 Vue 3 + Python Flask 项目打包为 macOS 桌面 AppPyWebview不使用 Electron/Tauri 或原生 macOS 对话框。
## 核心文件
| 文件 | 作用 |
|------|------|
| `_packaging/app.py` | PyWebview 主入口:检测 `.env` → 直接启动 / setup页面 |
| `_packaging/setup.html` | 首次设置页面4步工作区→模型→管理员→确认classic暖奶油主题 |
| `_packaging/app.spec` | PyInstaller 打包配置 |
| `_packaging/dist/AI-Agent-System.app` | 打包产物 |
| `_packaging/AI-Agent-System-v8.dmg` | 最后一个可用DMG527MB |
## 关键修复历史
### 1. DMG 禁止标志
- **原因**DMG 内同时存在 `AI-Agent-System/`onedir目录`AI-Agent-System.app`
- **修复**DMG 只放 `.app` + `Applications` 符号链接
- **hdiutil 创建需完全访问权限**:当前受限制,需切换到完全访问权限模式
### 2. OpenSSL 符号冲突
- **原因**`_ssl.cpython-311-darwin.so` 加载 psycopg2 自带的旧版 `libcrypto.3.dylib`
- **修复**:用 Homebrew OpenSSL 3.6.2 的 dylib 替换 bundle 中 `__dot__dylibs` 目录
### 3. `.env` 加载路径
- **修复**`config/__init__.py` 的 `_load_dotenv()` 改为 frozen 时读 `~/.astrion/astrion/host/.env`
### 4. engineio Invalid async_mode
- **原因**PyInstaller frozen 环境缺少 `engineio.async_drivers.threading`
- **修复**`app.spec` hiddenimports 添加 `'engineio.async_drivers.threading'`
### 5. PyWebview 6.x private_mode 🚨 **关键问题**
- **现象**Playwright 浏览器中正常0 errorsPyWebview App 中所有 API 返回 HTML 导致 "The string did not match the expected pattern"
- **根因**`webview.start()` 默认 `private_mode=True`WKWebView 隐私模式下 cookie 不工作session 丢失
- **修复**`webview.start(private_mode=False)`
### 6. App Transport Security
- **修复**`app.spec` Info.plist 添加 `NSAppTransportSecurity: { NSAllowsLocalNetworking: True }`
### 7. 环境变量污染
- **问题**:旧环境变量 `AGENTS_HOST_HOME=~/.agents/host-clone` 导致数据目录错误(现已被 `ASTRION_DATA_ROOT` 替代)
- **注意**`~/.astrion/astrion-clone` 是本对话副本数据,不要动
- **修复**`_start_flask` 导入前清除 `ASTRION_DATA_ROOT`/`DATA_DIR`/`LOGS_DIR` 等旧环境变量污染
### 8. JSON 错误处理器
- **修复**`_start_flask` 中注册全局 error handler确保任何异常都返回 JSON 而非 HTML
## 当前状态2026-06-12
### ✅ 已确认正常
- Flask 后端在浏览器中完全正常curl/Playwright 测试 0 errors
- 登录、对话列表、数据加载均正常
- API 返回纯 JSON
### ❌ 仍存在问题
- **PyWebview App 中仍然无数据**,前端报 "The string did not match the expected pattern"
- 已排除backend 崩溃、engineio 错误、private_mode、ATS、环境变量污染
- **问题定位**:在 PyWebview 的 WKWebView 内部fetch API 请求被某种机制拦截/修改,导致返回非 JSON 响应
### 🔍 下一步排查方向
1. 在 PyWebview 中启用远程调试(`webview.start(debug=True)`)查看 WKWebView console
2. 检查 PyWebview 6.x 的 `request_sent`/`response_received` 事件是否拦截了请求
3. 检查 WKWebView 对 `127.0.0.1` 的 same-origin 策略是否有特殊处理
4. 尝试用 `localhost` 替代 `127.0.0.1`
5. 考虑降级 PyWebview 到 5.x 或尝试其他打包方案Tauri/Electron
## 打包命令
```bash
# Python 必须是 Homebrew Python 3.11Xcode Python 3.9 会 SIGKILL
cd _packaging
pyinstaller --noconfirm --distpath ./dist --workpath ./build app.spec
# 安装到 /Applications
cp -R dist/AI-Agent-System.app /Applications/
codesign --force --deep -s - /Applications/AI-Agent-System.app
xattr -cr /Applications/AI-Agent-System.app
# 创建 DMG需完全访问权限
hdiutil create -srcfolder dist/AI-Agent-System.app -volname "AI_Agent_System" -ov -format UDZO AI-Agent-System.dmg
```
## 用户要求
- 禁止原生 macOS/浏览器组件
- setup 页面需与项目设计风格统一
- 只读一个 `.env`(数据存储目录 ~/.astrion/astrion/host/.env
- 等待时间不要设置太长
- `~/.astrion/astrion-clone` 是本对话副本数据,不要乱动
- `~/.astrion/astrion/host` 是正常运行时数据

View File

@ -0,0 +1,68 @@
---
name: server_deployment_venv
description: 当服务器部署时遇到 venv/pip 损坏、Python 路径错误,或需要更新部署脚本时,应该索引本记忆
---
# 服务器 venv 部署注意事项
## 背景
服务器 `/opt/agent/venv` 最初是从 macOS 复制到 LinuxUbuntu 24.04)的,导致:
- `python3` 等符号链接指向 macOS 路径(`/Library/Developer/...`
- `pip`、`flask` 等脚本的 shebang 指向 macOS 路径或错误路径
- 结果:`python3` 可能能用,但 `pip` 无法执行
## 修复方法
### 1. 重建 venv推荐
在服务器上用 Linux 系统 Python 重建:
```bash
/usr/bin/python3.12 -m venv --clear /opt/agent/venv
/opt/agent/venv/bin/pip install -r /opt/agent/agents/requirements.txt
```
### 2. 修改后的部署脚本
#### `/opt/agent/start_webapp_new.sh`
`fix_venv()` 同时检查 `python3``pip` 是否可用:
```bash
fix_venv() {
if [ -x "$VENV_DIR/bin/python3" ] && "$VENV_DIR/bin/python3" --version &>/dev/null && \
[ -x "$VENV_DIR/bin/pip" ] && "$VENV_DIR/bin/pip" --version &>/dev/null; then
return 0
fi
# ... 重建 venv ...
}
```
#### `/opt/agent/refresh_agents.sh`
安装依赖前验证 `pip` 是否可执行,不可执行则自动重建 venv
```bash
VENV_DIR="/opt/agent/venv"
if [ -x "$VENV_DIR/bin/pip" ] && "$VENV_DIR/bin/pip" --version &>/dev/null; then
"$VENV_DIR/bin/pip" install -r "$AGENTS_DIR/requirements.txt" -q 2>&1 | tail -3
else
log "venv pip 不可用,重建虚拟环境..."
sys_python=$(command -v python3.12 2>/dev/null || command -v python3 2>/dev/null || command -v python 2>/dev/null || true)
if [ -z "$sys_python" ]; then
log "错误: 找不到系统 Python"
exit 1
fi
"$sys_python" -m venv --clear "$VENV_DIR"
"$VENV_DIR/bin/pip" install -r "$AGENTS_DIR/requirements.txt" -q 2>&1 | tail -3
log "虚拟环境重建完成"
fi
```
## 注意事项
- 服务器内存只有 2G前端构建不在服务器执行由本地 `deploy_agents.sh` scp 上传 `static/dist/`
- 以后部署不要再从 macOS 复制 venv 到服务器
- 如果 pip 包版本升级引入破坏性变更(如 `openai>=2.40` 强制要求 `api_key`),需要同步修复代码

View File

@ -0,0 +1,27 @@
---
name: server_frontend_build_oom
description: 当服务器执行前端构建失败、OOM、或需要部署前端时应该索引本记忆
---
# 服务器前端构建 OOM
## 问题
服务器2G 内存 Linux执行 `npm run build` 时因内存不足导致 OOM进程被 kill服务器可能 SSH 超时无响应。
## 解决方案
**不在服务器上构建前端。** 在本地macOS充足内存构建然后 scp 上传 `static/dist/`
## 操作步骤
```bash
# 本地构建
cd agents && npm run build
# 打包上传
tar czf /tmp/static_dist.tar.gz static/dist/
scp /tmp/static_dist.tar.gz root@59.110.19.30:/tmp/
ssh root@59.110.19.30 "cd /opt/agent/agents && tar xzf /tmp/static_dist.tar.gz"
```
## 已落实到脚本
- `deploy_agents.sh`(本地):自动本地 build + 上传
- `refresh_agents.sh`(服务器):已移除 npm build 步骤,注释说明原因

View File

@ -0,0 +1,23 @@
---
name: slash_menu_highlight_animation
description: 当修改/菜单选中高亮动画时,应该索引本记忆
---
## / 菜单选中高亮动画 — 设计教训
### 最终方案
- 提取 `skill-slash-menu-wrapper` 外壳层,高亮条(`.skill-slash-menu__highlight`)放在 wrapper 内但**滚动容器外**,用 `position: absolute` 相对于 wrapper 定位
- 用一个 `requestAnimationFrame` 循环**同时驱动 scrollTop 和 slashHighlightTop**,相同 easingeaseOutCubic、相同时间180ms帧帧同步
- 不使用 CSS transition、scroll-behavior: smooth、scroll 事件
### 踩过的坑
1. **高亮条必须在滚动容器外**:放在内部会随内容滚动,钉死在中间的效果无法实现
2. **CSS transition + scroll-behavior: smooth 无法精确同步**easing 曲线和时间窗口不完全匹配,导致运动快慢不一致
3. **scroll 事件有盲区**:当 scrollTop 不变(边界、所有项可见)时不触发,导致高亮条卡死
4. **底部 5px 偏差**`maxScroll` 不是 step(43px) 的整数倍,用 `visibleRows` 推算永远无法精确对齐。正确做法:`highlightTop = gap + index * step - targetScroll`,公式本身就保证了精确对齐
### 中间区域"固定"原理
高亮条和列表以相同距离(step)、相同时间(180ms)、相同 easing 反向运动,视觉上高亮条钉在屏幕中间不动,只有列表在滚。到达滚动极限时,高亮条才开始实际移动。
### 已选中项 hover 不叠加
`.skill-slash-item--active:hover` 设为 `background: transparent`,避免高亮条 + hover 两层背景叠加。

View File

@ -0,0 +1,24 @@
---
name: sub_agent_network_permission
description: 当需要理解或调整子智能体在受限网络下的行为时,应该索引本记忆
---
# 子智能体进程网络权限设计
## 问题
当用户把「网络权限」设置为受限(`HOST_SANDBOX_NETWORK_PERMISSION=restricted`)时,创建子智能体会失败,子智能体进程内报 `fetch failed (ENOTFOUND)`。原因是子智能体进程本身也被加上了与工具命令相同的宿主机沙箱,导致它无法解析模型 API 域名、无法调用模型接口。
## 解决方案
子智能体进程使用独立的网络权限配置 `SUB_AGENT_HOST_NETWORK_PERMISSION`(默认 `full`),与工具级 `HOST_SANDBOX_NETWORK_PERMISSION` 解耦。
- 子智能体本身需要调用模型 API因此默认拥有完整网络避免在受限网络下直接无法启动。
- 主进程对普通 `run_command` / `terminal_input` 等命令单独施加 `HOST_SANDBOX_NETWORK_PERMISSION` 沙箱,这部分限制不受影响。
- 子智能体内部执行的 `run_command` 目前不额外加沙箱macOS 的 `sandbox-exec` 不支持嵌套沙箱,无法在同一个子智能体进程内再套一层)。
## 配置项
- `config/sub_agent.py` 新增 `SUB_AGENT_HOST_NETWORK_PERMISSION`,可通过环境变量覆盖,默认 `full`
- `modules/sub_agent_manager.py` 在构建宿主机沙箱启动计划时使用该配置,而不是直接使用 `HOST_SANDBOX_NETWORK_PERMISSION`
## 注意事项
- 若未来需要在子智能体内部也对命令做网络限制,必须采用非嵌套方案(例如由主进程提供本地代理/执行服务,或让子智能体通过 localhost 调用主进程代理后再外出)。不能简单在子智能体里再次调用 `sandbox-exec`
- 在 Docker/容器模式下,网络由容器自身策略控制,上述配置不影响容器行为。

View File

@ -0,0 +1,73 @@
---
name: sub_agent_python_rewrite
description: 当需要了解子智能体当前实现、修改子智能体代码、或排查子智能体相关问题时,应该索引本记忆
---
# 子智能体现状Python 主进程内协程)
## 核心变更
子智能体已经从 **Node.js 子进程**`easyagent/src/batch/index.js`)彻底改为 **Python 主进程内协程**
## 代码位置
所有子智能体专用代码集中在 `modules/sub_agent/` 包内:
```
modules/sub_agent/
├── __init__.py # 导出 SubAgentManager
├── manager.py # 任务调度、创建、终止、状态查询
├── task.py # LLM 循环、模型调用、工具执行驱动
├── toolkit.py # 8 个工具定义、工具结果格式化、模型配置解析
├── prompts.py # 用户消息和系统提示词构建
├── tools.py # search_workspace、read_mediafile 本地实现
├── state.py # 状态加载、保存、刷新、超时、僵尸清理 Mixin
├── stats.py # 统计摘要与结果消息组装 Mixin
└── creation.py # 创建参数校验、任务 ID 生成、交付目录解析 Mixin
```
## 执行机制
- 子智能体作为 `asyncio.Task` 在独立的后台事件循环线程中运行(避免与 Flask-SocketIO threading 模式冲突)。
- 所有实际工具调用都通过 `WebTerminal.handle_tool_call()` 执行,因此**自然复用主进程的宿主机沙箱 / Docker 容器链路**。
- 子智能体自身不再被整体沙箱限制网络(因为它需要调用模型 API网络调用走 `utils.api_client.DeepSeekClient`
- 权限固定为 `unrestricted`,但工具执行本身受主进程沙箱/容器/审批链路约束。
## 模型配置
- 子智能体模型独立配置,不跟主模型合并。
- 配置文件:`~/.astrion/astrion/config/sub_agent_models.json`(由 `SUB_AGENT_MODELS_CONFIG_FILE` 指定)。
- 默认读取该文件中的 `default_model``models` 列表。
## 可用工具8 个)
1. `read_file` - 读取/搜索/抽取文件
2. `write_file` - 创建或覆盖文件(支持 append
3. `edit_file` - 精确字符串替换,支持 `replacements` 数组和 `replace_all`
4. `run_command` - 执行命令(走主进程沙箱/容器)
5. `web_search` - 网络搜索
6. `extract_webpage` - 网页内容提取
7. `search_workspace` - 工作区搜索
8. `read_mediafile` - 读取图片/视频文件base64 返回)
## easyagent/ 目录状态
- `easyagent/` 是旧的 Node.js 子智能体实现,目前**暂时保留但已不再使用**。
- 主项目 Python 代码没有任何地方引用 `easyagent/`
- 是否删除待后续决策。
## 入口点
- 主项目创建子智能体:`modules.sub_agent.manager.SubAgentManager.create_sub_agent()`
- `core/main_terminal.py` 中通过 `SubAgentManager.set_terminal(self)` 注入 WebTerminal 引用。
## 回归测试
- 测试脚本:`test/test_sub_agent_regression.py`
- 覆盖write_file、edit_file多处替换 + replace_all、search_workspace、read_mediafile、terminate
## 已删除/清理的内容
- `config/sub_agent.py` 中已删除 `SUB_AGENT_HOST_NETWORK_PERMISSION` 临时配置。
- `easyagent/src/batch/index.js` 已删除(旧子进程入口)。
- `AGENTS.md``CLAUDE.md` 中关于子智能体的描述已更新为当前实现。