ai-memory-layer 2.0.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/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +765 -0
- package/bin/memory-server.mjs +157 -0
- package/dist/adapters/memory/embeddings.d.ts +4 -0
- package/dist/adapters/memory/embeddings.d.ts.map +1 -0
- package/dist/adapters/memory/embeddings.js +53 -0
- package/dist/adapters/memory/embeddings.js.map +1 -0
- package/dist/adapters/memory/index.d.ts +7 -0
- package/dist/adapters/memory/index.d.ts.map +1 -0
- package/dist/adapters/memory/index.js +650 -0
- package/dist/adapters/memory/index.js.map +1 -0
- package/dist/adapters/postgres/index.d.ts +38 -0
- package/dist/adapters/postgres/index.d.ts.map +1 -0
- package/dist/adapters/postgres/index.js +982 -0
- package/dist/adapters/postgres/index.js.map +1 -0
- package/dist/adapters/sqlite/embeddings.d.ts +5 -0
- package/dist/adapters/sqlite/embeddings.d.ts.map +1 -0
- package/dist/adapters/sqlite/embeddings.js +122 -0
- package/dist/adapters/sqlite/embeddings.js.map +1 -0
- package/dist/adapters/sqlite/index.d.ts +8 -0
- package/dist/adapters/sqlite/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/index.js +839 -0
- package/dist/adapters/sqlite/index.js.map +1 -0
- package/dist/adapters/sqlite/mappers.d.ts +40 -0
- package/dist/adapters/sqlite/mappers.d.ts.map +1 -0
- package/dist/adapters/sqlite/mappers.js +95 -0
- package/dist/adapters/sqlite/mappers.js.map +1 -0
- package/dist/adapters/sqlite/schema.d.ts +4 -0
- package/dist/adapters/sqlite/schema.d.ts.map +1 -0
- package/dist/adapters/sqlite/schema.js +394 -0
- package/dist/adapters/sqlite/schema.js.map +1 -0
- package/dist/adapters/sync-to-async.d.ts +15 -0
- package/dist/adapters/sync-to-async.d.ts.map +1 -0
- package/dist/adapters/sync-to-async.js +95 -0
- package/dist/adapters/sync-to-async.js.map +1 -0
- package/dist/cli/inspect.d.ts +34 -0
- package/dist/cli/inspect.d.ts.map +1 -0
- package/dist/cli/inspect.js +190 -0
- package/dist/cli/inspect.js.map +1 -0
- package/dist/contracts/async-storage.d.ts +86 -0
- package/dist/contracts/async-storage.d.ts.map +1 -0
- package/dist/contracts/async-storage.js +2 -0
- package/dist/contracts/async-storage.js.map +1 -0
- package/dist/contracts/embedding.d.ts +22 -0
- package/dist/contracts/embedding.d.ts.map +1 -0
- package/dist/contracts/embedding.js +2 -0
- package/dist/contracts/embedding.js.map +1 -0
- package/dist/contracts/identity.d.ts +29 -0
- package/dist/contracts/identity.d.ts.map +1 -0
- package/dist/contracts/identity.js +34 -0
- package/dist/contracts/identity.js.map +1 -0
- package/dist/contracts/observability.d.ts +18 -0
- package/dist/contracts/observability.d.ts.map +1 -0
- package/dist/contracts/observability.js +7 -0
- package/dist/contracts/observability.js.map +1 -0
- package/dist/contracts/policy.d.ts +108 -0
- package/dist/contracts/policy.d.ts.map +1 -0
- package/dist/contracts/policy.js +107 -0
- package/dist/contracts/policy.js.map +1 -0
- package/dist/contracts/storage.d.ts +78 -0
- package/dist/contracts/storage.d.ts.map +1 -0
- package/dist/contracts/storage.js +2 -0
- package/dist/contracts/storage.js.map +1 -0
- package/dist/contracts/types.d.ts +381 -0
- package/dist/contracts/types.d.ts.map +1 -0
- package/dist/contracts/types.js +94 -0
- package/dist/contracts/types.js.map +1 -0
- package/dist/core/circuit-breaker.d.ts +11 -0
- package/dist/core/circuit-breaker.d.ts.map +1 -0
- package/dist/core/circuit-breaker.js +38 -0
- package/dist/core/circuit-breaker.js.map +1 -0
- package/dist/core/context.d.ts +56 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +345 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/events.d.ts +8 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +25 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/extractor.d.ts +37 -0
- package/dist/core/extractor.d.ts.map +1 -0
- package/dist/core/extractor.js +448 -0
- package/dist/core/extractor.js.map +1 -0
- package/dist/core/formatter.d.ts +25 -0
- package/dist/core/formatter.d.ts.map +1 -0
- package/dist/core/formatter.js +97 -0
- package/dist/core/formatter.js.map +1 -0
- package/dist/core/knowledge-lifecycle.d.ts +15 -0
- package/dist/core/knowledge-lifecycle.d.ts.map +1 -0
- package/dist/core/knowledge-lifecycle.js +103 -0
- package/dist/core/knowledge-lifecycle.js.map +1 -0
- package/dist/core/maintenance.d.ts +13 -0
- package/dist/core/maintenance.d.ts.map +1 -0
- package/dist/core/maintenance.js +102 -0
- package/dist/core/maintenance.js.map +1 -0
- package/dist/core/manager.d.ts +110 -0
- package/dist/core/manager.d.ts.map +1 -0
- package/dist/core/manager.js +640 -0
- package/dist/core/manager.js.map +1 -0
- package/dist/core/monitor.d.ts +73 -0
- package/dist/core/monitor.d.ts.map +1 -0
- package/dist/core/monitor.js +395 -0
- package/dist/core/monitor.js.map +1 -0
- package/dist/core/orchestrator.d.ts +64 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +916 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/presets.d.ts +15 -0
- package/dist/core/presets.d.ts.map +1 -0
- package/dist/core/presets.js +99 -0
- package/dist/core/presets.js.map +1 -0
- package/dist/core/provider-managers.d.ts +47 -0
- package/dist/core/provider-managers.d.ts.map +1 -0
- package/dist/core/provider-managers.js +112 -0
- package/dist/core/provider-managers.js.map +1 -0
- package/dist/core/quick.d.ts +62 -0
- package/dist/core/quick.d.ts.map +1 -0
- package/dist/core/quick.js +300 -0
- package/dist/core/quick.js.map +1 -0
- package/dist/core/retrieval.d.ts +29 -0
- package/dist/core/retrieval.d.ts.map +1 -0
- package/dist/core/retrieval.js +150 -0
- package/dist/core/retrieval.js.map +1 -0
- package/dist/core/runtime.d.ts +67 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +84 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/streaming.d.ts +37 -0
- package/dist/core/streaming.d.ts.map +1 -0
- package/dist/core/streaming.js +51 -0
- package/dist/core/streaming.js.map +1 -0
- package/dist/core/sync.d.ts +13 -0
- package/dist/core/sync.d.ts.map +1 -0
- package/dist/core/sync.js +46 -0
- package/dist/core/sync.js.map +1 -0
- package/dist/core/telemetry.d.ts +8 -0
- package/dist/core/telemetry.d.ts.map +1 -0
- package/dist/core/telemetry.js +14 -0
- package/dist/core/telemetry.js.map +1 -0
- package/dist/core/tokens.d.ts +8 -0
- package/dist/core/tokens.d.ts.map +1 -0
- package/dist/core/tokens.js +59 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core/trust.d.ts +23 -0
- package/dist/core/trust.d.ts.map +1 -0
- package/dist/core/trust.js +164 -0
- package/dist/core/trust.js.map +1 -0
- package/dist/core/validation.d.ts +36 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +185 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/embeddings/local.d.ts +5 -0
- package/dist/embeddings/local.d.ts.map +1 -0
- package/dist/embeddings/local.js +128 -0
- package/dist/embeddings/local.js.map +1 -0
- package/dist/embeddings/openai.d.ts +26 -0
- package/dist/embeddings/openai.d.ts.map +1 -0
- package/dist/embeddings/openai.js +48 -0
- package/dist/embeddings/openai.js.map +1 -0
- package/dist/embeddings/resilience.d.ts +5 -0
- package/dist/embeddings/resilience.d.ts.map +1 -0
- package/dist/embeddings/resilience.js +53 -0
- package/dist/embeddings/resilience.js.map +1 -0
- package/dist/embeddings/voyage.d.ts +30 -0
- package/dist/embeddings/voyage.d.ts.map +1 -0
- package/dist/embeddings/voyage.js +53 -0
- package/dist/embeddings/voyage.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/claude-agent.d.ts +21 -0
- package/dist/integrations/claude-agent.d.ts.map +1 -0
- package/dist/integrations/claude-agent.js +44 -0
- package/dist/integrations/claude-agent.js.map +1 -0
- package/dist/integrations/claude-tools.d.ts +18 -0
- package/dist/integrations/claude-tools.d.ts.map +1 -0
- package/dist/integrations/claude-tools.js +60 -0
- package/dist/integrations/claude-tools.js.map +1 -0
- package/dist/integrations/langchain.d.ts +24 -0
- package/dist/integrations/langchain.d.ts.map +1 -0
- package/dist/integrations/langchain.js +48 -0
- package/dist/integrations/langchain.js.map +1 -0
- package/dist/integrations/mcp.d.ts +23 -0
- package/dist/integrations/mcp.d.ts.map +1 -0
- package/dist/integrations/mcp.js +60 -0
- package/dist/integrations/mcp.js.map +1 -0
- package/dist/integrations/middleware.d.ts +15 -0
- package/dist/integrations/middleware.d.ts.map +1 -0
- package/dist/integrations/middleware.js +27 -0
- package/dist/integrations/middleware.js.map +1 -0
- package/dist/integrations/openai-tools.d.ts +21 -0
- package/dist/integrations/openai-tools.d.ts.map +1 -0
- package/dist/integrations/openai-tools.js +69 -0
- package/dist/integrations/openai-tools.js.map +1 -0
- package/dist/integrations/vercel-ai.d.ts +19 -0
- package/dist/integrations/vercel-ai.d.ts.map +1 -0
- package/dist/integrations/vercel-ai.js +41 -0
- package/dist/integrations/vercel-ai.js.map +1 -0
- package/dist/server/http-server.d.ts +61 -0
- package/dist/server/http-server.d.ts.map +1 -0
- package/dist/server/http-server.js +684 -0
- package/dist/server/http-server.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp-server.d.ts +61 -0
- package/dist/server/mcp-server.d.ts.map +1 -0
- package/dist/server/mcp-server.js +465 -0
- package/dist/server/mcp-server.js.map +1 -0
- package/dist/summarizers/claude.d.ts +11 -0
- package/dist/summarizers/claude.d.ts.map +1 -0
- package/dist/summarizers/claude.js +39 -0
- package/dist/summarizers/claude.js.map +1 -0
- package/dist/summarizers/client.d.ts +23 -0
- package/dist/summarizers/client.d.ts.map +1 -0
- package/dist/summarizers/client.js +24 -0
- package/dist/summarizers/client.js.map +1 -0
- package/dist/summarizers/extractive.d.ts +6 -0
- package/dist/summarizers/extractive.d.ts.map +1 -0
- package/dist/summarizers/extractive.js +204 -0
- package/dist/summarizers/extractive.js.map +1 -0
- package/dist/summarizers/extractor.d.ts +12 -0
- package/dist/summarizers/extractor.d.ts.map +1 -0
- package/dist/summarizers/extractor.js +75 -0
- package/dist/summarizers/extractor.js.map +1 -0
- package/dist/summarizers/openai.d.ts +11 -0
- package/dist/summarizers/openai.d.ts.map +1 -0
- package/dist/summarizers/openai.js +41 -0
- package/dist/summarizers/openai.js.map +1 -0
- package/dist/summarizers/prompts.d.ts +11 -0
- package/dist/summarizers/prompts.d.ts.map +1 -0
- package/dist/summarizers/prompts.js +104 -0
- package/dist/summarizers/prompts.js.map +1 -0
- package/docs/DEPLOYMENT.md +84 -0
- package/docs/INTEGRATIONS.md +64 -0
- package/docs/MEMORY_QUALITY_BASELINE.md +55 -0
- package/docs/MEMORY_QUALITY_RELEASE_GATE.md +63 -0
- package/docs/MEMORY_QUALITY_RUBRIC.md +249 -0
- package/docs/OPERATIONS.md +49 -0
- package/docs/SECURITY.md +25 -0
- package/openapi.yaml +843 -0
- package/package.json +157 -0
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
import { normalizeScope, scopeValues } from '../../contracts/identity.js';
|
|
5
|
+
import { estimateTokens } from '../../core/tokens.js';
|
|
6
|
+
import { emitMemoryEvent } from '../../core/telemetry.js';
|
|
7
|
+
import { matchesKnowledgeSearchOptions } from '../../core/retrieval.js';
|
|
8
|
+
import { assertArchiveInput, nowSeconds, validateContextMonitorUpsert, validateNewCompactionLog, validateNewKnowledgeCandidate, validateNewKnowledgeEvidence, validateNewKnowledgeMemoryAudit, validateNewKnowledgeMemory, validateNewWorkItem, validateTimeRange, validateNewTurn, validateNewWorkingMemory, } from '../../core/validation.js';
|
|
9
|
+
import { rowToCompactionLog, rowToContextMonitor, rowToKnowledgeCandidate, rowToKnowledgeEvidence, rowToKnowledgeMemory, rowToKnowledgeMemoryAudit, rowToTurn, rowToWorkItem, rowToWorkingMemory, serializeNumberArray, serializeStringArray, } from './mappers.js';
|
|
10
|
+
import { createSQLiteEmbeddingAdapter } from './embeddings.js';
|
|
11
|
+
import { createSQLiteSchema } from './schema.js';
|
|
12
|
+
const SCOPE_WHERE = 'tenant_id = ? AND system_id = ? AND workspace_id = ? AND collaboration_id = ? AND scope_id = ?';
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
function loadBetterSqlite3() {
|
|
15
|
+
try {
|
|
16
|
+
return require('better-sqlite3');
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw new Error('memory-layer: SQLite support requires the optional "better-sqlite3" package. Install it with: npm install better-sqlite3', { cause: error });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function scopeWhereForLevel(scope, level) {
|
|
23
|
+
const normalized = normalizeScope(scope);
|
|
24
|
+
if (level === 'tenant')
|
|
25
|
+
return 'tenant_id = ?';
|
|
26
|
+
if (level === 'system')
|
|
27
|
+
return 'tenant_id = ? AND system_id = ?';
|
|
28
|
+
if (level === 'workspace') {
|
|
29
|
+
return normalized.collaboration_id.length > 0
|
|
30
|
+
? 'tenant_id = ? AND collaboration_id = ?'
|
|
31
|
+
: 'tenant_id = ? AND system_id = ? AND workspace_id = ?';
|
|
32
|
+
}
|
|
33
|
+
return SCOPE_WHERE;
|
|
34
|
+
}
|
|
35
|
+
function scopeParamsForLevel(scope, level) {
|
|
36
|
+
const normalized = normalizeScope(scope);
|
|
37
|
+
if (level === 'tenant')
|
|
38
|
+
return [normalized.tenant_id];
|
|
39
|
+
if (level === 'system')
|
|
40
|
+
return [normalized.tenant_id, normalized.system_id];
|
|
41
|
+
if (level === 'workspace') {
|
|
42
|
+
return normalized.collaboration_id.length > 0
|
|
43
|
+
? [normalized.tenant_id, normalized.collaboration_id]
|
|
44
|
+
: [normalized.tenant_id, normalized.system_id, normalized.workspace_id];
|
|
45
|
+
}
|
|
46
|
+
return [...scopeValues(normalized)];
|
|
47
|
+
}
|
|
48
|
+
function timeRangeWhere(range, column = 'created_at') {
|
|
49
|
+
validateTimeRange(range);
|
|
50
|
+
const clauses = [];
|
|
51
|
+
const params = [];
|
|
52
|
+
if (range.start_at !== undefined) {
|
|
53
|
+
clauses.push(`${column} >= ?`);
|
|
54
|
+
params.push(range.start_at);
|
|
55
|
+
}
|
|
56
|
+
if (range.end_at !== undefined) {
|
|
57
|
+
clauses.push(`${column} <= ?`);
|
|
58
|
+
params.push(range.end_at);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
clause: clauses.length > 0 ? ` AND ${clauses.join(' AND ')}` : '',
|
|
62
|
+
params,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function sessionWhere(sessionId, column = 'session_id') {
|
|
66
|
+
if (!sessionId) {
|
|
67
|
+
return { clause: '', params: [] };
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
clause: ` AND ${column} = ?`,
|
|
71
|
+
params: [sessionId],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function normalizeRank(rawRank) {
|
|
75
|
+
const safe = Number.isFinite(rawRank) ? Math.max(0, Number(rawRank)) : 0;
|
|
76
|
+
return 1 / (1 + safe);
|
|
77
|
+
}
|
|
78
|
+
function tokenizeSearch(text) {
|
|
79
|
+
return text
|
|
80
|
+
.toLowerCase()
|
|
81
|
+
.split(/[^a-z0-9]+/g)
|
|
82
|
+
.filter((token) => token.length > 0);
|
|
83
|
+
}
|
|
84
|
+
function scoreSearchText(query, text) {
|
|
85
|
+
const queryTokens = new Set(tokenizeSearch(query));
|
|
86
|
+
const textTokens = new Set(tokenizeSearch(text));
|
|
87
|
+
if (queryTokens.size === 0 || textTokens.size === 0)
|
|
88
|
+
return 0;
|
|
89
|
+
let matches = 0;
|
|
90
|
+
for (const token of queryTokens) {
|
|
91
|
+
if (textTokens.has(token))
|
|
92
|
+
matches += 1;
|
|
93
|
+
}
|
|
94
|
+
if (matches === 0)
|
|
95
|
+
return 0;
|
|
96
|
+
return matches / queryTokens.size + (text.toLowerCase().includes(query.toLowerCase()) ? 0.25 : 0);
|
|
97
|
+
}
|
|
98
|
+
function toSafeFtsQuery(query) {
|
|
99
|
+
return query
|
|
100
|
+
.toLowerCase()
|
|
101
|
+
.split(/[^a-z0-9]+/g)
|
|
102
|
+
.filter((token) => token.length > 0)
|
|
103
|
+
.join(' ');
|
|
104
|
+
}
|
|
105
|
+
function resolveSearchOptions(options) {
|
|
106
|
+
return {
|
|
107
|
+
limit: options?.limit ?? 10,
|
|
108
|
+
activeOnly: options?.activeOnly ?? true,
|
|
109
|
+
includeProvisional: options?.includeProvisional ?? false,
|
|
110
|
+
includeDisputed: options?.includeDisputed ?? false,
|
|
111
|
+
minimumTrustScore: options?.minimumTrustScore ?? 0,
|
|
112
|
+
knowledgeStates: options?.knowledgeStates ?? [],
|
|
113
|
+
knowledgeClasses: options?.knowledgeClasses ?? [],
|
|
114
|
+
preferLocalTrusted: options?.preferLocalTrusted ?? false,
|
|
115
|
+
preferLineageMemory: options?.preferLineageMemory ?? false,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function resolvePaginationOptions(options) {
|
|
119
|
+
return {
|
|
120
|
+
limit: options?.limit ?? 25,
|
|
121
|
+
offset: options?.offset ?? 0,
|
|
122
|
+
cursor: options?.cursor ?? 0,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
export function createSQLiteAdapter(dbPath, telemetry) {
|
|
126
|
+
const db = openSQLiteDatabase(dbPath);
|
|
127
|
+
return createAdapterFromDatabase(db, telemetry);
|
|
128
|
+
}
|
|
129
|
+
export function createSQLiteAdapterWithEmbeddings(dbPath, telemetry) {
|
|
130
|
+
const db = openSQLiteDatabase(dbPath);
|
|
131
|
+
const adapter = createAdapterFromDatabase(db, telemetry);
|
|
132
|
+
const embeddings = createSQLiteEmbeddingAdapter(db, telemetry?.logger);
|
|
133
|
+
return Object.assign(adapter, { embeddings });
|
|
134
|
+
}
|
|
135
|
+
function openSQLiteDatabase(dbPath) {
|
|
136
|
+
if (dbPath !== ':memory:') {
|
|
137
|
+
const dir = path.dirname(dbPath);
|
|
138
|
+
if (!fs.existsSync(dir)) {
|
|
139
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const BetterSqlite3 = loadBetterSqlite3();
|
|
143
|
+
const db = new BetterSqlite3(dbPath);
|
|
144
|
+
createSQLiteSchema(db);
|
|
145
|
+
return db;
|
|
146
|
+
}
|
|
147
|
+
function createAdapterFromDatabase(db, telemetry) {
|
|
148
|
+
function getTurnById(id) {
|
|
149
|
+
const row = db.prepare('SELECT * FROM turns WHERE id = ?').get(id);
|
|
150
|
+
return row ? rowToTurn(row) : null;
|
|
151
|
+
}
|
|
152
|
+
function getWorkingMemoryById(id) {
|
|
153
|
+
const row = db
|
|
154
|
+
.prepare('SELECT * FROM working_memory WHERE id = ?')
|
|
155
|
+
.get(id);
|
|
156
|
+
return row ? rowToWorkingMemory(row) : null;
|
|
157
|
+
}
|
|
158
|
+
function getKnowledgeMemoryById(id) {
|
|
159
|
+
const row = db
|
|
160
|
+
.prepare('SELECT * FROM knowledge_memory WHERE id = ?')
|
|
161
|
+
.get(id);
|
|
162
|
+
return row ? rowToKnowledgeMemory(row) : null;
|
|
163
|
+
}
|
|
164
|
+
function getKnowledgeCandidateById(id) {
|
|
165
|
+
const row = db
|
|
166
|
+
.prepare('SELECT * FROM knowledge_candidate WHERE id = ?')
|
|
167
|
+
.get(id);
|
|
168
|
+
return row ? rowToKnowledgeCandidate(row) : null;
|
|
169
|
+
}
|
|
170
|
+
function getContextMonitor(scope) {
|
|
171
|
+
const row = db
|
|
172
|
+
.prepare(`SELECT * FROM context_monitor WHERE ${SCOPE_WHERE}`)
|
|
173
|
+
.get(...scopeValues(scope));
|
|
174
|
+
return row ? rowToContextMonitor(row) : null;
|
|
175
|
+
}
|
|
176
|
+
function getCompactionLogById(id) {
|
|
177
|
+
const row = db
|
|
178
|
+
.prepare('SELECT * FROM compaction_log WHERE id = ?')
|
|
179
|
+
.get(id);
|
|
180
|
+
return row ? rowToCompactionLog(row) : null;
|
|
181
|
+
}
|
|
182
|
+
function getRecentKnowledgeMemoryAudits(scope, limit = 10) {
|
|
183
|
+
const rows = db
|
|
184
|
+
.prepare(`SELECT * FROM knowledge_memory_audit
|
|
185
|
+
WHERE ${SCOPE_WHERE}
|
|
186
|
+
ORDER BY id DESC
|
|
187
|
+
LIMIT ?`)
|
|
188
|
+
.all(...scopeValues(scope), limit);
|
|
189
|
+
return rows.map(rowToKnowledgeMemoryAudit);
|
|
190
|
+
}
|
|
191
|
+
function getKnowledgeMemoryAuditsForKnowledge(scope, knowledgeId, limit = 10) {
|
|
192
|
+
const rows = db
|
|
193
|
+
.prepare(`SELECT * FROM knowledge_memory_audit
|
|
194
|
+
WHERE ${SCOPE_WHERE}
|
|
195
|
+
AND (created_knowledge_id = ? OR related_knowledge_id = ?)
|
|
196
|
+
ORDER BY id DESC
|
|
197
|
+
LIMIT ?`)
|
|
198
|
+
.all(...scopeValues(scope), knowledgeId, knowledgeId, limit);
|
|
199
|
+
return rows.map(rowToKnowledgeMemoryAudit);
|
|
200
|
+
}
|
|
201
|
+
function insertValidatedTurn(input) {
|
|
202
|
+
const scope = validateNewTurn(input);
|
|
203
|
+
const tokenEstimate = input.token_estimate ?? estimateTokens(input.content);
|
|
204
|
+
const createdAt = input.created_at ?? nowSeconds();
|
|
205
|
+
const result = db
|
|
206
|
+
.prepare(`INSERT INTO turns
|
|
207
|
+
(session_id, tenant_id, system_id, workspace_id, collaboration_id, scope_id, actor, role, content, priority, token_estimate, created_at)
|
|
208
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
209
|
+
.run(input.session_id, scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.actor, input.role, input.content, input.priority ?? (input.role === 'system' ? 1.5 : 1), tokenEstimate, createdAt);
|
|
210
|
+
return getTurnById(Number(result.lastInsertRowid));
|
|
211
|
+
}
|
|
212
|
+
function insertValidatedKnowledgeMemory(input) {
|
|
213
|
+
const scope = validateNewKnowledgeMemory(input);
|
|
214
|
+
const createdAt = nowSeconds();
|
|
215
|
+
const result = db
|
|
216
|
+
.prepare(`INSERT INTO knowledge_memory
|
|
217
|
+
(tenant_id, system_id, workspace_id, collaboration_id, scope_id, fact, fact_type, knowledge_state,
|
|
218
|
+
knowledge_class, fact_subject, fact_attribute, fact_value, normalized_fact, slot_key,
|
|
219
|
+
is_negated, source, confidence, confidence_score, grounding_strength, evidence_count,
|
|
220
|
+
trust_score, verification_status, verification_notes, last_verified_at,
|
|
221
|
+
next_reverification_at, last_confirmed_at, confirmation_count,
|
|
222
|
+
source_system_id, source_scope_id, source_collaboration_id, source_working_memory_id,
|
|
223
|
+
source_turn_ids, successful_use_count, failed_use_count, disputed_at, dispute_reason,
|
|
224
|
+
contradiction_score, superseded_at, retired_at, created_at, last_accessed_at)
|
|
225
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
226
|
+
.run(scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.fact, input.fact_type, input.knowledge_state ?? 'trusted', input.knowledge_class ?? 'project_fact', input.fact_subject ?? null, input.fact_attribute ?? null, input.fact_value ?? null, input.normalized_fact ?? null, input.slot_key ?? null, input.is_negated ? 1 : 0, input.source, input.confidence, input.confidence_score ?? 0.5, input.grounding_strength ?? 'moderate', input.evidence_count ?? Math.max(1, (input.source_turn_ids ?? []).length), input.trust_score ?? (input.confidence_score ?? 0.5), input.verification_status ?? 'unverified', input.verification_notes ?? null, input.last_verified_at ?? null, input.next_reverification_at ?? null, input.last_confirmed_at ?? null, input.confirmation_count ?? 0, input.source_system_id ?? scope.system_id, input.source_scope_id ?? scope.scope_id, input.source_collaboration_id ?? scope.collaboration_id, input.source_working_memory_id ?? null, serializeNumberArray(input.source_turn_ids ?? []), input.successful_use_count ?? 0, input.failed_use_count ?? 0, input.disputed_at ?? null, input.dispute_reason ?? null, input.contradiction_score ?? 0, input.superseded_at ?? null, input.retired_at ?? null, createdAt, createdAt);
|
|
227
|
+
return getKnowledgeMemoryById(Number(result.lastInsertRowid));
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
insertTurn(input) {
|
|
231
|
+
return insertValidatedTurn(input);
|
|
232
|
+
},
|
|
233
|
+
insertTurns(inputs) {
|
|
234
|
+
return db.transaction(() => inputs.map((input) => insertValidatedTurn(input)))();
|
|
235
|
+
},
|
|
236
|
+
getTurnById,
|
|
237
|
+
getActiveTurns(scope, sessionId) {
|
|
238
|
+
const session = sessionWhere(sessionId);
|
|
239
|
+
const rows = db
|
|
240
|
+
.prepare(`SELECT * FROM turns
|
|
241
|
+
WHERE ${SCOPE_WHERE} AND archived_at IS NULL${session.clause}
|
|
242
|
+
ORDER BY id ASC`)
|
|
243
|
+
.all(...scopeValues(scope), ...session.params);
|
|
244
|
+
return rows.map(rowToTurn);
|
|
245
|
+
},
|
|
246
|
+
getActiveTurnsPaginated(scope, options) {
|
|
247
|
+
const resolved = resolvePaginationOptions(options);
|
|
248
|
+
const cursorClause = resolved.cursor > 0 ? ' AND id > ?' : '';
|
|
249
|
+
const offsetClause = resolved.cursor > 0 ? '' : ' OFFSET ?';
|
|
250
|
+
const rows = db
|
|
251
|
+
.prepare(`SELECT * FROM turns
|
|
252
|
+
WHERE ${SCOPE_WHERE} AND archived_at IS NULL${cursorClause}
|
|
253
|
+
ORDER BY id ASC
|
|
254
|
+
LIMIT ?${offsetClause}`)
|
|
255
|
+
.all(...scopeValues(scope), ...(resolved.cursor > 0 ? [resolved.cursor] : []), resolved.limit + 1, ...(resolved.cursor > 0 ? [] : [resolved.offset]));
|
|
256
|
+
const pageRows = rows.slice(0, resolved.limit).map(rowToTurn);
|
|
257
|
+
return {
|
|
258
|
+
items: pageRows,
|
|
259
|
+
hasMore: rows.length > resolved.limit,
|
|
260
|
+
nextCursor: rows.length > resolved.limit ? pageRows[pageRows.length - 1]?.id ?? null : null,
|
|
261
|
+
};
|
|
262
|
+
},
|
|
263
|
+
getTurnsByTimeRange(scope, range) {
|
|
264
|
+
const time = timeRangeWhere(range, 'created_at');
|
|
265
|
+
const rows = db
|
|
266
|
+
.prepare(`SELECT * FROM turns
|
|
267
|
+
WHERE ${SCOPE_WHERE}${time.clause}
|
|
268
|
+
ORDER BY created_at ASC`)
|
|
269
|
+
.all(...scopeValues(scope), ...time.params);
|
|
270
|
+
return rows.map(rowToTurn);
|
|
271
|
+
},
|
|
272
|
+
searchTurns(scope, query, options) {
|
|
273
|
+
const startedAt = Date.now();
|
|
274
|
+
const resolved = resolveSearchOptions(options);
|
|
275
|
+
try {
|
|
276
|
+
const rows = db
|
|
277
|
+
.prepare(`SELECT turns.*, bm25(turns_fts) AS raw_rank
|
|
278
|
+
FROM turns_fts
|
|
279
|
+
JOIN turns ON turns_fts.rowid = turns.id
|
|
280
|
+
WHERE turns_fts MATCH ?
|
|
281
|
+
AND ${SCOPE_WHERE}
|
|
282
|
+
AND (? = 0 OR turns.archived_at IS NULL)
|
|
283
|
+
ORDER BY bm25(turns_fts)
|
|
284
|
+
LIMIT ?`)
|
|
285
|
+
.all(query, ...scopeValues(scope), resolved.activeOnly ? 1 : 0, resolved.limit);
|
|
286
|
+
const results = rows.map((row) => ({
|
|
287
|
+
item: rowToTurn(row),
|
|
288
|
+
rank: normalizeRank(row.raw_rank),
|
|
289
|
+
}));
|
|
290
|
+
emitMemoryEvent('search', scope, telemetry, Date.now() - startedAt, {
|
|
291
|
+
entity: 'turns',
|
|
292
|
+
query,
|
|
293
|
+
resultCount: results.length,
|
|
294
|
+
});
|
|
295
|
+
return results;
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
emitMemoryEvent('search', scope, telemetry, Date.now() - startedAt, {
|
|
299
|
+
entity: 'turns',
|
|
300
|
+
query,
|
|
301
|
+
resultCount: 0,
|
|
302
|
+
invalidQuery: true,
|
|
303
|
+
});
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
archiveTurn(id, archivedAt, compactionLogId) {
|
|
308
|
+
assertArchiveInput(id, archivedAt, compactionLogId);
|
|
309
|
+
db.prepare(`UPDATE turns
|
|
310
|
+
SET archived_at = ?, compaction_log_id = ?
|
|
311
|
+
WHERE id = ? AND archived_at IS NULL`).run(archivedAt, compactionLogId, id);
|
|
312
|
+
},
|
|
313
|
+
getArchivedTurnRange(sessionId, startId, endId, scope) {
|
|
314
|
+
const query = `SELECT * FROM turns
|
|
315
|
+
WHERE session_id = ? AND id >= ? AND id <= ? AND archived_at IS NOT NULL
|
|
316
|
+
AND ${SCOPE_WHERE}
|
|
317
|
+
ORDER BY id ASC`;
|
|
318
|
+
const rows = db
|
|
319
|
+
.prepare(query)
|
|
320
|
+
.all(sessionId, startId, endId, ...scopeValues(scope));
|
|
321
|
+
return rows.map(rowToTurn);
|
|
322
|
+
},
|
|
323
|
+
insertWorkingMemory(input) {
|
|
324
|
+
const scope = validateNewWorkingMemory(input);
|
|
325
|
+
const createdAt = nowSeconds();
|
|
326
|
+
const expiresAt = input.expires_at ?? createdAt + 86400;
|
|
327
|
+
const result = db
|
|
328
|
+
.prepare(`INSERT INTO working_memory
|
|
329
|
+
(session_id, tenant_id, system_id, workspace_id, collaboration_id, scope_id, summary, key_entities, topic_tags,
|
|
330
|
+
turn_id_start, turn_id_end, turn_count, compaction_trigger, created_at, expires_at)
|
|
331
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
332
|
+
.run(input.session_id, scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.summary, serializeStringArray(input.key_entities), serializeStringArray(input.topic_tags), input.turn_id_start, input.turn_id_end, input.turn_count, input.compaction_trigger, createdAt, expiresAt);
|
|
333
|
+
return getWorkingMemoryById(Number(result.lastInsertRowid));
|
|
334
|
+
},
|
|
335
|
+
getWorkingMemoryById,
|
|
336
|
+
getWorkingMemoryBySession(sessionId, scope) {
|
|
337
|
+
const query = `SELECT * FROM working_memory
|
|
338
|
+
WHERE session_id = ? AND ${SCOPE_WHERE}
|
|
339
|
+
ORDER BY id ASC`;
|
|
340
|
+
const rows = db
|
|
341
|
+
.prepare(query)
|
|
342
|
+
.all(sessionId, ...scopeValues(scope));
|
|
343
|
+
return rows.map(rowToWorkingMemory);
|
|
344
|
+
},
|
|
345
|
+
getActiveWorkingMemory(scope, sessionId) {
|
|
346
|
+
const now = nowSeconds();
|
|
347
|
+
const session = sessionWhere(sessionId);
|
|
348
|
+
const rows = db
|
|
349
|
+
.prepare(`SELECT * FROM working_memory
|
|
350
|
+
WHERE ${SCOPE_WHERE}
|
|
351
|
+
AND (expires_at IS NULL OR expires_at > ?)${session.clause}
|
|
352
|
+
ORDER BY id DESC`)
|
|
353
|
+
.all(...scopeValues(scope), now, ...session.params);
|
|
354
|
+
return rows.map(rowToWorkingMemory);
|
|
355
|
+
},
|
|
356
|
+
getLatestWorkingMemory(scope, sessionId) {
|
|
357
|
+
const now = nowSeconds();
|
|
358
|
+
const session = sessionWhere(sessionId);
|
|
359
|
+
const row = db
|
|
360
|
+
.prepare(`SELECT * FROM working_memory
|
|
361
|
+
WHERE ${SCOPE_WHERE}
|
|
362
|
+
AND (expires_at IS NULL OR expires_at > ?)${session.clause}
|
|
363
|
+
ORDER BY id DESC
|
|
364
|
+
LIMIT 1`)
|
|
365
|
+
.get(...scopeValues(scope), now, ...session.params);
|
|
366
|
+
return row ? rowToWorkingMemory(row) : null;
|
|
367
|
+
},
|
|
368
|
+
getWorkingMemoryByTimeRange(scope, range) {
|
|
369
|
+
const time = timeRangeWhere(range, 'created_at');
|
|
370
|
+
const rows = db
|
|
371
|
+
.prepare(`SELECT * FROM working_memory
|
|
372
|
+
WHERE ${SCOPE_WHERE}${time.clause}
|
|
373
|
+
ORDER BY created_at ASC`)
|
|
374
|
+
.all(...scopeValues(scope), ...time.params);
|
|
375
|
+
return rows.map(rowToWorkingMemory);
|
|
376
|
+
},
|
|
377
|
+
expireWorkingMemory(id) {
|
|
378
|
+
db.prepare('UPDATE working_memory SET expires_at = ? WHERE id = ?').run(nowSeconds(), id);
|
|
379
|
+
},
|
|
380
|
+
markWorkingMemoryPromoted(id, knowledgeMemoryId) {
|
|
381
|
+
db.prepare('UPDATE working_memory SET promoted_to_knowledge_id = ? WHERE id = ?').run(knowledgeMemoryId, id);
|
|
382
|
+
},
|
|
383
|
+
insertKnowledgeMemory(input) {
|
|
384
|
+
return insertValidatedKnowledgeMemory(input);
|
|
385
|
+
},
|
|
386
|
+
insertKnowledgeMemories(inputs) {
|
|
387
|
+
return db.transaction(() => inputs.map((input) => insertValidatedKnowledgeMemory(input)))();
|
|
388
|
+
},
|
|
389
|
+
insertKnowledgeCandidate(input) {
|
|
390
|
+
const scope = validateNewKnowledgeCandidate(input);
|
|
391
|
+
const createdAt = input.created_at ?? nowSeconds();
|
|
392
|
+
const result = db
|
|
393
|
+
.prepare(`INSERT INTO knowledge_candidate
|
|
394
|
+
(tenant_id, system_id, workspace_id, collaboration_id, scope_id, working_memory_id, fact, fact_type,
|
|
395
|
+
knowledge_class, normalized_fact, slot_key, confidence, source_summary, source_turns,
|
|
396
|
+
grounding_strength, evidence_count, trust_score, state, promoted_knowledge_id, created_at)
|
|
397
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
398
|
+
.run(scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.working_memory_id, input.fact, input.fact_type, input.knowledge_class, input.normalized_fact, input.slot_key ?? null, input.confidence, input.source_summary ? 1 : 0, input.source_turns === false ? 0 : 1, input.grounding_strength ?? 'weak', input.evidence_count ?? 0, input.trust_score ?? 0, input.state ?? 'candidate', input.promoted_knowledge_id ?? null, createdAt);
|
|
399
|
+
return getKnowledgeCandidateById(Number(result.lastInsertRowid));
|
|
400
|
+
},
|
|
401
|
+
insertKnowledgeCandidates(inputs) {
|
|
402
|
+
return db.transaction(() => inputs.map((input) => this.insertKnowledgeCandidate(input)))();
|
|
403
|
+
},
|
|
404
|
+
getKnowledgeCandidateById,
|
|
405
|
+
listKnowledgeCandidates(scope, options) {
|
|
406
|
+
const rows = db
|
|
407
|
+
.prepare(`SELECT * FROM knowledge_candidate
|
|
408
|
+
WHERE ${SCOPE_WHERE}
|
|
409
|
+
ORDER BY created_at DESC, id DESC`)
|
|
410
|
+
.all(...scopeValues(scope));
|
|
411
|
+
return rows
|
|
412
|
+
.map(rowToKnowledgeCandidate)
|
|
413
|
+
.filter((item) => !options?.state || options.state.includes(item.state));
|
|
414
|
+
},
|
|
415
|
+
insertKnowledgeEvidence(input) {
|
|
416
|
+
const scope = validateNewKnowledgeEvidence(input);
|
|
417
|
+
const createdAt = input.created_at ?? nowSeconds();
|
|
418
|
+
const result = db
|
|
419
|
+
.prepare(`INSERT INTO knowledge_evidence
|
|
420
|
+
(tenant_id, system_id, workspace_id, collaboration_id, scope_id, knowledge_memory_id, knowledge_candidate_id,
|
|
421
|
+
working_memory_id, turn_id, source_type, support_polarity, speaker_role, actor, excerpt,
|
|
422
|
+
start_offset, end_offset, is_explicit, explicitness_score, outcome, created_at)
|
|
423
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
424
|
+
.run(scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.knowledge_memory_id ?? null, input.knowledge_candidate_id ?? null, input.working_memory_id ?? null, input.turn_id ?? null, input.source_type, input.support_polarity, input.speaker_role ?? null, input.actor ?? null, input.excerpt, input.start_offset ?? null, input.end_offset ?? null, input.is_explicit ? 1 : 0, input.explicitness_score ?? 0, input.outcome ?? null, createdAt);
|
|
425
|
+
const row = db
|
|
426
|
+
.prepare('SELECT * FROM knowledge_evidence WHERE id = ?')
|
|
427
|
+
.get(Number(result.lastInsertRowid));
|
|
428
|
+
return rowToKnowledgeEvidence(row);
|
|
429
|
+
},
|
|
430
|
+
insertKnowledgeEvidenceBatch(inputs) {
|
|
431
|
+
return db.transaction(() => inputs.map((input) => this.insertKnowledgeEvidence(input)))();
|
|
432
|
+
},
|
|
433
|
+
listKnowledgeEvidenceForKnowledge(knowledgeId) {
|
|
434
|
+
const rows = db
|
|
435
|
+
.prepare('SELECT * FROM knowledge_evidence WHERE knowledge_memory_id = ? ORDER BY created_at DESC, id DESC')
|
|
436
|
+
.all(knowledgeId);
|
|
437
|
+
return rows.map(rowToKnowledgeEvidence);
|
|
438
|
+
},
|
|
439
|
+
listKnowledgeEvidenceForCandidate(candidateId) {
|
|
440
|
+
const rows = db
|
|
441
|
+
.prepare('SELECT * FROM knowledge_evidence WHERE knowledge_candidate_id = ? ORDER BY created_at DESC, id DESC')
|
|
442
|
+
.all(candidateId);
|
|
443
|
+
return rows.map(rowToKnowledgeEvidence);
|
|
444
|
+
},
|
|
445
|
+
promoteKnowledgeCandidate(candidateId, input) {
|
|
446
|
+
const knowledge = insertValidatedKnowledgeMemory(input);
|
|
447
|
+
db.prepare('UPDATE knowledge_candidate SET promoted_knowledge_id = ?, state = ? WHERE id = ?').run(knowledge.id, 'provisional', candidateId);
|
|
448
|
+
return knowledge;
|
|
449
|
+
},
|
|
450
|
+
getKnowledgeMemoryById,
|
|
451
|
+
getActiveKnowledgeMemory(scope) {
|
|
452
|
+
const rows = db
|
|
453
|
+
.prepare(`SELECT * FROM knowledge_memory
|
|
454
|
+
WHERE ${SCOPE_WHERE} AND superseded_by_id IS NULL AND retired_at IS NULL
|
|
455
|
+
ORDER BY last_accessed_at DESC`)
|
|
456
|
+
.all(...scopeValues(scope));
|
|
457
|
+
return rows.map(rowToKnowledgeMemory);
|
|
458
|
+
},
|
|
459
|
+
getActiveKnowledgeMemoryPaginated(scope, options) {
|
|
460
|
+
const resolved = resolvePaginationOptions(options);
|
|
461
|
+
const cursorClause = resolved.cursor > 0 ? ' AND id > ?' : '';
|
|
462
|
+
const offsetClause = resolved.cursor > 0 ? '' : ' OFFSET ?';
|
|
463
|
+
const rows = db
|
|
464
|
+
.prepare(`SELECT * FROM knowledge_memory
|
|
465
|
+
WHERE ${SCOPE_WHERE} AND superseded_by_id IS NULL AND retired_at IS NULL${cursorClause}
|
|
466
|
+
ORDER BY id ASC
|
|
467
|
+
LIMIT ?${offsetClause}`)
|
|
468
|
+
.all(...scopeValues(scope), ...(resolved.cursor > 0 ? [resolved.cursor] : []), resolved.limit + 1, ...(resolved.cursor > 0 ? [] : [resolved.offset]));
|
|
469
|
+
const pageRows = rows.slice(0, resolved.limit).map(rowToKnowledgeMemory);
|
|
470
|
+
return {
|
|
471
|
+
items: pageRows,
|
|
472
|
+
hasMore: rows.length > resolved.limit,
|
|
473
|
+
nextCursor: rows.length > resolved.limit ? pageRows[pageRows.length - 1]?.id ?? null : null,
|
|
474
|
+
};
|
|
475
|
+
},
|
|
476
|
+
getActiveKnowledgeCrossScope(scope, level) {
|
|
477
|
+
const rows = db
|
|
478
|
+
.prepare(`SELECT * FROM knowledge_memory
|
|
479
|
+
WHERE ${scopeWhereForLevel(scope, level)} AND superseded_by_id IS NULL AND retired_at IS NULL
|
|
480
|
+
ORDER BY last_accessed_at DESC`)
|
|
481
|
+
.all(...scopeParamsForLevel(scope, level));
|
|
482
|
+
return rows.map(rowToKnowledgeMemory);
|
|
483
|
+
},
|
|
484
|
+
getKnowledgeSince(scope, level, since) {
|
|
485
|
+
const rows = db
|
|
486
|
+
.prepare(`SELECT * FROM knowledge_memory
|
|
487
|
+
WHERE ${scopeWhereForLevel(scope, level)}
|
|
488
|
+
AND created_at >= ?
|
|
489
|
+
AND superseded_by_id IS NULL
|
|
490
|
+
AND retired_at IS NULL
|
|
491
|
+
ORDER BY created_at ASC, id ASC`)
|
|
492
|
+
.all(...scopeParamsForLevel(scope, level), since);
|
|
493
|
+
return rows.map(rowToKnowledgeMemory);
|
|
494
|
+
},
|
|
495
|
+
getKnowledgeByTimeRange(scope, range) {
|
|
496
|
+
const time = timeRangeWhere(range, 'created_at');
|
|
497
|
+
const rows = db
|
|
498
|
+
.prepare(`SELECT * FROM knowledge_memory
|
|
499
|
+
WHERE ${SCOPE_WHERE}${time.clause}
|
|
500
|
+
ORDER BY created_at ASC`)
|
|
501
|
+
.all(...scopeValues(scope), ...time.params);
|
|
502
|
+
return rows.map(rowToKnowledgeMemory);
|
|
503
|
+
},
|
|
504
|
+
searchKnowledge(scope, query, options) {
|
|
505
|
+
const startedAt = Date.now();
|
|
506
|
+
const resolved = resolveSearchOptions(options);
|
|
507
|
+
try {
|
|
508
|
+
const statement = db.prepare(`SELECT knowledge_memory.*, bm25(knowledge_memory_fts) AS raw_rank
|
|
509
|
+
FROM knowledge_memory_fts
|
|
510
|
+
JOIN knowledge_memory ON knowledge_memory_fts.rowid = knowledge_memory.id
|
|
511
|
+
WHERE knowledge_memory_fts MATCH ?
|
|
512
|
+
AND ${SCOPE_WHERE}
|
|
513
|
+
AND (? = 0 OR (knowledge_memory.superseded_by_id IS NULL AND knowledge_memory.retired_at IS NULL))
|
|
514
|
+
ORDER BY bm25(knowledge_memory_fts)
|
|
515
|
+
LIMIT ?`);
|
|
516
|
+
let rows = statement.all(query, ...scopeValues(scope), resolved.activeOnly ? 1 : 0, resolved.limit);
|
|
517
|
+
const safeQuery = toSafeFtsQuery(query);
|
|
518
|
+
if (rows.length === 0 && safeQuery.length > 0 && safeQuery !== query && !/["']/.test(query)) {
|
|
519
|
+
rows = statement.all(safeQuery, ...scopeValues(scope), resolved.activeOnly ? 1 : 0, resolved.limit);
|
|
520
|
+
}
|
|
521
|
+
let results = rows
|
|
522
|
+
.map((row) => ({
|
|
523
|
+
item: rowToKnowledgeMemory(row),
|
|
524
|
+
rank: normalizeRank(row.raw_rank),
|
|
525
|
+
}))
|
|
526
|
+
.filter((result) => matchesKnowledgeSearchOptions(result.item, resolved))
|
|
527
|
+
.slice(0, resolved.limit);
|
|
528
|
+
if (results.length === 0 && !/["']/.test(query)) {
|
|
529
|
+
const fallbackRows = db
|
|
530
|
+
.prepare(`SELECT knowledge_memory.*
|
|
531
|
+
FROM knowledge_memory
|
|
532
|
+
WHERE ${SCOPE_WHERE}
|
|
533
|
+
AND (? = 0 OR (knowledge_memory.superseded_by_id IS NULL AND knowledge_memory.retired_at IS NULL))`)
|
|
534
|
+
.all(...scopeValues(scope), resolved.activeOnly ? 1 : 0);
|
|
535
|
+
results = fallbackRows
|
|
536
|
+
.map((row) => {
|
|
537
|
+
const item = rowToKnowledgeMemory(row);
|
|
538
|
+
return {
|
|
539
|
+
item,
|
|
540
|
+
rank: scoreSearchText(query, item.fact),
|
|
541
|
+
};
|
|
542
|
+
})
|
|
543
|
+
.filter((result) => result.rank > 0 && matchesKnowledgeSearchOptions(result.item, resolved))
|
|
544
|
+
.sort((a, b) => b.rank - a.rank || b.item.last_accessed_at - a.item.last_accessed_at)
|
|
545
|
+
.slice(0, resolved.limit);
|
|
546
|
+
}
|
|
547
|
+
emitMemoryEvent('search', scope, telemetry, Date.now() - startedAt, {
|
|
548
|
+
entity: 'knowledge',
|
|
549
|
+
query,
|
|
550
|
+
resultCount: results.length,
|
|
551
|
+
});
|
|
552
|
+
return results;
|
|
553
|
+
}
|
|
554
|
+
catch {
|
|
555
|
+
if (!/["']/.test(query)) {
|
|
556
|
+
const fallbackRows = db
|
|
557
|
+
.prepare(`SELECT knowledge_memory.*
|
|
558
|
+
FROM knowledge_memory
|
|
559
|
+
WHERE ${SCOPE_WHERE}
|
|
560
|
+
AND (? = 0 OR (knowledge_memory.superseded_by_id IS NULL AND knowledge_memory.retired_at IS NULL))`)
|
|
561
|
+
.all(...scopeValues(scope), resolved.activeOnly ? 1 : 0);
|
|
562
|
+
const fallbackResults = fallbackRows
|
|
563
|
+
.map((row) => {
|
|
564
|
+
const item = rowToKnowledgeMemory(row);
|
|
565
|
+
return {
|
|
566
|
+
item,
|
|
567
|
+
rank: scoreSearchText(query, item.fact),
|
|
568
|
+
};
|
|
569
|
+
})
|
|
570
|
+
.filter((result) => result.rank > 0 && matchesKnowledgeSearchOptions(result.item, resolved))
|
|
571
|
+
.sort((a, b) => b.rank - a.rank || b.item.last_accessed_at - a.item.last_accessed_at)
|
|
572
|
+
.slice(0, resolved.limit);
|
|
573
|
+
emitMemoryEvent('search', scope, telemetry, Date.now() - startedAt, {
|
|
574
|
+
entity: 'knowledge',
|
|
575
|
+
query,
|
|
576
|
+
resultCount: fallbackResults.length,
|
|
577
|
+
fallbackQuery: true,
|
|
578
|
+
});
|
|
579
|
+
return fallbackResults;
|
|
580
|
+
}
|
|
581
|
+
emitMemoryEvent('search', scope, telemetry, Date.now() - startedAt, {
|
|
582
|
+
entity: 'knowledge',
|
|
583
|
+
query,
|
|
584
|
+
resultCount: 0,
|
|
585
|
+
invalidQuery: true,
|
|
586
|
+
});
|
|
587
|
+
return [];
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
searchKnowledgeCrossScope(scope, level, query, options) {
|
|
591
|
+
const startedAt = Date.now();
|
|
592
|
+
const resolved = resolveSearchOptions(options);
|
|
593
|
+
try {
|
|
594
|
+
const statement = db.prepare(`SELECT knowledge_memory.*, bm25(knowledge_memory_fts) AS raw_rank
|
|
595
|
+
FROM knowledge_memory_fts
|
|
596
|
+
JOIN knowledge_memory ON knowledge_memory_fts.rowid = knowledge_memory.id
|
|
597
|
+
WHERE knowledge_memory_fts MATCH ?
|
|
598
|
+
AND ${scopeWhereForLevel(scope, level)}
|
|
599
|
+
AND (? = 0 OR (knowledge_memory.superseded_by_id IS NULL AND knowledge_memory.retired_at IS NULL))
|
|
600
|
+
ORDER BY bm25(knowledge_memory_fts)
|
|
601
|
+
LIMIT ?`);
|
|
602
|
+
let rows = statement.all(query, ...scopeParamsForLevel(scope, level), resolved.activeOnly ? 1 : 0, resolved.limit);
|
|
603
|
+
const safeQuery = toSafeFtsQuery(query);
|
|
604
|
+
if (rows.length === 0 && safeQuery.length > 0 && safeQuery !== query && !/["']/.test(query)) {
|
|
605
|
+
rows = statement.all(safeQuery, ...scopeParamsForLevel(scope, level), resolved.activeOnly ? 1 : 0, resolved.limit);
|
|
606
|
+
}
|
|
607
|
+
let results = rows
|
|
608
|
+
.map((row) => ({
|
|
609
|
+
item: rowToKnowledgeMemory(row),
|
|
610
|
+
rank: normalizeRank(row.raw_rank),
|
|
611
|
+
}))
|
|
612
|
+
.filter((result) => matchesKnowledgeSearchOptions(result.item, resolved))
|
|
613
|
+
.slice(0, resolved.limit);
|
|
614
|
+
if (results.length === 0 && !/["']/.test(query)) {
|
|
615
|
+
const fallbackRows = db
|
|
616
|
+
.prepare(`SELECT knowledge_memory.*
|
|
617
|
+
FROM knowledge_memory
|
|
618
|
+
WHERE ${scopeWhereForLevel(scope, level)}
|
|
619
|
+
AND (? = 0 OR (knowledge_memory.superseded_by_id IS NULL AND knowledge_memory.retired_at IS NULL))`)
|
|
620
|
+
.all(...scopeParamsForLevel(scope, level), resolved.activeOnly ? 1 : 0);
|
|
621
|
+
results = fallbackRows
|
|
622
|
+
.map((row) => {
|
|
623
|
+
const item = rowToKnowledgeMemory(row);
|
|
624
|
+
return {
|
|
625
|
+
item,
|
|
626
|
+
rank: scoreSearchText(query, item.fact),
|
|
627
|
+
};
|
|
628
|
+
})
|
|
629
|
+
.filter((result) => result.rank > 0 && matchesKnowledgeSearchOptions(result.item, resolved))
|
|
630
|
+
.sort((a, b) => b.rank - a.rank || b.item.last_accessed_at - a.item.last_accessed_at)
|
|
631
|
+
.slice(0, resolved.limit);
|
|
632
|
+
}
|
|
633
|
+
emitMemoryEvent('search', scope, telemetry, Date.now() - startedAt, {
|
|
634
|
+
entity: 'knowledge',
|
|
635
|
+
query,
|
|
636
|
+
resultCount: results.length,
|
|
637
|
+
scopeLevel: level,
|
|
638
|
+
});
|
|
639
|
+
return results;
|
|
640
|
+
}
|
|
641
|
+
catch {
|
|
642
|
+
if (!/["']/.test(query)) {
|
|
643
|
+
const fallbackRows = db
|
|
644
|
+
.prepare(`SELECT knowledge_memory.*
|
|
645
|
+
FROM knowledge_memory
|
|
646
|
+
WHERE ${scopeWhereForLevel(scope, level)}
|
|
647
|
+
AND (? = 0 OR (knowledge_memory.superseded_by_id IS NULL AND knowledge_memory.retired_at IS NULL))`)
|
|
648
|
+
.all(...scopeParamsForLevel(scope, level), resolved.activeOnly ? 1 : 0);
|
|
649
|
+
const fallbackResults = fallbackRows
|
|
650
|
+
.map((row) => {
|
|
651
|
+
const item = rowToKnowledgeMemory(row);
|
|
652
|
+
return {
|
|
653
|
+
item,
|
|
654
|
+
rank: scoreSearchText(query, item.fact),
|
|
655
|
+
};
|
|
656
|
+
})
|
|
657
|
+
.filter((result) => result.rank > 0 && matchesKnowledgeSearchOptions(result.item, resolved))
|
|
658
|
+
.sort((a, b) => b.rank - a.rank || b.item.last_accessed_at - a.item.last_accessed_at)
|
|
659
|
+
.slice(0, resolved.limit);
|
|
660
|
+
emitMemoryEvent('search', scope, telemetry, Date.now() - startedAt, {
|
|
661
|
+
entity: 'knowledge',
|
|
662
|
+
query,
|
|
663
|
+
resultCount: fallbackResults.length,
|
|
664
|
+
scopeLevel: level,
|
|
665
|
+
fallbackQuery: true,
|
|
666
|
+
});
|
|
667
|
+
return fallbackResults;
|
|
668
|
+
}
|
|
669
|
+
emitMemoryEvent('search', scope, telemetry, Date.now() - startedAt, {
|
|
670
|
+
entity: 'knowledge',
|
|
671
|
+
query,
|
|
672
|
+
resultCount: 0,
|
|
673
|
+
invalidQuery: true,
|
|
674
|
+
scopeLevel: level,
|
|
675
|
+
});
|
|
676
|
+
return [];
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
insertKnowledgeMemoryAudit(input) {
|
|
680
|
+
const scope = validateNewKnowledgeMemoryAudit(input);
|
|
681
|
+
const createdAt = input.created_at ?? nowSeconds();
|
|
682
|
+
const result = db
|
|
683
|
+
.prepare(`INSERT INTO knowledge_memory_audit
|
|
684
|
+
(tenant_id, system_id, workspace_id, collaboration_id, scope_id, working_memory_id, fact, fact_type,
|
|
685
|
+
fact_subject, fact_attribute, fact_value, normalized_fact, slot_key, is_negated,
|
|
686
|
+
confidence, confidence_score, verification_status, source_text, decision,
|
|
687
|
+
created_knowledge_id, related_knowledge_id, detail, created_at)
|
|
688
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
689
|
+
.run(scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.working_memory_id ?? null, input.fact, input.fact_type, input.fact_subject ?? null, input.fact_attribute ?? null, input.fact_value ?? null, input.normalized_fact ?? null, input.slot_key ?? null, input.is_negated ? 1 : 0, input.confidence, input.confidence_score ?? 0.5, input.verification_status ?? 'unverified', input.source_text ?? null, input.decision, input.created_knowledge_id ?? null, input.related_knowledge_id ?? null, input.detail ?? null, createdAt);
|
|
690
|
+
const row = db
|
|
691
|
+
.prepare('SELECT * FROM knowledge_memory_audit WHERE id = ?')
|
|
692
|
+
.get(Number(result.lastInsertRowid));
|
|
693
|
+
return rowToKnowledgeMemoryAudit(row);
|
|
694
|
+
},
|
|
695
|
+
getRecentKnowledgeMemoryAudits,
|
|
696
|
+
getKnowledgeMemoryAuditsForKnowledge,
|
|
697
|
+
updateKnowledgeMemory(id, patch) {
|
|
698
|
+
const assignments = [];
|
|
699
|
+
const values = [];
|
|
700
|
+
const push = (column, value) => {
|
|
701
|
+
assignments.push(`${column} = ?`);
|
|
702
|
+
values.push(value);
|
|
703
|
+
};
|
|
704
|
+
if (patch.knowledge_state !== undefined)
|
|
705
|
+
push('knowledge_state', patch.knowledge_state);
|
|
706
|
+
if (patch.knowledge_class !== undefined)
|
|
707
|
+
push('knowledge_class', patch.knowledge_class);
|
|
708
|
+
if (patch.trust_score !== undefined)
|
|
709
|
+
push('trust_score', patch.trust_score);
|
|
710
|
+
if (patch.verification_status !== undefined)
|
|
711
|
+
push('verification_status', patch.verification_status);
|
|
712
|
+
if (patch.verification_notes !== undefined)
|
|
713
|
+
push('verification_notes', patch.verification_notes);
|
|
714
|
+
if (patch.last_verified_at !== undefined)
|
|
715
|
+
push('last_verified_at', patch.last_verified_at);
|
|
716
|
+
if (patch.next_reverification_at !== undefined) {
|
|
717
|
+
push('next_reverification_at', patch.next_reverification_at);
|
|
718
|
+
}
|
|
719
|
+
if (patch.last_confirmed_at !== undefined)
|
|
720
|
+
push('last_confirmed_at', patch.last_confirmed_at);
|
|
721
|
+
if (patch.confirmation_count !== undefined)
|
|
722
|
+
push('confirmation_count', patch.confirmation_count);
|
|
723
|
+
if (patch.disputed_at !== undefined)
|
|
724
|
+
push('disputed_at', patch.disputed_at);
|
|
725
|
+
if (patch.dispute_reason !== undefined)
|
|
726
|
+
push('dispute_reason', patch.dispute_reason);
|
|
727
|
+
if (patch.contradiction_score !== undefined)
|
|
728
|
+
push('contradiction_score', patch.contradiction_score);
|
|
729
|
+
if (patch.superseded_at !== undefined)
|
|
730
|
+
push('superseded_at', patch.superseded_at);
|
|
731
|
+
if (patch.successful_use_count !== undefined)
|
|
732
|
+
push('successful_use_count', patch.successful_use_count);
|
|
733
|
+
if (patch.failed_use_count !== undefined)
|
|
734
|
+
push('failed_use_count', patch.failed_use_count);
|
|
735
|
+
if (assignments.length === 0) {
|
|
736
|
+
return getKnowledgeMemoryById(id);
|
|
737
|
+
}
|
|
738
|
+
db.prepare(`UPDATE knowledge_memory SET ${assignments.join(', ')} WHERE id = ?`).run(...values, id);
|
|
739
|
+
return getKnowledgeMemoryById(id);
|
|
740
|
+
},
|
|
741
|
+
insertWorkItem(input) {
|
|
742
|
+
const scope = validateNewWorkItem(input);
|
|
743
|
+
const createdAt = input.created_at ?? nowSeconds();
|
|
744
|
+
const result = db
|
|
745
|
+
.prepare(`INSERT INTO work_items
|
|
746
|
+
(session_id, tenant_id, system_id, workspace_id, collaboration_id, scope_id, kind, title, detail, status,
|
|
747
|
+
source_working_memory_id, created_at, updated_at)
|
|
748
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
749
|
+
.run(input.session_id ?? null, scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.kind, input.title, input.detail ?? null, input.status ?? 'open', input.source_working_memory_id ?? null, createdAt, createdAt);
|
|
750
|
+
const row = db
|
|
751
|
+
.prepare('SELECT * FROM work_items WHERE id = ?')
|
|
752
|
+
.get(Number(result.lastInsertRowid));
|
|
753
|
+
return rowToWorkItem(row);
|
|
754
|
+
},
|
|
755
|
+
getActiveWorkItems(scope) {
|
|
756
|
+
const rows = db
|
|
757
|
+
.prepare(`SELECT * FROM work_items
|
|
758
|
+
WHERE ${SCOPE_WHERE} AND status != 'done'
|
|
759
|
+
ORDER BY updated_at DESC`)
|
|
760
|
+
.all(...scopeValues(scope));
|
|
761
|
+
return rows.map(rowToWorkItem);
|
|
762
|
+
},
|
|
763
|
+
getWorkItemsByTimeRange(scope, range) {
|
|
764
|
+
const time = timeRangeWhere(range, 'created_at');
|
|
765
|
+
const rows = db
|
|
766
|
+
.prepare(`SELECT * FROM work_items
|
|
767
|
+
WHERE ${SCOPE_WHERE}${time.clause}
|
|
768
|
+
ORDER BY created_at ASC`)
|
|
769
|
+
.all(...scopeValues(scope), ...time.params);
|
|
770
|
+
return rows.map(rowToWorkItem);
|
|
771
|
+
},
|
|
772
|
+
updateWorkItemStatus(id, status) {
|
|
773
|
+
db.prepare('UPDATE work_items SET status = ?, updated_at = ? WHERE id = ?').run(status, nowSeconds(), id);
|
|
774
|
+
},
|
|
775
|
+
deleteWorkItem(id) {
|
|
776
|
+
db.prepare('DELETE FROM work_items WHERE id = ?').run(id);
|
|
777
|
+
},
|
|
778
|
+
touchKnowledgeMemory(id) {
|
|
779
|
+
db.prepare(`UPDATE knowledge_memory
|
|
780
|
+
SET last_accessed_at = ?, access_count = access_count + 1
|
|
781
|
+
WHERE id = ?`).run(nowSeconds(), id);
|
|
782
|
+
},
|
|
783
|
+
retireKnowledgeMemory(id, retiredAt = nowSeconds()) {
|
|
784
|
+
db.prepare('UPDATE knowledge_memory SET retired_at = ? WHERE id = ?').run(retiredAt, id);
|
|
785
|
+
},
|
|
786
|
+
supersedeKnowledgeMemory(oldId, newId) {
|
|
787
|
+
db.prepare(`UPDATE knowledge_memory
|
|
788
|
+
SET superseded_by_id = ?, superseded_at = ?, knowledge_state = 'superseded'
|
|
789
|
+
WHERE id = ?`).run(newId, nowSeconds(), oldId);
|
|
790
|
+
},
|
|
791
|
+
upsertContextMonitor(input) {
|
|
792
|
+
const scope = validateContextMonitorUpsert(input);
|
|
793
|
+
const updatedAt = nowSeconds();
|
|
794
|
+
db.prepare(`INSERT INTO context_monitor
|
|
795
|
+
(tenant_id, system_id, workspace_id, collaboration_id, scope_id, compaction_state, last_compaction_at,
|
|
796
|
+
active_turn_count, active_token_estimate, compaction_score, updated_at)
|
|
797
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
798
|
+
ON CONFLICT(tenant_id, system_id, workspace_id, collaboration_id, scope_id) DO UPDATE SET
|
|
799
|
+
compaction_state = excluded.compaction_state,
|
|
800
|
+
last_compaction_at = excluded.last_compaction_at,
|
|
801
|
+
active_turn_count = excluded.active_turn_count,
|
|
802
|
+
active_token_estimate = excluded.active_token_estimate,
|
|
803
|
+
compaction_score = excluded.compaction_score,
|
|
804
|
+
updated_at = excluded.updated_at`).run(scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.compaction_state, input.last_compaction_at ?? null, input.active_turn_count, input.active_token_estimate, input.compaction_score, updatedAt);
|
|
805
|
+
return getContextMonitor(scope);
|
|
806
|
+
},
|
|
807
|
+
getContextMonitor,
|
|
808
|
+
insertCompactionLog(input) {
|
|
809
|
+
const scope = validateNewCompactionLog(input);
|
|
810
|
+
const createdAt = input.created_at ?? nowSeconds();
|
|
811
|
+
const result = db
|
|
812
|
+
.prepare(`INSERT INTO compaction_log
|
|
813
|
+
(session_id, tenant_id, system_id, workspace_id, collaboration_id, scope_id, trigger_type,
|
|
814
|
+
turn_id_start, turn_id_end, turns_compacted, tokens_compacted_estimate,
|
|
815
|
+
working_memory_id, active_turn_count_before, active_turn_count_after,
|
|
816
|
+
duration_ms, model_call_made, error, created_at)
|
|
817
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
818
|
+
.run(input.session_id, scope.tenant_id, scope.system_id, scope.workspace_id, scope.collaboration_id, scope.scope_id, input.trigger_type, input.turn_id_start, input.turn_id_end, input.turns_compacted, input.tokens_compacted_estimate, input.working_memory_id, input.active_turn_count_before, input.active_turn_count_after, input.duration_ms, input.model_call_made ? 1 : 0, input.error ?? null, createdAt);
|
|
819
|
+
return getCompactionLogById(Number(result.lastInsertRowid));
|
|
820
|
+
},
|
|
821
|
+
getCompactionLogById,
|
|
822
|
+
getRecentCompactionLogs(scope, limit = 10) {
|
|
823
|
+
const rows = db
|
|
824
|
+
.prepare(`SELECT * FROM compaction_log
|
|
825
|
+
WHERE ${SCOPE_WHERE}
|
|
826
|
+
ORDER BY id DESC
|
|
827
|
+
LIMIT ?`)
|
|
828
|
+
.all(...scopeValues(scope), limit);
|
|
829
|
+
return rows.map(rowToCompactionLog);
|
|
830
|
+
},
|
|
831
|
+
transaction(fn) {
|
|
832
|
+
return db.transaction(fn)();
|
|
833
|
+
},
|
|
834
|
+
close() {
|
|
835
|
+
db.close();
|
|
836
|
+
},
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
//# sourceMappingURL=index.js.map
|