@mastra/pg 1.31.0-alpha.1 → 1.31.0-alpha.3
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/dist/_types/@internal_core/dist/knowledge-compat/index.d.ts +594 -0
- package/dist/_types/@internal_core/package.json +1 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-rag-chunking-and-embedding.md +1 -1
- package/dist/docs/references/reference-rag-retrieval.md +7 -5
- package/dist/index.cjs +1396 -220
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1399 -223
- package/dist/index.js.map +1 -1
- package/dist/shared/config.d.ts +6 -0
- package/dist/shared/config.d.ts.map +1 -1
- package/dist/storage/db/index.d.ts +17 -5
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/db/schema-snapshot.d.ts +2 -0
- package/dist/storage/db/schema-snapshot.d.ts.map +1 -1
- package/dist/storage/domains/experiments/index.d.ts.map +1 -1
- package/dist/storage/domains/knowledge/index.d.ts +38 -9
- package/dist/storage/domains/knowledge/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +2 -1
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
|
|
2
2
|
import * as coreStorage from "@mastra/core/storage";
|
|
3
|
-
import { AgentsStorage, BRANCH_SPAN_TYPES, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, EntityType, ExperimentsStorage, FactoryStorage, FavoritesStorage,
|
|
3
|
+
import { AgentsStorage, BRANCH_SPAN_TYPES, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, EntityType, ExperimentsStorage, FactoryStorage, FavoritesStorage, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_THREAD_STATE, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, executeRetentionPrune, getDefaultValue, getSqlType, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveListOrderBy, resolveRetentionTargets, retentionCutoffMs, runRetentionBatches, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
4
4
|
import { parseFieldKey, parseSqlIdentifier } from "@mastra/core/utils";
|
|
5
5
|
import { MastraVector, validateTopK, validateUpsertInput } from "@mastra/core/vector";
|
|
6
6
|
import { Mutex } from "async-mutex";
|
|
7
7
|
import * as pg$1 from "pg";
|
|
8
|
-
import pg, { Pool } from "pg";
|
|
8
|
+
import pg, { Pool, defaults } from "pg";
|
|
9
9
|
import xxhash from "xxhash-wasm";
|
|
10
10
|
import { parse } from "pg-connection-string";
|
|
11
11
|
import { BaseFilterTranslator } from "@mastra/core/vector/filter";
|
|
12
12
|
import { MastraBase } from "@mastra/core/base";
|
|
13
|
-
import { createHash } from "crypto";
|
|
14
|
-
import { MessageList } from "@mastra/core/agent";
|
|
13
|
+
import { createHash, randomUUID } from "crypto";
|
|
15
14
|
import { coreFeatures } from "@mastra/core/features";
|
|
15
|
+
import { MessageList } from "@mastra/core/agent";
|
|
16
16
|
import { saveScorePayloadSchema } from "@mastra/core/evals";
|
|
17
17
|
import { skillSnapshotFieldValuesEqual } from "@mastra/core/storage/domains/skills";
|
|
18
18
|
import { isDeepStrictEqual } from "util";
|
|
@@ -2475,7 +2475,8 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2475
2475
|
const schema = schemaName || "public";
|
|
2476
2476
|
const [tableRows, columnRows, indexRows] = await Promise.all([
|
|
2477
2477
|
client.manyOrNone(`SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = $1`, [schema]),
|
|
2478
|
-
client.manyOrNone(`SELECT c.relname AS table_name, a.attname AS column_name, format_type(a.atttypid, a.atttypmod) AS data_type
|
|
2478
|
+
client.manyOrNone(`SELECT c.relname AS table_name, a.attname AS column_name, format_type(a.atttypid, a.atttypmod) AS data_type,
|
|
2479
|
+
a.attnotnull AS not_null
|
|
2479
2480
|
FROM pg_catalog.pg_class c
|
|
2480
2481
|
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2481
2482
|
JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
|
|
@@ -2491,6 +2492,7 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2491
2492
|
]);
|
|
2492
2493
|
const columns = /* @__PURE__ */ new Map();
|
|
2493
2494
|
const columnTypes = /* @__PURE__ */ new Map();
|
|
2495
|
+
const notNullColumns = /* @__PURE__ */ new Map();
|
|
2494
2496
|
for (const row of columnRows) {
|
|
2495
2497
|
let set = columns.get(row.table_name);
|
|
2496
2498
|
if (!set) {
|
|
@@ -2504,6 +2506,14 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2504
2506
|
columnTypes.set(row.table_name, types);
|
|
2505
2507
|
}
|
|
2506
2508
|
types.set(row.column_name, row.data_type);
|
|
2509
|
+
if (row.not_null) {
|
|
2510
|
+
let notNull = notNullColumns.get(row.table_name);
|
|
2511
|
+
if (!notNull) {
|
|
2512
|
+
notNull = /* @__PURE__ */ new Set();
|
|
2513
|
+
notNullColumns.set(row.table_name, notNull);
|
|
2514
|
+
}
|
|
2515
|
+
notNull.add(row.column_name);
|
|
2516
|
+
}
|
|
2507
2517
|
}
|
|
2508
2518
|
const indexes = /* @__PURE__ */ new Set();
|
|
2509
2519
|
const replicaIdentityIndexes = /* @__PURE__ */ new Set();
|
|
@@ -2520,6 +2530,7 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2520
2530
|
tables: new Set(tableRows.map((r) => r.tablename)),
|
|
2521
2531
|
columns,
|
|
2522
2532
|
columnTypes,
|
|
2533
|
+
notNullColumns,
|
|
2523
2534
|
indexes,
|
|
2524
2535
|
replicaIdentityIndexes,
|
|
2525
2536
|
primaryKeyIndexes,
|
|
@@ -3598,6 +3609,33 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
3598
3609
|
this.columnTypeCache.delete(tableName);
|
|
3599
3610
|
}
|
|
3600
3611
|
}
|
|
3612
|
+
/**
|
|
3613
|
+
* Drops NOT NULL from `columns` on `tableName` where it is still set. Answered
|
|
3614
|
+
* from the init snapshot when one is installed, so a converged schema issues
|
|
3615
|
+
* no query and never takes the ACCESS EXCLUSIVE lock.
|
|
3616
|
+
*/
|
|
3617
|
+
async dropNotNull({ tableName, columns }) {
|
|
3618
|
+
const parsedColumns = columns.map((c) => parseSqlIdentifier(c, "column name"));
|
|
3619
|
+
const snapshot = this.schemaSnapshot;
|
|
3620
|
+
let toAlter;
|
|
3621
|
+
if (snapshot) {
|
|
3622
|
+
const notNull = snapshot.notNullColumns.get(tableName);
|
|
3623
|
+
toAlter = parsedColumns.filter((c) => notNull?.has(c));
|
|
3624
|
+
} else toAlter = (await this.client.any(`SELECT column_name FROM information_schema.columns
|
|
3625
|
+
WHERE table_schema = $1 AND table_name = $2 AND column_name = ANY($3) AND is_nullable = 'NO'`, [
|
|
3626
|
+
this.schemaName || "public",
|
|
3627
|
+
tableName,
|
|
3628
|
+
parsedColumns
|
|
3629
|
+
])).map((r) => r.column_name);
|
|
3630
|
+
if (toAlter.length === 0) return;
|
|
3631
|
+
const fullTableName = getTableName$6({
|
|
3632
|
+
indexName: tableName,
|
|
3633
|
+
schemaName: getSchemaName$6(this.schemaName)
|
|
3634
|
+
});
|
|
3635
|
+
await this.client.none(`ALTER TABLE ${fullTableName} ${toAlter.map((c) => `ALTER COLUMN "${c}" DROP NOT NULL`).join(", ")}`);
|
|
3636
|
+
const notNull = snapshot?.notNullColumns.get(tableName);
|
|
3637
|
+
for (const c of toAlter) notNull?.delete(c);
|
|
3638
|
+
}
|
|
3601
3639
|
async load({ tableName, keys }) {
|
|
3602
3640
|
try {
|
|
3603
3641
|
const keyEntries = Object.entries(keys).map(([key, value]) => [parseSqlIdentifier(key, "column name"), value]);
|
|
@@ -7088,6 +7126,10 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
|
|
|
7088
7126
|
"scorerIds"
|
|
7089
7127
|
]
|
|
7090
7128
|
});
|
|
7129
|
+
await this.#db.dropNotNull({
|
|
7130
|
+
tableName: TABLE_EXPERIMENTS,
|
|
7131
|
+
columns: ["targetType", "targetId"]
|
|
7132
|
+
});
|
|
7091
7133
|
await this.#db.alterTable({
|
|
7092
7134
|
tableName: TABLE_EXPERIMENT_RESULTS,
|
|
7093
7135
|
schema: EXPERIMENT_RESULTS_SCHEMA,
|
|
@@ -8235,18 +8277,650 @@ var FavoritesPG = class FavoritesPG extends FavoritesStorage {
|
|
|
8235
8277
|
}
|
|
8236
8278
|
};
|
|
8237
8279
|
//#endregion
|
|
8280
|
+
//#region ../../packages/_internal-core/dist/knowledge-compat/index.js
|
|
8281
|
+
const KNOWLEDGE_V2_CORE_FEATURE = "knowledge-v2";
|
|
8282
|
+
/** Hard cap on scope nodes returned by one `listScopeNodes` read. */
|
|
8283
|
+
const MAX_KNOWLEDGE_SCOPE_NODES = 1e3;
|
|
8284
|
+
function knowledgeScopeNodeFilterKey(input) {
|
|
8285
|
+
return JSON.stringify([
|
|
8286
|
+
input.withinAddress ?? null,
|
|
8287
|
+
input.addresses ? [...input.addresses].sort() : null,
|
|
8288
|
+
input.ids ? [...input.ids].sort() : null
|
|
8289
|
+
]);
|
|
8290
|
+
}
|
|
8291
|
+
function createKnowledgeScopeNodeCursor(scope, input) {
|
|
8292
|
+
return encodeURIComponent(JSON.stringify({
|
|
8293
|
+
version: 1,
|
|
8294
|
+
type: "scope",
|
|
8295
|
+
name: scope.name,
|
|
8296
|
+
id: scope.id,
|
|
8297
|
+
filter: knowledgeScopeNodeFilterKey(input)
|
|
8298
|
+
}));
|
|
8299
|
+
}
|
|
8300
|
+
/** Validates the page size and cursor of a `listScopeNodes` query; throws on a cursor from a different query. */
|
|
8301
|
+
function parseListKnowledgeScopeNodesInput(input = {}) {
|
|
8302
|
+
const requested = Number.isFinite(input.limit) ? Math.trunc(input.limit) : MAX_KNOWLEDGE_SCOPE_NODES;
|
|
8303
|
+
const limit = Math.min(Math.max(requested, 1), MAX_KNOWLEDGE_SCOPE_NODES);
|
|
8304
|
+
if (!input.cursor) return {
|
|
8305
|
+
limit,
|
|
8306
|
+
after: null
|
|
8307
|
+
};
|
|
8308
|
+
let value;
|
|
8309
|
+
try {
|
|
8310
|
+
value = JSON.parse(decodeURIComponent(input.cursor));
|
|
8311
|
+
} catch {
|
|
8312
|
+
throw new Error("Invalid Knowledge scope node cursor.");
|
|
8313
|
+
}
|
|
8314
|
+
const parsed = value && typeof value === "object" ? value : {};
|
|
8315
|
+
if (parsed.version !== 1 || parsed.type !== "scope" || typeof parsed.name !== "string" || typeof parsed.id !== "string" || parsed.filter !== knowledgeScopeNodeFilterKey(input)) throw new Error("Knowledge scope node cursor does not match this query.");
|
|
8316
|
+
return {
|
|
8317
|
+
limit,
|
|
8318
|
+
after: {
|
|
8319
|
+
name: parsed.name,
|
|
8320
|
+
id: parsed.id
|
|
8321
|
+
}
|
|
8322
|
+
};
|
|
8323
|
+
}
|
|
8324
|
+
/** Builds a page from up to `limit + 1` name/id-ordered scope nodes. */
|
|
8325
|
+
function pageKnowledgeScopeNodes(rows, limit, input) {
|
|
8326
|
+
const scopes = rows.slice(0, limit);
|
|
8327
|
+
const last = scopes.at(-1);
|
|
8328
|
+
return {
|
|
8329
|
+
scopes,
|
|
8330
|
+
nextCursor: rows.length > limit && last ? createKnowledgeScopeNodeCursor(last, input) : null
|
|
8331
|
+
};
|
|
8332
|
+
}
|
|
8333
|
+
/** Clamps a requested member limit to 1–{@link MAX_KNOWLEDGE_SCOPE_MEMBERS_LIMIT}. */
|
|
8334
|
+
function knowledgeScopeMembersLimit(limit) {
|
|
8335
|
+
if (limit === void 0 || !Number.isFinite(limit)) return 500;
|
|
8336
|
+
return Math.min(Math.max(Math.trunc(limit), 1), 500);
|
|
8337
|
+
}
|
|
8338
|
+
/** Validates the page size and cursor of a `listScopeMembers` query; throws on a cursor from another scope. */
|
|
8339
|
+
function parseListKnowledgeScopeMembersInput(input) {
|
|
8340
|
+
const limit = knowledgeScopeMembersLimit(input.limit);
|
|
8341
|
+
if (!input.cursor) return {
|
|
8342
|
+
limit,
|
|
8343
|
+
after: null
|
|
8344
|
+
};
|
|
8345
|
+
let value;
|
|
8346
|
+
try {
|
|
8347
|
+
value = JSON.parse(decodeURIComponent(input.cursor));
|
|
8348
|
+
} catch {
|
|
8349
|
+
throw new Error("Invalid Knowledge scope member cursor.");
|
|
8350
|
+
}
|
|
8351
|
+
const parsed = value && typeof value === "object" ? value : {};
|
|
8352
|
+
const updatedAt = typeof parsed.updatedAt === "string" ? new Date(parsed.updatedAt) : /* @__PURE__ */ new Date(NaN);
|
|
8353
|
+
if (parsed.version !== 1 || parsed.type !== "scope-member" || parsed.scopeNodeId !== input.scopeNodeId || typeof parsed.name !== "string" || typeof parsed.id !== "string" || Number.isNaN(updatedAt.getTime())) throw new Error("Knowledge scope member cursor does not match this query.");
|
|
8354
|
+
return {
|
|
8355
|
+
limit,
|
|
8356
|
+
after: {
|
|
8357
|
+
updatedAt,
|
|
8358
|
+
name: parsed.name,
|
|
8359
|
+
id: parsed.id
|
|
8360
|
+
}
|
|
8361
|
+
};
|
|
8362
|
+
}
|
|
8363
|
+
/** Builds a page from up to `limit + 1` members in `listScopeMembers` order. */
|
|
8364
|
+
function pageKnowledgeScopeMembers(rows, limit, input) {
|
|
8365
|
+
const members = rows.slice(0, limit);
|
|
8366
|
+
const last = members.at(-1);
|
|
8367
|
+
const hasMore = rows.length > limit;
|
|
8368
|
+
return {
|
|
8369
|
+
members,
|
|
8370
|
+
hasMore,
|
|
8371
|
+
nextCursor: hasMore && last ? encodeURIComponent(JSON.stringify({
|
|
8372
|
+
version: 1,
|
|
8373
|
+
type: "scope-member",
|
|
8374
|
+
scopeNodeId: input.scopeNodeId,
|
|
8375
|
+
updatedAt: last.updatedAt.toISOString(),
|
|
8376
|
+
name: last.name,
|
|
8377
|
+
id: last.id
|
|
8378
|
+
})) : null
|
|
8379
|
+
};
|
|
8380
|
+
}
|
|
8381
|
+
const TABLE_KNOWLEDGE_NODES$1 = "mastra_knowledge_nodes";
|
|
8382
|
+
const TABLE_KNOWLEDGE_RECORDS$1 = "mastra_knowledge_records";
|
|
8383
|
+
const TABLE_KNOWLEDGE_MENTIONS$1 = "mastra_knowledge_mentions";
|
|
8384
|
+
const TABLE_KNOWLEDGE_ACTIVITY$1 = "mastra_knowledge_activity";
|
|
8385
|
+
const TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1 = "mastra_knowledge_semantic_outbox";
|
|
8386
|
+
const TABLE_KNOWLEDGE_NODE_SCOPES = "mastra_knowledge_node_scopes";
|
|
8387
|
+
const TABLE_KNOWLEDGE_RECORD_SCOPES = "mastra_knowledge_record_scopes";
|
|
8388
|
+
const TABLE_KNOWLEDGE_SCOPE_GRANTS = "mastra_knowledge_scope_grants";
|
|
8389
|
+
const TABLE_KNOWLEDGE_ACCESS_STATE = "mastra_knowledge_access_state";
|
|
8390
|
+
const TABLE_KNOWLEDGE_SCOPE_ADDRESSES = "mastra_knowledge_scope_addresses";
|
|
8391
|
+
const TABLE_KNOWLEDGE_NODE_ADDRESSES = "mastra_knowledge_node_addresses";
|
|
8392
|
+
const TABLE_KNOWLEDGE_IMPORT_STATE = "mastra_knowledge_import_state";
|
|
8393
|
+
const TABLE_KNOWLEDGE_IMPORT_RUNS = "mastra_knowledge_import_runs";
|
|
8394
|
+
const TABLE_KNOWLEDGE_PROPOSALS = "mastra_knowledge_proposals";
|
|
8395
|
+
const KNOWLEDGE_TABLE_NAMES = [
|
|
8396
|
+
TABLE_KNOWLEDGE_NODES$1,
|
|
8397
|
+
TABLE_KNOWLEDGE_RECORDS$1,
|
|
8398
|
+
TABLE_KNOWLEDGE_MENTIONS$1,
|
|
8399
|
+
TABLE_KNOWLEDGE_ACTIVITY$1,
|
|
8400
|
+
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1,
|
|
8401
|
+
TABLE_KNOWLEDGE_NODE_SCOPES,
|
|
8402
|
+
TABLE_KNOWLEDGE_RECORD_SCOPES,
|
|
8403
|
+
TABLE_KNOWLEDGE_SCOPE_GRANTS,
|
|
8404
|
+
TABLE_KNOWLEDGE_ACCESS_STATE,
|
|
8405
|
+
TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
|
|
8406
|
+
TABLE_KNOWLEDGE_NODE_ADDRESSES,
|
|
8407
|
+
TABLE_KNOWLEDGE_IMPORT_STATE,
|
|
8408
|
+
TABLE_KNOWLEDGE_IMPORT_RUNS,
|
|
8409
|
+
TABLE_KNOWLEDGE_PROPOSALS
|
|
8410
|
+
];
|
|
8411
|
+
/** Knowledge v1 tables with no v2 equivalent; an explicit schema reset drops them. */
|
|
8412
|
+
const RETIRED_KNOWLEDGE_TABLE_NAMES = ["mastra_knowledge_cursors"];
|
|
8413
|
+
/** Tables and indexes published v1 adapters created for every app, whether or not it used Knowledge. */
|
|
8414
|
+
const PUBLISHED_KNOWLEDGE_V1_TABLE_NAMES = /* @__PURE__ */ new Set([
|
|
8415
|
+
TABLE_KNOWLEDGE_NODES$1,
|
|
8416
|
+
TABLE_KNOWLEDGE_RECORDS$1,
|
|
8417
|
+
TABLE_KNOWLEDGE_MENTIONS$1,
|
|
8418
|
+
TABLE_KNOWLEDGE_ACTIVITY$1,
|
|
8419
|
+
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX$1,
|
|
8420
|
+
...RETIRED_KNOWLEDGE_TABLE_NAMES
|
|
8421
|
+
]);
|
|
8422
|
+
const PUBLISHED_KNOWLEDGE_V1_INDEX_NAMES = /* @__PURE__ */ new Set([
|
|
8423
|
+
"idx_knowledge_nodes_identity",
|
|
8424
|
+
"idx_knowledge_nodes_scope",
|
|
8425
|
+
"idx_knowledge_records_node_latest",
|
|
8426
|
+
"idx_knowledge_records_thread_latest",
|
|
8427
|
+
"idx_knowledge_mentions_record",
|
|
8428
|
+
"idx_knowledge_activity_latest",
|
|
8429
|
+
"idx_knowledge_outbox_idempotency",
|
|
8430
|
+
"idx_knowledge_outbox_claim"
|
|
8431
|
+
]);
|
|
8432
|
+
const KNOWLEDGE_V2_NODES_SCHEMA = {
|
|
8433
|
+
id: {
|
|
8434
|
+
type: "text",
|
|
8435
|
+
nullable: false,
|
|
8436
|
+
primaryKey: true
|
|
8437
|
+
},
|
|
8438
|
+
name: {
|
|
8439
|
+
type: "text",
|
|
8440
|
+
nullable: false
|
|
8441
|
+
},
|
|
8442
|
+
kind: {
|
|
8443
|
+
type: "text",
|
|
8444
|
+
nullable: true
|
|
8445
|
+
},
|
|
8446
|
+
isScope: {
|
|
8447
|
+
type: "boolean",
|
|
8448
|
+
nullable: false
|
|
8449
|
+
},
|
|
8450
|
+
metadata: {
|
|
8451
|
+
type: "jsonb",
|
|
8452
|
+
nullable: true
|
|
8453
|
+
},
|
|
8454
|
+
version: {
|
|
8455
|
+
type: "integer",
|
|
8456
|
+
nullable: false
|
|
8457
|
+
},
|
|
8458
|
+
createdAt: {
|
|
8459
|
+
type: "timestamp",
|
|
8460
|
+
nullable: false
|
|
8461
|
+
},
|
|
8462
|
+
updatedAt: {
|
|
8463
|
+
type: "timestamp",
|
|
8464
|
+
nullable: false
|
|
8465
|
+
},
|
|
8466
|
+
deletedAt: {
|
|
8467
|
+
type: "timestamp",
|
|
8468
|
+
nullable: true
|
|
8469
|
+
},
|
|
8470
|
+
deletedBy: {
|
|
8471
|
+
type: "text",
|
|
8472
|
+
nullable: true
|
|
8473
|
+
},
|
|
8474
|
+
type: {
|
|
8475
|
+
type: "text",
|
|
8476
|
+
nullable: true
|
|
8477
|
+
},
|
|
8478
|
+
canonicalName: {
|
|
8479
|
+
type: "text",
|
|
8480
|
+
nullable: true
|
|
8481
|
+
},
|
|
8482
|
+
content: {
|
|
8483
|
+
type: "text",
|
|
8484
|
+
nullable: true
|
|
8485
|
+
},
|
|
8486
|
+
description: {
|
|
8487
|
+
type: "text",
|
|
8488
|
+
nullable: true
|
|
8489
|
+
},
|
|
8490
|
+
scope: {
|
|
8491
|
+
type: "jsonb",
|
|
8492
|
+
nullable: true
|
|
8493
|
+
},
|
|
8494
|
+
scopeKey: {
|
|
8495
|
+
type: "text",
|
|
8496
|
+
nullable: true
|
|
8497
|
+
},
|
|
8498
|
+
mergedInto: {
|
|
8499
|
+
type: "text",
|
|
8500
|
+
nullable: true
|
|
8501
|
+
}
|
|
8502
|
+
};
|
|
8503
|
+
const KNOWLEDGE_V2_RECORDS_SCHEMA = {
|
|
8504
|
+
id: {
|
|
8505
|
+
type: "text",
|
|
8506
|
+
nullable: false,
|
|
8507
|
+
primaryKey: true
|
|
8508
|
+
},
|
|
8509
|
+
node: {
|
|
8510
|
+
type: "text",
|
|
8511
|
+
nullable: false,
|
|
8512
|
+
references: {
|
|
8513
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8514
|
+
column: "id"
|
|
8515
|
+
}
|
|
8516
|
+
},
|
|
8517
|
+
text: {
|
|
8518
|
+
type: "text",
|
|
8519
|
+
nullable: false
|
|
8520
|
+
},
|
|
8521
|
+
metadata: {
|
|
8522
|
+
type: "jsonb",
|
|
8523
|
+
nullable: true
|
|
8524
|
+
},
|
|
8525
|
+
version: {
|
|
8526
|
+
type: "integer",
|
|
8527
|
+
nullable: false
|
|
8528
|
+
},
|
|
8529
|
+
capturedAt: {
|
|
8530
|
+
type: "timestamp",
|
|
8531
|
+
nullable: false
|
|
8532
|
+
},
|
|
8533
|
+
updatedAt: {
|
|
8534
|
+
type: "timestamp",
|
|
8535
|
+
nullable: false
|
|
8536
|
+
},
|
|
8537
|
+
deletedAt: {
|
|
8538
|
+
type: "timestamp",
|
|
8539
|
+
nullable: true
|
|
8540
|
+
},
|
|
8541
|
+
deletedBy: {
|
|
8542
|
+
type: "text",
|
|
8543
|
+
nullable: true
|
|
8544
|
+
},
|
|
8545
|
+
scope: {
|
|
8546
|
+
type: "jsonb",
|
|
8547
|
+
nullable: true
|
|
8548
|
+
},
|
|
8549
|
+
scopeKey: {
|
|
8550
|
+
type: "text",
|
|
8551
|
+
nullable: true
|
|
8552
|
+
},
|
|
8553
|
+
sourceThreadId: {
|
|
8554
|
+
type: "text",
|
|
8555
|
+
nullable: true
|
|
8556
|
+
},
|
|
8557
|
+
when: {
|
|
8558
|
+
type: "timestamp",
|
|
8559
|
+
nullable: true
|
|
8560
|
+
}
|
|
8561
|
+
};
|
|
8562
|
+
const KNOWLEDGE_V2_MENTIONS_SCHEMA = {
|
|
8563
|
+
recordId: {
|
|
8564
|
+
type: "text",
|
|
8565
|
+
nullable: false,
|
|
8566
|
+
references: {
|
|
8567
|
+
table: TABLE_KNOWLEDGE_RECORDS$1,
|
|
8568
|
+
column: "id"
|
|
8569
|
+
}
|
|
8570
|
+
},
|
|
8571
|
+
targetNodeId: {
|
|
8572
|
+
type: "text",
|
|
8573
|
+
nullable: true,
|
|
8574
|
+
references: {
|
|
8575
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8576
|
+
column: "id"
|
|
8577
|
+
}
|
|
8578
|
+
},
|
|
8579
|
+
sourceType: {
|
|
8580
|
+
type: "text",
|
|
8581
|
+
nullable: true
|
|
8582
|
+
},
|
|
8583
|
+
sourceId: {
|
|
8584
|
+
type: "text",
|
|
8585
|
+
nullable: true
|
|
8586
|
+
}
|
|
8587
|
+
};
|
|
8588
|
+
const KNOWLEDGE_NODE_SCOPES_SCHEMA = {
|
|
8589
|
+
nodeId: {
|
|
8590
|
+
type: "text",
|
|
8591
|
+
nullable: false,
|
|
8592
|
+
references: {
|
|
8593
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8594
|
+
column: "id"
|
|
8595
|
+
}
|
|
8596
|
+
},
|
|
8597
|
+
scopeNodeId: {
|
|
8598
|
+
type: "text",
|
|
8599
|
+
nullable: false,
|
|
8600
|
+
references: {
|
|
8601
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8602
|
+
column: "id"
|
|
8603
|
+
}
|
|
8604
|
+
},
|
|
8605
|
+
addedAt: {
|
|
8606
|
+
type: "timestamp",
|
|
8607
|
+
nullable: false
|
|
8608
|
+
}
|
|
8609
|
+
};
|
|
8610
|
+
const KNOWLEDGE_RECORD_SCOPES_SCHEMA = {
|
|
8611
|
+
recordId: {
|
|
8612
|
+
type: "text",
|
|
8613
|
+
nullable: false,
|
|
8614
|
+
references: {
|
|
8615
|
+
table: TABLE_KNOWLEDGE_RECORDS$1,
|
|
8616
|
+
column: "id"
|
|
8617
|
+
}
|
|
8618
|
+
},
|
|
8619
|
+
scopeNodeId: {
|
|
8620
|
+
type: "text",
|
|
8621
|
+
nullable: false,
|
|
8622
|
+
references: {
|
|
8623
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8624
|
+
column: "id"
|
|
8625
|
+
}
|
|
8626
|
+
},
|
|
8627
|
+
addedAt: {
|
|
8628
|
+
type: "timestamp",
|
|
8629
|
+
nullable: false
|
|
8630
|
+
}
|
|
8631
|
+
};
|
|
8632
|
+
const KNOWLEDGE_SCOPE_GRANTS_SCHEMA = {
|
|
8633
|
+
scopeNodeId: {
|
|
8634
|
+
type: "text",
|
|
8635
|
+
nullable: false,
|
|
8636
|
+
references: {
|
|
8637
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8638
|
+
column: "id"
|
|
8639
|
+
}
|
|
8640
|
+
},
|
|
8641
|
+
scopeRefId: {
|
|
8642
|
+
type: "text",
|
|
8643
|
+
nullable: false,
|
|
8644
|
+
references: {
|
|
8645
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8646
|
+
column: "id"
|
|
8647
|
+
}
|
|
8648
|
+
},
|
|
8649
|
+
role: {
|
|
8650
|
+
type: "text",
|
|
8651
|
+
nullable: false
|
|
8652
|
+
},
|
|
8653
|
+
canSuggest: {
|
|
8654
|
+
type: "boolean",
|
|
8655
|
+
nullable: true
|
|
8656
|
+
}
|
|
8657
|
+
};
|
|
8658
|
+
const KNOWLEDGE_ACCESS_STATE_SCHEMA = {
|
|
8659
|
+
id: {
|
|
8660
|
+
type: "text",
|
|
8661
|
+
nullable: false,
|
|
8662
|
+
primaryKey: true
|
|
8663
|
+
},
|
|
8664
|
+
epoch: {
|
|
8665
|
+
type: "integer",
|
|
8666
|
+
nullable: false
|
|
8667
|
+
},
|
|
8668
|
+
schemaVersion: {
|
|
8669
|
+
type: "integer",
|
|
8670
|
+
nullable: false
|
|
8671
|
+
}
|
|
8672
|
+
};
|
|
8673
|
+
const KNOWLEDGE_SCOPE_ADDRESSES_SCHEMA = {
|
|
8674
|
+
address: {
|
|
8675
|
+
type: "text",
|
|
8676
|
+
nullable: false,
|
|
8677
|
+
primaryKey: true
|
|
8678
|
+
},
|
|
8679
|
+
scopeNodeId: {
|
|
8680
|
+
type: "text",
|
|
8681
|
+
nullable: false,
|
|
8682
|
+
references: {
|
|
8683
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8684
|
+
column: "id"
|
|
8685
|
+
}
|
|
8686
|
+
}
|
|
8687
|
+
};
|
|
8688
|
+
const KNOWLEDGE_NODE_ADDRESSES_SCHEMA = {
|
|
8689
|
+
source: {
|
|
8690
|
+
type: "text",
|
|
8691
|
+
nullable: false
|
|
8692
|
+
},
|
|
8693
|
+
address: {
|
|
8694
|
+
type: "text",
|
|
8695
|
+
nullable: false
|
|
8696
|
+
},
|
|
8697
|
+
nodeId: {
|
|
8698
|
+
type: "text",
|
|
8699
|
+
nullable: false,
|
|
8700
|
+
references: {
|
|
8701
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8702
|
+
column: "id"
|
|
8703
|
+
}
|
|
8704
|
+
}
|
|
8705
|
+
};
|
|
8706
|
+
const KNOWLEDGE_IMPORT_STATE_SCHEMA = {
|
|
8707
|
+
importerId: {
|
|
8708
|
+
type: "text",
|
|
8709
|
+
nullable: false
|
|
8710
|
+
},
|
|
8711
|
+
binding: {
|
|
8712
|
+
type: "text",
|
|
8713
|
+
nullable: false
|
|
8714
|
+
},
|
|
8715
|
+
key: {
|
|
8716
|
+
type: "text",
|
|
8717
|
+
nullable: false
|
|
8718
|
+
},
|
|
8719
|
+
value: {
|
|
8720
|
+
type: "text",
|
|
8721
|
+
nullable: false
|
|
8722
|
+
}
|
|
8723
|
+
};
|
|
8724
|
+
const KNOWLEDGE_IMPORT_RUNS_SCHEMA = {
|
|
8725
|
+
id: {
|
|
8726
|
+
type: "text",
|
|
8727
|
+
nullable: false,
|
|
8728
|
+
primaryKey: true
|
|
8729
|
+
},
|
|
8730
|
+
importerId: {
|
|
8731
|
+
type: "text",
|
|
8732
|
+
nullable: false
|
|
8733
|
+
},
|
|
8734
|
+
binding: {
|
|
8735
|
+
type: "text",
|
|
8736
|
+
nullable: false
|
|
8737
|
+
},
|
|
8738
|
+
importKind: {
|
|
8739
|
+
type: "text",
|
|
8740
|
+
nullable: false
|
|
8741
|
+
},
|
|
8742
|
+
triggerKind: {
|
|
8743
|
+
type: "text",
|
|
8744
|
+
nullable: false
|
|
8745
|
+
},
|
|
8746
|
+
status: {
|
|
8747
|
+
type: "text",
|
|
8748
|
+
nullable: false
|
|
8749
|
+
},
|
|
8750
|
+
error: {
|
|
8751
|
+
type: "text",
|
|
8752
|
+
nullable: true
|
|
8753
|
+
},
|
|
8754
|
+
transcriptThreadId: {
|
|
8755
|
+
type: "text",
|
|
8756
|
+
nullable: true
|
|
8757
|
+
},
|
|
8758
|
+
traceId: {
|
|
8759
|
+
type: "text",
|
|
8760
|
+
nullable: true
|
|
8761
|
+
},
|
|
8762
|
+
queuedAt: {
|
|
8763
|
+
type: "timestamp",
|
|
8764
|
+
nullable: false
|
|
8765
|
+
},
|
|
8766
|
+
startedAt: {
|
|
8767
|
+
type: "timestamp",
|
|
8768
|
+
nullable: true
|
|
8769
|
+
},
|
|
8770
|
+
completedAt: {
|
|
8771
|
+
type: "timestamp",
|
|
8772
|
+
nullable: true
|
|
8773
|
+
}
|
|
8774
|
+
};
|
|
8775
|
+
const KNOWLEDGE_V2_ACTIVITY_SCHEMA = {
|
|
8776
|
+
id: {
|
|
8777
|
+
type: "text",
|
|
8778
|
+
nullable: false,
|
|
8779
|
+
primaryKey: true
|
|
8780
|
+
},
|
|
8781
|
+
action: {
|
|
8782
|
+
type: "text",
|
|
8783
|
+
nullable: false
|
|
8784
|
+
},
|
|
8785
|
+
targetType: {
|
|
8786
|
+
type: "text",
|
|
8787
|
+
nullable: true
|
|
8788
|
+
},
|
|
8789
|
+
targetId: {
|
|
8790
|
+
type: "text",
|
|
8791
|
+
nullable: true
|
|
8792
|
+
},
|
|
8793
|
+
contextScopeId: {
|
|
8794
|
+
type: "text",
|
|
8795
|
+
nullable: true,
|
|
8796
|
+
references: {
|
|
8797
|
+
table: TABLE_KNOWLEDGE_NODES$1,
|
|
8798
|
+
column: "id"
|
|
8799
|
+
}
|
|
8800
|
+
},
|
|
8801
|
+
importRunId: {
|
|
8802
|
+
type: "text",
|
|
8803
|
+
nullable: true,
|
|
8804
|
+
references: {
|
|
8805
|
+
table: TABLE_KNOWLEDGE_IMPORT_RUNS,
|
|
8806
|
+
column: "id"
|
|
8807
|
+
}
|
|
8808
|
+
},
|
|
8809
|
+
details: {
|
|
8810
|
+
type: "jsonb",
|
|
8811
|
+
nullable: true
|
|
8812
|
+
},
|
|
8813
|
+
createdAt: {
|
|
8814
|
+
type: "timestamp",
|
|
8815
|
+
nullable: false
|
|
8816
|
+
},
|
|
8817
|
+
recordType: {
|
|
8818
|
+
type: "text",
|
|
8819
|
+
nullable: true
|
|
8820
|
+
},
|
|
8821
|
+
recordId: {
|
|
8822
|
+
type: "text",
|
|
8823
|
+
nullable: true
|
|
8824
|
+
},
|
|
8825
|
+
scope: {
|
|
8826
|
+
type: "jsonb",
|
|
8827
|
+
nullable: true
|
|
8828
|
+
},
|
|
8829
|
+
scopeKey: {
|
|
8830
|
+
type: "text",
|
|
8831
|
+
nullable: true
|
|
8832
|
+
},
|
|
8833
|
+
sourceThreadId: {
|
|
8834
|
+
type: "text",
|
|
8835
|
+
nullable: true
|
|
8836
|
+
}
|
|
8837
|
+
};
|
|
8838
|
+
const KNOWLEDGE_PROPOSALS_SCHEMA = {
|
|
8839
|
+
id: {
|
|
8840
|
+
type: "text",
|
|
8841
|
+
nullable: false,
|
|
8842
|
+
primaryKey: true
|
|
8843
|
+
},
|
|
8844
|
+
targetType: {
|
|
8845
|
+
type: "text",
|
|
8846
|
+
nullable: false
|
|
8847
|
+
},
|
|
8848
|
+
targetId: {
|
|
8849
|
+
type: "text",
|
|
8850
|
+
nullable: false
|
|
8851
|
+
},
|
|
8852
|
+
action: {
|
|
8853
|
+
type: "text",
|
|
8854
|
+
nullable: false
|
|
8855
|
+
},
|
|
8856
|
+
changes: {
|
|
8857
|
+
type: "jsonb",
|
|
8858
|
+
nullable: false
|
|
8859
|
+
},
|
|
8860
|
+
reason: {
|
|
8861
|
+
type: "text",
|
|
8862
|
+
nullable: true
|
|
8863
|
+
},
|
|
8864
|
+
proposerContextScopeId: {
|
|
8865
|
+
type: "text",
|
|
8866
|
+
nullable: false
|
|
8867
|
+
},
|
|
8868
|
+
expectedVersion: {
|
|
8869
|
+
type: "integer",
|
|
8870
|
+
nullable: false
|
|
8871
|
+
},
|
|
8872
|
+
status: {
|
|
8873
|
+
type: "text",
|
|
8874
|
+
nullable: false
|
|
8875
|
+
},
|
|
8876
|
+
reviewerContextScopeId: {
|
|
8877
|
+
type: "text",
|
|
8878
|
+
nullable: true
|
|
8879
|
+
},
|
|
8880
|
+
reviewedAt: {
|
|
8881
|
+
type: "timestamp",
|
|
8882
|
+
nullable: true
|
|
8883
|
+
},
|
|
8884
|
+
createdAt: {
|
|
8885
|
+
type: "timestamp",
|
|
8886
|
+
nullable: false
|
|
8887
|
+
}
|
|
8888
|
+
};
|
|
8889
|
+
function assertKnowledgeV2CoreSupport(features) {
|
|
8890
|
+
if (!features.has("knowledge-v2")) throw new Error(`Knowledge v2 requires a @mastra/core release with the "${KNOWLEDGE_V2_CORE_FEATURE}" feature. Upgrade @mastra/core to use Knowledge; other storage domains keep working on this version.`);
|
|
8891
|
+
}
|
|
8892
|
+
function resolveKnowledgeV2Core(storageModule) {
|
|
8893
|
+
if (typeof storageModule !== "object" || storageModule === null) throw new Error("@mastra/core advertises Knowledge v2 without the required storage API");
|
|
8894
|
+
const { assertKnowledgeDescriptionWithinBound: assertDescription, assertKnowledgeRecordTextWithinBound: assertRecordText, assertKnowledgeSchemaCompatible: assertCompatible, inspectKnowledgeSchema: inspectSchema } = storageModule;
|
|
8895
|
+
if (typeof assertDescription !== "function" || typeof assertRecordText !== "function" || typeof assertCompatible !== "function" || typeof inspectSchema !== "function") throw new Error("@mastra/core advertises Knowledge v2 without the required storage API");
|
|
8896
|
+
return {
|
|
8897
|
+
assertKnowledgeDescriptionWithinBound: (description) => assertDescription(description),
|
|
8898
|
+
assertKnowledgeRecordTextWithinBound: (text) => assertRecordText(text),
|
|
8899
|
+
assertKnowledgeSchemaCompatible: (inspection) => assertCompatible(inspection),
|
|
8900
|
+
inspectKnowledgeSchema: (snapshot) => inspectSchema(snapshot)
|
|
8901
|
+
};
|
|
8902
|
+
}
|
|
8903
|
+
function createKnowledgeV2CoreLoader(features, loadStorageModule) {
|
|
8904
|
+
let knowledgeV2Core;
|
|
8905
|
+
return async () => {
|
|
8906
|
+
assertKnowledgeV2CoreSupport(features);
|
|
8907
|
+
knowledgeV2Core ??= loadStorageModule().then(resolveKnowledgeV2Core).catch((error) => {
|
|
8908
|
+
knowledgeV2Core = void 0;
|
|
8909
|
+
throw error;
|
|
8910
|
+
});
|
|
8911
|
+
return knowledgeV2Core;
|
|
8912
|
+
};
|
|
8913
|
+
}
|
|
8914
|
+
//#endregion
|
|
8238
8915
|
//#region src/storage/domains/knowledge/index.ts
|
|
8239
|
-
|
|
8916
|
+
const loadKnowledgeV2Core = createKnowledgeV2CoreLoader(coreFeatures, () => import("@mastra/core/storage"));
|
|
8240
8917
|
async function assertKnowledgeDescriptionWithinBoundCompat(description) {
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
assertWithinBound = resolvedAssert;
|
|
8248
|
-
}
|
|
8249
|
-
assertWithinBound(description);
|
|
8918
|
+
const { assertKnowledgeDescriptionWithinBound } = await loadKnowledgeV2Core();
|
|
8919
|
+
assertKnowledgeDescriptionWithinBound(description);
|
|
8920
|
+
}
|
|
8921
|
+
async function assertKnowledgeRecordTextWithinBoundCompat(text) {
|
|
8922
|
+
const { assertKnowledgeRecordTextWithinBound } = await loadKnowledgeV2Core();
|
|
8923
|
+
assertKnowledgeRecordTextWithinBound(text);
|
|
8250
8924
|
}
|
|
8251
8925
|
const camelCaseColumns = [
|
|
8252
8926
|
"canonicalName",
|
|
@@ -8257,7 +8931,6 @@ const camelCaseColumns = [
|
|
|
8257
8931
|
"node",
|
|
8258
8932
|
"sourceThreadId",
|
|
8259
8933
|
"capturedAt",
|
|
8260
|
-
"maxScope",
|
|
8261
8934
|
"deletedAt",
|
|
8262
8935
|
"deletedBy",
|
|
8263
8936
|
"sourceType",
|
|
@@ -8271,7 +8944,30 @@ const camelCaseColumns = [
|
|
|
8271
8944
|
"availableAt",
|
|
8272
8945
|
"claimedAt",
|
|
8273
8946
|
"claimedBy",
|
|
8274
|
-
"completedAt"
|
|
8947
|
+
"completedAt",
|
|
8948
|
+
"isScope",
|
|
8949
|
+
"nodeId",
|
|
8950
|
+
"targetNodeId",
|
|
8951
|
+
"scopeNodeId",
|
|
8952
|
+
"scopeRefId",
|
|
8953
|
+
"canSuggest",
|
|
8954
|
+
"schemaVersion",
|
|
8955
|
+
"importerId",
|
|
8956
|
+
"importKind",
|
|
8957
|
+
"triggerKind",
|
|
8958
|
+
"transcriptThreadId",
|
|
8959
|
+
"traceId",
|
|
8960
|
+
"queuedAt",
|
|
8961
|
+
"startedAt",
|
|
8962
|
+
"targetType",
|
|
8963
|
+
"targetId",
|
|
8964
|
+
"contextScopeId",
|
|
8965
|
+
"importRunId",
|
|
8966
|
+
"proposerContextScopeId",
|
|
8967
|
+
"expectedVersion",
|
|
8968
|
+
"reviewerContextScopeId",
|
|
8969
|
+
"reviewedAt",
|
|
8970
|
+
"addedAt"
|
|
8275
8971
|
];
|
|
8276
8972
|
function transformSqlCode(sql, transform) {
|
|
8277
8973
|
return sql.split(/('(?:''|[^'])*')/g).map((part, index) => index % 2 === 0 ? transform(part) : part).join("");
|
|
@@ -8286,14 +8982,7 @@ function postgresSql(sql, schemaName) {
|
|
|
8286
8982
|
const quotedSchema = `"${parseSchemaName(schemaName)}"`;
|
|
8287
8983
|
normalized = transformSqlCode(normalized, (code) => {
|
|
8288
8984
|
let transformed = code;
|
|
8289
|
-
for (const table of [
|
|
8290
|
-
TABLE_KNOWLEDGE_NODES,
|
|
8291
|
-
TABLE_KNOWLEDGE_RECORDS,
|
|
8292
|
-
TABLE_KNOWLEDGE_MENTIONS,
|
|
8293
|
-
TABLE_KNOWLEDGE_CURSORS,
|
|
8294
|
-
TABLE_KNOWLEDGE_ACTIVITY,
|
|
8295
|
-
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
|
|
8296
|
-
]) transformed = transformed.replaceAll(`"${table}"`, `${quotedSchema}."${table}"`);
|
|
8985
|
+
for (const table of [...KNOWLEDGE_TABLE_NAMES, ...RETIRED_KNOWLEDGE_TABLE_NAMES]) transformed = transformed.replaceAll(`"${table}"`, `${quotedSchema}."${table}"`);
|
|
8297
8986
|
return transformed;
|
|
8298
8987
|
});
|
|
8299
8988
|
}
|
|
@@ -8301,17 +8990,35 @@ function postgresSql(sql, schemaName) {
|
|
|
8301
8990
|
return transformSqlCode(normalized, (code) => code.replace(/\?/g, () => `$${++index}`));
|
|
8302
8991
|
}
|
|
8303
8992
|
function createExecutor(client, schemaName) {
|
|
8304
|
-
|
|
8993
|
+
const execute = async (statement, qualifyWithSchema) => {
|
|
8305
8994
|
const sql = typeof statement === "string" ? statement : statement.sql;
|
|
8306
8995
|
const args = typeof statement === "string" ? [] : statement.args ?? [];
|
|
8307
|
-
const result = await client.query(postgresSql(sql, schemaName), args);
|
|
8996
|
+
const result = await client.query(postgresSql(sql, qualifyWithSchema ? schemaName : void 0), args);
|
|
8308
8997
|
return {
|
|
8309
8998
|
rows: result.rows,
|
|
8310
8999
|
rowsAffected: result.rowCount ?? 0
|
|
8311
9000
|
};
|
|
8312
|
-
}
|
|
9001
|
+
};
|
|
9002
|
+
return {
|
|
9003
|
+
execute: (statement) => execute(statement, true),
|
|
9004
|
+
executeRaw: (statement) => execute(statement, false)
|
|
9005
|
+
};
|
|
9006
|
+
}
|
|
9007
|
+
/**
|
|
9008
|
+
* Scope keys visible to a caller holding `scope`: a row is visible when its scope is a subset of the
|
|
9009
|
+
* caller's (companion entries such as `resource:x:uncurated` make this more than a prefix match).
|
|
9010
|
+
* Matching rows by `scopeKey` keeps visibility filters on an index; a caller scope has only a few
|
|
9011
|
+
* entries, so the list stays small.
|
|
9012
|
+
*/
|
|
9013
|
+
function visibleScopeKeys(scope) {
|
|
9014
|
+
const canonical = canonicalizeKnowledgeScope(scope);
|
|
9015
|
+
const keys = /* @__PURE__ */ new Set();
|
|
9016
|
+
for (let mask = 1; mask < 1 << canonical.length; mask++) try {
|
|
9017
|
+
keys.add(knowledgeScopeKey(canonical.filter((_, index) => mask & 1 << index)));
|
|
9018
|
+
} catch {}
|
|
9019
|
+
return [...keys];
|
|
8313
9020
|
}
|
|
8314
|
-
const visibleSql =
|
|
9021
|
+
const visibleSql = (keys, scopeKeyColumn = "scopeKey") => `${scopeKeyColumn} IN (${keys.map(() => "?").join(",")})`;
|
|
8315
9022
|
function parseJson$1(value) {
|
|
8316
9023
|
if (typeof value === "string") return JSON.parse(value);
|
|
8317
9024
|
if (value instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(value));
|
|
@@ -8351,9 +9058,10 @@ function parseNode(row) {
|
|
|
8351
9058
|
id: String(row.id),
|
|
8352
9059
|
type: "node",
|
|
8353
9060
|
name: String(row.name),
|
|
8354
|
-
kind: String(row.kind),
|
|
9061
|
+
kind: row.kind == null ? "" : String(row.kind),
|
|
8355
9062
|
content: row.content == null ? void 0 : String(row.content),
|
|
8356
9063
|
description: row.description == null ? void 0 : String(row.description),
|
|
9064
|
+
isScope: row.isScope === true || row.isScope === 1 ? true : void 0,
|
|
8357
9065
|
scope: parseJson$1(row.scopeJson ?? row.scope),
|
|
8358
9066
|
version: Number(row.version),
|
|
8359
9067
|
mergedInto: row.mergedInto == null ? void 0 : String(row.mergedInto),
|
|
@@ -8370,7 +9078,6 @@ function parseKnowledge(row) {
|
|
|
8370
9078
|
sourceThreadId: String(row.sourceThreadId),
|
|
8371
9079
|
capturedAt: toDate$1(row.capturedAt),
|
|
8372
9080
|
when: optionalDate(row.when),
|
|
8373
|
-
maxScope: row.maxScope == null ? void 0 : String(row.maxScope),
|
|
8374
9081
|
metadata: row.metadata == null ? void 0 : parseJson$1(row.metadata),
|
|
8375
9082
|
deletedAt: optionalDate(row.deletedAt),
|
|
8376
9083
|
deletedBy: row.deletedBy == null ? void 0 : String(row.deletedBy)
|
|
@@ -8407,6 +9114,10 @@ function knowledgeIndexes(schemaName) {
|
|
|
8407
9114
|
name: "idx_knowledge_nodes_scope",
|
|
8408
9115
|
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_nodes_scope ON ${table(TABLE_KNOWLEDGE_NODES)} ("scopeKey", "type");`
|
|
8409
9116
|
},
|
|
9117
|
+
{
|
|
9118
|
+
name: "idx_knowledge_nodes_name",
|
|
9119
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_nodes_name ON ${table(TABLE_KNOWLEDGE_NODES)} ("type", "canonicalName");`
|
|
9120
|
+
},
|
|
8410
9121
|
{
|
|
8411
9122
|
name: "idx_knowledge_records_node_latest",
|
|
8412
9123
|
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_records_node_latest ON ${table(TABLE_KNOWLEDGE_RECORDS)} ("node", "id" DESC);`
|
|
@@ -8423,6 +9134,14 @@ function knowledgeIndexes(schemaName) {
|
|
|
8423
9134
|
name: "idx_knowledge_activity_latest",
|
|
8424
9135
|
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_latest ON ${table(TABLE_KNOWLEDGE_ACTIVITY)} ("id" DESC);`
|
|
8425
9136
|
},
|
|
9137
|
+
{
|
|
9138
|
+
name: "idx_knowledge_records_scope",
|
|
9139
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_records_scope ON ${table(TABLE_KNOWLEDGE_RECORDS)} ("scopeKey", "id");`
|
|
9140
|
+
},
|
|
9141
|
+
{
|
|
9142
|
+
name: "idx_knowledge_activity_scope",
|
|
9143
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_scope ON ${table(TABLE_KNOWLEDGE_ACTIVITY)} ("scopeKey", "id" DESC);`
|
|
9144
|
+
},
|
|
8426
9145
|
{
|
|
8427
9146
|
name: "idx_knowledge_outbox_idempotency",
|
|
8428
9147
|
sql: `CREATE UNIQUE INDEX IF NOT EXISTS idx_knowledge_outbox_idempotency ON ${table(TABLE_KNOWLEDGE_SEMANTIC_OUTBOX)} ("idempotencyKey");`
|
|
@@ -8430,67 +9149,152 @@ function knowledgeIndexes(schemaName) {
|
|
|
8430
9149
|
{
|
|
8431
9150
|
name: "idx_knowledge_outbox_claim",
|
|
8432
9151
|
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_outbox_claim ON ${table(TABLE_KNOWLEDGE_SEMANTIC_OUTBOX)} ("status", "availableAt", "createdAt");`
|
|
9152
|
+
},
|
|
9153
|
+
{
|
|
9154
|
+
name: "idx_knowledge_node_scopes_scope",
|
|
9155
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_node_scopes_scope ON ${table(TABLE_KNOWLEDGE_NODE_SCOPES)} ("scopeNodeId", "nodeId");`
|
|
9156
|
+
},
|
|
9157
|
+
{
|
|
9158
|
+
name: "idx_knowledge_record_scopes_scope",
|
|
9159
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_record_scopes_scope ON ${table(TABLE_KNOWLEDGE_RECORD_SCOPES)} ("scopeNodeId", "recordId");`
|
|
9160
|
+
},
|
|
9161
|
+
{
|
|
9162
|
+
name: "idx_knowledge_scope_grants_ref",
|
|
9163
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_scope_grants_ref ON ${table(TABLE_KNOWLEDGE_SCOPE_GRANTS)} ("scopeRefId", "scopeNodeId");`
|
|
9164
|
+
},
|
|
9165
|
+
{
|
|
9166
|
+
name: "idx_knowledge_node_addresses_node",
|
|
9167
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_node_addresses_node ON ${table(TABLE_KNOWLEDGE_NODE_ADDRESSES)} ("nodeId");`
|
|
9168
|
+
},
|
|
9169
|
+
{
|
|
9170
|
+
name: "idx_knowledge_import_runs_lookup",
|
|
9171
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_import_runs_lookup ON ${table(TABLE_KNOWLEDGE_IMPORT_RUNS)} ("importerId", "binding", "queuedAt" DESC);`
|
|
9172
|
+
},
|
|
9173
|
+
{
|
|
9174
|
+
name: "idx_knowledge_activity_import_run",
|
|
9175
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_import_run ON ${table(TABLE_KNOWLEDGE_ACTIVITY)} ("importRunId", "id" DESC);`
|
|
8433
9176
|
}
|
|
8434
9177
|
];
|
|
8435
9178
|
}
|
|
8436
9179
|
function knowledgeIndexDDL(schemaName) {
|
|
8437
9180
|
return knowledgeIndexes(schemaName).map((index) => index.sql);
|
|
8438
9181
|
}
|
|
9182
|
+
const KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE = "Knowledge curation cursors were removed: observation-time curate is the only Knowledge writer and needs no cursor.";
|
|
9183
|
+
const knowledgeTableDefinitions = [
|
|
9184
|
+
{
|
|
9185
|
+
tableName: TABLE_KNOWLEDGE_NODES,
|
|
9186
|
+
schema: KNOWLEDGE_V2_NODES_SCHEMA
|
|
9187
|
+
},
|
|
9188
|
+
{
|
|
9189
|
+
tableName: TABLE_KNOWLEDGE_RECORDS,
|
|
9190
|
+
schema: KNOWLEDGE_V2_RECORDS_SCHEMA
|
|
9191
|
+
},
|
|
9192
|
+
{
|
|
9193
|
+
tableName: TABLE_KNOWLEDGE_MENTIONS,
|
|
9194
|
+
schema: KNOWLEDGE_V2_MENTIONS_SCHEMA,
|
|
9195
|
+
compositePrimaryKey: ["recordId", "sourceId"]
|
|
9196
|
+
},
|
|
9197
|
+
{
|
|
9198
|
+
tableName: TABLE_KNOWLEDGE_NODE_SCOPES,
|
|
9199
|
+
schema: KNOWLEDGE_NODE_SCOPES_SCHEMA,
|
|
9200
|
+
compositePrimaryKey: ["nodeId", "scopeNodeId"]
|
|
9201
|
+
},
|
|
9202
|
+
{
|
|
9203
|
+
tableName: TABLE_KNOWLEDGE_RECORD_SCOPES,
|
|
9204
|
+
schema: KNOWLEDGE_RECORD_SCOPES_SCHEMA,
|
|
9205
|
+
compositePrimaryKey: ["recordId", "scopeNodeId"]
|
|
9206
|
+
},
|
|
9207
|
+
{
|
|
9208
|
+
tableName: TABLE_KNOWLEDGE_SCOPE_GRANTS,
|
|
9209
|
+
schema: KNOWLEDGE_SCOPE_GRANTS_SCHEMA,
|
|
9210
|
+
compositePrimaryKey: ["scopeNodeId", "scopeRefId"]
|
|
9211
|
+
},
|
|
9212
|
+
{
|
|
9213
|
+
tableName: TABLE_KNOWLEDGE_ACCESS_STATE,
|
|
9214
|
+
schema: KNOWLEDGE_ACCESS_STATE_SCHEMA
|
|
9215
|
+
},
|
|
9216
|
+
{
|
|
9217
|
+
tableName: TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
|
|
9218
|
+
schema: KNOWLEDGE_SCOPE_ADDRESSES_SCHEMA
|
|
9219
|
+
},
|
|
9220
|
+
{
|
|
9221
|
+
tableName: TABLE_KNOWLEDGE_NODE_ADDRESSES,
|
|
9222
|
+
schema: KNOWLEDGE_NODE_ADDRESSES_SCHEMA,
|
|
9223
|
+
compositePrimaryKey: ["source", "address"]
|
|
9224
|
+
},
|
|
9225
|
+
{
|
|
9226
|
+
tableName: TABLE_KNOWLEDGE_IMPORT_STATE,
|
|
9227
|
+
schema: KNOWLEDGE_IMPORT_STATE_SCHEMA,
|
|
9228
|
+
compositePrimaryKey: [
|
|
9229
|
+
"importerId",
|
|
9230
|
+
"binding",
|
|
9231
|
+
"key"
|
|
9232
|
+
]
|
|
9233
|
+
},
|
|
9234
|
+
{
|
|
9235
|
+
tableName: TABLE_KNOWLEDGE_IMPORT_RUNS,
|
|
9236
|
+
schema: KNOWLEDGE_IMPORT_RUNS_SCHEMA
|
|
9237
|
+
},
|
|
9238
|
+
{
|
|
9239
|
+
tableName: TABLE_KNOWLEDGE_PROPOSALS,
|
|
9240
|
+
schema: KNOWLEDGE_PROPOSALS_SCHEMA
|
|
9241
|
+
},
|
|
9242
|
+
{
|
|
9243
|
+
tableName: TABLE_KNOWLEDGE_ACTIVITY,
|
|
9244
|
+
schema: KNOWLEDGE_V2_ACTIVITY_SCHEMA
|
|
9245
|
+
},
|
|
9246
|
+
{
|
|
9247
|
+
tableName: TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
|
|
9248
|
+
schema: KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
|
|
9249
|
+
}
|
|
9250
|
+
];
|
|
9251
|
+
function pgSetting(config, key) {
|
|
9252
|
+
const value = config[key] || process.env[`PG${key.toUpperCase()}`] || defaults[key];
|
|
9253
|
+
return value === void 0 || value === null || value === "" ? void 0 : String(value);
|
|
9254
|
+
}
|
|
9255
|
+
function effectivePgTarget(config) {
|
|
9256
|
+
const host = pgSetting(config, "host");
|
|
9257
|
+
const database = pgSetting(config, "database") ?? pgSetting(config, "user");
|
|
9258
|
+
if (!host || !database) return void 0;
|
|
9259
|
+
return `${host.startsWith("/") ? host : host.toLocaleLowerCase()}:${pgSetting(config, "port") ?? "5432"}/${database}`;
|
|
9260
|
+
}
|
|
9261
|
+
function canonicalPgTarget(config) {
|
|
9262
|
+
if (config.connectionString) try {
|
|
9263
|
+
const parsed = new URL(config.connectionString);
|
|
9264
|
+
return effectivePgTarget({
|
|
9265
|
+
host: decodeURIComponent(parsed.hostname) || config.host,
|
|
9266
|
+
port: parsed.port || config.port,
|
|
9267
|
+
database: decodeURIComponent(parsed.pathname.slice(1)) || config.database,
|
|
9268
|
+
user: decodeURIComponent(parsed.username) || config.user
|
|
9269
|
+
});
|
|
9270
|
+
} catch {
|
|
9271
|
+
return config.connectionString;
|
|
9272
|
+
}
|
|
9273
|
+
return effectivePgTarget(config);
|
|
9274
|
+
}
|
|
9275
|
+
function pgSourceConfig(source) {
|
|
9276
|
+
if (!source || !("options" in source)) return void 0;
|
|
9277
|
+
return source.options;
|
|
9278
|
+
}
|
|
9279
|
+
function pgClientPool(client) {
|
|
9280
|
+
if (!client || !("$pool" in client)) return void 0;
|
|
9281
|
+
return client.$pool;
|
|
9282
|
+
}
|
|
9283
|
+
function getPgKnowledgeIsolationKey(config) {
|
|
9284
|
+
const schema = config.schemaName ?? "public";
|
|
9285
|
+
const poolConfig = pgSourceConfig(config.pool ?? pgClientPool(config.client));
|
|
9286
|
+
const target = Boolean(config.connectionString || config.host || config.database) ? canonicalPgTarget(config) : poolConfig ? canonicalPgTarget(poolConfig) : void 0;
|
|
9287
|
+
if (target) return `pg:${target}:schema:${schema}`;
|
|
9288
|
+
return `pg:unidentified:schema:${schema}`;
|
|
9289
|
+
}
|
|
8439
9290
|
var KnowledgePG = class extends KnowledgeStorage {
|
|
8440
|
-
static MANAGED_TABLES =
|
|
8441
|
-
TABLE_KNOWLEDGE_NODES,
|
|
8442
|
-
TABLE_KNOWLEDGE_RECORDS,
|
|
8443
|
-
TABLE_KNOWLEDGE_MENTIONS,
|
|
8444
|
-
TABLE_KNOWLEDGE_CURSORS,
|
|
8445
|
-
TABLE_KNOWLEDGE_ACTIVITY,
|
|
8446
|
-
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
|
|
8447
|
-
];
|
|
9291
|
+
static MANAGED_TABLES = KNOWLEDGE_TABLE_NAMES;
|
|
8448
9292
|
static getExportDDL(schemaName) {
|
|
8449
|
-
return [
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
includeAllConstraints: true
|
|
8455
|
-
}),
|
|
8456
|
-
generateTableSQL({
|
|
8457
|
-
tableName: TABLE_KNOWLEDGE_RECORDS,
|
|
8458
|
-
schema: KNOWLEDGE_RECORDS_SCHEMA,
|
|
8459
|
-
schemaName,
|
|
8460
|
-
includeAllConstraints: true
|
|
8461
|
-
}),
|
|
8462
|
-
generateTableSQL({
|
|
8463
|
-
tableName: TABLE_KNOWLEDGE_MENTIONS,
|
|
8464
|
-
schema: KNOWLEDGE_MENTIONS_SCHEMA,
|
|
8465
|
-
schemaName,
|
|
8466
|
-
compositePrimaryKey: [
|
|
8467
|
-
"sourceType",
|
|
8468
|
-
"sourceId",
|
|
8469
|
-
"recordId"
|
|
8470
|
-
],
|
|
8471
|
-
includeAllConstraints: true
|
|
8472
|
-
}),
|
|
8473
|
-
generateTableSQL({
|
|
8474
|
-
tableName: TABLE_KNOWLEDGE_CURSORS,
|
|
8475
|
-
schema: KNOWLEDGE_CURSORS_SCHEMA,
|
|
8476
|
-
schemaName,
|
|
8477
|
-
compositePrimaryKey: ["sourceThreadId", "agent"],
|
|
8478
|
-
includeAllConstraints: true
|
|
8479
|
-
}),
|
|
8480
|
-
generateTableSQL({
|
|
8481
|
-
tableName: TABLE_KNOWLEDGE_ACTIVITY,
|
|
8482
|
-
schema: KNOWLEDGE_ACTIVITY_SCHEMA,
|
|
8483
|
-
schemaName,
|
|
8484
|
-
includeAllConstraints: true
|
|
8485
|
-
}),
|
|
8486
|
-
generateTableSQL({
|
|
8487
|
-
tableName: TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
|
|
8488
|
-
schema: KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA,
|
|
8489
|
-
schemaName,
|
|
8490
|
-
includeAllConstraints: true
|
|
8491
|
-
}),
|
|
8492
|
-
...knowledgeIndexDDL(schemaName)
|
|
8493
|
-
];
|
|
9293
|
+
return [...knowledgeTableDefinitions.map((definition) => generateTableSQL({
|
|
9294
|
+
...definition,
|
|
9295
|
+
schemaName,
|
|
9296
|
+
includeAllConstraints: true
|
|
9297
|
+
})), ...knowledgeIndexDDL(schemaName)];
|
|
8494
9298
|
}
|
|
8495
9299
|
#client;
|
|
8496
9300
|
#executor;
|
|
@@ -8499,7 +9303,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8499
9303
|
#db;
|
|
8500
9304
|
#schemaName;
|
|
8501
9305
|
constructor(config) {
|
|
8502
|
-
super();
|
|
9306
|
+
super({ storageIsolationKey: config.storageIsolationKey ?? getPgKnowledgeIsolationKey(config) });
|
|
8503
9307
|
const { client, readClient, schemaName, skipDefaultIndexes } = resolvePgConfig(config);
|
|
8504
9308
|
this.#client = client;
|
|
8505
9309
|
this.#schemaName = schemaName;
|
|
@@ -8512,56 +9316,359 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8512
9316
|
skipDefaultIndexes
|
|
8513
9317
|
});
|
|
8514
9318
|
}
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
9319
|
+
getCapabilities() {
|
|
9320
|
+
return {
|
|
9321
|
+
contractVersion: 2,
|
|
9322
|
+
schemaVersion: 2,
|
|
9323
|
+
supportsV2: true,
|
|
9324
|
+
supportsSchemaInspection: true,
|
|
9325
|
+
supportsExplicitReset: true
|
|
9326
|
+
};
|
|
9327
|
+
}
|
|
9328
|
+
async inspectSchema() {
|
|
9329
|
+
const { inspectKnowledgeSchema } = await loadKnowledgeV2Core();
|
|
9330
|
+
try {
|
|
9331
|
+
const snapshot = getSchemaSnapshot(this.#client, this.#schemaName);
|
|
9332
|
+
if (snapshot) {
|
|
9333
|
+
const tableNames = KNOWLEDGE_TABLE_NAMES.filter((table) => snapshot.tables.has(table));
|
|
9334
|
+
return this.#classifySchema(this.#executor, tableNames, snapshot.columns);
|
|
9335
|
+
}
|
|
9336
|
+
return this.#inspectSchemaWithExecutor(this.#executor);
|
|
9337
|
+
} catch (error) {
|
|
9338
|
+
return inspectKnowledgeSchema({
|
|
9339
|
+
available: false,
|
|
9340
|
+
tableNames: [],
|
|
9341
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
9342
|
+
});
|
|
9343
|
+
}
|
|
9344
|
+
}
|
|
9345
|
+
async #inspectSchemaWithExecutor(executor) {
|
|
9346
|
+
const tableNames = (await executor.execute({
|
|
9347
|
+
sql: `SELECT table_name FROM information_schema.tables WHERE table_schema = COALESCE(?, current_schema()) AND table_name = ANY(?::text[])`,
|
|
9348
|
+
args: [this.#schemaName ?? null, [...KNOWLEDGE_TABLE_NAMES]]
|
|
9349
|
+
})).rows.map((row) => String(row.table_name));
|
|
9350
|
+
const columnResult = await executor.execute({
|
|
9351
|
+
sql: `SELECT table_name, column_name FROM information_schema.columns WHERE table_schema = COALESCE(?, current_schema()) AND table_name = ANY(?::text[])`,
|
|
9352
|
+
args: [this.#schemaName ?? null, [...KNOWLEDGE_TABLE_NAMES]]
|
|
9353
|
+
});
|
|
9354
|
+
const columns = /* @__PURE__ */ new Map();
|
|
9355
|
+
for (const row of columnResult.rows) {
|
|
9356
|
+
const table = String(row.table_name);
|
|
9357
|
+
const names = columns.get(table) ?? /* @__PURE__ */ new Set();
|
|
9358
|
+
names.add(String(row.column_name));
|
|
9359
|
+
columns.set(table, names);
|
|
9360
|
+
}
|
|
9361
|
+
return this.#classifySchema(executor, tableNames, columns);
|
|
9362
|
+
}
|
|
9363
|
+
async #classifySchema(executor, tableNames, columns) {
|
|
9364
|
+
const { inspectKnowledgeSchema } = await loadKnowledgeV2Core();
|
|
9365
|
+
if (tableNames.length === 0) return inspectKnowledgeSchema({
|
|
9366
|
+
available: true,
|
|
9367
|
+
tableNames
|
|
9368
|
+
});
|
|
9369
|
+
const missingTables = KNOWLEDGE_TABLE_NAMES.filter((table) => !tableNames.includes(table));
|
|
9370
|
+
if (missingTables.length > 0) return inspectKnowledgeSchema({
|
|
9371
|
+
available: true,
|
|
9372
|
+
tableNames,
|
|
9373
|
+
reason: `Missing Knowledge v2 tables: ${missingTables.join(", ")}`
|
|
9374
|
+
});
|
|
9375
|
+
for (const { tableName: table, schema } of knowledgeTableDefinitions) {
|
|
9376
|
+
const actual = columns.get(table) ?? /* @__PURE__ */ new Set();
|
|
9377
|
+
const missing = Object.keys(schema).filter((column) => !actual.has(column));
|
|
9378
|
+
if (missing.length > 0) return inspectKnowledgeSchema({
|
|
9379
|
+
available: true,
|
|
9380
|
+
tableNames,
|
|
9381
|
+
reason: `Knowledge table ${table} is missing v2 columns: ${missing.join(", ")}`
|
|
9382
|
+
});
|
|
9383
|
+
}
|
|
9384
|
+
const accessState = await executor.execute(`SELECT schemaVersion FROM "${TABLE_KNOWLEDGE_ACCESS_STATE}" WHERE id='global'`);
|
|
9385
|
+
if (Number(accessState.rows[0]?.schemaVersion) !== 2) return inspectKnowledgeSchema({
|
|
9386
|
+
available: true,
|
|
9387
|
+
tableNames,
|
|
9388
|
+
reason: "Knowledge schema version marker is missing or incompatible"
|
|
9389
|
+
});
|
|
9390
|
+
return inspectKnowledgeSchema({
|
|
9391
|
+
available: true,
|
|
9392
|
+
tableNames,
|
|
9393
|
+
schemaVersion: 2
|
|
8524
9394
|
});
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
9395
|
+
}
|
|
9396
|
+
async init() {
|
|
9397
|
+
await this.#transaction(async (tx) => {
|
|
9398
|
+
await tx.execute({
|
|
9399
|
+
sql: "SELECT pg_advisory_xact_lock(hashtext(?))",
|
|
9400
|
+
args: [`mastra-knowledge-v2:${this.#schemaName ?? "current_schema"}`]
|
|
9401
|
+
});
|
|
9402
|
+
const { assertKnowledgeSchemaCompatible } = await loadKnowledgeV2Core();
|
|
9403
|
+
let inspection = await this.#inspectSchemaWithExecutor(tx);
|
|
9404
|
+
if (inspection.status === "incompatible-reset-required" && await this.#isPublishedV1Layout(tx)) {
|
|
9405
|
+
const tables = [...RETIRED_KNOWLEDGE_TABLE_NAMES, ...[...KNOWLEDGE_TABLE_NAMES].reverse()].map((table) => `"${table}"`).join(", ");
|
|
9406
|
+
await tx.execute(`DROP TABLE IF EXISTS ${tables}`);
|
|
9407
|
+
inspection = await this.#inspectSchemaWithExecutor(tx);
|
|
9408
|
+
}
|
|
9409
|
+
assertKnowledgeSchemaCompatible(inspection);
|
|
9410
|
+
for (const definition of knowledgeTableDefinitions) await tx.executeRaw(generateTableSQL({
|
|
9411
|
+
...definition,
|
|
9412
|
+
schemaName: this.#schemaName,
|
|
9413
|
+
includeAllConstraints: true
|
|
9414
|
+
}));
|
|
9415
|
+
for (const index of knowledgeIndexes(this.#schemaName)) await tx.executeRaw(index.sql);
|
|
9416
|
+
await tx.execute({
|
|
9417
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_ACCESS_STATE}" (id, epoch, schemaVersion) VALUES ('global', 0, ?) ON CONFLICT (id) DO NOTHING`,
|
|
9418
|
+
args: [2]
|
|
9419
|
+
});
|
|
8528
9420
|
});
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
9421
|
+
}
|
|
9422
|
+
/**
|
|
9423
|
+
* True when the only Knowledge objects are the tables and indexes published v1 adapters created,
|
|
9424
|
+
* with or without rows. Anything else (v2 tables, unknown tables, views, triggers, extra indexes)
|
|
9425
|
+
* needs an explicit reset.
|
|
9426
|
+
*/
|
|
9427
|
+
async #isPublishedV1Layout(executor) {
|
|
9428
|
+
const schema = this.#schemaName ?? null;
|
|
9429
|
+
const relations = await executor.execute({
|
|
9430
|
+
sql: `SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = COALESCE(?, current_schema()) AND table_name LIKE 'mastra\\_knowledge\\_%'`,
|
|
9431
|
+
args: [schema]
|
|
9432
|
+
});
|
|
9433
|
+
const tables = [];
|
|
9434
|
+
for (const row of relations.rows) {
|
|
9435
|
+
const name = String(row.table_name);
|
|
9436
|
+
if (row.table_type !== "BASE TABLE" || !PUBLISHED_KNOWLEDGE_V1_TABLE_NAMES.has(name)) return false;
|
|
9437
|
+
tables.push(name);
|
|
9438
|
+
}
|
|
9439
|
+
const indexes = await executor.execute({
|
|
9440
|
+
sql: `SELECT indexname FROM pg_indexes WHERE schemaname = COALESCE(?, current_schema()) AND tablename = ANY(?::text[])`,
|
|
9441
|
+
args: [schema, tables]
|
|
9442
|
+
});
|
|
9443
|
+
for (const row of indexes.rows) {
|
|
9444
|
+
const name = String(row.indexname);
|
|
9445
|
+
if (!PUBLISHED_KNOWLEDGE_V1_INDEX_NAMES.has(name) && !name.endsWith("_pkey")) return false;
|
|
9446
|
+
}
|
|
9447
|
+
if ((await executor.execute({
|
|
9448
|
+
sql: `SELECT 1 FROM information_schema.view_table_usage WHERE table_schema = COALESCE(?, current_schema()) AND table_name = ANY(?::text[]) UNION ALL SELECT 1 FROM information_schema.triggers WHERE event_object_schema = COALESCE(?, current_schema()) AND event_object_table = ANY(?::text[]) LIMIT 1`,
|
|
9449
|
+
args: [
|
|
9450
|
+
schema,
|
|
9451
|
+
tables,
|
|
9452
|
+
schema,
|
|
9453
|
+
tables
|
|
8536
9454
|
]
|
|
8537
|
-
});
|
|
8538
|
-
|
|
8539
|
-
tableName: TABLE_KNOWLEDGE_CURSORS,
|
|
8540
|
-
schema: KNOWLEDGE_CURSORS_SCHEMA,
|
|
8541
|
-
compositePrimaryKey: ["sourceThreadId", "agent"]
|
|
8542
|
-
});
|
|
8543
|
-
await this.#db.createTable({
|
|
8544
|
-
tableName: TABLE_KNOWLEDGE_ACTIVITY,
|
|
8545
|
-
schema: KNOWLEDGE_ACTIVITY_SCHEMA
|
|
8546
|
-
});
|
|
8547
|
-
await this.#db.createTable({
|
|
8548
|
-
tableName: TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
|
|
8549
|
-
schema: KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
|
|
8550
|
-
});
|
|
8551
|
-
await Promise.all(knowledgeIndexes(this.#schemaName).map((index) => this.#db.createIndexFromStatement(index.name, index.sql)));
|
|
9455
|
+
})).rows.length > 0) return false;
|
|
9456
|
+
return true;
|
|
8552
9457
|
}
|
|
8553
9458
|
async dangerouslyClearAll() {
|
|
8554
9459
|
await this.#transaction(async (tx) => {
|
|
8555
9460
|
for (const table of [
|
|
9461
|
+
TABLE_KNOWLEDGE_RECORD_SCOPES,
|
|
9462
|
+
TABLE_KNOWLEDGE_NODE_SCOPES,
|
|
9463
|
+
TABLE_KNOWLEDGE_SCOPE_GRANTS,
|
|
9464
|
+
TABLE_KNOWLEDGE_SCOPE_ADDRESSES,
|
|
9465
|
+
TABLE_KNOWLEDGE_NODE_ADDRESSES,
|
|
8556
9466
|
TABLE_KNOWLEDGE_MENTIONS,
|
|
8557
|
-
|
|
8558
|
-
TABLE_KNOWLEDGE_NODES,
|
|
8559
|
-
TABLE_KNOWLEDGE_CURSORS,
|
|
9467
|
+
TABLE_KNOWLEDGE_PROPOSALS,
|
|
8560
9468
|
TABLE_KNOWLEDGE_ACTIVITY,
|
|
8561
|
-
|
|
9469
|
+
TABLE_KNOWLEDGE_IMPORT_STATE,
|
|
9470
|
+
TABLE_KNOWLEDGE_IMPORT_RUNS,
|
|
9471
|
+
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
|
|
9472
|
+
TABLE_KNOWLEDGE_RECORDS,
|
|
9473
|
+
TABLE_KNOWLEDGE_NODES
|
|
8562
9474
|
]) await tx.execute(`DELETE FROM "${table}"`);
|
|
9475
|
+
await tx.execute(`UPDATE "${TABLE_KNOWLEDGE_ACCESS_STATE}" SET epoch = 0 WHERE id = 'global'`);
|
|
9476
|
+
});
|
|
9477
|
+
}
|
|
9478
|
+
async dangerouslyReset() {
|
|
9479
|
+
const tables = [...RETIRED_KNOWLEDGE_TABLE_NAMES, ...[...KNOWLEDGE_TABLE_NAMES].reverse()].map((table) => `"${table}"`).join(", ");
|
|
9480
|
+
await this.#executor.execute(`DROP TABLE IF EXISTS ${tables}`);
|
|
9481
|
+
await this.init();
|
|
9482
|
+
}
|
|
9483
|
+
async reconcileStructure(plan) {
|
|
9484
|
+
return this.#transaction(async (tx) => {
|
|
9485
|
+
await tx.execute({
|
|
9486
|
+
sql: `SELECT pg_advisory_xact_lock(hashtext(?))`,
|
|
9487
|
+
args: [`mastra-knowledge-reconcile:${this.#schemaName}`]
|
|
9488
|
+
});
|
|
9489
|
+
const scopes = {};
|
|
9490
|
+
const createdScopeIds = [];
|
|
9491
|
+
const createdAddresses = /* @__PURE__ */ new Set();
|
|
9492
|
+
const retrofit = plan.retrofit ?? true;
|
|
9493
|
+
let structureChanged = false;
|
|
9494
|
+
const deletedScopeAddresses = /* @__PURE__ */ new Set();
|
|
9495
|
+
const resolveAddress = async (address) => {
|
|
9496
|
+
if (scopes[address]) return scopes[address];
|
|
9497
|
+
const row = (await tx.execute({
|
|
9498
|
+
sql: `SELECT a."scopeNodeId",n."isScope",n."deletedAt" FROM "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" a JOIN "${TABLE_KNOWLEDGE_NODES}" n ON n.id=a."scopeNodeId" WHERE a.address=?`,
|
|
9499
|
+
args: [address]
|
|
9500
|
+
})).rows[0];
|
|
9501
|
+
if (!row) return void 0;
|
|
9502
|
+
if (!row.isScope) throw new Error(`Knowledge address ${address} does not reference a scope`);
|
|
9503
|
+
if (row.deletedAt) deletedScopeAddresses.add(address);
|
|
9504
|
+
scopes[address] = String(row.scopeNodeId);
|
|
9505
|
+
return scopes[address];
|
|
9506
|
+
};
|
|
9507
|
+
for (const scope of plan.scopes) {
|
|
9508
|
+
if (await resolveAddress(scope.address)) continue;
|
|
9509
|
+
const id = randomUUID();
|
|
9510
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9511
|
+
await tx.execute({
|
|
9512
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODES}" (id,type,name,"canonicalName",kind,description,"isScope",metadata,version,"createdAt","updatedAt") VALUES (?,'node',?,?,?,?,TRUE,?,1,?,?)`,
|
|
9513
|
+
args: [
|
|
9514
|
+
id,
|
|
9515
|
+
scope.name,
|
|
9516
|
+
canonicalName(scope.name),
|
|
9517
|
+
scope.kind ?? null,
|
|
9518
|
+
scope.description ?? null,
|
|
9519
|
+
scope.metadata ?? null,
|
|
9520
|
+
now,
|
|
9521
|
+
now
|
|
9522
|
+
]
|
|
9523
|
+
});
|
|
9524
|
+
await tx.execute({
|
|
9525
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" (address,"scopeNodeId") VALUES (?,?)`,
|
|
9526
|
+
args: [scope.address, id]
|
|
9527
|
+
});
|
|
9528
|
+
scopes[scope.address] = id;
|
|
9529
|
+
createdAddresses.add(scope.address);
|
|
9530
|
+
createdScopeIds.push(id);
|
|
9531
|
+
structureChanged = true;
|
|
9532
|
+
}
|
|
9533
|
+
for (const scope of plan.scopes) {
|
|
9534
|
+
if (!createdAddresses.has(scope.address) && (!retrofit || deletedScopeAddresses.has(scope.address))) continue;
|
|
9535
|
+
const scopeNodeId = scopes[scope.address];
|
|
9536
|
+
for (const parentAddress of scope.parentAddresses ?? []) {
|
|
9537
|
+
const parentId = await resolveAddress(parentAddress);
|
|
9538
|
+
if (!parentId || deletedScopeAddresses.has(parentAddress)) {
|
|
9539
|
+
const deletedParentId = scopes[parentAddress];
|
|
9540
|
+
if ((deletedParentId ? await tx.execute({
|
|
9541
|
+
sql: `SELECT 1 FROM "mastra_knowledge_node_scopes" WHERE "nodeId"=? AND "scopeNodeId"=?`,
|
|
9542
|
+
args: [scopeNodeId, deletedParentId]
|
|
9543
|
+
}) : void 0)?.rows.length) continue;
|
|
9544
|
+
throw new Error(`Knowledge parent scope does not exist: ${parentAddress}`);
|
|
9545
|
+
}
|
|
9546
|
+
if ((await tx.execute({
|
|
9547
|
+
sql: `SELECT 1 FROM "mastra_knowledge_node_scopes" WHERE "nodeId"=? AND "scopeNodeId"=?`,
|
|
9548
|
+
args: [scopeNodeId, parentId]
|
|
9549
|
+
})).rows.length) continue;
|
|
9550
|
+
if ((await tx.execute({
|
|
9551
|
+
sql: `SELECT n.id FROM "mastra_knowledge_node_scopes" ns JOIN "${TABLE_KNOWLEDGE_NODES}" n ON n.id=ns."nodeId" WHERE ns."scopeNodeId"=? AND n."isScope" AND n."canonicalName"=? AND n."deletedAt" IS NULL AND n.id<>? LIMIT 1`,
|
|
9552
|
+
args: [
|
|
9553
|
+
parentId,
|
|
9554
|
+
canonicalName(scope.name),
|
|
9555
|
+
scopeNodeId
|
|
9556
|
+
]
|
|
9557
|
+
})).rows.length) throw new Error(`Knowledge scope name ${scope.name} already exists under ${parentAddress}`);
|
|
9558
|
+
const inserted = await tx.execute({
|
|
9559
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" ("nodeId","scopeNodeId","addedAt") VALUES (?,?,?) ON CONFLICT DO NOTHING`,
|
|
9560
|
+
args: [
|
|
9561
|
+
scopeNodeId,
|
|
9562
|
+
parentId,
|
|
9563
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
9564
|
+
]
|
|
9565
|
+
});
|
|
9566
|
+
structureChanged ||= inserted.rowsAffected > 0;
|
|
9567
|
+
}
|
|
9568
|
+
for (const grant of scope.grants ?? []) {
|
|
9569
|
+
const scopeRefId = await resolveAddress(grant.scopeRefAddress);
|
|
9570
|
+
if (!scopeRefId || deletedScopeAddresses.has(grant.scopeRefAddress)) {
|
|
9571
|
+
const deletedScopeRefId = scopes[grant.scopeRefAddress];
|
|
9572
|
+
if ((deletedScopeRefId ? await tx.execute({
|
|
9573
|
+
sql: `SELECT 1 FROM "mastra_knowledge_scope_grants" WHERE "scopeNodeId"=? AND "scopeRefId"=?`,
|
|
9574
|
+
args: [scopeNodeId, deletedScopeRefId]
|
|
9575
|
+
}) : void 0)?.rows.length) continue;
|
|
9576
|
+
throw new Error(`Knowledge grant scope does not exist: ${grant.scopeRefAddress}`);
|
|
9577
|
+
}
|
|
9578
|
+
const inserted = await tx.execute({
|
|
9579
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_SCOPE_GRANTS}" ("scopeNodeId","scopeRefId",role,"canSuggest") VALUES (?,?,?,?) ON CONFLICT DO NOTHING`,
|
|
9580
|
+
args: [
|
|
9581
|
+
scopeNodeId,
|
|
9582
|
+
scopeRefId,
|
|
9583
|
+
grant.role,
|
|
9584
|
+
grant.canSuggest ?? null
|
|
9585
|
+
]
|
|
9586
|
+
});
|
|
9587
|
+
structureChanged ||= inserted.rowsAffected > 0;
|
|
9588
|
+
}
|
|
9589
|
+
}
|
|
9590
|
+
if (structureChanged) await tx.execute(`UPDATE "${TABLE_KNOWLEDGE_ACCESS_STATE}" SET epoch=epoch+1 WHERE id='global'`);
|
|
9591
|
+
const state = await tx.execute(`SELECT epoch FROM "${TABLE_KNOWLEDGE_ACCESS_STATE}" WHERE id='global'`);
|
|
9592
|
+
return {
|
|
9593
|
+
scopes,
|
|
9594
|
+
createdScopeIds,
|
|
9595
|
+
deletedScopeAddresses: [...deletedScopeAddresses],
|
|
9596
|
+
changed: structureChanged,
|
|
9597
|
+
accessEpoch: Number(state.rows[0]?.epoch ?? 0)
|
|
9598
|
+
};
|
|
8563
9599
|
});
|
|
8564
9600
|
}
|
|
9601
|
+
async listScopeNodes(input = {}) {
|
|
9602
|
+
const { limit, after } = parseListKnowledgeScopeNodesInput(input);
|
|
9603
|
+
if (input.addresses?.length === 0 || input.ids?.length === 0) return {
|
|
9604
|
+
scopes: [],
|
|
9605
|
+
nextCursor: null
|
|
9606
|
+
};
|
|
9607
|
+
const args = [];
|
|
9608
|
+
const where = [`n."isScope"`, `n."deletedAt" IS NULL`];
|
|
9609
|
+
let within = "";
|
|
9610
|
+
if (input.withinAddress !== void 0) {
|
|
9611
|
+
within = `WITH RECURSIVE within_scope(id) AS (SELECT r.id FROM "${TABLE_KNOWLEDGE_NODES}" r JOIN "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" ra ON ra."scopeNodeId"=r.id WHERE ra.address=? AND r."isScope" AND r."deletedAt" IS NULL UNION SELECT ns."nodeId" FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" ns JOIN within_scope w ON ns."scopeNodeId"=w.id JOIN "${TABLE_KNOWLEDGE_NODES}" c ON c.id=ns."nodeId" WHERE c."isScope" AND c."deletedAt" IS NULL) `;
|
|
9612
|
+
args.push(input.withinAddress);
|
|
9613
|
+
where.push("n.id IN (SELECT id FROM within_scope)");
|
|
9614
|
+
}
|
|
9615
|
+
if (input.addresses) {
|
|
9616
|
+
where.push(`a.address IN (${input.addresses.map(() => "?").join(",")})`);
|
|
9617
|
+
args.push(...input.addresses);
|
|
9618
|
+
}
|
|
9619
|
+
if (input.ids) {
|
|
9620
|
+
where.push(`n.id IN (${input.ids.map(() => "?").join(",")})`);
|
|
9621
|
+
args.push(...input.ids);
|
|
9622
|
+
}
|
|
9623
|
+
if (after) {
|
|
9624
|
+
where.push("(n.name COLLATE \"C\" > ? OR (n.name = ? AND n.id > ?))");
|
|
9625
|
+
args.push(after.name, after.name, after.id);
|
|
9626
|
+
}
|
|
9627
|
+
args.push(limit + 1);
|
|
9628
|
+
const rows = (await this.#readExecutor.execute({
|
|
9629
|
+
sql: `${within}SELECT n.id,n.name,n.kind,n.description,a.address FROM "${TABLE_KNOWLEDGE_NODES}" n LEFT JOIN "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" a ON a."scopeNodeId"=n.id WHERE ${where.join(" AND ")} ORDER BY n.name COLLATE "C", n.id LIMIT ?`,
|
|
9630
|
+
args
|
|
9631
|
+
})).rows;
|
|
9632
|
+
if (rows.length === 0) return {
|
|
9633
|
+
scopes: [],
|
|
9634
|
+
nextCursor: null
|
|
9635
|
+
};
|
|
9636
|
+
const parents = await this.#readExecutor.execute({
|
|
9637
|
+
sql: `SELECT ns."nodeId",ns."scopeNodeId" FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" ns WHERE ns."nodeId" IN (${rows.map(() => "?").join(",")}) ORDER BY ns."scopeNodeId" COLLATE "C"`,
|
|
9638
|
+
args: rows.map((row) => String(row.id))
|
|
9639
|
+
});
|
|
9640
|
+
const parentsByScopeId = /* @__PURE__ */ new Map();
|
|
9641
|
+
for (const row of parents.rows) {
|
|
9642
|
+
const scopeId = String(row.nodeId);
|
|
9643
|
+
const parentId = String(row.scopeNodeId);
|
|
9644
|
+
const existing = parentsByScopeId.get(scopeId);
|
|
9645
|
+
if (existing) existing.push(parentId);
|
|
9646
|
+
else parentsByScopeId.set(scopeId, [parentId]);
|
|
9647
|
+
}
|
|
9648
|
+
return pageKnowledgeScopeNodes(rows.map((row) => ({
|
|
9649
|
+
id: String(row.id),
|
|
9650
|
+
address: String(row.address),
|
|
9651
|
+
name: String(row.name),
|
|
9652
|
+
...row.kind == null ? {} : { kind: String(row.kind) },
|
|
9653
|
+
...row.description == null ? {} : { description: String(row.description) },
|
|
9654
|
+
parentIds: parentsByScopeId.get(String(row.id)) ?? []
|
|
9655
|
+
})), limit, input);
|
|
9656
|
+
}
|
|
9657
|
+
async listScopeMembers(input) {
|
|
9658
|
+
const { limit, after } = parseListKnowledgeScopeMembersInput(input);
|
|
9659
|
+
const args = [input.scopeNodeId];
|
|
9660
|
+
let keyset = "";
|
|
9661
|
+
if (after) {
|
|
9662
|
+
const updatedAt = postgresTimestamp(after.updatedAt);
|
|
9663
|
+
keyset = ` AND (n."updatedAt" < ? OR (n."updatedAt" = ? AND (n.name > ? OR (n.name = ? AND n.id > ?))))`;
|
|
9664
|
+
args.push(updatedAt, updatedAt, after.name, after.name, after.id);
|
|
9665
|
+
}
|
|
9666
|
+
args.push(limit + 1);
|
|
9667
|
+
return pageKnowledgeScopeMembers((await this.#readExecutor.execute({
|
|
9668
|
+
sql: `SELECT *, scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_NODES}" n WHERE EXISTS (SELECT 1 FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" ns WHERE ns."nodeId"=n.id AND ns."scopeNodeId"=?) AND n."deletedAt" IS NULL AND n."mergedInto" IS NULL${keyset} ORDER BY n."updatedAt" DESC, n.name ASC, n.id ASC LIMIT ?`,
|
|
9669
|
+
args
|
|
9670
|
+
})).rows.map(parseNode), limit, input);
|
|
9671
|
+
}
|
|
8565
9672
|
async createNode(input) {
|
|
8566
9673
|
await assertKnowledgeDescriptionWithinBoundCompat(input.description);
|
|
8567
9674
|
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
@@ -8570,6 +9677,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8570
9677
|
if (existing) {
|
|
8571
9678
|
const terminal = await this.#resolveTerminalNode(tx, existing.id);
|
|
8572
9679
|
if (!isKnowledgeScopeVisible(terminal.scope, scope)) throw new Error(`Merged knowledge node is not visible from scope: ${input.name}`);
|
|
9680
|
+
await this.#placeNodeInScopes(tx, terminal.id, input.scopeAddresses, /* @__PURE__ */ new Date());
|
|
8573
9681
|
return terminal;
|
|
8574
9682
|
}
|
|
8575
9683
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -8586,7 +9694,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8586
9694
|
updatedAt: now
|
|
8587
9695
|
};
|
|
8588
9696
|
await tx.execute({
|
|
8589
|
-
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,description,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,?,?,jsonb(?),?,?,NULL,?,?)`,
|
|
9697
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,description,isScope,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,?,?,FALSE,jsonb(?),?,?,NULL,?,?)`,
|
|
8590
9698
|
args: [
|
|
8591
9699
|
node.id,
|
|
8592
9700
|
"node",
|
|
@@ -8602,6 +9710,8 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8602
9710
|
now.toISOString()
|
|
8603
9711
|
]
|
|
8604
9712
|
});
|
|
9713
|
+
await this.#replaceNodeScopes(tx, node.id, scope, now);
|
|
9714
|
+
await this.#placeNodeInScopes(tx, node.id, input.scopeAddresses, now);
|
|
8605
9715
|
await this.#replaceMentions(tx, "node", node.id, node.content ?? "", input.resolutionScope ?? scope, scope);
|
|
8606
9716
|
await this.#activity(tx, "node-created", "node", node.id, scope);
|
|
8607
9717
|
await this.#outbox(tx, "node", node.id, "upsert", node.version, scope);
|
|
@@ -8618,13 +9728,13 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8618
9728
|
return this.#resolveNode(this.#readExecutor, input.name, canonicalizeKnowledgeScope(input.scope));
|
|
8619
9729
|
}
|
|
8620
9730
|
async listNodes(input) {
|
|
8621
|
-
const
|
|
9731
|
+
const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
|
|
8622
9732
|
const clauses = [
|
|
8623
9733
|
`type = 'node'`,
|
|
8624
9734
|
"mergedInto IS NULL",
|
|
8625
|
-
visibleSql
|
|
9735
|
+
visibleSql(keys)
|
|
8626
9736
|
];
|
|
8627
|
-
const args = [
|
|
9737
|
+
const args = [...keys];
|
|
8628
9738
|
if (input.namePrefix) {
|
|
8629
9739
|
clauses.push("canonicalName LIKE ? ESCAPE '='");
|
|
8630
9740
|
args.push(`${escapeLikePattern(canonicalName(input.namePrefix))}%`);
|
|
@@ -8676,6 +9786,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8676
9786
|
input.version
|
|
8677
9787
|
]
|
|
8678
9788
|
})).rowsAffected === 0) throw new KnowledgeConflictError(input.id);
|
|
9789
|
+
if (knowledgeScopeKey(existing.scope) !== knowledgeScopeKey(scope)) await this.#swapIdentityScopes(tx, input.id, existing.scope, scope, now);
|
|
8679
9790
|
if (input.content !== void 0 || input.name !== void 0 || input.scope !== void 0) await this.#replaceMentions(tx, "node", input.id, content ?? "", input.resolutionScope ?? scope, scope);
|
|
8680
9791
|
await this.#activity(tx, "node-updated", "node", input.id, scope);
|
|
8681
9792
|
if (knowledgeScopeKey(existing.scope) !== knowledgeScopeKey(scope)) {
|
|
@@ -8730,8 +9841,12 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8730
9841
|
]
|
|
8731
9842
|
})).rowsAffected === 0) throw new KnowledgeConflictError(source.id);
|
|
8732
9843
|
await tx.execute({
|
|
8733
|
-
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET node=? WHERE node=?`,
|
|
8734
|
-
args: [
|
|
9844
|
+
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET node=?,version=version+1,updatedAt=? WHERE node=?`,
|
|
9845
|
+
args: [
|
|
9846
|
+
target.id,
|
|
9847
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
9848
|
+
source.id
|
|
9849
|
+
]
|
|
8735
9850
|
});
|
|
8736
9851
|
await tx.execute({
|
|
8737
9852
|
sql: `DELETE FROM "${TABLE_KNOWLEDGE_MENTIONS}" WHERE recordId=? AND EXISTS (SELECT 1 FROM "${TABLE_KNOWLEDGE_MENTIONS}" target WHERE target.sourceType="${TABLE_KNOWLEDGE_MENTIONS}".sourceType AND target.sourceId="${TABLE_KNOWLEDGE_MENTIONS}".sourceId AND target.recordId=?)`,
|
|
@@ -8771,10 +9886,10 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8771
9886
|
});
|
|
8772
9887
|
}
|
|
8773
9888
|
async appendKnowledge(input) {
|
|
9889
|
+
await assertKnowledgeRecordTextWithinBoundCompat(input.text);
|
|
8774
9890
|
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
8775
9891
|
const resolutionScope = canonicalizeKnowledgeScope(input.resolutionScope);
|
|
8776
9892
|
const defaultScope = canonicalizeKnowledgeScope(input.defaultScope);
|
|
8777
|
-
assertKnowledgeScopeWithinCeiling(scope, input.maxScope);
|
|
8778
9893
|
return this.#transaction(async (tx) => {
|
|
8779
9894
|
const parent = await this.#resolveTerminalNode(tx, nodeReferenceId(input.node));
|
|
8780
9895
|
if (!parent) throw new KnowledgeNotFoundError("node", nodeReferenceId(input.node));
|
|
@@ -8787,11 +9902,10 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8787
9902
|
sourceThreadId: input.sourceThreadId,
|
|
8788
9903
|
capturedAt: /* @__PURE__ */ new Date(),
|
|
8789
9904
|
when: input.when ? new Date(input.when) : void 0,
|
|
8790
|
-
maxScope: input.maxScope,
|
|
8791
9905
|
metadata: input.metadata
|
|
8792
9906
|
};
|
|
8793
9907
|
await tx.execute({
|
|
8794
|
-
sql: `INSERT INTO "${TABLE_KNOWLEDGE_RECORDS}" (id,node,text,scope,scopeKey,sourceThreadId,capturedAt,"when",
|
|
9908
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_RECORDS}" (id,node,text,scope,scopeKey,sourceThreadId,capturedAt,"when",metadata,version,updatedAt,deletedAt,deletedBy) VALUES (?,?,?,jsonb(?),?,?,?,?,jsonb(?),?,?,NULL,NULL)`,
|
|
8795
9909
|
args: [
|
|
8796
9910
|
record.id,
|
|
8797
9911
|
record.node,
|
|
@@ -8801,10 +9915,12 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8801
9915
|
record.sourceThreadId,
|
|
8802
9916
|
record.capturedAt.toISOString(),
|
|
8803
9917
|
record.when?.toISOString() ?? null,
|
|
8804
|
-
|
|
8805
|
-
|
|
9918
|
+
metadataJson,
|
|
9919
|
+
1,
|
|
9920
|
+
record.capturedAt.toISOString()
|
|
8806
9921
|
]
|
|
8807
9922
|
});
|
|
9923
|
+
await this.#replaceRecordScopes(tx, record.id, scope, record.capturedAt);
|
|
8808
9924
|
await this.#replaceMentions(tx, "record", record.id, record.text, resolutionScope, defaultScope);
|
|
8809
9925
|
await this.#activity(tx, "record-created", "record", record.id, scope, record.sourceThreadId);
|
|
8810
9926
|
await this.#outbox(tx, "record", record.id, "upsert", record.id, scope);
|
|
@@ -8831,17 +9947,13 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8831
9947
|
return this.#queryKnowledge(input, "related");
|
|
8832
9948
|
}
|
|
8833
9949
|
async knowledgeBySource(input) {
|
|
8834
|
-
const
|
|
8835
|
-
const args = [
|
|
8836
|
-
input.sourceThreadId,
|
|
8837
|
-
key,
|
|
8838
|
-
key
|
|
8839
|
-
];
|
|
9950
|
+
const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
|
|
9951
|
+
const args = [input.sourceThreadId, ...keys];
|
|
8840
9952
|
if (input.after) args.push(input.after);
|
|
8841
9953
|
const limit = input.limit ?? 100;
|
|
8842
9954
|
args.push(limit + 1);
|
|
8843
9955
|
const records = (await this.#readExecutor.execute({
|
|
8844
|
-
sql: `SELECT *,scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_RECORDS}" WHERE sourceThreadId=? AND ${visibleSql}${input.includeDeleted ? "" : " AND deletedAt IS NULL"}${input.after ? " AND id > ?" : ""} ORDER BY id ASC LIMIT ?`,
|
|
9956
|
+
sql: `SELECT *,scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_RECORDS}" WHERE sourceThreadId=? AND ${visibleSql(keys)}${input.includeDeleted ? "" : " AND deletedAt IS NULL"}${input.after ? " AND id > ?" : ""} ORDER BY id ASC LIMIT ?`,
|
|
8845
9957
|
args
|
|
8846
9958
|
})).rows.map(parseKnowledge);
|
|
8847
9959
|
return {
|
|
@@ -8856,10 +9968,11 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8856
9968
|
if (record.deletedAt) return record;
|
|
8857
9969
|
const deletedAt = /* @__PURE__ */ new Date();
|
|
8858
9970
|
await tx.execute({
|
|
8859
|
-
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=?,deletedBy=? WHERE id=? AND deletedAt IS NULL`,
|
|
9971
|
+
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=?,deletedBy=?,version=version+1,updatedAt=? WHERE id=? AND deletedAt IS NULL`,
|
|
8860
9972
|
args: [
|
|
8861
9973
|
deletedAt.toISOString(),
|
|
8862
9974
|
input.deletedBy,
|
|
9975
|
+
deletedAt.toISOString(),
|
|
8863
9976
|
input.id
|
|
8864
9977
|
]
|
|
8865
9978
|
});
|
|
@@ -8878,8 +9991,8 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8878
9991
|
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
8879
9992
|
if (!record.deletedAt) return record;
|
|
8880
9993
|
await tx.execute({
|
|
8881
|
-
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=NULL,deletedBy=NULL WHERE id=?`,
|
|
8882
|
-
args: [input.id]
|
|
9994
|
+
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=NULL,deletedBy=NULL,version=version+1,updatedAt=? WHERE id=?`,
|
|
9995
|
+
args: [(/* @__PURE__ */ new Date()).toISOString(), input.id]
|
|
8883
9996
|
});
|
|
8884
9997
|
await this.#activity(tx, "record-restored", "record", input.id, record.scope, record.sourceThreadId);
|
|
8885
9998
|
await this.#outbox(tx, "record", input.id, "upsert", createKnowledgeUlid(), record.scope);
|
|
@@ -8895,15 +10008,17 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8895
10008
|
return this.#transaction(async (tx) => {
|
|
8896
10009
|
const record = await this.#getKnowledge(tx, input.id, true);
|
|
8897
10010
|
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
8898
|
-
|
|
10011
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
8899
10012
|
await tx.execute({
|
|
8900
|
-
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET scope=jsonb(?),scopeKey=? WHERE id=?`,
|
|
10013
|
+
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET scope=jsonb(?),scopeKey=?,version=version+1,updatedAt=? WHERE id=?`,
|
|
8901
10014
|
args: [
|
|
8902
10015
|
JSON.stringify(scope),
|
|
8903
10016
|
knowledgeScopeKey(scope),
|
|
10017
|
+
updatedAt.toISOString(),
|
|
8904
10018
|
input.id
|
|
8905
10019
|
]
|
|
8906
10020
|
});
|
|
10021
|
+
await this.#replaceRecordScopes(tx, input.id, scope, updatedAt);
|
|
8907
10022
|
await this.#activity(tx, "record-rescoped", "record", input.id, scope, record.sourceThreadId);
|
|
8908
10023
|
if (knowledgeScopeKey(record.scope) !== knowledgeScopeKey(scope)) await this.#outbox(tx, "record", input.id, "delete", createKnowledgeUlid(), record.scope);
|
|
8909
10024
|
if (!record.deletedAt) await this.#outbox(tx, "record", input.id, "upsert", createKnowledgeUlid(), scope);
|
|
@@ -8913,33 +10028,16 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8913
10028
|
};
|
|
8914
10029
|
});
|
|
8915
10030
|
}
|
|
8916
|
-
async raiseKnowledgeCeiling(input) {
|
|
8917
|
-
return this.#transaction(async (tx) => {
|
|
8918
|
-
const record = await this.#getKnowledge(tx, input.id, true);
|
|
8919
|
-
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
8920
|
-
assertKnowledgeScopeWithinCeiling(record.scope, input.maxScope);
|
|
8921
|
-
assertKnowledgeCeilingRaised(record.maxScope, input.maxScope);
|
|
8922
|
-
await tx.execute({
|
|
8923
|
-
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET maxScope=? WHERE id=?`,
|
|
8924
|
-
args: [input.maxScope ?? null, input.id]
|
|
8925
|
-
});
|
|
8926
|
-
return {
|
|
8927
|
-
...record,
|
|
8928
|
-
maxScope: input.maxScope
|
|
8929
|
-
};
|
|
8930
|
-
});
|
|
8931
|
-
}
|
|
8932
10031
|
async search(input) {
|
|
8933
10032
|
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
8934
|
-
const
|
|
10033
|
+
const keys = visibleScopeKeys(scope);
|
|
8935
10034
|
const normalizedQuery = input.query.trim().toLocaleLowerCase();
|
|
8936
10035
|
if (!normalizedQuery) return [];
|
|
8937
10036
|
const query = `%${escapeLikePattern(normalizedQuery)}%`;
|
|
8938
10037
|
const results = (await this.#readExecutor.execute({
|
|
8939
|
-
sql: `SELECT *,scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_NODES}" WHERE mergedInto IS NULL AND ${visibleSql} AND (canonicalName LIKE ? ESCAPE '=' OR lower(COALESCE(kind,'')) LIKE ? ESCAPE '=' OR lower(COALESCE(content,'')) LIKE ? ESCAPE '=' OR lower(COALESCE(description,'')) LIKE ? ESCAPE '=') ORDER BY updatedAt DESC LIMIT ?`,
|
|
10038
|
+
sql: `SELECT *,scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_NODES}" WHERE mergedInto IS NULL AND ${visibleSql(keys)} AND (canonicalName LIKE ? ESCAPE '=' OR lower(COALESCE(kind,'')) LIKE ? ESCAPE '=' OR lower(COALESCE(content,'')) LIKE ? ESCAPE '=' OR lower(COALESCE(description,'')) LIKE ? ESCAPE '=') ORDER BY updatedAt DESC LIMIT ?`,
|
|
8940
10039
|
args: [
|
|
8941
|
-
|
|
8942
|
-
key,
|
|
10040
|
+
...keys,
|
|
8943
10041
|
query,
|
|
8944
10042
|
query,
|
|
8945
10043
|
query,
|
|
@@ -8960,10 +10058,9 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8960
10058
|
}));
|
|
8961
10059
|
if (results.length < (input.limit ?? 20)) {
|
|
8962
10060
|
const records = await this.#readExecutor.execute({
|
|
8963
|
-
sql: `SELECT f.*,f.scope AS "scopeJson",r.name,r.scope AS "parentScopeJson" FROM "${TABLE_KNOWLEDGE_RECORDS}" f JOIN "${TABLE_KNOWLEDGE_NODES}" r ON r.id=f.node AND r.type='node' AND r.mergedInto IS NULL WHERE f.deletedAt IS NULL AND ${visibleSql
|
|
10061
|
+
sql: `SELECT f.*,f.scope AS "scopeJson",r.name,r.scope AS "parentScopeJson" FROM "${TABLE_KNOWLEDGE_RECORDS}" f JOIN "${TABLE_KNOWLEDGE_NODES}" r ON r.id=f.node AND r.type='node' AND r.mergedInto IS NULL WHERE f.deletedAt IS NULL AND ${visibleSql(keys, "f.scopeKey")} AND lower(f.text) LIKE ? ESCAPE '=' ORDER BY f.id DESC LIMIT ?`,
|
|
8964
10062
|
args: [
|
|
8965
|
-
|
|
8966
|
-
key,
|
|
10063
|
+
...keys,
|
|
8967
10064
|
query,
|
|
8968
10065
|
(input.limit ?? 20) - results.length
|
|
8969
10066
|
]
|
|
@@ -8973,7 +10070,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8973
10070
|
return {
|
|
8974
10071
|
type: "record",
|
|
8975
10072
|
id: String(row.id),
|
|
8976
|
-
recordId: String(row.node),
|
|
10073
|
+
recordId: parentVisible ? String(row.node) : String(row.id),
|
|
8977
10074
|
name: parentVisible ? String(row.name) : "(private node)",
|
|
8978
10075
|
text: String(row.text),
|
|
8979
10076
|
scope: parseJson$1(row.scopeJson)
|
|
@@ -8982,41 +10079,26 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8982
10079
|
}
|
|
8983
10080
|
return results;
|
|
8984
10081
|
}
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
const updatedAt = /* @__PURE__ */ new Date();
|
|
8999
|
-
if ((await this.#executor.execute({
|
|
9000
|
-
sql: `INSERT INTO "${TABLE_KNOWLEDGE_CURSORS}" (sourceThreadId,agent,lastKnowledgeId,updatedAt) VALUES (?,?,?,?) ON CONFLICT(sourceThreadId,agent) DO UPDATE SET lastKnowledgeId=excluded.lastKnowledgeId,updatedAt=excluded.updatedAt WHERE excluded.lastKnowledgeId >= "${TABLE_KNOWLEDGE_CURSORS}".lastKnowledgeId`,
|
|
9001
|
-
args: [
|
|
9002
|
-
input.sourceThreadId,
|
|
9003
|
-
input.agent,
|
|
9004
|
-
input.lastKnowledgeId,
|
|
9005
|
-
updatedAt.toISOString()
|
|
9006
|
-
]
|
|
9007
|
-
})).rowsAffected === 0) throw new Error("Knowledge curation cursor cannot move backwards");
|
|
9008
|
-
return {
|
|
9009
|
-
...input,
|
|
9010
|
-
updatedAt
|
|
9011
|
-
};
|
|
10082
|
+
/**
|
|
10083
|
+
* @deprecated Curation cursors were removed. Observation-time curate is the only Knowledge writer and needs no
|
|
10084
|
+
* cursor. Always throws.
|
|
10085
|
+
*/
|
|
10086
|
+
async getCurationCursor(_input) {
|
|
10087
|
+
throw new Error(KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE);
|
|
10088
|
+
}
|
|
10089
|
+
/**
|
|
10090
|
+
* @deprecated Curation cursors were removed. Observation-time curate is the only Knowledge writer and needs no
|
|
10091
|
+
* cursor. Always throws.
|
|
10092
|
+
*/
|
|
10093
|
+
async advanceCurationCursor(_input) {
|
|
10094
|
+
throw new Error(KNOWLEDGE_CURATION_CURSOR_REMOVED_MESSAGE);
|
|
9012
10095
|
}
|
|
9013
10096
|
async listActivity(input) {
|
|
9014
|
-
const
|
|
10097
|
+
const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
|
|
9015
10098
|
return (await this.#readExecutor.execute({
|
|
9016
|
-
sql: `SELECT *,scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
|
|
10099
|
+
sql: `SELECT *,scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_ACTIVITY}" WHERE ${visibleSql(keys)}${input.after ? " AND id < ?" : ""} ORDER BY id DESC LIMIT ?`,
|
|
9017
10100
|
args: [
|
|
9018
|
-
|
|
9019
|
-
key,
|
|
10101
|
+
...keys,
|
|
9020
10102
|
...input.after ? [input.after] : [],
|
|
9021
10103
|
input.limit ?? 100
|
|
9022
10104
|
]
|
|
@@ -9038,9 +10120,9 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9038
10120
|
args.push(input.status);
|
|
9039
10121
|
}
|
|
9040
10122
|
if (input.scope) {
|
|
9041
|
-
const
|
|
9042
|
-
clauses.push(visibleSql);
|
|
9043
|
-
args.push(
|
|
10123
|
+
const keys = visibleScopeKeys(input.scope);
|
|
10124
|
+
clauses.push(visibleSql(keys));
|
|
10125
|
+
args.push(...keys);
|
|
9044
10126
|
}
|
|
9045
10127
|
args.push(input.limit ?? 100);
|
|
9046
10128
|
return (await this.#executor.execute({
|
|
@@ -9059,9 +10141,9 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9059
10141
|
];
|
|
9060
10142
|
const args = [now.toISOString(), stale.toISOString()];
|
|
9061
10143
|
if (input.scope) {
|
|
9062
|
-
const
|
|
9063
|
-
clauses.push(visibleSql);
|
|
9064
|
-
args.push(
|
|
10144
|
+
const keys = visibleScopeKeys(input.scope);
|
|
10145
|
+
clauses.push(visibleSql(keys));
|
|
10146
|
+
args.push(...keys);
|
|
9065
10147
|
}
|
|
9066
10148
|
args.push(input.limit ?? 100);
|
|
9067
10149
|
const ids = (await tx.execute({
|
|
@@ -9128,12 +10210,14 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9128
10210
|
return result.rows[0] ? parseNode(result.rows[0]) : null;
|
|
9129
10211
|
}
|
|
9130
10212
|
async #resolveNode(executor, name, scope) {
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
|
|
10213
|
+
const keys = visibleScopeKeys(scope);
|
|
10214
|
+
const candidates = (await executor.execute({
|
|
10215
|
+
sql: `SELECT *,scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_NODES}" WHERE type='node' AND canonicalName=? AND ("scopeKey" IN (${keys.map(() => "?").join(",")}) OR "mergedInto" IS NOT NULL)`,
|
|
10216
|
+
args: [canonicalName(name), ...keys]
|
|
10217
|
+
})).rows.map(parseNode).sort((left, right) => right.scope.length - left.scope.length);
|
|
10218
|
+
for (const candidate of candidates) {
|
|
10219
|
+
const terminal = await this.#resolveTerminalNode(executor, candidate.id);
|
|
10220
|
+
if (terminal && isKnowledgeScopeVisible(terminal.scope, scope)) return terminal;
|
|
9137
10221
|
}
|
|
9138
10222
|
return null;
|
|
9139
10223
|
}
|
|
@@ -9158,17 +10242,16 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9158
10242
|
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
9159
10243
|
const node = await this.#resolveTerminalNode(this.#readExecutor, nodeReferenceId(input.node));
|
|
9160
10244
|
if (!node) return { records: [] };
|
|
9161
|
-
const
|
|
10245
|
+
const keys = visibleScopeKeys(scope);
|
|
9162
10246
|
const args = [
|
|
9163
10247
|
node.id,
|
|
9164
10248
|
...relationship === "related" ? [node.id] : [],
|
|
9165
|
-
|
|
9166
|
-
key
|
|
10249
|
+
...keys
|
|
9167
10250
|
];
|
|
9168
10251
|
if (input.after) args.push(input.after);
|
|
9169
10252
|
args.push((input.limit ?? 100) + 1);
|
|
9170
10253
|
const records = (await this.#readExecutor.execute({
|
|
9171
|
-
sql: `SELECT DISTINCT f.*,f.scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_RECORDS}" f${relationship === "about" ? "" : ` LEFT JOIN "${TABLE_KNOWLEDGE_MENTIONS}" m ON m.sourceType='record' AND m.sourceId=f.id`} WHERE ${relationship === "about" ? "f.node=?" : relationship === "mentioning" ? "m.recordId=?" : "(f.node=? OR m.recordId=?)"} AND ${visibleSql
|
|
10254
|
+
sql: `SELECT DISTINCT f.*,f.scope AS "scopeJson" FROM "${TABLE_KNOWLEDGE_RECORDS}" f${relationship === "about" ? "" : ` LEFT JOIN "${TABLE_KNOWLEDGE_MENTIONS}" m ON m.sourceType='record' AND m.sourceId=f.id`} WHERE ${relationship === "about" ? "f.node=?" : relationship === "mentioning" ? "m.recordId=?" : "(f.node=? OR m.recordId=?)"} AND ${visibleSql(keys, "f.scopeKey")}${input.includeDeleted ? "" : " AND f.deletedAt IS NULL"}${input.after ? " AND f.id < ?" : ""} ORDER BY f.id DESC LIMIT ?`,
|
|
9172
10255
|
args
|
|
9173
10256
|
})).rows.map(parseKnowledge);
|
|
9174
10257
|
const limit = input.limit ?? 100;
|
|
@@ -9177,6 +10260,90 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9177
10260
|
nextCursor: records.length > limit ? records[limit - 1]?.id : void 0
|
|
9178
10261
|
};
|
|
9179
10262
|
}
|
|
10263
|
+
async #resolveScopeNodeIds(executor, addresses) {
|
|
10264
|
+
const scopeNodeIds = /* @__PURE__ */ new Set();
|
|
10265
|
+
for (const address of addresses) {
|
|
10266
|
+
const result = await executor.execute({
|
|
10267
|
+
sql: `SELECT scopeNodeId FROM "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" WHERE address=?`,
|
|
10268
|
+
args: [address]
|
|
10269
|
+
});
|
|
10270
|
+
if (result.rows[0]?.scopeNodeId != null) scopeNodeIds.add(String(result.rows[0].scopeNodeId));
|
|
10271
|
+
}
|
|
10272
|
+
return [...scopeNodeIds];
|
|
10273
|
+
}
|
|
10274
|
+
async #replaceNodeScopes(executor, nodeId, addresses, addedAt) {
|
|
10275
|
+
await executor.execute({
|
|
10276
|
+
sql: `DELETE FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" WHERE nodeId=?`,
|
|
10277
|
+
args: [nodeId]
|
|
10278
|
+
});
|
|
10279
|
+
for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, addresses)) await executor.execute({
|
|
10280
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" (nodeId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
|
|
10281
|
+
args: [
|
|
10282
|
+
nodeId,
|
|
10283
|
+
scopeNodeId,
|
|
10284
|
+
addedAt.toISOString()
|
|
10285
|
+
]
|
|
10286
|
+
});
|
|
10287
|
+
}
|
|
10288
|
+
/**
|
|
10289
|
+
* Move a node's identity memberships from `from` to `to` without touching structural
|
|
10290
|
+
* placements added by `#placeNodeInScopes`, which a scope change must not erase.
|
|
10291
|
+
*/
|
|
10292
|
+
async #swapIdentityScopes(executor, nodeId, from, to, addedAt) {
|
|
10293
|
+
const next = await this.#resolveScopeNodeIds(executor, to);
|
|
10294
|
+
for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, from)) {
|
|
10295
|
+
if (next.includes(scopeNodeId)) continue;
|
|
10296
|
+
await executor.execute({
|
|
10297
|
+
sql: `DELETE FROM "${TABLE_KNOWLEDGE_NODE_SCOPES}" WHERE nodeId=? AND scopeNodeId=?`,
|
|
10298
|
+
args: [nodeId, scopeNodeId]
|
|
10299
|
+
});
|
|
10300
|
+
}
|
|
10301
|
+
for (const scopeNodeId of next) await executor.execute({
|
|
10302
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" (nodeId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
|
|
10303
|
+
args: [
|
|
10304
|
+
nodeId,
|
|
10305
|
+
scopeNodeId,
|
|
10306
|
+
addedAt.toISOString()
|
|
10307
|
+
]
|
|
10308
|
+
});
|
|
10309
|
+
}
|
|
10310
|
+
/**
|
|
10311
|
+
* Additive structural placement: every address must resolve to a live scope node
|
|
10312
|
+
* (unlike identity membership, an unknown address is a caller error, not a lazy
|
|
10313
|
+
* materialization miss). Runs inside the caller's transaction, so a throw aborts
|
|
10314
|
+
* the whole mutation.
|
|
10315
|
+
*/
|
|
10316
|
+
async #placeNodeInScopes(executor, nodeId, addresses, addedAt) {
|
|
10317
|
+
for (const address of addresses ?? []) {
|
|
10318
|
+
const scopeNodeId = (await executor.execute({
|
|
10319
|
+
sql: `SELECT sa.scopeNodeId AS "scopeNodeId" FROM "${TABLE_KNOWLEDGE_SCOPE_ADDRESSES}" sa JOIN "${TABLE_KNOWLEDGE_NODES}" n ON n.id=sa."scopeNodeId" WHERE sa.address=? AND n."isScope" AND n."deletedAt" IS NULL`,
|
|
10320
|
+
args: [address]
|
|
10321
|
+
})).rows[0]?.scopeNodeId;
|
|
10322
|
+
if (scopeNodeId == null) throw new KnowledgeNotFoundError("scope", address);
|
|
10323
|
+
await executor.execute({
|
|
10324
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODE_SCOPES}" ("nodeId","scopeNodeId","addedAt") VALUES (?,?,?) ON CONFLICT DO NOTHING`,
|
|
10325
|
+
args: [
|
|
10326
|
+
nodeId,
|
|
10327
|
+
String(scopeNodeId),
|
|
10328
|
+
addedAt.toISOString()
|
|
10329
|
+
]
|
|
10330
|
+
});
|
|
10331
|
+
}
|
|
10332
|
+
}
|
|
10333
|
+
async #replaceRecordScopes(executor, recordId, addresses, addedAt) {
|
|
10334
|
+
await executor.execute({
|
|
10335
|
+
sql: `DELETE FROM "${TABLE_KNOWLEDGE_RECORD_SCOPES}" WHERE recordId=?`,
|
|
10336
|
+
args: [recordId]
|
|
10337
|
+
});
|
|
10338
|
+
for (const scopeNodeId of await this.#resolveScopeNodeIds(executor, addresses)) await executor.execute({
|
|
10339
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_RECORD_SCOPES}" (recordId,scopeNodeId,addedAt) VALUES (?,?,?) ON CONFLICT DO NOTHING`,
|
|
10340
|
+
args: [
|
|
10341
|
+
recordId,
|
|
10342
|
+
scopeNodeId,
|
|
10343
|
+
addedAt.toISOString()
|
|
10344
|
+
]
|
|
10345
|
+
});
|
|
10346
|
+
}
|
|
9180
10347
|
async #replaceMentions(tx, sourceType, sourceId, text, resolutionScope, defaultScope) {
|
|
9181
10348
|
await tx.execute({
|
|
9182
10349
|
sql: `DELETE FROM "${TABLE_KNOWLEDGE_MENTIONS}" WHERE sourceType=? AND sourceId=?`,
|
|
@@ -9200,7 +10367,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9200
10367
|
updatedAt: now
|
|
9201
10368
|
};
|
|
9202
10369
|
await tx.execute({
|
|
9203
|
-
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,NULL,jsonb(?),?,?,NULL,?,?)`,
|
|
10370
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_NODES}" (id,type,name,canonicalName,kind,content,isScope,scope,scopeKey,version,mergedInto,createdAt,updatedAt) VALUES (?,?,?,?,?,NULL,FALSE,jsonb(?),?,?,NULL,?,?)`,
|
|
9204
10371
|
args: [
|
|
9205
10372
|
node.id,
|
|
9206
10373
|
"node",
|
|
@@ -9214,6 +10381,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9214
10381
|
now.toISOString()
|
|
9215
10382
|
]
|
|
9216
10383
|
});
|
|
10384
|
+
await this.#replaceNodeScopes(tx, node.id, defaultScope, now);
|
|
9217
10385
|
await this.#activity(tx, "node-created", "node", node.id, defaultScope);
|
|
9218
10386
|
await this.#outbox(tx, "node", node.id, "upsert", 1, defaultScope);
|
|
9219
10387
|
}
|
|
@@ -9230,13 +10398,17 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9230
10398
|
}
|
|
9231
10399
|
async #activity(executor, action, recordType, recordId, scope, sourceThreadId) {
|
|
9232
10400
|
const now = /* @__PURE__ */ new Date();
|
|
10401
|
+
const [contextScopeId] = await this.#resolveScopeNodeIds(executor, scope);
|
|
9233
10402
|
await executor.execute({
|
|
9234
|
-
sql: `INSERT INTO "${TABLE_KNOWLEDGE_ACTIVITY}" (id,action,recordType,recordId,scope,scopeKey,sourceThreadId,createdAt) VALUES (
|
|
10403
|
+
sql: `INSERT INTO "${TABLE_KNOWLEDGE_ACTIVITY}" (id,action,targetType,targetId,contextScopeId,recordType,recordId,scope,scopeKey,sourceThreadId,createdAt) VALUES (?,?,?,?,?,?,?,jsonb(?),?,?,?)`,
|
|
9235
10404
|
args: [
|
|
9236
10405
|
createKnowledgeUlid(),
|
|
9237
10406
|
action,
|
|
9238
10407
|
recordType,
|
|
9239
10408
|
recordId,
|
|
10409
|
+
contextScopeId ?? null,
|
|
10410
|
+
recordType,
|
|
10411
|
+
recordId,
|
|
9240
10412
|
JSON.stringify(scope),
|
|
9241
10413
|
knowledgeScopeKey(scope),
|
|
9242
10414
|
sourceThreadId ?? null,
|
|
@@ -23491,7 +24663,7 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
23491
24663
|
async dangerouslyClearAll() {
|
|
23492
24664
|
await this.#db.clearTable({ tableName: TABLE_WORKFLOW_SNAPSHOT });
|
|
23493
24665
|
}
|
|
23494
|
-
async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext }) {
|
|
24666
|
+
async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state }) {
|
|
23495
24667
|
try {
|
|
23496
24668
|
return await this.#db.client.tx(async (t) => {
|
|
23497
24669
|
const tableName = getTableName({
|
|
@@ -23522,7 +24694,8 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
23522
24694
|
snapshot,
|
|
23523
24695
|
stepId,
|
|
23524
24696
|
result,
|
|
23525
|
-
requestContext
|
|
24697
|
+
requestContext,
|
|
24698
|
+
state
|
|
23526
24699
|
});
|
|
23527
24700
|
const now = /* @__PURE__ */ new Date();
|
|
23528
24701
|
const sanitizedSnapshot = toPgJson(snapshot);
|
|
@@ -24995,7 +26168,10 @@ var PostgresStore = class extends MastraCompositeStore {
|
|
|
24995
26168
|
workflows: new WorkflowsPG(domainConfig),
|
|
24996
26169
|
workflowDefinitions: new WorkflowDefinitionsPG(domainConfig),
|
|
24997
26170
|
memory: new MemoryPG(domainConfig),
|
|
24998
|
-
knowledge: new KnowledgePG(
|
|
26171
|
+
knowledge: new KnowledgePG({
|
|
26172
|
+
...domainConfig,
|
|
26173
|
+
storageIsolationKey: config.storageIsolationKey ?? getPgKnowledgeIsolationKey(config)
|
|
26174
|
+
}),
|
|
24999
26175
|
notifications: new NotificationsPG(domainConfig),
|
|
25000
26176
|
observability: new ObservabilityPG(domainConfig),
|
|
25001
26177
|
agents: new AgentsPG(domainConfig),
|
|
@@ -25049,7 +26225,7 @@ var PostgresStore = class extends MastraCompositeStore {
|
|
|
25049
26225
|
const pinned = new PinnedClientAdapter(this.#writePool, pinnedClient);
|
|
25050
26226
|
this.#db.pin(pinned);
|
|
25051
26227
|
this.#db.setSchemaSnapshot(await loadSchemaSnapshot(pinned, this.schema));
|
|
25052
|
-
await
|
|
26228
|
+
await Promise.all(Object.entries(this.stores).filter(([name, store]) => name !== "knowledge" && store).map(([, store]) => store.init()));
|
|
25053
26229
|
this.isInitialized = true;
|
|
25054
26230
|
} catch (error) {
|
|
25055
26231
|
this.#initPromise = null;
|