mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
Compare commits
4 Commits
d5022aa2bd
...
e22f9e4e37
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e22f9e4e37 | ||
|
|
ea57cf9a6a | ||
|
|
f443b388ee | ||
|
|
880e2b9158 |
@@ -6,6 +6,6 @@
|
||||
"js": "index.js",
|
||||
"css": "style.css",
|
||||
"author": "Youzini",
|
||||
"version": "6.3.1",
|
||||
"version": "6.3.2",
|
||||
"homePage": "https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology"
|
||||
}
|
||||
|
||||
@@ -162,6 +162,26 @@ function readPayloadMessage(payload = {}, fallback = "") {
|
||||
return String(payload.error || payload.message || payload.reason || fallback || "");
|
||||
}
|
||||
|
||||
function classifyAuthorityProbeStatus(status = 0, payload = null) {
|
||||
const payloadCategory = String(payload?.category || "").trim();
|
||||
if (payloadCategory) return payloadCategory;
|
||||
const numericStatus = Number(status || 0);
|
||||
if (numericStatus === 408) return "timeout";
|
||||
if (numericStatus === 401 || numericStatus === 403) return "permission";
|
||||
if (numericStatus === 413) return "payload-too-large";
|
||||
if (numericStatus === 429) return "rate-limit";
|
||||
if (numericStatus >= 500) return "server";
|
||||
if (numericStatus >= 400) return "validation";
|
||||
return "";
|
||||
}
|
||||
|
||||
function classifyAuthorityProbeError(error = null) {
|
||||
const category = String(error?.category || error?.errorCategory || "").trim();
|
||||
if (category) return category;
|
||||
if (String(error?.name || "") === "AbortError") return "timeout";
|
||||
return error ? "network" : "";
|
||||
}
|
||||
|
||||
function buildAuthorityPermissionEvaluateRequests(settings = {}, readiness = {}, options = {}) {
|
||||
const requests = [];
|
||||
const sqlTarget = String(options.sqlTarget || settings.sqlTarget || "default");
|
||||
@@ -198,6 +218,8 @@ async function verifyAuthorityDataPlane(baseUrl, fetchImpl, headers, settings =
|
||||
reason: initStatus === 401 || initStatus === 403 ? "session-init-denied" : "session-init-failed",
|
||||
lastError: readPayloadMessage(initPayload, `HTTP ${initStatus || "unknown"}`),
|
||||
status: initStatus,
|
||||
errorCategory: classifyAuthorityProbeStatus(initStatus, initPayload),
|
||||
errorDomain: "authority",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -231,6 +253,8 @@ async function verifyAuthorityDataPlane(baseUrl, fetchImpl, headers, settings =
|
||||
reason: currentStatus === 401 || currentStatus === 403 ? "session-invalid" : "session-current-failed",
|
||||
lastError: readPayloadMessage(currentPayload, `HTTP ${currentStatus || "unknown"}`),
|
||||
status: currentStatus,
|
||||
errorCategory: classifyAuthorityProbeStatus(currentStatus, currentPayload),
|
||||
errorDomain: "authority",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -259,6 +283,8 @@ async function verifyAuthorityDataPlane(baseUrl, fetchImpl, headers, settings =
|
||||
reason: permissionStatus === 401 || permissionStatus === 403 ? "permission-denied" : "permission-evaluate-failed",
|
||||
lastError: readPayloadMessage(permissionPayload, `HTTP ${permissionStatus || "unknown"}`),
|
||||
status: permissionStatus,
|
||||
errorCategory: classifyAuthorityProbeStatus(permissionStatus, permissionPayload),
|
||||
errorDomain: "authority",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -408,6 +434,8 @@ export function createDefaultAuthorityCapabilityState(overrides = {}) {
|
||||
missingFeatures: ["sql.query", "sql.mutation", "trivium.search", "jobs", "blob-or-private-files"],
|
||||
reason: "not-probed",
|
||||
lastError: "",
|
||||
errorCategory: "",
|
||||
errorDomain: "",
|
||||
endpoint: "",
|
||||
status: 0,
|
||||
latencyMs: 0,
|
||||
@@ -459,6 +487,8 @@ export function normalizeAuthorityCapabilityState(input = {}, settings = {}) {
|
||||
missingFeatures,
|
||||
reason: String(source.reason || (healthy ? "ok" : "not-ready")),
|
||||
lastError: String(source.lastError || ""),
|
||||
errorCategory: String(source.errorCategory || ""),
|
||||
errorDomain: String(source.errorDomain || ""),
|
||||
endpoint: String(source.endpoint || ""),
|
||||
status: clampInteger(source.status, 0, 0, 999),
|
||||
latencyMs: Math.max(0, Number(source.latencyMs) || 0),
|
||||
@@ -547,6 +577,7 @@ export async function probeAuthorityCapabilities(options = {}) {
|
||||
|
||||
let lastError = "";
|
||||
let lastStatus = 0;
|
||||
let lastErrorCategory = "";
|
||||
for (const endpoint of buildAuthorityProbeUrls(settings.baseUrl)) {
|
||||
const startedAt = readNowMs();
|
||||
try {
|
||||
@@ -555,6 +586,7 @@ export async function probeAuthorityCapabilities(options = {}) {
|
||||
const status = Number(response?.status || 0);
|
||||
lastStatus = status;
|
||||
if (status === 404) continue;
|
||||
const errorPayload = response?.ok ? null : await readResponsePayload(response);
|
||||
if (status === 401 || status === 403) {
|
||||
return normalizeAuthorityCapabilityState(
|
||||
{
|
||||
@@ -563,7 +595,9 @@ export async function probeAuthorityCapabilities(options = {}) {
|
||||
sessionReady: false,
|
||||
permissionReady: false,
|
||||
reason: "permission-denied",
|
||||
lastError: `HTTP ${status}`,
|
||||
lastError: readPayloadMessage(errorPayload, `HTTP ${status}`),
|
||||
errorCategory: classifyAuthorityProbeStatus(status, errorPayload),
|
||||
errorDomain: "authority",
|
||||
endpoint,
|
||||
status,
|
||||
latencyMs: normalizeLatencyMs(startedAt, finishedAt),
|
||||
@@ -579,7 +613,9 @@ export async function probeAuthorityCapabilities(options = {}) {
|
||||
installed: status > 0,
|
||||
healthy: false,
|
||||
reason: "http-error",
|
||||
lastError: `HTTP ${status || "unknown"}`,
|
||||
lastError: readPayloadMessage(errorPayload, `HTTP ${status || "unknown"}`),
|
||||
errorCategory: classifyAuthorityProbeStatus(status, errorPayload),
|
||||
errorDomain: "authority",
|
||||
endpoint,
|
||||
status,
|
||||
latencyMs: normalizeLatencyMs(startedAt, finishedAt),
|
||||
@@ -605,12 +641,16 @@ export async function probeAuthorityCapabilities(options = {}) {
|
||||
let reason = missingFeatures.length ? "missing-required-features" : "ok";
|
||||
let dataPlaneLastError = "";
|
||||
let dataPlaneStatus = status;
|
||||
let dataPlaneErrorCategory = "";
|
||||
let dataPlaneErrorDomain = "";
|
||||
if (healthy) {
|
||||
const verified = await verifyAuthorityDataPlane(settings.baseUrl, fetchImpl, headers, settings, readiness, options);
|
||||
sessionReady = verified.sessionReady;
|
||||
permissionReady = verified.permissionReady;
|
||||
dataPlaneStatus = Number(verified.status || status || 0);
|
||||
dataPlaneLastError = String(verified.lastError || "");
|
||||
dataPlaneErrorCategory = String(verified.errorCategory || "");
|
||||
dataPlaneErrorDomain = String(verified.errorDomain || "");
|
||||
if (verified.reason && verified.reason !== "ok") {
|
||||
reason = verified.reason;
|
||||
}
|
||||
@@ -627,6 +667,8 @@ export async function probeAuthorityCapabilities(options = {}) {
|
||||
missingFeatures,
|
||||
reason,
|
||||
lastError: dataPlaneLastError,
|
||||
errorCategory: dataPlaneErrorCategory,
|
||||
errorDomain: dataPlaneErrorDomain,
|
||||
endpoint,
|
||||
status: dataPlaneStatus,
|
||||
latencyMs: normalizeLatencyMs(startedAt, finishedAt),
|
||||
@@ -637,6 +679,8 @@ export async function probeAuthorityCapabilities(options = {}) {
|
||||
);
|
||||
} catch (error) {
|
||||
lastError = error?.message || String(error);
|
||||
lastStatus = Number(error?.status || lastStatus || 0);
|
||||
lastErrorCategory = classifyAuthorityProbeError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,6 +690,8 @@ export async function probeAuthorityCapabilities(options = {}) {
|
||||
healthy: false,
|
||||
reason: lastStatus === 404 ? "not-installed" : "probe-failed",
|
||||
lastError,
|
||||
errorCategory: lastErrorCategory || classifyAuthorityProbeStatus(lastStatus),
|
||||
errorDomain: lastErrorCategory || lastStatus ? "authority" : "",
|
||||
status: lastStatus,
|
||||
lastProbeAt: nowMs,
|
||||
updatedAt: new Date(nowMs).toISOString(),
|
||||
|
||||
@@ -176,6 +176,78 @@ const relativeUnavailable = await probeAuthorityCapabilities({
|
||||
assert.equal(relativeUnavailable.reason, "relative-url-unavailable");
|
||||
assert.equal(relativeUnavailable.serverPrimaryReady, false);
|
||||
|
||||
const permissionDeniedState = await probeAuthorityCapabilities({
|
||||
settings: defaultSettings,
|
||||
allowRelativeUrl: true,
|
||||
nowMs: 3100,
|
||||
fetchImpl: async () => ({
|
||||
ok: false,
|
||||
status: 403,
|
||||
async json() {
|
||||
return { error: "permission denied" };
|
||||
},
|
||||
}),
|
||||
});
|
||||
assert.equal(permissionDeniedState.reason, "permission-denied");
|
||||
assert.equal(permissionDeniedState.errorCategory, "permission");
|
||||
assert.equal(permissionDeniedState.errorDomain, "authority");
|
||||
|
||||
const rateLimitedState = await probeAuthorityCapabilities({
|
||||
settings: defaultSettings,
|
||||
allowRelativeUrl: true,
|
||||
nowMs: 3200,
|
||||
fetchImpl: async () => ({
|
||||
ok: false,
|
||||
status: 429,
|
||||
async json() {
|
||||
return { error: "slow down" };
|
||||
},
|
||||
}),
|
||||
});
|
||||
assert.equal(rateLimitedState.reason, "http-error");
|
||||
assert.equal(rateLimitedState.errorCategory, "rate-limit");
|
||||
assert.equal(rateLimitedState.errorDomain, "authority");
|
||||
|
||||
const serverErrorState = await probeAuthorityCapabilities({
|
||||
settings: defaultSettings,
|
||||
allowRelativeUrl: true,
|
||||
nowMs: 3300,
|
||||
fetchImpl: async () => ({
|
||||
ok: false,
|
||||
status: 503,
|
||||
async json() {
|
||||
return { category: "backpressure", code: "job_queue_full" };
|
||||
},
|
||||
}),
|
||||
});
|
||||
assert.equal(serverErrorState.reason, "http-error");
|
||||
assert.equal(serverErrorState.errorCategory, "backpressure");
|
||||
assert.equal(serverErrorState.errorDomain, "authority");
|
||||
|
||||
const networkFailedState = await probeAuthorityCapabilities({
|
||||
settings: defaultSettings,
|
||||
allowRelativeUrl: true,
|
||||
nowMs: 3400,
|
||||
fetchImpl: async () => {
|
||||
throw new Error("fetch failed");
|
||||
},
|
||||
});
|
||||
assert.equal(networkFailedState.reason, "probe-failed");
|
||||
assert.equal(networkFailedState.errorCategory, "network");
|
||||
assert.equal(networkFailedState.errorDomain, "authority");
|
||||
|
||||
const timeoutState = await probeAuthorityCapabilities({
|
||||
settings: defaultSettings,
|
||||
allowRelativeUrl: true,
|
||||
nowMs: 3500,
|
||||
fetchImpl: async () => {
|
||||
throw Object.assign(new Error("aborted"), { name: "AbortError" });
|
||||
},
|
||||
});
|
||||
assert.equal(timeoutState.reason, "probe-failed");
|
||||
assert.equal(timeoutState.errorCategory, "timeout");
|
||||
assert.equal(timeoutState.errorDomain, "authority");
|
||||
|
||||
// Regression: Authority capability normalization records explicit supported job types from probe payloads.
|
||||
// When a probe payload provides jobs.supportedTypes, normalizeAuthorityCapabilityState should surface
|
||||
// them as supportedJobTypes and set supportedJobTypesKnown = true.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { addEdge, addNode, createEdge, createEmptyGraph, createNode } from "../graph/graph.js";
|
||||
import { AuthorityHttpError } from "../runtime/authority-http-client.js";
|
||||
import {
|
||||
installResolveHooks,
|
||||
toDataModuleUrl,
|
||||
@@ -33,7 +34,10 @@ const {
|
||||
normalizeAuthorityVectorConfig,
|
||||
queryAuthorityTriviumNeighbors,
|
||||
} = await import("../vector/authority-vector-primary-adapter.js");
|
||||
const { findSimilarNodesByText: findSimilarNodesByTextFromIndex, syncGraphVectorIndex: syncGraphVectorIndexFromIndex } = await import("../vector/vector-index.js");
|
||||
const {
|
||||
findSimilarNodesByText: findSimilarNodesByTextFromIndex,
|
||||
syncGraphVectorIndex: syncGraphVectorIndexFromIndex,
|
||||
} = await import("../vector/vector-index.js");
|
||||
|
||||
function createAuthorityVectorGraph() {
|
||||
const graph = createEmptyGraph();
|
||||
@@ -66,7 +70,7 @@ function createAuthorityVectorGraph() {
|
||||
return { graph, first, second };
|
||||
}
|
||||
|
||||
function createMockTriviumClient({ failBulkUpsert = false } = {}) {
|
||||
function createMockTriviumClient({ failBulkUpsert = false, failSearch = false } = {}) {
|
||||
const calls = [];
|
||||
return {
|
||||
calls,
|
||||
@@ -88,7 +92,11 @@ function createMockTriviumClient({ failBulkUpsert = false } = {}) {
|
||||
async bulkUpsert(payload) {
|
||||
calls.push(["bulkUpsert", payload]);
|
||||
if (failBulkUpsert) {
|
||||
throw new Error("trivium-down");
|
||||
throw new AuthorityHttpError("trivium-down", {
|
||||
status: 503,
|
||||
category: "server",
|
||||
path: "/trivium/bulk-upsert",
|
||||
});
|
||||
}
|
||||
return { ok: true, upserted: payload.items?.length || 0 };
|
||||
},
|
||||
@@ -102,6 +110,13 @@ function createMockTriviumClient({ failBulkUpsert = false } = {}) {
|
||||
},
|
||||
async search(payload) {
|
||||
calls.push(["search", payload]);
|
||||
if (failSearch) {
|
||||
throw new AuthorityHttpError("trivium search denied", {
|
||||
status: 403,
|
||||
category: "permission",
|
||||
path: "/trivium/search",
|
||||
});
|
||||
}
|
||||
return {
|
||||
results: [
|
||||
{ nodeId: "node-b", score: 0.91 },
|
||||
@@ -234,9 +249,77 @@ assert.equal(isAuthorityVectorConfig(config), true);
|
||||
assert.equal(graph.vectorIndexState.mode, "authority");
|
||||
assert.equal(graph.vectorIndexState.dirty, true);
|
||||
assert.equal(graph.vectorIndexState.dirtyReason, "authority-trivium-sync-failed");
|
||||
assert.equal(result.errorCategory, "server");
|
||||
assert.equal(result.errorDomain, "authority");
|
||||
assert.equal(result.timings.errorCategory, "server");
|
||||
assert.equal(result.timings.authorityErrorCategory, "server");
|
||||
assert.equal(graph.vectorIndexState.lastErrorCategory, "server");
|
||||
assert.equal(graph.vectorIndexState.lastErrorDomain, "authority");
|
||||
assert.equal(result.timings.authorityDiagnostics.upsert.errorCategory, "server");
|
||||
assert.equal(result.timings.authorityDiagnostics.upsert.chunks[0].errorCategory, "server");
|
||||
assert.match(graph.vectorIndexState.lastWarning, /Authority Trivium 同步失败/);
|
||||
}
|
||||
|
||||
{
|
||||
const previousOverrides = globalThis.__stBmeTestOverrides;
|
||||
globalThis.__stBmeTestOverrides = {
|
||||
embedding: {
|
||||
async embedBatch(texts = []) {
|
||||
return texts.map(() => null);
|
||||
},
|
||||
async embedText() {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
try {
|
||||
const { graph } = createAuthorityVectorGraph();
|
||||
graph.nodes.forEach((node) => {
|
||||
node.embedding = null;
|
||||
});
|
||||
const triviumClient = createMockTriviumClient();
|
||||
const result = await syncGraphVectorIndexFromIndex(graph, config, {
|
||||
chatId: "chat-authority-vector",
|
||||
purge: true,
|
||||
triviumClient,
|
||||
});
|
||||
assert.match(result.error, /Embedding provider failed/);
|
||||
assert.doesNotMatch(result.error, /Authority Trivium embedding failed/);
|
||||
assert.equal(result.errorCategory, "embedding-provider");
|
||||
assert.equal(result.errorDomain, "embedding");
|
||||
assert.equal(graph.vectorIndexState.dirtyReason, "embedding-provider-sync-failed");
|
||||
assert.equal(graph.vectorIndexState.lastErrorCategory, "embedding-provider");
|
||||
assert.equal(graph.vectorIndexState.lastErrorDomain, "embedding");
|
||||
assert.match(graph.vectorIndexState.lastWarning, /Embedding provider 同步失败/);
|
||||
assert.equal(triviumClient.calls.some(([name]) => name === "bulkUpsert"), false);
|
||||
} finally {
|
||||
globalThis.__stBmeTestOverrides = previousOverrides;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const { graph, first, second } = createAuthorityVectorGraph();
|
||||
const triviumClient = createMockTriviumClient({ failSearch: true });
|
||||
const queryConfig = { ...config, triviumClient };
|
||||
await syncGraphVectorIndexFromIndex(graph, queryConfig, {
|
||||
chatId: "chat-authority-vector",
|
||||
purge: true,
|
||||
triviumClient,
|
||||
});
|
||||
const results = await findSimilarNodesByTextFromIndex(
|
||||
graph,
|
||||
"archive door",
|
||||
queryConfig,
|
||||
5,
|
||||
[first, second],
|
||||
);
|
||||
assert.deepEqual(results, []);
|
||||
assert.equal(graph.vectorIndexState.lastSearchTimings.errorCategory, "permission");
|
||||
assert.equal(graph.vectorIndexState.lastSearchTimings.authorityErrorCategory, "permission");
|
||||
assert.equal(graph.vectorIndexState.lastErrorCategory, "permission");
|
||||
assert.equal(graph.vectorIndexState.lastErrorDomain, "authority");
|
||||
}
|
||||
|
||||
{
|
||||
const triviumClient = createMockTriviumClient();
|
||||
const queryConfig = { ...config, triviumClient };
|
||||
|
||||
@@ -2,6 +2,7 @@ import { normalizeAuthorityBaseUrl } from "../runtime/authority-capabilities.js"
|
||||
import {
|
||||
AUTHORITY_PROTOCOL_SERVER_PLUGIN_V06,
|
||||
AuthorityHttpClient,
|
||||
AuthorityHttpError,
|
||||
} from "../runtime/authority-http-client.js";
|
||||
import { embedText } from "./embedding.js";
|
||||
|
||||
@@ -89,6 +90,25 @@ function hasPlainKeys(value = null) {
|
||||
return isPlainObject(value) && Object.keys(value).length > 0;
|
||||
}
|
||||
|
||||
function getAuthorityErrorCategory(error = null) {
|
||||
return String(error?.category || error?.errorCategory || "").trim();
|
||||
}
|
||||
|
||||
function getAuthorityErrorDomain(error = null) {
|
||||
if (!error) return "";
|
||||
return error instanceof AuthorityHttpError || getAuthorityErrorCategory(error) ? "authority" : "";
|
||||
}
|
||||
|
||||
function buildAuthorityErrorDiagnostics(error = null) {
|
||||
const category = getAuthorityErrorCategory(error);
|
||||
const domain = getAuthorityErrorDomain(error);
|
||||
return {
|
||||
...(category ? { errorCategory: category, authorityErrorCategory: category } : {}),
|
||||
...(domain ? { errorDomain: domain, authorityErrorDomain: domain } : {}),
|
||||
...(Number(error?.status || 0) > 0 ? { status: Number(error.status) } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeOpenAICompatibleBaseUrl(value) {
|
||||
return String(value || "")
|
||||
.trim()
|
||||
@@ -816,6 +836,7 @@ export async function upsertAuthorityTriviumEntries(graph, config = {}, entries
|
||||
durationMs: roundMs(nowMs() - chunkStartedAt),
|
||||
ok: false,
|
||||
error: error?.message || String(error),
|
||||
...buildAuthorityErrorDiagnostics(error),
|
||||
});
|
||||
error.authorityDiagnostics = {
|
||||
operation: "bulkUpsert",
|
||||
@@ -824,6 +845,7 @@ export async function upsertAuthorityTriviumEntries(graph, config = {}, entries
|
||||
chunks,
|
||||
totalBytes,
|
||||
totalMs: roundMs(nowMs() - startedAt),
|
||||
...buildAuthorityErrorDiagnostics(error),
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -626,6 +626,7 @@ function markAuthorityVectorStateDirty(
|
||||
config = {},
|
||||
reason = "authority-trivium-failed",
|
||||
warning = "Authority Trivium 索引失败,已标记待重建",
|
||||
diagnostics = {},
|
||||
) {
|
||||
if (!graph?.vectorIndexState || !isAuthorityVectorConfig(config)) {
|
||||
return;
|
||||
@@ -655,6 +656,39 @@ function markAuthorityVectorStateDirty(
|
||||
pending: total > 0 ? Math.max(1, Number(state.lastStats?.pending || 0)) : 0,
|
||||
};
|
||||
state.lastWarning = String(warning || "Authority Trivium 索引失败,已标记待重建");
|
||||
const errorCategory = String(diagnostics.errorCategory || diagnostics.authorityErrorCategory || "").trim();
|
||||
const errorDomain = String(diagnostics.errorDomain || diagnostics.authorityErrorDomain || "").trim();
|
||||
if (errorCategory) state.lastErrorCategory = errorCategory;
|
||||
if (errorDomain) state.lastErrorDomain = errorDomain;
|
||||
}
|
||||
|
||||
function getErrorCategory(error = null) {
|
||||
return String(error?.category || error?.errorCategory || "").trim();
|
||||
}
|
||||
|
||||
function getErrorDomain(error = null, fallback = "") {
|
||||
if (!error) return "";
|
||||
if (error?.errorDomain) return String(error.errorDomain).trim();
|
||||
if (getErrorCategory(error)) return fallback || "authority";
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function getAuthorityDiagnosticsErrorPatch(error = null) {
|
||||
const errorCategory = getErrorCategory(error);
|
||||
const errorDomain = getErrorDomain(error, errorCategory ? "authority" : "");
|
||||
return {
|
||||
...(errorCategory ? { errorCategory, authorityErrorCategory: errorCategory } : {}),
|
||||
...(errorDomain ? { errorDomain, authorityErrorDomain: errorDomain } : {}),
|
||||
...(Number(error?.status || 0) > 0 ? { status: Number(error.status) } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function createEmbeddingProviderError(failures = 0) {
|
||||
const count = Math.max(0, Math.floor(Number(failures) || 0));
|
||||
const error = new Error(`Embedding provider failed for ${count} item(s)`);
|
||||
error.errorCategory = "embedding-provider";
|
||||
error.errorDomain = "embedding";
|
||||
return error;
|
||||
}
|
||||
|
||||
async function ensureEntryEmbeddings(graph, entries = [], config = {}, signal = undefined) {
|
||||
@@ -802,7 +836,7 @@ export async function syncGraphVectorIndex(
|
||||
embeddingsRequested += embeddingResult.requested;
|
||||
embedBatchMs += embeddingResult.elapsedMs;
|
||||
if (embeddingResult.failures > 0) {
|
||||
throw new Error(`Authority Trivium embedding failed for ${embeddingResult.failures} item(s)`);
|
||||
throw createEmbeddingProviderError(embeddingResult.failures);
|
||||
}
|
||||
const purgeStartedAt = nowMs();
|
||||
const purgeResult = await purgeAuthorityTriviumNamespace(config, authorityOptions);
|
||||
@@ -866,7 +900,7 @@ export async function syncGraphVectorIndex(
|
||||
embeddingsRequested += embeddingResult.requested;
|
||||
embedBatchMs += embeddingResult.elapsedMs;
|
||||
if (embeddingResult.failures > 0) {
|
||||
throw new Error(`Authority Trivium embedding failed for ${embeddingResult.failures} item(s)`);
|
||||
throw createEmbeddingProviderError(embeddingResult.failures);
|
||||
}
|
||||
deletedNodeCount = nodeIdsToDelete.length;
|
||||
const deleteStartedAt = nowMs();
|
||||
@@ -909,17 +943,29 @@ export async function syncGraphVectorIndex(
|
||||
} catch (error) {
|
||||
if (isAbortError(error)) throw error;
|
||||
const message = error?.message || String(error) || "Authority Trivium 同步失败";
|
||||
const errorCategory = getErrorCategory(error);
|
||||
const errorDomain = getErrorDomain(error, errorCategory ? "authority" : "");
|
||||
const dirtyReason = errorDomain === "embedding"
|
||||
? "embedding-provider-sync-failed"
|
||||
: "authority-trivium-sync-failed";
|
||||
const warningPrefix = errorDomain === "embedding"
|
||||
? "Embedding provider 同步失败"
|
||||
: "Authority Trivium 同步失败";
|
||||
markAuthorityVectorStateDirty(
|
||||
graph,
|
||||
config,
|
||||
"authority-trivium-sync-failed",
|
||||
`Authority Trivium 同步失败(${message}),已标记待重建`,
|
||||
dirtyReason,
|
||||
`${warningPrefix}(${message}),已标记待重建`,
|
||||
{ errorCategory, errorDomain },
|
||||
);
|
||||
state.lastSyncAt = Date.now();
|
||||
state.lastTimings = {
|
||||
mode: syncMode,
|
||||
success: false,
|
||||
error: message,
|
||||
...(errorCategory ? { errorCategory } : {}),
|
||||
...(errorDomain ? { errorDomain } : {}),
|
||||
...(errorCategory && errorDomain === "authority" ? { authorityErrorCategory: errorCategory, authorityErrorDomain: errorDomain } : {}),
|
||||
desiredEntries: Number(desiredBuildDiagnostics.entryCount || desiredEntries.length),
|
||||
desiredBuildMs: roundMs(desiredBuildMs),
|
||||
authorityPurgeMs: roundMs(authorityPurgeMs),
|
||||
@@ -940,6 +986,8 @@ export async function syncGraphVectorIndex(
|
||||
stats: state.lastStats,
|
||||
timings: state.lastTimings,
|
||||
error: message,
|
||||
...(errorCategory ? { errorCategory } : {}),
|
||||
...(errorDomain ? { errorDomain } : {}),
|
||||
};
|
||||
if (config.failOpen === false) {
|
||||
throw error;
|
||||
@@ -1291,17 +1339,20 @@ export async function findSimilarNodesByText(
|
||||
throw error;
|
||||
}
|
||||
const message = error?.message || String(error) || "Authority Trivium 查询失败";
|
||||
const errorPatch = getAuthorityDiagnosticsErrorPatch(error);
|
||||
markAuthorityVectorStateDirty(
|
||||
graph,
|
||||
config,
|
||||
"authority-trivium-query-failed",
|
||||
`Authority Trivium 查询失败(${message}),已标记待重建`,
|
||||
errorPatch,
|
||||
);
|
||||
recordSearchTimings({
|
||||
success: false,
|
||||
reason: "authority-trivium-query-failed",
|
||||
requestMs: roundMs(nowMs() - requestStartedAt),
|
||||
error: message,
|
||||
...errorPatch,
|
||||
resultCount: 0,
|
||||
});
|
||||
if (config.failOpen === false) {
|
||||
|
||||
Reference in New Issue
Block a user