noteconnection 1.7.0 → 1.8.0
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/LICENSE +674 -21
- package/README.md +242 -62
- package/dist/src/agent_workspace.contract.parity.test.js +475 -0
- package/dist/src/agent_workspace.frontend.test.js +9989 -0
- package/dist/src/agent_workspace.locale.contract.test.js +95 -0
- package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
- package/dist/src/copy.assets.contract.test.js +130 -0
- package/dist/src/core/PathBridge.js +28 -3
- package/dist/src/export/WorkspaceExportBundle.js +1130 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
- package/dist/src/export/index.js +18 -0
- package/dist/src/export/types.js +2 -0
- package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
- package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
- package/dist/src/foundation.release.evidence.contract.test.js +406 -0
- package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
- package/dist/src/frontend/README.md +242 -62
- package/dist/src/frontend/agent_workspace.js +5353 -0
- package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
- package/dist/src/frontend/analysis.js +31 -4
- package/dist/src/frontend/app.js +2178 -62
- package/dist/src/frontend/focus_mode_interactions.js +33 -0
- package/dist/src/frontend/godot_future_path_renderer.js +540 -0
- package/dist/src/frontend/godot_tree_interactions.js +178 -0
- package/dist/src/frontend/graph_state.mjs +105 -0
- package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
- package/dist/src/frontend/i18n.mjs +186 -0
- package/dist/src/frontend/index.html +641 -266
- package/dist/src/frontend/layout_gpu.js +12 -4
- package/dist/src/frontend/locales/en.json +721 -5
- package/dist/src/frontend/locales/zh.json +721 -5
- package/dist/src/frontend/main.mjs +60 -0
- package/dist/src/frontend/markdown_runtime.js +827 -0
- package/dist/src/frontend/notemd.css +49 -0
- package/dist/src/frontend/notemd.html +7 -1
- package/dist/src/frontend/notemd.js +64 -0
- package/dist/src/frontend/path.html +107 -0
- package/dist/src/frontend/path_app.js +2108 -130
- package/dist/src/frontend/path_layout.mjs +143 -0
- package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
- package/dist/src/frontend/path_modules_bridge.js +486 -0
- package/dist/src/frontend/path_state.mjs +118 -0
- package/dist/src/frontend/path_styles.css +146 -0
- package/dist/src/frontend/path_worker_bridge.mjs +85 -0
- package/dist/src/frontend/reader.js +393 -33
- package/dist/src/frontend/runtime_bridge.js +67 -54
- package/dist/src/frontend/runtime_bridge.mjs +279 -0
- package/dist/src/frontend/settings.js +130 -12
- package/dist/src/frontend/source_manager.js +190 -21
- package/dist/src/frontend/styles.css +2720 -72
- package/dist/src/frontend/workbench_state.mjs +101 -0
- package/dist/src/frontend/workspace_panes.js +10168 -0
- package/dist/src/frontend.locale.contract.test.js +62 -0
- package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
- package/dist/src/indexing/IndexLifecycle.js +195 -0
- package/dist/src/indexing/IndexLifecycle.test.js +49 -0
- package/dist/src/indexing/SegmentBuilder.js +64 -0
- package/dist/src/indexing/UnitBuilder.js +48 -0
- package/dist/src/indexing/types.js +2 -0
- package/dist/src/knowledge.api.contract.test.js +170 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
- package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
- package/dist/src/learning/answerReleaseReview.js +4319 -0
- package/dist/src/learning/answerReleaseReview.test.js +2888 -0
- package/dist/src/learning/api.js +2 -0
- package/dist/src/learning/conversationComposer.js +1480 -0
- package/dist/src/learning/conversationComposer.test.js +1817 -0
- package/dist/src/learning/domains/ConversationManager.js +53 -0
- package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
- package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
- package/dist/src/learning/domains/MasteryEngine.js +387 -0
- package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
- package/dist/src/learning/domains/QualityEvaluator.js +307 -0
- package/dist/src/learning/domains/TutorRouter.js +313 -0
- package/dist/src/learning/domains/index.js +33 -0
- package/dist/src/learning/domains/types.js +7 -0
- package/dist/src/learning/errors.js +29 -0
- package/dist/src/learning/evidenceContextAssembler.js +1176 -0
- package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
- package/dist/src/learning/graphContextAssembler.js +870 -0
- package/dist/src/learning/graphContextAssembler.test.js +1033 -0
- package/dist/src/learning/index.js +28 -0
- package/dist/src/learning/queryBackend.js +1898 -0
- package/dist/src/learning/queryBackend.test.js +955 -0
- package/dist/src/learning/ragContextPack.js +257 -0
- package/dist/src/learning/ragContextPack.test.js +160 -0
- package/dist/src/learning/ragPublicText.js +38 -0
- package/dist/src/learning/ragSufficiencyJudge.js +161 -0
- package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
- package/dist/src/learning/requestNormalization.js +198 -0
- package/dist/src/learning/runtimeCapability.js +4677 -0
- package/dist/src/learning/runtimeCapability.test.js +3635 -0
- package/dist/src/learning/store.js +1240 -0
- package/dist/src/learning/store.test.js +1126 -0
- package/dist/src/learning/tutorAdapter.js +2 -0
- package/dist/src/learning/types.js +2 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
- package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
- package/dist/src/lfs.asset.policy.contract.test.js +153 -0
- package/dist/src/license.policy.contract.test.js +66 -0
- package/dist/src/memory/MemoryGovernance.js +74 -0
- package/dist/src/memory/MemoryGovernance.test.js +46 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
- package/dist/src/middleware/auth.js +17 -0
- package/dist/src/middleware/body-parser.js +45 -0
- package/dist/src/middleware/cors.js +44 -0
- package/dist/src/middleware/index.js +21 -0
- package/dist/src/middleware/request-trace.js +96 -0
- package/dist/src/notemd/AppConfigToml.js +6 -4
- package/dist/src/notemd/MermaidProcessor.js +400 -50
- package/dist/src/notemd/NotemdService.js +498 -13
- package/dist/src/notemd/PromptManager.js +15 -0
- package/dist/src/notemd/cli/commands.js +357 -0
- package/dist/src/notemd/cli/dispatcher.js +225 -0
- package/dist/src/notemd/cli/index.js +169 -0
- package/dist/src/notemd/cli/parser.js +68 -0
- package/dist/src/notemd/cli/types.js +2 -0
- package/dist/src/notemd/constants.js +43 -0
- package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
- package/dist/src/notemd/diagram/diagramSpec.js +79 -0
- package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
- package/dist/src/notemd/diagram/intent.js +95 -0
- package/dist/src/notemd/diagram/planner.js +71 -0
- package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
- package/dist/src/notemd/diagram/types.js +18 -0
- package/dist/src/notemd/index.js +26 -0
- package/dist/src/notemd/operations/capabilityManifest.js +23 -0
- package/dist/src/notemd/operations/cliContracts.js +17 -0
- package/dist/src/notemd/operations/configProfileCommands.js +85 -0
- package/dist/src/notemd/operations/registry.contract.test.js +95 -0
- package/dist/src/notemd/operations/registry.js +991 -0
- package/dist/src/notemd/operations/types.js +2 -0
- package/dist/src/notemd/providerDiagnostics.js +220 -0
- package/dist/src/notemd/providerProfiles.js +42 -0
- package/dist/src/notemd/providerTemplates.js +231 -0
- package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
- package/dist/src/notemd/search/SearchManager.js +13 -0
- package/dist/src/notemd/search/SearchProvider.js +2 -0
- package/dist/src/notemd/search/TavilyProvider.js +44 -0
- package/dist/src/notemd.agent.manifest.test.js +85 -0
- package/dist/src/notemd.api.contract.test.js +14 -1
- package/dist/src/notemd.app_config_toml.test.js +2 -1
- package/dist/src/notemd.batch.workflow.test.js +117 -0
- package/dist/src/notemd.cli.e2e.test.js +136 -0
- package/dist/src/notemd.core.test.js +51 -0
- package/dist/src/notemd.diagram.pipeline.test.js +233 -0
- package/dist/src/notemd.providerTemplates.test.js +34 -0
- package/dist/src/notemd.server.integration.test.js +143 -35
- package/dist/src/notemd.workflow.pipeline.test.js +162 -0
- package/dist/src/pathbridge.handshake.contract.test.js +16 -2
- package/dist/src/pathmode.background.contract.test.js +69 -0
- package/dist/src/pathmode.settings.api.contract.test.js +9 -0
- package/dist/src/pkg.sidecar.contract.test.js +9 -3
- package/dist/src/platform/ExportProfile.js +58 -0
- package/dist/src/platform/PlatformCapabilities.js +45 -0
- package/dist/src/platform/PlatformCapabilities.test.js +30 -0
- package/dist/src/platform/RenderMaterializer.js +33 -0
- package/dist/src/platform/RenderMaterializer.test.js +32 -0
- package/dist/src/query_backend.external_http.integration.test.js +410 -0
- package/dist/src/reader_renderer.js +404 -3
- package/dist/src/reader_renderer.test.js +87 -0
- package/dist/src/release.godot.mirror.contract.test.js +73 -0
- package/dist/src/resources/ResourceRegistry.js +223 -0
- package/dist/src/resources/ResourceRegistry.test.js +61 -0
- package/dist/src/resources/types.js +2 -0
- package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
- package/dist/src/routes/data.js +267 -0
- package/dist/src/routes/diagnostics.js +51 -0
- package/dist/src/routes/index.js +23 -0
- package/dist/src/routes/knowledge.js +968 -0
- package/dist/src/routes/markdown.js +287 -0
- package/dist/src/routes/notemd.js +565 -0
- package/dist/src/routes/registry.contract.test.js +130 -0
- package/dist/src/routes/render.js +285 -0
- package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
- package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
- package/dist/src/routes/settings.js +6 -0
- package/dist/src/routes/staticFiles.js +94 -0
- package/dist/src/routes/types.js +2 -0
- package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
- package/dist/src/server.js +11090 -1549
- package/dist/src/server.migration.test.js +193 -21
- package/dist/src/server.port.fallback.contract.test.js +63 -0
- package/dist/src/session/SessionStateStore.js +81 -0
- package/dist/src/session/SessionStateStore.test.js +58 -0
- package/dist/src/session/types.js +2 -0
- package/dist/src/settings.runtime.contract.test.js +50 -0
- package/dist/src/shared/types.contract.test.js +107 -0
- package/dist/src/shared/types.js +22 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
- package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
- package/dist/src/source_manager.loadflow.test.js +46 -0
- package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
- package/dist/src/tauri.frontend.build.contract.test.js +60 -0
- package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
- package/dist/src/utils/RuntimePaths.js +4 -13
- package/dist/src/utils/platform.js +153 -0
- package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
- package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
- package/dist/src/workflows/types.js +2 -0
- package/dist/src/workspace/WorkspaceRegistry.js +122 -0
- package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
- package/dist/src/workspace/types.js +2 -0
- package/package.json +53 -10
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConversationManager = void 0;
|
|
4
|
+
class ConversationManager {
|
|
5
|
+
constructor(platform) {
|
|
6
|
+
this.platform = platform;
|
|
7
|
+
this.turnCount = 0;
|
|
8
|
+
this.totalResponseLatencyMs = 0;
|
|
9
|
+
this.memoryOpCounts = { add: 0, list: 0, search: 0, delete: 0, feedback: 0 };
|
|
10
|
+
this.lastConversationAt = null;
|
|
11
|
+
}
|
|
12
|
+
async runAgentConversation(request) {
|
|
13
|
+
this.validateConversationRequest(request);
|
|
14
|
+
const startMs = Date.now();
|
|
15
|
+
const response = await this.platform.runAgentConversation(request);
|
|
16
|
+
this.turnCount++;
|
|
17
|
+
this.totalResponseLatencyMs += Date.now() - startMs;
|
|
18
|
+
this.lastConversationAt = new Date().toISOString();
|
|
19
|
+
return this.augmentConversationResponse(response, Date.now() - startMs);
|
|
20
|
+
}
|
|
21
|
+
async addMemory(r) { this.validateMemoryRequest(r, 'add'); this.memoryOpCounts.add++; return this.platform.addConversationMemory(r); }
|
|
22
|
+
async listMemory(r) { this.memoryOpCounts.list++; return this.platform.listConversationMemory(r); }
|
|
23
|
+
async searchMemory(r) { this.memoryOpCounts.search++; return this.platform.searchConversationMemory(r); }
|
|
24
|
+
async deleteMemory(r) { this.memoryOpCounts.delete++; return this.platform.deleteConversationMemory(r); }
|
|
25
|
+
async feedbackMemory(r) { this.memoryOpCounts.feedback++; return this.platform.feedbackConversationMemory(r); }
|
|
26
|
+
getTurnCount() { return this.turnCount; }
|
|
27
|
+
averageResponseLatencyMs() { return this.turnCount === 0 ? 0 : Math.round(this.totalResponseLatencyMs / this.turnCount); }
|
|
28
|
+
getDiagnosticsSummary() {
|
|
29
|
+
return { turnCount: this.turnCount, averageResponseLatencyMs: this.averageResponseLatencyMs(), lastConversationAt: this.lastConversationAt, memoryOperations: { ...this.memoryOpCounts }, totalMemoryOps: Object.values(this.memoryOpCounts).reduce((a, b) => a + b, 0) };
|
|
30
|
+
}
|
|
31
|
+
validateConversationRequest(r) {
|
|
32
|
+
if (!r)
|
|
33
|
+
throw new Error('Conversation request is required.');
|
|
34
|
+
const query = String(r?.query ?? '').trim();
|
|
35
|
+
if (!query)
|
|
36
|
+
throw new Error('Conversation query must not be empty.');
|
|
37
|
+
if (query.length > 10000)
|
|
38
|
+
throw new Error('Conversation query exceeds maximum length.');
|
|
39
|
+
}
|
|
40
|
+
validateMemoryRequest(r, op) {
|
|
41
|
+
if (!r)
|
|
42
|
+
throw new Error(`Memory ${op} request is required.`);
|
|
43
|
+
if (op === 'add' || op === 'search') {
|
|
44
|
+
const content = String(r?.content ?? r?.query ?? '').trim();
|
|
45
|
+
if (!content)
|
|
46
|
+
throw new Error(`Memory ${op} requires non-empty content.`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
augmentConversationResponse(response, latencyMs) {
|
|
50
|
+
return { ...response, _domain: { turnNumber: this.turnCount, latencyMs: Math.round(latencyMs), memoryOps: this.memoryOpCounts, generatedAt: this.lastConversationAt } };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.ConversationManager = ConversationManager;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* KnowledgeIngestor domain — L0/L1: Document parsing, atom/evidence extraction,
|
|
4
|
+
* staleness diagnostics, guardrail evaluation. Adds domain-specific value:
|
|
5
|
+
* latency tracking, staleness caching, guardrail history.
|
|
6
|
+
* Note: full type imports pending M8-M10 type stabilization in ../types.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.KnowledgeIngestor = void 0;
|
|
10
|
+
class KnowledgeIngestor {
|
|
11
|
+
constructor(platform) {
|
|
12
|
+
this.platform = platform;
|
|
13
|
+
this.ingestLatencyHistoryMs = [];
|
|
14
|
+
this.recomputeLatencyHistoryMs = [];
|
|
15
|
+
this.latestIngestSummary = null;
|
|
16
|
+
this.stalenessCache = new Map();
|
|
17
|
+
this.stalenessQueryCount = 0;
|
|
18
|
+
this.stalenessSnapshots = [];
|
|
19
|
+
this.guardrailEvaluationHistory = [];
|
|
20
|
+
}
|
|
21
|
+
async ingestKnowledge(request) {
|
|
22
|
+
const startMs = Date.now();
|
|
23
|
+
const response = await this.platform.ingestKnowledge(request);
|
|
24
|
+
this.ingestLatencyHistoryMs.push(Date.now() - startMs);
|
|
25
|
+
if (this.ingestLatencyHistoryMs.length > 200)
|
|
26
|
+
this.ingestLatencyHistoryMs.shift();
|
|
27
|
+
if (response?.summary)
|
|
28
|
+
this.latestIngestSummary = response.summary;
|
|
29
|
+
this.stalenessCache.clear();
|
|
30
|
+
return response;
|
|
31
|
+
}
|
|
32
|
+
async queryStalenessDiagnostics(request, options) {
|
|
33
|
+
this.stalenessQueryCount++;
|
|
34
|
+
const cacheKey = this.buildStalenessCacheKey(request);
|
|
35
|
+
// Always serve cached results when available (cache is invalidated on new ingest)
|
|
36
|
+
const cached = !options?.skipCache ? this.stalenessCache.get(cacheKey) : undefined;
|
|
37
|
+
if (cached)
|
|
38
|
+
return cached.response;
|
|
39
|
+
const response = await this.platform.queryKnowledgeStalenessDiagnostics(request);
|
|
40
|
+
const generatedAt = new Date().toISOString();
|
|
41
|
+
// Domain-level staleness analysis
|
|
42
|
+
const domainAnalysis = this.buildStalenessAnalysis(response);
|
|
43
|
+
const augmented = { ...response, _domain: { stalenessAnalysis: domainAnalysis, generatedAt, queriedAt: generatedAt } };
|
|
44
|
+
this.stalenessCache.set(cacheKey, { response: augmented, generatedAt, sourceHash: cacheKey });
|
|
45
|
+
if (this.stalenessCache.size > 50) {
|
|
46
|
+
const firstKey = this.stalenessCache.keys().next().value;
|
|
47
|
+
if (firstKey)
|
|
48
|
+
this.stalenessCache.delete(firstKey);
|
|
49
|
+
}
|
|
50
|
+
// Track staleness trend for governance
|
|
51
|
+
this.recordStalenessSnapshot(domainAnalysis);
|
|
52
|
+
return augmented;
|
|
53
|
+
}
|
|
54
|
+
async rebuildFromStalenessDiagnostics(request) {
|
|
55
|
+
const startMs = Date.now();
|
|
56
|
+
const response = await this.platform.rebuildKnowledgeFromStalenessDiagnostics(request);
|
|
57
|
+
this.recomputeLatencyHistoryMs.push(Date.now() - startMs);
|
|
58
|
+
if (this.recomputeLatencyHistoryMs.length > 200)
|
|
59
|
+
this.recomputeLatencyHistoryMs.shift();
|
|
60
|
+
this.stalenessCache.clear();
|
|
61
|
+
return response;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Evaluate ingest guardrails with domain-level gate logic.
|
|
65
|
+
* Augments the platform response with independent gate validation
|
|
66
|
+
* and maintains a pass-rate history for governance dashboards.
|
|
67
|
+
*/
|
|
68
|
+
async evaluateGuardrails(request) {
|
|
69
|
+
const response = await this.platform.evaluateIngestGuardrails(request);
|
|
70
|
+
// Domain-level gate validation (independent of platform)
|
|
71
|
+
const domainGates = this.buildDomainGuardrailGates(request, response);
|
|
72
|
+
const allPassed = domainGates.every((g) => g.passed);
|
|
73
|
+
this.guardrailEvaluationHistory.push({
|
|
74
|
+
passed: allPassed,
|
|
75
|
+
timestamp: new Date().toISOString(),
|
|
76
|
+
});
|
|
77
|
+
if (this.guardrailEvaluationHistory.length > 200) {
|
|
78
|
+
this.guardrailEvaluationHistory.shift();
|
|
79
|
+
}
|
|
80
|
+
// Augment response with domain-level gate telemetry
|
|
81
|
+
return {
|
|
82
|
+
...response,
|
|
83
|
+
domainGates,
|
|
84
|
+
domainOverallPassed: allPassed,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
getLatestIngestSummary() { return this.latestIngestSummary; }
|
|
88
|
+
getIngestLatencyHistory() { return [...this.ingestLatencyHistoryMs]; }
|
|
89
|
+
getRecomputeLatencyHistory() { return [...this.recomputeLatencyHistoryMs]; }
|
|
90
|
+
averageIngestLatencyMs(n = 20) {
|
|
91
|
+
const w = this.ingestLatencyHistoryMs.slice(-n);
|
|
92
|
+
return w.length === 0 ? 0 : w.reduce((a, b) => a + b, 0) / w.length;
|
|
93
|
+
}
|
|
94
|
+
averageRecomputeLatencyMs(n = 20) {
|
|
95
|
+
const w = this.recomputeLatencyHistoryMs.slice(-n);
|
|
96
|
+
return w.length === 0 ? 0 : w.reduce((a, b) => a + b, 0) / w.length;
|
|
97
|
+
}
|
|
98
|
+
getStalenessQueryCount() { return this.stalenessQueryCount; }
|
|
99
|
+
getGuardrailPassRate() {
|
|
100
|
+
if (this.guardrailEvaluationHistory.length === 0)
|
|
101
|
+
return 1;
|
|
102
|
+
return this.guardrailEvaluationHistory.filter(e => e.passed).length / this.guardrailEvaluationHistory.length;
|
|
103
|
+
}
|
|
104
|
+
invalidateStalenessCache() { this.stalenessCache.clear(); }
|
|
105
|
+
getDiagnostics() {
|
|
106
|
+
return {
|
|
107
|
+
ingestCount: this.ingestLatencyHistoryMs.length,
|
|
108
|
+
averageIngestLatencyMs: this.averageIngestLatencyMs(20),
|
|
109
|
+
recomputeCount: this.recomputeLatencyHistoryMs.length,
|
|
110
|
+
averageRecomputeLatencyMs: this.averageRecomputeLatencyMs(20),
|
|
111
|
+
stalenessQueryCount: this.stalenessQueryCount,
|
|
112
|
+
stalenessCacheSize: this.stalenessCache.size,
|
|
113
|
+
stalenessSnapshots: this.stalenessSnapshots.length,
|
|
114
|
+
freshnessTrend: this.getFreshnessTrend(10),
|
|
115
|
+
guardrailEvaluationCount: this.guardrailEvaluationHistory.length,
|
|
116
|
+
guardrailPassRate: Number((this.getGuardrailPassRate() * 100).toFixed(1)),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build domain-level guardrail gates using ingest telemetry.
|
|
121
|
+
* These gates run independently of the platform's gate evaluation,
|
|
122
|
+
* providing a second layer of governance verification.
|
|
123
|
+
*/
|
|
124
|
+
buildDomainGuardrailGates(request, platformResponse) {
|
|
125
|
+
const summary = this.latestIngestSummary || {};
|
|
126
|
+
const changedDocs = summary.changedDocuments ?? 0;
|
|
127
|
+
const deletedDocs = summary.deletedDocuments ?? 0;
|
|
128
|
+
const avgLatency = this.averageIngestLatencyMs(20);
|
|
129
|
+
return [
|
|
130
|
+
{
|
|
131
|
+
gateId: 'domain:changed_docs',
|
|
132
|
+
passed: changedDocs <= 500,
|
|
133
|
+
observedValue: changedDocs,
|
|
134
|
+
threshold: 500,
|
|
135
|
+
message: 'Changed document count within domain budget.',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
gateId: 'domain:deleted_docs',
|
|
139
|
+
passed: deletedDocs <= 100,
|
|
140
|
+
observedValue: deletedDocs,
|
|
141
|
+
threshold: 100,
|
|
142
|
+
message: 'Deleted document count within rollback-safe budget.',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
gateId: 'domain:avg_latency_ms',
|
|
146
|
+
passed: avgLatency <= 30000,
|
|
147
|
+
observedValue: Math.round(avgLatency),
|
|
148
|
+
threshold: 30000,
|
|
149
|
+
message: 'Average ingest latency within performance budget.',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
gateId: 'domain:history_available',
|
|
153
|
+
passed: this.ingestLatencyHistoryMs.length >= 3,
|
|
154
|
+
observedValue: this.ingestLatencyHistoryMs.length,
|
|
155
|
+
threshold: 3,
|
|
156
|
+
message: 'Sufficient ingest history for statistical significance.',
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Build domain-level staleness analysis from platform response.
|
|
162
|
+
* Categorizes documents by staleness status and computes a freshness score.
|
|
163
|
+
*/
|
|
164
|
+
buildStalenessAnalysis(response) {
|
|
165
|
+
const records = Array.isArray(response?.records) ? response.records : [];
|
|
166
|
+
const counters = { up_to_date: 0, hash_mismatch: 0, missing_source: 0, read_error: 0 };
|
|
167
|
+
const staleBySource = new Map();
|
|
168
|
+
let totalDocuments = 0;
|
|
169
|
+
for (const record of records) {
|
|
170
|
+
counters[record.status] = (counters[record.status] || 0) + 1;
|
|
171
|
+
totalDocuments++;
|
|
172
|
+
if (record.status !== 'up_to_date' && record.sourcePath) {
|
|
173
|
+
const dir = String(record.sourcePath).split(/[/\\]/)[0] || 'root';
|
|
174
|
+
staleBySource.set(dir, (staleBySource.get(dir) || 0) + 1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const staleCount = counters.hash_mismatch + counters.missing_source + counters.read_error;
|
|
178
|
+
const freshnessScore = totalDocuments > 0
|
|
179
|
+
? Number(((counters.up_to_date / totalDocuments) * 100).toFixed(1))
|
|
180
|
+
: 100;
|
|
181
|
+
return {
|
|
182
|
+
freshnessScore,
|
|
183
|
+
freshCount: counters.up_to_date,
|
|
184
|
+
staleCount,
|
|
185
|
+
hashMismatchCount: counters.hash_mismatch,
|
|
186
|
+
missingSourceCount: counters.missing_source,
|
|
187
|
+
readErrorCount: counters.read_error,
|
|
188
|
+
totalDocuments,
|
|
189
|
+
staleBySource: Object.fromEntries(staleBySource),
|
|
190
|
+
freshnessRating: freshnessScore >= 95 ? 'excellent' : freshnessScore >= 80 ? 'good' : freshnessScore >= 60 ? 'fair' : 'poor',
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Record a staleness snapshot for trend computation.
|
|
195
|
+
* Keeps the last 100 snapshots for governance dashboards.
|
|
196
|
+
*/
|
|
197
|
+
recordStalenessSnapshot(analysis) {
|
|
198
|
+
this.stalenessSnapshots.push({
|
|
199
|
+
generatedAt: new Date().toISOString(),
|
|
200
|
+
freshCount: analysis.freshCount,
|
|
201
|
+
staleCount: analysis.staleCount,
|
|
202
|
+
hashMismatchCount: analysis.hashMismatchCount,
|
|
203
|
+
freshnessScore: analysis.freshnessScore,
|
|
204
|
+
});
|
|
205
|
+
if (this.stalenessSnapshots.length > 100) {
|
|
206
|
+
this.stalenessSnapshots.shift();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Compute the freshness trend over the last N snapshots.
|
|
211
|
+
* Returns trend direction: 'stable', 'improving', or 'regressing'.
|
|
212
|
+
*/
|
|
213
|
+
getFreshnessTrend(n = 10) {
|
|
214
|
+
const window = this.stalenessSnapshots.slice(-n);
|
|
215
|
+
if (window.length < 2)
|
|
216
|
+
return { direction: 'stable', recentScore: window[0]?.freshnessScore ?? 100, windowAverage: window[0]?.freshnessScore ?? 100, snapshots: window.length };
|
|
217
|
+
const recentScore = window[window.length - 1].freshnessScore;
|
|
218
|
+
const windowAverage = Number((window.reduce((s, e) => s + e.freshnessScore, 0) / window.length).toFixed(1));
|
|
219
|
+
// Compare recent half vs earlier half
|
|
220
|
+
const mid = Math.floor(window.length / 2);
|
|
221
|
+
const recentHalf = window.slice(-mid);
|
|
222
|
+
const earlierHalf = window.slice(0, mid);
|
|
223
|
+
const recentAvg = recentHalf.reduce((s, e) => s + e.freshnessScore, 0) / recentHalf.length;
|
|
224
|
+
const earlierAvg = earlierHalf.reduce((s, e) => s + e.freshnessScore, 0) / earlierHalf.length;
|
|
225
|
+
const delta = recentAvg - earlierAvg;
|
|
226
|
+
return {
|
|
227
|
+
direction: delta > 2 ? 'improving' : delta < -2 ? 'regressing' : 'stable',
|
|
228
|
+
recentScore,
|
|
229
|
+
windowAverage,
|
|
230
|
+
snapshots: window.length,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
getStalenessSnapshots() { return [...this.stalenessSnapshots]; }
|
|
234
|
+
buildStalenessCacheKey(request) {
|
|
235
|
+
return [request?.limit ?? 24, request?.sourcePathPrefix ?? '', Array.isArray(request?.statuses) ? request.statuses.join(',') : ''].join('|');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
exports.KnowledgeIngestor = KnowledgeIngestor;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* KnowledgeQuerier domain — L2: Evidence-first explainable retrieval.
|
|
4
|
+
* Query backends, comparison, configuration, diagnostics.
|
|
5
|
+
* Note: types pending M8-M10 stabilization; using any for now.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.KnowledgeQuerier = void 0;
|
|
9
|
+
class KnowledgeQuerier {
|
|
10
|
+
constructor(platform, options) {
|
|
11
|
+
this.platform = platform;
|
|
12
|
+
this.queryLatencyHistoryMs = [];
|
|
13
|
+
this.queryBackendFallbackCount = 0;
|
|
14
|
+
this.lastQueryAt = null;
|
|
15
|
+
this.queryCache = new Map();
|
|
16
|
+
this.cacheHits = 0;
|
|
17
|
+
this.cacheMisses = 0;
|
|
18
|
+
this.comparisonCount = 0;
|
|
19
|
+
this.queryPatternCounts = new Map();
|
|
20
|
+
this.slowQueryCount = 0;
|
|
21
|
+
this.cacheTtlMs = options?.cacheTtlMs ?? 60000;
|
|
22
|
+
}
|
|
23
|
+
async queryKnowledge(request, options) {
|
|
24
|
+
this.lastQueryAt = new Date().toISOString();
|
|
25
|
+
const cacheKey = this.buildCacheKey(request);
|
|
26
|
+
const cached = !options?.skipCache ? this.queryCache.get(cacheKey) : undefined;
|
|
27
|
+
if (cached && (Date.now() - new Date(cached.cachedAt).getTime()) < cached.ttlMs) {
|
|
28
|
+
this.cacheHits++;
|
|
29
|
+
return cached.response;
|
|
30
|
+
}
|
|
31
|
+
// Domain-level query validation
|
|
32
|
+
this.validateQueryRequest(request);
|
|
33
|
+
this.cacheMisses++;
|
|
34
|
+
const startMs = Date.now();
|
|
35
|
+
try {
|
|
36
|
+
const response = await this.platform.queryKnowledge(request);
|
|
37
|
+
const latencyMs = Date.now() - startMs;
|
|
38
|
+
this.recordLatency(latencyMs);
|
|
39
|
+
this.queryCache.set(cacheKey, { response, cachedAt: new Date().toISOString(), ttlMs: this.cacheTtlMs });
|
|
40
|
+
this.pruneCache();
|
|
41
|
+
// Track query pattern for analytics
|
|
42
|
+
this.trackQueryPattern(String(request?.query ?? '').toLowerCase());
|
|
43
|
+
// Augment response with domain-level telemetry
|
|
44
|
+
return this.augmentQueryResponse(response, latencyMs, request);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
this.queryBackendFallbackCount++;
|
|
48
|
+
this.queryBackendLastError = String(error);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async compareBackends(request) { this.comparisonCount++; return this.platform.compareQueryBackends(request); }
|
|
53
|
+
async queryComparisonHistory(request) { return this.platform.queryKnowledgeQueryBackendComparisonHistory(request); }
|
|
54
|
+
async queryComparisonTrend(request) { return this.platform.queryKnowledgeQueryBackendComparisonTrend(request); }
|
|
55
|
+
getConfig() { return this.platform.getQueryBackendConfig(); }
|
|
56
|
+
async updateConfig(request) {
|
|
57
|
+
const response = await this.platform.updateQueryBackendConfig(request);
|
|
58
|
+
this.invalidateCache();
|
|
59
|
+
return response;
|
|
60
|
+
}
|
|
61
|
+
getDiagnostics() { return this.platform.getQueryBackendDiagnostics(); }
|
|
62
|
+
invalidateCache() { this.queryCache.clear(); }
|
|
63
|
+
getQueryLatencyHistory() { return [...this.queryLatencyHistoryMs]; }
|
|
64
|
+
getFallbackCount() { return this.queryBackendFallbackCount; }
|
|
65
|
+
getLastError() { return this.queryBackendLastError; }
|
|
66
|
+
averageQueryLatencyMs(n = 20) {
|
|
67
|
+
const w = this.queryLatencyHistoryMs.slice(-n);
|
|
68
|
+
if (w.length === 0)
|
|
69
|
+
return 0;
|
|
70
|
+
return w.reduce((a, b) => a + b, 0) / w.length;
|
|
71
|
+
}
|
|
72
|
+
queryLatencyP95(n = 50) {
|
|
73
|
+
const w = [...this.queryLatencyHistoryMs.slice(-n)].sort((a, b) => a - b);
|
|
74
|
+
if (w.length === 0)
|
|
75
|
+
return 0;
|
|
76
|
+
return w[Math.ceil(w.length * 0.95) - 1];
|
|
77
|
+
}
|
|
78
|
+
getCacheHitRate() {
|
|
79
|
+
const total = this.cacheHits + this.cacheMisses;
|
|
80
|
+
return total === 0 ? 0 : this.cacheHits / total;
|
|
81
|
+
}
|
|
82
|
+
getDiagnosticsSummary() {
|
|
83
|
+
const topQueries = [...this.queryPatternCounts.entries()]
|
|
84
|
+
.sort((a, b) => b[1] - a[1])
|
|
85
|
+
.slice(0, 10)
|
|
86
|
+
.map(([term, count]) => ({ term, count }));
|
|
87
|
+
return {
|
|
88
|
+
queryCount: this.queryLatencyHistoryMs.length,
|
|
89
|
+
averageLatencyMs: this.averageQueryLatencyMs(20),
|
|
90
|
+
latencyP95Ms: this.queryLatencyP95(50),
|
|
91
|
+
latencyP99Ms: this.queryLatencyP99(100),
|
|
92
|
+
fallbackCount: this.queryBackendFallbackCount,
|
|
93
|
+
lastError: this.queryBackendLastError ?? null,
|
|
94
|
+
lastQueryAt: this.lastQueryAt,
|
|
95
|
+
cacheSize: this.queryCache.size,
|
|
96
|
+
cacheHitRate: Number((this.getCacheHitRate() * 100).toFixed(1)),
|
|
97
|
+
comparisonCount: this.comparisonCount,
|
|
98
|
+
slowQueryCount: this.slowQueryCount,
|
|
99
|
+
uniqueQueryTerms: this.queryPatternCounts.size,
|
|
100
|
+
topQueryTerms: topQueries,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
queryLatencyP99(n = 100) {
|
|
104
|
+
const w = [...this.queryLatencyHistoryMs.slice(-n)].sort((a, b) => a - b);
|
|
105
|
+
if (w.length === 0)
|
|
106
|
+
return 0;
|
|
107
|
+
return w[Math.ceil(w.length * 0.99) - 1];
|
|
108
|
+
}
|
|
109
|
+
recordLatency(ms) {
|
|
110
|
+
this.queryLatencyHistoryMs.push(ms);
|
|
111
|
+
if (this.queryLatencyHistoryMs.length > 500)
|
|
112
|
+
this.queryLatencyHistoryMs.shift();
|
|
113
|
+
}
|
|
114
|
+
/** Track query term frequency for pattern analysis. */
|
|
115
|
+
trackQueryPattern(query) {
|
|
116
|
+
if (!query)
|
|
117
|
+
return;
|
|
118
|
+
const terms = query.split(/\s+/).filter(t => t.length > 2);
|
|
119
|
+
for (const term of terms) {
|
|
120
|
+
this.queryPatternCounts.set(term, (this.queryPatternCounts.get(term) || 0) + 1);
|
|
121
|
+
}
|
|
122
|
+
// Prune to top 200 terms
|
|
123
|
+
if (this.queryPatternCounts.size > 200) {
|
|
124
|
+
const sorted = [...this.queryPatternCounts.entries()].sort((a, b) => b[1] - a[1]);
|
|
125
|
+
this.queryPatternCounts = new Map(sorted.slice(0, 150));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Mark a query as slow (exceeds latency threshold). */
|
|
129
|
+
markSlowQuery(latencyMs) {
|
|
130
|
+
const p95 = this.queryLatencyP95(50);
|
|
131
|
+
if (p95 > 0 && latencyMs > p95 * 2) {
|
|
132
|
+
this.slowQueryCount++;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
buildCacheKey(request) {
|
|
136
|
+
return [request.query ?? '', String(request.topK ?? 10), request.queryBackend ?? 'default', request.asOf ?? ''].join('|');
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Domain-level query validation: ensure the request meets minimum
|
|
140
|
+
* quality standards before dispatching to the platform.
|
|
141
|
+
*/
|
|
142
|
+
validateQueryRequest(request) {
|
|
143
|
+
if (!request) {
|
|
144
|
+
throw new Error('Query request is required.');
|
|
145
|
+
}
|
|
146
|
+
const query = String(request.query ?? '').trim();
|
|
147
|
+
if (!query) {
|
|
148
|
+
throw new Error('Query string must not be empty.');
|
|
149
|
+
}
|
|
150
|
+
if (query.length > 5000) {
|
|
151
|
+
throw new Error('Query string exceeds maximum length (5000 chars).');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Augment the platform response with domain-level telemetry:
|
|
156
|
+
* query latency, cache status, backend identity, and result metadata.
|
|
157
|
+
*/
|
|
158
|
+
augmentQueryResponse(response, latencyMs, request) {
|
|
159
|
+
const items = Array.isArray(response?.items) ? response.items : [];
|
|
160
|
+
return {
|
|
161
|
+
...response,
|
|
162
|
+
_domain: {
|
|
163
|
+
latencyMs: Math.round(latencyMs),
|
|
164
|
+
cacheHit: false,
|
|
165
|
+
cacheSize: this.queryCache.size,
|
|
166
|
+
backend: request?.queryBackend ?? 'default',
|
|
167
|
+
resultCount: items.length,
|
|
168
|
+
topScore: items.length > 0 ? items[0]?.score ?? null : null,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
pruneCache() {
|
|
173
|
+
if (this.queryCache.size <= 200)
|
|
174
|
+
return;
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
for (const [key, entry] of this.queryCache) {
|
|
177
|
+
if ((now - new Date(entry.cachedAt).getTime()) > entry.ttlMs * 2)
|
|
178
|
+
this.queryCache.delete(key);
|
|
179
|
+
}
|
|
180
|
+
if (this.queryCache.size > 200) {
|
|
181
|
+
const firstKey = this.queryCache.keys().next().value;
|
|
182
|
+
if (firstKey)
|
|
183
|
+
this.queryCache.delete(firstKey);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
exports.KnowledgeQuerier = KnowledgeQuerier;
|