@downcity/plugins 1.0.253 → 1.0.254

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.
Files changed (67) hide show
  1. package/bin/memory/Action.d.ts +27 -36
  2. package/bin/memory/Action.d.ts.map +1 -1
  3. package/bin/memory/Action.js +71 -311
  4. package/bin/memory/Action.js.map +1 -1
  5. package/bin/memory/Index.d.ts +3 -1
  6. package/bin/memory/Index.d.ts.map +1 -1
  7. package/bin/memory/Index.js +3 -1
  8. package/bin/memory/Index.js.map +1 -1
  9. package/bin/memory/MemoryPlugin.d.ts +20 -37
  10. package/bin/memory/MemoryPlugin.d.ts.map +1 -1
  11. package/bin/memory/MemoryPlugin.js +231 -233
  12. package/bin/memory/MemoryPlugin.js.map +1 -1
  13. package/bin/memory/adapters/FileMemoryStorageAdapter.d.ts +43 -0
  14. package/bin/memory/adapters/FileMemoryStorageAdapter.d.ts.map +1 -0
  15. package/bin/memory/adapters/FileMemoryStorageAdapter.js +163 -0
  16. package/bin/memory/adapters/FileMemoryStorageAdapter.js.map +1 -0
  17. package/bin/memory/providers/BuiltinMemoryProvider.d.ts +63 -0
  18. package/bin/memory/providers/BuiltinMemoryProvider.d.ts.map +1 -0
  19. package/bin/memory/providers/BuiltinMemoryProvider.js +772 -0
  20. package/bin/memory/providers/BuiltinMemoryProvider.js.map +1 -0
  21. package/bin/memory/runtime/SystemProvider.d.ts +7 -12
  22. package/bin/memory/runtime/SystemProvider.d.ts.map +1 -1
  23. package/bin/memory/runtime/SystemProvider.js +30 -89
  24. package/bin/memory/runtime/SystemProvider.js.map +1 -1
  25. package/bin/memory/types/BuiltinMemoryProvider.d.ts +88 -0
  26. package/bin/memory/types/BuiltinMemoryProvider.d.ts.map +1 -0
  27. package/bin/memory/types/BuiltinMemoryProvider.js +9 -0
  28. package/bin/memory/types/BuiltinMemoryProvider.js.map +1 -0
  29. package/bin/memory/types/Memory.d.ts +249 -408
  30. package/bin/memory/types/Memory.d.ts.map +1 -1
  31. package/bin/memory/types/Memory.js +4 -4
  32. package/bin/memory/types/MemoryStorage.d.ts +35 -0
  33. package/bin/memory/types/MemoryStorage.d.ts.map +1 -0
  34. package/bin/memory/types/MemoryStorage.js +10 -0
  35. package/bin/memory/types/MemoryStorage.js.map +1 -0
  36. package/bin/memory.d.ts +6 -2
  37. package/bin/memory.d.ts.map +1 -1
  38. package/bin/memory.js +3 -1
  39. package/bin/memory.js.map +1 -1
  40. package/package.json +3 -2
  41. package/scripts/memory-plugin.test.mjs +227 -0
  42. package/scripts/plugin-subpaths.test.mjs +8 -0
  43. package/src/memory/Action.ts +106 -377
  44. package/src/memory/Index.ts +6 -1
  45. package/src/memory/MemoryPlugin.ts +254 -246
  46. package/src/memory/adapters/FileMemoryStorageAdapter.ts +197 -0
  47. package/src/memory/providers/BuiltinMemoryProvider.ts +905 -0
  48. package/src/memory/runtime/SystemProvider.ts +32 -95
  49. package/src/memory/types/BuiltinMemoryProvider.ts +121 -0
  50. package/src/memory/types/Memory.ts +322 -456
  51. package/src/memory/types/MemoryStorage.ts +44 -0
  52. package/src/memory.ts +48 -24
  53. package/bin/memory/runtime/Search.d.ts +0 -19
  54. package/bin/memory/runtime/Search.d.ts.map +0 -1
  55. package/bin/memory/runtime/Search.js +0 -262
  56. package/bin/memory/runtime/Search.js.map +0 -1
  57. package/bin/memory/runtime/Store.d.ts +0 -42
  58. package/bin/memory/runtime/Store.d.ts.map +0 -1
  59. package/bin/memory/runtime/Store.js +0 -94
  60. package/bin/memory/runtime/Store.js.map +0 -1
  61. package/bin/memory/runtime/Writer.d.ts +0 -61
  62. package/bin/memory/runtime/Writer.d.ts.map +0 -1
  63. package/bin/memory/runtime/Writer.js +0 -274
  64. package/bin/memory/runtime/Writer.js.map +0 -1
  65. package/src/memory/runtime/Search.ts +0 -327
  66. package/src/memory/runtime/Store.ts +0 -158
  67. package/src/memory/runtime/Writer.ts +0 -351
@@ -0,0 +1,197 @@
1
+ /**
2
+ * FileMemoryStorageAdapter:Builtin Memory Provider 的本地文本存储实现。
3
+ *
4
+ * 关键点(中文)
5
+ * - 只理解 Provider 内部逻辑 key,不理解 memory_id、召回或提炼语义。
6
+ * - 所有 key 都被限制在独占 root_path 内,拒绝绝对路径和目录穿越。
7
+ * - 原子写入通过同目录临时文件加 rename 完成。
8
+ */
9
+
10
+ import path from "node:path";
11
+ import { randomUUID } from "node:crypto";
12
+ import {
13
+ access,
14
+ mkdir,
15
+ lstat,
16
+ readFile,
17
+ readdir,
18
+ rename,
19
+ rm,
20
+ writeFile,
21
+ } from "node:fs/promises";
22
+ import type {
23
+ DefaultFileMemoryRootInput,
24
+ FileMemoryStorageAdapterOptions,
25
+ } from "@/memory/types/BuiltinMemoryProvider.js";
26
+ import type {
27
+ MemoryStorageAdapter,
28
+ MemoryStorageEntry,
29
+ } from "@/memory/types/MemoryStorage.js";
30
+
31
+ /** 校验并规范化 Provider 内部逻辑 key。 */
32
+ function normalize_storage_key(input: string): string {
33
+ const key = String(input || "").replace(/\\/g, "/").replace(/^\/+/, "").trim();
34
+ if (!key) throw new Error("Memory storage key is required");
35
+ const segments = key.split("/");
36
+ if (segments.some((segment) => !segment || segment === "." || segment === "..")) {
37
+ throw new Error(`Invalid Memory storage key: ${input}`);
38
+ }
39
+ return segments.join("/");
40
+ }
41
+
42
+ /** 递归列出目录中的全部普通文件。 */
43
+ async function list_files_recursively(directory_path: string): Promise<string[]> {
44
+ const entries = await readdir(directory_path, { withFileTypes: true }).catch(
45
+ (error: NodeJS.ErrnoException) => {
46
+ if (error.code === "ENOENT") return [];
47
+ throw error;
48
+ },
49
+ );
50
+ const files: string[] = [];
51
+ for (const entry of entries) {
52
+ const entry_path = path.join(directory_path, entry.name);
53
+ if (entry.isDirectory()) {
54
+ files.push(...await list_files_recursively(entry_path));
55
+ } else if (entry.isFile() && !entry.name.endsWith(".tmp")) {
56
+ files.push(entry_path);
57
+ }
58
+ }
59
+ return files;
60
+ }
61
+
62
+ /**
63
+ * 返回 Builtin File Adapter 的默认 Agent 级存储目录。
64
+ *
65
+ * 关键点(中文):该路径规则属于 Memory Plugin 的本地 Adapter,不属于 Agent SDK。
66
+ */
67
+ export function get_default_file_memory_root_path(
68
+ input: DefaultFileMemoryRootInput,
69
+ ): string {
70
+ const platform_root_input = String(input.platform_root_path || "").trim();
71
+ if (!platform_root_input || !path.isAbsolute(platform_root_input)) {
72
+ throw new Error("Memory platform_root_path must be absolute");
73
+ }
74
+ const platform_root_path = path.resolve(platform_root_input);
75
+ const agent_id = String(input.agent_id || "").trim();
76
+ if (!agent_id || !/^[a-z0-9_]+$/u.test(agent_id)) {
77
+ throw new Error(`Invalid Memory agent_id: ${input.agent_id}`);
78
+ }
79
+ return path.join(platform_root_path, "agents", agent_id, "memory");
80
+ }
81
+
82
+ /** 基于本地文件的 Memory Storage Adapter。 */
83
+ export class FileMemoryStorageAdapter implements MemoryStorageAdapter {
84
+ /** 当前 Adapter 稳定名称。 */
85
+ readonly name = "file";
86
+
87
+ /** 当前 Adapter 独占的绝对根目录。 */
88
+ readonly root_path: string;
89
+
90
+ constructor(options: FileMemoryStorageAdapterOptions) {
91
+ const root_path = String(options.root_path || "").trim();
92
+ if (!root_path) throw new Error("FileMemoryStorageAdapter requires root_path");
93
+ if (!path.isAbsolute(root_path)) {
94
+ throw new Error("FileMemoryStorageAdapter root_path must be absolute");
95
+ }
96
+ this.root_path = path.resolve(root_path);
97
+ }
98
+
99
+ /** 初始化独占根目录。 */
100
+ async initialize(): Promise<void> {
101
+ await mkdir(this.root_path, { recursive: true });
102
+ }
103
+
104
+ /** 判断逻辑 key 是否存在。 */
105
+ async has(key: string): Promise<boolean> {
106
+ await this.assert_no_symbolic_links(key, true);
107
+ return await access(this.resolve_key(key)).then(() => true).catch(
108
+ (error: NodeJS.ErrnoException) => {
109
+ if (error.code === "ENOENT") return false;
110
+ throw error;
111
+ },
112
+ );
113
+ }
114
+
115
+ /** 读取逻辑 key;不存在时返回空。 */
116
+ async read(key: string): Promise<string | null> {
117
+ await this.assert_no_symbolic_links(key, true);
118
+ return await readFile(this.resolve_key(key), "utf8").catch((error: NodeJS.ErrnoException) => {
119
+ if (error.code === "ENOENT") return null;
120
+ throw error;
121
+ });
122
+ }
123
+
124
+ /** 原子创建或替换逻辑 key。 */
125
+ async write(key: string, content: string): Promise<void> {
126
+ const target_path = this.resolve_key(key);
127
+ await this.assert_no_symbolic_links(key, false);
128
+ await mkdir(path.dirname(target_path), { recursive: true });
129
+ await this.assert_no_symbolic_links(key, true);
130
+ const temporary_path = `${target_path}.${process.pid}.${randomUUID()}.tmp`;
131
+ try {
132
+ await writeFile(temporary_path, String(content || ""), "utf8");
133
+ await rename(temporary_path, target_path);
134
+ } catch (error) {
135
+ await rm(temporary_path, { force: true }).catch(() => undefined);
136
+ throw error;
137
+ }
138
+ }
139
+
140
+ /** 列出逻辑前缀下的全部文本条目。 */
141
+ async list(prefix: string): Promise<MemoryStorageEntry[]> {
142
+ const normalized_prefix = normalize_storage_key(prefix);
143
+ await this.assert_no_symbolic_links(normalized_prefix, true);
144
+ const prefix_path = this.resolve_key(normalized_prefix);
145
+ const files = await list_files_recursively(prefix_path);
146
+ const entries = await Promise.all(files.map(async (file_path) => ({
147
+ key: path.relative(this.root_path, file_path).replace(/\\/g, "/"),
148
+ content: await readFile(file_path, "utf8"),
149
+ })));
150
+ return entries.sort((left, right) => left.key.localeCompare(right.key));
151
+ }
152
+
153
+ /** 删除逻辑 key。 */
154
+ async delete(key: string): Promise<void> {
155
+ await this.assert_no_symbolic_links(key, true);
156
+ await rm(this.resolve_key(key), { force: true });
157
+ }
158
+
159
+ /** File Adapter 没有长期句柄需要释放。 */
160
+ async dispose(): Promise<void> {}
161
+
162
+ /** 把逻辑 key 安全解析到当前独占根目录。 */
163
+ private resolve_key(key: string): string {
164
+ const normalized_key = normalize_storage_key(key);
165
+ const resolved_path = path.resolve(this.root_path, normalized_key);
166
+ const relative_path = path.relative(this.root_path, resolved_path);
167
+ if (
168
+ relative_path === ".."
169
+ || relative_path.startsWith(`..${path.sep}`)
170
+ || path.isAbsolute(relative_path)
171
+ ) {
172
+ throw new Error(`Memory storage key escapes root: ${key}`);
173
+ }
174
+ return resolved_path;
175
+ }
176
+
177
+ /** 拒绝 root 内部通过符号链接把逻辑 key 重定向到其他物理位置。 */
178
+ private async assert_no_symbolic_links(
179
+ key: string,
180
+ include_target: boolean,
181
+ ): Promise<void> {
182
+ const segments = normalize_storage_key(key).split("/");
183
+ const segment_count = include_target ? segments.length : Math.max(0, segments.length - 1);
184
+ let current_path = this.root_path;
185
+ for (let index = 0; index < segment_count; index += 1) {
186
+ current_path = path.join(current_path, segments[index] || "");
187
+ const stats = await lstat(current_path).catch((error: NodeJS.ErrnoException) => {
188
+ if (error.code === "ENOENT") return null;
189
+ throw error;
190
+ });
191
+ if (!stats) return;
192
+ if (stats.isSymbolicLink()) {
193
+ throw new Error(`Memory storage key contains symbolic link: ${key}`);
194
+ }
195
+ }
196
+ }
197
+ }