diff --git a/index.js b/index.js index ad0f547..62ad3eb 100644 --- a/index.js +++ b/index.js @@ -1626,6 +1626,12 @@ function buildAuthorityPersistenceStatePatch(settings = getSettings()) { authorityTriviumPrimaryReady: Boolean(capability.triviumPrimaryReady), authorityJobsReady: Boolean(capability.jobsReady), authorityBlobReady: Boolean(capability.blobReady), + authorityBmeProtocolVersion: Math.max(0, Number(capability.bmeProtocolVersion) || 0), + authorityBmeVectorManifestReady: Boolean(capability.bmeVectorManifestReady), + authorityBmeVectorApplyReady: Boolean(capability.bmeVectorApplyReady), + authorityBmeVectorApplyJobsReady: Boolean(capability.bmeVectorApplyJobsReady), + authorityBmeServerEmbeddingProbeReady: Boolean(capability.bmeServerEmbeddingProbeReady), + authorityBmeCandidateSearchReady: Boolean(capability.bmeCandidateSearchReady), authorityBrowserCacheMode: String(browserState.mode || "minimal"), authorityOfflineQueueBytes: Number(browserState.offlineQueueBytes || 0), authorityOfflineQueueItems: Number(browserState.offlineQueueItems || 0), diff --git a/runtime/authority-capabilities.js b/runtime/authority-capabilities.js index 4c1bee0..5d781d4 100644 --- a/runtime/authority-capabilities.js +++ b/runtime/authority-capabilities.js @@ -6,6 +6,11 @@ const SQL_MUTATION_FEATURES = ["sql", "sql.mutation", "sql.execute", "sql.exec", const TRIVIUM_FEATURES = ["trivium", "trivium.search", "trivium.query", "trivium.filterwhere", "trivium.bulkupsert", "trivium.upsert", "trivium.bulkmutations"]; const JOB_FEATURES = ["jobs", "jobs.background", "jobs.list", "jobs.wait", "diagnostics.jobspage", "events", "sse"]; const BLOB_FEATURES = ["blob", "blob.write", "storage.blob", "transfers.blob", "transfers.fs", "fs.private", "privatefiles", "private.files", "files.private"]; +const BME_VECTOR_MANIFEST_FEATURES = ["bme.vectormanifest", "bme.vector.manifest", "bme.vector-manifest"]; +const BME_VECTOR_APPLY_FEATURES = ["bme.vectorapply", "bme.vector.apply"]; +const BME_VECTOR_APPLY_JOB_FEATURES = ["bme.vectorapplyjobs", "bme.vector.applyjobs", "bme.vector.apply.jobs"]; +const BME_SERVER_EMBEDDING_FEATURES = ["bme.serverembeddingprobe", "bme.server.embedding.probe"]; +const BME_CANDIDATE_SEARCH_FEATURES = ["bme.candidatesearch", "bme.candidate.search"]; function toBoolean(value, fallback = false) { if (typeof value === "boolean") return value; @@ -65,9 +70,20 @@ function createFeatureReadiness(features) { trivium: hasAnyFeature(features, TRIVIUM_FEATURES), jobs: hasAnyFeature(features, JOB_FEATURES), blob: hasAnyFeature(features, BLOB_FEATURES), + bmeVectorManifest: hasAnyFeature(features, BME_VECTOR_MANIFEST_FEATURES), + bmeVectorApply: hasAnyFeature(features, BME_VECTOR_APPLY_FEATURES), + bmeVectorApplyJobs: hasAnyFeature(features, BME_VECTOR_APPLY_JOB_FEATURES), + bmeServerEmbeddingProbe: hasAnyFeature(features, BME_SERVER_EMBEDDING_FEATURES), + bmeCandidateSearch: hasAnyFeature(features, BME_CANDIDATE_SEARCH_FEATURES), }; } +function normalizeBmeProtocolVersion(features, source = {}) { + const direct = Number(source?.bme?.protocolVersion ?? source?.features?.bme?.protocolVersion ?? 0); + if (Number.isFinite(direct) && direct > 0) return Math.trunc(direct); + return features.has("bme.protocolversion") ? 1 : 0; +} + function collectMissingFeatures(readiness) { const missing = []; if (!readiness.sql) missing.push("sql.query"); @@ -430,6 +446,12 @@ export function createDefaultAuthorityCapabilityState(overrides = {}) { supportedJobTypes: [], supportedJobTypesKnown: false, blobReady: false, + bmeVectorManifestReady: false, + bmeVectorApplyReady: false, + bmeVectorApplyJobsReady: false, + bmeServerEmbeddingProbeReady: false, + bmeCandidateSearchReady: false, + bmeProtocolVersion: 0, features: [], missingFeatures: ["sql.query", "sql.mutation", "trivium.search", "jobs", "blob-or-private-files"], reason: "not-probed", @@ -461,6 +483,12 @@ export function normalizeAuthorityCapabilityState(input = {}, settings = {}) { const triviumPrimaryReady = healthy && sessionReady && permissionReady && readiness.trivium; const jobsReady = healthy && readiness.jobs; const blobReady = healthy && readiness.blob; + const bmeProtocolVersion = normalizeBmeProtocolVersion(features, source); + const bmeVectorManifestReady = healthy && sessionReady && permissionReady && readiness.bmeVectorManifest; + const bmeVectorApplyReady = healthy && sessionReady && permissionReady && readiness.bmeVectorApply; + const bmeVectorApplyJobsReady = healthy && sessionReady && permissionReady && readiness.bmeVectorApplyJobs; + const bmeServerEmbeddingProbeReady = healthy && sessionReady && permissionReady && readiness.bmeServerEmbeddingProbe; + const bmeCandidateSearchReady = healthy && sessionReady && permissionReady && readiness.bmeCandidateSearch; const minimumFeatureSetReady = storagePrimaryReady && triviumPrimaryReady && jobsReady && blobReady; const serverPrimaryRequested = normalizedSettings.enabled && @@ -483,6 +511,12 @@ export function normalizeAuthorityCapabilityState(input = {}, settings = {}) { supportedJobTypes: supportedJobs.supportedJobTypes, supportedJobTypesKnown: supportedJobs.supportedJobTypesKnown, blobReady, + bmeVectorManifestReady, + bmeVectorApplyReady, + bmeVectorApplyJobsReady, + bmeServerEmbeddingProbeReady, + bmeCandidateSearchReady, + bmeProtocolVersion, features: Array.from(features).sort(), missingFeatures, reason: String(source.reason || (healthy ? "ok" : "not-ready")), diff --git a/runtime/authority-upgrade-state.js b/runtime/authority-upgrade-state.js index 476ba3f..4f91382 100644 --- a/runtime/authority-upgrade-state.js +++ b/runtime/authority-upgrade-state.js @@ -25,6 +25,9 @@ export function createAuthorityUpgradeState(overrides = {}) { storageReady: Boolean(overrides.storageReady), vectorReady: Boolean(overrides.vectorReady), jobsReady: Boolean(overrides.jobsReady), + bmeVectorManifestReady: Boolean(overrides.bmeVectorManifestReady), + bmeVectorApplyReady: Boolean(overrides.bmeVectorApplyReady), + bmeProtocolVersion: Math.max(0, Number(overrides.bmeProtocolVersion) || 0), browserCacheMode: normalizeString(overrides.browserCacheMode, "minimal"), updatedAt: normalizeString(overrides.updatedAt, new Date().toISOString()), }; @@ -42,6 +45,9 @@ export function deriveAuthorityUpgradeState({ const vectorReady = Boolean(capability.triviumPrimaryReady); const serverPrimaryReady = Boolean(capability.serverPrimaryReady || storageReady); const jobsReady = Boolean(capability.jobsReady); + const bmeVectorManifestReady = Boolean(capability.bmeVectorManifestReady); + const bmeVectorApplyReady = Boolean(capability.bmeVectorApplyReady); + const bmeProtocolVersion = Math.max(0, Number(capability.bmeProtocolVersion) || 0); const browserCacheMode = normalizeString(browserState.mode, "minimal"); const reason = normalizeString(capability.reason || capability.lastError, "standalone"); const updatedAt = new Date(Number.isFinite(Number(now)) ? Number(now) : Date.now()).toISOString(); @@ -93,6 +99,9 @@ export function deriveAuthorityUpgradeState({ storageReady, vectorReady, jobsReady, + bmeVectorManifestReady, + bmeVectorApplyReady, + bmeProtocolVersion, browserCacheMode, updatedAt, }); @@ -103,7 +112,9 @@ export function deriveAuthorityUpgradeState({ mode: AUTHORITY_UPGRADE_MODES.ENHANCED, text: "服务端增强已启用", meta: jobsReady - ? "图谱与向量存储已自动升级到 DOA/Authority 增强路径" + ? bmeVectorManifestReady + ? "图谱与向量存储已增强,服务端向量清单可用" + : "图谱与向量存储已增强,等待 BME 向量清单能力" : "图谱与向量存储已增强,服务端后台任务能力暂不可用", level: "success", ready: true, @@ -112,6 +123,9 @@ export function deriveAuthorityUpgradeState({ storageReady, vectorReady, jobsReady, + bmeVectorManifestReady, + bmeVectorApplyReady, + bmeProtocolVersion, browserCacheMode, updatedAt, }); @@ -130,6 +144,9 @@ export function deriveAuthorityUpgradeState({ storageReady, vectorReady, jobsReady, + bmeVectorManifestReady, + bmeVectorApplyReady, + bmeProtocolVersion, browserCacheMode, updatedAt, }); diff --git a/tests/authority-bme-capabilities.mjs b/tests/authority-bme-capabilities.mjs new file mode 100644 index 0000000..7cb676c --- /dev/null +++ b/tests/authority-bme-capabilities.mjs @@ -0,0 +1,43 @@ +import assert from "node:assert/strict"; + +import { + normalizeAuthorityProbeResponse, + normalizeAuthorityCapabilityState, +} from "../runtime/authority-capabilities.js"; + +const capability = normalizeAuthorityProbeResponse({ + healthy: true, + features: { + sql: { queryPage: true, stat: true }, + trivium: { bulkMutations: true, searchContext: true }, + jobs: { background: true, builtinTypes: ["delay", "trivium.flush"] }, + transfers: { blob: true, fs: true }, + bme: { + protocolVersion: 1, + vectorManifest: true, + vectorApply: false, + vectorApplyJobs: false, + serverEmbeddingProbe: false, + candidateSearch: false, + }, + }, +}); + +assert.equal(capability.bmeProtocolVersion, 1); +assert.equal(capability.bmeVectorManifestReady, true); +assert.equal(capability.bmeVectorApplyReady, false); +assert.equal(capability.bmeServerEmbeddingProbeReady, false); +assert.ok(capability.features.includes("bme.vectormanifest")); +assert.ok(capability.features.includes("bme.protocolversion")); + +const legacy = normalizeAuthorityCapabilityState({ + installed: true, + healthy: true, + sessionReady: true, + permissionReady: true, + features: ["sql.query", "sql.mutation", "trivium.search"], +}); +assert.equal(legacy.bmeVectorManifestReady, false); +assert.equal(legacy.bmeProtocolVersion, 0); + +console.log("authority-bme-capabilities tests passed"); diff --git a/tests/authority-upgrade-state.mjs b/tests/authority-upgrade-state.mjs index 2fe91c7..a1832e4 100644 --- a/tests/authority-upgrade-state.mjs +++ b/tests/authority-upgrade-state.mjs @@ -53,12 +53,16 @@ const enhanced = deriveAuthorityUpgradeState({ storagePrimaryReady: true, triviumPrimaryReady: true, jobsReady: true, + bmeVectorManifestReady: true, + bmeProtocolVersion: 1, }, browserState: { mode: "off" }, }); assert.equal(enhanced.mode, "authority-enhanced"); assert.equal(enhanced.ready, true); assert.equal(enhanced.text, "服务端增强已启用"); +assert.equal(enhanced.bmeVectorManifestReady, true); +assert.equal(enhanced.bmeProtocolVersion, 1); assert.equal( formatAuthorityUpgradeMeta("准备就绪", enhanced), diff --git a/ui/ui-status.js b/ui/ui-status.js index 06fff3d..24acc77 100644 --- a/ui/ui-status.js +++ b/ui/ui-status.js @@ -156,6 +156,12 @@ export function createGraphPersistenceState() { authorityMigrationLastError: "", lastAuthorityMigrationResult: null, authorityJobsReady: false, + authorityBmeProtocolVersion: 0, + authorityBmeVectorManifestReady: false, + authorityBmeVectorApplyReady: false, + authorityBmeVectorApplyJobsReady: false, + authorityBmeServerEmbeddingProbeReady: false, + authorityBmeCandidateSearchReady: false, authorityJobQueueState: "idle", authorityLastJob: null, authorityLastJobId: "",