@orquentra/codebuddy 2.5.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/README.md +8 -0
- package/WORKFLOW.md +5 -5
- package/dist/{chunk-JDZ3VK26.js → chunk-2XDPKFUW.js} +114 -823
- 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-ROQTT5ZO.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-3XYQGFPB.js → chunk-IBLJOHJL.js} +16 -3
- 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-CQPCHMBS.js → chunk-J2EAZ4MA.js} +21 -8
- package/dist/chunk-J2EAZ4MA.js.map +1 -0
- package/dist/{chunk-KYK6RPAJ.js → chunk-JFDRBPYF.js} +2 -2
- package/dist/{chunk-JMWJ7V6Y.js → chunk-JPHJBCZB.js} +2 -2
- package/dist/{chunk-JMWJ7V6Y.js.map → chunk-JPHJBCZB.js.map} +1 -1
- 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-Z5QB367W.js → chunk-R7CD6EXS.js} +367 -1798
- 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/{chunk-4BYGTEJT.js → chunk-XBJQKCLU.js} +2 -2
- package/dist/cli/index.js +14 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/{cloud-GP6G3EAK.js → cloud-7WM3YLI4.js} +3 -3
- 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 +22 -18
- package/dist/langgraph/index.d.ts +1 -1
- package/dist/lean-command-HTQCPH76.js +15 -0
- package/dist/local-5MZURLCZ.js +17 -0
- package/dist/{main-BDVQAGAS.js → main-MTBQZGJV.js} +333 -219
- package/dist/main-MTBQZGJV.js.map +1 -0
- package/dist/{memory-4RGVLPKG.js → memory-KIC5FJVW.js} +4 -4
- package/dist/{operations-EQGOFCBD.js → operations-POCHY3WR.js} +8 -7
- 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-3XYQGFPB.js.map +0 -1
- package/dist/chunk-776EQXDV.js.map +0 -1
- package/dist/chunk-CQPCHMBS.js.map +0 -1
- package/dist/chunk-JDZ3VK26.js.map +0 -1
- package/dist/chunk-ROQTT5ZO.js.map +0 -1
- package/dist/chunk-Z5QB367W.js.map +0 -1
- package/dist/lean-command-DA4ZNKG3.js +0 -15
- package/dist/local-3NGNESNB.js +0 -13
- package/dist/main-BDVQAGAS.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-KYK6RPAJ.js.map → chunk-JFDRBPYF.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/{chunk-4BYGTEJT.js.map → chunk-XBJQKCLU.js.map} +0 -0
- /package/dist/{cloud-GP6G3EAK.js.map → cloud-7WM3YLI4.js.map} +0 -0
- /package/dist/{config-KFEHLV6W.js.map → config-DEVHUDIU.js.map} +0 -0
- /package/dist/{lean-command-DA4ZNKG3.js.map → docker-autostart-KDME7TVC.js.map} +0 -0
- /package/dist/{local-3NGNESNB.js.map → lean-command-HTQCPH76.js.map} +0 -0
- /package/dist/{operations-EQGOFCBD.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
|
|
@@ -9,13 +25,13 @@ import {
|
|
|
9
25
|
countTokens,
|
|
10
26
|
generateEntityId,
|
|
11
27
|
generateSessionId
|
|
12
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-XBJQKCLU.js";
|
|
13
29
|
import {
|
|
14
30
|
OpenRouterEmbeddingProvider
|
|
15
|
-
} from "./chunk-
|
|
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,
|
|
@@ -23,328 +39,24 @@ import {
|
|
|
23
39
|
EMBEDDING_DIMENSIONS,
|
|
24
40
|
assertCompatibleEmbeddingModels,
|
|
25
41
|
getModelDefinition
|
|
26
|
-
} from "./chunk-
|
|
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,139 +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
|
-
}
|
|
151
|
+
import { and, desc, eq, inArray, isNull, lt, ne, or, sql } from "drizzle-orm";
|
|
552
152
|
|
|
553
153
|
// src/providers/embedding-space.ts
|
|
554
154
|
function embeddingSpace(response) {
|
|
@@ -566,12 +166,12 @@ function embeddingSpace(response) {
|
|
|
566
166
|
function embeddingSpaceKey(space) {
|
|
567
167
|
return JSON.stringify([space.model, space.revision, space.schema, space.dimensions]);
|
|
568
168
|
}
|
|
569
|
-
function validEmbeddingVector(
|
|
570
|
-
return dimensions > 0 &&
|
|
169
|
+
function validEmbeddingVector(vector, dimensions) {
|
|
170
|
+
return dimensions > 0 && vector.length === dimensions && vector.every(Number.isFinite);
|
|
571
171
|
}
|
|
572
172
|
function validateEmbeddingResponse(response, count) {
|
|
573
173
|
embeddingSpace(response);
|
|
574
|
-
if (response.vectors.length !== count || response.vectors.some((
|
|
174
|
+
if (response.vectors.length !== count || response.vectors.some((vector) => !validEmbeddingVector(vector, response.dimensions))) {
|
|
575
175
|
throw new Error("Provider returned invalid embedding dimensions, values, or batch size.");
|
|
576
176
|
}
|
|
577
177
|
}
|
|
@@ -602,7 +202,7 @@ var PostgresMemoryRepository = class {
|
|
|
602
202
|
async withSessionLock(namespaceId, sessionId, fn) {
|
|
603
203
|
const [k1, k2] = advisoryLockKeys(namespaceId, sessionId);
|
|
604
204
|
return this.client.db.transaction(async (tx) => {
|
|
605
|
-
await tx.execute(
|
|
205
|
+
await tx.execute(sql`select pg_advisory_xact_lock(${k1}, ${k2})`);
|
|
606
206
|
return this.sessionTransaction.run(tx, fn);
|
|
607
207
|
});
|
|
608
208
|
}
|
|
@@ -783,7 +383,7 @@ var PostgresMemoryRepository = class {
|
|
|
783
383
|
const contentChanged = existing.content !== fact.content;
|
|
784
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();
|
|
785
385
|
if (contentChanged || metadataChanged || !existing.fileBacked) {
|
|
786
|
-
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)));
|
|
787
387
|
}
|
|
788
388
|
await upsertPendingEmbedding(tx, input.embedding, contentChanged);
|
|
789
389
|
if (!contentChanged && !metadataChanged) return { status: "unchanged" };
|
|
@@ -852,12 +452,13 @@ var PostgresMemoryRepository = class {
|
|
|
852
452
|
* item twice. Expired leases are re-claimable, so a crashed worker's work is
|
|
853
453
|
* picked up again instead of being stuck forever.
|
|
854
454
|
*/
|
|
855
|
-
async claimPendingEmbeddings(limit) {
|
|
455
|
+
async claimPendingEmbeddings(limit, namespaceId) {
|
|
856
456
|
const rows = await this.client.sql`
|
|
857
457
|
with claimed as (
|
|
858
458
|
select id from embeddings
|
|
859
|
-
where status = 'pending'
|
|
860
|
-
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})
|
|
861
462
|
order by created_at asc
|
|
862
463
|
for update skip locked
|
|
863
464
|
limit ${limit}
|
|
@@ -896,33 +497,33 @@ var PostgresMemoryRepository = class {
|
|
|
896
497
|
}));
|
|
897
498
|
}
|
|
898
499
|
async renewEmbeddingLease(id, leaseToken) {
|
|
899
|
-
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(
|
|
900
501
|
and(
|
|
901
502
|
eq(embeddings.id, id),
|
|
902
503
|
eq(embeddings.leaseToken, leaseToken),
|
|
903
504
|
eq(embeddings.status, "processing"),
|
|
904
|
-
|
|
505
|
+
sql`${embeddings.leaseUntil} > now()`
|
|
905
506
|
)
|
|
906
507
|
).returning({ id: embeddings.id });
|
|
907
508
|
return rows.length > 0;
|
|
908
509
|
}
|
|
909
|
-
async markEmbeddingReady(id, leaseToken,
|
|
910
|
-
const literal = `[${
|
|
510
|
+
async markEmbeddingReady(id, leaseToken, vector, model, space) {
|
|
511
|
+
const literal = `[${vector.join(",")}]`;
|
|
911
512
|
const rows = await this.db.update(embeddings).set({
|
|
912
513
|
status: "ready",
|
|
913
514
|
vector: literal,
|
|
914
515
|
embeddingModel: model,
|
|
915
|
-
embeddingSpace: space ?? embeddingSpaceKey(embeddingSpace({ model, dimensions:
|
|
516
|
+
embeddingSpace: space ?? embeddingSpaceKey(embeddingSpace({ model, dimensions: vector.length })),
|
|
916
517
|
lastError: null,
|
|
917
518
|
leaseUntil: null,
|
|
918
519
|
leaseToken: null,
|
|
919
|
-
updatedAt:
|
|
520
|
+
updatedAt: sql`now()`
|
|
920
521
|
}).where(
|
|
921
522
|
and(
|
|
922
523
|
eq(embeddings.id, id),
|
|
923
524
|
eq(embeddings.leaseToken, leaseToken),
|
|
924
525
|
eq(embeddings.status, "processing"),
|
|
925
|
-
|
|
526
|
+
sql`${embeddings.leaseUntil} > now()`
|
|
926
527
|
)
|
|
927
528
|
).returning({ id: embeddings.id });
|
|
928
529
|
return rows.length > 0;
|
|
@@ -938,18 +539,18 @@ var PostgresMemoryRepository = class {
|
|
|
938
539
|
const maxAttempts = options?.maxAttempts ?? 5;
|
|
939
540
|
const backoffSeconds = Math.min(60, 2 ** Math.max(0, attempts - 1));
|
|
940
541
|
const rows = await this.db.update(embeddings).set({
|
|
941
|
-
status:
|
|
942
|
-
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`,
|
|
943
544
|
leaseToken: null,
|
|
944
545
|
attempts,
|
|
945
546
|
lastError: error,
|
|
946
|
-
updatedAt:
|
|
547
|
+
updatedAt: sql`now()`
|
|
947
548
|
}).where(
|
|
948
549
|
and(
|
|
949
550
|
eq(embeddings.id, id),
|
|
950
551
|
eq(embeddings.leaseToken, leaseToken),
|
|
951
552
|
eq(embeddings.status, "processing"),
|
|
952
|
-
|
|
553
|
+
sql`${embeddings.leaseUntil} > now()`
|
|
953
554
|
)
|
|
954
555
|
).returning({ id: embeddings.id });
|
|
955
556
|
return rows.length > 0;
|
|
@@ -1166,12 +767,12 @@ var PostgresMemoryRepository = class {
|
|
|
1166
767
|
lastError: null,
|
|
1167
768
|
leaseUntil: null,
|
|
1168
769
|
leaseToken: null,
|
|
1169
|
-
updatedAt:
|
|
770
|
+
updatedAt: sql`now()`
|
|
1170
771
|
}).where(
|
|
1171
772
|
and(
|
|
1172
773
|
eq(embeddings.namespaceId, namespaceId),
|
|
1173
774
|
inArray(embeddings.status, ["ready", "failed"]),
|
|
1174
|
-
|
|
775
|
+
sql`${embeddings.embeddingSpace} is distinct from ${space}`
|
|
1175
776
|
)
|
|
1176
777
|
).returning({ id: embeddings.id });
|
|
1177
778
|
return rows.length;
|
|
@@ -1179,7 +780,7 @@ var PostgresMemoryRepository = class {
|
|
|
1179
780
|
async searchSimilarEmbeddings(input) {
|
|
1180
781
|
if (!validSearchVector(input.vector))
|
|
1181
782
|
return { method: "exact_pgvector", candidates: [], compatibleReady: 0 };
|
|
1182
|
-
const rows = await this.db.execute(
|
|
783
|
+
const rows = await this.db.execute(sql`
|
|
1183
784
|
with compatible as materialized (
|
|
1184
785
|
select id, owner_type, owner_id, embedding_model, embedding_space, vector
|
|
1185
786
|
from embeddings
|
|
@@ -1188,7 +789,7 @@ var PostgresMemoryRepository = class {
|
|
|
1188
789
|
namespace_id = ${input.namespaceId}
|
|
1189
790
|
or (
|
|
1190
791
|
owner_type = 'fact'
|
|
1191
|
-
and ${liveReference(input.namespaceId,
|
|
792
|
+
and ${liveReference(input.namespaceId, sql`embeddings.namespace_id`, sql`embeddings.owner_id`)}
|
|
1192
793
|
)
|
|
1193
794
|
)
|
|
1194
795
|
and embedding_space = ${input.embeddingSpace}
|
|
@@ -1224,7 +825,7 @@ var PostgresMemoryRepository = class {
|
|
|
1224
825
|
async searchFactsLexically(namespaceId, query, limit) {
|
|
1225
826
|
const terms = lexicalTerms(query);
|
|
1226
827
|
if (!terms.length) return { candidates: [], matchedFacts: 0 };
|
|
1227
|
-
const rows = await this.db.execute(
|
|
828
|
+
const rows = await this.db.execute(sql`
|
|
1228
829
|
with scored as materialized (
|
|
1229
830
|
select id, content, subject, predicate, object, proposition_key, confidence,
|
|
1230
831
|
created_by_agent, created_at,
|
|
@@ -1238,7 +839,7 @@ var PostgresMemoryRepository = class {
|
|
|
1238
839
|
where not source_deleted and superseded_by is null
|
|
1239
840
|
and (
|
|
1240
841
|
namespace_id = ${namespaceId}
|
|
1241
|
-
or ${liveReference(namespaceId,
|
|
842
|
+
or ${liveReference(namespaceId, sql`facts.namespace_id`, sql`facts.id`)}
|
|
1242
843
|
)
|
|
1243
844
|
)
|
|
1244
845
|
select *, count(*) over () as total from scored where score > 0
|
|
@@ -1317,7 +918,7 @@ var PostgresMemoryRepository = class {
|
|
|
1317
918
|
isNull(facts.supersededBy),
|
|
1318
919
|
or(
|
|
1319
920
|
eq(facts.namespaceId, namespaceId),
|
|
1320
|
-
liveReference(namespaceId,
|
|
921
|
+
liveReference(namespaceId, sql`${facts.namespaceId}`, sql`${facts.id}`)
|
|
1321
922
|
)
|
|
1322
923
|
)
|
|
1323
924
|
);
|
|
@@ -1576,11 +1177,11 @@ var PostgresMemoryRepository = class {
|
|
|
1576
1177
|
limit 1
|
|
1577
1178
|
`;
|
|
1578
1179
|
const vectorCount = Number(countRows[0]?.count ?? 0);
|
|
1579
|
-
const
|
|
1180
|
+
const index = indexRows[0];
|
|
1580
1181
|
return {
|
|
1581
1182
|
vectorCount,
|
|
1582
|
-
indexName:
|
|
1583
|
-
indexDefinition:
|
|
1183
|
+
indexName: index?.indexname ?? null,
|
|
1184
|
+
indexDefinition: index?.indexdef ?? null,
|
|
1584
1185
|
needsTuning: vectorCount >= 1e5
|
|
1585
1186
|
};
|
|
1586
1187
|
}
|
|
@@ -1624,7 +1225,7 @@ async function upsertPendingEmbedding(tx, embedding, reset) {
|
|
|
1624
1225
|
lastError: null,
|
|
1625
1226
|
leaseUntil: null,
|
|
1626
1227
|
leaseToken: null,
|
|
1627
|
-
updatedAt:
|
|
1228
|
+
updatedAt: sql`now()`
|
|
1628
1229
|
}
|
|
1629
1230
|
});
|
|
1630
1231
|
}
|
|
@@ -1656,7 +1257,7 @@ var recentFactColumns = {
|
|
|
1656
1257
|
createdAt: facts.createdAt
|
|
1657
1258
|
};
|
|
1658
1259
|
function liveReference(namespaceId, ownerNamespace, factId) {
|
|
1659
|
-
return
|
|
1260
|
+
return sql`exists (
|
|
1660
1261
|
select 1 from shares s
|
|
1661
1262
|
where s.to_namespace_id = ${namespaceId}
|
|
1662
1263
|
and s.from_namespace_id = ${ownerNamespace}
|
|
@@ -1669,14 +1270,6 @@ function liveReference(namespaceId, ownerNamespace, factId) {
|
|
|
1669
1270
|
// src/core/codebuddy.ts
|
|
1670
1271
|
import pTimeout2 from "p-timeout";
|
|
1671
1272
|
|
|
1672
|
-
// src/core/memory-lifecycle.ts
|
|
1673
|
-
function isEligibleMemory(fact, options = {}) {
|
|
1674
|
-
if (options.namespace && fact.namespace !== options.namespace) return false;
|
|
1675
|
-
if (fact.sourceDeleted || fact.supersededBy) return false;
|
|
1676
|
-
if (fact.category === "incident" && fact.resolvedBy && !options.includeResolved) return false;
|
|
1677
|
-
return true;
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
1273
|
// src/planner/default-policy.ts
|
|
1681
1274
|
var DefaultPolicy = class {
|
|
1682
1275
|
recencyFloorSize;
|
|
@@ -2082,8 +1675,8 @@ var HuggingFaceResilience = class {
|
|
|
2082
1675
|
async execute(input) {
|
|
2083
1676
|
const models = [input.model, ...input.fallbackModels ?? []];
|
|
2084
1677
|
let lastError;
|
|
2085
|
-
for (const [
|
|
2086
|
-
const fallbackTriggered =
|
|
1678
|
+
for (const [index, model] of models.entries()) {
|
|
1679
|
+
const fallbackTriggered = index > 0;
|
|
2087
1680
|
try {
|
|
2088
1681
|
return await this.executeForModel(model, input, fallbackTriggered);
|
|
2089
1682
|
} catch (error) {
|
|
@@ -2150,8 +1743,7 @@ var HuggingFaceResilience = class {
|
|
|
2150
1743
|
retries = error.attemptNumber;
|
|
2151
1744
|
}
|
|
2152
1745
|
}
|
|
2153
|
-
)
|
|
2154
|
-
{ throwOnTimeout: true }
|
|
1746
|
+
)
|
|
2155
1747
|
);
|
|
2156
1748
|
this.markWarm(model);
|
|
2157
1749
|
status = fallbackTriggered ? "fallback" : "success";
|
|
@@ -2284,7 +1876,7 @@ function readRetryAfterMs(error) {
|
|
|
2284
1876
|
return Number.isFinite(retryAfterSeconds) ? retryAfterSeconds * 1e3 : void 0;
|
|
2285
1877
|
}
|
|
2286
1878
|
function sleep(ms) {
|
|
2287
|
-
return new Promise((
|
|
1879
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2288
1880
|
}
|
|
2289
1881
|
|
|
2290
1882
|
// src/providers/huggingface.ts
|
|
@@ -2389,7 +1981,7 @@ function normalizeEmbeddingResponse(response) {
|
|
|
2389
1981
|
return [response];
|
|
2390
1982
|
}
|
|
2391
1983
|
if (response.every(
|
|
2392
|
-
(
|
|
1984
|
+
(vector) => Array.isArray(vector) && vector.every((value) => typeof value === "number")
|
|
2393
1985
|
)) {
|
|
2394
1986
|
return response;
|
|
2395
1987
|
}
|
|
@@ -2479,308 +2071,6 @@ function validateConfig(config) {
|
|
|
2479
2071
|
return codeBuddyConfigSchema.parse(config);
|
|
2480
2072
|
}
|
|
2481
2073
|
|
|
2482
|
-
// src/core/memory-file-store.ts
|
|
2483
|
-
import { mkdir, readdir, readFile, rm } from "fs/promises";
|
|
2484
|
-
import { dirname as dirname2, join, relative, resolve as resolve2, sep } from "path";
|
|
2485
|
-
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
2486
|
-
import { z as z2 } from "zod";
|
|
2487
|
-
var FACT_CATEGORIES = ["general", "incident"];
|
|
2488
|
-
var INCIDENT_SEVERITIES = ["low", "medium", "high", "critical"];
|
|
2489
|
-
var factFrontMatterSchema = z2.object({
|
|
2490
|
-
schemaVersion: z2.literal(1),
|
|
2491
|
-
id: z2.string().regex(/^fact_[a-z0-9]+$/),
|
|
2492
|
-
namespace: z2.string().min(1),
|
|
2493
|
-
type: z2.literal("fact"),
|
|
2494
|
-
subject: z2.string(),
|
|
2495
|
-
predicate: z2.string(),
|
|
2496
|
-
object: z2.string(),
|
|
2497
|
-
/** Explicit single-valued claim identity; facts sharing it are rival assertions. */
|
|
2498
|
-
propositionKey: z2.string().min(1).nullable().default(null),
|
|
2499
|
-
confidence: z2.number().min(0).max(1),
|
|
2500
|
-
createdAt: z2.preprocess(
|
|
2501
|
-
(value) => value instanceof Date ? value.toISOString() : value,
|
|
2502
|
-
z2.string().datetime()
|
|
2503
|
-
),
|
|
2504
|
-
createdByAgent: z2.string().nullable(),
|
|
2505
|
-
sourceInteractionId: z2.string().nullable(),
|
|
2506
|
-
sourceDeleted: z2.boolean(),
|
|
2507
|
-
category: z2.enum(FACT_CATEGORIES).default("general"),
|
|
2508
|
-
paths: z2.array(z2.string().min(1)).default([]),
|
|
2509
|
-
severity: z2.enum(INCIDENT_SEVERITIES).nullable().default(null),
|
|
2510
|
-
introducedBy: z2.string().nullable().default(null),
|
|
2511
|
-
resolvedBy: z2.string().nullable().default(null),
|
|
2512
|
-
fingerprint: z2.string().regex(/^[a-f0-9]{64}$/).nullable().default(null),
|
|
2513
|
-
sourcePlanId: z2.string().nullable().default(null),
|
|
2514
|
-
sourceSessionId: z2.string().nullable().default(null),
|
|
2515
|
-
verification: z2.array(z2.string()).default([]),
|
|
2516
|
-
supersededBy: z2.string().nullable().default(null),
|
|
2517
|
-
/** Namespaces granted a live reference to this fact (durable form of reference shares). */
|
|
2518
|
-
sharedWith: z2.array(z2.string().min(1)).default([])
|
|
2519
|
-
});
|
|
2520
|
-
var summaryFrontMatterSchema = z2.object({
|
|
2521
|
-
schemaVersion: z2.literal(1),
|
|
2522
|
-
id: z2.string().regex(/^sum_[a-z0-9]+$/),
|
|
2523
|
-
namespace: z2.string().min(1),
|
|
2524
|
-
type: z2.literal("summary"),
|
|
2525
|
-
sessionId: z2.string().min(1),
|
|
2526
|
-
version: z2.number().int().positive(),
|
|
2527
|
-
tokenCount: z2.number().int().nonnegative(),
|
|
2528
|
-
createdAt: z2.preprocess(
|
|
2529
|
-
(value) => value instanceof Date ? value.toISOString() : value,
|
|
2530
|
-
z2.string().datetime()
|
|
2531
|
-
),
|
|
2532
|
-
createdByAgent: z2.string().nullable()
|
|
2533
|
-
});
|
|
2534
|
-
var MemoryFileStore = class {
|
|
2535
|
-
repositoryRoot;
|
|
2536
|
-
factsDirectory;
|
|
2537
|
-
summariesDirectory;
|
|
2538
|
-
constructor(repositoryRoot = process.cwd()) {
|
|
2539
|
-
this.repositoryRoot = resolve2(repositoryRoot);
|
|
2540
|
-
this.factsDirectory = join(this.repositoryRoot, ".codebuddy", "memory", "facts");
|
|
2541
|
-
this.summariesDirectory = join(this.repositoryRoot, ".codebuddy", "memory", "summaries");
|
|
2542
|
-
}
|
|
2543
|
-
async writeFact(raw) {
|
|
2544
|
-
const input = redactPersisted(raw);
|
|
2545
|
-
const path = this.factPath(input.id);
|
|
2546
|
-
await this.prepareDirectory(this.factsDirectory);
|
|
2547
|
-
await assertNoSymlinkBetween(this.repositoryRoot, dirname2(path));
|
|
2548
|
-
const metadata = {
|
|
2549
|
-
schemaVersion: 1,
|
|
2550
|
-
id: input.id,
|
|
2551
|
-
namespace: input.namespace,
|
|
2552
|
-
type: "fact",
|
|
2553
|
-
subject: input.subject,
|
|
2554
|
-
predicate: input.predicate,
|
|
2555
|
-
object: input.object,
|
|
2556
|
-
propositionKey: input.propositionKey,
|
|
2557
|
-
confidence: input.confidence,
|
|
2558
|
-
createdAt: input.createdAt,
|
|
2559
|
-
createdByAgent: input.createdByAgent,
|
|
2560
|
-
sourceInteractionId: input.sourceInteractionId,
|
|
2561
|
-
sourceDeleted: input.sourceDeleted,
|
|
2562
|
-
category: input.category,
|
|
2563
|
-
paths: input.paths,
|
|
2564
|
-
severity: input.severity,
|
|
2565
|
-
introducedBy: input.introducedBy,
|
|
2566
|
-
resolvedBy: input.resolvedBy,
|
|
2567
|
-
fingerprint: input.fingerprint,
|
|
2568
|
-
sourcePlanId: input.sourcePlanId,
|
|
2569
|
-
sourceSessionId: input.sourceSessionId,
|
|
2570
|
-
verification: input.verification,
|
|
2571
|
-
supersededBy: input.supersededBy,
|
|
2572
|
-
sharedWith: input.sharedWith
|
|
2573
|
-
};
|
|
2574
|
-
const frontMatter = stringifyYaml(stripUndefinedAndDefaultIncidentFields(metadata));
|
|
2575
|
-
await writeAtomic(path, composeMarkdown(frontMatter, input.content));
|
|
2576
|
-
return path;
|
|
2577
|
-
}
|
|
2578
|
-
async writeSummary(input) {
|
|
2579
|
-
const path = this.summaryPath(input.id);
|
|
2580
|
-
await this.prepareDirectory(this.summariesDirectory);
|
|
2581
|
-
await assertNoSymlinkBetween(this.repositoryRoot, dirname2(path));
|
|
2582
|
-
const metadata = stringifyYaml({
|
|
2583
|
-
schemaVersion: 1,
|
|
2584
|
-
id: input.id,
|
|
2585
|
-
namespace: input.namespace,
|
|
2586
|
-
type: "summary",
|
|
2587
|
-
sessionId: input.sessionId,
|
|
2588
|
-
version: input.version,
|
|
2589
|
-
tokenCount: input.tokenCount,
|
|
2590
|
-
createdAt: input.createdAt,
|
|
2591
|
-
createdByAgent: input.createdByAgent
|
|
2592
|
-
});
|
|
2593
|
-
await writeAtomic(path, composeMarkdown(metadata, input.content));
|
|
2594
|
-
return path;
|
|
2595
|
-
}
|
|
2596
|
-
async readFact(pathOrId) {
|
|
2597
|
-
const path = pathOrId.endsWith(".md") ? this.safePath(pathOrId) : this.factPath(pathOrId);
|
|
2598
|
-
await assertNoSymlinkBetween(this.repositoryRoot, path);
|
|
2599
|
-
const parsed = parseFrontMatter(await readFile(path, "utf8"));
|
|
2600
|
-
const metadata = factFrontMatterSchema.parse(parseYaml(parsed.frontMatter));
|
|
2601
|
-
return {
|
|
2602
|
-
...metadata,
|
|
2603
|
-
content: parsed.content.trim(),
|
|
2604
|
-
path
|
|
2605
|
-
};
|
|
2606
|
-
}
|
|
2607
|
-
async listFacts() {
|
|
2608
|
-
return (await this.scanFacts()).facts;
|
|
2609
|
-
}
|
|
2610
|
-
/**
|
|
2611
|
-
* Parse every managed fact file. Hand-written markdown is ignored, and a
|
|
2612
|
-
* schema-invalid/corrupt fact is reported in `invalid` (not thrown) so one
|
|
2613
|
-
* bad file can't break recall, capture or reindexing for the whole project.
|
|
2614
|
-
* Invalid files stay on disk for manual repair.
|
|
2615
|
-
*/
|
|
2616
|
-
async scanFacts() {
|
|
2617
|
-
const scan = await this.scan(
|
|
2618
|
-
this.factsDirectory,
|
|
2619
|
-
/^fact_[a-z0-9]+\.md$/,
|
|
2620
|
-
(path) => this.readFact(path)
|
|
2621
|
-
);
|
|
2622
|
-
return { facts: scan.items, invalid: scan.invalid };
|
|
2623
|
-
}
|
|
2624
|
-
/**
|
|
2625
|
-
* List incident facts for the namespace, ranked by severity then recency.
|
|
2626
|
-
* Unlike {@link findIncidentFactsForPaths} this does not filter by path, so
|
|
2627
|
-
* callers (e.g. the context engine's project bootstrap) can surface the
|
|
2628
|
-
* repository's incident hotspots before any specific edit target is known.
|
|
2629
|
-
*/
|
|
2630
|
-
async listIncidentFacts(input = {}) {
|
|
2631
|
-
const incidents = (await this.listFacts()).filter(
|
|
2632
|
-
(fact) => fact.category === "incident" && Boolean(fact.severity) && isEligibleMemory(fact, input)
|
|
2633
|
-
);
|
|
2634
|
-
return incidents.sort((left, right) => {
|
|
2635
|
-
const severity = severityRank(right.severity) - severityRank(left.severity);
|
|
2636
|
-
if (severity !== 0) return severity;
|
|
2637
|
-
return right.createdAt.localeCompare(left.createdAt);
|
|
2638
|
-
});
|
|
2639
|
-
}
|
|
2640
|
-
async findIncidentFactsForPaths(input) {
|
|
2641
|
-
const wanted = new Set(input.paths.map(normalizeMemoryPath));
|
|
2642
|
-
if (wanted.size === 0) return [];
|
|
2643
|
-
return (await this.listIncidentFacts({
|
|
2644
|
-
...input.namespace !== void 0 ? { namespace: input.namespace } : {},
|
|
2645
|
-
...input.includeResolved !== void 0 ? { includeResolved: input.includeResolved } : {}
|
|
2646
|
-
})).filter((fact) => fact.paths.map(normalizeMemoryPath).some((path) => wanted.has(path)));
|
|
2647
|
-
}
|
|
2648
|
-
async readSummary(pathOrId) {
|
|
2649
|
-
const path = pathOrId.endsWith(".md") ? this.safePath(pathOrId) : this.summaryPath(pathOrId);
|
|
2650
|
-
await assertNoSymlinkBetween(this.repositoryRoot, path);
|
|
2651
|
-
const parsed = parseFrontMatter(await readFile(path, "utf8"));
|
|
2652
|
-
return {
|
|
2653
|
-
...summaryFrontMatterSchema.parse(parseYaml(parsed.frontMatter)),
|
|
2654
|
-
content: parsed.content.trim(),
|
|
2655
|
-
path
|
|
2656
|
-
};
|
|
2657
|
-
}
|
|
2658
|
-
async listSummaries() {
|
|
2659
|
-
return (await this.scanSummaries()).summaries;
|
|
2660
|
-
}
|
|
2661
|
-
async scanSummaries() {
|
|
2662
|
-
const scan = await this.scan(
|
|
2663
|
-
this.summariesDirectory,
|
|
2664
|
-
/^sum_[a-z0-9]+\.md$/,
|
|
2665
|
-
(path) => this.readSummary(path)
|
|
2666
|
-
);
|
|
2667
|
-
return { summaries: scan.items, invalid: scan.invalid };
|
|
2668
|
-
}
|
|
2669
|
-
async scan(directory, managedName, read) {
|
|
2670
|
-
try {
|
|
2671
|
-
await this.prepareDirectory(directory);
|
|
2672
|
-
const entries = await readdir(directory, { withFileTypes: true });
|
|
2673
|
-
const result = { items: [], invalid: [] };
|
|
2674
|
-
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
2675
|
-
if (!entry.isFile() || !managedName.test(entry.name)) continue;
|
|
2676
|
-
const path = join(directory, entry.name);
|
|
2677
|
-
try {
|
|
2678
|
-
const item = await read(path);
|
|
2679
|
-
const id = entry.name.slice(0, -".md".length);
|
|
2680
|
-
if (item.id !== id)
|
|
2681
|
-
throw new Error(`file ID ${id} differs from front matter ID ${item.id}`);
|
|
2682
|
-
result.items.push(item);
|
|
2683
|
-
} catch (error) {
|
|
2684
|
-
result.invalid.push({
|
|
2685
|
-
id: entry.name.slice(0, -".md".length),
|
|
2686
|
-
path,
|
|
2687
|
-
error: error.message.split("\n")[0]?.slice(0, 300) ?? "unreadable"
|
|
2688
|
-
});
|
|
2689
|
-
}
|
|
2690
|
-
}
|
|
2691
|
-
return result;
|
|
2692
|
-
} catch (error) {
|
|
2693
|
-
if (error.code === "ENOENT") return { items: [], invalid: [] };
|
|
2694
|
-
throw error;
|
|
2695
|
-
}
|
|
2696
|
-
}
|
|
2697
|
-
async deleteFact(id) {
|
|
2698
|
-
await rm(this.factPath(id), { force: true });
|
|
2699
|
-
}
|
|
2700
|
-
async markIncidentResolved(id, resolvedBy) {
|
|
2701
|
-
const fact = await this.readFact(id);
|
|
2702
|
-
await this.writeFact(copyFact(fact, { resolvedBy }));
|
|
2703
|
-
}
|
|
2704
|
-
async markFactSuperseded(id, supersededBy) {
|
|
2705
|
-
const fact = await this.readFact(id);
|
|
2706
|
-
await this.writeFact(copyFact(fact, { supersededBy }));
|
|
2707
|
-
}
|
|
2708
|
-
async setFactSharedWith(id, sharedWith) {
|
|
2709
|
-
const fact = await this.readFact(id);
|
|
2710
|
-
await this.writeFact(copyFact(fact, { sharedWith: [...new Set(sharedWith)].sort() }));
|
|
2711
|
-
}
|
|
2712
|
-
/** Persist interaction deletion in Markdown before the derived DB is updated. */
|
|
2713
|
-
async markSourceInteractionDeleted(namespace, sourceInteractionId) {
|
|
2714
|
-
const { facts: facts2 } = await this.scanFacts();
|
|
2715
|
-
for (const fact of facts2) {
|
|
2716
|
-
if (fact.namespace !== namespace || fact.sourceInteractionId !== sourceInteractionId)
|
|
2717
|
-
continue;
|
|
2718
|
-
if (fact.sourceDeleted) continue;
|
|
2719
|
-
await this.writeFact(copyFact(fact, { sourceDeleted: true }));
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
|
-
/** Persist that a fact's source interaction was forgotten, keeping its provenance id. */
|
|
2723
|
-
async markFactSourceDeleted(id) {
|
|
2724
|
-
const fact = await this.readFact(id);
|
|
2725
|
-
await this.writeFact(copyFact(fact, { sourceDeleted: true }));
|
|
2726
|
-
}
|
|
2727
|
-
factPath(id) {
|
|
2728
|
-
if (!/^fact_[a-z0-9]+$/.test(id)) {
|
|
2729
|
-
throw new Error(`Invalid fact id: ${id}`);
|
|
2730
|
-
}
|
|
2731
|
-
return this.safePath(join(this.factsDirectory, `${id}.md`));
|
|
2732
|
-
}
|
|
2733
|
-
summaryPath(id) {
|
|
2734
|
-
if (!/^sum_[a-z0-9]+$/.test(id)) throw new Error(`Invalid summary id: ${id}`);
|
|
2735
|
-
return this.safePath(join(this.summariesDirectory, `${id}.md`));
|
|
2736
|
-
}
|
|
2737
|
-
safePath(path) {
|
|
2738
|
-
const absolute = resolve2(path);
|
|
2739
|
-
const relativePath = relative(this.repositoryRoot, absolute);
|
|
2740
|
-
if (relativePath === ".." || relativePath.startsWith(`..${sep}`) || relativePath === "") {
|
|
2741
|
-
throw new Error(`Memory path escapes repository root: ${path}`);
|
|
2742
|
-
}
|
|
2743
|
-
return absolute;
|
|
2744
|
-
}
|
|
2745
|
-
async prepareDirectory(directory) {
|
|
2746
|
-
await assertNoSymlinkBetween(this.repositoryRoot, dirname2(directory));
|
|
2747
|
-
await mkdir(directory, { recursive: true, mode: 448 });
|
|
2748
|
-
}
|
|
2749
|
-
};
|
|
2750
|
-
function copyFact(fact, patch) {
|
|
2751
|
-
const { path: _path, schemaVersion: _schemaVersion, type: _type, ...write } = fact;
|
|
2752
|
-
return { ...write, ...patch };
|
|
2753
|
-
}
|
|
2754
|
-
function stripUndefinedAndDefaultIncidentFields(metadata) {
|
|
2755
|
-
return Object.fromEntries(
|
|
2756
|
-
Object.entries(metadata).filter(([key, value]) => {
|
|
2757
|
-
if (value === void 0) return false;
|
|
2758
|
-
if (key === "category" && value === "general") return false;
|
|
2759
|
-
if ((key === "paths" || key === "sharedWith") && Array.isArray(value) && value.length === 0)
|
|
2760
|
-
return false;
|
|
2761
|
-
if (["severity", "introducedBy", "resolvedBy", "propositionKey"].includes(key) && (value === null || value === void 0)) {
|
|
2762
|
-
return false;
|
|
2763
|
-
}
|
|
2764
|
-
return true;
|
|
2765
|
-
})
|
|
2766
|
-
);
|
|
2767
|
-
}
|
|
2768
|
-
function normalizeMemoryPath(path) {
|
|
2769
|
-
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
2770
|
-
}
|
|
2771
|
-
function severityRank(severity) {
|
|
2772
|
-
switch (severity) {
|
|
2773
|
-
case "critical":
|
|
2774
|
-
return 4;
|
|
2775
|
-
case "high":
|
|
2776
|
-
return 3;
|
|
2777
|
-
case "medium":
|
|
2778
|
-
return 2;
|
|
2779
|
-
case "low":
|
|
2780
|
-
return 1;
|
|
2781
|
-
}
|
|
2782
|
-
}
|
|
2783
|
-
|
|
2784
2074
|
// src/core/worker.ts
|
|
2785
2075
|
var DEFAULT_POLL_MS = 250;
|
|
2786
2076
|
var DEFAULT_BATCH_SIZE = 8;
|
|
@@ -2793,6 +2083,7 @@ var EmbeddingWorker = class {
|
|
|
2793
2083
|
batchSize;
|
|
2794
2084
|
maxAttempts;
|
|
2795
2085
|
onDiagnostic;
|
|
2086
|
+
namespaceId;
|
|
2796
2087
|
state = "idle";
|
|
2797
2088
|
loopPromise = null;
|
|
2798
2089
|
wake = null;
|
|
@@ -2805,6 +2096,7 @@ var EmbeddingWorker = class {
|
|
|
2805
2096
|
this.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
2806
2097
|
this.maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
2807
2098
|
this.onDiagnostic = options.onDiagnostic;
|
|
2099
|
+
this.namespaceId = options.namespaceId;
|
|
2808
2100
|
}
|
|
2809
2101
|
getState() {
|
|
2810
2102
|
return this.state;
|
|
@@ -2834,8 +2126,8 @@ var EmbeddingWorker = class {
|
|
|
2834
2126
|
* wait out anymore.
|
|
2835
2127
|
*/
|
|
2836
2128
|
async drain() {
|
|
2837
|
-
await new Promise((
|
|
2838
|
-
this.idleResolvers.push(
|
|
2129
|
+
await new Promise((resolve2) => {
|
|
2130
|
+
this.idleResolvers.push(resolve2);
|
|
2839
2131
|
this.notify();
|
|
2840
2132
|
});
|
|
2841
2133
|
}
|
|
@@ -2861,13 +2153,13 @@ var EmbeddingWorker = class {
|
|
|
2861
2153
|
while (this.state === "running") {
|
|
2862
2154
|
let jobs;
|
|
2863
2155
|
try {
|
|
2864
|
-
jobs = await this.repo.claimPendingEmbeddings(this.batchSize);
|
|
2156
|
+
jobs = await this.repo.claimPendingEmbeddings(this.batchSize, this.namespaceId?.());
|
|
2865
2157
|
} catch (error) {
|
|
2866
2158
|
console.error(
|
|
2867
2159
|
`[worker] claimPendingEmbeddings failed: ${error instanceof Error ? error.message : String(error)}; retrying`
|
|
2868
2160
|
);
|
|
2869
2161
|
if (this.state !== "running") break;
|
|
2870
|
-
await new Promise((
|
|
2162
|
+
await new Promise((resolve2) => setTimeout(resolve2, ERROR_BACKOFF_MS));
|
|
2871
2163
|
continue;
|
|
2872
2164
|
}
|
|
2873
2165
|
if (jobs.length === 0) {
|
|
@@ -2894,7 +2186,7 @@ var EmbeddingWorker = class {
|
|
|
2894
2186
|
if (this.inFlight > 0) return;
|
|
2895
2187
|
const resolvers = this.idleResolvers;
|
|
2896
2188
|
this.idleResolvers = [];
|
|
2897
|
-
for (const
|
|
2189
|
+
for (const resolve2 of resolvers) resolve2();
|
|
2898
2190
|
}
|
|
2899
2191
|
async processJob(job) {
|
|
2900
2192
|
let leaseLost = false;
|
|
@@ -2914,14 +2206,14 @@ var EmbeddingWorker = class {
|
|
|
2914
2206
|
model: job.embeddingModel
|
|
2915
2207
|
});
|
|
2916
2208
|
validateEmbeddingResponse(response, 1);
|
|
2917
|
-
const
|
|
2918
|
-
if (!
|
|
2209
|
+
const vector = response.vectors[0];
|
|
2210
|
+
if (!vector || vector.length === 0) {
|
|
2919
2211
|
throw new Error("Provider returned no embedding vector.");
|
|
2920
2212
|
}
|
|
2921
2213
|
if (leaseLost || !await this.repo.markEmbeddingReady(
|
|
2922
2214
|
job.id,
|
|
2923
2215
|
job.leaseToken,
|
|
2924
|
-
|
|
2216
|
+
vector,
|
|
2925
2217
|
response.model,
|
|
2926
2218
|
embeddingSpaceKey(embeddingSpace(response))
|
|
2927
2219
|
))
|
|
@@ -2979,14 +2271,14 @@ var EmbeddingWorker = class {
|
|
|
2979
2271
|
});
|
|
2980
2272
|
}
|
|
2981
2273
|
sleep(ms) {
|
|
2982
|
-
return new Promise((
|
|
2274
|
+
return new Promise((resolve2) => {
|
|
2983
2275
|
const timer = setTimeout(() => {
|
|
2984
2276
|
this.wake = null;
|
|
2985
|
-
|
|
2277
|
+
resolve2();
|
|
2986
2278
|
}, ms ?? this.pollIntervalMs);
|
|
2987
2279
|
this.wake = () => {
|
|
2988
2280
|
clearTimeout(timer);
|
|
2989
|
-
|
|
2281
|
+
resolve2();
|
|
2990
2282
|
};
|
|
2991
2283
|
});
|
|
2992
2284
|
}
|
|
@@ -3017,6 +2309,7 @@ var CodeBuddy = class {
|
|
|
3017
2309
|
this.worker = deps.worker ?? new EmbeddingWorker({
|
|
3018
2310
|
repository: this.repo,
|
|
3019
2311
|
provider: this.provider,
|
|
2312
|
+
namespaceId: () => this.namespaceId ?? void 0,
|
|
3020
2313
|
...this.config.worker?.pollIntervalMs !== void 0 ? { pollIntervalMs: this.config.worker.pollIntervalMs } : {},
|
|
3021
2314
|
...this.config.worker?.batchSize !== void 0 ? { batchSize: this.config.worker.batchSize } : {},
|
|
3022
2315
|
...this.config.worker?.maxAttempts !== void 0 ? { maxAttempts: this.config.worker.maxAttempts } : {}
|
|
@@ -3160,8 +2453,8 @@ var CodeBuddy = class {
|
|
|
3160
2453
|
})
|
|
3161
2454
|
);
|
|
3162
2455
|
validateEmbeddingResponse(response, 1);
|
|
3163
|
-
const
|
|
3164
|
-
return
|
|
2456
|
+
const vector = response.vectors[0];
|
|
2457
|
+
return vector ? { vector, space: embeddingSpace(response) } : null;
|
|
3165
2458
|
} catch {
|
|
3166
2459
|
return null;
|
|
3167
2460
|
}
|
|
@@ -3343,9 +2636,10 @@ var CodeBuddy = class {
|
|
|
3343
2636
|
};
|
|
3344
2637
|
const factResult = await this.repo.withSessionLock(namespaceId, REINDEX_LOCK_KEY, async () => {
|
|
3345
2638
|
const result = await this.repo.forgetFact(namespaceId, id, factAudit);
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
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 };
|
|
3349
2643
|
}
|
|
3350
2644
|
return result;
|
|
3351
2645
|
});
|
|
@@ -3361,7 +2655,7 @@ var CodeBuddy = class {
|
|
|
3361
2655
|
* file is applied independently: malformed or conflicting files are reported
|
|
3362
2656
|
* in `failures` and never abort healthy imports (nor count as deletions).
|
|
3363
2657
|
*/
|
|
3364
|
-
async reindexMemory() {
|
|
2658
|
+
async reindexMemory(options = {}) {
|
|
3365
2659
|
const namespaceId = this.requireNamespaceId();
|
|
3366
2660
|
const store = this.memoryFileStore;
|
|
3367
2661
|
if (!store) {
|
|
@@ -3441,7 +2735,7 @@ var CodeBuddy = class {
|
|
|
3441
2735
|
failures: failures.slice(0, MAX_REPORTED_FAILURES)
|
|
3442
2736
|
};
|
|
3443
2737
|
});
|
|
3444
|
-
const space = this.provider.space;
|
|
2738
|
+
const space = options.respace === false ? void 0 : this.provider.space;
|
|
3445
2739
|
const canEmbed = space !== void 0 && await this.provider.embed({ input: "codebuddy" }).then(
|
|
3446
2740
|
() => true,
|
|
3447
2741
|
() => false
|
|
@@ -3787,8 +3081,8 @@ function decodeFactCursor(cursor) {
|
|
|
3787
3081
|
if (!Array.isArray(parsed) || parsed.length !== 2 || typeof parsed[0] !== "string" || typeof parsed[1] !== "string" || Number.isNaN(Date.parse(parsed[0]))) {
|
|
3788
3082
|
throw new Error("Invalid cursor: expected a base64url-encoded [createdAt, id] pair.");
|
|
3789
3083
|
}
|
|
3790
|
-
const [
|
|
3791
|
-
return { createdAt: new Date(
|
|
3084
|
+
const [createdAt, id] = parsed;
|
|
3085
|
+
return { createdAt: new Date(createdAt), id };
|
|
3792
3086
|
}
|
|
3793
3087
|
async function listFactsPage(memory, repository, input) {
|
|
3794
3088
|
const namespace = await repository.ensureNamespace(memory.config.namespace);
|
|
@@ -3824,6 +3118,7 @@ async function inspectNamespace(repository, namespace) {
|
|
|
3824
3118
|
};
|
|
3825
3119
|
}
|
|
3826
3120
|
async function runDoctor(options = {}) {
|
|
3121
|
+
const migrated = await migrateLegacyNamespace();
|
|
3827
3122
|
const fileConfig = await readConfigFile();
|
|
3828
3123
|
const scaffold = await checkProjectScaffold();
|
|
3829
3124
|
const configPermissions = await checkConfigPermissions();
|
|
@@ -3833,6 +3128,7 @@ async function runDoctor(options = {}) {
|
|
|
3833
3128
|
expectedDefault: expectedDefaultNamespace,
|
|
3834
3129
|
configured: fileConfig.namespace ?? null,
|
|
3835
3130
|
runtime: runtimeNamespace,
|
|
3131
|
+
...migrated ? { migrated } : {},
|
|
3836
3132
|
ok: !fileConfig.namespace || fileConfig.namespace === expectedDefaultNamespace || process.env.CODEBUDDY_NAMESPACE !== void 0,
|
|
3837
3133
|
...!fileConfig.namespace || fileConfig.namespace === expectedDefaultNamespace || process.env.CODEBUDDY_NAMESPACE !== void 0 ? {} : {
|
|
3838
3134
|
warning: `Configured namespace "${fileConfig.namespace}" differs from this folder's default "${expectedDefaultNamespace}". Confirm your MCP entries point at the intended namespace.`
|
|
@@ -3977,17 +3273,12 @@ async function checkModels(provider, skip = false) {
|
|
|
3977
3273
|
}
|
|
3978
3274
|
|
|
3979
3275
|
export {
|
|
3980
|
-
isEligibleMemory,
|
|
3981
|
-
lexicalTerms,
|
|
3982
3276
|
embeddingSpaceKey,
|
|
3983
3277
|
DefaultPolicy,
|
|
3984
3278
|
HuggingFaceProvider,
|
|
3985
3279
|
isLangSmithTracingEnabled,
|
|
3986
3280
|
createTracer,
|
|
3987
3281
|
codeBuddyConfigSchema,
|
|
3988
|
-
FACT_CATEGORIES,
|
|
3989
|
-
INCIDENT_SEVERITIES,
|
|
3990
|
-
MemoryFileStore,
|
|
3991
3282
|
EmbeddingWorker,
|
|
3992
3283
|
CodeBuddy,
|
|
3993
3284
|
buildProviderFromConfig,
|
|
@@ -4003,4 +3294,4 @@ export {
|
|
|
4003
3294
|
inspectNamespace,
|
|
4004
3295
|
runDoctor
|
|
4005
3296
|
};
|
|
4006
|
-
//# sourceMappingURL=chunk-
|
|
3297
|
+
//# sourceMappingURL=chunk-2XDPKFUW.js.map
|