Skip to content
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
96d46b6
feat(stage-tamagotchi,plugin-sdk,openviking-memory): add PluginHost c…
xiaobin83 May 15, 2026
4b8caa5
feat(plugin-sdk): propagate ModuleConfigEnvelope through PluginStartO…
xiaobin83 May 24, 2026
88d22d6
fix(stage-tamagotchi): reset conversationSessionId on chat cleanup
xiaobin83 May 24, 2026
0a5f7a4
fix(stage-tamagotchi): guard plugin IPC calls and derive session ID f…
xiaobin83 May 25, 2026
677ea42
fix(stage-tamagotchi): revoke old asset sessions and clear loaded sta…
xiaobin83 May 25, 2026
d41bd8b
feat(stage-tamagotchi): gate memory persistence to plugins that suppo…
xiaobin83 May 25, 2026
3000fe3
refactor(stage-tamagotchi): remove queryContext Eventa layer, use dir…
xiaobin83 May 25, 2026
6bd83ad
fix(stage-tamagotchi): bound memory-context lookup latency before com…
xiaobin83 May 25, 2026
1784a74
feat(host): enforce manifest schema validation in setPluginConfig
xiaobin-tal May 26, 2026
73d921a
fix(stage-tamagotchi): separate reload error handling from post-reloa…
xiaobin-tal May 26, 2026
9f3014b
fix(stage-tamagotchi): capture session metadata synchronously in onCh…
xiaobin-tal May 26, 2026
d0e1a79
refactor(stage-tamagotchi): use TypeError for config field type valid…
xiaobin83 May 26, 2026
f5faa70
fix(stage-tamagotchi): reject empty values for required secret fields…
xiaobin83 May 26, 2026
e084725
fix: propagate sessionId and generation through stream event context
xiaobin83 May 26, 2026
923dd1b
fix(stage-tamagotchi): preserve unsaved edits and reject invalid numb…
xiaobin83 May 26, 2026
406873b
fix(stage-ui): prefer snapshot generation in applyRemoteSnapshot
xiaobin83 May 26, 2026
10175ca
chore: remove completed planning document
xiaobin83 May 26, 2026
e830097
feat(openviking-memory): refactor saveConversation to add-accumulate-…
xiaobin83 May 27, 2026
9f64ace
feat(openviking-memory): add memory_recall tool, rename memory_save_t…
xiaobin83 May 27, 2026
2a24491
feat(openviking-memory): implement rankForInjection memory ranking st…
xiaobin83 May 27, 2026
1d66eac
docs(openviking-memory): remove outdated openclaw plugin implementati…
xiaobin83 May 27, 2026
aac374a
fix: clear stale plugin memory context on empty recall
xiaobin-tal May 28, 2026
799abee
fix(stage-tamagotchi): roll back plugin config on reload failure and …
xiaobin83 May 28, 2026
8962d1a
fix(stage-tamagotchi): merge manifest config schema defaults into plu…
xiaobin83 May 28, 2026
985e71d
fix(stage-tamagotchi): clear stale plugin memory context when no memo…
xiaobin83 May 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# OpenViking 长期记忆插件

基于 [OpenViking](https://openviking.ai) 的长期记忆系统插件,为 AIRI 提供记忆搜索、保存和删除功能。

## 功能

### 工具列表

- **搜索记忆**(`memory_search`):根据查询关键词搜索长期记忆。返回结果格式如下:

```json
[
{
"context_type": "memory",
"uri": "viking://user/default/memories/manual/1779530859829-dly184hl.md",
"level": 2,
"score": 0.6159865260124207,
"category": "",
"match_reason": "",
"relations": [],
"abstract": "1. 该文档是一份个人日程计划笔记...",
"overview": null
},
{
"context_type": "memory",
"uri": "viking://user/default/memories/manual/1779384773203-r0jq33bf.md",
"level": 2,
"score": 0.6076329350471497,
"category": "",
"match_reason": "",
"relations": [],
"abstract": "This document is a concise personal travel plan...",
"overview": null
}
]
```

每个结果字段说明:

| 字段 | 类型 | 说明 |
|------|------|------|
| `context_type` | `string` | 上下文类型,固定为 `memory` |
| `uri` | `string` | 记忆文件的 URI,可用于 `memory_read` 工具读取完整内容 |
| `level` | `number` | 层级(0-3),数字越大表示越相关 |
| `score` | `number` | 相关性评分(0-1),越高越匹配 |
| `category` | `string` | 分类标签 |
| `match_reason` | `string` | 匹配原因说明 |
| `relations` | `array` | 关联的其它记忆 URI 列表 |
| `abstract` | `string` | 记忆内容的摘要/概述 |
| `overview` | `string \| null` | 概览信息 |

- **读取记忆**(`memory_read`):根据 URI 读取一条记忆的完整内容
- **保存记忆**(`memory_save`):将重要信息保存到长期记忆
- **保存对话记录**(`memory_save_turn`):将一轮对话(用户消息 + 助手回复 + 工具调用)保存到长期记忆。此工具由系统自动触发,AI 助手不应主动调用。
- **召回记忆**(`memory_recall`):自动召回与当前对话相关的长期记忆,用于上下文注入。此工具由系统自动触发,AI 助手不应主动调用。
- **删除记忆**(`memory_delete`):删除指定的记忆条目

> `memory_recall` 和 `memory_save_turn` 为系统级工具,由框架在对话处理流程中自动调用,用于上下文注入和对话持久化。AI 助手不会在工具选择列表中看到它们,开发者也不应手动调用。

### Session 记忆处理

对话通过 `memory_save_turn` 保存到 Session 后,系统会按以下规则决定是否将对话内容转化为可检索的记忆:

- **短对话**(累计 pending tokens < 20,000):仅保存到 Session,不参与记忆搜索
- **长对话**(累计 pending tokens ≥ 20,000):自动提交并做 embedding 处理,之后可通过记忆注入(`memory_recall`)或 Agent 主动搜索(`memory_search`)找到

例如,一个持续数小时的长对话(如聊了一整晚)达到阈值后会被 embedding,后续用户提问时系统会自动召回相关记忆片段作为上下文注入。

## 安装

### 前提条件

- AIRI Stage Tamagotchi(Electron 桌面应用)
- OpenViking 服务(默认地址:`http://localhost:1933`)

### 安装步骤

1. **构建插件**

在插件目录下执行:

```bash
cd apps/stage-tamagotchi/src/main/services/airi/plugins/examples/openviking-memory
pnpm install
pnpm run pack
```

构建完成后会在当前目录生成 `openviking-memory.tar.gz` 打包文件。

2. **将插件复制到插件目录**

根据运行环境,将打包文件解压后的 `openviking-memory/` 目录复制到对应的插件目录。

**生产环境**(打包后的应用):

| 操作系统 | 插件目录 |
|----------|----------|
| **macOS** | `~/Library/Application Support/${appId}/plugins/v1/` |
| **Windows** | `%APPDATA%\\${appId}\\plugins\\v1\\` |
| **Linux** | `$XDG_CONFIG_HOME/${appId}/plugins/v1/` 或 `~/.config/${appId}/plugins/v1/` |

> `${appId}` 为 AIRI 应用的标识符(默认 `ai.moeru.airi`),具体值请参考应用配置。

**开发环境**(`pnpm dev`):

当使用 `electron-vite dev` 运行时,Electron 使用包名作为用户数据目录,插件目录为:

| 操作系统 | 插件目录 |
|----------|----------|
| **macOS** | `~/Library/Application Support/@proj-airi/stage-tamagotchi/plugins/v1/` |
| **Windows** | `%APPDATA%\\@proj-airi\\stage-tamagotchi\\plugins\\v1\\` |
| **Linux** | `~/.config/@proj-airi/stage-tamagotchi/plugins/v1/` |

3. **在插件管理器中启用**

- 打开 Stage Tamagotchi 的开发者工具页面(DevTools)
- 进入 **Plugin Host Inspector** 页面
- 点击 **Refresh** 刷新插件列表
- 找到 `openviking-memory` 插件
- 点击 **Enable** 启用
- 点击 **Load**(或 **Load Enabled**)加载插件

4. **配置插件**

插件加载后,在插件配置页面设置以下参数:

- **服务器地址**(`baseUrl`):OpenViking 服务的 base URL,默认为 `http://localhost:1933`
- **API 密钥**(`apiKey`):OpenViking 服务的 API 密钥(可选)

### 验证安装

加载成功后,AIRI 将获得以下工具能力:

- `memory_search` — 搜索长期记忆(Agent 主动调用)
- `memory_read` — 根据 URI 读取记忆完整内容(Agent 主动调用)
- `memory_save` — 保存记忆(Agent 主动调用)
- `memory_save_turn` — 保存对话记录(系统自动触发)
- `memory_recall` — 召回记忆(系统自动触发)
- `memory_delete` — 删除记忆(Agent 主动调用)

## 开发

### 目录结构

```
openviking-memory/
├── src/
│ ├── index.ts # 插件入口,注册工具
│ └── openviking.ts # OpenViking 客户端实现
├── scripts/
│ └── pack.mjs # 打包脚本
├── dist/
│ └── index.mjs # 编译后的插件入口(仅构建产物)
├── docs/
│ ├── Readme.zh-CN.md # 本文件
│ └── openclaw-plugin-implementation-analysis.md
├── plugin.airi.json # 插件清单(entrypoint: ./index.mjs)
├── tsdown.config.ts # 构建配置
└── package.json # 依赖与构建脚本
```

### 构建

```bash
pnpm run build # 使用 tsdown 编译 TypeScript
pnpm run pack # 构建并打包为 tar.gz
```

## 配置说明

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `baseUrl` | `string` | 是 | `http://localhost:1933` | OpenViking 服务器地址 |
| `apiKey` | `secret` | 否 | `""` | API 密钥 |

## 许可

此插件为 AIRI 示例插件,仅供学习和参考使用。
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "openviking-memory",
"type": "module",
"version": "1.0.0",
"private": true,
"description": "OpenViking 长期记忆插件",
"scripts": {
"build": "tsdown",
"dev": "pnpm run build",
"pack": "pnpm run build && cp plugin.airi.json dist/openviking-memory/ && tar -czf dist/openviking-memory.tar.gz -C dist openviking-memory"
},
"dependencies": {
"@proj-airi/plugin-protocol": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"apiVersion": "v1",
"kind": "manifest.plugin.airi.moeru.ai",
"name": "openviking-memory",
"displayName": "OpenViking 长期记忆",
"description": "基于 OpenViking 的长期记忆系统,提供记忆搜索、保存和删除功能",
"version": "0.1.0",
"permissions": {
"apis": [
{
"key": "proj-airi:plugin-sdk:apis:client:tools:register",
"actions": ["invoke"]
}
],
"resources": [
{
"key": "proj-airi:plugin-sdk:resources:tools",
"actions": ["write"]
}
]
},
"config": {
"schema": {
"baseUrl": {
"type": "string",
"label": "OPENVIKING_BASE_URL",
"default": "http://localhost:1933",
"required": true
},
"apiKey": {
"type": "secret",
"label": "OPENVIKING_API_KEY",
"default": "",
"required": false
}
}
},
"entrypoints": {
"electron": "./index.mjs"
}
}
Loading