fuli-context 0.7.3 → 0.7.4-beta.1

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 (107) hide show
  1. package/README.md +170 -18
  2. package/README.zh-CN.md +146 -12
  3. package/compose.graphiti.yml +2 -0
  4. package/dist/web/assets/{AboutPage-qeO_vm0T.js → AboutPage-CftRexSY.js} +1 -1
  5. package/dist/web/assets/{ConnectionsPage-DO0GR9Xg.js → ConnectionsPage-D5J91x6d.js} +1 -1
  6. package/dist/web/assets/{useMinimumLoadingDisplay-BpCyBeko.css → KnowledgeEditDialog-DWUV_NPp.css} +1 -1
  7. package/dist/web/assets/KnowledgeEditDialog-wotVahvr.js +1 -0
  8. package/dist/web/assets/{KnowledgeInspector-Bjhdu2mf.css → KnowledgeInspector--1NujtXW.css} +1 -1
  9. package/dist/web/assets/KnowledgeInspector-BzkW0mVs.js +1 -0
  10. package/dist/web/assets/KnowledgeOrganizerPage-BebUDiHt.js +1 -0
  11. package/dist/web/assets/KnowledgePage-OUT07aKH.js +1 -0
  12. package/dist/web/assets/KnowledgeWorkspace-1pHJ0MNZ.js +4 -0
  13. package/dist/web/assets/{OverviewPage-CmCcDCAs.js → OverviewPage-CHE6XhdS.js} +1 -1
  14. package/dist/web/assets/PersonalProfilePage-B7T09bow.css +1 -0
  15. package/dist/web/assets/PersonalProfilePage-CXXiabUy.js +1 -0
  16. package/dist/web/assets/PersonalProjectsPage-d2wYGW8n.js +1 -0
  17. package/dist/web/assets/PublicProjectsPage-hxLShtnZ.js +1 -0
  18. package/dist/web/assets/{ReviewPage-B3vnZ6gn.js → ReviewPage-DUeyu7E8.js} +1 -1
  19. package/dist/web/assets/{SearchableSelect-ih69qbcS.js → SearchableSelect-C5RiB5F8.js} +1 -1
  20. package/dist/web/assets/SettingsPage-BMuASSzQ.js +1 -0
  21. package/dist/web/assets/SettingsPage-CAfz4qiV.css +1 -0
  22. package/dist/web/assets/WritingTastePage-B9BCYIwQ.js +1 -0
  23. package/dist/web/assets/WritingTastePage-DSgvTH6x.css +1 -0
  24. package/dist/web/assets/{console-DE40hXGC.js → console-DMvHxKf9.js} +1 -1
  25. package/dist/web/assets/conversation-launcher-settings-Dnlcw7Rj.js +1 -0
  26. package/dist/web/assets/{i18n-CDxBs1sz.js → i18n-CWfd8Dtt.js} +1 -1
  27. package/dist/web/assets/{identity-BCxb1mcy.js → identity-C9mLdR8L.js} +1 -1
  28. package/dist/web/assets/index-F5e2sQ7p.js +2 -0
  29. package/dist/web/assets/{index-CCOGfZzE.css → index-X2j29j8i.css} +1 -1
  30. package/dist/web/assets/{model-CCMdt10Q.js → model-CsYAR8O3.js} +1 -1
  31. package/dist/web/assets/paths-CDREouhi.js +1 -0
  32. package/dist/web/assets/useApi-CROJJdhE-BLQiPVw0.js +1 -0
  33. package/dist/web/assets/vue-router-DN8x6iY1.js +1 -0
  34. package/dist/web/index.html +7 -6
  35. package/graph-provider/fuli_graph/app.py +238 -2
  36. package/graph-provider/fuli_graph/auth.py +18 -0
  37. package/graph-provider/fuli_graph/collaboration_context.py +253 -17
  38. package/graph-provider/fuli_graph/common_knowledge.py +6 -2
  39. package/graph-provider/fuli_graph/config.py +5 -0
  40. package/graph-provider/fuli_graph/graph_models.py +6 -0
  41. package/graph-provider/fuli_graph/graph_projection.py +14 -0
  42. package/graph-provider/fuli_graph/graph_query.py +27 -3
  43. package/graph-provider/fuli_graph/knowledge_management.py +19 -1
  44. package/graph-provider/fuli_graph/knowledge_search.py +11 -0
  45. package/graph-provider/fuli_graph/models.py +15 -2
  46. package/graph-provider/fuli_graph/personal_global_preference_models.py +234 -0
  47. package/graph-provider/fuli_graph/personal_global_preferences.py +1247 -0
  48. package/graph-provider/fuli_graph/project_action_models.py +22 -0
  49. package/graph-provider/fuli_graph/project_knowledge.py +121 -2
  50. package/graph-provider/fuli_graph/provider_values.py +24 -0
  51. package/graph-provider/fuli_graph/runtime.py +78 -0
  52. package/graph-provider/fuli_graph/search_projection.py +14 -1
  53. package/graph-provider/fuli_graph/store_knowledge.py +116 -2
  54. package/graph-provider/fuli_graph/workflow_candidate_models.py +168 -0
  55. package/graph-provider/fuli_graph/workflow_candidates.py +996 -0
  56. package/graph-provider/fuli_graph/workflow_observation_models.py +30 -0
  57. package/graph-provider/fuli_graph/workflow_observations.py +84 -0
  58. package/graph-provider/pyproject.toml +1 -1
  59. package/npm-shrinkwrap.json +18 -18
  60. package/package.json +4 -4
  61. package/skills/capturing-session-knowledge/SKILL.md +32 -5
  62. package/skills/flreview/SKILL.md +4 -3
  63. package/src/agent-tools/graph-definitions.js +136 -20
  64. package/src/agent-tools/graph-handlers.js +10 -4
  65. package/src/cli/command-registry.js +1 -1
  66. package/src/cli/local-runtime-command.js +69 -2
  67. package/src/graphiti/agent-knowledge-workflows.js +497 -16
  68. package/src/graphiti/collaboration-preference-projection.js +162 -0
  69. package/src/graphiti/federated-application.js +155 -161
  70. package/src/graphiti/federated-search-support.js +102 -0
  71. package/src/graphiti/knowledge-provider-mapping.js +15 -0
  72. package/src/graphiti/provider-client.js +162 -10
  73. package/src/graphiti/related-project-suggestions.js +109 -0
  74. package/src/graphiti/runtime-config.js +14 -0
  75. package/src/graphiti/source-marker.js +2 -2
  76. package/src/graphiti/user-taste-skill.js +241 -0
  77. package/src/graphiti/workflow-candidate-mapping.js +87 -0
  78. package/src/graphiti/workflow-observation.js +82 -0
  79. package/src/graphiti/writing-taste-profile-workflow.js +25 -0
  80. package/src/graphiti/writing-taste-profile.js +490 -0
  81. package/src/http/graph-api-router.js +15 -2
  82. package/src/mcp/context-resources.js +158 -0
  83. package/src/mcp/create-mcp-server.js +39 -5
  84. package/src/mcp/instructions.js +5 -7
  85. package/src/mcp/session-id.js +60 -0
  86. package/src/mcp/task-context-registry.js +15 -3
  87. package/src/mcp/tool-annotations.js +8 -1
  88. package/src/mcp/tool-result.js +28 -4
  89. package/src/server.js +0 -1
  90. package/src/setup/claude-code-config.js +17 -6
  91. package/src/setup/graph-runtime.js +20 -2
  92. package/src/system/runtime-settings.js +121 -2
  93. package/src/system/system-service.js +5 -1
  94. package/dist/web/assets/KnowledgeInspector-DEW5lA1m.js +0 -1
  95. package/dist/web/assets/KnowledgeOrganizerPage-BkM568Ld.js +0 -1
  96. package/dist/web/assets/KnowledgePage-BAT4aZIm.js +0 -1
  97. package/dist/web/assets/KnowledgeWorkspace-DyGtBz--.js +0 -4
  98. package/dist/web/assets/PersonalProfilePage-C42mwKN8.js +0 -1
  99. package/dist/web/assets/PersonalProfilePage-CdmEzyvZ.css +0 -1
  100. package/dist/web/assets/PersonalProjectsPage-BwaXR62K.js +0 -1
  101. package/dist/web/assets/PublicProjectsPage-egKBulOq.js +0 -1
  102. package/dist/web/assets/SettingsPage-C6ouU0sR.css +0 -1
  103. package/dist/web/assets/SettingsPage-oLE8mNs5.js +0 -1
  104. package/dist/web/assets/index-BzhNfzU_.js +0 -2
  105. package/dist/web/assets/paths-DwHeiGMT.js +0 -1
  106. package/dist/web/assets/useMinimumLoadingDisplay-HdI7XAmu.js +0 -1
  107. package/dist/web/assets/vue-router-Drfl1F8i.js +0 -1
@@ -163,8 +163,6 @@ def _validate_inheritance(
163
163
  raise ValueError(
164
164
  'inherited project ids are only valid for selected_projects inheritance'
165
165
  )
166
- if profile_aspect and mode != 'local_only':
167
- raise ValueError('personal preferences cannot inherit across projects')
168
166
 
169
167
 
170
168
  class ConfirmationActor(StrictModel):
@@ -772,6 +770,8 @@ class EntitySearchResult(StrictModel):
772
770
  preference_scope: PreferenceScope | None = None
773
771
  preference_project_id: str | None = None
774
772
  key: str | None = None
773
+ preference_key: str | None = None
774
+ preference_qualifiers: dict[str, Any] = Field(default_factory=dict)
775
775
  defined_project_id: str | None = None
776
776
  inheritance_mode: KnowledgeInheritanceMode = 'local_only'
777
777
  inherited_project_ids: list[str] = Field(default_factory=list, max_length=32)
@@ -819,6 +819,8 @@ class FactResult(StrictModel):
819
819
  preference_scope: PreferenceScope | None = None
820
820
  preference_project_id: str | None = None
821
821
  key: str | None = None
822
+ preference_key: str | None = None
823
+ preference_qualifiers: dict[str, Any] = Field(default_factory=dict)
822
824
  defined_project_id: str | None = None
823
825
  inheritance_mode: KnowledgeInheritanceMode = 'local_only'
824
826
  inherited_project_ids: list[str] = Field(default_factory=list, max_length=32)
@@ -860,9 +862,18 @@ class CollaborationPreferenceItem(StrictModel):
860
862
  preference_scope: PreferenceScope
861
863
  preference_project_id: str | None = None
862
864
  attributes: dict[str, Any] = Field(default_factory=dict)
865
+ weight: float | None = Field(default=None, ge=0, le=1, allow_inf_nan=False)
866
+ reason: str | None = None
867
+ confirmation_basis: ConfirmationBasis
868
+ reasoning_summary: str | None = None
869
+ inheritance_mode: KnowledgeInheritanceMode = 'local_only'
870
+ inherited_project_ids: list[str] = Field(default_factory=list, max_length=32)
863
871
  confirmation_status: Literal['confirmed', 'agent_confirmed']
864
872
  confirmed_at: datetime
865
873
  created_at: datetime | None = None
874
+ scope_distance: int = Field(default=0, ge=0, le=2)
875
+ inherited_from_project_id: str | None = None
876
+ scope_path: list[str] = Field(default_factory=list, max_length=3)
866
877
 
867
878
 
868
879
  class CollaborationPreferenceConflict(StrictModel):
@@ -880,6 +891,8 @@ class CollaborationContextResult(StrictModel):
880
891
  effective_preferences: list[CollaborationPreferenceItem] = Field(default_factory=list)
881
892
  conflicts: list[CollaborationPreferenceConflict] = Field(default_factory=list)
882
893
  overridden_global_ids: list[str] = Field(default_factory=list)
894
+ overridden_inherited_ids: list[str] = Field(default_factory=list)
895
+ overridden_lower_authority_ids: list[str] = Field(default_factory=list)
883
896
  truncated: bool = False
884
897
 
885
898
 
@@ -0,0 +1,234 @@
1
+ from datetime import datetime
2
+ from typing import Any, Literal
3
+
4
+ from pydantic import Field, model_validator
5
+
6
+ from .models import (
7
+ ConfirmationBasis,
8
+ ConfirmationStatus,
9
+ KnowledgeItemKind,
10
+ PersonalProfileAspect,
11
+ StrictModel,
12
+ )
13
+
14
+ PersonalGlobalPreferenceTargetScope = Literal[
15
+ 'parent_project',
16
+ 'personal_global',
17
+ ]
18
+
19
+
20
+ class PersonalGlobalPreferenceSourceRef(StrictModel):
21
+ item_id: str = Field(min_length=1, max_length=256)
22
+ item_kind: KnowledgeItemKind
23
+ project_id: str = Field(min_length=1, max_length=128)
24
+
25
+
26
+ class PersonalGlobalPreferenceSourceSnapshot(
27
+ PersonalGlobalPreferenceSourceRef
28
+ ):
29
+ key: str = Field(min_length=1, max_length=256)
30
+ preference_key: str = Field(min_length=1, max_length=512)
31
+ preference_qualifiers: dict[str, Any] = Field(default_factory=dict)
32
+ title: str = Field(min_length=1, max_length=512)
33
+ instruction: str = Field(max_length=8192)
34
+ profile_aspect: PersonalProfileAspect
35
+ confirmation_status: Literal['confirmed', 'agent_confirmed']
36
+ confirmation_basis: ConfirmationBasis
37
+ human_change_version: int = Field(default=0, ge=0)
38
+ usage_generation: int = Field(default=1, ge=1)
39
+ last_human_changed_at: datetime | None = None
40
+ negative_evidence_count: int = Field(default=0, ge=0)
41
+ requires_attention: bool = False
42
+ last_feedback_at: datetime | None = None
43
+ source_uris: list[str] = Field(default_factory=list, max_length=20)
44
+ stored_confirmation_basis_json: str = Field(
45
+ default='{}',
46
+ exclude=True,
47
+ repr=False,
48
+ )
49
+ stored_attributes_json: str = Field(default='{}', exclude=True, repr=False)
50
+
51
+
52
+ class PersonalGlobalPreferenceEligibleTargetScope(StrictModel):
53
+ target_scope: PersonalGlobalPreferenceTargetScope
54
+ target_project_id: str | None = Field(
55
+ default=None,
56
+ min_length=1,
57
+ max_length=128,
58
+ )
59
+ max_distance: int | None = Field(default=None, ge=1, le=2)
60
+
61
+ @model_validator(mode='after')
62
+ def validate_target(self):
63
+ if self.target_scope == 'parent_project' and not self.target_project_id:
64
+ raise ValueError('parent_project target requires target_project_id')
65
+ if self.target_scope == 'personal_global' and self.target_project_id:
66
+ raise ValueError('personal_global target cannot set target_project_id')
67
+ return self
68
+
69
+
70
+ class PersonalGlobalPreferenceScopeOptionsRequest(StrictModel):
71
+ personal_space_id: str = Field(min_length=1, max_length=128)
72
+ source_items: list[PersonalGlobalPreferenceSourceRef] = Field(
73
+ min_length=2,
74
+ max_length=32,
75
+ )
76
+ preference_key: str = Field(min_length=1, max_length=512)
77
+
78
+
79
+ class PersonalGlobalPreferenceScopeOptions(StrictModel):
80
+ personal_space_id: str
81
+ candidate_id: str
82
+ candidate_version: str
83
+ preference_key: str
84
+ source_snapshots: list[PersonalGlobalPreferenceSourceSnapshot]
85
+ eligible_target_scopes: list[PersonalGlobalPreferenceEligibleTargetScope]
86
+
87
+
88
+ class PersonalGlobalPreferenceDecisionIntent(StrictModel):
89
+ personal_space_id: str = Field(min_length=1, max_length=128)
90
+ candidate_version: str = Field(pattern=r'^v1:[a-f0-9]{24}$')
91
+ decision_revision: int = Field(ge=0)
92
+ source_items: list[PersonalGlobalPreferenceSourceRef] = Field(
93
+ min_length=2,
94
+ max_length=32,
95
+ )
96
+ preference_key: str = Field(min_length=1, max_length=512)
97
+ target_scope: PersonalGlobalPreferenceTargetScope
98
+ target_project_id: str | None = Field(
99
+ min_length=1,
100
+ max_length=128,
101
+ )
102
+ decision: Literal['approve', 'reject']
103
+ global_title: str | None = Field(default=None, min_length=1, max_length=512)
104
+ global_instruction: str | None = Field(
105
+ default=None,
106
+ min_length=1,
107
+ max_length=8192,
108
+ )
109
+ profile_aspect: PersonalProfileAspect | None = None
110
+ human_confirmation_reason: str = Field(min_length=1, max_length=4096)
111
+ confirmed_at: datetime
112
+ session_id: str = Field(min_length=1, max_length=256)
113
+ idempotency_key: str = Field(min_length=8, max_length=256)
114
+
115
+ @model_validator(mode='after')
116
+ def validate_decision(self):
117
+ item_keys = {
118
+ (item.item_kind, item.item_id)
119
+ for item in self.source_items
120
+ }
121
+ project_ids = {item.project_id for item in self.source_items}
122
+ if len(item_keys) != len(self.source_items):
123
+ raise ValueError('source preference items must be unique')
124
+ if len(project_ids) != len(self.source_items):
125
+ raise ValueError(
126
+ 'source preferences must come from distinct projects'
127
+ )
128
+ if self.target_scope == 'parent_project' and not self.target_project_id:
129
+ raise ValueError('parent_project target requires target_project_id')
130
+ if self.target_scope == 'personal_global' and self.target_project_id:
131
+ raise ValueError('personal_global target cannot set target_project_id')
132
+ if self.decision == 'approve':
133
+ if not (
134
+ self.global_title
135
+ and self.global_instruction
136
+ and self.profile_aspect
137
+ ):
138
+ raise ValueError(
139
+ 'approve requires a complete global preference assertion'
140
+ )
141
+ elif any((
142
+ self.global_title,
143
+ self.global_instruction,
144
+ self.profile_aspect,
145
+ )):
146
+ raise ValueError(
147
+ 'reject cannot include a global preference assertion'
148
+ )
149
+ return self
150
+
151
+
152
+ class PersonalGlobalPreferenceDecisionApply(
153
+ PersonalGlobalPreferenceDecisionIntent
154
+ ):
155
+ approval_token: str = Field(min_length=32, max_length=512)
156
+
157
+
158
+ class PersonalGlobalPreferenceDecisionInspection(StrictModel):
159
+ status: Literal['human_review_required']
160
+ personal_space_id: str
161
+ candidate_id: str
162
+ candidate_version: str
163
+ decision_revision: int = Field(ge=0)
164
+ decision: Literal['approve', 'reject']
165
+ preference_key: str
166
+ target_scope: PersonalGlobalPreferenceTargetScope
167
+ target_project_id: str | None = None
168
+ eligible_target_scopes: list[PersonalGlobalPreferenceEligibleTargetScope]
169
+ payload_fingerprint: str
170
+ source_snapshots: list[PersonalGlobalPreferenceSourceSnapshot]
171
+ candidate_binding_verified: bool = True
172
+ original_sources_will_remain_unchanged: bool = True
173
+ scope_apply_performed: bool = False
174
+ approval_token_issued: bool = False
175
+ required_action: str
176
+
177
+
178
+ class PersonalGlobalPreferenceDecisionPreview(StrictModel):
179
+ preview_id: str
180
+ candidate_id: str
181
+ candidate_version: str
182
+ decision_revision: int = Field(ge=0)
183
+ target_scope: PersonalGlobalPreferenceTargetScope
184
+ target_project_id: str | None = None
185
+ eligible_target_scopes: list[PersonalGlobalPreferenceEligibleTargetScope]
186
+ payload_fingerprint: str
187
+ approval_token: str
188
+ expires_at: datetime
189
+ source_snapshots: list[PersonalGlobalPreferenceSourceSnapshot]
190
+ candidate_binding_verified: bool = True
191
+ original_sources_will_remain_unchanged: bool = True
192
+ scope_apply_performed: bool = False
193
+
194
+
195
+ class PersonalGlobalPreferenceCandidateVersionRef(StrictModel):
196
+ candidate_id: str = Field(
197
+ pattern=r'^personal-global-[a-f0-9]{20}$',
198
+ )
199
+ candidate_version: str = Field(pattern=r'^v1:[a-f0-9]{24}$')
200
+
201
+
202
+ class PersonalGlobalPreferenceDecisionStatusRequest(StrictModel):
203
+ personal_space_id: str = Field(min_length=1, max_length=128)
204
+ candidates: list[PersonalGlobalPreferenceCandidateVersionRef] = Field(
205
+ min_length=1,
206
+ max_length=100,
207
+ )
208
+
209
+
210
+ class PersonalGlobalPreferenceDecisionRecord(StrictModel):
211
+ decision_event_id: str
212
+ candidate_id: str
213
+ candidate_version: str
214
+ decision_revision: int = Field(ge=1)
215
+ decision: Literal['approved', 'rejected']
216
+ target_scope: PersonalGlobalPreferenceTargetScope
217
+ target_project_id: str | None = None
218
+ global_assertion_id: str | None = None
219
+ global_assertion_active: bool
220
+ decision_sequence: int = Field(ge=1)
221
+ decided_at: datetime
222
+ human_confirmation_reason: str
223
+
224
+
225
+ class PersonalGlobalPreferenceDecisionRevision(StrictModel):
226
+ candidate_id: str
227
+ decision_revision: int = Field(ge=0)
228
+ current_candidate_version: str | None = None
229
+
230
+
231
+ class PersonalGlobalPreferenceDecisionStatusResult(StrictModel):
232
+ personal_space_id: str
233
+ decisions: list[PersonalGlobalPreferenceDecisionRecord]
234
+ revisions: list[PersonalGlobalPreferenceDecisionRevision]