fuli-context 0.4.0 → 0.7.2

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.
Files changed (207) hide show
  1. package/README.en.md +5 -0
  2. package/README.md +411 -173
  3. package/README.zh-CN.md +448 -0
  4. package/compose.graphiti.yml +6 -6
  5. package/dist/web/assets/AboutPage-DXh7Fwxt.css +1 -0
  6. package/dist/web/assets/AboutPage-DfnZo7Lo.js +1 -0
  7. package/dist/web/assets/ConnectionsPage-BloaSKmt.js +1 -0
  8. package/dist/web/assets/ConnectionsPage-CBHAdZXT.css +1 -0
  9. package/dist/web/assets/KnowledgeInspector-Bjhdu2mf.css +1 -0
  10. package/dist/web/assets/KnowledgeInspector-QvNpv0_k.js +1 -0
  11. package/dist/web/assets/KnowledgeOrganizerPage-Cx1w1jb2.css +1 -0
  12. package/dist/web/assets/KnowledgeOrganizerPage-DKq1jVD5.js +1 -0
  13. package/dist/web/assets/KnowledgePage-BWL0jT01.js +1 -0
  14. package/dist/web/assets/KnowledgeWorkspace-Czq6aZ7b.js +4 -0
  15. package/dist/web/assets/OverviewPage-5sJoO1Gh.js +1 -0
  16. package/dist/web/assets/{PersonalProfilePage-S8ZcG2LU.css → PersonalProfilePage-CdmEzyvZ.css} +1 -1
  17. package/dist/web/assets/PersonalProfilePage-tVChM9ik.js +1 -0
  18. package/dist/web/assets/PersonalProjectsPage-BPFrup4V.js +1 -0
  19. package/dist/web/assets/PublicProjectsPage-BPJSeREN.js +1 -0
  20. package/dist/web/assets/ReviewPage-B7EN817i.js +1 -0
  21. package/dist/web/assets/SearchableSelect-ClLN0rIb.js +1 -0
  22. package/dist/web/assets/SettingsPage-C6ouU0sR.css +1 -0
  23. package/dist/web/assets/SettingsPage-Chd_B3eH.js +1 -0
  24. package/dist/web/assets/_plugin-vue_export-helper-BDNMzG2s.js +1 -0
  25. package/dist/web/assets/console-CbDsKrsO.js +1 -0
  26. package/dist/web/assets/fuli-logo-Bu9WBuQe.js +1 -0
  27. package/dist/web/assets/fuli-logo-ER1wQ8Kk.png +0 -0
  28. package/dist/web/assets/i18n-BQcns1PH.js +5 -0
  29. package/dist/web/assets/identity-B8K4VYg6.js +1 -0
  30. package/dist/web/assets/index-CB8Xmsc2.js +2 -0
  31. package/dist/web/assets/index-CZeuPh-U.css +1 -0
  32. package/dist/web/assets/model-eF52GgPF.js +1 -0
  33. package/dist/web/assets/paths-hwz-Ac1g.js +1 -0
  34. package/dist/web/assets/useMinimumLoadingDisplay-BpCyBeko.css +1 -0
  35. package/dist/web/assets/useMinimumLoadingDisplay-wCgGDmHg.js +1 -0
  36. package/dist/web/assets/vue-router-BsEp_XwI.js +1 -0
  37. package/dist/web/index.html +9 -6
  38. package/docs/external-knowledge-architecture.md +279 -0
  39. package/examples/external-knowledge/markdown-folder.mjs +235 -0
  40. package/graph-provider/fuli_graph/app.py +57 -1
  41. package/graph-provider/fuli_graph/graph_models.py +3 -0
  42. package/graph-provider/fuli_graph/graph_query.py +62 -16
  43. package/graph-provider/fuli_graph/knowledge_review.py +612 -0
  44. package/graph-provider/fuli_graph/knowledge_review_models.py +127 -0
  45. package/graph-provider/fuli_graph/knowledge_search.py +51 -4
  46. package/graph-provider/fuli_graph/models.py +19 -0
  47. package/graph-provider/fuli_graph/runtime.py +15 -0
  48. package/graph-provider/fuli_graph/store_knowledge.py +2 -1
  49. package/graph-provider/pyproject.toml +1 -1
  50. package/npm-shrinkwrap.json +5 -407
  51. package/package.json +7 -4
  52. package/skills/capturing-session-knowledge/SKILL.md +24 -4
  53. package/skills/flreview/SKILL.md +73 -0
  54. package/skills/flreview/agents/openai.yaml +6 -0
  55. package/src/agent-tools/graph-definitions.js +79 -4
  56. package/src/agent-tools/graph-handlers.js +12 -0
  57. package/src/cli/command-registry.js +3 -3
  58. package/src/cli/local-runtime-command.js +60 -23
  59. package/src/cli/local-runtime-options.js +16 -6
  60. package/src/cli/setup-agent-selection.js +12 -12
  61. package/src/cli/setup-command.js +41 -18
  62. package/src/cli/shell-argument.js +10 -0
  63. package/src/cli/uninstall-command.js +17 -15
  64. package/src/cli/update-command.js +38 -30
  65. package/src/external-knowledge/catalog.js +61 -0
  66. package/src/external-knowledge/conflict-policy.js +58 -0
  67. package/src/external-knowledge/connected-search.js +166 -0
  68. package/src/external-knowledge/connectors/custom.js +133 -0
  69. package/src/external-knowledge/connectors/feishu.js +461 -0
  70. package/src/external-knowledge/connectors/mcp.js +438 -0
  71. package/src/external-knowledge/connectors/notion.js +307 -0
  72. package/src/external-knowledge/connectors/retrieval-api.js +222 -0
  73. package/src/external-knowledge/document-mapping.js +151 -0
  74. package/src/external-knowledge/graph-projection.js +17 -0
  75. package/src/external-knowledge/index.js +8 -0
  76. package/src/external-knowledge/registry.js +91 -0
  77. package/src/external-knowledge/runtime.js +68 -0
  78. package/src/external-knowledge/safe-diagnostic.js +14 -0
  79. package/src/external-knowledge/service.js +811 -0
  80. package/src/graphiti/agent-knowledge-workflows.js +7 -2
  81. package/src/graphiti/federated-application.js +66 -41
  82. package/src/graphiti/knowledge-item-role.js +21 -0
  83. package/src/graphiti/knowledge-review.js +43 -0
  84. package/src/graphiti/project-profile-mapping.js +32 -0
  85. package/src/graphiti/provider-client.js +22 -1
  86. package/src/graphiti/source-marker.js +54 -3
  87. package/src/graphiti/task-knowledge-recall.js +250 -0
  88. package/src/http/api-router.js +23 -108
  89. package/src/http/external-knowledge-api-router.js +104 -0
  90. package/src/http/graph-api-router.js +12 -1
  91. package/src/http/request-policy.js +38 -3
  92. package/src/local-runtime/lifecycle.js +37 -16
  93. package/src/mcp/create-mcp-server.js +1 -0
  94. package/src/mcp/instructions.js +7 -7
  95. package/src/mcp/tool-annotations.js +6 -0
  96. package/src/mcp/tool-result.js +1 -0
  97. package/src/server/application-lifecycle.js +2 -11
  98. package/src/server/blocked-ports.js +11 -0
  99. package/src/server/lan-access.js +52 -0
  100. package/src/server.js +103 -25
  101. package/src/setup/agent-installation-status.js +2 -1
  102. package/src/setup/agents.js +2 -1
  103. package/src/setup/claude-code-config.js +2 -1
  104. package/src/setup/codex-bootstrap.js +12 -7
  105. package/src/setup/container-runtime.js +25 -21
  106. package/src/setup/graph-runtime.js +219 -58
  107. package/src/setup/node-runtime.js +3 -3
  108. package/src/setup/options.js +2 -4
  109. package/src/setup/paths.js +18 -3
  110. package/src/setup/review-skill-adapters.js +49 -0
  111. package/src/setup/setup.js +26 -2
  112. package/src/setup/uninstall.js +4 -2
  113. package/src/system/resource-monitor.js +317 -0
  114. package/src/system/runtime-settings.js +131 -0
  115. package/src/system/system-service.js +119 -0
  116. package/dist/web/assets/ConnectionsPage-CCKWm-6p.js +0 -1
  117. package/dist/web/assets/KnowledgeInspector-BZkB2wJn.js +0 -1
  118. package/dist/web/assets/KnowledgeInspector-CrGYxEob.css +0 -1
  119. package/dist/web/assets/KnowledgeOrganizerPage-CJCNI2Wd.css +0 -1
  120. package/dist/web/assets/KnowledgeOrganizerPage-PXH-TlGt.js +0 -1
  121. package/dist/web/assets/KnowledgePage-CNQXd15y.js +0 -1
  122. package/dist/web/assets/KnowledgeWorkspace-CXPE4GCD.js +0 -4
  123. package/dist/web/assets/OverviewPage-ul7g7HXh.js +0 -1
  124. package/dist/web/assets/PersonalProfilePage-CC40Pw2L.js +0 -1
  125. package/dist/web/assets/PersonalProjectsPage-CPIEcShD.js +0 -1
  126. package/dist/web/assets/PublicProjectsPage-C700sR7z.js +0 -1
  127. package/dist/web/assets/ReviewPage-7MDDUDgA.js +0 -1
  128. package/dist/web/assets/console-B_Ena2DS.js +0 -5
  129. package/dist/web/assets/fuli-logo-DGuyqchQ.png +0 -0
  130. package/dist/web/assets/identity-CjBwYSMX.js +0 -1
  131. package/dist/web/assets/index-BQRkOwPx.js +0 -2
  132. package/dist/web/assets/index-CpLDx3of.css +0 -1
  133. package/dist/web/assets/model-C-5RVIJ2.js +0 -1
  134. package/dist/web/assets/paths-BkULqmGI.js +0 -1
  135. package/dist/web/assets/vue-router-DnD3hUm7.js +0 -1
  136. package/src/agent/candidate-read-service.js +0 -53
  137. package/src/agent/context-pack-service.js +0 -83
  138. package/src/agent/public-read-policy.js +0 -39
  139. package/src/agent/public-read-service.js +0 -69
  140. package/src/agent/read-projection.js +0 -107
  141. package/src/agent/search-service.js +0 -61
  142. package/src/agent/space-boundary.js +0 -33
  143. package/src/app/bootstrap.js +0 -8
  144. package/src/app/create-application.js +0 -143
  145. package/src/app/state-service.js +0 -38
  146. package/src/candidates.js +0 -78
  147. package/src/classifier.js +0 -63
  148. package/src/cli/command-arguments.js +0 -14
  149. package/src/context-pack.js +0 -206
  150. package/src/extractor.js +0 -77
  151. package/src/fact-history.js +0 -39
  152. package/src/facts/fact-service.js +0 -89
  153. package/src/http/bounded-json-array.js +0 -19
  154. package/src/http/lens-route.js +0 -50
  155. package/src/ingestion.js +0 -161
  156. package/src/lens/lens-correction-service.js +0 -81
  157. package/src/lens/lens-fact-writer.js +0 -85
  158. package/src/lens/lens-input.js +0 -62
  159. package/src/lens/lens-query-projection.js +0 -87
  160. package/src/lens/lens-query-ranking.js +0 -62
  161. package/src/lens/lens-query.js +0 -143
  162. package/src/lens/lens-resource-projection.js +0 -93
  163. package/src/lens/lens-resource-selection.js +0 -45
  164. package/src/lens/lens-resource-service.js +0 -103
  165. package/src/lens/lens-search-query.js +0 -122
  166. package/src/lens/lens-service.js +0 -183
  167. package/src/models.js +0 -44
  168. package/src/observer.js +0 -83
  169. package/src/project-rules.js +0 -33
  170. package/src/publication/outbox-service.js +0 -46
  171. package/src/publication/publication-envelope-schema.js +0 -75
  172. package/src/publication/publication-envelope.js +0 -37
  173. package/src/publication/publication-policy.js +0 -82
  174. package/src/publication/publication-service.js +0 -48
  175. package/src/router.js +0 -58
  176. package/src/runtime-options.js +0 -138
  177. package/src/security/episode-visibility.js +0 -14
  178. package/src/security/fact-visibility.js +0 -15
  179. package/src/security/source-metadata-policy.js +0 -8
  180. package/src/storage/episode-evidence-preview.js +0 -100
  181. package/src/storage/fact-search-order.js +0 -18
  182. package/src/storage/file/episode-evidence.js +0 -37
  183. package/src/storage/file/episode-index.js +0 -59
  184. package/src/storage/file/fact-search.js +0 -60
  185. package/src/storage/file-store.js +0 -437
  186. package/src/storage/migrate.js +0 -128
  187. package/src/storage/migrations/001-initial.sql +0 -83
  188. package/src/storage/migrations/002-storage-integrity.sql +0 -113
  189. package/src/storage/record-validation.js +0 -46
  190. package/src/storage/snapshot-defaults.js +0 -54
  191. package/src/storage/sqlite/candidates-repository.js +0 -84
  192. package/src/storage/sqlite/episode-evidence-repository.js +0 -154
  193. package/src/storage/sqlite/episode-privacy-sql.js +0 -33
  194. package/src/storage/sqlite/episodes-repository.js +0 -52
  195. package/src/storage/sqlite/fact-search-repository.js +0 -162
  196. package/src/storage/sqlite/facts-repository.js +0 -146
  197. package/src/storage/sqlite/imports-repository.js +0 -39
  198. package/src/storage/sqlite/mapper.js +0 -84
  199. package/src/storage/sqlite/open-database.js +0 -15
  200. package/src/storage/sqlite/outbox-repository.js +0 -103
  201. package/src/storage/sqlite/snapshot-repository.js +0 -69
  202. package/src/storage/sqlite/spaces-repository.js +0 -52
  203. package/src/storage/sqlite/subscriptions-repository.js +0 -54
  204. package/src/storage/sqlite-store.js +0 -159
  205. package/src/storage/stable-json.js +0 -24
  206. package/src/storage/store-port.js +0 -20
  207. package/src/store.js +0 -2
@@ -27,21 +27,25 @@ async def read_graph(
27
27
  space_id: str,
28
28
  limit: int | None = None,
29
29
  personal_project_id: str | None = None,
30
+ offset: int | None = None,
30
31
  ) -> GraphResult:
31
32
  space = await store.authorize(actor, space_id, 'reader')
32
33
  project = None
33
34
  if personal_project_id:
34
35
  project = await authorize_personal_project(store, actor, space, personal_project_id)
35
36
  bounded_limit = min(limit or store.settings.graph_limit, store.settings.graph_limit)
37
+ paginated = offset is not None
38
+ page_offset = offset or 0
36
39
  node_records, _, _ = await store.runtime.driver.execute_query(
37
- _node_query(bool(project)),
40
+ _node_query(bool(project), paginated),
38
41
  space_id=space_id,
39
42
  group_id=space['group_id'],
40
43
  project_id=personal_project_id,
41
44
  limit=bounded_limit + 1,
45
+ offset=page_offset,
42
46
  routing_='r',
43
47
  )
44
- truncated = len(node_records) > bounded_limit
48
+ nodes_truncated = len(node_records) > bounded_limit
45
49
  node_records = node_records[:bounded_limit]
46
50
  node_ids = [record['id'] for record in node_records]
47
51
  episode_ids = list({
@@ -50,15 +54,20 @@ async def read_graph(
50
54
  for episode_id in (record.get('episodes') or [])
51
55
  })
52
56
  edge_records, _, _ = await store.runtime.driver.execute_query(
53
- _edge_query(bool(project)),
57
+ _edge_query(bool(project), paginated),
54
58
  space_id=space_id,
55
59
  group_id=space['group_id'],
56
60
  project_id=personal_project_id,
57
61
  node_ids=node_ids,
58
62
  episode_ids=episode_ids,
59
- limit=bounded_limit,
63
+ limit=bounded_limit + 1 if paginated else bounded_limit,
64
+ offset=page_offset,
60
65
  routing_='r',
61
66
  )
67
+ edges_truncated = paginated and len(edge_records) > bounded_limit
68
+ if paginated:
69
+ edge_records = edge_records[:bounded_limit]
70
+ truncated = nodes_truncated or edges_truncated
62
71
  all_episode_ids = list({
63
72
  *episode_ids,
64
73
  *(episode_id for record in edge_records for episode_id in (record.get('episodes') or [])),
@@ -127,10 +136,11 @@ async def read_graph(
127
136
  nodes=graph_nodes,
128
137
  edges=graph_edges,
129
138
  truncated=truncated,
139
+ next_offset=(page_offset + bounded_limit) if paginated and truncated else None,
130
140
  )
131
141
 
132
142
 
133
- def _node_query(project_scoped: bool) -> str:
143
+ def _node_query(project_scoped: bool, paginated: bool = False) -> str:
134
144
  if project_scoped:
135
145
  match = '''
136
146
  MATCH (node:Entity {group_id: $group_id})
@@ -181,6 +191,7 @@ def _node_query(project_scoped: bool) -> str:
181
191
  OPTIONAL MATCH (episode:Episodic {group_id: $group_id})-[:MENTIONS]->(node)
182
192
  WITH node, collect(DISTINCT episode) AS episodes
183
193
  '''
194
+ pagination = 'SKIP $offset LIMIT $limit' if paginated else 'LIMIT $limit'
184
195
  return match + '''
185
196
  RETURN node.uuid AS id, node.name AS name, node.group_id AS group_id,
186
197
  coalesce(node.fuli_type, 'Entity') AS type,
@@ -233,12 +244,46 @@ def _node_query(project_scoped: bool) -> str:
233
244
  node.fuli_invalid_at AS invalid_at,
234
245
  node.fuli_replaced_by_item_id AS replaced_by_item_id,
235
246
  node.fuli_replaced_by_item_kind AS replaced_by_item_kind
236
- ORDER BY created_at DESC LIMIT $limit
237
- '''
247
+ ORDER BY created_at DESC, id DESC
248
+ ''' + pagination
238
249
 
239
250
 
240
- def _edge_query(project_scoped: bool) -> str:
241
- project_filter = '''
251
+ def _edge_query(project_scoped: bool, paginated: bool = False) -> str:
252
+ if paginated:
253
+ match = '''
254
+ MATCH (source:Entity)-[edge:RELATES_TO {group_id: $group_id}]->(target:Entity)
255
+ '''
256
+ project_filter = '''
257
+ OPTIONAL MATCH (assignment:FuliKnowledgeAssignment {
258
+ space_id: $space_id,
259
+ item_kind: 'relationship',
260
+ item_id: edge.uuid
261
+ })
262
+ OPTIONAL MATCH (episode:Episodic {group_id: $group_id})
263
+ WHERE episode.uuid IN coalesce(edge.episodes, [])
264
+ WITH source, edge, target, assignment,
265
+ collect(DISTINCT episode) AS knowledge_episodes
266
+ WHERE (
267
+ edge.fuli_profile_aspect IS NOT NULL
268
+ AND edge.fuli_preference_scope = 'project'
269
+ AND edge.fuli_preference_project_id = $project_id
270
+ ) OR (
271
+ edge.fuli_profile_aspect IS NULL
272
+ AND (
273
+ (assignment.project_id IS NOT NULL AND assignment.project_id = $project_id)
274
+ OR (assignment.project_id IS NULL AND any(
275
+ episode IN knowledge_episodes
276
+ WHERE episode.fuli_personal_project_id = $project_id
277
+ ))
278
+ )
279
+ )
280
+ ''' if project_scoped else ''
281
+ else:
282
+ match = '''
283
+ MATCH (source:Entity)-[edge:RELATES_TO {group_id: $group_id}]->(target:Entity)
284
+ WHERE source.uuid IN $node_ids AND target.uuid IN $node_ids
285
+ '''
286
+ project_filter = '''
242
287
  OPTIONAL MATCH (assignment:FuliKnowledgeAssignment {
243
288
  space_id: $space_id,
244
289
  item_kind: 'relationship',
@@ -259,12 +304,11 @@ def _edge_query(project_scoped: bool) -> str:
259
304
  ))
260
305
  )
261
306
  )
262
- ''' if project_scoped else ''
263
- return '''
264
- MATCH (source:Entity)-[edge:RELATES_TO {group_id: $group_id}]->(target:Entity)
265
- WHERE source.uuid IN $node_ids AND target.uuid IN $node_ids
266
- ''' + project_filter + '''
307
+ ''' if project_scoped else ''
308
+ pagination = 'SKIP $offset LIMIT $limit' if paginated else 'LIMIT $limit'
309
+ return match + project_filter + '''
267
310
  RETURN edge.uuid AS id, source.uuid AS source, target.uuid AS target,
311
+ source.name AS source_name, target.name AS target_name,
268
312
  edge.name AS type, edge.fact AS fact,
269
313
  coalesce(edge.fuli_origin_quadrant, 'known_known') AS origin_quadrant,
270
314
  coalesce(edge.fuli_current_quadrant, 'known_known') AS current_quadrant,
@@ -315,8 +359,8 @@ def _edge_query(project_scoped: bool) -> str:
315
359
  edge.fuli_confidence AS confidence,
316
360
  coalesce(edge.fuli_attributes_json, '{}') AS attributes_json,
317
361
  coalesce(edge.episodes, []) AS episodes
318
- ORDER BY edge.created_at DESC LIMIT $limit
319
- '''
362
+ ORDER BY created_at DESC, id DESC
363
+ ''' + pagination
320
364
 
321
365
 
322
366
  async def _personal_projects(store, space: dict) -> list[dict]:
@@ -497,6 +541,8 @@ def _graph_edge(
497
541
  id=record['id'],
498
542
  source=record['source'],
499
543
  target=record['target'],
544
+ source_name=record.get('source_name'),
545
+ target_name=record.get('target_name'),
500
546
  type=record['type'],
501
547
  fact=record['fact'],
502
548
  origin_quadrant=record.get('origin_quadrant') or 'known_known',