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