@mastra/pg 1.31.0-alpha.2 → 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/index.cjs +1350 -217
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1353 -220
- 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 +8 -5
- package/dist/storage/db/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/index.d.ts.map +1 -1
- package/package.json +5 -4
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";
|
|
@@ -8277,18 +8277,650 @@ var FavoritesPG = class FavoritesPG extends FavoritesStorage {
|
|
|
8277
8277
|
}
|
|
8278
8278
|
};
|
|
8279
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
|
|
8280
8915
|
//#region src/storage/domains/knowledge/index.ts
|
|
8281
|
-
|
|
8916
|
+
const loadKnowledgeV2Core = createKnowledgeV2CoreLoader(coreFeatures, () => import("@mastra/core/storage"));
|
|
8282
8917
|
async function assertKnowledgeDescriptionWithinBoundCompat(description) {
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
assertWithinBound = resolvedAssert;
|
|
8290
|
-
}
|
|
8291
|
-
assertWithinBound(description);
|
|
8918
|
+
const { assertKnowledgeDescriptionWithinBound } = await loadKnowledgeV2Core();
|
|
8919
|
+
assertKnowledgeDescriptionWithinBound(description);
|
|
8920
|
+
}
|
|
8921
|
+
async function assertKnowledgeRecordTextWithinBoundCompat(text) {
|
|
8922
|
+
const { assertKnowledgeRecordTextWithinBound } = await loadKnowledgeV2Core();
|
|
8923
|
+
assertKnowledgeRecordTextWithinBound(text);
|
|
8292
8924
|
}
|
|
8293
8925
|
const camelCaseColumns = [
|
|
8294
8926
|
"canonicalName",
|
|
@@ -8299,7 +8931,6 @@ const camelCaseColumns = [
|
|
|
8299
8931
|
"node",
|
|
8300
8932
|
"sourceThreadId",
|
|
8301
8933
|
"capturedAt",
|
|
8302
|
-
"maxScope",
|
|
8303
8934
|
"deletedAt",
|
|
8304
8935
|
"deletedBy",
|
|
8305
8936
|
"sourceType",
|
|
@@ -8313,7 +8944,30 @@ const camelCaseColumns = [
|
|
|
8313
8944
|
"availableAt",
|
|
8314
8945
|
"claimedAt",
|
|
8315
8946
|
"claimedBy",
|
|
8316
|
-
"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"
|
|
8317
8971
|
];
|
|
8318
8972
|
function transformSqlCode(sql, transform) {
|
|
8319
8973
|
return sql.split(/('(?:''|[^'])*')/g).map((part, index) => index % 2 === 0 ? transform(part) : part).join("");
|
|
@@ -8328,14 +8982,7 @@ function postgresSql(sql, schemaName) {
|
|
|
8328
8982
|
const quotedSchema = `"${parseSchemaName(schemaName)}"`;
|
|
8329
8983
|
normalized = transformSqlCode(normalized, (code) => {
|
|
8330
8984
|
let transformed = code;
|
|
8331
|
-
for (const table of [
|
|
8332
|
-
TABLE_KNOWLEDGE_NODES,
|
|
8333
|
-
TABLE_KNOWLEDGE_RECORDS,
|
|
8334
|
-
TABLE_KNOWLEDGE_MENTIONS,
|
|
8335
|
-
TABLE_KNOWLEDGE_CURSORS,
|
|
8336
|
-
TABLE_KNOWLEDGE_ACTIVITY,
|
|
8337
|
-
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
|
|
8338
|
-
]) transformed = transformed.replaceAll(`"${table}"`, `${quotedSchema}."${table}"`);
|
|
8985
|
+
for (const table of [...KNOWLEDGE_TABLE_NAMES, ...RETIRED_KNOWLEDGE_TABLE_NAMES]) transformed = transformed.replaceAll(`"${table}"`, `${quotedSchema}."${table}"`);
|
|
8339
8986
|
return transformed;
|
|
8340
8987
|
});
|
|
8341
8988
|
}
|
|
@@ -8343,17 +8990,35 @@ function postgresSql(sql, schemaName) {
|
|
|
8343
8990
|
return transformSqlCode(normalized, (code) => code.replace(/\?/g, () => `$${++index}`));
|
|
8344
8991
|
}
|
|
8345
8992
|
function createExecutor(client, schemaName) {
|
|
8346
|
-
|
|
8993
|
+
const execute = async (statement, qualifyWithSchema) => {
|
|
8347
8994
|
const sql = typeof statement === "string" ? statement : statement.sql;
|
|
8348
8995
|
const args = typeof statement === "string" ? [] : statement.args ?? [];
|
|
8349
|
-
const result = await client.query(postgresSql(sql, schemaName), args);
|
|
8996
|
+
const result = await client.query(postgresSql(sql, qualifyWithSchema ? schemaName : void 0), args);
|
|
8350
8997
|
return {
|
|
8351
8998
|
rows: result.rows,
|
|
8352
8999
|
rowsAffected: result.rowCount ?? 0
|
|
8353
9000
|
};
|
|
8354
|
-
}
|
|
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];
|
|
8355
9020
|
}
|
|
8356
|
-
const visibleSql =
|
|
9021
|
+
const visibleSql = (keys, scopeKeyColumn = "scopeKey") => `${scopeKeyColumn} IN (${keys.map(() => "?").join(",")})`;
|
|
8357
9022
|
function parseJson$1(value) {
|
|
8358
9023
|
if (typeof value === "string") return JSON.parse(value);
|
|
8359
9024
|
if (value instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(value));
|
|
@@ -8393,9 +9058,10 @@ function parseNode(row) {
|
|
|
8393
9058
|
id: String(row.id),
|
|
8394
9059
|
type: "node",
|
|
8395
9060
|
name: String(row.name),
|
|
8396
|
-
kind: String(row.kind),
|
|
9061
|
+
kind: row.kind == null ? "" : String(row.kind),
|
|
8397
9062
|
content: row.content == null ? void 0 : String(row.content),
|
|
8398
9063
|
description: row.description == null ? void 0 : String(row.description),
|
|
9064
|
+
isScope: row.isScope === true || row.isScope === 1 ? true : void 0,
|
|
8399
9065
|
scope: parseJson$1(row.scopeJson ?? row.scope),
|
|
8400
9066
|
version: Number(row.version),
|
|
8401
9067
|
mergedInto: row.mergedInto == null ? void 0 : String(row.mergedInto),
|
|
@@ -8412,7 +9078,6 @@ function parseKnowledge(row) {
|
|
|
8412
9078
|
sourceThreadId: String(row.sourceThreadId),
|
|
8413
9079
|
capturedAt: toDate$1(row.capturedAt),
|
|
8414
9080
|
when: optionalDate(row.when),
|
|
8415
|
-
maxScope: row.maxScope == null ? void 0 : String(row.maxScope),
|
|
8416
9081
|
metadata: row.metadata == null ? void 0 : parseJson$1(row.metadata),
|
|
8417
9082
|
deletedAt: optionalDate(row.deletedAt),
|
|
8418
9083
|
deletedBy: row.deletedBy == null ? void 0 : String(row.deletedBy)
|
|
@@ -8449,6 +9114,10 @@ function knowledgeIndexes(schemaName) {
|
|
|
8449
9114
|
name: "idx_knowledge_nodes_scope",
|
|
8450
9115
|
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_nodes_scope ON ${table(TABLE_KNOWLEDGE_NODES)} ("scopeKey", "type");`
|
|
8451
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
|
+
},
|
|
8452
9121
|
{
|
|
8453
9122
|
name: "idx_knowledge_records_node_latest",
|
|
8454
9123
|
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_records_node_latest ON ${table(TABLE_KNOWLEDGE_RECORDS)} ("node", "id" DESC);`
|
|
@@ -8465,6 +9134,14 @@ function knowledgeIndexes(schemaName) {
|
|
|
8465
9134
|
name: "idx_knowledge_activity_latest",
|
|
8466
9135
|
sql: `CREATE INDEX IF NOT EXISTS idx_knowledge_activity_latest ON ${table(TABLE_KNOWLEDGE_ACTIVITY)} ("id" DESC);`
|
|
8467
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
|
+
},
|
|
8468
9145
|
{
|
|
8469
9146
|
name: "idx_knowledge_outbox_idempotency",
|
|
8470
9147
|
sql: `CREATE UNIQUE INDEX IF NOT EXISTS idx_knowledge_outbox_idempotency ON ${table(TABLE_KNOWLEDGE_SEMANTIC_OUTBOX)} ("idempotencyKey");`
|
|
@@ -8472,67 +9149,152 @@ function knowledgeIndexes(schemaName) {
|
|
|
8472
9149
|
{
|
|
8473
9150
|
name: "idx_knowledge_outbox_claim",
|
|
8474
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);`
|
|
8475
9176
|
}
|
|
8476
9177
|
];
|
|
8477
9178
|
}
|
|
8478
9179
|
function knowledgeIndexDDL(schemaName) {
|
|
8479
9180
|
return knowledgeIndexes(schemaName).map((index) => index.sql);
|
|
8480
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
|
+
}
|
|
8481
9290
|
var KnowledgePG = class extends KnowledgeStorage {
|
|
8482
|
-
static MANAGED_TABLES =
|
|
8483
|
-
TABLE_KNOWLEDGE_NODES,
|
|
8484
|
-
TABLE_KNOWLEDGE_RECORDS,
|
|
8485
|
-
TABLE_KNOWLEDGE_MENTIONS,
|
|
8486
|
-
TABLE_KNOWLEDGE_CURSORS,
|
|
8487
|
-
TABLE_KNOWLEDGE_ACTIVITY,
|
|
8488
|
-
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX
|
|
8489
|
-
];
|
|
9291
|
+
static MANAGED_TABLES = KNOWLEDGE_TABLE_NAMES;
|
|
8490
9292
|
static getExportDDL(schemaName) {
|
|
8491
|
-
return [
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
includeAllConstraints: true
|
|
8497
|
-
}),
|
|
8498
|
-
generateTableSQL({
|
|
8499
|
-
tableName: TABLE_KNOWLEDGE_RECORDS,
|
|
8500
|
-
schema: KNOWLEDGE_RECORDS_SCHEMA,
|
|
8501
|
-
schemaName,
|
|
8502
|
-
includeAllConstraints: true
|
|
8503
|
-
}),
|
|
8504
|
-
generateTableSQL({
|
|
8505
|
-
tableName: TABLE_KNOWLEDGE_MENTIONS,
|
|
8506
|
-
schema: KNOWLEDGE_MENTIONS_SCHEMA,
|
|
8507
|
-
schemaName,
|
|
8508
|
-
compositePrimaryKey: [
|
|
8509
|
-
"sourceType",
|
|
8510
|
-
"sourceId",
|
|
8511
|
-
"recordId"
|
|
8512
|
-
],
|
|
8513
|
-
includeAllConstraints: true
|
|
8514
|
-
}),
|
|
8515
|
-
generateTableSQL({
|
|
8516
|
-
tableName: TABLE_KNOWLEDGE_CURSORS,
|
|
8517
|
-
schema: KNOWLEDGE_CURSORS_SCHEMA,
|
|
8518
|
-
schemaName,
|
|
8519
|
-
compositePrimaryKey: ["sourceThreadId", "agent"],
|
|
8520
|
-
includeAllConstraints: true
|
|
8521
|
-
}),
|
|
8522
|
-
generateTableSQL({
|
|
8523
|
-
tableName: TABLE_KNOWLEDGE_ACTIVITY,
|
|
8524
|
-
schema: KNOWLEDGE_ACTIVITY_SCHEMA,
|
|
8525
|
-
schemaName,
|
|
8526
|
-
includeAllConstraints: true
|
|
8527
|
-
}),
|
|
8528
|
-
generateTableSQL({
|
|
8529
|
-
tableName: TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
|
|
8530
|
-
schema: KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA,
|
|
8531
|
-
schemaName,
|
|
8532
|
-
includeAllConstraints: true
|
|
8533
|
-
}),
|
|
8534
|
-
...knowledgeIndexDDL(schemaName)
|
|
8535
|
-
];
|
|
9293
|
+
return [...knowledgeTableDefinitions.map((definition) => generateTableSQL({
|
|
9294
|
+
...definition,
|
|
9295
|
+
schemaName,
|
|
9296
|
+
includeAllConstraints: true
|
|
9297
|
+
})), ...knowledgeIndexDDL(schemaName)];
|
|
8536
9298
|
}
|
|
8537
9299
|
#client;
|
|
8538
9300
|
#executor;
|
|
@@ -8541,7 +9303,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8541
9303
|
#db;
|
|
8542
9304
|
#schemaName;
|
|
8543
9305
|
constructor(config) {
|
|
8544
|
-
super();
|
|
9306
|
+
super({ storageIsolationKey: config.storageIsolationKey ?? getPgKnowledgeIsolationKey(config) });
|
|
8545
9307
|
const { client, readClient, schemaName, skipDefaultIndexes } = resolvePgConfig(config);
|
|
8546
9308
|
this.#client = client;
|
|
8547
9309
|
this.#schemaName = schemaName;
|
|
@@ -8554,56 +9316,359 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8554
9316
|
skipDefaultIndexes
|
|
8555
9317
|
});
|
|
8556
9318
|
}
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
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
|
|
8566
9394
|
});
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
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
|
+
});
|
|
8570
9420
|
});
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
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
|
|
8578
9454
|
]
|
|
8579
|
-
});
|
|
8580
|
-
|
|
8581
|
-
tableName: TABLE_KNOWLEDGE_CURSORS,
|
|
8582
|
-
schema: KNOWLEDGE_CURSORS_SCHEMA,
|
|
8583
|
-
compositePrimaryKey: ["sourceThreadId", "agent"]
|
|
8584
|
-
});
|
|
8585
|
-
await this.#db.createTable({
|
|
8586
|
-
tableName: TABLE_KNOWLEDGE_ACTIVITY,
|
|
8587
|
-
schema: KNOWLEDGE_ACTIVITY_SCHEMA
|
|
8588
|
-
});
|
|
8589
|
-
await this.#db.createTable({
|
|
8590
|
-
tableName: TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
|
|
8591
|
-
schema: KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA
|
|
8592
|
-
});
|
|
8593
|
-
await Promise.all(knowledgeIndexes(this.#schemaName).map((index) => this.#db.createIndexFromStatement(index.name, index.sql)));
|
|
9455
|
+
})).rows.length > 0) return false;
|
|
9456
|
+
return true;
|
|
8594
9457
|
}
|
|
8595
9458
|
async dangerouslyClearAll() {
|
|
8596
9459
|
await this.#transaction(async (tx) => {
|
|
8597
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,
|
|
8598
9466
|
TABLE_KNOWLEDGE_MENTIONS,
|
|
8599
|
-
|
|
8600
|
-
TABLE_KNOWLEDGE_NODES,
|
|
8601
|
-
TABLE_KNOWLEDGE_CURSORS,
|
|
9467
|
+
TABLE_KNOWLEDGE_PROPOSALS,
|
|
8602
9468
|
TABLE_KNOWLEDGE_ACTIVITY,
|
|
8603
|
-
|
|
9469
|
+
TABLE_KNOWLEDGE_IMPORT_STATE,
|
|
9470
|
+
TABLE_KNOWLEDGE_IMPORT_RUNS,
|
|
9471
|
+
TABLE_KNOWLEDGE_SEMANTIC_OUTBOX,
|
|
9472
|
+
TABLE_KNOWLEDGE_RECORDS,
|
|
9473
|
+
TABLE_KNOWLEDGE_NODES
|
|
8604
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
|
+
};
|
|
8605
9599
|
});
|
|
8606
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
|
+
}
|
|
8607
9672
|
async createNode(input) {
|
|
8608
9673
|
await assertKnowledgeDescriptionWithinBoundCompat(input.description);
|
|
8609
9674
|
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
@@ -8612,6 +9677,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8612
9677
|
if (existing) {
|
|
8613
9678
|
const terminal = await this.#resolveTerminalNode(tx, existing.id);
|
|
8614
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());
|
|
8615
9681
|
return terminal;
|
|
8616
9682
|
}
|
|
8617
9683
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -8628,7 +9694,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8628
9694
|
updatedAt: now
|
|
8629
9695
|
};
|
|
8630
9696
|
await tx.execute({
|
|
8631
|
-
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,?,?)`,
|
|
8632
9698
|
args: [
|
|
8633
9699
|
node.id,
|
|
8634
9700
|
"node",
|
|
@@ -8644,6 +9710,8 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8644
9710
|
now.toISOString()
|
|
8645
9711
|
]
|
|
8646
9712
|
});
|
|
9713
|
+
await this.#replaceNodeScopes(tx, node.id, scope, now);
|
|
9714
|
+
await this.#placeNodeInScopes(tx, node.id, input.scopeAddresses, now);
|
|
8647
9715
|
await this.#replaceMentions(tx, "node", node.id, node.content ?? "", input.resolutionScope ?? scope, scope);
|
|
8648
9716
|
await this.#activity(tx, "node-created", "node", node.id, scope);
|
|
8649
9717
|
await this.#outbox(tx, "node", node.id, "upsert", node.version, scope);
|
|
@@ -8660,13 +9728,13 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8660
9728
|
return this.#resolveNode(this.#readExecutor, input.name, canonicalizeKnowledgeScope(input.scope));
|
|
8661
9729
|
}
|
|
8662
9730
|
async listNodes(input) {
|
|
8663
|
-
const
|
|
9731
|
+
const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
|
|
8664
9732
|
const clauses = [
|
|
8665
9733
|
`type = 'node'`,
|
|
8666
9734
|
"mergedInto IS NULL",
|
|
8667
|
-
visibleSql
|
|
9735
|
+
visibleSql(keys)
|
|
8668
9736
|
];
|
|
8669
|
-
const args = [
|
|
9737
|
+
const args = [...keys];
|
|
8670
9738
|
if (input.namePrefix) {
|
|
8671
9739
|
clauses.push("canonicalName LIKE ? ESCAPE '='");
|
|
8672
9740
|
args.push(`${escapeLikePattern(canonicalName(input.namePrefix))}%`);
|
|
@@ -8718,6 +9786,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8718
9786
|
input.version
|
|
8719
9787
|
]
|
|
8720
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);
|
|
8721
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);
|
|
8722
9791
|
await this.#activity(tx, "node-updated", "node", input.id, scope);
|
|
8723
9792
|
if (knowledgeScopeKey(existing.scope) !== knowledgeScopeKey(scope)) {
|
|
@@ -8772,8 +9841,12 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8772
9841
|
]
|
|
8773
9842
|
})).rowsAffected === 0) throw new KnowledgeConflictError(source.id);
|
|
8774
9843
|
await tx.execute({
|
|
8775
|
-
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET node=? WHERE node=?`,
|
|
8776
|
-
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
|
+
]
|
|
8777
9850
|
});
|
|
8778
9851
|
await tx.execute({
|
|
8779
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=?)`,
|
|
@@ -8813,10 +9886,10 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8813
9886
|
});
|
|
8814
9887
|
}
|
|
8815
9888
|
async appendKnowledge(input) {
|
|
9889
|
+
await assertKnowledgeRecordTextWithinBoundCompat(input.text);
|
|
8816
9890
|
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
8817
9891
|
const resolutionScope = canonicalizeKnowledgeScope(input.resolutionScope);
|
|
8818
9892
|
const defaultScope = canonicalizeKnowledgeScope(input.defaultScope);
|
|
8819
|
-
assertKnowledgeScopeWithinCeiling(scope, input.maxScope);
|
|
8820
9893
|
return this.#transaction(async (tx) => {
|
|
8821
9894
|
const parent = await this.#resolveTerminalNode(tx, nodeReferenceId(input.node));
|
|
8822
9895
|
if (!parent) throw new KnowledgeNotFoundError("node", nodeReferenceId(input.node));
|
|
@@ -8829,11 +9902,10 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8829
9902
|
sourceThreadId: input.sourceThreadId,
|
|
8830
9903
|
capturedAt: /* @__PURE__ */ new Date(),
|
|
8831
9904
|
when: input.when ? new Date(input.when) : void 0,
|
|
8832
|
-
maxScope: input.maxScope,
|
|
8833
9905
|
metadata: input.metadata
|
|
8834
9906
|
};
|
|
8835
9907
|
await tx.execute({
|
|
8836
|
-
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)`,
|
|
8837
9909
|
args: [
|
|
8838
9910
|
record.id,
|
|
8839
9911
|
record.node,
|
|
@@ -8843,10 +9915,12 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8843
9915
|
record.sourceThreadId,
|
|
8844
9916
|
record.capturedAt.toISOString(),
|
|
8845
9917
|
record.when?.toISOString() ?? null,
|
|
8846
|
-
|
|
8847
|
-
|
|
9918
|
+
metadataJson,
|
|
9919
|
+
1,
|
|
9920
|
+
record.capturedAt.toISOString()
|
|
8848
9921
|
]
|
|
8849
9922
|
});
|
|
9923
|
+
await this.#replaceRecordScopes(tx, record.id, scope, record.capturedAt);
|
|
8850
9924
|
await this.#replaceMentions(tx, "record", record.id, record.text, resolutionScope, defaultScope);
|
|
8851
9925
|
await this.#activity(tx, "record-created", "record", record.id, scope, record.sourceThreadId);
|
|
8852
9926
|
await this.#outbox(tx, "record", record.id, "upsert", record.id, scope);
|
|
@@ -8873,17 +9947,13 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8873
9947
|
return this.#queryKnowledge(input, "related");
|
|
8874
9948
|
}
|
|
8875
9949
|
async knowledgeBySource(input) {
|
|
8876
|
-
const
|
|
8877
|
-
const args = [
|
|
8878
|
-
input.sourceThreadId,
|
|
8879
|
-
key,
|
|
8880
|
-
key
|
|
8881
|
-
];
|
|
9950
|
+
const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
|
|
9951
|
+
const args = [input.sourceThreadId, ...keys];
|
|
8882
9952
|
if (input.after) args.push(input.after);
|
|
8883
9953
|
const limit = input.limit ?? 100;
|
|
8884
9954
|
args.push(limit + 1);
|
|
8885
9955
|
const records = (await this.#readExecutor.execute({
|
|
8886
|
-
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 ?`,
|
|
8887
9957
|
args
|
|
8888
9958
|
})).rows.map(parseKnowledge);
|
|
8889
9959
|
return {
|
|
@@ -8898,10 +9968,11 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8898
9968
|
if (record.deletedAt) return record;
|
|
8899
9969
|
const deletedAt = /* @__PURE__ */ new Date();
|
|
8900
9970
|
await tx.execute({
|
|
8901
|
-
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`,
|
|
8902
9972
|
args: [
|
|
8903
9973
|
deletedAt.toISOString(),
|
|
8904
9974
|
input.deletedBy,
|
|
9975
|
+
deletedAt.toISOString(),
|
|
8905
9976
|
input.id
|
|
8906
9977
|
]
|
|
8907
9978
|
});
|
|
@@ -8920,8 +9991,8 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8920
9991
|
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
8921
9992
|
if (!record.deletedAt) return record;
|
|
8922
9993
|
await tx.execute({
|
|
8923
|
-
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET deletedAt=NULL,deletedBy=NULL WHERE id=?`,
|
|
8924
|
-
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]
|
|
8925
9996
|
});
|
|
8926
9997
|
await this.#activity(tx, "record-restored", "record", input.id, record.scope, record.sourceThreadId);
|
|
8927
9998
|
await this.#outbox(tx, "record", input.id, "upsert", createKnowledgeUlid(), record.scope);
|
|
@@ -8937,15 +10008,17 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8937
10008
|
return this.#transaction(async (tx) => {
|
|
8938
10009
|
const record = await this.#getKnowledge(tx, input.id, true);
|
|
8939
10010
|
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
8940
|
-
|
|
10011
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
8941
10012
|
await tx.execute({
|
|
8942
|
-
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=?`,
|
|
8943
10014
|
args: [
|
|
8944
10015
|
JSON.stringify(scope),
|
|
8945
10016
|
knowledgeScopeKey(scope),
|
|
10017
|
+
updatedAt.toISOString(),
|
|
8946
10018
|
input.id
|
|
8947
10019
|
]
|
|
8948
10020
|
});
|
|
10021
|
+
await this.#replaceRecordScopes(tx, input.id, scope, updatedAt);
|
|
8949
10022
|
await this.#activity(tx, "record-rescoped", "record", input.id, scope, record.sourceThreadId);
|
|
8950
10023
|
if (knowledgeScopeKey(record.scope) !== knowledgeScopeKey(scope)) await this.#outbox(tx, "record", input.id, "delete", createKnowledgeUlid(), record.scope);
|
|
8951
10024
|
if (!record.deletedAt) await this.#outbox(tx, "record", input.id, "upsert", createKnowledgeUlid(), scope);
|
|
@@ -8955,33 +10028,16 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
8955
10028
|
};
|
|
8956
10029
|
});
|
|
8957
10030
|
}
|
|
8958
|
-
async raiseKnowledgeCeiling(input) {
|
|
8959
|
-
return this.#transaction(async (tx) => {
|
|
8960
|
-
const record = await this.#getKnowledge(tx, input.id, true);
|
|
8961
|
-
if (!record) throw new KnowledgeNotFoundError("record", input.id);
|
|
8962
|
-
assertKnowledgeScopeWithinCeiling(record.scope, input.maxScope);
|
|
8963
|
-
assertKnowledgeCeilingRaised(record.maxScope, input.maxScope);
|
|
8964
|
-
await tx.execute({
|
|
8965
|
-
sql: `UPDATE "${TABLE_KNOWLEDGE_RECORDS}" SET maxScope=? WHERE id=?`,
|
|
8966
|
-
args: [input.maxScope ?? null, input.id]
|
|
8967
|
-
});
|
|
8968
|
-
return {
|
|
8969
|
-
...record,
|
|
8970
|
-
maxScope: input.maxScope
|
|
8971
|
-
};
|
|
8972
|
-
});
|
|
8973
|
-
}
|
|
8974
10031
|
async search(input) {
|
|
8975
10032
|
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
8976
|
-
const
|
|
10033
|
+
const keys = visibleScopeKeys(scope);
|
|
8977
10034
|
const normalizedQuery = input.query.trim().toLocaleLowerCase();
|
|
8978
10035
|
if (!normalizedQuery) return [];
|
|
8979
10036
|
const query = `%${escapeLikePattern(normalizedQuery)}%`;
|
|
8980
10037
|
const results = (await this.#readExecutor.execute({
|
|
8981
|
-
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 ?`,
|
|
8982
10039
|
args: [
|
|
8983
|
-
|
|
8984
|
-
key,
|
|
10040
|
+
...keys,
|
|
8985
10041
|
query,
|
|
8986
10042
|
query,
|
|
8987
10043
|
query,
|
|
@@ -9002,10 +10058,9 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9002
10058
|
}));
|
|
9003
10059
|
if (results.length < (input.limit ?? 20)) {
|
|
9004
10060
|
const records = await this.#readExecutor.execute({
|
|
9005
|
-
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 ?`,
|
|
9006
10062
|
args: [
|
|
9007
|
-
|
|
9008
|
-
key,
|
|
10063
|
+
...keys,
|
|
9009
10064
|
query,
|
|
9010
10065
|
(input.limit ?? 20) - results.length
|
|
9011
10066
|
]
|
|
@@ -9015,7 +10070,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9015
10070
|
return {
|
|
9016
10071
|
type: "record",
|
|
9017
10072
|
id: String(row.id),
|
|
9018
|
-
recordId: String(row.node),
|
|
10073
|
+
recordId: parentVisible ? String(row.node) : String(row.id),
|
|
9019
10074
|
name: parentVisible ? String(row.name) : "(private node)",
|
|
9020
10075
|
text: String(row.text),
|
|
9021
10076
|
scope: parseJson$1(row.scopeJson)
|
|
@@ -9024,41 +10079,26 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9024
10079
|
}
|
|
9025
10080
|
return results;
|
|
9026
10081
|
}
|
|
9027
|
-
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
const updatedAt = /* @__PURE__ */ new Date();
|
|
9041
|
-
if ((await this.#executor.execute({
|
|
9042
|
-
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`,
|
|
9043
|
-
args: [
|
|
9044
|
-
input.sourceThreadId,
|
|
9045
|
-
input.agent,
|
|
9046
|
-
input.lastKnowledgeId,
|
|
9047
|
-
updatedAt.toISOString()
|
|
9048
|
-
]
|
|
9049
|
-
})).rowsAffected === 0) throw new Error("Knowledge curation cursor cannot move backwards");
|
|
9050
|
-
return {
|
|
9051
|
-
...input,
|
|
9052
|
-
updatedAt
|
|
9053
|
-
};
|
|
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);
|
|
9054
10095
|
}
|
|
9055
10096
|
async listActivity(input) {
|
|
9056
|
-
const
|
|
10097
|
+
const keys = visibleScopeKeys(canonicalizeKnowledgeScope(input.scope));
|
|
9057
10098
|
return (await this.#readExecutor.execute({
|
|
9058
|
-
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 ?`,
|
|
9059
10100
|
args: [
|
|
9060
|
-
|
|
9061
|
-
key,
|
|
10101
|
+
...keys,
|
|
9062
10102
|
...input.after ? [input.after] : [],
|
|
9063
10103
|
input.limit ?? 100
|
|
9064
10104
|
]
|
|
@@ -9080,9 +10120,9 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9080
10120
|
args.push(input.status);
|
|
9081
10121
|
}
|
|
9082
10122
|
if (input.scope) {
|
|
9083
|
-
const
|
|
9084
|
-
clauses.push(visibleSql);
|
|
9085
|
-
args.push(
|
|
10123
|
+
const keys = visibleScopeKeys(input.scope);
|
|
10124
|
+
clauses.push(visibleSql(keys));
|
|
10125
|
+
args.push(...keys);
|
|
9086
10126
|
}
|
|
9087
10127
|
args.push(input.limit ?? 100);
|
|
9088
10128
|
return (await this.#executor.execute({
|
|
@@ -9101,9 +10141,9 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9101
10141
|
];
|
|
9102
10142
|
const args = [now.toISOString(), stale.toISOString()];
|
|
9103
10143
|
if (input.scope) {
|
|
9104
|
-
const
|
|
9105
|
-
clauses.push(visibleSql);
|
|
9106
|
-
args.push(
|
|
10144
|
+
const keys = visibleScopeKeys(input.scope);
|
|
10145
|
+
clauses.push(visibleSql(keys));
|
|
10146
|
+
args.push(...keys);
|
|
9107
10147
|
}
|
|
9108
10148
|
args.push(input.limit ?? 100);
|
|
9109
10149
|
const ids = (await tx.execute({
|
|
@@ -9170,12 +10210,14 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9170
10210
|
return result.rows[0] ? parseNode(result.rows[0]) : null;
|
|
9171
10211
|
}
|
|
9172
10212
|
async #resolveNode(executor, name, scope) {
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
|
|
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;
|
|
9179
10221
|
}
|
|
9180
10222
|
return null;
|
|
9181
10223
|
}
|
|
@@ -9200,17 +10242,16 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9200
10242
|
const scope = canonicalizeKnowledgeScope(input.scope);
|
|
9201
10243
|
const node = await this.#resolveTerminalNode(this.#readExecutor, nodeReferenceId(input.node));
|
|
9202
10244
|
if (!node) return { records: [] };
|
|
9203
|
-
const
|
|
10245
|
+
const keys = visibleScopeKeys(scope);
|
|
9204
10246
|
const args = [
|
|
9205
10247
|
node.id,
|
|
9206
10248
|
...relationship === "related" ? [node.id] : [],
|
|
9207
|
-
|
|
9208
|
-
key
|
|
10249
|
+
...keys
|
|
9209
10250
|
];
|
|
9210
10251
|
if (input.after) args.push(input.after);
|
|
9211
10252
|
args.push((input.limit ?? 100) + 1);
|
|
9212
10253
|
const records = (await this.#readExecutor.execute({
|
|
9213
|
-
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 ?`,
|
|
9214
10255
|
args
|
|
9215
10256
|
})).rows.map(parseKnowledge);
|
|
9216
10257
|
const limit = input.limit ?? 100;
|
|
@@ -9219,6 +10260,90 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9219
10260
|
nextCursor: records.length > limit ? records[limit - 1]?.id : void 0
|
|
9220
10261
|
};
|
|
9221
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
|
+
}
|
|
9222
10347
|
async #replaceMentions(tx, sourceType, sourceId, text, resolutionScope, defaultScope) {
|
|
9223
10348
|
await tx.execute({
|
|
9224
10349
|
sql: `DELETE FROM "${TABLE_KNOWLEDGE_MENTIONS}" WHERE sourceType=? AND sourceId=?`,
|
|
@@ -9242,7 +10367,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9242
10367
|
updatedAt: now
|
|
9243
10368
|
};
|
|
9244
10369
|
await tx.execute({
|
|
9245
|
-
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,?,?)`,
|
|
9246
10371
|
args: [
|
|
9247
10372
|
node.id,
|
|
9248
10373
|
"node",
|
|
@@ -9256,6 +10381,7 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9256
10381
|
now.toISOString()
|
|
9257
10382
|
]
|
|
9258
10383
|
});
|
|
10384
|
+
await this.#replaceNodeScopes(tx, node.id, defaultScope, now);
|
|
9259
10385
|
await this.#activity(tx, "node-created", "node", node.id, defaultScope);
|
|
9260
10386
|
await this.#outbox(tx, "node", node.id, "upsert", 1, defaultScope);
|
|
9261
10387
|
}
|
|
@@ -9272,13 +10398,17 @@ var KnowledgePG = class extends KnowledgeStorage {
|
|
|
9272
10398
|
}
|
|
9273
10399
|
async #activity(executor, action, recordType, recordId, scope, sourceThreadId) {
|
|
9274
10400
|
const now = /* @__PURE__ */ new Date();
|
|
10401
|
+
const [contextScopeId] = await this.#resolveScopeNodeIds(executor, scope);
|
|
9275
10402
|
await executor.execute({
|
|
9276
|
-
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(?),?,?,?)`,
|
|
9277
10404
|
args: [
|
|
9278
10405
|
createKnowledgeUlid(),
|
|
9279
10406
|
action,
|
|
9280
10407
|
recordType,
|
|
9281
10408
|
recordId,
|
|
10409
|
+
contextScopeId ?? null,
|
|
10410
|
+
recordType,
|
|
10411
|
+
recordId,
|
|
9282
10412
|
JSON.stringify(scope),
|
|
9283
10413
|
knowledgeScopeKey(scope),
|
|
9284
10414
|
sourceThreadId ?? null,
|
|
@@ -25038,7 +26168,10 @@ var PostgresStore = class extends MastraCompositeStore {
|
|
|
25038
26168
|
workflows: new WorkflowsPG(domainConfig),
|
|
25039
26169
|
workflowDefinitions: new WorkflowDefinitionsPG(domainConfig),
|
|
25040
26170
|
memory: new MemoryPG(domainConfig),
|
|
25041
|
-
knowledge: new KnowledgePG(
|
|
26171
|
+
knowledge: new KnowledgePG({
|
|
26172
|
+
...domainConfig,
|
|
26173
|
+
storageIsolationKey: config.storageIsolationKey ?? getPgKnowledgeIsolationKey(config)
|
|
26174
|
+
}),
|
|
25042
26175
|
notifications: new NotificationsPG(domainConfig),
|
|
25043
26176
|
observability: new ObservabilityPG(domainConfig),
|
|
25044
26177
|
agents: new AgentsPG(domainConfig),
|
|
@@ -25092,7 +26225,7 @@ var PostgresStore = class extends MastraCompositeStore {
|
|
|
25092
26225
|
const pinned = new PinnedClientAdapter(this.#writePool, pinnedClient);
|
|
25093
26226
|
this.#db.pin(pinned);
|
|
25094
26227
|
this.#db.setSchemaSnapshot(await loadSchemaSnapshot(pinned, this.schema));
|
|
25095
|
-
await
|
|
26228
|
+
await Promise.all(Object.entries(this.stores).filter(([name, store]) => name !== "knowledge" && store).map(([, store]) => store.init()));
|
|
25096
26229
|
this.isInitialized = true;
|
|
25097
26230
|
} catch (error) {
|
|
25098
26231
|
this.#initPromise = null;
|