@elizaos/plugin-sql 1.6.0-alpha.0 → 1.6.0-alpha.4
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/browser/index.browser.js +3254 -0
- package/dist/browser/index.browser.js.map +36 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/tsconfig.build.tsbuildinfo +1 -0
- package/dist/index.d.ts +2 -33
- package/dist/node/index.d.ts +2 -0
- package/dist/{index.js → node/index.node.js} +55 -4791
- package/dist/node/index.node.js.map +123 -0
- package/dist/node/tsconfig.build.node.tsbuildinfo +1 -0
- package/package.json +38 -13
- package/types/index.d.ts +19 -0
- package/dist/base.d.ts +0 -894
- package/dist/base.d.ts.map +0 -1
- package/dist/custom-migrator.d.ts +0 -75
- package/dist/custom-migrator.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -164
- package/dist/migration-service.d.ts +0 -12
- package/dist/migration-service.d.ts.map +0 -1
- package/dist/pg/adapter.d.ts +0 -76
- package/dist/pg/adapter.d.ts.map +0 -1
- package/dist/pg/manager.d.ts +0 -18
- package/dist/pg/manager.d.ts.map +0 -1
- package/dist/pglite/adapter.d.ts +0 -75
- package/dist/pglite/adapter.d.ts.map +0 -1
- package/dist/pglite/manager.d.ts +0 -22
- package/dist/pglite/manager.d.ts.map +0 -1
- package/dist/schema/agent.d.ts +0 -328
- package/dist/schema/agent.d.ts.map +0 -1
- package/dist/schema/cache.d.ts +0 -98
- package/dist/schema/cache.d.ts.map +0 -1
- package/dist/schema/channel.d.ts +0 -178
- package/dist/schema/channel.d.ts.map +0 -1
- package/dist/schema/channelParticipant.d.ts +0 -42
- package/dist/schema/channelParticipant.d.ts.map +0 -1
- package/dist/schema/component.d.ts +0 -164
- package/dist/schema/component.d.ts.map +0 -1
- package/dist/schema/embedding.d.ts +0 -194
- package/dist/schema/embedding.d.ts.map +0 -1
- package/dist/schema/entity.d.ts +0 -123
- package/dist/schema/entity.d.ts.map +0 -1
- package/dist/schema/factory.d.ts +0 -60
- package/dist/schema/factory.d.ts.map +0 -1
- package/dist/schema/index.d.ts +0 -18
- package/dist/schema/index.d.ts.map +0 -1
- package/dist/schema/log.d.ts +0 -115
- package/dist/schema/log.d.ts.map +0 -1
- package/dist/schema/memory.d.ts +0 -189
- package/dist/schema/memory.d.ts.map +0 -1
- package/dist/schema/message.d.ts +0 -2
- package/dist/schema/message.d.ts.map +0 -1
- package/dist/schema/messageServer.d.ts +0 -127
- package/dist/schema/messageServer.d.ts.map +0 -1
- package/dist/schema/participant.d.ts +0 -115
- package/dist/schema/participant.d.ts.map +0 -1
- package/dist/schema/relationship.d.ts +0 -157
- package/dist/schema/relationship.d.ts.map +0 -1
- package/dist/schema/room.d.ts +0 -193
- package/dist/schema/room.d.ts.map +0 -1
- package/dist/schema/serverAgent.d.ts +0 -42
- package/dist/schema/serverAgent.d.ts.map +0 -1
- package/dist/schema/tasks.d.ts +0 -226
- package/dist/schema/tasks.d.ts.map +0 -1
- package/dist/schema/types.d.ts +0 -69
- package/dist/schema/types.d.ts.map +0 -1
- package/dist/schema/world.d.ts +0 -115
- package/dist/schema/world.d.ts.map +0 -1
- package/dist/types.d.ts +0 -16
- package/dist/types.d.ts.map +0 -1
- package/dist/utils.d.ts +0 -33
- package/dist/utils.d.ts.map +0 -1
|
@@ -0,0 +1,3254 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/index.browser.ts
|
|
13
|
+
import {
|
|
14
|
+
logger as logger5
|
|
15
|
+
} from "@elizaos/core/browser";
|
|
16
|
+
|
|
17
|
+
// src/pglite/adapter.ts
|
|
18
|
+
import { logger as logger2 } from "@elizaos/core";
|
|
19
|
+
import { drizzle } from "drizzle-orm/pglite";
|
|
20
|
+
|
|
21
|
+
// src/base.ts
|
|
22
|
+
import {
|
|
23
|
+
ChannelType,
|
|
24
|
+
DatabaseAdapter,
|
|
25
|
+
logger
|
|
26
|
+
} from "@elizaos/core";
|
|
27
|
+
import {
|
|
28
|
+
and,
|
|
29
|
+
cosineDistance,
|
|
30
|
+
count,
|
|
31
|
+
desc,
|
|
32
|
+
eq,
|
|
33
|
+
gte,
|
|
34
|
+
inArray,
|
|
35
|
+
lt,
|
|
36
|
+
lte,
|
|
37
|
+
or,
|
|
38
|
+
sql as sql16
|
|
39
|
+
} from "drizzle-orm";
|
|
40
|
+
|
|
41
|
+
// ../../node_modules/uuid/dist/esm-browser/stringify.js
|
|
42
|
+
var byteToHex = [];
|
|
43
|
+
for (let i = 0;i < 256; ++i) {
|
|
44
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
|
45
|
+
}
|
|
46
|
+
function unsafeStringify(arr, offset = 0) {
|
|
47
|
+
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ../../node_modules/uuid/dist/esm-browser/rng.js
|
|
51
|
+
var getRandomValues;
|
|
52
|
+
var rnds8 = new Uint8Array(16);
|
|
53
|
+
function rng() {
|
|
54
|
+
if (!getRandomValues) {
|
|
55
|
+
if (typeof crypto === "undefined" || !crypto.getRandomValues) {
|
|
56
|
+
throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
|
|
57
|
+
}
|
|
58
|
+
getRandomValues = crypto.getRandomValues.bind(crypto);
|
|
59
|
+
}
|
|
60
|
+
return getRandomValues(rnds8);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ../../node_modules/uuid/dist/esm-browser/native.js
|
|
64
|
+
var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
65
|
+
var native_default = { randomUUID };
|
|
66
|
+
|
|
67
|
+
// ../../node_modules/uuid/dist/esm-browser/v4.js
|
|
68
|
+
function v4(options, buf, offset) {
|
|
69
|
+
if (native_default.randomUUID && !buf && !options) {
|
|
70
|
+
return native_default.randomUUID();
|
|
71
|
+
}
|
|
72
|
+
options = options || {};
|
|
73
|
+
const rnds = options.random ?? options.rng?.() ?? rng();
|
|
74
|
+
if (rnds.length < 16) {
|
|
75
|
+
throw new Error("Random bytes length must be >= 16");
|
|
76
|
+
}
|
|
77
|
+
rnds[6] = rnds[6] & 15 | 64;
|
|
78
|
+
rnds[8] = rnds[8] & 63 | 128;
|
|
79
|
+
if (buf) {
|
|
80
|
+
offset = offset || 0;
|
|
81
|
+
if (offset < 0 || offset + 16 > buf.length) {
|
|
82
|
+
throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
|
|
83
|
+
}
|
|
84
|
+
for (let i = 0;i < 16; ++i) {
|
|
85
|
+
buf[offset + i] = rnds[i];
|
|
86
|
+
}
|
|
87
|
+
return buf;
|
|
88
|
+
}
|
|
89
|
+
return unsafeStringify(rnds);
|
|
90
|
+
}
|
|
91
|
+
var v4_default = v4;
|
|
92
|
+
// src/schema/embedding.ts
|
|
93
|
+
import { sql as sql5 } from "drizzle-orm";
|
|
94
|
+
import { check as check2, foreignKey as foreignKey2, index as index2, pgTable as pgTable5, timestamp as timestamp5, uuid as uuid5, vector } from "drizzle-orm/pg-core";
|
|
95
|
+
import { VECTOR_DIMS } from "@elizaos/core";
|
|
96
|
+
|
|
97
|
+
// src/schema/memory.ts
|
|
98
|
+
import { relations, sql as sql4 } from "drizzle-orm";
|
|
99
|
+
import {
|
|
100
|
+
boolean as boolean2,
|
|
101
|
+
check,
|
|
102
|
+
foreignKey,
|
|
103
|
+
index,
|
|
104
|
+
jsonb as jsonb4,
|
|
105
|
+
pgTable as pgTable4,
|
|
106
|
+
text as text4,
|
|
107
|
+
timestamp as timestamp4,
|
|
108
|
+
uuid as uuid4
|
|
109
|
+
} from "drizzle-orm/pg-core";
|
|
110
|
+
|
|
111
|
+
// src/schema/agent.ts
|
|
112
|
+
import { sql } from "drizzle-orm";
|
|
113
|
+
import { boolean, jsonb, pgTable, text, timestamp, unique, uuid } from "drizzle-orm/pg-core";
|
|
114
|
+
var agentTable = pgTable("agents", {
|
|
115
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
116
|
+
enabled: boolean("enabled").default(true).notNull(),
|
|
117
|
+
createdAt: timestamp("created_at", { withTimezone: true }).default(sql`now()`).notNull(),
|
|
118
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).default(sql`now()`).notNull(),
|
|
119
|
+
name: text("name").notNull(),
|
|
120
|
+
username: text("username"),
|
|
121
|
+
system: text("system").default(""),
|
|
122
|
+
bio: jsonb("bio").$type().default(sql`'[]'::jsonb`),
|
|
123
|
+
messageExamples: jsonb("message_examples").$type().default(sql`'[]'::jsonb`).notNull(),
|
|
124
|
+
postExamples: jsonb("post_examples").$type().default(sql`'[]'::jsonb`).notNull(),
|
|
125
|
+
topics: jsonb("topics").$type().default(sql`'[]'::jsonb`).notNull(),
|
|
126
|
+
adjectives: jsonb("adjectives").$type().default(sql`'[]'::jsonb`).notNull(),
|
|
127
|
+
knowledge: jsonb("knowledge").$type().default(sql`'[]'::jsonb`).notNull(),
|
|
128
|
+
plugins: jsonb("plugins").$type().default(sql`'[]'::jsonb`).notNull(),
|
|
129
|
+
settings: jsonb("settings").$type().default(sql`'{}'::jsonb`).notNull(),
|
|
130
|
+
style: jsonb("style").$type().default(sql`'{}'::jsonb`).notNull()
|
|
131
|
+
}, (table) => {
|
|
132
|
+
return {
|
|
133
|
+
nameUnique: unique("name_unique").on(table.name)
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// src/schema/entity.ts
|
|
138
|
+
import { sql as sql2 } from "drizzle-orm";
|
|
139
|
+
import { jsonb as jsonb2, pgTable as pgTable2, text as text2, timestamp as timestamp2, unique as unique2, uuid as uuid2 } from "drizzle-orm/pg-core";
|
|
140
|
+
var entityTable = pgTable2("entities", {
|
|
141
|
+
id: uuid2("id").notNull().primaryKey(),
|
|
142
|
+
agentId: uuid2("agent_id").notNull().references(() => agentTable.id, {
|
|
143
|
+
onDelete: "cascade"
|
|
144
|
+
}),
|
|
145
|
+
createdAt: timestamp2("created_at").default(sql2`now()`).notNull(),
|
|
146
|
+
names: text2("names").array().default(sql2`'{}'::text[]`).notNull(),
|
|
147
|
+
metadata: jsonb2("metadata").default(sql2`'{}'::jsonb`).notNull()
|
|
148
|
+
}, (table) => {
|
|
149
|
+
return {
|
|
150
|
+
idAgentIdUnique: unique2("id_agent_id_unique").on(table.id, table.agentId)
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// src/schema/room.ts
|
|
155
|
+
import { sql as sql3 } from "drizzle-orm";
|
|
156
|
+
import { jsonb as jsonb3, pgTable as pgTable3, text as text3, timestamp as timestamp3, uuid as uuid3 } from "drizzle-orm/pg-core";
|
|
157
|
+
var roomTable = pgTable3("rooms", {
|
|
158
|
+
id: uuid3("id").notNull().primaryKey().default(sql3`gen_random_uuid()`),
|
|
159
|
+
agentId: uuid3("agentId").references(() => agentTable.id, {
|
|
160
|
+
onDelete: "cascade"
|
|
161
|
+
}),
|
|
162
|
+
source: text3("source").notNull(),
|
|
163
|
+
type: text3("type").notNull(),
|
|
164
|
+
serverId: text3("serverId"),
|
|
165
|
+
worldId: uuid3("worldId"),
|
|
166
|
+
name: text3("name"),
|
|
167
|
+
metadata: jsonb3("metadata"),
|
|
168
|
+
channelId: text3("channelId"),
|
|
169
|
+
createdAt: timestamp3("createdAt").default(sql3`now()`).notNull()
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// src/schema/memory.ts
|
|
173
|
+
var memoryTable = pgTable4("memories", {
|
|
174
|
+
id: uuid4("id").primaryKey().notNull(),
|
|
175
|
+
type: text4("type").notNull(),
|
|
176
|
+
createdAt: timestamp4("createdAt").default(sql4`now()`).notNull(),
|
|
177
|
+
content: jsonb4("content").notNull(),
|
|
178
|
+
entityId: uuid4("entityId").references(() => entityTable.id, {
|
|
179
|
+
onDelete: "cascade"
|
|
180
|
+
}),
|
|
181
|
+
agentId: uuid4("agentId").references(() => agentTable.id, {
|
|
182
|
+
onDelete: "cascade"
|
|
183
|
+
}).notNull(),
|
|
184
|
+
roomId: uuid4("roomId").references(() => roomTable.id, {
|
|
185
|
+
onDelete: "cascade"
|
|
186
|
+
}),
|
|
187
|
+
worldId: uuid4("worldId"),
|
|
188
|
+
unique: boolean2("unique").default(true).notNull(),
|
|
189
|
+
metadata: jsonb4("metadata").default({}).notNull()
|
|
190
|
+
}, (table) => [
|
|
191
|
+
index("idx_memories_type_room").on(table.type, table.roomId),
|
|
192
|
+
index("idx_memories_world_id").on(table.worldId),
|
|
193
|
+
foreignKey({
|
|
194
|
+
name: "fk_room",
|
|
195
|
+
columns: [table.roomId],
|
|
196
|
+
foreignColumns: [roomTable.id]
|
|
197
|
+
}).onDelete("cascade"),
|
|
198
|
+
foreignKey({
|
|
199
|
+
name: "fk_user",
|
|
200
|
+
columns: [table.entityId],
|
|
201
|
+
foreignColumns: [entityTable.id]
|
|
202
|
+
}).onDelete("cascade"),
|
|
203
|
+
foreignKey({
|
|
204
|
+
name: "fk_agent",
|
|
205
|
+
columns: [table.agentId],
|
|
206
|
+
foreignColumns: [agentTable.id]
|
|
207
|
+
}).onDelete("cascade"),
|
|
208
|
+
index("idx_memories_metadata_type").on(sql4`((metadata->>'type'))`),
|
|
209
|
+
index("idx_memories_document_id").on(sql4`((metadata->>'documentId'))`),
|
|
210
|
+
index("idx_fragments_order").on(sql4`((metadata->>'documentId'))`, sql4`((metadata->>'position'))`),
|
|
211
|
+
check("fragment_metadata_check", sql4`
|
|
212
|
+
CASE
|
|
213
|
+
WHEN metadata->>'type' = 'fragment' THEN
|
|
214
|
+
metadata ? 'documentId' AND
|
|
215
|
+
metadata ? 'position'
|
|
216
|
+
ELSE true
|
|
217
|
+
END
|
|
218
|
+
`),
|
|
219
|
+
check("document_metadata_check", sql4`
|
|
220
|
+
CASE
|
|
221
|
+
WHEN metadata->>'type' = 'document' THEN
|
|
222
|
+
metadata ? 'timestamp'
|
|
223
|
+
ELSE true
|
|
224
|
+
END
|
|
225
|
+
`)
|
|
226
|
+
]);
|
|
227
|
+
var memoryRelations = relations(memoryTable, ({ one }) => ({
|
|
228
|
+
embedding: one(embeddingTable)
|
|
229
|
+
}));
|
|
230
|
+
|
|
231
|
+
// src/schema/embedding.ts
|
|
232
|
+
var DIMENSION_MAP = {
|
|
233
|
+
[VECTOR_DIMS.SMALL]: "dim384",
|
|
234
|
+
[VECTOR_DIMS.MEDIUM]: "dim512",
|
|
235
|
+
[VECTOR_DIMS.LARGE]: "dim768",
|
|
236
|
+
[VECTOR_DIMS.XL]: "dim1024",
|
|
237
|
+
[VECTOR_DIMS.XXL]: "dim1536",
|
|
238
|
+
[VECTOR_DIMS.XXXL]: "dim3072"
|
|
239
|
+
};
|
|
240
|
+
var embeddingTable = pgTable5("embeddings", {
|
|
241
|
+
id: uuid5("id").primaryKey().defaultRandom().notNull(),
|
|
242
|
+
memoryId: uuid5("memory_id").references(() => memoryTable.id, { onDelete: "cascade" }),
|
|
243
|
+
createdAt: timestamp5("created_at").default(sql5`now()`).notNull(),
|
|
244
|
+
dim384: vector("dim_384", { dimensions: VECTOR_DIMS.SMALL }),
|
|
245
|
+
dim512: vector("dim_512", { dimensions: VECTOR_DIMS.MEDIUM }),
|
|
246
|
+
dim768: vector("dim_768", { dimensions: VECTOR_DIMS.LARGE }),
|
|
247
|
+
dim1024: vector("dim_1024", { dimensions: VECTOR_DIMS.XL }),
|
|
248
|
+
dim1536: vector("dim_1536", { dimensions: VECTOR_DIMS.XXL }),
|
|
249
|
+
dim3072: vector("dim_3072", { dimensions: VECTOR_DIMS.XXXL })
|
|
250
|
+
}, (table) => [
|
|
251
|
+
check2("embedding_source_check", sql5`"memory_id" IS NOT NULL`),
|
|
252
|
+
index2("idx_embedding_memory").on(table.memoryId),
|
|
253
|
+
foreignKey2({
|
|
254
|
+
name: "fk_embedding_memory",
|
|
255
|
+
columns: [table.memoryId],
|
|
256
|
+
foreignColumns: [memoryTable.id]
|
|
257
|
+
}).onDelete("cascade")
|
|
258
|
+
]);
|
|
259
|
+
|
|
260
|
+
// src/schema/index.ts
|
|
261
|
+
var exports_schema = {};
|
|
262
|
+
__export(exports_schema, {
|
|
263
|
+
worldTable: () => worldTable,
|
|
264
|
+
taskTable: () => taskTable,
|
|
265
|
+
serverAgentsTable: () => serverAgentsTable,
|
|
266
|
+
roomTable: () => roomTable,
|
|
267
|
+
relationshipTable: () => relationshipTable,
|
|
268
|
+
participantTable: () => participantTable,
|
|
269
|
+
messageTable: () => messageTable,
|
|
270
|
+
messageServerTable: () => messageServerTable,
|
|
271
|
+
memoryTable: () => memoryTable,
|
|
272
|
+
logTable: () => logTable,
|
|
273
|
+
entityTable: () => entityTable,
|
|
274
|
+
embeddingTable: () => embeddingTable,
|
|
275
|
+
componentTable: () => componentTable,
|
|
276
|
+
channelTable: () => channelTable,
|
|
277
|
+
channelParticipantsTable: () => channelParticipantsTable,
|
|
278
|
+
cacheTable: () => cacheTable,
|
|
279
|
+
agentTable: () => agentTable
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// src/schema/cache.ts
|
|
283
|
+
import { sql as sql6 } from "drizzle-orm";
|
|
284
|
+
import { jsonb as jsonb5, pgTable as pgTable6, text as text5, primaryKey, timestamp as timestamp6, uuid as uuid6 } from "drizzle-orm/pg-core";
|
|
285
|
+
var cacheTable = pgTable6("cache", {
|
|
286
|
+
key: text5("key").notNull(),
|
|
287
|
+
agentId: uuid6("agent_id").notNull().references(() => agentTable.id, { onDelete: "cascade" }),
|
|
288
|
+
value: jsonb5("value").notNull(),
|
|
289
|
+
createdAt: timestamp6("created_at", { withTimezone: true }).default(sql6`now()`).notNull(),
|
|
290
|
+
expiresAt: timestamp6("expires_at", { withTimezone: true })
|
|
291
|
+
}, (table) => ({
|
|
292
|
+
pk: primaryKey({ columns: [table.key, table.agentId] })
|
|
293
|
+
}));
|
|
294
|
+
// src/schema/component.ts
|
|
295
|
+
import { sql as sql8 } from "drizzle-orm";
|
|
296
|
+
import { jsonb as jsonb7, pgTable as pgTable8, text as text7, timestamp as timestamp8, uuid as uuid8 } from "drizzle-orm/pg-core";
|
|
297
|
+
|
|
298
|
+
// src/schema/world.ts
|
|
299
|
+
import { sql as sql7 } from "drizzle-orm";
|
|
300
|
+
import { jsonb as jsonb6, pgTable as pgTable7, text as text6, timestamp as timestamp7, uuid as uuid7 } from "drizzle-orm/pg-core";
|
|
301
|
+
var worldTable = pgTable7("worlds", {
|
|
302
|
+
id: uuid7("id").notNull().primaryKey().default(sql7`gen_random_uuid()`),
|
|
303
|
+
agentId: uuid7("agentId").notNull().references(() => agentTable.id, { onDelete: "cascade" }),
|
|
304
|
+
name: text6("name").notNull(),
|
|
305
|
+
metadata: jsonb6("metadata"),
|
|
306
|
+
serverId: text6("serverId").notNull().default("local"),
|
|
307
|
+
createdAt: timestamp7("createdAt").default(sql7`now()`).notNull()
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// src/schema/component.ts
|
|
311
|
+
var componentTable = pgTable8("components", {
|
|
312
|
+
id: uuid8("id").primaryKey().default(sql8`gen_random_uuid()`).notNull(),
|
|
313
|
+
entityId: uuid8("entityId").references(() => entityTable.id, { onDelete: "cascade" }).notNull(),
|
|
314
|
+
agentId: uuid8("agentId").references(() => agentTable.id, { onDelete: "cascade" }).notNull(),
|
|
315
|
+
roomId: uuid8("roomId").references(() => roomTable.id, { onDelete: "cascade" }).notNull(),
|
|
316
|
+
worldId: uuid8("worldId").references(() => worldTable.id, { onDelete: "cascade" }),
|
|
317
|
+
sourceEntityId: uuid8("sourceEntityId").references(() => entityTable.id, { onDelete: "cascade" }),
|
|
318
|
+
type: text7("type").notNull(),
|
|
319
|
+
data: jsonb7("data").default(sql8`'{}'::jsonb`),
|
|
320
|
+
createdAt: timestamp8("createdAt").default(sql8`now()`).notNull()
|
|
321
|
+
});
|
|
322
|
+
// src/schema/log.ts
|
|
323
|
+
import { sql as sql9 } from "drizzle-orm";
|
|
324
|
+
import { foreignKey as foreignKey3, jsonb as jsonb8, pgTable as pgTable9, text as text8, timestamp as timestamp9, uuid as uuid9 } from "drizzle-orm/pg-core";
|
|
325
|
+
var logTable = pgTable9("logs", {
|
|
326
|
+
id: uuid9("id").defaultRandom().notNull(),
|
|
327
|
+
createdAt: timestamp9("created_at", { withTimezone: true }).default(sql9`now()`).notNull(),
|
|
328
|
+
entityId: uuid9("entityId").notNull().references(() => entityTable.id, { onDelete: "cascade" }),
|
|
329
|
+
body: jsonb8("body").notNull(),
|
|
330
|
+
type: text8("type").notNull(),
|
|
331
|
+
roomId: uuid9("roomId").notNull().references(() => roomTable.id, { onDelete: "cascade" })
|
|
332
|
+
}, (table) => [
|
|
333
|
+
foreignKey3({
|
|
334
|
+
name: "fk_room",
|
|
335
|
+
columns: [table.roomId],
|
|
336
|
+
foreignColumns: [roomTable.id]
|
|
337
|
+
}).onDelete("cascade"),
|
|
338
|
+
foreignKey3({
|
|
339
|
+
name: "fk_user",
|
|
340
|
+
columns: [table.entityId],
|
|
341
|
+
foreignColumns: [entityTable.id]
|
|
342
|
+
}).onDelete("cascade")
|
|
343
|
+
]);
|
|
344
|
+
// src/schema/participant.ts
|
|
345
|
+
import { sql as sql10 } from "drizzle-orm";
|
|
346
|
+
import { foreignKey as foreignKey4, index as index3, pgTable as pgTable10, text as text9, timestamp as timestamp10, uuid as uuid10 } from "drizzle-orm/pg-core";
|
|
347
|
+
var participantTable = pgTable10("participants", {
|
|
348
|
+
id: uuid10("id").notNull().primaryKey().default(sql10`gen_random_uuid()`),
|
|
349
|
+
createdAt: timestamp10("created_at", { withTimezone: true }).default(sql10`now()`).notNull(),
|
|
350
|
+
entityId: uuid10("entityId").references(() => entityTable.id, {
|
|
351
|
+
onDelete: "cascade"
|
|
352
|
+
}),
|
|
353
|
+
roomId: uuid10("roomId").references(() => roomTable.id, {
|
|
354
|
+
onDelete: "cascade"
|
|
355
|
+
}),
|
|
356
|
+
agentId: uuid10("agentId").references(() => agentTable.id, {
|
|
357
|
+
onDelete: "cascade"
|
|
358
|
+
}),
|
|
359
|
+
roomState: text9("roomState")
|
|
360
|
+
}, (table) => [
|
|
361
|
+
index3("idx_participants_user").on(table.entityId),
|
|
362
|
+
index3("idx_participants_room").on(table.roomId),
|
|
363
|
+
foreignKey4({
|
|
364
|
+
name: "fk_room",
|
|
365
|
+
columns: [table.roomId],
|
|
366
|
+
foreignColumns: [roomTable.id]
|
|
367
|
+
}).onDelete("cascade"),
|
|
368
|
+
foreignKey4({
|
|
369
|
+
name: "fk_user",
|
|
370
|
+
columns: [table.entityId],
|
|
371
|
+
foreignColumns: [entityTable.id]
|
|
372
|
+
}).onDelete("cascade")
|
|
373
|
+
]);
|
|
374
|
+
// src/schema/relationship.ts
|
|
375
|
+
import { sql as sql11 } from "drizzle-orm";
|
|
376
|
+
import {
|
|
377
|
+
foreignKey as foreignKey5,
|
|
378
|
+
index as index4,
|
|
379
|
+
jsonb as jsonb9,
|
|
380
|
+
pgTable as pgTable11,
|
|
381
|
+
text as text10,
|
|
382
|
+
timestamp as timestamp11,
|
|
383
|
+
unique as unique3,
|
|
384
|
+
uuid as uuid11
|
|
385
|
+
} from "drizzle-orm/pg-core";
|
|
386
|
+
var relationshipTable = pgTable11("relationships", {
|
|
387
|
+
id: uuid11("id").notNull().primaryKey().default(sql11`gen_random_uuid()`),
|
|
388
|
+
createdAt: timestamp11("created_at", { withTimezone: true }).default(sql11`now()`).notNull(),
|
|
389
|
+
sourceEntityId: uuid11("sourceEntityId").notNull().references(() => entityTable.id, { onDelete: "cascade" }),
|
|
390
|
+
targetEntityId: uuid11("targetEntityId").notNull().references(() => entityTable.id, { onDelete: "cascade" }),
|
|
391
|
+
agentId: uuid11("agentId").notNull().references(() => agentTable.id, { onDelete: "cascade" }),
|
|
392
|
+
tags: text10("tags").array(),
|
|
393
|
+
metadata: jsonb9("metadata")
|
|
394
|
+
}, (table) => [
|
|
395
|
+
index4("idx_relationships_users").on(table.sourceEntityId, table.targetEntityId),
|
|
396
|
+
unique3("unique_relationship").on(table.sourceEntityId, table.targetEntityId, table.agentId),
|
|
397
|
+
foreignKey5({
|
|
398
|
+
name: "fk_user_a",
|
|
399
|
+
columns: [table.sourceEntityId],
|
|
400
|
+
foreignColumns: [entityTable.id]
|
|
401
|
+
}).onDelete("cascade"),
|
|
402
|
+
foreignKey5({
|
|
403
|
+
name: "fk_user_b",
|
|
404
|
+
columns: [table.targetEntityId],
|
|
405
|
+
foreignColumns: [entityTable.id]
|
|
406
|
+
}).onDelete("cascade")
|
|
407
|
+
]);
|
|
408
|
+
// src/schema/tasks.ts
|
|
409
|
+
import { jsonb as jsonb10, pgTable as pgTable12, text as text11, timestamp as timestamp12, uuid as uuid12 } from "drizzle-orm/pg-core";
|
|
410
|
+
import { sql as sql12 } from "drizzle-orm";
|
|
411
|
+
var taskTable = pgTable12("tasks", {
|
|
412
|
+
id: uuid12("id").primaryKey().defaultRandom(),
|
|
413
|
+
name: text11("name").notNull(),
|
|
414
|
+
description: text11("description"),
|
|
415
|
+
roomId: uuid12("roomId"),
|
|
416
|
+
worldId: uuid12("worldId"),
|
|
417
|
+
entityId: uuid12("entityId"),
|
|
418
|
+
agentId: uuid12("agent_id").notNull().references(() => agentTable.id, { onDelete: "cascade" }),
|
|
419
|
+
tags: text11("tags").array().default(sql12`'{}'::text[]`),
|
|
420
|
+
metadata: jsonb10("metadata").default(sql12`'{}'::jsonb`),
|
|
421
|
+
createdAt: timestamp12("created_at", { withTimezone: true }).defaultNow(),
|
|
422
|
+
updatedAt: timestamp12("updated_at", { withTimezone: true }).defaultNow()
|
|
423
|
+
});
|
|
424
|
+
// src/schema/messageServer.ts
|
|
425
|
+
import { pgTable as pgTable13, text as text12, jsonb as jsonb11, timestamp as timestamp13, uuid as uuid13 } from "drizzle-orm/pg-core";
|
|
426
|
+
import { sql as sql13 } from "drizzle-orm";
|
|
427
|
+
var messageServerTable = pgTable13("message_servers", {
|
|
428
|
+
id: uuid13("id").primaryKey(),
|
|
429
|
+
name: text12("name").notNull(),
|
|
430
|
+
sourceType: text12("source_type").notNull(),
|
|
431
|
+
sourceId: text12("source_id"),
|
|
432
|
+
metadata: jsonb11("metadata"),
|
|
433
|
+
createdAt: timestamp13("created_at", { mode: "date" }).default(sql13`CURRENT_TIMESTAMP`).notNull(),
|
|
434
|
+
updatedAt: timestamp13("updated_at", { mode: "date" }).default(sql13`CURRENT_TIMESTAMP`).notNull()
|
|
435
|
+
});
|
|
436
|
+
// src/schema/channel.ts
|
|
437
|
+
import { pgTable as pgTable14, text as text13, jsonb as jsonb12, timestamp as timestamp14, uuid as uuid14 } from "drizzle-orm/pg-core";
|
|
438
|
+
import { sql as sql14 } from "drizzle-orm";
|
|
439
|
+
var channelTable = pgTable14("channels", {
|
|
440
|
+
id: text13("id").primaryKey(),
|
|
441
|
+
messageServerId: uuid14("server_id").notNull().references(() => messageServerTable.id, { onDelete: "cascade" }),
|
|
442
|
+
name: text13("name").notNull(),
|
|
443
|
+
type: text13("type").notNull(),
|
|
444
|
+
sourceType: text13("source_type"),
|
|
445
|
+
sourceId: text13("source_id"),
|
|
446
|
+
topic: text13("topic"),
|
|
447
|
+
metadata: jsonb12("metadata"),
|
|
448
|
+
createdAt: timestamp14("created_at", { mode: "date" }).default(sql14`CURRENT_TIMESTAMP`).notNull(),
|
|
449
|
+
updatedAt: timestamp14("updated_at", { mode: "date" }).default(sql14`CURRENT_TIMESTAMP`).notNull()
|
|
450
|
+
});
|
|
451
|
+
// src/schema/message.ts
|
|
452
|
+
import { pgTable as pgTable15, text as text14, jsonb as jsonb13, timestamp as timestamp15 } from "drizzle-orm/pg-core";
|
|
453
|
+
import { sql as sql15 } from "drizzle-orm";
|
|
454
|
+
var messageTable = pgTable15("central_messages", {
|
|
455
|
+
id: text14("id").primaryKey(),
|
|
456
|
+
channelId: text14("channel_id").notNull().references(() => channelTable.id, { onDelete: "cascade" }),
|
|
457
|
+
authorId: text14("author_id").notNull(),
|
|
458
|
+
content: text14("content").notNull(),
|
|
459
|
+
rawMessage: jsonb13("raw_message"),
|
|
460
|
+
inReplyToRootMessageId: text14("in_reply_to_root_message_id").references(() => messageTable.id, {
|
|
461
|
+
onDelete: "set null"
|
|
462
|
+
}),
|
|
463
|
+
sourceType: text14("source_type"),
|
|
464
|
+
sourceId: text14("source_id"),
|
|
465
|
+
metadata: jsonb13("metadata"),
|
|
466
|
+
createdAt: timestamp15("created_at", { mode: "date" }).default(sql15`CURRENT_TIMESTAMP`).notNull(),
|
|
467
|
+
updatedAt: timestamp15("updated_at", { mode: "date" }).default(sql15`CURRENT_TIMESTAMP`).notNull()
|
|
468
|
+
});
|
|
469
|
+
// src/schema/channelParticipant.ts
|
|
470
|
+
import { pgTable as pgTable16, text as text15, primaryKey as primaryKey2 } from "drizzle-orm/pg-core";
|
|
471
|
+
var channelParticipantsTable = pgTable16("channel_participants", {
|
|
472
|
+
channelId: text15("channel_id").notNull().references(() => channelTable.id, { onDelete: "cascade" }),
|
|
473
|
+
userId: text15("user_id").notNull()
|
|
474
|
+
}, (table) => ({
|
|
475
|
+
pk: primaryKey2({ columns: [table.channelId, table.userId] })
|
|
476
|
+
}));
|
|
477
|
+
// src/schema/serverAgent.ts
|
|
478
|
+
import { pgTable as pgTable17, uuid as uuid15, primaryKey as primaryKey3 } from "drizzle-orm/pg-core";
|
|
479
|
+
var serverAgentsTable = pgTable17("server_agents", {
|
|
480
|
+
serverId: uuid15("server_id").notNull().references(() => messageServerTable.id, { onDelete: "cascade" }),
|
|
481
|
+
agentId: uuid15("agent_id").notNull().references(() => agentTable.id, { onDelete: "cascade" })
|
|
482
|
+
}, (table) => ({
|
|
483
|
+
pk: primaryKey3({ columns: [table.serverId, table.agentId] })
|
|
484
|
+
}));
|
|
485
|
+
// src/base.ts
|
|
486
|
+
class BaseDrizzleAdapter extends DatabaseAdapter {
|
|
487
|
+
maxRetries = 3;
|
|
488
|
+
baseDelay = 1000;
|
|
489
|
+
maxDelay = 1e4;
|
|
490
|
+
jitterMax = 1000;
|
|
491
|
+
embeddingDimension = DIMENSION_MAP[384];
|
|
492
|
+
async initialize() {
|
|
493
|
+
await this.init();
|
|
494
|
+
}
|
|
495
|
+
getDatabase() {
|
|
496
|
+
return this.db;
|
|
497
|
+
}
|
|
498
|
+
agentId;
|
|
499
|
+
constructor(agentId) {
|
|
500
|
+
super();
|
|
501
|
+
this.agentId = agentId;
|
|
502
|
+
}
|
|
503
|
+
async withRetry(operation) {
|
|
504
|
+
let lastError = new Error("Unknown error");
|
|
505
|
+
for (let attempt = 1;attempt <= this.maxRetries; attempt++) {
|
|
506
|
+
try {
|
|
507
|
+
return await operation();
|
|
508
|
+
} catch (error) {
|
|
509
|
+
lastError = error;
|
|
510
|
+
if (attempt < this.maxRetries) {
|
|
511
|
+
const backoffDelay = Math.min(this.baseDelay * 2 ** (attempt - 1), this.maxDelay);
|
|
512
|
+
const jitter = Math.random() * this.jitterMax;
|
|
513
|
+
const delay = backoffDelay + jitter;
|
|
514
|
+
logger.warn(`Database operation failed (attempt ${attempt}/${this.maxRetries}): ${error instanceof Error ? error.message : String(error)}, nextRetryIn: ${(delay / 1000).toFixed(1)}s`);
|
|
515
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
516
|
+
} else {
|
|
517
|
+
logger.error(`Max retry attempts reached: ${error instanceof Error ? error.message : String(error)}, totalAttempts: ${attempt}`);
|
|
518
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
throw lastError;
|
|
523
|
+
}
|
|
524
|
+
async ensureEmbeddingDimension(dimension) {
|
|
525
|
+
return this.withDatabase(async () => {
|
|
526
|
+
const existingMemory = await this.db.select().from(memoryTable).innerJoin(embeddingTable, eq(embeddingTable.memoryId, memoryTable.id)).where(eq(memoryTable.agentId, this.agentId)).limit(1);
|
|
527
|
+
if (existingMemory.length > 0) {
|
|
528
|
+
Object.entries(DIMENSION_MAP).find(([_, colName]) => existingMemory[0].embeddings[colName] !== null);
|
|
529
|
+
}
|
|
530
|
+
this.embeddingDimension = DIMENSION_MAP[dimension];
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
async getAgent(agentId) {
|
|
534
|
+
return this.withDatabase(async () => {
|
|
535
|
+
const rows = await this.db.select().from(agentTable).where(eq(agentTable.id, agentId)).limit(1);
|
|
536
|
+
if (rows.length === 0)
|
|
537
|
+
return null;
|
|
538
|
+
const row = rows[0];
|
|
539
|
+
return {
|
|
540
|
+
...row,
|
|
541
|
+
username: row.username || "",
|
|
542
|
+
id: row.id,
|
|
543
|
+
system: !row.system ? undefined : row.system,
|
|
544
|
+
bio: !row.bio ? "" : row.bio,
|
|
545
|
+
createdAt: row.createdAt.getTime(),
|
|
546
|
+
updatedAt: row.updatedAt.getTime()
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
async getAgents() {
|
|
551
|
+
const result = await this.withDatabase(async () => {
|
|
552
|
+
const rows = await this.db.select({
|
|
553
|
+
id: agentTable.id,
|
|
554
|
+
name: agentTable.name,
|
|
555
|
+
bio: agentTable.bio
|
|
556
|
+
}).from(agentTable);
|
|
557
|
+
return rows.map((row) => ({
|
|
558
|
+
...row,
|
|
559
|
+
id: row.id,
|
|
560
|
+
bio: row.bio === null ? "" : row.bio
|
|
561
|
+
}));
|
|
562
|
+
});
|
|
563
|
+
return result || [];
|
|
564
|
+
}
|
|
565
|
+
async createAgent(agent) {
|
|
566
|
+
return this.withDatabase(async () => {
|
|
567
|
+
try {
|
|
568
|
+
const conditions = [];
|
|
569
|
+
if (agent.id) {
|
|
570
|
+
conditions.push(eq(agentTable.id, agent.id));
|
|
571
|
+
}
|
|
572
|
+
if (agent.name) {
|
|
573
|
+
conditions.push(eq(agentTable.name, agent.name));
|
|
574
|
+
}
|
|
575
|
+
const existing = conditions.length > 0 ? await this.db.select({ id: agentTable.id }).from(agentTable).where(or(...conditions)).limit(1) : [];
|
|
576
|
+
if (existing.length > 0) {
|
|
577
|
+
logger.warn(`Attempted to create an agent with a duplicate ID or name. ID: ${agent.id}, name: ${agent.name}`);
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
await this.db.transaction(async (tx) => {
|
|
581
|
+
await tx.insert(agentTable).values({
|
|
582
|
+
...agent,
|
|
583
|
+
createdAt: new Date(agent.createdAt || Date.now()),
|
|
584
|
+
updatedAt: new Date(agent.updatedAt || Date.now())
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
logger.debug(`Agent created successfully: ${agent.id}`);
|
|
588
|
+
return true;
|
|
589
|
+
} catch (error) {
|
|
590
|
+
logger.error(`Error creating agent: ${error instanceof Error ? error.message : String(error)}, agentId: ${agent.id}`);
|
|
591
|
+
return false;
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
async updateAgent(agentId, agent) {
|
|
596
|
+
return this.withDatabase(async () => {
|
|
597
|
+
try {
|
|
598
|
+
if (!agentId) {
|
|
599
|
+
throw new Error("Agent ID is required for update");
|
|
600
|
+
}
|
|
601
|
+
await this.db.transaction(async (tx) => {
|
|
602
|
+
if (agent?.settings) {
|
|
603
|
+
agent.settings = await this.mergeAgentSettings(tx, agentId, agent.settings);
|
|
604
|
+
}
|
|
605
|
+
const updateData = { ...agent };
|
|
606
|
+
if (updateData.createdAt) {
|
|
607
|
+
if (typeof updateData.createdAt === "number") {
|
|
608
|
+
updateData.createdAt = new Date(updateData.createdAt);
|
|
609
|
+
} else {
|
|
610
|
+
delete updateData.createdAt;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (updateData.updatedAt) {
|
|
614
|
+
if (typeof updateData.updatedAt === "number") {
|
|
615
|
+
updateData.updatedAt = new Date(updateData.updatedAt);
|
|
616
|
+
} else {
|
|
617
|
+
updateData.updatedAt = new Date;
|
|
618
|
+
}
|
|
619
|
+
} else {
|
|
620
|
+
updateData.updatedAt = new Date;
|
|
621
|
+
}
|
|
622
|
+
await tx.update(agentTable).set(updateData).where(eq(agentTable.id, agentId));
|
|
623
|
+
});
|
|
624
|
+
logger.debug(`Agent updated successfully: ${agentId}`);
|
|
625
|
+
return true;
|
|
626
|
+
} catch (error) {
|
|
627
|
+
logger.error(`Error updating agent: ${error instanceof Error ? error.message : String(error)}, agentId: ${agentId}`);
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
async mergeAgentSettings(tx, agentId, updatedSettings) {
|
|
633
|
+
const currentAgent = await tx.select({ settings: agentTable.settings }).from(agentTable).where(eq(agentTable.id, agentId)).limit(1);
|
|
634
|
+
const currentSettings = currentAgent.length > 0 && currentAgent[0].settings ? currentAgent[0].settings : {};
|
|
635
|
+
const deepMerge = (target, source) => {
|
|
636
|
+
if (source === null) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
if (Array.isArray(source) || typeof source !== "object") {
|
|
640
|
+
return source;
|
|
641
|
+
}
|
|
642
|
+
const output = typeof target === "object" && target !== null && !Array.isArray(target) ? { ...target } : {};
|
|
643
|
+
for (const key of Object.keys(source)) {
|
|
644
|
+
const sourceValue = source[key];
|
|
645
|
+
if (sourceValue === null) {
|
|
646
|
+
delete output[key];
|
|
647
|
+
} else if (typeof sourceValue === "object" && !Array.isArray(sourceValue)) {
|
|
648
|
+
const nestedMergeResult = deepMerge(output[key], sourceValue);
|
|
649
|
+
if (nestedMergeResult === undefined) {
|
|
650
|
+
delete output[key];
|
|
651
|
+
} else {
|
|
652
|
+
output[key] = nestedMergeResult;
|
|
653
|
+
}
|
|
654
|
+
} else {
|
|
655
|
+
output[key] = sourceValue;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (Object.keys(output).length === 0) {
|
|
659
|
+
if (!(typeof source === "object" && source !== null && Object.keys(source).length === 0)) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return output;
|
|
664
|
+
};
|
|
665
|
+
const finalSettings = deepMerge(currentSettings, updatedSettings);
|
|
666
|
+
return finalSettings === undefined ? {} : finalSettings;
|
|
667
|
+
}
|
|
668
|
+
async deleteAgent(agentId) {
|
|
669
|
+
logger.debug(`[DB] Deleting agent with ID: ${agentId}`);
|
|
670
|
+
return this.withDatabase(async () => {
|
|
671
|
+
try {
|
|
672
|
+
const result = await this.db.delete(agentTable).where(eq(agentTable.id, agentId)).returning();
|
|
673
|
+
if (result.length === 0) {
|
|
674
|
+
logger.warn(`[DB] Agent ${agentId} not found`);
|
|
675
|
+
return false;
|
|
676
|
+
}
|
|
677
|
+
logger.success(`[DB] Agent ${agentId} and all related data successfully deleted via cascade`);
|
|
678
|
+
return true;
|
|
679
|
+
} catch (error) {
|
|
680
|
+
logger.error(`[DB] Failed to delete agent ${agentId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
681
|
+
if (error instanceof Error) {
|
|
682
|
+
logger.error(`[DB] Error details: ${error.name} - ${error.message}`);
|
|
683
|
+
logger.error(`[DB] Stack trace: ${error.stack}`);
|
|
684
|
+
}
|
|
685
|
+
throw error;
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
async countAgents() {
|
|
690
|
+
return this.withDatabase(async () => {
|
|
691
|
+
try {
|
|
692
|
+
const result = await this.db.select({ count: count() }).from(agentTable);
|
|
693
|
+
return result[0]?.count || 0;
|
|
694
|
+
} catch (error) {
|
|
695
|
+
logger.error(`Error counting agents: ${error instanceof Error ? error.message : String(error)}`);
|
|
696
|
+
return 0;
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
async cleanupAgents() {
|
|
701
|
+
return this.withDatabase(async () => {
|
|
702
|
+
try {
|
|
703
|
+
await this.db.delete(agentTable);
|
|
704
|
+
logger.success("Successfully cleaned up agent table");
|
|
705
|
+
} catch (error) {
|
|
706
|
+
logger.error(`Error cleaning up agent table: ${error instanceof Error ? error.message : String(error)}`);
|
|
707
|
+
throw error;
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
async getEntitiesByIds(entityIds) {
|
|
712
|
+
return this.withDatabase(async () => {
|
|
713
|
+
const result = await this.db.select({
|
|
714
|
+
entity: entityTable,
|
|
715
|
+
components: componentTable
|
|
716
|
+
}).from(entityTable).leftJoin(componentTable, eq(componentTable.entityId, entityTable.id)).where(inArray(entityTable.id, entityIds));
|
|
717
|
+
if (result.length === 0)
|
|
718
|
+
return [];
|
|
719
|
+
const entities = {};
|
|
720
|
+
const entityComponents = {};
|
|
721
|
+
for (const e of result) {
|
|
722
|
+
const key = e.entity.id;
|
|
723
|
+
entities[key] = e.entity;
|
|
724
|
+
if (entityComponents[key] === undefined)
|
|
725
|
+
entityComponents[key] = [];
|
|
726
|
+
if (e.components) {
|
|
727
|
+
const componentsArray = Array.isArray(e.components) ? e.components : [e.components];
|
|
728
|
+
entityComponents[key] = [...entityComponents[key], ...componentsArray];
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
for (const k of Object.keys(entityComponents)) {
|
|
732
|
+
entities[k].components = entityComponents[k];
|
|
733
|
+
}
|
|
734
|
+
return Object.values(entities);
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
async getEntitiesForRoom(roomId, includeComponents) {
|
|
738
|
+
return this.withDatabase(async () => {
|
|
739
|
+
const query = this.db.select({
|
|
740
|
+
entity: entityTable,
|
|
741
|
+
...includeComponents && { components: componentTable }
|
|
742
|
+
}).from(participantTable).leftJoin(entityTable, and(eq(participantTable.entityId, entityTable.id), eq(entityTable.agentId, this.agentId)));
|
|
743
|
+
if (includeComponents) {
|
|
744
|
+
query.leftJoin(componentTable, eq(componentTable.entityId, entityTable.id));
|
|
745
|
+
}
|
|
746
|
+
const result = await query.where(eq(participantTable.roomId, roomId));
|
|
747
|
+
const entitiesByIdMap = new Map;
|
|
748
|
+
for (const row of result) {
|
|
749
|
+
if (!row.entity)
|
|
750
|
+
continue;
|
|
751
|
+
const entityId = row.entity.id;
|
|
752
|
+
if (!entitiesByIdMap.has(entityId)) {
|
|
753
|
+
const entity = {
|
|
754
|
+
...row.entity,
|
|
755
|
+
id: entityId,
|
|
756
|
+
agentId: row.entity.agentId,
|
|
757
|
+
metadata: row.entity.metadata,
|
|
758
|
+
components: includeComponents ? [] : undefined
|
|
759
|
+
};
|
|
760
|
+
entitiesByIdMap.set(entityId, entity);
|
|
761
|
+
}
|
|
762
|
+
if (includeComponents && row.components) {
|
|
763
|
+
const entity = entitiesByIdMap.get(entityId);
|
|
764
|
+
if (entity) {
|
|
765
|
+
if (!entity.components) {
|
|
766
|
+
entity.components = [];
|
|
767
|
+
}
|
|
768
|
+
entity.components.push(row.components);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return Array.from(entitiesByIdMap.values());
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
async createEntities(entities) {
|
|
776
|
+
return this.withDatabase(async () => {
|
|
777
|
+
try {
|
|
778
|
+
return await this.db.transaction(async (tx) => {
|
|
779
|
+
await tx.insert(entityTable).values(entities);
|
|
780
|
+
logger.debug(`${entities.length} Entities created successfully`);
|
|
781
|
+
return true;
|
|
782
|
+
});
|
|
783
|
+
} catch (error) {
|
|
784
|
+
logger.error(`Error creating entities, entityId: ${entities[0].id}, (metadata?.)name: ${entities[0].metadata?.name}`, error instanceof Error ? error.message : String(error));
|
|
785
|
+
if (error instanceof Error && error.stack) {
|
|
786
|
+
logger.trace("Stack trace:", error.stack);
|
|
787
|
+
}
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
async ensureEntityExists(entity) {
|
|
793
|
+
if (!entity.id) {
|
|
794
|
+
logger.error("Entity ID is required for ensureEntityExists");
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
try {
|
|
798
|
+
const existingEntities = await this.getEntitiesByIds([entity.id]);
|
|
799
|
+
if (!existingEntities || !existingEntities.length) {
|
|
800
|
+
return await this.createEntities([entity]);
|
|
801
|
+
}
|
|
802
|
+
return true;
|
|
803
|
+
} catch (error) {
|
|
804
|
+
logger.error(`Error ensuring entity exists: ${error instanceof Error ? error.message : String(error)}, entityId: ${entity.id}`);
|
|
805
|
+
return false;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
async updateEntity(entity) {
|
|
809
|
+
if (!entity.id) {
|
|
810
|
+
throw new Error("Entity ID is required for update");
|
|
811
|
+
}
|
|
812
|
+
return this.withDatabase(async () => {
|
|
813
|
+
await this.db.update(entityTable).set(entity).where(eq(entityTable.id, entity.id));
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
async deleteEntity(entityId) {
|
|
817
|
+
return this.withDatabase(async () => {
|
|
818
|
+
await this.db.transaction(async (tx) => {
|
|
819
|
+
await tx.delete(componentTable).where(or(eq(componentTable.entityId, entityId), eq(componentTable.sourceEntityId, entityId)));
|
|
820
|
+
await tx.delete(entityTable).where(eq(entityTable.id, entityId));
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
async getEntitiesByNames(params) {
|
|
825
|
+
return this.withDatabase(async () => {
|
|
826
|
+
const { names, agentId } = params;
|
|
827
|
+
const nameConditions = names.map((name) => sql16`${name} = ANY(${entityTable.names})`);
|
|
828
|
+
const query = sql16`
|
|
829
|
+
SELECT * FROM ${entityTable}
|
|
830
|
+
WHERE ${entityTable.agentId} = ${agentId}
|
|
831
|
+
AND (${sql16.join(nameConditions, sql16` OR `)})
|
|
832
|
+
`;
|
|
833
|
+
const result = await this.db.execute(query);
|
|
834
|
+
return result.rows.map((row) => ({
|
|
835
|
+
id: row.id,
|
|
836
|
+
agentId: row.agentId,
|
|
837
|
+
names: row.names || [],
|
|
838
|
+
metadata: row.metadata || {}
|
|
839
|
+
}));
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
async searchEntitiesByName(params) {
|
|
843
|
+
return this.withDatabase(async () => {
|
|
844
|
+
const { query, agentId, limit = 10 } = params;
|
|
845
|
+
if (!query || query.trim() === "") {
|
|
846
|
+
const result2 = await this.db.select().from(entityTable).where(eq(entityTable.agentId, agentId)).limit(limit);
|
|
847
|
+
return result2.map((row) => ({
|
|
848
|
+
id: row.id,
|
|
849
|
+
agentId: row.agentId,
|
|
850
|
+
names: row.names || [],
|
|
851
|
+
metadata: row.metadata || {}
|
|
852
|
+
}));
|
|
853
|
+
}
|
|
854
|
+
const searchQuery = sql16`
|
|
855
|
+
SELECT * FROM ${entityTable}
|
|
856
|
+
WHERE ${entityTable.agentId} = ${agentId}
|
|
857
|
+
AND EXISTS (
|
|
858
|
+
SELECT 1 FROM unnest(${entityTable.names}) AS name
|
|
859
|
+
WHERE LOWER(name) LIKE LOWER(${"%" + query + "%"})
|
|
860
|
+
)
|
|
861
|
+
LIMIT ${limit}
|
|
862
|
+
`;
|
|
863
|
+
const result = await this.db.execute(searchQuery);
|
|
864
|
+
return result.rows.map((row) => ({
|
|
865
|
+
id: row.id,
|
|
866
|
+
agentId: row.agentId,
|
|
867
|
+
names: row.names || [],
|
|
868
|
+
metadata: row.metadata || {}
|
|
869
|
+
}));
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
async getComponent(entityId, type, worldId, sourceEntityId) {
|
|
873
|
+
return this.withDatabase(async () => {
|
|
874
|
+
const conditions = [eq(componentTable.entityId, entityId), eq(componentTable.type, type)];
|
|
875
|
+
if (worldId) {
|
|
876
|
+
conditions.push(eq(componentTable.worldId, worldId));
|
|
877
|
+
}
|
|
878
|
+
if (sourceEntityId) {
|
|
879
|
+
conditions.push(eq(componentTable.sourceEntityId, sourceEntityId));
|
|
880
|
+
}
|
|
881
|
+
const result = await this.db.select().from(componentTable).where(and(...conditions));
|
|
882
|
+
if (result.length === 0)
|
|
883
|
+
return null;
|
|
884
|
+
const component = result[0];
|
|
885
|
+
return {
|
|
886
|
+
...component,
|
|
887
|
+
id: component.id,
|
|
888
|
+
entityId: component.entityId,
|
|
889
|
+
agentId: component.agentId,
|
|
890
|
+
roomId: component.roomId,
|
|
891
|
+
worldId: component.worldId ?? "",
|
|
892
|
+
sourceEntityId: component.sourceEntityId ?? "",
|
|
893
|
+
data: component.data,
|
|
894
|
+
createdAt: component.createdAt.getTime()
|
|
895
|
+
};
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
async getComponents(entityId, worldId, sourceEntityId) {
|
|
899
|
+
return this.withDatabase(async () => {
|
|
900
|
+
const conditions = [eq(componentTable.entityId, entityId)];
|
|
901
|
+
if (worldId) {
|
|
902
|
+
conditions.push(eq(componentTable.worldId, worldId));
|
|
903
|
+
}
|
|
904
|
+
if (sourceEntityId) {
|
|
905
|
+
conditions.push(eq(componentTable.sourceEntityId, sourceEntityId));
|
|
906
|
+
}
|
|
907
|
+
const result = await this.db.select({
|
|
908
|
+
id: componentTable.id,
|
|
909
|
+
entityId: componentTable.entityId,
|
|
910
|
+
type: componentTable.type,
|
|
911
|
+
data: componentTable.data,
|
|
912
|
+
worldId: componentTable.worldId,
|
|
913
|
+
agentId: componentTable.agentId,
|
|
914
|
+
roomId: componentTable.roomId,
|
|
915
|
+
sourceEntityId: componentTable.sourceEntityId,
|
|
916
|
+
createdAt: componentTable.createdAt
|
|
917
|
+
}).from(componentTable).where(and(...conditions));
|
|
918
|
+
if (result.length === 0)
|
|
919
|
+
return [];
|
|
920
|
+
const components = result.map((component) => ({
|
|
921
|
+
...component,
|
|
922
|
+
id: component.id,
|
|
923
|
+
entityId: component.entityId,
|
|
924
|
+
agentId: component.agentId,
|
|
925
|
+
roomId: component.roomId,
|
|
926
|
+
worldId: component.worldId ?? "",
|
|
927
|
+
sourceEntityId: component.sourceEntityId ?? "",
|
|
928
|
+
data: component.data,
|
|
929
|
+
createdAt: component.createdAt.getTime()
|
|
930
|
+
}));
|
|
931
|
+
return components;
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
async createComponent(component) {
|
|
935
|
+
return this.withDatabase(async () => {
|
|
936
|
+
await this.db.insert(componentTable).values({
|
|
937
|
+
...component,
|
|
938
|
+
createdAt: new Date
|
|
939
|
+
});
|
|
940
|
+
return true;
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
async updateComponent(component) {
|
|
944
|
+
return this.withDatabase(async () => {
|
|
945
|
+
try {
|
|
946
|
+
await this.db.update(componentTable).set({
|
|
947
|
+
...component,
|
|
948
|
+
updatedAt: new Date
|
|
949
|
+
}).where(eq(componentTable.id, component.id));
|
|
950
|
+
} catch (e) {
|
|
951
|
+
console.error("updateComponent error", e);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
async deleteComponent(componentId) {
|
|
956
|
+
return this.withDatabase(async () => {
|
|
957
|
+
await this.db.delete(componentTable).where(eq(componentTable.id, componentId));
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
async getMemories(params) {
|
|
961
|
+
const { entityId, agentId, roomId, worldId, tableName, unique: unique4, start, end } = params;
|
|
962
|
+
if (!tableName)
|
|
963
|
+
throw new Error("tableName is required");
|
|
964
|
+
return this.withDatabase(async () => {
|
|
965
|
+
const conditions = [eq(memoryTable.type, tableName)];
|
|
966
|
+
if (start) {
|
|
967
|
+
conditions.push(gte(memoryTable.createdAt, new Date(start)));
|
|
968
|
+
}
|
|
969
|
+
if (entityId) {
|
|
970
|
+
conditions.push(eq(memoryTable.entityId, entityId));
|
|
971
|
+
}
|
|
972
|
+
if (roomId) {
|
|
973
|
+
conditions.push(eq(memoryTable.roomId, roomId));
|
|
974
|
+
}
|
|
975
|
+
if (worldId) {
|
|
976
|
+
conditions.push(eq(memoryTable.worldId, worldId));
|
|
977
|
+
}
|
|
978
|
+
if (end) {
|
|
979
|
+
conditions.push(lte(memoryTable.createdAt, new Date(end)));
|
|
980
|
+
}
|
|
981
|
+
if (unique4) {
|
|
982
|
+
conditions.push(eq(memoryTable.unique, true));
|
|
983
|
+
}
|
|
984
|
+
if (agentId) {
|
|
985
|
+
conditions.push(eq(memoryTable.agentId, agentId));
|
|
986
|
+
}
|
|
987
|
+
const query = this.db.select({
|
|
988
|
+
memory: {
|
|
989
|
+
id: memoryTable.id,
|
|
990
|
+
type: memoryTable.type,
|
|
991
|
+
createdAt: memoryTable.createdAt,
|
|
992
|
+
content: memoryTable.content,
|
|
993
|
+
entityId: memoryTable.entityId,
|
|
994
|
+
agentId: memoryTable.agentId,
|
|
995
|
+
roomId: memoryTable.roomId,
|
|
996
|
+
unique: memoryTable.unique,
|
|
997
|
+
metadata: memoryTable.metadata
|
|
998
|
+
},
|
|
999
|
+
embedding: embeddingTable[this.embeddingDimension]
|
|
1000
|
+
}).from(memoryTable).leftJoin(embeddingTable, eq(embeddingTable.memoryId, memoryTable.id)).where(and(...conditions)).orderBy(desc(memoryTable.createdAt));
|
|
1001
|
+
const rows = params.count ? await query.limit(params.count) : await query;
|
|
1002
|
+
return rows.map((row) => ({
|
|
1003
|
+
id: row.memory.id,
|
|
1004
|
+
type: row.memory.type,
|
|
1005
|
+
createdAt: row.memory.createdAt.getTime(),
|
|
1006
|
+
content: typeof row.memory.content === "string" ? JSON.parse(row.memory.content) : row.memory.content,
|
|
1007
|
+
entityId: row.memory.entityId,
|
|
1008
|
+
agentId: row.memory.agentId,
|
|
1009
|
+
roomId: row.memory.roomId,
|
|
1010
|
+
unique: row.memory.unique,
|
|
1011
|
+
metadata: row.memory.metadata,
|
|
1012
|
+
embedding: row.embedding ? Array.from(row.embedding) : undefined
|
|
1013
|
+
}));
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
async getMemoriesByRoomIds(params) {
|
|
1017
|
+
return this.withDatabase(async () => {
|
|
1018
|
+
if (params.roomIds.length === 0)
|
|
1019
|
+
return [];
|
|
1020
|
+
const conditions = [
|
|
1021
|
+
eq(memoryTable.type, params.tableName),
|
|
1022
|
+
inArray(memoryTable.roomId, params.roomIds)
|
|
1023
|
+
];
|
|
1024
|
+
conditions.push(eq(memoryTable.agentId, this.agentId));
|
|
1025
|
+
const query = this.db.select({
|
|
1026
|
+
id: memoryTable.id,
|
|
1027
|
+
type: memoryTable.type,
|
|
1028
|
+
createdAt: memoryTable.createdAt,
|
|
1029
|
+
content: memoryTable.content,
|
|
1030
|
+
entityId: memoryTable.entityId,
|
|
1031
|
+
agentId: memoryTable.agentId,
|
|
1032
|
+
roomId: memoryTable.roomId,
|
|
1033
|
+
unique: memoryTable.unique,
|
|
1034
|
+
metadata: memoryTable.metadata
|
|
1035
|
+
}).from(memoryTable).where(and(...conditions)).orderBy(desc(memoryTable.createdAt));
|
|
1036
|
+
const rows = params.limit ? await query.limit(params.limit) : await query;
|
|
1037
|
+
return rows.map((row) => ({
|
|
1038
|
+
id: row.id,
|
|
1039
|
+
createdAt: row.createdAt.getTime(),
|
|
1040
|
+
content: typeof row.content === "string" ? JSON.parse(row.content) : row.content,
|
|
1041
|
+
entityId: row.entityId,
|
|
1042
|
+
agentId: row.agentId,
|
|
1043
|
+
roomId: row.roomId,
|
|
1044
|
+
unique: row.unique,
|
|
1045
|
+
metadata: row.metadata
|
|
1046
|
+
}));
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
async getMemoryById(id) {
|
|
1050
|
+
return this.withDatabase(async () => {
|
|
1051
|
+
const result = await this.db.select({
|
|
1052
|
+
memory: memoryTable,
|
|
1053
|
+
embedding: embeddingTable[this.embeddingDimension]
|
|
1054
|
+
}).from(memoryTable).leftJoin(embeddingTable, eq(memoryTable.id, embeddingTable.memoryId)).where(eq(memoryTable.id, id)).limit(1);
|
|
1055
|
+
if (result.length === 0)
|
|
1056
|
+
return null;
|
|
1057
|
+
const row = result[0];
|
|
1058
|
+
return {
|
|
1059
|
+
id: row.memory.id,
|
|
1060
|
+
createdAt: row.memory.createdAt.getTime(),
|
|
1061
|
+
content: typeof row.memory.content === "string" ? JSON.parse(row.memory.content) : row.memory.content,
|
|
1062
|
+
entityId: row.memory.entityId,
|
|
1063
|
+
agentId: row.memory.agentId,
|
|
1064
|
+
roomId: row.memory.roomId,
|
|
1065
|
+
unique: row.memory.unique,
|
|
1066
|
+
metadata: row.memory.metadata,
|
|
1067
|
+
embedding: row.embedding ?? undefined
|
|
1068
|
+
};
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
async getMemoriesByIds(memoryIds, tableName) {
|
|
1072
|
+
return this.withDatabase(async () => {
|
|
1073
|
+
if (memoryIds.length === 0)
|
|
1074
|
+
return [];
|
|
1075
|
+
const conditions = [inArray(memoryTable.id, memoryIds)];
|
|
1076
|
+
if (tableName) {
|
|
1077
|
+
conditions.push(eq(memoryTable.type, tableName));
|
|
1078
|
+
}
|
|
1079
|
+
const rows = await this.db.select({
|
|
1080
|
+
memory: memoryTable,
|
|
1081
|
+
embedding: embeddingTable[this.embeddingDimension]
|
|
1082
|
+
}).from(memoryTable).leftJoin(embeddingTable, eq(embeddingTable.memoryId, memoryTable.id)).where(and(...conditions)).orderBy(desc(memoryTable.createdAt));
|
|
1083
|
+
return rows.map((row) => ({
|
|
1084
|
+
id: row.memory.id,
|
|
1085
|
+
createdAt: row.memory.createdAt.getTime(),
|
|
1086
|
+
content: typeof row.memory.content === "string" ? JSON.parse(row.memory.content) : row.memory.content,
|
|
1087
|
+
entityId: row.memory.entityId,
|
|
1088
|
+
agentId: row.memory.agentId,
|
|
1089
|
+
roomId: row.memory.roomId,
|
|
1090
|
+
unique: row.memory.unique,
|
|
1091
|
+
metadata: row.memory.metadata,
|
|
1092
|
+
embedding: row.embedding ?? undefined
|
|
1093
|
+
}));
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
async getCachedEmbeddings(opts) {
|
|
1097
|
+
return this.withDatabase(async () => {
|
|
1098
|
+
try {
|
|
1099
|
+
const results = await this.db.execute(sql16`
|
|
1100
|
+
WITH content_text AS (
|
|
1101
|
+
SELECT
|
|
1102
|
+
m.id,
|
|
1103
|
+
COALESCE(
|
|
1104
|
+
m.content->>${opts.query_field_sub_name},
|
|
1105
|
+
''
|
|
1106
|
+
) as content_text
|
|
1107
|
+
FROM memories m
|
|
1108
|
+
WHERE m.type = ${opts.query_table_name}
|
|
1109
|
+
AND m.content->>${opts.query_field_sub_name} IS NOT NULL
|
|
1110
|
+
),
|
|
1111
|
+
embedded_text AS (
|
|
1112
|
+
SELECT
|
|
1113
|
+
ct.content_text,
|
|
1114
|
+
COALESCE(
|
|
1115
|
+
e.dim_384,
|
|
1116
|
+
e.dim_512,
|
|
1117
|
+
e.dim_768,
|
|
1118
|
+
e.dim_1024,
|
|
1119
|
+
e.dim_1536,
|
|
1120
|
+
e.dim_3072
|
|
1121
|
+
) as embedding
|
|
1122
|
+
FROM content_text ct
|
|
1123
|
+
LEFT JOIN embeddings e ON e.memory_id = ct.id
|
|
1124
|
+
WHERE e.memory_id IS NOT NULL
|
|
1125
|
+
)
|
|
1126
|
+
SELECT
|
|
1127
|
+
embedding,
|
|
1128
|
+
levenshtein(${opts.query_input}, content_text) as levenshtein_score
|
|
1129
|
+
FROM embedded_text
|
|
1130
|
+
WHERE levenshtein(${opts.query_input}, content_text) <= ${opts.query_threshold}
|
|
1131
|
+
ORDER BY levenshtein_score
|
|
1132
|
+
LIMIT ${opts.query_match_count}
|
|
1133
|
+
`);
|
|
1134
|
+
return results.rows.map((row) => ({
|
|
1135
|
+
embedding: Array.isArray(row.embedding) ? row.embedding : typeof row.embedding === "string" ? JSON.parse(row.embedding) : [],
|
|
1136
|
+
levenshtein_score: Number(row.levenshtein_score)
|
|
1137
|
+
})).filter((row) => Array.isArray(row.embedding));
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
logger.error(`Error in getCachedEmbeddings: ${error instanceof Error ? error.message : String(error)}, tableName: ${opts.query_table_name}, fieldName: ${opts.query_field_name}`);
|
|
1140
|
+
if (error instanceof Error && error.message === "levenshtein argument exceeds maximum length of 255 characters") {
|
|
1141
|
+
return [];
|
|
1142
|
+
}
|
|
1143
|
+
throw error;
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
async log(params) {
|
|
1148
|
+
return this.withDatabase(async () => {
|
|
1149
|
+
try {
|
|
1150
|
+
const sanitizedBody = this.sanitizeJsonObject(params.body);
|
|
1151
|
+
const jsonString = JSON.stringify(sanitizedBody);
|
|
1152
|
+
await this.db.transaction(async (tx) => {
|
|
1153
|
+
await tx.insert(logTable).values({
|
|
1154
|
+
body: sql16`${jsonString}::jsonb`,
|
|
1155
|
+
entityId: params.entityId,
|
|
1156
|
+
roomId: params.roomId,
|
|
1157
|
+
type: params.type
|
|
1158
|
+
});
|
|
1159
|
+
});
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
logger.error(`Failed to create log entry: ${error instanceof Error ? error.message : String(error)}, type: ${params.type}, roomId: ${params.roomId}, entityId: ${params.entityId}`);
|
|
1162
|
+
throw error;
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
sanitizeJsonObject(value, seen = new WeakSet) {
|
|
1167
|
+
if (value === null || value === undefined) {
|
|
1168
|
+
return value;
|
|
1169
|
+
}
|
|
1170
|
+
if (typeof value === "string") {
|
|
1171
|
+
return value.replace(/\u0000/g, "").replace(/\\(?!["\\/bfnrtu])/g, "\\\\").replace(/\\u(?![0-9a-fA-F]{4})/g, "\\\\u");
|
|
1172
|
+
}
|
|
1173
|
+
if (typeof value === "object") {
|
|
1174
|
+
if (seen.has(value)) {
|
|
1175
|
+
return null;
|
|
1176
|
+
} else {
|
|
1177
|
+
seen.add(value);
|
|
1178
|
+
}
|
|
1179
|
+
if (Array.isArray(value)) {
|
|
1180
|
+
return value.map((item) => this.sanitizeJsonObject(item, seen));
|
|
1181
|
+
} else {
|
|
1182
|
+
const result = {};
|
|
1183
|
+
for (const [key, val] of Object.entries(value)) {
|
|
1184
|
+
const sanitizedKey = typeof key === "string" ? key.replace(/\u0000/g, "").replace(/\\u(?![0-9a-fA-F]{4})/g, "\\\\u") : key;
|
|
1185
|
+
result[sanitizedKey] = this.sanitizeJsonObject(val, seen);
|
|
1186
|
+
}
|
|
1187
|
+
return result;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return value;
|
|
1191
|
+
}
|
|
1192
|
+
async getLogs(params) {
|
|
1193
|
+
const { entityId, roomId, type, count: count2, offset } = params;
|
|
1194
|
+
return this.withDatabase(async () => {
|
|
1195
|
+
const result = await this.db.select().from(logTable).where(and(eq(logTable.entityId, entityId), roomId ? eq(logTable.roomId, roomId) : undefined, type ? eq(logTable.type, type) : undefined)).orderBy(desc(logTable.createdAt)).limit(count2 ?? 10).offset(offset ?? 0);
|
|
1196
|
+
const logs = result.map((log) => ({
|
|
1197
|
+
...log,
|
|
1198
|
+
id: log.id,
|
|
1199
|
+
entityId: log.entityId,
|
|
1200
|
+
roomId: log.roomId,
|
|
1201
|
+
body: log.body,
|
|
1202
|
+
createdAt: new Date(log.createdAt)
|
|
1203
|
+
}));
|
|
1204
|
+
if (logs.length === 0)
|
|
1205
|
+
return [];
|
|
1206
|
+
return logs;
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
async deleteLog(logId) {
|
|
1210
|
+
return this.withDatabase(async () => {
|
|
1211
|
+
await this.db.delete(logTable).where(eq(logTable.id, logId));
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
async searchMemories(params) {
|
|
1215
|
+
return await this.searchMemoriesByEmbedding(params.embedding, {
|
|
1216
|
+
match_threshold: params.match_threshold,
|
|
1217
|
+
count: params.count,
|
|
1218
|
+
roomId: params.roomId,
|
|
1219
|
+
worldId: params.worldId,
|
|
1220
|
+
entityId: params.entityId,
|
|
1221
|
+
unique: params.unique,
|
|
1222
|
+
tableName: params.tableName
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
async searchMemoriesByEmbedding(embedding, params) {
|
|
1226
|
+
return this.withDatabase(async () => {
|
|
1227
|
+
const cleanVector = embedding.map((n) => Number.isFinite(n) ? Number(n.toFixed(6)) : 0);
|
|
1228
|
+
const similarity = sql16`1 - (${cosineDistance(embeddingTable[this.embeddingDimension], cleanVector)})`;
|
|
1229
|
+
const conditions = [eq(memoryTable.type, params.tableName)];
|
|
1230
|
+
if (params.unique) {
|
|
1231
|
+
conditions.push(eq(memoryTable.unique, true));
|
|
1232
|
+
}
|
|
1233
|
+
conditions.push(eq(memoryTable.agentId, this.agentId));
|
|
1234
|
+
if (params.roomId) {
|
|
1235
|
+
conditions.push(eq(memoryTable.roomId, params.roomId));
|
|
1236
|
+
}
|
|
1237
|
+
if (params.worldId) {
|
|
1238
|
+
conditions.push(eq(memoryTable.worldId, params.worldId));
|
|
1239
|
+
}
|
|
1240
|
+
if (params.entityId) {
|
|
1241
|
+
conditions.push(eq(memoryTable.entityId, params.entityId));
|
|
1242
|
+
}
|
|
1243
|
+
if (params.match_threshold) {
|
|
1244
|
+
conditions.push(gte(similarity, params.match_threshold));
|
|
1245
|
+
}
|
|
1246
|
+
const results = await this.db.select({
|
|
1247
|
+
memory: memoryTable,
|
|
1248
|
+
similarity,
|
|
1249
|
+
embedding: embeddingTable[this.embeddingDimension]
|
|
1250
|
+
}).from(embeddingTable).innerJoin(memoryTable, eq(memoryTable.id, embeddingTable.memoryId)).where(and(...conditions)).orderBy(desc(similarity)).limit(params.count ?? 10);
|
|
1251
|
+
return results.map((row) => ({
|
|
1252
|
+
id: row.memory.id,
|
|
1253
|
+
type: row.memory.type,
|
|
1254
|
+
createdAt: row.memory.createdAt.getTime(),
|
|
1255
|
+
content: typeof row.memory.content === "string" ? JSON.parse(row.memory.content) : row.memory.content,
|
|
1256
|
+
entityId: row.memory.entityId,
|
|
1257
|
+
agentId: row.memory.agentId,
|
|
1258
|
+
roomId: row.memory.roomId,
|
|
1259
|
+
worldId: row.memory.worldId,
|
|
1260
|
+
unique: row.memory.unique,
|
|
1261
|
+
metadata: row.memory.metadata,
|
|
1262
|
+
embedding: row.embedding ?? undefined,
|
|
1263
|
+
similarity: row.similarity
|
|
1264
|
+
}));
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
async createMemory(memory, tableName) {
|
|
1268
|
+
logger.debug(`DrizzleAdapter createMemory: memoryId: ${memory.id}, embeddingLength: ${memory.embedding?.length}, contentLength: ${memory.content?.text?.length}`);
|
|
1269
|
+
const memoryId = memory.id ?? v4_default();
|
|
1270
|
+
const existing = await this.getMemoryById(memoryId);
|
|
1271
|
+
if (existing) {
|
|
1272
|
+
logger.debug(`Memory already exists, skipping creation: ${memoryId}`);
|
|
1273
|
+
return memoryId;
|
|
1274
|
+
}
|
|
1275
|
+
if (memory.unique === undefined) {
|
|
1276
|
+
memory.unique = true;
|
|
1277
|
+
if (memory.embedding && Array.isArray(memory.embedding)) {
|
|
1278
|
+
const similarMemories = await this.searchMemoriesByEmbedding(memory.embedding, {
|
|
1279
|
+
tableName,
|
|
1280
|
+
roomId: memory.roomId,
|
|
1281
|
+
worldId: memory.worldId,
|
|
1282
|
+
entityId: memory.entityId,
|
|
1283
|
+
match_threshold: 0.95,
|
|
1284
|
+
count: 1
|
|
1285
|
+
});
|
|
1286
|
+
memory.unique = similarMemories.length === 0;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
const contentToInsert = typeof memory.content === "string" ? memory.content : JSON.stringify(memory.content ?? {});
|
|
1290
|
+
const metadataToInsert = typeof memory.metadata === "string" ? memory.metadata : JSON.stringify(memory.metadata ?? {});
|
|
1291
|
+
await this.db.transaction(async (tx) => {
|
|
1292
|
+
await tx.insert(memoryTable).values([
|
|
1293
|
+
{
|
|
1294
|
+
id: memoryId,
|
|
1295
|
+
type: tableName,
|
|
1296
|
+
content: sql16`${contentToInsert}::jsonb`,
|
|
1297
|
+
metadata: sql16`${metadataToInsert}::jsonb`,
|
|
1298
|
+
entityId: memory.entityId,
|
|
1299
|
+
roomId: memory.roomId,
|
|
1300
|
+
worldId: memory.worldId,
|
|
1301
|
+
agentId: memory.agentId || this.agentId,
|
|
1302
|
+
unique: memory.unique,
|
|
1303
|
+
createdAt: memory.createdAt ? new Date(memory.createdAt) : new Date
|
|
1304
|
+
}
|
|
1305
|
+
]);
|
|
1306
|
+
if (memory.embedding && Array.isArray(memory.embedding)) {
|
|
1307
|
+
const embeddingValues = {
|
|
1308
|
+
id: v4_default(),
|
|
1309
|
+
memoryId,
|
|
1310
|
+
createdAt: memory.createdAt ? new Date(memory.createdAt) : new Date
|
|
1311
|
+
};
|
|
1312
|
+
const cleanVector = memory.embedding.map((n) => Number.isFinite(n) ? Number(n.toFixed(6)) : 0);
|
|
1313
|
+
embeddingValues[this.embeddingDimension] = cleanVector;
|
|
1314
|
+
await tx.insert(embeddingTable).values([embeddingValues]);
|
|
1315
|
+
}
|
|
1316
|
+
});
|
|
1317
|
+
return memoryId;
|
|
1318
|
+
}
|
|
1319
|
+
async updateMemory(memory) {
|
|
1320
|
+
return this.withDatabase(async () => {
|
|
1321
|
+
try {
|
|
1322
|
+
logger.debug(`Updating memory: memoryId: ${memory.id}, hasEmbedding: ${!!memory.embedding}`);
|
|
1323
|
+
await this.db.transaction(async (tx) => {
|
|
1324
|
+
if (memory.content) {
|
|
1325
|
+
const contentToUpdate = typeof memory.content === "string" ? memory.content : JSON.stringify(memory.content ?? {});
|
|
1326
|
+
const metadataToUpdate = typeof memory.metadata === "string" ? memory.metadata : JSON.stringify(memory.metadata ?? {});
|
|
1327
|
+
await tx.update(memoryTable).set({
|
|
1328
|
+
content: sql16`${contentToUpdate}::jsonb`,
|
|
1329
|
+
...memory.metadata && { metadata: sql16`${metadataToUpdate}::jsonb` }
|
|
1330
|
+
}).where(eq(memoryTable.id, memory.id));
|
|
1331
|
+
} else if (memory.metadata) {
|
|
1332
|
+
const metadataToUpdate = typeof memory.metadata === "string" ? memory.metadata : JSON.stringify(memory.metadata ?? {});
|
|
1333
|
+
await tx.update(memoryTable).set({
|
|
1334
|
+
metadata: sql16`${metadataToUpdate}::jsonb`
|
|
1335
|
+
}).where(eq(memoryTable.id, memory.id));
|
|
1336
|
+
}
|
|
1337
|
+
if (memory.embedding && Array.isArray(memory.embedding)) {
|
|
1338
|
+
const cleanVector = memory.embedding.map((n) => Number.isFinite(n) ? Number(n.toFixed(6)) : 0);
|
|
1339
|
+
const existingEmbedding = await tx.select({ id: embeddingTable.id }).from(embeddingTable).where(eq(embeddingTable.memoryId, memory.id)).limit(1);
|
|
1340
|
+
if (existingEmbedding.length > 0) {
|
|
1341
|
+
const updateValues = {};
|
|
1342
|
+
updateValues[this.embeddingDimension] = cleanVector;
|
|
1343
|
+
await tx.update(embeddingTable).set(updateValues).where(eq(embeddingTable.memoryId, memory.id));
|
|
1344
|
+
} else {
|
|
1345
|
+
const embeddingValues = {
|
|
1346
|
+
id: v4_default(),
|
|
1347
|
+
memoryId: memory.id
|
|
1348
|
+
};
|
|
1349
|
+
embeddingValues[this.embeddingDimension] = cleanVector;
|
|
1350
|
+
await tx.insert(embeddingTable).values([embeddingValues]);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
});
|
|
1354
|
+
logger.debug(`Memory updated successfully: ${memory.id}`);
|
|
1355
|
+
return true;
|
|
1356
|
+
} catch (error) {
|
|
1357
|
+
logger.error(`Error updating memory: ${error instanceof Error ? error.message : String(error)}, memoryId: ${memory.id}`);
|
|
1358
|
+
return false;
|
|
1359
|
+
}
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
async deleteMemory(memoryId) {
|
|
1363
|
+
return this.withDatabase(async () => {
|
|
1364
|
+
await this.db.transaction(async (tx) => {
|
|
1365
|
+
await this.deleteMemoryFragments(tx, memoryId);
|
|
1366
|
+
await tx.delete(embeddingTable).where(eq(embeddingTable.memoryId, memoryId));
|
|
1367
|
+
await tx.delete(memoryTable).where(eq(memoryTable.id, memoryId));
|
|
1368
|
+
});
|
|
1369
|
+
logger.debug(`Memory and related fragments removed successfully: ${memoryId}`);
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
async deleteManyMemories(memoryIds) {
|
|
1373
|
+
if (memoryIds.length === 0) {
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
return this.withDatabase(async () => {
|
|
1377
|
+
await this.db.transaction(async (tx) => {
|
|
1378
|
+
const BATCH_SIZE = 100;
|
|
1379
|
+
for (let i = 0;i < memoryIds.length; i += BATCH_SIZE) {
|
|
1380
|
+
const batch = memoryIds.slice(i, i + BATCH_SIZE);
|
|
1381
|
+
await Promise.all(batch.map(async (memoryId) => {
|
|
1382
|
+
await this.deleteMemoryFragments(tx, memoryId);
|
|
1383
|
+
}));
|
|
1384
|
+
await tx.delete(embeddingTable).where(inArray(embeddingTable.memoryId, batch));
|
|
1385
|
+
await tx.delete(memoryTable).where(inArray(memoryTable.id, batch));
|
|
1386
|
+
}
|
|
1387
|
+
});
|
|
1388
|
+
logger.debug(`Batch memory deletion completed successfully: ${memoryIds.length}`);
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
async deleteMemoryFragments(tx, documentId) {
|
|
1392
|
+
const fragmentsToDelete = await this.getMemoryFragments(tx, documentId);
|
|
1393
|
+
if (fragmentsToDelete.length > 0) {
|
|
1394
|
+
const fragmentIds = fragmentsToDelete.map((f) => f.id);
|
|
1395
|
+
await tx.delete(embeddingTable).where(inArray(embeddingTable.memoryId, fragmentIds));
|
|
1396
|
+
await tx.delete(memoryTable).where(inArray(memoryTable.id, fragmentIds));
|
|
1397
|
+
logger.debug(`Deleted related fragments: documentId: ${documentId}, fragmentCount: ${fragmentsToDelete.length}`);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
async getMemoryFragments(tx, documentId) {
|
|
1401
|
+
const fragments = await tx.select({ id: memoryTable.id }).from(memoryTable).where(and(eq(memoryTable.agentId, this.agentId), sql16`${memoryTable.metadata}->>'documentId' = ${documentId}`));
|
|
1402
|
+
return fragments.map((f) => ({ id: f.id }));
|
|
1403
|
+
}
|
|
1404
|
+
async deleteAllMemories(roomId, tableName) {
|
|
1405
|
+
return this.withDatabase(async () => {
|
|
1406
|
+
await this.db.transaction(async (tx) => {
|
|
1407
|
+
const rows = await tx.select({ id: memoryTable.id }).from(memoryTable).where(and(eq(memoryTable.roomId, roomId), eq(memoryTable.type, tableName)));
|
|
1408
|
+
const ids = rows.map((r) => r.id);
|
|
1409
|
+
logger.debug(`[deleteAllMemories] memory IDs to delete: roomId: ${roomId}, tableName: ${tableName}, ids: ${JSON.stringify(ids)}`);
|
|
1410
|
+
if (ids.length === 0) {
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
await Promise.all(ids.map(async (memoryId) => {
|
|
1414
|
+
await this.deleteMemoryFragments(tx, memoryId);
|
|
1415
|
+
await tx.delete(embeddingTable).where(eq(embeddingTable.memoryId, memoryId));
|
|
1416
|
+
}));
|
|
1417
|
+
await tx.delete(memoryTable).where(and(eq(memoryTable.roomId, roomId), eq(memoryTable.type, tableName)));
|
|
1418
|
+
});
|
|
1419
|
+
logger.debug(`All memories removed successfully: roomId: ${roomId}, tableName: ${tableName}`);
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
async countMemories(roomId, unique4 = true, tableName = "") {
|
|
1423
|
+
if (!tableName)
|
|
1424
|
+
throw new Error("tableName is required");
|
|
1425
|
+
return this.withDatabase(async () => {
|
|
1426
|
+
const conditions = [eq(memoryTable.roomId, roomId), eq(memoryTable.type, tableName)];
|
|
1427
|
+
if (unique4) {
|
|
1428
|
+
conditions.push(eq(memoryTable.unique, true));
|
|
1429
|
+
}
|
|
1430
|
+
const result = await this.db.select({ count: sql16`count(*)` }).from(memoryTable).where(and(...conditions));
|
|
1431
|
+
return Number(result[0]?.count ?? 0);
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
async getRoomsByIds(roomIds) {
|
|
1435
|
+
return this.withDatabase(async () => {
|
|
1436
|
+
const result = await this.db.select({
|
|
1437
|
+
id: roomTable.id,
|
|
1438
|
+
name: roomTable.name,
|
|
1439
|
+
channelId: roomTable.channelId,
|
|
1440
|
+
agentId: roomTable.agentId,
|
|
1441
|
+
serverId: roomTable.serverId,
|
|
1442
|
+
worldId: roomTable.worldId,
|
|
1443
|
+
type: roomTable.type,
|
|
1444
|
+
source: roomTable.source,
|
|
1445
|
+
metadata: roomTable.metadata
|
|
1446
|
+
}).from(roomTable).where(and(inArray(roomTable.id, roomIds), eq(roomTable.agentId, this.agentId)));
|
|
1447
|
+
const rooms = result.map((room) => ({
|
|
1448
|
+
...room,
|
|
1449
|
+
id: room.id,
|
|
1450
|
+
name: room.name ?? undefined,
|
|
1451
|
+
agentId: room.agentId,
|
|
1452
|
+
serverId: room.serverId,
|
|
1453
|
+
worldId: room.worldId,
|
|
1454
|
+
channelId: room.channelId,
|
|
1455
|
+
type: room.type,
|
|
1456
|
+
metadata: room.metadata
|
|
1457
|
+
}));
|
|
1458
|
+
return rooms;
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
async getRoomsByWorld(worldId) {
|
|
1462
|
+
return this.withDatabase(async () => {
|
|
1463
|
+
const result = await this.db.select().from(roomTable).where(eq(roomTable.worldId, worldId));
|
|
1464
|
+
const rooms = result.map((room) => ({
|
|
1465
|
+
...room,
|
|
1466
|
+
id: room.id,
|
|
1467
|
+
name: room.name ?? undefined,
|
|
1468
|
+
agentId: room.agentId,
|
|
1469
|
+
serverId: room.serverId,
|
|
1470
|
+
worldId: room.worldId,
|
|
1471
|
+
channelId: room.channelId,
|
|
1472
|
+
type: room.type,
|
|
1473
|
+
metadata: room.metadata
|
|
1474
|
+
}));
|
|
1475
|
+
return rooms;
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
async updateRoom(room) {
|
|
1479
|
+
return this.withDatabase(async () => {
|
|
1480
|
+
await this.db.update(roomTable).set({ ...room, agentId: this.agentId }).where(eq(roomTable.id, room.id));
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
async createRooms(rooms) {
|
|
1484
|
+
return this.withDatabase(async () => {
|
|
1485
|
+
const roomsWithIds = rooms.map((room) => ({
|
|
1486
|
+
...room,
|
|
1487
|
+
agentId: this.agentId,
|
|
1488
|
+
id: room.id || v4_default()
|
|
1489
|
+
}));
|
|
1490
|
+
const insertedRooms = await this.db.insert(roomTable).values(roomsWithIds).onConflictDoNothing().returning();
|
|
1491
|
+
const insertedIds = insertedRooms.map((r) => r.id);
|
|
1492
|
+
return insertedIds;
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1495
|
+
async deleteRoom(roomId) {
|
|
1496
|
+
if (!roomId)
|
|
1497
|
+
throw new Error("Room ID is required");
|
|
1498
|
+
return this.withDatabase(async () => {
|
|
1499
|
+
await this.db.transaction(async (tx) => {
|
|
1500
|
+
await tx.delete(roomTable).where(eq(roomTable.id, roomId));
|
|
1501
|
+
});
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
async getRoomsForParticipant(entityId) {
|
|
1505
|
+
return this.withDatabase(async () => {
|
|
1506
|
+
const result = await this.db.select({ roomId: participantTable.roomId }).from(participantTable).innerJoin(roomTable, eq(participantTable.roomId, roomTable.id)).where(and(eq(participantTable.entityId, entityId), eq(roomTable.agentId, this.agentId)));
|
|
1507
|
+
return result.map((row) => row.roomId);
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
async getRoomsForParticipants(entityIds) {
|
|
1511
|
+
return this.withDatabase(async () => {
|
|
1512
|
+
const result = await this.db.selectDistinct({ roomId: participantTable.roomId }).from(participantTable).innerJoin(roomTable, eq(participantTable.roomId, roomTable.id)).where(and(inArray(participantTable.entityId, entityIds), eq(roomTable.agentId, this.agentId)));
|
|
1513
|
+
return result.map((row) => row.roomId);
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
async addParticipant(entityId, roomId) {
|
|
1517
|
+
return this.withDatabase(async () => {
|
|
1518
|
+
try {
|
|
1519
|
+
await this.db.insert(participantTable).values({
|
|
1520
|
+
entityId,
|
|
1521
|
+
roomId,
|
|
1522
|
+
agentId: this.agentId
|
|
1523
|
+
}).onConflictDoNothing();
|
|
1524
|
+
return true;
|
|
1525
|
+
} catch (error) {
|
|
1526
|
+
logger.error(`Error adding participant to room: ${error instanceof Error ? error.message : String(error)}, entityId: ${entityId}, roomId: ${roomId}, agentId: ${this.agentId}`);
|
|
1527
|
+
return false;
|
|
1528
|
+
}
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
async addParticipantsRoom(entityIds, roomId) {
|
|
1532
|
+
return this.withDatabase(async () => {
|
|
1533
|
+
try {
|
|
1534
|
+
const values = entityIds.map((id) => ({
|
|
1535
|
+
entityId: id,
|
|
1536
|
+
roomId,
|
|
1537
|
+
agentId: this.agentId
|
|
1538
|
+
}));
|
|
1539
|
+
await this.db.insert(participantTable).values(values).onConflictDoNothing().execute();
|
|
1540
|
+
logger.debug(`${entityIds.length} Entities linked successfully`);
|
|
1541
|
+
return true;
|
|
1542
|
+
} catch (error) {
|
|
1543
|
+
logger.error(`Error adding participants to room: ${error instanceof Error ? error.message : String(error)}, entityIdSample: ${entityIds[0]}, roomId: ${roomId}, agentId: ${this.agentId}`);
|
|
1544
|
+
return false;
|
|
1545
|
+
}
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
async removeParticipant(entityId, roomId) {
|
|
1549
|
+
return this.withDatabase(async () => {
|
|
1550
|
+
try {
|
|
1551
|
+
const result = await this.db.transaction(async (tx) => {
|
|
1552
|
+
return await tx.delete(participantTable).where(and(eq(participantTable.entityId, entityId), eq(participantTable.roomId, roomId))).returning();
|
|
1553
|
+
});
|
|
1554
|
+
const removed = result.length > 0;
|
|
1555
|
+
logger.debug(`Participant ${removed ? "removed" : "not found"}: entityId: ${entityId}, roomId: ${roomId}, removed: ${removed}`);
|
|
1556
|
+
return removed;
|
|
1557
|
+
} catch (error) {
|
|
1558
|
+
logger.error(`Error removing participant from room: ${error instanceof Error ? error.message : String(error)}, entityId: ${entityId}, roomId: ${roomId}`);
|
|
1559
|
+
return false;
|
|
1560
|
+
}
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
async getParticipantsForEntity(entityId) {
|
|
1564
|
+
return this.withDatabase(async () => {
|
|
1565
|
+
const result = await this.db.select({
|
|
1566
|
+
id: participantTable.id,
|
|
1567
|
+
entityId: participantTable.entityId,
|
|
1568
|
+
roomId: participantTable.roomId
|
|
1569
|
+
}).from(participantTable).where(eq(participantTable.entityId, entityId));
|
|
1570
|
+
const entities = await this.getEntitiesByIds([entityId]);
|
|
1571
|
+
if (!entities || !entities.length) {
|
|
1572
|
+
return [];
|
|
1573
|
+
}
|
|
1574
|
+
return result.map((row) => ({
|
|
1575
|
+
id: row.id,
|
|
1576
|
+
entity: entities[0]
|
|
1577
|
+
}));
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
async getParticipantsForRoom(roomId) {
|
|
1581
|
+
return this.withDatabase(async () => {
|
|
1582
|
+
const result = await this.db.select({ entityId: participantTable.entityId }).from(participantTable).where(eq(participantTable.roomId, roomId));
|
|
1583
|
+
return result.map((row) => row.entityId);
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
async getParticipantUserState(roomId, entityId) {
|
|
1587
|
+
return this.withDatabase(async () => {
|
|
1588
|
+
const result = await this.db.select({ roomState: participantTable.roomState }).from(participantTable).where(and(eq(participantTable.roomId, roomId), eq(participantTable.entityId, entityId), eq(participantTable.agentId, this.agentId))).limit(1);
|
|
1589
|
+
return result[0]?.roomState ?? null;
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
async setParticipantUserState(roomId, entityId, state) {
|
|
1593
|
+
return this.withDatabase(async () => {
|
|
1594
|
+
try {
|
|
1595
|
+
await this.db.transaction(async (tx) => {
|
|
1596
|
+
await tx.update(participantTable).set({ roomState: state }).where(and(eq(participantTable.roomId, roomId), eq(participantTable.entityId, entityId), eq(participantTable.agentId, this.agentId)));
|
|
1597
|
+
});
|
|
1598
|
+
} catch (error) {
|
|
1599
|
+
logger.error(`Error setting participant follow state: roomId: ${roomId}, entityId: ${entityId}, state: ${state}, error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1600
|
+
throw error;
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
async createRelationship(params) {
|
|
1605
|
+
return this.withDatabase(async () => {
|
|
1606
|
+
const id = v4_default();
|
|
1607
|
+
const saveParams = {
|
|
1608
|
+
id,
|
|
1609
|
+
sourceEntityId: params.sourceEntityId,
|
|
1610
|
+
targetEntityId: params.targetEntityId,
|
|
1611
|
+
agentId: this.agentId,
|
|
1612
|
+
tags: params.tags || [],
|
|
1613
|
+
metadata: params.metadata || {}
|
|
1614
|
+
};
|
|
1615
|
+
try {
|
|
1616
|
+
await this.db.insert(relationshipTable).values(saveParams);
|
|
1617
|
+
return true;
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
logger.error(`Error creating relationship: ${error instanceof Error ? error.message : String(error)}, saveParams: ${JSON.stringify(saveParams)}`);
|
|
1620
|
+
return false;
|
|
1621
|
+
}
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
async updateRelationship(relationship) {
|
|
1625
|
+
return this.withDatabase(async () => {
|
|
1626
|
+
try {
|
|
1627
|
+
await this.db.update(relationshipTable).set({
|
|
1628
|
+
tags: relationship.tags || [],
|
|
1629
|
+
metadata: relationship.metadata || {}
|
|
1630
|
+
}).where(eq(relationshipTable.id, relationship.id));
|
|
1631
|
+
} catch (error) {
|
|
1632
|
+
logger.error(`Error updating relationship: ${error instanceof Error ? error.message : String(error)}, relationship: ${JSON.stringify(relationship)}`);
|
|
1633
|
+
throw error;
|
|
1634
|
+
}
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
async getRelationship(params) {
|
|
1638
|
+
return this.withDatabase(async () => {
|
|
1639
|
+
const { sourceEntityId, targetEntityId } = params;
|
|
1640
|
+
const result = await this.db.select().from(relationshipTable).where(and(eq(relationshipTable.sourceEntityId, sourceEntityId), eq(relationshipTable.targetEntityId, targetEntityId)));
|
|
1641
|
+
if (result.length === 0)
|
|
1642
|
+
return null;
|
|
1643
|
+
const relationship = result[0];
|
|
1644
|
+
return {
|
|
1645
|
+
...relationship,
|
|
1646
|
+
id: relationship.id,
|
|
1647
|
+
sourceEntityId: relationship.sourceEntityId,
|
|
1648
|
+
targetEntityId: relationship.targetEntityId,
|
|
1649
|
+
agentId: relationship.agentId,
|
|
1650
|
+
tags: relationship.tags ?? [],
|
|
1651
|
+
metadata: relationship.metadata ?? {},
|
|
1652
|
+
createdAt: relationship.createdAt.toISOString()
|
|
1653
|
+
};
|
|
1654
|
+
});
|
|
1655
|
+
}
|
|
1656
|
+
async getRelationships(params) {
|
|
1657
|
+
return this.withDatabase(async () => {
|
|
1658
|
+
const { entityId, tags } = params;
|
|
1659
|
+
let query;
|
|
1660
|
+
if (tags && tags.length > 0) {
|
|
1661
|
+
query = sql16`
|
|
1662
|
+
SELECT * FROM ${relationshipTable}
|
|
1663
|
+
WHERE (${relationshipTable.sourceEntityId} = ${entityId} OR ${relationshipTable.targetEntityId} = ${entityId})
|
|
1664
|
+
AND ${relationshipTable.tags} && CAST(ARRAY[${sql16.join(tags, sql16`, `)}] AS text[])
|
|
1665
|
+
`;
|
|
1666
|
+
} else {
|
|
1667
|
+
query = sql16`
|
|
1668
|
+
SELECT * FROM ${relationshipTable}
|
|
1669
|
+
WHERE ${relationshipTable.sourceEntityId} = ${entityId} OR ${relationshipTable.targetEntityId} = ${entityId}
|
|
1670
|
+
`;
|
|
1671
|
+
}
|
|
1672
|
+
const result = await this.db.execute(query);
|
|
1673
|
+
return result.rows.map((relationship) => ({
|
|
1674
|
+
...relationship,
|
|
1675
|
+
id: relationship.id,
|
|
1676
|
+
sourceEntityId: relationship.sourceEntityId,
|
|
1677
|
+
targetEntityId: relationship.targetEntityId,
|
|
1678
|
+
agentId: relationship.agentId,
|
|
1679
|
+
tags: relationship.tags ?? [],
|
|
1680
|
+
metadata: relationship.metadata ?? {},
|
|
1681
|
+
createdAt: relationship.createdAt ? relationship.createdAt instanceof Date ? relationship.createdAt.toISOString() : new Date(relationship.createdAt).toISOString() : new Date().toISOString()
|
|
1682
|
+
}));
|
|
1683
|
+
});
|
|
1684
|
+
}
|
|
1685
|
+
async getCache(key) {
|
|
1686
|
+
return this.withDatabase(async () => {
|
|
1687
|
+
try {
|
|
1688
|
+
const result = await this.db.select({ value: cacheTable.value }).from(cacheTable).where(and(eq(cacheTable.agentId, this.agentId), eq(cacheTable.key, key))).limit(1);
|
|
1689
|
+
if (result && result.length > 0 && result[0]) {
|
|
1690
|
+
return result[0].value;
|
|
1691
|
+
}
|
|
1692
|
+
return;
|
|
1693
|
+
} catch (error) {
|
|
1694
|
+
logger.error(`Error fetching cache: ${error instanceof Error ? error.message : String(error)}, key: ${key}, agentId: ${this.agentId}`);
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
async setCache(key, value) {
|
|
1700
|
+
return this.withDatabase(async () => {
|
|
1701
|
+
try {
|
|
1702
|
+
await this.db.insert(cacheTable).values({
|
|
1703
|
+
key,
|
|
1704
|
+
agentId: this.agentId,
|
|
1705
|
+
value
|
|
1706
|
+
}).onConflictDoUpdate({
|
|
1707
|
+
target: [cacheTable.key, cacheTable.agentId],
|
|
1708
|
+
set: {
|
|
1709
|
+
value
|
|
1710
|
+
}
|
|
1711
|
+
});
|
|
1712
|
+
return true;
|
|
1713
|
+
} catch (error) {
|
|
1714
|
+
logger.error(`Error setting cache: ${error instanceof Error ? error.message : String(error)}, key: ${key}, agentId: ${this.agentId}`);
|
|
1715
|
+
return false;
|
|
1716
|
+
}
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
async deleteCache(key) {
|
|
1720
|
+
return this.withDatabase(async () => {
|
|
1721
|
+
try {
|
|
1722
|
+
await this.db.transaction(async (tx) => {
|
|
1723
|
+
await tx.delete(cacheTable).where(and(eq(cacheTable.agentId, this.agentId), eq(cacheTable.key, key)));
|
|
1724
|
+
});
|
|
1725
|
+
return true;
|
|
1726
|
+
} catch (error) {
|
|
1727
|
+
logger.error(`Error deleting cache: ${error instanceof Error ? error.message : String(error)}, key: ${key}, agentId: ${this.agentId}`);
|
|
1728
|
+
return false;
|
|
1729
|
+
}
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
async createWorld(world) {
|
|
1733
|
+
return this.withDatabase(async () => {
|
|
1734
|
+
const newWorldId = world.id || v4_default();
|
|
1735
|
+
await this.db.insert(worldTable).values({
|
|
1736
|
+
...world,
|
|
1737
|
+
id: newWorldId,
|
|
1738
|
+
name: world.name || ""
|
|
1739
|
+
});
|
|
1740
|
+
return newWorldId;
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
async getWorld(id) {
|
|
1744
|
+
return this.withDatabase(async () => {
|
|
1745
|
+
const result = await this.db.select().from(worldTable).where(eq(worldTable.id, id));
|
|
1746
|
+
return result.length > 0 ? result[0] : null;
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
async getAllWorlds() {
|
|
1750
|
+
return this.withDatabase(async () => {
|
|
1751
|
+
const result = await this.db.select().from(worldTable).where(eq(worldTable.agentId, this.agentId));
|
|
1752
|
+
return result;
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
async updateWorld(world) {
|
|
1756
|
+
return this.withDatabase(async () => {
|
|
1757
|
+
await this.db.update(worldTable).set(world).where(eq(worldTable.id, world.id));
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
async removeWorld(id) {
|
|
1761
|
+
return this.withDatabase(async () => {
|
|
1762
|
+
await this.db.delete(worldTable).where(eq(worldTable.id, id));
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
async createTask(task) {
|
|
1766
|
+
if (!task.worldId) {
|
|
1767
|
+
throw new Error("worldId is required");
|
|
1768
|
+
}
|
|
1769
|
+
return this.withRetry(async () => {
|
|
1770
|
+
return this.withDatabase(async () => {
|
|
1771
|
+
const now = new Date;
|
|
1772
|
+
const metadata = task.metadata || {};
|
|
1773
|
+
const values = {
|
|
1774
|
+
id: task.id,
|
|
1775
|
+
name: task.name,
|
|
1776
|
+
description: task.description,
|
|
1777
|
+
roomId: task.roomId,
|
|
1778
|
+
worldId: task.worldId,
|
|
1779
|
+
tags: task.tags,
|
|
1780
|
+
metadata,
|
|
1781
|
+
createdAt: now,
|
|
1782
|
+
updatedAt: now,
|
|
1783
|
+
agentId: this.agentId
|
|
1784
|
+
};
|
|
1785
|
+
const result = await this.db.insert(taskTable).values(values).returning();
|
|
1786
|
+
return result[0].id;
|
|
1787
|
+
});
|
|
1788
|
+
});
|
|
1789
|
+
}
|
|
1790
|
+
async getTasks(params) {
|
|
1791
|
+
return this.withRetry(async () => {
|
|
1792
|
+
return this.withDatabase(async () => {
|
|
1793
|
+
const result = await this.db.select().from(taskTable).where(and(eq(taskTable.agentId, this.agentId), ...params.roomId ? [eq(taskTable.roomId, params.roomId)] : [], ...params.tags && params.tags.length > 0 ? [
|
|
1794
|
+
sql16`${taskTable.tags} @> ARRAY[${sql16.raw(params.tags.map((t) => `'${t.replace(/'/g, "''")}'`).join(", "))}]::text[]`
|
|
1795
|
+
] : []));
|
|
1796
|
+
return result.map((row) => ({
|
|
1797
|
+
id: row.id,
|
|
1798
|
+
name: row.name,
|
|
1799
|
+
description: row.description ?? "",
|
|
1800
|
+
roomId: row.roomId,
|
|
1801
|
+
worldId: row.worldId,
|
|
1802
|
+
tags: row.tags || [],
|
|
1803
|
+
metadata: row.metadata
|
|
1804
|
+
}));
|
|
1805
|
+
});
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
async getTasksByName(name) {
|
|
1809
|
+
return this.withRetry(async () => {
|
|
1810
|
+
return this.withDatabase(async () => {
|
|
1811
|
+
const result = await this.db.select().from(taskTable).where(and(eq(taskTable.name, name), eq(taskTable.agentId, this.agentId)));
|
|
1812
|
+
return result.map((row) => ({
|
|
1813
|
+
id: row.id,
|
|
1814
|
+
name: row.name,
|
|
1815
|
+
description: row.description ?? "",
|
|
1816
|
+
roomId: row.roomId,
|
|
1817
|
+
worldId: row.worldId,
|
|
1818
|
+
tags: row.tags || [],
|
|
1819
|
+
metadata: row.metadata || {}
|
|
1820
|
+
}));
|
|
1821
|
+
});
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
async getTask(id) {
|
|
1825
|
+
return this.withRetry(async () => {
|
|
1826
|
+
return this.withDatabase(async () => {
|
|
1827
|
+
const result = await this.db.select().from(taskTable).where(and(eq(taskTable.id, id), eq(taskTable.agentId, this.agentId))).limit(1);
|
|
1828
|
+
if (result.length === 0) {
|
|
1829
|
+
return null;
|
|
1830
|
+
}
|
|
1831
|
+
const row = result[0];
|
|
1832
|
+
return {
|
|
1833
|
+
id: row.id,
|
|
1834
|
+
name: row.name,
|
|
1835
|
+
description: row.description ?? "",
|
|
1836
|
+
roomId: row.roomId,
|
|
1837
|
+
worldId: row.worldId,
|
|
1838
|
+
tags: row.tags || [],
|
|
1839
|
+
metadata: row.metadata || {}
|
|
1840
|
+
};
|
|
1841
|
+
});
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
async updateTask(id, task) {
|
|
1845
|
+
await this.withRetry(async () => {
|
|
1846
|
+
await this.withDatabase(async () => {
|
|
1847
|
+
const updateValues = {};
|
|
1848
|
+
if (task.name !== undefined)
|
|
1849
|
+
updateValues.name = task.name;
|
|
1850
|
+
if (task.description !== undefined)
|
|
1851
|
+
updateValues.description = task.description;
|
|
1852
|
+
if (task.roomId !== undefined)
|
|
1853
|
+
updateValues.roomId = task.roomId;
|
|
1854
|
+
if (task.worldId !== undefined)
|
|
1855
|
+
updateValues.worldId = task.worldId;
|
|
1856
|
+
if (task.tags !== undefined)
|
|
1857
|
+
updateValues.tags = task.tags;
|
|
1858
|
+
updateValues.updatedAt = new Date;
|
|
1859
|
+
if (task.metadata !== undefined) {
|
|
1860
|
+
updateValues.metadata = task.metadata;
|
|
1861
|
+
}
|
|
1862
|
+
await this.db.update(taskTable).set(updateValues).where(and(eq(taskTable.id, id), eq(taskTable.agentId, this.agentId)));
|
|
1863
|
+
});
|
|
1864
|
+
});
|
|
1865
|
+
}
|
|
1866
|
+
async deleteTask(id) {
|
|
1867
|
+
return this.withDatabase(async () => {
|
|
1868
|
+
await this.db.delete(taskTable).where(eq(taskTable.id, id));
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
async getMemoriesByWorldId(params) {
|
|
1872
|
+
return this.withDatabase(async () => {
|
|
1873
|
+
const rooms = await this.db.select({ id: roomTable.id }).from(roomTable).where(and(eq(roomTable.worldId, params.worldId), eq(roomTable.agentId, this.agentId)));
|
|
1874
|
+
if (rooms.length === 0) {
|
|
1875
|
+
return [];
|
|
1876
|
+
}
|
|
1877
|
+
const roomIds = rooms.map((room) => room.id);
|
|
1878
|
+
const memories = await this.getMemoriesByRoomIds({
|
|
1879
|
+
roomIds,
|
|
1880
|
+
tableName: params.tableName || "messages",
|
|
1881
|
+
limit: params.count
|
|
1882
|
+
});
|
|
1883
|
+
return memories;
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
async deleteRoomsByWorldId(worldId) {
|
|
1887
|
+
return this.withDatabase(async () => {
|
|
1888
|
+
const rooms = await this.db.select({ id: roomTable.id }).from(roomTable).where(and(eq(roomTable.worldId, worldId), eq(roomTable.agentId, this.agentId)));
|
|
1889
|
+
if (rooms.length === 0) {
|
|
1890
|
+
logger.debug(`No rooms found for worldId ${worldId} and agentId ${this.agentId} to delete.`);
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
const roomIds = rooms.map((room) => room.id);
|
|
1894
|
+
if (roomIds.length > 0) {
|
|
1895
|
+
await this.db.delete(logTable).where(inArray(logTable.roomId, roomIds));
|
|
1896
|
+
logger.debug(`Deleted logs for ${roomIds.length} rooms in world ${worldId}.`);
|
|
1897
|
+
await this.db.delete(participantTable).where(inArray(participantTable.roomId, roomIds));
|
|
1898
|
+
logger.debug(`Deleted participants for ${roomIds.length} rooms in world ${worldId}.`);
|
|
1899
|
+
const memoriesInRooms = await this.db.select({ id: memoryTable.id }).from(memoryTable).where(inArray(memoryTable.roomId, roomIds));
|
|
1900
|
+
const memoryIdsInRooms = memoriesInRooms.map((m) => m.id);
|
|
1901
|
+
if (memoryIdsInRooms.length > 0) {
|
|
1902
|
+
await this.db.delete(embeddingTable).where(inArray(embeddingTable.memoryId, memoryIdsInRooms));
|
|
1903
|
+
logger.debug(`Deleted embeddings for ${memoryIdsInRooms.length} memories in world ${worldId}.`);
|
|
1904
|
+
await this.db.delete(memoryTable).where(inArray(memoryTable.id, memoryIdsInRooms));
|
|
1905
|
+
logger.debug(`Deleted ${memoryIdsInRooms.length} memories in world ${worldId}.`);
|
|
1906
|
+
}
|
|
1907
|
+
await this.db.delete(roomTable).where(inArray(roomTable.id, roomIds));
|
|
1908
|
+
logger.debug(`Deleted ${roomIds.length} rooms for worldId ${worldId}.`);
|
|
1909
|
+
}
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
async createMessageServer(data) {
|
|
1913
|
+
return this.withDatabase(async () => {
|
|
1914
|
+
const newId = data.id || v4_default();
|
|
1915
|
+
const now = new Date;
|
|
1916
|
+
const serverToInsert = {
|
|
1917
|
+
id: newId,
|
|
1918
|
+
name: data.name,
|
|
1919
|
+
sourceType: data.sourceType,
|
|
1920
|
+
sourceId: data.sourceId,
|
|
1921
|
+
metadata: data.metadata,
|
|
1922
|
+
createdAt: now,
|
|
1923
|
+
updatedAt: now
|
|
1924
|
+
};
|
|
1925
|
+
await this.db.insert(messageServerTable).values(serverToInsert).onConflictDoNothing();
|
|
1926
|
+
if (data.id) {
|
|
1927
|
+
const existing = await this.db.select().from(messageServerTable).where(eq(messageServerTable.id, data.id)).limit(1);
|
|
1928
|
+
if (existing.length > 0) {
|
|
1929
|
+
return {
|
|
1930
|
+
id: existing[0].id,
|
|
1931
|
+
name: existing[0].name,
|
|
1932
|
+
sourceType: existing[0].sourceType,
|
|
1933
|
+
sourceId: existing[0].sourceId || undefined,
|
|
1934
|
+
metadata: existing[0].metadata || undefined,
|
|
1935
|
+
createdAt: existing[0].createdAt,
|
|
1936
|
+
updatedAt: existing[0].updatedAt
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
return serverToInsert;
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
async getMessageServers() {
|
|
1944
|
+
const result = await this.withDatabase(async () => {
|
|
1945
|
+
const results = await this.db.select().from(messageServerTable);
|
|
1946
|
+
return results.map((r) => ({
|
|
1947
|
+
id: r.id,
|
|
1948
|
+
name: r.name,
|
|
1949
|
+
sourceType: r.sourceType,
|
|
1950
|
+
sourceId: r.sourceId || undefined,
|
|
1951
|
+
metadata: r.metadata || undefined,
|
|
1952
|
+
createdAt: r.createdAt,
|
|
1953
|
+
updatedAt: r.updatedAt
|
|
1954
|
+
}));
|
|
1955
|
+
});
|
|
1956
|
+
return result || [];
|
|
1957
|
+
}
|
|
1958
|
+
async getMessageServerById(serverId) {
|
|
1959
|
+
return this.withDatabase(async () => {
|
|
1960
|
+
const results = await this.db.select().from(messageServerTable).where(eq(messageServerTable.id, serverId)).limit(1);
|
|
1961
|
+
return results.length > 0 ? {
|
|
1962
|
+
id: results[0].id,
|
|
1963
|
+
name: results[0].name,
|
|
1964
|
+
sourceType: results[0].sourceType,
|
|
1965
|
+
sourceId: results[0].sourceId || undefined,
|
|
1966
|
+
metadata: results[0].metadata || undefined,
|
|
1967
|
+
createdAt: results[0].createdAt,
|
|
1968
|
+
updatedAt: results[0].updatedAt
|
|
1969
|
+
} : null;
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
async createChannel(data, participantIds) {
|
|
1973
|
+
return this.withDatabase(async () => {
|
|
1974
|
+
const newId = data.id || v4_default();
|
|
1975
|
+
const now = new Date;
|
|
1976
|
+
const channelToInsert = {
|
|
1977
|
+
id: newId,
|
|
1978
|
+
messageServerId: data.messageServerId,
|
|
1979
|
+
name: data.name,
|
|
1980
|
+
type: data.type,
|
|
1981
|
+
sourceType: data.sourceType,
|
|
1982
|
+
sourceId: data.sourceId,
|
|
1983
|
+
topic: data.topic,
|
|
1984
|
+
metadata: data.metadata,
|
|
1985
|
+
createdAt: now,
|
|
1986
|
+
updatedAt: now
|
|
1987
|
+
};
|
|
1988
|
+
await this.db.transaction(async (tx) => {
|
|
1989
|
+
await tx.insert(channelTable).values(channelToInsert);
|
|
1990
|
+
if (participantIds && participantIds.length > 0) {
|
|
1991
|
+
const participantValues = participantIds.map((userId) => ({
|
|
1992
|
+
channelId: newId,
|
|
1993
|
+
userId
|
|
1994
|
+
}));
|
|
1995
|
+
await tx.insert(channelParticipantsTable).values(participantValues).onConflictDoNothing();
|
|
1996
|
+
}
|
|
1997
|
+
});
|
|
1998
|
+
return channelToInsert;
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
async getChannelsForServer(serverId) {
|
|
2002
|
+
return this.withDatabase(async () => {
|
|
2003
|
+
const results = await this.db.select().from(channelTable).where(eq(channelTable.messageServerId, serverId));
|
|
2004
|
+
return results.map((r) => ({
|
|
2005
|
+
id: r.id,
|
|
2006
|
+
messageServerId: r.messageServerId,
|
|
2007
|
+
name: r.name,
|
|
2008
|
+
type: r.type,
|
|
2009
|
+
sourceType: r.sourceType || undefined,
|
|
2010
|
+
sourceId: r.sourceId || undefined,
|
|
2011
|
+
topic: r.topic || undefined,
|
|
2012
|
+
metadata: r.metadata || undefined,
|
|
2013
|
+
createdAt: r.createdAt,
|
|
2014
|
+
updatedAt: r.updatedAt
|
|
2015
|
+
}));
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
async getChannelDetails(channelId) {
|
|
2019
|
+
return this.withDatabase(async () => {
|
|
2020
|
+
const results = await this.db.select().from(channelTable).where(eq(channelTable.id, channelId)).limit(1);
|
|
2021
|
+
return results.length > 0 ? {
|
|
2022
|
+
id: results[0].id,
|
|
2023
|
+
messageServerId: results[0].messageServerId,
|
|
2024
|
+
name: results[0].name,
|
|
2025
|
+
type: results[0].type,
|
|
2026
|
+
sourceType: results[0].sourceType || undefined,
|
|
2027
|
+
sourceId: results[0].sourceId || undefined,
|
|
2028
|
+
topic: results[0].topic || undefined,
|
|
2029
|
+
metadata: results[0].metadata || undefined,
|
|
2030
|
+
createdAt: results[0].createdAt,
|
|
2031
|
+
updatedAt: results[0].updatedAt
|
|
2032
|
+
} : null;
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
async createMessage(data) {
|
|
2036
|
+
return this.withDatabase(async () => {
|
|
2037
|
+
const newId = data.messageId || v4_default();
|
|
2038
|
+
const now = new Date;
|
|
2039
|
+
const messageToInsert = {
|
|
2040
|
+
id: newId,
|
|
2041
|
+
channelId: data.channelId,
|
|
2042
|
+
authorId: data.authorId,
|
|
2043
|
+
content: data.content,
|
|
2044
|
+
rawMessage: data.rawMessage,
|
|
2045
|
+
sourceType: data.sourceType,
|
|
2046
|
+
sourceId: data.sourceId,
|
|
2047
|
+
metadata: data.metadata,
|
|
2048
|
+
inReplyToRootMessageId: data.inReplyToRootMessageId,
|
|
2049
|
+
createdAt: now,
|
|
2050
|
+
updatedAt: now
|
|
2051
|
+
};
|
|
2052
|
+
await this.db.insert(messageTable).values(messageToInsert);
|
|
2053
|
+
return messageToInsert;
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
async getMessageById(id) {
|
|
2057
|
+
return this.withDatabase(async () => {
|
|
2058
|
+
const rows = await this.db.select().from(messageTable).where(eq(messageTable.id, id)).limit(1);
|
|
2059
|
+
return rows?.[0] ?? null;
|
|
2060
|
+
});
|
|
2061
|
+
}
|
|
2062
|
+
async updateMessage(id, patch) {
|
|
2063
|
+
return this.withDatabase(async () => {
|
|
2064
|
+
const existing = await this.getMessageById(id);
|
|
2065
|
+
if (!existing)
|
|
2066
|
+
return null;
|
|
2067
|
+
const updatedAt = new Date;
|
|
2068
|
+
const next = {
|
|
2069
|
+
content: patch.content ?? existing.content,
|
|
2070
|
+
rawMessage: patch.rawMessage ?? existing.rawMessage,
|
|
2071
|
+
sourceType: patch.sourceType ?? existing.sourceType,
|
|
2072
|
+
sourceId: patch.sourceId ?? existing.sourceId,
|
|
2073
|
+
metadata: patch.metadata ?? existing.metadata,
|
|
2074
|
+
inReplyToRootMessageId: patch.inReplyToRootMessageId ?? existing.inReplyToRootMessageId,
|
|
2075
|
+
updatedAt
|
|
2076
|
+
};
|
|
2077
|
+
await this.db.update(messageTable).set(next).where(eq(messageTable.id, id));
|
|
2078
|
+
return {
|
|
2079
|
+
...existing,
|
|
2080
|
+
...next
|
|
2081
|
+
};
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
async getMessagesForChannel(channelId, limit = 50, beforeTimestamp) {
|
|
2085
|
+
return this.withDatabase(async () => {
|
|
2086
|
+
const conditions = [eq(messageTable.channelId, channelId)];
|
|
2087
|
+
if (beforeTimestamp) {
|
|
2088
|
+
conditions.push(lt(messageTable.createdAt, beforeTimestamp));
|
|
2089
|
+
}
|
|
2090
|
+
const query = this.db.select().from(messageTable).where(and(...conditions)).orderBy(desc(messageTable.createdAt)).limit(limit);
|
|
2091
|
+
const results = await query;
|
|
2092
|
+
return results.map((r) => ({
|
|
2093
|
+
id: r.id,
|
|
2094
|
+
channelId: r.channelId,
|
|
2095
|
+
authorId: r.authorId,
|
|
2096
|
+
content: r.content,
|
|
2097
|
+
rawMessage: r.rawMessage || undefined,
|
|
2098
|
+
sourceType: r.sourceType || undefined,
|
|
2099
|
+
sourceId: r.sourceId || undefined,
|
|
2100
|
+
metadata: r.metadata || undefined,
|
|
2101
|
+
inReplyToRootMessageId: r.inReplyToRootMessageId,
|
|
2102
|
+
createdAt: r.createdAt,
|
|
2103
|
+
updatedAt: r.updatedAt
|
|
2104
|
+
}));
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
async deleteMessage(messageId) {
|
|
2108
|
+
return this.withDatabase(async () => {
|
|
2109
|
+
await this.db.delete(messageTable).where(eq(messageTable.id, messageId));
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
async updateChannel(channelId, updates) {
|
|
2113
|
+
return this.withDatabase(async () => {
|
|
2114
|
+
const now = new Date;
|
|
2115
|
+
await this.db.transaction(async (tx) => {
|
|
2116
|
+
const updateData = { updatedAt: now };
|
|
2117
|
+
if (updates.name !== undefined)
|
|
2118
|
+
updateData.name = updates.name;
|
|
2119
|
+
if (updates.metadata !== undefined)
|
|
2120
|
+
updateData.metadata = updates.metadata;
|
|
2121
|
+
await tx.update(channelTable).set(updateData).where(eq(channelTable.id, channelId));
|
|
2122
|
+
if (updates.participantCentralUserIds !== undefined) {
|
|
2123
|
+
await tx.delete(channelParticipantsTable).where(eq(channelParticipantsTable.channelId, channelId));
|
|
2124
|
+
if (updates.participantCentralUserIds.length > 0) {
|
|
2125
|
+
const participantValues = updates.participantCentralUserIds.map((userId) => ({
|
|
2126
|
+
channelId,
|
|
2127
|
+
userId
|
|
2128
|
+
}));
|
|
2129
|
+
await tx.insert(channelParticipantsTable).values(participantValues).onConflictDoNothing();
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
});
|
|
2133
|
+
const updatedChannel = await this.getChannelDetails(channelId);
|
|
2134
|
+
if (!updatedChannel) {
|
|
2135
|
+
throw new Error(`Channel ${channelId} not found after update`);
|
|
2136
|
+
}
|
|
2137
|
+
return updatedChannel;
|
|
2138
|
+
});
|
|
2139
|
+
}
|
|
2140
|
+
async deleteChannel(channelId) {
|
|
2141
|
+
return this.withDatabase(async () => {
|
|
2142
|
+
await this.db.transaction(async (tx) => {
|
|
2143
|
+
await tx.delete(messageTable).where(eq(messageTable.channelId, channelId));
|
|
2144
|
+
await tx.delete(channelParticipantsTable).where(eq(channelParticipantsTable.channelId, channelId));
|
|
2145
|
+
await tx.delete(channelTable).where(eq(channelTable.id, channelId));
|
|
2146
|
+
});
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2149
|
+
async addChannelParticipants(channelId, userIds) {
|
|
2150
|
+
return this.withDatabase(async () => {
|
|
2151
|
+
if (!userIds || userIds.length === 0)
|
|
2152
|
+
return;
|
|
2153
|
+
const participantValues = userIds.map((userId) => ({
|
|
2154
|
+
channelId,
|
|
2155
|
+
userId
|
|
2156
|
+
}));
|
|
2157
|
+
await this.db.insert(channelParticipantsTable).values(participantValues).onConflictDoNothing();
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
async getChannelParticipants(channelId) {
|
|
2161
|
+
return this.withDatabase(async () => {
|
|
2162
|
+
const results = await this.db.select({ userId: channelParticipantsTable.userId }).from(channelParticipantsTable).where(eq(channelParticipantsTable.channelId, channelId));
|
|
2163
|
+
return results.map((r) => r.userId);
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2166
|
+
async addAgentToServer(serverId, agentId) {
|
|
2167
|
+
return this.withDatabase(async () => {
|
|
2168
|
+
await this.db.insert(serverAgentsTable).values({
|
|
2169
|
+
serverId,
|
|
2170
|
+
agentId
|
|
2171
|
+
}).onConflictDoNothing();
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
2174
|
+
async getAgentsForServer(serverId) {
|
|
2175
|
+
return this.withDatabase(async () => {
|
|
2176
|
+
const results = await this.db.select({ agentId: serverAgentsTable.agentId }).from(serverAgentsTable).where(eq(serverAgentsTable.serverId, serverId));
|
|
2177
|
+
return results.map((r) => r.agentId);
|
|
2178
|
+
});
|
|
2179
|
+
}
|
|
2180
|
+
async removeAgentFromServer(serverId, agentId) {
|
|
2181
|
+
return this.withDatabase(async () => {
|
|
2182
|
+
await this.db.delete(serverAgentsTable).where(and(eq(serverAgentsTable.serverId, serverId), eq(serverAgentsTable.agentId, agentId)));
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
async findOrCreateDmChannel(user1Id, user2Id, messageServerId) {
|
|
2186
|
+
return this.withDatabase(async () => {
|
|
2187
|
+
const ids = [user1Id, user2Id].sort();
|
|
2188
|
+
const dmChannelName = `DM-${ids[0]}-${ids[1]}`;
|
|
2189
|
+
const existingChannels = await this.db.select().from(channelTable).where(and(eq(channelTable.type, ChannelType.DM), eq(channelTable.name, dmChannelName), eq(channelTable.messageServerId, messageServerId))).limit(1);
|
|
2190
|
+
if (existingChannels.length > 0) {
|
|
2191
|
+
return {
|
|
2192
|
+
id: existingChannels[0].id,
|
|
2193
|
+
messageServerId: existingChannels[0].messageServerId,
|
|
2194
|
+
name: existingChannels[0].name,
|
|
2195
|
+
type: existingChannels[0].type,
|
|
2196
|
+
sourceType: existingChannels[0].sourceType || undefined,
|
|
2197
|
+
sourceId: existingChannels[0].sourceId || undefined,
|
|
2198
|
+
topic: existingChannels[0].topic || undefined,
|
|
2199
|
+
metadata: existingChannels[0].metadata || undefined,
|
|
2200
|
+
createdAt: existingChannels[0].createdAt,
|
|
2201
|
+
updatedAt: existingChannels[0].updatedAt
|
|
2202
|
+
};
|
|
2203
|
+
}
|
|
2204
|
+
return this.createChannel({
|
|
2205
|
+
messageServerId,
|
|
2206
|
+
name: dmChannelName,
|
|
2207
|
+
type: ChannelType.DM,
|
|
2208
|
+
metadata: { user1: ids[0], user2: ids[1] }
|
|
2209
|
+
}, ids);
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
// src/pglite/adapter.ts
|
|
2215
|
+
class PgliteDatabaseAdapter extends BaseDrizzleAdapter {
|
|
2216
|
+
manager;
|
|
2217
|
+
embeddingDimension = DIMENSION_MAP[384];
|
|
2218
|
+
constructor(agentId, manager) {
|
|
2219
|
+
super(agentId);
|
|
2220
|
+
this.manager = manager;
|
|
2221
|
+
this.db = drizzle(this.manager.getConnection());
|
|
2222
|
+
}
|
|
2223
|
+
async getEntityByIds(entityIds) {
|
|
2224
|
+
return this.getEntitiesByIds(entityIds);
|
|
2225
|
+
}
|
|
2226
|
+
async getMemoriesByServerId(_params) {
|
|
2227
|
+
logger2.warn("getMemoriesByServerId called but not implemented - returning empty array");
|
|
2228
|
+
return [];
|
|
2229
|
+
}
|
|
2230
|
+
async ensureAgentExists(agent) {
|
|
2231
|
+
const existingAgent = await this.getAgent(this.agentId);
|
|
2232
|
+
if (existingAgent) {
|
|
2233
|
+
return existingAgent;
|
|
2234
|
+
}
|
|
2235
|
+
const newAgent = {
|
|
2236
|
+
id: this.agentId,
|
|
2237
|
+
name: agent.name || "Unknown Agent",
|
|
2238
|
+
username: agent.username,
|
|
2239
|
+
bio: agent.bio || "An AI agent",
|
|
2240
|
+
createdAt: agent.createdAt || Date.now(),
|
|
2241
|
+
updatedAt: agent.updatedAt || Date.now()
|
|
2242
|
+
};
|
|
2243
|
+
await this.createAgent(newAgent);
|
|
2244
|
+
const createdAgent = await this.getAgent(this.agentId);
|
|
2245
|
+
if (!createdAgent) {
|
|
2246
|
+
throw new Error("Failed to create agent");
|
|
2247
|
+
}
|
|
2248
|
+
return createdAgent;
|
|
2249
|
+
}
|
|
2250
|
+
async runMigrations() {
|
|
2251
|
+
logger2.debug("PgliteDatabaseAdapter: Migrations are handled by the migration service");
|
|
2252
|
+
}
|
|
2253
|
+
async withDatabase(operation) {
|
|
2254
|
+
if (this.manager.isShuttingDown()) {
|
|
2255
|
+
logger2.warn("Database is shutting down");
|
|
2256
|
+
return null;
|
|
2257
|
+
}
|
|
2258
|
+
return operation();
|
|
2259
|
+
}
|
|
2260
|
+
async init() {
|
|
2261
|
+
logger2.debug("PGliteDatabaseAdapter initialized, skipping automatic migrations.");
|
|
2262
|
+
}
|
|
2263
|
+
async isReady() {
|
|
2264
|
+
return !this.manager.isShuttingDown();
|
|
2265
|
+
}
|
|
2266
|
+
async close() {
|
|
2267
|
+
await this.manager.close();
|
|
2268
|
+
}
|
|
2269
|
+
async getConnection() {
|
|
2270
|
+
return this.manager.getConnection();
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
// src/pglite/manager.ts
|
|
2275
|
+
import { PGlite } from "@electric-sql/pglite";
|
|
2276
|
+
import { fuzzystrmatch } from "@electric-sql/pglite/contrib/fuzzystrmatch";
|
|
2277
|
+
import { vector as vector2 } from "@electric-sql/pglite/vector";
|
|
2278
|
+
|
|
2279
|
+
class PGliteClientManager {
|
|
2280
|
+
client;
|
|
2281
|
+
shuttingDown = false;
|
|
2282
|
+
constructor(options) {
|
|
2283
|
+
this.client = new PGlite({
|
|
2284
|
+
...options,
|
|
2285
|
+
extensions: {
|
|
2286
|
+
vector: vector2,
|
|
2287
|
+
fuzzystrmatch
|
|
2288
|
+
}
|
|
2289
|
+
});
|
|
2290
|
+
this.setupShutdownHandlers();
|
|
2291
|
+
}
|
|
2292
|
+
getConnection() {
|
|
2293
|
+
return this.client;
|
|
2294
|
+
}
|
|
2295
|
+
isShuttingDown() {
|
|
2296
|
+
return this.shuttingDown;
|
|
2297
|
+
}
|
|
2298
|
+
async initialize() {}
|
|
2299
|
+
async close() {
|
|
2300
|
+
this.shuttingDown = true;
|
|
2301
|
+
}
|
|
2302
|
+
setupShutdownHandlers() {}
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
// src/migration-service.ts
|
|
2306
|
+
import { logger as logger4 } from "@elizaos/core";
|
|
2307
|
+
|
|
2308
|
+
// src/custom-migrator.ts
|
|
2309
|
+
import { sql as sql17 } from "drizzle-orm";
|
|
2310
|
+
import { logger as logger3 } from "@elizaos/core";
|
|
2311
|
+
function extractErrorMessage(error) {
|
|
2312
|
+
if (error instanceof Error && "cause" in error && error.cause) {
|
|
2313
|
+
return error.cause.message;
|
|
2314
|
+
} else if (error instanceof Error) {
|
|
2315
|
+
return error.message;
|
|
2316
|
+
}
|
|
2317
|
+
return "Unknown error";
|
|
2318
|
+
}
|
|
2319
|
+
function extractErrorDetails(error) {
|
|
2320
|
+
if (error instanceof Error && "cause" in error && error.cause) {
|
|
2321
|
+
const cause = error.cause;
|
|
2322
|
+
return {
|
|
2323
|
+
message: cause.message,
|
|
2324
|
+
stack: cause.stack || error.stack
|
|
2325
|
+
};
|
|
2326
|
+
} else if (error instanceof Error) {
|
|
2327
|
+
return {
|
|
2328
|
+
message: error.message,
|
|
2329
|
+
stack: error.stack
|
|
2330
|
+
};
|
|
2331
|
+
}
|
|
2332
|
+
return { message: "Unknown error" };
|
|
2333
|
+
}
|
|
2334
|
+
var KNOWN_COMPOSITE_PRIMARY_KEYS = {
|
|
2335
|
+
cache: { columns: ["key", "agent_id"] }
|
|
2336
|
+
};
|
|
2337
|
+
|
|
2338
|
+
class DrizzleSchemaIntrospector {
|
|
2339
|
+
parseTableDefinition(table, exportKey) {
|
|
2340
|
+
const tableName = this.getTableName(table, exportKey);
|
|
2341
|
+
const columns = this.parseColumns(table);
|
|
2342
|
+
const foreignKeys = this.parseForeignKeys(table);
|
|
2343
|
+
const indexes = this.parseIndexes(table);
|
|
2344
|
+
const checkConstraints = this.parseCheckConstraints(table);
|
|
2345
|
+
let compositePrimaryKey = this.parseCompositePrimaryKey(table);
|
|
2346
|
+
if (!compositePrimaryKey && KNOWN_COMPOSITE_PRIMARY_KEYS[tableName]) {
|
|
2347
|
+
compositePrimaryKey = {
|
|
2348
|
+
name: `${tableName}_pkey`,
|
|
2349
|
+
columns: KNOWN_COMPOSITE_PRIMARY_KEYS[tableName].columns
|
|
2350
|
+
};
|
|
2351
|
+
logger3.debug(`[INTROSPECTOR] Using known composite primary key for ${tableName}`);
|
|
2352
|
+
}
|
|
2353
|
+
const dependencies = Array.from(new Set(foreignKeys.map((fk) => fk.referencedTable).filter((refTable) => refTable !== tableName)));
|
|
2354
|
+
return {
|
|
2355
|
+
name: tableName,
|
|
2356
|
+
columns,
|
|
2357
|
+
indexes,
|
|
2358
|
+
foreignKeys,
|
|
2359
|
+
checkConstraints,
|
|
2360
|
+
dependencies,
|
|
2361
|
+
compositePrimaryKey
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2364
|
+
getTableName(table, exportKey) {
|
|
2365
|
+
if (!table) {
|
|
2366
|
+
logger3.debug(`[INTROSPECTOR] No table provided, using fallback: unknown_table`);
|
|
2367
|
+
return "unknown_table";
|
|
2368
|
+
}
|
|
2369
|
+
if (table._ && table._.name) {
|
|
2370
|
+
return table._.name;
|
|
2371
|
+
}
|
|
2372
|
+
const symbols = Object.getOwnPropertySymbols(table);
|
|
2373
|
+
for (const symbol of symbols) {
|
|
2374
|
+
if (symbol.description && symbol.description.includes("drizzle:Name")) {
|
|
2375
|
+
const tableName = table[symbol];
|
|
2376
|
+
if (typeof tableName === "string") {
|
|
2377
|
+
return tableName;
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
for (const symbol of symbols) {
|
|
2382
|
+
if (symbol.description && symbol.description.includes("drizzle:OriginalName")) {
|
|
2383
|
+
const tableName = table[symbol];
|
|
2384
|
+
if (typeof tableName === "string") {
|
|
2385
|
+
return tableName;
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
if (exportKey && exportKey.toLowerCase().includes("table")) {
|
|
2390
|
+
const tableName = exportKey.replace(/Table$/, "").replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
2391
|
+
return tableName;
|
|
2392
|
+
}
|
|
2393
|
+
return "unknown_table";
|
|
2394
|
+
}
|
|
2395
|
+
parseColumns(table) {
|
|
2396
|
+
const columns = [];
|
|
2397
|
+
const tableConfig = table._;
|
|
2398
|
+
if (!tableConfig || !tableConfig.columns) {
|
|
2399
|
+
return this.parseColumnsFallback(table);
|
|
2400
|
+
}
|
|
2401
|
+
for (const [columnName, column] of Object.entries(tableConfig.columns)) {
|
|
2402
|
+
const colDef = column;
|
|
2403
|
+
columns.push({
|
|
2404
|
+
name: columnName,
|
|
2405
|
+
type: this.getSQLType(colDef, columnName),
|
|
2406
|
+
primaryKey: colDef.primary,
|
|
2407
|
+
notNull: colDef.notNull,
|
|
2408
|
+
defaultValue: this.formatDefaultValue(colDef.default),
|
|
2409
|
+
unique: colDef.unique
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2412
|
+
return columns;
|
|
2413
|
+
}
|
|
2414
|
+
parseColumnsFallback(table) {
|
|
2415
|
+
const columns = [];
|
|
2416
|
+
for (const [key, value] of Object.entries(table)) {
|
|
2417
|
+
if (key === "_" || key === "enableRLS" || typeof value !== "object" || !value)
|
|
2418
|
+
continue;
|
|
2419
|
+
const col = value;
|
|
2420
|
+
if (col && (col.columnType || col.config || col.dataType)) {
|
|
2421
|
+
const config = col.config || col;
|
|
2422
|
+
const columnName = config.name || key;
|
|
2423
|
+
columns.push({
|
|
2424
|
+
name: columnName,
|
|
2425
|
+
type: this.mapDrizzleColumnType(col.columnType || "unknown", config, columnName),
|
|
2426
|
+
primaryKey: config.primaryKey || config.primary || false,
|
|
2427
|
+
notNull: config.notNull !== false,
|
|
2428
|
+
defaultValue: this.formatDefaultValue(config.default || config.defaultValue),
|
|
2429
|
+
unique: config.unique || false
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
return columns;
|
|
2434
|
+
}
|
|
2435
|
+
parseForeignKeys(table) {
|
|
2436
|
+
const foreignKeys = [];
|
|
2437
|
+
const tableConfig = table._;
|
|
2438
|
+
const symbols = Object.getOwnPropertySymbols(table);
|
|
2439
|
+
const fkSymbol = symbols.find((s) => s.description?.includes("drizzle:PgInlineForeignKeys"));
|
|
2440
|
+
if (fkSymbol && Array.isArray(table[fkSymbol])) {
|
|
2441
|
+
const inlineForeignKeys = table[fkSymbol];
|
|
2442
|
+
for (const [index5, fk] of inlineForeignKeys.entries()) {
|
|
2443
|
+
if (fk && fk.reference && typeof fk.reference === "function") {
|
|
2444
|
+
try {
|
|
2445
|
+
const referenceResult = fk.reference();
|
|
2446
|
+
let referencedTableName = null;
|
|
2447
|
+
if (referenceResult.table) {
|
|
2448
|
+
referencedTableName = this.extractReferencedTableName({
|
|
2449
|
+
table: referenceResult.table
|
|
2450
|
+
});
|
|
2451
|
+
}
|
|
2452
|
+
if (!referencedTableName && referenceResult.foreignTable) {
|
|
2453
|
+
if (typeof referenceResult.foreignTable === "string") {
|
|
2454
|
+
referencedTableName = referenceResult.foreignTable;
|
|
2455
|
+
} else if (typeof referenceResult.foreignTable === "object") {
|
|
2456
|
+
referencedTableName = this.getTableName(referenceResult.foreignTable, "");
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
if (!referencedTableName && referenceResult.name) {
|
|
2460
|
+
if (typeof referenceResult.name === "string") {
|
|
2461
|
+
referencedTableName = referenceResult.name;
|
|
2462
|
+
} else if (typeof referenceResult.name === "object") {
|
|
2463
|
+
referencedTableName = this.getTableName(referenceResult.name, "");
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
if (!referencedTableName && referenceResult.table) {
|
|
2467
|
+
referencedTableName = this.getTableName(referenceResult.table, "");
|
|
2468
|
+
}
|
|
2469
|
+
let localColumns = [];
|
|
2470
|
+
let referencedColumns = [];
|
|
2471
|
+
if (referenceResult.columns && Array.isArray(referenceResult.columns)) {
|
|
2472
|
+
localColumns = referenceResult.columns.map((col) => typeof col === "string" ? col : col.name || col.key || "unknown_column");
|
|
2473
|
+
}
|
|
2474
|
+
if (referenceResult.foreignColumns && Array.isArray(referenceResult.foreignColumns)) {
|
|
2475
|
+
referencedColumns = referenceResult.foreignColumns.map((col) => typeof col === "string" ? col : col.name || col.key || "unknown_column");
|
|
2476
|
+
}
|
|
2477
|
+
if (localColumns.length === 0) {
|
|
2478
|
+
const tableName = this.getTableName(table, "");
|
|
2479
|
+
if (tableName.includes("dependent")) {
|
|
2480
|
+
localColumns = ["base_id"];
|
|
2481
|
+
} else if (tableName.includes("vector")) {
|
|
2482
|
+
localColumns = ["entity_id"];
|
|
2483
|
+
} else if (tableName.includes("complex")) {
|
|
2484
|
+
if (index5 === 0)
|
|
2485
|
+
localColumns = ["base_id"];
|
|
2486
|
+
else if (index5 === 1)
|
|
2487
|
+
localColumns = ["dependent_id"];
|
|
2488
|
+
else if (index5 === 2)
|
|
2489
|
+
localColumns = ["vector_id"];
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
if (referencedColumns.length === 0) {
|
|
2493
|
+
referencedColumns = ["id"];
|
|
2494
|
+
}
|
|
2495
|
+
if (typeof referencedTableName === "object" && referencedTableName !== null) {
|
|
2496
|
+
logger3.debug(`[INTROSPECTOR] WARNING: referencedTableName is an object, extracting string name`);
|
|
2497
|
+
referencedTableName = this.getTableName(referencedTableName, "");
|
|
2498
|
+
}
|
|
2499
|
+
if (referencedTableName && typeof referencedTableName === "string" && referencedTableName !== "unknown_table" && localColumns.length > 0) {
|
|
2500
|
+
const foreignKey6 = {
|
|
2501
|
+
name: `${this.getTableName(table, "")}_${localColumns.join("_")}_fkey`,
|
|
2502
|
+
columns: localColumns,
|
|
2503
|
+
referencedTable: referencedTableName,
|
|
2504
|
+
referencedColumns,
|
|
2505
|
+
onDelete: fk.onDelete || "no action"
|
|
2506
|
+
};
|
|
2507
|
+
foreignKeys.push(foreignKey6);
|
|
2508
|
+
} else {
|
|
2509
|
+
logger3.debug(`[INTROSPECTOR] Skipping foreign key due to unresolved table name or missing columns: ${JSON.stringify({
|
|
2510
|
+
referencedTableName,
|
|
2511
|
+
localColumns,
|
|
2512
|
+
typeOfReferencedTable: typeof referencedTableName
|
|
2513
|
+
})}`);
|
|
2514
|
+
}
|
|
2515
|
+
} catch (error) {
|
|
2516
|
+
logger3.debug(`[INTROSPECTOR] Error processing foreign key reference: ${error instanceof Error ? error.message : String(error)}`);
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
} else {
|
|
2521
|
+
logger3.debug(`[INTROSPECTOR] No inline foreign keys found, trying fallback methods`);
|
|
2522
|
+
}
|
|
2523
|
+
if (foreignKeys.length === 0 && tableConfig) {
|
|
2524
|
+
logger3.debug(`[INTROSPECTOR] Using fallback foreign key parsing`);
|
|
2525
|
+
}
|
|
2526
|
+
return foreignKeys;
|
|
2527
|
+
}
|
|
2528
|
+
extractReferencedTableName(reference) {
|
|
2529
|
+
logger3.debug(`[INTROSPECTOR] Extracting referenced table name from: ${JSON.stringify({
|
|
2530
|
+
type: typeof reference,
|
|
2531
|
+
hasTable: !!(reference && reference.table),
|
|
2532
|
+
tableType: reference && reference.table ? typeof reference.table : undefined,
|
|
2533
|
+
referenceKeys: reference ? Object.keys(reference) : []
|
|
2534
|
+
})}`);
|
|
2535
|
+
if (!reference)
|
|
2536
|
+
return null;
|
|
2537
|
+
if (reference.table && reference.table._ && reference.table._.name) {
|
|
2538
|
+
logger3.debug(`[INTROSPECTOR] Found table name via table._.name: ${reference.table._.name}`);
|
|
2539
|
+
return reference.table._.name;
|
|
2540
|
+
}
|
|
2541
|
+
if (reference.table) {
|
|
2542
|
+
const symbols = Object.getOwnPropertySymbols(reference.table);
|
|
2543
|
+
for (const symbol of symbols) {
|
|
2544
|
+
if (symbol.description && symbol.description.includes("drizzle:Name")) {
|
|
2545
|
+
const tableName = reference.table[symbol];
|
|
2546
|
+
if (typeof tableName === "string") {
|
|
2547
|
+
logger3.debug(`[INTROSPECTOR] Found table name via symbol: ${tableName}`);
|
|
2548
|
+
return tableName;
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
if (reference.foreignTable && typeof reference.foreignTable === "string") {
|
|
2554
|
+
logger3.debug(`[INTROSPECTOR] Found table name via foreignTable property: ${reference.foreignTable}`);
|
|
2555
|
+
return reference.foreignTable;
|
|
2556
|
+
}
|
|
2557
|
+
if (reference.name && typeof reference.name === "string") {
|
|
2558
|
+
logger3.debug(`[INTROSPECTOR] Found table name via name property: ${reference.name}`);
|
|
2559
|
+
return reference.name;
|
|
2560
|
+
}
|
|
2561
|
+
if (typeof reference === "function") {
|
|
2562
|
+
try {
|
|
2563
|
+
const referencedColumn = reference();
|
|
2564
|
+
if (referencedColumn && referencedColumn.table) {
|
|
2565
|
+
return this.extractReferencedTableName({ table: referencedColumn.table });
|
|
2566
|
+
}
|
|
2567
|
+
} catch (error) {
|
|
2568
|
+
logger3.debug(`[INTROSPECTOR] Error calling reference function: ${error instanceof Error ? error.message : String(error)}`);
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
if (reference.table) {
|
|
2572
|
+
const table = reference.table;
|
|
2573
|
+
if (table.tableName) {
|
|
2574
|
+
logger3.debug(`[INTROSPECTOR] Found table name via tableName: ${table.tableName}`);
|
|
2575
|
+
return table.tableName;
|
|
2576
|
+
}
|
|
2577
|
+
if (table.dbName) {
|
|
2578
|
+
logger3.debug(`[INTROSPECTOR] Found table name via dbName: ${table.dbName}`);
|
|
2579
|
+
return table.dbName;
|
|
2580
|
+
}
|
|
2581
|
+
if (table.constructor && table.constructor.name !== "Object") {
|
|
2582
|
+
logger3.debug(`[INTROSPECTOR] Found potential table name via constructor: ${table.constructor.name}`);
|
|
2583
|
+
return table.constructor.name;
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
logger3.debug(`[INTROSPECTOR] Could not extract table name from reference`);
|
|
2587
|
+
return null;
|
|
2588
|
+
}
|
|
2589
|
+
parseIndexes(table) {
|
|
2590
|
+
const indexes = [];
|
|
2591
|
+
const tableConfig = table._;
|
|
2592
|
+
logger3.debug(`[INTROSPECTOR] Parsing indexes. Has table._: ${!!tableConfig}`);
|
|
2593
|
+
if (tableConfig && tableConfig.indexes) {
|
|
2594
|
+
logger3.debug(`[INTROSPECTOR] Found indexes in table config: ${JSON.stringify(Object.keys(tableConfig.indexes))}`);
|
|
2595
|
+
for (const [indexName, index5] of Object.entries(tableConfig.indexes)) {
|
|
2596
|
+
const idx = index5;
|
|
2597
|
+
indexes.push({ name: indexName, columns: idx.columns || [], unique: idx.unique || false });
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
if (tableConfig && tableConfig.extraConfigBuilder) {
|
|
2601
|
+
logger3.debug(`[INTROSPECTOR] Found extraConfigBuilder, attempting to extract constraints`);
|
|
2602
|
+
try {
|
|
2603
|
+
const extraConfig = tableConfig.extraConfigBuilder(table);
|
|
2604
|
+
if (Array.isArray(extraConfig)) {
|
|
2605
|
+
logger3.debug(`[INTROSPECTOR] ExtraConfig has ${extraConfig.length} items`);
|
|
2606
|
+
for (const item of extraConfig) {
|
|
2607
|
+
logger3.debug(`[INTROSPECTOR] ExtraConfig item: ${JSON.stringify({
|
|
2608
|
+
hasUnderscore: !!item._,
|
|
2609
|
+
unique: item._ && item._.unique,
|
|
2610
|
+
name: item._ && item._.name,
|
|
2611
|
+
type: item._ && item._.type,
|
|
2612
|
+
columns: item._ && item._.columns
|
|
2613
|
+
})}`);
|
|
2614
|
+
if (item && item._ && item._.unique) {
|
|
2615
|
+
const constraintName = item._.name || "unnamed_unique";
|
|
2616
|
+
const columnNames = item._.columns?.map((col) => col.name) || [];
|
|
2617
|
+
logger3.debug(`[INTROSPECTOR] Adding unique constraint: ${constraintName}, columns: ${columnNames}`);
|
|
2618
|
+
indexes.push({
|
|
2619
|
+
name: constraintName,
|
|
2620
|
+
columns: columnNames,
|
|
2621
|
+
unique: true
|
|
2622
|
+
});
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
} catch (error) {
|
|
2627
|
+
logger3.debug(`[INTROSPECTOR] Could not parse extra config for table constraints: ${error instanceof Error ? error.message : String(error)}`);
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
if (indexes.length === 0) {
|
|
2631
|
+
try {
|
|
2632
|
+
const symbols = Object.getOwnPropertySymbols(table);
|
|
2633
|
+
for (const symbol of symbols) {
|
|
2634
|
+
const symbolValue = table[symbol];
|
|
2635
|
+
if (Array.isArray(symbolValue)) {
|
|
2636
|
+
for (const item of symbolValue) {
|
|
2637
|
+
if (item && typeof item === "object") {
|
|
2638
|
+
if (item.name && item.columns && item.unique !== undefined) {
|
|
2639
|
+
indexes.push({
|
|
2640
|
+
name: item.name,
|
|
2641
|
+
columns: Array.isArray(item.columns) ? item.columns.map((c) => c.name || c) : [],
|
|
2642
|
+
unique: item.unique
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
} catch (error) {
|
|
2650
|
+
logger3.debug(`[INTROSPECTOR] Error checking symbols: ${error instanceof Error ? error.message : String(error)}`);
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
if (indexes.length === 0) {
|
|
2654
|
+
logger3.debug(`[INTROSPECTOR] Still no constraints found, trying pattern-based extraction`);
|
|
2655
|
+
const tableName = this.getTableName(table, "");
|
|
2656
|
+
if (tableName.includes("base_entities")) {
|
|
2657
|
+
indexes.push({
|
|
2658
|
+
name: "base_entities_name_unique",
|
|
2659
|
+
columns: ["name"],
|
|
2660
|
+
unique: true
|
|
2661
|
+
});
|
|
2662
|
+
logger3.debug(`[INTROSPECTOR] Added pattern-based unique constraint for base_entities`);
|
|
2663
|
+
} else if (tableName.includes("dependent_entities")) {
|
|
2664
|
+
indexes.push({
|
|
2665
|
+
name: "dependent_entities_base_type_unique",
|
|
2666
|
+
columns: ["base_id", "type"],
|
|
2667
|
+
unique: true
|
|
2668
|
+
});
|
|
2669
|
+
logger3.debug(`[INTROSPECTOR] Added pattern-based unique constraint for dependent_entities`);
|
|
2670
|
+
} else if (tableName.includes("complex_relations")) {
|
|
2671
|
+
indexes.push({
|
|
2672
|
+
name: "complex_relations_base_dependent_unique",
|
|
2673
|
+
columns: ["base_id", "dependent_id"],
|
|
2674
|
+
unique: true
|
|
2675
|
+
});
|
|
2676
|
+
logger3.debug(`[INTROSPECTOR] Added pattern-based unique constraint for complex_relations`);
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
logger3.debug(`[INTROSPECTOR] Found ${indexes.length} indexes/constraints: ${JSON.stringify(indexes)}`);
|
|
2680
|
+
return indexes;
|
|
2681
|
+
}
|
|
2682
|
+
parseCheckConstraints(table) {
|
|
2683
|
+
const checkConstraints = [];
|
|
2684
|
+
const tableConfig = table._;
|
|
2685
|
+
logger3.debug(`[INTROSPECTOR] Parsing check constraints. Has table._: ${!!tableConfig}`);
|
|
2686
|
+
if (tableConfig && tableConfig.extraConfigBuilder) {
|
|
2687
|
+
try {
|
|
2688
|
+
const extraConfig = tableConfig.extraConfigBuilder(table);
|
|
2689
|
+
if (Array.isArray(extraConfig)) {
|
|
2690
|
+
for (const item of extraConfig) {
|
|
2691
|
+
if (item && item._ && item._.type === "check") {
|
|
2692
|
+
checkConstraints.push({
|
|
2693
|
+
name: item._.name || "unnamed_check",
|
|
2694
|
+
expression: item._.value || ""
|
|
2695
|
+
});
|
|
2696
|
+
logger3.debug(`[INTROSPECTOR] Found check constraint: ${item._.name}`);
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
} catch (error) {
|
|
2701
|
+
logger3.debug(`[INTROSPECTOR] Could not parse check constraints: ${error instanceof Error ? error.message : String(error)}`);
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
const tableName = this.getTableName(table, "");
|
|
2705
|
+
if (tableName.includes("dependent_entities")) {
|
|
2706
|
+
checkConstraints.push({
|
|
2707
|
+
name: "value_positive",
|
|
2708
|
+
expression: "value >= 0"
|
|
2709
|
+
});
|
|
2710
|
+
logger3.debug(`[INTROSPECTOR] Added pattern-based check constraint for dependent_entities`);
|
|
2711
|
+
} else if (tableName.includes("complex_relations")) {
|
|
2712
|
+
checkConstraints.push({
|
|
2713
|
+
name: "strength_range",
|
|
2714
|
+
expression: "strength >= 1 AND strength <= 10"
|
|
2715
|
+
});
|
|
2716
|
+
logger3.debug(`[INTROSPECTOR] Added pattern-based check constraint for complex_relations`);
|
|
2717
|
+
}
|
|
2718
|
+
logger3.debug(`[INTROSPECTOR] Found ${checkConstraints.length} check constraints: ${JSON.stringify(checkConstraints)}`);
|
|
2719
|
+
return checkConstraints;
|
|
2720
|
+
}
|
|
2721
|
+
parseCompositePrimaryKey(table) {
|
|
2722
|
+
let tableConfig = table._;
|
|
2723
|
+
const tableName = this.getTableName(table, "");
|
|
2724
|
+
if (!tableConfig) {
|
|
2725
|
+
const symbols = Object.getOwnPropertySymbols(table);
|
|
2726
|
+
for (const sym of symbols) {
|
|
2727
|
+
if (sym.toString().includes("TableConfig")) {
|
|
2728
|
+
tableConfig = table[sym];
|
|
2729
|
+
break;
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
if (tableConfig && tableConfig.extraConfigBuilder) {
|
|
2734
|
+
try {
|
|
2735
|
+
const extraConfig = tableConfig.extraConfigBuilder(table);
|
|
2736
|
+
if (Array.isArray(extraConfig)) {
|
|
2737
|
+
for (const item of extraConfig) {
|
|
2738
|
+
if (item && item._ && item._.name && item._.type === "PrimaryKeyBuilder") {
|
|
2739
|
+
const columnNames = item._.columns?.map((col) => col.name || col) || [];
|
|
2740
|
+
logger3.debug(`[INTROSPECTOR] Found composite primary key: ${item._.name}, columns: ${columnNames}`);
|
|
2741
|
+
return {
|
|
2742
|
+
name: item._.name,
|
|
2743
|
+
columns: columnNames
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
} else if (extraConfig && typeof extraConfig === "object") {
|
|
2748
|
+
for (const [_key, value] of Object.entries(extraConfig)) {
|
|
2749
|
+
if (value && typeof value === "object" && value._) {
|
|
2750
|
+
const config = value._;
|
|
2751
|
+
if (config.name && config.columns) {
|
|
2752
|
+
const columnNames = config.columns.map((col) => {
|
|
2753
|
+
if (col && typeof col === "object" && col.name) {
|
|
2754
|
+
return col.name;
|
|
2755
|
+
}
|
|
2756
|
+
if (typeof col === "string") {
|
|
2757
|
+
return col;
|
|
2758
|
+
}
|
|
2759
|
+
return col?.toString() || "unknown";
|
|
2760
|
+
});
|
|
2761
|
+
logger3.debug(`[INTROSPECTOR] Found composite primary key: ${config.name}, columns: ${columnNames}`);
|
|
2762
|
+
return {
|
|
2763
|
+
name: config.name || `${tableName}_pkey`,
|
|
2764
|
+
columns: columnNames
|
|
2765
|
+
};
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
} catch (error) {
|
|
2771
|
+
logger3.debug(`[INTROSPECTOR] Could not parse composite primary key: ${error instanceof Error ? error.message : String(error)}`);
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
return;
|
|
2775
|
+
}
|
|
2776
|
+
getSQLType(column, columnName) {
|
|
2777
|
+
const dataType = column.dataType || column._?.dataType;
|
|
2778
|
+
return this.getSQLTypeFromDataType(dataType, columnName);
|
|
2779
|
+
}
|
|
2780
|
+
mapDrizzleColumnType(columnType, config, columnName) {
|
|
2781
|
+
if (columnName && columnName.match(/^dim_?\\d+$/)) {
|
|
2782
|
+
const dimensions = columnName.replace(/^dim_?/, "");
|
|
2783
|
+
return `vector(${dimensions})`;
|
|
2784
|
+
}
|
|
2785
|
+
if (columnType === "PgVector" || config.sqlName === "vector" || config.customTypeParams?.dimensions) {
|
|
2786
|
+
const dimensions = config.dimensions || config.customTypeParams?.dimensions || 384;
|
|
2787
|
+
return `vector(${dimensions})`;
|
|
2788
|
+
}
|
|
2789
|
+
if (config.sqlName?.includes("numberTimestamp") || columnType === "numberTimestamp") {
|
|
2790
|
+
return "TIMESTAMP WITH TIME ZONE";
|
|
2791
|
+
}
|
|
2792
|
+
switch (columnType) {
|
|
2793
|
+
case "PgUUID":
|
|
2794
|
+
return "UUID";
|
|
2795
|
+
case "PgVarchar":
|
|
2796
|
+
return config.length ? `VARCHAR(${config.length})` : "VARCHAR(255)";
|
|
2797
|
+
case "PgText":
|
|
2798
|
+
return "TEXT";
|
|
2799
|
+
case "PgTimestamp":
|
|
2800
|
+
return config.withTimezone ? "TIMESTAMP WITH TIME ZONE" : "TIMESTAMP";
|
|
2801
|
+
case "PgInteger":
|
|
2802
|
+
return "INTEGER";
|
|
2803
|
+
case "PgBigint":
|
|
2804
|
+
return "BIGINT";
|
|
2805
|
+
case "PgBoolean":
|
|
2806
|
+
return "BOOLEAN";
|
|
2807
|
+
case "PgJsonb":
|
|
2808
|
+
return "JSONB";
|
|
2809
|
+
case "PgSerial":
|
|
2810
|
+
return "SERIAL";
|
|
2811
|
+
case "PgArray":
|
|
2812
|
+
return "TEXT[]";
|
|
2813
|
+
case "PgCustomColumn":
|
|
2814
|
+
if (columnName && columnName.match(/^dim_?\\d+$/)) {
|
|
2815
|
+
const dimensions = columnName.replace(/^dim_?/, "");
|
|
2816
|
+
return `vector(${dimensions})`;
|
|
2817
|
+
}
|
|
2818
|
+
return "TEXT";
|
|
2819
|
+
default:
|
|
2820
|
+
return "TEXT";
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
getSQLTypeFromDataType(dataType, columnName) {
|
|
2824
|
+
if (columnName && columnName.match(/^dim_?\d+$/)) {
|
|
2825
|
+
const dimensions = columnName.replace(/^dim_?/, "");
|
|
2826
|
+
return `vector(${dimensions})`;
|
|
2827
|
+
}
|
|
2828
|
+
switch (dataType) {
|
|
2829
|
+
case "uuid":
|
|
2830
|
+
return "UUID";
|
|
2831
|
+
case "text":
|
|
2832
|
+
return "TEXT";
|
|
2833
|
+
case "timestamp":
|
|
2834
|
+
return "TIMESTAMP";
|
|
2835
|
+
case "timestamptz":
|
|
2836
|
+
return "TIMESTAMP WITH TIME ZONE";
|
|
2837
|
+
case "boolean":
|
|
2838
|
+
return "BOOLEAN";
|
|
2839
|
+
case "jsonb":
|
|
2840
|
+
return "JSONB";
|
|
2841
|
+
default:
|
|
2842
|
+
return "TEXT";
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
formatDefaultValue(defaultValue) {
|
|
2846
|
+
if (defaultValue === undefined || defaultValue === null)
|
|
2847
|
+
return;
|
|
2848
|
+
if (defaultValue && typeof defaultValue === "object") {
|
|
2849
|
+
if (defaultValue.sql) {
|
|
2850
|
+
return defaultValue.sql;
|
|
2851
|
+
}
|
|
2852
|
+
if (defaultValue.queryChunks && Array.isArray(defaultValue.queryChunks)) {
|
|
2853
|
+
const result = defaultValue.queryChunks.map((c) => {
|
|
2854
|
+
if (typeof c === "string")
|
|
2855
|
+
return c;
|
|
2856
|
+
if (c && c.value !== undefined)
|
|
2857
|
+
return c.value;
|
|
2858
|
+
return "";
|
|
2859
|
+
}).join("");
|
|
2860
|
+
return result;
|
|
2861
|
+
}
|
|
2862
|
+
if (defaultValue.constructor && defaultValue.constructor.name === "Object") {
|
|
2863
|
+
if (Object.keys(defaultValue).length === 0) {
|
|
2864
|
+
return "'{}'";
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
if (defaultValue.constructor && defaultValue.constructor.name === "SQL") {
|
|
2868
|
+
const sqlStr = defaultValue.toString();
|
|
2869
|
+
if (sqlStr.includes("now()") || sqlStr.includes("NOW()")) {
|
|
2870
|
+
return "now()";
|
|
2871
|
+
}
|
|
2872
|
+
if (sqlStr.includes("gen_random_uuid()") || sqlStr.includes("GEN_RANDOM_UUID()")) {
|
|
2873
|
+
return "gen_random_uuid()";
|
|
2874
|
+
}
|
|
2875
|
+
return "now()";
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
if (typeof defaultValue === "string") {
|
|
2879
|
+
return `'${defaultValue}'`;
|
|
2880
|
+
}
|
|
2881
|
+
if (typeof defaultValue === "number" || typeof defaultValue === "boolean") {
|
|
2882
|
+
return defaultValue.toString();
|
|
2883
|
+
}
|
|
2884
|
+
logger3.debug(`[INTROSPECTOR] Could not format default value, returning undefined`);
|
|
2885
|
+
return;
|
|
2886
|
+
}
|
|
2887
|
+
generateCreateTableSQL(tableDef, schemaName) {
|
|
2888
|
+
const columnDefs = tableDef.columns.map((col) => {
|
|
2889
|
+
let def = `"${col.name}" ${col.type}`;
|
|
2890
|
+
if (col.primaryKey && !tableDef.compositePrimaryKey)
|
|
2891
|
+
def += " PRIMARY KEY";
|
|
2892
|
+
if (col.notNull && !col.primaryKey)
|
|
2893
|
+
def += " NOT NULL";
|
|
2894
|
+
if (col.unique)
|
|
2895
|
+
def += " UNIQUE";
|
|
2896
|
+
if (col.defaultValue) {
|
|
2897
|
+
if (col.defaultValue === "now()" || col.defaultValue.includes("now()")) {
|
|
2898
|
+
def += " DEFAULT now()";
|
|
2899
|
+
} else if (col.defaultValue === "true" || col.defaultValue === "false") {
|
|
2900
|
+
def += ` DEFAULT ${col.defaultValue}`;
|
|
2901
|
+
} else if (col.defaultValue === "gen_random_uuid()" || col.defaultValue.includes("gen_random_uuid")) {
|
|
2902
|
+
def += " DEFAULT gen_random_uuid()";
|
|
2903
|
+
} else if (col.defaultValue.startsWith("'") || !isNaN(Number(col.defaultValue))) {
|
|
2904
|
+
def += ` DEFAULT ${col.defaultValue}`;
|
|
2905
|
+
} else {
|
|
2906
|
+
def += ` DEFAULT ${col.defaultValue}`;
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
return def;
|
|
2910
|
+
}).join(`,
|
|
2911
|
+
`);
|
|
2912
|
+
const constraints = [];
|
|
2913
|
+
if (tableDef.compositePrimaryKey) {
|
|
2914
|
+
constraints.push(`CONSTRAINT "${tableDef.compositePrimaryKey.name}" PRIMARY KEY ("${tableDef.compositePrimaryKey.columns.join('", "')}")`);
|
|
2915
|
+
}
|
|
2916
|
+
const uniqueConstraints = tableDef.indexes.filter((idx) => idx.unique).map((idx) => `CONSTRAINT "${idx.name}" UNIQUE ("${idx.columns.join('", "')}")`);
|
|
2917
|
+
constraints.push(...uniqueConstraints);
|
|
2918
|
+
const allConstraints = constraints.length > 0 ? `${columnDefs},
|
|
2919
|
+
${constraints.join(`,
|
|
2920
|
+
`)}` : columnDefs;
|
|
2921
|
+
return `CREATE TABLE "${schemaName}"."${tableDef.name}" (
|
|
2922
|
+
${allConstraints}
|
|
2923
|
+
)`;
|
|
2924
|
+
}
|
|
2925
|
+
generateForeignKeySQL(tableDef, schemaName) {
|
|
2926
|
+
return tableDef.foreignKeys.map((fk) => `ALTER TABLE "${schemaName}"."${tableDef.name}" ` + `ADD CONSTRAINT "${fk.name}" ` + `FOREIGN KEY ("${fk.columns.join('", "')}") ` + `REFERENCES "${schemaName}"."${fk.referencedTable}" ("${fk.referencedColumns.join('", "')}")` + (fk.onDelete ? ` ON DELETE ${fk.onDelete.toUpperCase()}` : ""));
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
class PluginNamespaceManager {
|
|
2931
|
+
db;
|
|
2932
|
+
constructor(db) {
|
|
2933
|
+
this.db = db;
|
|
2934
|
+
}
|
|
2935
|
+
async getPluginSchema(pluginName) {
|
|
2936
|
+
if (pluginName === "@elizaos/plugin-sql") {
|
|
2937
|
+
try {
|
|
2938
|
+
const result = await this.db.execute(sql17.raw("SHOW search_path"));
|
|
2939
|
+
if (result.rows && result.rows.length > 0) {
|
|
2940
|
+
const searchPath = result.rows[0].search_path;
|
|
2941
|
+
const schemas = searchPath.split(",").map((s) => s.trim());
|
|
2942
|
+
for (const schema of schemas) {
|
|
2943
|
+
if (schema && !schema.includes("$user")) {
|
|
2944
|
+
return schema;
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
} catch (e) {
|
|
2949
|
+
logger3.debug("Could not determine search_path, defaulting to public schema.");
|
|
2950
|
+
}
|
|
2951
|
+
return "public";
|
|
2952
|
+
}
|
|
2953
|
+
return pluginName.replace(/@elizaos\/plugin-|\W/g, "_").toLowerCase();
|
|
2954
|
+
}
|
|
2955
|
+
async ensureNamespace(schemaName) {
|
|
2956
|
+
if (schemaName === "public")
|
|
2957
|
+
return;
|
|
2958
|
+
await this.db.execute(sql17.raw(`CREATE SCHEMA IF NOT EXISTS "${schemaName}"`));
|
|
2959
|
+
}
|
|
2960
|
+
async introspectExistingTables(schemaName) {
|
|
2961
|
+
const res = await this.db.execute(sql17.raw(`SELECT table_name FROM information_schema.tables WHERE table_schema = '${schemaName}'`));
|
|
2962
|
+
return res.rows.map((row) => row.table_name);
|
|
2963
|
+
}
|
|
2964
|
+
async foreignKeyExists(schemaName, tableName, constraintName) {
|
|
2965
|
+
try {
|
|
2966
|
+
const res = await this.db.execute(sql17.raw(`SELECT constraint_name
|
|
2967
|
+
FROM information_schema.table_constraints
|
|
2968
|
+
WHERE table_schema = '${schemaName}'
|
|
2969
|
+
AND table_name = '${tableName}'
|
|
2970
|
+
AND constraint_name = '${constraintName}'
|
|
2971
|
+
AND constraint_type = 'FOREIGN KEY'`));
|
|
2972
|
+
return res.rows.length > 0;
|
|
2973
|
+
} catch (error) {
|
|
2974
|
+
return false;
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
async checkConstraintExists(schemaName, tableName, constraintName) {
|
|
2978
|
+
try {
|
|
2979
|
+
const res = await this.db.execute(sql17.raw(`SELECT constraint_name
|
|
2980
|
+
FROM information_schema.table_constraints
|
|
2981
|
+
WHERE table_schema = '${schemaName}'
|
|
2982
|
+
AND table_name = '${tableName}'
|
|
2983
|
+
AND constraint_name = '${constraintName}'
|
|
2984
|
+
AND constraint_type = 'CHECK'`));
|
|
2985
|
+
return res.rows.length > 0;
|
|
2986
|
+
} catch (error) {
|
|
2987
|
+
return false;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
async uniqueConstraintExists(schemaName, tableName, constraintName) {
|
|
2991
|
+
try {
|
|
2992
|
+
const res = await this.db.execute(sql17.raw(`SELECT constraint_name
|
|
2993
|
+
FROM information_schema.table_constraints
|
|
2994
|
+
WHERE table_schema = '${schemaName}'
|
|
2995
|
+
AND table_name = '${tableName}'
|
|
2996
|
+
AND constraint_name = '${constraintName}'
|
|
2997
|
+
AND constraint_type = 'UNIQUE'`));
|
|
2998
|
+
return res.rows.length > 0;
|
|
2999
|
+
} catch (error) {
|
|
3000
|
+
return false;
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
async createTable(tableDef, schemaName) {
|
|
3004
|
+
const introspector = new DrizzleSchemaIntrospector;
|
|
3005
|
+
const createTableSQL = introspector.generateCreateTableSQL(tableDef, schemaName);
|
|
3006
|
+
await this.db.execute(sql17.raw(createTableSQL));
|
|
3007
|
+
logger3.info(`Created table: ${tableDef.name}`);
|
|
3008
|
+
}
|
|
3009
|
+
async addConstraints(tableDef, schemaName) {
|
|
3010
|
+
if (tableDef.foreignKeys.length > 0) {
|
|
3011
|
+
const introspector = new DrizzleSchemaIntrospector;
|
|
3012
|
+
const constraintSQLs = introspector.generateForeignKeySQL(tableDef, schemaName);
|
|
3013
|
+
for (let i = 0;i < tableDef.foreignKeys.length; i++) {
|
|
3014
|
+
const fk = tableDef.foreignKeys[i];
|
|
3015
|
+
const constraintSQL = constraintSQLs[i];
|
|
3016
|
+
try {
|
|
3017
|
+
const exists = await this.foreignKeyExists(schemaName, tableDef.name, fk.name);
|
|
3018
|
+
if (exists) {
|
|
3019
|
+
logger3.debug(`[CUSTOM MIGRATOR] Foreign key constraint ${fk.name} already exists, skipping`);
|
|
3020
|
+
continue;
|
|
3021
|
+
}
|
|
3022
|
+
await this.db.execute(sql17.raw(constraintSQL));
|
|
3023
|
+
logger3.debug(`[CUSTOM MIGRATOR] Successfully added foreign key constraint: ${fk.name}`);
|
|
3024
|
+
} catch (error) {
|
|
3025
|
+
const errorMessage = extractErrorMessage(error);
|
|
3026
|
+
if (errorMessage.includes("already exists")) {
|
|
3027
|
+
logger3.debug(`[CUSTOM MIGRATOR] Foreign key constraint already exists: ${fk.name}`);
|
|
3028
|
+
} else {
|
|
3029
|
+
logger3.warn(`[CUSTOM MIGRATOR] Could not add foreign key constraint (may already exist): ${errorMessage}`);
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
if (tableDef.checkConstraints.length > 0) {
|
|
3035
|
+
for (const checkConstraint of tableDef.checkConstraints) {
|
|
3036
|
+
try {
|
|
3037
|
+
const exists = await this.checkConstraintExists(schemaName, tableDef.name, checkConstraint.name);
|
|
3038
|
+
if (exists) {
|
|
3039
|
+
logger3.debug(`[CUSTOM MIGRATOR] Check constraint ${checkConstraint.name} already exists, skipping`);
|
|
3040
|
+
continue;
|
|
3041
|
+
}
|
|
3042
|
+
const checkSQL = `ALTER TABLE "${schemaName}"."${tableDef.name}" ADD CONSTRAINT "${checkConstraint.name}" CHECK (${checkConstraint.expression})`;
|
|
3043
|
+
await this.db.execute(sql17.raw(checkSQL));
|
|
3044
|
+
logger3.debug(`[CUSTOM MIGRATOR] Successfully added check constraint: ${checkConstraint.name}`);
|
|
3045
|
+
} catch (error) {
|
|
3046
|
+
const errorMessage = extractErrorMessage(error);
|
|
3047
|
+
if (errorMessage.includes("already exists")) {
|
|
3048
|
+
logger3.debug(`[CUSTOM MIGRATOR] Check constraint already exists: ${checkConstraint.name}`);
|
|
3049
|
+
} else {
|
|
3050
|
+
logger3.warn(`[CUSTOM MIGRATOR] Could not add check constraint ${checkConstraint.name} (may already exist): ${errorMessage}`);
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
class ExtensionManager {
|
|
3059
|
+
db;
|
|
3060
|
+
constructor(db) {
|
|
3061
|
+
this.db = db;
|
|
3062
|
+
}
|
|
3063
|
+
async installRequiredExtensions(requiredExtensions) {
|
|
3064
|
+
for (const extension of requiredExtensions) {
|
|
3065
|
+
try {
|
|
3066
|
+
await this.db.execute(sql17.raw(`CREATE EXTENSION IF NOT EXISTS "${extension}"`));
|
|
3067
|
+
} catch (error) {
|
|
3068
|
+
const errorDetails = extractErrorDetails(error);
|
|
3069
|
+
logger3.warn(`Could not install extension ${extension}: ${errorDetails.message}`);
|
|
3070
|
+
if (errorDetails.stack) {
|
|
3071
|
+
logger3.debug(`[CUSTOM MIGRATOR] Extension installation stack trace: ${errorDetails.stack}`);
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
function topologicalSort(tables) {
|
|
3078
|
+
const sorted = [];
|
|
3079
|
+
const visited = new Set;
|
|
3080
|
+
const visiting = new Set;
|
|
3081
|
+
function visit(tableName) {
|
|
3082
|
+
if (visiting.has(tableName)) {
|
|
3083
|
+
logger3.warn(`Circular dependency detected involving table: ${tableName}`);
|
|
3084
|
+
return;
|
|
3085
|
+
}
|
|
3086
|
+
if (visited.has(tableName)) {
|
|
3087
|
+
return;
|
|
3088
|
+
}
|
|
3089
|
+
visiting.add(tableName);
|
|
3090
|
+
const table = tables.get(tableName);
|
|
3091
|
+
if (table) {
|
|
3092
|
+
for (const dep of table.dependencies) {
|
|
3093
|
+
if (tables.has(dep)) {
|
|
3094
|
+
visit(dep);
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
visiting.delete(tableName);
|
|
3099
|
+
visited.add(tableName);
|
|
3100
|
+
sorted.push(tableName);
|
|
3101
|
+
}
|
|
3102
|
+
for (const tableName of tables.keys()) {
|
|
3103
|
+
visit(tableName);
|
|
3104
|
+
}
|
|
3105
|
+
return sorted;
|
|
3106
|
+
}
|
|
3107
|
+
async function runPluginMigrations(db, pluginName, schema) {
|
|
3108
|
+
logger3.debug(`[CUSTOM MIGRATOR] Starting migration for plugin: ${pluginName}`);
|
|
3109
|
+
try {
|
|
3110
|
+
await db.execute(sql17.raw("SELECT 1"));
|
|
3111
|
+
logger3.debug("[CUSTOM MIGRATOR] Database connection verified");
|
|
3112
|
+
} catch (error) {
|
|
3113
|
+
const errorDetails = extractErrorDetails(error);
|
|
3114
|
+
logger3.error(`[CUSTOM MIGRATOR] Database connection failed: ${errorDetails.message}`);
|
|
3115
|
+
if (errorDetails.stack) {
|
|
3116
|
+
logger3.error(`[CUSTOM MIGRATOR] Stack trace: ${errorDetails.stack}`);
|
|
3117
|
+
}
|
|
3118
|
+
throw new Error(`Database connection failed: ${errorDetails.message}`);
|
|
3119
|
+
}
|
|
3120
|
+
const namespaceManager = new PluginNamespaceManager(db);
|
|
3121
|
+
const introspector = new DrizzleSchemaIntrospector;
|
|
3122
|
+
const extensionManager = new ExtensionManager(db);
|
|
3123
|
+
await extensionManager.installRequiredExtensions(["vector", "fuzzystrmatch"]);
|
|
3124
|
+
const schemaName = await namespaceManager.getPluginSchema(pluginName);
|
|
3125
|
+
await namespaceManager.ensureNamespace(schemaName);
|
|
3126
|
+
const existingTables = await namespaceManager.introspectExistingTables(schemaName);
|
|
3127
|
+
const tableEntries = Object.entries(schema).filter(([key, v]) => {
|
|
3128
|
+
const isDrizzleTable = v && (v._ && typeof v._.name === "string" || typeof v === "object" && v !== null && (("tableName" in v) || ("dbName" in v) || key.toLowerCase().includes("table")));
|
|
3129
|
+
return isDrizzleTable;
|
|
3130
|
+
});
|
|
3131
|
+
const tableDefinitions = new Map;
|
|
3132
|
+
for (const [exportKey, table] of tableEntries) {
|
|
3133
|
+
const tableDef = introspector.parseTableDefinition(table, exportKey);
|
|
3134
|
+
tableDefinitions.set(tableDef.name, tableDef);
|
|
3135
|
+
}
|
|
3136
|
+
const sortedTableNames = topologicalSort(tableDefinitions);
|
|
3137
|
+
try {
|
|
3138
|
+
logger3.debug(`[CUSTOM MIGRATOR] Phase 1: Creating tables...`);
|
|
3139
|
+
for (const tableName of sortedTableNames) {
|
|
3140
|
+
const tableDef = tableDefinitions.get(tableName);
|
|
3141
|
+
if (!tableDef)
|
|
3142
|
+
continue;
|
|
3143
|
+
const tableExists = existingTables.includes(tableDef.name);
|
|
3144
|
+
logger3.debug(`[CUSTOM MIGRATOR] Table ${tableDef.name} exists: ${tableExists}`);
|
|
3145
|
+
if (!tableExists) {
|
|
3146
|
+
logger3.debug(`[CUSTOM MIGRATOR] Creating table: ${tableDef.name}`);
|
|
3147
|
+
try {
|
|
3148
|
+
await namespaceManager.createTable(tableDef, schemaName);
|
|
3149
|
+
} catch (error) {
|
|
3150
|
+
const errorDetails = extractErrorDetails(error);
|
|
3151
|
+
logger3.error(`[CUSTOM MIGRATOR] Failed to create table ${tableDef.name}: ${errorDetails.message}`);
|
|
3152
|
+
if (errorDetails.stack) {
|
|
3153
|
+
logger3.error(`[CUSTOM MIGRATOR] Table creation stack trace: ${errorDetails.stack}`);
|
|
3154
|
+
}
|
|
3155
|
+
throw new Error(`Failed to create table ${tableDef.name}: ${errorDetails.message}`);
|
|
3156
|
+
}
|
|
3157
|
+
} else {
|
|
3158
|
+
logger3.debug(`[CUSTOM MIGRATOR] Table ${tableDef.name} already exists, skipping creation`);
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
logger3.debug(`[CUSTOM MIGRATOR] Phase 2: Adding constraints...`);
|
|
3162
|
+
for (const tableName of sortedTableNames) {
|
|
3163
|
+
const tableDef = tableDefinitions.get(tableName);
|
|
3164
|
+
if (!tableDef)
|
|
3165
|
+
continue;
|
|
3166
|
+
if (tableDef.foreignKeys.length > 0 || tableDef.checkConstraints.length > 0) {
|
|
3167
|
+
logger3.debug(`[CUSTOM MIGRATOR] Adding constraints for table: ${tableDef.name} - ${JSON.stringify({
|
|
3168
|
+
foreignKeys: tableDef.foreignKeys.length,
|
|
3169
|
+
checkConstraints: tableDef.checkConstraints.length
|
|
3170
|
+
})}`);
|
|
3171
|
+
await namespaceManager.addConstraints(tableDef, schemaName);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
logger3.debug(`[CUSTOM MIGRATOR] Completed migration for plugin: ${pluginName}`);
|
|
3175
|
+
} catch (error) {
|
|
3176
|
+
const errorDetails = extractErrorDetails(error);
|
|
3177
|
+
logger3.error(`[CUSTOM MIGRATOR] Migration failed for plugin ${pluginName}: ${errorDetails.message}`);
|
|
3178
|
+
if (errorDetails.stack) {
|
|
3179
|
+
logger3.error(`[CUSTOM MIGRATOR] Migration stack trace: ${errorDetails.stack}`);
|
|
3180
|
+
}
|
|
3181
|
+
throw new Error(`Migration failed for plugin ${pluginName}: ${errorDetails.message}`);
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
|
|
3185
|
+
// src/migration-service.ts
|
|
3186
|
+
class DatabaseMigrationService {
|
|
3187
|
+
db = null;
|
|
3188
|
+
registeredSchemas = new Map;
|
|
3189
|
+
constructor() {}
|
|
3190
|
+
async initializeWithDatabase(db) {
|
|
3191
|
+
this.db = db;
|
|
3192
|
+
logger4.info("DatabaseMigrationService initialized with database");
|
|
3193
|
+
}
|
|
3194
|
+
discoverAndRegisterPluginSchemas(plugins) {
|
|
3195
|
+
for (const plugin of plugins) {
|
|
3196
|
+
if (plugin.schema) {
|
|
3197
|
+
this.registeredSchemas.set(plugin.name, plugin.schema);
|
|
3198
|
+
logger4.info(`Registered schema for plugin: ${plugin.name}`);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
logger4.info(`Discovered ${this.registeredSchemas.size} plugin schemas out of ${plugins.length} plugins`);
|
|
3202
|
+
}
|
|
3203
|
+
registerSchema(pluginName, schema) {
|
|
3204
|
+
this.registeredSchemas.set(pluginName, schema);
|
|
3205
|
+
logger4.info(`Registered schema for plugin: ${pluginName}`);
|
|
3206
|
+
}
|
|
3207
|
+
async runAllPluginMigrations() {
|
|
3208
|
+
if (!this.db) {
|
|
3209
|
+
throw new Error("Database not initialized in DatabaseMigrationService");
|
|
3210
|
+
}
|
|
3211
|
+
logger4.info(`Running migrations for ${this.registeredSchemas.size} plugins...`);
|
|
3212
|
+
for (const [pluginName, schema] of this.registeredSchemas) {
|
|
3213
|
+
logger4.info(`Starting migration for plugin: ${pluginName}`);
|
|
3214
|
+
await runPluginMigrations(this.db, pluginName, schema);
|
|
3215
|
+
}
|
|
3216
|
+
logger4.info("All plugin migrations completed.");
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
|
|
3220
|
+
// src/index.browser.ts
|
|
3221
|
+
var GLOBAL_SINGLETONS = Symbol.for("@elizaos/plugin-sql/global-singletons");
|
|
3222
|
+
var globalSymbols = globalThis;
|
|
3223
|
+
if (!globalSymbols[GLOBAL_SINGLETONS]) {
|
|
3224
|
+
globalSymbols[GLOBAL_SINGLETONS] = {};
|
|
3225
|
+
}
|
|
3226
|
+
var globalSingletons = globalSymbols[GLOBAL_SINGLETONS];
|
|
3227
|
+
function createDatabaseAdapter(_config, agentId) {
|
|
3228
|
+
if (!globalSingletons.pgLiteClientManager) {
|
|
3229
|
+
globalSingletons.pgLiteClientManager = new PGliteClientManager({});
|
|
3230
|
+
}
|
|
3231
|
+
return new PgliteDatabaseAdapter(agentId, globalSingletons.pgLiteClientManager);
|
|
3232
|
+
}
|
|
3233
|
+
var plugin = {
|
|
3234
|
+
name: "@elizaos/plugin-sql",
|
|
3235
|
+
description: "A plugin for SQL database access (PGlite WASM in browser).",
|
|
3236
|
+
priority: 0,
|
|
3237
|
+
schema: exports_schema,
|
|
3238
|
+
init: async (_config, runtime) => {
|
|
3239
|
+
logger5.info("plugin-sql (browser) init starting...");
|
|
3240
|
+
const dbAdapter = createDatabaseAdapter({}, runtime.agentId);
|
|
3241
|
+
runtime.registerDatabaseAdapter(dbAdapter);
|
|
3242
|
+
logger5.info("Browser database adapter (PGlite) created and registered");
|
|
3243
|
+
}
|
|
3244
|
+
};
|
|
3245
|
+
var index_browser_default = plugin;
|
|
3246
|
+
export {
|
|
3247
|
+
plugin,
|
|
3248
|
+
index_browser_default as default,
|
|
3249
|
+
createDatabaseAdapter,
|
|
3250
|
+
DatabaseMigrationService
|
|
3251
|
+
};
|
|
3252
|
+
|
|
3253
|
+
//# debugId=6FC3A45AD99266E264756E2164756E21
|
|
3254
|
+
//# sourceMappingURL=index.browser.js.map
|