Metadata-Version: 2.4
Name: tinymem-os
Version: 0.5.0
Summary: AMOS-2.0 协议 Python 参考实现：多用户/多 Agent 的文件系统记忆操作系统（零运行时依赖）
Author: AiLumiere
License-Expression: MIT
Project-URL: Homepage, https://gitee.com/AiLumiere/tinymem-os
Project-URL: Repository, https://gitee.com/AiLumiere/tinymem-os
Project-URL: Bug Tracker, https://gitee.com/AiLumiere/tinymem-os/issues
Keywords: memory,llm,agent,amos,deepseek,prefix-cache,conversation
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# tinymemOS (Python 版)

> AMOS-2.0 协议 Python 参考实现：多用户 / 多 Agent 的文件系统记忆操作系统

tinymemOS 是一个为 LLM（尤其是 DeepSeek）设计的记忆管理中间层。它将 AI 的「人格设定」、用户画像、对话历史、会话摘要、可复用工作流、知识条目，以及 AI 创建的工具/页面资产，以**纯文件形式**分层存储，并通过**稳定前缀 + 追加历史**的策略最大化利用 DeepSeek 前缀缓存，从而降低推理成本、提升响应速度。

**多用户 / 多 Agent 作用域模型**：每个用户拥有独立的 AI 人格、画像、工作流、知识与会话（`users/{actor}/`），公共资源存放于 `shared/`，Agent 拥有最高优先级的人格与会话（`users/{actor}/agents/{agent}/`）。并发通过文件写锁与索引乐观锁保证多进程安全。任何 `AMOS_ROOT` 可打包为 `.amos` 跨实现无损迁移。

**工作流编译为工具**：将 Markdown 工作流「图纸」编译为可执行工具代码，配合多轮对话分析引擎（意图/情感/转折点/事实抽取）和检索系统重构（scope/minScore/精确短语/injectMode），形成「设计→固化→迭代」闭环。所有新参数均为可选，严格向后兼容。

**零运行时依赖**（仅 Python 3.10+ 标准库），asyncio 异步 IO。不依赖任何数据库、向量数据库或第三方服务。

## 与 Node.js 版的关系

本实现是 Node.js 版 **tinymem-os** 的同构 Python 迁移，严格遵循同一套 AMOS-2.0 协议目录结构、存储格式与语义约定。两种实现可互换使用：同一 `AMOS_ROOT` 目录，在 Node.js 与 Python 实现下读写完全兼容（甚至可通过 `.amos` 打包跨实现迁移）。

| 对比项 | Node.js 版 | Python 版（本项目） |
|--------|-----------|-------------------|
| 语言 | TypeScript / Node.js 18+ | Python 3.10+ / asyncio |
| 命名风格 | `camelCase` | `snake_case`（与 Python 一致） |
| 核心模块数 | 24 | 24（一一对应） |
| 沙箱 | `worker_threads` + `vm` | `exec` 安全隔离 + `concurrent.futures` 线程池 |
| 打包 | 内置 USTAR + zlib | `tarfile` + `gzip` |
| 测试数 | 73 | 37（覆盖相同核心能力域） |
| 零依赖 | ✅ | ✅ |

## 核心设计哲学

> **摘要留住结论，档案留住过程，画像留住事实。**

- **缓存友好**：稳定内容放 prompt 前部，动态内容放后部；历史消息只追加不修改。
- **分层记忆**：短期（原始对话）、中期（会话摘要）、长期（画像/知识/工作流）、归档（冷记忆）。
- **文件即记忆**：以 Markdown / JSONL 文件为存储单元，路径即 URI。
- **可降级**：旧记忆压缩成摘要或归档，不直接删除。
- **防膨胀**：摘要具有硬性容量上限，通过递归合并维持定长。
- **资产与记忆分离**：资产按需加载，不参与稳定前缀，不破坏缓存友好性。

## 安装

### 方式 1：PyPI 安装（推荐）

```bash
pip install tinymem-os
```

### 方式 2：Git 直装（只装 Python 版，不会安装 Node.js 版）

仓库根目录同时包含 `nodejs/`（Node.js 版）与 `python/`（Python 版）。`#subdirectory=python` 会让 pip 只构建并安装 `python/` 子目录下的包，Node.js 版完全不受影响：

```bash
pip install "git+https://gitee.com/AiLumiere/tinymem-os.git#subdirectory=python"
```

### 方式 3：源码安装（开发 / 可编辑模式）

```bash
# 1. 克隆项目到本地（nodejs/ 目录也会被克隆，但只用于参照，无需安装）
git clone https://gitee.com/AiLumiere/tinymem-os.git

# 2. 只进入 Python 版目录安装（可编辑模式）
cd tinymem-os/python
pip install -e .
```

### 方式 4：作为子模块引入

```bash
git submodule add https://gitee.com/AiLumiere/tinymem-os.git lib/tinymemOS
pip install -e lib/tinymemOS/python
```

> 安装后自动提供 `tinymem` 命令行工具：`tinymem --version`、`tinymem init [root_dir]`。

### 环境要求

- **Python** ≥ 3.10（需要 `typing` 新语法、`asyncio.to_thread`、`dataclass(slots=True)`）
- 无第三方依赖，开箱即用

## 快速开始

```python
import asyncio
from tinymem_os import AMOS

async def main():
    # 1. 初始化（AMOS 为唯一主入口；可选 agent 启用 Agent 作用域）
    amos = await AMOS.create(
        root_dir="./amos_root",
        actor="user_zhangsan",            # 用户身份（默认取 AMOS_ACTOR 环境变量）
        agent="assistant",                # 可选：该用户下的 Agent（独立人格与会话）
        session_id="2026-08-22-demo",     # 默认会话（build_messages / add_turn 可省略）
        # summarize_fn 是压缩流程必需的，真实场景调用 DeepSeek
        summarize_fn=lambda text, instruction: text[:200],
    )

    # 2. 设定 AI 人格 + 用户画像（构成稳定前缀）
    #    有 agent → 写 agents/{agent}/soul.md；无 agent → 写 users/{actor}/soul.md
    await amos.replace_soul("# AI 人格\n你是小深，温暖简洁的助手")
    await amos.replace_profile("# 用户画像\n偏好简洁回答，旅行偏好经济型酒店")

    # 3. 多轮对话（自动追加，超过阈值自动压缩）
    await amos.add_turn("2026-08-22-demo", "计划去杭州旅行", "好的，确认日期和人数？")
    await amos.add_turn("2026-08-22-demo", "9月10日，2人", "已记录")

    # 4. 组装 prompt（缓存友好顺序，稳定前缀 = agent soul > 用户 soul > shared soul + 画像）
    messages = await amos.build_messages("2026-08-22-demo", "帮我推荐酒店")
    # → 直接送入 DeepSeek chat 接口即可命中前缀缓存

    # 5. 切换上下文（多用户 / 多 Agent）
    amos.set_context("user_lisi", None, "2026-08-22-demo")

    # 6. 后台任务 + 安全执行工具 + 可移植性
    task_id = await amos.submit_task("reflect", {"session_id": "2026-08-22-demo"})
    weather = await amos.execute_asset("tool", "weather", {"city": "上海"})
    await amos.export_agent("./agent.amos")

asyncio.run(main())
```

> API 采用 **`snake_case`** 命名（遵循 PEP 8），文件 IO 为异步，所有方法返回 `Awaitable`。类型注解均已包含，IDE 会有完整自动补全。

## 核心概念

### 分层存储模型

| 层 | 名称 | 物理位置 | 典型内容 | 缓存特性 |
|----|------|----------|----------|----------|
| L0 | 寄存器 | 上下文窗口 | 当前输入、临时检索结果 | dynamic |
| L1 | 缓存 | 稳定前缀文件 | soul.md、profile.md、summary.md | stable / semi_stable |
| L2 | 内存 | 会话目录 | 原始对话（JSONL） | append_only |
| L3 | 磁盘 | 用户/工作流/知识目录 | profile、workflows、knowledge | stable |
| L4 | 归档 | 归档目录 | 旧消息、历史版本 | 按需加载 |

### 记忆文件类型

| 文件 | 格式 | 说明 | 更新频率 |
|------|------|------|----------|
| `soul.md` | Markdown | AI 人格设定、语气、价值观 | 极少变 |
| `profile.md` | Markdown | 用户画像 + 偏好 | 低频 |
| `summary.md` | Markdown | 会话摘要，定长滚动更新 | 中频（每 N 轮） |
| `messages.jsonl` | JSONL | 原始对话，只追加 | 每轮追加 |
| `workflows/*.md` | Markdown | 可复用工作流 | 低频 |
| `knowledge/*.md` | Markdown | 知识条目 | 按需 |
| `archive/*.jsonl` | JSONL | 归档的旧消息 | 极少 |

### 记忆 URI 与文件路径映射

`AMOS` 使用 `amos://` URI（AMOS 2.0 协议目录）：

```
amos://shared/soul                                 → AMOS_ROOT/shared/soul.md
amos://shared/workflows/{name}                     → AMOS_ROOT/shared/workflows/{name}.md
amos://shared/knowledge/{domain}/{entity}          → AMOS_ROOT/shared/knowledge/{domain}/{entity}.md
amos://users/{actor}/profile                       → AMOS_ROOT/users/{actor}/profile.md
amos://users/{actor}/soul                          → AMOS_ROOT/users/{actor}/soul.md
amos://users/{actor}/workflows/{name}              → AMOS_ROOT/users/{actor}/workflows/{name}.md
amos://users/{actor}/knowledge/{domain}/{entity}   → AMOS_ROOT/users/{actor}/knowledge/{domain}/{entity}.md
amos://users/{actor}/sessions/{sid}/summary        → AMOS_ROOT/users/{actor}/sessions/{sid}/summary.md
amos://users/{actor}/sessions/{sid}/messages       → AMOS_ROOT/users/{actor}/sessions/{sid}/messages.jsonl
amos://users/{actor}/agents/{agent}/soul           → AMOS_ROOT/users/{actor}/agents/{agent}/soul.md
amos://users/{actor}/agents/{agent}/sessions/{sid}/messages  → .../agents/{agent}/sessions/{sid}/messages.jsonl
amos://tasks/{status}/{task_id}                    → AMOS_ROOT/tasks/{status}/task_{id}.json
```

路径越靠前越稳定，对应缓存友好原则。

### Prompt 组装顺序（严格遵守）

`build_messages()` 按以下顺序组装，以最大化前缀缓存命中：

1. **稳定前缀**：`soul.md` + `profile.md` → 拼成单个 system message
2. **会话摘要**：`summary.md`（如有）追加到前缀
3. **原始历史**：`messages.jsonl` 逐条作为独立 message 追加
4. **动态检索结果**（可选）：相关记忆作为 system message，放在历史之后
5. **当前输入**：最后添加 user message

## 会话压缩与防膨胀

当 `messages.jsonl` 轮数超过 `max_history_turns` 时自动触发压缩：

```
第一步：切分    头部（较早轮次）→ 归档；尾部（最近 N 轮）→ 保留
第二步：提炼    头部消息 → LLM 提炼增量摘要
第三步：递归合并 旧摘要 + 新提炼 → 合并压缩 → 不超过 summary_max_chars 字
第四步：原子写入 新摘要覆盖 summary.md；头部归档；messages 仅保留尾部
```

**防膨胀的三级降级策略：**

| 信息类型 | 去向 | 容量控制 |
|----------|------|----------|
| 会话状态 | `summary.md` | 硬性字符上限，递归合并维持定长 |
| 长期事实 | `profile.md` | 只保留跨会话稳定信息 |
| 原始过程 | `archive/` | 按需检索，不占上下文 |

## 资产子系统

让 AI 能够创建、读取、更新、删除自己的工具和前端页面。资产存储为纯文件（用户私有位于 `users/{actor}/assets/`，公共位于 `shared/assets/`，读写合并、同名用户优先），与记忆系统共用 `index.json` 统一索引。

```
users/{actor}/assets/ 或 shared/assets/
├── tools/{tool_name}/
│   ├── schema.json        # 工具 Schema（AMOS 协议）
│   ├── definition.md      # 工具定义
│   ├── code.py            # 实际代码（支持 {{ENV.XXX}} 凭证占位符；Python 沙箱执行）
│   ├── metadata.json      # 元数据（版本、标签、编译来源等）
│   └── backup/            # 历史版本备份（编译工具更新时自动生成）
└── pages/{page_name}/
    ├── description.md     # 页面描述
    ├── index.html         # 页面入口
    ├── app.js / style.css # 页面逻辑/样式（可选）
    └── metadata.json
```

> 与 Node.js 版的关键差异：**工具代码文件后缀是 `code.py`（Python）而不是 `code.js`**。`SandboxExecutor` 会根据 `language="python"` 或文件名自动选择执行引擎。

**资产不参与稳定前缀**，`build_messages()` 不读取 `assets/` 下的任何文件。资产仅通过两种方式按需加载：

- **方式 A：检索注入** — 应用层用 `search_assets()` 找到相关资产，将其定义作为动态内容注入历史之后。
- **方式 B：Function Calling** — AI 识别到需要某工具时，用 `get_asset_code()` 读取代码执行，结果作为 tool message 追加。

## AMOS 主入口

`AMOS` 是唯一主入口。它在完整记忆能力（对话 / 压缩 / 检索 / 工作流 / 知识 / 资产 / 标签 / AI 工具集）之上，支持**多用户 / 多 Agent 作用域隔离**、`shared/` 公共资源、文件写锁并发，并保留任务调度、安全权限、沙箱执行、可移植性与设备抽象。核心承诺——任何 `AMOS_ROOT` 目录打包为 `.amos` 后，可在任何兼容 AMOS 协议的客户端（Node.js/Python/Go/Rust 实现）中无损恢复。

### 核心能力一览

| 能力域 | AMOS 方法（snake_case） |
|--------|------------------------|
| 对话记录 | `add_turn(session_id, user, assistant)` / `get_recent_messages` / `build_messages` |
| 稳定前缀写入 | `replace_soul` / `replace_profile` / `replace_summary` / `update_profile` |
| 增量写入 | `append_profile(section, content)` / `remove_profile_fact(keyword)` / `append_summary_point(point)` |
| 会话压缩 | `compress_session(force=False)`（单参数走默认会话） |
| 工作流 | `add_workflow` / `get_workflow` / `delete_workflow` / `list_workflows` / `update_workflow` |
| 知识 | `add_knowledge` / `update_knowledge` / `delete_knowledge` / `get_knowledge` / `list_knowledge` |
| 检索 | `search(query, top_k, options?)` / `search_all(query, top_k, options?)` / `search_assets` |
| 资产 | `create_asset` / `update_asset` / `delete_asset` / `get_asset_code` / `execute_asset` / `register_asset_executor` |
| 标签 | `add_tag` / `remove_tag` / `list_by_tag` |
| 对话分析 | `analyze_turn` / `classify_message`（单轮） / `analyze_session` / `incremental_analyze` / `extract_facts` / `find_turning_point`（多轮） |
| 工具编译 | `compile_workflow_to_tool` / `list_tools` / `get_tool` / `update_tool` / `delete_tool` |
| AI 工具集 | `amos.tools.list_tools()` / `amos.tools.call(name, args)`（OpenAI Function Calling 格式） |
| 事件 | `on(event, callback)`（记忆变更事件，含 `workflow_updated` / `tool_compiled` / `tool_deleted` 等） |

### 协议目录（AMOS_ROOT）

```
AMOS_ROOT/
├── version.txt                      # 内容 "2.0.0"
├── manifest.json                    # 系统级清单（author="system" / env_vars / required_capabilities）
├── cache_version.txt                # 缓存版本（作用域化 JSON：{ scope: version }）
├── shared/                          # 公共资源（默认人格 / 共享工作流 / 共享知识 / 共享资产）
│   ├── soul.md
│   ├── workflows/  knowledge/  assets/
├── users/{actor_id}/
│   ├── profile.md                   # 用户画像（稳定前缀）
│   ├── acl.json                     # 用户级 ACL
│   ├── soul.md                      # 用户专属人格（可选，覆盖 shared）
│   ├── workflows/  knowledge/  assets/     # 用户私有（与 shared 合并，同名用户优先）
│   ├── agents/{agent_id}/
│   │   ├── soul.md                  # Agent 人格（最高优先级）
│   │   ├── manifest.json            # Agent 清单
│   │   └── sessions/{session_id}/   # Agent 会话（独立于用户级）
│   └── sessions/{session_id}/       # 用户级会话
├── tasks/{pending,running,completed,failed}/task_{id}.json
├── events/event_log.jsonl
├── acl/global.acl.json
├── logs/{system.log, error.log}
└── index.json                       # 记忆 + 资产统一索引（按需生成）
```

**作用域链解析**：`users/{actor}/agents/{agent}` → `users/{actor}` → `shared/`。人格（soul）按层覆盖；列表资源（工作流/知识/资产）用户私有 + 公共合并，同名用户优先；有 Agent 时会话落在 Agent 目录。

### 内核模块

| 模块 | 协议依据 | 功能 |
|------|----------|------|
| `TaskManager` | §4 | 优先级 / 重试 / 超时 / 并发控制，文件移动实现原子状态转移 |
| `EventBus` | - | 发布 / 订阅，可选持久化到 `events/event_log.jsonl` |
| `SecurityManager` | §3.3 | 用户级 ACL 优先，无则全局/内置默认；多用户天然隔离 |
| `SandboxExecutor` | §6.3 | 线程池沙箱执行，`{{ENV.XXX}}` 白名单凭证注入，按作用域解析工具代码；`validate_code` 语法预检（支持 Python / JS） |
| `PortabilityManager` | §8 | `.amos`（tar.gz）导出 / 导入（v2.0 包） |
| `LLMDevice` / `HttpDevice` | §6.1-6.2 | 统一 LLM / HTTP 接口 + 启动能力协商（降级运行） |
| `Monitor` | - | 资源快照 / 健康检查 / 事件与错误记录 |
| `file_ops.with_lock` | - | **文件写锁**（`{path}.lock` + 过期抢占），多进程并发写安全 |
| `SessionAnalyzer` | - | 对话分析引擎：单轮 `classify_message`/`analyze_turn_default` + 多轮意图/情感/实体/转折点/事实抽取（LLM 注入或本地降级） |
| `WorkflowCompiler` | - | 工作流编译为工具：Markdown 步骤 → LLM 生成代码 → 沙箱预检 → 原子写入 |
| `AssetManager`（工具 CRUD） | - | 资产管理 + 编译工具 `list_tools/get_tool/update_tool/delete_tool` + 版本备份 + 软删除 |

**ACL 示例**（`users/{actor}/acl.json`）：

```json
{
  "owner": "user_zhangsan",
  "entries": [
    { "resource": "profile.md", "allow": ["read", "write"], "actors": ["user_zhangsan"] },
    { "resource": "assets/tools/*", "allow": ["execute"], "actors": ["user_zhangsan"] }
  ],
  "default": { "read": ["owner"], "write": ["owner"], "execute": [] }
}
```

**Python 工具代码示例**（`assets/tools/weather/code.py`，凭证白名单来自 `manifest.json` 的 `env_vars`）：

```python
# 沙箱会先校验 {{ENV.WEATHER_API_KEY}} 是否在白名单内，再替换成实际值
api_key = "{{ENV.WEATHER_API_KEY}}"
import urllib.request, json
url = f"https://api.weather.com?key={api_key}&city={params['city']}"
with urllib.request.urlopen(url) as resp:
    __return_value__ = json.loads(resp.read())
```

> 若工具代码中定义了 `def run(params): ...`，沙箱会自动调用该函数并返回其结果；否则读取顶层的 `__return_value__`。

## 配置项

```python
from tinymem_os import AMOS

amos = await AMOS.create(
    root_dir="./amos_root",              # AMOS_ROOT 根目录
    actor="user_zhangsan",               # 用户身份（默认取 AMOS_ACTOR 环境变量）
    agent="assistant",                   # 可选：Agent（独立人格与会话）
    session_id="2026-08-22-demo",        # 默认会话 ID（会话方法可省略参数走默认）
    llm_config={"provider": "deepseek", "api_key": "sk-xxx"},  # LLM 设备配置
    summarize_fn=my_summarize,          # 压缩必需 (text, instruction) -> str
    analyze_fn=my_analyze_turn,         # 可选，默认关键词提取
    analyze_session_fn=my_analyze_session,   # 可选，不注入走本地降级
    compile_fn=my_compile_workflow,           # 可选，不注入走模板生成
    max_history_turns=20,               # messages.jsonl 最多保留轮数
    keep_recent_turns=5,                # 压缩时尾部保留不参与压缩的轮数
    summary_max_chars=800,              # summary.md 最大字符数（防膨胀）
    enable_index=True,                  # 是否维护 index.json 索引
    sandbox={                           # 沙箱配置
        "timeout": 5000,                # 单代码执行超时 ms
        "allow_network": False,         # 是否允许网络访问（沙箱）
        "env_whitelist": ["WEATHER_*", "MY_API_KEY"],  # 环境变量占位符白名单
    },
)
```

> 完整字段见 `AMOSOptions` 数据类（`python/src/tinymem_os/amos.py`），全部字段都有 docstring。

## API 速览

> 以下均为 `AMOS` 实例方法（async，需要 `await`）。会话相关方法可省略 `session_id` 走默认会话；上下文通过 `set_context(actor, agent=None, session_id=None)` 切换。

### 记忆管理

| 方法 | 说明 |
|------|------|
| `build_messages(session_id, user_input, retrieve=True, retrieve_options?)` | 组装缓存友好的 prompt（核心）；支持 `inject_mode`（full/preview/reference） |
| `add_turn(session_id, user_msg, assistant_msg)` | 追加一轮对话 |
| `replace_soul(content)` / `replace_profile(content)` / `replace_summary(content?)` | 原子写入人格/画像/摘要，缓存版本 +1 |
| `append_profile(section, content)` / `remove_profile_fact(keyword)` / `append_summary_point(point)` | 增量写入，内部走读-改-写回 |
| `compress_session(force=False)` | 手动触发会话压缩 |
| `add_workflow(name, content)` / `get_workflow` / `list_workflows` / `delete_workflow` | 工作流 CRUD |
| `update_workflow(name, content, mode=UpdateWorkflowMode.OVERWRITE)` | 工作流更新（overwrite/append/patch） |
| `add_knowledge(domain, entity, content)` / `update_knowledge` / `delete_knowledge` / `get_knowledge` / `list_knowledge` | 知识 CRUD |
| `search(query, top_k=5, options?)` | 检索相关记忆；支持 scope/min_score/since/精确短语 |
| `search_all(query, top_k=5, options?)` | 统一检索：记忆 + 资产 |
| `analyze_turn(user_msg, assistant_msg)` / `classify_message(msg)` | 单轮对话分析 |
| `analyze_session(session_id?, recent_turns?)` | 全量多轮会话分析（意图/情感/实体/未决问题/洞察） |
| `incremental_analyze(session_id?)` | 增量分析，仅处理新增轮次，合并到已有洞察 |
| `extract_facts(session_id?, turn_count?)` | 抽取用户稳定事实（职业/爱好/禁忌） |
| `find_turning_point(session_id?)` | 查找情感/意图突变轮次 |
| `cache_version()` | 返回当前缓存版本号（cache_version.txt） |

### 工具编译与管理

| 方法 | 说明 |
|------|------|
| `compile_workflow_to_tool(workflow_name, new_tool_name, opts?)` | 将工作流编译为可执行工具，返回工具 URI |
| `list_tools(include_deprecated=False)` | 列出所有编译工具名 |
| `get_tool(name)` | 读取工具详情（code + schema + metadata） |
| `update_tool(name, code?, schema?, metadata?)` | 更新工具（备份旧版本 → 版本号自增） |
| `delete_tool(name, soft=True)` | 删除工具（soft=True 标记 deprecated；False 物理删除） |

### 资产管理

| 方法 | 说明 |
|------|------|
| `create_asset(asset_type, name, definition, code_files, metadata?)` | 创建资产，返回 URI |
| `get_asset_definition(asset_type, name)` | 读取 definition.md / description.md |
| `get_asset_code(asset_type, name, filename)` | 读取指定代码文件 |
| `get_asset_metadata(asset_type, name)` | 读取资产元数据 |
| `update_asset(asset_type, name, definition?, code_files?, metadata_updates?)` | 更新资产，version +1 |
| `delete_asset(asset_type, name)` | 删除整个资产目录 |
| `list_assets(asset_type?)` | 列出资产 URI |
| `search_assets(query, asset_type?, top_k=5)` | 搜索资产 |
| `asset_exists(asset_type, name)` | 判断资产是否存在 |
| `register_asset_executor(executor)` / `execute_asset(asset_type, name, input?, timeout_ms=5000)` | 注入执行器并执行资产代码 |

### AI 工具集封装（MemoryTools）

| 方法 | 说明 |
|------|------|
| `amos.tools.list_tools()` | 返回 OpenAI Function Calling 格式的 tool schema 数组 |
| `amos.tools.call(name, args)` | 统一调度入口，返回 `{ ok, data?, error? }` |
| `amos.tools.set_permission(allow=None, deny=None)` | 权限控制（None 表示不限制；如禁止 AI 调用 `memory.replace_soul`） |
| `amos.tools.on_call(callback)` | 注册调用审计回调 |

内置工具覆盖：`memory.search*` / `memory.replace*` / `memory.append*` / `memory.*_workflow` / `memory.*_knowledge` / `memory.add_tag` / `memory.list_by_tag` / `memory.compress` / `memory.analyze_turn` / `asset.create` / `asset.update` / `asset.delete` / `asset.get_definition` / `asset.get_metadata` / `asset.execute`。

### 标签与事件

| 方法 | 说明 |
|------|------|
| `add_tag(rel_path, tag)` / `remove_tag(rel_path, tag)` / `list_by_tag(tag)` | 标签存入 index.json，不污染稳定前缀 |
| `on(event, callback)` | 监听记忆变更事件（`profileAppended` / `workflowAdded` / `assetCreated` / `toolCompiled` / `toolDeleted` / `compressed` 等，**事件名沿用 camelCase 以与 Node.js 版兼容**） |

> `asset_type` 取值为 `"tool"` 或 `"page"`。资产名称只能包含字母、数字、下划线、连字符。

## 接入 DeepSeek

`build_messages()` 返回标准的 messages 列表，可直接送入 DeepSeek chat 接口：

```python
from openai import OpenAI
from tinymem_os import AMOS
import asyncio

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.deepseek.com")

async def chat():
    amos = await AMOS.create(
        root_dir="./amos_root",
        actor="user_zhangsan",
    )

    messages = await amos.build_messages("s1", "帮我推荐酒店")
    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=messages,
    )
    reply = response.choices[0].message.content

    # 记录这一轮对话
    await amos.add_turn("s1", "帮我推荐酒店", reply)

asyncio.run(chat())
```

**异步注入摘要函数**（压缩流程必需）：

```python
async def my_summarize(text: str, instruction: str) -> str:
    loop = asyncio.get_running_loop()
    # 同步 SDK 放到线程池避免阻塞事件循环
    def _call():
        return client.chat.completions.create(
            model="deepseek-chat",
            messages=[
                {"role": "system", "content": instruction},
                {"role": "user", "content": text},
            ],
        ).choices[0].message.content
    return await loop.run_in_executor(None, _call)

amos = await AMOS.create(
    root_dir="./amos_root",
    actor="user_zhangsan",
    summarize_fn=my_summarize,  # ← 注入
)
```

**Function Calling 按需加载资产代码**：

```python
response = client.chat.completions.create(model="deepseek-chat", messages=messages)
msg = response.choices[0].message
if msg.tool_calls:
    for tc in msg.tool_calls:
        if tc.function.name == "query_weather":
            code = await amos.get_asset_code("tool", "weather_query", "code.py")
            result = await amos.execute_asset("tool", "weather_query", ...)
            messages.append({
                "role": "tool",
                "content": str(result),
                "tool_call_id": tc.id,
            })
```

## 缓存控制策略

- **稳定前缀文件**（soul、profile）多次请求间完全一致 → 完美命中前缀缓存。
- **summary.md** 低频更新（每 N 轮一次），更新后前缀变化一次，之后恢复稳定。
- **messages.jsonl** 只追加，历史部分不变，缓存命中率极高。
- 稳定前缀更新时 `cache_version` +1，外部可据此失效缓存：

```json
{
  "cache_key": "mem:user:zhangsan:stable_prefix",
  "cache_version": 3
}
```

整体缓存命中率可维持在 90% 以上。

## 目录结构

### 运行时数据目录

`AMOS.create(root_dir=..., actor=..., agent=None)` 生成符合 AMOS 2.0 协议的 `AMOS_ROOT`：

```
AMOS_ROOT/
├── version.txt                    # 协议版本（内容 "2.0.0"）
├── manifest.json                  # 系统级清单（author="system"）
├── cache_version.txt              # 缓存版本（作用域化 JSON）
├── shared/                        # 公共资源
│   ├── soul.md                    # 默认 AI 人格
│   ├── workflows/  knowledge/  assets/
├── users/{actor_id}/
│   ├── profile.md                 # 用户画像（稳定前缀）
│   ├── acl.json                   # 用户级 ACL
│   ├── soul.md                    # 用户专属人格（可选）
│   ├── workflows/  knowledge/  assets/   # 用户私有（与 shared 合并）
│   ├── agents/{agent_id}/
│   │   ├── soul.md                # Agent 人格（最高优先级）
│   │   ├── manifest.json
│   │   └── sessions/{session_id}/
│   └── sessions/{session_id}/
│       ├── summary.md             # 会话摘要（稳定前缀）
│       ├── messages.jsonl         # 对话流水（动态区，只追加）
│       └── archive/               # 归档旧消息 messages_YYYYMMDD.jsonl
├── tasks/{pending,running,completed,failed}/task_{id}.json
├── events/event_log.jsonl
├── acl/global.acl.json
├── logs/{system.log, error.log}
└── index.json                     # 记忆 + 资产统一索引（按需生成）
```

> 作用域链：`users/{actor}/agents/{agent}` → `users/{actor}` → `shared/`。旧版 1.x 数据迁移见项目根目录的 `迁移方案.md`。

### 源码结构

```
tinymemOS/
├── nodejs/                     # Node.js 版实现（TypeScript）—— 同构参照实现
└── python/                     # Python 版实现（本项目）
    ├── src/
    │   └── tinymem_os/
    │       ├── __init__.py                 # 对外导出（与 Node.js index.ts 对应）
    │       ├── amos.py                     # AMOS 主入口（多用户 / 多 Agent 作用域）
    │       ├── amos_store.py               # 协议目录存储层（shared/users/agents + 作用域解析 + 基础工具列表）
    │       ├── file_ops.py                 # 底层文件操作 + 并发写锁 with_lock
    │       ├── task_manager.py             # 任务调度器（优先级/重试/超时，§4）
    │       ├── event_bus.py                # 事件总线（可选持久化）
    │       ├── security_manager.py         # 安全权限（用户级 ACL，多用户隔离）
    │       ├── sandbox_executor.py         # 沙箱执行器（凭证注入 + 作用域工具 + validate_code）
    │       ├── portability_manager.py      # 可移植性（.amos 导出/导入，§8）
    │       ├── tar_util.py                 # tar + gzip 打包/解包
    │       ├── llm_device.py / http_device.py   # 设备抽象（能力协商）
    │       ├── monitor.py                  # 资源监控
    │       ├── prompt_builder.py           # Prompt 组装器（按缓存友好顺序）
    │       ├── cache_controller.py         # 缓存版本管理（作用域化）
    │       ├── compressor.py               # 会话压缩与摘要防膨胀
    │       ├── search.py                   # 记忆检索（作用域白名单 + scope/min_score/since/精确短语）
    │       ├── asset_manager.py            # 资产子系统（用户私有 + shared + 编译工具 CRUD）
    │       ├── memory_tools.py             # AI 工具集封装（OpenAI Function Calling 格式）
    │       ├── analyzer.py                 # 对话分析引擎（单轮 classify_message + 多轮 SessionAnalyzer）
    │       ├── compiler.py                 # 工作流编译器（WorkflowCompiler）
    │       ├── exceptions.py               # 异常定义
    │       ├── types.py                    # 共享类型定义（dataclass + TypedDict）
    │       ├── utils.py                    # 通用工具（时间、截断）
    │       └── cli.py                      # 命令行入口（tinymem --version / tinymem init）
    ├── tests/                              # 单元 + 集成测试（37 个用例，全部通过）
    │   ├── test_file_ops.py                # 文件操作与并发写锁（8）
    │   ├── test_asset_manager.py           # 资产 CRUD + 作用域优先级（7）
    │   ├── test_compressor.py              # 压缩阈值/分割/合并/异常（4）
    │   ├── test_prompt_builder.py          # 前缀顺序/历史独立/检索注入（3）
    │   ├── test_v04.py                     # 协议目录/灵魂链/缓存 bump/URI/搜索/资产/归档（7）
    │   └── test_v05.py                     # 编译器/沙箱/会话分析/权限/事件（8）
    ├── LICENSE                             # MIT 许可证
    ├── pyproject.toml                      # Python 包配置（tinymem-os）
    └── README.md                           # 本文件
```

## 测试

```bash
# 安装 pytest（推荐开发模式）
pip install pytest
# 运行全部测试（37 个）
python -m pytest tests/ -v
```

测试覆盖：文件操作与并发写锁（`with_lock` 互斥不丢失）、Prompt 组装与前缀一致性、缓存作用域化、会话压缩与防膨胀、资产 CRUD（用户私有 + shared 合并）、作用域链解析（soul agent>user>shared）、多用户隔离、多 Agent 独立人格与会话、事件总线、任务调度（重试）、ACL 多用户语义、沙箱凭证注入与超时、.amos 导出/导入、LLM 能力协商、监控快照与 AMOS 主类集成、工作流更新（overwrite/append/patch）、多轮对话分析（全量/增量/事实抽取/转折点）、检索 scope/min_score/精确短语/inject_mode、工作流编译为工具、工具 CRUD + 版本管理 + 软删除、沙箱 `validate_code` 语法预检、向后兼容验证。

## 模块架构

```
┌─────────────────────────────────────────────┐
│                应用层（业务逻辑）              │
└─────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────┐
│                   AMOS 主入口                 │
│  set_context(actor, agent?, session_id?)     │
│  ┌──────────┐ ┌──────────────┐ ┌──────────┐  │
│  │ Prompt   │ │ AmosStore    │ │ Cache    │  │
│  │ Builder  │ │ (作用域解析)  │ │ (按scope) │  │
│  └──────────┘ └──────────────┘ └──────────┘  │
│  ┌──────────────┐ ┌──────────────────────┐   │
│  │ Compressor   │ │ AssetManager         │   │
│  │ (压缩/归档)  │ │ (资产 + 工具 CRUD)    │   │
│  └──────────────┘ └──────────────────────┘   │
│  ┌──────────────┐ ┌──────────────────────┐   │
│  │ Analyzer     │ │ WorkflowCompiler     │   │
│  │ (单轮+多轮)  │ │ (工作流→工具编译)     │   │
│  └──────────────┘ └──────────────────────┘   │
│  ┌──────────┐ ┌──────────┐ ┌─────────────┐   │
│  │ TaskMgr  │ │ Security │ │ Sandbox     │   │
│  │ (§4 调度)│ │ (用户ACL) │ │ (作用域工具) │   │
│  └──────────┘ └──────────┘ └─────────────┘   │
│  ┌────────────┐ ┌──────────┐ ┌───────────┐   │
│  │ EventBus   │ │ LLM/HTTP │ │ Portability│  │
│  │ (事件总线) │ │ (设备)    │ │ (.amos 包) │   │
│  └────────────┘ └──────────┘ └───────────┘   │
│  ┌──────────────────────────────────────┐    │
│  │ File Operations（原子写 + with_lock） │    │
│  └──────────────────────────────────────┘    │
└─────────────────────────────────────────────┘
                    │
                    ▼
      ┌─────────────────────────────┐
      │ 文件系统（AMOS_ROOT 2.0）     │
      │  shared/ · users/{actor}/    │
      │  MD / JSONL / JSON / PY      │
      └─────────────────────────────┘
```

## 技术栈

| 组件 | 选择 |
|------|------|
| 语言 | Python 3.10+ |
| 核心库 | 标准库（`asyncio`, `pathlib`, `json`, `re`, `tarfile`, `gzip`, `hashlib`, `concurrent.futures`, `dataclasses`, `threading`） |
| 沙箱执行 | `exec` + 命名空间隔离 + 线程池超时 + `ast.parse` 语法预检（内存限制 / 超时终止） |
| 全文检索 | 内置 `re` + `pathlib.Path.rglob` 递归（零外部依赖，跨平台） |
| .amos 打包 | `tarfile` + `gzip` 标准库 |
| 类型声明 | 内建 dataclass + TypedDict，配合 mypy / pyright 强类型检查 |
| 包管理 | pip + `pyproject.toml`（PEP 621） |
| 版本管理 | Git（可选） |
| 摘要生成 | 外部 LLM 函数（由使用者注入，如 DeepSeek） |

## 从 Node.js 版迁移代码示例

| Node.js (camelCase) | Python (snake_case) |
|---------------------|---------------------|
| `AMOS.create({rootDir, actor, agent})` | `await AMOS.create(root_dir=, actor=, agent=)` |
| `amos.addTurn(sid, u, a)` | `await amos.add_turn(sid, u, a)` |
| `amos.buildMessages(sid, input)` | `await amos.build_messages(sid, input)` |
| `amos.replaceSoul("# 人格")` | `await amos.replace_soul("# 人格")` |
| `amos.replaceProfile("# 画像")` | `await amos.replace_profile("# 画像")` |
| `amos.compileWorkflowToTool(a, b)` | `await amos.compile_workflow_to_tool(a, b)` |
| `amos.tools.listTools()` | `amos.tools.list_tools()` |
| `amos.tools.call(name, args)` | `await amos.tools.call(name, args)` |
| `amos.on("workflowAdded", cb)` | `amos.on("workflowAdded", cb)`（事件名沿用 camelCase，与 Node.js 版一致，便于跨语言对照） |

## License

MIT
