@aigne/afs-history 1.2.0-beta.4 → 1.2.0-beta.6

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 (45) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/lib/cjs/index.d.ts +9 -3
  3. package/lib/cjs/index.js +217 -22
  4. package/lib/cjs/storage/index.d.ts +10 -6
  5. package/lib/cjs/storage/index.js +67 -21
  6. package/lib/cjs/storage/migrate.d.ts +1 -1
  7. package/lib/cjs/storage/migrate.js +14 -5
  8. package/lib/cjs/storage/migrations/003-add-compact-table.d.ts +2 -0
  9. package/lib/cjs/storage/migrations/003-add-compact-table.js +23 -0
  10. package/lib/cjs/storage/migrations/004-add-memory-table.d.ts +2 -0
  11. package/lib/cjs/storage/migrations/004-add-memory-table.js +23 -0
  12. package/lib/cjs/storage/migrations/005-add-indexes.d.ts +2 -0
  13. package/lib/cjs/storage/migrations/005-add-indexes.js +31 -0
  14. package/lib/cjs/storage/models/compact.d.ts +183 -0
  15. package/lib/cjs/storage/models/compact.js +27 -0
  16. package/lib/cjs/storage/models/memory.d.ts +182 -0
  17. package/lib/cjs/storage/models/memory.js +27 -0
  18. package/lib/cjs/storage/type.d.ts +31 -4
  19. package/lib/dts/index.d.ts +9 -3
  20. package/lib/dts/storage/index.d.ts +10 -6
  21. package/lib/dts/storage/migrate.d.ts +1 -1
  22. package/lib/dts/storage/migrations/003-add-compact-table.d.ts +2 -0
  23. package/lib/dts/storage/migrations/004-add-memory-table.d.ts +2 -0
  24. package/lib/dts/storage/migrations/005-add-indexes.d.ts +2 -0
  25. package/lib/dts/storage/models/compact.d.ts +183 -0
  26. package/lib/dts/storage/models/memory.d.ts +182 -0
  27. package/lib/dts/storage/type.d.ts +31 -4
  28. package/lib/esm/index.d.ts +9 -3
  29. package/lib/esm/index.js +217 -22
  30. package/lib/esm/storage/index.d.ts +10 -6
  31. package/lib/esm/storage/index.js +68 -22
  32. package/lib/esm/storage/migrate.d.ts +1 -1
  33. package/lib/esm/storage/migrate.js +14 -5
  34. package/lib/esm/storage/migrations/003-add-compact-table.d.ts +2 -0
  35. package/lib/esm/storage/migrations/003-add-compact-table.js +20 -0
  36. package/lib/esm/storage/migrations/004-add-memory-table.d.ts +2 -0
  37. package/lib/esm/storage/migrations/004-add-memory-table.js +20 -0
  38. package/lib/esm/storage/migrations/005-add-indexes.d.ts +2 -0
  39. package/lib/esm/storage/migrations/005-add-indexes.js +28 -0
  40. package/lib/esm/storage/models/compact.d.ts +183 -0
  41. package/lib/esm/storage/models/compact.js +22 -0
  42. package/lib/esm/storage/models/memory.d.ts +182 -0
  43. package/lib/esm/storage/models/memory.js +22 -0
  44. package/lib/esm/storage/type.d.ts +31 -4
  45. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -6,6 +6,27 @@
6
6
  * dependencies
7
7
  * @aigne/afs bumped to 1.2.0
8
8
 
9
+ ## [1.2.0-beta.6](https://github.com/AIGNE-io/aigne-framework/compare/afs-history-v1.2.0-beta.5...afs-history-v1.2.0-beta.6) (2026-01-06)
10
+
11
+
12
+ ### Features
13
+
14
+ * **core:** add cross session user memory support ([#873](https://github.com/AIGNE-io/aigne-framework/issues/873)) ([f377aa1](https://github.com/AIGNE-io/aigne-framework/commit/f377aa17f2cf8004fd3225ade4a37fd90af1292f))
15
+
16
+ ## [1.2.0-beta.5](https://github.com/AIGNE-io/aigne-framework/compare/afs-history-v1.2.0-beta.4...afs-history-v1.2.0-beta.5) (2025-12-31)
17
+
18
+
19
+ ### Features
20
+
21
+ * add session compact support for AIAgent ([#863](https://github.com/AIGNE-io/aigne-framework/issues/863)) ([9010918](https://github.com/AIGNE-io/aigne-framework/commit/9010918cd3f18b02b5c60ddc9ed5c34b568d0b28))
22
+
23
+
24
+ ### Dependencies
25
+
26
+ * The following workspace dependencies were updated
27
+ * dependencies
28
+ * @aigne/afs bumped to 1.4.0-beta.5
29
+
9
30
  ## [1.2.0-beta.4](https://github.com/AIGNE-io/aigne-framework/compare/afs-history-v1.2.0-beta.3...afs-history-v1.2.0-beta.4) (2025-12-26)
10
31
 
11
32
 
@@ -1,4 +1,4 @@
1
- import type { AFSListOptions, AFSListResult, AFSModule, AFSReadResult, AFSRoot } from "@aigne/afs";
1
+ import type { AFSDeleteOptions, AFSDeleteResult, AFSListOptions, AFSListResult, AFSModule, AFSReadOptions, AFSReadResult, AFSRoot, AFSWriteEntryPayload, AFSWriteResult } from "@aigne/afs";
2
2
  import { SharedAFSStorage, type SharedAFSStorageOptions } from "./storage/index.js";
3
3
  export * from "./storage/index.js";
4
4
  export interface AFSHistoryOptions {
@@ -6,9 +6,15 @@ export interface AFSHistoryOptions {
6
6
  }
7
7
  export declare class AFSHistory implements AFSModule {
8
8
  constructor(options?: AFSHistoryOptions);
9
- private storage;
10
9
  readonly name: string;
10
+ private storage;
11
+ private afs?;
12
+ private router;
13
+ private rootEntries;
11
14
  onMount(afs: AFSRoot): void;
12
15
  list(path: string, options?: AFSListOptions): Promise<AFSListResult>;
13
- read(path: string): Promise<AFSReadResult>;
16
+ read(path: string, options?: AFSReadOptions): Promise<AFSReadResult>;
17
+ write(path: string, content: AFSWriteEntryPayload): Promise<AFSWriteResult>;
18
+ delete(path: string, _options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
19
+ private normalizePath;
14
20
  }
package/lib/cjs/index.js CHANGED
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.AFSHistory = void 0;
18
18
  const uuid_1 = require("@aigne/uuid");
19
+ const radix3_1 = require("radix3");
19
20
  const ufo_1 = require("ufo");
20
21
  const index_js_1 = require("./storage/index.js");
21
22
  __exportStar(require("./storage/index.js"), exports);
@@ -26,34 +27,228 @@ class AFSHistory {
26
27
  ? options.storage.withModule(this)
27
28
  : new index_js_1.SharedAFSStorage(options?.storage).withModule(this);
28
29
  }
29
- storage;
30
30
  name = "history";
31
+ storage;
32
+ afs;
33
+ router = (0, radix3_1.createRouter)({
34
+ routes: {
35
+ "/by-session": { action: "list", type: "history", scope: "session" },
36
+ "/by-session/:sessionId": { action: "list", type: "history", scope: "session" },
37
+ "/by-session/:sessionId/new": { action: "create", type: "history", scope: "session" },
38
+ "/by-session/:sessionId/@metadata/compact": {
39
+ action: "list",
40
+ type: "compact",
41
+ scope: "session",
42
+ },
43
+ "/by-session/:sessionId/@metadata/compact/new": {
44
+ action: "create",
45
+ type: "compact",
46
+ scope: "session",
47
+ },
48
+ "/by-session/:sessionId/@metadata/compact/:compactId": {
49
+ action: "read",
50
+ type: "compact",
51
+ scope: "session",
52
+ },
53
+ "/by-session/:sessionId/@metadata/memory": {
54
+ action: "list",
55
+ type: "memory",
56
+ scope: "session",
57
+ },
58
+ "/by-session/:sessionId/@metadata/memory/new": {
59
+ action: "create",
60
+ type: "memory",
61
+ scope: "session",
62
+ },
63
+ "/by-session/:sessionId/@metadata/memory/:memoryId": {
64
+ action: "read",
65
+ type: "memory",
66
+ scope: "session",
67
+ },
68
+ "/by-session/:sessionId/:entryId": { action: "read", type: "history", scope: "session" },
69
+ "/by-user": { action: "list", type: "history", scope: "user" },
70
+ "/by-user/:userId": { action: "list", type: "history", scope: "user" },
71
+ "/by-user/:userId/new": { action: "create", type: "history", scope: "user" },
72
+ "/by-user/:userId/@metadata/compact": { action: "list", type: "compact", scope: "user" },
73
+ "/by-user/:userId/@metadata/compact/new": {
74
+ action: "create",
75
+ type: "compact",
76
+ scope: "user",
77
+ },
78
+ "/by-user/:userId/@metadata/compact/:compactId": {
79
+ action: "read",
80
+ type: "compact",
81
+ scope: "user",
82
+ },
83
+ "/by-user/:userId/@metadata/memory": { action: "list", type: "memory", scope: "user" },
84
+ "/by-user/:userId/@metadata/memory/new": { action: "create", type: "memory", scope: "user" },
85
+ "/by-user/:userId/@metadata/memory/:memoryId": {
86
+ action: "read",
87
+ type: "memory",
88
+ scope: "user",
89
+ },
90
+ "/by-user/:userId/:entryId": { action: "read", type: "history", scope: "user" },
91
+ "/by-agent": { action: "list", type: "history", scope: "agent" },
92
+ "/by-agent/:agentId": { action: "list", type: "history", scope: "agent" },
93
+ "/by-agent/:agentId/new": { action: "create", type: "history", scope: "agent" },
94
+ "/by-agent/:agentId/@metadata/compact": { action: "list", type: "compact", scope: "agent" },
95
+ "/by-agent/:agentId/@metadata/compact/new": {
96
+ action: "create",
97
+ type: "compact",
98
+ scope: "agent",
99
+ },
100
+ "/by-agent/:agentId/@metadata/compact/:compactId": {
101
+ action: "read",
102
+ type: "compact",
103
+ scope: "agent",
104
+ },
105
+ "/by-agent/:agentId/:entryId": { action: "read", type: "history", scope: "agent" },
106
+ },
107
+ });
108
+ rootEntries = [
109
+ {
110
+ id: "by-session",
111
+ path: "/by-session",
112
+ description: "Retrieve history entries by session ID.",
113
+ },
114
+ {
115
+ id: "by-user",
116
+ path: "/by-user",
117
+ description: "Retrieve history entries by user ID.",
118
+ },
119
+ {
120
+ id: "by-agent",
121
+ path: "/by-agent",
122
+ description: "Retrieve history entries by agent ID.",
123
+ },
124
+ ];
31
125
  onMount(afs) {
32
- afs.on("agentSucceed", ({ agentId, userId, sessionId, input, output, messages }) => {
33
- this.storage
34
- .create({
35
- path: (0, ufo_1.joinURL)("/", (0, uuid_1.v7)()),
36
- agentId,
37
- userId,
38
- sessionId,
39
- content: { input, output, messages },
40
- })
41
- .then((entry) => {
42
- afs.emit("historyCreated", { entry });
43
- })
44
- .catch((error) => {
45
- console.error("Failed to store history entry", error);
46
- });
47
- });
126
+ this.afs = afs;
48
127
  }
49
128
  async list(path, options) {
50
- if (path !== "/")
129
+ if (path === "/")
130
+ return { data: this.rootEntries };
131
+ const match = this.router.lookup(path);
132
+ if (!match || match.action !== "list") {
51
133
  return { data: [] };
52
- return await this.storage.list(options);
134
+ }
135
+ const { type, scope } = match;
136
+ const mergedFilter = {
137
+ ...options?.filter,
138
+ ...match.params,
139
+ };
140
+ const result = await this.storage.list({
141
+ ...options,
142
+ type,
143
+ scope,
144
+ filter: mergedFilter,
145
+ });
146
+ return {
147
+ ...result,
148
+ data: result.data.map((entry) => ({
149
+ ...entry,
150
+ path: this.normalizePath(entry, scope, type),
151
+ })),
152
+ };
153
+ }
154
+ async read(path, options) {
155
+ const match = this.router.lookup(path);
156
+ if (!match || match.action !== "read")
157
+ return {};
158
+ const { type, scope } = match;
159
+ const entryId = match.params?.entryId ?? match.params?.compactId ?? match.params?.memoryId;
160
+ if (!entryId)
161
+ throw new Error(`Entry ID is required in the path to read ${type}.`);
162
+ const mergedFilter = {
163
+ ...options?.filter,
164
+ ...match.params,
165
+ };
166
+ const data = await this.storage.read(entryId, {
167
+ type,
168
+ scope,
169
+ filter: mergedFilter,
170
+ });
171
+ // Add virtual path prefix for entries
172
+ return {
173
+ data: data && {
174
+ ...data,
175
+ path: this.normalizePath(data, scope, type),
176
+ },
177
+ };
178
+ }
179
+ async write(path, content) {
180
+ const id = (0, uuid_1.v7)();
181
+ const match = this.router.lookup(path);
182
+ if (!match || match.action !== "create") {
183
+ throw new Error("Can only write to paths with 'new' suffix: /by-{scope}/{scopeId}/new or /by-{scope}/{scopeId}/@metadata/{type}/new");
184
+ }
185
+ const { type, scope } = match;
186
+ // Validate that scope ID is provided in path params
187
+ const scopeIdField = `${scope}Id`;
188
+ const scopeIdValue = match.params?.[scopeIdField];
189
+ if (!scopeIdValue) {
190
+ throw new Error(`${scopeIdField} is required in the path to create ${type} entry.`);
191
+ }
192
+ const entry = await this.storage.create({
193
+ ...match.params,
194
+ ...content,
195
+ id,
196
+ path: (0, ufo_1.joinURL)("/", type, id),
197
+ }, { type, scope });
198
+ // Emit event for history entries
199
+ if (type === "history") {
200
+ this.afs?.emit("historyCreated", { entry });
201
+ }
202
+ return {
203
+ data: {
204
+ ...entry,
205
+ path: this.normalizePath(entry, scope, type),
206
+ },
207
+ };
208
+ }
209
+ async delete(path, _options) {
210
+ const match = this.router.lookup(path);
211
+ if (!match || match.action !== "read") {
212
+ throw new Error(`Cannot delete: path not found or not a valid entry path`);
213
+ }
214
+ const { type, scope } = match;
215
+ const entryId = match.params?.entryId ?? match.params?.compactId ?? match.params?.memoryId;
216
+ if (!entryId)
217
+ throw new Error(`Entry ID is required in the path to delete ${type}.`);
218
+ const result = await this.storage.delete(entryId, {
219
+ type,
220
+ scope,
221
+ filter: match.params,
222
+ });
223
+ if (result.deletedCount === 0) {
224
+ return {
225
+ message: `No ${type} entry found with id ${entryId}`,
226
+ };
227
+ }
228
+ return {
229
+ message: `Deleted ${result.deletedCount} ${type} entry`,
230
+ };
53
231
  }
54
- async read(path) {
55
- const data = await this.storage.read(path);
56
- return { data };
232
+ normalizePath(entry, scope, entryType) {
233
+ const scopeIdMap = {
234
+ session: entry.sessionId,
235
+ user: entry.userId,
236
+ agent: entry.agentId,
237
+ };
238
+ const scopeId = scopeIdMap[scope];
239
+ if (!scopeId) {
240
+ throw new Error(`Cannot reset path for entry without ${scope} info.`);
241
+ }
242
+ const prefix = `by-${scope}`;
243
+ // Build path based on entry type
244
+ if (entryType === "compact") {
245
+ return (0, ufo_1.joinURL)("/", prefix, scopeId, "@metadata/compact", entry.id);
246
+ }
247
+ if (entryType === "memory") {
248
+ return (0, ufo_1.joinURL)("/", prefix, scopeId, "@metadata/memory", entry.id);
249
+ }
250
+ // Default: history entry
251
+ return (0, ufo_1.joinURL)("/", prefix, scopeId, entry.id);
57
252
  }
58
253
  }
59
254
  exports.AFSHistory = AFSHistory;
@@ -1,7 +1,6 @@
1
1
  import type { AFSEntry, AFSModule } from "@aigne/afs";
2
2
  import { initDatabase } from "@aigne/sqlite";
3
- import { entriesTable } from "./models/entries.js";
4
- import type { AFSStorage, AFSStorageCreatePayload, AFSStorageListOptions } from "./type.js";
3
+ import type { AFSStorage, AFSStorageCreateOptions, AFSStorageCreatePayload, AFSStorageDeleteOptions, AFSStorageListOptions, AFSStorageReadOptions } from "./type.js";
5
4
  export * from "./type.js";
6
5
  export interface SharedAFSStorageOptions {
7
6
  url?: string;
@@ -15,11 +14,16 @@ export declare class SharedAFSStorage {
15
14
  }
16
15
  export declare class AFSStorageWithModule implements AFSStorage {
17
16
  private db;
18
- private table;
19
- constructor(db: ReturnType<typeof initDatabase>, table: Promise<ReturnType<typeof entriesTable>>);
17
+ private module;
18
+ constructor(db: ReturnType<typeof initDatabase>, module: AFSModule);
19
+ private _tables?;
20
+ private get tables();
20
21
  list(options?: AFSStorageListOptions): Promise<{
21
22
  data: AFSEntry[];
22
23
  }>;
23
- read(path: string): Promise<AFSEntry | undefined>;
24
- create(entry: AFSStorageCreatePayload): Promise<AFSEntry>;
24
+ read(id: string, options?: AFSStorageReadOptions): Promise<AFSEntry | undefined>;
25
+ create(entry: AFSStorageCreatePayload, options?: AFSStorageCreateOptions): Promise<AFSEntry>;
26
+ delete(id: string, options?: AFSStorageDeleteOptions): Promise<{
27
+ deletedCount: number;
28
+ }>;
25
29
  }
@@ -17,7 +17,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.AFSStorageWithModule = exports.SharedAFSStorage = void 0;
18
18
  const sqlite_1 = require("@aigne/sqlite");
19
19
  const migrate_js_1 = require("./migrate.js");
20
+ const compact_js_1 = require("./models/compact.js");
20
21
  const entries_js_1 = require("./models/entries.js");
22
+ const memory_js_1 = require("./models/memory.js");
21
23
  __exportStar(require("./type.js"), exports);
22
24
  const DEFAULT_AFS_STORAGE_LIST_LIMIT = 10;
23
25
  class SharedAFSStorage {
@@ -31,57 +33,101 @@ class SharedAFSStorage {
31
33
  return this._db;
32
34
  }
33
35
  withModule(module) {
34
- return new AFSStorageWithModule(this.db, (0, migrate_js_1.migrate)(this.db, module).then(() => (0, entries_js_1.entriesTable)(module)));
36
+ return new AFSStorageWithModule(this.db, module);
35
37
  }
36
38
  }
37
39
  exports.SharedAFSStorage = SharedAFSStorage;
38
40
  class AFSStorageWithModule {
39
41
  db;
40
- table;
41
- constructor(db, table) {
42
+ module;
43
+ constructor(db, module) {
42
44
  this.db = db;
43
- this.table = table;
45
+ this.module = module;
46
+ }
47
+ _tables;
48
+ get tables() {
49
+ if (!this._tables) {
50
+ this._tables = this.db.then((db) => (0, migrate_js_1.migrate)(db, this.module).then(() => ({
51
+ db,
52
+ entries: (0, entries_js_1.entriesTable)(this.module),
53
+ compact: (0, compact_js_1.compactTable)(this.module),
54
+ memory: (0, memory_js_1.memoryTable)(this.module),
55
+ })));
56
+ }
57
+ return this._tables;
44
58
  }
45
59
  async list(options = {}) {
46
- const { filter, limit = DEFAULT_AFS_STORAGE_LIST_LIMIT } = options;
47
- const db = await this.db;
48
- const table = await this.table;
60
+ const { type = "history", scope, filter, limit = DEFAULT_AFS_STORAGE_LIST_LIMIT } = options;
61
+ const { db, entries, compact, memory } = await this.tables;
62
+ // Select table based on type
63
+ const table = type === "compact" ? compact : type === "memory" ? memory : entries;
49
64
  const data = await db
50
65
  .select()
51
66
  .from(table)
52
- .where((0, sqlite_1.and)(filter?.agentId ? (0, sqlite_1.eq)(table.agentId, filter.agentId) : undefined, filter?.userId ? (0, sqlite_1.eq)(table.userId, filter.userId) : undefined, filter?.sessionId ? (0, sqlite_1.eq)(table.sessionId, filter.sessionId) : undefined))
53
- .orderBy(...(options.orderBy ?? []).map((item) => (item[1] === "asc" ? sqlite_1.asc : sqlite_1.desc)(sqlite_1.sql.identifier(item[0]))))
67
+ .where((0, sqlite_1.and)(
68
+ // Add scope filter for compact/memory tables
69
+ scope && type !== "history"
70
+ ? (0, sqlite_1.eq)((0, sqlite_1.sql) `json_extract(${table.metadata}, '$.scope')`, scope)
71
+ : undefined, filter?.agentId ? (0, sqlite_1.eq)(table.agentId, filter.agentId) : undefined, filter?.userId ? (0, sqlite_1.eq)(table.userId, filter.userId) : undefined, filter?.sessionId ? (0, sqlite_1.eq)(table.sessionId, filter.sessionId) : undefined, filter?.before ? (0, sqlite_1.lt)(table.createdAt, new Date(filter.before)) : undefined, filter?.after ? (0, sqlite_1.gt)(table.createdAt, new Date(filter.after)) : undefined))
72
+ .orderBy(...(options.orderBy ?? [["createdAt", "desc"]]).map((item) => (item[1] === "asc" ? sqlite_1.asc : sqlite_1.desc)(sqlite_1.sql.identifier(item[0]))))
54
73
  .limit(limit)
55
74
  .execute();
56
75
  return { data };
57
76
  }
58
- async read(path) {
59
- const db = await this.db;
60
- const table = await this.table;
77
+ async read(id, options) {
78
+ const { type = "history", scope, filter } = options ?? {};
79
+ const { db, entries, compact, memory } = await this.tables;
80
+ // Select table based on type
81
+ const table = type === "compact" ? compact : type === "memory" ? memory : entries;
61
82
  return db
62
83
  .select()
63
84
  .from(table)
64
- .where((0, sqlite_1.eq)(table.path, path))
85
+ .where((0, sqlite_1.and)((0, sqlite_1.eq)(table.id, id),
86
+ // Add scope filter for compact/memory tables
87
+ scope && type !== "history"
88
+ ? (0, sqlite_1.eq)((0, sqlite_1.sql) `json_extract(${table.metadata}, '$.scope')`, scope)
89
+ : undefined, filter?.agentId ? (0, sqlite_1.eq)(table.agentId, filter.agentId) : undefined, filter?.userId ? (0, sqlite_1.eq)(table.userId, filter.userId) : undefined, filter?.sessionId ? (0, sqlite_1.eq)(table.sessionId, filter.sessionId) : undefined))
65
90
  .limit(1)
66
91
  .execute()
67
- .then((memory) => memory.at(0));
92
+ .then((rows) => rows.at(0));
68
93
  }
69
- async create(entry) {
70
- const db = await this.db;
71
- const table = await this.table;
94
+ async create(entry, options) {
95
+ const { type = "history", scope } = options ?? {};
96
+ const { db, entries, compact, memory } = await this.tables;
97
+ // Select table based on type
98
+ const table = type === "compact" ? compact : type === "memory" ? memory : entries;
99
+ // Prepare entry data - only add scope to metadata for compact/memory types
100
+ const entryData = { ...entry, metadata: { ...entry.metadata, scope } };
101
+ // Try update first, then insert if not found (upsert)
72
102
  let result = await db
73
103
  .update(table)
74
- .set(entry)
75
- .where((0, sqlite_1.eq)(table.path, entry.path))
104
+ .set(entryData)
105
+ .where((0, sqlite_1.eq)(table.id, entry.id))
76
106
  .returning()
77
107
  .execute();
78
108
  if (!result.length) {
79
- result = await db.insert(table).values(entry).returning().execute();
109
+ result = await db.insert(table).values(entryData).returning().execute();
80
110
  }
81
111
  const [res] = result;
82
112
  if (!res)
83
- throw new Error("Failed to create AFS entry, no result");
113
+ throw new Error(`Failed to create ${type} entry, no result`);
84
114
  return res;
85
115
  }
116
+ async delete(id, options) {
117
+ const { type = "history", scope, filter } = options ?? {};
118
+ const { db, entries, compact, memory } = await this.tables;
119
+ // Select table based on type
120
+ const table = type === "compact" ? compact : type === "memory" ? memory : entries;
121
+ const result = await db
122
+ .delete(table)
123
+ .where((0, sqlite_1.and)((0, sqlite_1.eq)(table.id, id),
124
+ // Add scope filter for compact/memory tables
125
+ scope && type !== "history"
126
+ ? (0, sqlite_1.eq)((0, sqlite_1.sql) `json_extract(${table.metadata}, '$.scope')`, scope)
127
+ : undefined, filter?.agentId ? (0, sqlite_1.eq)(table.agentId, filter.agentId) : undefined, filter?.userId ? (0, sqlite_1.eq)(table.userId, filter.userId) : undefined, filter?.sessionId ? (0, sqlite_1.eq)(table.sessionId, filter.sessionId) : undefined))
128
+ .returning()
129
+ .execute();
130
+ return { deletedCount: result.length };
131
+ }
86
132
  }
87
133
  exports.AFSStorageWithModule = AFSStorageWithModule;
@@ -1,3 +1,3 @@
1
1
  import type { AFSModule } from "@aigne/afs";
2
2
  import { type initDatabase } from "@aigne/sqlite";
3
- export declare function migrate(db: ReturnType<typeof initDatabase>, module: AFSModule): Promise<void>;
3
+ export declare function migrate(db: Awaited<ReturnType<typeof initDatabase>>, module: AFSModule): Promise<void>;
@@ -5,8 +5,17 @@ const sqlite_1 = require("@aigne/sqlite");
5
5
  const uuid_1 = require("@aigne/uuid");
6
6
  const _001_init_js_1 = require("./migrations/001-init.js");
7
7
  const _002_add_agent_id_js_1 = require("./migrations/002-add-agent-id.js");
8
+ const _003_add_compact_table_js_1 = require("./migrations/003-add-compact-table.js");
9
+ const _004_add_memory_table_js_1 = require("./migrations/004-add-memory-table.js");
10
+ const _005_add_indexes_js_1 = require("./migrations/005-add-indexes.js");
8
11
  async function migrate(db, module) {
9
- const migrations = [_001_init_js_1.init, _002_add_agent_id_js_1.addAgentId];
12
+ const migrations = [
13
+ _001_init_js_1.init,
14
+ _002_add_agent_id_js_1.addAgentId,
15
+ _003_add_compact_table_js_1.addCompactTable,
16
+ _004_add_memory_table_js_1.addMemoryTable,
17
+ _005_add_indexes_js_1.addIndexes,
18
+ ];
10
19
  const migrationsTable = "__drizzle_migrations";
11
20
  const migrationTableCreate = (0, sqlite_1.sql) `
12
21
  CREATE TABLE IF NOT EXISTS ${sqlite_1.sql.identifier(migrationsTable)} (
@@ -15,18 +24,18 @@ async function migrate(db, module) {
15
24
  "hash" TEXT NOT NULL
16
25
  )
17
26
  `;
18
- await (await db).run(migrationTableCreate).execute();
19
- const dbMigrations = await (await db)
27
+ await db.run(migrationTableCreate).execute();
28
+ const dbMigrations = await db
20
29
  .values((0, sqlite_1.sql) `SELECT "id", "moduleId", "hash" FROM ${sqlite_1.sql.identifier(migrationsTable)} WHERE "moduleId" = ${sqlite_1.sql.param(module.name)} ORDER BY id DESC LIMIT 1`)
21
30
  .execute();
22
31
  const lastDbMigration = dbMigrations[0];
23
32
  const queriesToRun = [];
24
33
  for (const migration of migrations) {
25
- if (!lastDbMigration || lastDbMigration[1] < migration.hash) {
34
+ if (!lastDbMigration || lastDbMigration[2] < migration.hash) {
26
35
  queriesToRun.push(...migration.sql(module), (0, sqlite_1.sql) `INSERT INTO ${sqlite_1.sql.identifier(migrationsTable)} ("id", "moduleId", "hash") VALUES(${sqlite_1.sql.param((0, uuid_1.v7)())}, ${sqlite_1.sql.param(module.name)}, ${sqlite_1.sql.param(migration.hash)})`);
27
36
  }
28
37
  }
29
38
  for (const query of queriesToRun) {
30
- await (await db).run(query).execute();
39
+ await db.run(query).execute();
31
40
  }
32
41
  }
@@ -0,0 +1,2 @@
1
+ import type { AFSStorageMigrations } from "../type.js";
2
+ export declare const addCompactTable: AFSStorageMigrations;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addCompactTable = void 0;
4
+ const sqlite_1 = require("@aigne/sqlite");
5
+ const compact_js_1 = require("../models/compact.js");
6
+ exports.addCompactTable = {
7
+ hash: "003-add-compact-table",
8
+ sql: (module) => [
9
+ (0, sqlite_1.sql) `\
10
+ CREATE TABLE IF NOT EXISTS ${sqlite_1.sql.identifier((0, compact_js_1.compactTableName)(module))} (
11
+ "id" TEXT NOT NULL PRIMARY KEY,
12
+ "createdAt" DATETIME NOT NULL,
13
+ "updatedAt" DATETIME NOT NULL,
14
+ "path" TEXT NOT NULL,
15
+ "sessionId" TEXT,
16
+ "userId" TEXT,
17
+ "agentId" TEXT,
18
+ "metadata" JSON,
19
+ "content" JSON
20
+ )
21
+ `,
22
+ ],
23
+ };
@@ -0,0 +1,2 @@
1
+ import type { AFSStorageMigrations } from "../type.js";
2
+ export declare const addMemoryTable: AFSStorageMigrations;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addMemoryTable = void 0;
4
+ const sqlite_1 = require("@aigne/sqlite");
5
+ const memory_js_1 = require("../models/memory.js");
6
+ exports.addMemoryTable = {
7
+ hash: "004-add-memory-table",
8
+ sql: (module) => [
9
+ (0, sqlite_1.sql) `\
10
+ CREATE TABLE IF NOT EXISTS ${sqlite_1.sql.identifier((0, memory_js_1.memoryTableName)(module))} (
11
+ "id" TEXT NOT NULL PRIMARY KEY,
12
+ "createdAt" DATETIME NOT NULL,
13
+ "updatedAt" DATETIME NOT NULL,
14
+ "path" TEXT NOT NULL,
15
+ "sessionId" TEXT,
16
+ "userId" TEXT,
17
+ "agentId" TEXT,
18
+ "metadata" JSON,
19
+ "content" JSON
20
+ )
21
+ `,
22
+ ],
23
+ };
@@ -0,0 +1,2 @@
1
+ import type { AFSStorageMigrations } from "../type.js";
2
+ export declare const addIndexes: AFSStorageMigrations;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addIndexes = void 0;
4
+ const sqlite_1 = require("@aigne/sqlite");
5
+ const compact_js_1 = require("../models/compact.js");
6
+ const entries_js_1 = require("../models/entries.js");
7
+ const memory_js_1 = require("../models/memory.js");
8
+ exports.addIndexes = {
9
+ hash: "005-add-indexes",
10
+ sql: (module) => {
11
+ const entriesTable = (0, entries_js_1.entriesTableName)(module);
12
+ const memoryTable = (0, memory_js_1.memoryTableName)(module);
13
+ const compactTable = (0, compact_js_1.compactTableName)(module);
14
+ return [
15
+ // Entries table indexes
16
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_entries_session_created" ON ${sqlite_1.sql.identifier(entriesTable)} ("sessionId", "createdAt" DESC)`,
17
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_entries_user_created" ON ${sqlite_1.sql.identifier(entriesTable)} ("userId", "createdAt" DESC)`,
18
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_entries_agent_created" ON ${sqlite_1.sql.identifier(entriesTable)} ("agentId", "createdAt" DESC)`,
19
+ // Memory table indexes
20
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_memory_session_created" ON ${sqlite_1.sql.identifier(memoryTable)} ("sessionId", "createdAt" DESC)`,
21
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_memory_user_created" ON ${sqlite_1.sql.identifier(memoryTable)} ("userId", "createdAt" DESC)`,
22
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_memory_agent_created" ON ${sqlite_1.sql.identifier(memoryTable)} ("agentId", "createdAt" DESC)`,
23
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_memory_scope" ON ${sqlite_1.sql.identifier(memoryTable)} (json_extract("metadata", '$.scope'))`,
24
+ // Compact table indexes
25
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_compact_session_created" ON ${sqlite_1.sql.identifier(compactTable)} ("sessionId", "createdAt" DESC)`,
26
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_compact_user_created" ON ${sqlite_1.sql.identifier(compactTable)} ("userId", "createdAt" DESC)`,
27
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_compact_agent_created" ON ${sqlite_1.sql.identifier(compactTable)} ("agentId", "createdAt" DESC)`,
28
+ (0, sqlite_1.sql) `CREATE INDEX IF NOT EXISTS "idx_compact_scope" ON ${sqlite_1.sql.identifier(compactTable)} (json_extract("metadata", '$.scope'))`,
29
+ ];
30
+ },
31
+ };