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