@ponraaj/dimple-sdk 0.0.0-alpha.4 → 0.0.0-alpha.5
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 +198 -5
- package/dist/dimple.d.ts +101 -3
- package/dist/errors.d.ts +23 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +948 -210
- package/dist/indexer.d.ts +9 -0
- package/dist/internal/config/schema.d.ts +18 -0
- package/dist/internal/embedder/auto-install.d.ts +35 -0
- package/dist/internal/embedder/transformers.d.ts +10 -1
- package/dist/internal/extractor/models/extraction.d.ts +14 -0
- package/dist/internal/logger/index.d.ts +1 -1
- package/dist/internal/logger/service.d.ts +15 -7
- package/dist/internal/store/db-backend.d.ts +14 -2
- package/dist/internal/store/graph/candidates.d.ts +3 -1
- package/dist/internal/store/models.d.ts +4 -3
- package/dist/internal/store/schema/graph.d.ts +7 -7
- package/dist/internal/store/schema/libsql.d.ts +4 -4
- package/dist/internal/store/schema/metadata.d.ts +4 -1
- package/dist/internal/store/service.d.ts +45 -1
- package/dist/make.d.ts +21 -0
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __returnValue = (v) => v;
|
|
3
4
|
function __exportSetter(name, newValue) {
|
|
@@ -12,9 +13,10 @@ var __export = (target, all) => {
|
|
|
12
13
|
set: __exportSetter.bind(all, name)
|
|
13
14
|
});
|
|
14
15
|
};
|
|
16
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
15
17
|
|
|
16
18
|
// src/make.ts
|
|
17
|
-
import { Effect as Effect50, Exit as Exit7, Layer as Layer26, ManagedRuntime
|
|
19
|
+
import { Effect as Effect50, Exit as Exit7, Layer as Layer26, ManagedRuntime, Scope as Scope5 } from "effect";
|
|
18
20
|
|
|
19
21
|
// ../core/src/core.ts
|
|
20
22
|
import { Context, Schema } from "effect";
|
|
@@ -31,7 +33,7 @@ import { Effect as Effect39, Layer as Layer15, Schema as Schema24 } from "effect
|
|
|
31
33
|
|
|
32
34
|
// ../store/src/store.ts
|
|
33
35
|
import { Config as Config4, Effect as Effect26, Layer as Layer10, Schema as Schema19 } from "effect";
|
|
34
|
-
import { eq as eq8, and as and8, desc as desc2, asc as asc5, inArray as inArray4, ne as ne4, or, isNull as isNull2, sql as sql7 } from "drizzle-orm";
|
|
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";
|
|
35
37
|
|
|
36
38
|
// ../store/src/db-backend.ts
|
|
37
39
|
import { Context as Context2 } from "effect";
|
|
@@ -44,9 +46,6 @@ import { Effect as Effect9, Layer as Layer3, Config as Config2 } from "effect";
|
|
|
44
46
|
import { createClient } from "@libsql/client";
|
|
45
47
|
import { drizzle } from "drizzle-orm/libsql";
|
|
46
48
|
import { sql as sql2 } from "drizzle-orm";
|
|
47
|
-
import * as fs2 from "node:fs";
|
|
48
|
-
import { dirname as dirname2 } from "node:path";
|
|
49
|
-
import { migrate } from "drizzle-orm/libsql/migrator";
|
|
50
49
|
|
|
51
50
|
// ../store/src/error.ts
|
|
52
51
|
import { Schema as Schema2 } from "effect";
|
|
@@ -109,6 +108,11 @@ var EMBEDDED_MIGRATIONS = [
|
|
|
109
108
|
name: "20260804035154_dream_state",
|
|
110
109
|
hash: "376f6768a43edf8941614b92720222c895e258411504fb5857569dff5990b62f",
|
|
111
110
|
sql: "CREATE TABLE `dream_state` (\n\t`model_key` text PRIMARY KEY,\n\t`last_dream_at` integer NOT NULL,\n\t`last_dream_memory_count` integer NOT NULL\n);\n"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "20260807074034_ttl_secs_nullable",
|
|
114
|
+
hash: "be3a8d0e64b0224021d869c1c7e217e40b6eb868615cc4c86a6717f5b7211721",
|
|
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';"
|
|
112
116
|
}
|
|
113
117
|
];
|
|
114
118
|
|
|
@@ -148,7 +152,7 @@ var memories = sqliteTable("memories", {
|
|
|
148
152
|
contentType: text("content_type").notNull().default("text/plain"),
|
|
149
153
|
state: text("state", { enum: ["active", "superseded", "archived", "forgotten"] }).notNull().default("active"),
|
|
150
154
|
createdAt: integer("created_at").notNull(),
|
|
151
|
-
ttlSecs: integer("ttl_secs").
|
|
155
|
+
ttlSecs: integer("ttl_secs").default(604800),
|
|
152
156
|
namespace: text("namespace").notNull().default("default"),
|
|
153
157
|
metadata: text("metadata"),
|
|
154
158
|
embedding: float32Array("embedding", { dimensions: 384 }),
|
|
@@ -326,7 +330,7 @@ var artifactEdges = sqliteTable3("artifact_edges", {
|
|
|
326
330
|
fromMemoryId: text3("from_memory_id").notNull().references(() => memories.id, { onDelete: "cascade" }),
|
|
327
331
|
toMemoryId: text3("to_memory_id").notNull().references(() => memories.id, { onDelete: "cascade" }),
|
|
328
332
|
edgeKind: text3("edge_kind", {
|
|
329
|
-
enum: ["memory_supports", "memory_supersedes", "memory_contradicts"]
|
|
333
|
+
enum: ["memory_supports", "memory_supersedes", "memory_contradicts", "code_calls"]
|
|
330
334
|
}).notNull(),
|
|
331
335
|
weight: real3("weight").notNull().default(1),
|
|
332
336
|
status: text3("status", { enum: ["pending", "confirmed", "rejected"] }).notNull().default("pending"),
|
|
@@ -378,7 +382,6 @@ import { Effect as Effect6, Schema as Schema6 } from "effect";
|
|
|
378
382
|
|
|
379
383
|
// ../logger/src/service.ts
|
|
380
384
|
import { Config, Context as Context3, Effect as Effect5, Layer, Logger, References } from "effect";
|
|
381
|
-
import { closeSync, fsyncSync, openSync, writeSync } from "node:fs";
|
|
382
385
|
|
|
383
386
|
// ../logger/src/format.ts
|
|
384
387
|
function renderJson(entry) {
|
|
@@ -498,13 +501,14 @@ var consoleSink = (pretty) => {
|
|
|
498
501
|
const render = pretty ? renderPretty : renderJson;
|
|
499
502
|
return {
|
|
500
503
|
write: (entry) => {
|
|
501
|
-
process.
|
|
504
|
+
process.stderr.write(render(entry) + `
|
|
502
505
|
`);
|
|
503
506
|
},
|
|
504
507
|
dispose: () => {}
|
|
505
508
|
};
|
|
506
509
|
};
|
|
507
|
-
var fileSink = (path) => {
|
|
510
|
+
var fileSink = (path) => Effect5.tryPromise(async () => {
|
|
511
|
+
const { openSync, closeSync, fsyncSync, writeSync } = await import("node:fs");
|
|
508
512
|
const fd = openSync(path, "a");
|
|
509
513
|
let disposed = false;
|
|
510
514
|
const flush = () => {
|
|
@@ -537,11 +541,15 @@ var fileSink = (path) => {
|
|
|
537
541
|
closeSync(fd);
|
|
538
542
|
}
|
|
539
543
|
};
|
|
540
|
-
};
|
|
544
|
+
});
|
|
541
545
|
|
|
542
546
|
class Service3 extends Context3.Service()("@dimple/logger/Logging") {
|
|
543
547
|
}
|
|
544
|
-
var
|
|
548
|
+
var makeEffect = (config) => Effect5.gen(function* () {
|
|
549
|
+
const file = config.file === undefined ? undefined : yield* fileSink(config.file);
|
|
550
|
+
const sinks = [consoleSink((config.format ?? "jsonl") === "pretty")];
|
|
551
|
+
if (file !== undefined)
|
|
552
|
+
sinks.push(file);
|
|
545
553
|
const level = config.level ?? "info";
|
|
546
554
|
const floor = LEVEL_ORDER[level];
|
|
547
555
|
const overrides = {};
|
|
@@ -551,9 +559,6 @@ var make = (config) => {
|
|
|
551
559
|
overrides[scope] = order;
|
|
552
560
|
}
|
|
553
561
|
const ring = new RingBuffer(config.ringSize ?? 4096);
|
|
554
|
-
const sinks = [consoleSink((config.format ?? "jsonl") === "pretty")];
|
|
555
|
-
if (config.file !== undefined)
|
|
556
|
-
sinks.push(fileSink(config.file));
|
|
557
562
|
return Service3.of({
|
|
558
563
|
ring,
|
|
559
564
|
emit: (entry) => {
|
|
@@ -572,7 +577,7 @@ var make = (config) => {
|
|
|
572
577
|
sink.dispose();
|
|
573
578
|
}
|
|
574
579
|
});
|
|
575
|
-
};
|
|
580
|
+
});
|
|
576
581
|
var LEVEL_MAP = {
|
|
577
582
|
FATAL: "error",
|
|
578
583
|
ERROR: "error",
|
|
@@ -637,7 +642,7 @@ var EFFECT_LEVEL = {
|
|
|
637
642
|
};
|
|
638
643
|
var minLevelLayer = (minLevel) => Layer.succeed(References.MinimumLogLevel, minLevel === "None" ? "None" : EFFECT_LEVEL[minLevel]);
|
|
639
644
|
var layer = (config) => {
|
|
640
|
-
const loggingLayer = Layer.effect(Service3, Effect5.acquireRelease(
|
|
645
|
+
const loggingLayer = Layer.effect(Service3, Effect5.acquireRelease(makeEffect(config), (logging) => Effect5.sync(() => logging.dispose())));
|
|
641
646
|
const minLevel = config.enabled === false ? "None" : lowestLevel(config);
|
|
642
647
|
const withLogger = Layer.provideMerge(loggingLayer)(loggerReplacement());
|
|
643
648
|
return Layer.provideMerge(minLevelLayer(minLevel))(withLogger);
|
|
@@ -688,7 +693,8 @@ var EmbeddingModelConfig = Schema6.Struct({
|
|
|
688
693
|
])),
|
|
689
694
|
pooling: Schema6.optional(Schema6.Literals(["mean", "cls", "none"])),
|
|
690
695
|
normalize: Schema6.optional(Schema6.Boolean),
|
|
691
|
-
cacheDir: Schema6.optional(Schema6.String)
|
|
696
|
+
cacheDir: Schema6.optional(Schema6.String),
|
|
697
|
+
autoInstall: Schema6.optional(Schema6.Boolean)
|
|
692
698
|
});
|
|
693
699
|
var EmbeddingConfig = Schema6.Struct({
|
|
694
700
|
defaultModel: Schema6.String,
|
|
@@ -755,8 +761,6 @@ import { Context as Context4, Effect as Effect8, Layer as Layer2 } from "effect"
|
|
|
755
761
|
// ../config/src/loader.ts
|
|
756
762
|
import { Effect as Effect7, Schema as Schema7 } from "effect";
|
|
757
763
|
import { parse, parseTree, printParseErrorCode } from "jsonc-parser";
|
|
758
|
-
import * as fs from "node:fs";
|
|
759
|
-
import * as path from "node:path";
|
|
760
764
|
var CONFIG_FILE_NAMES = ["dimple.jsonc", "dimple.json"];
|
|
761
765
|
var GLOBAL_DIR = ".config/dimple";
|
|
762
766
|
var defaults = {
|
|
@@ -856,11 +860,14 @@ var parseJsoncEffect = (text4, formatError) => {
|
|
|
856
860
|
return Effect7.fail(formatError(result.error));
|
|
857
861
|
return Effect7.succeed(result.value);
|
|
858
862
|
};
|
|
859
|
-
var readFile = (filePath) => Effect7.
|
|
860
|
-
try: () => fs.
|
|
863
|
+
var readFile = (filePath) => Effect7.tryPromise({
|
|
864
|
+
try: async () => (await import("node:fs")).promises.readFile(filePath, "utf8"),
|
|
861
865
|
catch: (cause) => new Error(`failed to read config file ${filePath}: ${cause instanceof Error ? cause.message : String(cause)}`)
|
|
862
866
|
}).pipe(Effect7.flatMap((content) => parseJsoncEffect(content, (cause) => new Error(`failed to read config file ${filePath}: ${cause.message}`))));
|
|
863
|
-
var
|
|
867
|
+
var loadFs = () => Effect7.tryPromise(() => import("node:fs"));
|
|
868
|
+
var findProjectConfig = () => Effect7.gen(function* () {
|
|
869
|
+
const fs = yield* loadFs();
|
|
870
|
+
const path = yield* Effect7.tryPromise(() => import("node:path"));
|
|
864
871
|
let dir = process.cwd();
|
|
865
872
|
for (let i = 0;i < 20; i++) {
|
|
866
873
|
for (const name of CONFIG_FILE_NAMES) {
|
|
@@ -874,37 +881,40 @@ var findProjectConfig = () => {
|
|
|
874
881
|
dir = parent;
|
|
875
882
|
}
|
|
876
883
|
return;
|
|
877
|
-
};
|
|
878
|
-
var getGlobalConfigPath = () => {
|
|
884
|
+
});
|
|
885
|
+
var getGlobalConfigPath = () => Effect7.gen(function* () {
|
|
879
886
|
const home = process.env["HOME"] ?? process.env["USERPROFILE"];
|
|
880
887
|
if (!home)
|
|
881
888
|
return;
|
|
889
|
+
const fs = yield* loadFs();
|
|
890
|
+
const path = yield* Effect7.tryPromise(() => import("node:path"));
|
|
882
891
|
for (const name of CONFIG_FILE_NAMES) {
|
|
883
892
|
const p = path.join(home, GLOBAL_DIR, name);
|
|
884
893
|
if (fs.existsSync(p))
|
|
885
894
|
return p;
|
|
886
895
|
}
|
|
887
896
|
return;
|
|
888
|
-
};
|
|
889
|
-
var loadFromFiles = () => {
|
|
897
|
+
});
|
|
898
|
+
var loadFromFiles = () => Effect7.gen(function* () {
|
|
890
899
|
const sources = [];
|
|
891
|
-
const globalPath = getGlobalConfigPath();
|
|
900
|
+
const globalPath = yield* getGlobalConfigPath();
|
|
892
901
|
if (globalPath)
|
|
893
902
|
sources.push({ path: globalPath });
|
|
894
|
-
const projectPath = findProjectConfig();
|
|
903
|
+
const projectPath = yield* findProjectConfig();
|
|
895
904
|
if (projectPath)
|
|
896
905
|
sources.push({ path: projectPath });
|
|
897
906
|
const envPath = process.env["DIMPLE_CONFIG"];
|
|
898
907
|
if (envPath) {
|
|
908
|
+
const fs = yield* loadFs();
|
|
899
909
|
if (!fs.existsSync(envPath)) {
|
|
900
|
-
return Effect7.fail(new Error(`DIMPLE_CONFIG path not found: ${envPath}`));
|
|
910
|
+
return yield* Effect7.fail(new Error(`DIMPLE_CONFIG path not found: ${envPath}`));
|
|
901
911
|
}
|
|
902
912
|
sources.push({ path: envPath });
|
|
903
913
|
}
|
|
904
914
|
if (sources.length === 0)
|
|
905
|
-
return
|
|
906
|
-
return Effect7.forEach(sources, (s) => readFile(s.path));
|
|
907
|
-
};
|
|
915
|
+
return [];
|
|
916
|
+
return yield* Effect7.forEach(sources, (s) => readFile(s.path));
|
|
917
|
+
});
|
|
908
918
|
var loadFromEnvContent = () => {
|
|
909
919
|
const content = process.env["DIMPLE_CONFIG_CONTENT"];
|
|
910
920
|
if (!content)
|
|
@@ -935,15 +945,16 @@ var deepMerge = (base, over) => {
|
|
|
935
945
|
}
|
|
936
946
|
return out;
|
|
937
947
|
};
|
|
938
|
-
var loadConfigFromFile = (
|
|
948
|
+
var loadConfigFromFile = (path) => Effect7.gen(function* () {
|
|
949
|
+
const fs = yield* loadFs();
|
|
939
950
|
const content = yield* Effect7.tryPromise({
|
|
940
|
-
try: () => fs.promises.readFile(
|
|
941
|
-
catch: (cause) => new Error(`config read ${
|
|
951
|
+
try: () => fs.promises.readFile(path, "utf8"),
|
|
952
|
+
catch: (cause) => new Error(`config read ${path}: ${cause}`)
|
|
942
953
|
});
|
|
943
|
-
const parsed = yield* parseJsoncEffect(content, (cause) => new Error(`config parse ${
|
|
954
|
+
const parsed = yield* parseJsoncEffect(content, (cause) => new Error(`config parse ${path}: ${cause.message}`));
|
|
944
955
|
const merged = deepMerge(defaults, parsed);
|
|
945
956
|
const resolved = resolveEnvVars(merged);
|
|
946
|
-
return yield* Schema7.decodeUnknownEffect(DimpleConfig)(resolved).pipe(Effect7.mapError((e) => new Error(`config validation: ${e.message}`)));
|
|
957
|
+
return yield* Schema7.decodeUnknownEffect(DimpleConfig, { errors: "all" })(resolved).pipe(Effect7.mapError((e) => new Error(`config validation: ${e.message}`)));
|
|
947
958
|
});
|
|
948
959
|
var loadConfig = (overrides) => Effect7.gen(function* () {
|
|
949
960
|
const fileParts = yield* loadFromFiles();
|
|
@@ -956,7 +967,7 @@ var loadConfig = (overrides) => Effect7.gen(function* () {
|
|
|
956
967
|
if (overrides)
|
|
957
968
|
merged = deepMerge(merged, overrides);
|
|
958
969
|
const resolved = resolveEnvVars(merged);
|
|
959
|
-
return yield* Schema7.decodeUnknownEffect(DimpleConfig)(resolved).pipe(Effect7.mapError((e) => new Error(`config validation: ${e.message}`)));
|
|
970
|
+
return yield* Schema7.decodeUnknownEffect(DimpleConfig, { errors: "all" })(resolved).pipe(Effect7.mapError((e) => new Error(`config validation: ${e.message}`)));
|
|
960
971
|
});
|
|
961
972
|
|
|
962
973
|
// ../config/src/service.ts
|
|
@@ -1049,9 +1060,6 @@ var runEmbeddedMigrations = async (client) => {
|
|
|
1049
1060
|
}
|
|
1050
1061
|
};
|
|
1051
1062
|
var makeClientDb = (url) => {
|
|
1052
|
-
if (url.startsWith("file:")) {
|
|
1053
|
-
fs2.mkdirSync(dirname2(url.slice("file:".length)), { recursive: true });
|
|
1054
|
-
}
|
|
1055
1063
|
const client = createClient({ url });
|
|
1056
1064
|
const db = drizzle({ client });
|
|
1057
1065
|
const rawTransaction = client.transaction.bind(client);
|
|
@@ -1114,25 +1122,29 @@ var makeClientDb = (url) => {
|
|
|
1114
1122
|
};
|
|
1115
1123
|
return { client, db };
|
|
1116
1124
|
};
|
|
1125
|
+
var ensureFileDir = (url) => url.startsWith("file:") ? import("node:fs").then((fs) => import("node:path").then(({ dirname }) => {
|
|
1126
|
+
fs.mkdirSync(dirname(url.slice("file:".length)), { recursive: true });
|
|
1127
|
+
})) : Promise.resolve();
|
|
1117
1128
|
var acquireMigrationLock = async (url) => {
|
|
1118
1129
|
if (!url.startsWith("file:"))
|
|
1119
1130
|
return;
|
|
1131
|
+
const fs = await import("node:fs");
|
|
1120
1132
|
const dbPath = url.slice("file:".length);
|
|
1121
1133
|
const lockPath = `${dbPath}.migrate-lock`;
|
|
1122
1134
|
const deadline = Date.now() + 30000;
|
|
1123
1135
|
for (;; ) {
|
|
1124
1136
|
try {
|
|
1125
|
-
const fd =
|
|
1137
|
+
const fd = fs.openSync(lockPath, "wx");
|
|
1126
1138
|
return () => {
|
|
1127
1139
|
try {
|
|
1128
|
-
|
|
1129
|
-
|
|
1140
|
+
fs.closeSync(fd);
|
|
1141
|
+
fs.unlinkSync(lockPath);
|
|
1130
1142
|
} catch {}
|
|
1131
1143
|
};
|
|
1132
1144
|
} catch {
|
|
1133
1145
|
try {
|
|
1134
|
-
if (Date.now() -
|
|
1135
|
-
|
|
1146
|
+
if (Date.now() - fs.statSync(lockPath).mtimeMs > 300000)
|
|
1147
|
+
fs.unlinkSync(lockPath);
|
|
1136
1148
|
} catch {}
|
|
1137
1149
|
if (Date.now() > deadline) {
|
|
1138
1150
|
return Promise.reject(new Error(`timed out waiting for migration lock ${lockPath}`));
|
|
@@ -1142,6 +1154,10 @@ var acquireMigrationLock = async (url) => {
|
|
|
1142
1154
|
}
|
|
1143
1155
|
};
|
|
1144
1156
|
var topicFilter = (topicKeys) => topicKeys && topicKeys.length > 0 ? ` AND m.id IN (SELECT memory_id FROM topic_memberships WHERE topic_key IN (${topicKeys.map(() => "?").join(", ")}) AND model_key = ?)` : "";
|
|
1157
|
+
var contentTypeFilter = (contentType) => {
|
|
1158
|
+
const kinds = typeof contentType === "string" ? [contentType] : contentType ?? [];
|
|
1159
|
+
return kinds.length === 0 ? "" : ` AND m.content_type IN (${kinds.map(() => "?").join(", ")})`;
|
|
1160
|
+
};
|
|
1145
1161
|
var makeBackend = (url, client, db, migrationFolder) => ({
|
|
1146
1162
|
listIsolatedMemories: (limit, modelKey) => Effect9.tryPromise({
|
|
1147
1163
|
try: () => client.execute({
|
|
@@ -1177,6 +1193,7 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1177
1193
|
try: async () => {
|
|
1178
1194
|
try {
|
|
1179
1195
|
if (migrationFolder !== undefined) {
|
|
1196
|
+
const { migrate } = await import("drizzle-orm/libsql/migrator");
|
|
1180
1197
|
await migrate(db, { migrationsFolder: migrationFolder });
|
|
1181
1198
|
} else {
|
|
1182
1199
|
await runEmbeddedMigrations(client);
|
|
@@ -1207,25 +1224,25 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1207
1224
|
topics,
|
|
1208
1225
|
artifactEdges
|
|
1209
1226
|
},
|
|
1210
|
-
ftsSearch: (query, namespace, limit, topicKeys, modelKey) => Effect9.tryPromise({
|
|
1227
|
+
ftsSearch: (query, namespace, limit, topicKeys, modelKey, contentType) => Effect9.tryPromise({
|
|
1211
1228
|
try: () => client.execute({
|
|
1212
1229
|
sql: `SELECT m.*, f.rank
|
|
1213
1230
|
FROM memories_fts f
|
|
1214
1231
|
JOIN memories m ON m.rowid = f.rowid
|
|
1215
|
-
WHERE f.content MATCH ? AND m.namespace = ? AND m.state = 'active'${topicFilter(topicKeys)}
|
|
1232
|
+
WHERE f.content MATCH ? AND m.namespace = ? AND m.state = 'active'${topicFilter(topicKeys)}${contentTypeFilter(contentType)}
|
|
1216
1233
|
ORDER BY f.rank
|
|
1217
1234
|
LIMIT ?`,
|
|
1218
|
-
args:
|
|
1235
|
+
args: [
|
|
1219
1236
|
`"${query.replaceAll('"', '""')}"`,
|
|
1220
1237
|
namespace,
|
|
1221
|
-
...topicKeys,
|
|
1222
|
-
|
|
1238
|
+
...topicKeys && topicKeys.length > 0 ? [...topicKeys, modelKey ?? ""] : [],
|
|
1239
|
+
...typeof contentType === "string" ? [contentType] : contentType ?? [],
|
|
1223
1240
|
limit
|
|
1224
|
-
]
|
|
1241
|
+
]
|
|
1225
1242
|
}).then((rs) => rs.rows),
|
|
1226
1243
|
catch: (cause) => new StoreError({ message: `DbBackend.ftsSearch: ${cause}` })
|
|
1227
1244
|
}),
|
|
1228
|
-
vectorSearch: (query, namespace, limit, model, topicKeys) => Effect9.gen(function* () {
|
|
1245
|
+
vectorSearch: (query, namespace, limit, model, topicKeys, contentType) => Effect9.gen(function* () {
|
|
1229
1246
|
for (const n of query) {
|
|
1230
1247
|
if (!Number.isFinite(n)) {
|
|
1231
1248
|
yield* new StoreError({
|
|
@@ -1236,7 +1253,13 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1236
1253
|
const tableName = vectorTableName(model);
|
|
1237
1254
|
const vecJson = JSON.stringify([...query]);
|
|
1238
1255
|
const convertFn = VECTOR_CONVERT_FNS[model.vectorType ?? "float32"] ?? "vector32";
|
|
1239
|
-
const args =
|
|
1256
|
+
const args = [
|
|
1257
|
+
vecJson,
|
|
1258
|
+
namespace,
|
|
1259
|
+
...topicKeys && topicKeys.length > 0 ? [...topicKeys, model.id] : [],
|
|
1260
|
+
...typeof contentType === "string" ? [contentType] : contentType ?? [],
|
|
1261
|
+
limit
|
|
1262
|
+
];
|
|
1240
1263
|
const rows = yield* Effect9.tryPromise({
|
|
1241
1264
|
try: () => client.execute({
|
|
1242
1265
|
sql: `
|
|
@@ -1244,7 +1267,7 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1244
1267
|
vector_distance_cos(v.embedding, ${convertFn}(?)) AS distance
|
|
1245
1268
|
FROM memories m
|
|
1246
1269
|
JOIN ${tableName} v ON v.memory_id = m.id
|
|
1247
|
-
WHERE m.namespace = ? AND m.state = 'active'${topicFilter(topicKeys)}
|
|
1270
|
+
WHERE m.namespace = ? AND m.state = 'active'${topicFilter(topicKeys)}${contentTypeFilter(contentType)}
|
|
1248
1271
|
ORDER BY distance
|
|
1249
1272
|
LIMIT ?
|
|
1250
1273
|
`,
|
|
@@ -1282,6 +1305,23 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1282
1305
|
}),
|
|
1283
1306
|
catch: (cause) => new StoreError({ message: `DbBackend.sweep: ${cause}` })
|
|
1284
1307
|
}),
|
|
1308
|
+
listSchema: () => Effect9.tryPromise({
|
|
1309
|
+
try: async () => {
|
|
1310
|
+
const tables = (await client.execute({
|
|
1311
|
+
sql: `SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name`
|
|
1312
|
+
})).rows;
|
|
1313
|
+
const out = [];
|
|
1314
|
+
for (const t of tables) {
|
|
1315
|
+
const cols = (await client.execute({ sql: `PRAGMA table_info(${t.name})` })).rows;
|
|
1316
|
+
out.push({
|
|
1317
|
+
table: t.name,
|
|
1318
|
+
columns: cols.map((c) => ({ name: c.name, type: c.type }))
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
return out;
|
|
1322
|
+
},
|
|
1323
|
+
catch: (cause) => new StoreError({ message: `DbBackend.listSchema: ${cause}` })
|
|
1324
|
+
}),
|
|
1285
1325
|
writeAuditRows: (rows) => rows.length === 0 ? Effect9.void : Effect9.tryPromise({
|
|
1286
1326
|
try: () => db.insert(retrievalLog).values([...rows]),
|
|
1287
1327
|
catch: (cause) => new StoreError({ message: `DbBackend.writeAuditRows: ${cause}` })
|
|
@@ -1330,10 +1370,12 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1330
1370
|
const maxTotal = opts?.maxTotal ?? 80;
|
|
1331
1371
|
const includePending = opts?.includePending ?? true;
|
|
1332
1372
|
const modelKey = opts?.modelKey;
|
|
1333
|
-
const statusClause = includePending ? `AND e.status IN ('active', 'confirmed', 'pending')` : `AND e.status IN ('active', 'confirmed')`;
|
|
1373
|
+
const statusClause = includePending ? `AND e.expired_at IS NULL AND e.status IN ('active', 'confirmed', 'pending')` : `AND e.expired_at IS NULL AND e.status IN ('active', 'confirmed')`;
|
|
1334
1374
|
const modelClause = modelKey === undefined ? "" : `AND (e.from_kind <> 'topic'
|
|
1335
1375
|
OR EXISTS (SELECT 1 FROM topic_memberships tm WHERE tm.topic_key = e.from_id AND tm.memory_id = e.to_id AND tm.model_key = ?)
|
|
1336
1376
|
OR EXISTS (SELECT 1 FROM topic_relations tr WHERE tr.parent_key = e.from_id AND tr.child_key = e.to_id AND tr.model_key = ?))`;
|
|
1377
|
+
const kinds = opts?.edgeKinds;
|
|
1378
|
+
const kindClause = kinds === undefined || kinds.length === 0 ? "" : `AND e.edge_kind IN (${kinds.map(() => "?").join(",")})`;
|
|
1337
1379
|
const results = [];
|
|
1338
1380
|
const seenEdges = new Set;
|
|
1339
1381
|
const visited = new Set([`${kind}:${id}`]);
|
|
@@ -1346,6 +1388,8 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1346
1388
|
args.push(node.id, node.kind, node.id, node.kind);
|
|
1347
1389
|
if (modelKey !== undefined)
|
|
1348
1390
|
args.push(modelKey, modelKey);
|
|
1391
|
+
if (kinds !== undefined && kinds.length > 0)
|
|
1392
|
+
args.push(...kinds);
|
|
1349
1393
|
const rows = yield* Effect9.tryPromise({
|
|
1350
1394
|
try: () => client.execute({
|
|
1351
1395
|
sql: `SELECT e.from_kind, e.from_id, e.to_kind, e.to_id, e.edge_kind, e.weight, e.status, e.source, e.valid_at, e.expired_at, ? AS depth
|
|
@@ -1353,6 +1397,7 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1353
1397
|
WHERE (${touches})
|
|
1354
1398
|
${statusClause}
|
|
1355
1399
|
${modelClause}
|
|
1400
|
+
${kindClause}
|
|
1356
1401
|
ORDER BY e.from_id, e.edge_kind, e.to_id, e.to_kind`,
|
|
1357
1402
|
args
|
|
1358
1403
|
}).then((rs) => rs.rows),
|
|
@@ -1524,13 +1569,20 @@ var makeBackend = (url, client, db, migrationFolder) => ({
|
|
|
1524
1569
|
})
|
|
1525
1570
|
});
|
|
1526
1571
|
var layer3 = (url, options) => {
|
|
1527
|
-
const effect = options?.releaseClient === true ? Effect9.acquireRelease(Effect9.
|
|
1572
|
+
const effect = options?.releaseClient === true ? Effect9.acquireRelease(Effect9.tryPromise({
|
|
1573
|
+
try: () => ensureFileDir(url).then(() => makeClientDb(url)),
|
|
1574
|
+
catch: (cause) => new StoreError({ message: `DbBackend.client: ${cause}` })
|
|
1575
|
+
}), ({ client }) => Effect9.tryPromise({
|
|
1528
1576
|
try: async () => client.close(),
|
|
1529
1577
|
catch: () => new Error("DbBackend.close failed")
|
|
1530
1578
|
}).pipe(Effect9.ignore)).pipe(Effect9.flatMap(({ client, db }) => {
|
|
1531
1579
|
const backend = Service2.of(makeBackend(url, client, db, options?.migrationFolder));
|
|
1532
1580
|
return backend.runMigrations().pipe(Effect9.as(backend));
|
|
1533
1581
|
})) : Effect9.gen(function* () {
|
|
1582
|
+
yield* Effect9.tryPromise({
|
|
1583
|
+
try: () => ensureFileDir(url),
|
|
1584
|
+
catch: (cause) => new StoreError({ message: `DbBackend.client: ${cause}` })
|
|
1585
|
+
});
|
|
1534
1586
|
const { client, db } = yield* Effect9.sync(() => makeClientDb(url));
|
|
1535
1587
|
const backend = Service2.of(makeBackend(url, client, db, options?.migrationFolder));
|
|
1536
1588
|
yield* backend.runMigrations();
|
|
@@ -1557,6 +1609,7 @@ var MemoryMetadata = Schema8.Struct({
|
|
|
1557
1609
|
confidence: Schema8.Number,
|
|
1558
1610
|
affordances: Schema8.Array(Schema8.String),
|
|
1559
1611
|
language: Schema8.optional(Schema8.String),
|
|
1612
|
+
codeVersion: Schema8.optional(Schema8.String),
|
|
1560
1613
|
pinned: Schema8.optional(Schema8.Boolean)
|
|
1561
1614
|
});
|
|
1562
1615
|
var parseMetadata = (blob) => {
|
|
@@ -2423,7 +2476,6 @@ import {
|
|
|
2423
2476
|
} from "effect";
|
|
2424
2477
|
import { PersistedQueue } from "effect/unstable/persistence";
|
|
2425
2478
|
import { SqlClient } from "effect/unstable/sql";
|
|
2426
|
-
import { randomUUID } from "node:crypto";
|
|
2427
2479
|
|
|
2428
2480
|
class QueueKey extends Data.Class {
|
|
2429
2481
|
}
|
|
@@ -2434,7 +2486,7 @@ var makeStore = Effect15.fnUntraced(function* (options) {
|
|
|
2434
2486
|
const pollInterval = Duration.max(options?.pollInterval ? Duration.fromInputUnsafe(options.pollInterval) : Duration.millis(1000), Duration.millis(1));
|
|
2435
2487
|
const lockRefreshInterval = Duration.max(options?.lockRefreshInterval ? Duration.fromInputUnsafe(options.lockRefreshInterval) : Duration.seconds(30), Duration.millis(1));
|
|
2436
2488
|
const lockExpiration = Duration.max(options?.lockExpiration ? Duration.fromInputUnsafe(options.lockExpiration) : Duration.minutes(2), Duration.millis(1));
|
|
2437
|
-
const workerId = randomUUID();
|
|
2489
|
+
const workerId = globalThis.crypto.randomUUID();
|
|
2438
2490
|
const sqlNow = sql3.literal("CURRENT_TIMESTAMP");
|
|
2439
2491
|
const expiresAt = sql3.literal(`datetime(CURRENT_TIMESTAMP, '-${Math.ceil(Duration.toSeconds(lockExpiration))} seconds')`);
|
|
2440
2492
|
const workerIdSql = sql3.literal(`'${workerId}'`);
|
|
@@ -2574,7 +2626,7 @@ var storeSqliteLayer = Layer4.effect(PersistedQueue.PersistedQueueStore, makeSto
|
|
|
2574
2626
|
// ../../node_modules/.bun/@effect+sql-libsql@4.0.0-beta.103+10c4c6971de0179f/node_modules/@effect/sql-libsql/dist/LibsqlClient.js
|
|
2575
2627
|
var exports_LibsqlClient = {};
|
|
2576
2628
|
__export(exports_LibsqlClient, {
|
|
2577
|
-
make: () =>
|
|
2629
|
+
make: () => make4,
|
|
2578
2630
|
layerConfig: () => layerConfig2,
|
|
2579
2631
|
layer: () => layer5,
|
|
2580
2632
|
TypeId: () => TypeId,
|
|
@@ -2603,7 +2655,7 @@ var classifyError = (cause, message, operation) => classifySqliteError(cause, {
|
|
|
2603
2655
|
var TypeId = "~@effect/sql-libsql/LibsqlClient";
|
|
2604
2656
|
var LibsqlClient = /* @__PURE__ */ Context6.Service("@effect/sql-libsql/LibsqlClient");
|
|
2605
2657
|
var LibsqlTransaction = /* @__PURE__ */ Context6.Service("@effect/sql-libsql/LibsqlClient/LibsqlTransaction");
|
|
2606
|
-
var
|
|
2658
|
+
var make4 = (options) => Effect16.gen(function* () {
|
|
2607
2659
|
const compiler = Statement.makeCompilerSqlite(options.transformQueryNames);
|
|
2608
2660
|
const transformRows = options.transformResultNames ? Statement.defaultTransforms(options.transformResultNames).array : undefined;
|
|
2609
2661
|
const spanAttributes = [...options.spanAttributes ? Object.entries(options.spanAttributes) : [], [ATTR_DB_SYSTEM_NAME, "sqlite"]];
|
|
@@ -2718,11 +2770,9 @@ var make5 = (options) => Effect16.gen(function* () {
|
|
|
2718
2770
|
sdk: connection.sdk
|
|
2719
2771
|
});
|
|
2720
2772
|
});
|
|
2721
|
-
var layerConfig2 = (config) => Layer5.effectContext(Config3.unwrap(config).pipe(Effect16.flatMap(
|
|
2722
|
-
var layer5 = (config) => Layer5.effectContext(Effect16.map(
|
|
2773
|
+
var layerConfig2 = (config) => Layer5.effectContext(Config3.unwrap(config).pipe(Effect16.flatMap(make4), Effect16.map((client) => Context6.make(LibsqlClient, client).pipe(Context6.add(Client.SqlClient, client))))).pipe(Layer5.provide(Reactivity.layer));
|
|
2774
|
+
var layer5 = (config) => Layer5.effectContext(Effect16.map(make4(config), (client) => Context6.make(LibsqlClient, client).pipe(Context6.add(Client.SqlClient, client)))).pipe(Layer5.provide(Reactivity.layer));
|
|
2723
2775
|
// ../workflow/src/engine.ts
|
|
2724
|
-
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
2725
|
-
import { dirname as dirname3 } from "node:path";
|
|
2726
2776
|
var Persistence = PersistenceNamespace2.Persistence;
|
|
2727
2777
|
var PersistedQueueFactory = PersistedQueue2.PersistedQueueFactory;
|
|
2728
2778
|
var layerDurable = Layer6.effect(WorkflowEngine2.WorkflowEngine)(Effect17.gen(function* () {
|
|
@@ -2923,7 +2973,9 @@ var workflowTagFor = (workflows, store, executionId) => Effect17.gen(function* (
|
|
|
2923
2973
|
});
|
|
2924
2974
|
var ensureDbDir = (url) => {
|
|
2925
2975
|
if (url.startsWith("file:")) {
|
|
2926
|
-
|
|
2976
|
+
import("node:fs").then((fs) => import("node:path").then(({ dirname }) => {
|
|
2977
|
+
fs.mkdirSync(dirname(url.slice("file:".length)), { recursive: true });
|
|
2978
|
+
}));
|
|
2927
2979
|
}
|
|
2928
2980
|
};
|
|
2929
2981
|
var libsqlStack = (options) => {
|
|
@@ -4314,6 +4366,11 @@ var sameLogicalKeyFamily = (a, b) => {
|
|
|
4314
4366
|
const fb = familyOf(b);
|
|
4315
4367
|
return fa !== "" && fa === fb;
|
|
4316
4368
|
};
|
|
4369
|
+
var sameFileChunkFamily = (a, b) => {
|
|
4370
|
+
if (a === undefined || b === undefined || a === "" || b === "")
|
|
4371
|
+
return false;
|
|
4372
|
+
return a.startsWith(`${b}#`) || b.startsWith(`${a}#`);
|
|
4373
|
+
};
|
|
4317
4374
|
var topicsOf = (blob) => {
|
|
4318
4375
|
if (blob === undefined || blob === null)
|
|
4319
4376
|
return new Set;
|
|
@@ -4358,7 +4415,7 @@ var leafLocalCandidates = (newId, newVector, newCreatedAt, newLogicalKey, newMet
|
|
|
4358
4415
|
});
|
|
4359
4416
|
continue;
|
|
4360
4417
|
}
|
|
4361
|
-
if (cosine > bands.nearDuplicate) {
|
|
4418
|
+
if (cosine > bands.nearDuplicate && !sameFileChunkFamily(newLogicalKey, member.logicalKey)) {
|
|
4362
4419
|
const dir = direction(member, newId, newCreatedAt);
|
|
4363
4420
|
out.push({
|
|
4364
4421
|
...dir,
|
|
@@ -4370,7 +4427,7 @@ var leafLocalCandidates = (newId, newVector, newCreatedAt, newLogicalKey, newMet
|
|
|
4370
4427
|
});
|
|
4371
4428
|
continue;
|
|
4372
4429
|
}
|
|
4373
|
-
if (cosine > bands.conflictLow && (sameLogicalKeyFamily(newLogicalKey, member.logicalKey) || sharedMetadataTopics(newMetadata, member.metadata))) {
|
|
4430
|
+
if (cosine > bands.conflictLow && !sameFileChunkFamily(newLogicalKey, member.logicalKey) && (sameLogicalKeyFamily(newLogicalKey, member.logicalKey) || sharedMetadataTopics(newMetadata, member.metadata))) {
|
|
4374
4431
|
const dir = direction(member, newId, newCreatedAt);
|
|
4375
4432
|
out.push({
|
|
4376
4433
|
...dir,
|
|
@@ -4505,7 +4562,12 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4505
4562
|
supersedeDemotion: GRAPH_SUPERSEDE_DEMOTION
|
|
4506
4563
|
});
|
|
4507
4564
|
});
|
|
4508
|
-
const EDGE_KINDS = [
|
|
4565
|
+
const EDGE_KINDS = [
|
|
4566
|
+
"memory_supports",
|
|
4567
|
+
"memory_supersedes",
|
|
4568
|
+
"memory_contradicts",
|
|
4569
|
+
"code_calls"
|
|
4570
|
+
];
|
|
4509
4571
|
const EDGE_SOURCES = ["rule", "llm", "agent"];
|
|
4510
4572
|
const write = Effect26.fn("Store.write")(function* (input) {
|
|
4511
4573
|
if (input.content.includes("\x00")) {
|
|
@@ -4524,7 +4586,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4524
4586
|
content: input.content,
|
|
4525
4587
|
contentType: input.contentType ?? "text/plain",
|
|
4526
4588
|
createdAt: now,
|
|
4527
|
-
ttlSecs: input.ttlSecs ?? defaultTtlSecs,
|
|
4589
|
+
ttlSecs: input.ttlSecs === null ? null : input.ttlSecs ?? defaultTtlSecs,
|
|
4528
4590
|
namespace: input.namespace ?? "default",
|
|
4529
4591
|
metadata: metadataBlob
|
|
4530
4592
|
});
|
|
@@ -4542,7 +4604,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4542
4604
|
contentType: input.contentType ?? "text/plain",
|
|
4543
4605
|
state: "active",
|
|
4544
4606
|
createdAt: now,
|
|
4545
|
-
ttlSecs: input.ttlSecs ?? defaultTtlSecs,
|
|
4607
|
+
ttlSecs: input.ttlSecs === null ? null : input.ttlSecs ?? defaultTtlSecs,
|
|
4546
4608
|
namespace: input.namespace ?? "default",
|
|
4547
4609
|
metadata: metadataBlob ?? undefined,
|
|
4548
4610
|
embedding: undefined,
|
|
@@ -4586,7 +4648,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4586
4648
|
});
|
|
4587
4649
|
const searchFts5 = Effect26.fn("Store.searchFts5")(function* (query, namespace, limit, opts) {
|
|
4588
4650
|
const start = Date.now();
|
|
4589
|
-
const rows = yield* backend.ftsSearch(query, namespace, limit, opts?.topicKeys, modelConfig?.id);
|
|
4651
|
+
const rows = yield* backend.ftsSearch(query, namespace, limit, opts?.topicKeys, modelConfig?.id, opts?.contentType);
|
|
4590
4652
|
if (opts?.audit !== false) {
|
|
4591
4653
|
yield* logRetrieval(query, namespace, "fts", rows.length, start);
|
|
4592
4654
|
}
|
|
@@ -4629,7 +4691,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4629
4691
|
});
|
|
4630
4692
|
allowedMemoryIds = new Set(conceptRows.map((r) => r.memoryId));
|
|
4631
4693
|
}
|
|
4632
|
-
const rows = yield* backend.vectorSearch(query, namespace, limit, modelConfig, opts?.topicKeys);
|
|
4694
|
+
const rows = yield* backend.vectorSearch(query, namespace, limit, modelConfig, opts?.topicKeys, opts?.contentType);
|
|
4633
4695
|
const allowed = allowedMemoryIds;
|
|
4634
4696
|
const scopedRows = allowed !== undefined ? rows.filter((row) => allowed.has(row.id)) : rows;
|
|
4635
4697
|
if (opts?.audit !== false) {
|
|
@@ -4964,7 +5026,7 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4964
5026
|
});
|
|
4965
5027
|
return rows.map((row) => row.id);
|
|
4966
5028
|
});
|
|
4967
|
-
const flipToSupersededById = async (tx, memoryId, now) => {
|
|
5029
|
+
const flipToSupersededById = async (tx, memoryId, now, reason = "superseded") => {
|
|
4968
5030
|
const rs = await tx.update(memories2).set({ state: "superseded" }).where(and8(eq8(memories2.id, memoryId), eq8(memories2.state, "active")));
|
|
4969
5031
|
if (rs.rowsAffected === 0)
|
|
4970
5032
|
return null;
|
|
@@ -4973,11 +5035,106 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
4973
5035
|
eventType: "superseded",
|
|
4974
5036
|
fromState: "active",
|
|
4975
5037
|
toState: "superseded",
|
|
4976
|
-
reason
|
|
5038
|
+
reason,
|
|
4977
5039
|
createdAt: now
|
|
4978
5040
|
});
|
|
4979
5041
|
return memoryId;
|
|
4980
5042
|
};
|
|
5043
|
+
const reconcile = Effect26.fn("Store.reconcile")(function* (namespace, keyPrefix, keyRoot, walkedRoots, keptKeys) {
|
|
5044
|
+
const inDomain = (key) => {
|
|
5045
|
+
const rel = key.slice(keyPrefix.length).split("#")[0];
|
|
5046
|
+
const filePath = keyRoot === "/" ? `/${rel}` : `${keyRoot}/${rel}`;
|
|
5047
|
+
return walkedRoots.some((root) => filePath === root || filePath.startsWith(`${root}/`));
|
|
5048
|
+
};
|
|
5049
|
+
const owned = (key) => keptKeys.includes(key);
|
|
5050
|
+
const rows = yield* Effect26.tryPromise({
|
|
5051
|
+
try: () => db.select({
|
|
5052
|
+
id: memories2.id,
|
|
5053
|
+
logicalKey: memories2.logicalKey,
|
|
5054
|
+
embedding: memories2.embedding
|
|
5055
|
+
}).from(memories2).where(and8(eq8(memories2.namespace, namespace), eq8(memories2.state, "active"), like(memories2.logicalKey, `${keyPrefix}%`))),
|
|
5056
|
+
catch: (cause) => new StoreError({ message: `Store.reconcile: ${cause}` })
|
|
5057
|
+
});
|
|
5058
|
+
const vanished = rows.filter((r) => inDomain(r.logicalKey) && !owned(r.logicalKey));
|
|
5059
|
+
if (vanished.length > 0) {
|
|
5060
|
+
const now = Date.now();
|
|
5061
|
+
yield* Effect26.tryPromise({
|
|
5062
|
+
try: () => db.transaction(async (tx) => {
|
|
5063
|
+
for (const row of vanished) {
|
|
5064
|
+
await flipToSupersededById(tx, row.id, now, "source_removed");
|
|
5065
|
+
}
|
|
5066
|
+
}),
|
|
5067
|
+
catch: (cause) => new StoreError({ message: `Store.reconcile: ${cause}` })
|
|
5068
|
+
});
|
|
5069
|
+
}
|
|
5070
|
+
return vanished;
|
|
5071
|
+
});
|
|
5072
|
+
const writeSuperseding = Effect26.fn("Store.writeSuperseding")(function* (input) {
|
|
5073
|
+
if (input.content.includes("\x00")) {
|
|
5074
|
+
return yield* new StoreError({
|
|
5075
|
+
message: "Store.writeSuperseding: content contains a NUL byte (libSQL would silently truncate it)"
|
|
5076
|
+
});
|
|
5077
|
+
}
|
|
5078
|
+
const id = crypto.randomUUID();
|
|
5079
|
+
const now = Date.now();
|
|
5080
|
+
const metadataBlob = input.typedMetadata !== undefined ? mergeMetadataBlob(input.metadata, input.typedMetadata) : input.metadata ?? null;
|
|
5081
|
+
const namespace = input.namespace ?? "default";
|
|
5082
|
+
let supersededId;
|
|
5083
|
+
yield* Effect26.tryPromise({
|
|
5084
|
+
try: () => db.transaction(async (tx) => {
|
|
5085
|
+
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);
|
|
5086
|
+
const old = existing[0];
|
|
5087
|
+
if (old !== undefined) {
|
|
5088
|
+
await flipToSupersededById(tx, old.id, now);
|
|
5089
|
+
supersededId = old.id;
|
|
5090
|
+
}
|
|
5091
|
+
await tx.insert(memories2).values({
|
|
5092
|
+
id,
|
|
5093
|
+
logicalKey: input.logicalKey,
|
|
5094
|
+
content: input.content,
|
|
5095
|
+
contentType: input.contentType ?? "text/plain",
|
|
5096
|
+
createdAt: now,
|
|
5097
|
+
ttlSecs: input.ttlSecs === null ? null : input.ttlSecs ?? defaultTtlSecs,
|
|
5098
|
+
namespace,
|
|
5099
|
+
metadata: metadataBlob
|
|
5100
|
+
});
|
|
5101
|
+
await tx.insert(memoryEvents2).values({ memoryId: id, eventType: "created", createdAt: now });
|
|
5102
|
+
if (old !== undefined) {
|
|
5103
|
+
await tx.insert(artifactEdges).values({
|
|
5104
|
+
id: crypto.randomUUID(),
|
|
5105
|
+
fromMemoryId: old.id,
|
|
5106
|
+
toMemoryId: id,
|
|
5107
|
+
edgeKind: "memory_supersedes",
|
|
5108
|
+
weight: 1,
|
|
5109
|
+
status: "confirmed",
|
|
5110
|
+
source: "rule",
|
|
5111
|
+
confidence: 1,
|
|
5112
|
+
validAt: now,
|
|
5113
|
+
expiredAt: null,
|
|
5114
|
+
createdAt: now,
|
|
5115
|
+
updatedAt: now
|
|
5116
|
+
});
|
|
5117
|
+
}
|
|
5118
|
+
}),
|
|
5119
|
+
catch: (cause) => backend.isUniqueViolation(cause) ? new DuplicateActiveKey({ logicalKey: input.logicalKey, namespace }) : new StoreError({ message: `Store.writeSuperseding: ${cause}` })
|
|
5120
|
+
});
|
|
5121
|
+
return {
|
|
5122
|
+
memory: {
|
|
5123
|
+
id,
|
|
5124
|
+
logicalKey: input.logicalKey,
|
|
5125
|
+
content: input.content,
|
|
5126
|
+
contentType: input.contentType ?? "text/plain",
|
|
5127
|
+
state: "active",
|
|
5128
|
+
createdAt: now,
|
|
5129
|
+
ttlSecs: input.ttlSecs === null ? null : input.ttlSecs ?? defaultTtlSecs,
|
|
5130
|
+
namespace,
|
|
5131
|
+
metadata: metadataBlob ?? undefined,
|
|
5132
|
+
embedding: undefined,
|
|
5133
|
+
embeddingModel: undefined
|
|
5134
|
+
},
|
|
5135
|
+
...supersededId !== undefined ? { supersededId } : {}
|
|
5136
|
+
};
|
|
5137
|
+
});
|
|
4981
5138
|
const addEdge = Effect26.fn("Store.addEdge")(function* (input) {
|
|
4982
5139
|
if (input.fromMemoryId === input.toMemoryId) {
|
|
4983
5140
|
return yield* new StoreError({ message: "Store.addEdge: self-loops are not allowed" });
|
|
@@ -5030,7 +5187,12 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5030
5187
|
updatedAt: now
|
|
5031
5188
|
};
|
|
5032
5189
|
yield* Effect26.tryPromise({
|
|
5033
|
-
try: () => db.
|
|
5190
|
+
try: () => db.transaction(async (tx) => {
|
|
5191
|
+
await tx.insert(artifactEdges).values(row);
|
|
5192
|
+
if (input.confirmed && input.edgeKind === "memory_supersedes") {
|
|
5193
|
+
await flipToSupersededById(tx, input.fromMemoryId, now);
|
|
5194
|
+
}
|
|
5195
|
+
}),
|
|
5034
5196
|
catch: (cause) => {
|
|
5035
5197
|
if (backend.isUniqueViolation(cause)) {
|
|
5036
5198
|
return new EdgeExists({
|
|
@@ -5169,6 +5331,42 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5169
5331
|
}),
|
|
5170
5332
|
catch: (cause) => new StoreError({ message: `Store.writeCandidateEdge: ${cause}` })
|
|
5171
5333
|
});
|
|
5334
|
+
const reconcileRenameCandidates = Effect26.fn("Store.reconcileRenameCandidates")(function* (vanished, newUnitIds) {
|
|
5335
|
+
const withVectors = vanished.filter((v) => v.embedding !== null);
|
|
5336
|
+
if (withVectors.length === 0 || newUnitIds.length === 0)
|
|
5337
|
+
return 0;
|
|
5338
|
+
const newRows = yield* Effect26.tryPromise({
|
|
5339
|
+
try: () => db.select({ id: memories2.id, embedding: memories2.embedding }).from(memories2).where(and8(inArray4(memories2.id, newUnitIds))),
|
|
5340
|
+
catch: (cause) => new StoreError({ message: `Store.reconcileRenameCandidates: ${cause}` })
|
|
5341
|
+
});
|
|
5342
|
+
const newWithVectors = newRows.filter((r) => r.embedding !== null);
|
|
5343
|
+
if (newWithVectors.length === 0)
|
|
5344
|
+
return 0;
|
|
5345
|
+
const now = Date.now();
|
|
5346
|
+
let inserted = 0;
|
|
5347
|
+
for (const v of withVectors) {
|
|
5348
|
+
const vVec = Float32Array.from(v.embedding);
|
|
5349
|
+
for (const n of newWithVectors) {
|
|
5350
|
+
if (v.id === n.id)
|
|
5351
|
+
continue;
|
|
5352
|
+
const cosine = cosineSimilarity(vVec, Float32Array.from(n.embedding));
|
|
5353
|
+
if (cosine >= GRAPH_CONFLICT_BANDS.nearDuplicate) {
|
|
5354
|
+
const ok = yield* writeCandidateEdge({
|
|
5355
|
+
fromMemoryId: v.id,
|
|
5356
|
+
toMemoryId: n.id,
|
|
5357
|
+
edgeKind: "memory_supersedes",
|
|
5358
|
+
source: "rule",
|
|
5359
|
+
status: "pending",
|
|
5360
|
+
confidence: cosine,
|
|
5361
|
+
reason: "rename"
|
|
5362
|
+
}, now);
|
|
5363
|
+
if (ok)
|
|
5364
|
+
inserted += 1;
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5368
|
+
return inserted;
|
|
5369
|
+
});
|
|
5172
5370
|
const scanLeafCandidates = (memoryId, vector, topicKey, model) => Effect26.gen(function* () {
|
|
5173
5371
|
const memberRows = yield* Effect26.tryPromise({
|
|
5174
5372
|
try: () => db.select({ memoryId: topicMemberships.memoryId }).from(topicMemberships).where(and8(eq8(topicMemberships.topicKey, topicKey), eq8(topicMemberships.modelKey, model.id))).orderBy(asc5(topicMemberships.memoryId)),
|
|
@@ -5369,12 +5567,16 @@ var makeStore2 = (backend, modelConfig, topicsOptions, graphConfig, auditOptions
|
|
|
5369
5567
|
});
|
|
5370
5568
|
return {
|
|
5371
5569
|
write,
|
|
5570
|
+
writeSuperseding,
|
|
5571
|
+
reconcile,
|
|
5572
|
+
reconcileRenameCandidates,
|
|
5372
5573
|
get,
|
|
5373
5574
|
getByKey,
|
|
5374
5575
|
recency,
|
|
5375
5576
|
searchFts5,
|
|
5376
5577
|
searchVector,
|
|
5377
5578
|
logAudit,
|
|
5579
|
+
listSchema: () => backend.listSchema(),
|
|
5378
5580
|
supersede,
|
|
5379
5581
|
forget,
|
|
5380
5582
|
sweep,
|
|
@@ -5508,6 +5710,7 @@ __export(exports_graph, {
|
|
|
5508
5710
|
farthestPointSeeds: () => farthestPointSeeds,
|
|
5509
5711
|
dreamStateDefaults: () => dreamStateDefaults,
|
|
5510
5712
|
dreamState: () => dreamState,
|
|
5713
|
+
cosineSimilarity: () => cosineSimilarity,
|
|
5511
5714
|
conceptConfidence: () => conceptConfidence,
|
|
5512
5715
|
conceptClusterHandler: () => conceptClusterHandler,
|
|
5513
5716
|
clusterMembers: () => clusterMembers,
|
|
@@ -6261,7 +6464,7 @@ var MemoryUnit = Schema20.Struct({
|
|
|
6261
6464
|
contentType: Schema20.String,
|
|
6262
6465
|
state: MemoryState,
|
|
6263
6466
|
createdAt: Schema20.Number,
|
|
6264
|
-
ttlSecs: Schema20.Number,
|
|
6467
|
+
ttlSecs: Schema20.NullOr(Schema20.Number),
|
|
6265
6468
|
namespace: Schema20.String,
|
|
6266
6469
|
metadata: Schema20.optional(Schema20.String),
|
|
6267
6470
|
embedding: Schema20.optional(Schema20.Array(Schema20.Number)),
|
|
@@ -6272,7 +6475,7 @@ var WriteMemoryInput = Schema20.Struct({
|
|
|
6272
6475
|
content: Schema20.String,
|
|
6273
6476
|
contentType: Schema20.optional(Schema20.String),
|
|
6274
6477
|
namespace: Schema20.optional(Schema20.String),
|
|
6275
|
-
ttlSecs: Schema20.optional(Schema20.Number),
|
|
6478
|
+
ttlSecs: Schema20.optional(Schema20.NullOr(Schema20.Number)),
|
|
6276
6479
|
metadata: Schema20.optional(Schema20.String),
|
|
6277
6480
|
typedMetadata: Schema20.optional(MemoryMetadata)
|
|
6278
6481
|
});
|
|
@@ -6325,7 +6528,103 @@ class Service9 extends Context9.Service()("@dimple/embedder/EmbeddingModelRegist
|
|
|
6325
6528
|
}
|
|
6326
6529
|
// ../embedder/src/transformers.ts
|
|
6327
6530
|
import { Config as Config5, Effect as Effect32, Layer as Layer11 } from "effect";
|
|
6328
|
-
import {
|
|
6531
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
6532
|
+
import { join as join2 } from "node:path";
|
|
6533
|
+
import { pathToFileURL } from "node:url";
|
|
6534
|
+
|
|
6535
|
+
// ../embedder/src/auto-install.ts
|
|
6536
|
+
import { execFile } from "node:child_process";
|
|
6537
|
+
import { existsSync } from "node:fs";
|
|
6538
|
+
import { join } from "node:path";
|
|
6539
|
+
var detectPackageManager = (cwd) => {
|
|
6540
|
+
let dir = cwd;
|
|
6541
|
+
while (true) {
|
|
6542
|
+
if (existsSync(join(dir, "bun.lock")) || existsSync(join(dir, "bun.lockb"))) {
|
|
6543
|
+
return { pm: "bun", root: dir };
|
|
6544
|
+
}
|
|
6545
|
+
if (existsSync(join(dir, "pnpm-lock.yaml")))
|
|
6546
|
+
return { pm: "pnpm", root: dir };
|
|
6547
|
+
if (existsSync(join(dir, "yarn.lock")))
|
|
6548
|
+
return { pm: "yarn", root: dir };
|
|
6549
|
+
if (existsSync(join(dir, "package-lock.json")))
|
|
6550
|
+
return { pm: "npm", root: dir };
|
|
6551
|
+
const parent = join(dir, "..");
|
|
6552
|
+
if (parent === dir)
|
|
6553
|
+
return { pm: "bun", root: cwd };
|
|
6554
|
+
dir = parent;
|
|
6555
|
+
}
|
|
6556
|
+
};
|
|
6557
|
+
var installCommand = (pm) => {
|
|
6558
|
+
switch (pm) {
|
|
6559
|
+
case "bun":
|
|
6560
|
+
return ["bun", "add", "@huggingface/transformers"];
|
|
6561
|
+
case "npm":
|
|
6562
|
+
return [
|
|
6563
|
+
"npm",
|
|
6564
|
+
"install",
|
|
6565
|
+
"@huggingface/transformers",
|
|
6566
|
+
"--ignore-scripts",
|
|
6567
|
+
"--no-audit",
|
|
6568
|
+
"--no-fund"
|
|
6569
|
+
];
|
|
6570
|
+
case "pnpm":
|
|
6571
|
+
return ["pnpm", "add", "@huggingface/transformers", "--ignore-scripts"];
|
|
6572
|
+
case "yarn":
|
|
6573
|
+
return ["yarn", "add", "@huggingface/transformers", "--ignore-scripts"];
|
|
6574
|
+
}
|
|
6575
|
+
};
|
|
6576
|
+
var installTransformers = (cwd) => new Promise((resolve, reject) => {
|
|
6577
|
+
const target = detectPackageManager(cwd);
|
|
6578
|
+
const [cmd, ...args] = installCommand(target.pm);
|
|
6579
|
+
execFile(cmd, args, { cwd: target.root, encoding: "utf8" }, (error) => {
|
|
6580
|
+
if (error) {
|
|
6581
|
+
reject(new Error(`auto-install of @huggingface/transformers failed (${target.pm} add …): ${error.message} — ` + "run it manually or set `autoInstall: false` and configure a hosted embedding provider"));
|
|
6582
|
+
return;
|
|
6583
|
+
}
|
|
6584
|
+
resolve();
|
|
6585
|
+
});
|
|
6586
|
+
});
|
|
6587
|
+
|
|
6588
|
+
// ../embedder/src/transformers.ts
|
|
6589
|
+
var transformersEntryPath = (root) => {
|
|
6590
|
+
let dir = root;
|
|
6591
|
+
while (true) {
|
|
6592
|
+
const pkgJson = join2(dir, "node_modules", "@huggingface", "transformers", "package.json");
|
|
6593
|
+
if (existsSync2(pkgJson)) {
|
|
6594
|
+
let entry;
|
|
6595
|
+
try {
|
|
6596
|
+
const pkg = JSON.parse(readFileSync(pkgJson, "utf8"));
|
|
6597
|
+
const ex = pkg.exports;
|
|
6598
|
+
const dot4 = typeof ex === "object" ? ex["."] : ex;
|
|
6599
|
+
entry = typeof dot4 === "string" ? dot4 : dot4?.import ?? dot4?.default ?? pkg.module ?? pkg.main ?? "index.js";
|
|
6600
|
+
} catch {
|
|
6601
|
+
entry = "index.js";
|
|
6602
|
+
}
|
|
6603
|
+
return join2(dir, "node_modules", "@huggingface", "transformers", entry);
|
|
6604
|
+
}
|
|
6605
|
+
const parent = join2(dir, "..");
|
|
6606
|
+
if (parent === dir)
|
|
6607
|
+
return null;
|
|
6608
|
+
dir = parent;
|
|
6609
|
+
}
|
|
6610
|
+
};
|
|
6611
|
+
var importFromDisk = () => new Promise((resolve, reject) => {
|
|
6612
|
+
try {
|
|
6613
|
+
const root = detectPackageManager(process.cwd()).root;
|
|
6614
|
+
const entry = transformersEntryPath(root);
|
|
6615
|
+
if (entry === null) {
|
|
6616
|
+
reject(new Error("@huggingface/transformers not found on disk after install"));
|
|
6617
|
+
return;
|
|
6618
|
+
}
|
|
6619
|
+
import(pathToFileURL(entry).href).then((mod) => {
|
|
6620
|
+
resolve(mod);
|
|
6621
|
+
}).catch((cause) => {
|
|
6622
|
+
reject(cause);
|
|
6623
|
+
});
|
|
6624
|
+
} catch (cause) {
|
|
6625
|
+
reject(cause);
|
|
6626
|
+
}
|
|
6627
|
+
});
|
|
6329
6628
|
var defaults2 = {
|
|
6330
6629
|
modelId: "Xenova/all-MiniLM-L6-v2",
|
|
6331
6630
|
device: "cpu",
|
|
@@ -6333,14 +6632,31 @@ var defaults2 = {
|
|
|
6333
6632
|
pooling: "mean",
|
|
6334
6633
|
normalize: true
|
|
6335
6634
|
};
|
|
6336
|
-
var
|
|
6635
|
+
var make5 = (options) => {
|
|
6337
6636
|
let pipe = null;
|
|
6338
6637
|
const getPipeline = Effect32.fnUntraced(function* () {
|
|
6339
6638
|
if (pipe)
|
|
6340
6639
|
return pipe;
|
|
6640
|
+
const loadModule = () => Effect32.tryPromise(() => import("@huggingface/transformers"));
|
|
6641
|
+
let transformers = yield* loadModule().pipe(Effect32.catch(() => {
|
|
6642
|
+
if (options.autoInstall === false) {
|
|
6643
|
+
return Effect32.fail(new EmbeddingError({
|
|
6644
|
+
message: "@huggingface/transformers is not installed — run `bun add @huggingface/transformers` " + "to use local embeddings (or configure a hosted embedding provider)"
|
|
6645
|
+
}));
|
|
6646
|
+
}
|
|
6647
|
+
return Effect32.gen(function* () {
|
|
6648
|
+
yield* Effect32.logInfo("auto-installing @huggingface/transformers (first local-embed use — scripts skipped)").pipe(Effect32.annotateLogs({ scope: "@dimple/embedder", event: "embedder.auto-install" }));
|
|
6649
|
+
yield* Effect32.tryPromise(() => installTransformers(process.cwd())).pipe(Effect32.timeout("5 minutes"), Effect32.catch((cause) => Effect32.fail(new EmbeddingError({
|
|
6650
|
+
message: cause._tag === "TimeoutError" ? "auto-install of @huggingface/transformers timed out (5 minutes) — run " + "`bun add @huggingface/transformers` manually" : cause.cause instanceof Error ? cause.cause.message : cause instanceof Error ? cause.message : `auto-install failed: ${String(cause)}`
|
|
6651
|
+
}))));
|
|
6652
|
+
return yield* Effect32.tryPromise(importFromDisk).pipe(Effect32.mapError(() => new EmbeddingError({
|
|
6653
|
+
message: "@huggingface/transformers still unavailable after auto-install — run `bun add " + "@huggingface/transformers` manually (or set `autoInstall: false` and configure a hosted embedding provider)"
|
|
6654
|
+
})));
|
|
6655
|
+
});
|
|
6656
|
+
}));
|
|
6341
6657
|
if (options.cacheDir)
|
|
6342
|
-
env.cacheDir = options.cacheDir;
|
|
6343
|
-
pipe = yield* Effect32.
|
|
6658
|
+
transformers.env.cacheDir = options.cacheDir;
|
|
6659
|
+
pipe = yield* Effect32.tryPromise(() => transformers.pipeline("feature-extraction", options.modelId ?? defaults2.modelId, {
|
|
6344
6660
|
device: options.device ?? defaults2.device,
|
|
6345
6661
|
dtype: options.dtype ?? defaults2.dtype
|
|
6346
6662
|
})).pipe(Effect32.mapError((cause) => new EmbeddingError({ message: `load model: ${cause}` })));
|
|
@@ -6386,7 +6702,7 @@ var make6 = (options) => {
|
|
|
6386
6702
|
return { embed, embedSingle };
|
|
6387
6703
|
};
|
|
6388
6704
|
var makeTransformersModel = (options = {}) => {
|
|
6389
|
-
const impl =
|
|
6705
|
+
const impl = make5(options);
|
|
6390
6706
|
return {
|
|
6391
6707
|
modelId: options.modelId ?? "local-minilm",
|
|
6392
6708
|
provider: "transformers",
|
|
@@ -6517,7 +6833,7 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6517
6833
|
const namespace = options2?.namespace ?? "default";
|
|
6518
6834
|
const limit = options2?.limit ?? defaultLimit;
|
|
6519
6835
|
const k = options2?.k ?? defaultK;
|
|
6520
|
-
const profile = typeof options2?.profile === "string" ? {} : options2?.profile ?? {};
|
|
6836
|
+
const profile = typeof options2?.profile === "string" ? options2.profile === "keyword" ? { modeWeights: { vector: 0, fts: 1 } } : options2.profile === "semantic" ? { modeWeights: { vector: 1, fts: 0 } } : {} : options2?.profile ?? {};
|
|
6521
6837
|
const topicKeys = options2?.topics?.topicKeys;
|
|
6522
6838
|
const fetchMultiplier = 2;
|
|
6523
6839
|
const start = Date.now();
|
|
@@ -6529,21 +6845,24 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6529
6845
|
vectorOpts.conceptIds = profile.conceptFilter;
|
|
6530
6846
|
const vectorResults = yield* store.searchVector([...embedding], namespace, limit * fetchMultiplier, {
|
|
6531
6847
|
...vectorOpts,
|
|
6848
|
+
...options2?.contentType !== undefined ? { contentType: options2.contentType } : {},
|
|
6532
6849
|
audit: false
|
|
6533
6850
|
}).pipe(wrapError("searchVector"));
|
|
6534
6851
|
const fts5Results = yield* store.searchFts5(query2, namespace, limit * fetchMultiplier, {
|
|
6535
6852
|
...topicKeys !== undefined ? { topicKeys } : {},
|
|
6853
|
+
...options2?.contentType !== undefined ? { contentType: options2.contentType } : {},
|
|
6536
6854
|
audit: false
|
|
6537
6855
|
}).pipe(wrapError("searchFts5"));
|
|
6538
6856
|
const vWeight = profile.modeWeights?.vector ?? 1;
|
|
6539
6857
|
const fWeight = profile.modeWeights?.fts ?? 1;
|
|
6858
|
+
const mode = vWeight === 0 && fWeight > 0 ? "keyword" : fWeight === 0 && vWeight > 0 ? "semantic" : "hybrid";
|
|
6540
6859
|
const denseRanks = vectorResults.length > 0 ? vectorResults.map((s) => [s.memory.id, s.score * vWeight]) : null;
|
|
6541
6860
|
const fts5Ranks = fts5Results.length > 0 ? fts5Results.map((s) => [s.memory.id, s.score * fWeight]) : null;
|
|
6542
6861
|
if (!denseRanks && !fts5Ranks) {
|
|
6543
6862
|
yield* store.logAudit({
|
|
6544
6863
|
query: query2,
|
|
6545
6864
|
namespace,
|
|
6546
|
-
mode
|
|
6865
|
+
mode,
|
|
6547
6866
|
resultCount: 0,
|
|
6548
6867
|
startTime: start,
|
|
6549
6868
|
queryProfile: JSON.stringify({
|
|
@@ -6551,6 +6870,7 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6551
6870
|
recencyBoost: profile.recencyBoost ?? 0,
|
|
6552
6871
|
conceptFilter: profile.conceptFilter,
|
|
6553
6872
|
topicKeys,
|
|
6873
|
+
contentType: options2?.contentType,
|
|
6554
6874
|
legs: { vector: { count: 0, topScores: [] }, fts: { count: 0, topScores: [] } }
|
|
6555
6875
|
}),
|
|
6556
6876
|
sources: JSON.stringify({ vector: [], fts: [] })
|
|
@@ -6593,7 +6913,7 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6593
6913
|
yield* store.logAudit({
|
|
6594
6914
|
query: query2,
|
|
6595
6915
|
namespace,
|
|
6596
|
-
mode
|
|
6916
|
+
mode,
|
|
6597
6917
|
resultCount: results.length,
|
|
6598
6918
|
startTime: start,
|
|
6599
6919
|
queryProfile: JSON.stringify({
|
|
@@ -6601,6 +6921,7 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6601
6921
|
recencyBoost: profile.recencyBoost ?? 0,
|
|
6602
6922
|
conceptFilter: profile.conceptFilter,
|
|
6603
6923
|
topicKeys,
|
|
6924
|
+
contentType: options2?.contentType,
|
|
6604
6925
|
legs: {
|
|
6605
6926
|
vector: {
|
|
6606
6927
|
count: vectorResults.length,
|
|
@@ -6617,9 +6938,10 @@ var layer11 = (options) => Layer13.effect(Service10, Effect35.gen(function* () {
|
|
|
6617
6938
|
fts: fts5Results.map((s) => s.memory.id)
|
|
6618
6939
|
})
|
|
6619
6940
|
}).pipe(wrapError("logAudit"));
|
|
6620
|
-
yield* Effect35.
|
|
6941
|
+
yield* Effect35.logInfo("hybrid.search").pipe(Effect35.annotateLogs({
|
|
6621
6942
|
scope: "@dimple/retriever",
|
|
6622
6943
|
event: "hybrid.search",
|
|
6944
|
+
mode,
|
|
6623
6945
|
namespace,
|
|
6624
6946
|
query: query2,
|
|
6625
6947
|
resultCount: results.length
|
|
@@ -6861,7 +7183,8 @@ var embedderFromConfig = (model) => model.provider === "transformers" ? Effect39
|
|
|
6861
7183
|
...model.dtype !== undefined ? { dtype: model.dtype } : {},
|
|
6862
7184
|
...model.pooling !== undefined ? { pooling: model.pooling } : {},
|
|
6863
7185
|
...model.normalize !== undefined ? { normalize: model.normalize } : {},
|
|
6864
|
-
...model.cacheDir !== undefined ? { cacheDir: model.cacheDir } : {}
|
|
7186
|
+
...model.cacheDir !== undefined ? { cacheDir: model.cacheDir } : {},
|
|
7187
|
+
...model.autoInstall !== undefined ? { autoInstall: model.autoInstall } : {}
|
|
6865
7188
|
})) : model.provider === "openai" ? model.apiKey === undefined ? Effect39.fail(new EmbeddingError({ message: `OpenAI model ${model.id} requires an apiKey` })) : Effect39.succeed(makeHostedEmbeddingModel({
|
|
6866
7189
|
modelId: model.id,
|
|
6867
7190
|
model: model.model,
|
|
@@ -7042,7 +7365,8 @@ var ExtractedChunk = Schema25.Struct({
|
|
|
7042
7365
|
startLine: Schema25.Number,
|
|
7043
7366
|
endLine: Schema25.Number,
|
|
7044
7367
|
language: Schema25.String,
|
|
7045
|
-
docstring: Schema25.optional(Schema25.String)
|
|
7368
|
+
docstring: Schema25.optional(Schema25.String),
|
|
7369
|
+
calls: Schema25.optional(Schema25.Array(Schema25.Struct({ name: Schema25.String, line: Schema25.Number })))
|
|
7046
7370
|
});
|
|
7047
7371
|
var ImportInfo = Schema25.Struct({
|
|
7048
7372
|
source: Schema25.String,
|
|
@@ -7126,6 +7450,7 @@ function emit(source, semantic, filePath, lang, chunks) {
|
|
|
7126
7450
|
}
|
|
7127
7451
|
function makeChunk(source, _semantic, filePath, lang, kind, name, docstring, parentClass) {
|
|
7128
7452
|
const id = parentClass ? `${filePath}:${parentClass}.${name}:${source.startPosition.row + 1}` : `${filePath}:${name}:${source.startPosition.row + 1}`;
|
|
7453
|
+
const calls = callsOf(source);
|
|
7129
7454
|
return {
|
|
7130
7455
|
id,
|
|
7131
7456
|
filePath,
|
|
@@ -7135,9 +7460,49 @@ function makeChunk(source, _semantic, filePath, lang, kind, name, docstring, par
|
|
|
7135
7460
|
startLine: source.startPosition.row + 1,
|
|
7136
7461
|
endLine: source.endPosition.row + 1,
|
|
7137
7462
|
language: lang,
|
|
7138
|
-
docstring
|
|
7463
|
+
docstring,
|
|
7464
|
+
...calls.length > 0 ? { calls } : {}
|
|
7139
7465
|
};
|
|
7140
7466
|
}
|
|
7467
|
+
function callsOf(node) {
|
|
7468
|
+
const out = [];
|
|
7469
|
+
const calleeName = (n) => {
|
|
7470
|
+
let cur = n;
|
|
7471
|
+
for (let guard = 0;guard < 4; guard++) {
|
|
7472
|
+
if (cur.type === "identifier")
|
|
7473
|
+
return cur.text;
|
|
7474
|
+
if (cur.type === "member_expression") {
|
|
7475
|
+
const prop = cur.childForFieldName("property");
|
|
7476
|
+
if (prop === null)
|
|
7477
|
+
return;
|
|
7478
|
+
cur = prop;
|
|
7479
|
+
continue;
|
|
7480
|
+
}
|
|
7481
|
+
if (cur.type === "non_null_expression" || cur.type === "parenthesized_expression") {
|
|
7482
|
+
const inner = cur.namedChildren[0];
|
|
7483
|
+
if (inner === undefined)
|
|
7484
|
+
return;
|
|
7485
|
+
cur = inner;
|
|
7486
|
+
continue;
|
|
7487
|
+
}
|
|
7488
|
+
return;
|
|
7489
|
+
}
|
|
7490
|
+
return;
|
|
7491
|
+
};
|
|
7492
|
+
const visit = (n) => {
|
|
7493
|
+
if (n.type === "call_expression") {
|
|
7494
|
+
const callee = n.childForFieldName("function");
|
|
7495
|
+
const name = callee === null ? undefined : calleeName(callee);
|
|
7496
|
+
if (name !== undefined && name.length > 0) {
|
|
7497
|
+
out.push({ name, line: n.startPosition.row + 1 });
|
|
7498
|
+
}
|
|
7499
|
+
}
|
|
7500
|
+
for (const child of n.namedChildren)
|
|
7501
|
+
visit(child);
|
|
7502
|
+
};
|
|
7503
|
+
visit(node);
|
|
7504
|
+
return out;
|
|
7505
|
+
}
|
|
7141
7506
|
function unwrap2(node) {
|
|
7142
7507
|
for (const child of node.namedChildren) {
|
|
7143
7508
|
if (child.type !== "decorator" && child.type !== "comment")
|
|
@@ -7613,11 +7978,11 @@ class Service15 extends Context15.Service()("@dimple/wasm/WasmDownloader") {
|
|
|
7613
7978
|
}
|
|
7614
7979
|
// ../wasm/src/wasm-cache.ts
|
|
7615
7980
|
import { Context as Context16, Effect as Effect43, Layer as Layer20 } from "effect";
|
|
7616
|
-
import { existsSync as
|
|
7617
|
-
import { join as
|
|
7981
|
+
import { existsSync as existsSync3, mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
7982
|
+
import { join as join3 } from "node:path";
|
|
7618
7983
|
|
|
7619
7984
|
// ../../node_modules/.bun/env-paths@4.0.0/node_modules/env-paths/index.js
|
|
7620
|
-
import
|
|
7985
|
+
import path from "node:path";
|
|
7621
7986
|
import os from "node:os";
|
|
7622
7987
|
import process2 from "node:process";
|
|
7623
7988
|
|
|
@@ -7657,36 +8022,36 @@ function assertSafeFilename(filename) {
|
|
|
7657
8022
|
// ../../node_modules/.bun/env-paths@4.0.0/node_modules/env-paths/index.js
|
|
7658
8023
|
var homedir = os.homedir();
|
|
7659
8024
|
var tmpdir = os.tmpdir();
|
|
7660
|
-
var { env
|
|
8025
|
+
var { env } = process2;
|
|
7661
8026
|
var macos = (name) => {
|
|
7662
|
-
const library =
|
|
8027
|
+
const library = path.join(homedir, "Library");
|
|
7663
8028
|
return {
|
|
7664
|
-
data:
|
|
7665
|
-
config:
|
|
7666
|
-
cache:
|
|
7667
|
-
log:
|
|
7668
|
-
temp:
|
|
8029
|
+
data: path.join(library, "Application Support", name),
|
|
8030
|
+
config: path.join(library, "Preferences", name),
|
|
8031
|
+
cache: path.join(library, "Caches", name),
|
|
8032
|
+
log: path.join(library, "Logs", name),
|
|
8033
|
+
temp: path.join(tmpdir, name)
|
|
7669
8034
|
};
|
|
7670
8035
|
};
|
|
7671
8036
|
var windows = (name) => {
|
|
7672
|
-
const appData =
|
|
7673
|
-
const localAppData =
|
|
8037
|
+
const appData = env.APPDATA || path.join(homedir, "AppData", "Roaming");
|
|
8038
|
+
const localAppData = env.LOCALAPPDATA || path.join(homedir, "AppData", "Local");
|
|
7674
8039
|
return {
|
|
7675
|
-
data:
|
|
7676
|
-
config:
|
|
7677
|
-
cache:
|
|
7678
|
-
log:
|
|
7679
|
-
temp:
|
|
8040
|
+
data: path.join(localAppData, name, "Data"),
|
|
8041
|
+
config: path.join(appData, name, "Config"),
|
|
8042
|
+
cache: path.join(localAppData, name, "Cache"),
|
|
8043
|
+
log: path.join(localAppData, name, "Log"),
|
|
8044
|
+
temp: path.join(tmpdir, name)
|
|
7680
8045
|
};
|
|
7681
8046
|
};
|
|
7682
8047
|
var linux = (name) => {
|
|
7683
|
-
const username =
|
|
8048
|
+
const username = path.basename(homedir);
|
|
7684
8049
|
return {
|
|
7685
|
-
data:
|
|
7686
|
-
config:
|
|
7687
|
-
cache:
|
|
7688
|
-
log:
|
|
7689
|
-
temp:
|
|
8050
|
+
data: path.join(env.XDG_DATA_HOME || path.join(homedir, ".local", "share"), name),
|
|
8051
|
+
config: path.join(env.XDG_CONFIG_HOME || path.join(homedir, ".config"), name),
|
|
8052
|
+
cache: path.join(env.XDG_CACHE_HOME || path.join(homedir, ".cache"), name),
|
|
8053
|
+
log: path.join(env.XDG_STATE_HOME || path.join(homedir, ".local", "state"), name),
|
|
8054
|
+
temp: path.join(tmpdir, username, name)
|
|
7690
8055
|
};
|
|
7691
8056
|
};
|
|
7692
8057
|
function envPaths(name, { suffix = "nodejs" } = {}) {
|
|
@@ -7711,19 +8076,19 @@ class Service16 extends Context16.Service()("@dimple/wasm/WasmCache") {
|
|
|
7711
8076
|
}
|
|
7712
8077
|
var layer16 = Layer20.effect(Service16, Effect43.succeed(Service16.of({
|
|
7713
8078
|
ensure: Effect43.fn("WasmCache.ensure")(function* (lang, version, download) {
|
|
7714
|
-
const versionDir =
|
|
7715
|
-
const finalPath =
|
|
8079
|
+
const versionDir = join3(paths.cache, "tree-sitter", lang, version);
|
|
8080
|
+
const finalPath = join3(versionDir, "parser.wasm");
|
|
7716
8081
|
const exists = yield* Effect43.try({
|
|
7717
|
-
try: () =>
|
|
8082
|
+
try: () => existsSync3(finalPath),
|
|
7718
8083
|
catch: (cause) => new WasmCacheError({ message: `Failed to stat ${finalPath}`, cause })
|
|
7719
8084
|
});
|
|
7720
8085
|
if (exists)
|
|
7721
8086
|
return finalPath;
|
|
7722
8087
|
yield* Effect43.try({
|
|
7723
|
-
try: () =>
|
|
8088
|
+
try: () => mkdirSync(versionDir, { recursive: true }),
|
|
7724
8089
|
catch: (cause) => new WasmCacheError({ message: `Failed to create ${versionDir}`, cause })
|
|
7725
8090
|
});
|
|
7726
|
-
const tempPath =
|
|
8091
|
+
const tempPath = join3(versionDir, `.tmp-${process.pid}`);
|
|
7727
8092
|
const wasm = yield* download;
|
|
7728
8093
|
yield* Effect43.try({
|
|
7729
8094
|
try: () => writeFileSync(tempPath, wasm),
|
|
@@ -7738,7 +8103,7 @@ var layer16 = Layer20.effect(Service16, Effect43.succeed(Service16.of({
|
|
|
7738
8103
|
}).pipe(Effect43.catchCause(() => Effect43.succeed(false)));
|
|
7739
8104
|
if (!renamed) {
|
|
7740
8105
|
const existsAfter = yield* Effect43.try({
|
|
7741
|
-
try: () =>
|
|
8106
|
+
try: () => existsSync3(finalPath),
|
|
7742
8107
|
catch: (cause) => new WasmCacheError({ message: `Failed to stat ${finalPath}`, cause })
|
|
7743
8108
|
});
|
|
7744
8109
|
if (!existsAfter) {
|
|
@@ -7769,12 +8134,12 @@ var layer17 = Layer21.effect(Service17, Effect44.gen(function* () {
|
|
|
7769
8134
|
message: `Failed to download grammar for: ${lang}`,
|
|
7770
8135
|
cause
|
|
7771
8136
|
})));
|
|
7772
|
-
const
|
|
8137
|
+
const path2 = yield* cache.ensure(lang, metadata.version, Effect44.succeed(wasmBytes)).pipe(Effect44.mapError((cause) => new GrammarProvisionError({
|
|
7773
8138
|
language: lang,
|
|
7774
8139
|
message: `Failed to provision grammar for: ${lang}`,
|
|
7775
8140
|
cause
|
|
7776
8141
|
})));
|
|
7777
|
-
return
|
|
8142
|
+
return path2;
|
|
7778
8143
|
});
|
|
7779
8144
|
return Service17.of({ ensure });
|
|
7780
8145
|
}));
|
|
@@ -7893,11 +8258,27 @@ class DuplicateEdgeError extends Schema33.TaggedErrorClass()("Sdk.DuplicateEdge"
|
|
|
7893
8258
|
}) {
|
|
7894
8259
|
}
|
|
7895
8260
|
|
|
8261
|
+
class EdgeNotFoundError extends Schema33.TaggedErrorClass()("Sdk.EdgeNotFound", {
|
|
8262
|
+
id: Schema33.optional(Schema33.String),
|
|
8263
|
+
message: Schema33.String
|
|
8264
|
+
}) {
|
|
8265
|
+
}
|
|
8266
|
+
|
|
7896
8267
|
class StoreFailure extends Schema33.TaggedErrorClass()("Sdk.StoreFailure", {
|
|
7897
8268
|
message: Schema33.String
|
|
7898
8269
|
}) {
|
|
7899
8270
|
}
|
|
7900
8271
|
|
|
8272
|
+
class ReloadError extends Schema33.TaggedErrorClass()("Sdk.Reload", {
|
|
8273
|
+
message: Schema33.String
|
|
8274
|
+
}) {
|
|
8275
|
+
}
|
|
8276
|
+
|
|
8277
|
+
class EmbeddingFailure extends Schema33.TaggedErrorClass()("Sdk.Embedding", {
|
|
8278
|
+
message: Schema33.String
|
|
8279
|
+
}) {
|
|
8280
|
+
}
|
|
8281
|
+
|
|
7901
8282
|
class InputError extends Schema33.TaggedErrorClass()("Sdk.InputError", {
|
|
7902
8283
|
message: Schema33.String
|
|
7903
8284
|
}) {
|
|
@@ -7919,12 +8300,14 @@ var messageOf = (error) => {
|
|
|
7919
8300
|
}
|
|
7920
8301
|
};
|
|
7921
8302
|
var remapError = (error) => {
|
|
7922
|
-
if (error instanceof ConfigError || error instanceof NotFoundError || error instanceof DuplicateKeyError || error instanceof DuplicateEdgeError || error instanceof LLMNotConfiguredError || error instanceof JobFailedError || error instanceof StoreFailure || error instanceof InputError) {
|
|
8303
|
+
if (error instanceof ConfigError || error instanceof NotFoundError || error instanceof DuplicateKeyError || error instanceof DuplicateEdgeError || error instanceof EdgeNotFoundError || error instanceof LLMNotConfiguredError || error instanceof JobFailedError || error instanceof EmbeddingFailure || error instanceof StoreFailure || error instanceof ReloadError || error instanceof InputError) {
|
|
7923
8304
|
return error;
|
|
7924
8305
|
}
|
|
7925
8306
|
const message = messageOf(error);
|
|
7926
8307
|
if (error instanceof CoreConfigError)
|
|
7927
8308
|
return new ConfigError({ message });
|
|
8309
|
+
if (error instanceof EmbeddingError)
|
|
8310
|
+
return new EmbeddingFailure({ message });
|
|
7928
8311
|
if (error instanceof NotFound) {
|
|
7929
8312
|
return new NotFoundError({
|
|
7930
8313
|
...error.id !== undefined ? { id: error.id } : {},
|
|
@@ -7946,6 +8329,12 @@ var remapError = (error) => {
|
|
|
7946
8329
|
message: `Edge already exists: ${error.fromMemoryId} → ${error.toMemoryId} (${error.edgeKind})`
|
|
7947
8330
|
});
|
|
7948
8331
|
}
|
|
8332
|
+
if (error instanceof exports_graph.EdgeNotFound) {
|
|
8333
|
+
return new EdgeNotFoundError({
|
|
8334
|
+
...error.id !== undefined ? { id: error.id } : {},
|
|
8335
|
+
message: `Edge not found: ${error.id ?? "unknown id"}`
|
|
8336
|
+
});
|
|
8337
|
+
}
|
|
7949
8338
|
if (error instanceof JobFailed || error instanceof JobTimeout || error instanceof JobCancelled) {
|
|
7950
8339
|
return message.includes("LLM not configured") ? new LLMNotConfiguredError({ message }) : new JobFailedError({ message });
|
|
7951
8340
|
}
|
|
@@ -7962,8 +8351,9 @@ var configLayerFromInput = (input) => Layer25.effect(Service4, resolveConfigInpu
|
|
|
7962
8351
|
import { Cause as Cause5, Effect as Effect49, Exit as Exit6 } from "effect";
|
|
7963
8352
|
|
|
7964
8353
|
// src/indexer.ts
|
|
7965
|
-
import {
|
|
7966
|
-
import {
|
|
8354
|
+
import { execFileSync } from "node:child_process";
|
|
8355
|
+
import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
8356
|
+
import { basename, dirname, extname, join as join4, resolve, sep } from "node:path";
|
|
7967
8357
|
var INDEXABLE_EXTENSIONS = [
|
|
7968
8358
|
".ts",
|
|
7969
8359
|
".mts",
|
|
@@ -8000,52 +8390,68 @@ var LANGUAGE_BY_EXTENSION = {
|
|
|
8000
8390
|
".cjs": "javascript",
|
|
8001
8391
|
".jsx": "jsx"
|
|
8002
8392
|
};
|
|
8003
|
-
var languageForPath = (
|
|
8393
|
+
var languageForPath = (path2) => LANGUAGE_BY_EXTENSION[extname(path2)];
|
|
8004
8394
|
var walkFiles = (paths2, extensions) => {
|
|
8005
8395
|
const extensionSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
8006
8396
|
const files = [];
|
|
8007
8397
|
const errors3 = [];
|
|
8008
8398
|
let unsupported = 0;
|
|
8009
|
-
const
|
|
8010
|
-
const
|
|
8399
|
+
const resolved = paths2.map((p) => resolve(p));
|
|
8400
|
+
const root = commonRoot([...resolved, process.cwd()]);
|
|
8401
|
+
const visit = (path2) => {
|
|
8011
8402
|
let stat;
|
|
8012
8403
|
try {
|
|
8013
|
-
stat =
|
|
8404
|
+
stat = statSync(path2);
|
|
8014
8405
|
} catch (cause) {
|
|
8015
|
-
errors3.push({ filePath:
|
|
8406
|
+
errors3.push({ filePath: path2, message: `stat failed: ${messageOf2(cause)}` });
|
|
8016
8407
|
return;
|
|
8017
8408
|
}
|
|
8018
8409
|
if (stat.isDirectory()) {
|
|
8019
|
-
const name = basename(
|
|
8410
|
+
const name = basename(path2);
|
|
8020
8411
|
if (EXCLUDED_DIRS.has(name))
|
|
8021
8412
|
return;
|
|
8022
8413
|
let entries;
|
|
8023
8414
|
try {
|
|
8024
|
-
entries = readdirSync(
|
|
8415
|
+
entries = readdirSync(path2);
|
|
8025
8416
|
} catch (cause) {
|
|
8026
|
-
errors3.push({ filePath:
|
|
8417
|
+
errors3.push({ filePath: path2, message: `readdir failed: ${messageOf2(cause)}` });
|
|
8027
8418
|
return;
|
|
8028
8419
|
}
|
|
8029
8420
|
for (const entry of entries)
|
|
8030
|
-
visit(
|
|
8421
|
+
visit(join4(path2, entry));
|
|
8031
8422
|
return;
|
|
8032
8423
|
}
|
|
8033
8424
|
if (!stat.isFile())
|
|
8034
8425
|
return;
|
|
8035
|
-
if (!extensionSet.has(extname(
|
|
8426
|
+
if (!extensionSet.has(extname(path2))) {
|
|
8036
8427
|
unsupported += 1;
|
|
8037
8428
|
return;
|
|
8038
8429
|
}
|
|
8039
|
-
files.push(
|
|
8430
|
+
files.push(path2);
|
|
8040
8431
|
};
|
|
8041
|
-
for (const
|
|
8042
|
-
visit(
|
|
8043
|
-
return { files, unsupported, errors: errors3, root };
|
|
8432
|
+
for (const path2 of resolved)
|
|
8433
|
+
visit(path2);
|
|
8434
|
+
return { files, unsupported, errors: errors3, root, roots: resolved };
|
|
8044
8435
|
};
|
|
8045
|
-
var readCapped = (
|
|
8046
|
-
const text4 = readFileSync2(
|
|
8436
|
+
var readCapped = (path2, maxBytes) => {
|
|
8437
|
+
const text4 = readFileSync2(path2, "utf8");
|
|
8047
8438
|
return text4.length > maxBytes ? text4.slice(0, maxBytes) : text4;
|
|
8048
8439
|
};
|
|
8440
|
+
var currentCommit = (firstFile) => {
|
|
8441
|
+
if (firstFile === undefined)
|
|
8442
|
+
return null;
|
|
8443
|
+
try {
|
|
8444
|
+
const out = execFileSync("git", ["rev-parse", "HEAD"], {
|
|
8445
|
+
cwd: dirname(firstFile),
|
|
8446
|
+
encoding: "utf8",
|
|
8447
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8448
|
+
});
|
|
8449
|
+
const sha = out.trim();
|
|
8450
|
+
return /^[0-9a-f]{7,40}$/.test(sha) ? sha : null;
|
|
8451
|
+
} catch {
|
|
8452
|
+
return null;
|
|
8453
|
+
}
|
|
8454
|
+
};
|
|
8049
8455
|
var resolveImportTarget = (fromDir, specifier, extensions) => {
|
|
8050
8456
|
if (!specifier.startsWith("."))
|
|
8051
8457
|
return;
|
|
@@ -8053,11 +8459,11 @@ var resolveImportTarget = (fromDir, specifier, extensions) => {
|
|
|
8053
8459
|
const candidates2 = [
|
|
8054
8460
|
base,
|
|
8055
8461
|
...extensions.map((e) => base + e),
|
|
8056
|
-
...extensions.map((e) =>
|
|
8462
|
+
...extensions.map((e) => join4(base, `index${e}`))
|
|
8057
8463
|
];
|
|
8058
8464
|
for (const candidate of candidates2) {
|
|
8059
8465
|
try {
|
|
8060
|
-
if (
|
|
8466
|
+
if (existsSync4(candidate) && statSync(candidate).isFile())
|
|
8061
8467
|
return candidate;
|
|
8062
8468
|
} catch {
|
|
8063
8469
|
return;
|
|
@@ -8068,7 +8474,7 @@ var resolveImportTarget = (fromDir, specifier, extensions) => {
|
|
|
8068
8474
|
var resolveImports = (filePath, sources, extensions) => {
|
|
8069
8475
|
const targets = [];
|
|
8070
8476
|
for (const source of sources) {
|
|
8071
|
-
const target = resolveImportTarget(
|
|
8477
|
+
const target = resolveImportTarget(dirname(filePath), source, extensions);
|
|
8072
8478
|
if (target !== undefined)
|
|
8073
8479
|
targets.push(target);
|
|
8074
8480
|
}
|
|
@@ -8098,16 +8504,11 @@ var keyForPath = (root, filePath) => {
|
|
|
8098
8504
|
var messageOf2 = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
8099
8505
|
|
|
8100
8506
|
// src/dimple.ts
|
|
8101
|
-
var makeFacade = (
|
|
8102
|
-
|
|
8103
|
-
const
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
}
|
|
8107
|
-
return runtime.runPromise(effect.pipe(Effect49.mapError(remapError))).catch((cause) => {
|
|
8108
|
-
return Promise.reject(remapError(cause));
|
|
8109
|
-
});
|
|
8110
|
-
};
|
|
8507
|
+
var makeFacade = (state, reload, dispose) => {
|
|
8508
|
+
const run = state.run;
|
|
8509
|
+
const core = () => state.core();
|
|
8510
|
+
const parser = () => state.parser();
|
|
8511
|
+
const extractor = () => state.extractor();
|
|
8111
8512
|
const validateQueryOptions = (options) => {
|
|
8112
8513
|
const limit = options?.limit;
|
|
8113
8514
|
if (limit !== undefined && (!Number.isInteger(limit) || limit < 0)) {
|
|
@@ -8119,6 +8520,23 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8119
8520
|
if (k !== undefined && (!Number.isInteger(k) || k < 0)) {
|
|
8120
8521
|
return new InputError({ message: `query: k must be a non-negative integer (got ${k})` });
|
|
8121
8522
|
}
|
|
8523
|
+
const budget = options?.budget;
|
|
8524
|
+
if (budget !== undefined) {
|
|
8525
|
+
if (budget === null || typeof budget !== "object" || Array.isArray(budget)) {
|
|
8526
|
+
return new InputError({ message: "query: budget must be an object" });
|
|
8527
|
+
}
|
|
8528
|
+
for (const [name, v] of [
|
|
8529
|
+
["maxUnits", budget.maxUnits],
|
|
8530
|
+
["maxChars", budget.maxChars],
|
|
8531
|
+
["maxMs", budget.maxMs]
|
|
8532
|
+
]) {
|
|
8533
|
+
if (v !== undefined && (!Number.isInteger(v) || v <= 0)) {
|
|
8534
|
+
return new InputError({
|
|
8535
|
+
message: `query: budget.${name} must be a positive integer (got ${String(v)})`
|
|
8536
|
+
});
|
|
8537
|
+
}
|
|
8538
|
+
}
|
|
8539
|
+
}
|
|
8122
8540
|
const profile = options?.profile;
|
|
8123
8541
|
if (profile !== undefined) {
|
|
8124
8542
|
if (typeof profile === "string") {
|
|
@@ -8159,13 +8577,57 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8159
8577
|
if (topicKeys !== undefined && (!Array.isArray(topicKeys) || topicKeys.some((t) => typeof t !== "string"))) {
|
|
8160
8578
|
return new InputError({ message: "query: topics.topicKeys must be a string array" });
|
|
8161
8579
|
}
|
|
8580
|
+
const contentType = options?.contentType;
|
|
8581
|
+
if (contentType !== undefined) {
|
|
8582
|
+
const kinds = typeof contentType === "string" ? [contentType] : contentType;
|
|
8583
|
+
if (kinds.length === 0 || kinds.some((k2) => typeof k2 !== "string" || k2.length === 0)) {
|
|
8584
|
+
return new InputError({
|
|
8585
|
+
message: "query: contentType must be a non-empty string or a non-empty string array"
|
|
8586
|
+
});
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8162
8589
|
return;
|
|
8163
8590
|
};
|
|
8164
8591
|
const runQuery = (text4, options) => run(Effect49.gen(function* () {
|
|
8592
|
+
if (typeof text4 !== "string") {
|
|
8593
|
+
return yield* new InputError({ message: "query: text must be a string" });
|
|
8594
|
+
}
|
|
8165
8595
|
const invalid = validateQueryOptions(options);
|
|
8166
8596
|
if (invalid !== undefined)
|
|
8167
8597
|
return yield* invalid;
|
|
8168
|
-
|
|
8598
|
+
const { budget, ...rest } = options ?? {};
|
|
8599
|
+
const started = Date.now();
|
|
8600
|
+
const capLimit = budget?.maxUnits !== undefined && (rest.limit === undefined || rest.limit > budget.maxUnits) ? budget.maxUnits : rest.limit;
|
|
8601
|
+
let rows = yield* core().hybrid.hybrid(text4, {
|
|
8602
|
+
...rest,
|
|
8603
|
+
...capLimit !== undefined ? { limit: capLimit } : {}
|
|
8604
|
+
}).pipe(Effect49.map((r) => [...r]));
|
|
8605
|
+
let truncated = false;
|
|
8606
|
+
if (budget?.maxChars !== undefined && budget.maxChars > 0) {
|
|
8607
|
+
let used = 0;
|
|
8608
|
+
rows = rows.map((row) => {
|
|
8609
|
+
const content = row.memory.content;
|
|
8610
|
+
const room = budget.maxChars - used;
|
|
8611
|
+
if (room <= 0) {
|
|
8612
|
+
truncated = true;
|
|
8613
|
+
return { ...row, memory: { ...row.memory, content: "" } };
|
|
8614
|
+
}
|
|
8615
|
+
if (content.length > room) {
|
|
8616
|
+
truncated = true;
|
|
8617
|
+
used += room;
|
|
8618
|
+
return { ...row, memory: { ...row.memory, content: content.slice(0, room) } };
|
|
8619
|
+
}
|
|
8620
|
+
used += content.length;
|
|
8621
|
+
return row;
|
|
8622
|
+
});
|
|
8623
|
+
}
|
|
8624
|
+
if (budget?.maxMs !== undefined && Date.now() - started > budget.maxMs) {
|
|
8625
|
+
truncated = true;
|
|
8626
|
+
}
|
|
8627
|
+
const out = rows;
|
|
8628
|
+
if (truncated)
|
|
8629
|
+
out.truncated = true;
|
|
8630
|
+
return out;
|
|
8169
8631
|
}));
|
|
8170
8632
|
const validateWriteInput = (input) => {
|
|
8171
8633
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
@@ -8184,9 +8646,9 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8184
8646
|
return new InputError({ message: "write: namespace must be a string" });
|
|
8185
8647
|
}
|
|
8186
8648
|
const ttl = input.ttlSecs;
|
|
8187
|
-
if (ttl
|
|
8649
|
+
if (typeof ttl === "number" && (!Number.isInteger(ttl) || ttl < 0)) {
|
|
8188
8650
|
return new InputError({
|
|
8189
|
-
message: `write: ttlSecs must be a non-negative integer (got ${String(ttl)})`
|
|
8651
|
+
message: `write: ttlSecs must be a non-negative integer or null (got ${String(ttl)})`
|
|
8190
8652
|
});
|
|
8191
8653
|
}
|
|
8192
8654
|
if (input.metadata !== undefined && typeof input.metadata !== "string") {
|
|
@@ -8230,15 +8692,47 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8230
8692
|
return;
|
|
8231
8693
|
};
|
|
8232
8694
|
const writeUnit = (input, embed) => Effect49.gen(function* () {
|
|
8233
|
-
const mem = yield* core.store.write(input);
|
|
8695
|
+
const mem = yield* core().store.write(input);
|
|
8234
8696
|
if (embed) {
|
|
8235
|
-
yield* core.store.ensureTopicTree(core.defaultModel.id);
|
|
8236
|
-
const vector = yield* core.defaultEmbedder.embedSingle(input.content);
|
|
8237
|
-
yield* core.store.updateEmbedding(mem.id, [...vector], core.defaultModel.id);
|
|
8238
|
-
return yield* core.store.get(mem.id);
|
|
8697
|
+
yield* core().store.ensureTopicTree(core().defaultModel.id);
|
|
8698
|
+
const vector = yield* core().defaultEmbedder.embedSingle(input.content);
|
|
8699
|
+
yield* core().store.updateEmbedding(mem.id, [...vector], core().defaultModel.id);
|
|
8700
|
+
return yield* core().store.get(mem.id);
|
|
8239
8701
|
}
|
|
8240
8702
|
return mem;
|
|
8241
8703
|
});
|
|
8704
|
+
const upsertUnit = (input, embed) => Effect49.gen(function* () {
|
|
8705
|
+
const existing = yield* core().store.getByKey(input.logicalKey, input.namespace ?? "default").pipe(Effect49.catchTag("Store.NotFound", () => Effect49.succeed(undefined)));
|
|
8706
|
+
if (existing !== undefined && existing.content === input.content) {
|
|
8707
|
+
const stamp = codeVersionOf(input.metadata);
|
|
8708
|
+
if (stamp !== undefined && codeVersionOf(existing.metadata) === undefined) {
|
|
8709
|
+
yield* core().store.setMemoryMetadata(existing.id, { codeVersion: stamp });
|
|
8710
|
+
}
|
|
8711
|
+
if (embed && (existing.embedding === null || existing.embedding === undefined)) {
|
|
8712
|
+
yield* core().store.ensureTopicTree(core().defaultModel.id);
|
|
8713
|
+
const vector = yield* core().defaultEmbedder.embedSingle(input.content);
|
|
8714
|
+
yield* core().store.updateEmbedding(existing.id, [...vector], core().defaultModel.id);
|
|
8715
|
+
return { kind: "updated", id: existing.id };
|
|
8716
|
+
}
|
|
8717
|
+
return { kind: "skipped", id: existing.id };
|
|
8718
|
+
}
|
|
8719
|
+
if (existing !== undefined) {
|
|
8720
|
+
const { memory: memory2 } = yield* core().store.writeSuperseding(input);
|
|
8721
|
+
if (embed) {
|
|
8722
|
+
yield* core().store.ensureTopicTree(core().defaultModel.id);
|
|
8723
|
+
const vector = yield* core().defaultEmbedder.embedSingle(input.content);
|
|
8724
|
+
yield* core().store.updateEmbedding(memory2.id, [...vector], core().defaultModel.id);
|
|
8725
|
+
}
|
|
8726
|
+
return { kind: "updated", id: memory2.id };
|
|
8727
|
+
}
|
|
8728
|
+
const memory = yield* core().store.write(input);
|
|
8729
|
+
if (embed) {
|
|
8730
|
+
yield* core().store.ensureTopicTree(core().defaultModel.id);
|
|
8731
|
+
const vector = yield* core().defaultEmbedder.embedSingle(input.content);
|
|
8732
|
+
yield* core().store.updateEmbedding(memory.id, [...vector], core().defaultModel.id);
|
|
8733
|
+
}
|
|
8734
|
+
return { kind: "indexed", id: memory.id };
|
|
8735
|
+
});
|
|
8242
8736
|
const validateIndexOptions = (options) => {
|
|
8243
8737
|
if (options === null || typeof options !== "object" || Array.isArray(options)) {
|
|
8244
8738
|
return new InputError({ message: "index: options must be an object" });
|
|
@@ -8273,16 +8767,32 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8273
8767
|
return;
|
|
8274
8768
|
};
|
|
8275
8769
|
const messageOf3 = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
8770
|
+
const resolveMemory = (idOrKey) => core().store.get(idOrKey).pipe(Effect49.catchTag("Store.NotFound", () => core().store.getByKey(idOrKey, "default").pipe(Effect49.catchTag("Store.NotFound", () => Effect49.fail(new NotFoundError({ id: idOrKey, message: `Memory not found: ${idOrKey}` }))))));
|
|
8771
|
+
const codeVersionOf = (blob) => {
|
|
8772
|
+
if (blob === undefined || blob === null)
|
|
8773
|
+
return;
|
|
8774
|
+
try {
|
|
8775
|
+
const parsed = JSON.parse(blob);
|
|
8776
|
+
if (parsed !== null && typeof parsed === "object") {
|
|
8777
|
+
const v = parsed["codeVersion"];
|
|
8778
|
+
return typeof v === "string" ? v : undefined;
|
|
8779
|
+
}
|
|
8780
|
+
} catch {}
|
|
8781
|
+
return;
|
|
8782
|
+
};
|
|
8276
8783
|
return {
|
|
8784
|
+
get defaultModelId() {
|
|
8785
|
+
return core().defaultModel.id;
|
|
8786
|
+
},
|
|
8277
8787
|
write: (input, options) => run(Effect49.gen(function* () {
|
|
8278
8788
|
const invalid = validateWriteInput(input);
|
|
8279
8789
|
if (invalid !== undefined)
|
|
8280
8790
|
return yield* invalid;
|
|
8281
8791
|
return yield* writeUnit(input, options?.embed !== false);
|
|
8282
8792
|
})),
|
|
8283
|
-
get: (id) => run(
|
|
8793
|
+
get: (id) => run(resolveMemory(id)),
|
|
8284
8794
|
query: runQuery,
|
|
8285
|
-
forget: (id) => run(core.store.forget(id)),
|
|
8795
|
+
forget: (id) => run(resolveMemory(id).pipe(Effect49.flatMap((memory) => core().store.forget(memory.id)))),
|
|
8286
8796
|
index: (options) => run(Effect49.gen(function* () {
|
|
8287
8797
|
const invalid = validateIndexOptions(options);
|
|
8288
8798
|
if (invalid !== undefined)
|
|
@@ -8300,13 +8810,19 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8300
8810
|
})
|
|
8301
8811
|
});
|
|
8302
8812
|
const failed = [...walk.errors];
|
|
8813
|
+
const commit = currentCommit(walk.files[0]);
|
|
8303
8814
|
let indexed = 0;
|
|
8815
|
+
let updated = 0;
|
|
8816
|
+
let reconciled = 0;
|
|
8304
8817
|
let skipped = 0;
|
|
8305
8818
|
const unitIds = new Map;
|
|
8819
|
+
const freshIds = [];
|
|
8306
8820
|
const pendingEdges = [];
|
|
8821
|
+
const pendingCallEdges = [];
|
|
8822
|
+
const stableChunkId = (chunkId) => chunkId.replace(/:\d+$/, "");
|
|
8307
8823
|
const parentClassOf = (chunkId) => {
|
|
8308
|
-
const parts = chunkId.split(":");
|
|
8309
|
-
const parentAndMethod = parts[parts.length -
|
|
8824
|
+
const parts = stableChunkId(chunkId).split(":");
|
|
8825
|
+
const parentAndMethod = parts[parts.length - 1];
|
|
8310
8826
|
if (parentAndMethod === undefined || !parentAndMethod.includes("."))
|
|
8311
8827
|
return;
|
|
8312
8828
|
return parentAndMethod.split(".")[0];
|
|
@@ -8316,49 +8832,59 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8316
8832
|
const language = languageForPath(filePath);
|
|
8317
8833
|
if (language === undefined)
|
|
8318
8834
|
continue;
|
|
8835
|
+
const chunkKeyOf = (chunkId) => `${keyPrefix}${relative}#${stableChunkId(chunkId)}`;
|
|
8319
8836
|
const exit = yield* Effect49.exit(Effect49.gen(function* () {
|
|
8320
8837
|
const source = yield* Effect49.try({
|
|
8321
8838
|
try: () => readCapped(filePath, maxFileBytes),
|
|
8322
8839
|
catch: (cause) => new InputError({ message: `read failed: ${messageOf3(cause)}` })
|
|
8323
8840
|
});
|
|
8324
|
-
const handle = yield* parser.parse({ lang: language, source });
|
|
8325
|
-
const extracted = yield* extractor.extract({ filePath: relative, tree: handle });
|
|
8841
|
+
const handle = yield* parser().parse({ lang: language, source });
|
|
8842
|
+
const extracted = yield* extractor().extract({ filePath: relative, tree: handle });
|
|
8326
8843
|
let units = 0;
|
|
8844
|
+
let upd = 0;
|
|
8327
8845
|
let dups = 0;
|
|
8328
8846
|
const fileKey = `${keyPrefix}${relative}`;
|
|
8329
|
-
const fileOutcome = yield*
|
|
8847
|
+
const fileOutcome = yield* upsertUnit({
|
|
8330
8848
|
logicalKey: fileKey,
|
|
8331
8849
|
content: source,
|
|
8332
8850
|
...namespace !== undefined ? { namespace } : {},
|
|
8851
|
+
ttlSecs: null,
|
|
8333
8852
|
metadata: JSON.stringify({
|
|
8334
8853
|
filePath,
|
|
8335
8854
|
language,
|
|
8336
8855
|
kind: "file",
|
|
8337
|
-
imports: extracted.imports ?? []
|
|
8856
|
+
imports: extracted.imports ?? [],
|
|
8857
|
+
...commit !== null ? { codeVersion: commit } : {}
|
|
8338
8858
|
}),
|
|
8339
8859
|
contentType: `text/x-${language}`
|
|
8340
|
-
}, embed)
|
|
8341
|
-
if (fileOutcome === "
|
|
8860
|
+
}, embed);
|
|
8861
|
+
if (fileOutcome.kind === "skipped") {
|
|
8342
8862
|
dups += 1;
|
|
8343
|
-
else {
|
|
8344
|
-
units += 1;
|
|
8345
8863
|
unitIds.set(fileKey, fileOutcome.id);
|
|
8864
|
+
} else {
|
|
8865
|
+
if (fileOutcome.kind === "updated")
|
|
8866
|
+
upd += 1;
|
|
8867
|
+
else
|
|
8868
|
+
units += 1;
|
|
8869
|
+
unitIds.set(fileKey, fileOutcome.id);
|
|
8870
|
+
freshIds.push(fileOutcome.id);
|
|
8346
8871
|
}
|
|
8347
8872
|
const classKeys = new Map;
|
|
8348
8873
|
for (const chunk of extracted.chunks) {
|
|
8349
8874
|
if (chunk.kind === "class" || chunk.kind.endsWith("class")) {
|
|
8350
|
-
classKeys.set(chunk.name,
|
|
8875
|
+
classKeys.set(chunk.name, chunkKeyOf(chunk.id));
|
|
8351
8876
|
}
|
|
8352
8877
|
}
|
|
8353
8878
|
for (const chunk of extracted.chunks) {
|
|
8354
|
-
const chunkKey =
|
|
8879
|
+
const chunkKey = chunkKeyOf(chunk.id);
|
|
8355
8880
|
const content = [chunk.docstring, chunk.sourceText].filter((c) => c !== undefined && c.length > 0).join(`
|
|
8356
8881
|
|
|
8357
8882
|
`).slice(0, maxChunkBytes);
|
|
8358
|
-
const chunkOutcome = yield*
|
|
8883
|
+
const chunkOutcome = yield* upsertUnit({
|
|
8359
8884
|
logicalKey: chunkKey,
|
|
8360
8885
|
content,
|
|
8361
8886
|
...namespace !== undefined ? { namespace } : {},
|
|
8887
|
+
ttlSecs: null,
|
|
8362
8888
|
metadata: JSON.stringify({
|
|
8363
8889
|
filePath,
|
|
8364
8890
|
language,
|
|
@@ -8366,17 +8892,23 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8366
8892
|
name: chunk.name,
|
|
8367
8893
|
startLine: chunk.startLine,
|
|
8368
8894
|
endLine: chunk.endLine,
|
|
8369
|
-
...chunk.docstring !== undefined ? { docstring: chunk.docstring } : {}
|
|
8895
|
+
...chunk.docstring !== undefined ? { docstring: chunk.docstring } : {},
|
|
8896
|
+
...commit !== null ? { codeVersion: commit } : {}
|
|
8370
8897
|
}),
|
|
8371
8898
|
contentType: `text/x-${language}`
|
|
8372
|
-
}, embed)
|
|
8373
|
-
if (chunkOutcome === "
|
|
8899
|
+
}, embed);
|
|
8900
|
+
if (chunkOutcome.kind === "skipped") {
|
|
8374
8901
|
dups += 1;
|
|
8902
|
+
unitIds.set(chunkKey, chunkOutcome.id);
|
|
8375
8903
|
} else {
|
|
8376
|
-
|
|
8904
|
+
if (chunkOutcome.kind === "updated")
|
|
8905
|
+
upd += 1;
|
|
8906
|
+
else
|
|
8907
|
+
units += 1;
|
|
8377
8908
|
unitIds.set(chunkKey, chunkOutcome.id);
|
|
8909
|
+
freshIds.push(chunkOutcome.id);
|
|
8378
8910
|
}
|
|
8379
|
-
if (chunkOutcome !== "
|
|
8911
|
+
if (chunkOutcome.kind !== "skipped" && chunk.kind === "method") {
|
|
8380
8912
|
const parent = parentClassOf(chunk.id);
|
|
8381
8913
|
const classKey = parent === undefined ? undefined : classKeys.get(parent);
|
|
8382
8914
|
if (classKey !== undefined) {
|
|
@@ -8390,37 +8922,68 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8390
8922
|
to: fileKey
|
|
8391
8923
|
});
|
|
8392
8924
|
}
|
|
8393
|
-
|
|
8925
|
+
const importRels = resolveImports(filePath, (extracted.imports ?? []).map((imp) => imp.source), extensions).map((target) => keyForPath(walk.root, target));
|
|
8926
|
+
for (const chunk of extracted.chunks) {
|
|
8927
|
+
const callerKey = chunkKeyOf(chunk.id);
|
|
8928
|
+
if (!unitIds.has(callerKey))
|
|
8929
|
+
continue;
|
|
8930
|
+
for (const call of chunk.calls ?? []) {
|
|
8931
|
+
const candidates2 = [
|
|
8932
|
+
`${keyPrefix}${relative}#${relative}:${call.name}`,
|
|
8933
|
+
...importRels.map((rel) => `${keyPrefix}${rel}#${rel}:${call.name}`)
|
|
8934
|
+
];
|
|
8935
|
+
const first = candidates2.find((key) => unitIds.has(key));
|
|
8936
|
+
if (first !== undefined) {
|
|
8937
|
+
pendingCallEdges.push({ from: callerKey, to: first });
|
|
8938
|
+
}
|
|
8939
|
+
}
|
|
8940
|
+
}
|
|
8941
|
+
return { units, upd, dups };
|
|
8394
8942
|
}));
|
|
8395
8943
|
if (Exit6.isFailure(exit)) {
|
|
8396
8944
|
failed.push({ filePath, message: Cause5.pretty(exit.cause) });
|
|
8397
8945
|
} else {
|
|
8398
8946
|
indexed += exit.value.units;
|
|
8947
|
+
updated += exit.value.upd;
|
|
8399
8948
|
skipped += exit.value.dups;
|
|
8400
8949
|
}
|
|
8401
8950
|
}
|
|
8402
|
-
const
|
|
8403
|
-
|
|
8404
|
-
|
|
8951
|
+
const vanished = yield* core().store.reconcile(namespace ?? "default", keyPrefix, walk.root, walk.roots, [...unitIds.keys()]);
|
|
8952
|
+
reconciled = vanished.length;
|
|
8953
|
+
yield* core().store.reconcileRenameCandidates(vanished, freshIds);
|
|
8954
|
+
const resolveKey = (key) => {
|
|
8955
|
+
const fromMap = unitIds.get(key);
|
|
8956
|
+
if (fromMap !== undefined)
|
|
8957
|
+
return Effect49.succeed(fromMap);
|
|
8958
|
+
return core().store.getByKey(key, namespace ?? "default").pipe(Effect49.map((m) => m.id), Effect49.catchTag("Store.NotFound", () => Effect49.succeed(undefined)));
|
|
8959
|
+
};
|
|
8960
|
+
const edgeEffect = (edge) => Effect49.gen(function* () {
|
|
8961
|
+
const [from, to] = yield* Effect49.all([resolveKey(edge.from), resolveKey(edge.to)]);
|
|
8405
8962
|
if (from === undefined || to === undefined || from === to)
|
|
8406
|
-
return
|
|
8407
|
-
|
|
8963
|
+
return;
|
|
8964
|
+
yield* Effect49.exit(core().store.addEdge({
|
|
8408
8965
|
fromMemoryId: from,
|
|
8409
8966
|
toMemoryId: to,
|
|
8410
|
-
edgeKind:
|
|
8967
|
+
edgeKind: edge.edgeKind,
|
|
8411
8968
|
source: "rule",
|
|
8412
8969
|
confidence: 1,
|
|
8413
8970
|
confirmed: true
|
|
8414
|
-
});
|
|
8415
|
-
};
|
|
8971
|
+
}));
|
|
8972
|
+
});
|
|
8416
8973
|
for (const edge of pendingEdges) {
|
|
8417
|
-
yield* Effect49.exit(edgeEffect(edge));
|
|
8974
|
+
yield* Effect49.exit(edgeEffect({ ...edge, edgeKind: "memory_supports" }));
|
|
8975
|
+
}
|
|
8976
|
+
for (const edge of pendingCallEdges) {
|
|
8977
|
+
yield* Effect49.exit(edgeEffect({ ...edge, edgeKind: "code_calls" }));
|
|
8418
8978
|
}
|
|
8419
8979
|
return {
|
|
8420
8980
|
files: walk.files.length,
|
|
8421
8981
|
indexed,
|
|
8982
|
+
updated,
|
|
8983
|
+
reconciled,
|
|
8422
8984
|
skipped,
|
|
8423
8985
|
unsupported: walk.unsupported,
|
|
8986
|
+
commit,
|
|
8424
8987
|
failed
|
|
8425
8988
|
};
|
|
8426
8989
|
})),
|
|
@@ -8430,57 +8993,232 @@ var makeFacade = (runtime, core, parser, extractor, dispose) => {
|
|
|
8430
8993
|
message: "updateEmbedding: embedding must be a non-empty array of finite numbers"
|
|
8431
8994
|
});
|
|
8432
8995
|
}
|
|
8433
|
-
const key = modelKey ?? core.defaultModel.id;
|
|
8434
|
-
yield*
|
|
8435
|
-
yield* core.store.
|
|
8996
|
+
const key = modelKey ?? core().defaultModel.id;
|
|
8997
|
+
const memory = yield* resolveMemory(id);
|
|
8998
|
+
yield* core().store.ensureTopicTree(key);
|
|
8999
|
+
yield* core().store.updateEmbedding(memory.id, [...embedding], key);
|
|
8436
9000
|
})),
|
|
8437
|
-
embed: (text4) => run(core.defaultEmbedder.embedSingle(text4).pipe(Effect49.map((vector) => [...vector]))),
|
|
8438
|
-
dream: (modelKey) => run(core.runtime.enqueue(MemoryDream, { modelKey, runId: crypto.randomUUID() }).pipe(Effect49.flatMap((jobId) => core.runtime.wait(jobId)), Effect49.asVoid)),
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
9001
|
+
embed: (text4) => run(core().defaultEmbedder.embedSingle(text4).pipe(Effect49.map((vector) => [...vector]))),
|
|
9002
|
+
dream: (modelKey) => run(core().runtime.enqueue(MemoryDream, { modelKey, runId: crypto.randomUUID() }).pipe(Effect49.flatMap((jobId) => core().runtime.wait(jobId)), Effect49.asVoid)),
|
|
9003
|
+
dbSchema: () => run(core().store.listSchema()),
|
|
9004
|
+
repair: (modelKey) => run(core().runtime.enqueue(GraphRepair, { modelKey, runId: crypto.randomUUID() }).pipe(Effect49.flatMap((jobId) => core().runtime.wait(jobId)), Effect49.asVoid)),
|
|
9005
|
+
explain: (input, options) => run(core().store.explain(input, {
|
|
9006
|
+
...options?.edgeKinds !== undefined ? { edgeKinds: options.edgeKinds } : {},
|
|
9007
|
+
...options?.maxDepth !== undefined ? { maxDepth: options.maxDepth } : {},
|
|
9008
|
+
...options?.maxNeighbors !== undefined ? { maxNeighbors: options.maxNeighbors } : {},
|
|
9009
|
+
...options?.maxTotal !== undefined ? { maxTotal: options.maxTotal } : {},
|
|
9010
|
+
...options?.includePending !== undefined ? { includePending: options.includePending } : {}
|
|
9011
|
+
})),
|
|
9012
|
+
health: (modelKey) => run(core().store.topicHealth(modelKey)),
|
|
8442
9013
|
graph: {
|
|
8443
9014
|
addEdge: (input) => run(Effect49.gen(function* () {
|
|
8444
9015
|
const invalid = validateAddEdgeInput(input);
|
|
8445
9016
|
if (invalid !== undefined)
|
|
8446
9017
|
return yield* invalid;
|
|
8447
|
-
return yield* core.store.addEdge(input);
|
|
9018
|
+
return yield* core().store.addEdge(input);
|
|
8448
9019
|
})),
|
|
8449
|
-
candidates: () => run(core.store.graphCandidates()),
|
|
8450
|
-
coverage: (modelKey) => run(core.store.graphCoverage(modelKey))
|
|
9020
|
+
candidates: () => run(core().store.graphCandidates()),
|
|
9021
|
+
coverage: (modelKey) => run(core().store.graphCoverage(modelKey)),
|
|
9022
|
+
confirm: (id) => run(core().store.confirmEdge(id)),
|
|
9023
|
+
reject: (id) => run(core().store.rejectEdge(id)),
|
|
9024
|
+
expire: (id) => run(core().store.expireEdge(id))
|
|
8451
9025
|
},
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
})
|
|
9026
|
+
reload: (input) => reload(input),
|
|
9027
|
+
dispose: () => dispose()
|
|
8455
9028
|
};
|
|
8456
9029
|
};
|
|
8457
9030
|
|
|
8458
9031
|
// src/make.ts
|
|
8459
|
-
var
|
|
9032
|
+
var stableKey = (value2) => {
|
|
9033
|
+
if (Array.isArray(value2))
|
|
9034
|
+
return `[${value2.map(stableKey).join(",")}]`;
|
|
9035
|
+
if (value2 !== null && typeof value2 === "object") {
|
|
9036
|
+
const entries = Object.entries(value2).filter(([, v]) => v !== undefined).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
9037
|
+
return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableKey(v)}`).join(",")}}`;
|
|
9038
|
+
}
|
|
9039
|
+
return JSON.stringify(value2);
|
|
9040
|
+
};
|
|
9041
|
+
var diffConfig = (oldC, newC) => {
|
|
9042
|
+
if (oldC === undefined)
|
|
9043
|
+
return { storeUrl: true, jobsUrl: true, rest: true };
|
|
9044
|
+
const oldJobsUrl = oldC.jobs?.dbUrl;
|
|
9045
|
+
const newJobsUrl = newC.jobs?.dbUrl;
|
|
9046
|
+
const restOld = { ...oldC, storeUrl: "", jobs: { ...oldC.jobs, dbUrl: "" } };
|
|
9047
|
+
const restNew = { ...newC, storeUrl: "", jobs: { ...newC.jobs, dbUrl: "" } };
|
|
9048
|
+
return {
|
|
9049
|
+
storeUrl: oldC.storeUrl !== newC.storeUrl,
|
|
9050
|
+
jobsUrl: oldJobsUrl !== newJobsUrl,
|
|
9051
|
+
rest: stableKey(restOld) !== stableKey(restNew)
|
|
9052
|
+
};
|
|
9053
|
+
};
|
|
9054
|
+
var RELOAD_DRAIN_MS = 30000;
|
|
9055
|
+
var bootStack = async (options) => {
|
|
8460
9056
|
const scope = await Effect50.runPromise(Scope5.make());
|
|
8461
9057
|
let runtime;
|
|
8462
9058
|
try {
|
|
8463
9059
|
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)));
|
|
8464
9060
|
const appLayer = Layer26.mergeAll(layer21, layer20, layer14);
|
|
8465
|
-
const rt =
|
|
9061
|
+
const rt = ManagedRuntime.make(appLayer);
|
|
8466
9062
|
runtime = rt;
|
|
8467
9063
|
const [core, parser, extractor] = await rt.runPromise(Effect50.all([Service, Service19, Service12]));
|
|
8468
|
-
return
|
|
9064
|
+
return {
|
|
9065
|
+
runPromise: (effect) => rt.runPromise(effect),
|
|
9066
|
+
disposeEffect: rt.disposeEffect,
|
|
9067
|
+
core,
|
|
9068
|
+
parser,
|
|
9069
|
+
extractor,
|
|
9070
|
+
dispose: () => Effect50.runPromise(Scope5.close(scope, Exit7.void).pipe(Effect50.andThen(rt.disposeEffect)))
|
|
9071
|
+
};
|
|
8469
9072
|
} catch (cause) {
|
|
8470
9073
|
await Effect50.runPromise(Scope5.close(scope, Exit7.void).pipe(Effect50.andThen(runtime?.disposeEffect ?? Effect50.void))).catch(() => {
|
|
8471
9074
|
return;
|
|
8472
9075
|
});
|
|
8473
|
-
return Promise.reject(
|
|
9076
|
+
return Promise.reject(cause);
|
|
8474
9077
|
}
|
|
8475
9078
|
};
|
|
9079
|
+
var makeDimple = async (options) => {
|
|
9080
|
+
const configSource = "config" in options ? options.config : undefined;
|
|
9081
|
+
const migrationFolder = "config" in options ? options.migrationFolder : undefined;
|
|
9082
|
+
let currentConfig;
|
|
9083
|
+
if (configSource !== undefined) {
|
|
9084
|
+
currentConfig = await Effect50.runPromise(resolveConfigInput(configSource)).catch((cause) => Promise.reject(remapError(cause)));
|
|
9085
|
+
}
|
|
9086
|
+
let current = await bootStack(configSource !== undefined && currentConfig !== undefined ? {
|
|
9087
|
+
config: currentConfig,
|
|
9088
|
+
...migrationFolder !== undefined ? { migrationFolder } : {}
|
|
9089
|
+
} : options).then((stack) => stack, (cause) => Promise.reject(remapError(cause)));
|
|
9090
|
+
let disposed = false;
|
|
9091
|
+
let gate = Promise.resolve();
|
|
9092
|
+
let releaseGate;
|
|
9093
|
+
let inflight = 0;
|
|
9094
|
+
let drainWaiters = [];
|
|
9095
|
+
let reloadChain = Promise.resolve();
|
|
9096
|
+
const run = (effect) => {
|
|
9097
|
+
if (disposed) {
|
|
9098
|
+
return Promise.reject(new StoreFailure({ message: "SDK disposed" }));
|
|
9099
|
+
}
|
|
9100
|
+
return gate.then(() => {
|
|
9101
|
+
if (disposed) {
|
|
9102
|
+
return Promise.reject(new StoreFailure({ message: "SDK disposed" }));
|
|
9103
|
+
}
|
|
9104
|
+
const stack = current;
|
|
9105
|
+
inflight += 1;
|
|
9106
|
+
return stack.runPromise(effect.pipe(Effect50.mapError(remapError))).catch((cause) => {
|
|
9107
|
+
return Promise.reject(remapError(cause));
|
|
9108
|
+
}).finally(() => {
|
|
9109
|
+
inflight -= 1;
|
|
9110
|
+
if (inflight === 0 && drainWaiters.length > 0) {
|
|
9111
|
+
const waiters = drainWaiters;
|
|
9112
|
+
drainWaiters = [];
|
|
9113
|
+
for (const wake of waiters)
|
|
9114
|
+
wake();
|
|
9115
|
+
}
|
|
9116
|
+
});
|
|
9117
|
+
});
|
|
9118
|
+
};
|
|
9119
|
+
const pause = () => {
|
|
9120
|
+
gate = new Promise((resolve2) => {
|
|
9121
|
+
releaseGate = resolve2;
|
|
9122
|
+
});
|
|
9123
|
+
};
|
|
9124
|
+
const resume = () => {
|
|
9125
|
+
const release = releaseGate;
|
|
9126
|
+
releaseGate = undefined;
|
|
9127
|
+
gate = Promise.resolve();
|
|
9128
|
+
release?.();
|
|
9129
|
+
};
|
|
9130
|
+
const drain = () => {
|
|
9131
|
+
if (inflight === 0)
|
|
9132
|
+
return Promise.resolve();
|
|
9133
|
+
return new Promise((resolve2) => {
|
|
9134
|
+
drainWaiters.push(resolve2);
|
|
9135
|
+
});
|
|
9136
|
+
};
|
|
9137
|
+
const drainWithTimeout = () => new Promise((resolve2, reject) => {
|
|
9138
|
+
const timer = setTimeout(() => {
|
|
9139
|
+
reject(new ReloadError({
|
|
9140
|
+
message: `reload: drain timeout after ${RELOAD_DRAIN_MS}ms — in-flight calls still running`
|
|
9141
|
+
}));
|
|
9142
|
+
}, RELOAD_DRAIN_MS);
|
|
9143
|
+
drain().then(() => {
|
|
9144
|
+
clearTimeout(timer);
|
|
9145
|
+
resolve2();
|
|
9146
|
+
}, (cause) => {
|
|
9147
|
+
clearTimeout(timer);
|
|
9148
|
+
reject(cause);
|
|
9149
|
+
});
|
|
9150
|
+
});
|
|
9151
|
+
const reload = (input) => {
|
|
9152
|
+
const task = reloadChain.then(async () => {
|
|
9153
|
+
if (disposed) {
|
|
9154
|
+
return Promise.reject(new ReloadError({ message: "SDK disposed — reload unavailable" }));
|
|
9155
|
+
}
|
|
9156
|
+
if (configSource === undefined) {
|
|
9157
|
+
return Promise.reject(new ReloadError({
|
|
9158
|
+
message: "reload: no config source — this dimple was built from `core` options"
|
|
9159
|
+
}));
|
|
9160
|
+
}
|
|
9161
|
+
const nextInput = input ?? configSource;
|
|
9162
|
+
const resolved = await Effect50.runPromise(resolveConfigInput(nextInput));
|
|
9163
|
+
if (currentConfig !== undefined && stableKey(resolved) === stableKey(currentConfig)) {
|
|
9164
|
+
return {
|
|
9165
|
+
config: resolved,
|
|
9166
|
+
changed: { storeUrl: false, jobsUrl: false, rest: false },
|
|
9167
|
+
reloaded: false
|
|
9168
|
+
};
|
|
9169
|
+
}
|
|
9170
|
+
const changes = diffConfig(currentConfig, resolved);
|
|
9171
|
+
pause();
|
|
9172
|
+
try {
|
|
9173
|
+
const next = await bootStack({
|
|
9174
|
+
config: resolved,
|
|
9175
|
+
...migrationFolder !== undefined ? { migrationFolder } : {}
|
|
9176
|
+
});
|
|
9177
|
+
await drainWithTimeout();
|
|
9178
|
+
const oldStoreUrl = currentConfig?.storeUrl;
|
|
9179
|
+
const oldJobsUrl = currentConfig?.jobs?.dbUrl;
|
|
9180
|
+
const old = current;
|
|
9181
|
+
current = next;
|
|
9182
|
+
currentConfig = resolved;
|
|
9183
|
+
await old.dispose();
|
|
9184
|
+
if (changes.storeUrl) {
|
|
9185
|
+
await Effect50.runPromise(Effect50.logWarning(`reload: store database switched "${oldStoreUrl}" → "${resolved.storeUrl}" — ` + "the old db is preserved but no longer served (nothing was migrated)").pipe(Effect50.annotateLogs({ scope: "@dimple/sdk", event: "reload.store.switch" })));
|
|
9186
|
+
}
|
|
9187
|
+
if (changes.jobsUrl) {
|
|
9188
|
+
await Effect50.runPromise(Effect50.logWarning(`reload: jobs database switched "${oldJobsUrl}" → "${resolved.jobs?.dbUrl}" — ` + "pending jobs remain durable in the old db").pipe(Effect50.annotateLogs({ scope: "@dimple/sdk", event: "reload.jobs.switch" })));
|
|
9189
|
+
}
|
|
9190
|
+
return { config: resolved, changed: changes, reloaded: true };
|
|
9191
|
+
} finally {
|
|
9192
|
+
resume();
|
|
9193
|
+
}
|
|
9194
|
+
});
|
|
9195
|
+
reloadChain = task.catch(() => {
|
|
9196
|
+
return;
|
|
9197
|
+
});
|
|
9198
|
+
return task.then((config) => config, (cause) => Promise.reject(remapError(cause)));
|
|
9199
|
+
};
|
|
9200
|
+
const dispose = () => {
|
|
9201
|
+
disposed = true;
|
|
9202
|
+
return reloadChain.then(() => current.dispose());
|
|
9203
|
+
};
|
|
9204
|
+
return makeFacade({
|
|
9205
|
+
run,
|
|
9206
|
+
core: () => current.core,
|
|
9207
|
+
parser: () => current.parser,
|
|
9208
|
+
extractor: () => current.extractor
|
|
9209
|
+
}, reload, dispose);
|
|
9210
|
+
};
|
|
8476
9211
|
export {
|
|
8477
9212
|
remapError,
|
|
8478
9213
|
makeDimple,
|
|
8479
9214
|
StoreFailure,
|
|
9215
|
+
ReloadError,
|
|
8480
9216
|
NotFoundError,
|
|
8481
9217
|
LLMNotConfiguredError,
|
|
8482
9218
|
JobFailedError,
|
|
8483
9219
|
InputError,
|
|
9220
|
+
EmbeddingFailure,
|
|
9221
|
+
EdgeNotFoundError,
|
|
8484
9222
|
DuplicateKeyError,
|
|
8485
9223
|
DuplicateEdgeError,
|
|
8486
9224
|
ConfigError
|