Bundle
only-memory
DeepSeek Harness 记忆插件 - 零外部依赖的 LLM 长期记忆系统
- Source
- wilburli
- stars
- 2 stars
- License
- MIT
- Updated
- Updated 11 days ago
Readme
# OnlyMemory GitHub topic dsh-plugin
零外部依赖的 LLM 长期记忆插件,专为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 设计。
---
效果图

记忆管理界面

## 目录
- [特性](#特性)
- [从零安装(新人必看)](#从零安装新人必看)
- [快速开始](#快速开始)
- [架构概览](#架构概览)
- [模块详解](#模块详解)
- [配置参考](#配置参考)
- [MCP 工具清单](#mcp-工具清单)
- [Web 管理界面](#web-管理界面)
- [Embedding 配置](#embedding-配置)
- [二次开发指南](#二次开发指南)
- [数据存储结构](#数据存储结构)
- [常见问题](#常见问题)
---
## 特性
- **零外部依赖** — 不需要向量数据库、Redis、PostgreSQL 等外部服务
- **SQLite + 纯 JS 向量检索** — sql.js(WASM)实现,单文件存储
- **Web 管理界面** — 浏览器中查看、编辑、置顶、删除记忆
- **多项目隔离** — 不同项目记忆完全独立
- **MCP 标准协议** — 通过 `@deepseek-ai/dsh-mcp-client` 与 Harness 无缝集成
- **模块化设计** — 每个子模块可独立替换和扩展
- **导入导出** — JSON 格式,支持跨机器迁移
---
## 从零安装(新人必看)
以下流程假设你刚拿到一份源码,手把手带你走完从下载到运行的全过程。
### 第 1 步:环境准备
确保你的机器上已安装:
| 工具 | 版本要求 | 检查命令 |
|------|----------|----------|
| Node.js | >= 18 | `node -v` |
| pnpm | >= 8 | `pnpm -v` |
| DeepSeek Harness | 最新版 | 参考 [Harness 安装文档](https://deepseek-harness.github.io/deepseek-harness/develop/basic/) |
> Harness 是 DeepSeek 的 Agent 运行时,OnlyMemory 作为插件运行在它之上。
> 如果你还没有安装 Harness,请先完成 Harness 的安装再继续。
### 第 2 步:获取源码
```bash
# 方式一:Git 克隆
git clone <仓库地址>
cd onlyMemory-plugin
# 方式二:直接下载 ZIP 并解压
cd onlyMemory-plugin
```
### 第 3 步:安装依赖 + 编译
```bash
npm install # 安装 sql.js、@modelcontextprotocol/sdk 等依赖
npm run build # 编译 TypeScript → dist/
```
编译成功后会看到 `dist/` 目录下生成 `.js` + `.d.ts` 文件。
### 第 4 步:验证编译结果
```bash
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | node bin/only-memory.mjs
```
如果看到如下 JSON 响应,说明编译成功:
```json
{"result":{"serverInfo":{"name":"only-memory","version":"0.1.0"},...},"jsonrpc":"2.0","id":1}
```
### 第 5 步:安装到 Harness
```bash
# 进入 Harness 安装目录
cd /path/to/deepseek-harness
# 安装插件到 web profile
dsh plugin --profile web add /path/to/onlyMemory-plugin
```
> **报 `ERR_PNPM_ADDING_TO_ROOT`?**
> 这是因为 pnpm 的 workspace 保护机制,需要在 profile 目录创建 `.npmrc` 解除限制:
>
> **Windows (PowerShell):**
> ```powershell
> echo "ignore-workspace-root-check=true" > $env:USERPROFILE\.dsh\profiles\web\.npmrc
> ```
>
> **macOS / Linux:**
> ```bash
> echo "ignore-workspace-root-check=true" > ~/.dsh/profiles/web/.npmrc
> ```
>
> 然后重新执行 `dsh plugin --profile web add` 命令。
### 第 6 步:启动 Harness
```bash
dsh web
```
> 如果报 `EADDRINUSE`(端口被占用),换一个端口:
> ```bash
> dsh web --port 3081
> ```
>
> 启动成功后浏览器会自动打开 Harness Web UI(默认 http://127.0.0.1:3080)。
### 第 7 步:验证插件生效
在 Harness 对话中输入:
```
请记住我的验证代号是 lapsang-42
```
然后**开一个新会话**,问:
```
我的验证代号是什么?查一下记忆
```
如果模型调用了 `mcp__only_memory__search` 并返回 `lapsang-42`,说明插件安装成功!
### 第 8 步:验证安装状态(可选)
```bash
# 查看配置树,确认 only-memory 在 bundle 列表中
dsh --profile web --dump-config
```
在输出中搜索 `only_memory`,应该能看到 MCP 客户端配置。
### 卸载
```bash
dsh plugin --profile web remove only-memory
```
---
## 快速开始
### 安装到 Harness
```bash
# 方式一:dsh plugin add(推荐,永久生效)
dsh plugin --profile web add ./path/to/onlyMemory-plugin
# 方式二:--patch(临时使用)
dsh web --patch ./path/to/onlyMemory-plugin/cordis-patch.yml
# 卸载
dsh plugin --profile web remove only-memory
```
> **首次安装报 `ERR_PNPM_ADDING_TO_ROOT`?** 在 profile 目录创建 `.npmrc`:
> ```powershell
> echo "ignore-workspace-root-check=true" > $env:USERPROFILE\.dsh\profiles\web\.npmrc
> ```
### 本地开发
```bash
npm install # 安装依赖
npm run build # 编译 TypeScript → dist/
npm run test # 运行测试
npm run dev # watch 模式编译
```
### 独立使用(不依赖 Harness)
```typescript
import { MemoryEngine } from './dist/engine.js';
const engine = new MemoryEngine({ projectId: 'my-app' });
await engine.init();
// 存储
await engine.remember('用户名叫张三,在北京工作', 0.9);
// 检索
const results = await engine.search('用户在哪里工作?');
// 对话集成
const context = await engine.onUserMessage('你好,还记得我吗?');
await engine.onAssistantMessage('当然记得,你是张三,在北京工作。');
// 会话结束触发自动维护(衰减、去重、清理)
await engine.endSession('session-001');
engine.close();
```
---
## 架构概览
```
Harness (dsh web)
└── @deepseek-ai/dsh-mcp-client ──stdio──▶ node bin/only-memory.mjs
│
┌─────┴─────┐
│ MemoryEngine │ src/engine.ts
└─────┬─────┘
┌───────────┬───────────┬───────┼───────┬───────────┐
▼ ▼ ▼ ▼ ▼ ▼
┌──────────┐ ┌────────┐ ┌────────┐ ┌──────┐ ┌──────┐ ┌──────────┐
│ SqliteStore│ │Vector │ │Session │ │Scorer│ │Retrie│ │Maintenance│
│ (sql.js) │ │ Store │ │ Store │ │ │ │ ver │ │ (3个) │
└──────────┘ └────────┘ └────────┘ └──────┘ └──────┘ └──────────┘
storage/ storage/ storage/ scorer/ retriever/ maintenance/
```
### 数据流
```
用户消息 ──▶ onUserMessage()
├── EntityExtractor.extract() 提取实体
├── MultiRecallRetriever.retrieve() 多路召回
└── 返回相关记忆上下文
助手消息 ──▶ onAssistantMessage()
├── ImportanceScorer.score() 计算重要性
├── SqliteStore.insertMemory() 持久化
└── LocalVectorStore.add() 向量索引
会话结束 ──▶ endSession()
├── DecayManager.applyDecay() 时间衰减
├── MemoryMerger.merge() 去重合并
└── MemoryCleaner.clean() 低分清理
```
---
## 模块详解
### `src/models.ts` — 数据模型
| 导出 | 说明 |
|------|------|
| `enum MemoryType` | `Fact` / `Preference` / `Event` / `Behavior` |
| `enum MemoryStatus` | `Active` / `Archived` / `Deleted` |
| `enum RelationType` | `Contradicts` / `Supports` / `Updates` / `Relates` |
| `interface Memory` | 记忆条目(id, content, type, entities, importance, embedding, status...) |
| `interface SessionSummary` | 会话摘要 |
| `interface RetrievalResult` | 检索结果(memory + score + channels) |
| `interface CreateMemoryInput` | 创建记忆参数 |
| `generateId()` | 生成 UUID |
| `createMemory()` | 创建新 Memory 对象 |
### `src/config.ts` — 配置管理
```typescript
interface MemoryPluginConfig {
projectId: string; // 项目标识,默认 'default'
dataDir: string; // 数据根目录,默认 ~/.deepseek_mem
dbName: string; // 数据库文件名,默认 'memory.db'
topK: number; // 检索返回条数,默认 5
importanceThreshold: number; // 重要性过滤阈值,默认 0.3
halfLifeDays: number; // 衰减半衰期(天),默认 30
embeddingBackend: 'none' | 'openai' | 'dashscope' | 'local';
embeddingModel: string; // Embedding 模型名
embeddingDim: number; // 向量维度,默认 1536
summarizerBackend: 'none' | 'openai' | 'dashscope' | 'deepseek';
}
```
辅助函数:`resolveConfig()` / `getProjectDir()` / `getDbPath()` / `getSessionDir()` / `ensureDirs()`
### `src/engine.ts` — 核心引擎
`MemoryEngine` 是整合所有子模块的主类:
| 方法 | 签名 | 说明 |
|------|------|------|
| `constructor` | `(config?: Partial<MemoryPluginConfig>)` | 创建引擎实例 |
| `init()` | `async (): Promise<void>` | 异步初始化(加载 WASM、数据库、向量) |
| `remember()` | `(content: string, importance?: number): Promise<Memory>` | 显式存储一条记忆 |
| `forget()` | `(query: string): Promise<number>` | 按关键词删除记忆,返回删除数 |
| `search()` | `(query: string): RetrievalResult[]` | 搜索记忆 |
| `getMemory()` | `(id: string): Memory \| null` | 获取单条记忆详情 |
| `updateMemory()` | `(id, updates): boolean` | 编辑记忆内容/重要度/类型 |
| `pinMemory()` | `(id: string): boolean` | 置顶记忆(防止衰减和清理) |
| `unpinMemory()` | `(id: string): boolean` | 取消置顶 |
| `getAllMemories()` | `(): Memory[]` | 获取所有活跃记忆 |
| `getStats()` | `(): object` | 获取统计信息 |
| `onUserMessage()` | `(text: string): Promise<string>` | 处理用户消息,返回相关记忆上下文 |
| `onAssistantMessage()` | `(text: string): Promise<void>` | 处理助手消息,提取并存储信息 |
| `startSession()` | `(sessionId: string): void` | 开始会话 |
| `endSession()` | `(sessionId: string): Promise<void>` | 结束会话,触发维护 |
| `exportToFile()` | `(filePath: string): Promise<void>` | 导出为 JSON |
| `importFromFile()` | `(filePath: string): Promise<number>` | 从 JSON 导入 |
| `close()` | `(): void` | 关闭引擎 |
### `src/storage/sqlite-store.ts` — SQLite 存储
基于 sql.js(纯 JS/WASM),内存操作 + 延迟批量写盘:
| 方法 | 说明 |
|------|------|
| `init()` | 异步初始化,加载 WASM 并打开/创建数据库 |
| `insertMemory(memory)` | 插入记忆 |
| `getMemory(id)` | 按 ID 获取 |
| `updateImportance(id, score)` | 更新重要性 |
| `incrementAccessCount(id)` | 增加访问计数 |
| `archiveMemory(id)` / `deleteMemory(id)` | 归档/删除 |
| `getAllActive()` / `getActiveCount()` | 查询活跃记忆 |
| `ftsSearch(query, limit)` | LIKE 全文搜索 |
| `entitySearch(entities, limit)` | 实体匹配搜索 |
| `getLowImportanceMemories(threshold)` | 获取低分记忆 |
| `saveSessionLog(session)` | 保存会话日志 |
| `exportAll()` | 导出全部记忆为 JSON |
| `flush()` | 强制写盘 |
| `close()` | 关闭数据库 |
> WASM 路径通过环境变量 `SQL_JS_WASM_PATH` 指定,支持自定义安装位置。
### `src/storage/vector-store.ts` — 向量检索
纯 JS 内存向量存储,余弦相似度计算:
```typescript
cosineSimilarity(a: Float32Array, b: Float32Array): number
class LocalVectorStore {
load(entries: VectorEntry[]): void
add(id: string, embedding: Float32Array): void
remove(id: string): void
search(query: Float32Array, topK: number): { id: string; score: number }[]
clear(): void
get size(): number
}
```
### `src/storage/session-store.ts` — 会话存储
JSON 文件存储会话摘要:`save()` / `load()` / `list()`
### `src/encoder/entity-extractor.ts` — 实体抽取
正则匹配,支持:中文人名、英文专有名词、技术名词、邮箱地址。
```typescript
class EntityExtractor {
extract(text: string): string[]
}
```
### `src/scorer/importance.ts` — 重要性评分
6 因子加权评分(总分 0~1):
| 因子 | 权重 | 说明 |
|------|------|------|
| `explicit` | 0.30 | 显式指令("请记住"、"important") |
| `novelty` | 0.20 | 新颖性(基于文本长度代理) |
| `emotion` | 0.10 | 情感强度(感叹号、情感词) |
| `entity` | 0.15 | 实体密度 |
| `behavior` | 0.15 | 行为信息(偏好、习惯) |
| `timeliness` | 0.10 | 时效性(含日期信息) |
```typescript
interface ScoreResult { score: number; factors: Record<string, number> }
class ImportanceScorer {
constructor(extractor: EntityExtractor)
score(text: string, type: MemoryType): ScoreResult
}
```
### `src/retriever/multi-recall.ts` — 多路召回
4 路召回 + 加权融合排序:
| 召回通道 | 权重 | 实现 |
|----------|------|------|
| FTS 全文 | 0.20 | SQLite LIKE 查询 |
| 实体匹配 | 0.15 | 正则提取实体交叉匹配 |
| 重要度 | 0.10 | importance 字段排序 |
| 时效性 | 0.05 | 创建时间排序 |
> 语义向量召回在 `embeddingBackend` 配置后自动启用(额外权重 0.50)。
```typescript
class MultiRecallRetriever {
retrieve(query: string, limit: number): Promise<RetrievalResult[]>
retrieveContextText(query: string, limit?: number): Promise<string>
}
```
### `src/maintenance/` — 维护子系统
| 模块 | 类 | 核心方法 | 说明 |
|------|-----|----------|------|
| `decay.ts` | `DecayManager` | `decayedScore(score, createdAt)` / `applyDecay(store)` | 指数衰减,半衰期可配,跳过置顶记忆 |
| `merger.ts` | `MemoryMerger` | `merge(store)` | bigram Jaccard 相似度去重合并 |
| `cleaner.ts` | `MemoryCleaner` | `clean(store)` | 清理低于阈值的记忆,跳过置顶记忆 |
### `src/web-server.ts` — Web 管理界面
内置 HTTP 服务器,提供 REST API 和静态前端页面:
```typescript
class WebServer {
constructor(options: { engine: MemoryEngine; port?: number; host?: string })
start(): Promise<void>
stop(): Promise<void>
getUrl(): string
}
```
与 MCP stdio 服务器共享同一个 MemoryEngine 实例,无额外数据库连接开销。
前端页面位于 `web/index.html`,零外部依赖,纯 HTML/CSS/JS 实现。
---
## 配置参考
### 环境变量
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `ONLYMEM_PROJECT` | `default` | 项目标识 |
| `ONLYMEM_DATA_DIR` | `~/.onlymem` | 数据存储目录 |
| `ONLYMEM_WEB_PORT` | `3456` | Web 管理界面端口(0 = 禁用) |
| `OPENAI_API_KEY` | 无 | OpenAI API 密钥(embeddingBackend=openai 时需要) |
| `OPENAI_BASE_URL` | 无 | 自定义 OpenAI API 地址(可选) |
| `DASHSCOPE_API_KEY` | 无 | 阿里云 DashScope API 密钥(embeddingBackend=dashscope 时需要) |
| `SQL_JS_WASM_PATH` | 自动探测 | sql.js WASM 文件路径 |
### Harness patch 配置
通过 profile 的 `cordis.patch.yml` 覆盖:
```yaml
- set:
id: memory-onlymemory
config:
serverName: only_memory
env:
ONLYMEM_PROJECT: my-project
ONLYMEM_DATA_DIR: /custom/data/path
```
---
## MCP 工具清单
安装后 Harness 自动发现 11 个工具(前缀 `mcp__only_memory__`):
| 工具 | 参数 | 说明 |
|------|------|------|
| `remember` | `content: string`, `importance?: number` | 记住一条信息 |
| `search` | `query: string`, `limit?: number` | 搜索记忆 |
| `get_memory` | `id: string` | 查看单条记忆详情(含 ID、类型、重要度、置顶状态) |
| `update_memory` | `id`, `content?`, `importance?`, `type?` | 编辑记忆内容/重要度/类型 |
| `pin_memory` | `id: string` | 置顶记忆(防止衰减和自动清理) |
| `unpin_memory` | `id: string` | 取消置顶 |
| `list_memories` | `limit?: number` | 列出所有记忆(📌 表示置顶) |
| `forget` | `query: string` | 按关键词遗忘 |
| `stats` | 无 | 记忆库统计 |
| `export_memories` | `path: string` | 导出到 JSON 文件 |
| `import_memories` | `path: string` | 从 JSON 导入 |
---
## Web 管理界面
启动 Harness 后,Web 管理界面自动在 `http://127.0.0.1:3456` 开启。你可以在浏览器中:
- **查看所有记忆** — 卡片式布局,显示类型、重要度、访问次数
- **搜索和过滤** — 关键词搜索 + 按类型/置顶状态筛选
- **新建记忆** — 手动添加记忆条目
- **编辑记忆** — 修改内容、重要度、类型
- **置顶/取消置顶** — 重要记忆防止衰减和自动清理
- **删除记忆** — 删除不再需要的记忆
### 配置端口
```bash
# 自定义端口
dsh web --env ONLYMEM_WEB_PORT=8080
# 禁用 Web 界面
dsh web --env ONLYMEM_WEB_PORT=0
```
### REST API
Web 服务器同时暴露 REST API,方便二次开发集成:
| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/api/memories?limit=&type=&search=` | 查询记忆列表 |
| `GET` | `/api/memories/:id` | 查看单条记忆 |
| `GET` | `/api/stats` | 统计信息 |
| `POST` | `/api/memories` | 创建记忆 `{content, importance}` |
| `POST` | `/api/memories/:id` | 更新记忆 `{content?, importance?, type?}` |
| `POST` | `/api/pin/:id` | 置顶 |
| `POST` | `/api/unpin/:id` | 取消置顶 |
| `POST` | `/api/delete/:id` | 删除 |
| `POST` | `/api/forget` | 按关键词删除 `{query}` |
---
## Embedding 配置
默认使用**关键词检索**(`embeddingBackend: 'none'`),无需任何额外依赖。
如需语义检索能力,可切换为以下三种后端之一:
| 后端 | 配置值 | 依赖 | 适用场景 |
|------|---------|------|----------|
| 关键词检索 | `none`(默认) | 无 | 轻量、零配置、离线 |
| OpenAI API | `openai` | 无(需 API Key) | 高质量、联网 |
| 阿里云 DashScope | `dashscope` | 无(需 API Key) | 中文优化、国内网络 |
| 本地 WASM 模型 | `local` | `@xenova/transformers` | 离线、免费、无网络 |
### 方案 A:云端 API(最简单)
只需配置 API Key 环境变量,无需安装任何东西:
```bash
# OpenAI
export OPENAI_API_KEY="sk-xxx"
# 或阿里云 DashScope(中文效果更好)
export DASHSCOPE_API_KEY="sk-xxx"
```
然后在 Harness patch 配置中启用:
```yaml
- set:
id: memory-onlymemory
config:
env:
ONLYMEM_PROJECT: default
OPENAI_API_KEY: sk-xxx # 或 DASHSCOPE_API_KEY
```
> **自定义 API 地址?** 设置 `OPENAI_BASE_URL` 环境变量,可兼容任何 OpenAI 兼容接口(如 Ollama、LM Studio)。
### 方案 B:本地 WASM 模型(推荐离线场景)
使用 `@xenova/transformers` 在浏览器/Node.js 中运行模型,完全离线:
```bash
# 安装可选依赖
cd onlyMemory-plugin
npm install @xenova/transformers
# 首次运行时自动下载模型(~47MB,缓存在 ~/.cache)
```
然后在 patch 配置中启用:
```yaml
- set:
id: memory-onlymemory
config:
env:
ONLYMEM_PROJECT: default
```
并在 `cordis.patch.yml` 中设置 `embeddingBackend: local`:
```yaml
- set:
id: memory-onlymemory
config:
embeddingBackend: local
embeddingModel: paraphrase-multilingual-MiniLM-L12-v2
embeddingDim: 384
```
### 降级机制
如果配置了 embedding 后端但初始化失败(缺少 API Key、模型下载失败等),插件会**自动降级为关键词检索**,不会崩溃。
### 语义检索权重
启用 embedding 后,多路召回的权重分配:
| 召回通道 | 无 embedding 时 | 有 embedding 时 |
|----------|--------------|---------------|
| 语义向量 | — | 0.50 |
| FTS 全文 | 0.35 | 0.20 |
| 实体匹配 | 0.15 | 0.15 |
| 重要度 | 0.10 | 0.10 |
| 时效性 | 0.05 | 0.05 |
---
## 二次开发指南
### 添加新的召回通道
在 `src/retriever/multi-recall.ts` 中扩展:
```typescript
// 1. 添加新的召回方法
private async recallKnowledgeGraph(query: string, limit: number): Promise<RetrievalResult[]> {
// 你的召回逻辑
}
// 2. 在 retrieve() 中注册新通道
const channels = [
// ...existing
{ name: 'knowledge_graph', weight: 0.15, fn: this.recallKnowledgeGraph.bind(this) },
];
```
### 替换 Embedding 后端
在 `src/storage/vector-store.ts` 中添加适配器:
```typescript
// 当前 MVP 使用纯文本匹配,接入 Embedding 后:
async function getEmbedding(text: string): Promise<Float32Array> {
// 调用 OpenAI / DashScope / 本地模型 API
}
```
在 `engine.ts` 的 `onAssistantMessage()` 中调用:
```typescript
const embedding = await getEmbedding(text);
this.vectorStore.add(memory.id, embedding);
```
### 自定义评分因子
在 `src/scorer/importance.ts` 中:
```typescript
// 添加新因子
private scoreSocialSignal(text: string): number {
// 检测 @提及、引用等社交信号
}
// 在 score() 中注册并设置权重
factors.social = this.scoreSocialSignal(text);
weights.social = 0.10; // 调整其他权重使总和 = 1.0
```
### 添加新的存储后端
实现与 `SqliteStore` 相同的接口即可替换:
```typescript
// src/storage/pg-store.ts
export class PostgresStore {
async init(): Promise<void> { /* 连接 PostgreSQL */ }
async insertMemory(memory: Memory): Promise<void> { /* ... */ }
// ... 实现 SqliteStore 的所有公开方法
}
// 在 engine.ts 的 init() 中替换
this.store = new PostgresStore(connectionString);
```
### 添加新的 MCP 工具
在 `src/mcp-server.ts` 中注册:
```typescript
import { z } from 'zod';
server.tool(
'tag_memory', // 工具名
'Add tags to a memory entry', // 描述(模型据此决定调用)
{ id: z.string(), tags: z.array(z.string()) }, // zod schema
async ({ id, tags }) => {
// 实现逻辑
return { content: [{ type: 'text', text: `Tagged ${id}` }] };
}
);
```
### 添加 Cordis 事件钩子
在 `src/index.ts` 的 `apply()` 中:
```typescript
ctx.on('before-message', async (session, message) => {
// 消息到达前的处理
});
ctx.on('after-message', async (session, message) => {
// 消息处理后的钩子
});
```
### 编写测试
参考 `tests/test.ts`:
```typescript
import { MemoryEngine } from '../src/engine.js';
const engine = new MemoryEngine({ dataDir: '/tmp/test-mem' });
await engine.init();
// 测试存储
const mem = await engine.remember('测试内容', 0.8);
console.assert(mem.content === '测试内容');
// 测试搜索
const results = await engine.search('测试');
console.assert(results.length > 0);
engine.close();
```
---
## 数据存储结构
```
~/.onlymem/
default/ ← 默认项目
memory.db ← SQLite 数据库
sessions/ ← 会话摘要 (JSON)
2026-08-25-session-001.json
my-project/ ← 自定义项目
memory.db
sessions/
```
### SQLite 表结构
| 表 | 字段 | 说明 |
|----|------|------|
| `memories` | `id TEXT PK` | 记忆条目 |
| | `content TEXT` | 记忆内容 |
| | `type TEXT` | fact/preference/event/behavior |
| | `entities TEXT` | JSON 数组,提取的实体 |
| | `importance REAL` | 重要性分数 0~1 |
| | `embedding BLOB` | Float32Array 向量 |
| | `status TEXT` | active/archived/deleted |
| | `pinned INTEGER` | 0=普通, 1=置顶(防衰减和清理) |
| | `access_count INTEGER` | 访问计数 |
| | `created_at TEXT` | 创建时间 |
| `memory_relations` | `from_id`, `to_id`, `relation_type` | 记忆间关系 |
| `session_logs` | `session_id PK`, `summary`, `memory_count` | 会话日志 |
---
## 常见问题
| 问题 | 原因 | 解决 |
|------|------|------|
| `ERR_PNPM_ADDING_TO_ROOT` | pnpm workspace 拒绝向 root 添加依赖 | 创建 `.npmrc` 加 `ignore-workspace-root-check=true` |
| `__dirname is not defined` | Harness `!!js` 上下文无此变量 | 已修复,使用 `process.getBuiltinModule` 动态定位 |
| `EADDRINUSE 3080` | 端口被占用 | `dsh web --port 3081` |
| `memory-onlymemory` 未出现在配置中 | 插件未正确安装 | 重新执行 `dsh plugin --profile web add /path/to/onlyMemory-plugin` |
| 记忆为空 | 未触发存储 | 需先进行对话让模型调用 `remember` 工具 |
---
## License
MIT
Install
dsh plugin --profile web add github:wilburli/onlyMemory-plugin#c775a722823a9aed3368d42e4539f7ecd4d19949
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install only-memory from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.