fix(memory): 将项目记忆文件从 .agents/memory 迁移到 .astrion/memory 并更新提示词路径
This commit is contained in:
parent
e3c897947f
commit
b7a535fc8f
153
.astrion/memory/agent_hooks_design.md
Normal file
153
.astrion/memory/agent_hooks_design.md
Normal file
@ -0,0 +1,153 @@
|
||||
---
|
||||
name: agent_hooks_design
|
||||
description: 当需要继续讨论或实现本项目的 hooks / 生命周期钩子功能时,应该索引本记忆
|
||||
---
|
||||
|
||||
# Hooks / 生命周期钩子功能设计讨论(进行中)
|
||||
|
||||
## 调研结论
|
||||
|
||||
### 主流实现
|
||||
- **Claude Code**:最完整,20+ 事件、5 种 handler(command/http/mcp_tool/prompt/agent)、多层配置(全局/项目/本地/组织/插件/SDK)。
|
||||
- **OpenAI Codex**:11 个事件、command 回调为主、有信任审查机制和企业托管 hooks。
|
||||
- **Cursor**:`.cursor/hooks.json`,Beta,command 回调,项目/用户/企业三级。
|
||||
- **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 code:0=通过,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`
|
||||
|
||||
### 例子 2:edit_file 单行全替换触发审核
|
||||
- 事件:`PreToolUse`
|
||||
- 条件:`matcher=edit_file` + `old_string` 只有一行 + `replace_all=true`
|
||||
- 行为:返回 `permissionDecision: ask`
|
||||
|
||||
### 例子 3:Stop 时自动插入 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`
|
||||
68
.astrion/memory/ai_avatar_demo.md
Normal file
68
.astrion/memory/ai_avatar_demo.md
Normal 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 插值动画,解决工作/休息切换时长度跳变问题。
|
||||
30
.astrion/memory/app_initialization_flow.md
Normal file
30
.astrion/memory/app_initialization_flow.md
Normal 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` 保持一致
|
||||
109
.astrion/memory/background_notification_pool.md
Normal file
109
.astrion/memory/background_notification_pool.md
Normal 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 与单通知场景一致。
|
||||
49
.astrion/memory/chat_block_scroll_anchor.md
Normal file
49
.astrion/memory/chat_block_scroll_anchor.md
Normal 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 过渡期间(约 260–300ms),用 `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` 开始,并优先定位向上滚动跳回的根本原因
|
||||
148
.astrion/memory/cloud_server_disk_usage.md
Normal file
148
.astrion/memory/cloud_server_disk_usage.md
Normal file
@ -0,0 +1,148 @@
|
||||
---
|
||||
name: cloud_server_disk_usage
|
||||
description: 当需要了解云服务器磁盘使用现状、规划Docker镜像构建空间、或决定清理哪些文件释放空间时,应该索引本记忆
|
||||
---
|
||||
|
||||
# 云服务器磁盘使用现状
|
||||
|
||||
> 记录时间:2026-06-25
|
||||
> 服务器:59.110.19.30(Ubuntu 24.04.2 LTS, x86_64)
|
||||
|
||||
## 总体情况
|
||||
|
||||
```text
|
||||
Filesystem Size Used Avail Use%
|
||||
/dev/vda3 49G 43G 4.0G 92%
|
||||
```
|
||||
|
||||
- 总磁盘:约 49 GB
|
||||
- 已用:约 43 GB(92%)
|
||||
- 可用:约 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`
|
||||
75
.astrion/memory/cloud_server_ssh_and_directories.md
Normal file
75
.astrion/memory/cloud_server_ssh_and_directories.md
Normal 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/`
|
||||
13
.astrion/memory/config_system_and_deployment.md
Normal file
13
.astrion/memory/config_system_and_deployment.md
Normal 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 发布。
|
||||
210
.astrion/memory/docker_toolbox_enhancement_plan.md
Normal file
210
.astrion/memory/docker_toolbox_enhancement_plan.md
Normal 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、pdftoppm(poppler-utils)
|
||||
- 完全缺少 Node.js / npm
|
||||
- 完全缺少中文字体(`fc-list` 为 0)
|
||||
|
||||
导致用户常见的 Office 转换、图片处理、OCR、网页截图等需求无法跑通。
|
||||
|
||||
## 改造方案
|
||||
|
||||
### 方案 B(已选定)
|
||||
|
||||
在最小方案基础上扩展常见业务能力:
|
||||
|
||||
**系统 apt 包:**
|
||||
- Office:libreoffice、pandoc、poppler-utils
|
||||
- 图片/视频:imagemagick、ffmpeg
|
||||
- OCR:tesseract-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`(服务器磁盘现状)
|
||||
@ -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`
|
||||
|
||||
### 前端函数
|
||||
|
||||
41
.astrion/memory/ocr_client_initialization.md
Normal file
41
.astrion/memory/ocr_client_initialization.md
Normal 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 时,应优雅降级而不是直接崩溃
|
||||
100
.astrion/memory/opencode_key_replacement_script.md
Normal file
100
.astrion/memory/opencode_key_replacement_script.md
Normal 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 替换为 key3(4 文件 20 处)。服务器尚未操作,当前仍为 key1。
|
||||
- 2026-06-25:将本地 `~/.astrion/astrion` 和 `~/.astrion/astrion-clone` 的配置从 key2 替换为 key3(4 文件 20 处),删除备份。服务器仍为 key1。
|
||||
|
||||
## 相关 key 记录
|
||||
|
||||
| 说明 | Key |
|
||||
|---|---|
|
||||
| key1 | `sk-zNU867TGGXNKxoM0H6Pg6Jq4PYUPUOPDgMlzrOl3SS6jECRMWK5nNi6YMSsHzoZ` |
|
||||
| key2 | `sk-sgt4ERgERPx2axU18PSfmenHv9zNDD3y8M5yr0p4ryhcNSm04CZsCxDHftJ9AkFD` |
|
||||
| key3 | `sk-Jhvi76vJdCEQzvEdl8cAS5MIwBxBS4iTrJYSru2zCAXVnDVQpiZIvrcn9hBwkdZ4` |
|
||||
| legacy(已停用,等同 key1 轮换到 key2) | `sk-j0NdTvEDoqqkKCHEAFXXYneEsuXEiOXNCgLeZARJmfYUBf2Riym7KPFWq1amkB6z` |
|
||||
94
.astrion/memory/pywebview_macos_packaging.md
Normal file
94
.astrion/memory/pywebview_macos_packaging.md
Normal 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 桌面 App(PyWebview),不使用 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` | 最后一个可用DMG(527MB) |
|
||||
|
||||
## 关键修复历史
|
||||
|
||||
### 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 errors),PyWebview 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.11(Xcode 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` 是正常运行时数据
|
||||
68
.astrion/memory/server_deployment_venv.md
Normal file
68
.astrion/memory/server_deployment_venv.md
Normal file
@ -0,0 +1,68 @@
|
||||
---
|
||||
name: server_deployment_venv
|
||||
description: 当服务器部署时遇到 venv/pip 损坏、Python 路径错误,或需要更新部署脚本时,应该索引本记忆
|
||||
---
|
||||
|
||||
# 服务器 venv 部署注意事项
|
||||
|
||||
## 背景
|
||||
|
||||
服务器 `/opt/agent/venv` 最初是从 macOS 复制到 Linux(Ubuntu 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`),需要同步修复代码
|
||||
27
.astrion/memory/server_frontend_build_oom.md
Normal file
27
.astrion/memory/server_frontend_build_oom.md
Normal 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 步骤,注释说明原因
|
||||
23
.astrion/memory/slash_menu_highlight_animation.md
Normal file
23
.astrion/memory/slash_menu_highlight_animation.md
Normal 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**,相同 easing(easeOutCubic)、相同时间(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 两层背景叠加。
|
||||
24
.astrion/memory/sub_agent_network_permission.md
Normal file
24
.astrion/memory/sub_agent_network_permission.md
Normal 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/容器模式下,网络由容器自身策略控制,上述配置不影响容器行为。
|
||||
73
.astrion/memory/sub_agent_python_rewrite.md
Normal file
73
.astrion/memory/sub_agent_python_rewrite.md
Normal 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` 中关于子智能体的描述已更新为当前实现。
|
||||
Loading…
Reference in New Issue
Block a user