@orquentra/codebuddy 2.6.0 → 2.6.2
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/CLAUDE_CODEX.md +6 -4
- package/WORKFLOW.md +5 -5
- package/dist/{chunk-UN57FKQX.js → chunk-2XDPKFUW.js} +111 -847
- package/dist/chunk-2XDPKFUW.js.map +1 -0
- package/dist/{chunk-QDBDYCM2.js → chunk-5FW3PMNP.js} +2 -2
- package/dist/{chunk-776EQXDV.js → chunk-5KZY6OTG.js} +82 -5
- package/dist/chunk-5KZY6OTG.js.map +1 -0
- package/dist/{chunk-UFZD3JAA.js → chunk-5MQOE4J6.js} +3 -3
- package/dist/chunk-5UH3BEQR.js +32 -0
- package/dist/chunk-5UH3BEQR.js.map +1 -0
- package/dist/{chunk-N34XHWBA.js → chunk-B6CO63SQ.js} +8 -7
- package/dist/chunk-B6CO63SQ.js.map +1 -0
- package/dist/chunk-CSRD5OQA.js +79 -0
- package/dist/chunk-CSRD5OQA.js.map +1 -0
- package/dist/{chunk-PYLH4MH5.js → chunk-FJOTP632.js} +1 -1
- package/dist/{chunk-U4HAJLIB.js → chunk-IBLJOHJL.js} +15 -2
- package/dist/chunk-IBLJOHJL.js.map +1 -0
- package/dist/chunk-IMFUYEZA.js +1607 -0
- package/dist/chunk-IMFUYEZA.js.map +1 -0
- package/dist/{chunk-SYWJG5NA.js → chunk-J2EAZ4MA.js} +20 -7
- package/dist/chunk-J2EAZ4MA.js.map +1 -0
- package/dist/{chunk-L5AYZC3F.js → chunk-NERKZSSE.js} +7 -7
- package/dist/{chunk-PCE4STAY.js → chunk-OWWCDRXW.js} +5 -5
- package/dist/{chunk-WHZSVY2L.js → chunk-QBDJXGG5.js} +2 -2
- package/dist/{chunk-VAKBJV26.js → chunk-R7CD6EXS.js} +307 -1822
- package/dist/chunk-R7CD6EXS.js.map +1 -0
- package/dist/{chunk-6MKEIDX5.js → chunk-RAJJSCIP.js} +2 -2
- package/dist/chunk-S6VEG4S2.js +991 -0
- package/dist/chunk-S6VEG4S2.js.map +1 -0
- package/dist/cli/index.js +14 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/{codebuddy-DM-i0Fu5.d.ts → codebuddy-B_pCaQrV.d.ts} +22 -2
- package/dist/{config-KFEHLV6W.js → config-DEVHUDIU.js} +3 -3
- package/dist/docker-autostart-KDME7TVC.js +12 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +19 -15
- package/dist/langgraph/index.d.ts +1 -1
- package/dist/lean-command-HTQCPH76.js +15 -0
- package/dist/{local-OTOY56B4.js → local-5MZURLCZ.js} +6 -2
- package/dist/{main-HFHLGID4.js → main-MTBQZGJV.js} +139 -171
- package/dist/main-MTBQZGJV.js.map +1 -0
- package/dist/{memory-4RGVLPKG.js → memory-KIC5FJVW.js} +4 -4
- package/dist/{operations-LOBAQRLO.js → operations-POCHY3WR.js} +5 -4
- package/dist/postgres-docker-QQZQ2ABK.js +16 -0
- package/dist/{pretool-command-MQQ2UNQM.js → pretool-command-AX6JXP25.js} +3 -3
- package/dist/{rerank-3P3C2UHN.js → rerank-5QZ3PNUW.js} +4 -4
- package/dist/runtime-CUBOOPZO.js +43 -0
- package/dist/runtime-CUBOOPZO.js.map +1 -0
- package/dist/stdio-HOV4P3DQ.js +12 -0
- package/dist/stdio-HOV4P3DQ.js.map +1 -0
- package/dist/{summaries-ZBV5IN7Y.js → summaries-SB5L2TSW.js} +6 -6
- package/dist/summaries-SB5L2TSW.js.map +1 -0
- package/dist/{zvec-MAPSJQSR.js → zvec-MSRKT7IV.js} +3 -3
- package/dist/zvec-MSRKT7IV.js.map +1 -0
- package/package.json +7 -10
- package/dist/chunk-776EQXDV.js.map +0 -1
- package/dist/chunk-N34XHWBA.js.map +0 -1
- package/dist/chunk-SYWJG5NA.js.map +0 -1
- package/dist/chunk-U4HAJLIB.js.map +0 -1
- package/dist/chunk-UN57FKQX.js.map +0 -1
- package/dist/chunk-VAKBJV26.js.map +0 -1
- package/dist/lean-command-C5YPFKHP.js +0 -15
- package/dist/main-HFHLGID4.js.map +0 -1
- /package/dist/{chunk-QDBDYCM2.js.map → chunk-5FW3PMNP.js.map} +0 -0
- /package/dist/{chunk-UFZD3JAA.js.map → chunk-5MQOE4J6.js.map} +0 -0
- /package/dist/{chunk-PYLH4MH5.js.map → chunk-FJOTP632.js.map} +0 -0
- /package/dist/{chunk-L5AYZC3F.js.map → chunk-NERKZSSE.js.map} +0 -0
- /package/dist/{chunk-PCE4STAY.js.map → chunk-OWWCDRXW.js.map} +0 -0
- /package/dist/{chunk-WHZSVY2L.js.map → chunk-QBDJXGG5.js.map} +0 -0
- /package/dist/{chunk-6MKEIDX5.js.map → chunk-RAJJSCIP.js.map} +0 -0
- /package/dist/{config-KFEHLV6W.js.map → config-DEVHUDIU.js.map} +0 -0
- /package/dist/{lean-command-C5YPFKHP.js.map → docker-autostart-KDME7TVC.js.map} +0 -0
- /package/dist/{local-OTOY56B4.js.map → lean-command-HTQCPH76.js.map} +0 -0
- /package/dist/{operations-LOBAQRLO.js.map → local-5MZURLCZ.js.map} +0 -0
- /package/dist/{memory-4RGVLPKG.js.map → memory-KIC5FJVW.js.map} +0 -0
- /package/dist/{pretool-command-MQQ2UNQM.js.map → operations-POCHY3WR.js.map} +0 -0
- /package/dist/{summaries-ZBV5IN7Y.js.map → postgres-docker-QQZQ2ABK.js.map} +0 -0
- /package/dist/{zvec-MAPSJQSR.js.map → pretool-command-AX6JXP25.js.map} +0 -0
- /package/dist/{rerank-3P3C2UHN.js.map → rerank-5QZ3PNUW.js.map} +0 -0
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MemoryFileStore,
|
|
3
|
+
auditLog,
|
|
4
|
+
candidateLimit,
|
|
5
|
+
embeddings,
|
|
6
|
+
facts,
|
|
7
|
+
interactions,
|
|
8
|
+
isEligibleMemory,
|
|
9
|
+
lexicalTerms,
|
|
10
|
+
modelCalls,
|
|
11
|
+
namespaces,
|
|
12
|
+
schema_exports,
|
|
13
|
+
sessionSummaries,
|
|
14
|
+
shares,
|
|
15
|
+
validSearchVector
|
|
16
|
+
} from "./chunk-S6VEG4S2.js";
|
|
1
17
|
import {
|
|
2
18
|
REDACTED,
|
|
3
19
|
redactPersisted
|
|
@@ -15,7 +31,7 @@ import {
|
|
|
15
31
|
} from "./chunk-JFDRBPYF.js";
|
|
16
32
|
import {
|
|
17
33
|
LocalModelProvider
|
|
18
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-IBLJOHJL.js";
|
|
19
35
|
import {
|
|
20
36
|
DEFAULT_CLOUD_EMBEDDING_MODELS,
|
|
21
37
|
DEFAULT_EMBEDDING_MODELS,
|
|
@@ -26,325 +42,21 @@ import {
|
|
|
26
42
|
} from "./chunk-JPHJBCZB.js";
|
|
27
43
|
import {
|
|
28
44
|
MISSING_DATABASE_URL,
|
|
29
|
-
assertNoSymlinkBetween,
|
|
30
45
|
checkConfigPermissions,
|
|
31
46
|
checkProjectScaffold,
|
|
32
|
-
composeMarkdown,
|
|
33
47
|
defaultNamespaceForCwd,
|
|
34
48
|
loadRuntimeConfig,
|
|
35
|
-
|
|
49
|
+
migrateLegacyNamespace,
|
|
36
50
|
readConfigFile,
|
|
37
|
-
redactSecrets
|
|
38
|
-
|
|
39
|
-
} from "./chunk-776EQXDV.js";
|
|
40
|
-
import {
|
|
41
|
-
__export
|
|
42
|
-
} from "./chunk-PZ5AY32C.js";
|
|
43
|
-
|
|
44
|
-
// src/db/schema.ts
|
|
45
|
-
var schema_exports = {};
|
|
46
|
-
__export(schema_exports, {
|
|
47
|
-
HNSW_EF_CONSTRUCTION: () => HNSW_EF_CONSTRUCTION,
|
|
48
|
-
HNSW_M: () => HNSW_M,
|
|
49
|
-
VECTOR_DIMENSIONS: () => VECTOR_DIMENSIONS,
|
|
50
|
-
auditActionEnum: () => auditActionEnum,
|
|
51
|
-
auditLog: () => auditLog,
|
|
52
|
-
checkpoints: () => checkpoints,
|
|
53
|
-
embeddingOwnerTypeEnum: () => embeddingOwnerTypeEnum,
|
|
54
|
-
embeddingStatusEnum: () => embeddingStatusEnum,
|
|
55
|
-
embeddings: () => embeddings,
|
|
56
|
-
facts: () => facts,
|
|
57
|
-
interactionRoleEnum: () => interactionRoleEnum,
|
|
58
|
-
interactions: () => interactions,
|
|
59
|
-
memoryTypeEnum: () => memoryTypeEnum,
|
|
60
|
-
modelCallStatusEnum: () => modelCallStatusEnum,
|
|
61
|
-
modelCallTypeEnum: () => modelCallTypeEnum,
|
|
62
|
-
modelCalls: () => modelCalls,
|
|
63
|
-
namespaces: () => namespaces,
|
|
64
|
-
sessionSummaries: () => sessionSummaries,
|
|
65
|
-
shareModeEnum: () => shareModeEnum,
|
|
66
|
-
shares: () => shares
|
|
67
|
-
});
|
|
68
|
-
import { sql } from "drizzle-orm";
|
|
69
|
-
import {
|
|
70
|
-
boolean,
|
|
71
|
-
customType,
|
|
72
|
-
index,
|
|
73
|
-
integer,
|
|
74
|
-
jsonb,
|
|
75
|
-
numeric,
|
|
76
|
-
pgEnum,
|
|
77
|
-
pgTable,
|
|
78
|
-
text,
|
|
79
|
-
timestamp,
|
|
80
|
-
uniqueIndex
|
|
81
|
-
} from "drizzle-orm/pg-core";
|
|
82
|
-
var VECTOR_DIMENSIONS = 384;
|
|
83
|
-
var HNSW_M = 16;
|
|
84
|
-
var HNSW_EF_CONSTRUCTION = 64;
|
|
85
|
-
var vector = customType({
|
|
86
|
-
dataType() {
|
|
87
|
-
return `vector(${VECTOR_DIMENSIONS})`;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
var memoryTypeEnum = pgEnum("memory_type", ["interaction", "fact", "summary"]);
|
|
91
|
-
var interactionRoleEnum = pgEnum("interaction_role", ["user", "assistant", "system"]);
|
|
92
|
-
var embeddingOwnerTypeEnum = pgEnum("embedding_owner_type", [
|
|
93
|
-
"interaction",
|
|
94
|
-
"fact",
|
|
95
|
-
"summary"
|
|
96
|
-
]);
|
|
97
|
-
var embeddingStatusEnum = pgEnum("embedding_status", [
|
|
98
|
-
"pending",
|
|
99
|
-
"processing",
|
|
100
|
-
"ready",
|
|
101
|
-
"failed"
|
|
102
|
-
]);
|
|
103
|
-
var shareModeEnum = pgEnum("share_mode", ["reference", "snapshot"]);
|
|
104
|
-
var modelCallTypeEnum = pgEnum("model_call_type", ["embedding", "llm"]);
|
|
105
|
-
var modelCallStatusEnum = pgEnum("model_call_status", [
|
|
106
|
-
"success",
|
|
107
|
-
"failed",
|
|
108
|
-
"timeout",
|
|
109
|
-
"rate_limited",
|
|
110
|
-
"gated",
|
|
111
|
-
"fallback"
|
|
112
|
-
]);
|
|
113
|
-
var auditActionEnum = pgEnum("audit_action", [
|
|
114
|
-
"remember",
|
|
115
|
-
"remember_batch",
|
|
116
|
-
"share",
|
|
117
|
-
"forget",
|
|
118
|
-
"config"
|
|
119
|
-
]);
|
|
120
|
-
var createdAt = timestamp("created_at", { withTimezone: true }).notNull().defaultNow();
|
|
121
|
-
var updatedAt = timestamp("updated_at", { withTimezone: true }).notNull().defaultNow();
|
|
122
|
-
var namespaces = pgTable(
|
|
123
|
-
"namespaces",
|
|
124
|
-
{
|
|
125
|
-
id: text("id").primaryKey(),
|
|
126
|
-
name: text("name").notNull(),
|
|
127
|
-
createdAt,
|
|
128
|
-
updatedAt
|
|
129
|
-
},
|
|
130
|
-
(table) => ({
|
|
131
|
-
nameUnique: uniqueIndex("namespaces_name_unique").on(table.name)
|
|
132
|
-
})
|
|
133
|
-
);
|
|
134
|
-
var interactions = pgTable(
|
|
135
|
-
"interactions",
|
|
136
|
-
{
|
|
137
|
-
id: text("id").primaryKey(),
|
|
138
|
-
namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
|
|
139
|
-
sessionId: text("session_id").notNull(),
|
|
140
|
-
role: interactionRoleEnum("role").notNull().default("user"),
|
|
141
|
-
content: text("content").notNull(),
|
|
142
|
-
contentHash: text("content_hash").notNull(),
|
|
143
|
-
tokenCount: integer("token_count").notNull().default(0),
|
|
144
|
-
createdByAgent: text("created_by_agent"),
|
|
145
|
-
createdAt
|
|
146
|
-
},
|
|
147
|
-
(table) => ({
|
|
148
|
-
namespaceContentHashUnique: uniqueIndex("interactions_namespace_content_hash_unique").on(
|
|
149
|
-
table.namespaceId,
|
|
150
|
-
table.contentHash
|
|
151
|
-
),
|
|
152
|
-
namespaceSessionCreatedIdx: index("interactions_namespace_session_created_idx").on(
|
|
153
|
-
table.namespaceId,
|
|
154
|
-
table.sessionId,
|
|
155
|
-
table.createdAt
|
|
156
|
-
)
|
|
157
|
-
})
|
|
158
|
-
);
|
|
159
|
-
var sessionSummaries = pgTable(
|
|
160
|
-
"session_summaries",
|
|
161
|
-
{
|
|
162
|
-
id: text("id").primaryKey(),
|
|
163
|
-
namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
|
|
164
|
-
sessionId: text("session_id").notNull(),
|
|
165
|
-
content: text("content").notNull(),
|
|
166
|
-
version: integer("version").notNull().default(1),
|
|
167
|
-
tokenCount: integer("token_count").notNull().default(0),
|
|
168
|
-
createdByAgent: text("created_by_agent"),
|
|
169
|
-
/** See facts.fileBacked. */
|
|
170
|
-
fileBacked: boolean("file_backed").notNull().default(false),
|
|
171
|
-
createdAt
|
|
172
|
-
},
|
|
173
|
-
(table) => ({
|
|
174
|
-
namespaceSessionVersionIdx: index("session_summaries_namespace_session_version_idx").on(
|
|
175
|
-
table.namespaceId,
|
|
176
|
-
table.sessionId,
|
|
177
|
-
table.version
|
|
178
|
-
)
|
|
179
|
-
})
|
|
180
|
-
);
|
|
181
|
-
var facts = pgTable(
|
|
182
|
-
"facts",
|
|
183
|
-
{
|
|
184
|
-
id: text("id").primaryKey(),
|
|
185
|
-
namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
|
|
186
|
-
subject: text("subject").notNull(),
|
|
187
|
-
predicate: text("predicate").notNull(),
|
|
188
|
-
object: text("object").notNull(),
|
|
189
|
-
propositionKey: text("proposition_key"),
|
|
190
|
-
content: text("content").notNull(),
|
|
191
|
-
contentHash: text("content_hash").notNull(),
|
|
192
|
-
confidence: numeric("confidence", { precision: 5, scale: 4 }).notNull().default("1"),
|
|
193
|
-
/**
|
|
194
|
-
* Historical provenance only — deliberately not a foreign key. Interactions
|
|
195
|
-
* are ephemeral DB rows; Markdown facts must re-import after a rebuild that
|
|
196
|
-
* lost them, and the ID must survive so `sourceDeleted` can be tracked.
|
|
197
|
-
*/
|
|
198
|
-
sourceInteractionId: text("source_interaction_id"),
|
|
199
|
-
sourceDeleted: boolean("source_deleted").notNull().default(false),
|
|
200
|
-
supersededBy: text("superseded_by"),
|
|
201
|
-
/**
|
|
202
|
-
* True once a reindex imported this row from its Markdown file. Only such
|
|
203
|
-
* rows are deleted when the file disappears; DB-only legacy rows are kept.
|
|
204
|
-
*/
|
|
205
|
-
fileBacked: boolean("file_backed").notNull().default(false),
|
|
206
|
-
embeddingModel: text("embedding_model"),
|
|
207
|
-
createdByAgent: text("created_by_agent"),
|
|
208
|
-
createdAt,
|
|
209
|
-
updatedAt
|
|
210
|
-
},
|
|
211
|
-
(table) => ({
|
|
212
|
-
namespaceContentHashUnique: uniqueIndex("facts_namespace_content_hash_unique").on(
|
|
213
|
-
table.namespaceId,
|
|
214
|
-
table.contentHash
|
|
215
|
-
),
|
|
216
|
-
namespaceSubjectIdx: index("facts_namespace_subject_idx").on(table.namespaceId, table.subject),
|
|
217
|
-
sourceInteractionIdx: index("facts_source_interaction_idx").on(table.sourceInteractionId)
|
|
218
|
-
})
|
|
219
|
-
);
|
|
220
|
-
var embeddings = pgTable(
|
|
221
|
-
"embeddings",
|
|
222
|
-
{
|
|
223
|
-
id: text("id").primaryKey(),
|
|
224
|
-
namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
|
|
225
|
-
ownerType: embeddingOwnerTypeEnum("owner_type").notNull(),
|
|
226
|
-
ownerId: text("owner_id").notNull(),
|
|
227
|
-
vector: vector("vector").notNull(),
|
|
228
|
-
embeddingModel: text("embedding_model").notNull(),
|
|
229
|
-
embeddingSpace: text("embedding_space"),
|
|
230
|
-
status: embeddingStatusEnum("status").notNull().default("pending"),
|
|
231
|
-
attempts: integer("attempts").notNull().default(0),
|
|
232
|
-
lastError: text("last_error"),
|
|
233
|
-
/** Lease deadline while status='processing'; null otherwise. */
|
|
234
|
-
leaseUntil: timestamp("lease_until", { withTimezone: true }),
|
|
235
|
-
leaseToken: text("lease_token"),
|
|
236
|
-
createdAt,
|
|
237
|
-
updatedAt
|
|
238
|
-
},
|
|
239
|
-
(table) => ({
|
|
240
|
-
ownerUnique: uniqueIndex("embeddings_owner_unique").on(table.ownerType, table.ownerId),
|
|
241
|
-
namespaceModelStatusIdx: index("embeddings_namespace_model_status_idx").on(
|
|
242
|
-
table.namespaceId,
|
|
243
|
-
table.embeddingModel,
|
|
244
|
-
table.status
|
|
245
|
-
),
|
|
246
|
-
namespaceSpaceStatusIdx: index("embeddings_namespace_space_status_idx").on(
|
|
247
|
-
table.namespaceId,
|
|
248
|
-
table.embeddingSpace,
|
|
249
|
-
table.status
|
|
250
|
-
),
|
|
251
|
-
vectorHnswIdx: index("embeddings_vector_hnsw_idx").using(
|
|
252
|
-
"hnsw",
|
|
253
|
-
sql`${table.vector} vector_cosine_ops`
|
|
254
|
-
)
|
|
255
|
-
})
|
|
256
|
-
);
|
|
257
|
-
var shares = pgTable(
|
|
258
|
-
"shares",
|
|
259
|
-
{
|
|
260
|
-
id: text("id").primaryKey(),
|
|
261
|
-
fromNamespaceId: text("from_namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
|
|
262
|
-
toNamespaceId: text("to_namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
|
|
263
|
-
sourceFactId: text("source_fact_id").notNull().references(() => facts.id, { onDelete: "cascade" }),
|
|
264
|
-
snapshotFactId: text("snapshot_fact_id").references(() => facts.id, { onDelete: "set null" }),
|
|
265
|
-
mode: shareModeEnum("mode").notNull().default("reference"),
|
|
266
|
-
tombstoned: boolean("tombstoned").notNull().default(false),
|
|
267
|
-
createdByAgent: text("created_by_agent"),
|
|
268
|
-
createdAt
|
|
269
|
-
},
|
|
270
|
-
(table) => ({
|
|
271
|
-
shareUnique: uniqueIndex("shares_target_source_unique").on(
|
|
272
|
-
table.toNamespaceId,
|
|
273
|
-
table.sourceFactId,
|
|
274
|
-
table.mode
|
|
275
|
-
),
|
|
276
|
-
fromNamespaceIdx: index("shares_from_namespace_idx").on(table.fromNamespaceId)
|
|
277
|
-
})
|
|
278
|
-
);
|
|
279
|
-
var checkpoints = pgTable(
|
|
280
|
-
"checkpoints",
|
|
281
|
-
{
|
|
282
|
-
id: text("id").primaryKey(),
|
|
283
|
-
namespaceId: text("namespace_id").notNull().references(() => namespaces.id, { onDelete: "cascade" }),
|
|
284
|
-
threadId: text("thread_id").notNull(),
|
|
285
|
-
checkpointId: text("checkpoint_id").notNull(),
|
|
286
|
-
parentId: text("parent_id"),
|
|
287
|
-
channelValues: jsonb("channel_values").notNull().default(sql`'{}'::jsonb`),
|
|
288
|
-
metadata: jsonb("metadata").notNull().default(sql`'{}'::jsonb`),
|
|
289
|
-
createdAt
|
|
290
|
-
},
|
|
291
|
-
(table) => ({
|
|
292
|
-
checkpointUnique: uniqueIndex("checkpoints_thread_checkpoint_unique").on(
|
|
293
|
-
table.namespaceId,
|
|
294
|
-
table.threadId,
|
|
295
|
-
table.checkpointId
|
|
296
|
-
)
|
|
297
|
-
})
|
|
298
|
-
);
|
|
299
|
-
var modelCalls = pgTable(
|
|
300
|
-
"model_calls",
|
|
301
|
-
{
|
|
302
|
-
id: text("id").primaryKey(),
|
|
303
|
-
namespaceId: text("namespace_id").references(() => namespaces.id, { onDelete: "set null" }),
|
|
304
|
-
model: text("model").notNull(),
|
|
305
|
-
type: modelCallTypeEnum("type").notNull(),
|
|
306
|
-
latencyMs: integer("latency_ms"),
|
|
307
|
-
tokens: integer("tokens"),
|
|
308
|
-
status: modelCallStatusEnum("status").notNull(),
|
|
309
|
-
error: text("error"),
|
|
310
|
-
metadata: jsonb("metadata").notNull().default(sql`'{}'::jsonb`),
|
|
311
|
-
createdAt
|
|
312
|
-
},
|
|
313
|
-
(table) => ({
|
|
314
|
-
modelCreatedIdx: index("model_calls_model_created_idx").on(table.model, table.createdAt),
|
|
315
|
-
namespaceCreatedIdx: index("model_calls_namespace_created_idx").on(
|
|
316
|
-
table.namespaceId,
|
|
317
|
-
table.createdAt
|
|
318
|
-
)
|
|
319
|
-
})
|
|
320
|
-
);
|
|
321
|
-
var auditLog = pgTable(
|
|
322
|
-
"audit_log",
|
|
323
|
-
{
|
|
324
|
-
id: text("id").primaryKey(),
|
|
325
|
-
namespaceId: text("namespace_id").references(() => namespaces.id, { onDelete: "set null" }),
|
|
326
|
-
action: auditActionEnum("action").notNull(),
|
|
327
|
-
entityType: text("entity_type").notNull(),
|
|
328
|
-
entityId: text("entity_id"),
|
|
329
|
-
createdByAgent: text("created_by_agent"),
|
|
330
|
-
metadata: jsonb("metadata").notNull().default(sql`'{}'::jsonb`),
|
|
331
|
-
createdAt
|
|
332
|
-
},
|
|
333
|
-
(table) => ({
|
|
334
|
-
namespaceActionCreatedIdx: index("audit_log_namespace_action_created_idx").on(
|
|
335
|
-
table.namespaceId,
|
|
336
|
-
table.action,
|
|
337
|
-
table.createdAt
|
|
338
|
-
)
|
|
339
|
-
})
|
|
340
|
-
);
|
|
51
|
+
redactSecrets
|
|
52
|
+
} from "./chunk-5KZY6OTG.js";
|
|
341
53
|
|
|
342
54
|
// src/db/bootstrap.ts
|
|
343
|
-
async function enablePgvector(
|
|
344
|
-
await
|
|
55
|
+
async function enablePgvector(sql2) {
|
|
56
|
+
await sql2`create extension if not exists vector`;
|
|
345
57
|
}
|
|
346
|
-
async function checkPgvector(
|
|
347
|
-
const result = await
|
|
58
|
+
async function checkPgvector(sql2) {
|
|
59
|
+
const result = await sql2`
|
|
348
60
|
select extversion from pg_extension where extname = 'vector'
|
|
349
61
|
`;
|
|
350
62
|
return {
|
|
@@ -352,16 +64,30 @@ async function checkPgvector(sql3) {
|
|
|
352
64
|
installedVersion: result[0]?.extversion ?? null
|
|
353
65
|
};
|
|
354
66
|
}
|
|
355
|
-
async function bootstrapDatabase(
|
|
356
|
-
await enablePgvector(
|
|
357
|
-
return checkPgvector(
|
|
67
|
+
async function bootstrapDatabase(sql2) {
|
|
68
|
+
await withSchemaLock(sql2, () => enablePgvector(sql2));
|
|
69
|
+
return checkPgvector(sql2);
|
|
70
|
+
}
|
|
71
|
+
var SCHEMA_LOCK = 7310250421;
|
|
72
|
+
async function withSchemaLock(sql2, work) {
|
|
73
|
+
const reserved = await sql2.reserve();
|
|
74
|
+
try {
|
|
75
|
+
await reserved`select pg_advisory_lock(${SCHEMA_LOCK}::bigint)`;
|
|
76
|
+
try {
|
|
77
|
+
return await work();
|
|
78
|
+
} finally {
|
|
79
|
+
await reserved`select pg_advisory_unlock(${SCHEMA_LOCK}::bigint)`;
|
|
80
|
+
}
|
|
81
|
+
} finally {
|
|
82
|
+
reserved.release();
|
|
83
|
+
}
|
|
358
84
|
}
|
|
359
85
|
|
|
360
86
|
// src/db/client.ts
|
|
361
87
|
import { drizzle } from "drizzle-orm/postgres-js";
|
|
362
88
|
import postgres from "postgres";
|
|
363
89
|
function createDatabaseClient(config) {
|
|
364
|
-
const
|
|
90
|
+
const sql2 = postgres(config.postgresUrl, {
|
|
365
91
|
max: config.maxConnections ?? 10,
|
|
366
92
|
...config.connectTimeoutSeconds !== void 0 ? { connect_timeout: config.connectTimeoutSeconds } : {},
|
|
367
93
|
// postgres.js logs NOTICE messages (e.g. "extension already exists,
|
|
@@ -375,10 +101,10 @@ function createDatabaseClient(config) {
|
|
|
375
101
|
}
|
|
376
102
|
});
|
|
377
103
|
return {
|
|
378
|
-
sql:
|
|
379
|
-
db: drizzle(
|
|
104
|
+
sql: sql2,
|
|
105
|
+
db: drizzle(sql2, { schema: schema_exports }),
|
|
380
106
|
async close() {
|
|
381
|
-
await
|
|
107
|
+
await sql2.end({ timeout: 2 });
|
|
382
108
|
}
|
|
383
109
|
};
|
|
384
110
|
}
|
|
@@ -416,165 +142,13 @@ If this is an npm-installed package, make sure src/db/migrations was included in
|
|
|
416
142
|
}
|
|
417
143
|
async function runMigrations(client) {
|
|
418
144
|
const migrationsFolder = resolveMigrationsFolder();
|
|
419
|
-
await migrate(client.db, { migrationsFolder });
|
|
145
|
+
await withSchemaLock(client.sql, () => migrate(client.db, { migrationsFolder }));
|
|
420
146
|
}
|
|
421
147
|
|
|
422
148
|
// src/db/repository.ts
|
|
423
149
|
import { AsyncLocalStorage } from "async_hooks";
|
|
424
150
|
import { createHash } from "crypto";
|
|
425
|
-
import { and, desc, eq, inArray, isNull, lt, ne, or, sql
|
|
426
|
-
|
|
427
|
-
// src/core/memory-search.ts
|
|
428
|
-
function candidateLimit(limit) {
|
|
429
|
-
if (!Number.isFinite(limit)) return 256;
|
|
430
|
-
return Math.max(1, Math.min(1024, Math.trunc(limit)));
|
|
431
|
-
}
|
|
432
|
-
function validSearchVector(vector2) {
|
|
433
|
-
return vector2.length === VECTOR_DIMENSIONS && vector2.every((value) => Number.isFinite(Math.fround(value))) && vector2.some((value) => value !== 0);
|
|
434
|
-
}
|
|
435
|
-
var QUERY_STOPWORDS = /* @__PURE__ */ new Set([
|
|
436
|
-
"a",
|
|
437
|
-
"about",
|
|
438
|
-
"after",
|
|
439
|
-
"again",
|
|
440
|
-
"all",
|
|
441
|
-
"also",
|
|
442
|
-
"always",
|
|
443
|
-
"an",
|
|
444
|
-
"and",
|
|
445
|
-
"any",
|
|
446
|
-
"are",
|
|
447
|
-
"as",
|
|
448
|
-
"at",
|
|
449
|
-
"back",
|
|
450
|
-
"be",
|
|
451
|
-
"been",
|
|
452
|
-
"before",
|
|
453
|
-
"being",
|
|
454
|
-
"but",
|
|
455
|
-
"by",
|
|
456
|
-
"can",
|
|
457
|
-
"could",
|
|
458
|
-
"did",
|
|
459
|
-
"do",
|
|
460
|
-
"does",
|
|
461
|
-
"done",
|
|
462
|
-
"each",
|
|
463
|
-
"even",
|
|
464
|
-
"ever",
|
|
465
|
-
"for",
|
|
466
|
-
"from",
|
|
467
|
-
"get",
|
|
468
|
-
"gets",
|
|
469
|
-
"got",
|
|
470
|
-
"had",
|
|
471
|
-
"has",
|
|
472
|
-
"have",
|
|
473
|
-
"here",
|
|
474
|
-
"how",
|
|
475
|
-
"i",
|
|
476
|
-
"if",
|
|
477
|
-
"in",
|
|
478
|
-
"into",
|
|
479
|
-
"is",
|
|
480
|
-
"it",
|
|
481
|
-
"its",
|
|
482
|
-
"just",
|
|
483
|
-
"like",
|
|
484
|
-
"make",
|
|
485
|
-
"me",
|
|
486
|
-
"more",
|
|
487
|
-
"most",
|
|
488
|
-
"my",
|
|
489
|
-
"never",
|
|
490
|
-
"no",
|
|
491
|
-
"not",
|
|
492
|
-
"now",
|
|
493
|
-
"of",
|
|
494
|
-
"on",
|
|
495
|
-
"only",
|
|
496
|
-
"or",
|
|
497
|
-
"other",
|
|
498
|
-
"our",
|
|
499
|
-
"out",
|
|
500
|
-
"over",
|
|
501
|
-
"please",
|
|
502
|
-
"really",
|
|
503
|
-
"same",
|
|
504
|
-
"should",
|
|
505
|
-
"so",
|
|
506
|
-
"some",
|
|
507
|
-
"sometimes",
|
|
508
|
-
"still",
|
|
509
|
-
"such",
|
|
510
|
-
"than",
|
|
511
|
-
"that",
|
|
512
|
-
"the",
|
|
513
|
-
"their",
|
|
514
|
-
"them",
|
|
515
|
-
"then",
|
|
516
|
-
"there",
|
|
517
|
-
"these",
|
|
518
|
-
"they",
|
|
519
|
-
"this",
|
|
520
|
-
"those",
|
|
521
|
-
"through",
|
|
522
|
-
"to",
|
|
523
|
-
"too",
|
|
524
|
-
"under",
|
|
525
|
-
"up",
|
|
526
|
-
"us",
|
|
527
|
-
"very",
|
|
528
|
-
"was",
|
|
529
|
-
"we",
|
|
530
|
-
"were",
|
|
531
|
-
"what",
|
|
532
|
-
"when",
|
|
533
|
-
"where",
|
|
534
|
-
"which",
|
|
535
|
-
"while",
|
|
536
|
-
"who",
|
|
537
|
-
"why",
|
|
538
|
-
"will",
|
|
539
|
-
"with",
|
|
540
|
-
"would",
|
|
541
|
-
"yet",
|
|
542
|
-
"you",
|
|
543
|
-
"your"
|
|
544
|
-
]);
|
|
545
|
-
function lexicalTerms(query) {
|
|
546
|
-
return [
|
|
547
|
-
...new Set(
|
|
548
|
-
query.slice(0, 4096).toLowerCase().match(/[\p{L}\p{N}_]+/gu) ?? []
|
|
549
|
-
)
|
|
550
|
-
].filter((term) => !QUERY_STOPWORDS.has(term)).slice(0, 32).map((term) => term.slice(0, 64));
|
|
551
|
-
}
|
|
552
|
-
var CLAIM_BOILERPLATE = /* @__PURE__ */ new Set([
|
|
553
|
-
"decided",
|
|
554
|
-
"decide",
|
|
555
|
-
"decision",
|
|
556
|
-
"made",
|
|
557
|
-
"use",
|
|
558
|
-
"uses",
|
|
559
|
-
"used",
|
|
560
|
-
"using",
|
|
561
|
-
"now",
|
|
562
|
-
"going",
|
|
563
|
-
"will"
|
|
564
|
-
]);
|
|
565
|
-
function termOverlap(a, b) {
|
|
566
|
-
const terms = (text2) => new Set(
|
|
567
|
-
(text2.toLowerCase().match(/[\p{L}\p{N}_]+/gu) ?? []).filter(
|
|
568
|
-
(term) => !QUERY_STOPWORDS.has(term) && !CLAIM_BOILERPLATE.has(term)
|
|
569
|
-
)
|
|
570
|
-
);
|
|
571
|
-
const left = terms(a);
|
|
572
|
-
const right = terms(b);
|
|
573
|
-
if (left.size === 0 || right.size === 0) return 0;
|
|
574
|
-
let shared = 0;
|
|
575
|
-
for (const term of left) if (right.has(term)) shared += 1;
|
|
576
|
-
return shared / (left.size + right.size - shared);
|
|
577
|
-
}
|
|
151
|
+
import { and, desc, eq, inArray, isNull, lt, ne, or, sql } from "drizzle-orm";
|
|
578
152
|
|
|
579
153
|
// src/providers/embedding-space.ts
|
|
580
154
|
function embeddingSpace(response) {
|
|
@@ -592,12 +166,12 @@ function embeddingSpace(response) {
|
|
|
592
166
|
function embeddingSpaceKey(space) {
|
|
593
167
|
return JSON.stringify([space.model, space.revision, space.schema, space.dimensions]);
|
|
594
168
|
}
|
|
595
|
-
function validEmbeddingVector(
|
|
596
|
-
return dimensions > 0 &&
|
|
169
|
+
function validEmbeddingVector(vector, dimensions) {
|
|
170
|
+
return dimensions > 0 && vector.length === dimensions && vector.every(Number.isFinite);
|
|
597
171
|
}
|
|
598
172
|
function validateEmbeddingResponse(response, count) {
|
|
599
173
|
embeddingSpace(response);
|
|
600
|
-
if (response.vectors.length !== count || response.vectors.some((
|
|
174
|
+
if (response.vectors.length !== count || response.vectors.some((vector) => !validEmbeddingVector(vector, response.dimensions))) {
|
|
601
175
|
throw new Error("Provider returned invalid embedding dimensions, values, or batch size.");
|
|
602
176
|
}
|
|
603
177
|
}
|
|
@@ -628,7 +202,7 @@ var PostgresMemoryRepository = class {
|
|
|
628
202
|
async withSessionLock(namespaceId, sessionId, fn) {
|
|
629
203
|
const [k1, k2] = advisoryLockKeys(namespaceId, sessionId);
|
|
630
204
|
return this.client.db.transaction(async (tx) => {
|
|
631
|
-
await tx.execute(
|
|
205
|
+
await tx.execute(sql`select pg_advisory_xact_lock(${k1}, ${k2})`);
|
|
632
206
|
return this.sessionTransaction.run(tx, fn);
|
|
633
207
|
});
|
|
634
208
|
}
|
|
@@ -809,7 +383,7 @@ var PostgresMemoryRepository = class {
|
|
|
809
383
|
const contentChanged = existing.content !== fact.content;
|
|
810
384
|
const metadataChanged = existing.subject !== values.subject || existing.predicate !== values.predicate || existing.object !== values.object || Number(existing.confidence) !== Number(fact.confidence.toFixed(4)) || existing.sourceInteractionId !== values.sourceInteractionId || existing.sourceDeleted !== values.sourceDeleted || existing.supersededBy !== values.supersededBy || existing.propositionKey !== values.propositionKey || existing.createdByAgent !== values.createdByAgent || existing.createdAt.getTime() !== values.createdAt.getTime();
|
|
811
385
|
if (contentChanged || metadataChanged || !existing.fileBacked) {
|
|
812
|
-
await tx.update(facts).set({ ...values, updatedAt:
|
|
386
|
+
await tx.update(facts).set({ ...values, updatedAt: sql`now()` }).where(and(eq(facts.namespaceId, fact.namespaceId), eq(facts.id, fact.id)));
|
|
813
387
|
}
|
|
814
388
|
await upsertPendingEmbedding(tx, input.embedding, contentChanged);
|
|
815
389
|
if (!contentChanged && !metadataChanged) return { status: "unchanged" };
|
|
@@ -878,12 +452,13 @@ var PostgresMemoryRepository = class {
|
|
|
878
452
|
* item twice. Expired leases are re-claimable, so a crashed worker's work is
|
|
879
453
|
* picked up again instead of being stuck forever.
|
|
880
454
|
*/
|
|
881
|
-
async claimPendingEmbeddings(limit) {
|
|
455
|
+
async claimPendingEmbeddings(limit, namespaceId) {
|
|
882
456
|
const rows = await this.client.sql`
|
|
883
457
|
with claimed as (
|
|
884
458
|
select id from embeddings
|
|
885
|
-
where status = 'pending'
|
|
886
|
-
or (status = 'processing' and (lease_until is null or lease_until < now()))
|
|
459
|
+
where (status = 'pending'
|
|
460
|
+
or (status = 'processing' and (lease_until is null or lease_until < now())))
|
|
461
|
+
and (${namespaceId ?? null}::text is null or namespace_id = ${namespaceId ?? null})
|
|
887
462
|
order by created_at asc
|
|
888
463
|
for update skip locked
|
|
889
464
|
limit ${limit}
|
|
@@ -922,33 +497,33 @@ var PostgresMemoryRepository = class {
|
|
|
922
497
|
}));
|
|
923
498
|
}
|
|
924
499
|
async renewEmbeddingLease(id, leaseToken) {
|
|
925
|
-
const rows = await this.db.update(embeddings).set({ leaseUntil:
|
|
500
|
+
const rows = await this.db.update(embeddings).set({ leaseUntil: sql`now() + interval '120 seconds'` }).where(
|
|
926
501
|
and(
|
|
927
502
|
eq(embeddings.id, id),
|
|
928
503
|
eq(embeddings.leaseToken, leaseToken),
|
|
929
504
|
eq(embeddings.status, "processing"),
|
|
930
|
-
|
|
505
|
+
sql`${embeddings.leaseUntil} > now()`
|
|
931
506
|
)
|
|
932
507
|
).returning({ id: embeddings.id });
|
|
933
508
|
return rows.length > 0;
|
|
934
509
|
}
|
|
935
|
-
async markEmbeddingReady(id, leaseToken,
|
|
936
|
-
const literal = `[${
|
|
510
|
+
async markEmbeddingReady(id, leaseToken, vector, model, space) {
|
|
511
|
+
const literal = `[${vector.join(",")}]`;
|
|
937
512
|
const rows = await this.db.update(embeddings).set({
|
|
938
513
|
status: "ready",
|
|
939
514
|
vector: literal,
|
|
940
515
|
embeddingModel: model,
|
|
941
|
-
embeddingSpace: space ?? embeddingSpaceKey(embeddingSpace({ model, dimensions:
|
|
516
|
+
embeddingSpace: space ?? embeddingSpaceKey(embeddingSpace({ model, dimensions: vector.length })),
|
|
942
517
|
lastError: null,
|
|
943
518
|
leaseUntil: null,
|
|
944
519
|
leaseToken: null,
|
|
945
|
-
updatedAt:
|
|
520
|
+
updatedAt: sql`now()`
|
|
946
521
|
}).where(
|
|
947
522
|
and(
|
|
948
523
|
eq(embeddings.id, id),
|
|
949
524
|
eq(embeddings.leaseToken, leaseToken),
|
|
950
525
|
eq(embeddings.status, "processing"),
|
|
951
|
-
|
|
526
|
+
sql`${embeddings.leaseUntil} > now()`
|
|
952
527
|
)
|
|
953
528
|
).returning({ id: embeddings.id });
|
|
954
529
|
return rows.length > 0;
|
|
@@ -964,18 +539,18 @@ var PostgresMemoryRepository = class {
|
|
|
964
539
|
const maxAttempts = options?.maxAttempts ?? 5;
|
|
965
540
|
const backoffSeconds = Math.min(60, 2 ** Math.max(0, attempts - 1));
|
|
966
541
|
const rows = await this.db.update(embeddings).set({
|
|
967
|
-
status:
|
|
968
|
-
leaseUntil:
|
|
542
|
+
status: sql`case when ${attempts} >= ${maxAttempts} then 'failed'::embedding_status else 'processing'::embedding_status end`,
|
|
543
|
+
leaseUntil: sql`case when ${attempts} >= ${maxAttempts} then null else now() + (${backoffSeconds} || ' seconds')::interval end`,
|
|
969
544
|
leaseToken: null,
|
|
970
545
|
attempts,
|
|
971
546
|
lastError: error,
|
|
972
|
-
updatedAt:
|
|
547
|
+
updatedAt: sql`now()`
|
|
973
548
|
}).where(
|
|
974
549
|
and(
|
|
975
550
|
eq(embeddings.id, id),
|
|
976
551
|
eq(embeddings.leaseToken, leaseToken),
|
|
977
552
|
eq(embeddings.status, "processing"),
|
|
978
|
-
|
|
553
|
+
sql`${embeddings.leaseUntil} > now()`
|
|
979
554
|
)
|
|
980
555
|
).returning({ id: embeddings.id });
|
|
981
556
|
return rows.length > 0;
|
|
@@ -1192,12 +767,12 @@ var PostgresMemoryRepository = class {
|
|
|
1192
767
|
lastError: null,
|
|
1193
768
|
leaseUntil: null,
|
|
1194
769
|
leaseToken: null,
|
|
1195
|
-
updatedAt:
|
|
770
|
+
updatedAt: sql`now()`
|
|
1196
771
|
}).where(
|
|
1197
772
|
and(
|
|
1198
773
|
eq(embeddings.namespaceId, namespaceId),
|
|
1199
774
|
inArray(embeddings.status, ["ready", "failed"]),
|
|
1200
|
-
|
|
775
|
+
sql`${embeddings.embeddingSpace} is distinct from ${space}`
|
|
1201
776
|
)
|
|
1202
777
|
).returning({ id: embeddings.id });
|
|
1203
778
|
return rows.length;
|
|
@@ -1205,7 +780,7 @@ var PostgresMemoryRepository = class {
|
|
|
1205
780
|
async searchSimilarEmbeddings(input) {
|
|
1206
781
|
if (!validSearchVector(input.vector))
|
|
1207
782
|
return { method: "exact_pgvector", candidates: [], compatibleReady: 0 };
|
|
1208
|
-
const rows = await this.db.execute(
|
|
783
|
+
const rows = await this.db.execute(sql`
|
|
1209
784
|
with compatible as materialized (
|
|
1210
785
|
select id, owner_type, owner_id, embedding_model, embedding_space, vector
|
|
1211
786
|
from embeddings
|
|
@@ -1214,7 +789,7 @@ var PostgresMemoryRepository = class {
|
|
|
1214
789
|
namespace_id = ${input.namespaceId}
|
|
1215
790
|
or (
|
|
1216
791
|
owner_type = 'fact'
|
|
1217
|
-
and ${liveReference(input.namespaceId,
|
|
792
|
+
and ${liveReference(input.namespaceId, sql`embeddings.namespace_id`, sql`embeddings.owner_id`)}
|
|
1218
793
|
)
|
|
1219
794
|
)
|
|
1220
795
|
and embedding_space = ${input.embeddingSpace}
|
|
@@ -1250,7 +825,7 @@ var PostgresMemoryRepository = class {
|
|
|
1250
825
|
async searchFactsLexically(namespaceId, query, limit) {
|
|
1251
826
|
const terms = lexicalTerms(query);
|
|
1252
827
|
if (!terms.length) return { candidates: [], matchedFacts: 0 };
|
|
1253
|
-
const rows = await this.db.execute(
|
|
828
|
+
const rows = await this.db.execute(sql`
|
|
1254
829
|
with scored as materialized (
|
|
1255
830
|
select id, content, subject, predicate, object, proposition_key, confidence,
|
|
1256
831
|
created_by_agent, created_at,
|
|
@@ -1264,7 +839,7 @@ var PostgresMemoryRepository = class {
|
|
|
1264
839
|
where not source_deleted and superseded_by is null
|
|
1265
840
|
and (
|
|
1266
841
|
namespace_id = ${namespaceId}
|
|
1267
|
-
or ${liveReference(namespaceId,
|
|
842
|
+
or ${liveReference(namespaceId, sql`facts.namespace_id`, sql`facts.id`)}
|
|
1268
843
|
)
|
|
1269
844
|
)
|
|
1270
845
|
select *, count(*) over () as total from scored where score > 0
|
|
@@ -1343,7 +918,7 @@ var PostgresMemoryRepository = class {
|
|
|
1343
918
|
isNull(facts.supersededBy),
|
|
1344
919
|
or(
|
|
1345
920
|
eq(facts.namespaceId, namespaceId),
|
|
1346
|
-
liveReference(namespaceId,
|
|
921
|
+
liveReference(namespaceId, sql`${facts.namespaceId}`, sql`${facts.id}`)
|
|
1347
922
|
)
|
|
1348
923
|
)
|
|
1349
924
|
);
|
|
@@ -1602,11 +1177,11 @@ var PostgresMemoryRepository = class {
|
|
|
1602
1177
|
limit 1
|
|
1603
1178
|
`;
|
|
1604
1179
|
const vectorCount = Number(countRows[0]?.count ?? 0);
|
|
1605
|
-
const
|
|
1180
|
+
const index = indexRows[0];
|
|
1606
1181
|
return {
|
|
1607
1182
|
vectorCount,
|
|
1608
|
-
indexName:
|
|
1609
|
-
indexDefinition:
|
|
1183
|
+
indexName: index?.indexname ?? null,
|
|
1184
|
+
indexDefinition: index?.indexdef ?? null,
|
|
1610
1185
|
needsTuning: vectorCount >= 1e5
|
|
1611
1186
|
};
|
|
1612
1187
|
}
|
|
@@ -1650,7 +1225,7 @@ async function upsertPendingEmbedding(tx, embedding, reset) {
|
|
|
1650
1225
|
lastError: null,
|
|
1651
1226
|
leaseUntil: null,
|
|
1652
1227
|
leaseToken: null,
|
|
1653
|
-
updatedAt:
|
|
1228
|
+
updatedAt: sql`now()`
|
|
1654
1229
|
}
|
|
1655
1230
|
});
|
|
1656
1231
|
}
|
|
@@ -1682,7 +1257,7 @@ var recentFactColumns = {
|
|
|
1682
1257
|
createdAt: facts.createdAt
|
|
1683
1258
|
};
|
|
1684
1259
|
function liveReference(namespaceId, ownerNamespace, factId) {
|
|
1685
|
-
return
|
|
1260
|
+
return sql`exists (
|
|
1686
1261
|
select 1 from shares s
|
|
1687
1262
|
where s.to_namespace_id = ${namespaceId}
|
|
1688
1263
|
and s.from_namespace_id = ${ownerNamespace}
|
|
@@ -1695,14 +1270,6 @@ function liveReference(namespaceId, ownerNamespace, factId) {
|
|
|
1695
1270
|
// src/core/codebuddy.ts
|
|
1696
1271
|
import pTimeout2 from "p-timeout";
|
|
1697
1272
|
|
|
1698
|
-
// src/core/memory-lifecycle.ts
|
|
1699
|
-
function isEligibleMemory(fact, options = {}) {
|
|
1700
|
-
if (options.namespace && fact.namespace !== options.namespace) return false;
|
|
1701
|
-
if (fact.sourceDeleted || fact.supersededBy) return false;
|
|
1702
|
-
if (fact.category === "incident" && fact.resolvedBy && !options.includeResolved) return false;
|
|
1703
|
-
return true;
|
|
1704
|
-
}
|
|
1705
|
-
|
|
1706
1273
|
// src/planner/default-policy.ts
|
|
1707
1274
|
var DefaultPolicy = class {
|
|
1708
1275
|
recencyFloorSize;
|
|
@@ -2108,8 +1675,8 @@ var HuggingFaceResilience = class {
|
|
|
2108
1675
|
async execute(input) {
|
|
2109
1676
|
const models = [input.model, ...input.fallbackModels ?? []];
|
|
2110
1677
|
let lastError;
|
|
2111
|
-
for (const [
|
|
2112
|
-
const fallbackTriggered =
|
|
1678
|
+
for (const [index, model] of models.entries()) {
|
|
1679
|
+
const fallbackTriggered = index > 0;
|
|
2113
1680
|
try {
|
|
2114
1681
|
return await this.executeForModel(model, input, fallbackTriggered);
|
|
2115
1682
|
} catch (error) {
|
|
@@ -2176,8 +1743,7 @@ var HuggingFaceResilience = class {
|
|
|
2176
1743
|
retries = error.attemptNumber;
|
|
2177
1744
|
}
|
|
2178
1745
|
}
|
|
2179
|
-
)
|
|
2180
|
-
{ throwOnTimeout: true }
|
|
1746
|
+
)
|
|
2181
1747
|
);
|
|
2182
1748
|
this.markWarm(model);
|
|
2183
1749
|
status = fallbackTriggered ? "fallback" : "success";
|
|
@@ -2310,7 +1876,7 @@ function readRetryAfterMs(error) {
|
|
|
2310
1876
|
return Number.isFinite(retryAfterSeconds) ? retryAfterSeconds * 1e3 : void 0;
|
|
2311
1877
|
}
|
|
2312
1878
|
function sleep(ms) {
|
|
2313
|
-
return new Promise((
|
|
1879
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2314
1880
|
}
|
|
2315
1881
|
|
|
2316
1882
|
// src/providers/huggingface.ts
|
|
@@ -2415,7 +1981,7 @@ function normalizeEmbeddingResponse(response) {
|
|
|
2415
1981
|
return [response];
|
|
2416
1982
|
}
|
|
2417
1983
|
if (response.every(
|
|
2418
|
-
(
|
|
1984
|
+
(vector) => Array.isArray(vector) && vector.every((value) => typeof value === "number")
|
|
2419
1985
|
)) {
|
|
2420
1986
|
return response;
|
|
2421
1987
|
}
|
|
@@ -2505,308 +2071,6 @@ function validateConfig(config) {
|
|
|
2505
2071
|
return codeBuddyConfigSchema.parse(config);
|
|
2506
2072
|
}
|
|
2507
2073
|
|
|
2508
|
-
// src/core/memory-file-store.ts
|
|
2509
|
-
import { mkdir, readdir, readFile, rm } from "fs/promises";
|
|
2510
|
-
import { dirname as dirname2, join, relative, resolve as resolve2, sep } from "path";
|
|
2511
|
-
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
2512
|
-
import { z as z2 } from "zod";
|
|
2513
|
-
var FACT_CATEGORIES = ["general", "incident"];
|
|
2514
|
-
var INCIDENT_SEVERITIES = ["low", "medium", "high", "critical"];
|
|
2515
|
-
var factFrontMatterSchema = z2.object({
|
|
2516
|
-
schemaVersion: z2.literal(1),
|
|
2517
|
-
id: z2.string().regex(/^fact_[a-z0-9]+$/),
|
|
2518
|
-
namespace: z2.string().min(1),
|
|
2519
|
-
type: z2.literal("fact"),
|
|
2520
|
-
subject: z2.string(),
|
|
2521
|
-
predicate: z2.string(),
|
|
2522
|
-
object: z2.string(),
|
|
2523
|
-
/** Explicit single-valued claim identity; facts sharing it are rival assertions. */
|
|
2524
|
-
propositionKey: z2.string().min(1).nullable().default(null),
|
|
2525
|
-
confidence: z2.number().min(0).max(1),
|
|
2526
|
-
createdAt: z2.preprocess(
|
|
2527
|
-
(value) => value instanceof Date ? value.toISOString() : value,
|
|
2528
|
-
z2.string().datetime()
|
|
2529
|
-
),
|
|
2530
|
-
createdByAgent: z2.string().nullable(),
|
|
2531
|
-
sourceInteractionId: z2.string().nullable(),
|
|
2532
|
-
sourceDeleted: z2.boolean(),
|
|
2533
|
-
category: z2.enum(FACT_CATEGORIES).default("general"),
|
|
2534
|
-
paths: z2.array(z2.string().min(1)).default([]),
|
|
2535
|
-
severity: z2.enum(INCIDENT_SEVERITIES).nullable().default(null),
|
|
2536
|
-
introducedBy: z2.string().nullable().default(null),
|
|
2537
|
-
resolvedBy: z2.string().nullable().default(null),
|
|
2538
|
-
fingerprint: z2.string().regex(/^[a-f0-9]{64}$/).nullable().default(null),
|
|
2539
|
-
sourcePlanId: z2.string().nullable().default(null),
|
|
2540
|
-
sourceSessionId: z2.string().nullable().default(null),
|
|
2541
|
-
verification: z2.array(z2.string()).default([]),
|
|
2542
|
-
supersededBy: z2.string().nullable().default(null),
|
|
2543
|
-
/** Namespaces granted a live reference to this fact (durable form of reference shares). */
|
|
2544
|
-
sharedWith: z2.array(z2.string().min(1)).default([])
|
|
2545
|
-
});
|
|
2546
|
-
var summaryFrontMatterSchema = z2.object({
|
|
2547
|
-
schemaVersion: z2.literal(1),
|
|
2548
|
-
id: z2.string().regex(/^sum_[a-z0-9]+$/),
|
|
2549
|
-
namespace: z2.string().min(1),
|
|
2550
|
-
type: z2.literal("summary"),
|
|
2551
|
-
sessionId: z2.string().min(1),
|
|
2552
|
-
version: z2.number().int().positive(),
|
|
2553
|
-
tokenCount: z2.number().int().nonnegative(),
|
|
2554
|
-
createdAt: z2.preprocess(
|
|
2555
|
-
(value) => value instanceof Date ? value.toISOString() : value,
|
|
2556
|
-
z2.string().datetime()
|
|
2557
|
-
),
|
|
2558
|
-
createdByAgent: z2.string().nullable()
|
|
2559
|
-
});
|
|
2560
|
-
var MemoryFileStore = class {
|
|
2561
|
-
repositoryRoot;
|
|
2562
|
-
factsDirectory;
|
|
2563
|
-
summariesDirectory;
|
|
2564
|
-
constructor(repositoryRoot = process.cwd()) {
|
|
2565
|
-
this.repositoryRoot = resolve2(repositoryRoot);
|
|
2566
|
-
this.factsDirectory = join(this.repositoryRoot, ".codebuddy", "memory", "facts");
|
|
2567
|
-
this.summariesDirectory = join(this.repositoryRoot, ".codebuddy", "memory", "summaries");
|
|
2568
|
-
}
|
|
2569
|
-
async writeFact(raw) {
|
|
2570
|
-
const input = redactPersisted(raw);
|
|
2571
|
-
const path = this.factPath(input.id);
|
|
2572
|
-
await this.prepareDirectory(this.factsDirectory);
|
|
2573
|
-
await assertNoSymlinkBetween(this.repositoryRoot, dirname2(path));
|
|
2574
|
-
const metadata = {
|
|
2575
|
-
schemaVersion: 1,
|
|
2576
|
-
id: input.id,
|
|
2577
|
-
namespace: input.namespace,
|
|
2578
|
-
type: "fact",
|
|
2579
|
-
subject: input.subject,
|
|
2580
|
-
predicate: input.predicate,
|
|
2581
|
-
object: input.object,
|
|
2582
|
-
propositionKey: input.propositionKey,
|
|
2583
|
-
confidence: input.confidence,
|
|
2584
|
-
createdAt: input.createdAt,
|
|
2585
|
-
createdByAgent: input.createdByAgent,
|
|
2586
|
-
sourceInteractionId: input.sourceInteractionId,
|
|
2587
|
-
sourceDeleted: input.sourceDeleted,
|
|
2588
|
-
category: input.category,
|
|
2589
|
-
paths: input.paths,
|
|
2590
|
-
severity: input.severity,
|
|
2591
|
-
introducedBy: input.introducedBy,
|
|
2592
|
-
resolvedBy: input.resolvedBy,
|
|
2593
|
-
fingerprint: input.fingerprint,
|
|
2594
|
-
sourcePlanId: input.sourcePlanId,
|
|
2595
|
-
sourceSessionId: input.sourceSessionId,
|
|
2596
|
-
verification: input.verification,
|
|
2597
|
-
supersededBy: input.supersededBy,
|
|
2598
|
-
sharedWith: input.sharedWith
|
|
2599
|
-
};
|
|
2600
|
-
const frontMatter = stringifyYaml(stripUndefinedAndDefaultIncidentFields(metadata));
|
|
2601
|
-
await writeAtomic(path, composeMarkdown(frontMatter, input.content));
|
|
2602
|
-
return path;
|
|
2603
|
-
}
|
|
2604
|
-
async writeSummary(input) {
|
|
2605
|
-
const path = this.summaryPath(input.id);
|
|
2606
|
-
await this.prepareDirectory(this.summariesDirectory);
|
|
2607
|
-
await assertNoSymlinkBetween(this.repositoryRoot, dirname2(path));
|
|
2608
|
-
const metadata = stringifyYaml({
|
|
2609
|
-
schemaVersion: 1,
|
|
2610
|
-
id: input.id,
|
|
2611
|
-
namespace: input.namespace,
|
|
2612
|
-
type: "summary",
|
|
2613
|
-
sessionId: input.sessionId,
|
|
2614
|
-
version: input.version,
|
|
2615
|
-
tokenCount: input.tokenCount,
|
|
2616
|
-
createdAt: input.createdAt,
|
|
2617
|
-
createdByAgent: input.createdByAgent
|
|
2618
|
-
});
|
|
2619
|
-
await writeAtomic(path, composeMarkdown(metadata, input.content));
|
|
2620
|
-
return path;
|
|
2621
|
-
}
|
|
2622
|
-
async readFact(pathOrId) {
|
|
2623
|
-
const path = pathOrId.endsWith(".md") ? this.safePath(pathOrId) : this.factPath(pathOrId);
|
|
2624
|
-
await assertNoSymlinkBetween(this.repositoryRoot, path);
|
|
2625
|
-
const parsed = parseFrontMatter(await readFile(path, "utf8"));
|
|
2626
|
-
const metadata = factFrontMatterSchema.parse(parseYaml(parsed.frontMatter));
|
|
2627
|
-
return {
|
|
2628
|
-
...metadata,
|
|
2629
|
-
content: parsed.content.trim(),
|
|
2630
|
-
path
|
|
2631
|
-
};
|
|
2632
|
-
}
|
|
2633
|
-
async listFacts() {
|
|
2634
|
-
return (await this.scanFacts()).facts;
|
|
2635
|
-
}
|
|
2636
|
-
/**
|
|
2637
|
-
* Parse every managed fact file. Hand-written markdown is ignored, and a
|
|
2638
|
-
* schema-invalid/corrupt fact is reported in `invalid` (not thrown) so one
|
|
2639
|
-
* bad file can't break recall, capture or reindexing for the whole project.
|
|
2640
|
-
* Invalid files stay on disk for manual repair.
|
|
2641
|
-
*/
|
|
2642
|
-
async scanFacts() {
|
|
2643
|
-
const scan = await this.scan(
|
|
2644
|
-
this.factsDirectory,
|
|
2645
|
-
/^fact_[a-z0-9]+\.md$/,
|
|
2646
|
-
(path) => this.readFact(path)
|
|
2647
|
-
);
|
|
2648
|
-
return { facts: scan.items, invalid: scan.invalid };
|
|
2649
|
-
}
|
|
2650
|
-
/**
|
|
2651
|
-
* List incident facts for the namespace, ranked by severity then recency.
|
|
2652
|
-
* Unlike {@link findIncidentFactsForPaths} this does not filter by path, so
|
|
2653
|
-
* callers (e.g. the context engine's project bootstrap) can surface the
|
|
2654
|
-
* repository's incident hotspots before any specific edit target is known.
|
|
2655
|
-
*/
|
|
2656
|
-
async listIncidentFacts(input = {}) {
|
|
2657
|
-
const incidents = (await this.listFacts()).filter(
|
|
2658
|
-
(fact) => fact.category === "incident" && Boolean(fact.severity) && isEligibleMemory(fact, input)
|
|
2659
|
-
);
|
|
2660
|
-
return incidents.sort((left, right) => {
|
|
2661
|
-
const severity = severityRank(right.severity) - severityRank(left.severity);
|
|
2662
|
-
if (severity !== 0) return severity;
|
|
2663
|
-
return right.createdAt.localeCompare(left.createdAt);
|
|
2664
|
-
});
|
|
2665
|
-
}
|
|
2666
|
-
async findIncidentFactsForPaths(input) {
|
|
2667
|
-
const wanted = new Set(input.paths.map(normalizeMemoryPath));
|
|
2668
|
-
if (wanted.size === 0) return [];
|
|
2669
|
-
return (await this.listIncidentFacts({
|
|
2670
|
-
...input.namespace !== void 0 ? { namespace: input.namespace } : {},
|
|
2671
|
-
...input.includeResolved !== void 0 ? { includeResolved: input.includeResolved } : {}
|
|
2672
|
-
})).filter((fact) => fact.paths.map(normalizeMemoryPath).some((path) => wanted.has(path)));
|
|
2673
|
-
}
|
|
2674
|
-
async readSummary(pathOrId) {
|
|
2675
|
-
const path = pathOrId.endsWith(".md") ? this.safePath(pathOrId) : this.summaryPath(pathOrId);
|
|
2676
|
-
await assertNoSymlinkBetween(this.repositoryRoot, path);
|
|
2677
|
-
const parsed = parseFrontMatter(await readFile(path, "utf8"));
|
|
2678
|
-
return {
|
|
2679
|
-
...summaryFrontMatterSchema.parse(parseYaml(parsed.frontMatter)),
|
|
2680
|
-
content: parsed.content.trim(),
|
|
2681
|
-
path
|
|
2682
|
-
};
|
|
2683
|
-
}
|
|
2684
|
-
async listSummaries() {
|
|
2685
|
-
return (await this.scanSummaries()).summaries;
|
|
2686
|
-
}
|
|
2687
|
-
async scanSummaries() {
|
|
2688
|
-
const scan = await this.scan(
|
|
2689
|
-
this.summariesDirectory,
|
|
2690
|
-
/^sum_[a-z0-9]+\.md$/,
|
|
2691
|
-
(path) => this.readSummary(path)
|
|
2692
|
-
);
|
|
2693
|
-
return { summaries: scan.items, invalid: scan.invalid };
|
|
2694
|
-
}
|
|
2695
|
-
async scan(directory, managedName, read) {
|
|
2696
|
-
try {
|
|
2697
|
-
await this.prepareDirectory(directory);
|
|
2698
|
-
const entries = await readdir(directory, { withFileTypes: true });
|
|
2699
|
-
const result = { items: [], invalid: [] };
|
|
2700
|
-
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
2701
|
-
if (!entry.isFile() || !managedName.test(entry.name)) continue;
|
|
2702
|
-
const path = join(directory, entry.name);
|
|
2703
|
-
try {
|
|
2704
|
-
const item = await read(path);
|
|
2705
|
-
const id = entry.name.slice(0, -".md".length);
|
|
2706
|
-
if (item.id !== id)
|
|
2707
|
-
throw new Error(`file ID ${id} differs from front matter ID ${item.id}`);
|
|
2708
|
-
result.items.push(item);
|
|
2709
|
-
} catch (error) {
|
|
2710
|
-
result.invalid.push({
|
|
2711
|
-
id: entry.name.slice(0, -".md".length),
|
|
2712
|
-
path,
|
|
2713
|
-
error: error.message.split("\n")[0]?.slice(0, 300) ?? "unreadable"
|
|
2714
|
-
});
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
return result;
|
|
2718
|
-
} catch (error) {
|
|
2719
|
-
if (error.code === "ENOENT") return { items: [], invalid: [] };
|
|
2720
|
-
throw error;
|
|
2721
|
-
}
|
|
2722
|
-
}
|
|
2723
|
-
async deleteFact(id) {
|
|
2724
|
-
await rm(this.factPath(id), { force: true });
|
|
2725
|
-
}
|
|
2726
|
-
async markIncidentResolved(id, resolvedBy) {
|
|
2727
|
-
const fact = await this.readFact(id);
|
|
2728
|
-
await this.writeFact(copyFact(fact, { resolvedBy }));
|
|
2729
|
-
}
|
|
2730
|
-
async markFactSuperseded(id, supersededBy) {
|
|
2731
|
-
const fact = await this.readFact(id);
|
|
2732
|
-
await this.writeFact(copyFact(fact, { supersededBy }));
|
|
2733
|
-
}
|
|
2734
|
-
async setFactSharedWith(id, sharedWith) {
|
|
2735
|
-
const fact = await this.readFact(id);
|
|
2736
|
-
await this.writeFact(copyFact(fact, { sharedWith: [...new Set(sharedWith)].sort() }));
|
|
2737
|
-
}
|
|
2738
|
-
/** Persist interaction deletion in Markdown before the derived DB is updated. */
|
|
2739
|
-
async markSourceInteractionDeleted(namespace, sourceInteractionId) {
|
|
2740
|
-
const { facts: facts2 } = await this.scanFacts();
|
|
2741
|
-
for (const fact of facts2) {
|
|
2742
|
-
if (fact.namespace !== namespace || fact.sourceInteractionId !== sourceInteractionId)
|
|
2743
|
-
continue;
|
|
2744
|
-
if (fact.sourceDeleted) continue;
|
|
2745
|
-
await this.writeFact(copyFact(fact, { sourceDeleted: true }));
|
|
2746
|
-
}
|
|
2747
|
-
}
|
|
2748
|
-
/** Persist that a fact's source interaction was forgotten, keeping its provenance id. */
|
|
2749
|
-
async markFactSourceDeleted(id) {
|
|
2750
|
-
const fact = await this.readFact(id);
|
|
2751
|
-
await this.writeFact(copyFact(fact, { sourceDeleted: true }));
|
|
2752
|
-
}
|
|
2753
|
-
factPath(id) {
|
|
2754
|
-
if (!/^fact_[a-z0-9]+$/.test(id)) {
|
|
2755
|
-
throw new Error(`Invalid fact id: ${id}`);
|
|
2756
|
-
}
|
|
2757
|
-
return this.safePath(join(this.factsDirectory, `${id}.md`));
|
|
2758
|
-
}
|
|
2759
|
-
summaryPath(id) {
|
|
2760
|
-
if (!/^sum_[a-z0-9]+$/.test(id)) throw new Error(`Invalid summary id: ${id}`);
|
|
2761
|
-
return this.safePath(join(this.summariesDirectory, `${id}.md`));
|
|
2762
|
-
}
|
|
2763
|
-
safePath(path) {
|
|
2764
|
-
const absolute = resolve2(path);
|
|
2765
|
-
const relativePath = relative(this.repositoryRoot, absolute);
|
|
2766
|
-
if (relativePath === ".." || relativePath.startsWith(`..${sep}`) || relativePath === "") {
|
|
2767
|
-
throw new Error(`Memory path escapes repository root: ${path}`);
|
|
2768
|
-
}
|
|
2769
|
-
return absolute;
|
|
2770
|
-
}
|
|
2771
|
-
async prepareDirectory(directory) {
|
|
2772
|
-
await assertNoSymlinkBetween(this.repositoryRoot, dirname2(directory));
|
|
2773
|
-
await mkdir(directory, { recursive: true, mode: 448 });
|
|
2774
|
-
}
|
|
2775
|
-
};
|
|
2776
|
-
function copyFact(fact, patch) {
|
|
2777
|
-
const { path: _path, schemaVersion: _schemaVersion, type: _type, ...write } = fact;
|
|
2778
|
-
return { ...write, ...patch };
|
|
2779
|
-
}
|
|
2780
|
-
function stripUndefinedAndDefaultIncidentFields(metadata) {
|
|
2781
|
-
return Object.fromEntries(
|
|
2782
|
-
Object.entries(metadata).filter(([key, value]) => {
|
|
2783
|
-
if (value === void 0) return false;
|
|
2784
|
-
if (key === "category" && value === "general") return false;
|
|
2785
|
-
if ((key === "paths" || key === "sharedWith") && Array.isArray(value) && value.length === 0)
|
|
2786
|
-
return false;
|
|
2787
|
-
if (["severity", "introducedBy", "resolvedBy", "propositionKey"].includes(key) && (value === null || value === void 0)) {
|
|
2788
|
-
return false;
|
|
2789
|
-
}
|
|
2790
|
-
return true;
|
|
2791
|
-
})
|
|
2792
|
-
);
|
|
2793
|
-
}
|
|
2794
|
-
function normalizeMemoryPath(path) {
|
|
2795
|
-
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
2796
|
-
}
|
|
2797
|
-
function severityRank(severity) {
|
|
2798
|
-
switch (severity) {
|
|
2799
|
-
case "critical":
|
|
2800
|
-
return 4;
|
|
2801
|
-
case "high":
|
|
2802
|
-
return 3;
|
|
2803
|
-
case "medium":
|
|
2804
|
-
return 2;
|
|
2805
|
-
case "low":
|
|
2806
|
-
return 1;
|
|
2807
|
-
}
|
|
2808
|
-
}
|
|
2809
|
-
|
|
2810
2074
|
// src/core/worker.ts
|
|
2811
2075
|
var DEFAULT_POLL_MS = 250;
|
|
2812
2076
|
var DEFAULT_BATCH_SIZE = 8;
|
|
@@ -2819,6 +2083,7 @@ var EmbeddingWorker = class {
|
|
|
2819
2083
|
batchSize;
|
|
2820
2084
|
maxAttempts;
|
|
2821
2085
|
onDiagnostic;
|
|
2086
|
+
namespaceId;
|
|
2822
2087
|
state = "idle";
|
|
2823
2088
|
loopPromise = null;
|
|
2824
2089
|
wake = null;
|
|
@@ -2831,6 +2096,7 @@ var EmbeddingWorker = class {
|
|
|
2831
2096
|
this.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
2832
2097
|
this.maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
2833
2098
|
this.onDiagnostic = options.onDiagnostic;
|
|
2099
|
+
this.namespaceId = options.namespaceId;
|
|
2834
2100
|
}
|
|
2835
2101
|
getState() {
|
|
2836
2102
|
return this.state;
|
|
@@ -2860,8 +2126,8 @@ var EmbeddingWorker = class {
|
|
|
2860
2126
|
* wait out anymore.
|
|
2861
2127
|
*/
|
|
2862
2128
|
async drain() {
|
|
2863
|
-
await new Promise((
|
|
2864
|
-
this.idleResolvers.push(
|
|
2129
|
+
await new Promise((resolve2) => {
|
|
2130
|
+
this.idleResolvers.push(resolve2);
|
|
2865
2131
|
this.notify();
|
|
2866
2132
|
});
|
|
2867
2133
|
}
|
|
@@ -2887,13 +2153,13 @@ var EmbeddingWorker = class {
|
|
|
2887
2153
|
while (this.state === "running") {
|
|
2888
2154
|
let jobs;
|
|
2889
2155
|
try {
|
|
2890
|
-
jobs = await this.repo.claimPendingEmbeddings(this.batchSize);
|
|
2156
|
+
jobs = await this.repo.claimPendingEmbeddings(this.batchSize, this.namespaceId?.());
|
|
2891
2157
|
} catch (error) {
|
|
2892
2158
|
console.error(
|
|
2893
2159
|
`[worker] claimPendingEmbeddings failed: ${error instanceof Error ? error.message : String(error)}; retrying`
|
|
2894
2160
|
);
|
|
2895
2161
|
if (this.state !== "running") break;
|
|
2896
|
-
await new Promise((
|
|
2162
|
+
await new Promise((resolve2) => setTimeout(resolve2, ERROR_BACKOFF_MS));
|
|
2897
2163
|
continue;
|
|
2898
2164
|
}
|
|
2899
2165
|
if (jobs.length === 0) {
|
|
@@ -2920,7 +2186,7 @@ var EmbeddingWorker = class {
|
|
|
2920
2186
|
if (this.inFlight > 0) return;
|
|
2921
2187
|
const resolvers = this.idleResolvers;
|
|
2922
2188
|
this.idleResolvers = [];
|
|
2923
|
-
for (const
|
|
2189
|
+
for (const resolve2 of resolvers) resolve2();
|
|
2924
2190
|
}
|
|
2925
2191
|
async processJob(job) {
|
|
2926
2192
|
let leaseLost = false;
|
|
@@ -2940,14 +2206,14 @@ var EmbeddingWorker = class {
|
|
|
2940
2206
|
model: job.embeddingModel
|
|
2941
2207
|
});
|
|
2942
2208
|
validateEmbeddingResponse(response, 1);
|
|
2943
|
-
const
|
|
2944
|
-
if (!
|
|
2209
|
+
const vector = response.vectors[0];
|
|
2210
|
+
if (!vector || vector.length === 0) {
|
|
2945
2211
|
throw new Error("Provider returned no embedding vector.");
|
|
2946
2212
|
}
|
|
2947
2213
|
if (leaseLost || !await this.repo.markEmbeddingReady(
|
|
2948
2214
|
job.id,
|
|
2949
2215
|
job.leaseToken,
|
|
2950
|
-
|
|
2216
|
+
vector,
|
|
2951
2217
|
response.model,
|
|
2952
2218
|
embeddingSpaceKey(embeddingSpace(response))
|
|
2953
2219
|
))
|
|
@@ -3005,14 +2271,14 @@ var EmbeddingWorker = class {
|
|
|
3005
2271
|
});
|
|
3006
2272
|
}
|
|
3007
2273
|
sleep(ms) {
|
|
3008
|
-
return new Promise((
|
|
2274
|
+
return new Promise((resolve2) => {
|
|
3009
2275
|
const timer = setTimeout(() => {
|
|
3010
2276
|
this.wake = null;
|
|
3011
|
-
|
|
2277
|
+
resolve2();
|
|
3012
2278
|
}, ms ?? this.pollIntervalMs);
|
|
3013
2279
|
this.wake = () => {
|
|
3014
2280
|
clearTimeout(timer);
|
|
3015
|
-
|
|
2281
|
+
resolve2();
|
|
3016
2282
|
};
|
|
3017
2283
|
});
|
|
3018
2284
|
}
|
|
@@ -3043,6 +2309,7 @@ var CodeBuddy = class {
|
|
|
3043
2309
|
this.worker = deps.worker ?? new EmbeddingWorker({
|
|
3044
2310
|
repository: this.repo,
|
|
3045
2311
|
provider: this.provider,
|
|
2312
|
+
namespaceId: () => this.namespaceId ?? void 0,
|
|
3046
2313
|
...this.config.worker?.pollIntervalMs !== void 0 ? { pollIntervalMs: this.config.worker.pollIntervalMs } : {},
|
|
3047
2314
|
...this.config.worker?.batchSize !== void 0 ? { batchSize: this.config.worker.batchSize } : {},
|
|
3048
2315
|
...this.config.worker?.maxAttempts !== void 0 ? { maxAttempts: this.config.worker.maxAttempts } : {}
|
|
@@ -3186,8 +2453,8 @@ var CodeBuddy = class {
|
|
|
3186
2453
|
})
|
|
3187
2454
|
);
|
|
3188
2455
|
validateEmbeddingResponse(response, 1);
|
|
3189
|
-
const
|
|
3190
|
-
return
|
|
2456
|
+
const vector = response.vectors[0];
|
|
2457
|
+
return vector ? { vector, space: embeddingSpace(response) } : null;
|
|
3191
2458
|
} catch {
|
|
3192
2459
|
return null;
|
|
3193
2460
|
}
|
|
@@ -3369,9 +2636,10 @@ var CodeBuddy = class {
|
|
|
3369
2636
|
};
|
|
3370
2637
|
const factResult = await this.repo.withSessionLock(namespaceId, REINDEX_LOCK_KEY, async () => {
|
|
3371
2638
|
const result = await this.repo.forgetFact(namespaceId, id, factAudit);
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
2639
|
+
const file = await this.memoryFileStore?.readFact(id).catch(() => null);
|
|
2640
|
+
if (file?.namespace === this.config.namespace) {
|
|
2641
|
+
await this.memoryFileStore?.deleteFact(id);
|
|
2642
|
+
return { ...result, found: true };
|
|
3375
2643
|
}
|
|
3376
2644
|
return result;
|
|
3377
2645
|
});
|
|
@@ -3387,7 +2655,7 @@ var CodeBuddy = class {
|
|
|
3387
2655
|
* file is applied independently: malformed or conflicting files are reported
|
|
3388
2656
|
* in `failures` and never abort healthy imports (nor count as deletions).
|
|
3389
2657
|
*/
|
|
3390
|
-
async reindexMemory() {
|
|
2658
|
+
async reindexMemory(options = {}) {
|
|
3391
2659
|
const namespaceId = this.requireNamespaceId();
|
|
3392
2660
|
const store = this.memoryFileStore;
|
|
3393
2661
|
if (!store) {
|
|
@@ -3467,7 +2735,7 @@ var CodeBuddy = class {
|
|
|
3467
2735
|
failures: failures.slice(0, MAX_REPORTED_FAILURES)
|
|
3468
2736
|
};
|
|
3469
2737
|
});
|
|
3470
|
-
const space = this.provider.space;
|
|
2738
|
+
const space = options.respace === false ? void 0 : this.provider.space;
|
|
3471
2739
|
const canEmbed = space !== void 0 && await this.provider.embed({ input: "codebuddy" }).then(
|
|
3472
2740
|
() => true,
|
|
3473
2741
|
() => false
|
|
@@ -3813,8 +3081,8 @@ function decodeFactCursor(cursor) {
|
|
|
3813
3081
|
if (!Array.isArray(parsed) || parsed.length !== 2 || typeof parsed[0] !== "string" || typeof parsed[1] !== "string" || Number.isNaN(Date.parse(parsed[0]))) {
|
|
3814
3082
|
throw new Error("Invalid cursor: expected a base64url-encoded [createdAt, id] pair.");
|
|
3815
3083
|
}
|
|
3816
|
-
const [
|
|
3817
|
-
return { createdAt: new Date(
|
|
3084
|
+
const [createdAt, id] = parsed;
|
|
3085
|
+
return { createdAt: new Date(createdAt), id };
|
|
3818
3086
|
}
|
|
3819
3087
|
async function listFactsPage(memory, repository, input) {
|
|
3820
3088
|
const namespace = await repository.ensureNamespace(memory.config.namespace);
|
|
@@ -3850,6 +3118,7 @@ async function inspectNamespace(repository, namespace) {
|
|
|
3850
3118
|
};
|
|
3851
3119
|
}
|
|
3852
3120
|
async function runDoctor(options = {}) {
|
|
3121
|
+
const migrated = await migrateLegacyNamespace();
|
|
3853
3122
|
const fileConfig = await readConfigFile();
|
|
3854
3123
|
const scaffold = await checkProjectScaffold();
|
|
3855
3124
|
const configPermissions = await checkConfigPermissions();
|
|
@@ -3859,6 +3128,7 @@ async function runDoctor(options = {}) {
|
|
|
3859
3128
|
expectedDefault: expectedDefaultNamespace,
|
|
3860
3129
|
configured: fileConfig.namespace ?? null,
|
|
3861
3130
|
runtime: runtimeNamespace,
|
|
3131
|
+
...migrated ? { migrated } : {},
|
|
3862
3132
|
ok: !fileConfig.namespace || fileConfig.namespace === expectedDefaultNamespace || process.env.CODEBUDDY_NAMESPACE !== void 0,
|
|
3863
3133
|
...!fileConfig.namespace || fileConfig.namespace === expectedDefaultNamespace || process.env.CODEBUDDY_NAMESPACE !== void 0 ? {} : {
|
|
3864
3134
|
warning: `Configured namespace "${fileConfig.namespace}" differs from this folder's default "${expectedDefaultNamespace}". Confirm your MCP entries point at the intended namespace.`
|
|
@@ -4003,18 +3273,12 @@ async function checkModels(provider, skip = false) {
|
|
|
4003
3273
|
}
|
|
4004
3274
|
|
|
4005
3275
|
export {
|
|
4006
|
-
isEligibleMemory,
|
|
4007
|
-
lexicalTerms,
|
|
4008
|
-
termOverlap,
|
|
4009
3276
|
embeddingSpaceKey,
|
|
4010
3277
|
DefaultPolicy,
|
|
4011
3278
|
HuggingFaceProvider,
|
|
4012
3279
|
isLangSmithTracingEnabled,
|
|
4013
3280
|
createTracer,
|
|
4014
3281
|
codeBuddyConfigSchema,
|
|
4015
|
-
FACT_CATEGORIES,
|
|
4016
|
-
INCIDENT_SEVERITIES,
|
|
4017
|
-
MemoryFileStore,
|
|
4018
3282
|
EmbeddingWorker,
|
|
4019
3283
|
CodeBuddy,
|
|
4020
3284
|
buildProviderFromConfig,
|
|
@@ -4030,4 +3294,4 @@ export {
|
|
|
4030
3294
|
inspectNamespace,
|
|
4031
3295
|
runDoctor
|
|
4032
3296
|
};
|
|
4033
|
-
//# sourceMappingURL=chunk-
|
|
3297
|
+
//# sourceMappingURL=chunk-2XDPKFUW.js.map
|