@dsh-overdrive/gateway 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands.d.ts +14 -0
- package/dist/commands.js +26 -0
- package/dist/commands.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +74 -4
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +24 -0
- package/dist/memory.js +100 -0
- package/dist/memory.js.map +1 -0
- package/package.json +2 -2
- package/src/commands.ts +27 -1
- package/src/index.ts +64 -3
- package/src/memory.ts +108 -0
- package/test/commands.test.ts +14 -0
- package/test/memory.test.ts +60 -0
- package/test/multi.test.ts +49 -1
package/dist/commands.d.ts
CHANGED
|
@@ -18,6 +18,20 @@ export type ParsedCommand = {
|
|
|
18
18
|
} | {
|
|
19
19
|
kind: 'cronrm';
|
|
20
20
|
taskId: string;
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'remember';
|
|
23
|
+
text: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'recall';
|
|
26
|
+
query: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: 'forget';
|
|
29
|
+
memoryId: string;
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'remind';
|
|
32
|
+
text: string;
|
|
33
|
+
inMinutes: number | null;
|
|
34
|
+
atTime: string | null;
|
|
21
35
|
};
|
|
22
36
|
export declare function parseCommand(text: string): ParsedCommand | null;
|
|
23
37
|
export declare const HELP_TEXT: string;
|
package/dist/commands.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// cron 语法:/cron <分 时 日 月 周> <需求>(schedule 为 5 个空白分隔字段)
|
|
2
2
|
const CRON_RE = /^\/cron\s+(\S+\s+\S+\s+\S+\s+\S+\s+\S+)\s+(.+)$/;
|
|
3
|
+
// /remind in N 分钟/小时/天 <text>(也支持 min/minutes/hour/hours/day/days);或 /remind at HH:MM <text>
|
|
4
|
+
const REMIND_IN_RE = /^\/remind\s+in\s+(\d+)\s+(\S+)\s+(.+)$/i;
|
|
5
|
+
const REMIND_AT_RE = /^\/remind\s+at\s+(\d{1,2}:\d{2})\s+(.+)$/i;
|
|
3
6
|
export function parseCommand(text) {
|
|
4
7
|
const trimmed = text.trim();
|
|
5
8
|
if (trimmed === '/trace')
|
|
@@ -21,6 +24,25 @@ export function parseCommand(text) {
|
|
|
21
24
|
const cronrm = trimmed.match(/^\/cronrm\s+(\S+)$/);
|
|
22
25
|
if (cronrm)
|
|
23
26
|
return { kind: 'cronrm', taskId: cronrm[1] };
|
|
27
|
+
const remember = trimmed.match(/^\/remember\s+(.+)$/);
|
|
28
|
+
if (remember)
|
|
29
|
+
return { kind: 'remember', text: remember[1] };
|
|
30
|
+
const recall = trimmed.match(/^\/recall\s*(.*)$/);
|
|
31
|
+
if (recall)
|
|
32
|
+
return { kind: 'recall', query: recall[1].trim() };
|
|
33
|
+
const forget = trimmed.match(/^\/forget\s+(\S+)$/);
|
|
34
|
+
if (forget)
|
|
35
|
+
return { kind: 'forget', memoryId: forget[1] };
|
|
36
|
+
const remindIn = trimmed.match(REMIND_IN_RE);
|
|
37
|
+
if (remindIn) {
|
|
38
|
+
const unit = (remindIn[2] ?? '').toLowerCase();
|
|
39
|
+
const n = Number(remindIn[1]);
|
|
40
|
+
const minutes = /^(小|h|hour)/.test(unit) ? n * 60 : /^(天|d)/.test(unit) ? n * 1440 : n;
|
|
41
|
+
return { kind: 'remind', text: remindIn[3], inMinutes: minutes, atTime: null };
|
|
42
|
+
}
|
|
43
|
+
const remindAt = trimmed.match(REMIND_AT_RE);
|
|
44
|
+
if (remindAt)
|
|
45
|
+
return { kind: 'remind', text: remindAt[2], inMinutes: null, atTime: remindAt[1] };
|
|
24
46
|
return null;
|
|
25
47
|
}
|
|
26
48
|
export const HELP_TEXT = [
|
|
@@ -30,6 +52,10 @@ export const HELP_TEXT = [
|
|
|
30
52
|
'/cron <分 时 日 月 周> <需求> — 定时任务',
|
|
31
53
|
'/crons — 查看定时任务列表',
|
|
32
54
|
'/cronrm <任务id> — 删除定时任务',
|
|
55
|
+
'/remind in 10 分钟 <提醒内容> — 一次性定时提醒(也支持 at HH:MM)',
|
|
56
|
+
'/remember <事实> — 记住关于我的事',
|
|
57
|
+
'/recall <关键词> — 回忆相关记忆',
|
|
58
|
+
'/forget <记忆id> — 删除一条记忆',
|
|
33
59
|
'/agents — 查看子任务状态',
|
|
34
60
|
'/new — 重置会话',
|
|
35
61
|
].join('\n');
|
package/dist/commands.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { GatewayClient, type ServerEvent } from '@dsh-overdrive/sdk';
|
|
|
2
2
|
import type { Adapter, OutboundPayload } from './adapter.js';
|
|
3
3
|
import { CliAdapter } from './adapters/cli.js';
|
|
4
4
|
import { type AsrTranscriber } from './asr.js';
|
|
5
|
+
import { MemoryStore } from './memory.js';
|
|
5
6
|
/**
|
|
6
7
|
* message.delta → 打字指示去重:同一 turn 内首个 delta 触发一次 typing,
|
|
7
8
|
* complete 后复位,下一 turn 可再次触发。纯逻辑,便于单测。
|
|
@@ -22,7 +23,11 @@ export interface WireOptions {
|
|
|
22
23
|
allowAll?: boolean;
|
|
23
24
|
/** ASR 转写器;配置了 API key 时启用,语音消息转成文本再发给 agent。 */
|
|
24
25
|
asr?: AsrTranscriber;
|
|
26
|
+
/** 记忆系统(OpenClaw 式长期记忆);未提供则记忆命令返回不可用。 */
|
|
27
|
+
memory?: MemoryStore;
|
|
25
28
|
}
|
|
29
|
+
/** 纯函数:一次性提醒的时间 → cron 5 字段表达式(分钟精度)。 */
|
|
30
|
+
export declare function remindSchedule(minutes: number, atTime: string | null, now?: Date): string;
|
|
26
31
|
/** 单个适配器的接线:白名单 → 命令面/upsert → sendMessage;按钮 → resolveApproval;事件流经轨迹聚合。 */
|
|
27
32
|
export declare function wireAdapter(adapter: Adapter, client: GatewayClient, opts: WireOptions): Promise<void>;
|
|
28
33
|
export { CliAdapter };
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { parseCommand, HELP_TEXT } from './commands.js';
|
|
|
6
6
|
import { TrajectoryAggregator, formatTrajectorySummary } from './trajectory.js';
|
|
7
7
|
import { createStatusServer } from './status.js';
|
|
8
8
|
import { createTranscriber } from './asr.js';
|
|
9
|
+
import { MemoryStore, memoryScope, formatMemories } from './memory.js';
|
|
9
10
|
/**
|
|
10
11
|
* message.delta → 打字指示去重:同一 turn 内首个 delta 触发一次 typing,
|
|
11
12
|
* complete 后复位,下一 turn 可再次触发。纯逻辑,便于单测。
|
|
@@ -58,8 +59,22 @@ export function planOutbound(ev) {
|
|
|
58
59
|
return null;
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
|
-
/**
|
|
62
|
-
|
|
62
|
+
/** 纯函数:一次性提醒的时间 → cron 5 字段表达式(分钟精度)。 */
|
|
63
|
+
export function remindSchedule(minutes, atTime, now = new Date()) {
|
|
64
|
+
const target = new Date(now);
|
|
65
|
+
if (atTime) {
|
|
66
|
+
const [h, m] = atTime.split(':').map(Number);
|
|
67
|
+
target.setHours(h, m, 0, 0);
|
|
68
|
+
if (target <= now)
|
|
69
|
+
target.setDate(target.getDate() + 1); // 已过则明天
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
target.setMinutes(target.getMinutes() + minutes);
|
|
73
|
+
}
|
|
74
|
+
return `${target.getMinutes()} ${target.getHours()} ${target.getDate()} ${target.getMonth() + 1} *`;
|
|
75
|
+
}
|
|
76
|
+
/** 命令面分发:/trace /new /task /cron /agents /help /remind /remember /recall /forget(M4 + v0.3)。 */
|
|
77
|
+
async function handleCommand(adapter, client, command, sessionId, chatId, aggregator, memory) {
|
|
63
78
|
switch (command.kind) {
|
|
64
79
|
case 'trace': {
|
|
65
80
|
const summary = aggregator.recentSummary(sessionId);
|
|
@@ -105,6 +120,50 @@ async function handleCommand(adapter, client, command, sessionId, chatId, aggreg
|
|
|
105
120
|
await adapter.send(chatId, { text: '(M4 简化)子任务状态由 agent 汇报,/task 派发' });
|
|
106
121
|
return;
|
|
107
122
|
}
|
|
123
|
+
case 'remember': {
|
|
124
|
+
if (!memory) {
|
|
125
|
+
await adapter.send(chatId, { text: '记忆系统未启用。' });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const scope = memoryScope(adapter.id, sessionId.split(':')[2] ?? '');
|
|
129
|
+
const entry = memory.add(scope, command.text);
|
|
130
|
+
await adapter.send(chatId, { text: `✅ 已记住(\`${entry.id}\`):${command.text}` });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
case 'recall': {
|
|
134
|
+
if (!memory) {
|
|
135
|
+
await adapter.send(chatId, { text: '记忆系统未启用。' });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const scope = memoryScope(adapter.id, sessionId.split(':')[2] ?? '');
|
|
139
|
+
const hits = memory.search(scope, command.query);
|
|
140
|
+
if (hits.length === 0) {
|
|
141
|
+
await adapter.send(chatId, { text: '没有相关记忆。' });
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
await adapter.send(chatId, {
|
|
145
|
+
text: `🧠 ${hits.length} 条记忆:\n` + hits.map((e) => `- \`${e.id}\` ${e.text}`).join('\n'),
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
case 'forget': {
|
|
150
|
+
if (!memory) {
|
|
151
|
+
await adapter.send(chatId, { text: '记忆系统未启用。' });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const scope = memoryScope(adapter.id, sessionId.split(':')[2] ?? '');
|
|
155
|
+
const ok = memory.remove(scope, command.memoryId);
|
|
156
|
+
await adapter.send(chatId, { text: ok ? `🗑️ 已删除记忆 \`${command.memoryId}\`` : `未找到记忆 \`${command.memoryId}\`` });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
case 'remind': {
|
|
160
|
+
const schedule = remindSchedule(command.inMinutes ?? 0, command.atTime);
|
|
161
|
+
await client.createTask({ sessionId, kind: 'cron', prompt: `⏰ 提醒:${command.text}`, schedule, once: true });
|
|
162
|
+
await adapter.send(chatId, {
|
|
163
|
+
text: `⏰ 已设置提醒「${command.text}」(${command.atTime ? `at ${command.atTime}` : `${command.inMinutes} 分钟后`},一次性)`,
|
|
164
|
+
});
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
108
167
|
case 'help': {
|
|
109
168
|
await adapter.send(chatId, { text: HELP_TEXT });
|
|
110
169
|
return;
|
|
@@ -129,9 +188,18 @@ export async function wireAdapter(adapter, client, opts) {
|
|
|
129
188
|
const command = parseCommand(msg.text);
|
|
130
189
|
if (command) {
|
|
131
190
|
console.log(`[gateway][${adapter.id}] 命令: ${JSON.stringify(command)}`);
|
|
132
|
-
await handleCommand(adapter, client, command, key, msg.chatId, aggregator);
|
|
191
|
+
await handleCommand(adapter, client, command, key, msg.chatId, aggregator, opts.memory);
|
|
133
192
|
return;
|
|
134
193
|
}
|
|
194
|
+
// OpenClaw 式记忆注入:入站消息前检索相关记忆,拼到文本后让 agent「记得你」
|
|
195
|
+
if (opts.memory) {
|
|
196
|
+
const scope = memoryScope(adapter.id, msg.userId);
|
|
197
|
+
const hits = opts.memory.search(scope, msg.text);
|
|
198
|
+
if (hits.length > 0) {
|
|
199
|
+
msg.text = `${msg.text}${formatMemories(hits)}`;
|
|
200
|
+
console.log(`[gateway][${adapter.id}] 注入 ${hits.length} 条相关记忆`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
135
203
|
// ASR 语音转写:配置了 API key 时把语音消息转成文本;失败/未配置走原降级路径
|
|
136
204
|
if (msg.media?.kind === 'voice' && opts.asr?.enabled) {
|
|
137
205
|
const transcript = await opts.asr.transcribe(msg.media);
|
|
@@ -216,12 +284,14 @@ async function main() {
|
|
|
216
284
|
});
|
|
217
285
|
if (asr.enabled)
|
|
218
286
|
console.log('[gateway] ASR 语音转写已启用');
|
|
287
|
+
const memory = new MemoryStore(process.env.MEMORY_FILE ?? 'data/memory.json');
|
|
288
|
+
console.log(`[gateway] 记忆系统已启用(文件: ${process.env.MEMORY_FILE ?? 'data/memory.json'})`);
|
|
219
289
|
const client = new GatewayClient(dshBaseUrl, dshToken);
|
|
220
290
|
await client.health(); // 确认 DSH 侧(或 mock)活着
|
|
221
291
|
const adapters = adapterIds.map((id) => createAdapter(id, env));
|
|
222
292
|
for (const adapter of adapters) {
|
|
223
293
|
await adapter.connect();
|
|
224
|
-
await wireAdapter(adapter, client, { allowlist, allowAll, asr });
|
|
294
|
+
await wireAdapter(adapter, client, { allowlist, allowAll, asr, memory });
|
|
225
295
|
console.log(`[gateway] ${adapter.id} 适配器已就绪`);
|
|
226
296
|
}
|
|
227
297
|
const consolePort = Number(process.env.GATEWAY_CONSOLE_PORT ?? 3190);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/memory.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface MemoryEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
text: string;
|
|
4
|
+
createdAt: string;
|
|
5
|
+
}
|
|
6
|
+
/** 作用域键:platform:userId(记忆跟随用户,跨频道共享,与 OpenClaw 一致)。 */
|
|
7
|
+
export declare function memoryScope(adapterId: string, userId: string): string;
|
|
8
|
+
/** 纯函数:按查询文本检索记忆——与查询共享任意 2-gram 即相关;空查询返回全部。 */
|
|
9
|
+
export declare function searchMemories(entries: MemoryEntry[], query: string): MemoryEntry[];
|
|
10
|
+
/** 纯函数:记忆列表 → 注入文本(拼在用户消息后)。 */
|
|
11
|
+
export declare function formatMemories(entries: MemoryEntry[]): string;
|
|
12
|
+
/** JSON 文件持久化的记忆存储;file 缺省时仅内存(测试/无盘环境用)。 */
|
|
13
|
+
export declare class MemoryStore {
|
|
14
|
+
private readonly data;
|
|
15
|
+
private readonly file?;
|
|
16
|
+
constructor(file?: string);
|
|
17
|
+
private persist;
|
|
18
|
+
add(scope: string, text: string): MemoryEntry;
|
|
19
|
+
list(scope: string): MemoryEntry[];
|
|
20
|
+
search(scope: string, query: string): MemoryEntry[];
|
|
21
|
+
/** 删除某作用域下指定 id 的记忆;不存在返回 false。 */
|
|
22
|
+
remove(scope: string, id: string): boolean;
|
|
23
|
+
count(scope: string): number;
|
|
24
|
+
}
|
package/dist/memory.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// 记忆系统(对标 OpenClaw 的 long-term memory)。
|
|
2
|
+
// 按 platform:userId 作用域存储用户显式记忆(/remember),支持搜索(/recall)与删除(/forget);
|
|
3
|
+
// 入站消息时自动检索相关记忆注入上下文,让 agent「记得你」。
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { dirname } from 'node:path';
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
7
|
+
/** 作用域键:platform:userId(记忆跟随用户,跨频道共享,与 OpenClaw 一致)。 */
|
|
8
|
+
export function memoryScope(adapterId, userId) {
|
|
9
|
+
return `${adapterId}:${userId}`;
|
|
10
|
+
}
|
|
11
|
+
/** 字符 2-gram:CJK 无空格分词,用共享 bigram 判断相关性(比子串包含更鲁棒)。 */
|
|
12
|
+
function bigrams(text) {
|
|
13
|
+
const clean = text.toLowerCase();
|
|
14
|
+
const out = new Set();
|
|
15
|
+
for (let i = 0; i < clean.length - 1; i++)
|
|
16
|
+
out.add(clean.slice(i, i + 2));
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
/** 纯函数:按查询文本检索记忆——与查询共享任意 2-gram 即相关;空查询返回全部。 */
|
|
20
|
+
export function searchMemories(entries, query) {
|
|
21
|
+
const queryBigrams = bigrams(query);
|
|
22
|
+
if (queryBigrams.size === 0)
|
|
23
|
+
return entries;
|
|
24
|
+
return entries.filter((entry) => {
|
|
25
|
+
const memoryBigrams = bigrams(entry.text);
|
|
26
|
+
for (const gram of queryBigrams) {
|
|
27
|
+
if (memoryBigrams.has(gram))
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** 纯函数:记忆列表 → 注入文本(拼在用户消息后)。 */
|
|
34
|
+
export function formatMemories(entries) {
|
|
35
|
+
if (entries.length === 0)
|
|
36
|
+
return '';
|
|
37
|
+
const lines = entries.map((e) => `- ${e.text}`).join('\n');
|
|
38
|
+
return `\n📌 相关记忆:\n${lines}`;
|
|
39
|
+
}
|
|
40
|
+
/** JSON 文件持久化的记忆存储;file 缺省时仅内存(测试/无盘环境用)。 */
|
|
41
|
+
export class MemoryStore {
|
|
42
|
+
data = new Map();
|
|
43
|
+
file;
|
|
44
|
+
constructor(file) {
|
|
45
|
+
this.file = file;
|
|
46
|
+
if (file && existsSync(file)) {
|
|
47
|
+
try {
|
|
48
|
+
const parsed = JSON.parse(readFileSync(file, 'utf8'));
|
|
49
|
+
for (const [scope, entries] of Object.entries(parsed)) {
|
|
50
|
+
if (Array.isArray(entries))
|
|
51
|
+
this.data.set(scope, entries);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
/* 损坏则从空开始 */
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
persist() {
|
|
60
|
+
if (!this.file)
|
|
61
|
+
return;
|
|
62
|
+
try {
|
|
63
|
+
mkdirSync(dirname(this.file), { recursive: true });
|
|
64
|
+
writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.data), null, 2), 'utf8');
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* 持久化失败不阻断 */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
add(scope, text) {
|
|
71
|
+
const entry = { id: randomUUID().slice(0, 8), text: text.trim(), createdAt: new Date().toISOString() };
|
|
72
|
+
const list = this.data.get(scope) ?? [];
|
|
73
|
+
list.push(entry);
|
|
74
|
+
this.data.set(scope, list);
|
|
75
|
+
this.persist();
|
|
76
|
+
return entry;
|
|
77
|
+
}
|
|
78
|
+
list(scope) {
|
|
79
|
+
return this.data.get(scope) ?? [];
|
|
80
|
+
}
|
|
81
|
+
search(scope, query) {
|
|
82
|
+
return searchMemories(this.list(scope), query);
|
|
83
|
+
}
|
|
84
|
+
/** 删除某作用域下指定 id 的记忆;不存在返回 false。 */
|
|
85
|
+
remove(scope, id) {
|
|
86
|
+
const list = this.data.get(scope);
|
|
87
|
+
if (!list)
|
|
88
|
+
return false;
|
|
89
|
+
const next = list.filter((e) => e.id !== id);
|
|
90
|
+
if (next.length === list.length)
|
|
91
|
+
return false;
|
|
92
|
+
this.data.set(scope, next);
|
|
93
|
+
this.persist();
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
count(scope) {
|
|
97
|
+
return this.list(scope).length;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/commands.ts
CHANGED
|
@@ -6,10 +6,17 @@ export type ParsedCommand =
|
|
|
6
6
|
| { kind: 'task'; prompt: string }
|
|
7
7
|
| { kind: 'cron'; schedule: string; prompt: string }
|
|
8
8
|
| { kind: 'crons' }
|
|
9
|
-
| { kind: 'cronrm'; taskId: string }
|
|
9
|
+
| { kind: 'cronrm'; taskId: string }
|
|
10
|
+
| { kind: 'remember'; text: string }
|
|
11
|
+
| { kind: 'recall'; query: string }
|
|
12
|
+
| { kind: 'forget'; memoryId: string }
|
|
13
|
+
| { kind: 'remind'; text: string; inMinutes: number | null; atTime: string | null };
|
|
10
14
|
|
|
11
15
|
// cron 语法:/cron <分 时 日 月 周> <需求>(schedule 为 5 个空白分隔字段)
|
|
12
16
|
const CRON_RE = /^\/cron\s+(\S+\s+\S+\s+\S+\s+\S+\s+\S+)\s+(.+)$/;
|
|
17
|
+
// /remind in N 分钟/小时/天 <text>(也支持 min/minutes/hour/hours/day/days);或 /remind at HH:MM <text>
|
|
18
|
+
const REMIND_IN_RE = /^\/remind\s+in\s+(\d+)\s+(\S+)\s+(.+)$/i;
|
|
19
|
+
const REMIND_AT_RE = /^\/remind\s+at\s+(\d{1,2}:\d{2})\s+(.+)$/i;
|
|
13
20
|
|
|
14
21
|
export function parseCommand(text: string): ParsedCommand | null {
|
|
15
22
|
const trimmed = text.trim();
|
|
@@ -24,6 +31,21 @@ export function parseCommand(text: string): ParsedCommand | null {
|
|
|
24
31
|
if (cron) return { kind: 'cron', schedule: cron[1], prompt: cron[2] };
|
|
25
32
|
const cronrm = trimmed.match(/^\/cronrm\s+(\S+)$/);
|
|
26
33
|
if (cronrm) return { kind: 'cronrm', taskId: cronrm[1] };
|
|
34
|
+
const remember = trimmed.match(/^\/remember\s+(.+)$/);
|
|
35
|
+
if (remember) return { kind: 'remember', text: remember[1] };
|
|
36
|
+
const recall = trimmed.match(/^\/recall\s*(.*)$/);
|
|
37
|
+
if (recall) return { kind: 'recall', query: recall[1].trim() };
|
|
38
|
+
const forget = trimmed.match(/^\/forget\s+(\S+)$/);
|
|
39
|
+
if (forget) return { kind: 'forget', memoryId: forget[1] };
|
|
40
|
+
const remindIn = trimmed.match(REMIND_IN_RE);
|
|
41
|
+
if (remindIn) {
|
|
42
|
+
const unit = (remindIn[2] ?? '').toLowerCase();
|
|
43
|
+
const n = Number(remindIn[1]);
|
|
44
|
+
const minutes = /^(小|h|hour)/.test(unit) ? n * 60 : /^(天|d)/.test(unit) ? n * 1440 : n;
|
|
45
|
+
return { kind: 'remind', text: remindIn[3], inMinutes: minutes, atTime: null };
|
|
46
|
+
}
|
|
47
|
+
const remindAt = trimmed.match(REMIND_AT_RE);
|
|
48
|
+
if (remindAt) return { kind: 'remind', text: remindAt[2], inMinutes: null, atTime: remindAt[1] };
|
|
27
49
|
return null;
|
|
28
50
|
}
|
|
29
51
|
|
|
@@ -34,6 +56,10 @@ export const HELP_TEXT = [
|
|
|
34
56
|
'/cron <分 时 日 月 周> <需求> — 定时任务',
|
|
35
57
|
'/crons — 查看定时任务列表',
|
|
36
58
|
'/cronrm <任务id> — 删除定时任务',
|
|
59
|
+
'/remind in 10 分钟 <提醒内容> — 一次性定时提醒(也支持 at HH:MM)',
|
|
60
|
+
'/remember <事实> — 记住关于我的事',
|
|
61
|
+
'/recall <关键词> — 回忆相关记忆',
|
|
62
|
+
'/forget <记忆id> — 删除一条记忆',
|
|
37
63
|
'/agents — 查看子任务状态',
|
|
38
64
|
'/new — 重置会话',
|
|
39
65
|
].join('\n');
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { parseCommand, HELP_TEXT, type ParsedCommand } from './commands.js';
|
|
|
7
7
|
import { TrajectoryAggregator, formatTrajectorySummary } from './trajectory.js';
|
|
8
8
|
import { createStatusServer } from './status.js';
|
|
9
9
|
import { createTranscriber, type AsrTranscriber } from './asr.js';
|
|
10
|
+
import { MemoryStore, memoryScope, formatMemories } from './memory.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* message.delta → 打字指示去重:同一 turn 内首个 delta 触发一次 typing,
|
|
@@ -69,9 +70,24 @@ export interface WireOptions {
|
|
|
69
70
|
allowAll?: boolean;
|
|
70
71
|
/** ASR 转写器;配置了 API key 时启用,语音消息转成文本再发给 agent。 */
|
|
71
72
|
asr?: AsrTranscriber;
|
|
73
|
+
/** 记忆系统(OpenClaw 式长期记忆);未提供则记忆命令返回不可用。 */
|
|
74
|
+
memory?: MemoryStore;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
/**
|
|
77
|
+
/** 纯函数:一次性提醒的时间 → cron 5 字段表达式(分钟精度)。 */
|
|
78
|
+
export function remindSchedule(minutes: number, atTime: string | null, now = new Date()): string {
|
|
79
|
+
const target = new Date(now);
|
|
80
|
+
if (atTime) {
|
|
81
|
+
const [h, m] = atTime.split(':').map(Number);
|
|
82
|
+
target.setHours(h, m, 0, 0);
|
|
83
|
+
if (target <= now) target.setDate(target.getDate() + 1); // 已过则明天
|
|
84
|
+
} else {
|
|
85
|
+
target.setMinutes(target.getMinutes() + minutes);
|
|
86
|
+
}
|
|
87
|
+
return `${target.getMinutes()} ${target.getHours()} ${target.getDate()} ${target.getMonth() + 1} *`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** 命令面分发:/trace /new /task /cron /agents /help /remind /remember /recall /forget(M4 + v0.3)。 */
|
|
75
91
|
async function handleCommand(
|
|
76
92
|
adapter: Adapter,
|
|
77
93
|
client: GatewayClient,
|
|
@@ -79,6 +95,7 @@ async function handleCommand(
|
|
|
79
95
|
sessionId: string,
|
|
80
96
|
chatId: string,
|
|
81
97
|
aggregator: TrajectoryAggregator,
|
|
98
|
+
memory: MemoryStore | undefined,
|
|
82
99
|
): Promise<void> {
|
|
83
100
|
switch (command.kind) {
|
|
84
101
|
case 'trace': {
|
|
@@ -125,6 +142,38 @@ async function handleCommand(
|
|
|
125
142
|
await adapter.send(chatId, { text: '(M4 简化)子任务状态由 agent 汇报,/task 派发' });
|
|
126
143
|
return;
|
|
127
144
|
}
|
|
145
|
+
case 'remember': {
|
|
146
|
+
if (!memory) { await adapter.send(chatId, { text: '记忆系统未启用。' }); return; }
|
|
147
|
+
const scope = memoryScope(adapter.id, sessionId.split(':')[2] ?? '');
|
|
148
|
+
const entry = memory.add(scope, command.text);
|
|
149
|
+
await adapter.send(chatId, { text: `✅ 已记住(\`${entry.id}\`):${command.text}` });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
case 'recall': {
|
|
153
|
+
if (!memory) { await adapter.send(chatId, { text: '记忆系统未启用。' }); return; }
|
|
154
|
+
const scope = memoryScope(adapter.id, sessionId.split(':')[2] ?? '');
|
|
155
|
+
const hits = memory.search(scope, command.query);
|
|
156
|
+
if (hits.length === 0) { await adapter.send(chatId, { text: '没有相关记忆。' }); return; }
|
|
157
|
+
await adapter.send(chatId, {
|
|
158
|
+
text: `🧠 ${hits.length} 条记忆:\n` + hits.map((e) => `- \`${e.id}\` ${e.text}`).join('\n'),
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
case 'forget': {
|
|
163
|
+
if (!memory) { await adapter.send(chatId, { text: '记忆系统未启用。' }); return; }
|
|
164
|
+
const scope = memoryScope(adapter.id, sessionId.split(':')[2] ?? '');
|
|
165
|
+
const ok = memory.remove(scope, command.memoryId);
|
|
166
|
+
await adapter.send(chatId, { text: ok ? `🗑️ 已删除记忆 \`${command.memoryId}\`` : `未找到记忆 \`${command.memoryId}\`` });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
case 'remind': {
|
|
170
|
+
const schedule = remindSchedule(command.inMinutes ?? 0, command.atTime);
|
|
171
|
+
await client.createTask({ sessionId, kind: 'cron', prompt: `⏰ 提醒:${command.text}`, schedule, once: true });
|
|
172
|
+
await adapter.send(chatId, {
|
|
173
|
+
text: `⏰ 已设置提醒「${command.text}」(${command.atTime ? `at ${command.atTime}` : `${command.inMinutes} 分钟后`},一次性)`,
|
|
174
|
+
});
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
128
177
|
case 'help': {
|
|
129
178
|
await adapter.send(chatId, { text: HELP_TEXT });
|
|
130
179
|
return;
|
|
@@ -156,10 +205,20 @@ export async function wireAdapter(
|
|
|
156
205
|
const command = parseCommand(msg.text);
|
|
157
206
|
if (command) {
|
|
158
207
|
console.log(`[gateway][${adapter.id}] 命令: ${JSON.stringify(command)}`);
|
|
159
|
-
await handleCommand(adapter, client, command, key, msg.chatId, aggregator);
|
|
208
|
+
await handleCommand(adapter, client, command, key, msg.chatId, aggregator, opts.memory);
|
|
160
209
|
return;
|
|
161
210
|
}
|
|
162
211
|
|
|
212
|
+
// OpenClaw 式记忆注入:入站消息前检索相关记忆,拼到文本后让 agent「记得你」
|
|
213
|
+
if (opts.memory) {
|
|
214
|
+
const scope = memoryScope(adapter.id, msg.userId);
|
|
215
|
+
const hits = opts.memory.search(scope, msg.text);
|
|
216
|
+
if (hits.length > 0) {
|
|
217
|
+
msg.text = `${msg.text}${formatMemories(hits)}`;
|
|
218
|
+
console.log(`[gateway][${adapter.id}] 注入 ${hits.length} 条相关记忆`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
163
222
|
// ASR 语音转写:配置了 API key 时把语音消息转成文本;失败/未配置走原降级路径
|
|
164
223
|
if (msg.media?.kind === 'voice' && opts.asr?.enabled) {
|
|
165
224
|
const transcript = await opts.asr.transcribe(msg.media);
|
|
@@ -246,6 +305,8 @@ async function main(): Promise<void> {
|
|
|
246
305
|
model: env.asrModel,
|
|
247
306
|
});
|
|
248
307
|
if (asr.enabled) console.log('[gateway] ASR 语音转写已启用');
|
|
308
|
+
const memory = new MemoryStore(process.env.MEMORY_FILE ?? 'data/memory.json');
|
|
309
|
+
console.log(`[gateway] 记忆系统已启用(文件: ${process.env.MEMORY_FILE ?? 'data/memory.json'})`);
|
|
249
310
|
|
|
250
311
|
const client = new GatewayClient(dshBaseUrl, dshToken);
|
|
251
312
|
await client.health(); // 确认 DSH 侧(或 mock)活着
|
|
@@ -253,7 +314,7 @@ async function main(): Promise<void> {
|
|
|
253
314
|
const adapters: Adapter[] = adapterIds.map((id) => createAdapter(id, env));
|
|
254
315
|
for (const adapter of adapters) {
|
|
255
316
|
await adapter.connect();
|
|
256
|
-
await wireAdapter(adapter, client, { allowlist, allowAll, asr });
|
|
317
|
+
await wireAdapter(adapter, client, { allowlist, allowAll, asr, memory });
|
|
257
318
|
console.log(`[gateway] ${adapter.id} 适配器已就绪`);
|
|
258
319
|
}
|
|
259
320
|
|
package/src/memory.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// 记忆系统(对标 OpenClaw 的 long-term memory)。
|
|
2
|
+
// 按 platform:userId 作用域存储用户显式记忆(/remember),支持搜索(/recall)与删除(/forget);
|
|
3
|
+
// 入站消息时自动检索相关记忆注入上下文,让 agent「记得你」。
|
|
4
|
+
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { dirname } from 'node:path';
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
8
|
+
|
|
9
|
+
export interface MemoryEntry {
|
|
10
|
+
id: string;
|
|
11
|
+
text: string;
|
|
12
|
+
createdAt: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** 作用域键:platform:userId(记忆跟随用户,跨频道共享,与 OpenClaw 一致)。 */
|
|
16
|
+
export function memoryScope(adapterId: string, userId: string): string {
|
|
17
|
+
return `${adapterId}:${userId}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 字符 2-gram:CJK 无空格分词,用共享 bigram 判断相关性(比子串包含更鲁棒)。 */
|
|
21
|
+
function bigrams(text: string): Set<string> {
|
|
22
|
+
const clean = text.toLowerCase();
|
|
23
|
+
const out = new Set<string>();
|
|
24
|
+
for (let i = 0; i < clean.length - 1; i++) out.add(clean.slice(i, i + 2));
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 纯函数:按查询文本检索记忆——与查询共享任意 2-gram 即相关;空查询返回全部。 */
|
|
29
|
+
export function searchMemories(entries: MemoryEntry[], query: string): MemoryEntry[] {
|
|
30
|
+
const queryBigrams = bigrams(query);
|
|
31
|
+
if (queryBigrams.size === 0) return entries;
|
|
32
|
+
return entries.filter((entry) => {
|
|
33
|
+
const memoryBigrams = bigrams(entry.text);
|
|
34
|
+
for (const gram of queryBigrams) {
|
|
35
|
+
if (memoryBigrams.has(gram)) return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 纯函数:记忆列表 → 注入文本(拼在用户消息后)。 */
|
|
42
|
+
export function formatMemories(entries: MemoryEntry[]): string {
|
|
43
|
+
if (entries.length === 0) return '';
|
|
44
|
+
const lines = entries.map((e) => `- ${e.text}`).join('\n');
|
|
45
|
+
return `\n📌 相关记忆:\n${lines}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** JSON 文件持久化的记忆存储;file 缺省时仅内存(测试/无盘环境用)。 */
|
|
49
|
+
export class MemoryStore {
|
|
50
|
+
private readonly data = new Map<string, MemoryEntry[]>();
|
|
51
|
+
private readonly file?: string;
|
|
52
|
+
|
|
53
|
+
constructor(file?: string) {
|
|
54
|
+
this.file = file;
|
|
55
|
+
if (file && existsSync(file)) {
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(readFileSync(file, 'utf8')) as Record<string, MemoryEntry[]>;
|
|
58
|
+
for (const [scope, entries] of Object.entries(parsed)) {
|
|
59
|
+
if (Array.isArray(entries)) this.data.set(scope, entries);
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
/* 损坏则从空开始 */
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private persist(): void {
|
|
68
|
+
if (!this.file) return;
|
|
69
|
+
try {
|
|
70
|
+
mkdirSync(dirname(this.file), { recursive: true });
|
|
71
|
+
writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.data), null, 2), 'utf8');
|
|
72
|
+
} catch {
|
|
73
|
+
/* 持久化失败不阻断 */
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
add(scope: string, text: string): MemoryEntry {
|
|
78
|
+
const entry: MemoryEntry = { id: randomUUID().slice(0, 8), text: text.trim(), createdAt: new Date().toISOString() };
|
|
79
|
+
const list = this.data.get(scope) ?? [];
|
|
80
|
+
list.push(entry);
|
|
81
|
+
this.data.set(scope, list);
|
|
82
|
+
this.persist();
|
|
83
|
+
return entry;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
list(scope: string): MemoryEntry[] {
|
|
87
|
+
return this.data.get(scope) ?? [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
search(scope: string, query: string): MemoryEntry[] {
|
|
91
|
+
return searchMemories(this.list(scope), query);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** 删除某作用域下指定 id 的记忆;不存在返回 false。 */
|
|
95
|
+
remove(scope: string, id: string): boolean {
|
|
96
|
+
const list = this.data.get(scope);
|
|
97
|
+
if (!list) return false;
|
|
98
|
+
const next = list.filter((e) => e.id !== id);
|
|
99
|
+
if (next.length === list.length) return false;
|
|
100
|
+
this.data.set(scope, next);
|
|
101
|
+
this.persist();
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
count(scope: string): number {
|
|
106
|
+
return this.list(scope).length;
|
|
107
|
+
}
|
|
108
|
+
}
|
package/test/commands.test.ts
CHANGED
|
@@ -21,4 +21,18 @@ describe('parseCommand', () => {
|
|
|
21
21
|
expect(parseCommand('/task')).toBeNull(); // 缺参数
|
|
22
22
|
expect(parseCommand('/cronrm')).toBeNull(); // 缺任务 id
|
|
23
23
|
});
|
|
24
|
+
it('识别 /remember /recall /forget', () => {
|
|
25
|
+
expect(parseCommand('/remember 用户喜欢美式咖啡')).toEqual({ kind: 'remember', text: '用户喜欢美式咖啡' });
|
|
26
|
+
expect(parseCommand('/recall 咖啡')).toEqual({ kind: 'recall', query: '咖啡' });
|
|
27
|
+
expect(parseCommand('/recall')).toEqual({ kind: 'recall', query: '' });
|
|
28
|
+
expect(parseCommand('/forget abc123')).toEqual({ kind: 'forget', memoryId: 'abc123' });
|
|
29
|
+
expect(parseCommand('/remember')).toBeNull(); // 缺内容
|
|
30
|
+
});
|
|
31
|
+
it('识别 /remind(相对时间与定点时间)', () => {
|
|
32
|
+
expect(parseCommand('/remind in 10 分钟 喝水')).toEqual({ kind: 'remind', text: '喝水', inMinutes: 10, atTime: null });
|
|
33
|
+
expect(parseCommand('/remind in 2 小时 开会')).toEqual({ kind: 'remind', text: '开会', inMinutes: 120, atTime: null });
|
|
34
|
+
expect(parseCommand('/remind in 30 minutes 散步')).toEqual({ kind: 'remind', text: '散步', inMinutes: 30, atTime: null });
|
|
35
|
+
expect(parseCommand('/remind in 1 day 汇报')).toEqual({ kind: 'remind', text: '汇报', inMinutes: 1440, atTime: null });
|
|
36
|
+
expect(parseCommand('/remind at 14:30 开会')).toEqual({ kind: 'remind', text: '开会', inMinutes: null, atTime: '14:30' });
|
|
37
|
+
});
|
|
24
38
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { MemoryStore, formatMemories, memoryScope, searchMemories } from '../src/memory.js';
|
|
3
|
+
|
|
4
|
+
describe('memoryScope', () => {
|
|
5
|
+
it('按 platform:userId 作用域(记忆跟随用户跨频道)', () => {
|
|
6
|
+
expect(memoryScope('telegram', 'u1')).toBe('telegram:u1');
|
|
7
|
+
});
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe('searchMemories', () => {
|
|
11
|
+
const entries = [
|
|
12
|
+
{ id: '1', text: '用户喜欢喝美式咖啡', createdAt: 'x' },
|
|
13
|
+
{ id: '2', text: '用户住在杭州', createdAt: 'x' },
|
|
14
|
+
{ id: '3', text: '项目用 TypeScript', createdAt: 'x' },
|
|
15
|
+
];
|
|
16
|
+
it('任一关键词命中即返回', () => {
|
|
17
|
+
expect(searchMemories(entries, '咖啡').map((e) => e.id)).toEqual(['1']);
|
|
18
|
+
expect(searchMemories(entries, '杭州 咖啡').map((e) => e.id).sort()).toEqual(['1', '2']);
|
|
19
|
+
});
|
|
20
|
+
it('无匹配返回空', () => {
|
|
21
|
+
expect(searchMemories(entries, '滑雪')).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
it('空查询返回全部', () => {
|
|
24
|
+
expect(searchMemories(entries, '')).toHaveLength(3);
|
|
25
|
+
});
|
|
26
|
+
it('大小写不敏感', () => {
|
|
27
|
+
expect(searchMemories(entries, 'typescript').map((e) => e.id)).toEqual(['3']);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('formatMemories', () => {
|
|
32
|
+
it('空列表返回空串', () => {
|
|
33
|
+
expect(formatMemories([])).toBe('');
|
|
34
|
+
});
|
|
35
|
+
it('渲染注入块', () => {
|
|
36
|
+
const text = formatMemories([{ id: '1', text: '用户住在杭州', createdAt: 'x' }]);
|
|
37
|
+
expect(text).toContain('📌 相关记忆');
|
|
38
|
+
expect(text).toContain('用户住在杭州');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('MemoryStore(内存模式)', () => {
|
|
43
|
+
it('add / list / search / remove 全流程', () => {
|
|
44
|
+
const store = new MemoryStore(); // 无文件 = 纯内存
|
|
45
|
+
const entry = store.add('telegram:u1', '用户喜欢喝美式咖啡');
|
|
46
|
+
expect(store.count('telegram:u1')).toBe(1);
|
|
47
|
+
expect(store.list('telegram:u1')[0].text).toBe('用户喜欢喝美式咖啡');
|
|
48
|
+
expect(store.search('telegram:u1', '咖啡')).toHaveLength(1);
|
|
49
|
+
expect(store.remove('telegram:u1', entry.id)).toBe(true);
|
|
50
|
+
expect(store.count('telegram:u1')).toBe(0);
|
|
51
|
+
expect(store.remove('telegram:u1', entry.id)).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
it('不同作用域隔离', () => {
|
|
54
|
+
const store = new MemoryStore();
|
|
55
|
+
store.add('telegram:u1', 'A 的记忆');
|
|
56
|
+
store.add('whatsapp:u1', 'B 的记忆');
|
|
57
|
+
expect(store.list('telegram:u1')).toHaveLength(1);
|
|
58
|
+
expect(store.list('whatsapp:u1')).toHaveLength(1);
|
|
59
|
+
});
|
|
60
|
+
});
|
package/test/multi.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { wireAdapter } from '../src/index.js';
|
|
2
|
+
import { remindSchedule, wireAdapter } from '../src/index.js';
|
|
3
3
|
import { GatewayClient } from '@dsh-overdrive/sdk';
|
|
4
|
+
import { MemoryStore } from '../src/memory.js';
|
|
4
5
|
import type { Adapter, NormalizedMessage, OutboundPayload, ReplySender } from '../src/adapter.js';
|
|
5
6
|
|
|
6
7
|
/** 可编程 FakeAdapter:验证 wiring 逻辑(白名单/会话键/错误兜底)。 */
|
|
@@ -104,4 +105,51 @@ describe('wireAdapter(多适配器装配核心)', () => {
|
|
|
104
105
|
await adapter.emit({ chatId: 'C1', userId: 'U1', text: 'hi' });
|
|
105
106
|
expect(adapter.sent[0].payload.text).toContain('❌');
|
|
106
107
|
});
|
|
108
|
+
|
|
109
|
+
it('相关记忆自动注入到发给 agent 的文本(OpenClaw 式)', async () => {
|
|
110
|
+
const adapter = new FakeAdapter('telegram');
|
|
111
|
+
const { client, messages } = fakeClient();
|
|
112
|
+
const memory = new MemoryStore();
|
|
113
|
+
memory.add('telegram:222', '用户喜欢美式咖啡');
|
|
114
|
+
await wireAdapter(adapter, client, { allowlist: ['telegram:111:222'], memory });
|
|
115
|
+
|
|
116
|
+
await adapter.emit({ chatId: '111', userId: '222', text: '帮我点一杯咖啡' });
|
|
117
|
+
expect(messages[0].text).toContain('帮我点一杯咖啡');
|
|
118
|
+
expect(messages[0].text).toContain('📌 相关记忆');
|
|
119
|
+
expect(messages[0].text).toContain('用户喜欢美式咖啡');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('无相关记忆时不注入', async () => {
|
|
123
|
+
const adapter = new FakeAdapter('telegram');
|
|
124
|
+
const { client, messages } = fakeClient();
|
|
125
|
+
const memory = new MemoryStore();
|
|
126
|
+
memory.add('telegram:222', '用户喜欢美式咖啡');
|
|
127
|
+
await wireAdapter(adapter, client, { allowlist: ['telegram:111:222'], memory });
|
|
128
|
+
|
|
129
|
+
await adapter.emit({ chatId: '111', userId: '222', text: '今天天气如何' });
|
|
130
|
+
expect(messages[0].text).toBe('今天天气如何');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('/remember 命令写入记忆并回执', async () => {
|
|
134
|
+
const adapter = new FakeAdapter('telegram');
|
|
135
|
+
const { client } = fakeClient();
|
|
136
|
+
const memory = new MemoryStore();
|
|
137
|
+
await wireAdapter(adapter, client, { allowlist: ['telegram:111:222'], memory });
|
|
138
|
+
|
|
139
|
+
await adapter.emit({ chatId: '111', userId: '222', text: '/remember 用户住在杭州' });
|
|
140
|
+
expect(memory.count('telegram:222')).toBe(1);
|
|
141
|
+
expect(adapter.sent[0].payload.text).toContain('已记住');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('remindSchedule', () => {
|
|
146
|
+
it('相对分钟 → cron 5 字段', () => {
|
|
147
|
+
const now = new Date('2026-08-20T10:05:00');
|
|
148
|
+
expect(remindSchedule(10, null, now)).toBe('15 10 20 8 *');
|
|
149
|
+
});
|
|
150
|
+
it('定点时间 → cron;已过则推到明天', () => {
|
|
151
|
+
const now = new Date('2026-08-20T10:05:00');
|
|
152
|
+
expect(remindSchedule(0, '14:30', now)).toBe('30 14 20 8 *');
|
|
153
|
+
expect(remindSchedule(0, '09:00', now)).toBe('0 9 21 8 *');
|
|
154
|
+
});
|
|
107
155
|
});
|