mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-06-13 18:31:16 +08:00
refactor(authority): complete v0.6-only sql/blob/jobs rollout
This commit is contained in:
@@ -432,8 +432,150 @@ async function testSyncUploadDownloadUsesAuthorityBlob() {
|
||||
assert.equal(db.snapshot.nodes[0].id, "sync-blob-node");
|
||||
}
|
||||
|
||||
async function testAuthorityBlobHttpBoundary() {
|
||||
const requests = [];
|
||||
const adapter = createAuthorityBlobAdapter(
|
||||
{ authorityBaseUrl: "https://authority.example.test/root" },
|
||||
{
|
||||
headerProvider: () => ({ "X-Test": "1" }),
|
||||
fetchImpl: async (url, options = {}) => {
|
||||
requests.push({ url, options });
|
||||
if (url.endsWith("/session/init")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return { sessionToken: "blob-session-token" };
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/fs/private/write-file")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
entry: {
|
||||
path: "user/files/demo.json",
|
||||
sizeBytes: 17,
|
||||
updatedAt: "2026-04-28T12:00:00.000Z",
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/fs/private/read-file")) {
|
||||
const body = JSON.parse(String(options.body || "{}"));
|
||||
if (body.path === "user/files/missing.json") {
|
||||
return {
|
||||
ok: false,
|
||||
status: 404,
|
||||
async json() {
|
||||
return { error: "not found" };
|
||||
},
|
||||
async text() {
|
||||
return "not found";
|
||||
},
|
||||
headers: { get: () => "application/json" },
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
entry: {
|
||||
path: "user/files/demo.json",
|
||||
sizeBytes: 17,
|
||||
updatedAt: "2026-04-28T12:00:00.000Z",
|
||||
},
|
||||
content: JSON.stringify({ hello: "world" }),
|
||||
encoding: "utf8",
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/fs/private/stat")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
entry: {
|
||||
path: "user/files/demo.json",
|
||||
sizeBytes: 17,
|
||||
updatedAt: "2026-04-28T12:00:00.000Z",
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/fs/private/delete")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return { ok: true };
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
status: 404,
|
||||
async json() {
|
||||
return {};
|
||||
},
|
||||
async text() {
|
||||
return "not found";
|
||||
},
|
||||
headers: { get: () => "application/json" },
|
||||
};
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const writeResult = await adapter.writeJson("user/files/demo.json", { hello: "world" });
|
||||
assert.equal(writeResult.ok, true);
|
||||
assert.equal(writeResult.path, "user/files/demo.json");
|
||||
|
||||
const readResult = await adapter.readJson("user/files/demo.json");
|
||||
assert.equal(readResult.exists, true);
|
||||
assert.deepEqual(readResult.payload, { hello: "world" });
|
||||
|
||||
const statResult = await adapter.stat("user/files/demo.json");
|
||||
assert.equal(statResult.exists, true);
|
||||
assert.equal(statResult.path, "user/files/demo.json");
|
||||
|
||||
const missingResult = await adapter.readJson("user/files/missing.json");
|
||||
assert.equal(missingResult.exists, false);
|
||||
|
||||
const deleteResult = await adapter.delete("user/files/demo.json");
|
||||
assert.equal(deleteResult.ok, true);
|
||||
|
||||
assert.deepEqual(
|
||||
requests.map((request) => request.url),
|
||||
[
|
||||
"https://authority.example.test/root/session/init",
|
||||
"https://authority.example.test/root/fs/private/write-file",
|
||||
"https://authority.example.test/root/fs/private/read-file",
|
||||
"https://authority.example.test/root/fs/private/stat",
|
||||
"https://authority.example.test/root/fs/private/read-file",
|
||||
"https://authority.example.test/root/fs/private/delete",
|
||||
],
|
||||
);
|
||||
assert.equal(requests[1].options.headers["x-authority-session-token"], "blob-session-token");
|
||||
assert.equal(requests[1].options.headers["X-Test"], "1");
|
||||
assert.deepEqual(JSON.parse(String(requests[1].options.body || "{}")), {
|
||||
path: "user/files/demo.json",
|
||||
content: JSON.stringify({ hello: "world" }),
|
||||
encoding: "utf8",
|
||||
createParents: true,
|
||||
});
|
||||
}
|
||||
|
||||
await testAdapterBasics();
|
||||
await testAuthorityBlobFailOpenFallsBackToUserFiles();
|
||||
await testBackupRestoreUsesAuthorityBlob();
|
||||
await testSyncUploadDownloadUsesAuthorityBlob();
|
||||
await testAuthorityBlobHttpBoundary();
|
||||
console.log("authority-blob tests passed");
|
||||
|
||||
@@ -18,31 +18,29 @@ assert.equal(normalizedSettings.vectorMode, "auto-primary");
|
||||
assert.equal(normalizedSettings.primaryWhenAvailable, true);
|
||||
|
||||
assert.deepEqual(buildAuthorityProbeUrls("/api/plugins/authority/"), [
|
||||
"/api/plugins/authority/v1/diagnostics/probe",
|
||||
"/api/plugins/authority/v1/probe",
|
||||
"/api/plugins/authority/probe",
|
||||
"/api/plugins/authority",
|
||||
]);
|
||||
|
||||
const collected = collectAuthorityFeatures({
|
||||
features: ["sql.query", "trivium.search"],
|
||||
services: {
|
||||
sql: true,
|
||||
jobs: true,
|
||||
blob: true,
|
||||
features: {
|
||||
sql: { queryPage: true },
|
||||
trivium: { upsert: true },
|
||||
jobs: { background: true },
|
||||
transfers: { fs: true },
|
||||
},
|
||||
});
|
||||
assert.equal(collected.has("sql.query"), true);
|
||||
assert.equal(collected.has("trivium.search"), true);
|
||||
assert.equal(collected.has("sql"), true);
|
||||
assert.equal(collected.has("jobs"), true);
|
||||
assert.equal(collected.has("blob"), true);
|
||||
assert.equal(collected.has("sql.querypage"), true);
|
||||
assert.equal(collected.has("sql"), true);
|
||||
assert.equal(collected.has("trivium"), true);
|
||||
assert.equal(collected.has("jobs.background"), true);
|
||||
assert.equal(collected.has("transfers.fs"), true);
|
||||
|
||||
const readyState = normalizeAuthorityCapabilityState(
|
||||
{
|
||||
installed: true,
|
||||
healthy: true,
|
||||
features: ["sql", "trivium", "jobs", "blob"],
|
||||
features: ["sql", "trivium", "jobs", "transfers.fs"],
|
||||
},
|
||||
defaultSettings,
|
||||
);
|
||||
@@ -77,28 +75,91 @@ assert.equal(disabledState.reason, "disabled");
|
||||
assert.equal(disabledState.serverPrimaryReady, false);
|
||||
assert.equal(disabledState.lastProbeAt, 1000);
|
||||
|
||||
let requestedUrl = "";
|
||||
const requestedUrls = [];
|
||||
const probedState = await probeAuthorityCapabilities({
|
||||
settings: defaultSettings,
|
||||
allowRelativeUrl: true,
|
||||
nowMs: 2000,
|
||||
fetchImpl: async (url) => {
|
||||
requestedUrl = url;
|
||||
fetchImpl: async (url, options = {}) => {
|
||||
requestedUrls.push([url, options.method || "GET", options.headers || {}]);
|
||||
if (url.endsWith("/probe")) {
|
||||
assert.equal(options.method, "POST");
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
healthy: true,
|
||||
features: {
|
||||
sql: { queryPage: true },
|
||||
trivium: { upsert: true },
|
||||
jobs: { background: true },
|
||||
transfers: { fs: true },
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/session/init")) {
|
||||
assert.equal(options.method, "POST");
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return { sessionToken: "session-probe-token" };
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/session/current")) {
|
||||
assert.equal(options.method, "GET");
|
||||
assert.equal(options.headers["x-authority-session-token"], "session-probe-token");
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return { ok: true };
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/permissions/evaluate-batch")) {
|
||||
assert.equal(options.method, "POST");
|
||||
assert.equal(options.headers["x-authority-session-token"], "session-probe-token");
|
||||
const body = JSON.parse(String(options.body || "{}"));
|
||||
assert.equal(Array.isArray(body.requests), true);
|
||||
assert.equal(body.requests.some((request) => request.resource === "fs.private"), true);
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
results: body.requests.map((request) => ({
|
||||
decision: "granted",
|
||||
resource: request.resource,
|
||||
target: request.target || "",
|
||||
})),
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
ok: false,
|
||||
status: 404,
|
||||
async json() {
|
||||
return {
|
||||
healthy: true,
|
||||
sessionReady: true,
|
||||
permissionReady: true,
|
||||
features: ["sql", "trivium", "jobs", "blob"],
|
||||
};
|
||||
return {};
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
assert.equal(requestedUrl, "/api/plugins/authority/v1/diagnostics/probe");
|
||||
assert.equal(requestedUrls[0]?.[0], "/api/plugins/authority/probe");
|
||||
assert.deepEqual(
|
||||
requestedUrls.map(([url]) => url),
|
||||
[
|
||||
"/api/plugins/authority/probe",
|
||||
"/api/plugins/authority/session/init",
|
||||
"/api/plugins/authority/session/current",
|
||||
"/api/plugins/authority/permissions/evaluate-batch",
|
||||
],
|
||||
);
|
||||
assert.equal(probedState.installed, true);
|
||||
assert.equal(probedState.healthy, true);
|
||||
assert.equal(probedState.serverPrimaryReady, true);
|
||||
|
||||
@@ -301,6 +301,15 @@ async function testHttpSqlClientBoundary() {
|
||||
headerProvider: () => ({ "X-Test": "1" }),
|
||||
fetchImpl: async (url, init) => {
|
||||
requests.push({ url, init });
|
||||
if (url.endsWith("/session/init")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return { sessionToken: "sql-session-token" };
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
@@ -313,12 +322,19 @@ async function testHttpSqlClientBoundary() {
|
||||
|
||||
const result = await client.query("SELECT 1", { chatId: "chat" });
|
||||
assert.deepEqual(result, { rows: [{ value: 1 }] });
|
||||
assert.equal(requests[0].url, "https://authority.example.test/root/v1/sql");
|
||||
assert.equal(requests[0].init.method, "POST");
|
||||
assert.equal(requests[0].init.headers["X-Test"], "1");
|
||||
assert.deepEqual(JSON.parse(requests[0].init.body), {
|
||||
action: "query",
|
||||
sql: "SELECT 1",
|
||||
assert.deepEqual(
|
||||
requests.map((request) => request.url),
|
||||
[
|
||||
"https://authority.example.test/root/session/init",
|
||||
"https://authority.example.test/root/sql/query",
|
||||
],
|
||||
);
|
||||
assert.equal(requests[1].init.method, "POST");
|
||||
assert.equal(requests[1].init.headers["X-Test"], "1");
|
||||
assert.equal(requests[1].init.headers["x-authority-session-token"], "sql-session-token");
|
||||
assert.deepEqual(JSON.parse(requests[1].init.body), {
|
||||
database: "default",
|
||||
statement: "SELECT 1",
|
||||
params: { chatId: "chat" },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -455,4 +455,150 @@ const rangeSync = rangeRuntime.calls.find(([name]) => name === "syncVectorState"
|
||||
assert.equal(rangeSync?.[1]?.purge, false);
|
||||
assert.equal(rangeSync?.[1]?.range, range);
|
||||
|
||||
const httpRequests = [];
|
||||
const httpAdapter = createAuthorityJobAdapter(
|
||||
{ authorityBaseUrl: "https://authority.example.test/root" },
|
||||
{
|
||||
headerProvider: () => ({ "X-Test": "1" }),
|
||||
fetchImpl: async (url, options = {}) => {
|
||||
httpRequests.push({ url, options });
|
||||
if (url.endsWith("/session/init")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return { sessionToken: "job-session-token" };
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/jobs/create")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
id: "job-http-1",
|
||||
type: "authority.vector.rebuild",
|
||||
status: "queued",
|
||||
progress: 0,
|
||||
idempotencyKey: "idem-http-1",
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/jobs/job-http-1")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
id: "job-http-1",
|
||||
type: "authority.vector.rebuild",
|
||||
status: "completed",
|
||||
progress: 1,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/jobs/list")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
jobs: [
|
||||
{
|
||||
id: "job-http-1",
|
||||
type: "authority.vector.rebuild",
|
||||
status: "completed",
|
||||
progress: 1,
|
||||
},
|
||||
],
|
||||
page: {
|
||||
nextCursor: "next-http-1",
|
||||
hasMore: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/jobs/job-http-1/requeue")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
id: "job-http-2",
|
||||
type: "authority.vector.rebuild",
|
||||
status: "queued",
|
||||
progress: 0,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
if (url.endsWith("/jobs/job-http-1/cancel")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return {
|
||||
id: "job-http-1",
|
||||
type: "authority.vector.rebuild",
|
||||
status: "cancelled",
|
||||
progress: 1,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
status: 404,
|
||||
async json() {
|
||||
return {};
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const httpSubmitted = await httpAdapter.submit(
|
||||
"authority.vector.rebuild",
|
||||
{ chatId: "chat-http" },
|
||||
{ idempotencyKey: "idem-http-1" },
|
||||
);
|
||||
assert.equal(httpSubmitted.id, "job-http-1");
|
||||
const httpLoaded = await httpAdapter.get("job-http-1");
|
||||
assert.equal(httpLoaded.status, "completed");
|
||||
const httpPage = await httpAdapter.listPage({ cursor: "cursor-http", limit: 10 });
|
||||
assert.equal(httpPage.nextCursor, "next-http-1");
|
||||
assert.equal(httpPage.hasMore, true);
|
||||
const httpRequeued = await httpAdapter.requeue("job-http-1");
|
||||
assert.equal(httpRequeued.id, "job-http-2");
|
||||
const httpCancelled = await httpAdapter.cancel("job-http-1");
|
||||
assert.equal(httpCancelled.status, "cancelled");
|
||||
assert.deepEqual(
|
||||
httpRequests.map((request) => request.url),
|
||||
[
|
||||
"https://authority.example.test/root/session/init",
|
||||
"https://authority.example.test/root/jobs/create",
|
||||
"https://authority.example.test/root/jobs/job-http-1",
|
||||
"https://authority.example.test/root/jobs/list",
|
||||
"https://authority.example.test/root/jobs/job-http-1/requeue",
|
||||
"https://authority.example.test/root/jobs/job-http-1/cancel",
|
||||
],
|
||||
);
|
||||
assert.equal(httpRequests[1].options.headers["x-authority-session-token"], "job-session-token");
|
||||
assert.equal(httpRequests[1].options.headers["X-Test"], "1");
|
||||
assert.deepEqual(JSON.parse(String(httpRequests[1].options.body || "{}")), {
|
||||
type: "authority.vector.rebuild",
|
||||
payload: { chatId: "chat-http" },
|
||||
idempotencyKey: "idem-http-1",
|
||||
});
|
||||
assert.deepEqual(JSON.parse(String(httpRequests[3].options.body || "{}")), {
|
||||
page: {
|
||||
cursor: "cursor-http",
|
||||
limit: 10,
|
||||
},
|
||||
});
|
||||
|
||||
console.log("authority-jobs tests passed");
|
||||
|
||||
@@ -16,6 +16,15 @@ installResolveHooks([
|
||||
},
|
||||
]);
|
||||
|
||||
globalThis.__stBmeTestOverrides = {
|
||||
embedding: {
|
||||
async embedText(text) {
|
||||
const seed = String(text || "").length || 1;
|
||||
return [seed / 100, 0.2, 0.3];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { normalizeAuthorityVectorConfig } = await import(
|
||||
"../vector/authority-vector-primary-adapter.js"
|
||||
);
|
||||
@@ -153,6 +162,8 @@ function createMockTriviumClient({ failFilter = false, failSearch = false, failN
|
||||
const config = normalizeAuthorityVectorConfig(
|
||||
{
|
||||
authorityBaseUrl: "/api/plugins/authority",
|
||||
authorityEmbeddingApiUrl: "https://example.com/v1",
|
||||
authorityEmbeddingModel: "test-embedding",
|
||||
authorityVectorFailOpen: true,
|
||||
},
|
||||
{ triviumClient },
|
||||
@@ -216,6 +227,8 @@ function createMockTriviumClient({ failFilter = false, failSearch = false, failN
|
||||
const config = normalizeAuthorityVectorConfig(
|
||||
{
|
||||
authorityBaseUrl: "/api/plugins/authority",
|
||||
authorityEmbeddingApiUrl: "https://example.com/v1",
|
||||
authorityEmbeddingModel: "test-embedding",
|
||||
authorityVectorFailOpen: true,
|
||||
},
|
||||
{ triviumClient },
|
||||
|
||||
@@ -16,6 +16,17 @@ installResolveHooks([
|
||||
},
|
||||
]);
|
||||
|
||||
globalThis.__stBmeTestOverrides = {
|
||||
embedding: {
|
||||
async embedBatch(texts = []) {
|
||||
return texts.map((text, index) => [1, index / 10, String(text || "").length / 100]);
|
||||
},
|
||||
async embedText(text = "") {
|
||||
return [1, 0.5, String(text || "").length / 100];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const {
|
||||
filterAuthorityTriviumNodes,
|
||||
isAuthorityVectorConfig,
|
||||
@@ -112,8 +123,20 @@ function createMockTriviumClient({ failBulkUpsert = false } = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
async function withMockFetch(handler, fn) {
|
||||
const previousFetch = globalThis.fetch;
|
||||
globalThis.fetch = handler;
|
||||
try {
|
||||
return await fn();
|
||||
} finally {
|
||||
globalThis.fetch = previousFetch;
|
||||
}
|
||||
}
|
||||
|
||||
const config = normalizeAuthorityVectorConfig({
|
||||
authorityBaseUrl: "/api/plugins/authority",
|
||||
authorityEmbeddingApiUrl: "https://example.com/v1",
|
||||
authorityEmbeddingModel: "test-embedding",
|
||||
authorityVectorSyncChunkSize: 1,
|
||||
authorityVectorFailOpen: true,
|
||||
});
|
||||
@@ -144,6 +167,10 @@ assert.equal(isAuthorityVectorConfig(config), true);
|
||||
upserts.flatMap(([, payload]) => payload.items.map((item) => item.nodeId)).sort(),
|
||||
["node-a", "node-b"],
|
||||
);
|
||||
assert.equal(
|
||||
upserts.every(([, payload]) => payload.items.every((item) => Array.isArray(item.vector) && item.vector.length > 0)),
|
||||
true,
|
||||
);
|
||||
const linkCall = triviumClient.calls.find(([name]) => name === "linkMany");
|
||||
assert.equal(linkCall?.[1]?.links?.[0]?.fromId, "node-a");
|
||||
assert.equal(linkCall?.[1]?.links?.[0]?.toId, "node-b");
|
||||
@@ -170,6 +197,8 @@ assert.equal(isAuthorityVectorConfig(config), true);
|
||||
assert.deepEqual(results, [{ nodeId: "node-b", score: 0.91 }]);
|
||||
const searchCall = triviumClient.calls.find(([name]) => name === "search");
|
||||
assert.deepEqual(searchCall?.[1]?.candidateIds.sort(), ["node-a", "node-b"]);
|
||||
assert.equal(Array.isArray(searchCall?.[1]?.queryVector), true);
|
||||
assert.ok(searchCall?.[1]?.queryVector.length > 0);
|
||||
assert.equal(graph.vectorIndexState.lastSearchTimings.mode, "authority");
|
||||
assert.equal(graph.vectorIndexState.lastSearchTimings.success, true);
|
||||
}
|
||||
@@ -221,4 +250,72 @@ assert.equal(isAuthorityVectorConfig(config), true);
|
||||
assert.deepEqual(neighborCall?.[1]?.nodeIds, ["node-a"]);
|
||||
}
|
||||
|
||||
{
|
||||
const previousOverrides = globalThis.__stBmeTestOverrides;
|
||||
globalThis.__stBmeTestOverrides = {};
|
||||
const fetchCalls = [];
|
||||
try {
|
||||
await withMockFetch(async (url, options = {}) => {
|
||||
fetchCalls.push([url, JSON.parse(String(options.body || "{}"))]);
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
const body = JSON.parse(String(options.body || "{}"));
|
||||
if (Array.isArray(body.texts)) {
|
||||
return {
|
||||
vectors: body.texts.map((text, index) => [1, index + 1, String(text || "").length / 100]),
|
||||
};
|
||||
}
|
||||
return {
|
||||
vector: [1, 9, String(body.text || "").length / 100],
|
||||
};
|
||||
},
|
||||
async text() {
|
||||
return "";
|
||||
},
|
||||
};
|
||||
}, async () => {
|
||||
const backendConfig = normalizeAuthorityVectorConfig({
|
||||
authorityBaseUrl: "/api/plugins/authority",
|
||||
embeddingTransportMode: "backend",
|
||||
embeddingBackendSource: "openai",
|
||||
embeddingBackendModel: "text-embedding-3-small",
|
||||
authorityVectorSyncChunkSize: 2,
|
||||
});
|
||||
const { graph, first, second } = createAuthorityVectorGraph();
|
||||
first.embedding = null;
|
||||
second.embedding = null;
|
||||
const triviumClient = createMockTriviumClient();
|
||||
await syncGraphVectorIndexFromIndex(graph, backendConfig, {
|
||||
chatId: "chat-authority-vector",
|
||||
purge: true,
|
||||
triviumClient,
|
||||
});
|
||||
const results = await findSimilarNodesByTextFromIndex(
|
||||
graph,
|
||||
"archive door",
|
||||
{ ...backendConfig, triviumClient },
|
||||
5,
|
||||
[first, second],
|
||||
);
|
||||
assert.deepEqual(results, [{ nodeId: "node-b", score: 0.91 }]);
|
||||
const upsertCall = triviumClient.calls.find(([name]) => name === "bulkUpsert");
|
||||
assert.equal(
|
||||
upsertCall?.[1]?.items?.every((item) => Array.isArray(item.vector) && item.vector.length > 0),
|
||||
true,
|
||||
);
|
||||
const searchCall = triviumClient.calls.find(([name]) => name === "search");
|
||||
assert.equal(Array.isArray(searchCall?.[1]?.queryVector), true);
|
||||
assert.equal(fetchCalls.every(([url]) => url === "/api/vector/embed"), true);
|
||||
assert.equal(fetchCalls[0]?.[1]?.source, "openai");
|
||||
assert.equal(fetchCalls[0]?.[1]?.model, "text-embedding-3-small");
|
||||
assert.equal(Array.isArray(fetchCalls[0]?.[1]?.texts), true);
|
||||
assert.equal(fetchCalls[fetchCalls.length - 1]?.[1]?.isQuery, true);
|
||||
});
|
||||
} finally {
|
||||
globalThis.__stBmeTestOverrides = previousOverrides;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("authority-vector-primary tests passed");
|
||||
|
||||
@@ -1,19 +1,36 @@
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { buildLukerGraphCheckpointV2 } from "../../graph/graph-persistence.js";
|
||||
import {
|
||||
applyAuthorityCheckpointToStore,
|
||||
buildAuthorityConsistencyAudit,
|
||||
buildAuthorityCheckpointImportSnapshot,
|
||||
} from "../../maintenance/authority-consistency.js";
|
||||
import { createAuthorityBlobAdapter } from "../../maintenance/authority-blob-adapter.js";
|
||||
import { AuthorityGraphStore } from "../../sync/authority-graph-store.js";
|
||||
installResolveHooks,
|
||||
toDataModuleUrl,
|
||||
} from "../helpers/register-hooks-compat.mjs";
|
||||
|
||||
installResolveHooks([
|
||||
{
|
||||
specifiers: ["../../../../../script.js"],
|
||||
url: toDataModuleUrl("export function getRequestHeaders() { return {}; }"),
|
||||
},
|
||||
{
|
||||
specifiers: ["../../../../extensions.js"],
|
||||
url: toDataModuleUrl("export const extension_settings = { st_bme: {} };"),
|
||||
},
|
||||
]);
|
||||
|
||||
import {
|
||||
createAuthorityE2eContext,
|
||||
createAuthorityE2eContractGraph,
|
||||
runAuthorityE2eStep,
|
||||
} from "../helpers/authority-e2e-context.mjs";
|
||||
|
||||
const { buildLukerGraphCheckpointV2 } = await import("../../graph/graph-persistence.js");
|
||||
const {
|
||||
applyAuthorityCheckpointToStore,
|
||||
buildAuthorityConsistencyAudit,
|
||||
buildAuthorityCheckpointImportSnapshot,
|
||||
} = await import("../../maintenance/authority-consistency.js");
|
||||
const { createAuthorityBlobAdapter } = await import("../../maintenance/authority-blob-adapter.js");
|
||||
const { AuthorityGraphStore } = await import("../../sync/authority-graph-store.js");
|
||||
|
||||
const context = createAuthorityE2eContext({
|
||||
skipMessage:
|
||||
"authority checkpoint restore E2E skipped: set AUTHORITY_E2E_BASE_URL to run against a real Authority server",
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
buildAuthorityDiagnosticsBundle,
|
||||
buildAuthorityPerformanceBaseline,
|
||||
writeAuthorityDiagnosticsBundle,
|
||||
} from "../../maintenance/authority-diagnostics-bundle.js";
|
||||
import { createAuthorityBlobAdapter } from "../../maintenance/authority-blob-adapter.js";
|
||||
installResolveHooks,
|
||||
toDataModuleUrl,
|
||||
} from "../helpers/register-hooks-compat.mjs";
|
||||
|
||||
installResolveHooks([
|
||||
{
|
||||
specifiers: ["../../../../../script.js"],
|
||||
url: toDataModuleUrl("export function getRequestHeaders() { return {}; }"),
|
||||
},
|
||||
{
|
||||
specifiers: ["../../../../extensions.js"],
|
||||
url: toDataModuleUrl("export const extension_settings = { st_bme: {} };"),
|
||||
},
|
||||
]);
|
||||
|
||||
import {
|
||||
createAuthorityE2eContext,
|
||||
createAuthorityE2eContractGraph,
|
||||
runAuthorityE2eStep,
|
||||
} from "../helpers/authority-e2e-context.mjs";
|
||||
|
||||
const {
|
||||
buildAuthorityDiagnosticsBundle,
|
||||
buildAuthorityPerformanceBaseline,
|
||||
writeAuthorityDiagnosticsBundle,
|
||||
} = await import("../../maintenance/authority-diagnostics-bundle.js");
|
||||
const { createAuthorityBlobAdapter } = await import("../../maintenance/authority-blob-adapter.js");
|
||||
|
||||
const context = createAuthorityE2eContext({
|
||||
skipMessage:
|
||||
"authority diagnostics E2E skipped: set AUTHORITY_E2E_BASE_URL to run against a real Authority server",
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { probeAuthorityCapabilities } from "../../runtime/authority-capabilities.js";
|
||||
import { AuthorityGraphStore } from "../../sync/authority-graph-store.js";
|
||||
import {
|
||||
installResolveHooks,
|
||||
toDataModuleUrl,
|
||||
} from "../helpers/register-hooks-compat.mjs";
|
||||
|
||||
installResolveHooks([
|
||||
{
|
||||
specifiers: ["../../../../../script.js"],
|
||||
url: toDataModuleUrl("export function getRequestHeaders() { return {}; }"),
|
||||
},
|
||||
{
|
||||
specifiers: ["../../../../extensions.js"],
|
||||
url: toDataModuleUrl("export const extension_settings = { st_bme: {} };"),
|
||||
},
|
||||
]);
|
||||
|
||||
import {
|
||||
buildAuthorityE2eVectorEntries,
|
||||
createAuthorityE2eContext,
|
||||
createAuthorityE2eContractGraph,
|
||||
createAuthorityE2eContractNode,
|
||||
runAuthorityE2eStep,
|
||||
} from "../helpers/authority-e2e-context.mjs";
|
||||
|
||||
const { probeAuthorityCapabilities } = await import("../../runtime/authority-capabilities.js");
|
||||
const { AuthorityGraphStore } = await import("../../sync/authority-graph-store.js");
|
||||
const {
|
||||
deleteAuthorityTriviumNodes,
|
||||
filterAuthorityTriviumNodes,
|
||||
normalizeAuthorityVectorConfig,
|
||||
@@ -11,19 +35,12 @@ import {
|
||||
searchAuthorityTriviumNodes,
|
||||
syncAuthorityTriviumLinks,
|
||||
upsertAuthorityTriviumEntries,
|
||||
} from "../../vector/authority-vector-primary-adapter.js";
|
||||
import {
|
||||
} = await import("../../vector/authority-vector-primary-adapter.js");
|
||||
const {
|
||||
buildAuthorityJobIdempotencyKey,
|
||||
createAuthorityJobAdapter,
|
||||
} from "../../maintenance/authority-job-adapter.js";
|
||||
import { createAuthorityBlobAdapter } from "../../maintenance/authority-blob-adapter.js";
|
||||
import {
|
||||
buildAuthorityE2eVectorEntries,
|
||||
createAuthorityE2eContext,
|
||||
createAuthorityE2eContractGraph,
|
||||
createAuthorityE2eContractNode,
|
||||
runAuthorityE2eStep,
|
||||
} from "../helpers/authority-e2e-context.mjs";
|
||||
} = await import("../../maintenance/authority-job-adapter.js");
|
||||
const { createAuthorityBlobAdapter } = await import("../../maintenance/authority-blob-adapter.js");
|
||||
|
||||
const context = createAuthorityE2eContext({
|
||||
skipMessage:
|
||||
@@ -35,7 +52,7 @@ if (context.skip) {
|
||||
process.exit(0);
|
||||
}
|
||||
const resolvedBaseUrl = context.baseUrl;
|
||||
const { chatId, namespace, collectionId, blobPath, fetchImpl, headerProvider, runId } = context;
|
||||
const { chatId, namespace, collectionId, blobPath, fetchImpl, headerProvider, runId, embeddingApiUrl, embeddingApiKey, embeddingModel } = context;
|
||||
const graph = createAuthorityE2eContractGraph(chatId, runId);
|
||||
|
||||
const runContext = {
|
||||
@@ -105,7 +122,12 @@ await runAuthorityE2eStep("sql", async () => {
|
||||
});
|
||||
|
||||
await runAuthorityE2eStep("trivium", async () => {
|
||||
const config = normalizeAuthorityVectorConfig({ authorityBaseUrl: resolvedBaseUrl });
|
||||
const config = normalizeAuthorityVectorConfig({
|
||||
authorityBaseUrl: resolvedBaseUrl,
|
||||
authorityEmbeddingApiUrl: embeddingApiUrl,
|
||||
authorityEmbeddingApiKey: embeddingApiKey,
|
||||
authorityEmbeddingModel: embeddingModel,
|
||||
});
|
||||
const entries = buildAuthorityE2eVectorEntries(graph);
|
||||
await purgeAuthorityTriviumNamespace(config, {
|
||||
namespace,
|
||||
@@ -141,6 +163,7 @@ await runAuthorityE2eStep("trivium", async () => {
|
||||
namespace,
|
||||
collectionId,
|
||||
chatId,
|
||||
queryVector: [1, 1, 0.18],
|
||||
topK: 5,
|
||||
fetchImpl,
|
||||
headerProvider,
|
||||
|
||||
@@ -97,6 +97,9 @@ export function createAuthorityE2eContext(options = {}) {
|
||||
const namespace = String(env.AUTHORITY_E2E_NAMESPACE || `st-bme-e2e-${runId}`);
|
||||
const collectionId = String(env.AUTHORITY_E2E_COLLECTION_ID || `${namespace}::${chatId}`);
|
||||
const blobPath = String(env.AUTHORITY_E2E_BLOB_PATH || `st-bme/e2e/${runId}/contract.json`);
|
||||
const embeddingApiUrl = String(env.AUTHORITY_E2E_EMBEDDING_API_URL || "").trim();
|
||||
const embeddingApiKey = String(env.AUTHORITY_E2E_EMBEDDING_API_KEY || "").trim();
|
||||
const embeddingModel = String(env.AUTHORITY_E2E_EMBEDDING_MODEL || "").trim();
|
||||
return {
|
||||
skip: false,
|
||||
env,
|
||||
@@ -110,6 +113,9 @@ export function createAuthorityE2eContext(options = {}) {
|
||||
namespace,
|
||||
collectionId,
|
||||
blobPath,
|
||||
embeddingApiUrl,
|
||||
embeddingApiKey,
|
||||
embeddingModel,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -181,6 +187,7 @@ export function buildAuthorityE2eVectorEntries(graph = null) {
|
||||
index,
|
||||
hash: `${node.id}:hash`,
|
||||
text: `${node.fields?.title || node.id}. ${node.fields?.summary || ""}`,
|
||||
vector: [1, index + 1, String(node.fields?.title || node.id || "").length / 100],
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,14 @@ installResolveHooks([
|
||||
},
|
||||
]);
|
||||
|
||||
globalThis.__stBmeTestOverrides = {
|
||||
embedding: {
|
||||
async embedText(text = "") {
|
||||
return [1, 0.25, String(text || "").length / 100];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const outputJson = process.argv.includes("--json");
|
||||
const RUNS = 5;
|
||||
const SIZE_PRESETS = [
|
||||
@@ -233,6 +241,8 @@ async function runPreset(preset) {
|
||||
const config = normalizeAuthorityVectorConfig(
|
||||
{
|
||||
authorityBaseUrl: "/api/plugins/authority",
|
||||
authorityEmbeddingApiUrl: "https://example.com/v1",
|
||||
authorityEmbeddingModel: "test-embedding",
|
||||
authorityVectorFailOpen: true,
|
||||
},
|
||||
{ triviumClient },
|
||||
|
||||
@@ -70,6 +70,54 @@ const defaultModeConfig = getVectorConfigFromSettings({
|
||||
assert.equal(defaultModeConfig.mode, "direct");
|
||||
assert.equal(validateVectorConfig(defaultModeConfig).valid, true);
|
||||
|
||||
const validAuthorityConfig = {
|
||||
mode: "authority",
|
||||
source: "authority-trivium",
|
||||
baseUrl: "/api/plugins/authority",
|
||||
apiUrl: "https://example.com/v1",
|
||||
model: "text-embedding-3-small",
|
||||
};
|
||||
assert.equal(validateVectorConfig(validAuthorityConfig).valid, true);
|
||||
|
||||
const invalidAuthorityConfig = {
|
||||
mode: "authority",
|
||||
source: "authority-trivium",
|
||||
baseUrl: "/api/plugins/authority",
|
||||
apiUrl: "",
|
||||
model: "",
|
||||
};
|
||||
assert.equal(validateVectorConfig(invalidAuthorityConfig).valid, false);
|
||||
|
||||
const validAuthorityBackendConfig = {
|
||||
mode: "authority",
|
||||
source: "authority-trivium",
|
||||
baseUrl: "/api/plugins/authority",
|
||||
embeddingMode: "backend",
|
||||
embeddingSource: "openai",
|
||||
apiUrl: "",
|
||||
model: "text-embedding-3-small",
|
||||
};
|
||||
assert.equal(validateVectorConfig(validAuthorityBackendConfig).valid, true);
|
||||
|
||||
const invalidAuthorityBackendConfig = {
|
||||
mode: "authority",
|
||||
source: "authority-trivium",
|
||||
baseUrl: "/api/plugins/authority",
|
||||
embeddingMode: "backend",
|
||||
embeddingSource: "vllm",
|
||||
apiUrl: "",
|
||||
model: "BAAI/bge-m3",
|
||||
};
|
||||
assert.equal(validateVectorConfig(invalidAuthorityBackendConfig).valid, false);
|
||||
|
||||
const authorityLikeConfig = getVectorConfigFromSettings({
|
||||
embeddingApiUrl: "https://example.com/v1/embeddings",
|
||||
embeddingApiKey: "sk-test",
|
||||
embeddingModel: "text-embedding-3-small",
|
||||
});
|
||||
assert.equal(authorityLikeConfig.apiUrl, "https://example.com/v1");
|
||||
assert.equal(authorityLikeConfig.model, "text-embedding-3-small");
|
||||
|
||||
const invalidBackendConfig = getVectorConfigFromSettings({
|
||||
embeddingTransportMode: "backend",
|
||||
embeddingBackendSource: "vllm",
|
||||
|
||||
Reference in New Issue
Block a user