mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-06-13 18:31:16 +08:00
fix(vector): scope authority search by namespace
This commit is contained in:
@@ -33,6 +33,7 @@ const {
|
||||
isAuthorityVectorConfig,
|
||||
normalizeAuthorityVectorConfig,
|
||||
queryAuthorityTriviumNeighbors,
|
||||
searchAuthorityTriviumNodes,
|
||||
applyAuthorityBmeVectorManifest,
|
||||
} = await import("../vector/authority-vector-primary-adapter.js");
|
||||
const {
|
||||
@@ -125,6 +126,7 @@ function createMockTriviumClient({
|
||||
}
|
||||
return {
|
||||
results: [
|
||||
{ nodeId: "node-a", namespace: "other-chat", score: 0.95 },
|
||||
{ nodeId: "node-b", score: 0.91 },
|
||||
{ nodeId: "node-outside", score: 0.88 },
|
||||
],
|
||||
@@ -378,6 +380,7 @@ 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(searchCall?.[1]?.namespace, "st-bme::chat-authority-vector");
|
||||
assert.equal(Array.isArray(searchCall?.[1]?.queryVector), true);
|
||||
assert.ok(searchCall?.[1]?.queryVector.length > 0);
|
||||
assert.equal(graph.vectorIndexState.lastSearchTimings.mode, "authority");
|
||||
@@ -445,6 +448,50 @@ assert.equal(isAuthorityVectorConfig(config), true);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const { graph } = createAuthorityVectorGraph();
|
||||
const fetchCalls = [];
|
||||
const fetchImpl = async (url, options = {}) => {
|
||||
const body = JSON.parse(String(options.body || "{}"));
|
||||
fetchCalls.push({ url: String(url), body });
|
||||
if (String(url).endsWith("/session/init")) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({ sessionToken: "test-session" }),
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({
|
||||
results: [
|
||||
{ externalId: "node-a", namespace: "other-chat", score: 0.99 },
|
||||
{ externalId: "node-b", namespace: "st-bme::chat-authority-vector", score: 0.93 },
|
||||
{ externalId: "node-c", score: 0.72 },
|
||||
],
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
const results = await searchAuthorityTriviumNodes(graph, "archive door", config, {
|
||||
namespace: "st-bme::chat-authority-vector",
|
||||
collectionId: "st-bme::chat-authority-vector",
|
||||
chatId: "chat-authority-vector",
|
||||
queryVector: [1, 0, 0],
|
||||
topK: 5,
|
||||
fetchImpl,
|
||||
});
|
||||
const searchCall = fetchCalls.find((call) => call.url.endsWith("/trivium/search-hybrid"));
|
||||
assert.equal(searchCall?.body?.namespace, "st-bme::chat-authority-vector");
|
||||
assert.equal(searchCall?.body?.collectionId, "st-bme::chat-authority-vector");
|
||||
assert.equal(searchCall?.body?.chatId, "chat-authority-vector");
|
||||
assert.deepEqual(
|
||||
results.map((entry) => entry.nodeId),
|
||||
["node-b", "node-c"],
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
const { graph, first, second } = createAuthorityVectorGraph();
|
||||
const triviumClient = createMockTriviumClient({ failSearch: true });
|
||||
|
||||
@@ -140,6 +140,15 @@ function normalizeNodeResultId(item = null) {
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeSearchResultNamespace(item = null) {
|
||||
return normalizeRecordId(
|
||||
item?.namespace ||
|
||||
item?.collectionId ||
|
||||
readNestedValue(item, ["payload", "namespace"]) ||
|
||||
readNestedValue(item, ["payload", "collectionId"]),
|
||||
);
|
||||
}
|
||||
|
||||
function readResultRows(payload = null) {
|
||||
if (Array.isArray(payload)) return payload;
|
||||
if (!payload || typeof payload !== "object") return [];
|
||||
@@ -211,12 +220,17 @@ function getNodeFieldText(node = {}, keys = []) {
|
||||
return "";
|
||||
}
|
||||
|
||||
function normalizeSearchResults(payload = null) {
|
||||
function normalizeSearchResults(payload = null, { namespace = "" } = {}) {
|
||||
const rows = readResultRows(payload);
|
||||
const expectedNamespace = normalizeRecordId(namespace);
|
||||
return rows
|
||||
.map((item, index) => {
|
||||
const nodeId = normalizeNodeResultId(item);
|
||||
if (!nodeId) return null;
|
||||
const resultNamespace = normalizeSearchResultNamespace(item);
|
||||
if (expectedNamespace && resultNamespace && resultNamespace !== expectedNamespace) {
|
||||
return null;
|
||||
}
|
||||
const rawScore = Number(item?.score ?? item?.similarity ?? item?.rankScore);
|
||||
const distance = Number(item?.distance);
|
||||
const score = Number.isFinite(rawScore)
|
||||
@@ -224,7 +238,11 @@ function normalizeSearchResults(payload = null) {
|
||||
: Number.isFinite(distance)
|
||||
? 1 / (1 + Math.max(0, distance))
|
||||
: Math.max(0.01, 1 - index / Math.max(1, rows.length));
|
||||
return { nodeId, score };
|
||||
return {
|
||||
nodeId,
|
||||
score,
|
||||
...(resultNamespace ? { namespace: resultNamespace } : {}),
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
@@ -597,8 +615,12 @@ export class AuthorityTriviumHttpClient {
|
||||
throw new Error("Authority Trivium v0.6 search requires vector");
|
||||
}
|
||||
const queryText = String(payload.queryText || payload.text || payload.searchText || payload.query || "");
|
||||
const namespace = getNamespace(payload);
|
||||
const body = {
|
||||
...this.buildOpenOptions(payload),
|
||||
...(namespace ? { namespace } : {}),
|
||||
...(payload.collectionId ? { collectionId: String(payload.collectionId) } : {}),
|
||||
...(payload.chatId ? { chatId: String(payload.chatId) } : {}),
|
||||
vector,
|
||||
topK: Number(payload.topK || payload.limit || 0) || undefined,
|
||||
expandDepth: Number(payload.expandDepth || payload.depth || 0) || undefined,
|
||||
@@ -1045,7 +1067,7 @@ export async function searchAuthorityTriviumNodes(graph, text, config = {}, opti
|
||||
topK: Math.max(1, Math.floor(Number(options.topK) || 1)),
|
||||
candidateIds: toArray(options.candidateIds).map(normalizeRecordId).filter(Boolean),
|
||||
});
|
||||
return normalizeSearchResults(payload);
|
||||
return normalizeSearchResults(payload, { namespace: options.namespace });
|
||||
}
|
||||
|
||||
export async function testAuthorityTriviumConnection(config = {}, options = {}) {
|
||||
|
||||
Reference in New Issue
Block a user