@powerhousedao/knowledge-note 1.0.2 → 1.0.4
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/README.md +359 -122
- package/dist/editors/knowledge-vault/components/DriveExplorer.d.ts.map +1 -1
- package/dist/editors/knowledge-vault/components/DriveExplorer.js +8 -2
- package/dist/editors/knowledge-vault/components/GraphView.d.ts.map +1 -1
- package/dist/editors/knowledge-vault/components/GraphView.js +210 -32
- package/dist/editors/knowledge-vault/components/NoteList.d.ts.map +1 -1
- package/dist/editors/knowledge-vault/components/NoteList.js +13 -16
- package/dist/editors/knowledge-vault/components/SearchView.d.ts +2 -0
- package/dist/editors/knowledge-vault/components/SearchView.d.ts.map +1 -0
- package/dist/editors/knowledge-vault/components/SearchView.js +96 -0
- package/dist/editors/knowledge-vault/hooks/use-drive-init.d.ts.map +1 -1
- package/dist/editors/knowledge-vault/hooks/use-drive-init.js +0 -2
- package/dist/editors/knowledge-vault/hooks/use-graph-search.d.ts +25 -0
- package/dist/editors/knowledge-vault/hooks/use-graph-search.d.ts.map +1 -0
- package/dist/editors/knowledge-vault/hooks/use-graph-search.js +198 -0
- package/dist/package.json +3 -2
- package/dist/processors/factory.d.ts.map +1 -1
- package/dist/processors/factory.js +0 -3
- package/dist/processors/graph-indexer/embedder.d.ts +5 -0
- package/dist/processors/graph-indexer/embedder.d.ts.map +1 -0
- package/dist/processors/graph-indexer/embedder.js +27 -0
- package/dist/processors/graph-indexer/embedding-store.d.ts +11 -0
- package/dist/processors/graph-indexer/embedding-store.d.ts.map +1 -0
- package/dist/processors/graph-indexer/embedding-store.js +70 -0
- package/dist/processors/graph-indexer/index.d.ts.map +1 -1
- package/dist/processors/graph-indexer/index.js +53 -8
- package/dist/processors/graph-indexer/migrations.d.ts.map +1 -1
- package/dist/processors/graph-indexer/migrations.js +35 -0
- package/dist/processors/graph-indexer/query.d.ts +21 -0
- package/dist/processors/graph-indexer/query.d.ts.map +1 -1
- package/dist/processors/graph-indexer/query.js +154 -13
- package/dist/processors/graph-indexer/schema.d.ts +11 -0
- package/dist/processors/graph-indexer/schema.d.ts.map +1 -1
- package/dist/style.css +130 -0
- package/dist/subgraphs/index.d.ts +0 -1
- package/dist/subgraphs/index.d.ts.map +1 -1
- package/dist/subgraphs/index.js +0 -1
- package/dist/subgraphs/knowledge-graph/subgraph.d.ts +348 -24
- package/dist/subgraphs/knowledge-graph/subgraph.d.ts.map +1 -1
- package/dist/subgraphs/knowledge-graph/subgraph.js +334 -20
- package/package.json +4 -3
- package/dist/processors/methodology-indexer/factory.d.ts +0 -4
- package/dist/processors/methodology-indexer/factory.d.ts.map +0 -1
- package/dist/processors/methodology-indexer/factory.js +0 -23
- package/dist/processors/methodology-indexer/index.d.ts +0 -11
- package/dist/processors/methodology-indexer/index.d.ts.map +0 -1
- package/dist/processors/methodology-indexer/index.js +0 -116
- package/dist/processors/methodology-indexer/migrations.d.ts +0 -4
- package/dist/processors/methodology-indexer/migrations.d.ts.map +0 -1
- package/dist/processors/methodology-indexer/migrations.js +0 -39
- package/dist/processors/methodology-indexer/query.d.ts +0 -35
- package/dist/processors/methodology-indexer/query.d.ts.map +0 -1
- package/dist/processors/methodology-indexer/query.js +0 -114
- package/dist/processors/methodology-indexer/schema.d.ts +0 -22
- package/dist/processors/methodology-indexer/schema.d.ts.map +0 -1
- package/dist/processors/methodology-indexer/schema.js +0 -1
- package/dist/subgraphs/methodology/index.d.ts +0 -2
- package/dist/subgraphs/methodology/index.d.ts.map +0 -1
- package/dist/subgraphs/methodology/index.js +0 -1
- package/dist/subgraphs/methodology/subgraph.d.ts +0 -47
- package/dist/subgraphs/methodology/subgraph.d.ts.map +0 -1
- package/dist/subgraphs/methodology/subgraph.js +0 -100
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { gql } from "graphql-tag";
|
|
2
|
-
import { BaseSubgraph
|
|
2
|
+
import { BaseSubgraph } from "@powerhousedao/reactor-api";
|
|
3
3
|
import { GraphIndexerProcessor } from "../../processors/graph-indexer/index.js";
|
|
4
4
|
import { createGraphQuery } from "../../processors/graph-indexer/query.js";
|
|
5
|
+
import { generateEmbedding } from "../../processors/graph-indexer/embedder.js";
|
|
6
|
+
import { searchSimilar, getEmbedding, upsertEmbedding, } from "../../processors/graph-indexer/embedding-store.js";
|
|
5
7
|
export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
6
8
|
name = "knowledgeGraph";
|
|
7
9
|
typeDefs = gql `
|
|
@@ -12,6 +14,11 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
12
14
|
description: String
|
|
13
15
|
noteType: String
|
|
14
16
|
status: String
|
|
17
|
+
content: String
|
|
18
|
+
author: String
|
|
19
|
+
sourceOrigin: String
|
|
20
|
+
createdAt: String
|
|
21
|
+
topics: [String!]!
|
|
15
22
|
updatedAt: String!
|
|
16
23
|
}
|
|
17
24
|
|
|
@@ -36,6 +43,17 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
36
43
|
viaLinkType: String
|
|
37
44
|
}
|
|
38
45
|
|
|
46
|
+
type TopicInfo {
|
|
47
|
+
name: String!
|
|
48
|
+
noteCount: Int!
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type RelatedNode {
|
|
52
|
+
node: KnowledgeGraphNode!
|
|
53
|
+
sharedTopics: [String!]!
|
|
54
|
+
sharedTopicCount: Int!
|
|
55
|
+
}
|
|
56
|
+
|
|
39
57
|
extend type Query {
|
|
40
58
|
knowledgeGraphNodes(driveId: ID!): [KnowledgeGraphNode!]!
|
|
41
59
|
knowledgeGraphEdges(driveId: ID!): [KnowledgeGraphEdge!]!
|
|
@@ -72,6 +90,46 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
72
90
|
documentId: String!
|
|
73
91
|
): [KnowledgeGraphEdge!]!
|
|
74
92
|
|
|
93
|
+
knowledgeGraphTopics(driveId: ID!): [TopicInfo!]!
|
|
94
|
+
knowledgeGraphByTopic(
|
|
95
|
+
driveId: ID!
|
|
96
|
+
topic: String!
|
|
97
|
+
): [KnowledgeGraphNode!]!
|
|
98
|
+
knowledgeGraphRelatedByTopic(
|
|
99
|
+
driveId: ID!
|
|
100
|
+
documentId: String!
|
|
101
|
+
limit: Int
|
|
102
|
+
): [RelatedNode!]!
|
|
103
|
+
knowledgeGraphFullSearch(
|
|
104
|
+
driveId: ID!
|
|
105
|
+
query: String!
|
|
106
|
+
limit: Int
|
|
107
|
+
): [KnowledgeGraphNode!]!
|
|
108
|
+
knowledgeGraphByAuthor(
|
|
109
|
+
driveId: ID!
|
|
110
|
+
author: String!
|
|
111
|
+
): [KnowledgeGraphNode!]!
|
|
112
|
+
knowledgeGraphByOrigin(
|
|
113
|
+
driveId: ID!
|
|
114
|
+
origin: String!
|
|
115
|
+
): [KnowledgeGraphNode!]!
|
|
116
|
+
knowledgeGraphRecent(
|
|
117
|
+
driveId: ID!
|
|
118
|
+
limit: Int
|
|
119
|
+
since: String
|
|
120
|
+
): [KnowledgeGraphNode!]!
|
|
121
|
+
|
|
122
|
+
knowledgeGraphSemanticSearch(
|
|
123
|
+
driveId: ID!
|
|
124
|
+
query: String!
|
|
125
|
+
limit: Int
|
|
126
|
+
): [SemanticResult!]!
|
|
127
|
+
knowledgeGraphSimilar(
|
|
128
|
+
driveId: ID!
|
|
129
|
+
documentId: String!
|
|
130
|
+
limit: Int
|
|
131
|
+
): [SemanticResult!]!
|
|
132
|
+
|
|
75
133
|
"""
|
|
76
134
|
Debug: raw processor DB tables
|
|
77
135
|
"""
|
|
@@ -84,6 +142,11 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
84
142
|
sharedTarget: KnowledgeGraphNode!
|
|
85
143
|
}
|
|
86
144
|
|
|
145
|
+
type SemanticResult {
|
|
146
|
+
node: KnowledgeGraphNode!
|
|
147
|
+
similarity: Float!
|
|
148
|
+
}
|
|
149
|
+
|
|
87
150
|
type GraphDebugInfo {
|
|
88
151
|
rawNodeCount: Int!
|
|
89
152
|
rawEdgeCount: Int!
|
|
@@ -91,13 +154,44 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
91
154
|
rawEdges: [KnowledgeGraphEdge!]!
|
|
92
155
|
processorNamespace: String!
|
|
93
156
|
}
|
|
157
|
+
|
|
158
|
+
type ReindexResult {
|
|
159
|
+
indexedNodes: Int!
|
|
160
|
+
indexedEdges: Int!
|
|
161
|
+
errors: [String!]!
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
extend type Mutation {
|
|
165
|
+
"""
|
|
166
|
+
Backfill the graph index by reading all bai/knowledge-note documents
|
|
167
|
+
in the drive. Use when the processor missed historical operations.
|
|
168
|
+
"""
|
|
169
|
+
knowledgeGraphReindex(driveId: ID!): ReindexResult!
|
|
170
|
+
}
|
|
94
171
|
`;
|
|
95
172
|
resolvers = {
|
|
173
|
+
KnowledgeGraphNode: {
|
|
174
|
+
topics: async (parent) => {
|
|
175
|
+
// If topics were already resolved inline, return them
|
|
176
|
+
if (parent.topics)
|
|
177
|
+
return parent.topics;
|
|
178
|
+
// Otherwise resolve via field resolver using _driveId hint
|
|
179
|
+
if (parent._driveId) {
|
|
180
|
+
const query = this.getQuery(parent._driveId);
|
|
181
|
+
return query.topicsForNode(parent.documentId);
|
|
182
|
+
}
|
|
183
|
+
return [];
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
Mutation: {
|
|
187
|
+
knowledgeGraphReindex: (_, args) => this.reindexDrive(args.driveId),
|
|
188
|
+
},
|
|
96
189
|
Query: {
|
|
97
190
|
knowledgeGraphNodes: async (_, args) => {
|
|
98
191
|
await this.ensureGraphDoc(args.driveId);
|
|
99
192
|
const query = this.getQuery(args.driveId);
|
|
100
|
-
|
|
193
|
+
const nodes = await query.allNodes();
|
|
194
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
101
195
|
},
|
|
102
196
|
knowledgeGraphEdges: async (_, args) => {
|
|
103
197
|
await this.ensureGraphDoc(args.driveId);
|
|
@@ -111,19 +205,26 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
111
205
|
},
|
|
112
206
|
knowledgeGraphNodeByDocumentId: async (_, args) => {
|
|
113
207
|
const query = this.getQuery(args.driveId);
|
|
114
|
-
|
|
208
|
+
const node = await query.nodeByDocumentId(args.documentId);
|
|
209
|
+
return node ? { ...node, _driveId: args.driveId } : null;
|
|
115
210
|
},
|
|
116
211
|
knowledgeGraphOrphans: async (_, args) => {
|
|
117
212
|
const query = this.getQuery(args.driveId);
|
|
118
|
-
|
|
213
|
+
const nodes = await query.orphanNodes();
|
|
214
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
119
215
|
},
|
|
120
216
|
knowledgeGraphConnections: async (_, args) => {
|
|
121
217
|
const query = this.getQuery(args.driveId);
|
|
122
|
-
|
|
218
|
+
const connections = await query.connections(args.documentId, args.depth ?? 2);
|
|
219
|
+
return connections.map((c) => ({
|
|
220
|
+
...c,
|
|
221
|
+
node: { ...c.node, _driveId: args.driveId },
|
|
222
|
+
}));
|
|
123
223
|
},
|
|
124
224
|
knowledgeGraphNodesByStatus: async (_, args) => {
|
|
125
225
|
const query = this.getQuery(args.driveId);
|
|
126
|
-
|
|
226
|
+
const nodes = await query.nodesByStatus(args.status);
|
|
227
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
127
228
|
},
|
|
128
229
|
knowledgeGraphBacklinks: async (_, args) => {
|
|
129
230
|
const query = this.getQuery(args.driveId);
|
|
@@ -135,33 +236,110 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
135
236
|
},
|
|
136
237
|
knowledgeGraphSearch: async (_, args) => {
|
|
137
238
|
const query = this.getQuery(args.driveId);
|
|
138
|
-
|
|
239
|
+
const nodes = await query.searchNodes(args.query, args.limit ?? 50);
|
|
240
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
139
241
|
},
|
|
140
242
|
knowledgeGraphTriangles: async (_, args) => {
|
|
141
243
|
const query = this.getQuery(args.driveId);
|
|
142
244
|
const triangles = await query.triangles(args.limit ?? 20);
|
|
143
245
|
return triangles.map((t) => ({
|
|
144
|
-
noteA: t.a,
|
|
145
|
-
noteB: t.b,
|
|
146
|
-
sharedTarget: t.sharedTarget,
|
|
246
|
+
noteA: { ...t.a, _driveId: args.driveId },
|
|
247
|
+
noteB: { ...t.b, _driveId: args.driveId },
|
|
248
|
+
sharedTarget: { ...t.sharedTarget, _driveId: args.driveId },
|
|
147
249
|
}));
|
|
148
250
|
},
|
|
149
251
|
knowledgeGraphBridges: async (_, args) => {
|
|
150
252
|
const query = this.getQuery(args.driveId);
|
|
151
|
-
|
|
253
|
+
const nodes = await query.bridges();
|
|
254
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
152
255
|
},
|
|
153
256
|
knowledgeGraphForwardLinks: async (_, args) => {
|
|
154
257
|
const query = this.getQuery(args.driveId);
|
|
155
258
|
return query.forwardLinks(args.documentId);
|
|
156
259
|
},
|
|
260
|
+
// --- Phase 1: new query resolvers ---
|
|
261
|
+
knowledgeGraphTopics: async (_, args) => {
|
|
262
|
+
const query = this.getQuery(args.driveId);
|
|
263
|
+
return query.topicStats();
|
|
264
|
+
},
|
|
265
|
+
knowledgeGraphByTopic: async (_, args) => {
|
|
266
|
+
const query = this.getQuery(args.driveId);
|
|
267
|
+
const nodes = await query.nodesByTopic(args.topic);
|
|
268
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
269
|
+
},
|
|
270
|
+
knowledgeGraphRelatedByTopic: async (_, args) => {
|
|
271
|
+
const query = this.getQuery(args.driveId);
|
|
272
|
+
const results = await query.relatedByTopic(args.documentId, args.limit ?? 10);
|
|
273
|
+
return results.map((r) => ({
|
|
274
|
+
...r,
|
|
275
|
+
node: { ...r.node, _driveId: args.driveId },
|
|
276
|
+
}));
|
|
277
|
+
},
|
|
278
|
+
knowledgeGraphFullSearch: async (_, args) => {
|
|
279
|
+
const query = this.getQuery(args.driveId);
|
|
280
|
+
const nodes = await query.fullSearch(args.query, args.limit ?? 50);
|
|
281
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
282
|
+
},
|
|
283
|
+
knowledgeGraphByAuthor: async (_, args) => {
|
|
284
|
+
const query = this.getQuery(args.driveId);
|
|
285
|
+
const nodes = await query.nodesByAuthor(args.author);
|
|
286
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
287
|
+
},
|
|
288
|
+
knowledgeGraphByOrigin: async (_, args) => {
|
|
289
|
+
const query = this.getQuery(args.driveId);
|
|
290
|
+
const nodes = await query.nodesByOrigin(args.origin);
|
|
291
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
292
|
+
},
|
|
293
|
+
knowledgeGraphRecent: async (_, args) => {
|
|
294
|
+
const query = this.getQuery(args.driveId);
|
|
295
|
+
const nodes = await query.recentNodes(args.limit ?? 20, args.since ?? undefined);
|
|
296
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
297
|
+
},
|
|
298
|
+
knowledgeGraphSemanticSearch: async (_, args) => {
|
|
299
|
+
const queryEmbedding = await generateEmbedding(args.query);
|
|
300
|
+
const results = await searchSimilar(queryEmbedding, args.limit ?? 10);
|
|
301
|
+
const graphQuery = this.getQuery(args.driveId);
|
|
302
|
+
const semanticResults = [];
|
|
303
|
+
for (const result of results) {
|
|
304
|
+
const node = await graphQuery.nodeByDocumentId(result.documentId);
|
|
305
|
+
if (node) {
|
|
306
|
+
semanticResults.push({
|
|
307
|
+
node: { ...node, _driveId: args.driveId },
|
|
308
|
+
similarity: result.similarity,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return semanticResults;
|
|
313
|
+
},
|
|
314
|
+
knowledgeGraphSimilar: async (_, args) => {
|
|
315
|
+
const embedding = await getEmbedding(args.documentId);
|
|
316
|
+
if (!embedding)
|
|
317
|
+
return [];
|
|
318
|
+
const results = await searchSimilar(embedding, (args.limit ?? 10) + 1);
|
|
319
|
+
const graphQuery = this.getQuery(args.driveId);
|
|
320
|
+
const semanticResults = [];
|
|
321
|
+
for (const result of results) {
|
|
322
|
+
if (result.documentId === args.documentId)
|
|
323
|
+
continue;
|
|
324
|
+
const node = await graphQuery.nodeByDocumentId(result.documentId);
|
|
325
|
+
if (node) {
|
|
326
|
+
semanticResults.push({
|
|
327
|
+
node: { ...node, _driveId: args.driveId },
|
|
328
|
+
similarity: result.similarity,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return semanticResults.slice(0, args.limit ?? 10);
|
|
333
|
+
},
|
|
157
334
|
knowledgeGraphDebug: async (_, args) => {
|
|
158
335
|
const namespace = GraphIndexerProcessor.getNamespace(args.driveId);
|
|
159
336
|
try {
|
|
160
|
-
const
|
|
337
|
+
const db = this.getDb(args.driveId);
|
|
338
|
+
const rawNodes = await db
|
|
161
339
|
.selectFrom("graph_nodes")
|
|
162
340
|
.selectAll()
|
|
163
341
|
.execute();
|
|
164
|
-
const rawEdges = await
|
|
342
|
+
const rawEdges = await db
|
|
165
343
|
.selectFrom("graph_edges")
|
|
166
344
|
.selectAll()
|
|
167
345
|
.execute();
|
|
@@ -175,7 +353,13 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
175
353
|
description: r.description,
|
|
176
354
|
noteType: r.note_type,
|
|
177
355
|
status: r.status,
|
|
356
|
+
content: r.content,
|
|
357
|
+
author: r.author,
|
|
358
|
+
sourceOrigin: r.source_origin,
|
|
359
|
+
createdAt: r.created_at,
|
|
360
|
+
topics: [],
|
|
178
361
|
updatedAt: r.updated_at,
|
|
362
|
+
_driveId: args.driveId,
|
|
179
363
|
})),
|
|
180
364
|
rawEdges: rawEdges.map((r) => ({
|
|
181
365
|
id: r.id,
|
|
@@ -204,18 +388,148 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
204
388
|
constructor(args) {
|
|
205
389
|
super(args);
|
|
206
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Returns a Kysely<DB> instance scoped to the processor's namespace
|
|
393
|
+
* for the given drive. Centralizes the Legacy -> IRelationalDb cast.
|
|
394
|
+
*/
|
|
395
|
+
/**
|
|
396
|
+
* Read-only namespaced query builder — use for all SELECT resolvers.
|
|
397
|
+
*/
|
|
398
|
+
getDb(driveId) {
|
|
399
|
+
return GraphIndexerProcessor.query(driveId, this.relationalDb);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Writable namespaced Kysely instance — use for reindex (INSERT/DELETE).
|
|
403
|
+
* createNamespace returns a full Kysely, not the read-only query builder.
|
|
404
|
+
*/
|
|
405
|
+
async getWritableDb(driveId) {
|
|
406
|
+
const namespace = GraphIndexerProcessor.getNamespace(driveId);
|
|
407
|
+
return (await this.relationalDb.createNamespace(namespace));
|
|
408
|
+
}
|
|
207
409
|
getQuery(driveId) {
|
|
208
|
-
|
|
209
|
-
// (same pattern as the working workstreams example)
|
|
210
|
-
const queryBuilder = GraphIndexerProcessor.query(driveId, this.relationalDb);
|
|
211
|
-
return createGraphQuery(queryBuilder);
|
|
410
|
+
return createGraphQuery(this.getDb(driveId));
|
|
212
411
|
}
|
|
213
412
|
/**
|
|
214
413
|
* Ensures a bai/knowledge-graph document exists in the given drive.
|
|
215
|
-
* Called lazily on first query
|
|
414
|
+
* Called lazily on first query -- supports API/plugin access without
|
|
216
415
|
* requiring the Connect UI to have initialized the drive first.
|
|
217
416
|
*/
|
|
218
417
|
ensuredDrives = new Set();
|
|
418
|
+
async reindexDrive(driveId) {
|
|
419
|
+
const errors = [];
|
|
420
|
+
let indexedNodes = 0;
|
|
421
|
+
let indexedEdges = 0;
|
|
422
|
+
try {
|
|
423
|
+
const drive = await this.reactorClient.get(driveId);
|
|
424
|
+
const nodes = drive.state.global.nodes;
|
|
425
|
+
const noteNodes = nodes.filter((n) => n.kind === "file" && n.documentType === "bai/knowledge-note");
|
|
426
|
+
const db = await this.getWritableDb(driveId);
|
|
427
|
+
const now = new Date().toISOString();
|
|
428
|
+
for (const node of noteNodes) {
|
|
429
|
+
try {
|
|
430
|
+
const doc = await this.reactorClient.get(node.id);
|
|
431
|
+
const state = doc.state;
|
|
432
|
+
const global = state.global;
|
|
433
|
+
// Extract provenance
|
|
434
|
+
const provenance = global.provenance;
|
|
435
|
+
await db
|
|
436
|
+
.insertInto("graph_nodes")
|
|
437
|
+
.values({
|
|
438
|
+
id: node.id,
|
|
439
|
+
document_id: node.id,
|
|
440
|
+
title: global.title ?? null,
|
|
441
|
+
description: global.description ?? null,
|
|
442
|
+
note_type: global.noteType ?? null,
|
|
443
|
+
status: global.status ?? "DRAFT",
|
|
444
|
+
content: global.content ?? null,
|
|
445
|
+
author: provenance?.author ?? null,
|
|
446
|
+
source_origin: provenance?.sourceOrigin ?? null,
|
|
447
|
+
created_at: provenance?.createdAt ?? null,
|
|
448
|
+
updated_at: now,
|
|
449
|
+
})
|
|
450
|
+
.onConflict((oc) => oc.column("document_id").doUpdateSet({
|
|
451
|
+
title: global.title ?? null,
|
|
452
|
+
description: global.description ?? null,
|
|
453
|
+
note_type: global.noteType ?? null,
|
|
454
|
+
status: global.status ?? "DRAFT",
|
|
455
|
+
content: global.content ?? null,
|
|
456
|
+
author: provenance?.author ?? null,
|
|
457
|
+
source_origin: provenance?.sourceOrigin ?? null,
|
|
458
|
+
created_at: provenance?.createdAt ?? null,
|
|
459
|
+
updated_at: now,
|
|
460
|
+
}))
|
|
461
|
+
.execute();
|
|
462
|
+
indexedNodes++;
|
|
463
|
+
// Reconcile topics
|
|
464
|
+
await db
|
|
465
|
+
.deleteFrom("graph_topics")
|
|
466
|
+
.where("document_id", "=", node.id)
|
|
467
|
+
.execute();
|
|
468
|
+
const topics = global.topics ?? [];
|
|
469
|
+
if (topics.length > 0) {
|
|
470
|
+
await db
|
|
471
|
+
.insertInto("graph_topics")
|
|
472
|
+
.values(topics.map((topic, idx) => {
|
|
473
|
+
const name = typeof topic === "string"
|
|
474
|
+
? topic
|
|
475
|
+
: (topic.name ?? "");
|
|
476
|
+
return {
|
|
477
|
+
id: `${node.id}-topic-${idx}`,
|
|
478
|
+
document_id: node.id,
|
|
479
|
+
name,
|
|
480
|
+
updated_at: now,
|
|
481
|
+
};
|
|
482
|
+
}))
|
|
483
|
+
.execute();
|
|
484
|
+
}
|
|
485
|
+
// Reconcile edges
|
|
486
|
+
await db
|
|
487
|
+
.deleteFrom("graph_edges")
|
|
488
|
+
.where("source_document_id", "=", node.id)
|
|
489
|
+
.execute();
|
|
490
|
+
const links = global.links ?? [];
|
|
491
|
+
if (links.length > 0) {
|
|
492
|
+
await db
|
|
493
|
+
.insertInto("graph_edges")
|
|
494
|
+
.values(links.map((link) => ({
|
|
495
|
+
id: link.id ??
|
|
496
|
+
`${node.id}-${link.targetDocumentId}`,
|
|
497
|
+
source_document_id: node.id,
|
|
498
|
+
target_document_id: link.targetDocumentId ?? "",
|
|
499
|
+
link_type: link.linkType ?? null,
|
|
500
|
+
target_title: link.targetTitle ?? null,
|
|
501
|
+
updated_at: now,
|
|
502
|
+
})))
|
|
503
|
+
.execute();
|
|
504
|
+
indexedEdges += links.length;
|
|
505
|
+
}
|
|
506
|
+
// Generate embedding for semantic search
|
|
507
|
+
const text = [global.title, global.description, global.content]
|
|
508
|
+
.filter(Boolean)
|
|
509
|
+
.join(" ");
|
|
510
|
+
if (text.length > 0) {
|
|
511
|
+
try {
|
|
512
|
+
const emb = await generateEmbedding(text);
|
|
513
|
+
await upsertEmbedding(node.id, emb);
|
|
514
|
+
}
|
|
515
|
+
catch (embErr) {
|
|
516
|
+
console.warn(`[KnowledgeGraphSubgraph] Embedding failed for ${node.id}:`, embErr);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
catch (err) {
|
|
521
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
522
|
+
errors.push(`${node.id}: ${msg}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
console.log(`[KnowledgeGraphSubgraph] Reindex complete: ${indexedNodes} nodes, ${indexedEdges} edges, ${errors.length} errors`);
|
|
526
|
+
}
|
|
527
|
+
catch (err) {
|
|
528
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
529
|
+
errors.push(`Drive read failed: ${msg}`);
|
|
530
|
+
}
|
|
531
|
+
return { indexedNodes, indexedEdges, errors };
|
|
532
|
+
}
|
|
219
533
|
async ensureGraphDoc(driveId) {
|
|
220
534
|
if (this.ensuredDrives.has(driveId))
|
|
221
535
|
return;
|
|
@@ -235,12 +549,12 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
235
549
|
console.log(`[KnowledgeGraphSubgraph] Auto-created KnowledgeGraph in drive ${driveId}` +
|
|
236
550
|
(parentFolder
|
|
237
551
|
? ` (folder: /self/)`
|
|
238
|
-
: ` (drive root
|
|
552
|
+
: ` (drive root -- /self/ folder not found)`));
|
|
239
553
|
}
|
|
240
554
|
}
|
|
241
555
|
catch (err) {
|
|
242
556
|
console.error(`[KnowledgeGraphSubgraph] Failed to ensure graph doc:`, err);
|
|
243
|
-
// Don't block queries if this fails
|
|
557
|
+
// Don't block queries if this fails -- processor data still works
|
|
244
558
|
}
|
|
245
559
|
}
|
|
246
560
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/knowledge-note",
|
|
3
3
|
"description": "Knowledge Note document model package for Powerhouse",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.4",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
8
8
|
"/dist"
|
|
9
9
|
],
|
|
10
|
-
|
|
10
|
+
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
13
|
"exports": {
|
|
@@ -107,13 +107,14 @@
|
|
|
107
107
|
},
|
|
108
108
|
"dependencies": {
|
|
109
109
|
"@electric-sql/pglite": "0.3.15",
|
|
110
|
+
"@huggingface/transformers": "^4.0.1",
|
|
110
111
|
"@powerhousedao/builder-tools": "6.0.0-dev.105",
|
|
111
112
|
"@powerhousedao/common": "6.0.0-dev.105",
|
|
112
113
|
"@powerhousedao/design-system": "6.0.0-dev.105",
|
|
113
114
|
"@powerhousedao/document-engineering": "1.40.1",
|
|
114
115
|
"@powerhousedao/vetra": "6.0.0-dev.105",
|
|
115
116
|
"cytoscape": "^3.33.1",
|
|
116
|
-
"cytoscape-
|
|
117
|
+
"cytoscape-fcose": "^2.2.0",
|
|
117
118
|
"document-model": "6.0.0-dev.105",
|
|
118
119
|
"graphql": "16.12.0",
|
|
119
120
|
"graphql-tag": "^2.12.6",
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { ProcessorRecord, IProcessorHostModule } from "@powerhousedao/reactor-browser";
|
|
2
|
-
import type { PHDocumentHeader } from "document-model";
|
|
3
|
-
export declare const methodologyIndexerProcessorFactory: (module: IProcessorHostModule) => (driveHeader: PHDocumentHeader) => Promise<ProcessorRecord[]>;
|
|
4
|
-
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../processors/methodology-indexer/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,eAAO,MAAM,kCAAkC,GAC5C,QAAQ,oBAAoB,MACtB,aAAa,gBAAgB,KAAG,OAAO,CAAC,eAAe,EAAE,CAgC/D,CAAC"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import {} from "@powerhousedao/shared/processors";
|
|
2
|
-
import { MethodologyIndexerProcessor } from "./index.js";
|
|
3
|
-
export const methodologyIndexerProcessorFactory = (module) => async (driveHeader) => {
|
|
4
|
-
const namespace = MethodologyIndexerProcessor.getNamespace(driveHeader.id);
|
|
5
|
-
console.log(`[MethodologyIndexer] Factory called for drive: ${driveHeader.id}, namespace: ${namespace}`);
|
|
6
|
-
const store = await module.relationalDb.createNamespace(namespace);
|
|
7
|
-
const filter = {
|
|
8
|
-
branch: ["main"],
|
|
9
|
-
documentId: ["*"],
|
|
10
|
-
documentType: ["bai/research-claim", "powerhouse/document-drive"],
|
|
11
|
-
scope: ["global"],
|
|
12
|
-
};
|
|
13
|
-
const processor = new MethodologyIndexerProcessor(namespace, filter, store);
|
|
14
|
-
await processor.initAndUpgrade();
|
|
15
|
-
console.log(`[MethodologyIndexer] Processor created for drive: ${driveHeader.id}`);
|
|
16
|
-
return [
|
|
17
|
-
{
|
|
18
|
-
processor,
|
|
19
|
-
filter,
|
|
20
|
-
startFrom: "beginning",
|
|
21
|
-
},
|
|
22
|
-
];
|
|
23
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { RelationalDbProcessor } from "@powerhousedao/shared/processors";
|
|
2
|
-
import type { OperationWithContext } from "@powerhousedao/shared/document-model";
|
|
3
|
-
import type { MethodologyDB } from "./schema.js";
|
|
4
|
-
export declare class MethodologyIndexerProcessor extends RelationalDbProcessor<MethodologyDB> {
|
|
5
|
-
static getNamespace(driveId: string): string;
|
|
6
|
-
initAndUpgrade(): Promise<void>;
|
|
7
|
-
onOperations(operations: OperationWithContext[]): Promise<void>;
|
|
8
|
-
onDisconnect(): Promise<void>;
|
|
9
|
-
private deleteClaim;
|
|
10
|
-
}
|
|
11
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../processors/methodology-indexer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,qBAAa,2BAA4B,SAAQ,qBAAqB,CAAC,aAAa,CAAC;WACnE,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAItC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,YAAY,CACzB,UAAU,EAAE,oBAAoB,EAAE,GACjC,OAAO,CAAC,IAAI,CAAC;IAsGV,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAYrB,WAAW;CAkB1B"}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { RelationalDbProcessor } from "@powerhousedao/shared/processors";
|
|
2
|
-
import { up } from "./migrations.js";
|
|
3
|
-
export class MethodologyIndexerProcessor extends RelationalDbProcessor {
|
|
4
|
-
static getNamespace(driveId) {
|
|
5
|
-
return super.getNamespace(driveId);
|
|
6
|
-
}
|
|
7
|
-
async initAndUpgrade() {
|
|
8
|
-
await up(this.relationalDb);
|
|
9
|
-
}
|
|
10
|
-
async onOperations(operations) {
|
|
11
|
-
if (operations.length === 0)
|
|
12
|
-
return;
|
|
13
|
-
const lastByDocument = new Map();
|
|
14
|
-
for (const entry of operations) {
|
|
15
|
-
const { operation, context } = entry;
|
|
16
|
-
const documentId = context.documentId;
|
|
17
|
-
// Handle deletion from drive
|
|
18
|
-
if (context.documentType === "powerhouse/document-drive" &&
|
|
19
|
-
operation.action.type === "DELETE_NODE") {
|
|
20
|
-
const deleteInput = operation.action.input;
|
|
21
|
-
await this.deleteClaim(deleteInput.id);
|
|
22
|
-
lastByDocument.delete(deleteInput.id);
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
// Only process research-claim documents
|
|
26
|
-
if (context.documentType !== "bai/research-claim")
|
|
27
|
-
continue;
|
|
28
|
-
if (context.resultingState) {
|
|
29
|
-
lastByDocument.set(documentId, entry);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
for (const [documentId, entry] of lastByDocument) {
|
|
33
|
-
try {
|
|
34
|
-
const stateJson = entry.context.resultingState;
|
|
35
|
-
if (!stateJson)
|
|
36
|
-
continue;
|
|
37
|
-
const parsed = JSON.parse(stateJson);
|
|
38
|
-
const global = (parsed.global ?? parsed);
|
|
39
|
-
const now = new Date().toISOString();
|
|
40
|
-
// Upsert claim
|
|
41
|
-
const topics = global.topics ?? [];
|
|
42
|
-
const methodology = global.methodology ?? [];
|
|
43
|
-
await this.relationalDb
|
|
44
|
-
.insertInto("methodology_claims")
|
|
45
|
-
.values({
|
|
46
|
-
id: documentId,
|
|
47
|
-
document_id: documentId,
|
|
48
|
-
title: global.title ?? null,
|
|
49
|
-
description: global.description ?? null,
|
|
50
|
-
kind: global.kind ?? null,
|
|
51
|
-
topics: JSON.stringify(topics),
|
|
52
|
-
methodology: JSON.stringify(methodology),
|
|
53
|
-
updated_at: now,
|
|
54
|
-
})
|
|
55
|
-
.onConflict((oc) => oc.column("document_id").doUpdateSet({
|
|
56
|
-
title: global.title ?? null,
|
|
57
|
-
description: global.description ?? null,
|
|
58
|
-
kind: global.kind ?? null,
|
|
59
|
-
topics: JSON.stringify(topics),
|
|
60
|
-
methodology: JSON.stringify(methodology),
|
|
61
|
-
updated_at: now,
|
|
62
|
-
}))
|
|
63
|
-
.execute();
|
|
64
|
-
// Reconcile connections
|
|
65
|
-
await this.relationalDb
|
|
66
|
-
.deleteFrom("methodology_connections")
|
|
67
|
-
.where("source_document_id", "=", documentId)
|
|
68
|
-
.execute();
|
|
69
|
-
const connections = global.connections ?? [];
|
|
70
|
-
if (connections.length > 0) {
|
|
71
|
-
await this.relationalDb
|
|
72
|
-
.insertInto("methodology_connections")
|
|
73
|
-
.values(connections.map((conn) => ({
|
|
74
|
-
id: conn.id ??
|
|
75
|
-
`${documentId}-${conn.targetRef}`,
|
|
76
|
-
source_document_id: documentId,
|
|
77
|
-
target_ref: conn.targetRef ?? "",
|
|
78
|
-
context_phrase: conn.contextPhrase ?? null,
|
|
79
|
-
updated_at: now,
|
|
80
|
-
})))
|
|
81
|
-
.execute();
|
|
82
|
-
}
|
|
83
|
-
console.log(`[MethodologyIndexer] Reconciled ${documentId}: ${connections.length} connections`);
|
|
84
|
-
}
|
|
85
|
-
catch (err) {
|
|
86
|
-
console.error(`[MethodologyIndexer] Error reconciling ${documentId}:`, err);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
async onDisconnect() {
|
|
91
|
-
try {
|
|
92
|
-
await this.relationalDb.deleteFrom("methodology_connections").execute();
|
|
93
|
-
await this.relationalDb.deleteFrom("methodology_claims").execute();
|
|
94
|
-
console.log(`[MethodologyIndexer] Cleaned up namespace: ${this.namespace}`);
|
|
95
|
-
}
|
|
96
|
-
catch (err) {
|
|
97
|
-
console.error(`[MethodologyIndexer] Error cleaning up:`, err);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
async deleteClaim(documentId) {
|
|
101
|
-
try {
|
|
102
|
-
await this.relationalDb
|
|
103
|
-
.deleteFrom("methodology_connections")
|
|
104
|
-
.where("source_document_id", "=", documentId)
|
|
105
|
-
.execute();
|
|
106
|
-
await this.relationalDb
|
|
107
|
-
.deleteFrom("methodology_claims")
|
|
108
|
-
.where("document_id", "=", documentId)
|
|
109
|
-
.execute();
|
|
110
|
-
console.log(`[MethodologyIndexer] Deleted claim ${documentId}`);
|
|
111
|
-
}
|
|
112
|
-
catch (err) {
|
|
113
|
-
console.error(`[MethodologyIndexer] Error deleting claim ${documentId}:`, err);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|