Metadata-Version: 2.4
Name: agentbase-memory-agentscope
Version: 0.1.0
Summary: AgentScope long-term memory middleware backed by Agentbase Memory
Author: Agentbase Team
License-Expression: Apache-2.0
Keywords: agentbase,agentscope,agent,memory,middleware
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: agentscope<2.1,>=2.0.7
Requires-Dist: httpx<1,>=0.27
Provides-Extra: service
Requires-Dist: agentscope[service,storage-redis]<2.1,>=2.0.7; extra == "service"
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
Requires-Dist: ruff>=0.9; extra == "dev"
Dynamic: license-file

# Agentbase Memory for AgentScope

`agentbase-memory-agentscope` 为 AgentScope 2.x 提供 Agentbase 长期 Memory Middleware。
插件在模型推理前统一召回 Memory、Profile、Skill 和 Experience，在一轮成功结束后把新增的
用户/助手消息提交给 Agentbase 异步抽取；也可以向模型提供按需搜索和显式记忆工具。

插件不代理模型请求，不替换 AgentScope 的会话状态，不把 API Key 或用户身份暴露给模型。

- [使用手册：从安装到跨 Session 验收](docs/user-guide.md)
- [集成设计：生命周期、身份映射与安全边界](docs/agentscope-memory-integration.md)
- [可运行 Demo：安装、自动测试与跨 Session 演示](demo/README.md)

## 安装

发布包：

```bash
python -m pip install agentbase-memory-agentscope
```

仓库开发版本：

```bash
python -m pip install -e ".[dev]"
```

也可以直接使用 Demo 目录中的脚本创建隔离环境并运行全部自动测试：

```bash
./demo/test.sh
```

使用 AgentScope Agent Service 示例时安装 Service 与 Redis Storage 依赖：

```bash
python -m pip install "agentbase-memory-agentscope[service]"
```

## 配置

```bash
export AGENTBASE_MEMORY_ENDPOINT="https://<agentbase-host>"
export AGENTBASE_PROJECT_ID="<project-id>"
export AGENTBASE_API_KEY="<project-api-key>"
```

API Key 至少需要 `memories.read` 和 `memories.write`。项目必须已经启用 Memory；当前服务端
要求 Shared V2 项目。

常用可选项：

| 环境变量 | 默认值 | 说明 |
| --- | --- | --- |
| `AGENTBASE_MEMORY_ENABLED` | `true` | Agent Service Factory 的总开关 |
| `AGENTBASE_MEMORY_MODE` | `both` | `static_control`、`agent_control` 或 `both` |
| `AGENTBASE_MEMORY_SCOPE` | `user` | `user`、`agent` 或 `project`；后两者必须显式配置 |
| `AGENTBASE_MEMORY_ACCESS_MODE` | `owned` | `owned` 或 `accessible` |
| `AGENTBASE_MEMORY_KINDS` | `memory,profile,skill,experience` | 统一召回的内容类型 |
| `AGENTBASE_MEMORY_LIMIT` | `10` | 每次召回最多 1～100 项 |
| `AGENTBASE_MEMORY_TOKEN_BUDGET` | `1200` | 注入上下文的 Token 上限 |
| `AGENTBASE_MEMORY_TOOL_TOKEN_BUDGET` | `2400` | 一次 `search_memory` 调用中所有关键词共享的 Token 上限 |
| `AGENTBASE_MEMORY_TOOL_RESULT_MAX_BYTES` | `12288` | 一次 `search_memory` Tool Result 的 UTF-8 字节硬上限 |
| `AGENTBASE_MEMORY_WRITE_PERMISSION` | `ask` | `add_memory` 权限策略：`ask`、`allow` 或 `deny` |
| `AGENTBASE_MEMORY_TIMEOUT_SECONDS` | `5` | HTTP 超时 |
| `AGENTBASE_MEMORY_VERIFY_TLS` | `true` | 是否校验 Agentbase TLS 证书；生产环境保持开启 |
| `AGENTBASE_MEMORY_FAIL_OPEN` | `true` | Memory 故障时是否继续无 Memory 回复 |
| `AGENTBASE_MEMORY_CAPTURE_INFER` | `true` | 是否由 Agentbase 抽取和去重 |
| `AGENTBASE_MEMORY_CAPTURE_ASYNC` | `true` | 是否使用服务端异步写入 |
| `AGENTBASE_MEMORY_SUB_STORE_ID` | 空 | 可选 Memory 子存储 |
| `AGENTBASE_MEMORY_RESPONSE_FORMAT` | `2.7.0` | Agentbase Memory API 响应格式版本 |

`AGENTBASE_MEMORY_PROJECT_ID`、`AGENTBASE_MEMORY_API_KEY` 可以覆盖通用的 Project / API Key。
凭据只能通过 Secret 或环境变量注入，不要写进代码、Prompt 或 Tool Schema。

## 接入现有 Agent

```python
from agentbase_memory_agentscope import AgentbaseMemoryMiddleware
from agentscope.agent import Agent
from agentscope.tool import Toolkit


memory = AgentbaseMemoryMiddleware(
    user_id=authenticated_user_id,
    agent_id="support-agent",
)

agent = Agent(
    name="support-agent",
    system_prompt="You are a helpful support agent.",
    model=model,
    toolkit=Toolkit(tools=await memory.list_tools()),
    middlewares=[memory],
)
```

`user_id` 必须来自认证上下文，不能使用模型输出。Session 默认从
`agent.state.session_id` 获取。默认 `scope=user`，同一 User 的不同 Agent 共享长期 Memory；需要
按 Agent 隔离时设置 `AGENTBASE_MEMORY_SCOPE=agent`，并传入可信 `agent_id`。应用退出时，如果
Middleware 自己创建了 HTTP Client，应执行：

```python
await memory.aclose()
```

## Agent Service：配置化 Factory

AgentScope Agent Service 会向 Factory 传入可信的 `user_id`、`agent_id` 和 `session_id`：

```python
from agentbase_memory_agentscope import AgentbaseMemoryMiddlewareFactory
from agentscope.app import create_app


memory_factory = AgentbaseMemoryMiddlewareFactory()
app = create_app(
    # storage=...,
    # message_bus=...,
    extra_agent_middlewares=memory_factory,
)
memory_factory.attach_to_app(app)
```

完成一次装配后，租户只需修改环境变量；设置 `AGENTBASE_MEMORY_ENABLED=false` 时 Factory 返回
空 Middleware 列表。

## 三种控制模式

| 模式 | 自动召回 | 自动写回 | Memory 工具 |
| --- | --- | --- | --- |
| `static_control` | 是 | 是 | 无 |
| `agent_control` | 否 | 否 | `search_memory`、`add_memory` |
| `both` | 是 | 是 | 两个工具均有 |

自动召回直接使用 Agentbase `/memory/memories/recall` 返回的、有 Token Budget 的 `context`。
AgentScope 2.0.7 在接收本轮输入后、模型推理前发出 `ReplyStartEvent`；插件在此时把
`HintBlock` 临时插入到本轮 User 消息之前。`HintBlock` 由 AgentScope 的 `AssistantMsg` 容器承载，
但 provider formatter 会把它发送为 `user` role，因此不会形成 Assistant prefill，也不会把不可信
Memory 提升为 system 指令。完成或异常退出后，插件立即按对象身份移除临时消息，避免跨轮累积。

自动写回要求同一 Reply ID 同时出现显式 `ReplyEndEvent(COMPLETED)` 和
`AssistantMsg(finished_reason=COMPLETED)`，中断、超出最大迭代、错误和缺失完成状态都不会写入。
插件使用 User Message ID、User、Agent 和 Session 生成稳定 `Idempotency-Key`；长消息会按
Agentbase API 上限裁剪并在 metadata 中标记。默认等待服务端接受异步任务，而不是启动本地
fire-and-forget Task。

需要用户确认或外部工具执行时，插件把经过长度限制的本轮输入保存在 `AgentState.middle_context`，
并绑定 Reply ID、可信身份和 Memory 配置。应用保存并恢复完整 `AgentState` 后，即使重建 Middleware，
恢复执行仍会重新召回，并在同一回合完成后写回原始用户输入与最终回复。中断会清理待完成回合；
身份或配置不匹配时不会恢复该回合的 Memory 处理。
上下文压缩移除原 User 消息后，恢复注入仍保留末尾的待执行工具状态，支持继续确认或外部执行。

作用域会按 Agentbase 两类 API 的正式语义映射：`user` 召回写入 User Memory，`agent` 召回写入
带 `agentId` 的 Private Memory，`project` 召回写入 Project Memory。`scope=project` 还应配合
`AGENTBASE_MEMORY_ACCESS_MODE=accessible`，并只向可信服务端 API Key 开放。

`search_memory` 和 `add_memory` 的 Tool Schema 不包含用户、Agent、Project、Session 或 API Key。
多个搜索关键词会平分一次工具调用的总 Token Budget，最终 Tool Result 还受 UTF-8 字节硬上限
约束。`add_memory` 的 `thinking` 只用于 Tool Result 审计，不会写入 Memory；默认
`AGENTBASE_MEMORY_WRITE_PERMISSION=ask`，返回不可被普通 allow rule 静默放行的 ASK 决策，防止
Prompt Injection 被固化。AgentScope `DEFAULT` / `ACCEPT_EDITS` 会逐次确认，`DONT_ASK` 会拒绝；
显式 `BYPASS` 仍遵循框架自身“跳过确认”的契约。只有受控、无人值守且上游已经完成内容审核的
场景才应改为 `allow`；`deny` 可彻底关闭模型主动写入，且不影响自动捕获。

## 延迟与故障语义

自动召回位于首个模型调用前，失败时每轮最多会付出配置的 HTTP Timeout；插件当前不内置熔断器。
生产环境应设置较短的 `AGENTBASE_MEMORY_TIMEOUT_SECONDS`，并在网关层使用熔断/退避。自动捕获在
异步 Generator 的收尾阶段内联等待服务端接受请求，因此客户端完整消费流时，流关闭最多会增加
一次写入请求的尾延迟；客户端在最终 Assistant 消息之前提前关闭 Generator 时不会捕获不完整回复。

`AGENTBASE_MEMORY_FAIL_OPEN=true` 同时适用于自动召回、自动捕获、工具搜索和工具写入：故障被转换
为空结果或 Error ToolChunk；`false` 时异常向 AgentScope 调用方传播。取消信号始终传播，不会被
fail-open 吞掉。

严格模式通过 `on_acting` 在 Toolkit 的错误转换边界之外传播 Memory 工具故障，阻止继续生成成功
回复；并发工具故障由 AgentScope 汇总为 `ExceptionGroup`。工具参数校验仍返回可供模型修正的错误结果。

HTTP 2xx 响应中的 `status=failed` / `partial_failed` 也按写入失败处理，遵循相同的 `fail_open`
配置；错误不会回显服务端可能包含原始内容的 `reason`。`queued` 表示服务端已接受异步任务。

## 兼容范围

- Python `>=3.11`
- AgentScope `>=2.0.7,<2.1`
- Agentbase Memory response format `2.7.0`

完整生命周期、故障降级、身份映射和验收矩阵见
[集成设计](docs/agentscope-memory-integration.md)。

## 可运行 Demo

`demo/` 提供依赖安装、自动测试和真实跨 Session Memory 验收入口。准备好 Agentbase 与
DashScope 凭据后执行：

```bash
cd demo
cp .env.example .env
# 编辑 .env 后运行；首次执行会自动安装依赖
./run.sh
```

完整步骤和验收条件见 [Demo README](demo/README.md)。
