@soleri/core 9.0.0 → 9.0.1
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/dist/engine/module-manifest.d.ts +1 -1
- package/dist/engine/module-manifest.d.ts.map +1 -1
- package/dist/engine/module-manifest.js +1 -7
- package/dist/engine/module-manifest.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/admin-extra-ops.test.ts +0 -3
- package/src/__tests__/admin-ops.test.ts +1 -5
- package/src/__tests__/brain.test.ts +1 -225
- package/src/__tests__/context-engine.test.ts +1 -6
- package/src/__tests__/core-ops.test.ts +1 -8
- package/src/__tests__/curator-extra-ops.test.ts +0 -2
- package/src/__tests__/curator-pipeline-e2e.test.ts +3 -28
- package/src/__tests__/feature-flags.test.ts +0 -1
- package/src/__tests__/health-registry.test.ts +18 -18
- package/src/__tests__/replayable-stream.test.ts +3 -3
- package/src/engine/module-manifest.ts +1 -7
|
@@ -24,5 +24,5 @@ export declare const ENGINE_MODULE_MANIFEST: ModuleManifestEntry[];
|
|
|
24
24
|
/** Core facade ops (always present, not in ENGINE_MODULES) */
|
|
25
25
|
export declare const CORE_KEY_OPS: string[];
|
|
26
26
|
/** Engine major version — used for compatibility checks against domain packs. */
|
|
27
|
-
export declare const ENGINE_MAJOR_VERSION =
|
|
27
|
+
export declare const ENGINE_MAJOR_VERSION = 9;
|
|
28
28
|
//# sourceMappingURL=module-manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-manifest.d.ts","sourceRoot":"","sources":["../../src/engine/module-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"module-manifest.d.ts","sourceRoot":"","sources":["../../src/engine/module-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,EA8DvD,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,YAAY,UAAiD,CAAC;AAE3E,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,IAAI,CAAC"}
|
|
@@ -71,15 +71,9 @@ export const ENGINE_MODULE_MANIFEST = [
|
|
|
71
71
|
description: 'Chat transport — session management, response chunking, authentication.',
|
|
72
72
|
keyOps: ['chat_send', 'chat_history', 'chat_session'],
|
|
73
73
|
},
|
|
74
|
-
{
|
|
75
|
-
suffix: 'cognee',
|
|
76
|
-
description: 'Knowledge graph — Cognee search, sync, export, graph stats.',
|
|
77
|
-
keyOps: ['cognee_search', 'cognee_add', 'cognee_cognify'],
|
|
78
|
-
conditional: true,
|
|
79
|
-
},
|
|
80
74
|
];
|
|
81
75
|
/** Core facade ops (always present, not in ENGINE_MODULES) */
|
|
82
76
|
export const CORE_KEY_OPS = ['health', 'identity', 'register', 'activate'];
|
|
83
77
|
/** Engine major version — used for compatibility checks against domain packs. */
|
|
84
|
-
export const ENGINE_MAJOR_VERSION =
|
|
78
|
+
export const ENGINE_MAJOR_VERSION = 9;
|
|
85
79
|
//# sourceMappingURL=module-manifest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-manifest.js","sourceRoot":"","sources":["../../src/engine/module-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA0B;IAC3D;QACE,MAAM,EAAE,OAAO;QACf,WAAW,EAAE,uEAAuE;QACpF,MAAM,EAAE,CAAC,oBAAoB,EAAE,mBAAmB,EAAE,eAAe,CAAC;KACrE;IACD;QACE,MAAM,EAAE,MAAM;QACd,WAAW,EAAE,0EAA0E;QACvF,MAAM,EAAE,CAAC,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,CAAC;KACxE;IACD;QACE,MAAM,EAAE,OAAO;QACf,WAAW,EAAE,yEAAyE;QACtF,MAAM,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC;KAC/C;IACD;QACE,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,mEAAmE;QAChF,MAAM,EAAE,CAAC,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,CAAC;KAC/D;IACD;QACE,MAAM,EAAE,OAAO;QACf,WAAW,EAAE,mEAAmE;QAChF,MAAM,EAAE,CAAC,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,CAAC;KAChE;IACD;QACE,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,wEAAwE;QACrF,MAAM,EAAE,CAAC,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,CAAC;KAC9D;IACD;QACE,MAAM,EAAE,MAAM;QACd,WAAW,EAAE,yEAAyE;QACtF,MAAM,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,aAAa,CAAC;KACrD;IACD;QACE,MAAM,EAAE,aAAa;QACrB,WAAW,EACT,mFAAmF;QACrF,MAAM,EAAE,CAAC,kBAAkB,EAAE,qBAAqB,EAAE,sBAAsB,CAAC;KAC5E;IACD;QACE,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,8EAA8E;QAC3F,MAAM,EAAE,CAAC,cAAc,EAAE,OAAO,EAAE,oBAAoB,CAAC;KACxD;IACD;QACE,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,gFAAgF;QAC7F,MAAM,EAAE,CAAC,0BAA0B,EAAE,4BAA4B,EAAE,iBAAiB,CAAC;KACtF;IACD;QACE,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,sEAAsE;QACnF,MAAM,EAAE,CAAC,kBAAkB,EAAE,yBAAyB,EAAE,iBAAiB,CAAC;KAC3E;IACD;QACE,MAAM,EAAE,MAAM;QACd,WAAW,EAAE,yEAAyE;QACtF,MAAM,EAAE,CAAC,WAAW,EAAE,cAAc,EAAE,cAAc,CAAC;KACtD;
|
|
1
|
+
{"version":3,"file":"module-manifest.js","sourceRoot":"","sources":["../../src/engine/module-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA0B;IAC3D;QACE,MAAM,EAAE,OAAO;QACf,WAAW,EAAE,uEAAuE;QACpF,MAAM,EAAE,CAAC,oBAAoB,EAAE,mBAAmB,EAAE,eAAe,CAAC;KACrE;IACD;QACE,MAAM,EAAE,MAAM;QACd,WAAW,EAAE,0EAA0E;QACvF,MAAM,EAAE,CAAC,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,CAAC;KACxE;IACD;QACE,MAAM,EAAE,OAAO;QACf,WAAW,EAAE,yEAAyE;QACtF,MAAM,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC;KAC/C;IACD;QACE,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,mEAAmE;QAChF,MAAM,EAAE,CAAC,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,CAAC;KAC/D;IACD;QACE,MAAM,EAAE,OAAO;QACf,WAAW,EAAE,mEAAmE;QAChF,MAAM,EAAE,CAAC,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,CAAC;KAChE;IACD;QACE,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,wEAAwE;QACrF,MAAM,EAAE,CAAC,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,CAAC;KAC9D;IACD;QACE,MAAM,EAAE,MAAM;QACd,WAAW,EAAE,yEAAyE;QACtF,MAAM,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,aAAa,CAAC;KACrD;IACD;QACE,MAAM,EAAE,aAAa;QACrB,WAAW,EACT,mFAAmF;QACrF,MAAM,EAAE,CAAC,kBAAkB,EAAE,qBAAqB,EAAE,sBAAsB,CAAC;KAC5E;IACD;QACE,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,8EAA8E;QAC3F,MAAM,EAAE,CAAC,cAAc,EAAE,OAAO,EAAE,oBAAoB,CAAC;KACxD;IACD;QACE,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,gFAAgF;QAC7F,MAAM,EAAE,CAAC,0BAA0B,EAAE,4BAA4B,EAAE,iBAAiB,CAAC;KACtF;IACD;QACE,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,sEAAsE;QACnF,MAAM,EAAE,CAAC,kBAAkB,EAAE,yBAAyB,EAAE,iBAAiB,CAAC;KAC3E;IACD;QACE,MAAM,EAAE,MAAM;QACd,WAAW,EAAE,yEAAyE;QACtF,MAAM,EAAE,CAAC,WAAW,EAAE,cAAc,EAAE,cAAc,CAAC;KACtD;CACF,CAAC;AAEF,8DAA8D;AAC9D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAE3E,iFAAiF;AACjF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -344,7 +344,6 @@ describe('createAdminExtraOps', () => {
|
|
|
344
344
|
planner: boolean;
|
|
345
345
|
curator: boolean;
|
|
346
346
|
governance: boolean;
|
|
347
|
-
cognee: { available: boolean };
|
|
348
347
|
loop: { active: boolean };
|
|
349
348
|
llm: { openai: boolean; anthropic: boolean };
|
|
350
349
|
};
|
|
@@ -354,7 +353,6 @@ describe('createAdminExtraOps', () => {
|
|
|
354
353
|
expect(result.planner).toBe(true);
|
|
355
354
|
expect(result.curator).toBe(true);
|
|
356
355
|
expect(result.governance).toBe(true);
|
|
357
|
-
expect(result.cognee).toEqual({ available: false });
|
|
358
356
|
expect(result.loop).toEqual({ active: false });
|
|
359
357
|
expect(typeof result.llm.openai).toBe('boolean');
|
|
360
358
|
expect(typeof result.llm.anthropic).toBe('boolean');
|
|
@@ -392,7 +390,6 @@ describe('createAdminExtraOps', () => {
|
|
|
392
390
|
const result = (await findOp('admin_gc').handler({})) as { cleared: string[] };
|
|
393
391
|
|
|
394
392
|
expect(result.cleared).toContain('brain');
|
|
395
|
-
// cognee is only cleared when enabled (opt-in)
|
|
396
393
|
expect(result.cleared).toContain('telemetry');
|
|
397
394
|
});
|
|
398
395
|
|
|
@@ -51,7 +51,6 @@ describe('createAdminOps', () => {
|
|
|
51
51
|
|
|
52
52
|
expect(result.status).toBe('ok');
|
|
53
53
|
expect(result.vault).toEqual({ entries: 0, domains: [] });
|
|
54
|
-
expect(result.cognee).toEqual({ available: false });
|
|
55
54
|
expect(result.llm).toHaveProperty('openai');
|
|
56
55
|
expect(result.llm).toHaveProperty('anthropic');
|
|
57
56
|
expect(result.brain).toHaveProperty('vocabularySize');
|
|
@@ -181,10 +180,8 @@ describe('createAdminOps', () => {
|
|
|
181
180
|
setup();
|
|
182
181
|
const result = (await findOp('admin_reset_cache').handler({})) as Record<string, unknown>;
|
|
183
182
|
|
|
184
|
-
// When cognee is disabled (default), only brain vocabulary is cleared
|
|
185
183
|
expect(result.cleared).toContain('brain_vocabulary');
|
|
186
184
|
expect(typeof (result as { brainVocabularySize: number }).brainVocabularySize).toBe('number');
|
|
187
|
-
expect(typeof (result as { cogneeAvailable: boolean }).cogneeAvailable).toBe('boolean');
|
|
188
185
|
});
|
|
189
186
|
|
|
190
187
|
it('should have write auth', () => {
|
|
@@ -206,13 +203,12 @@ describe('createAdminOps', () => {
|
|
|
206
203
|
};
|
|
207
204
|
|
|
208
205
|
expect(['healthy', 'degraded', 'unhealthy']).toContain(result.overall);
|
|
209
|
-
expect(result.checks.length).toBeGreaterThanOrEqual(
|
|
206
|
+
expect(result.checks.length).toBeGreaterThanOrEqual(6);
|
|
210
207
|
|
|
211
208
|
const checkNames = result.checks.map((c) => c.name);
|
|
212
209
|
expect(checkNames).toContain('vault');
|
|
213
210
|
expect(checkNames).toContain('brain_vocabulary');
|
|
214
211
|
expect(checkNames).toContain('brain_intelligence');
|
|
215
|
-
expect(checkNames).toContain('cognee');
|
|
216
212
|
expect(checkNames).toContain('llm_openai');
|
|
217
213
|
expect(checkNames).toContain('llm_anthropic');
|
|
218
214
|
expect(checkNames).toContain('curator');
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
2
|
import { Vault } from '../vault/vault.js';
|
|
3
3
|
import { Brain } from '../brain/brain.js';
|
|
4
4
|
import type { IntelligenceEntry } from '../intelligence/types.js';
|
|
5
|
-
import type { CogneeClient } from '../cognee/client.js';
|
|
6
|
-
import type { CogneeSearchResult, CogneeStatus } from '../cognee/types.js';
|
|
7
5
|
|
|
8
6
|
function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntry {
|
|
9
7
|
return {
|
|
@@ -17,36 +15,6 @@ function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntr
|
|
|
17
15
|
};
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
function makeMockCognee(
|
|
21
|
-
overrides: {
|
|
22
|
-
available?: boolean;
|
|
23
|
-
searchResults?: CogneeSearchResult[];
|
|
24
|
-
searchError?: boolean;
|
|
25
|
-
} = {},
|
|
26
|
-
): CogneeClient {
|
|
27
|
-
const available = overrides.available ?? true;
|
|
28
|
-
return {
|
|
29
|
-
get isAvailable() {
|
|
30
|
-
return available;
|
|
31
|
-
},
|
|
32
|
-
search: overrides.searchError
|
|
33
|
-
? vi.fn().mockRejectedValue(new Error('timeout'))
|
|
34
|
-
: vi.fn().mockResolvedValue(overrides.searchResults ?? []),
|
|
35
|
-
addEntries: vi.fn().mockResolvedValue({ added: 0 }),
|
|
36
|
-
cognify: vi.fn().mockResolvedValue({ status: 'ok' }),
|
|
37
|
-
healthCheck: vi
|
|
38
|
-
.fn()
|
|
39
|
-
.mockResolvedValue({ available, url: 'http://localhost:8000', latencyMs: 1 } as CogneeStatus),
|
|
40
|
-
getConfig: vi.fn().mockReturnValue({
|
|
41
|
-
baseUrl: 'http://localhost:8000',
|
|
42
|
-
dataset: 'vault',
|
|
43
|
-
timeoutMs: 5000,
|
|
44
|
-
healthCacheTtlMs: 60000,
|
|
45
|
-
}),
|
|
46
|
-
getStatus: vi.fn().mockReturnValue(null),
|
|
47
|
-
} as unknown as CogneeClient;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
18
|
describe('Brain', () => {
|
|
51
19
|
let vault: Vault;
|
|
52
20
|
let brain: Brain;
|
|
@@ -85,12 +53,6 @@ describe('Brain', () => {
|
|
|
85
53
|
const brain2 = new Brain(vault);
|
|
86
54
|
expect(brain2.getVocabularySize()).toBeGreaterThan(0);
|
|
87
55
|
});
|
|
88
|
-
|
|
89
|
-
it('should accept optional CogneeClient', () => {
|
|
90
|
-
const cognee = makeMockCognee();
|
|
91
|
-
const brain2 = new Brain(vault, cognee);
|
|
92
|
-
expect(brain2.getVocabularySize()).toBe(0);
|
|
93
|
-
});
|
|
94
56
|
});
|
|
95
57
|
|
|
96
58
|
// ─── Intelligent Search ──────────────────────────────────────
|
|
@@ -145,7 +107,6 @@ describe('Brain', () => {
|
|
|
145
107
|
expect(breakdown).toHaveProperty('domainMatch');
|
|
146
108
|
expect(breakdown).toHaveProperty('total');
|
|
147
109
|
expect(breakdown.total).toBe(results[0].score);
|
|
148
|
-
// Without cognee, vector should be 0
|
|
149
110
|
expect(breakdown.vector).toBe(0);
|
|
150
111
|
});
|
|
151
112
|
|
|
@@ -203,176 +164,6 @@ describe('Brain', () => {
|
|
|
203
164
|
});
|
|
204
165
|
});
|
|
205
166
|
|
|
206
|
-
// ─── Hybrid Search (with Cognee) ──────────────────────────────
|
|
207
|
-
|
|
208
|
-
describe('hybrid search with Cognee', () => {
|
|
209
|
-
beforeEach(() => {
|
|
210
|
-
vault.seed([
|
|
211
|
-
makeEntry({
|
|
212
|
-
id: 'hs-1',
|
|
213
|
-
title: 'Authentication flow',
|
|
214
|
-
description: 'JWT-based authentication for API endpoints.',
|
|
215
|
-
domain: 'security',
|
|
216
|
-
severity: 'critical',
|
|
217
|
-
tags: ['auth', 'jwt'],
|
|
218
|
-
}),
|
|
219
|
-
makeEntry({
|
|
220
|
-
id: 'hs-2',
|
|
221
|
-
title: 'Logging best practices',
|
|
222
|
-
description: 'Structured logging with correlation IDs for debugging.',
|
|
223
|
-
domain: 'observability',
|
|
224
|
-
severity: 'warning',
|
|
225
|
-
tags: ['logging', 'debugging'],
|
|
226
|
-
}),
|
|
227
|
-
]);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('should match via [vault-id:] prefix (strategy 1)', async () => {
|
|
231
|
-
const cognee = makeMockCognee({
|
|
232
|
-
searchResults: [
|
|
233
|
-
{
|
|
234
|
-
id: 'cognee-uuid-1',
|
|
235
|
-
score: 0.92,
|
|
236
|
-
text: '[vault-id:hs-1]\nAuthentication flow\nJWT-based authentication for API endpoints.',
|
|
237
|
-
searchType: 'CHUNKS',
|
|
238
|
-
},
|
|
239
|
-
],
|
|
240
|
-
});
|
|
241
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
242
|
-
const results = await hybridBrain.intelligentSearch('authentication');
|
|
243
|
-
expect(results.length).toBeGreaterThan(0);
|
|
244
|
-
const authResult = results.find((r) => r.entry.id === 'hs-1');
|
|
245
|
-
expect(authResult).toBeDefined();
|
|
246
|
-
expect(authResult!.breakdown.vector).toBe(0.92);
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it('should match via title first-line (strategy 2)', async () => {
|
|
250
|
-
// Cognee stripped the [vault-id:] prefix during chunking — title is on first line
|
|
251
|
-
const cognee = makeMockCognee({
|
|
252
|
-
searchResults: [
|
|
253
|
-
{
|
|
254
|
-
id: 'cognee-uuid-2',
|
|
255
|
-
score: 0.9,
|
|
256
|
-
text: 'Authentication flow\nJWT-based authentication for API endpoints.',
|
|
257
|
-
searchType: 'CHUNKS',
|
|
258
|
-
},
|
|
259
|
-
],
|
|
260
|
-
});
|
|
261
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
262
|
-
const results = await hybridBrain.intelligentSearch('authentication');
|
|
263
|
-
const authResult = results.find((r) => r.entry.id === 'hs-1');
|
|
264
|
-
expect(authResult).toBeDefined();
|
|
265
|
-
expect(authResult!.breakdown.vector).toBe(0.9);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('should match via title substring (strategy 3)', async () => {
|
|
269
|
-
// Mid-document chunk where title isn't on the first line
|
|
270
|
-
const cognee = makeMockCognee({
|
|
271
|
-
searchResults: [
|
|
272
|
-
{
|
|
273
|
-
id: 'cognee-uuid-3',
|
|
274
|
-
score: 0.85,
|
|
275
|
-
text: 'Some preamble text\nAuthentication flow\nJWT-based auth...',
|
|
276
|
-
searchType: 'CHUNKS',
|
|
277
|
-
},
|
|
278
|
-
],
|
|
279
|
-
});
|
|
280
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
281
|
-
const results = await hybridBrain.intelligentSearch('authentication');
|
|
282
|
-
const authResult = results.find((r) => r.entry.id === 'hs-1');
|
|
283
|
-
expect(authResult).toBeDefined();
|
|
284
|
-
expect(authResult!.breakdown.vector).toBe(0.85);
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
it('should merge cognee-only entries via FTS fallback (strategy 4)', async () => {
|
|
288
|
-
// hs-2 may not match FTS5 for "authentication" but Cognee finds it via semantic similarity.
|
|
289
|
-
// The chunk text starts with the entry title so strategy 4's vault.search(firstLine) finds it.
|
|
290
|
-
const cognee = makeMockCognee({
|
|
291
|
-
searchResults: [
|
|
292
|
-
{
|
|
293
|
-
id: 'cognee-uuid-a',
|
|
294
|
-
score: 0.95,
|
|
295
|
-
text: 'Authentication flow\nJWT-based authentication for API endpoints.',
|
|
296
|
-
searchType: 'CHUNKS',
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
id: 'cognee-uuid-b',
|
|
300
|
-
score: 0.6,
|
|
301
|
-
text: 'Logging best practices\nStructured logging with correlation IDs.',
|
|
302
|
-
searchType: 'CHUNKS',
|
|
303
|
-
},
|
|
304
|
-
],
|
|
305
|
-
});
|
|
306
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
307
|
-
const results = await hybridBrain.intelligentSearch('authentication');
|
|
308
|
-
// Both entries should be in results (hs-2 merged from Cognee even if not in FTS5)
|
|
309
|
-
const ids = results.map((r) => r.entry.id);
|
|
310
|
-
expect(ids).toContain('hs-1');
|
|
311
|
-
expect(ids).toContain('hs-2');
|
|
312
|
-
const loggingResult = results.find((r) => r.entry.id === 'hs-2');
|
|
313
|
-
expect(loggingResult).toBeDefined();
|
|
314
|
-
expect(loggingResult!.breakdown.vector).toBe(0.6);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
it('should fall back to FTS5-only on Cognee search error', async () => {
|
|
318
|
-
const cognee = makeMockCognee({ searchError: true });
|
|
319
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
320
|
-
const results = await hybridBrain.intelligentSearch('authentication');
|
|
321
|
-
// Should still work, just without vector scores
|
|
322
|
-
for (const r of results) {
|
|
323
|
-
expect(r.breakdown.vector).toBe(0);
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
it('should work without Cognee (backward compatible)', async () => {
|
|
328
|
-
const noCogneeBrain = new Brain(vault);
|
|
329
|
-
const results = await noCogneeBrain.intelligentSearch('authentication');
|
|
330
|
-
for (const r of results) {
|
|
331
|
-
expect(r.breakdown.vector).toBe(0);
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
it('should handle unavailable Cognee gracefully', async () => {
|
|
336
|
-
const cognee = makeMockCognee({ available: false });
|
|
337
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
338
|
-
const results = await hybridBrain.intelligentSearch('authentication');
|
|
339
|
-
for (const r of results) {
|
|
340
|
-
expect(r.breakdown.vector).toBe(0);
|
|
341
|
-
}
|
|
342
|
-
// search should not have been called
|
|
343
|
-
expect(cognee.search).not.toHaveBeenCalled();
|
|
344
|
-
});
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
// ─── syncToCognee ──────────────────────────────────────────────
|
|
348
|
-
|
|
349
|
-
describe('syncToCognee', () => {
|
|
350
|
-
it('should return 0 when Cognee not available', async () => {
|
|
351
|
-
const result = await brain.syncToCognee();
|
|
352
|
-
expect(result).toEqual({ synced: 0, cognified: false });
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
it('should sync all entries and cognify', async () => {
|
|
356
|
-
vault.seed([makeEntry({ id: 'sync-1' }), makeEntry({ id: 'sync-2' })]);
|
|
357
|
-
const cognee = makeMockCognee();
|
|
358
|
-
(cognee.addEntries as ReturnType<typeof vi.fn>).mockResolvedValue({ added: 2 });
|
|
359
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
360
|
-
const result = await hybridBrain.syncToCognee();
|
|
361
|
-
expect(result.synced).toBe(2);
|
|
362
|
-
expect(result.cognified).toBe(true);
|
|
363
|
-
expect(cognee.addEntries).toHaveBeenCalledTimes(1);
|
|
364
|
-
expect(cognee.cognify).toHaveBeenCalledTimes(1);
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
it('should skip cognify when no entries added', async () => {
|
|
368
|
-
const cognee = makeMockCognee();
|
|
369
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
370
|
-
const result = await hybridBrain.syncToCognee();
|
|
371
|
-
expect(result.synced).toBe(0);
|
|
372
|
-
expect(result.cognified).toBe(false);
|
|
373
|
-
});
|
|
374
|
-
});
|
|
375
|
-
|
|
376
167
|
// ─── Enrich and Capture ─────────────────────────────────────
|
|
377
168
|
|
|
378
169
|
describe('enrichAndCapture', () => {
|
|
@@ -456,21 +247,6 @@ describe('Brain', () => {
|
|
|
456
247
|
const entry = vault.get('cap-5');
|
|
457
248
|
expect(entry!.tags.length).toBeGreaterThan(0);
|
|
458
249
|
});
|
|
459
|
-
|
|
460
|
-
it('should fire-and-forget sync to Cognee on capture', () => {
|
|
461
|
-
const cognee = makeMockCognee();
|
|
462
|
-
const hybridBrain = new Brain(vault, cognee);
|
|
463
|
-
hybridBrain.enrichAndCapture({
|
|
464
|
-
id: 'cap-cognee-1',
|
|
465
|
-
type: 'pattern',
|
|
466
|
-
domain: 'testing',
|
|
467
|
-
title: 'Cognee sync test',
|
|
468
|
-
severity: 'warning',
|
|
469
|
-
description: 'Testing fire-and-forget Cognee sync.',
|
|
470
|
-
tags: [],
|
|
471
|
-
});
|
|
472
|
-
expect(cognee.addEntries).toHaveBeenCalledTimes(1);
|
|
473
|
-
});
|
|
474
250
|
});
|
|
475
251
|
|
|
476
252
|
// ─── Duplicate Detection ────────────────────────────────────
|
|
@@ -117,11 +117,6 @@ describe('ContextEngine', () => {
|
|
|
117
117
|
expect(result.vaultHits).toBe(0);
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
test('handles null cognee gracefully', async () => {
|
|
121
|
-
const result = await engine.retrieveKnowledge('anything');
|
|
122
|
-
expect(result.cogneeHits).toBe(0);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
120
|
test('filters by domain', async () => {
|
|
126
121
|
vault.seed([
|
|
127
122
|
{
|
|
@@ -231,7 +226,7 @@ describe('ContextEngine', () => {
|
|
|
231
226
|
|
|
232
227
|
describe('configuration', () => {
|
|
233
228
|
test('respects custom config', async () => {
|
|
234
|
-
const customEngine = new ContextEngine(vault, brain, intelligence,
|
|
229
|
+
const customEngine = new ContextEngine(vault, brain, intelligence, {
|
|
235
230
|
vaultSearchLimit: 2,
|
|
236
231
|
minScoreThreshold: 0.9,
|
|
237
232
|
});
|
|
@@ -34,7 +34,7 @@ describe('createSemanticFacades', () => {
|
|
|
34
34
|
return op;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
it('should return ops from all semantic facades
|
|
37
|
+
it('should return ops from all semantic facades', () => {
|
|
38
38
|
// Op count varies as new ops are added. Just verify a reasonable minimum.
|
|
39
39
|
expect(ops.length).toBeGreaterThan(250);
|
|
40
40
|
});
|
|
@@ -104,8 +104,6 @@ describe('createSemanticFacades', () => {
|
|
|
104
104
|
expect(names).toContain('route_intent');
|
|
105
105
|
expect(names).toContain('morph');
|
|
106
106
|
expect(names).toContain('get_behavior_rules');
|
|
107
|
-
// Cognee — only present when cognee is enabled in runtime
|
|
108
|
-
// (this test creates runtime without cognee: true)
|
|
109
107
|
// Context Engine (#172)
|
|
110
108
|
expect(names).toContain('context_extract_entities');
|
|
111
109
|
expect(names).toContain('context_retrieve_knowledge');
|
|
@@ -321,7 +319,6 @@ describe('createSemanticFacades', () => {
|
|
|
321
319
|
// Prompt templates
|
|
322
320
|
expect(names).toContain('render_prompt');
|
|
323
321
|
expect(names).toContain('list_templates');
|
|
324
|
-
// Cognee Sync ops — only present when cognee is enabled
|
|
325
322
|
// Intake ops
|
|
326
323
|
expect(names).toContain('intake_ingest_book');
|
|
327
324
|
expect(names).toContain('intake_process');
|
|
@@ -509,10 +506,6 @@ describe('createSemanticFacades', () => {
|
|
|
509
506
|
expect(result.totalEntries).toBe(1);
|
|
510
507
|
});
|
|
511
508
|
|
|
512
|
-
// Cognee ops are only registered when runtime has cognee enabled.
|
|
513
|
-
// This test creates runtime without cognee: true, so these ops are not present.
|
|
514
|
-
// See e2e/full-pipeline.test.ts for cognee facade tests with cognee enabled.
|
|
515
|
-
|
|
516
509
|
it('llm_rotate should return rotation status', async () => {
|
|
517
510
|
const result = (await findOp('llm_rotate').handler({ provider: 'openai' })) as {
|
|
518
511
|
rotated?: boolean;
|
|
@@ -353,11 +353,9 @@ describe('createCuratorExtraOps', () => {
|
|
|
353
353
|
setup();
|
|
354
354
|
const result = (await findOp('curator_hybrid_contradictions').handler({})) as {
|
|
355
355
|
contradictions: unknown[];
|
|
356
|
-
cogneeAvailable: boolean;
|
|
357
356
|
method: string;
|
|
358
357
|
};
|
|
359
358
|
expect(result.contradictions).toEqual([]);
|
|
360
|
-
expect(result.cogneeAvailable).toBe(false);
|
|
361
359
|
expect(result.method).toBe('tfidf-only');
|
|
362
360
|
});
|
|
363
361
|
|
|
@@ -130,13 +130,6 @@ beforeAll(() => {
|
|
|
130
130
|
const result = curator.consolidate({ dryRun: false, staleDaysThreshold: 90 });
|
|
131
131
|
return { archived: result.staleEntries.length, result };
|
|
132
132
|
});
|
|
133
|
-
runner.registerHandler('cognee-ingest', async (job) => {
|
|
134
|
-
// No Cognee in tests — graceful degradation
|
|
135
|
-
return { skipped: true, reason: 'cognee not available' };
|
|
136
|
-
});
|
|
137
|
-
runner.registerHandler('cognee-cognify', async () => {
|
|
138
|
-
return { skipped: true, reason: 'cognee not available' };
|
|
139
|
-
});
|
|
140
133
|
runner.registerHandler('verify-searchable', async (job) => {
|
|
141
134
|
const entry = vault.get(job.entryId ?? '');
|
|
142
135
|
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
@@ -371,22 +364,6 @@ describe('Pipeline Runner — Salvador parity handlers (#216)', () => {
|
|
|
371
364
|
expect(typeof result.archived).toBe('number');
|
|
372
365
|
});
|
|
373
366
|
|
|
374
|
-
it('cognee-ingest degrades gracefully without Cognee', async () => {
|
|
375
|
-
const id = queue.enqueue('cognee-ingest', { entryId: 'pattern-circuit-breaker' });
|
|
376
|
-
await runner.processOnce();
|
|
377
|
-
const job = queue.get(id);
|
|
378
|
-
expect(job!.status).toBe('completed');
|
|
379
|
-
expect((job!.result as Record<string, unknown>).skipped).toBe(true);
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
it('cognee-cognify degrades gracefully without Cognee', async () => {
|
|
383
|
-
const id = queue.enqueue('cognee-cognify', {});
|
|
384
|
-
await runner.processOnce();
|
|
385
|
-
const job = queue.get(id);
|
|
386
|
-
expect(job!.status).toBe('completed');
|
|
387
|
-
expect((job!.result as Record<string, unknown>).skipped).toBe(true);
|
|
388
|
-
});
|
|
389
|
-
|
|
390
367
|
it('verify-searchable confirms entry is FTS-indexed', async () => {
|
|
391
368
|
const id = queue.enqueue('verify-searchable', { entryId: 'pattern-circuit-breaker' });
|
|
392
369
|
await runner.processOnce();
|
|
@@ -414,7 +391,7 @@ describe('Pipeline Runner — Salvador parity handlers (#216)', () => {
|
|
|
414
391
|
});
|
|
415
392
|
});
|
|
416
393
|
|
|
417
|
-
describe('Full Salvador DAG —
|
|
394
|
+
describe('Full Salvador DAG — 7-step curator pipeline', () => {
|
|
418
395
|
it('runs the complete quality pipeline in DAG order', async () => {
|
|
419
396
|
const entryId = 'pattern-semantic-tokens';
|
|
420
397
|
const pipelineId = 'full-salvador-dag';
|
|
@@ -428,9 +405,8 @@ describe('Full Salvador DAG — 8-step curator pipeline', () => {
|
|
|
428
405
|
pipelineId,
|
|
429
406
|
dependsOn: [step4],
|
|
430
407
|
});
|
|
431
|
-
const step6 = queue.enqueue('
|
|
432
|
-
const step7 = queue.enqueue('
|
|
433
|
-
const step8 = queue.enqueue('verify-searchable', { entryId, pipelineId, dependsOn: [step7] });
|
|
408
|
+
const step6 = queue.enqueue('auto-link', { entryId, pipelineId, dependsOn: [step5] });
|
|
409
|
+
const step7 = queue.enqueue('verify-searchable', { entryId, pipelineId, dependsOn: [step6] });
|
|
434
410
|
|
|
435
411
|
// Drain the DAG
|
|
436
412
|
for (let i = 0; i < 15; i++) {
|
|
@@ -446,7 +422,6 @@ describe('Full Salvador DAG — 8-step curator pipeline', () => {
|
|
|
446
422
|
'tag-normalize:completed',
|
|
447
423
|
'dedup-check:completed',
|
|
448
424
|
'detect-contradiction:completed',
|
|
449
|
-
'cognee-ingest:completed',
|
|
450
425
|
'auto-link:completed',
|
|
451
426
|
'verify-searchable:completed',
|
|
452
427
|
]);
|
|
@@ -28,7 +28,6 @@ describe('FeatureFlags', () => {
|
|
|
28
28
|
expect(flags.isEnabled('search-feedback')).toBe(true);
|
|
29
29
|
expect(flags.isEnabled('telemetry')).toBe(true);
|
|
30
30
|
expect(flags.isEnabled('agency-mode')).toBe(false);
|
|
31
|
-
expect(flags.isEnabled('cognee-sync')).toBe(true);
|
|
32
31
|
});
|
|
33
32
|
|
|
34
33
|
it('returns false for unknown flags', () => {
|
|
@@ -21,16 +21,16 @@ describe('HealthRegistry', () => {
|
|
|
21
21
|
|
|
22
22
|
it('tracks status transitions', () => {
|
|
23
23
|
const reg = new HealthRegistry();
|
|
24
|
-
reg.register('
|
|
25
|
-
reg.update('
|
|
26
|
-
expect(reg.get('
|
|
27
|
-
expect(reg.get('
|
|
28
|
-
expect(reg.get('
|
|
29
|
-
|
|
30
|
-
reg.update('
|
|
31
|
-
expect(reg.get('
|
|
32
|
-
expect(reg.get('
|
|
33
|
-
expect(reg.get('
|
|
24
|
+
reg.register('external');
|
|
25
|
+
reg.update('external', 'degraded', 'timeout');
|
|
26
|
+
expect(reg.get('external')!.status).toBe('degraded');
|
|
27
|
+
expect(reg.get('external')!.failureCount).toBe(1);
|
|
28
|
+
expect(reg.get('external')!.lastError).toBe('timeout');
|
|
29
|
+
|
|
30
|
+
reg.update('external', 'healthy');
|
|
31
|
+
expect(reg.get('external')!.failureCount).toBe(0);
|
|
32
|
+
expect(reg.get('external')!.lastError).toBeNull();
|
|
33
|
+
expect(reg.get('external')!.lastHealthyAt).toBeGreaterThan(0);
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
it('auto-registers on update if not registered', () => {
|
|
@@ -84,22 +84,22 @@ describe('HealthRegistry', () => {
|
|
|
84
84
|
|
|
85
85
|
it('fires recovery hooks when transitioning to healthy', () => {
|
|
86
86
|
const reg = new HealthRegistry();
|
|
87
|
-
reg.register('
|
|
87
|
+
reg.register('external', 'down');
|
|
88
88
|
const hook = vi.fn();
|
|
89
|
-
reg.onRecovery('
|
|
89
|
+
reg.onRecovery('external', hook);
|
|
90
90
|
|
|
91
|
-
reg.update('
|
|
92
|
-
expect(hook).toHaveBeenCalledWith('
|
|
91
|
+
reg.update('external', 'healthy');
|
|
92
|
+
expect(hook).toHaveBeenCalledWith('external');
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
it('does not fire recovery hooks for non-recovery transitions', () => {
|
|
96
96
|
const reg = new HealthRegistry();
|
|
97
|
-
reg.register('
|
|
97
|
+
reg.register('external', 'healthy');
|
|
98
98
|
const hook = vi.fn();
|
|
99
|
-
reg.onRecovery('
|
|
99
|
+
reg.onRecovery('external', hook);
|
|
100
100
|
|
|
101
|
-
reg.update('
|
|
102
|
-
reg.update('
|
|
101
|
+
reg.update('external', 'degraded');
|
|
102
|
+
reg.update('external', 'down');
|
|
103
103
|
expect(hook).not.toHaveBeenCalled();
|
|
104
104
|
});
|
|
105
105
|
|
|
@@ -132,7 +132,7 @@ describe('fanOut', () => {
|
|
|
132
132
|
|
|
133
133
|
const brainLog: string[] = [];
|
|
134
134
|
const vaultLog: string[] = [];
|
|
135
|
-
const
|
|
135
|
+
const curatorLog: string[] = [];
|
|
136
136
|
|
|
137
137
|
await fanOut(source(), [
|
|
138
138
|
async (items) => {
|
|
@@ -142,14 +142,14 @@ describe('fanOut', () => {
|
|
|
142
142
|
for await (const item of items) vaultLog.push(`vault:${item}`);
|
|
143
143
|
},
|
|
144
144
|
async (items) => {
|
|
145
|
-
for await (const item of items)
|
|
145
|
+
for await (const item of items) curatorLog.push(`curator:${item}`);
|
|
146
146
|
},
|
|
147
147
|
]);
|
|
148
148
|
|
|
149
149
|
const expected = ['plan-result', 'session-data', 'extraction'];
|
|
150
150
|
expect(brainLog).toEqual(expected.map((e) => `brain:${e}`));
|
|
151
151
|
expect(vaultLog).toEqual(expected.map((e) => `vault:${e}`));
|
|
152
|
-
expect(
|
|
152
|
+
expect(curatorLog).toEqual(expected.map((e) => `curator:${e}`));
|
|
153
153
|
});
|
|
154
154
|
|
|
155
155
|
it('source executes only once with fanOut', async () => {
|
|
@@ -84,16 +84,10 @@ export const ENGINE_MODULE_MANIFEST: ModuleManifestEntry[] = [
|
|
|
84
84
|
description: 'Chat transport — session management, response chunking, authentication.',
|
|
85
85
|
keyOps: ['chat_send', 'chat_history', 'chat_session'],
|
|
86
86
|
},
|
|
87
|
-
{
|
|
88
|
-
suffix: 'cognee',
|
|
89
|
-
description: 'Knowledge graph — Cognee search, sync, export, graph stats.',
|
|
90
|
-
keyOps: ['cognee_search', 'cognee_add', 'cognee_cognify'],
|
|
91
|
-
conditional: true,
|
|
92
|
-
},
|
|
93
87
|
];
|
|
94
88
|
|
|
95
89
|
/** Core facade ops (always present, not in ENGINE_MODULES) */
|
|
96
90
|
export const CORE_KEY_OPS = ['health', 'identity', 'register', 'activate'];
|
|
97
91
|
|
|
98
92
|
/** Engine major version — used for compatibility checks against domain packs. */
|
|
99
|
-
export const ENGINE_MAJOR_VERSION =
|
|
93
|
+
export const ENGINE_MAJOR_VERSION = 9;
|