@ponraaj/dimple-sdk 0.0.0-alpha.7 → 0.0.0-alpha.9
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/README.md +19 -18
- package/dist/dimple.d.ts +10 -0
- package/dist/index.js +1329 -786
- package/dist/internal/embedder/auto-install.d.ts +8 -33
- package/dist/internal/installer/index.d.ts +26 -0
- package/dist/internal/store/db-backend.d.ts +21 -2
- package/dist/internal/store/service.d.ts +36 -2
- package/dist/internal/store/topics/routing.d.ts +33 -0
- package/dist/internal/workflow/signals.d.ts +20 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ var __export = (target, all) => {
|
|
|
16
16
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
17
17
|
|
|
18
18
|
// src/make.ts
|
|
19
|
-
import { Effect as
|
|
19
|
+
import { Effect as Effect51, Exit as Exit8, Layer as Layer26, ManagedRuntime, Scope as Scope5 } from "effect";
|
|
20
20
|
|
|
21
21
|
// ../core/src/core.ts
|
|
22
22
|
import { Context, Schema } from "effect";
|
|
@@ -29,10 +29,10 @@ class CoreConfigError extends Schema.TaggedErrorClass()("core.ConfigError", {
|
|
|
29
29
|
class Service extends Context.Service()("@dimple/core/Core") {
|
|
30
30
|
}
|
|
31
31
|
// ../core/src/layer.ts
|
|
32
|
-
import { Effect as
|
|
32
|
+
import { Effect as Effect40, Layer as Layer15, Schema as Schema24 } from "effect";
|
|
33
33
|
|
|
34
34
|
// ../store/src/store.ts
|
|
35
|
-
import { Config as Config4, Effect as
|
|
35
|
+
import { Config as Config4, Effect as Effect27, Layer as Layer10, Schema as Schema19 } from "effect";
|
|
36
36
|
import { eq as eq8, and as and8, desc as desc2, asc as asc5, inArray as inArray4, ne as ne4, or, isNull as isNull2, like, sql as sql7 } from "drizzle-orm";
|
|
37
37
|
|
|
38
38
|
// ../store/src/db-backend.ts
|
|
@@ -113,6 +113,11 @@ var EMBEDDED_MIGRATIONS = [
|
|
|
113
113
|
name: "20260807074034_ttl_secs_nullable",
|
|
114
114
|
hash: "be3a8d0e64b0224021d869c1c7e217e40b6eb868615cc4c86a6717f5b7211721",
|
|
115
115
|
sql: "PRAGMA foreign_keys=OFF;--> statement-breakpoint\nCREATE TABLE `__new_memories` (\n\t`id` text PRIMARY KEY,\n\t`logical_key` text NOT NULL,\n\t`content` text NOT NULL,\n\t`content_type` text DEFAULT 'text/plain' NOT NULL,\n\t`state` text DEFAULT 'active' NOT NULL,\n\t`created_at` integer NOT NULL,\n\t`ttl_secs` integer DEFAULT 604800,\n\t`namespace` text DEFAULT 'default' NOT NULL,\n\t`metadata` text,\n\t`embedding` F32_BLOB(384),\n\t`embedding_model` text\n);\n--> statement-breakpoint\nINSERT INTO `__new_memories`(`id`, `logical_key`, `content`, `content_type`, `state`, `created_at`, `ttl_secs`, `namespace`, `metadata`, `embedding`, `embedding_model`) SELECT `id`, `logical_key`, `content`, `content_type`, `state`, `created_at`, `ttl_secs`, `namespace`, `metadata`, `embedding`, `embedding_model` FROM `memories`;--> statement-breakpoint\nDROP TABLE `memories`;--> statement-breakpoint\nALTER TABLE `__new_memories` RENAME TO `memories`;--> statement-breakpoint\nPRAGMA foreign_keys=ON;--> statement-breakpoint\nCREATE INDEX `idx_memories_ns_created` ON `memories` (`namespace`,`created_at`);--> statement-breakpoint\nCREATE INDEX `idx_memories_state_created` ON `memories` (`state`,`created_at`);--> statement-breakpoint\nCREATE UNIQUE INDEX `idx_memories_active_key` ON `memories` (`namespace`,`logical_key`) WHERE state = 'active';"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "20260812122840_perf_indexes",
|
|
119
|
+
hash: "cc45ad830f7101fae454e9d5b43cfdfb922dbee7a5e5b7d9b9b81ec610d21d8e",
|
|
120
|
+
sql: "CREATE INDEX `idx_memories_created` ON `memories` (`created_at`);--> statement-breakpoint\nCREATE INDEX `ae_status_source` ON `artifact_edges` (`status`,`source`,`expired_at`,`created_at`);"
|
|
116
121
|
}
|
|
117
122
|
];
|
|
118
123
|
|
|
@@ -160,6 +165,7 @@ var memories = sqliteTable("memories", {
|
|
|
160
165
|
}, (table) => [
|
|
161
166
|
index("idx_memories_ns_created").on(table.namespace, table.createdAt),
|
|
162
167
|
index("idx_memories_state_created").on(table.state, table.createdAt),
|
|
168
|
+
index("idx_memories_created").on(table.createdAt),
|
|
163
169
|
uniqueIndex("idx_memories_active_key").on(table.namespace, table.logicalKey).where(sql`state = 'active'`)
|
|
164
170
|
]);
|
|
165
171
|
var memoryEvents = sqliteTable("memory_events", {
|
|
@@ -343,7 +349,8 @@ var artifactEdges = sqliteTable3("artifact_edges", {
|
|
|
343
349
|
}, (t) => [
|
|
344
350
|
primaryKey3({ columns: [t.fromMemoryId, t.toMemoryId, t.edgeKind] }),
|
|
345
351
|
index3("ae_from").on(t.fromMemoryId, t.status),
|
|
346
|
-
index3("ae_to").on(t.toMemoryId, t.status)
|
|
352
|
+
index3("ae_to").on(t.toMemoryId, t.status),
|
|
353
|
+
index3("ae_status_source").on(t.status, t.source, t.expiredAt, t.createdAt)
|
|
347
354
|
]);
|
|
348
355
|
var ArtifactEdgeInsert = createInsertSchema3(artifactEdges);
|
|
349
356
|
var ArtifactEdgeSelect = createSelectSchema3(artifactEdges);
|
|
@@ -766,6 +773,7 @@ import { Effect as Effect7, Schema as Schema7 } from "effect";
|
|
|
766
773
|
import { parse, parseTree, printParseErrorCode } from "jsonc-parser";
|
|
767
774
|
var CONFIG_FILE_NAMES = ["dimple.jsonc", "dimple.json"];
|
|
768
775
|
var GLOBAL_DIR = ".config/dimple";
|
|
776
|
+
var resolveCwd = () => process.env["DIMPLE_CWD"] ?? process.cwd();
|
|
769
777
|
var defaults = {
|
|
770
778
|
storeUrl: "file:./.dimple/dimple.db",
|
|
771
779
|
defaultK: 60,
|
|
@@ -871,7 +879,7 @@ var loadFs = () => Effect7.tryPromise(() => import("node:fs"));
|
|
|
871
879
|
var findProjectConfig = () => Effect7.gen(function* () {
|
|
872
880
|
const fs = yield* loadFs();
|
|
873
881
|
const path = yield* Effect7.tryPromise(() => import("node:path"));
|
|
874
|
-
let dir =
|
|
882
|
+
let dir = resolveCwd();
|
|
875
883
|
for (let i = 0;i < 20; i++) {
|
|
876
884
|
for (const name of CONFIG_FILE_NAMES) {
|
|
877
885
|
const p = path.join(dir, name);
|
|
@@ -940,6 +948,23 @@ var resolveEnvVars = (value) => {
|
|
|
940
948
|
}
|
|
941
949
|
return value;
|
|
942
950
|
};
|
|
951
|
+
var resolveCwdUrls = (value) => {
|
|
952
|
+
const cwd = process.env["DIMPLE_CWD"];
|
|
953
|
+
if (cwd === undefined)
|
|
954
|
+
return value;
|
|
955
|
+
if (typeof value === "string" && value.startsWith("file:./")) {
|
|
956
|
+
return `file:${cwd}${cwd.endsWith("/") ? "" : "/"}${value.slice("file:./".length)}`;
|
|
957
|
+
}
|
|
958
|
+
if (Array.isArray(value))
|
|
959
|
+
return value.map(resolveCwdUrls);
|
|
960
|
+
if (value !== null && typeof value === "object") {
|
|
961
|
+
const result = {};
|
|
962
|
+
for (const [k, v] of Object.entries(value))
|
|
963
|
+
result[k] = resolveCwdUrls(v);
|
|
964
|
+
return result;
|
|
965
|
+
}
|
|
966
|
+
return value;
|
|
967
|
+
};
|
|
943
968
|
var deepMerge = (base, over) => {
|
|
944
969
|
const out = { ...base };
|
|
945
970
|
for (const [key, value] of Object.entries(over)) {
|
|
@@ -957,7 +982,7 @@ var loadConfigFromFile = (path) => Effect7.gen(function* () {
|
|
|
957
982
|
const parsed = yield* parseJsoncEffect(content, (cause) => new Error(`config parse ${path}: ${cause.message}`));
|
|
958
983
|
const merged = deepMerge(defaults, parsed);
|
|
959
984
|
const resolved = resolveEnvVars(merged);
|
|
960
|
-
return yield* Schema7.decodeUnknownEffect(DimpleConfig, { errors: "all" })(resolved).pipe(Effect7.mapError((e) => new Error(`config validation: ${e.message}`)));
|
|
985
|
+
return yield* Schema7.decodeUnknownEffect(DimpleConfig, { errors: "all" })(resolveCwdUrls(resolved)).pipe(Effect7.mapError((e) => new Error(`config validation: ${e.message}`)));
|
|
961
986
|
});
|
|
962
987
|
var loadConfig = (overrides) => Effect7.gen(function* () {
|
|
963
988
|
const fileParts = yield* loadFromFiles();
|
|
@@ -970,7 +995,7 @@ var loadConfig = (overrides) => Effect7.gen(function* () {
|
|
|
970
995
|
if (overrides)
|
|
971
996
|
merged = deepMerge(merged, overrides);
|
|
972
997
|
const resolved = resolveEnvVars(merged);
|
|
973
|
-
return yield* Schema7.decodeUnknownEffect(DimpleConfig, { errors: "all" })(resolved).pipe(Effect7.mapError((e) => new Error(`config validation: ${e.message}`)));
|
|
998
|
+
return yield* Schema7.decodeUnknownEffect(DimpleConfig, { errors: "all" })(resolveCwdUrls(resolved)).pipe(Effect7.mapError((e) => new Error(`config validation: ${e.message}`)));
|
|
974
999
|
});
|
|
975
1000
|
|
|
976
1001
|
// ../config/src/service.ts
|
|
@@ -1065,7 +1090,14 @@ var runEmbeddedMigrations = async (client) => {
|
|
|
1065
1090
|
var makeClientDb = (url) => {
|
|
1066
1091
|
const client = createClient({ url });
|
|
1067
1092
|
const db = drizzle({ client });
|
|
1093
|
+
const rawExecute = client.execute.bind(client);
|
|
1094
|
+
const rawExecuteMultiple = client.executeMultiple.bind(client);
|
|
1095
|
+
const rawBatch = client.batch.bind(client);
|
|
1068
1096
|
const rawTransaction = client.transaction.bind(client);
|
|
1097
|
+
const local = url.startsWith("file:");
|
|
1098
|
+
if (local) {
|
|
1099
|
+
rawExecute("PRAGMA busy_timeout=5000");
|
|
1100
|
+
}
|
|
1069
1101
|
let txTail = Promise.resolve();
|
|
1070
1102
|
let releaseSlot;
|
|
1071
1103
|
const acquire = () => {
|
|
@@ -1082,14 +1114,18 @@ var makeClientDb = (url) => {
|
|
|
1082
1114
|
releaseSlot?.();
|
|
1083
1115
|
releaseSlot = undefined;
|
|
1084
1116
|
};
|
|
1085
|
-
const rawExecute = client.execute.bind(client);
|
|
1086
|
-
const rawExecuteMultiple = client.executeMultiple.bind(client);
|
|
1087
|
-
const rawBatch = client.batch.bind(client);
|
|
1088
1117
|
const chained = (run) => {
|
|
1089
1118
|
const prev = acquire();
|
|
1090
1119
|
return prev.then(run, run).finally(release);
|
|
1091
1120
|
};
|
|
1092
|
-
|
|
1121
|
+
const WRITE_RE = /^\s*(INSERT|UPDATE|DELETE|CREATE|DROP|ALTER|REPLACE|PRAGMA|BEGIN|COMMIT|ROLLBACK|VACUUM|REINDEX|ANALYZE|ATTACH|DETACH)\b/i;
|
|
1122
|
+
const isWrite = (sql3) => WRITE_RE.test(sql3);
|
|
1123
|
+
client.execute = (...args) => {
|
|
1124
|
+
const statement = args[0];
|
|
1125
|
+
const sql3 = typeof statement === "string" ? statement : statement.sql ?? "";
|
|
1126
|
+
const run = () => rawExecute(...args);
|
|
1127
|
+
return local && !isWrite(sql3) ? run() : chained(run);
|
|
1128
|
+
};
|
|
1093
1129
|
client.executeMultiple = (sql3) => chained(() => rawExecuteMultiple(sql3));
|
|
1094
1130
|
client.batch = (statements, mode) => chained(() => rawBatch(statements, mode));
|
|
1095
1131
|
client.transaction = async (mode) => {
|
|
@@ -1227,16 +1263,16 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1227
1263
|
topics,
|
|
1228
1264
|
artifactEdges
|
|
1229
1265
|
},
|
|
1230
|
-
ftsSearch: (query, namespace, limit, topicKeys, modelKey, contentType) => Effect9.tryPromise({
|
|
1266
|
+
ftsSearch: (query, namespace, limit, topicKeys, modelKey, contentType, includeEmbedding) => Effect9.tryPromise({
|
|
1231
1267
|
try: () => client.execute({
|
|
1232
|
-
sql: `SELECT m
|
|
1268
|
+
sql: `SELECT m.id, m.logical_key, m.content, m.content_type, m.state, m.created_at, m.ttl_secs, m.namespace, m.metadata, m.embedding_model${includeEmbedding ? ", m.embedding" : ""}, f.rank
|
|
1233
1269
|
FROM memories_fts f
|
|
1234
1270
|
JOIN memories m ON m.rowid = f.rowid
|
|
1235
1271
|
WHERE f.content MATCH ? AND m.namespace = ? AND m.state = 'active'${topicFilter(topicKeys)}${contentTypeFilter(contentType)}
|
|
1236
1272
|
ORDER BY f.rank
|
|
1237
1273
|
LIMIT ?`,
|
|
1238
1274
|
args: [
|
|
1239
|
-
`"${
|
|
1275
|
+
query.split(/\s+/).filter((token) => token.length > 0).map((token) => `"${token.replaceAll('"', '""')}"`).join(" "),
|
|
1240
1276
|
namespace,
|
|
1241
1277
|
...topicKeys && topicKeys.length > 0 ? [...topicKeys, modelKey ?? ""] : [],
|
|
1242
1278
|
...typeof contentType === "string" ? [contentType] : contentType ?? [],
|
|
@@ -1245,7 +1281,7 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1245
1281
|
}).then((rs) => rs.rows),
|
|
1246
1282
|
catch: (cause) => new StoreError({ message: `DbBackend.ftsSearch: ${cause}` })
|
|
1247
1283
|
}),
|
|
1248
|
-
vectorSearch: (query, namespace, limit, model, topicKeys, contentType) => Effect9.gen(function* () {
|
|
1284
|
+
vectorSearch: (query, namespace, limit, model, topicKeys, contentType, includeEmbedding) => Effect9.gen(function* () {
|
|
1249
1285
|
for (const n of query) {
|
|
1250
1286
|
if (!Number.isFinite(n)) {
|
|
1251
1287
|
yield* new StoreError({
|
|
@@ -1256,26 +1292,50 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1256
1292
|
const tableName = vectorTableName(model);
|
|
1257
1293
|
const vecJson = JSON.stringify([...query]);
|
|
1258
1294
|
const convertFn = VECTOR_CONVERT_FNS[model.vectorType ?? "float32"] ?? "vector32";
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1295
|
+
const whereClause = `WHERE m.namespace = ? AND m.state = 'active'${topicFilter(topicKeys)}${contentTypeFilter(contentType)}`;
|
|
1296
|
+
const selectColumns = `m.id, m.logical_key, m.content, m.content_type, m.state, m.created_at, m.ttl_secs, m.namespace, m.metadata, m.embedding_model${includeEmbedding ? ", m.embedding" : ""}`;
|
|
1297
|
+
const baseArgs = [
|
|
1261
1298
|
namespace,
|
|
1262
1299
|
...topicKeys && topicKeys.length > 0 ? [...topicKeys, model.id] : [],
|
|
1263
|
-
...typeof contentType === "string" ? [contentType] : contentType ?? []
|
|
1264
|
-
limit
|
|
1300
|
+
...typeof contentType === "string" ? [contentType] : contentType ?? []
|
|
1265
1301
|
];
|
|
1302
|
+
const indexName = `idx_${tableName}_vec`;
|
|
1303
|
+
const annSql = `
|
|
1304
|
+
SELECT ${selectColumns},
|
|
1305
|
+
vector_distance_cos(v.embedding, ${convertFn}(?)) AS distance
|
|
1306
|
+
FROM vector_top_k(?, ${convertFn}(?), ?) AS k
|
|
1307
|
+
JOIN ${tableName} v ON v.rowid = k.id
|
|
1308
|
+
JOIN memories m ON m.id = v.memory_id
|
|
1309
|
+
${whereClause}
|
|
1310
|
+
ORDER BY distance, m.id
|
|
1311
|
+
LIMIT ?
|
|
1312
|
+
`;
|
|
1313
|
+
const scanSql = `
|
|
1314
|
+
SELECT ${selectColumns},
|
|
1315
|
+
vector_distance_cos(v.embedding, ${convertFn}(?)) AS distance
|
|
1316
|
+
FROM memories m
|
|
1317
|
+
JOIN ${tableName} v ON v.memory_id = m.id
|
|
1318
|
+
${whereClause}
|
|
1319
|
+
ORDER BY distance, m.id
|
|
1320
|
+
LIMIT ?
|
|
1321
|
+
`;
|
|
1322
|
+
const annK = Math.max(limit * 16, 64);
|
|
1323
|
+
const runAnn = () => client.execute({
|
|
1324
|
+
sql: annSql,
|
|
1325
|
+
args: [vecJson, indexName, vecJson, annK, ...baseArgs, limit]
|
|
1326
|
+
}).then((rs) => rs.rows);
|
|
1327
|
+
const runScan = () => client.execute({
|
|
1328
|
+
sql: scanSql,
|
|
1329
|
+
args: [vecJson, ...baseArgs, limit]
|
|
1330
|
+
}).then((rs) => rs.rows);
|
|
1266
1331
|
const rows = yield* Effect9.tryPromise({
|
|
1267
|
-
try: () =>
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
ORDER BY distance
|
|
1275
|
-
LIMIT ?
|
|
1276
|
-
`,
|
|
1277
|
-
args
|
|
1278
|
-
}).then((rs) => rs.rows),
|
|
1332
|
+
try: () => runAnn().catch((cause) => {
|
|
1333
|
+
const message = String(cause.message ?? cause);
|
|
1334
|
+
const absent = message.includes("no such table") || message.includes("no such index") || message.includes("vector_top_k");
|
|
1335
|
+
if (absent)
|
|
1336
|
+
return runScan();
|
|
1337
|
+
throw cause;
|
|
1338
|
+
}),
|
|
1279
1339
|
catch: (cause) => new StoreError({ message: `DbBackend.vectorSearch: ${cause}` })
|
|
1280
1340
|
}).pipe(Effect9.catchTag("Store.StoreError", (error) => error.message.includes("no such table") ? Effect9.succeed([]) : Effect9.fail(error)));
|
|
1281
1341
|
return rows;
|
|
@@ -1455,7 +1515,7 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1455
1515
|
return results;
|
|
1456
1516
|
}),
|
|
1457
1517
|
ensureVectorTable: (model) => Effect9.tryPromise({
|
|
1458
|
-
try: () => {
|
|
1518
|
+
try: async () => {
|
|
1459
1519
|
const tableName = vectorTableName(model);
|
|
1460
1520
|
const vecType = model.vectorType ?? "float32";
|
|
1461
1521
|
const sqlType = VECTOR_SQL_TYPES[vecType] ?? "F32_BLOB";
|
|
@@ -1467,7 +1527,12 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1467
1527
|
model_id TEXT NOT NULL
|
|
1468
1528
|
);
|
|
1469
1529
|
`;
|
|
1470
|
-
|
|
1530
|
+
await client.executeMultiple(sql3);
|
|
1531
|
+
if (vecType === "float32") {
|
|
1532
|
+
try {
|
|
1533
|
+
await client.execute(`CREATE INDEX IF NOT EXISTS idx_${tableName}_vec ON ${tableName}(libsql_vector_idx(embedding))`);
|
|
1534
|
+
} catch {}
|
|
1535
|
+
}
|
|
1471
1536
|
},
|
|
1472
1537
|
catch: (cause) => new StoreError({ message: `DbBackend.ensureVectorTable: ${cause}` })
|
|
1473
1538
|
}),
|
|
@@ -1483,6 +1548,24 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1483
1548
|
},
|
|
1484
1549
|
catch: (cause) => new StoreError({ message: `DbBackend.insertVector: ${cause}` })
|
|
1485
1550
|
}),
|
|
1551
|
+
insertVectors: (entries, model) => Effect9.tryPromise({
|
|
1552
|
+
try: async () => {
|
|
1553
|
+
if (entries.length === 0)
|
|
1554
|
+
return;
|
|
1555
|
+
const tableName = vectorTableName(model);
|
|
1556
|
+
const convertFn = VECTOR_CONVERT_FNS[model.vectorType ?? "float32"] ?? "vector32";
|
|
1557
|
+
const values = entries.map(() => `(?, ${convertFn}(?), ?)`).join(", ");
|
|
1558
|
+
const args = [];
|
|
1559
|
+
for (const entry of entries) {
|
|
1560
|
+
args.push(entry.memoryId, JSON.stringify([...entry.vector]), model.id);
|
|
1561
|
+
}
|
|
1562
|
+
return client.execute({
|
|
1563
|
+
sql: `INSERT INTO ${tableName} (memory_id, embedding, model_id) VALUES ${values} ON CONFLICT(memory_id) DO UPDATE SET embedding = excluded.embedding, model_id = excluded.model_id`,
|
|
1564
|
+
args
|
|
1565
|
+
});
|
|
1566
|
+
},
|
|
1567
|
+
catch: (cause) => new StoreError({ message: `DbBackend.insertVectors: ${cause}` })
|
|
1568
|
+
}),
|
|
1486
1569
|
deleteVector: () => Effect9.succeed(undefined),
|
|
1487
1570
|
ensureTopicVectorTable: (model) => Effect9.tryPromise({
|
|
1488
1571
|
try: () => {
|
|
@@ -1510,6 +1593,23 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1510
1593
|
},
|
|
1511
1594
|
catch: (cause) => new StoreError({ message: `DbBackend.upsertTopicVector: ${cause}` })
|
|
1512
1595
|
}),
|
|
1596
|
+
upsertTopicVectors: (entries, model) => Effect9.tryPromise({
|
|
1597
|
+
try: async () => {
|
|
1598
|
+
if (entries.length === 0)
|
|
1599
|
+
return;
|
|
1600
|
+
const tableName = topicVectorTableName(model);
|
|
1601
|
+
const values = entries.map((e) => "(?, vector32(?), ?)").join(", ");
|
|
1602
|
+
const args = [];
|
|
1603
|
+
for (const entry of entries) {
|
|
1604
|
+
args.push(entry.topicKey, JSON.stringify([...entry.sumVector]), model.id);
|
|
1605
|
+
}
|
|
1606
|
+
return client.execute({
|
|
1607
|
+
sql: `INSERT OR REPLACE INTO ${tableName} (topic_key, sum_vector, model_key) VALUES ${values}`,
|
|
1608
|
+
args
|
|
1609
|
+
});
|
|
1610
|
+
},
|
|
1611
|
+
catch: (cause) => new StoreError({ message: `DbBackend.upsertTopicVectors: ${cause}` })
|
|
1612
|
+
}),
|
|
1513
1613
|
deleteTopicVectors: (model) => Effect9.tryPromise({
|
|
1514
1614
|
try: () => {
|
|
1515
1615
|
const tableName = topicVectorTableName(model);
|
|
@@ -1531,6 +1631,20 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1531
1631
|
sumVector: decodeVectorBlob(row.sum_vector)
|
|
1532
1632
|
}));
|
|
1533
1633
|
}),
|
|
1634
|
+
fetchTopicVector: (topicKey, model) => Effect9.gen(function* () {
|
|
1635
|
+
const tableName = topicVectorTableName(model);
|
|
1636
|
+
const rows = yield* Effect9.tryPromise({
|
|
1637
|
+
try: () => client.execute({
|
|
1638
|
+
sql: `SELECT topic_key, sum_vector FROM ${tableName} WHERE topic_key = ?`,
|
|
1639
|
+
args: [topicKey]
|
|
1640
|
+
}).then((rs) => rs.rows),
|
|
1641
|
+
catch: (cause) => new StoreError({ message: `DbBackend.fetchTopicVector: ${cause}` })
|
|
1642
|
+
});
|
|
1643
|
+
const row = rows[0];
|
|
1644
|
+
if (!row)
|
|
1645
|
+
return;
|
|
1646
|
+
return { topicKey: row.topic_key, sumVector: decodeVectorBlob(row.sum_vector) };
|
|
1647
|
+
}),
|
|
1534
1648
|
fetchMemoryVectors: (memoryIds, model) => Effect9.gen(function* () {
|
|
1535
1649
|
if (memoryIds.length === 0)
|
|
1536
1650
|
return [];
|
|
@@ -2124,6 +2238,131 @@ var routeInsert = Effect11.fn("topics.routeInsert")(function* (memoryId, vector,
|
|
|
2124
2238
|
}
|
|
2125
2239
|
return { topicKey, overflow: leafCf.count > (config.maxLeafItems ?? 128) };
|
|
2126
2240
|
});
|
|
2241
|
+
var routeInsertMany = Effect11.fn("topics.routeInsertMany")(function* (entries, model, config) {
|
|
2242
|
+
const violations = validateConfig(config);
|
|
2243
|
+
if (violations.length > 0) {
|
|
2244
|
+
return yield* new InvariantViolation({ topicKey: ROOT_TOPIC_KEY, violations });
|
|
2245
|
+
}
|
|
2246
|
+
for (const entry of entries) {
|
|
2247
|
+
if (entry.vector.length !== model.dimensions) {
|
|
2248
|
+
return yield* new ModelMismatch({
|
|
2249
|
+
expected: `${model.id} (${model.dimensions} dims)`,
|
|
2250
|
+
actual: `${entry.vector.length} dims`
|
|
2251
|
+
});
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
if (entries.length === 0)
|
|
2255
|
+
return [];
|
|
2256
|
+
const backend = yield* Service2;
|
|
2257
|
+
const db = backend.db;
|
|
2258
|
+
const now = yield* Clock.currentTimeMillis;
|
|
2259
|
+
const maxLeafItems = config.maxLeafItems ?? 128;
|
|
2260
|
+
const rootRows = yield* Effect11.tryPromise({
|
|
2261
|
+
try: () => db.select({ topicKey: topics.topicKey }).from(topics).where(and(eq(topics.topicKey, ROOT_TOPIC_KEY), eq(topics.modelKey, model.id))).limit(1),
|
|
2262
|
+
catch: (cause) => cause
|
|
2263
|
+
}).pipe(routingFailure("topics.routeInsertMany"));
|
|
2264
|
+
if (rootRows.length === 0) {
|
|
2265
|
+
return yield* new TopicNotFound({ topicKey: ROOT_TOPIC_KEY });
|
|
2266
|
+
}
|
|
2267
|
+
const vectorRows = yield* backend.fetchTopicVectors(model).pipe(routingFailure("topics.routeInsertMany"));
|
|
2268
|
+
const sumByTopic = new Map(vectorRows.map((r) => [r.topicKey, new Float32Array(r.sumVector)]));
|
|
2269
|
+
const zeros = new Float32Array(model.dimensions);
|
|
2270
|
+
const sumOf = (topicKey) => sumByTopic.get(topicKey) ?? zeros;
|
|
2271
|
+
const result = yield* Effect11.tryPromise({
|
|
2272
|
+
try: () => db.transaction(async (tx) => {
|
|
2273
|
+
const topicRows = await tx.select({
|
|
2274
|
+
topicKey: topics.topicKey,
|
|
2275
|
+
kind: topics.kind,
|
|
2276
|
+
status: topics.status,
|
|
2277
|
+
depth: topics.depth,
|
|
2278
|
+
memberCount: topics.memberCount,
|
|
2279
|
+
sumSquares: topics.sumSquares
|
|
2280
|
+
}).from(topics).where(eq(topics.modelKey, model.id)).orderBy(asc(topics.topicKey));
|
|
2281
|
+
const relations = await tx.select({
|
|
2282
|
+
parentKey: topicRelations.parentKey,
|
|
2283
|
+
childKey: topicRelations.childKey
|
|
2284
|
+
}).from(topicRelations).where(and(eq(topicRelations.modelKey, model.id), eq(topicRelations.relationKind, "parent_child")));
|
|
2285
|
+
const topicByKey = new Map(topicRows.map((r) => [r.topicKey, r]));
|
|
2286
|
+
const childrenByParent = new Map;
|
|
2287
|
+
const parentOf = new Map;
|
|
2288
|
+
for (const rel of relations) {
|
|
2289
|
+
const list = childrenByParent.get(rel.parentKey);
|
|
2290
|
+
if (list)
|
|
2291
|
+
list.push(rel.childKey);
|
|
2292
|
+
else
|
|
2293
|
+
childrenByParent.set(rel.parentKey, [rel.childKey]);
|
|
2294
|
+
parentOf.set(rel.childKey, rel.parentKey);
|
|
2295
|
+
}
|
|
2296
|
+
for (const children of childrenByParent.values()) {
|
|
2297
|
+
children.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
2298
|
+
}
|
|
2299
|
+
const membershipRows = [];
|
|
2300
|
+
const topicDelta = new Map;
|
|
2301
|
+
const outcomes = [];
|
|
2302
|
+
for (const entry of entries) {
|
|
2303
|
+
const x = new Float32Array(entry.vector);
|
|
2304
|
+
const descent = descendTree(topicByKey, childrenByParent, sumOf, x, config);
|
|
2305
|
+
if (!descent.ok)
|
|
2306
|
+
return Promise.reject(descent.error);
|
|
2307
|
+
const topicKey = descent.topicKey;
|
|
2308
|
+
const leafRow = topicByKey.get(topicKey);
|
|
2309
|
+
if (!leafRow) {
|
|
2310
|
+
return Promise.reject(new Error(`topics.routeInsertMany: topic row missing for ${topicKey}`));
|
|
2311
|
+
}
|
|
2312
|
+
const currentSum = sumOf(topicKey);
|
|
2313
|
+
const leafCf = cfInsert({ count: leafRow.memberCount, ls: currentSum, ss: leafRow.sumSquares }, x);
|
|
2314
|
+
leafRow.memberCount = leafCf.count;
|
|
2315
|
+
leafRow.sumSquares = leafCf.ss;
|
|
2316
|
+
sumByTopic.set(topicKey, leafCf.ls);
|
|
2317
|
+
membershipRows.push({
|
|
2318
|
+
topicKey,
|
|
2319
|
+
memoryId: entry.memoryId,
|
|
2320
|
+
modelKey: model.id,
|
|
2321
|
+
updatedAt: now
|
|
2322
|
+
});
|
|
2323
|
+
const acc = topicDelta.get(topicKey);
|
|
2324
|
+
if (acc) {
|
|
2325
|
+
acc.count += 1;
|
|
2326
|
+
acc.ss = leafCf.ss;
|
|
2327
|
+
} else {
|
|
2328
|
+
topicDelta.set(topicKey, { count: 1, ss: leafCf.ss });
|
|
2329
|
+
}
|
|
2330
|
+
let ancestorKey = parentOf.get(topicKey);
|
|
2331
|
+
while (ancestorKey !== undefined) {
|
|
2332
|
+
const row = topicByKey.get(ancestorKey);
|
|
2333
|
+
if (!row) {
|
|
2334
|
+
return Promise.reject(new Error(`topics.routeInsertMany: ancestor row missing for ${ancestorKey}`));
|
|
2335
|
+
}
|
|
2336
|
+
row.memberCount += 1;
|
|
2337
|
+
const ancestorSum = addToSum(sumOf(ancestorKey), x);
|
|
2338
|
+
sumByTopic.set(ancestorKey, ancestorSum);
|
|
2339
|
+
const accA = topicDelta.get(ancestorKey);
|
|
2340
|
+
if (accA)
|
|
2341
|
+
accA.count += 1;
|
|
2342
|
+
else
|
|
2343
|
+
topicDelta.set(ancestorKey, { count: 1, ss: row.sumSquares });
|
|
2344
|
+
ancestorKey = parentOf.get(ancestorKey);
|
|
2345
|
+
}
|
|
2346
|
+
outcomes.push({
|
|
2347
|
+
memoryId: entry.memoryId,
|
|
2348
|
+
topicKey,
|
|
2349
|
+
overflow: leafCf.count > maxLeafItems
|
|
2350
|
+
});
|
|
2351
|
+
}
|
|
2352
|
+
await tx.insert(topicMemberships).values(membershipRows);
|
|
2353
|
+
for (const [key, delta] of topicDelta) {
|
|
2354
|
+
await tx.update(topics).set({ memberCount: delta.count, sumSquares: delta.ss, updatedAt: now }).where(and(eq(topics.topicKey, key), eq(topics.modelKey, model.id)));
|
|
2355
|
+
}
|
|
2356
|
+
return { outcomes, topicDelta };
|
|
2357
|
+
}),
|
|
2358
|
+
catch: (cause) => cause
|
|
2359
|
+
}).pipe(routingFailure("topics.routeInsertMany"));
|
|
2360
|
+
yield* backend.upsertTopicVectors(Array.from(result.topicDelta, ([topicKey]) => ({
|
|
2361
|
+
topicKey,
|
|
2362
|
+
sumVector: Array.from(sumByTopic.get(topicKey) ?? zeros)
|
|
2363
|
+
})), model).pipe(routingFailure("topics.routeInsertMany"));
|
|
2364
|
+
return result.outcomes;
|
|
2365
|
+
});
|
|
2127
2366
|
|
|
2128
2367
|
// ../store/src/topics/query.ts
|
|
2129
2368
|
var DEFAULT_BEAM_WIDTH = 3;
|
|
@@ -2219,7 +2458,7 @@ var resolveTopics = Effect12.fn("topics.resolveTopics")(function* (queryVector,
|
|
|
2219
2458
|
});
|
|
2220
2459
|
|
|
2221
2460
|
// ../store/src/topics/lifecycle.ts
|
|
2222
|
-
import { Clock as Clock3, Effect as
|
|
2461
|
+
import { Clock as Clock3, Effect as Effect22 } from "effect";
|
|
2223
2462
|
import { and as and3, eq as eq3, inArray, ne } from "drizzle-orm";
|
|
2224
2463
|
|
|
2225
2464
|
// ../workflow/src/queue.ts
|
|
@@ -2368,7 +2607,18 @@ var queues = [
|
|
|
2368
2607
|
AuditWrite
|
|
2369
2608
|
];
|
|
2370
2609
|
// ../workflow/src/runtime.ts
|
|
2371
|
-
import {
|
|
2610
|
+
import {
|
|
2611
|
+
Cause as Cause2,
|
|
2612
|
+
Clock as Clock2,
|
|
2613
|
+
Context as Context7,
|
|
2614
|
+
Deferred as Deferred2,
|
|
2615
|
+
Duration as Duration2,
|
|
2616
|
+
Effect as Effect19,
|
|
2617
|
+
Exit as Exit6,
|
|
2618
|
+
Layer as Layer7,
|
|
2619
|
+
Option as Option5,
|
|
2620
|
+
Schema as Schema14
|
|
2621
|
+
} from "effect";
|
|
2372
2622
|
import { WorkflowEngine as WorkflowEngine3 } from "effect/unstable/workflow";
|
|
2373
2623
|
import { PersistedQueue as PersistedQueue3, Persistence as PersistenceNamespace3 } from "effect/unstable/persistence";
|
|
2374
2624
|
|
|
@@ -2458,8 +2708,37 @@ var readWorkflowResult = (store, workflow, executionId) => Effect14.gen(function
|
|
|
2458
2708
|
return Option2.none();
|
|
2459
2709
|
});
|
|
2460
2710
|
|
|
2711
|
+
// ../workflow/src/signals.ts
|
|
2712
|
+
import { Deferred, Effect as Effect15, Exit as Exit2 } from "effect";
|
|
2713
|
+
var listeners = new Map;
|
|
2714
|
+
var onExecutionDone = (executionId, deferred) => {
|
|
2715
|
+
let set = listeners.get(executionId);
|
|
2716
|
+
if (set === undefined) {
|
|
2717
|
+
set = new Set;
|
|
2718
|
+
listeners.set(executionId, set);
|
|
2719
|
+
}
|
|
2720
|
+
set.add(deferred);
|
|
2721
|
+
};
|
|
2722
|
+
var offExecutionDone = (executionId, deferred) => {
|
|
2723
|
+
const set = listeners.get(executionId);
|
|
2724
|
+
if (set === undefined)
|
|
2725
|
+
return;
|
|
2726
|
+
set.delete(deferred);
|
|
2727
|
+
if (set.size === 0)
|
|
2728
|
+
listeners.delete(executionId);
|
|
2729
|
+
};
|
|
2730
|
+
var notifyExecutionDone = (executionId) => {
|
|
2731
|
+
const set = listeners.get(executionId);
|
|
2732
|
+
if (set === undefined)
|
|
2733
|
+
return;
|
|
2734
|
+
listeners.delete(executionId);
|
|
2735
|
+
for (const deferred of set) {
|
|
2736
|
+
Effect15.runFork(Deferred.done(deferred, Exit2.void));
|
|
2737
|
+
}
|
|
2738
|
+
};
|
|
2739
|
+
|
|
2461
2740
|
// ../workflow/src/engine.ts
|
|
2462
|
-
import { Effect as
|
|
2741
|
+
import { Effect as Effect18, Exit as Exit5, Fiber, FiberMap, Layer as Layer6, Option as Option4, Schema as Schema13 } from "effect";
|
|
2463
2742
|
import { Workflow as Workflow3, WorkflowEngine as WorkflowEngine2 } from "effect/unstable/workflow";
|
|
2464
2743
|
import { Persistence as PersistenceNamespace2, PersistedQueue as PersistedQueue2 } from "effect/unstable/persistence";
|
|
2465
2744
|
|
|
@@ -2468,8 +2747,8 @@ import {
|
|
|
2468
2747
|
Cause,
|
|
2469
2748
|
Data,
|
|
2470
2749
|
Duration,
|
|
2471
|
-
Effect as
|
|
2472
|
-
Exit as
|
|
2750
|
+
Effect as Effect16,
|
|
2751
|
+
Exit as Exit3,
|
|
2473
2752
|
Latch,
|
|
2474
2753
|
Layer as Layer4,
|
|
2475
2754
|
MutableRef,
|
|
@@ -2482,7 +2761,7 @@ import { SqlClient } from "effect/unstable/sql";
|
|
|
2482
2761
|
|
|
2483
2762
|
class QueueKey extends Data.Class {
|
|
2484
2763
|
}
|
|
2485
|
-
var makeStore =
|
|
2764
|
+
var makeStore = Effect16.fnUntraced(function* (options) {
|
|
2486
2765
|
const sql3 = (yield* SqlClient.SqlClient).withoutTransforms();
|
|
2487
2766
|
const tableName = options?.tableName ?? "effect_queue";
|
|
2488
2767
|
const tableNameSql = sql3(tableName);
|
|
@@ -2515,16 +2794,16 @@ var makeStore = Effect15.fnUntraced(function* (options) {
|
|
|
2515
2794
|
VALUES (${id}, ${name}, ${element}, FALSE, 0, ${sqlNow}, ${sqlNow})
|
|
2516
2795
|
`;
|
|
2517
2796
|
const elementIds = new Set;
|
|
2518
|
-
const refreshLocks =
|
|
2797
|
+
const refreshLocks = Effect16.suspend(() => {
|
|
2519
2798
|
if (elementIds.size === 0)
|
|
2520
|
-
return
|
|
2799
|
+
return Effect16.void;
|
|
2521
2800
|
const ids = Array.from(elementIds);
|
|
2522
2801
|
return sql3`
|
|
2523
2802
|
UPDATE ${tableNameSql}
|
|
2524
2803
|
SET acquired_at = ${sqlNow}
|
|
2525
2804
|
WHERE sequence IN (${sql3.literal(ids.join(","))})
|
|
2526
2805
|
AND acquired_by = ${workerIdSql}
|
|
2527
|
-
`.pipe(
|
|
2806
|
+
`.pipe(Effect16.asVoid);
|
|
2528
2807
|
});
|
|
2529
2808
|
const complete = (sequence, attempts) => {
|
|
2530
2809
|
elementIds.delete(sequence);
|
|
@@ -2533,7 +2812,7 @@ var makeStore = Effect15.fnUntraced(function* (options) {
|
|
|
2533
2812
|
SET acquired_at = NULL, acquired_by = NULL, updated_at = ${sqlNow}, completed = ${sqlTrue}, attempts = ${attempts}
|
|
2534
2813
|
WHERE sequence = ${sequence}
|
|
2535
2814
|
AND acquired_by = ${workerIdSql}
|
|
2536
|
-
`.pipe(
|
|
2815
|
+
`.pipe(Effect16.retry({ times: 5, schedule: Schedule.exponential(100, 1.5) }), Effect16.orDie);
|
|
2537
2816
|
};
|
|
2538
2817
|
const retry = (sequence, attempts, cause) => {
|
|
2539
2818
|
elementIds.delete(sequence);
|
|
@@ -2542,33 +2821,33 @@ var makeStore = Effect15.fnUntraced(function* (options) {
|
|
|
2542
2821
|
SET acquired_at = NULL, acquired_by = NULL, updated_at = ${sqlNow}, attempts = ${attempts}, last_failure = ${Cause.pretty(cause)}
|
|
2543
2822
|
WHERE sequence = ${sequence}
|
|
2544
2823
|
AND acquired_by = ${workerIdSql}
|
|
2545
|
-
`.pipe(
|
|
2824
|
+
`.pipe(Effect16.retry({ times: 5, schedule: Schedule.exponential(100, 1.5) }), Effect16.orDie);
|
|
2546
2825
|
};
|
|
2547
2826
|
const interrupt = (ids) => {
|
|
2548
2827
|
for (const id of ids)
|
|
2549
2828
|
elementIds.delete(id);
|
|
2550
2829
|
if (ids.length === 0)
|
|
2551
|
-
return
|
|
2830
|
+
return Effect16.void;
|
|
2552
2831
|
return sql3`
|
|
2553
2832
|
UPDATE ${tableNameSql}
|
|
2554
2833
|
SET acquired_at = NULL, acquired_by = NULL
|
|
2555
2834
|
WHERE sequence IN (${sql3.literal(ids.join(","))})
|
|
2556
2835
|
AND acquired_by = ${workerIdSql}
|
|
2557
|
-
`.pipe(
|
|
2836
|
+
`.pipe(Effect16.retry({ times: 5, schedule: Schedule.exponential(100, 1.5) }), Effect16.orDie);
|
|
2558
2837
|
};
|
|
2559
|
-
yield* refreshLocks.pipe(
|
|
2838
|
+
yield* refreshLocks.pipe(Effect16.tapCause(Effect16.logWarning), Effect16.retry(Schedule.spaced(500)), Effect16.schedule(Schedule.fixed(lockRefreshInterval)), Effect16.annotateLogs({
|
|
2560
2839
|
package: "@dimple/workflow",
|
|
2561
2840
|
module: "QueueStore",
|
|
2562
2841
|
fiber: "refreshLocks"
|
|
2563
|
-
}),
|
|
2842
|
+
}), Effect16.forkScoped);
|
|
2564
2843
|
const mailboxes = yield* RcMap.make({
|
|
2565
|
-
lookup:
|
|
2844
|
+
lookup: Effect16.fnUntraced(function* ({ maxAttempts, name }) {
|
|
2566
2845
|
const queue = yield* Queue.make();
|
|
2567
2846
|
const takers = MutableRef.make(0);
|
|
2568
2847
|
const pollLatch = Latch.makeUnsafe();
|
|
2569
2848
|
const takenLatch = Latch.makeUnsafe();
|
|
2570
|
-
yield*
|
|
2571
|
-
const poll = (size) =>
|
|
2849
|
+
yield* Effect16.addFinalizer(() => Effect16.flatMap(Queue.clear(queue), (elements) => elements.length === 0 ? Effect16.void : interrupt(Array.from(elements, (e) => e.sequence))));
|
|
2850
|
+
const poll = (size) => Effect16.suspend(() => sql3`
|
|
2572
2851
|
UPDATE ${tableNameSql}
|
|
2573
2852
|
SET acquired_at = ${sqlNow}, acquired_by = ${workerIdSql}
|
|
2574
2853
|
WHERE queue_name = ${name}
|
|
@@ -2576,14 +2855,14 @@ var makeStore = Effect15.fnUntraced(function* (options) {
|
|
|
2576
2855
|
AND attempts < ${maxAttempts}
|
|
2577
2856
|
AND (acquired_at IS NULL OR acquired_at < ${expiresAt})
|
|
2578
2857
|
RETURNING sequence, id, queue_name, element, attempts
|
|
2579
|
-
`.pipe(
|
|
2580
|
-
yield*
|
|
2858
|
+
`.pipe(Effect16.map((rows) => rows)));
|
|
2859
|
+
yield* Effect16.gen(function* () {
|
|
2581
2860
|
while (true) {
|
|
2582
2861
|
yield* pollLatch.await;
|
|
2583
|
-
yield*
|
|
2862
|
+
yield* Effect16.yieldNow;
|
|
2584
2863
|
const results = takers.current === 0 ? [] : yield* poll(takers.current);
|
|
2585
2864
|
if (results.length === 0) {
|
|
2586
|
-
yield*
|
|
2865
|
+
yield* Effect16.sleep(pollInterval);
|
|
2587
2866
|
continue;
|
|
2588
2867
|
}
|
|
2589
2868
|
takenLatch.closeUnsafe();
|
|
@@ -2592,24 +2871,24 @@ var makeStore = Effect15.fnUntraced(function* (options) {
|
|
|
2592
2871
|
}
|
|
2593
2872
|
yield* Queue.offerAll(queue, results);
|
|
2594
2873
|
yield* takenLatch.await;
|
|
2595
|
-
yield*
|
|
2874
|
+
yield* Effect16.yieldNow;
|
|
2596
2875
|
}
|
|
2597
|
-
}).pipe(
|
|
2876
|
+
}).pipe(Effect16.sandbox, Effect16.retry(Schedule.spaced(500)), Effect16.forkScoped, Effect16.interruptible);
|
|
2598
2877
|
return { queue, takers, pollLatch, takenLatch };
|
|
2599
2878
|
}),
|
|
2600
2879
|
idleTimeToLive: Duration.seconds(30)
|
|
2601
2880
|
});
|
|
2602
2881
|
return PersistedQueue.PersistedQueueStore.of({
|
|
2603
|
-
offer: ({ element, id, name }) =>
|
|
2882
|
+
offer: ({ element, id, name }) => Effect16.catchCause(Effect16.suspend(() => offer(id, name, JSON.stringify(element))), (cause) => Effect16.fail(new PersistedQueue.PersistedQueueError({
|
|
2604
2883
|
message: "Failed to offer element to persisted queue",
|
|
2605
2884
|
cause
|
|
2606
2885
|
}))),
|
|
2607
|
-
take: ({ maxAttempts, name }) =>
|
|
2886
|
+
take: ({ maxAttempts, name }) => Effect16.uninterruptibleMask((restore) => RcMap.get(mailboxes, new QueueKey({ name, maxAttempts })).pipe(Effect16.flatMap(({ pollLatch, queue, takenLatch, takers }) => {
|
|
2608
2887
|
takers.current++;
|
|
2609
2888
|
if (takers.current === 1) {
|
|
2610
2889
|
pollLatch.openUnsafe();
|
|
2611
2890
|
}
|
|
2612
|
-
return
|
|
2891
|
+
return Effect16.tap(restore(Queue.take(queue)), () => Effect16.sync(() => {
|
|
2613
2892
|
takers.current--;
|
|
2614
2893
|
if (takers.current === 0) {
|
|
2615
2894
|
pollLatch.closeUnsafe();
|
|
@@ -2618,10 +2897,10 @@ var makeStore = Effect15.fnUntraced(function* (options) {
|
|
|
2618
2897
|
takenLatch.openUnsafe();
|
|
2619
2898
|
}
|
|
2620
2899
|
}));
|
|
2621
|
-
}),
|
|
2900
|
+
}), Effect16.scoped, restore, Effect16.tap((element) => Effect16.addFinalizer(Exit3.match({
|
|
2622
2901
|
onFailure: (cause) => Cause.hasInterruptsOnly(cause) ? interrupt([element.sequence]) : retry(element.sequence, element.attempts + 1, cause),
|
|
2623
2902
|
onSuccess: () => complete(element.sequence, element.attempts + 1)
|
|
2624
|
-
}))),
|
|
2903
|
+
}))), Effect16.map((element) => ({ ...element, element: JSON.parse(element.element) }))))
|
|
2625
2904
|
});
|
|
2626
2905
|
});
|
|
2627
2906
|
var storeSqliteLayer = Layer4.effect(PersistedQueue.PersistedQueueStore, makeStore());
|
|
@@ -2638,8 +2917,8 @@ __export(exports_LibsqlClient, {
|
|
|
2638
2917
|
import * as Libsql from "@libsql/client";
|
|
2639
2918
|
import * as Config3 from "effect/Config";
|
|
2640
2919
|
import * as Context6 from "effect/Context";
|
|
2641
|
-
import * as
|
|
2642
|
-
import * as
|
|
2920
|
+
import * as Effect17 from "effect/Effect";
|
|
2921
|
+
import * as Exit4 from "effect/Exit";
|
|
2643
2922
|
import * as Layer5 from "effect/Layer";
|
|
2644
2923
|
import * as Option3 from "effect/Option";
|
|
2645
2924
|
import * as Redacted from "effect/Redacted";
|
|
@@ -2658,7 +2937,7 @@ var classifyError = (cause, message, operation) => classifySqliteError(cause, {
|
|
|
2658
2937
|
var TypeId = "~@effect/sql-libsql/LibsqlClient";
|
|
2659
2938
|
var LibsqlClient = /* @__PURE__ */ Context6.Service("@effect/sql-libsql/LibsqlClient");
|
|
2660
2939
|
var LibsqlTransaction = /* @__PURE__ */ Context6.Service("@effect/sql-libsql/LibsqlClient/LibsqlTransaction");
|
|
2661
|
-
var make4 = (options) =>
|
|
2940
|
+
var make4 = (options) => Effect17.gen(function* () {
|
|
2662
2941
|
const compiler = Statement.makeCompilerSqlite(options.transformQueryNames);
|
|
2663
2942
|
const transformRows = options.transformResultNames ? Statement.defaultTransforms(options.transformResultNames).array : undefined;
|
|
2664
2943
|
const spanAttributes = [...options.spanAttributes ? Object.entries(options.spanAttributes) : [], [ATTR_DB_SYSTEM_NAME, "sqlite"]];
|
|
@@ -2669,7 +2948,7 @@ var make4 = (options) => Effect16.gen(function* () {
|
|
|
2669
2948
|
this.sdk = sdk;
|
|
2670
2949
|
}
|
|
2671
2950
|
run(sql3, params = []) {
|
|
2672
|
-
return
|
|
2951
|
+
return Effect17.map(Effect17.tryPromise({
|
|
2673
2952
|
try: () => this.sdk.execute({
|
|
2674
2953
|
sql: sql3,
|
|
2675
2954
|
args: params
|
|
@@ -2680,7 +2959,7 @@ var make4 = (options) => Effect16.gen(function* () {
|
|
|
2680
2959
|
}), (results) => results.rows);
|
|
2681
2960
|
}
|
|
2682
2961
|
runRaw(sql3, params = []) {
|
|
2683
|
-
return
|
|
2962
|
+
return Effect17.tryPromise({
|
|
2684
2963
|
try: () => this.sdk.execute({
|
|
2685
2964
|
sql: sql3,
|
|
2686
2965
|
args: params
|
|
@@ -2691,13 +2970,13 @@ var make4 = (options) => Effect16.gen(function* () {
|
|
|
2691
2970
|
});
|
|
2692
2971
|
}
|
|
2693
2972
|
execute(sql3, params, transformRows2) {
|
|
2694
|
-
return transformRows2 ?
|
|
2973
|
+
return transformRows2 ? Effect17.map(this.run(sql3, params), transformRows2) : this.run(sql3, params);
|
|
2695
2974
|
}
|
|
2696
2975
|
executeRaw(sql3, params) {
|
|
2697
2976
|
return this.runRaw(sql3, params);
|
|
2698
2977
|
}
|
|
2699
2978
|
executeValues(sql3, params) {
|
|
2700
|
-
return
|
|
2979
|
+
return Effect17.map(this.run(sql3, params), (rows) => rows.map((row) => Array.from(row)));
|
|
2701
2980
|
}
|
|
2702
2981
|
executeValuesUnprepared(sql3, params) {
|
|
2703
2982
|
return this.executeValues(sql3, params);
|
|
@@ -2709,7 +2988,7 @@ var make4 = (options) => Effect16.gen(function* () {
|
|
|
2709
2988
|
return Stream.die("executeStream not implemented");
|
|
2710
2989
|
}
|
|
2711
2990
|
get beginTransaction() {
|
|
2712
|
-
return
|
|
2991
|
+
return Effect17.map(Effect17.tryPromise({
|
|
2713
2992
|
try: () => this.sdk.transaction("write"),
|
|
2714
2993
|
catch: (cause) => new SqlError2({
|
|
2715
2994
|
reason: classifyError(cause, "Failed to begin transaction", "beginTransaction")
|
|
@@ -2717,7 +2996,7 @@ var make4 = (options) => Effect16.gen(function* () {
|
|
|
2717
2996
|
}), (tx) => new LibsqlConnectionImpl(tx));
|
|
2718
2997
|
}
|
|
2719
2998
|
get commit() {
|
|
2720
|
-
return
|
|
2999
|
+
return Effect17.tryPromise({
|
|
2721
3000
|
try: () => this.sdk.commit(),
|
|
2722
3001
|
catch: (cause) => new SqlError2({
|
|
2723
3002
|
reason: classifyError(cause, "Failed to commit transaction", "commitTransaction")
|
|
@@ -2725,7 +3004,7 @@ var make4 = (options) => Effect16.gen(function* () {
|
|
|
2725
3004
|
});
|
|
2726
3005
|
}
|
|
2727
3006
|
get rollback() {
|
|
2728
|
-
return
|
|
3007
|
+
return Effect17.tryPromise({
|
|
2729
3008
|
try: () => this.sdk.rollback(),
|
|
2730
3009
|
catch: (cause) => new SqlError2({
|
|
2731
3010
|
reason: classifyError(cause, "Failed to rollback transaction", "rollbackTransaction")
|
|
@@ -2733,33 +3012,33 @@ var make4 = (options) => Effect16.gen(function* () {
|
|
|
2733
3012
|
});
|
|
2734
3013
|
}
|
|
2735
3014
|
}
|
|
2736
|
-
const connection = "liveClient" in options ? new LibsqlConnectionImpl(options.liveClient) : yield*
|
|
3015
|
+
const connection = "liveClient" in options ? new LibsqlConnectionImpl(options.liveClient) : yield* Effect17.map(Effect17.acquireRelease(Effect17.sync(() => Libsql.createClient({
|
|
2737
3016
|
...options,
|
|
2738
3017
|
authToken: Redacted.isRedacted(options.authToken) ? Redacted.value(options.authToken) : options.authToken,
|
|
2739
3018
|
encryptionKey: Redacted.isRedacted(options.encryptionKey) ? Redacted.value(options.encryptionKey) : options.encryptionKey,
|
|
2740
3019
|
url: options.url.toString(),
|
|
2741
3020
|
syncUrl: options.syncUrl?.toString()
|
|
2742
|
-
})), (sdk) =>
|
|
3021
|
+
})), (sdk) => Effect17.sync(() => sdk.close())), (sdk) => new LibsqlConnectionImpl(sdk));
|
|
2743
3022
|
const semaphore = yield* Semaphore.make(1);
|
|
2744
3023
|
const withTransaction = Client.makeWithTransaction({
|
|
2745
3024
|
transactionService: LibsqlTransaction,
|
|
2746
3025
|
spanAttributes,
|
|
2747
|
-
acquireConnection:
|
|
3026
|
+
acquireConnection: Effect17.uninterruptibleMask(Effect17.fnUntraced(function* (restore) {
|
|
2748
3027
|
const scope = Scope3.makeUnsafe();
|
|
2749
3028
|
yield* restore(semaphore.take(1));
|
|
2750
3029
|
yield* Scope3.addFinalizer(scope, semaphore.release(1));
|
|
2751
|
-
const conn = yield* connection.beginTransaction.pipe(
|
|
3030
|
+
const conn = yield* connection.beginTransaction.pipe(Effect17.tapCause((cause) => Scope3.close(scope, Exit4.failCause(cause))));
|
|
2752
3031
|
return [scope, conn];
|
|
2753
3032
|
})),
|
|
2754
|
-
begin: () =>
|
|
3033
|
+
begin: () => Effect17.void,
|
|
2755
3034
|
savepoint: (conn, id) => conn.executeRaw(`SAVEPOINT effect_sql_${id};`, []),
|
|
2756
3035
|
commit: (conn) => conn.commit,
|
|
2757
3036
|
rollback: (conn) => conn.rollback,
|
|
2758
3037
|
rollbackSavepoint: (conn, id) => conn.executeRaw(`ROLLBACK TO SAVEPOINT effect_sql_${id};`, [])
|
|
2759
3038
|
});
|
|
2760
|
-
const acquirer =
|
|
2761
|
-
onNone: () => semaphore.withPermits(1)(
|
|
2762
|
-
onSome: ([conn]) =>
|
|
3039
|
+
const acquirer = Effect17.flatMap(Effect17.serviceOption(LibsqlTransaction), Option3.match({
|
|
3040
|
+
onNone: () => semaphore.withPermits(1)(Effect17.succeed(connection)),
|
|
3041
|
+
onSome: ([conn]) => Effect17.succeed(conn)
|
|
2763
3042
|
}));
|
|
2764
3043
|
return Object.assign(yield* Client.make({
|
|
2765
3044
|
acquirer,
|
|
@@ -2773,21 +3052,21 @@ var make4 = (options) => Effect16.gen(function* () {
|
|
|
2773
3052
|
sdk: connection.sdk
|
|
2774
3053
|
});
|
|
2775
3054
|
});
|
|
2776
|
-
var layerConfig2 = (config) => Layer5.effectContext(Config3.unwrap(config).pipe(
|
|
2777
|
-
var layer5 = (config) => Layer5.effectContext(
|
|
3055
|
+
var layerConfig2 = (config) => Layer5.effectContext(Config3.unwrap(config).pipe(Effect17.flatMap(make4), Effect17.map((client) => Context6.make(LibsqlClient, client).pipe(Context6.add(Client.SqlClient, client))))).pipe(Layer5.provide(Reactivity.layer));
|
|
3056
|
+
var layer5 = (config) => Layer5.effectContext(Effect17.map(make4(config), (client) => Context6.make(LibsqlClient, client).pipe(Context6.add(Client.SqlClient, client)))).pipe(Layer5.provide(Reactivity.layer));
|
|
2778
3057
|
// ../workflow/src/engine.ts
|
|
2779
3058
|
var Persistence = PersistenceNamespace2.Persistence;
|
|
2780
3059
|
var PersistedQueueFactory = PersistedQueue2.PersistedQueueFactory;
|
|
2781
|
-
var layerDurable = Layer6.effect(WorkflowEngine2.WorkflowEngine)(
|
|
3060
|
+
var layerDurable = Layer6.effect(WorkflowEngine2.WorkflowEngine)(Effect18.gen(function* () {
|
|
2782
3061
|
const persistence = yield* Persistence;
|
|
2783
3062
|
const queueFactory = yield* PersistedQueueFactory;
|
|
2784
|
-
const scope = yield*
|
|
3063
|
+
const scope = yield* Effect18.scope;
|
|
2785
3064
|
const store = yield* persistence.make({ storeId: STORE_ID });
|
|
2786
3065
|
const resumeQueue = yield* queueFactory.make({ name: RESUME_QUEUE, schema: ResumeSignal });
|
|
2787
3066
|
const workflows = new Map;
|
|
2788
3067
|
const executions = new Map;
|
|
2789
3068
|
const clocks = yield* FiberMap.make();
|
|
2790
|
-
const resume = (state) =>
|
|
3069
|
+
const resume = (state) => Effect18.gen(function* () {
|
|
2791
3070
|
const exit = state.fiber?.pollUnsafe();
|
|
2792
3071
|
if (exit && exit._tag === "Success" && exit.value._tag === "Complete")
|
|
2793
3072
|
return;
|
|
@@ -2799,31 +3078,32 @@ var layerDurable = Layer6.effect(WorkflowEngine2.WorkflowEngine)(Effect17.gen(fu
|
|
|
2799
3078
|
const instance = WorkflowEngine2.WorkflowInstance.initial(state.instance.workflow, state.instance.executionId);
|
|
2800
3079
|
instance.interrupted = state.instance.interrupted;
|
|
2801
3080
|
state.instance = instance;
|
|
2802
|
-
state.fiber = yield* state.execute(state.payload, state.instance.executionId).pipe(
|
|
3081
|
+
state.fiber = yield* state.execute(state.payload, state.instance.executionId).pipe(Effect18.onExit(() => {
|
|
2803
3082
|
if (!instance.interrupted)
|
|
2804
|
-
return
|
|
3083
|
+
return Effect18.void;
|
|
2805
3084
|
instance.suspended = false;
|
|
2806
|
-
return
|
|
2807
|
-
}), Workflow3.intoResult,
|
|
3085
|
+
return Effect18.withFiber((fiber) => Effect18.interruptible(Fiber.interrupt(fiber)));
|
|
3086
|
+
}), Workflow3.intoResult, Effect18.provideService(WorkflowEngine2.WorkflowInstance, instance), Effect18.provideService(WorkflowEngine2.WorkflowEngine, engine), Effect18.tap((result) => {
|
|
2808
3087
|
if (result._tag !== "Complete")
|
|
2809
|
-
return
|
|
2810
|
-
return
|
|
3088
|
+
return Effect18.void;
|
|
3089
|
+
return Effect18.gen(function* () {
|
|
2811
3090
|
const entry2 = workflows.get(state.instance.workflow._tag);
|
|
2812
3091
|
if (!entry2)
|
|
2813
3092
|
return;
|
|
2814
|
-
const encoded = yield*
|
|
2815
|
-
yield* setEncodedExit(store, resultKey(state.instance.executionId),
|
|
3093
|
+
const encoded = yield* Effect18.orDie(Schema13.encodeEffect(resultCodecFor(entry2.workflow))(result));
|
|
3094
|
+
yield* setEncodedExit(store, resultKey(state.instance.executionId), Exit5.succeed(encoded));
|
|
3095
|
+
notifyExecutionDone(state.instance.executionId);
|
|
2816
3096
|
});
|
|
2817
|
-
}),
|
|
3097
|
+
}), Effect18.tap((result) => {
|
|
2818
3098
|
if (!state.parent || result._tag !== "Complete")
|
|
2819
|
-
return
|
|
3099
|
+
return Effect18.void;
|
|
2820
3100
|
const parent = executions.get(state.parent);
|
|
2821
3101
|
if (parent)
|
|
2822
|
-
return
|
|
2823
|
-
return
|
|
2824
|
-
}),
|
|
3102
|
+
return Effect18.forkIn(resume(parent), scope);
|
|
3103
|
+
return Effect18.void;
|
|
3104
|
+
}), Effect18.forkIn(entry.scope));
|
|
2825
3105
|
});
|
|
2826
|
-
const resumeExecution = (executionId) =>
|
|
3106
|
+
const resumeExecution = (executionId) => Effect18.gen(function* () {
|
|
2827
3107
|
const state = executions.get(executionId);
|
|
2828
3108
|
if (state) {
|
|
2829
3109
|
yield* resume(state);
|
|
@@ -2846,22 +3126,22 @@ var layerDurable = Layer6.effect(WorkflowEngine2.WorkflowEngine)(Effect17.gen(fu
|
|
|
2846
3126
|
}
|
|
2847
3127
|
});
|
|
2848
3128
|
const engine = WorkflowEngine2.makeUnsafe({
|
|
2849
|
-
register:
|
|
3129
|
+
register: Effect18.fnUntraced(function* (workflow, execute) {
|
|
2850
3130
|
workflows.set(workflow._tag, {
|
|
2851
3131
|
workflow,
|
|
2852
3132
|
execute,
|
|
2853
|
-
scope: yield*
|
|
3133
|
+
scope: yield* Effect18.scope
|
|
2854
3134
|
});
|
|
2855
3135
|
}),
|
|
2856
3136
|
execute: executeEncoded(workflows, executions, store, resume),
|
|
2857
|
-
interrupt:
|
|
3137
|
+
interrupt: Effect18.fnUntraced(function* (_workflow, executionId) {
|
|
2858
3138
|
const state = executions.get(executionId);
|
|
2859
3139
|
if (!state)
|
|
2860
3140
|
return;
|
|
2861
3141
|
state.instance.interrupted = true;
|
|
2862
3142
|
yield* resume(state);
|
|
2863
3143
|
}),
|
|
2864
|
-
interruptUnsafe:
|
|
3144
|
+
interruptUnsafe: Effect18.fnUntraced(function* (_workflow, executionId) {
|
|
2865
3145
|
const state = executions.get(executionId);
|
|
2866
3146
|
if (!state)
|
|
2867
3147
|
return;
|
|
@@ -2871,36 +3151,36 @@ var layerDurable = Layer6.effect(WorkflowEngine2.WorkflowEngine)(Effect17.gen(fu
|
|
|
2871
3151
|
}
|
|
2872
3152
|
}),
|
|
2873
3153
|
resume: (_workflow, executionId) => resumeExecution(executionId),
|
|
2874
|
-
activityExecute:
|
|
3154
|
+
activityExecute: Effect18.fnUntraced(function* (activity, attempt) {
|
|
2875
3155
|
const instance = yield* WorkflowEngine2.WorkflowInstance;
|
|
2876
3156
|
const key = activityKey(instance.executionId, activity.name, attempt);
|
|
2877
3157
|
const persisted = yield* getEncodedExit(store, key);
|
|
2878
|
-
if (persisted &&
|
|
3158
|
+
if (persisted && Exit5.isSuccess(persisted)) {
|
|
2879
3159
|
const entry = workflows.get(instance.workflow._tag);
|
|
2880
3160
|
if (!entry)
|
|
2881
|
-
return yield*
|
|
2882
|
-
return yield*
|
|
3161
|
+
return yield* Effect18.die(`activity replay: unknown workflow ${instance.workflow._tag}`);
|
|
3162
|
+
return yield* Effect18.orDie(Schema13.decodeUnknownEffect(resultCodecFor(entry.workflow))(persisted.value));
|
|
2883
3163
|
}
|
|
2884
3164
|
const activityInstance = WorkflowEngine2.WorkflowInstance.initial(instance.workflow, instance.executionId);
|
|
2885
3165
|
activityInstance.interrupted = instance.interrupted;
|
|
2886
|
-
const result = yield* activity.executeEncoded.pipe(Workflow3.intoResult,
|
|
3166
|
+
const result = yield* activity.executeEncoded.pipe(Workflow3.intoResult, Effect18.provideService(WorkflowEngine2.WorkflowInstance, activityInstance), Effect18.exit);
|
|
2887
3167
|
if (result._tag === "Success" && result.value._tag !== "Suspended") {
|
|
2888
3168
|
const entry = workflows.get(instance.workflow._tag);
|
|
2889
3169
|
if (entry) {
|
|
2890
|
-
const encoded = yield*
|
|
2891
|
-
yield* setEncodedExit(store, key,
|
|
3170
|
+
const encoded = yield* Effect18.orDie(Schema13.encodeEffect(resultCodecFor(entry.workflow))(result.value));
|
|
3171
|
+
yield* setEncodedExit(store, key, Exit5.succeed(encoded));
|
|
2892
3172
|
}
|
|
2893
3173
|
}
|
|
2894
3174
|
return yield* result;
|
|
2895
3175
|
}),
|
|
2896
|
-
poll: (_workflow, executionId) =>
|
|
3176
|
+
poll: (_workflow, executionId) => Effect18.gen(function* () {
|
|
2897
3177
|
const state = executions.get(executionId);
|
|
2898
3178
|
if (!state) {
|
|
2899
3179
|
const persisted = yield* getEncodedExit(store, resultKey(executionId));
|
|
2900
|
-
if (persisted &&
|
|
3180
|
+
if (persisted && Exit5.isSuccess(persisted)) {
|
|
2901
3181
|
const workflow = yield* workflowTagFor(workflows, store, executionId);
|
|
2902
3182
|
if (workflow) {
|
|
2903
|
-
return Option4.some(yield*
|
|
3183
|
+
return Option4.some(yield* Effect18.orDie(Schema13.decodeUnknownEffect(resultCodecFor(workflow))(persisted.value)));
|
|
2904
3184
|
}
|
|
2905
3185
|
}
|
|
2906
3186
|
return Option4.none();
|
|
@@ -2910,9 +3190,9 @@ var layerDurable = Layer6.effect(WorkflowEngine2.WorkflowEngine)(Effect17.gen(fu
|
|
|
2910
3190
|
return Option4.none();
|
|
2911
3191
|
if (exit._tag === "Success")
|
|
2912
3192
|
return Option4.some(exit.value);
|
|
2913
|
-
return yield*
|
|
3193
|
+
return yield* Effect18.die(exit.cause);
|
|
2914
3194
|
}),
|
|
2915
|
-
deferredResult:
|
|
3195
|
+
deferredResult: Effect18.fnUntraced(function* (deferred) {
|
|
2916
3196
|
const instance = yield* WorkflowEngine2.WorkflowInstance;
|
|
2917
3197
|
const persisted = yield* getEncodedExit(store, deferredKey(instance.executionId, deferred.name));
|
|
2918
3198
|
if (persisted) {
|
|
@@ -2920,26 +3200,26 @@ var layerDurable = Layer6.effect(WorkflowEngine2.WorkflowEngine)(Effect17.gen(fu
|
|
|
2920
3200
|
}
|
|
2921
3201
|
return Option4.none();
|
|
2922
3202
|
}),
|
|
2923
|
-
deferredDone: (options) =>
|
|
3203
|
+
deferredDone: (options) => Effect18.gen(function* () {
|
|
2924
3204
|
yield* setEncodedExit(store, deferredKey(options.executionId, options.deferredName), options.exit);
|
|
2925
|
-
yield* resumeQueue.offer({ executionId: options.executionId }, { id: options.executionId }).pipe(
|
|
3205
|
+
yield* resumeQueue.offer({ executionId: options.executionId }, { id: options.executionId }).pipe(Effect18.orDie);
|
|
2926
3206
|
yield* resumeExecution(options.executionId);
|
|
2927
3207
|
}),
|
|
2928
3208
|
scheduleClock: (workflow, options) => engine.deferredDone(options.clock.deferred, {
|
|
2929
3209
|
workflowName: workflow._tag,
|
|
2930
3210
|
executionId: options.executionId,
|
|
2931
3211
|
deferredName: options.clock.deferred.name,
|
|
2932
|
-
exit:
|
|
2933
|
-
}).pipe(
|
|
3212
|
+
exit: Exit5.void
|
|
3213
|
+
}).pipe(Effect18.delay(options.clock.duration), FiberMap.run(clocks, `${options.executionId}/${options.clock.name}`, {
|
|
2934
3214
|
onlyIfMissing: true
|
|
2935
|
-
}),
|
|
3215
|
+
}), Effect18.asVoid)
|
|
2936
3216
|
});
|
|
2937
3217
|
return engine;
|
|
2938
3218
|
}));
|
|
2939
|
-
var executeEncoded = (workflows, executions, store, resume) =>
|
|
3219
|
+
var executeEncoded = (workflows, executions, store, resume) => Effect18.fnUntraced(function* (workflow, options) {
|
|
2940
3220
|
const entry = workflows.get(workflow._tag);
|
|
2941
3221
|
if (!entry) {
|
|
2942
|
-
return yield*
|
|
3222
|
+
return yield* Effect18.orDie(Effect18.fail(`Workflow ${workflow._tag} is not registered`));
|
|
2943
3223
|
}
|
|
2944
3224
|
let state = executions.get(options.executionId);
|
|
2945
3225
|
if (!state) {
|
|
@@ -2951,24 +3231,24 @@ var executeEncoded = (workflows, executions, store, resume) => Effect17.fnUntrac
|
|
|
2951
3231
|
parent: options.parent?.executionId
|
|
2952
3232
|
};
|
|
2953
3233
|
executions.set(options.executionId, state);
|
|
2954
|
-
yield* setEncodedExit(store, recordKey(options.executionId),
|
|
3234
|
+
yield* setEncodedExit(store, recordKey(options.executionId), Exit5.succeed({ workflowTag: workflow._tag, payload: options.payload }));
|
|
2955
3235
|
yield* resume(state);
|
|
2956
3236
|
}
|
|
2957
3237
|
if (options.discard)
|
|
2958
|
-
return yield*
|
|
3238
|
+
return yield* Effect18.void;
|
|
2959
3239
|
if (!state.fiber) {
|
|
2960
|
-
return yield*
|
|
3240
|
+
return yield* Effect18.orDie(Effect18.fail(`Workflow ${workflow._tag}: execution ${options.executionId} has no fiber`));
|
|
2961
3241
|
}
|
|
2962
3242
|
return yield* Fiber.join(state.fiber);
|
|
2963
3243
|
});
|
|
2964
|
-
var loadRecord = (store, executionId) =>
|
|
3244
|
+
var loadRecord = (store, executionId) => Effect18.gen(function* () {
|
|
2965
3245
|
const persisted = yield* getEncodedExit(store, recordKey(executionId));
|
|
2966
|
-
if (persisted &&
|
|
2967
|
-
return yield*
|
|
3246
|
+
if (persisted && Exit5.isSuccess(persisted)) {
|
|
3247
|
+
return yield* Effect18.orDie(Schema13.decodeUnknownEffect(ExecutionRecord)(persisted.value));
|
|
2968
3248
|
}
|
|
2969
3249
|
return;
|
|
2970
3250
|
});
|
|
2971
|
-
var workflowTagFor = (workflows, store, executionId) =>
|
|
3251
|
+
var workflowTagFor = (workflows, store, executionId) => Effect18.gen(function* () {
|
|
2972
3252
|
const record = yield* loadRecord(store, executionId);
|
|
2973
3253
|
if (!record)
|
|
2974
3254
|
return;
|
|
@@ -2977,10 +3257,10 @@ var workflowTagFor = (workflows, store, executionId) => Effect17.gen(function* (
|
|
|
2977
3257
|
var ensureDbDir = (url) => url.startsWith("file:") ? import("node:fs").then((fs) => import("node:path").then(({ dirname }) => {
|
|
2978
3258
|
fs.mkdirSync(dirname(url.slice("file:".length)), { recursive: true });
|
|
2979
3259
|
})) : Promise.resolve();
|
|
2980
|
-
var libsqlStack = (options) => Layer6.unwrap(
|
|
3260
|
+
var libsqlStack = (options) => Layer6.unwrap(Effect18.tryPromise({
|
|
2981
3261
|
try: () => ensureDbDir(options.url),
|
|
2982
3262
|
catch: (cause) => new Error(String(cause))
|
|
2983
|
-
}).pipe(
|
|
3263
|
+
}).pipe(Effect18.catch(() => Effect18.void), Effect18.map(() => Layer6.mergeAll(PersistenceNamespace2.layerSql, PersistedQueue2.layer.pipe(Layer6.provide(storeSqliteLayer))).pipe(Layer6.provide(exports_LibsqlClient.layer(options))))));
|
|
2984
3264
|
var layerDurableLibsql = (options) => layerDurable.pipe(Layer6.provide(libsqlStack(options)));
|
|
2985
3265
|
|
|
2986
3266
|
// ../workflow/src/runtime.ts
|
|
@@ -2999,7 +3279,7 @@ var jobsError = (jobId, e) => {
|
|
|
2999
3279
|
return e;
|
|
3000
3280
|
return new QueueError({ message: e instanceof Error ? e.message : String(e) });
|
|
3001
3281
|
};
|
|
3002
|
-
var layer6 = (defs) => Layer7.effect(Service7,
|
|
3282
|
+
var layer6 = (defs) => Layer7.effect(Service7, Effect19.gen(function* () {
|
|
3003
3283
|
const engine = yield* WorkflowEngine3.WorkflowEngine;
|
|
3004
3284
|
const persistence = yield* Persistence2;
|
|
3005
3285
|
const queueFactory = yield* PersistedQueueFactory2;
|
|
@@ -3007,51 +3287,57 @@ var layer6 = (defs) => Layer7.effect(Service7, Effect18.gen(function* () {
|
|
|
3007
3287
|
for (const def of defs) {
|
|
3008
3288
|
yield* def.register(engine);
|
|
3009
3289
|
}
|
|
3010
|
-
const enqueue =
|
|
3011
|
-
const decoded = yield* Schema14.decodeUnknownEffect(def.payloadSchema)(payload).pipe(
|
|
3290
|
+
const enqueue = Effect19.fn("JobRuntime.enqueue")(function* (def, payload) {
|
|
3291
|
+
const decoded = yield* Schema14.decodeUnknownEffect(def.payloadSchema)(payload).pipe(Effect19.mapError((e) => new QueueError({ message: `invalid payload: ${e.message}` })));
|
|
3012
3292
|
const token = def.idempotencyKey(decoded);
|
|
3013
3293
|
const envelope = { token, payload: decoded, traceId: "" };
|
|
3014
|
-
const jobId = yield* def.workflow.executionId(envelope).pipe(
|
|
3015
|
-
yield* def.workflow.execute(envelope, { discard: true }).pipe(
|
|
3294
|
+
const jobId = yield* def.workflow.executionId(envelope).pipe(Effect19.provideService(WorkflowEngine3.WorkflowEngine, engine), Effect19.mapError((e) => new QueueError({ message: e instanceof Error ? e.message : String(e) })));
|
|
3295
|
+
yield* def.workflow.execute(envelope, { discard: true }).pipe(Effect19.provideService(WorkflowEngine3.WorkflowEngine, engine), Effect19.mapError((e) => jobsError(jobId, e)));
|
|
3016
3296
|
return jobId;
|
|
3017
3297
|
});
|
|
3018
|
-
const wait =
|
|
3298
|
+
const wait = Effect19.fn("JobRuntime.wait")(function* (jobId, options) {
|
|
3019
3299
|
const timeout = Duration2.fromInput(options?.timeout ?? DEFAULT_TIMEOUT).pipe(Option5.getOrElse(() => Duration2.minutes(5)));
|
|
3020
3300
|
const pollInterval = Duration2.fromInput(options?.pollInterval ?? DEFAULT_POLL_INTERVAL).pipe(Option5.getOrElse(() => Duration2.millis(250)));
|
|
3021
|
-
const deadline = yield* Clock2.currentTimeMillis.pipe(
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3301
|
+
const deadline = yield* Clock2.currentTimeMillis.pipe(Effect19.map((now) => now + Duration2.toMillis(timeout)));
|
|
3302
|
+
const completionSignal = yield* Deferred2.make();
|
|
3303
|
+
onExecutionDone(jobId, completionSignal);
|
|
3304
|
+
try {
|
|
3305
|
+
while (true) {
|
|
3306
|
+
if (yield* readMarker(store, jobId, CANCELLED)) {
|
|
3307
|
+
return yield* Effect19.fail(new JobCancelled({ jobId }));
|
|
3308
|
+
}
|
|
3309
|
+
const def = yield* findDef(defs, jobId, store);
|
|
3310
|
+
if (def) {
|
|
3311
|
+
const result = yield* readWorkflowResult(store, def.workflow, jobId);
|
|
3312
|
+
if (Option5.isSome(result)) {
|
|
3313
|
+
const r = result.value;
|
|
3314
|
+
if (r._tag === "Complete") {
|
|
3315
|
+
if (Exit6.isSuccess(r.exit))
|
|
3316
|
+
return r.exit.value;
|
|
3317
|
+
const failure = Exit6.getCause(r.exit).pipe(Option5.flatMap(Cause2.findErrorOption), Option5.map((e) => typeof e === "string" ? e : String(e)));
|
|
3318
|
+
return yield* Effect19.fail(new JobFailed({
|
|
3319
|
+
jobId,
|
|
3320
|
+
message: Option5.getOrElse(failure, () => "workflow failed")
|
|
3321
|
+
}));
|
|
3322
|
+
}
|
|
3039
3323
|
}
|
|
3040
3324
|
}
|
|
3325
|
+
const now = yield* Clock2.currentTimeMillis;
|
|
3326
|
+
if (now >= deadline) {
|
|
3327
|
+
yield* writeMarker(store, jobId, TIMED_OUT);
|
|
3328
|
+
return yield* Effect19.fail(new JobTimeout({ jobId, timeout }));
|
|
3329
|
+
}
|
|
3330
|
+
yield* Effect19.race(Deferred2.await(completionSignal).pipe(Effect19.asVoid), Effect19.sleep(pollInterval));
|
|
3041
3331
|
}
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
yield* writeMarker(store, jobId, TIMED_OUT);
|
|
3045
|
-
return yield* Effect18.fail(new JobTimeout({ jobId, timeout }));
|
|
3046
|
-
}
|
|
3047
|
-
yield* Effect18.sleep(pollInterval);
|
|
3332
|
+
} finally {
|
|
3333
|
+
offExecutionDone(jobId, completionSignal);
|
|
3048
3334
|
}
|
|
3049
3335
|
});
|
|
3050
|
-
const submit =
|
|
3336
|
+
const submit = Effect19.fn("JobRuntime.submit")(function* (def, payload) {
|
|
3051
3337
|
const jobId = yield* enqueue(def, payload);
|
|
3052
3338
|
return yield* wait(jobId);
|
|
3053
3339
|
});
|
|
3054
|
-
const status =
|
|
3340
|
+
const status = Effect19.fn("JobRuntime.status")(function* (jobId) {
|
|
3055
3341
|
if (yield* readMarker(store, jobId, CANCELLED))
|
|
3056
3342
|
return "cancelled";
|
|
3057
3343
|
if (yield* readMarker(store, jobId, TIMED_OUT))
|
|
@@ -3062,35 +3348,35 @@ var layer6 = (defs) => Layer7.effect(Service7, Effect18.gen(function* () {
|
|
|
3062
3348
|
if (Option5.isSome(result)) {
|
|
3063
3349
|
const r = result.value;
|
|
3064
3350
|
if (r._tag === "Complete") {
|
|
3065
|
-
return
|
|
3351
|
+
return Exit6.isSuccess(r.exit) ? "succeeded" : "failed";
|
|
3066
3352
|
}
|
|
3067
3353
|
}
|
|
3068
3354
|
}
|
|
3069
3355
|
return "pending";
|
|
3070
3356
|
});
|
|
3071
|
-
const cancel =
|
|
3357
|
+
const cancel = Effect19.fn("JobRuntime.cancel")(function* (jobId) {
|
|
3072
3358
|
yield* writeMarker(store, jobId, CANCELLED);
|
|
3073
3359
|
return true;
|
|
3074
3360
|
});
|
|
3075
|
-
const processPending =
|
|
3361
|
+
const processPending = Effect19.fn("JobRuntime.processPending")(function* (options) {
|
|
3076
3362
|
const resumeQueue = yield* queueFactory.make({ name: RESUME_QUEUE, schema: ResumeSignal });
|
|
3077
3363
|
const window = Duration2.toMillis(Duration2.fromInput(options?.window ?? PROCESS_WINDOW).pipe(Option5.getOrElse(() => Duration2.seconds(30))));
|
|
3078
|
-
const deadline = yield* Clock2.currentTimeMillis.pipe(
|
|
3364
|
+
const deadline = yield* Clock2.currentTimeMillis.pipe(Effect19.map((now) => now + window));
|
|
3079
3365
|
let processed = 0;
|
|
3080
3366
|
while (true) {
|
|
3081
3367
|
const now = yield* Clock2.currentTimeMillis;
|
|
3082
3368
|
if (now >= deadline)
|
|
3083
3369
|
break;
|
|
3084
|
-
const signal = yield* resumeQueue.take((value2, _meta) =>
|
|
3370
|
+
const signal = yield* resumeQueue.take((value2, _meta) => Effect19.succeed(Option5.some(value2)), { maxAttempts: 1 }).pipe(Effect19.mapError((e) => new QueueError({ message: e instanceof Error ? e.message : String(e) })), Effect19.timeoutOrElse({
|
|
3085
3371
|
duration: Duration2.millis(100),
|
|
3086
|
-
orElse: () =>
|
|
3372
|
+
orElse: () => Effect19.succeed(Option5.none())
|
|
3087
3373
|
}));
|
|
3088
3374
|
if (Option5.isNone(signal))
|
|
3089
3375
|
continue;
|
|
3090
3376
|
const executionId = signal.value.executionId;
|
|
3091
3377
|
const def = yield* findDef(defs, executionId, store);
|
|
3092
3378
|
if (def) {
|
|
3093
|
-
yield* engine.resume(def.workflow, executionId).pipe(
|
|
3379
|
+
yield* engine.resume(def.workflow, executionId).pipe(Effect19.orDie);
|
|
3094
3380
|
processed++;
|
|
3095
3381
|
}
|
|
3096
3382
|
}
|
|
@@ -3098,16 +3384,16 @@ var layer6 = (defs) => Layer7.effect(Service7, Effect18.gen(function* () {
|
|
|
3098
3384
|
});
|
|
3099
3385
|
return Service7.of({ enqueue, wait, submit, status, cancel, processPending });
|
|
3100
3386
|
}));
|
|
3101
|
-
var findDef = (defs, executionId, store) =>
|
|
3387
|
+
var findDef = (defs, executionId, store) => Effect19.gen(function* () {
|
|
3102
3388
|
const persisted = yield* getEncodedExit(store, `${executionId}/record`);
|
|
3103
|
-
if (!persisted || !
|
|
3389
|
+
if (!persisted || !Exit6.isSuccess(persisted))
|
|
3104
3390
|
return;
|
|
3105
|
-
const record = yield*
|
|
3391
|
+
const record = yield* Effect19.orDie(Schema14.decodeUnknownEffect(ExecutionRecord)(persisted.value));
|
|
3106
3392
|
return defs.find((d) => d.workflow._tag === record.workflowTag);
|
|
3107
3393
|
});
|
|
3108
3394
|
var layerLibsql = (defs, options) => layer6(defs).pipe(Layer7.provideMerge(Layer7.mergeAll(layerDurableLibsql(options), libsqlStack(options))));
|
|
3109
3395
|
// ../workflow/src/registry.ts
|
|
3110
|
-
import { Context as Context8, Effect as
|
|
3396
|
+
import { Context as Context8, Effect as Effect20, Layer as Layer8, Option as Option6, Ref, Schema as Schema15 } from "effect";
|
|
3111
3397
|
class JobFailure extends Schema15.TaggedErrorClass()("JobFailure", {
|
|
3112
3398
|
jobId: Schema15.String,
|
|
3113
3399
|
message: Schema15.String
|
|
@@ -3116,9 +3402,9 @@ class JobFailure extends Schema15.TaggedErrorClass()("JobFailure", {
|
|
|
3116
3402
|
|
|
3117
3403
|
class Service8 extends Context8.Service()("@dimple/workflow/JobRegistry") {
|
|
3118
3404
|
}
|
|
3119
|
-
var layer7 = Layer8.effect(Service8,
|
|
3405
|
+
var layer7 = Layer8.effect(Service8, Effect20.gen(function* () {
|
|
3120
3406
|
const handlers = yield* Ref.make(new Map);
|
|
3121
|
-
const register =
|
|
3407
|
+
const register = Effect20.fn("JobRegistry.register")(function* (type, handler) {
|
|
3122
3408
|
const existed = yield* Ref.modify(handlers, (map2) => {
|
|
3123
3409
|
if (map2.has(type)) {
|
|
3124
3410
|
return [true, map2];
|
|
@@ -3126,46 +3412,46 @@ var layer7 = Layer8.effect(Service8, Effect19.gen(function* () {
|
|
|
3126
3412
|
return [false, new Map(map2).set(type, handler)];
|
|
3127
3413
|
});
|
|
3128
3414
|
if (existed) {
|
|
3129
|
-
return yield*
|
|
3415
|
+
return yield* Effect20.fail(new RegistryError({ type, message: `Job type already registered: ${type}` }));
|
|
3130
3416
|
}
|
|
3131
3417
|
});
|
|
3132
|
-
const resolve =
|
|
3133
|
-
const handler = yield* Ref.get(handlers).pipe(
|
|
3418
|
+
const resolve = Effect20.fn("JobRegistry.resolve")(function* (type) {
|
|
3419
|
+
const handler = yield* Ref.get(handlers).pipe(Effect20.map((map2) => Option6.fromNullishOr(map2.get(type))));
|
|
3134
3420
|
if (Option6.isNone(handler)) {
|
|
3135
|
-
return yield*
|
|
3421
|
+
return yield* Effect20.fail(new UnknownJobType({ type }));
|
|
3136
3422
|
}
|
|
3137
3423
|
return handler.value;
|
|
3138
3424
|
});
|
|
3139
3425
|
return Service8.of({ register, resolve });
|
|
3140
3426
|
}));
|
|
3141
3427
|
// ../workflow/src/executor.ts
|
|
3142
|
-
import { Cause as Cause3, Duration as Duration3, Effect as
|
|
3428
|
+
import { Cause as Cause3, Duration as Duration3, Effect as Effect21, Layer as Layer9, Schedule as Schedule2 } from "effect";
|
|
3143
3429
|
import { DurableQueue as DurableQueue2, WorkflowEngine as WorkflowEngine4 } from "effect/unstable/workflow";
|
|
3144
|
-
var runHandler = (def, payload, jobId, maxAttempts) =>
|
|
3430
|
+
var runHandler = (def, payload, jobId, maxAttempts) => Effect21.gen(function* () {
|
|
3145
3431
|
const registry = yield* Service8;
|
|
3146
3432
|
const handler = yield* registry.resolve(def.name);
|
|
3147
|
-
yield*
|
|
3433
|
+
yield* Effect21.logInfo("job.started").pipe(Effect21.annotateLogs({
|
|
3148
3434
|
scope: "@dimple/workflow",
|
|
3149
3435
|
event: "job.started",
|
|
3150
3436
|
job: def.name,
|
|
3151
3437
|
idempotencyKey: jobId
|
|
3152
3438
|
}));
|
|
3153
3439
|
const run = () => handler(payload, { jobId });
|
|
3154
|
-
const outcome = yield* (maxAttempts > 1 ? run().pipe(
|
|
3440
|
+
const outcome = yield* (maxAttempts > 1 ? run().pipe(Effect21.retry({
|
|
3155
3441
|
times: maxAttempts - 1,
|
|
3156
3442
|
schedule: Schedule2.spaced(Duration3.millis(250)).pipe(Schedule2.jittered)
|
|
3157
|
-
})) : run()).pipe(
|
|
3443
|
+
})) : run()).pipe(Effect21.exit);
|
|
3158
3444
|
if (outcome._tag === "Failure") {
|
|
3159
|
-
yield*
|
|
3445
|
+
yield* Effect21.logError("job.failed").pipe(Effect21.annotateLogs({
|
|
3160
3446
|
scope: "@dimple/workflow",
|
|
3161
3447
|
event: "job.failed",
|
|
3162
3448
|
job: def.name,
|
|
3163
3449
|
idempotencyKey: jobId,
|
|
3164
3450
|
error: Cause3.pretty(outcome.cause)
|
|
3165
3451
|
}));
|
|
3166
|
-
return yield*
|
|
3452
|
+
return yield* Effect21.failCause(outcome.cause).pipe(Effect21.mapError((e) => e.message));
|
|
3167
3453
|
}
|
|
3168
|
-
yield*
|
|
3454
|
+
yield* Effect21.logInfo("job.completed").pipe(Effect21.annotateLogs({
|
|
3169
3455
|
scope: "@dimple/workflow",
|
|
3170
3456
|
event: "job.completed",
|
|
3171
3457
|
job: def.name,
|
|
@@ -3198,17 +3484,17 @@ var JobsConfig2 = Schema16.Struct({
|
|
|
3198
3484
|
pollIntervalMs: Schema16.optional(Schema16.Number)
|
|
3199
3485
|
});
|
|
3200
3486
|
// ../store/src/topics/lifecycle.ts
|
|
3201
|
-
var routingFailure3 = (tag) => (effect) => effect.pipe(
|
|
3202
|
-
var isActive =
|
|
3487
|
+
var routingFailure3 = (tag) => (effect) => effect.pipe(Effect22.mapError((cause) => new RoutingFailure({ cause: { operation: tag, cause } })));
|
|
3488
|
+
var isActive = Effect22.fn("topics.isActive")(function* (modelKey) {
|
|
3203
3489
|
const backend = yield* Service2;
|
|
3204
3490
|
const db = backend.db;
|
|
3205
|
-
const rows = yield*
|
|
3491
|
+
const rows = yield* Effect22.tryPromise({
|
|
3206
3492
|
try: () => db.select({ topicKey: topics.topicKey }).from(topics).where(and3(eq3(topics.modelKey, modelKey), eq3(topics.status, "active"))).limit(1),
|
|
3207
3493
|
catch: (cause) => cause
|
|
3208
3494
|
}).pipe(routingFailure3("topics.isActive"));
|
|
3209
3495
|
return rows.length > 0;
|
|
3210
3496
|
});
|
|
3211
|
-
var setActiveModel =
|
|
3497
|
+
var setActiveModel = Effect22.fn("topics.setActiveModel")(function* (model, config) {
|
|
3212
3498
|
const backend = yield* Service2;
|
|
3213
3499
|
const db = backend.db;
|
|
3214
3500
|
yield* ensureTopicTree(model, config).pipe(routingFailure3("topics.setActiveModel.seed"));
|
|
@@ -3216,14 +3502,14 @@ var setActiveModel = Effect21.fn("topics.setActiveModel")(function* (model, conf
|
|
|
3216
3502
|
let routed = 0;
|
|
3217
3503
|
let alreadyInTree = 0;
|
|
3218
3504
|
if (memoryIds.length > 0) {
|
|
3219
|
-
const topicRows = yield*
|
|
3505
|
+
const topicRows = yield* Effect22.tryPromise({
|
|
3220
3506
|
try: () => db.select({ topicKey: topics.topicKey }).from(topics).where(eq3(topics.modelKey, model.id)),
|
|
3221
3507
|
catch: (cause) => cause
|
|
3222
3508
|
}).pipe(routingFailure3("topics.setActiveModel.topics"));
|
|
3223
3509
|
const modelTopicKeys = topicRows.map((r) => r.topicKey);
|
|
3224
3510
|
if (modelTopicKeys.length > 0) {
|
|
3225
3511
|
for (const memoryId of memoryIds) {
|
|
3226
|
-
const existing = yield*
|
|
3512
|
+
const existing = yield* Effect22.tryPromise({
|
|
3227
3513
|
try: () => db.select({ topicKey: topicMemberships.topicKey }).from(topicMemberships).where(and3(eq3(topicMemberships.memoryId, memoryId), eq3(topicMemberships.modelKey, model.id), inArray(topicMemberships.topicKey, modelTopicKeys))).limit(1),
|
|
3228
3514
|
catch: (cause) => cause
|
|
3229
3515
|
}).pipe(routingFailure3("topics.setActiveModel.membership"));
|
|
@@ -3241,7 +3527,7 @@ var setActiveModel = Effect21.fn("topics.setActiveModel")(function* (model, conf
|
|
|
3241
3527
|
}
|
|
3242
3528
|
}
|
|
3243
3529
|
const auditTimestamp = yield* Clock3.currentTimeMillis;
|
|
3244
|
-
const deactivated = yield*
|
|
3530
|
+
const deactivated = yield* Effect22.tryPromise({
|
|
3245
3531
|
try: () => db.transaction(async (tx) => {
|
|
3246
3532
|
const others = await tx.selectDistinct({ modelKey: topics.modelKey }).from(topics).where(and3(ne(topics.modelKey, model.id), ne(topics.status, "inactive")));
|
|
3247
3533
|
const affected = others.map((r) => r.modelKey).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
@@ -3265,18 +3551,18 @@ var setActiveModel = Effect21.fn("topics.setActiveModel")(function* (model, conf
|
|
|
3265
3551
|
return { routed, alreadyInTree, deactivated };
|
|
3266
3552
|
});
|
|
3267
3553
|
function memoryEmbedHandler(deps) {
|
|
3268
|
-
const run = (payload, ctx) =>
|
|
3554
|
+
const run = (payload, ctx) => Effect22.gen(function* () {
|
|
3269
3555
|
const envelope = payload;
|
|
3270
3556
|
const model = deps.getModelConfig(envelope.modelKey);
|
|
3271
3557
|
if (!model) {
|
|
3272
|
-
return yield*
|
|
3558
|
+
return yield* Effect22.fail(new JobFailure({
|
|
3273
3559
|
jobId: ctx.jobId,
|
|
3274
3560
|
message: `memory.embed: unknown model "${envelope.modelKey}"`
|
|
3275
3561
|
}));
|
|
3276
3562
|
}
|
|
3277
|
-
const content = yield* deps.getMemoryContent(envelope.memoryId).pipe(
|
|
3563
|
+
const content = yield* deps.getMemoryContent(envelope.memoryId).pipe(Effect22.catchTag("Store.NotFound", () => Effect22.succeed(undefined)), Effect22.mapError((e) => new JobFailure({ jobId: ctx.jobId, message: `memory.embed: load content: ${e}` })));
|
|
3278
3564
|
if (content === undefined) {
|
|
3279
|
-
yield*
|
|
3565
|
+
yield* Effect22.logDebug("embed.stale-reoffer").pipe(Effect22.annotateLogs({
|
|
3280
3566
|
scope: "@dimple/store",
|
|
3281
3567
|
event: "embed.stale-reoffer",
|
|
3282
3568
|
memoryId: envelope.memoryId,
|
|
@@ -3284,20 +3570,20 @@ function memoryEmbedHandler(deps) {
|
|
|
3284
3570
|
}));
|
|
3285
3571
|
return;
|
|
3286
3572
|
}
|
|
3287
|
-
const vector = yield* deps.embedOne(content, model).pipe(
|
|
3573
|
+
const vector = yield* deps.embedOne(content, model).pipe(Effect22.mapError((e) => new JobFailure({ jobId: ctx.jobId, message: `memory.embed: embed: ${e}` })));
|
|
3288
3574
|
const backend = yield* Service2;
|
|
3289
3575
|
const db = backend.db;
|
|
3290
|
-
const existing = yield*
|
|
3576
|
+
const existing = yield* Effect22.tryPromise({
|
|
3291
3577
|
try: () => db.select({ memoryId: topicMemberships.memoryId }).from(topicMemberships).where(and3(eq3(topicMemberships.memoryId, envelope.memoryId), eq3(topicMemberships.modelKey, model.id))),
|
|
3292
3578
|
catch: (cause) => new StoreError({ message: `memory.embed: membership check: ${cause}` })
|
|
3293
|
-
}).pipe(
|
|
3294
|
-
yield* ensureTopicTree(model, deps.config).pipe(
|
|
3295
|
-
yield* backend.ensureVectorTable(model).pipe(
|
|
3296
|
-
yield* backend.insertVector(envelope.memoryId, [...vector], model).pipe(
|
|
3579
|
+
}).pipe(Effect22.mapError((e) => new JobFailure({ jobId: ctx.jobId, message: `memory.embed: membership check: ${e}` })));
|
|
3580
|
+
yield* ensureTopicTree(model, deps.config).pipe(Effect22.mapError((e) => new JobFailure({ jobId: ctx.jobId, message: `memory.embed: seed tree: ${e}` })));
|
|
3581
|
+
yield* backend.ensureVectorTable(model).pipe(Effect22.mapError((e) => new JobFailure({ jobId: ctx.jobId, message: `memory.embed: vector table: ${e}` })));
|
|
3582
|
+
yield* backend.insertVector(envelope.memoryId, [...vector], model).pipe(Effect22.mapError((e) => new JobFailure({ jobId: ctx.jobId, message: `memory.embed: insert vector: ${e}` })));
|
|
3297
3583
|
if (existing.length === 0) {
|
|
3298
|
-
yield* routeInsert(envelope.memoryId, [...vector], model, deps.config).pipe(
|
|
3584
|
+
yield* routeInsert(envelope.memoryId, [...vector], model, deps.config).pipe(Effect22.mapError((e) => new JobFailure({ jobId: ctx.jobId, message: `memory.embed: route: ${e}` })));
|
|
3299
3585
|
}
|
|
3300
|
-
yield*
|
|
3586
|
+
yield* Effect22.logInfo("embed.completed").pipe(Effect22.annotateLogs({
|
|
3301
3587
|
scope: "@dimple/store",
|
|
3302
3588
|
event: "embed.completed",
|
|
3303
3589
|
memoryId: envelope.memoryId,
|
|
@@ -3306,11 +3592,11 @@ function memoryEmbedHandler(deps) {
|
|
|
3306
3592
|
}));
|
|
3307
3593
|
return;
|
|
3308
3594
|
});
|
|
3309
|
-
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(
|
|
3595
|
+
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(Effect22.provideService(Service2, deps.backend)) : run;
|
|
3310
3596
|
}
|
|
3311
3597
|
|
|
3312
3598
|
// ../store/src/topics/jobs.ts
|
|
3313
|
-
import { Clock as Clock4, Effect as
|
|
3599
|
+
import { Clock as Clock4, Effect as Effect23 } from "effect";
|
|
3314
3600
|
import { and as and4, asc as asc3, eq as eq4, inArray as inArray2, sql as sql4 } from "drizzle-orm";
|
|
3315
3601
|
|
|
3316
3602
|
// ../store/src/topics/topic-vectors.ts
|
|
@@ -3334,23 +3620,28 @@ var DEFAULT_SPLIT_DEFERRED_HARD_LIMIT = 512;
|
|
|
3334
3620
|
var shouldSplit = (leafMemberCount, config) => leafMemberCount > (config.maxLeafItems ?? DEFAULT_MAX_LEAF_ITEMS);
|
|
3335
3621
|
var childBaseKey = (parent, vectors) => {
|
|
3336
3622
|
const dims = vectors.length > 0 ? vectors[0].length : 0;
|
|
3337
|
-
|
|
3623
|
+
let hash = 2166136261;
|
|
3624
|
+
const step = (byte) => {
|
|
3625
|
+
hash ^= byte;
|
|
3626
|
+
hash = Math.imul(hash, 16777619);
|
|
3627
|
+
};
|
|
3628
|
+
for (let i = 0;i < parent.length; i++)
|
|
3629
|
+
step(parent.charCodeAt(i) & 255);
|
|
3630
|
+
step(255);
|
|
3338
3631
|
for (const v of vectors) {
|
|
3339
|
-
const bytes =
|
|
3340
|
-
for (let i = 0;i <
|
|
3341
|
-
bytes
|
|
3342
|
-
}
|
|
3343
|
-
parts.push(bytes.join(","));
|
|
3632
|
+
const bytes = new Uint8Array(v.buffer, v.byteOffset, dims * 4);
|
|
3633
|
+
for (let i = 0;i < bytes.length; i++)
|
|
3634
|
+
step(bytes[i]);
|
|
3344
3635
|
}
|
|
3345
|
-
return `t_${
|
|
3636
|
+
return `t_${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
3346
3637
|
};
|
|
3347
|
-
var splitTopic =
|
|
3638
|
+
var splitTopic = Effect23.fn("TopicSplit.splitTopic")(function* (topicKey, model, config) {
|
|
3348
3639
|
const backend = yield* Service2;
|
|
3349
3640
|
const db = backend.db;
|
|
3350
3641
|
yield* backend.ensureTopicVectorTable(model);
|
|
3351
3642
|
const maxLeafItems = config.maxLeafItems ?? DEFAULT_MAX_LEAF_ITEMS;
|
|
3352
3643
|
const hardLimit = config.splitDeferredHardLimit ?? DEFAULT_SPLIT_DEFERRED_HARD_LIMIT;
|
|
3353
|
-
const leafRows = yield*
|
|
3644
|
+
const leafRows = yield* Effect23.tryPromise({
|
|
3354
3645
|
try: () => db.select().from(topics).where(and4(eq4(topics.topicKey, topicKey), eq4(topics.modelKey, model.id))),
|
|
3355
3646
|
catch: (cause) => new StoreError({ message: `splitTopic: load topic: ${cause}` })
|
|
3356
3647
|
});
|
|
@@ -3361,13 +3652,13 @@ var splitTopic = Effect22.fn("TopicSplit.splitTopic")(function* (topicKey, model
|
|
|
3361
3652
|
if (leaf.modelKey !== model.id) {
|
|
3362
3653
|
return yield* new ModelMismatch({ expected: model.id, actual: leaf.modelKey });
|
|
3363
3654
|
}
|
|
3364
|
-
const memberRows = yield*
|
|
3655
|
+
const memberRows = yield* Effect23.tryPromise({
|
|
3365
3656
|
try: () => db.select({ memoryId: topicMemberships.memoryId }).from(topicMemberships).where(and4(eq4(topicMemberships.topicKey, topicKey), eq4(topicMemberships.modelKey, model.id))).orderBy(asc3(topicMemberships.memoryId)),
|
|
3366
3657
|
catch: (cause) => new StoreError({ message: `splitTopic: load members: ${cause}` })
|
|
3367
3658
|
});
|
|
3368
3659
|
const memberIds = memberRows.map((r) => r.memoryId);
|
|
3369
3660
|
const memberCount = memberIds.length;
|
|
3370
|
-
const growthRows = yield*
|
|
3661
|
+
const growthRows = yield* Effect23.tryPromise({
|
|
3371
3662
|
try: () => db.select().from(topicGrowthState).where(and4(eq4(topicGrowthState.topicKey, topicKey), eq4(topicGrowthState.modelKey, model.id))),
|
|
3372
3663
|
catch: (cause) => new StoreError({ message: `splitTopic: load growth state: ${cause}` })
|
|
3373
3664
|
});
|
|
@@ -3399,7 +3690,7 @@ var splitTopic = Effect22.fn("TopicSplit.splitTopic")(function* (topicKey, model
|
|
|
3399
3690
|
const forced = memberCount > hardLimit;
|
|
3400
3691
|
if (!plan.accepted && !forced) {
|
|
3401
3692
|
const now2 = yield* Clock4.currentTimeMillis;
|
|
3402
|
-
yield*
|
|
3693
|
+
yield* Effect23.tryPromise({
|
|
3403
3694
|
try: () => db.transaction(async (tx) => {
|
|
3404
3695
|
await tx.insert(topicGrowthState).values({
|
|
3405
3696
|
topicKey,
|
|
@@ -3432,7 +3723,7 @@ var splitTopic = Effect22.fn("TopicSplit.splitTopic")(function* (topicKey, model
|
|
|
3432
3723
|
};
|
|
3433
3724
|
}
|
|
3434
3725
|
const now = yield* Clock4.currentTimeMillis;
|
|
3435
|
-
const children = yield*
|
|
3726
|
+
const children = yield* Effect23.tryPromise({
|
|
3436
3727
|
try: () => db.transaction(async (tx) => {
|
|
3437
3728
|
const child0Cf = cfFromVectors(groupVectors(0));
|
|
3438
3729
|
const child1Cf = cfFromVectors(groupVectors(1));
|
|
@@ -3553,34 +3844,34 @@ var splitTopic = Effect22.fn("TopicSplit.splitTopic")(function* (topicKey, model
|
|
|
3553
3844
|
});
|
|
3554
3845
|
return { accepted: true, children: children.keys, childCounts: children.counts };
|
|
3555
3846
|
});
|
|
3556
|
-
var staleSplitNoOp = (notFound, model) =>
|
|
3847
|
+
var staleSplitNoOp = (notFound, model) => Effect23.gen(function* () {
|
|
3557
3848
|
const backend = yield* Service2;
|
|
3558
3849
|
const db = backend.db;
|
|
3559
|
-
const rows = yield*
|
|
3850
|
+
const rows = yield* Effect23.tryPromise({
|
|
3560
3851
|
try: () => db.select({ topicKey: topics.topicKey }).from(topics).where(and4(eq4(topics.topicKey, notFound.topicKey), eq4(topics.modelKey, model.id))),
|
|
3561
3852
|
catch: (cause) => new StoreError({ message: `topic.split: stale check: ${cause}` })
|
|
3562
3853
|
});
|
|
3563
3854
|
if (rows.length > 0) {
|
|
3564
3855
|
return { accepted: false, reason: "no-improvement" };
|
|
3565
3856
|
}
|
|
3566
|
-
return yield*
|
|
3857
|
+
return yield* Effect23.fail(notFound);
|
|
3567
3858
|
});
|
|
3568
3859
|
function topicSplitHandler(deps) {
|
|
3569
|
-
const run = (payload, ctx) =>
|
|
3860
|
+
const run = (payload, ctx) => Effect23.gen(function* () {
|
|
3570
3861
|
const envelope = payload;
|
|
3571
3862
|
const model = deps.getModelConfig(envelope.modelKey);
|
|
3572
3863
|
if (!model) {
|
|
3573
|
-
return yield*
|
|
3864
|
+
return yield* Effect23.fail(new JobFailure({
|
|
3574
3865
|
jobId: ctx.jobId,
|
|
3575
3866
|
message: `topic.split: unknown model "${envelope.modelKey}"`
|
|
3576
3867
|
}));
|
|
3577
3868
|
}
|
|
3578
|
-
const outcome = yield* splitTopic(envelope.topicId, model, deps.config).pipe(
|
|
3869
|
+
const outcome = yield* splitTopic(envelope.topicId, model, deps.config).pipe(Effect23.catchIf((error) => error._tag === "topics.TopicNotFound", (notFound) => staleSplitNoOp(notFound, model)), Effect23.mapError((error) => new JobFailure({ jobId: ctx.jobId, message: `${error}` })));
|
|
3579
3870
|
if (outcome.accepted && deps.onUnevenSplit) {
|
|
3580
3871
|
const [n0, n1] = outcome.childCounts;
|
|
3581
3872
|
const [k0] = outcome.children;
|
|
3582
3873
|
if (Math.max(n0, n1) > 2 * Math.min(n0, n1)) {
|
|
3583
|
-
yield* deps.onUnevenSplit(k0, envelope.modelKey).pipe(
|
|
3874
|
+
yield* deps.onUnevenSplit(k0, envelope.modelKey).pipe(Effect23.mapError((error) => new JobFailure({
|
|
3584
3875
|
jobId: ctx.jobId,
|
|
3585
3876
|
message: `topic.split: enqueue rebalance: ${error}`
|
|
3586
3877
|
})));
|
|
@@ -3590,14 +3881,14 @@ function topicSplitHandler(deps) {
|
|
|
3590
3881
|
const maxLeafItems = deps.config.maxLeafItems ?? DEFAULT_MAX_LEAF_ITEMS;
|
|
3591
3882
|
for (let i = 0;i < outcome.children.length; i++) {
|
|
3592
3883
|
if (outcome.childCounts[i] > maxLeafItems) {
|
|
3593
|
-
yield* deps.onChildOverflow(outcome.children[i], envelope.modelKey).pipe(
|
|
3884
|
+
yield* deps.onChildOverflow(outcome.children[i], envelope.modelKey).pipe(Effect23.mapError((error) => new JobFailure({
|
|
3594
3885
|
jobId: ctx.jobId,
|
|
3595
3886
|
message: `topic.split: enqueue child split: ${error}`
|
|
3596
3887
|
})));
|
|
3597
3888
|
}
|
|
3598
3889
|
}
|
|
3599
3890
|
}
|
|
3600
|
-
yield*
|
|
3891
|
+
yield* Effect23.logInfo("split.completed").pipe(Effect23.annotateLogs({
|
|
3601
3892
|
scope: "@dimple/store",
|
|
3602
3893
|
event: "split.completed",
|
|
3603
3894
|
topicId: envelope.topicId,
|
|
@@ -3607,16 +3898,16 @@ function topicSplitHandler(deps) {
|
|
|
3607
3898
|
}));
|
|
3608
3899
|
return;
|
|
3609
3900
|
});
|
|
3610
|
-
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(
|
|
3901
|
+
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(Effect23.provideService(Service2, deps.backend)) : run;
|
|
3611
3902
|
}
|
|
3612
3903
|
|
|
3613
3904
|
// ../store/src/topics/maintenance.ts
|
|
3614
|
-
import { Clock as Clock5, Effect as
|
|
3905
|
+
import { Clock as Clock5, Effect as Effect24 } from "effect";
|
|
3615
3906
|
import { and as and5, asc as asc4, eq as eq5, ne as ne2 } from "drizzle-orm";
|
|
3616
3907
|
var DEFAULT_MIN_LEAF_ITEMS = 32;
|
|
3617
3908
|
var DEFAULT_MAX_LEAF_ITEMS2 = 128;
|
|
3618
3909
|
var DEFAULT_REBALANCE_COOLDOWN_MS = 60000;
|
|
3619
|
-
var maintenanceError = (tag) => (effect) => effect.pipe(
|
|
3910
|
+
var maintenanceError = (tag) => (effect) => effect.pipe(Effect24.mapError((cause) => new StoreError({ message: `${tag}: ${cause}` })));
|
|
3620
3911
|
var dot2 = (a, b) => {
|
|
3621
3912
|
let sum = 0;
|
|
3622
3913
|
for (let i = 0;i < a.length; i++)
|
|
@@ -3634,12 +3925,12 @@ var resolvedConfig2 = (config) => ({
|
|
|
3634
3925
|
maxLeafItems: config.maxLeafItems ?? DEFAULT_MAX_LEAF_ITEMS2,
|
|
3635
3926
|
rebalanceCooldownMs: config.rebalanceCooldownMs ?? DEFAULT_REBALANCE_COOLDOWN_MS
|
|
3636
3927
|
});
|
|
3637
|
-
var mergeOrBorrow =
|
|
3928
|
+
var mergeOrBorrow = Effect24.fn("topics.mergeOrBorrow")(function* (topicKey, model, config) {
|
|
3638
3929
|
const backend = yield* Service2;
|
|
3639
3930
|
const db = backend.db;
|
|
3640
3931
|
const { minLeafItems, maxLeafItems } = resolvedConfig2(config);
|
|
3641
3932
|
const now = yield* Clock5.currentTimeMillis;
|
|
3642
|
-
const leafRows = yield*
|
|
3933
|
+
const leafRows = yield* Effect24.tryPromise({
|
|
3643
3934
|
try: () => db.select().from(topics).where(and5(eq5(topics.topicKey, topicKey), eq5(topics.modelKey, model.id))),
|
|
3644
3935
|
catch: (cause) => new StoreError({ message: `mergeOrBorrow: load topic: ${cause}` })
|
|
3645
3936
|
});
|
|
@@ -3652,7 +3943,7 @@ var mergeOrBorrow = Effect23.fn("topics.mergeOrBorrow")(function* (topicKey, mod
|
|
|
3652
3943
|
}
|
|
3653
3944
|
if (leaf.memberCount >= minLeafItems)
|
|
3654
3945
|
return { action: "none" };
|
|
3655
|
-
const parentRows = yield*
|
|
3946
|
+
const parentRows = yield* Effect24.tryPromise({
|
|
3656
3947
|
try: () => db.select({ parentKey: topicRelations.parentKey }).from(topicRelations).where(and5(eq5(topicRelations.childKey, topicKey), eq5(topicRelations.modelKey, model.id), eq5(topicRelations.relationKind, "parent_child"))).orderBy(asc4(topicRelations.parentKey)),
|
|
3657
3948
|
catch: (cause) => new StoreError({ message: `mergeOrBorrow: load parent: ${cause}` })
|
|
3658
3949
|
});
|
|
@@ -3660,16 +3951,16 @@ var mergeOrBorrow = Effect23.fn("topics.mergeOrBorrow")(function* (topicKey, mod
|
|
|
3660
3951
|
return yield* logUnderfilled(db, topicKey, model, now, "no-borrowable");
|
|
3661
3952
|
}
|
|
3662
3953
|
const parentKey = parentRows[0].parentKey;
|
|
3663
|
-
const parentRowRows = yield*
|
|
3954
|
+
const parentRowRows = yield* Effect24.tryPromise({
|
|
3664
3955
|
try: () => db.select({ childCount: topics.childCount }).from(topics).where(and5(eq5(topics.topicKey, parentKey), eq5(topics.modelKey, model.id))),
|
|
3665
3956
|
catch: (cause) => new StoreError({ message: `mergeOrBorrow: load parent row: ${cause}` })
|
|
3666
3957
|
});
|
|
3667
3958
|
const parentRow = parentRowRows[0];
|
|
3668
|
-
const siblingRows = yield*
|
|
3959
|
+
const siblingRows = yield* Effect24.tryPromise({
|
|
3669
3960
|
try: () => db.select().from(topics).where(and5(eq5(topics.modelKey, model.id), eq5(topics.kind, "leaf"), ne2(topics.status, "inactive"))).orderBy(asc4(topics.topicKey)),
|
|
3670
3961
|
catch: (cause) => new StoreError({ message: `mergeOrBorrow: load siblings: ${cause}` })
|
|
3671
3962
|
});
|
|
3672
|
-
const relationRows = yield*
|
|
3963
|
+
const relationRows = yield* Effect24.tryPromise({
|
|
3673
3964
|
try: () => db.select({ childKey: topicRelations.childKey }).from(topicRelations).where(and5(eq5(topicRelations.parentKey, parentKey), eq5(topicRelations.modelKey, model.id), eq5(topicRelations.relationKind, "parent_child"))).orderBy(asc4(topicRelations.childKey)),
|
|
3674
3965
|
catch: (cause) => new StoreError({ message: `mergeOrBorrow: load relations: ${cause}` })
|
|
3675
3966
|
});
|
|
@@ -3691,7 +3982,7 @@ var mergeOrBorrow = Effect23.fn("topics.mergeOrBorrow")(function* (topicKey, mod
|
|
|
3691
3982
|
const membersByTopic = new Map;
|
|
3692
3983
|
const vecById = new Map;
|
|
3693
3984
|
for (const sibling of siblingsOf) {
|
|
3694
|
-
const members = yield*
|
|
3985
|
+
const members = yield* Effect24.tryPromise({
|
|
3695
3986
|
try: () => db.select({
|
|
3696
3987
|
memoryId: topicMemberships.memoryId,
|
|
3697
3988
|
manualLock: topicMemberships.manualLock
|
|
@@ -3704,7 +3995,7 @@ var mergeOrBorrow = Effect23.fn("topics.mergeOrBorrow")(function* (topicKey, mod
|
|
|
3704
3995
|
vecById.set(row.memoryId, new Float32Array(row.vector));
|
|
3705
3996
|
}
|
|
3706
3997
|
const movedIds = new Set;
|
|
3707
|
-
const outcome = yield*
|
|
3998
|
+
const outcome = yield* Effect24.tryPromise({
|
|
3708
3999
|
try: () => db.transaction(async (tx) => {
|
|
3709
4000
|
const leafCf0 = cfOf(leaf);
|
|
3710
4001
|
let leafCf = leafCf0;
|
|
@@ -3820,7 +4111,36 @@ var mergeOrBorrow = Effect23.fn("topics.mergeOrBorrow")(function* (topicKey, mod
|
|
|
3820
4111
|
await tx.delete(topicRelations).where(and5(eq5(topicRelations.parentKey, parentKey), eq5(topicRelations.childKey, sibling.topicKey), eq5(topicRelations.modelKey, model.id)));
|
|
3821
4112
|
await deleteTopicVectorRow(tx, model, sibling.topicKey);
|
|
3822
4113
|
await writeTopicVector(tx, model, topicKey, mergedCf.ls);
|
|
3823
|
-
|
|
4114
|
+
const remainingChildren = Math.max(0, (parentRow?.childCount ?? 1) - 1);
|
|
4115
|
+
await tx.update(topics).set({ childCount: remainingChildren, updatedAt: now }).where(and5(eq5(topics.topicKey, parentKey), eq5(topics.modelKey, model.id)));
|
|
4116
|
+
if (remainingChildren === 1) {
|
|
4117
|
+
const grandparentRows = await tx.select({ parentKey: topicRelations.parentKey }).from(topicRelations).where(and5(eq5(topicRelations.childKey, parentKey), eq5(topicRelations.modelKey, model.id), eq5(topicRelations.relationKind, "parent_child"))).limit(1);
|
|
4118
|
+
const grandparentKey = grandparentRows[0]?.parentKey;
|
|
4119
|
+
if (grandparentKey !== undefined) {
|
|
4120
|
+
await tx.delete(topicRelations).where(and5(eq5(topicRelations.parentKey, parentKey), eq5(topicRelations.childKey, topicKey), eq5(topicRelations.modelKey, model.id)));
|
|
4121
|
+
await tx.delete(topicRelations).where(and5(eq5(topicRelations.parentKey, grandparentKey), eq5(topicRelations.childKey, parentKey), eq5(topicRelations.modelKey, model.id)));
|
|
4122
|
+
await tx.insert(topicRelations).values({
|
|
4123
|
+
parentKey: grandparentKey,
|
|
4124
|
+
childKey: topicKey,
|
|
4125
|
+
modelKey: model.id,
|
|
4126
|
+
relationKind: "parent_child",
|
|
4127
|
+
updatedAt: now
|
|
4128
|
+
});
|
|
4129
|
+
await tx.update(topics).set({
|
|
4130
|
+
status: "inactive",
|
|
4131
|
+
memberCount: 0,
|
|
4132
|
+
sumSquares: 0,
|
|
4133
|
+
childCount: 0,
|
|
4134
|
+
updatedAt: now
|
|
4135
|
+
}).where(and5(eq5(topics.topicKey, parentKey), eq5(topics.modelKey, model.id)));
|
|
4136
|
+
await deleteTopicVectorRow(tx, model, parentKey);
|
|
4137
|
+
const grandparentDepthRows = await tx.select({ depth: topics.depth }).from(topics).where(and5(eq5(topics.topicKey, grandparentKey), eq5(topics.modelKey, model.id))).limit(1);
|
|
4138
|
+
await tx.update(topics).set({
|
|
4139
|
+
depth: (grandparentDepthRows[0]?.depth ?? 0) + 1,
|
|
4140
|
+
updatedAt: now
|
|
4141
|
+
}).where(and5(eq5(topics.topicKey, topicKey), eq5(topics.modelKey, model.id)));
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
3824
4144
|
await tx.insert(topicGrowthState).values({
|
|
3825
4145
|
topicKey,
|
|
3826
4146
|
modelKey: model.id,
|
|
@@ -3844,12 +4164,12 @@ var mergeOrBorrow = Effect23.fn("topics.mergeOrBorrow")(function* (topicKey, mod
|
|
|
3844
4164
|
});
|
|
3845
4165
|
return outcome;
|
|
3846
4166
|
});
|
|
3847
|
-
var rebalanceSiblings =
|
|
4167
|
+
var rebalanceSiblings = Effect24.fn("topics.rebalanceSiblings")(function* (topicKey, model, config) {
|
|
3848
4168
|
const backend = yield* Service2;
|
|
3849
4169
|
const db = backend.db;
|
|
3850
4170
|
const { rebalanceCooldownMs } = resolvedConfig2(config);
|
|
3851
4171
|
const now = yield* Clock5.currentTimeMillis;
|
|
3852
|
-
const rows = yield*
|
|
4172
|
+
const rows = yield* Effect24.tryPromise({
|
|
3853
4173
|
try: () => db.select().from(topics).where(and5(eq5(topics.topicKey, topicKey), eq5(topics.modelKey, model.id))),
|
|
3854
4174
|
catch: (cause) => new StoreError({ message: `rebalanceSiblings: load topic: ${cause}` })
|
|
3855
4175
|
});
|
|
@@ -3858,19 +4178,19 @@ var rebalanceSiblings = Effect23.fn("topics.rebalanceSiblings")(function* (topic
|
|
|
3858
4178
|
return yield* new TopicNotFound({ topicKey });
|
|
3859
4179
|
if (row.modelKey !== model.id)
|
|
3860
4180
|
return yield* new ModelMismatch({ expected: model.id, actual: row.modelKey });
|
|
3861
|
-
const parentRows = yield*
|
|
4181
|
+
const parentRows = yield* Effect24.tryPromise({
|
|
3862
4182
|
try: () => db.select({ parentKey: topicRelations.parentKey }).from(topicRelations).where(and5(eq5(topicRelations.childKey, topicKey), eq5(topicRelations.modelKey, model.id), eq5(topicRelations.relationKind, "parent_child"))).orderBy(asc4(topicRelations.parentKey)),
|
|
3863
4183
|
catch: (cause) => new StoreError({ message: `rebalanceSiblings: load parent: ${cause}` })
|
|
3864
4184
|
});
|
|
3865
4185
|
if (parentRows.length === 0)
|
|
3866
4186
|
return { action: "none", reason: "balanced" };
|
|
3867
4187
|
const parentKey = parentRows[0].parentKey;
|
|
3868
|
-
const relationRows = yield*
|
|
4188
|
+
const relationRows = yield* Effect24.tryPromise({
|
|
3869
4189
|
try: () => db.select({ childKey: topicRelations.childKey }).from(topicRelations).where(and5(eq5(topicRelations.parentKey, parentKey), eq5(topicRelations.modelKey, model.id), eq5(topicRelations.relationKind, "parent_child"))).orderBy(asc4(topicRelations.childKey)),
|
|
3870
4190
|
catch: (cause) => new StoreError({ message: `rebalanceSiblings: load relations: ${cause}` })
|
|
3871
4191
|
});
|
|
3872
4192
|
const siblingKeys = relationRows.map((r) => r.childKey);
|
|
3873
|
-
const topicRows = yield*
|
|
4193
|
+
const topicRows = yield* Effect24.tryPromise({
|
|
3874
4194
|
try: () => db.select().from(topics).where(and5(eq5(topics.modelKey, model.id), eq5(topics.kind, "leaf"), ne2(topics.status, "inactive"))),
|
|
3875
4195
|
catch: (cause) => new StoreError({ message: `rebalanceSiblings: load siblings: ${cause}` })
|
|
3876
4196
|
});
|
|
@@ -3878,7 +4198,7 @@ var rebalanceSiblings = Effect23.fn("topics.rebalanceSiblings")(function* (topic
|
|
|
3878
4198
|
const siblings = siblingKeys.map((k) => map2.get(k)).filter(Boolean);
|
|
3879
4199
|
if (siblings.length < 2)
|
|
3880
4200
|
return { action: "none", reason: "balanced" };
|
|
3881
|
-
const growthRows = yield*
|
|
4201
|
+
const growthRows = yield* Effect24.tryPromise({
|
|
3882
4202
|
try: () => db.select().from(topicGrowthState).where(and5(eq5(topicGrowthState.topicKey, topicKey), eq5(topicGrowthState.modelKey, model.id))),
|
|
3883
4203
|
catch: (cause) => new StoreError({ message: `rebalanceSiblings: load growth: ${cause}` })
|
|
3884
4204
|
});
|
|
@@ -3903,7 +4223,7 @@ var rebalanceSiblings = Effect23.fn("topics.rebalanceSiblings")(function* (topic
|
|
|
3903
4223
|
const membersByTopic = new Map;
|
|
3904
4224
|
const vecById = new Map;
|
|
3905
4225
|
for (const sibling of siblings) {
|
|
3906
|
-
const members = yield*
|
|
4226
|
+
const members = yield* Effect24.tryPromise({
|
|
3907
4227
|
try: () => db.select({
|
|
3908
4228
|
memoryId: topicMemberships.memoryId,
|
|
3909
4229
|
manualLock: topicMemberships.manualLock
|
|
@@ -3916,7 +4236,7 @@ var rebalanceSiblings = Effect23.fn("topics.rebalanceSiblings")(function* (topic
|
|
|
3916
4236
|
vecById.set(row2.memoryId, new Float32Array(row2.vector));
|
|
3917
4237
|
}
|
|
3918
4238
|
const movedIds = new Set;
|
|
3919
|
-
const outcome = yield*
|
|
4239
|
+
const outcome = yield* Effect24.tryPromise({
|
|
3920
4240
|
try: () => db.transaction(async (tx) => {
|
|
3921
4241
|
const liveCfs = new Map(siblings.map((s) => [s.topicKey, cfOf(s)]));
|
|
3922
4242
|
const liveList = () => [...liveCfs.entries()].map(([topicKey2, cf]) => ({ topicKey: topicKey2, cf })).sort((a, b) => b.cf.count - a.cf.count || (a.topicKey < b.topicKey ? -1 : 1));
|
|
@@ -4003,7 +4323,7 @@ var loadMembers = async (tx, topicKey, modelKey) => {
|
|
|
4003
4323
|
const rows = await tx.select({ memoryId: topicMemberships.memoryId, manualLock: topicMemberships.manualLock }).from(topicMemberships).where(and5(eq5(topicMemberships.topicKey, topicKey), eq5(topicMemberships.modelKey, modelKey))).orderBy(asc4(topicMemberships.memoryId));
|
|
4004
4324
|
return rows;
|
|
4005
4325
|
};
|
|
4006
|
-
var logUnderfilled = (db, topicKey, model, now, reason) =>
|
|
4326
|
+
var logUnderfilled = (db, topicKey, model, now, reason) => Effect24.tryPromise({
|
|
4007
4327
|
try: () => db.insert(topicChangeLog).values({
|
|
4008
4328
|
topicKey,
|
|
4009
4329
|
operation: "merge",
|
|
@@ -4013,7 +4333,7 @@ var logUnderfilled = (db, topicKey, model, now, reason) => Effect23.tryPromise({
|
|
|
4013
4333
|
createdAt: now
|
|
4014
4334
|
}),
|
|
4015
4335
|
catch: (cause) => new StoreError({ message: `mergeOrBorrow: log underfilled: ${cause}` })
|
|
4016
|
-
}).pipe(
|
|
4336
|
+
}).pipe(Effect24.map(() => ({ action: "underfilled", reason })));
|
|
4017
4337
|
var logUnderfilledTx = async (tx, topicKey, model, now, reason) => {
|
|
4018
4338
|
await tx.insert(topicChangeLog).values({
|
|
4019
4339
|
topicKey,
|
|
@@ -4026,61 +4346,61 @@ var logUnderfilledTx = async (tx, topicKey, model, now, reason) => {
|
|
|
4026
4346
|
return { action: "underfilled", reason };
|
|
4027
4347
|
};
|
|
4028
4348
|
function topicMergeHandler(deps) {
|
|
4029
|
-
const run = (payload, ctx) =>
|
|
4349
|
+
const run = (payload, ctx) => Effect24.gen(function* () {
|
|
4030
4350
|
const envelope = payload;
|
|
4031
4351
|
const model = deps.getModelConfig(envelope.modelKey);
|
|
4032
4352
|
if (!model) {
|
|
4033
|
-
return yield*
|
|
4353
|
+
return yield* Effect24.fail(new JobFailure({
|
|
4034
4354
|
jobId: ctx.jobId,
|
|
4035
4355
|
message: `topic.merge: unknown model "${envelope.modelKey}"`
|
|
4036
4356
|
}));
|
|
4037
4357
|
}
|
|
4038
|
-
yield* mergeOrBorrow(envelope.topicId, model, deps.config).pipe(
|
|
4358
|
+
yield* mergeOrBorrow(envelope.topicId, model, deps.config).pipe(Effect24.catchIf((error) => error._tag === "topics.TopicNotFound", (notFound) => staleNoOp(notFound, model)), Effect24.mapError((error) => new JobFailure({ jobId: ctx.jobId, message: `${error}` })));
|
|
4039
4359
|
return;
|
|
4040
4360
|
});
|
|
4041
|
-
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(
|
|
4361
|
+
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(Effect24.provideService(Service2, deps.backend)) : run;
|
|
4042
4362
|
}
|
|
4043
4363
|
function topicRebalanceHandler(deps) {
|
|
4044
|
-
const run = (payload, ctx) =>
|
|
4364
|
+
const run = (payload, ctx) => Effect24.gen(function* () {
|
|
4045
4365
|
const envelope = payload;
|
|
4046
4366
|
const model = deps.getModelConfig(envelope.modelKey);
|
|
4047
4367
|
if (!model) {
|
|
4048
|
-
return yield*
|
|
4368
|
+
return yield* Effect24.fail(new JobFailure({
|
|
4049
4369
|
jobId: ctx.jobId,
|
|
4050
4370
|
message: `topic.rebalance: unknown model "${envelope.modelKey}"`
|
|
4051
4371
|
}));
|
|
4052
4372
|
}
|
|
4053
|
-
yield* rebalanceSiblings(envelope.topicId, model, deps.config).pipe(
|
|
4373
|
+
yield* rebalanceSiblings(envelope.topicId, model, deps.config).pipe(Effect24.catchIf((error) => error._tag === "topics.TopicNotFound", (notFound) => staleNoOp(notFound, model)), Effect24.mapError((error) => new JobFailure({ jobId: ctx.jobId, message: `${error}` })));
|
|
4054
4374
|
return;
|
|
4055
4375
|
});
|
|
4056
|
-
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(
|
|
4376
|
+
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(Effect24.provideService(Service2, deps.backend)) : run;
|
|
4057
4377
|
}
|
|
4058
|
-
var staleNoOp = (notFound, model) =>
|
|
4378
|
+
var staleNoOp = (notFound, model) => Effect24.gen(function* () {
|
|
4059
4379
|
const backend = yield* Service2;
|
|
4060
4380
|
const db = backend.db;
|
|
4061
|
-
const rows = yield*
|
|
4381
|
+
const rows = yield* Effect24.tryPromise({
|
|
4062
4382
|
try: () => db.select({ topicKey: topics.topicKey }).from(topics).where(and5(eq5(topics.topicKey, notFound.topicKey), eq5(topics.modelKey, model.id))),
|
|
4063
4383
|
catch: (cause) => new StoreError({ message: `maintenance: stale check: ${cause}` })
|
|
4064
4384
|
});
|
|
4065
4385
|
if (rows.length > 0) {
|
|
4066
4386
|
return;
|
|
4067
4387
|
}
|
|
4068
|
-
return yield*
|
|
4069
|
-
}).pipe(
|
|
4388
|
+
return yield* Effect24.fail(new JobFailure({ jobId: notFound.topicKey, message: `topic missing: ${notFound.topicKey}` }));
|
|
4389
|
+
}).pipe(Effect24.mapError((error) => error instanceof JobFailure ? error : new JobFailure({ jobId: notFound.topicKey, message: `${error}` })));
|
|
4070
4390
|
|
|
4071
4391
|
// ../store/src/topics/observability.ts
|
|
4072
|
-
import { Effect as
|
|
4392
|
+
import { Effect as Effect25 } from "effect";
|
|
4073
4393
|
import { and as and6, desc, eq as eq6, inArray as inArray3, ne as ne3, sql as sql5 } from "drizzle-orm";
|
|
4074
4394
|
var DEFAULT_MAX_LEAF_ITEMS3 = 128;
|
|
4075
4395
|
var DEFAULT_SPLIT_DEFERRED_HARD_LIMIT2 = 512;
|
|
4076
4396
|
var DEFAULT_CHANGE_LOG_LIMIT = 50;
|
|
4077
|
-
var routingFailure4 = (tag) => (effect) => effect.pipe(
|
|
4397
|
+
var routingFailure4 = (tag) => (effect) => effect.pipe(Effect25.mapError((cause) => new RoutingFailure({ cause: { operation: tag, cause } })));
|
|
4078
4398
|
var modelTopicKeys = (db, modelKey) => db.select({ topicKey: topics.topicKey }).from(topics).where(eq6(topics.modelKey, modelKey));
|
|
4079
|
-
var topicMetrics =
|
|
4399
|
+
var topicMetrics = Effect25.fn("topics.topicMetrics")(function* (modelKey, config) {
|
|
4080
4400
|
const backend = yield* Service2;
|
|
4081
4401
|
const db = backend.db;
|
|
4082
4402
|
const maxLeafItems = config.maxLeafItems ?? DEFAULT_MAX_LEAF_ITEMS3;
|
|
4083
|
-
const rows = yield*
|
|
4403
|
+
const rows = yield* Effect25.tryPromise({
|
|
4084
4404
|
try: () => db.select({
|
|
4085
4405
|
topicKey: topics.topicKey,
|
|
4086
4406
|
kind: topics.kind,
|
|
@@ -4113,12 +4433,12 @@ var topicMetrics = Effect24.fn("topics.topicMetrics")(function* (modelKey, confi
|
|
|
4113
4433
|
deferredLeaves++;
|
|
4114
4434
|
}
|
|
4115
4435
|
leafMemberCounts.sort((a, b) => a - b);
|
|
4116
|
-
const growth = yield*
|
|
4436
|
+
const growth = yield* Effect25.tryPromise({
|
|
4117
4437
|
try: () => db.select({ total: sql5`coalesce(sum(${topicGrowthState.splitRejectedCount}), 0)` }).from(topicGrowthState).where(eq6(topicGrowthState.modelKey, modelKey)),
|
|
4118
4438
|
catch: (cause) => cause
|
|
4119
4439
|
}).pipe(routingFailure4("topics.topicMetrics.growth"));
|
|
4120
4440
|
const splitRejectedTotal = Number(growth[0]?.total ?? 0);
|
|
4121
|
-
const lastLog = yield*
|
|
4441
|
+
const lastLog = yield* Effect25.tryPromise({
|
|
4122
4442
|
try: () => db.select({
|
|
4123
4443
|
operation: topicChangeLog.operation,
|
|
4124
4444
|
createdAt: topicChangeLog.createdAt
|
|
@@ -4138,11 +4458,11 @@ var topicMetrics = Effect24.fn("topics.topicMetrics")(function* (modelKey, confi
|
|
|
4138
4458
|
lastOperation
|
|
4139
4459
|
};
|
|
4140
4460
|
});
|
|
4141
|
-
var topicChangeLog2 =
|
|
4461
|
+
var topicChangeLog2 = Effect25.fn("topics.topicChangeLog")(function* (modelKey, opts) {
|
|
4142
4462
|
const backend = yield* Service2;
|
|
4143
4463
|
const db = backend.db;
|
|
4144
4464
|
const limit = opts?.limit ?? DEFAULT_CHANGE_LOG_LIMIT;
|
|
4145
|
-
const rows = yield*
|
|
4465
|
+
const rows = yield* Effect25.tryPromise({
|
|
4146
4466
|
try: () => {
|
|
4147
4467
|
const scoped = inArray3(topicChangeLog.topicKey, modelTopicKeys(db, modelKey));
|
|
4148
4468
|
const filtered = opts?.operation ? and6(scoped, eq6(topicChangeLog.operation, opts.operation)) : scoped;
|
|
@@ -4152,14 +4472,14 @@ var topicChangeLog2 = Effect24.fn("topics.topicChangeLog")(function* (modelKey,
|
|
|
4152
4472
|
}).pipe(routingFailure4("topics.topicChangeLog"));
|
|
4153
4473
|
return rows;
|
|
4154
4474
|
});
|
|
4155
|
-
var topicHealth =
|
|
4475
|
+
var topicHealth = Effect25.fn("topics.topicHealth")(function* (modelKey, config) {
|
|
4156
4476
|
const backend = yield* Service2;
|
|
4157
4477
|
const db = backend.db;
|
|
4158
4478
|
const maxLeafItems = config.maxLeafItems ?? DEFAULT_MAX_LEAF_ITEMS3;
|
|
4159
4479
|
const hardLimit = config.splitDeferredHardLimit ?? DEFAULT_SPLIT_DEFERRED_HARD_LIMIT2;
|
|
4160
4480
|
const slack = Math.max(2, Math.ceil(hardLimit / 2) - maxLeafItems);
|
|
4161
4481
|
const leafLimit = maxLeafItems + slack;
|
|
4162
|
-
const rows = yield*
|
|
4482
|
+
const rows = yield* Effect25.tryPromise({
|
|
4163
4483
|
try: () => db.select({
|
|
4164
4484
|
topicKey: topics.topicKey,
|
|
4165
4485
|
kind: topics.kind,
|
|
@@ -4169,7 +4489,7 @@ var topicHealth = Effect24.fn("topics.topicHealth")(function* (modelKey, config)
|
|
|
4169
4489
|
}).from(topics).where(and6(eq6(topics.modelKey, modelKey), ne3(topics.status, "inactive"))),
|
|
4170
4490
|
catch: (cause) => cause
|
|
4171
4491
|
}).pipe(routingFailure4("topics.topicHealth.topics"));
|
|
4172
|
-
const countRows = yield*
|
|
4492
|
+
const countRows = yield* Effect25.tryPromise({
|
|
4173
4493
|
try: () => db.select({ topicKey: topicMemberships.topicKey, count: sql5`count(*)` }).from(topicMemberships).where(eq6(topicMemberships.modelKey, modelKey)).groupBy(topicMemberships.topicKey),
|
|
4174
4494
|
catch: (cause) => cause
|
|
4175
4495
|
}).pipe(routingFailure4("topics.topicHealth.memberships"));
|
|
@@ -4194,30 +4514,30 @@ var topicHealth = Effect24.fn("topics.topicHealth")(function* (modelKey, config)
|
|
|
4194
4514
|
});
|
|
4195
4515
|
|
|
4196
4516
|
// ../store/src/graph/observability.ts
|
|
4197
|
-
import { Effect as
|
|
4517
|
+
import { Effect as Effect26 } from "effect";
|
|
4198
4518
|
import { and as and7, eq as eq7, isNull, sql as sql6 } from "drizzle-orm";
|
|
4199
|
-
var graphCoverage =
|
|
4519
|
+
var graphCoverage = Effect26.fn("GraphCoverage.run")(function* (modelKey) {
|
|
4200
4520
|
const backend = yield* Service2;
|
|
4201
4521
|
const db = backend.db;
|
|
4202
|
-
const totalRows = yield*
|
|
4522
|
+
const totalRows = yield* Effect26.tryPromise({
|
|
4203
4523
|
try: () => db.select({ id: memories.id }).from(memories).where(and7(eq7(memories.state, "active"), eq7(memories.embeddingModel, modelKey))),
|
|
4204
4524
|
catch: (cause) => new StoreError({ message: `graphCoverage: total: ${cause}` })
|
|
4205
4525
|
});
|
|
4206
4526
|
const totalMemories = totalRows.length;
|
|
4207
|
-
const isolatedRows = yield* backend.listIsolatedMemories(0, modelKey).pipe(
|
|
4527
|
+
const isolatedRows = yield* backend.listIsolatedMemories(0, modelKey).pipe(Effect26.mapError((cause) => new StoreError({ message: `graphCoverage: isolated: ${cause}` })));
|
|
4208
4528
|
const isolatedMemories = isolatedRows.length;
|
|
4209
4529
|
const coveredMemories = totalMemories - isolatedMemories;
|
|
4210
4530
|
const coveragePercent = totalMemories === 0 ? 0 : Math.round(coveredMemories / totalMemories * 1000) / 10;
|
|
4211
|
-
const pendingRows = yield*
|
|
4531
|
+
const pendingRows = yield* Effect26.tryPromise({
|
|
4212
4532
|
try: () => db.select({ count: sql6`count(*)` }).from(artifactEdges).where(and7(eq7(artifactEdges.status, "pending"), isNull(artifactEdges.expiredAt))),
|
|
4213
4533
|
catch: (cause) => new StoreError({ message: `graphCoverage: pending: ${cause}` })
|
|
4214
4534
|
});
|
|
4215
4535
|
const pendingCandidates = totalMemories === 0 ? 0 : Number(pendingRows[0]?.count ?? 0);
|
|
4216
|
-
const conceptCount = totalMemories === 0 ? 0 : (yield*
|
|
4536
|
+
const conceptCount = totalMemories === 0 ? 0 : (yield* Effect26.tryPromise({
|
|
4217
4537
|
try: () => db.select({ id: concepts.id }).from(concepts),
|
|
4218
4538
|
catch: (cause) => new StoreError({ message: `graphCoverage: concepts: ${cause}` })
|
|
4219
4539
|
})).length;
|
|
4220
|
-
const annotatedMemories = totalMemories === 0 ? 0 : new Set((yield*
|
|
4540
|
+
const annotatedMemories = totalMemories === 0 ? 0 : new Set((yield* Effect26.tryPromise({
|
|
4221
4541
|
try: () => db.select({ memoryId: memoryConcepts.memoryId }).from(memoryConcepts),
|
|
4222
4542
|
catch: (cause) => new StoreError({ message: `graphCoverage: annotations: ${cause}` })
|
|
4223
4543
|
})).map((row) => row.memoryId)).size;
|
|
@@ -4447,27 +4767,25 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4447
4767
|
const db = backend.db;
|
|
4448
4768
|
const topicsConfig = topicsOptions?.config ?? Schema19.decodeUnknownSync(TopicConfig)({});
|
|
4449
4769
|
const topicsEnabled = topicsOptions?.enabled ?? false;
|
|
4450
|
-
const updateTopicVectorForget = (backendImpl, model, topicKey, x) =>
|
|
4451
|
-
const
|
|
4452
|
-
const current = rows.find((r) => r.topicKey === topicKey);
|
|
4770
|
+
const updateTopicVectorForget = (backendImpl, model, topicKey, x) => Effect27.gen(function* () {
|
|
4771
|
+
const current = yield* backendImpl.fetchTopicVector(topicKey, model).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.forget: load vector: ${cause}` })));
|
|
4453
4772
|
const ls = current ? new Float32Array(current.sumVector) : new Float32Array(model.dimensions);
|
|
4454
4773
|
for (let i = 0;i < ls.length; i++)
|
|
4455
4774
|
ls[i] = ls[i] - x[i];
|
|
4456
|
-
yield* backendImpl.upsertTopicVector(topicKey, Array.from(ls), model).pipe(
|
|
4457
|
-
const relRows = yield*
|
|
4775
|
+
yield* backendImpl.upsertTopicVector(topicKey, Array.from(ls), model).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.forget: write vector: ${cause}` })));
|
|
4776
|
+
const relRows = yield* Effect27.tryPromise({
|
|
4458
4777
|
try: () => db.select({ parentKey: topicRelations.parentKey }).from(topicRelations).where(and8(eq8(topicRelations.childKey, topicKey), eq8(topicRelations.modelKey, model.id), eq8(topicRelations.relationKind, "parent_child"))),
|
|
4459
4778
|
catch: (cause) => new StoreError({ message: `Store.forget: load ancestor: ${cause}` })
|
|
4460
4779
|
});
|
|
4461
4780
|
let ancestorKey = relRows[0]?.parentKey;
|
|
4462
4781
|
while (ancestorKey !== undefined) {
|
|
4463
4782
|
const key = ancestorKey;
|
|
4464
|
-
const
|
|
4465
|
-
const a = aRows.find((r) => r.topicKey === key);
|
|
4783
|
+
const a = yield* backendImpl.fetchTopicVector(key, model).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.forget: load vector: ${cause}` })));
|
|
4466
4784
|
const als = a ? new Float32Array(a.sumVector) : new Float32Array(model.dimensions);
|
|
4467
4785
|
for (let i = 0;i < als.length; i++)
|
|
4468
4786
|
als[i] = als[i] - x[i];
|
|
4469
|
-
yield* backendImpl.upsertTopicVector(key, Array.from(als), model).pipe(
|
|
4470
|
-
const up = yield*
|
|
4787
|
+
yield* backendImpl.upsertTopicVector(key, Array.from(als), model).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.forget: write vector: ${cause}` })));
|
|
4788
|
+
const up = yield* Effect27.tryPromise({
|
|
4471
4789
|
try: () => db.select({ parentKey: topicRelations.parentKey }).from(topicRelations).where(and8(eq8(topicRelations.childKey, key), eq8(topicRelations.modelKey, model.id), eq8(topicRelations.relationKind, "parent_child"))),
|
|
4472
4790
|
catch: (cause) => new StoreError({ message: `Store.forget: load ancestor: ${cause}` })
|
|
4473
4791
|
});
|
|
@@ -4517,18 +4835,18 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4517
4835
|
};
|
|
4518
4836
|
const seam = auditOptions?.enqueueAudit;
|
|
4519
4837
|
if (seam !== undefined) {
|
|
4520
|
-
return propagateSeam ? seam(row).pipe(
|
|
4838
|
+
return propagateSeam ? seam(row).pipe(Effect27.mapError((cause) => new StoreError({ message: `audit.enqueue-failed: ${cause}` }))) : seam(row).pipe(Effect27.catch((cause) => Effect27.logError("audit.enqueue-failed").pipe(Effect27.annotateLogs({
|
|
4521
4839
|
scope: "@dimple/store",
|
|
4522
4840
|
event: "audit.enqueue-failed",
|
|
4523
4841
|
mode,
|
|
4524
4842
|
cause: String(cause)
|
|
4525
4843
|
}))));
|
|
4526
4844
|
}
|
|
4527
|
-
return
|
|
4845
|
+
return Effect27.sync(() => {
|
|
4528
4846
|
db.insert(retrievalLog2).values(row).catch(() => {});
|
|
4529
4847
|
});
|
|
4530
4848
|
};
|
|
4531
|
-
const logAudit =
|
|
4849
|
+
const logAudit = Effect27.fn("Store.logAudit")(function* (input) {
|
|
4532
4850
|
return yield* logRetrieval(input.query, input.namespace, input.mode, input.resultCount, input.startTime, input.queryProfile, input.sources, input.hashSeed, true);
|
|
4533
4851
|
});
|
|
4534
4852
|
const GRAPH_SUPERSEDE_DEMOTION = graphConfig?.supersedeDemotion ?? 0.5;
|
|
@@ -4536,9 +4854,10 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4536
4854
|
nearDuplicate: 0.9,
|
|
4537
4855
|
conflictLow: 0.6
|
|
4538
4856
|
};
|
|
4857
|
+
const graphEnabled = graphConfig?.enabled !== false;
|
|
4539
4858
|
const GRAPH_CANDIDATE_LIMIT_MAX = 200;
|
|
4540
4859
|
const GRAPH_ISOLATED_EXAMPLES = 10;
|
|
4541
|
-
const fetchResultEdges = (ids) =>
|
|
4860
|
+
const fetchResultEdges = (ids) => Effect27.tryPromise({
|
|
4542
4861
|
try: () => db.select({
|
|
4543
4862
|
fromMemoryId: artifactEdges.fromMemoryId,
|
|
4544
4863
|
toMemoryId: artifactEdges.toMemoryId,
|
|
@@ -4547,11 +4866,11 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4547
4866
|
}).from(artifactEdges).where(and8(or(inArray4(artifactEdges.fromMemoryId, ids), inArray4(artifactEdges.toMemoryId, ids)), ne4(artifactEdges.status, "rejected"), isNull2(artifactEdges.expiredAt))),
|
|
4548
4867
|
catch: (cause) => new StoreError({ message: `Store.retrieval post-pass: edges: ${cause}` })
|
|
4549
4868
|
});
|
|
4550
|
-
const fetchResultConcepts = (ids) =>
|
|
4869
|
+
const fetchResultConcepts = (ids) => Effect27.tryPromise({
|
|
4551
4870
|
try: () => db.select({ memoryId: memoryConcepts2.memoryId, conceptId: memoryConcepts2.conceptId }).from(memoryConcepts2).where(inArray4(memoryConcepts2.memoryId, ids)),
|
|
4552
4871
|
catch: (cause) => new StoreError({ message: `Store.retrieval post-pass: concepts: ${cause}` })
|
|
4553
4872
|
});
|
|
4554
|
-
const augmentRetrieval = (results) =>
|
|
4873
|
+
const augmentRetrieval = (results) => Effect27.gen(function* () {
|
|
4555
4874
|
if (results.length === 0)
|
|
4556
4875
|
return results;
|
|
4557
4876
|
const ids = results.map((r) => r.memory.id);
|
|
@@ -4561,6 +4880,9 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4561
4880
|
supersedeDemotion: GRAPH_SUPERSEDE_DEMOTION
|
|
4562
4881
|
});
|
|
4563
4882
|
});
|
|
4883
|
+
const augmentSearchResults = Effect27.fn("Store.augmentSearchResults")(function* (results) {
|
|
4884
|
+
return yield* augmentRetrieval(results);
|
|
4885
|
+
});
|
|
4564
4886
|
const EDGE_KINDS = [
|
|
4565
4887
|
"memory_supports",
|
|
4566
4888
|
"memory_supersedes",
|
|
@@ -4568,7 +4890,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4568
4890
|
"code_calls"
|
|
4569
4891
|
];
|
|
4570
4892
|
const EDGE_SOURCES = ["rule", "llm", "agent"];
|
|
4571
|
-
const write =
|
|
4893
|
+
const write = Effect27.fn("Store.write")(function* (input) {
|
|
4572
4894
|
if (input.content.includes("\x00")) {
|
|
4573
4895
|
return yield* new StoreError({
|
|
4574
4896
|
message: "Store.write: content contains a NUL byte (libSQL would silently truncate it)"
|
|
@@ -4577,7 +4899,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4577
4899
|
const id = crypto.randomUUID();
|
|
4578
4900
|
const now = Date.now();
|
|
4579
4901
|
const metadataBlob = input.typedMetadata !== undefined ? mergeMetadataBlob(input.metadata, input.typedMetadata) : input.metadata ?? null;
|
|
4580
|
-
yield*
|
|
4902
|
+
yield* Effect27.tryPromise({
|
|
4581
4903
|
try: () => db.transaction(async (tx) => {
|
|
4582
4904
|
await tx.insert(memories2).values({
|
|
4583
4905
|
id,
|
|
@@ -4610,8 +4932,60 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4610
4932
|
embeddingModel: undefined
|
|
4611
4933
|
};
|
|
4612
4934
|
});
|
|
4613
|
-
const
|
|
4614
|
-
|
|
4935
|
+
const writeMany = Effect27.fn("Store.writeMany")(function* (inputs) {
|
|
4936
|
+
if (inputs.length === 0)
|
|
4937
|
+
return [];
|
|
4938
|
+
for (const input of inputs) {
|
|
4939
|
+
if (input.content.includes("\x00")) {
|
|
4940
|
+
return yield* new StoreError({
|
|
4941
|
+
message: "Store.writeMany: content contains a NUL byte (libSQL would silently truncate it)"
|
|
4942
|
+
});
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
const now = Date.now();
|
|
4946
|
+
const rows = inputs.map((input) => {
|
|
4947
|
+
const metadataBlob = input.typedMetadata !== undefined ? mergeMetadataBlob(input.metadata, input.typedMetadata) : input.metadata ?? null;
|
|
4948
|
+
return {
|
|
4949
|
+
id: crypto.randomUUID(),
|
|
4950
|
+
logicalKey: input.logicalKey,
|
|
4951
|
+
content: input.content,
|
|
4952
|
+
contentType: input.contentType ?? "text/plain",
|
|
4953
|
+
createdAt: now,
|
|
4954
|
+
ttlSecs: input.ttlSecs === null ? null : input.ttlSecs ?? defaultTtlSecs,
|
|
4955
|
+
namespace: input.namespace ?? "default",
|
|
4956
|
+
metadata: metadataBlob
|
|
4957
|
+
};
|
|
4958
|
+
});
|
|
4959
|
+
yield* Effect27.tryPromise({
|
|
4960
|
+
try: () => db.transaction(async (tx) => {
|
|
4961
|
+
await tx.insert(memories2).values(rows);
|
|
4962
|
+
await tx.insert(memoryEvents2).values(rows.map((row) => ({
|
|
4963
|
+
memoryId: row.id,
|
|
4964
|
+
eventType: "created",
|
|
4965
|
+
createdAt: now
|
|
4966
|
+
})));
|
|
4967
|
+
}),
|
|
4968
|
+
catch: (cause) => backend.isUniqueViolation(cause) ? new DuplicateActiveKey({
|
|
4969
|
+
logicalKey: inputs[0].logicalKey,
|
|
4970
|
+
namespace: inputs[0].namespace ?? "default"
|
|
4971
|
+
}) : new StoreError({ message: `Store.writeMany: ${cause}` })
|
|
4972
|
+
});
|
|
4973
|
+
return rows.map((row) => ({
|
|
4974
|
+
id: row.id,
|
|
4975
|
+
logicalKey: row.logicalKey,
|
|
4976
|
+
content: row.content,
|
|
4977
|
+
contentType: row.contentType,
|
|
4978
|
+
state: "active",
|
|
4979
|
+
createdAt: row.createdAt,
|
|
4980
|
+
ttlSecs: row.ttlSecs,
|
|
4981
|
+
namespace: row.namespace,
|
|
4982
|
+
metadata: row.metadata ?? undefined,
|
|
4983
|
+
embedding: undefined,
|
|
4984
|
+
embeddingModel: undefined
|
|
4985
|
+
}));
|
|
4986
|
+
});
|
|
4987
|
+
const get = Effect27.fn("Store.get")(function* (id) {
|
|
4988
|
+
const rows = yield* Effect27.tryPromise({
|
|
4615
4989
|
try: () => db.select(memoryFields).from(memories2).where(eq8(memories2.id, id)).limit(1),
|
|
4616
4990
|
catch: (cause) => new StoreError({ message: `Store.get: ${cause}` })
|
|
4617
4991
|
});
|
|
@@ -4620,8 +4994,8 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4620
4994
|
return yield* new NotFound({ id });
|
|
4621
4995
|
return fromMemoryRow(row);
|
|
4622
4996
|
});
|
|
4623
|
-
const getByKey =
|
|
4624
|
-
const rows = yield*
|
|
4997
|
+
const getByKey = Effect27.fn("Store.getByKey")(function* (key, namespace) {
|
|
4998
|
+
const rows = yield* Effect27.tryPromise({
|
|
4625
4999
|
try: () => db.select(memoryFields).from(memories2).where(and8(eq8(memories2.logicalKey, key), eq8(memories2.namespace, namespace), eq8(memories2.state, "active"))).orderBy(desc2(memories2.createdAt)).limit(1),
|
|
4626
5000
|
catch: (cause) => new StoreError({ message: `Store.getByKey: ${cause}` })
|
|
4627
5001
|
});
|
|
@@ -4630,9 +5004,9 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4630
5004
|
return yield* new NotFound({ id: key });
|
|
4631
5005
|
return fromMemoryRow(row);
|
|
4632
5006
|
});
|
|
4633
|
-
const recency =
|
|
5007
|
+
const recency = Effect27.fn("Store.recency")(function* (namespace, limit) {
|
|
4634
5008
|
const start = Date.now();
|
|
4635
|
-
const rows = yield*
|
|
5009
|
+
const rows = yield* Effect27.tryPromise({
|
|
4636
5010
|
try: () => db.select(memoryFields).from(memories2).where(and8(eq8(memories2.namespace, namespace), eq8(memories2.state, "active"))).orderBy(desc2(memories2.createdAt)).limit(limit),
|
|
4637
5011
|
catch: (cause) => new StoreError({ message: `Store.recency: ${cause}` })
|
|
4638
5012
|
});
|
|
@@ -4645,9 +5019,9 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4645
5019
|
yield* logRetrieval(namespace, namespace, "recency", results.length, start);
|
|
4646
5020
|
return yield* augmentRetrieval(results);
|
|
4647
5021
|
});
|
|
4648
|
-
const searchFts5 =
|
|
5022
|
+
const searchFts5 = Effect27.fn("Store.searchFts5")(function* (query, namespace, limit, opts) {
|
|
4649
5023
|
const start = Date.now();
|
|
4650
|
-
const rows = yield* backend.ftsSearch(query, namespace, limit, opts?.topicKeys, modelConfig?.id, opts?.contentType);
|
|
5024
|
+
const rows = yield* backend.ftsSearch(query, namespace, limit, opts?.topicKeys, modelConfig?.id, opts?.contentType, opts?.includeEmbedding === true);
|
|
4651
5025
|
if (opts?.audit !== false) {
|
|
4652
5026
|
yield* logRetrieval(query, namespace, "fts", rows.length, start);
|
|
4653
5027
|
}
|
|
@@ -4664,7 +5038,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4664
5038
|
ttlSecs: r.ttl_secs,
|
|
4665
5039
|
namespace: r.namespace,
|
|
4666
5040
|
metadata: r.metadata ?? undefined,
|
|
4667
|
-
embedding: decodeBlobVector(r.embedding),
|
|
5041
|
+
embedding: opts?.includeEmbedding === true ? decodeBlobVector(r.embedding) : undefined,
|
|
4668
5042
|
embeddingModel: r.embedding_model ?? undefined
|
|
4669
5043
|
},
|
|
4670
5044
|
score: -r.rank,
|
|
@@ -4672,9 +5046,11 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4672
5046
|
source: "fts5"
|
|
4673
5047
|
};
|
|
4674
5048
|
});
|
|
5049
|
+
if (opts?.augment === false)
|
|
5050
|
+
return results;
|
|
4675
5051
|
return yield* augmentRetrieval(results);
|
|
4676
5052
|
});
|
|
4677
|
-
const searchVector =
|
|
5053
|
+
const searchVector = Effect27.fn("Store.searchVector")(function* (query, namespace, limit, opts) {
|
|
4678
5054
|
if (!modelConfig) {
|
|
4679
5055
|
return yield* new StoreError({
|
|
4680
5056
|
message: "Store.searchVector: no embedding model configured"
|
|
@@ -4684,13 +5060,13 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4684
5060
|
let allowedMemoryIds;
|
|
4685
5061
|
const conceptIds = opts?.conceptIds;
|
|
4686
5062
|
if (conceptIds !== undefined && conceptIds.length > 0) {
|
|
4687
|
-
const conceptRows = yield*
|
|
5063
|
+
const conceptRows = yield* Effect27.tryPromise({
|
|
4688
5064
|
try: () => db.select({ memoryId: memoryConcepts2.memoryId }).from(memoryConcepts2).where(inArray4(memoryConcepts2.conceptId, conceptIds)),
|
|
4689
5065
|
catch: (cause) => new StoreError({ message: `Store.searchVector: concepts: ${cause}` })
|
|
4690
5066
|
});
|
|
4691
5067
|
allowedMemoryIds = new Set(conceptRows.map((r) => r.memoryId));
|
|
4692
5068
|
}
|
|
4693
|
-
const rows = yield* backend.vectorSearch(query, namespace, limit, modelConfig, opts?.topicKeys, opts?.contentType);
|
|
5069
|
+
const rows = yield* backend.vectorSearch(query, namespace, limit, modelConfig, opts?.topicKeys, opts?.contentType, opts?.includeEmbedding === true);
|
|
4694
5070
|
const allowed = allowedMemoryIds;
|
|
4695
5071
|
const scopedRows = allowed !== undefined ? rows.filter((row) => allowed.has(row.id)) : rows;
|
|
4696
5072
|
if (opts?.audit !== false) {
|
|
@@ -4709,7 +5085,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4709
5085
|
ttlSecs: r.ttl_secs,
|
|
4710
5086
|
namespace: r.namespace,
|
|
4711
5087
|
metadata: r.metadata ?? undefined,
|
|
4712
|
-
embedding: decodeBlobVector(r.embedding),
|
|
5088
|
+
embedding: opts?.includeEmbedding === true ? decodeBlobVector(r.embedding) : undefined,
|
|
4713
5089
|
embeddingModel: r.embedding_model ?? undefined
|
|
4714
5090
|
},
|
|
4715
5091
|
score: 1 - r.distance,
|
|
@@ -4717,11 +5093,13 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4717
5093
|
source: "vector"
|
|
4718
5094
|
};
|
|
4719
5095
|
});
|
|
5096
|
+
if (opts?.augment === false)
|
|
5097
|
+
return results;
|
|
4720
5098
|
return yield* augmentRetrieval(results);
|
|
4721
5099
|
});
|
|
4722
|
-
const supersede =
|
|
5100
|
+
const supersede = Effect27.fn("Store.supersede")(function* (key, namespace) {
|
|
4723
5101
|
const now = Date.now();
|
|
4724
|
-
const result = yield*
|
|
5102
|
+
const result = yield* Effect27.tryPromise({
|
|
4725
5103
|
try: () => db.transaction(async (tx) => {
|
|
4726
5104
|
const active = await tx.select({ id: memories2.id }).from(memories2).where(and8(eq8(memories2.logicalKey, key), eq8(memories2.namespace, namespace), eq8(memories2.state, "active"))).limit(1);
|
|
4727
5105
|
if (active.length === 0)
|
|
@@ -4733,7 +5111,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4733
5111
|
if (!result)
|
|
4734
5112
|
return yield* new NotFound({ id: key });
|
|
4735
5113
|
});
|
|
4736
|
-
const decrementTreeCf = (model, membership, x) =>
|
|
5114
|
+
const decrementTreeCf = (model, membership, x) => Effect27.tryPromise({
|
|
4737
5115
|
try: () => db.transaction(async (tx) => {
|
|
4738
5116
|
const leafRows = await tx.select({
|
|
4739
5117
|
topicKey: topics.topicKey,
|
|
@@ -4763,10 +5141,10 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4763
5141
|
}),
|
|
4764
5142
|
catch: (cause) => new StoreError({ message: `Store: tree CF decrement: ${cause}` })
|
|
4765
5143
|
});
|
|
4766
|
-
const forget =
|
|
5144
|
+
const forget = Effect27.fn("Store.forget")(function* (id) {
|
|
4767
5145
|
let membership;
|
|
4768
5146
|
if (topicsEnabled) {
|
|
4769
|
-
const memberRows = yield*
|
|
5147
|
+
const memberRows = yield* Effect27.tryPromise({
|
|
4770
5148
|
try: () => db.select({ topicKey: topicMemberships.topicKey, modelKey: topicMemberships.modelKey }).from(topicMemberships).where(eq8(topicMemberships.memoryId, id)),
|
|
4771
5149
|
catch: (cause) => new StoreError({ message: `Store.forget: load membership: ${cause}` })
|
|
4772
5150
|
});
|
|
@@ -4781,14 +5159,14 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4781
5159
|
}
|
|
4782
5160
|
}
|
|
4783
5161
|
}
|
|
4784
|
-
const rs = yield*
|
|
5162
|
+
const rs = yield* Effect27.tryPromise({
|
|
4785
5163
|
try: () => db.delete(memories2).where(eq8(memories2.id, id)),
|
|
4786
5164
|
catch: (cause) => new StoreError({ message: `Store.forget: ${cause}` })
|
|
4787
5165
|
});
|
|
4788
5166
|
if (rs.rowsAffected === 0)
|
|
4789
5167
|
return yield* new NotFound({ id });
|
|
4790
5168
|
if (topicsEnabled && membership && modelConfig && modelConfig.id === membership.modelKey) {
|
|
4791
|
-
const leafRows = yield*
|
|
5169
|
+
const leafRows = yield* Effect27.tryPromise({
|
|
4792
5170
|
try: () => db.select({ memberCount: topics.memberCount }).from(topics).where(and8(eq8(topics.topicKey, membership.topicKey), eq8(topics.modelKey, membership.modelKey))),
|
|
4793
5171
|
catch: (cause) => new StoreError({ message: `Store.forget: load leaf: ${cause}` })
|
|
4794
5172
|
});
|
|
@@ -4796,18 +5174,18 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4796
5174
|
if (liveCount < (topicsConfig.minLeafItems ?? 32)) {
|
|
4797
5175
|
const enqueueMerge = topicsOptions?.enqueueMerge;
|
|
4798
5176
|
if (enqueueMerge) {
|
|
4799
|
-
yield* enqueueMerge(membership.topicKey, membership.modelKey).pipe(
|
|
5177
|
+
yield* enqueueMerge(membership.topicKey, membership.modelKey).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.forget enqueueMerge: ${cause}` })));
|
|
4800
5178
|
} else {
|
|
4801
|
-
yield* mergeOrBorrow(membership.topicKey, modelConfig, topicsConfig).pipe(
|
|
5179
|
+
yield* mergeOrBorrow(membership.topicKey, modelConfig, topicsConfig).pipe(Effect27.provideService(Service2, backend), Effect27.mapError((cause) => new StoreError({ message: `Store.forget mergeOrBorrow: ${cause}` })));
|
|
4802
5180
|
}
|
|
4803
5181
|
}
|
|
4804
5182
|
}
|
|
4805
5183
|
});
|
|
4806
|
-
const sweep =
|
|
5184
|
+
const sweep = Effect27.fn("Store.sweep")(function* (namespace) {
|
|
4807
5185
|
return yield* backend.sweep(namespace);
|
|
4808
5186
|
});
|
|
4809
|
-
const events =
|
|
4810
|
-
const rows = yield*
|
|
5187
|
+
const events = Effect27.fn("Store.events")(function* (memoryId) {
|
|
5188
|
+
const rows = yield* Effect27.tryPromise({
|
|
4811
5189
|
try: () => db.select().from(memoryEvents2).where(eq8(memoryEvents2.memoryId, memoryId)).orderBy(asc5(memoryEvents2.createdAt)),
|
|
4812
5190
|
catch: (cause) => new StoreError({ message: `Store.events: ${cause}` })
|
|
4813
5191
|
});
|
|
@@ -4822,7 +5200,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4822
5200
|
}));
|
|
4823
5201
|
});
|
|
4824
5202
|
const resolveModel = (modelKey) => modelConfig?.id === modelKey ? modelConfig : undefined;
|
|
4825
|
-
const ensureTopicTree2 =
|
|
5203
|
+
const ensureTopicTree2 = Effect27.fn("Store.ensureTopicTree")(function* (modelKey) {
|
|
4826
5204
|
const model = resolveModel(modelKey);
|
|
4827
5205
|
if (!model) {
|
|
4828
5206
|
return yield* new ModelMismatch({
|
|
@@ -4830,33 +5208,33 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4830
5208
|
actual: modelKey
|
|
4831
5209
|
});
|
|
4832
5210
|
}
|
|
4833
|
-
return yield* ensureTopicTree(model, topicsConfig).pipe(
|
|
5211
|
+
return yield* ensureTopicTree(model, topicsConfig).pipe(Effect27.provideService(Service2, backend));
|
|
4834
5212
|
});
|
|
4835
|
-
const resolveTopics2 =
|
|
5213
|
+
const resolveTopics2 = Effect27.fn("Store.resolveTopics")(function* (queryVector, opts) {
|
|
4836
5214
|
if (!modelConfig) {
|
|
4837
5215
|
return yield* new ModelMismatch({
|
|
4838
5216
|
expected: "a configured embedding model",
|
|
4839
5217
|
actual: "(none)"
|
|
4840
5218
|
});
|
|
4841
5219
|
}
|
|
4842
|
-
return yield* resolveTopics(queryVector, modelConfig, topicsConfig, opts).pipe(
|
|
5220
|
+
return yield* resolveTopics(queryVector, modelConfig, topicsConfig, opts).pipe(Effect27.provideService(Service2, backend));
|
|
4843
5221
|
});
|
|
4844
|
-
const topicMembers =
|
|
4845
|
-
const rows = yield*
|
|
5222
|
+
const topicMembers = Effect27.fn("Store.topicMembers")(function* (topicKey) {
|
|
5223
|
+
const rows = yield* Effect27.tryPromise({
|
|
4846
5224
|
try: () => db.select({ memoryId: topicMemberships.memoryId }).from(topicMemberships).where(eq8(topicMemberships.topicKey, topicKey)).orderBy(asc5(topicMemberships.memoryId)),
|
|
4847
5225
|
catch: (cause) => new StoreError({ message: `Store.topicMembers: ${cause}` })
|
|
4848
5226
|
});
|
|
4849
5227
|
return rows;
|
|
4850
5228
|
});
|
|
4851
|
-
const listTopics =
|
|
4852
|
-
const rows = yield*
|
|
5229
|
+
const listTopics = Effect27.fn("Store.listTopics")(function* (modelKey) {
|
|
5230
|
+
const rows = yield* Effect27.tryPromise({
|
|
4853
5231
|
try: () => db.select().from(topics).where(eq8(topics.modelKey, modelKey)).orderBy(asc5(topics.topicKey)),
|
|
4854
5232
|
catch: (cause) => new StoreError({ message: `Store.listTopics: ${cause}` })
|
|
4855
5233
|
});
|
|
4856
5234
|
return rows;
|
|
4857
5235
|
});
|
|
4858
|
-
const topicStats =
|
|
4859
|
-
const rows = yield*
|
|
5236
|
+
const topicStats = Effect27.fn("Store.topicStats")(function* (modelKey) {
|
|
5237
|
+
const rows = yield* Effect27.tryPromise({
|
|
4860
5238
|
try: () => db.select({ kind: topics.kind, depth: topics.depth }).from(topics).where(eq8(topics.modelKey, modelKey)),
|
|
4861
5239
|
catch: (cause) => new StoreError({ message: `Store.topicStats: ${cause}` })
|
|
4862
5240
|
});
|
|
@@ -4873,7 +5251,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4873
5251
|
}
|
|
4874
5252
|
return { depth, leafCount, internalCount, totalTopics: rows.length };
|
|
4875
5253
|
});
|
|
4876
|
-
const deleteTree =
|
|
5254
|
+
const deleteTree = Effect27.fn("Store.deleteTree")(function* (modelKey) {
|
|
4877
5255
|
const model = resolveModel(modelKey);
|
|
4878
5256
|
if (!model) {
|
|
4879
5257
|
return yield* new ModelMismatch({
|
|
@@ -4882,7 +5260,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4882
5260
|
});
|
|
4883
5261
|
}
|
|
4884
5262
|
yield* backend.deleteTopicVectors(model);
|
|
4885
|
-
yield*
|
|
5263
|
+
yield* Effect27.tryPromise({
|
|
4886
5264
|
try: () => db.transaction(async (tx) => {
|
|
4887
5265
|
const modelTopicKeys2 = tx.select({ topicKey: topics.topicKey }).from(topics).where(eq8(topics.modelKey, modelKey));
|
|
4888
5266
|
await tx.delete(topicChangeLog).where(inArray4(topicChangeLog.topicKey, modelTopicKeys2));
|
|
@@ -4894,7 +5272,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4894
5272
|
catch: (cause) => new StoreError({ message: `Store.deleteTree: ${cause}` })
|
|
4895
5273
|
});
|
|
4896
5274
|
});
|
|
4897
|
-
const processSplits =
|
|
5275
|
+
const processSplits = Effect27.fn("Store.processSplits")(function* (modelKey) {
|
|
4898
5276
|
const model = resolveModel(modelKey);
|
|
4899
5277
|
if (!model) {
|
|
4900
5278
|
return yield* new ModelMismatch({
|
|
@@ -4904,19 +5282,19 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4904
5282
|
}
|
|
4905
5283
|
let processed = 0;
|
|
4906
5284
|
for (let iteration = 0;iteration < 100; iteration++) {
|
|
4907
|
-
const leaves = yield*
|
|
5285
|
+
const leaves = yield* Effect27.tryPromise({
|
|
4908
5286
|
try: () => db.select({ topicKey: topics.topicKey, memberCount: topics.memberCount }).from(topics).where(and8(eq8(topics.modelKey, modelKey), eq8(topics.kind, "leaf"), ne4(topics.status, "inactive"))).orderBy(asc5(topics.topicKey)),
|
|
4909
5287
|
catch: (cause) => new StoreError({ message: `Store.processSplits: ${cause}` })
|
|
4910
5288
|
});
|
|
4911
5289
|
const candidate = leaves.find((leaf) => shouldSplit(leaf.memberCount, topicsConfig));
|
|
4912
5290
|
if (!candidate)
|
|
4913
5291
|
break;
|
|
4914
|
-
yield* splitTopic(candidate.topicKey, model, topicsConfig).pipe(
|
|
5292
|
+
yield* splitTopic(candidate.topicKey, model, topicsConfig).pipe(Effect27.provideService(Service2, backend), Effect27.mapError((cause) => new StoreError({ message: `Store.processSplits: ${cause}` })));
|
|
4915
5293
|
processed++;
|
|
4916
5294
|
}
|
|
4917
5295
|
return processed;
|
|
4918
5296
|
});
|
|
4919
|
-
const mergeOrBorrow2 =
|
|
5297
|
+
const mergeOrBorrow2 = Effect27.fn("Store.mergeOrBorrow")(function* (modelKey, topicKey) {
|
|
4920
5298
|
const model = resolveModel(modelKey);
|
|
4921
5299
|
if (!model) {
|
|
4922
5300
|
return yield* new ModelMismatch({
|
|
@@ -4924,9 +5302,9 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4924
5302
|
actual: modelKey
|
|
4925
5303
|
});
|
|
4926
5304
|
}
|
|
4927
|
-
return yield* mergeOrBorrow(topicKey, model, topicsConfig).pipe(
|
|
5305
|
+
return yield* mergeOrBorrow(topicKey, model, topicsConfig).pipe(Effect27.provideService(Service2, backend), Effect27.mapError((cause) => new StoreError({ message: `Store.mergeOrBorrow: ${cause}` })));
|
|
4928
5306
|
});
|
|
4929
|
-
const rebalanceSiblings2 =
|
|
5307
|
+
const rebalanceSiblings2 = Effect27.fn("Store.rebalanceSiblings")(function* (modelKey, topicKey) {
|
|
4930
5308
|
const model = resolveModel(modelKey);
|
|
4931
5309
|
if (!model) {
|
|
4932
5310
|
return yield* new ModelMismatch({
|
|
@@ -4934,15 +5312,15 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4934
5312
|
actual: modelKey
|
|
4935
5313
|
});
|
|
4936
5314
|
}
|
|
4937
|
-
return yield* rebalanceSiblings(topicKey, model, topicsConfig).pipe(
|
|
5315
|
+
return yield* rebalanceSiblings(topicKey, model, topicsConfig).pipe(Effect27.provideService(Service2, backend), Effect27.mapError((cause) => new StoreError({ message: `Store.rebalanceSiblings: ${cause}` })));
|
|
4938
5316
|
});
|
|
4939
|
-
const setActiveModel2 =
|
|
4940
|
-
return yield* setActiveModel(model, topicsConfig).pipe(
|
|
5317
|
+
const setActiveModel2 = Effect27.fn("Store.setActiveModel")(function* (model) {
|
|
5318
|
+
return yield* setActiveModel(model, topicsConfig).pipe(Effect27.provideService(Service2, backend));
|
|
4941
5319
|
});
|
|
4942
|
-
const isActive2 =
|
|
4943
|
-
return yield* isActive(modelKey).pipe(
|
|
5320
|
+
const isActive2 = Effect27.fn("Store.isActive")(function* (modelKey) {
|
|
5321
|
+
return yield* isActive(modelKey).pipe(Effect27.provideService(Service2, backend));
|
|
4944
5322
|
});
|
|
4945
|
-
const topicMetrics2 =
|
|
5323
|
+
const topicMetrics2 = Effect27.fn("Store.topicMetrics")(function* (modelKey) {
|
|
4946
5324
|
const model = resolveModel(modelKey);
|
|
4947
5325
|
if (!model) {
|
|
4948
5326
|
return yield* new ModelMismatch({
|
|
@@ -4950,9 +5328,9 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4950
5328
|
actual: modelKey
|
|
4951
5329
|
});
|
|
4952
5330
|
}
|
|
4953
|
-
return yield* topicMetrics(modelKey, topicsConfig).pipe(
|
|
5331
|
+
return yield* topicMetrics(modelKey, topicsConfig).pipe(Effect27.provideService(Service2, backend));
|
|
4954
5332
|
});
|
|
4955
|
-
const topicChangeLog3 =
|
|
5333
|
+
const topicChangeLog3 = Effect27.fn("Store.topicChangeLog")(function* (modelKey, opts) {
|
|
4956
5334
|
const model = resolveModel(modelKey);
|
|
4957
5335
|
if (!model) {
|
|
4958
5336
|
return yield* new ModelMismatch({
|
|
@@ -4960,9 +5338,9 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4960
5338
|
actual: modelKey
|
|
4961
5339
|
});
|
|
4962
5340
|
}
|
|
4963
|
-
return yield* topicChangeLog2(modelKey, opts).pipe(
|
|
5341
|
+
return yield* topicChangeLog2(modelKey, opts).pipe(Effect27.provideService(Service2, backend));
|
|
4964
5342
|
});
|
|
4965
|
-
const topicHealth2 =
|
|
5343
|
+
const topicHealth2 = Effect27.fn("Store.topicHealth")(function* (modelKey) {
|
|
4966
5344
|
const model = resolveModel(modelKey);
|
|
4967
5345
|
if (!model) {
|
|
4968
5346
|
return yield* new ModelMismatch({
|
|
@@ -4970,11 +5348,11 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4970
5348
|
actual: modelKey
|
|
4971
5349
|
});
|
|
4972
5350
|
}
|
|
4973
|
-
return yield* topicHealth(modelKey, topicsConfig).pipe(
|
|
5351
|
+
return yield* topicHealth(modelKey, topicsConfig).pipe(Effect27.provideService(Service2, backend));
|
|
4974
5352
|
});
|
|
4975
|
-
const updateEmbedding =
|
|
5353
|
+
const updateEmbedding = Effect27.fn("Store.updateEmbedding")(function* (id, embedding, modelName, options) {
|
|
4976
5354
|
const now = Date.now();
|
|
4977
|
-
const affected = yield*
|
|
5355
|
+
const affected = yield* Effect27.tryPromise({
|
|
4978
5356
|
try: () => db.transaction(async (tx) => {
|
|
4979
5357
|
const rs = await tx.update(memories2).set({ embedding: [...embedding], embeddingModel: modelName }).where(eq8(memories2.id, id));
|
|
4980
5358
|
if (rs.rowsAffected === 0)
|
|
@@ -5004,7 +5382,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5004
5382
|
if (modelConfig && modelConfig.id === modelName) {
|
|
5005
5383
|
yield* backend.ensureVectorTable(modelConfig);
|
|
5006
5384
|
if (topicsEnabled) {
|
|
5007
|
-
const memberRows = yield*
|
|
5385
|
+
const memberRows = yield* Effect27.tryPromise({
|
|
5008
5386
|
try: () => db.select({
|
|
5009
5387
|
topicKey: topicMemberships.topicKey,
|
|
5010
5388
|
modelKey: topicMemberships.modelKey
|
|
@@ -5019,7 +5397,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5019
5397
|
yield* decrementTreeCf(modelConfig, mem, x);
|
|
5020
5398
|
yield* updateTopicVectorForget(backend, modelConfig, mem.topicKey, x);
|
|
5021
5399
|
}
|
|
5022
|
-
yield*
|
|
5400
|
+
yield* Effect27.tryPromise({
|
|
5023
5401
|
try: () => db.delete(topicMemberships).where(and8(eq8(topicMemberships.memoryId, id), eq8(topicMemberships.modelKey, modelName))),
|
|
5024
5402
|
catch: (cause) => new StoreError({ message: `Store.updateEmbedding: delete membership: ${cause}` })
|
|
5025
5403
|
});
|
|
@@ -5027,21 +5405,76 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5027
5405
|
}
|
|
5028
5406
|
yield* backend.insertVector(id, embedding, modelConfig);
|
|
5029
5407
|
if (topicsEnabled) {
|
|
5030
|
-
const routed = yield* routeInsert(id, embedding, modelConfig, topicsConfig).pipe(
|
|
5031
|
-
|
|
5408
|
+
const routed = yield* routeInsert(id, embedding, modelConfig, topicsConfig).pipe(Effect27.provideService(Service2, backend), Effect27.mapError((cause) => new StoreError({ message: `Store.updateEmbedding topic route: ${cause}` })));
|
|
5409
|
+
if (options?.scanCandidates !== false && graphEnabled) {
|
|
5410
|
+
yield* scanLeafCandidates(id, embedding, routed.topicKey, modelConfig);
|
|
5411
|
+
}
|
|
5032
5412
|
if (routed.overflow) {
|
|
5033
5413
|
const enqueueSplit = topicsOptions?.enqueueSplit;
|
|
5034
5414
|
if (enqueueSplit) {
|
|
5035
|
-
yield* enqueueSplit(routed.topicKey, modelConfig.id).pipe(
|
|
5415
|
+
yield* enqueueSplit(routed.topicKey, modelConfig.id).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.updateEmbedding enqueueSplit: ${cause}` })));
|
|
5036
5416
|
} else {
|
|
5037
|
-
yield* processSplits(modelConfig.id).pipe(
|
|
5417
|
+
yield* processSplits(modelConfig.id).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.updateEmbedding processSplits: ${cause}` })));
|
|
5038
5418
|
}
|
|
5039
5419
|
}
|
|
5040
5420
|
}
|
|
5041
5421
|
}
|
|
5042
5422
|
});
|
|
5043
|
-
const
|
|
5044
|
-
|
|
5423
|
+
const updateEmbeddingMany = Effect27.fn("Store.updateEmbeddingMany")(function* (entries, modelName, options) {
|
|
5424
|
+
if (entries.length === 0)
|
|
5425
|
+
return;
|
|
5426
|
+
const now = Date.now();
|
|
5427
|
+
yield* Effect27.tryPromise({
|
|
5428
|
+
try: () => db.transaction(async (tx) => {
|
|
5429
|
+
await tx.run(sql7`UPDATE ${memories2} SET embedding = CASE id ${sql7.join(entries.map((entry) => sql7`WHEN ${entry.id} THEN ${new Float32Array(entry.embedding).buffer}`), sql7` `)} END, embedding_model = ${modelName} WHERE id IN (${sql7.join(entries.map((entry) => entry.id), sql7`, `)})`);
|
|
5430
|
+
await tx.insert(memoryEvents2).values(entries.map((entry) => ({
|
|
5431
|
+
memoryId: entry.id,
|
|
5432
|
+
eventType: "embedding_updated",
|
|
5433
|
+
reason: modelName,
|
|
5434
|
+
createdAt: now
|
|
5435
|
+
})));
|
|
5436
|
+
}),
|
|
5437
|
+
catch: (cause) => {
|
|
5438
|
+
let chain = "";
|
|
5439
|
+
let c = cause;
|
|
5440
|
+
let i = 0;
|
|
5441
|
+
while (c && i < 6) {
|
|
5442
|
+
chain += " | " + String(c.message ?? c);
|
|
5443
|
+
c = c.cause;
|
|
5444
|
+
i++;
|
|
5445
|
+
}
|
|
5446
|
+
return new StoreError({ message: `Store.updateEmbeddingMany: ${cause}` + chain });
|
|
5447
|
+
}
|
|
5448
|
+
});
|
|
5449
|
+
if (modelConfig && modelConfig.id === modelName) {
|
|
5450
|
+
yield* backend.ensureVectorTable(modelConfig);
|
|
5451
|
+
yield* backend.insertVectors(entries.map((entry) => ({ memoryId: entry.id, vector: entry.embedding })), modelConfig);
|
|
5452
|
+
if (topicsEnabled) {
|
|
5453
|
+
const routed = yield* routeInsertMany(entries.map((entry) => ({ memoryId: entry.id, vector: entry.embedding })), modelConfig, topicsConfig).pipe(Effect27.provideService(Service2, backend), Effect27.mapError((cause) => new StoreError({ message: `Store.updateEmbeddingMany route: ${cause}` })));
|
|
5454
|
+
if (options?.scanCandidates === true && graphEnabled) {
|
|
5455
|
+
for (const routedEntry of routed) {
|
|
5456
|
+
const entry = entries.find((e) => e.id === routedEntry.memoryId);
|
|
5457
|
+
if (entry) {
|
|
5458
|
+
yield* scanLeafCandidates(routedEntry.memoryId, entry.embedding, routedEntry.topicKey, modelConfig);
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
const overflowed = [...new Set(routed.filter((r) => r.overflow).map((r) => r.topicKey))];
|
|
5463
|
+
if (overflowed.length > 0) {
|
|
5464
|
+
const enqueueSplit = topicsOptions?.enqueueSplit;
|
|
5465
|
+
if (enqueueSplit) {
|
|
5466
|
+
for (const topicKey of overflowed) {
|
|
5467
|
+
yield* enqueueSplit(topicKey, modelConfig.id).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.updateEmbeddingMany enqueueSplit: ${cause}` })));
|
|
5468
|
+
}
|
|
5469
|
+
} else {
|
|
5470
|
+
yield* processSplits(modelConfig.id).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.updateEmbeddingMany processSplits: ${cause}` })));
|
|
5471
|
+
}
|
|
5472
|
+
}
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
});
|
|
5476
|
+
const findStale = Effect27.fn("Store.findStale")(function* (model) {
|
|
5477
|
+
const rows = yield* Effect27.tryPromise({
|
|
5045
5478
|
try: () => db.select({ id: memories2.id }).from(memories2).where(and8(eq8(memories2.state, "active"), sql7`(embedding IS NULL OR embedding_model IS NULL OR embedding_model != ${model})`)),
|
|
5046
5479
|
catch: (cause) => new StoreError({ message: `Store.findStale: ${cause}` })
|
|
5047
5480
|
});
|
|
@@ -5061,14 +5494,14 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5061
5494
|
});
|
|
5062
5495
|
return memoryId;
|
|
5063
5496
|
};
|
|
5064
|
-
const reconcile =
|
|
5497
|
+
const reconcile = Effect27.fn("Store.reconcile")(function* (namespace, keyPrefix, keyRoot, walkedRoots, keptKeys) {
|
|
5065
5498
|
const inDomain = (key) => {
|
|
5066
5499
|
const rel = key.slice(keyPrefix.length).split("#")[0];
|
|
5067
5500
|
const filePath = keyRoot === "/" ? `/${rel}` : `${keyRoot}/${rel}`;
|
|
5068
5501
|
return walkedRoots.some((root) => filePath === root || filePath.startsWith(`${root}/`));
|
|
5069
5502
|
};
|
|
5070
5503
|
const owned = (key) => keptKeys.includes(key);
|
|
5071
|
-
const rows = yield*
|
|
5504
|
+
const rows = yield* Effect27.tryPromise({
|
|
5072
5505
|
try: () => db.select({
|
|
5073
5506
|
id: memories2.id,
|
|
5074
5507
|
logicalKey: memories2.logicalKey,
|
|
@@ -5079,7 +5512,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5079
5512
|
const vanished = rows.filter((r) => inDomain(r.logicalKey) && !owned(r.logicalKey));
|
|
5080
5513
|
if (vanished.length > 0) {
|
|
5081
5514
|
const now = Date.now();
|
|
5082
|
-
yield*
|
|
5515
|
+
yield* Effect27.tryPromise({
|
|
5083
5516
|
try: () => db.transaction(async (tx) => {
|
|
5084
5517
|
for (const row of vanished) {
|
|
5085
5518
|
await flipToSupersededById(tx, row.id, now, "source_removed");
|
|
@@ -5090,7 +5523,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5090
5523
|
}
|
|
5091
5524
|
return vanished;
|
|
5092
5525
|
});
|
|
5093
|
-
const writeSuperseding =
|
|
5526
|
+
const writeSuperseding = Effect27.fn("Store.writeSuperseding")(function* (input) {
|
|
5094
5527
|
if (input.content.includes("\x00")) {
|
|
5095
5528
|
return yield* new StoreError({
|
|
5096
5529
|
message: "Store.writeSuperseding: content contains a NUL byte (libSQL would silently truncate it)"
|
|
@@ -5101,7 +5534,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5101
5534
|
const metadataBlob = input.typedMetadata !== undefined ? mergeMetadataBlob(input.metadata, input.typedMetadata) : input.metadata ?? null;
|
|
5102
5535
|
const namespace = input.namespace ?? "default";
|
|
5103
5536
|
let supersededId;
|
|
5104
|
-
yield*
|
|
5537
|
+
yield* Effect27.tryPromise({
|
|
5105
5538
|
try: () => db.transaction(async (tx) => {
|
|
5106
5539
|
const existing = await tx.select({ id: memories2.id }).from(memories2).where(and8(eq8(memories2.logicalKey, input.logicalKey), eq8(memories2.namespace, namespace), eq8(memories2.state, "active"))).limit(1);
|
|
5107
5540
|
const old = existing[0];
|
|
@@ -5156,7 +5589,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5156
5589
|
...supersededId !== undefined ? { supersededId } : {}
|
|
5157
5590
|
};
|
|
5158
5591
|
});
|
|
5159
|
-
const addEdge =
|
|
5592
|
+
const addEdge = Effect27.fn("Store.addEdge")(function* (input) {
|
|
5160
5593
|
if (input.fromMemoryId === input.toMemoryId) {
|
|
5161
5594
|
return yield* new StoreError({ message: "Store.addEdge: self-loops are not allowed" });
|
|
5162
5595
|
}
|
|
@@ -5182,7 +5615,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5182
5615
|
message: `Store.addEdge: confidence must be a finite number in [0,1] (got ${String(confidence)})`
|
|
5183
5616
|
});
|
|
5184
5617
|
}
|
|
5185
|
-
const endpoints = yield*
|
|
5618
|
+
const endpoints = yield* Effect27.tryPromise({
|
|
5186
5619
|
try: () => db.select({ id: memories2.id }).from(memories2).where(inArray4(memories2.id, [input.fromMemoryId, input.toMemoryId])),
|
|
5187
5620
|
catch: (cause) => new StoreError({ message: `Store.addEdge: endpoints: ${cause}` })
|
|
5188
5621
|
});
|
|
@@ -5207,7 +5640,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5207
5640
|
createdAt: now,
|
|
5208
5641
|
updatedAt: now
|
|
5209
5642
|
};
|
|
5210
|
-
yield*
|
|
5643
|
+
yield* Effect27.tryPromise({
|
|
5211
5644
|
try: () => db.transaction(async (tx) => {
|
|
5212
5645
|
await tx.insert(artifactEdges).values(row);
|
|
5213
5646
|
if (input.confirmed && input.edgeKind === "memory_supersedes") {
|
|
@@ -5227,17 +5660,17 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5227
5660
|
});
|
|
5228
5661
|
return row;
|
|
5229
5662
|
});
|
|
5230
|
-
const expireEdge =
|
|
5231
|
-
const rs = yield*
|
|
5663
|
+
const expireEdge = Effect27.fn("Store.expireEdge")(function* (id) {
|
|
5664
|
+
const rs = yield* Effect27.tryPromise({
|
|
5232
5665
|
try: () => db.update(artifactEdges).set({ expiredAt: Date.now(), updatedAt: Date.now() }).where(eq8(artifactEdges.id, id)),
|
|
5233
5666
|
catch: (cause) => new StoreError({ message: `Store.expireEdge: ${cause}` })
|
|
5234
5667
|
});
|
|
5235
5668
|
if (rs.rowsAffected === 0)
|
|
5236
5669
|
return yield* new EdgeNotFound({ id });
|
|
5237
5670
|
});
|
|
5238
|
-
const confirmEdge =
|
|
5671
|
+
const confirmEdge = Effect27.fn("Store.confirmEdge")(function* (id) {
|
|
5239
5672
|
const now = Date.now();
|
|
5240
|
-
const found = yield*
|
|
5673
|
+
const found = yield* Effect27.tryPromise({
|
|
5241
5674
|
try: () => db.transaction(async (tx) => {
|
|
5242
5675
|
const rows = await tx.select().from(artifactEdges).where(eq8(artifactEdges.id, id)).limit(1);
|
|
5243
5676
|
const edge = rows[0];
|
|
@@ -5254,15 +5687,15 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5254
5687
|
if (!found)
|
|
5255
5688
|
return yield* new EdgeNotFound({ id });
|
|
5256
5689
|
});
|
|
5257
|
-
const rejectEdge =
|
|
5258
|
-
const rs = yield*
|
|
5690
|
+
const rejectEdge = Effect27.fn("Store.rejectEdge")(function* (id) {
|
|
5691
|
+
const rs = yield* Effect27.tryPromise({
|
|
5259
5692
|
try: () => db.update(artifactEdges).set({ status: "rejected", updatedAt: Date.now() }).where(eq8(artifactEdges.id, id)),
|
|
5260
5693
|
catch: (cause) => new StoreError({ message: `Store.rejectEdge: ${cause}` })
|
|
5261
5694
|
});
|
|
5262
5695
|
if (rs.rowsAffected === 0)
|
|
5263
5696
|
return yield* new EdgeNotFound({ id });
|
|
5264
5697
|
});
|
|
5265
|
-
const listEdges =
|
|
5698
|
+
const listEdges = Effect27.fn("Store.listEdges")(function* (opts) {
|
|
5266
5699
|
const conditions = [];
|
|
5267
5700
|
if (!opts?.includeExpired)
|
|
5268
5701
|
conditions.push(isNull2(artifactEdges.expiredAt));
|
|
@@ -5273,7 +5706,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5273
5706
|
conditions.push(eq8(artifactEdges.edgeKind, opts.edgeKind));
|
|
5274
5707
|
if (opts?.status)
|
|
5275
5708
|
conditions.push(eq8(artifactEdges.status, opts.status));
|
|
5276
|
-
const rows = yield*
|
|
5709
|
+
const rows = yield* Effect27.tryPromise({
|
|
5277
5710
|
try: () => {
|
|
5278
5711
|
const base = db.select().from(artifactEdges);
|
|
5279
5712
|
return (conditions.length === 0 ? base : base.where(and8(...conditions))).orderBy(desc2(artifactEdges.createdAt));
|
|
@@ -5282,7 +5715,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5282
5715
|
});
|
|
5283
5716
|
return rows;
|
|
5284
5717
|
});
|
|
5285
|
-
const explain =
|
|
5718
|
+
const explain = Effect27.fn("Store.explain")(function* (node, opts) {
|
|
5286
5719
|
if (node.kind !== "memory" && node.kind !== "topic" && node.kind !== "concept") {
|
|
5287
5720
|
return yield* new StoreError({
|
|
5288
5721
|
message: `Store.explain: unknown kind "${String(node.kind)}"`
|
|
@@ -5326,37 +5759,41 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5326
5759
|
pendingConflicts: pending
|
|
5327
5760
|
};
|
|
5328
5761
|
});
|
|
5329
|
-
const
|
|
5762
|
+
const writeCandidateEdges = (candidates, now) => Effect27.tryPromise({
|
|
5330
5763
|
try: () => db.transaction(async (tx) => {
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5764
|
+
let inserted = 0;
|
|
5765
|
+
for (const candidate of candidates) {
|
|
5766
|
+
const existing = await tx.select({ id: artifactEdges.id }).from(artifactEdges).where(and8(eq8(artifactEdges.fromMemoryId, candidate.fromMemoryId), eq8(artifactEdges.toMemoryId, candidate.toMemoryId), eq8(artifactEdges.edgeKind, candidate.edgeKind))).limit(1);
|
|
5767
|
+
if (existing.length > 0)
|
|
5768
|
+
continue;
|
|
5769
|
+
await tx.insert(artifactEdges).values({
|
|
5770
|
+
id: crypto.randomUUID(),
|
|
5771
|
+
fromMemoryId: candidate.fromMemoryId,
|
|
5772
|
+
toMemoryId: candidate.toMemoryId,
|
|
5773
|
+
edgeKind: candidate.edgeKind,
|
|
5774
|
+
weight: 1,
|
|
5775
|
+
status: candidate.status,
|
|
5776
|
+
source: candidate.source,
|
|
5777
|
+
confidence: candidate.confidence,
|
|
5778
|
+
validAt: candidate.status === "confirmed" ? now : null,
|
|
5779
|
+
expiredAt: null,
|
|
5780
|
+
createdAt: now,
|
|
5781
|
+
updatedAt: now
|
|
5782
|
+
});
|
|
5783
|
+
if (candidate.status === "confirmed") {
|
|
5784
|
+
await flipToSupersededById(tx, candidate.fromMemoryId, now);
|
|
5785
|
+
}
|
|
5786
|
+
inserted += 1;
|
|
5350
5787
|
}
|
|
5351
|
-
return
|
|
5788
|
+
return inserted;
|
|
5352
5789
|
}),
|
|
5353
|
-
catch: (cause) => new StoreError({ message: `Store.
|
|
5790
|
+
catch: (cause) => new StoreError({ message: `Store.writeCandidateEdges: ${cause}` })
|
|
5354
5791
|
});
|
|
5355
|
-
const reconcileRenameCandidates =
|
|
5792
|
+
const reconcileRenameCandidates = Effect27.fn("Store.reconcileRenameCandidates")(function* (vanished, newUnitIds) {
|
|
5356
5793
|
const withVectors = vanished.filter((v) => v.embedding !== null);
|
|
5357
5794
|
if (withVectors.length === 0 || newUnitIds.length === 0)
|
|
5358
5795
|
return 0;
|
|
5359
|
-
const newRows = yield*
|
|
5796
|
+
const newRows = yield* Effect27.tryPromise({
|
|
5360
5797
|
try: () => db.select({ id: memories2.id, embedding: memories2.embedding }).from(memories2).where(and8(inArray4(memories2.id, newUnitIds))),
|
|
5361
5798
|
catch: (cause) => new StoreError({ message: `Store.reconcileRenameCandidates: ${cause}` })
|
|
5362
5799
|
});
|
|
@@ -5365,6 +5802,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5365
5802
|
return 0;
|
|
5366
5803
|
const now = Date.now();
|
|
5367
5804
|
let inserted = 0;
|
|
5805
|
+
const batch = [];
|
|
5368
5806
|
for (const v of withVectors) {
|
|
5369
5807
|
const vVec = Float32Array.from(v.embedding);
|
|
5370
5808
|
for (const n of newWithVectors) {
|
|
@@ -5372,7 +5810,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5372
5810
|
continue;
|
|
5373
5811
|
const cosine = cosineSimilarity(vVec, Float32Array.from(n.embedding));
|
|
5374
5812
|
if (cosine >= GRAPH_CONFLICT_BANDS.nearDuplicate) {
|
|
5375
|
-
|
|
5813
|
+
batch.push({
|
|
5376
5814
|
fromMemoryId: v.id,
|
|
5377
5815
|
toMemoryId: n.id,
|
|
5378
5816
|
edgeKind: "memory_supersedes",
|
|
@@ -5380,24 +5818,23 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5380
5818
|
status: "pending",
|
|
5381
5819
|
confidence: cosine,
|
|
5382
5820
|
reason: "rename"
|
|
5383
|
-
}
|
|
5384
|
-
if (ok)
|
|
5385
|
-
inserted += 1;
|
|
5821
|
+
});
|
|
5386
5822
|
}
|
|
5387
5823
|
}
|
|
5388
5824
|
}
|
|
5825
|
+
inserted = yield* writeCandidateEdges(batch, now);
|
|
5389
5826
|
return inserted;
|
|
5390
5827
|
});
|
|
5391
|
-
const scanLeafCandidates = (memoryId, vector, topicKey, model) =>
|
|
5392
|
-
const memberRows = yield*
|
|
5828
|
+
const scanLeafCandidates = (memoryId, vector, topicKey, model) => Effect27.gen(function* () {
|
|
5829
|
+
const memberRows = yield* Effect27.tryPromise({
|
|
5393
5830
|
try: () => db.select({ memoryId: topicMemberships.memoryId }).from(topicMemberships).where(and8(eq8(topicMemberships.topicKey, topicKey), eq8(topicMemberships.modelKey, model.id))).orderBy(asc5(topicMemberships.memoryId)),
|
|
5394
5831
|
catch: (cause) => new StoreError({ message: `Store.updateEmbedding candidates: members: ${cause}` })
|
|
5395
5832
|
});
|
|
5396
5833
|
const memberIds = memberRows.map((r) => r.memoryId);
|
|
5397
5834
|
if (memberIds.length === 0)
|
|
5398
5835
|
return;
|
|
5399
|
-
const vectorRows = yield* backend.fetchMemoryVectors(memberIds, model).pipe(
|
|
5400
|
-
const memoryRows = yield*
|
|
5836
|
+
const vectorRows = yield* backend.fetchMemoryVectors(memberIds, model).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.updateEmbedding candidates: vectors: ${cause}` })));
|
|
5837
|
+
const memoryRows = yield* Effect27.tryPromise({
|
|
5401
5838
|
try: () => db.select({
|
|
5402
5839
|
id: memories2.id,
|
|
5403
5840
|
logicalKey: memories2.logicalKey,
|
|
@@ -5406,7 +5843,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5406
5843
|
}).from(memories2).where(and8(inArray4(memories2.id, memberIds), eq8(memories2.state, "active"))),
|
|
5407
5844
|
catch: (cause) => new StoreError({ message: `Store.updateEmbedding candidates: memories: ${cause}` })
|
|
5408
5845
|
});
|
|
5409
|
-
const selfRows = yield*
|
|
5846
|
+
const selfRows = yield* Effect27.tryPromise({
|
|
5410
5847
|
try: () => db.select({
|
|
5411
5848
|
logicalKey: memories2.logicalKey,
|
|
5412
5849
|
createdAt: memories2.createdAt,
|
|
@@ -5432,13 +5869,11 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5432
5869
|
});
|
|
5433
5870
|
const candidates = leafLocalCandidates(memoryId, new Float32Array(vector), self.createdAt, self.logicalKey, self.metadata, members, GRAPH_CONFLICT_BANDS);
|
|
5434
5871
|
const now = Date.now();
|
|
5435
|
-
|
|
5436
|
-
yield* writeCandidateEdge(candidate, now);
|
|
5437
|
-
}
|
|
5872
|
+
yield* writeCandidateEdges(candidates, now);
|
|
5438
5873
|
});
|
|
5439
|
-
const graphCandidates =
|
|
5874
|
+
const graphCandidates = Effect27.fn("Store.graphCandidates")(function* (opts) {
|
|
5440
5875
|
const limit = Math.max(1, Math.min(opts?.limit ?? 50, GRAPH_CANDIDATE_LIMIT_MAX));
|
|
5441
|
-
const rows = yield*
|
|
5876
|
+
const rows = yield* Effect27.tryPromise({
|
|
5442
5877
|
try: () => db.select({
|
|
5443
5878
|
id: artifactEdges.id,
|
|
5444
5879
|
fromMemoryId: artifactEdges.fromMemoryId,
|
|
@@ -5450,7 +5885,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5450
5885
|
}).from(artifactEdges).where(and8(eq8(artifactEdges.status, "pending"), isNull2(artifactEdges.expiredAt))).orderBy(desc2(artifactEdges.createdAt), asc5(artifactEdges.id)).limit(limit),
|
|
5451
5886
|
catch: (cause) => new StoreError({ message: `Store.graphCandidates: pending: ${cause}` })
|
|
5452
5887
|
});
|
|
5453
|
-
const isolatedRows = yield* backend.listIsolatedMemories(0).pipe(
|
|
5888
|
+
const isolatedRows = yield* backend.listIsolatedMemories(0).pipe(Effect27.mapError((cause) => new StoreError({ message: `Store.graphCandidates: isolated: ${cause}` })));
|
|
5454
5889
|
const isolated = isolatedRows.map((row) => ({
|
|
5455
5890
|
id: String(row.id),
|
|
5456
5891
|
createdAt: Number(row.createdAt)
|
|
@@ -5469,13 +5904,13 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5469
5904
|
oldestIsolated: isolated.slice(0, GRAPH_ISOLATED_EXAMPLES)
|
|
5470
5905
|
};
|
|
5471
5906
|
});
|
|
5472
|
-
const graphCoverage2 =
|
|
5473
|
-
return yield* graphCoverage(modelKey).pipe(
|
|
5907
|
+
const graphCoverage2 = Effect27.fn("Store.graphCoverage")(function* (modelKey) {
|
|
5908
|
+
return yield* graphCoverage(modelKey).pipe(Effect27.provideService(Service2, backend));
|
|
5474
5909
|
});
|
|
5475
|
-
const createConcept =
|
|
5910
|
+
const createConcept = Effect27.fn("Store.createConcept")(function* (name, embedding) {
|
|
5476
5911
|
const id = crypto.randomUUID();
|
|
5477
5912
|
const now = Date.now();
|
|
5478
|
-
yield*
|
|
5913
|
+
yield* Effect27.tryPromise({
|
|
5479
5914
|
try: () => db.insert(concepts2).values({
|
|
5480
5915
|
id,
|
|
5481
5916
|
name,
|
|
@@ -5495,8 +5930,8 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5495
5930
|
lastSeen: now
|
|
5496
5931
|
};
|
|
5497
5932
|
});
|
|
5498
|
-
const getConcept =
|
|
5499
|
-
const rows = yield*
|
|
5933
|
+
const getConcept = Effect27.fn("Store.getConcept")(function* (id) {
|
|
5934
|
+
const rows = yield* Effect27.tryPromise({
|
|
5500
5935
|
try: () => db.select().from(concepts2).where(eq8(concepts2.id, id)).limit(1),
|
|
5501
5936
|
catch: (cause) => new StoreError({ message: `Store.getConcept: ${cause}` })
|
|
5502
5937
|
});
|
|
@@ -5512,8 +5947,8 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5512
5947
|
lastSeen: row.lastSeen
|
|
5513
5948
|
};
|
|
5514
5949
|
});
|
|
5515
|
-
const listConcepts =
|
|
5516
|
-
const rows = yield*
|
|
5950
|
+
const listConcepts = Effect27.fn("Store.listConcepts")(function* () {
|
|
5951
|
+
const rows = yield* Effect27.tryPromise({
|
|
5517
5952
|
try: () => db.select().from(concepts2),
|
|
5518
5953
|
catch: (cause) => new StoreError({ message: `Store.listConcepts: ${cause}` })
|
|
5519
5954
|
});
|
|
@@ -5526,8 +5961,8 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5526
5961
|
lastSeen: row.lastSeen
|
|
5527
5962
|
}));
|
|
5528
5963
|
});
|
|
5529
|
-
const annotateMemory =
|
|
5530
|
-
yield*
|
|
5964
|
+
const annotateMemory = Effect27.fn("Store.annotateMemory")(function* (memoryId, conceptId, confidence) {
|
|
5965
|
+
yield* Effect27.tryPromise({
|
|
5531
5966
|
try: () => db.insert(memoryConcepts2).values({
|
|
5532
5967
|
conceptId,
|
|
5533
5968
|
memoryId,
|
|
@@ -5537,14 +5972,14 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5537
5972
|
catch: (cause) => new StoreError({ message: `Store.annotateMemory: ${cause}` })
|
|
5538
5973
|
});
|
|
5539
5974
|
});
|
|
5540
|
-
const getMemoryAnnotations =
|
|
5541
|
-
const rows = yield*
|
|
5975
|
+
const getMemoryAnnotations = Effect27.fn("Store.getMemoryAnnotations")(function* (memoryId) {
|
|
5976
|
+
const rows = yield* Effect27.tryPromise({
|
|
5542
5977
|
try: () => db.select({ conceptId: memoryConcepts2.conceptId }).from(memoryConcepts2).where(eq8(memoryConcepts2.memoryId, memoryId)),
|
|
5543
5978
|
catch: (cause) => new StoreError({ message: `Store.getMemoryAnnotations: ${cause}` })
|
|
5544
5979
|
});
|
|
5545
5980
|
return rows.map((r) => r.conceptId);
|
|
5546
5981
|
});
|
|
5547
|
-
const queryByMetadata =
|
|
5982
|
+
const queryByMetadata = Effect27.fn("Store.queryByMetadata")(function* (filter) {
|
|
5548
5983
|
const rows = yield* backend.queryByMetadata(filter);
|
|
5549
5984
|
const typed = rows;
|
|
5550
5985
|
return typed.map((row) => fromMemoryRow({
|
|
@@ -5561,8 +5996,8 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5561
5996
|
embeddingModel: row.embedding_model
|
|
5562
5997
|
}));
|
|
5563
5998
|
});
|
|
5564
|
-
const getMemoryMetadata =
|
|
5565
|
-
const rows = yield*
|
|
5999
|
+
const getMemoryMetadata = Effect27.fn("Store.getMemoryMetadata")(function* (id) {
|
|
6000
|
+
const rows = yield* Effect27.tryPromise({
|
|
5566
6001
|
try: () => db.select({ metadata: memories2.metadata }).from(memories2).where(eq8(memories2.id, id)).limit(1),
|
|
5567
6002
|
catch: (cause) => new StoreError({ message: `Store.getMemoryMetadata: ${cause}` })
|
|
5568
6003
|
});
|
|
@@ -5571,8 +6006,8 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5571
6006
|
return yield* new NotFound({ id });
|
|
5572
6007
|
return parseMetadata(row.metadata);
|
|
5573
6008
|
});
|
|
5574
|
-
const setMemoryMetadata =
|
|
5575
|
-
const updated = yield*
|
|
6009
|
+
const setMemoryMetadata = Effect27.fn("Store.setMemoryMetadata")(function* (id, metadata) {
|
|
6010
|
+
const updated = yield* Effect27.tryPromise({
|
|
5576
6011
|
try: () => db.transaction(async (tx) => {
|
|
5577
6012
|
const rows = await tx.select({ metadata: memories2.metadata }).from(memories2).where(eq8(memories2.id, id)).limit(1);
|
|
5578
6013
|
const row = rows[0];
|
|
@@ -5588,6 +6023,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5588
6023
|
});
|
|
5589
6024
|
return {
|
|
5590
6025
|
write,
|
|
6026
|
+
writeMany,
|
|
5591
6027
|
writeSuperseding,
|
|
5592
6028
|
reconcile,
|
|
5593
6029
|
reconcileRenameCandidates,
|
|
@@ -5596,6 +6032,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5596
6032
|
recency,
|
|
5597
6033
|
searchFts5,
|
|
5598
6034
|
searchVector,
|
|
6035
|
+
augmentSearchResults,
|
|
5599
6036
|
logAudit,
|
|
5600
6037
|
listSchema: () => backend.listSchema(),
|
|
5601
6038
|
supersede,
|
|
@@ -5603,6 +6040,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5603
6040
|
sweep,
|
|
5604
6041
|
events,
|
|
5605
6042
|
updateEmbedding,
|
|
6043
|
+
updateEmbeddingMany,
|
|
5606
6044
|
findStale,
|
|
5607
6045
|
createConcept,
|
|
5608
6046
|
getConcept,
|
|
@@ -5637,7 +6075,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5637
6075
|
};
|
|
5638
6076
|
};
|
|
5639
6077
|
var layer8 = (url, options) => {
|
|
5640
|
-
const base = Layer10.effect(Service5,
|
|
6078
|
+
const base = Layer10.effect(Service5, Effect27.gen(function* () {
|
|
5641
6079
|
const backend = yield* Service2;
|
|
5642
6080
|
return Service5.of(makeStore2(backend, options?.embeddingModelConfig, options?.topics, options?.graphConfig, options?.enqueueAudit !== undefined ? { enqueueAudit: options.enqueueAudit } : undefined, options?.defaultTtlSecs));
|
|
5643
6081
|
})).pipe(Layer10.provideMerge(layer3(url, options)));
|
|
@@ -5650,7 +6088,7 @@ var DISABLED_LOGGING = {
|
|
|
5650
6088
|
format: "jsonl",
|
|
5651
6089
|
ringSize: 4096
|
|
5652
6090
|
};
|
|
5653
|
-
var loggingFromConfig = Layer10.unwrap(
|
|
6091
|
+
var loggingFromConfig = Layer10.unwrap(Effect27.map(Effect27.service(Service4), (cfg) => layer(cfg.config.logging ?? DISABLED_LOGGING)));
|
|
5654
6092
|
// ../store/src/topics/index.ts
|
|
5655
6093
|
var exports_topics = {};
|
|
5656
6094
|
__export(exports_topics, {
|
|
@@ -5671,6 +6109,7 @@ __export(exports_topics, {
|
|
|
5671
6109
|
shouldSplit: () => shouldSplit,
|
|
5672
6110
|
setActiveModel: () => setActiveModel,
|
|
5673
6111
|
scoreChildren: () => scoreChildren,
|
|
6112
|
+
routeInsertMany: () => routeInsertMany,
|
|
5674
6113
|
routeInsert: () => routeInsert,
|
|
5675
6114
|
resolveTopics: () => resolveTopics,
|
|
5676
6115
|
rebalanceSiblings: () => rebalanceSiblings,
|
|
@@ -5708,15 +6147,15 @@ __export(exports_topics, {
|
|
|
5708
6147
|
});
|
|
5709
6148
|
|
|
5710
6149
|
// ../store/src/audit.ts
|
|
5711
|
-
import { Effect as
|
|
6150
|
+
import { Effect as Effect28 } from "effect";
|
|
5712
6151
|
function auditWriteHandler(deps = {}) {
|
|
5713
|
-
const run = (payload, ctx) =>
|
|
6152
|
+
const run = (payload, ctx) => Effect28.gen(function* () {
|
|
5714
6153
|
const envelope = payload;
|
|
5715
6154
|
const backend = yield* Service2;
|
|
5716
|
-
yield* backend.writeAuditRows(envelope.rows).pipe(
|
|
6155
|
+
yield* backend.writeAuditRows(envelope.rows).pipe(Effect28.mapError((error) => new JobFailure({ jobId: ctx.jobId, message: `audit.write: ${error}` })));
|
|
5717
6156
|
return;
|
|
5718
6157
|
});
|
|
5719
|
-
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(
|
|
6158
|
+
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(Effect28.provideService(Service2, deps.backend)) : run;
|
|
5720
6159
|
}
|
|
5721
6160
|
// ../store/src/graph/index.ts
|
|
5722
6161
|
var exports_graph = {};
|
|
@@ -5751,7 +6190,7 @@ __export(exports_graph, {
|
|
|
5751
6190
|
});
|
|
5752
6191
|
|
|
5753
6192
|
// ../store/src/graph/concepts.ts
|
|
5754
|
-
import { Clock as Clock6, Effect as
|
|
6193
|
+
import { Clock as Clock6, Effect as Effect29 } from "effect";
|
|
5755
6194
|
import { and as and9, asc as asc6, eq as eq9, isNotNull, sql as sql8 } from "drizzle-orm";
|
|
5756
6195
|
var DEFAULT_CLUSTER_K = 8;
|
|
5757
6196
|
var DEFAULT_CLUSTER_MIN_SIZE = 3;
|
|
@@ -5874,11 +6313,11 @@ var conceptConfidence = (vector, centroid) => {
|
|
|
5874
6313
|
return 0;
|
|
5875
6314
|
return Math.min(1, Math.max(0, dot3(vector, centroid) / Math.sqrt(norm)));
|
|
5876
6315
|
};
|
|
5877
|
-
var clusterLeaf =
|
|
6316
|
+
var clusterLeaf = Effect29.fn("ConceptCluster.clusterLeaf")(function* (topicKey, model, config) {
|
|
5878
6317
|
const backend = yield* Service2;
|
|
5879
6318
|
const db = backend.db;
|
|
5880
6319
|
const now = yield* Clock6.currentTimeMillis;
|
|
5881
|
-
const memberRows = yield*
|
|
6320
|
+
const memberRows = yield* Effect29.tryPromise({
|
|
5882
6321
|
try: () => db.select({ memoryId: topicMemberships.memoryId }).from(topicMemberships).where(and9(eq9(topicMemberships.topicKey, topicKey), eq9(topicMemberships.modelKey, model.id))).orderBy(asc6(topicMemberships.memoryId)),
|
|
5883
6322
|
catch: (cause) => new StoreError({ message: `clusterLeaf: load members: ${cause}` })
|
|
5884
6323
|
});
|
|
@@ -5897,11 +6336,11 @@ var clusterLeaf = Effect28.fn("ConceptCluster.clusterLeaf")(function* (topicKey,
|
|
|
5897
6336
|
return { concepts: 0, annotated: 0 };
|
|
5898
6337
|
return yield* persistClusters(db, members, config, now);
|
|
5899
6338
|
});
|
|
5900
|
-
var clusterCorpus =
|
|
6339
|
+
var clusterCorpus = Effect29.fn("ConceptCluster.clusterCorpus")(function* (model, config) {
|
|
5901
6340
|
const backend = yield* Service2;
|
|
5902
6341
|
const db = backend.db;
|
|
5903
6342
|
const now = yield* Clock6.currentTimeMillis;
|
|
5904
|
-
const rows = yield*
|
|
6343
|
+
const rows = yield* Effect29.tryPromise({
|
|
5905
6344
|
try: () => db.select({ id: memories.id, embedding: memories.embedding }).from(memories).where(and9(eq9(memories.state, "active"), isNotNull(memories.embedding))).orderBy(asc6(memories.id)),
|
|
5906
6345
|
catch: (cause) => new StoreError({ message: `clusterCorpus: load memories: ${cause}` })
|
|
5907
6346
|
});
|
|
@@ -5918,7 +6357,7 @@ var clusterCorpus = Effect28.fn("ConceptCluster.clusterCorpus")(function* (model
|
|
|
5918
6357
|
return { concepts: 0, annotated: 0 };
|
|
5919
6358
|
return yield* persistClusters(db, members, config, now);
|
|
5920
6359
|
});
|
|
5921
|
-
var persistClusters = (db, members, config, now) =>
|
|
6360
|
+
var persistClusters = (db, members, config, now) => Effect29.tryPromise({
|
|
5922
6361
|
try: () => db.transaction(async (tx) => {
|
|
5923
6362
|
const { k, minClusterSize } = resolvedClusterConfig(config);
|
|
5924
6363
|
const vectors = members.map((m) => m.vector);
|
|
@@ -5949,18 +6388,18 @@ var persistClusters = (db, members, config, now) => Effect28.tryPromise({
|
|
|
5949
6388
|
lastSeen: now
|
|
5950
6389
|
}
|
|
5951
6390
|
});
|
|
5952
|
-
|
|
6391
|
+
await tx.insert(memoryConcepts).values(memberIndices.map((i) => {
|
|
5953
6392
|
const member = members[i];
|
|
5954
|
-
|
|
6393
|
+
return {
|
|
5955
6394
|
conceptId: id,
|
|
5956
6395
|
memoryId: member.id,
|
|
5957
6396
|
confidence: conceptConfidence(member.vector, centroid),
|
|
5958
6397
|
assignedAt: now
|
|
5959
|
-
}
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
}
|
|
5963
|
-
}
|
|
6398
|
+
};
|
|
6399
|
+
})).onConflictDoUpdate({
|
|
6400
|
+
target: [memoryConcepts.conceptId, memoryConcepts.memoryId],
|
|
6401
|
+
set: { confidence: sql8`excluded.confidence`, assignedAt: now }
|
|
6402
|
+
});
|
|
5964
6403
|
conceptCount++;
|
|
5965
6404
|
annotated += memberIndices.length;
|
|
5966
6405
|
}
|
|
@@ -5969,21 +6408,21 @@ var persistClusters = (db, members, config, now) => Effect28.tryPromise({
|
|
|
5969
6408
|
catch: (cause) => new StoreError({ message: `concept cluster: persist: ${cause}` })
|
|
5970
6409
|
});
|
|
5971
6410
|
function conceptClusterHandler(deps) {
|
|
5972
|
-
const run = (payload, ctx) =>
|
|
6411
|
+
const run = (payload, ctx) => Effect29.gen(function* () {
|
|
5973
6412
|
const envelope = payload;
|
|
5974
6413
|
const model = deps.getModelConfig(envelope.modelKey);
|
|
5975
6414
|
if (!model) {
|
|
5976
|
-
return yield*
|
|
6415
|
+
return yield* Effect29.fail(new JobFailure({
|
|
5977
6416
|
jobId: ctx.jobId,
|
|
5978
6417
|
message: `concept.cluster: unknown model "${envelope.modelKey}"`
|
|
5979
6418
|
}));
|
|
5980
6419
|
}
|
|
5981
6420
|
if (envelope.topicKey !== undefined) {
|
|
5982
|
-
yield* clusterLeaf(envelope.topicKey, model, deps.config).pipe(
|
|
6421
|
+
yield* clusterLeaf(envelope.topicKey, model, deps.config).pipe(Effect29.mapError((error) => new JobFailure({ jobId: ctx.jobId, message: `concept.cluster: ${error}` })));
|
|
5983
6422
|
} else {
|
|
5984
|
-
yield* clusterCorpus(model, deps.config).pipe(
|
|
6423
|
+
yield* clusterCorpus(model, deps.config).pipe(Effect29.mapError((error) => new JobFailure({ jobId: ctx.jobId, message: `concept.cluster: ${error}` })));
|
|
5985
6424
|
}
|
|
5986
|
-
yield*
|
|
6425
|
+
yield* Effect29.logInfo("concepts.clustered").pipe(Effect29.annotateLogs({
|
|
5987
6426
|
scope: "@dimple/store",
|
|
5988
6427
|
event: "concepts.clustered",
|
|
5989
6428
|
modelKey: envelope.modelKey,
|
|
@@ -5991,10 +6430,10 @@ function conceptClusterHandler(deps) {
|
|
|
5991
6430
|
}));
|
|
5992
6431
|
return;
|
|
5993
6432
|
});
|
|
5994
|
-
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(
|
|
6433
|
+
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(Effect29.provideService(Service2, deps.backend)) : run;
|
|
5995
6434
|
}
|
|
5996
6435
|
// ../store/src/graph/dream.ts
|
|
5997
|
-
import { Clock as Clock7, Effect as
|
|
6436
|
+
import { Clock as Clock7, Effect as Effect30 } from "effect";
|
|
5998
6437
|
import { and as and10, asc as asc7, eq as eq10, gt, inArray as inArray5, isNull as isNull3, sql as sql9 } from "drizzle-orm";
|
|
5999
6438
|
var dreamStateDefaults = {
|
|
6000
6439
|
minHours: 24,
|
|
@@ -6024,110 +6463,99 @@ var flipToSuperseded = async (tx, memoryId, now) => {
|
|
|
6024
6463
|
});
|
|
6025
6464
|
return true;
|
|
6026
6465
|
};
|
|
6027
|
-
var
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
if (row.status !== "pending")
|
|
6034
|
-
return { inserted: false, flipped: false };
|
|
6035
|
-
if (confirmed) {
|
|
6036
|
-
await tx.update(artifactEdges).set({
|
|
6037
|
-
status: "confirmed",
|
|
6038
|
-
validAt: now,
|
|
6039
|
-
confidence: relation.confidence,
|
|
6040
|
-
updatedAt: now
|
|
6041
|
-
}).where(eq10(artifactEdges.id, row.id));
|
|
6042
|
-
const flipped2 = await flipToSuperseded(tx, relation.fromMemoryId, now);
|
|
6043
|
-
return { inserted: false, flipped: flipped2 };
|
|
6044
|
-
}
|
|
6466
|
+
var writeRelationEdgeTx = async (tx, relation, now) => {
|
|
6467
|
+
const existing = await tx.select({ id: artifactEdges.id, status: artifactEdges.status }).from(artifactEdges).where(and10(eq10(artifactEdges.fromMemoryId, relation.fromMemoryId), eq10(artifactEdges.toMemoryId, relation.toMemoryId), eq10(artifactEdges.edgeKind, relation.edgeKind))).limit(1);
|
|
6468
|
+
const confirmed = relation.edgeKind === "memory_supersedes" && relation.confidence >= SUPERSEDE_CONFIRM_BAR;
|
|
6469
|
+
if (existing.length > 0) {
|
|
6470
|
+
const row = existing[0];
|
|
6471
|
+
if (row.status !== "pending")
|
|
6045
6472
|
return { inserted: false, flipped: false };
|
|
6046
|
-
|
|
6473
|
+
if (confirmed) {
|
|
6474
|
+
await tx.update(artifactEdges).set({
|
|
6475
|
+
status: "confirmed",
|
|
6476
|
+
validAt: now,
|
|
6477
|
+
confidence: relation.confidence,
|
|
6478
|
+
updatedAt: now
|
|
6479
|
+
}).where(eq10(artifactEdges.id, row.id));
|
|
6480
|
+
const flipped2 = await flipToSuperseded(tx, relation.fromMemoryId, now);
|
|
6481
|
+
return { inserted: false, flipped: flipped2 };
|
|
6482
|
+
}
|
|
6483
|
+
return { inserted: false, flipped: false };
|
|
6484
|
+
}
|
|
6485
|
+
await tx.insert(artifactEdges).values({
|
|
6486
|
+
id: crypto.randomUUID(),
|
|
6487
|
+
fromMemoryId: relation.fromMemoryId,
|
|
6488
|
+
toMemoryId: relation.toMemoryId,
|
|
6489
|
+
edgeKind: relation.edgeKind,
|
|
6490
|
+
weight: 1,
|
|
6491
|
+
status: confirmed ? "confirmed" : "pending",
|
|
6492
|
+
source: "llm",
|
|
6493
|
+
confidence: relation.confidence,
|
|
6494
|
+
validAt: confirmed ? now : null,
|
|
6495
|
+
expiredAt: null,
|
|
6496
|
+
createdAt: now,
|
|
6497
|
+
updatedAt: now
|
|
6498
|
+
});
|
|
6499
|
+
const flipped = confirmed ? await flipToSuperseded(tx, relation.fromMemoryId, now) : false;
|
|
6500
|
+
return { inserted: true, flipped };
|
|
6501
|
+
};
|
|
6502
|
+
var writeDerivedMemoryTx = async (tx, content, sources, now) => {
|
|
6503
|
+
const logicalKey = derivedKey(content);
|
|
6504
|
+
const existing = await tx.select({ id: memories.id }).from(memories).where(and10(eq10(memories.logicalKey, logicalKey), eq10(memories.namespace, DERIVED_NAMESPACE), eq10(memories.state, "active"))).limit(1);
|
|
6505
|
+
const memoryId = existing[0]?.id ?? crypto.randomUUID();
|
|
6506
|
+
let inserted = false;
|
|
6507
|
+
if (existing.length === 0) {
|
|
6508
|
+
await tx.insert(memories).values({
|
|
6509
|
+
id: memoryId,
|
|
6510
|
+
logicalKey,
|
|
6511
|
+
content,
|
|
6512
|
+
contentType: "text/plain",
|
|
6513
|
+
state: "active",
|
|
6514
|
+
createdAt: now,
|
|
6515
|
+
ttlSecs: DERIVED_TTL_SECS,
|
|
6516
|
+
namespace: DERIVED_NAMESPACE,
|
|
6517
|
+
metadata: JSON.stringify({ sources })
|
|
6518
|
+
});
|
|
6519
|
+
await tx.insert(memoryEvents).values({
|
|
6520
|
+
memoryId,
|
|
6521
|
+
eventType: "created",
|
|
6522
|
+
createdAt: now
|
|
6523
|
+
});
|
|
6524
|
+
inserted = true;
|
|
6525
|
+
}
|
|
6526
|
+
for (const sourceId of sources) {
|
|
6527
|
+
const edge = await tx.select({ id: artifactEdges.id }).from(artifactEdges).where(and10(eq10(artifactEdges.fromMemoryId, sourceId), eq10(artifactEdges.toMemoryId, memoryId), eq10(artifactEdges.edgeKind, "memory_supports"))).limit(1);
|
|
6528
|
+
if (edge.length > 0)
|
|
6529
|
+
continue;
|
|
6047
6530
|
await tx.insert(artifactEdges).values({
|
|
6048
6531
|
id: crypto.randomUUID(),
|
|
6049
|
-
fromMemoryId:
|
|
6050
|
-
toMemoryId:
|
|
6051
|
-
edgeKind:
|
|
6532
|
+
fromMemoryId: sourceId,
|
|
6533
|
+
toMemoryId: memoryId,
|
|
6534
|
+
edgeKind: "memory_supports",
|
|
6052
6535
|
weight: 1,
|
|
6053
|
-
status:
|
|
6536
|
+
status: "pending",
|
|
6054
6537
|
source: "llm",
|
|
6055
|
-
confidence:
|
|
6056
|
-
validAt:
|
|
6538
|
+
confidence: null,
|
|
6539
|
+
validAt: null,
|
|
6057
6540
|
expiredAt: null,
|
|
6058
6541
|
createdAt: now,
|
|
6059
6542
|
updatedAt: now
|
|
6060
6543
|
});
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
});
|
|
6066
|
-
var writeDerivedMemory = (db, content, sources, now) => Effect29.tryPromise({
|
|
6067
|
-
try: () => db.transaction(async (tx) => {
|
|
6068
|
-
const logicalKey = derivedKey(content);
|
|
6069
|
-
const existing = await tx.select({ id: memories.id }).from(memories).where(and10(eq10(memories.logicalKey, logicalKey), eq10(memories.namespace, DERIVED_NAMESPACE), eq10(memories.state, "active"))).limit(1);
|
|
6070
|
-
const memoryId = existing[0]?.id ?? crypto.randomUUID();
|
|
6071
|
-
let inserted = false;
|
|
6072
|
-
if (existing.length === 0) {
|
|
6073
|
-
await tx.insert(memories).values({
|
|
6074
|
-
id: memoryId,
|
|
6075
|
-
logicalKey,
|
|
6076
|
-
content,
|
|
6077
|
-
contentType: "text/plain",
|
|
6078
|
-
state: "active",
|
|
6079
|
-
createdAt: now,
|
|
6080
|
-
ttlSecs: DERIVED_TTL_SECS,
|
|
6081
|
-
namespace: DERIVED_NAMESPACE,
|
|
6082
|
-
metadata: JSON.stringify({ sources })
|
|
6083
|
-
});
|
|
6084
|
-
await tx.insert(memoryEvents).values({
|
|
6085
|
-
memoryId,
|
|
6086
|
-
eventType: "created",
|
|
6087
|
-
createdAt: now
|
|
6088
|
-
});
|
|
6089
|
-
inserted = true;
|
|
6090
|
-
}
|
|
6091
|
-
for (const sourceId of sources) {
|
|
6092
|
-
const edge = await tx.select({ id: artifactEdges.id }).from(artifactEdges).where(and10(eq10(artifactEdges.fromMemoryId, sourceId), eq10(artifactEdges.toMemoryId, memoryId), eq10(artifactEdges.edgeKind, "memory_supports"))).limit(1);
|
|
6093
|
-
if (edge.length > 0)
|
|
6094
|
-
continue;
|
|
6095
|
-
await tx.insert(artifactEdges).values({
|
|
6096
|
-
id: crypto.randomUUID(),
|
|
6097
|
-
fromMemoryId: sourceId,
|
|
6098
|
-
toMemoryId: memoryId,
|
|
6099
|
-
edgeKind: "memory_supports",
|
|
6100
|
-
weight: 1,
|
|
6101
|
-
status: "pending",
|
|
6102
|
-
source: "llm",
|
|
6103
|
-
confidence: null,
|
|
6104
|
-
validAt: null,
|
|
6105
|
-
expiredAt: null,
|
|
6106
|
-
createdAt: now,
|
|
6107
|
-
updatedAt: now
|
|
6108
|
-
});
|
|
6109
|
-
}
|
|
6110
|
-
return { inserted };
|
|
6111
|
-
}),
|
|
6112
|
-
catch: (cause) => new StoreError({ message: `memory.dream: write derived: ${cause}` })
|
|
6113
|
-
});
|
|
6114
|
-
var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
6544
|
+
}
|
|
6545
|
+
return { inserted };
|
|
6546
|
+
};
|
|
6547
|
+
var runDream = Effect30.fn("MemoryDream.run")(function* (model, classify) {
|
|
6115
6548
|
const backend = yield* Service2;
|
|
6116
6549
|
const db = backend.db;
|
|
6117
6550
|
const now = yield* Clock7.currentTimeMillis;
|
|
6118
6551
|
const { minHours, minNewMemories, maxPairs, maxDerived } = dreamStateDefaults;
|
|
6119
|
-
const stateRows = yield*
|
|
6552
|
+
const stateRows = yield* Effect30.tryPromise({
|
|
6120
6553
|
try: () => db.select().from(dreamState).where(eq10(dreamState.modelKey, model.id)),
|
|
6121
6554
|
catch: (cause) => new StoreError({ message: `memory.dream: load state: ${cause}` })
|
|
6122
6555
|
});
|
|
6123
6556
|
const lastDreamAt = stateRows[0]?.lastDreamAt ?? 0;
|
|
6124
|
-
const sinceCountRows = yield* Effect29.tryPromise({
|
|
6125
|
-
try: () => db.select({ count: sql9`count(*)` }).from(memories).where(gt(memories.createdAt, lastDreamAt)),
|
|
6126
|
-
catch: (cause) => new StoreError({ message: `memory.dream: count new: ${cause}` })
|
|
6127
|
-
});
|
|
6128
|
-
const memoriesSinceWatermark = Number(sinceCountRows[0]?.count ?? 0);
|
|
6129
6557
|
if (now - lastDreamAt < minHours * 3600000) {
|
|
6130
|
-
yield*
|
|
6558
|
+
yield* Effect30.logDebug("dream.skipped").pipe(Effect30.annotateLogs({ scope: "@dimple/store", event: "dream.skipped", reason: "cooldown" }));
|
|
6131
6559
|
return {
|
|
6132
6560
|
skipped: true,
|
|
6133
6561
|
reason: "cooldown",
|
|
@@ -6136,8 +6564,13 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6136
6564
|
superseded: 0
|
|
6137
6565
|
};
|
|
6138
6566
|
}
|
|
6567
|
+
const sinceCountRows = yield* Effect30.tryPromise({
|
|
6568
|
+
try: () => db.select({ count: sql9`count(*)` }).from(memories).where(gt(memories.createdAt, lastDreamAt)),
|
|
6569
|
+
catch: (cause) => new StoreError({ message: `memory.dream: count new: ${cause}` })
|
|
6570
|
+
});
|
|
6571
|
+
const memoriesSinceWatermark = Number(sinceCountRows[0]?.count ?? 0);
|
|
6139
6572
|
if (memoriesSinceWatermark < minNewMemories) {
|
|
6140
|
-
yield*
|
|
6573
|
+
yield* Effect30.logDebug("dream.skipped").pipe(Effect30.annotateLogs({
|
|
6141
6574
|
scope: "@dimple/store",
|
|
6142
6575
|
event: "dream.skipped",
|
|
6143
6576
|
reason: "insufficient-new-memories",
|
|
@@ -6151,7 +6584,7 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6151
6584
|
superseded: 0
|
|
6152
6585
|
};
|
|
6153
6586
|
}
|
|
6154
|
-
const pendingRows = yield*
|
|
6587
|
+
const pendingRows = yield* Effect30.tryPromise({
|
|
6155
6588
|
try: () => db.select({
|
|
6156
6589
|
fromMemoryId: artifactEdges.fromMemoryId,
|
|
6157
6590
|
toMemoryId: artifactEdges.toMemoryId
|
|
@@ -6164,7 +6597,7 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6164
6597
|
};
|
|
6165
6598
|
for (const row of pendingRows)
|
|
6166
6599
|
addPair(row.fromMemoryId, row.toMemoryId);
|
|
6167
|
-
const sinceRows = yield*
|
|
6600
|
+
const sinceRows = yield* Effect30.tryPromise({
|
|
6168
6601
|
try: () => db.select({
|
|
6169
6602
|
id: memories.id,
|
|
6170
6603
|
logicalKey: memories.logicalKey,
|
|
@@ -6175,19 +6608,19 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6175
6608
|
});
|
|
6176
6609
|
if (sinceRows.length > 0) {
|
|
6177
6610
|
const sinceIds = sinceRows.map((r) => r.id);
|
|
6178
|
-
const membershipRows = yield*
|
|
6611
|
+
const membershipRows = yield* Effect30.tryPromise({
|
|
6179
6612
|
try: () => db.select({ memoryId: topicMemberships.memoryId, topicKey: topicMemberships.topicKey }).from(topicMemberships).where(and10(eq10(topicMemberships.modelKey, model.id), inArray5(topicMemberships.memoryId, sinceIds))),
|
|
6180
6613
|
catch: (cause) => new StoreError({ message: `memory.dream: scan memberships: ${cause}` })
|
|
6181
6614
|
});
|
|
6182
6615
|
const leafKeys = [...new Set(membershipRows.map((m) => m.topicKey))];
|
|
6183
6616
|
if (leafKeys.length > 0) {
|
|
6184
|
-
const mateRows = yield*
|
|
6617
|
+
const mateRows = yield* Effect30.tryPromise({
|
|
6185
6618
|
try: () => db.select({ memoryId: topicMemberships.memoryId, topicKey: topicMemberships.topicKey }).from(topicMemberships).where(and10(eq10(topicMemberships.modelKey, model.id), inArray5(topicMemberships.topicKey, leafKeys))),
|
|
6186
6619
|
catch: (cause) => new StoreError({ message: `memory.dream: scan mates: ${cause}` })
|
|
6187
6620
|
});
|
|
6188
6621
|
const memberIds = [...new Set([...sinceIds, ...mateRows.map((m) => m.memoryId)])];
|
|
6189
|
-
const vectorRows = yield* backend.fetchMemoryVectors(memberIds, model).pipe(
|
|
6190
|
-
const memoryRows = yield*
|
|
6622
|
+
const vectorRows = yield* backend.fetchMemoryVectors(memberIds, model).pipe(Effect30.mapError((cause) => new StoreError({ message: `memory.dream: scan vectors: ${cause}` })));
|
|
6623
|
+
const memoryRows = yield* Effect30.tryPromise({
|
|
6191
6624
|
try: () => db.select({
|
|
6192
6625
|
id: memories.id,
|
|
6193
6626
|
logicalKey: memories.logicalKey,
|
|
@@ -6244,7 +6677,7 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6244
6677
|
}
|
|
6245
6678
|
const orderedPairs = [...pairSet.values()].sort((a, b) => cmp3(a.toMemoryId, b.toMemoryId) || cmp3(a.fromMemoryId, b.fromMemoryId)).slice(0, maxPairs);
|
|
6246
6679
|
const endpointIds = [...new Set(orderedPairs.flatMap((p) => [p.fromMemoryId, p.toMemoryId]))];
|
|
6247
|
-
const contentRows = endpointIds.length > 0 ? yield*
|
|
6680
|
+
const contentRows = endpointIds.length > 0 ? yield* Effect30.tryPromise({
|
|
6248
6681
|
try: () => db.select({ id: memories.id, content: memories.content }).from(memories).where(inArray5(memories.id, endpointIds)),
|
|
6249
6682
|
catch: (cause) => new StoreError({ message: `memory.dream: pair contents: ${cause}` })
|
|
6250
6683
|
}) : [];
|
|
@@ -6264,17 +6697,17 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6264
6697
|
}
|
|
6265
6698
|
let classification = { relations: [], derived: [] };
|
|
6266
6699
|
if (dreamPairs.length > 0) {
|
|
6267
|
-
classification = yield* classify.classify(dreamPairs, { maxDerived }).pipe(
|
|
6700
|
+
classification = yield* classify.classify(dreamPairs, { maxDerived }).pipe(Effect30.mapError((error) => new StoreError({ message: `memory.dream: classify: ${error}` })));
|
|
6268
6701
|
}
|
|
6269
6702
|
const endpointIdsOf = [
|
|
6270
6703
|
...new Set(classification.relations.flatMap((r) => [r.fromMemoryId, r.toMemoryId]))
|
|
6271
6704
|
];
|
|
6272
|
-
const endpointRows = endpointIdsOf.length > 0 ? yield*
|
|
6705
|
+
const endpointRows = endpointIdsOf.length > 0 ? yield* Effect30.tryPromise({
|
|
6273
6706
|
try: () => db.select({ id: memories.id, metadata: memories.metadata }).from(memories).where(inArray5(memories.id, endpointIdsOf)),
|
|
6274
6707
|
catch: (cause) => new StoreError({ message: `memory.dream: endpoints: ${cause}` })
|
|
6275
6708
|
}) : [];
|
|
6276
6709
|
const metadataById = new Map(endpointRows.map((r) => [r.id, r.metadata]));
|
|
6277
|
-
|
|
6710
|
+
const acceptedRelations = [];
|
|
6278
6711
|
for (const relation of classification.relations) {
|
|
6279
6712
|
const fromMetadata = metadataById.get(relation.fromMemoryId);
|
|
6280
6713
|
const toMetadata = metadataById.get(relation.toMemoryId);
|
|
@@ -6283,13 +6716,11 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6283
6716
|
if (parseMetadata(fromMetadata)?.pinned === true || parseMetadata(toMetadata)?.pinned === true) {
|
|
6284
6717
|
continue;
|
|
6285
6718
|
}
|
|
6286
|
-
|
|
6287
|
-
if (result.flipped)
|
|
6288
|
-
superseded++;
|
|
6719
|
+
acceptedRelations.push(relation);
|
|
6289
6720
|
}
|
|
6290
|
-
|
|
6721
|
+
const acceptedDerived = [];
|
|
6291
6722
|
for (const derived of classification.derived) {
|
|
6292
|
-
const sourceRows = derived.sources.length > 0 ? yield*
|
|
6723
|
+
const sourceRows = derived.sources.length > 0 ? yield* Effect30.tryPromise({
|
|
6293
6724
|
try: () => db.select({ id: memories.id }).from(memories).where(inArray5(memories.id, derived.sources)),
|
|
6294
6725
|
catch: (cause) => new StoreError({ message: `memory.dream: derived sources: ${cause}` })
|
|
6295
6726
|
}) : [];
|
|
@@ -6297,27 +6728,36 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6297
6728
|
const survivingSources = derived.sources.filter((id) => survivingIds.has(id));
|
|
6298
6729
|
if (survivingSources.length === 0)
|
|
6299
6730
|
continue;
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
try: () => db.
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6731
|
+
acceptedDerived.push({ content: derived.content, sources: survivingSources });
|
|
6732
|
+
}
|
|
6733
|
+
let superseded = 0;
|
|
6734
|
+
let created = 0;
|
|
6735
|
+
yield* Effect30.tryPromise({
|
|
6736
|
+
try: () => db.transaction(async (tx) => {
|
|
6737
|
+
for (const relation of acceptedRelations) {
|
|
6738
|
+
const result = await writeRelationEdgeTx(tx, relation, now);
|
|
6739
|
+
if (result.flipped)
|
|
6740
|
+
superseded++;
|
|
6741
|
+
}
|
|
6742
|
+
for (const derived of acceptedDerived) {
|
|
6743
|
+
const outcome = await writeDerivedMemoryTx(tx, derived.content, derived.sources, now);
|
|
6744
|
+
if (outcome.inserted)
|
|
6745
|
+
created++;
|
|
6746
|
+
}
|
|
6747
|
+
const countRows = await tx.select({ count: sql9`count(*)` }).from(memories);
|
|
6748
|
+
const totalMemories = Number(countRows[0]?.count ?? 0);
|
|
6749
|
+
await tx.insert(dreamState).values({
|
|
6750
|
+
modelKey: model.id,
|
|
6751
|
+
lastDreamAt: now,
|
|
6752
|
+
lastDreamMemoryCount: totalMemories
|
|
6753
|
+
}).onConflictDoUpdate({
|
|
6754
|
+
target: dreamState.modelKey,
|
|
6755
|
+
set: { lastDreamAt: now, lastDreamMemoryCount: totalMemories }
|
|
6756
|
+
});
|
|
6317
6757
|
}),
|
|
6318
|
-
catch: (cause) => new StoreError({ message: `memory.dream:
|
|
6758
|
+
catch: (cause) => new StoreError({ message: `memory.dream: persist: ${cause}` })
|
|
6319
6759
|
});
|
|
6320
|
-
yield*
|
|
6760
|
+
yield* Effect30.logInfo("dream.completed").pipe(Effect30.annotateLogs({
|
|
6321
6761
|
scope: "@dimple/store",
|
|
6322
6762
|
event: "dream.completed",
|
|
6323
6763
|
modelKey: model.id,
|
|
@@ -6328,24 +6768,24 @@ var runDream = Effect29.fn("MemoryDream.run")(function* (model, classify) {
|
|
|
6328
6768
|
return { skipped: false, classified: dreamPairs.length, created, superseded };
|
|
6329
6769
|
});
|
|
6330
6770
|
function graphDreamHandler(deps) {
|
|
6331
|
-
const run = (payload, ctx) =>
|
|
6771
|
+
const run = (payload, ctx) => Effect30.gen(function* () {
|
|
6332
6772
|
const envelope = payload;
|
|
6333
6773
|
const model = deps.getModelConfig(envelope.modelKey);
|
|
6334
6774
|
if (!model) {
|
|
6335
|
-
return yield*
|
|
6775
|
+
return yield* Effect30.fail(new JobFailure({
|
|
6336
6776
|
jobId: ctx.jobId,
|
|
6337
6777
|
message: `memory.dream: unknown model "${envelope.modelKey}"`
|
|
6338
6778
|
}));
|
|
6339
6779
|
}
|
|
6340
|
-
return yield* runDream(model, deps.classify).pipe(
|
|
6780
|
+
return yield* runDream(model, deps.classify).pipe(Effect30.mapError((error) => new JobFailure({ jobId: ctx.jobId, message: `memory.dream: ${error}` })));
|
|
6341
6781
|
});
|
|
6342
|
-
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(
|
|
6782
|
+
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(Effect30.provideService(Service2, deps.backend)) : run;
|
|
6343
6783
|
}
|
|
6344
6784
|
// ../store/src/graph/repair.ts
|
|
6345
|
-
import { Clock as Clock8, Effect as
|
|
6785
|
+
import { Clock as Clock8, Effect as Effect31 } from "effect";
|
|
6346
6786
|
import { and as and11, eq as eq11, isNotNull as isNotNull2, lt, or as or2, sql as sql10 } from "drizzle-orm";
|
|
6347
6787
|
var DEFAULT_EXPIRED_GRACE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
6348
|
-
var runRepair = (db, includePurgeExpired, expiredGraceMs, now) =>
|
|
6788
|
+
var runRepair = (db, includePurgeExpired, expiredGraceMs, now) => Effect31.tryPromise({
|
|
6349
6789
|
try: () => db.transaction(async (tx) => {
|
|
6350
6790
|
let orphanedEdges = 0;
|
|
6351
6791
|
let staleAnnotations = 0;
|
|
@@ -6439,10 +6879,10 @@ var runRepair = (db, includePurgeExpired, expiredGraceMs, now) => Effect30.tryPr
|
|
|
6439
6879
|
catch: (cause) => new StoreError({ message: `graph.repair: ${cause}` })
|
|
6440
6880
|
});
|
|
6441
6881
|
function graphRepairHandler(deps) {
|
|
6442
|
-
const run = (payload, ctx) =>
|
|
6882
|
+
const run = (payload, ctx) => Effect31.gen(function* () {
|
|
6443
6883
|
const envelope = payload;
|
|
6444
6884
|
if (!deps.getModelConfig(envelope.modelKey)) {
|
|
6445
|
-
return yield*
|
|
6885
|
+
return yield* Effect31.fail(new JobFailure({
|
|
6446
6886
|
jobId: ctx.jobId,
|
|
6447
6887
|
message: `graph.repair: unknown model "${envelope.modelKey}"`
|
|
6448
6888
|
}));
|
|
@@ -6450,8 +6890,8 @@ function graphRepairHandler(deps) {
|
|
|
6450
6890
|
const backend = yield* Service2;
|
|
6451
6891
|
const db = backend.db;
|
|
6452
6892
|
const now = yield* Clock8.currentTimeMillis;
|
|
6453
|
-
const result = yield* runRepair(db, deps.includePurgeExpired ?? false, deps.expiredGraceMs ?? DEFAULT_EXPIRED_GRACE_MS, now).pipe(
|
|
6454
|
-
yield*
|
|
6893
|
+
const result = yield* runRepair(db, deps.includePurgeExpired ?? false, deps.expiredGraceMs ?? DEFAULT_EXPIRED_GRACE_MS, now).pipe(Effect31.mapError((error) => new JobFailure({ jobId: ctx.jobId, message: `graph.repair: ${error}` })));
|
|
6894
|
+
yield* Effect31.logInfo("repair.completed").pipe(Effect31.annotateLogs({
|
|
6455
6895
|
scope: "@dimple/store",
|
|
6456
6896
|
event: "repair.completed",
|
|
6457
6897
|
modelKey: envelope.modelKey,
|
|
@@ -6461,7 +6901,7 @@ function graphRepairHandler(deps) {
|
|
|
6461
6901
|
}));
|
|
6462
6902
|
return result;
|
|
6463
6903
|
});
|
|
6464
|
-
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(
|
|
6904
|
+
return deps.backend ? (payload, ctx) => run(payload, ctx).pipe(Effect31.provideService(Service2, deps.backend)) : run;
|
|
6465
6905
|
}
|
|
6466
6906
|
// ../store/src/models.ts
|
|
6467
6907
|
import { Schema as Schema20 } from "effect";
|
|
@@ -6548,15 +6988,21 @@ class EmbeddingError extends Schema21.TaggedErrorClass()("EmbeddingProvider.Embe
|
|
|
6548
6988
|
class Service9 extends Context9.Service()("@dimple/embedder/EmbeddingModelRegistry") {
|
|
6549
6989
|
}
|
|
6550
6990
|
// ../embedder/src/transformers.ts
|
|
6551
|
-
import { Config as Config5, Effect as
|
|
6991
|
+
import { Config as Config5, Effect as Effect33, Layer as Layer11 } from "effect";
|
|
6552
6992
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
6553
6993
|
import { join as join2 } from "node:path";
|
|
6554
6994
|
import { pathToFileURL } from "node:url";
|
|
6555
6995
|
|
|
6556
|
-
// ../
|
|
6557
|
-
import { execFile } from "node:child_process";
|
|
6996
|
+
// ../installer/src/index.ts
|
|
6558
6997
|
import { existsSync } from "node:fs";
|
|
6559
6998
|
import { join } from "node:path";
|
|
6999
|
+
|
|
7000
|
+
class InstallerError extends Error {
|
|
7001
|
+
constructor(message) {
|
|
7002
|
+
super(message);
|
|
7003
|
+
this.name = "InstallerError";
|
|
7004
|
+
}
|
|
7005
|
+
}
|
|
6560
7006
|
var detectPackageManager = (cwd) => {
|
|
6561
7007
|
let dir = cwd;
|
|
6562
7008
|
while (true) {
|
|
@@ -6571,38 +7017,74 @@ var detectPackageManager = (cwd) => {
|
|
|
6571
7017
|
return { pm: "npm", root: dir };
|
|
6572
7018
|
const parent = join(dir, "..");
|
|
6573
7019
|
if (parent === dir)
|
|
6574
|
-
return { pm: "
|
|
7020
|
+
return { pm: "npm", root: cwd };
|
|
6575
7021
|
dir = parent;
|
|
6576
7022
|
}
|
|
6577
7023
|
};
|
|
6578
|
-
var
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
7024
|
+
var resolveExecutable = (pm, platform = process.platform) => platform === "win32" && pm !== "bun" ? `${pm}.cmd` : pm;
|
|
7025
|
+
var installArgs = (pm, packages, root) => {
|
|
7026
|
+
const argv = [pm === "npm" ? "install" : "add", ...packages];
|
|
7027
|
+
if (pm !== "bun")
|
|
7028
|
+
argv.push("--ignore-scripts");
|
|
7029
|
+
if (pm === "npm")
|
|
7030
|
+
argv.push("--no-audit", "--no-fund");
|
|
7031
|
+
if (pm === "pnpm" && existsSync(join(root, "pnpm-workspace.yaml")))
|
|
7032
|
+
argv.push("-w");
|
|
7033
|
+
return argv;
|
|
7034
|
+
};
|
|
7035
|
+
var installOnce = async (target, packages, opts) => {
|
|
7036
|
+
const { spawn } = await import("node:child_process");
|
|
7037
|
+
return new Promise((resolve, reject) => {
|
|
7038
|
+
const timeoutMs = opts.timeoutMs ?? 300000;
|
|
7039
|
+
const cmd = resolveExecutable(target.pm, opts.platform);
|
|
7040
|
+
const args = installArgs(target.pm, packages, target.root);
|
|
7041
|
+
const manual = `${cmd} ${args.join(" ")}`;
|
|
7042
|
+
const child = spawn(cmd, args, { cwd: target.root, stdio: "ignore" });
|
|
7043
|
+
let settled = false;
|
|
7044
|
+
const timer = setTimeout(() => {
|
|
7045
|
+
child.kill("SIGKILL");
|
|
7046
|
+
if (settled)
|
|
7047
|
+
return;
|
|
7048
|
+
settled = true;
|
|
7049
|
+
reject(new InstallerError(`auto-install timed out after ${timeoutMs} ms — the child was killed; run it manually: ${manual}`));
|
|
7050
|
+
}, timeoutMs);
|
|
7051
|
+
child.on("error", (cause) => {
|
|
7052
|
+
clearTimeout(timer);
|
|
7053
|
+
if (settled)
|
|
7054
|
+
return;
|
|
7055
|
+
settled = true;
|
|
7056
|
+
reject(new InstallerError(`auto-install failed to start (${manual}): ${cause.message} — run it manually`));
|
|
7057
|
+
});
|
|
7058
|
+
child.on("exit", (code, signal) => {
|
|
7059
|
+
clearTimeout(timer);
|
|
7060
|
+
if (settled)
|
|
7061
|
+
return;
|
|
7062
|
+
settled = true;
|
|
7063
|
+
if (code === 0) {
|
|
7064
|
+
resolve();
|
|
7065
|
+
return;
|
|
7066
|
+
}
|
|
7067
|
+
reject(new InstallerError(`auto-install failed (${manual} exited ${signal !== null ? `with ${signal}` : `code ${code ?? "?"}`}) — run it manually`));
|
|
7068
|
+
});
|
|
7069
|
+
});
|
|
6596
7070
|
};
|
|
6597
|
-
var
|
|
7071
|
+
var inflight = new Map;
|
|
7072
|
+
var installOptionalPeers = (packages, opts) => {
|
|
7073
|
+
const cwd = opts?.cwd ?? process.cwd();
|
|
6598
7074
|
const target = detectPackageManager(cwd);
|
|
6599
|
-
const
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
7075
|
+
const key = `${target.root}\x00${packages.join(",")}`;
|
|
7076
|
+
const existing = inflight.get(key);
|
|
7077
|
+
if (existing !== undefined)
|
|
7078
|
+
return existing;
|
|
7079
|
+
const run = installOnce(target, packages, opts ?? {});
|
|
7080
|
+
inflight.set(key, run);
|
|
7081
|
+
run.then(() => inflight.delete(key), () => inflight.delete(key));
|
|
7082
|
+
return run;
|
|
7083
|
+
};
|
|
7084
|
+
// ../embedder/src/auto-install.ts
|
|
7085
|
+
var installTransformers = (cwd) => installOptionalPeers(["@huggingface/transformers"], { cwd, timeoutMs: 300000 }).catch((cause) => {
|
|
7086
|
+
throw new EmbeddingError({
|
|
7087
|
+
message: cause instanceof InstallerError ? `${cause.message} — or set \`autoInstall: false\` and configure a hosted embedding provider` : `auto-install of @huggingface/transformers failed: ${String(cause)} — run it manually ` + "or set `autoInstall: false` and configure a hosted embedding provider"
|
|
6606
7088
|
});
|
|
6607
7089
|
});
|
|
6608
7090
|
|
|
@@ -6653,44 +7135,59 @@ var defaults2 = {
|
|
|
6653
7135
|
pooling: "mean",
|
|
6654
7136
|
normalize: true
|
|
6655
7137
|
};
|
|
7138
|
+
var outputVectors = (result) => {
|
|
7139
|
+
const { data, dims } = result;
|
|
7140
|
+
const stride = dims.length > 0 ? dims[dims.length - 1] : data.length;
|
|
7141
|
+
if (stride > 0 && data.length % stride === 0) {
|
|
7142
|
+
const vectors = [];
|
|
7143
|
+
for (let offset = 0;offset < data.length; offset += stride) {
|
|
7144
|
+
vectors.push(data.subarray(offset, offset + stride));
|
|
7145
|
+
}
|
|
7146
|
+
return vectors;
|
|
7147
|
+
}
|
|
7148
|
+
return result.tolist().map((v) => new Float32Array(v));
|
|
7149
|
+
};
|
|
6656
7150
|
var make5 = (options) => {
|
|
6657
7151
|
let pipe = null;
|
|
6658
|
-
const getPipeline =
|
|
7152
|
+
const getPipeline = Effect33.fnUntraced(function* () {
|
|
6659
7153
|
if (pipe)
|
|
6660
7154
|
return pipe;
|
|
6661
|
-
const loadModule = () =>
|
|
6662
|
-
let transformers = yield* loadModule().pipe(
|
|
7155
|
+
const loadModule = () => Effect33.tryPromise(() => import("@huggingface/transformers"));
|
|
7156
|
+
let transformers = yield* loadModule().pipe(Effect33.catch(() => {
|
|
6663
7157
|
if (options.autoInstall === false) {
|
|
6664
|
-
return
|
|
7158
|
+
return Effect33.fail(new EmbeddingError({
|
|
6665
7159
|
message: "@huggingface/transformers is not installed — run `bun add @huggingface/transformers` " + "to use local embeddings (or configure a hosted embedding provider)"
|
|
6666
7160
|
}));
|
|
6667
7161
|
}
|
|
6668
|
-
return
|
|
6669
|
-
yield*
|
|
6670
|
-
yield*
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
7162
|
+
return Effect33.gen(function* () {
|
|
7163
|
+
yield* Effect33.logInfo("auto-installing @huggingface/transformers (first local-embed use — scripts skipped)").pipe(Effect33.annotateLogs({ scope: "@dimple/embedder", event: "embedder.auto-install" }));
|
|
7164
|
+
yield* Effect33.tryPromise(() => installTransformers(process.cwd())).pipe(Effect33.catch((cause) => {
|
|
7165
|
+
const inner = cause.cause;
|
|
7166
|
+
return Effect33.fail(inner instanceof EmbeddingError ? inner : new EmbeddingError({
|
|
7167
|
+
message: `auto-install failed: ${inner instanceof Error ? inner.message : String(cause)}`
|
|
7168
|
+
}));
|
|
7169
|
+
}));
|
|
7170
|
+
return yield* Effect33.tryPromise(importFromDisk).pipe(Effect33.mapError(() => new EmbeddingError({
|
|
6674
7171
|
message: "@huggingface/transformers still unavailable after auto-install — run `bun add " + "@huggingface/transformers` manually (or set `autoInstall: false` and configure a hosted embedding provider)"
|
|
6675
7172
|
})));
|
|
6676
7173
|
});
|
|
6677
7174
|
}));
|
|
6678
7175
|
if (options.cacheDir)
|
|
6679
7176
|
transformers.env.cacheDir = options.cacheDir;
|
|
6680
|
-
pipe = yield*
|
|
7177
|
+
pipe = yield* Effect33.tryPromise(() => transformers.pipeline("feature-extraction", options.modelId ?? defaults2.modelId, {
|
|
6681
7178
|
device: options.device ?? defaults2.device,
|
|
6682
7179
|
dtype: options.dtype ?? defaults2.dtype
|
|
6683
|
-
})).pipe(
|
|
7180
|
+
})).pipe(Effect33.mapError((cause) => new EmbeddingError({ message: `load model: ${cause}` })));
|
|
6684
7181
|
return pipe;
|
|
6685
7182
|
});
|
|
6686
|
-
const embed =
|
|
7183
|
+
const embed = Effect33.fn("TransformersEmbedding.embed")(function* (texts) {
|
|
6687
7184
|
const started = Date.now();
|
|
6688
7185
|
const p = yield* getPipeline();
|
|
6689
|
-
const result = yield*
|
|
7186
|
+
const result = yield* Effect33.promise(() => p(texts, {
|
|
6690
7187
|
pooling: options.pooling ?? defaults2.pooling,
|
|
6691
7188
|
normalize: options.normalize ?? defaults2.normalize
|
|
6692
|
-
})).pipe(
|
|
6693
|
-
const vectors = result
|
|
7189
|
+
})).pipe(Effect33.mapError((cause) => new EmbeddingError({ message: `embed: ${cause}` })));
|
|
7190
|
+
const vectors = outputVectors(result);
|
|
6694
7191
|
for (const vector of vectors) {
|
|
6695
7192
|
if (options.dimensions !== undefined && vector.length !== options.dimensions) {
|
|
6696
7193
|
return yield* new EmbeddingError({
|
|
@@ -6698,7 +7195,7 @@ var make5 = (options) => {
|
|
|
6698
7195
|
});
|
|
6699
7196
|
}
|
|
6700
7197
|
}
|
|
6701
|
-
yield*
|
|
7198
|
+
yield* Effect33.logDebug("embedder.embed").pipe(Effect33.annotateLogs({
|
|
6702
7199
|
scope: "@dimple/embedder",
|
|
6703
7200
|
event: "embedder.embed",
|
|
6704
7201
|
count: texts.length,
|
|
@@ -6706,13 +7203,13 @@ var make5 = (options) => {
|
|
|
6706
7203
|
}));
|
|
6707
7204
|
return vectors;
|
|
6708
7205
|
});
|
|
6709
|
-
const embedSingle =
|
|
7206
|
+
const embedSingle = Effect33.fn("TransformersEmbedding.embedSingle")(function* (text4) {
|
|
6710
7207
|
const p = yield* getPipeline();
|
|
6711
|
-
const result = yield*
|
|
7208
|
+
const result = yield* Effect33.promise(() => p(text4, {
|
|
6712
7209
|
pooling: options.pooling ?? defaults2.pooling,
|
|
6713
7210
|
normalize: options.normalize ?? defaults2.normalize
|
|
6714
|
-
})).pipe(
|
|
6715
|
-
const vector =
|
|
7211
|
+
})).pipe(Effect33.mapError((cause) => new EmbeddingError({ message: `embedSingle: ${cause}` })));
|
|
7212
|
+
const vector = outputVectors(result)[0] ?? new Float32Array(0);
|
|
6716
7213
|
if (options.dimensions !== undefined && vector.length !== options.dimensions) {
|
|
6717
7214
|
return yield* new EmbeddingError({
|
|
6718
7215
|
message: `embedder dimension mismatch: model outputs ${vector.length} dims but config declares ${String(options.dimensions)}`
|
|
@@ -6733,14 +7230,14 @@ var makeTransformersModel = (options = {}) => {
|
|
|
6733
7230
|
};
|
|
6734
7231
|
};
|
|
6735
7232
|
// ../embedder/src/registry.ts
|
|
6736
|
-
import { Effect as
|
|
7233
|
+
import { Effect as Effect34, Layer as Layer12 } from "effect";
|
|
6737
7234
|
// ../core/src/hosted-embedding.ts
|
|
6738
7235
|
import { embedMany } from "ai";
|
|
6739
7236
|
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
6740
7237
|
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
6741
7238
|
import { createCohere } from "@ai-sdk/cohere";
|
|
6742
7239
|
import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
|
|
6743
|
-
import { Effect as
|
|
7240
|
+
import { Effect as Effect35 } from "effect";
|
|
6744
7241
|
var makeHostedEmbeddingModel = (options) => {
|
|
6745
7242
|
const provider = options.provider ?? "openai";
|
|
6746
7243
|
const model = provider === "google" ? createGoogleGenerativeAI({
|
|
@@ -6771,8 +7268,8 @@ var makeHostedEmbeddingModel = (options) => {
|
|
|
6771
7268
|
return { openaiCompatible: { dimensions: options.dimensions } };
|
|
6772
7269
|
}
|
|
6773
7270
|
})();
|
|
6774
|
-
const embed =
|
|
6775
|
-
const result = yield*
|
|
7271
|
+
const embed = Effect35.fn("HostedEmbedding.embed")(function* (texts) {
|
|
7272
|
+
const result = yield* Effect35.tryPromise({
|
|
6776
7273
|
try: () => embedMany({ model, values: [...texts], providerOptions }),
|
|
6777
7274
|
catch: (cause) => new EmbeddingError({ message: `hosted embedMany: ${cause}` })
|
|
6778
7275
|
});
|
|
@@ -6785,7 +7282,7 @@ var makeHostedEmbeddingModel = (options) => {
|
|
|
6785
7282
|
}
|
|
6786
7283
|
return result.embeddings.map((e) => new Float32Array(e));
|
|
6787
7284
|
});
|
|
6788
|
-
const embedSingle =
|
|
7285
|
+
const embedSingle = Effect35.fn("HostedEmbedding.embedSingle")(function* (text4) {
|
|
6789
7286
|
const results = yield* embed([text4]);
|
|
6790
7287
|
return results[0];
|
|
6791
7288
|
});
|
|
@@ -6799,7 +7296,7 @@ var makeHostedEmbeddingModel = (options) => {
|
|
|
6799
7296
|
};
|
|
6800
7297
|
|
|
6801
7298
|
// ../retriever/src/hybrid.ts
|
|
6802
|
-
import { Context as Context10, Effect as
|
|
7299
|
+
import { Context as Context10, Effect as Effect36, Layer as Layer13, Schema as Schema22 } from "effect";
|
|
6803
7300
|
|
|
6804
7301
|
// ../retriever/src/rrf.ts
|
|
6805
7302
|
function fuse(denseRanks, fts5Ranks, k, limit) {
|
|
@@ -6842,15 +7339,15 @@ class HybridError extends Schema22.TaggedErrorClass()("HybridRetrieval.HybridErr
|
|
|
6842
7339
|
|
|
6843
7340
|
class Service10 extends Context10.Service()("@dimple/retriever/HybridRetrieval") {
|
|
6844
7341
|
}
|
|
6845
|
-
var wrapError = (tag) => (effect) => effect.pipe(
|
|
6846
|
-
var layer11 = (options) => Layer13.effect(Service10,
|
|
7342
|
+
var wrapError = (tag) => (effect) => effect.pipe(Effect36.mapError((cause) => new HybridError({ message: `${tag}: ${cause}` })));
|
|
7343
|
+
var layer11 = (options) => Layer13.effect(Service10, Effect36.gen(function* () {
|
|
6847
7344
|
const store = yield* Service5;
|
|
6848
7345
|
const registry = yield* Service9;
|
|
6849
7346
|
const defaultId = yield* registry.defaultModelId.pipe(wrapError("defaultModelId"));
|
|
6850
7347
|
const defaultModel = yield* registry.getModel(defaultId).pipe(wrapError("getModel"));
|
|
6851
7348
|
const defaultK = options?.defaultK ?? 60;
|
|
6852
7349
|
const defaultLimit = options?.defaultLimit ?? 10;
|
|
6853
|
-
const hybrid =
|
|
7350
|
+
const hybrid = Effect36.fn("HybridRetrieval.hybrid")(function* (query2, options2) {
|
|
6854
7351
|
const namespace = options2?.namespace ?? "default";
|
|
6855
7352
|
const limit = options2?.limit ?? defaultLimit;
|
|
6856
7353
|
const k = options2?.k ?? defaultK;
|
|
@@ -6867,12 +7364,16 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6867
7364
|
const vectorResults = yield* store.searchVector([...embedding], namespace, limit * fetchMultiplier, {
|
|
6868
7365
|
...vectorOpts,
|
|
6869
7366
|
...options2?.contentType !== undefined ? { contentType: options2.contentType } : {},
|
|
6870
|
-
audit: false
|
|
7367
|
+
audit: false,
|
|
7368
|
+
augment: false,
|
|
7369
|
+
includeEmbedding: options2?.includeEmbedding === true
|
|
6871
7370
|
}).pipe(wrapError("searchVector"));
|
|
6872
7371
|
const fts5Results = yield* store.searchFts5(query2, namespace, limit * fetchMultiplier, {
|
|
6873
7372
|
...topicKeys !== undefined ? { topicKeys } : {},
|
|
6874
7373
|
...options2?.contentType !== undefined ? { contentType: options2.contentType } : {},
|
|
6875
|
-
audit: false
|
|
7374
|
+
audit: false,
|
|
7375
|
+
augment: false,
|
|
7376
|
+
includeEmbedding: options2?.includeEmbedding === true
|
|
6876
7377
|
}).pipe(wrapError("searchFts5"));
|
|
6877
7378
|
const vWeight = profile.modeWeights?.vector ?? 1;
|
|
6878
7379
|
const fWeight = profile.modeWeights?.fts ?? 1;
|
|
@@ -6908,25 +7409,15 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6908
7409
|
const now = Date.now();
|
|
6909
7410
|
const DAY_MS = 86400000;
|
|
6910
7411
|
const recencyBoost = profile.recencyBoost ?? 0;
|
|
6911
|
-
const augmentedById = new Map;
|
|
6912
|
-
for (const sm of vectorResults)
|
|
6913
|
-
augmentedById.set(sm.memory.id, sm);
|
|
6914
|
-
for (const sm of fts5Results)
|
|
6915
|
-
if (!augmentedById.has(sm.memory.id))
|
|
6916
|
-
augmentedById.set(sm.memory.id, sm);
|
|
6917
7412
|
const boosted = fused.map((r) => {
|
|
6918
7413
|
const memory = memoryMap.get(r.memoryId);
|
|
6919
7414
|
const ageDays = (now - memory.createdAt) / DAY_MS;
|
|
6920
7415
|
const recencyFactor = 1 / (1 + ageDays);
|
|
6921
7416
|
const score = r.rrfScore * (1 + recencyBoost * recencyFactor);
|
|
6922
|
-
const aug = augmentedById.get(r.memoryId);
|
|
6923
7417
|
return {
|
|
6924
7418
|
memory,
|
|
6925
7419
|
score,
|
|
6926
|
-
source: "hybrid"
|
|
6927
|
-
...aug?.supersededBy !== undefined ? { supersededBy: aug.supersededBy } : {},
|
|
6928
|
-
...aug?.conflicts !== undefined ? { conflicts: aug.conflicts } : {},
|
|
6929
|
-
...aug?.supportedBy !== undefined ? { supportedBy: aug.supportedBy } : {}
|
|
7420
|
+
source: "hybrid"
|
|
6930
7421
|
};
|
|
6931
7422
|
});
|
|
6932
7423
|
boosted.sort((a, b) => b.score - a.score);
|
|
@@ -6959,7 +7450,7 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6959
7450
|
fts: fts5Results.map((s) => s.memory.id)
|
|
6960
7451
|
})
|
|
6961
7452
|
}).pipe(wrapError("logAudit"));
|
|
6962
|
-
yield*
|
|
7453
|
+
yield* Effect36.logInfo("hybrid.search").pipe(Effect36.annotateLogs({
|
|
6963
7454
|
scope: "@dimple/retriever",
|
|
6964
7455
|
event: "hybrid.search",
|
|
6965
7456
|
mode,
|
|
@@ -6973,7 +7464,7 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6973
7464
|
}));
|
|
6974
7465
|
var hybridRetrievalLayer = layer11();
|
|
6975
7466
|
// ../llm/src/llm.ts
|
|
6976
|
-
import { Cause as Cause4, Effect as
|
|
7467
|
+
import { Cause as Cause4, Effect as Effect37, Schema as Schema23 } from "effect";
|
|
6977
7468
|
import {
|
|
6978
7469
|
generateText as generateTextCall,
|
|
6979
7470
|
NoSuchToolError,
|
|
@@ -7027,9 +7518,9 @@ var makeLLM = (model, defaults3 = {}) => {
|
|
|
7027
7518
|
...reasoningEffort !== undefined ? { providerOptions: { openaiCompatible: { reasoningEffort } } } : {}
|
|
7028
7519
|
};
|
|
7029
7520
|
};
|
|
7030
|
-
const generateText =
|
|
7521
|
+
const generateText = Effect37.fn("LLM.generateText")(function* (input) {
|
|
7031
7522
|
const started = Date.now();
|
|
7032
|
-
const text4 = yield*
|
|
7523
|
+
const text4 = yield* Effect37.tryPromise({
|
|
7033
7524
|
try: () => generateTextCall({
|
|
7034
7525
|
model,
|
|
7035
7526
|
prompt: input.prompt,
|
|
@@ -7038,16 +7529,16 @@ var makeLLM = (model, defaults3 = {}) => {
|
|
|
7038
7529
|
}).then((result) => result.text),
|
|
7039
7530
|
catch: (cause) => new LLMError({ message: "LLM text generation failed", cause: Cause4.die(cause) })
|
|
7040
7531
|
});
|
|
7041
|
-
yield*
|
|
7532
|
+
yield* Effect37.logDebug("llm.generate-text").pipe(Effect37.annotateLogs({
|
|
7042
7533
|
scope: "@dimple/llm",
|
|
7043
7534
|
event: "llm.generate-text",
|
|
7044
7535
|
latencyMs: Date.now() - started
|
|
7045
7536
|
}));
|
|
7046
7537
|
return text4;
|
|
7047
7538
|
});
|
|
7048
|
-
const generateObject =
|
|
7539
|
+
const generateObject = Effect37.fn("LLM.generateObject")(function* (input) {
|
|
7049
7540
|
const started = Date.now();
|
|
7050
|
-
const result = yield*
|
|
7541
|
+
const result = yield* Effect37.tryPromise({
|
|
7051
7542
|
try: async () => {
|
|
7052
7543
|
try {
|
|
7053
7544
|
const result3 = await generateTextCall({
|
|
@@ -7090,7 +7581,7 @@ ${schemaJson}`,
|
|
|
7090
7581
|
},
|
|
7091
7582
|
catch: (cause) => new LLMError({ message: "LLM structured generation failed", cause: Cause4.die(cause) })
|
|
7092
7583
|
});
|
|
7093
|
-
yield*
|
|
7584
|
+
yield* Effect37.logDebug("llm.generate-object").pipe(Effect37.annotateLogs({
|
|
7094
7585
|
scope: "@dimple/llm",
|
|
7095
7586
|
event: "llm.generate-object",
|
|
7096
7587
|
latencyMs: Date.now() - started
|
|
@@ -7110,7 +7601,7 @@ var openAICompatible = (options) => {
|
|
|
7110
7601
|
return provider.languageModel(options.modelId ?? "default");
|
|
7111
7602
|
};
|
|
7112
7603
|
// ../llm/src/dream-classifier.ts
|
|
7113
|
-
import { Effect as
|
|
7604
|
+
import { Effect as Effect38 } from "effect";
|
|
7114
7605
|
import { z as z2 } from "zod";
|
|
7115
7606
|
var EDGE_KINDS = ["memory_supersedes", "memory_contradicts", "memory_supports"];
|
|
7116
7607
|
var EDGE_KIND_SET = new Set(EDGE_KINDS);
|
|
@@ -7157,7 +7648,7 @@ var buildPrompt = (pairs, maxDerived) => [
|
|
|
7157
7648
|
].join(`
|
|
7158
7649
|
`);
|
|
7159
7650
|
var makeDreamClassifier = (deps) => {
|
|
7160
|
-
const classify =
|
|
7651
|
+
const classify = Effect38.fn("DreamClassifier.classify")(function* (pairs, opts) {
|
|
7161
7652
|
const system = deps.modelId === undefined ? SYSTEM_PROMPT : `${SYSTEM_PROMPT}
|
|
7162
7653
|
Judging for model: ${deps.modelId}`;
|
|
7163
7654
|
const judged = yield* deps.llm.generateObject({
|
|
@@ -7187,7 +7678,7 @@ Judging for model: ${deps.modelId}`;
|
|
|
7187
7678
|
return { classify };
|
|
7188
7679
|
};
|
|
7189
7680
|
// ../llm/src/service.ts
|
|
7190
|
-
import { Config as Config6, Context as Context11, Effect as
|
|
7681
|
+
import { Config as Config6, Context as Context11, Effect as Effect39, Layer as Layer14 } from "effect";
|
|
7191
7682
|
class Service11 extends Context11.Service()("@dimple/LLM") {
|
|
7192
7683
|
}
|
|
7193
7684
|
// ../core/src/layer.ts
|
|
@@ -7197,7 +7688,7 @@ var DISABLED_LOGGING2 = {
|
|
|
7197
7688
|
format: "jsonl",
|
|
7198
7689
|
ringSize: 4096
|
|
7199
7690
|
};
|
|
7200
|
-
var embedderFromConfig = (model) => model.provider === "transformers" ?
|
|
7691
|
+
var embedderFromConfig = (model) => model.provider === "transformers" ? Effect40.succeed(makeTransformersModel({
|
|
7201
7692
|
modelId: model.model,
|
|
7202
7693
|
dimensions: model.dimensions,
|
|
7203
7694
|
...model.device !== undefined ? { device: model.device } : {},
|
|
@@ -7206,14 +7697,14 @@ var embedderFromConfig = (model) => model.provider === "transformers" ? Effect39
|
|
|
7206
7697
|
...model.normalize !== undefined ? { normalize: model.normalize } : {},
|
|
7207
7698
|
...model.cacheDir !== undefined ? { cacheDir: model.cacheDir } : {},
|
|
7208
7699
|
...model.autoInstall !== undefined ? { autoInstall: model.autoInstall } : {}
|
|
7209
|
-
})) : model.provider === "openai" ? model.apiKey === undefined ?
|
|
7700
|
+
})) : model.provider === "openai" ? model.apiKey === undefined ? Effect40.fail(new EmbeddingError({ message: `OpenAI model ${model.id} requires an apiKey` })) : Effect40.succeed(makeHostedEmbeddingModel({
|
|
7210
7701
|
modelId: model.id,
|
|
7211
7702
|
model: model.model,
|
|
7212
7703
|
dimensions: model.dimensions,
|
|
7213
7704
|
apiKey: model.apiKey,
|
|
7214
7705
|
...model.provider !== "openai" ? { provider: model.provider } : {},
|
|
7215
7706
|
...model.baseURL !== undefined ? { baseURL: model.baseURL } : {}
|
|
7216
|
-
})) :
|
|
7707
|
+
})) : Effect40.fail(new EmbeddingError({ message: `Unknown provider: ${model.provider}` }));
|
|
7217
7708
|
var layer13 = (options) => {
|
|
7218
7709
|
const topicConfig = Schema24.decodeUnknownSync(TopicConfig)(options.topics?.config ?? {});
|
|
7219
7710
|
const graphConfig = Schema24.decodeUnknownSync(exports_graph.GraphConfig)(options.graph ?? {});
|
|
@@ -7221,11 +7712,31 @@ var layer13 = (options) => {
|
|
|
7221
7712
|
const defaultModel = models2.get(options.defaultModelId);
|
|
7222
7713
|
const loggingConfig = options.logging ?? DISABLED_LOGGING2;
|
|
7223
7714
|
const getModelConfig = (key) => models2.get(key);
|
|
7224
|
-
const storeWithSeams = Layer15.unwrap(
|
|
7715
|
+
const storeWithSeams = Layer15.unwrap(Effect40.gen(function* () {
|
|
7225
7716
|
const rt = yield* Service7;
|
|
7226
|
-
const enqueueSplit = (topicKey, modelKey) => rt.enqueue(TopicSplit, { topicId: topicKey, modelKey }).pipe(
|
|
7227
|
-
const enqueueMerge = (topicKey, modelKey) => rt.enqueue(TopicMerge, { topicId: topicKey, modelKey }).pipe(
|
|
7228
|
-
const
|
|
7717
|
+
const enqueueSplit = (topicKey, modelKey) => rt.enqueue(TopicSplit, { topicId: topicKey, modelKey }).pipe(Effect40.asVoid);
|
|
7718
|
+
const enqueueMerge = (topicKey, modelKey) => rt.enqueue(TopicMerge, { topicId: topicKey, modelKey }).pipe(Effect40.asVoid);
|
|
7719
|
+
const auditBuffer = [];
|
|
7720
|
+
let auditTimer;
|
|
7721
|
+
const flushAudit = () => Effect40.gen(function* () {
|
|
7722
|
+
auditTimer = undefined;
|
|
7723
|
+
if (auditBuffer.length === 0)
|
|
7724
|
+
return;
|
|
7725
|
+
const rows = auditBuffer.splice(0, auditBuffer.length);
|
|
7726
|
+
yield* rt.enqueue(AuditWrite, { rows }).pipe(Effect40.asVoid);
|
|
7727
|
+
});
|
|
7728
|
+
const enqueueAudit = (row) => Effect40.gen(function* () {
|
|
7729
|
+
auditBuffer.push(row);
|
|
7730
|
+
if (auditTimer === undefined) {
|
|
7731
|
+
auditTimer = setTimeout(() => {
|
|
7732
|
+
Effect40.runPromise(flushAudit()).catch(() => {});
|
|
7733
|
+
}, 1000);
|
|
7734
|
+
auditTimer.unref?.();
|
|
7735
|
+
}
|
|
7736
|
+
if (auditBuffer.length >= 50) {
|
|
7737
|
+
yield* flushAudit();
|
|
7738
|
+
}
|
|
7739
|
+
});
|
|
7229
7740
|
return layer8(options.storeUrl, {
|
|
7230
7741
|
...options.defaultTtlSecs !== undefined ? { defaultTtlSecs: options.defaultTtlSecs } : {},
|
|
7231
7742
|
...options.migrationFolder !== undefined ? { migrationFolder: options.migrationFolder } : {},
|
|
@@ -7244,15 +7755,15 @@ var layer13 = (options) => {
|
|
|
7244
7755
|
...options.audit === false ? {} : { enqueueAudit }
|
|
7245
7756
|
});
|
|
7246
7757
|
}));
|
|
7247
|
-
const embedderRegistry = Layer15.effect(Service9,
|
|
7758
|
+
const embedderRegistry = Layer15.effect(Service9, Effect40.sync(() => Service9.of({
|
|
7248
7759
|
getModel: (id) => {
|
|
7249
7760
|
const model = models2.get(id);
|
|
7250
|
-
return model !== undefined ? options.embedderFor(model) :
|
|
7761
|
+
return model !== undefined ? options.embedderFor(model) : Effect40.fail(new EmbeddingError({ message: `Unknown model: ${id}` }));
|
|
7251
7762
|
},
|
|
7252
|
-
defaultModelId:
|
|
7253
|
-
registerModel: () =>
|
|
7763
|
+
defaultModelId: Effect40.succeed(options.defaultModelId),
|
|
7764
|
+
registerModel: () => Effect40.void
|
|
7254
7765
|
})));
|
|
7255
|
-
const coreService = Layer15.effect(Service,
|
|
7766
|
+
const coreService = Layer15.effect(Service, Effect40.gen(function* () {
|
|
7256
7767
|
if (defaultModel === undefined) {
|
|
7257
7768
|
return yield* new CoreConfigError({
|
|
7258
7769
|
message: `@dimple/core: unknown defaultModelId "${options.defaultModelId}"`
|
|
@@ -7265,20 +7776,20 @@ var layer13 = (options) => {
|
|
|
7265
7776
|
const hybrid = yield* Service10;
|
|
7266
7777
|
const logging = yield* Service3;
|
|
7267
7778
|
const extraByName = new Map((options.extraHandlers ?? []).map((h) => [h.name, h.handler]));
|
|
7268
|
-
const register = (name, handler) => extraByName.has(name) ?
|
|
7779
|
+
const register = (name, handler) => extraByName.has(name) ? Effect40.void : registry.register(name, handler);
|
|
7269
7780
|
yield* register("topic.split", exports_topics.topicSplitHandler({
|
|
7270
7781
|
getModelConfig,
|
|
7271
7782
|
config: topicConfig,
|
|
7272
7783
|
backend,
|
|
7273
|
-
onUnevenSplit: (childKey, modelKey) => rt.enqueue(TopicRebalance, { topicId: childKey, modelKey }).pipe(
|
|
7274
|
-
onChildOverflow: (childKey, modelKey) => rt.enqueue(TopicSplit, { topicId: childKey, modelKey }).pipe(
|
|
7784
|
+
onUnevenSplit: (childKey, modelKey) => rt.enqueue(TopicRebalance, { topicId: childKey, modelKey }).pipe(Effect40.asVoid),
|
|
7785
|
+
onChildOverflow: (childKey, modelKey) => rt.enqueue(TopicSplit, { topicId: childKey, modelKey }).pipe(Effect40.asVoid)
|
|
7275
7786
|
}));
|
|
7276
7787
|
yield* register("topic.merge", exports_topics.topicMergeHandler({ getModelConfig, config: topicConfig, backend }));
|
|
7277
7788
|
yield* register("topic.rebalance", exports_topics.topicRebalanceHandler({ getModelConfig, config: topicConfig, backend }));
|
|
7278
7789
|
yield* register("memory.embed", exports_topics.memoryEmbedHandler({
|
|
7279
7790
|
getModelConfig,
|
|
7280
|
-
embedOne: (text4, model) => options.embedderFor(model).pipe(
|
|
7281
|
-
getMemoryContent: (memoryId) => store.get(memoryId).pipe(
|
|
7791
|
+
embedOne: (text4, model) => options.embedderFor(model).pipe(Effect40.flatMap((m) => m.embedSingle(text4))),
|
|
7792
|
+
getMemoryContent: (memoryId) => store.get(memoryId).pipe(Effect40.map((m) => m.content)),
|
|
7282
7793
|
config: topicConfig,
|
|
7283
7794
|
backend
|
|
7284
7795
|
}));
|
|
@@ -7293,12 +7804,12 @@ var layer13 = (options) => {
|
|
|
7293
7804
|
yield* register("memory.dream", (payload, ctx) => {
|
|
7294
7805
|
const envelope = payload;
|
|
7295
7806
|
if (getModelConfig(envelope.modelKey) === undefined) {
|
|
7296
|
-
return
|
|
7807
|
+
return Effect40.fail(new JobFailure({
|
|
7297
7808
|
jobId: ctx.jobId,
|
|
7298
7809
|
message: `memory.dream: unknown model "${envelope.modelKey}"`
|
|
7299
7810
|
}));
|
|
7300
7811
|
}
|
|
7301
|
-
return
|
|
7812
|
+
return Effect40.fail(new JobFailure({
|
|
7302
7813
|
jobId: ctx.jobId,
|
|
7303
7814
|
message: "memory.dream: LLM not configured — provide `llm` to @dimple/core"
|
|
7304
7815
|
}));
|
|
@@ -7333,7 +7844,7 @@ var layer13 = (options) => {
|
|
|
7333
7844
|
...options.defaultLimit !== undefined ? { defaultLimit: options.defaultLimit } : {}
|
|
7334
7845
|
})), Layer15.provideMerge(embedderRegistry), Layer15.provideMerge(storeWithSeams), Layer15.provideMerge(Layer15.mergeAll(jobStack, layer7, layer(loggingConfig))));
|
|
7335
7846
|
};
|
|
7336
|
-
var layerConfig7 = (options) => Layer15.unwrap(
|
|
7847
|
+
var layerConfig7 = (options) => Layer15.unwrap(Effect40.gen(function* () {
|
|
7337
7848
|
const cfg = yield* Service4;
|
|
7338
7849
|
const embedding = cfg.config.embedding;
|
|
7339
7850
|
if (embedding === undefined || embedding.models.length === 0) {
|
|
@@ -7367,7 +7878,7 @@ var layerConfig7 = (options) => Layer15.unwrap(Effect39.gen(function* () {
|
|
|
7367
7878
|
});
|
|
7368
7879
|
}));
|
|
7369
7880
|
// ../extractor/src/code-extractor.ts
|
|
7370
|
-
import { Context as Context12, Effect as
|
|
7881
|
+
import { Context as Context12, Effect as Effect41, Layer as Layer16 } from "effect";
|
|
7371
7882
|
|
|
7372
7883
|
// ../extractor/src/models/extraction.ts
|
|
7373
7884
|
import { Schema as Schema25 } from "effect";
|
|
@@ -7813,9 +8324,9 @@ function extract3(filePath, tree2) {
|
|
|
7813
8324
|
// ../extractor/src/code-extractor.ts
|
|
7814
8325
|
class Service12 extends Context12.Service()("@dimple/extractor/CodeExtractor") {
|
|
7815
8326
|
}
|
|
7816
|
-
var layer14 = Layer16.effect(Service12,
|
|
7817
|
-
extract:
|
|
7818
|
-
const result = yield*
|
|
8327
|
+
var layer14 = Layer16.effect(Service12, Effect41.succeed(Service12.of({
|
|
8328
|
+
extract: Effect41.fn("CodeExtractor.extract")(function* (request) {
|
|
8329
|
+
const result = yield* Effect41.try({
|
|
7819
8330
|
try: () => extract3(request.filePath, request.tree),
|
|
7820
8331
|
catch: (cause) => new ExtractionError({ message: `Extraction failed for ${request.filePath}`, cause })
|
|
7821
8332
|
});
|
|
@@ -7848,14 +8359,14 @@ var layer15 = Layer17.succeed(Service13, Service13.of({
|
|
|
7848
8359
|
extractText: (content) => content
|
|
7849
8360
|
}));
|
|
7850
8361
|
// ../parser/src/code-parser.ts
|
|
7851
|
-
import { Context as Context19, Effect as
|
|
8362
|
+
import { Context as Context19, Effect as Effect48, Layer as Layer24 } from "effect";
|
|
7852
8363
|
import { Parser as Parser2 } from "web-tree-sitter";
|
|
7853
8364
|
|
|
7854
8365
|
// ../parser/src/language-store.ts
|
|
7855
|
-
import { Cache, Context as Context18, Effect as
|
|
8366
|
+
import { Cache, Context as Context18, Effect as Effect47, Layer as Layer23 } from "effect";
|
|
7856
8367
|
|
|
7857
8368
|
// ../wasm/src/wasm-registry.ts
|
|
7858
|
-
import { Context as Context14, Effect as
|
|
8369
|
+
import { Context as Context14, Effect as Effect42, Layer as Layer18, Schema as Schema30 } from "effect";
|
|
7859
8370
|
|
|
7860
8371
|
// ../shared/src/errors/wasm.ts
|
|
7861
8372
|
import { Schema as Schema27 } from "effect";
|
|
@@ -7957,7 +8468,7 @@ for (const grammar of grammars.grammars) {
|
|
|
7957
8468
|
|
|
7958
8469
|
class Service14 extends Context14.Service()("@dimple/wasm/TreeSitterRegistry") {
|
|
7959
8470
|
static layer = Layer18.succeed(Service14, Service14.of({
|
|
7960
|
-
resolve:
|
|
8471
|
+
resolve: Effect42.fn("TreeSitterRegistry.resolve")(function* (lang) {
|
|
7961
8472
|
const found = registryMap.get(lang);
|
|
7962
8473
|
if (found === undefined) {
|
|
7963
8474
|
return yield* new RegistryError2({ message: `Language not found in registry: ${lang}` });
|
|
@@ -7967,11 +8478,11 @@ class Service14 extends Context14.Service()("@dimple/wasm/TreeSitterRegistry") {
|
|
|
7967
8478
|
}));
|
|
7968
8479
|
}
|
|
7969
8480
|
// ../wasm/src/wasm-downloader.ts
|
|
7970
|
-
import { Context as Context15, Effect as
|
|
8481
|
+
import { Context as Context15, Effect as Effect43, Layer as Layer19 } from "effect";
|
|
7971
8482
|
class Service15 extends Context15.Service()("@dimple/wasm/WasmDownloader") {
|
|
7972
|
-
static layer = Layer19.effect(Service15,
|
|
7973
|
-
download:
|
|
7974
|
-
const response = yield*
|
|
8483
|
+
static layer = Layer19.effect(Service15, Effect43.succeed(Service15.of({
|
|
8484
|
+
download: Effect43.fn("WasmDownloader.download")(function* (url) {
|
|
8485
|
+
const response = yield* Effect43.tryPromise({
|
|
7975
8486
|
try: () => fetch(url),
|
|
7976
8487
|
catch: (cause) => new WasmDownloadError({
|
|
7977
8488
|
message: `Failed to fetch from ${url}`,
|
|
@@ -7985,7 +8496,7 @@ class Service15 extends Context15.Service()("@dimple/wasm/WasmDownloader") {
|
|
|
7985
8496
|
url
|
|
7986
8497
|
});
|
|
7987
8498
|
}
|
|
7988
|
-
const arrayBuffer = yield*
|
|
8499
|
+
const arrayBuffer = yield* Effect43.tryPromise({
|
|
7989
8500
|
try: () => response.arrayBuffer(),
|
|
7990
8501
|
catch: (cause) => new WasmDownloadError({
|
|
7991
8502
|
message: `Failed to read response from ${url}`,
|
|
@@ -7998,7 +8509,7 @@ class Service15 extends Context15.Service()("@dimple/wasm/WasmDownloader") {
|
|
|
7998
8509
|
})));
|
|
7999
8510
|
}
|
|
8000
8511
|
// ../wasm/src/wasm-cache.ts
|
|
8001
|
-
import { Context as Context16, Effect as
|
|
8512
|
+
import { Context as Context16, Effect as Effect44, Layer as Layer20 } from "effect";
|
|
8002
8513
|
import { existsSync as existsSync3, mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
8003
8514
|
import { join as join3 } from "node:path";
|
|
8004
8515
|
|
|
@@ -8095,35 +8606,35 @@ var paths = envPaths("dimple");
|
|
|
8095
8606
|
|
|
8096
8607
|
class Service16 extends Context16.Service()("@dimple/wasm/WasmCache") {
|
|
8097
8608
|
}
|
|
8098
|
-
var layer16 = Layer20.effect(Service16,
|
|
8099
|
-
ensure:
|
|
8609
|
+
var layer16 = Layer20.effect(Service16, Effect44.succeed(Service16.of({
|
|
8610
|
+
ensure: Effect44.fn("WasmCache.ensure")(function* (lang, version, download) {
|
|
8100
8611
|
const versionDir = join3(paths.cache, "tree-sitter", lang, version);
|
|
8101
8612
|
const finalPath = join3(versionDir, "parser.wasm");
|
|
8102
|
-
const exists = yield*
|
|
8613
|
+
const exists = yield* Effect44.try({
|
|
8103
8614
|
try: () => existsSync3(finalPath),
|
|
8104
8615
|
catch: (cause) => new WasmCacheError({ message: `Failed to stat ${finalPath}`, cause })
|
|
8105
8616
|
});
|
|
8106
8617
|
if (exists)
|
|
8107
8618
|
return finalPath;
|
|
8108
|
-
yield*
|
|
8619
|
+
yield* Effect44.try({
|
|
8109
8620
|
try: () => mkdirSync(versionDir, { recursive: true }),
|
|
8110
8621
|
catch: (cause) => new WasmCacheError({ message: `Failed to create ${versionDir}`, cause })
|
|
8111
8622
|
});
|
|
8112
8623
|
const tempPath = join3(versionDir, `.tmp-${process.pid}`);
|
|
8113
8624
|
const wasm = yield* download;
|
|
8114
|
-
yield*
|
|
8625
|
+
yield* Effect44.try({
|
|
8115
8626
|
try: () => writeFileSync(tempPath, wasm),
|
|
8116
8627
|
catch: (cause) => new WasmCacheError({ message: `Failed to write ${tempPath}`, cause })
|
|
8117
8628
|
});
|
|
8118
|
-
const renamed = yield*
|
|
8629
|
+
const renamed = yield* Effect44.try({
|
|
8119
8630
|
try: () => {
|
|
8120
8631
|
renameSync(tempPath, finalPath);
|
|
8121
8632
|
return true;
|
|
8122
8633
|
},
|
|
8123
8634
|
catch: (cause) => new WasmCacheError({ message: `Failed to rename ${tempPath}`, cause })
|
|
8124
|
-
}).pipe(
|
|
8635
|
+
}).pipe(Effect44.catchCause(() => Effect44.succeed(false)));
|
|
8125
8636
|
if (!renamed) {
|
|
8126
|
-
const existsAfter = yield*
|
|
8637
|
+
const existsAfter = yield* Effect44.try({
|
|
8127
8638
|
try: () => existsSync3(finalPath),
|
|
8128
8639
|
catch: (cause) => new WasmCacheError({ message: `Failed to stat ${finalPath}`, cause })
|
|
8129
8640
|
});
|
|
@@ -8137,25 +8648,25 @@ var layer16 = Layer20.effect(Service16, Effect43.succeed(Service16.of({
|
|
|
8137
8648
|
})
|
|
8138
8649
|
})));
|
|
8139
8650
|
// ../wasm/src/grammar-store.ts
|
|
8140
|
-
import { Context as Context17, Effect as
|
|
8651
|
+
import { Context as Context17, Effect as Effect45, Layer as Layer21 } from "effect";
|
|
8141
8652
|
class Service17 extends Context17.Service()("@dimple/wasm/GrammarStore") {
|
|
8142
8653
|
}
|
|
8143
|
-
var layer17 = Layer21.effect(Service17,
|
|
8654
|
+
var layer17 = Layer21.effect(Service17, Effect45.gen(function* () {
|
|
8144
8655
|
const registry = yield* Service14;
|
|
8145
8656
|
const downloader = yield* Service15;
|
|
8146
8657
|
const cache = yield* Service16;
|
|
8147
|
-
const ensure =
|
|
8148
|
-
const metadata = yield* registry.resolve(lang).pipe(
|
|
8658
|
+
const ensure = Effect45.fn("GrammarStore.ensure")(function* (lang) {
|
|
8659
|
+
const metadata = yield* registry.resolve(lang).pipe(Effect45.mapError((cause) => new GrammarProvisionError({
|
|
8149
8660
|
language: lang,
|
|
8150
8661
|
message: `Failed to resolve grammar metadata for: ${lang}`,
|
|
8151
8662
|
cause
|
|
8152
8663
|
})));
|
|
8153
|
-
const wasmBytes = yield* downloader.download(metadata.url).pipe(
|
|
8664
|
+
const wasmBytes = yield* downloader.download(metadata.url).pipe(Effect45.mapError((cause) => new GrammarProvisionError({
|
|
8154
8665
|
language: lang,
|
|
8155
8666
|
message: `Failed to download grammar for: ${lang}`,
|
|
8156
8667
|
cause
|
|
8157
8668
|
})));
|
|
8158
|
-
const path2 = yield* cache.ensure(lang, metadata.version,
|
|
8669
|
+
const path2 = yield* cache.ensure(lang, metadata.version, Effect45.succeed(wasmBytes)).pipe(Effect45.mapError((cause) => new GrammarProvisionError({
|
|
8159
8670
|
language: lang,
|
|
8160
8671
|
message: `Failed to provision grammar for: ${lang}`,
|
|
8161
8672
|
cause
|
|
@@ -8169,9 +8680,9 @@ var allLive = layer17.pipe(Layer21.provideMerge(Layer21.mergeAll(Service14.layer
|
|
|
8169
8680
|
import { Language } from "web-tree-sitter";
|
|
8170
8681
|
|
|
8171
8682
|
// ../parser/src/tree-sitter-engine.ts
|
|
8172
|
-
import { Effect as
|
|
8683
|
+
import { Effect as Effect46, Layer as Layer22 } from "effect";
|
|
8173
8684
|
import { Parser } from "web-tree-sitter";
|
|
8174
|
-
var layer18 = Layer22.effectDiscard(
|
|
8685
|
+
var layer18 = Layer22.effectDiscard(Effect46.tryPromise({
|
|
8175
8686
|
try: () => Parser.init(),
|
|
8176
8687
|
catch: (cause) => new ParserInitError({ message: "Failed to initialize tree sitter", cause })
|
|
8177
8688
|
}));
|
|
@@ -8179,20 +8690,20 @@ var layer18 = Layer22.effectDiscard(Effect45.tryPromise({
|
|
|
8179
8690
|
// ../parser/src/language-store.ts
|
|
8180
8691
|
class Service18 extends Context18.Service()("@dimple/parser/LanguageStore") {
|
|
8181
8692
|
}
|
|
8182
|
-
var layer19 = Layer23.effect(Service18,
|
|
8693
|
+
var layer19 = Layer23.effect(Service18, Effect47.gen(function* () {
|
|
8183
8694
|
const grammarStore = yield* Service17;
|
|
8184
8695
|
const resolveLang = (lang) => lang === "jsx" ? "javascript" : lang;
|
|
8185
8696
|
const cache = yield* Cache.make({
|
|
8186
8697
|
capacity: 100,
|
|
8187
8698
|
timeToLive: Infinity,
|
|
8188
|
-
lookup: (lang) =>
|
|
8699
|
+
lookup: (lang) => Effect47.gen(function* () {
|
|
8189
8700
|
const grammarLang = resolveLang(lang);
|
|
8190
|
-
const wasmPath = yield* grammarStore.ensure(grammarLang).pipe(
|
|
8701
|
+
const wasmPath = yield* grammarStore.ensure(grammarLang).pipe(Effect47.mapError((e) => new LanguageLoadError({
|
|
8191
8702
|
lang,
|
|
8192
8703
|
message: `Failed to provision grammar for ${lang}`,
|
|
8193
8704
|
cause: e
|
|
8194
8705
|
})));
|
|
8195
|
-
return yield*
|
|
8706
|
+
return yield* Effect47.tryPromise({
|
|
8196
8707
|
try: () => Language.load(wasmPath),
|
|
8197
8708
|
catch: (cause) => new LanguageLoadError({ lang, message: `Failed to load language: ${lang}`, cause })
|
|
8198
8709
|
});
|
|
@@ -8215,15 +8726,20 @@ var TreeHandle = Schema31.Struct({
|
|
|
8215
8726
|
// ../parser/src/code-parser.ts
|
|
8216
8727
|
class Service19 extends Context19.Service()("@dimple/parser/CodeParser") {
|
|
8217
8728
|
}
|
|
8218
|
-
var layer20 = Layer24.effect(Service19,
|
|
8729
|
+
var layer20 = Layer24.effect(Service19, Effect48.gen(function* () {
|
|
8219
8730
|
const languageStore = yield* Service18;
|
|
8220
|
-
const
|
|
8221
|
-
|
|
8731
|
+
const parserByLanguage = new Map;
|
|
8732
|
+
const parse2 = Effect48.fn("CodeParser.parse")(function* (request) {
|
|
8733
|
+
const language = yield* languageStore.get(request.lang).pipe(Effect48.mapError((cause) => new ParseError({
|
|
8222
8734
|
message: `Failed to load language '${request.lang}' for parsing`,
|
|
8223
8735
|
cause
|
|
8224
8736
|
})));
|
|
8225
|
-
|
|
8226
|
-
parser
|
|
8737
|
+
let parser = parserByLanguage.get(request.lang);
|
|
8738
|
+
if (parser === undefined) {
|
|
8739
|
+
parser = new Parser2;
|
|
8740
|
+
parser.setLanguage(language);
|
|
8741
|
+
parserByLanguage.set(request.lang, parser);
|
|
8742
|
+
}
|
|
8227
8743
|
const tree2 = parser.parse(request.source);
|
|
8228
8744
|
if (!tree2) {
|
|
8229
8745
|
return yield* new ParseError({ message: "Failed to parse source" });
|
|
@@ -8239,7 +8755,7 @@ var ParseRequest = Schema32.Struct({
|
|
|
8239
8755
|
source: Schema32.String
|
|
8240
8756
|
});
|
|
8241
8757
|
// src/config.ts
|
|
8242
|
-
import { Effect as
|
|
8758
|
+
import { Effect as Effect49, Layer as Layer25 } from "effect";
|
|
8243
8759
|
|
|
8244
8760
|
// src/errors.ts
|
|
8245
8761
|
import { Schema as Schema33 } from "effect";
|
|
@@ -8363,13 +8879,13 @@ var remapError = (error) => {
|
|
|
8363
8879
|
};
|
|
8364
8880
|
|
|
8365
8881
|
// src/config.ts
|
|
8366
|
-
var resolveConfigInput =
|
|
8367
|
-
return yield* (typeof input === "string" ? loadConfigFromFile(input) : loadConfig(input)).pipe(
|
|
8882
|
+
var resolveConfigInput = Effect49.fn("Sdk.resolveConfigInput")(function* (input) {
|
|
8883
|
+
return yield* (typeof input === "string" ? loadConfigFromFile(input) : loadConfig(input)).pipe(Effect49.mapError((error) => new ConfigError({ message: error.message })));
|
|
8368
8884
|
});
|
|
8369
|
-
var configLayerFromInput = (input) => Layer25.effect(Service4, resolveConfigInput(input).pipe(
|
|
8885
|
+
var configLayerFromInput = (input) => Layer25.effect(Service4, resolveConfigInput(input).pipe(Effect49.map((config) => Service4.of({ config }))));
|
|
8370
8886
|
|
|
8371
8887
|
// src/dimple.ts
|
|
8372
|
-
import { Cause as Cause5, Effect as
|
|
8888
|
+
import { Cause as Cause5, Effect as Effect50, Exit as Exit7 } from "effect";
|
|
8373
8889
|
|
|
8374
8890
|
// src/indexer.ts
|
|
8375
8891
|
import { execFileSync } from "node:child_process";
|
|
@@ -8417,8 +8933,8 @@ var walkFiles = (paths2, extensions) => {
|
|
|
8417
8933
|
const files = [];
|
|
8418
8934
|
const errors3 = [];
|
|
8419
8935
|
let unsupported = 0;
|
|
8420
|
-
const resolved = paths2.map((p) => resolve(p));
|
|
8421
|
-
const root = commonRoot([...resolved, process.cwd()]);
|
|
8936
|
+
const resolved = paths2.map((p) => resolve(process.env["DIMPLE_CWD"] ?? process.cwd(), p));
|
|
8937
|
+
const root = commonRoot([...resolved, process.env["DIMPLE_CWD"] ?? process.cwd()]);
|
|
8422
8938
|
const visit = (path2) => {
|
|
8423
8939
|
let stat;
|
|
8424
8940
|
try {
|
|
@@ -8609,7 +9125,7 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8609
9125
|
}
|
|
8610
9126
|
return;
|
|
8611
9127
|
};
|
|
8612
|
-
const runQuery = (text4, options) => run(
|
|
9128
|
+
const runQuery = (text4, options) => run(Effect50.gen(function* () {
|
|
8613
9129
|
if (typeof text4 !== "string") {
|
|
8614
9130
|
return yield* new InputError({ message: "query: text must be a string" });
|
|
8615
9131
|
}
|
|
@@ -8622,7 +9138,7 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8622
9138
|
let rows = yield* core().hybrid.hybrid(text4, {
|
|
8623
9139
|
...rest,
|
|
8624
9140
|
...capLimit !== undefined ? { limit: capLimit } : {}
|
|
8625
|
-
}).pipe(
|
|
9141
|
+
}).pipe(Effect50.map((r) => [...r]));
|
|
8626
9142
|
let truncated = false;
|
|
8627
9143
|
if (budget?.maxChars !== undefined && budget.maxChars > 0) {
|
|
8628
9144
|
let used = 0;
|
|
@@ -8712,7 +9228,7 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8712
9228
|
}
|
|
8713
9229
|
return;
|
|
8714
9230
|
};
|
|
8715
|
-
const writeUnit = (input, embed) =>
|
|
9231
|
+
const writeUnit = (input, embed) => Effect50.gen(function* () {
|
|
8716
9232
|
const mem = yield* core().store.write(input);
|
|
8717
9233
|
if (embed) {
|
|
8718
9234
|
yield* core().store.ensureTopicTree(core().defaultModel.id);
|
|
@@ -8722,8 +9238,8 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8722
9238
|
}
|
|
8723
9239
|
return mem;
|
|
8724
9240
|
});
|
|
8725
|
-
const upsertUnit = (input, embed) =>
|
|
8726
|
-
const existing = yield* core().store.getByKey(input.logicalKey, input.namespace ?? "default").pipe(
|
|
9241
|
+
const upsertUnit = (input, embed) => Effect50.gen(function* () {
|
|
9242
|
+
const existing = yield* core().store.getByKey(input.logicalKey, input.namespace ?? "default").pipe(Effect50.catchTag("Store.NotFound", () => Effect50.succeed(undefined)));
|
|
8727
9243
|
if (existing !== undefined && existing.content === input.content) {
|
|
8728
9244
|
const stamp = codeVersionOf(input.metadata);
|
|
8729
9245
|
if (stamp !== undefined && codeVersionOf(existing.metadata) === undefined) {
|
|
@@ -8788,7 +9304,7 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8788
9304
|
return;
|
|
8789
9305
|
};
|
|
8790
9306
|
const messageOf3 = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
8791
|
-
const resolveMemory = (idOrKey) => core().store.get(idOrKey).pipe(
|
|
9307
|
+
const resolveMemory = (idOrKey) => core().store.get(idOrKey).pipe(Effect50.catchTag("Store.NotFound", () => core().store.getByKey(idOrKey, "default").pipe(Effect50.catchTag("Store.NotFound", () => Effect50.fail(new NotFoundError({ id: idOrKey, message: `Memory not found: ${idOrKey}` }))))));
|
|
8792
9308
|
const codeVersionOf = (blob) => {
|
|
8793
9309
|
if (blob === undefined || blob === null)
|
|
8794
9310
|
return;
|
|
@@ -8805,16 +9321,42 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8805
9321
|
get defaultModelId() {
|
|
8806
9322
|
return core().defaultModel.id;
|
|
8807
9323
|
},
|
|
8808
|
-
write: (input, options) => run(
|
|
9324
|
+
write: (input, options) => run(Effect50.gen(function* () {
|
|
8809
9325
|
const invalid = validateWriteInput(input);
|
|
8810
9326
|
if (invalid !== undefined)
|
|
8811
9327
|
return yield* invalid;
|
|
8812
9328
|
return yield* writeUnit(input, options?.embed !== false);
|
|
8813
9329
|
})),
|
|
9330
|
+
writeMany: (units, options) => run(Effect50.gen(function* () {
|
|
9331
|
+
if (!Array.isArray(units)) {
|
|
9332
|
+
return yield* new InputError({ message: "writeMany: units must be an array" });
|
|
9333
|
+
}
|
|
9334
|
+
for (const input of units) {
|
|
9335
|
+
const invalid = validateWriteInput(input);
|
|
9336
|
+
if (invalid !== undefined)
|
|
9337
|
+
return yield* invalid;
|
|
9338
|
+
}
|
|
9339
|
+
const mems = yield* core().store.writeMany(units);
|
|
9340
|
+
if (options?.embed !== false) {
|
|
9341
|
+
yield* core().store.ensureTopicTree(core().defaultModel.id);
|
|
9342
|
+
const EMBED_CHUNK = 64;
|
|
9343
|
+
const vectors = [];
|
|
9344
|
+
for (let i = 0;i < mems.length; i += EMBED_CHUNK) {
|
|
9345
|
+
const chunk = mems.slice(i, i + EMBED_CHUNK).map((m) => m.content);
|
|
9346
|
+
const vs = yield* core().defaultEmbedder.embed(chunk);
|
|
9347
|
+
vectors.push(...vs);
|
|
9348
|
+
}
|
|
9349
|
+
yield* core().store.updateEmbeddingMany(mems.map((mem, i) => ({ id: mem.id, embedding: [...vectors[i]] })), core().defaultModel.id);
|
|
9350
|
+
return yield* Effect50.forEach(mems, (mem) => core().store.get(mem.id), {
|
|
9351
|
+
discard: false
|
|
9352
|
+
});
|
|
9353
|
+
}
|
|
9354
|
+
return mems;
|
|
9355
|
+
})),
|
|
8814
9356
|
get: (id) => run(resolveMemory(id)),
|
|
8815
9357
|
query: runQuery,
|
|
8816
|
-
forget: (id) => run(resolveMemory(id).pipe(
|
|
8817
|
-
index: (options) => run(
|
|
9358
|
+
forget: (id) => run(resolveMemory(id).pipe(Effect50.flatMap((memory) => core().store.forget(memory.id)))),
|
|
9359
|
+
index: (options) => run(Effect50.gen(function* () {
|
|
8818
9360
|
const invalid = validateIndexOptions(options);
|
|
8819
9361
|
if (invalid !== undefined)
|
|
8820
9362
|
return yield* invalid;
|
|
@@ -8824,7 +9366,7 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8824
9366
|
const maxFileBytes = options.maxFileBytes ?? 64 * 1024;
|
|
8825
9367
|
const maxChunkBytes = options.maxChunkBytes ?? 8 * 1024;
|
|
8826
9368
|
const extensions = [...options.extensions ?? INDEXABLE_EXTENSIONS];
|
|
8827
|
-
const walk = yield*
|
|
9369
|
+
const walk = yield* Effect50.try({
|
|
8828
9370
|
try: () => walkFiles([...options.paths], extensions),
|
|
8829
9371
|
catch: (cause) => new InputError({
|
|
8830
9372
|
message: `index: failed to walk paths: ${messageOf3(cause)}`
|
|
@@ -8854,8 +9396,8 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8854
9396
|
if (language === undefined)
|
|
8855
9397
|
continue;
|
|
8856
9398
|
const chunkKeyOf = (chunkId) => `${keyPrefix}${relative}#${stableChunkId(chunkId)}`;
|
|
8857
|
-
const exit = yield*
|
|
8858
|
-
const source = yield*
|
|
9399
|
+
const exit = yield* Effect50.exit(Effect50.gen(function* () {
|
|
9400
|
+
const source = yield* Effect50.try({
|
|
8859
9401
|
try: () => readCapped(filePath, maxFileBytes),
|
|
8860
9402
|
catch: (cause) => new InputError({ message: `read failed: ${messageOf3(cause)}` })
|
|
8861
9403
|
});
|
|
@@ -8937,13 +9479,14 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8937
9479
|
}
|
|
8938
9480
|
}
|
|
8939
9481
|
}
|
|
8940
|
-
|
|
9482
|
+
const importTargets = resolveImports(filePath, (extracted.imports ?? []).map((imp) => imp.source), extensions);
|
|
9483
|
+
for (const target of importTargets) {
|
|
8941
9484
|
pendingEdges.push({
|
|
8942
9485
|
from: `${keyPrefix}${keyForPath(walk.root, target)}`,
|
|
8943
9486
|
to: fileKey
|
|
8944
9487
|
});
|
|
8945
9488
|
}
|
|
8946
|
-
const importRels =
|
|
9489
|
+
const importRels = importTargets.map((target) => keyForPath(walk.root, target));
|
|
8947
9490
|
for (const chunk of extracted.chunks) {
|
|
8948
9491
|
const callerKey = chunkKeyOf(chunk.id);
|
|
8949
9492
|
if (!unitIds.has(callerKey))
|
|
@@ -8961,7 +9504,7 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8961
9504
|
}
|
|
8962
9505
|
return { units, upd, dups };
|
|
8963
9506
|
}));
|
|
8964
|
-
if (
|
|
9507
|
+
if (Exit7.isFailure(exit)) {
|
|
8965
9508
|
failed.push({ filePath, message: Cause5.pretty(exit.cause) });
|
|
8966
9509
|
} else {
|
|
8967
9510
|
indexed += exit.value.units;
|
|
@@ -8975,14 +9518,14 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8975
9518
|
const resolveKey = (key) => {
|
|
8976
9519
|
const fromMap = unitIds.get(key);
|
|
8977
9520
|
if (fromMap !== undefined)
|
|
8978
|
-
return
|
|
8979
|
-
return core().store.getByKey(key, namespace ?? "default").pipe(
|
|
9521
|
+
return Effect50.succeed(fromMap);
|
|
9522
|
+
return core().store.getByKey(key, namespace ?? "default").pipe(Effect50.map((m) => m.id), Effect50.catchTag("Store.NotFound", () => Effect50.succeed(undefined)));
|
|
8980
9523
|
};
|
|
8981
|
-
const edgeEffect = (edge) =>
|
|
8982
|
-
const [from, to] = yield*
|
|
9524
|
+
const edgeEffect = (edge) => Effect50.gen(function* () {
|
|
9525
|
+
const [from, to] = yield* Effect50.all([resolveKey(edge.from), resolveKey(edge.to)]);
|
|
8983
9526
|
if (from === undefined || to === undefined || from === to)
|
|
8984
9527
|
return;
|
|
8985
|
-
yield*
|
|
9528
|
+
yield* Effect50.exit(core().store.addEdge({
|
|
8986
9529
|
fromMemoryId: from,
|
|
8987
9530
|
toMemoryId: to,
|
|
8988
9531
|
edgeKind: edge.edgeKind,
|
|
@@ -8992,10 +9535,10 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
8992
9535
|
}));
|
|
8993
9536
|
});
|
|
8994
9537
|
for (const edge of pendingEdges) {
|
|
8995
|
-
yield*
|
|
9538
|
+
yield* Effect50.exit(edgeEffect({ ...edge, edgeKind: "memory_supports" }));
|
|
8996
9539
|
}
|
|
8997
9540
|
for (const edge of pendingCallEdges) {
|
|
8998
|
-
yield*
|
|
9541
|
+
yield* Effect50.exit(edgeEffect({ ...edge, edgeKind: "code_calls" }));
|
|
8999
9542
|
}
|
|
9000
9543
|
return {
|
|
9001
9544
|
files: walk.files.length,
|
|
@@ -9008,7 +9551,7 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
9008
9551
|
failed
|
|
9009
9552
|
};
|
|
9010
9553
|
})),
|
|
9011
|
-
updateEmbedding: (id, embedding, modelKey) => run(
|
|
9554
|
+
updateEmbedding: (id, embedding, modelKey) => run(Effect50.gen(function* () {
|
|
9012
9555
|
if (!Array.isArray(embedding) || embedding.length === 0 || embedding.some((v) => typeof v !== "number" || !Number.isFinite(v))) {
|
|
9013
9556
|
return yield* new InputError({
|
|
9014
9557
|
message: "updateEmbedding: embedding must be a non-empty array of finite numbers"
|
|
@@ -9019,10 +9562,10 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
9019
9562
|
yield* core().store.ensureTopicTree(key);
|
|
9020
9563
|
yield* core().store.updateEmbedding(memory.id, [...embedding], key);
|
|
9021
9564
|
})),
|
|
9022
|
-
embed: (text4) => run(core().defaultEmbedder.embedSingle(text4).pipe(
|
|
9023
|
-
dream: (modelKey) => run(core().runtime.enqueue(MemoryDream, { modelKey, runId: crypto.randomUUID() }).pipe(
|
|
9565
|
+
embed: (text4) => run(core().defaultEmbedder.embedSingle(text4).pipe(Effect50.map((vector) => [...vector]))),
|
|
9566
|
+
dream: (modelKey) => run(core().runtime.enqueue(MemoryDream, { modelKey, runId: crypto.randomUUID() }).pipe(Effect50.flatMap((jobId) => core().runtime.wait(jobId)), Effect50.asVoid)),
|
|
9024
9567
|
dbSchema: () => run(core().store.listSchema()),
|
|
9025
|
-
repair: (modelKey) => run(core().runtime.enqueue(GraphRepair, { modelKey, runId: crypto.randomUUID() }).pipe(
|
|
9568
|
+
repair: (modelKey) => run(core().runtime.enqueue(GraphRepair, { modelKey, runId: crypto.randomUUID() }).pipe(Effect50.flatMap((jobId) => core().runtime.wait(jobId)), Effect50.asVoid)),
|
|
9026
9569
|
explain: (input, options) => run(core().store.explain(input, {
|
|
9027
9570
|
...options?.edgeKinds !== undefined ? { edgeKinds: options.edgeKinds } : {},
|
|
9028
9571
|
...options?.maxDepth !== undefined ? { maxDepth: options.maxDepth } : {},
|
|
@@ -9032,7 +9575,7 @@ var makeFacade = (state, reload, dispose) => {
|
|
|
9032
9575
|
})),
|
|
9033
9576
|
health: (modelKey) => run(core().store.topicHealth(modelKey)),
|
|
9034
9577
|
graph: {
|
|
9035
|
-
addEdge: (input) => run(
|
|
9578
|
+
addEdge: (input) => run(Effect50.gen(function* () {
|
|
9036
9579
|
const invalid = validateAddEdgeInput(input);
|
|
9037
9580
|
if (invalid !== undefined)
|
|
9038
9581
|
return yield* invalid;
|
|
@@ -9074,24 +9617,24 @@ var diffConfig = (oldC, newC) => {
|
|
|
9074
9617
|
};
|
|
9075
9618
|
var RELOAD_DRAIN_MS = 30000;
|
|
9076
9619
|
var bootStack = async (options) => {
|
|
9077
|
-
const scope = await
|
|
9620
|
+
const scope = await Effect51.runPromise(Scope5.make());
|
|
9078
9621
|
let runtime;
|
|
9079
9622
|
try {
|
|
9080
9623
|
const layer21 = ("core" in options ? layer13(options.core) : layerConfig7(options.migrationFolder !== undefined ? { migrationFolder: options.migrationFolder } : {}).pipe(Layer26.provide(configLayerFromInput(options.config)))).pipe(Layer26.provide(Layer26.succeed(Scope5.Scope, scope)));
|
|
9081
9624
|
const appLayer = Layer26.mergeAll(layer21, layer20, layer14);
|
|
9082
9625
|
const rt = ManagedRuntime.make(appLayer);
|
|
9083
9626
|
runtime = rt;
|
|
9084
|
-
const [core, parser, extractor] = await rt.runPromise(
|
|
9627
|
+
const [core, parser, extractor] = await rt.runPromise(Effect51.all([Service, Service19, Service12]));
|
|
9085
9628
|
return {
|
|
9086
9629
|
runPromise: (effect) => rt.runPromise(effect),
|
|
9087
9630
|
disposeEffect: rt.disposeEffect,
|
|
9088
9631
|
core,
|
|
9089
9632
|
parser,
|
|
9090
9633
|
extractor,
|
|
9091
|
-
dispose: () =>
|
|
9634
|
+
dispose: () => Effect51.runPromise(Scope5.close(scope, Exit8.void).pipe(Effect51.andThen(rt.disposeEffect)))
|
|
9092
9635
|
};
|
|
9093
9636
|
} catch (cause) {
|
|
9094
|
-
await
|
|
9637
|
+
await Effect51.runPromise(Scope5.close(scope, Exit8.void).pipe(Effect51.andThen(runtime?.disposeEffect ?? Effect51.void))).catch(() => {
|
|
9095
9638
|
return;
|
|
9096
9639
|
});
|
|
9097
9640
|
return Promise.reject(cause);
|
|
@@ -9102,7 +9645,7 @@ var makeDimple = async (options) => {
|
|
|
9102
9645
|
const migrationFolder = "config" in options ? options.migrationFolder : undefined;
|
|
9103
9646
|
let currentConfig;
|
|
9104
9647
|
if (configSource !== undefined) {
|
|
9105
|
-
currentConfig = await
|
|
9648
|
+
currentConfig = await Effect51.runPromise(resolveConfigInput(configSource)).catch((cause) => Promise.reject(remapError(cause)));
|
|
9106
9649
|
}
|
|
9107
9650
|
let current = await bootStack(configSource !== undefined && currentConfig !== undefined ? {
|
|
9108
9651
|
config: currentConfig,
|
|
@@ -9111,7 +9654,7 @@ var makeDimple = async (options) => {
|
|
|
9111
9654
|
let disposed = false;
|
|
9112
9655
|
let gate = Promise.resolve();
|
|
9113
9656
|
let releaseGate;
|
|
9114
|
-
let
|
|
9657
|
+
let inflight2 = 0;
|
|
9115
9658
|
let drainWaiters = [];
|
|
9116
9659
|
let reloadChain = Promise.resolve();
|
|
9117
9660
|
const run = (effect) => {
|
|
@@ -9123,12 +9666,12 @@ var makeDimple = async (options) => {
|
|
|
9123
9666
|
return Promise.reject(new StoreFailure({ message: "SDK disposed" }));
|
|
9124
9667
|
}
|
|
9125
9668
|
const stack = current;
|
|
9126
|
-
|
|
9127
|
-
return stack.runPromise(effect.pipe(
|
|
9669
|
+
inflight2 += 1;
|
|
9670
|
+
return stack.runPromise(effect.pipe(Effect51.mapError(remapError))).catch((cause) => {
|
|
9128
9671
|
return Promise.reject(remapError(cause));
|
|
9129
9672
|
}).finally(() => {
|
|
9130
|
-
|
|
9131
|
-
if (
|
|
9673
|
+
inflight2 -= 1;
|
|
9674
|
+
if (inflight2 === 0 && drainWaiters.length > 0) {
|
|
9132
9675
|
const waiters = drainWaiters;
|
|
9133
9676
|
drainWaiters = [];
|
|
9134
9677
|
for (const wake of waiters)
|
|
@@ -9149,7 +9692,7 @@ var makeDimple = async (options) => {
|
|
|
9149
9692
|
release?.();
|
|
9150
9693
|
};
|
|
9151
9694
|
const drain = () => {
|
|
9152
|
-
if (
|
|
9695
|
+
if (inflight2 === 0)
|
|
9153
9696
|
return Promise.resolve();
|
|
9154
9697
|
return new Promise((resolve2) => {
|
|
9155
9698
|
drainWaiters.push(resolve2);
|
|
@@ -9180,7 +9723,7 @@ var makeDimple = async (options) => {
|
|
|
9180
9723
|
}));
|
|
9181
9724
|
}
|
|
9182
9725
|
const nextInput = input ?? configSource;
|
|
9183
|
-
const resolved = await
|
|
9726
|
+
const resolved = await Effect51.runPromise(resolveConfigInput(nextInput));
|
|
9184
9727
|
if (currentConfig !== undefined && stableKey(resolved) === stableKey(currentConfig)) {
|
|
9185
9728
|
return {
|
|
9186
9729
|
config: resolved,
|
|
@@ -9203,10 +9746,10 @@ var makeDimple = async (options) => {
|
|
|
9203
9746
|
currentConfig = resolved;
|
|
9204
9747
|
await old.dispose();
|
|
9205
9748
|
if (changes.storeUrl) {
|
|
9206
|
-
await
|
|
9749
|
+
await Effect51.runPromise(Effect51.logWarning(`reload: store database switched "${oldStoreUrl}" → "${resolved.storeUrl}" — ` + "the old db is preserved but no longer served (nothing was migrated)").pipe(Effect51.annotateLogs({ scope: "@dimple/sdk", event: "reload.store.switch" })));
|
|
9207
9750
|
}
|
|
9208
9751
|
if (changes.jobsUrl) {
|
|
9209
|
-
await
|
|
9752
|
+
await Effect51.runPromise(Effect51.logWarning(`reload: jobs database switched "${oldJobsUrl}" → "${resolved.jobs?.dbUrl}" — ` + "pending jobs remain durable in the old db").pipe(Effect51.annotateLogs({ scope: "@dimple/sdk", event: "reload.jobs.switch" })));
|
|
9210
9753
|
}
|
|
9211
9754
|
return { config: resolved, changed: changes, reloaded: true };
|
|
9212
9755
|
} finally {
|