fuli-context 0.5.0 → 0.7.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/README.md +370 -202
- package/README.zh-CN.md +448 -0
- package/compose.graphiti.yml +6 -6
- package/dist/web/assets/AboutPage-DXh7Fwxt.css +1 -0
- package/dist/web/assets/AboutPage-qeO_vm0T.js +1 -0
- package/dist/web/assets/ConnectionsPage-CBHAdZXT.css +1 -0
- package/dist/web/assets/ConnectionsPage-DO0GR9Xg.js +1 -0
- package/dist/web/assets/KnowledgeInspector-Bjhdu2mf.css +1 -0
- package/dist/web/assets/KnowledgeInspector-DEW5lA1m.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-BkM568Ld.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-Cx1w1jb2.css +1 -0
- package/dist/web/assets/KnowledgePage-BAT4aZIm.js +1 -0
- package/dist/web/assets/KnowledgeWorkspace-DyGtBz--.js +4 -0
- package/dist/web/assets/OverviewPage-CmCcDCAs.js +1 -0
- package/dist/web/assets/PersonalProfilePage-C42mwKN8.js +1 -0
- package/dist/web/assets/{PersonalProfilePage-S8ZcG2LU.css → PersonalProfilePage-CdmEzyvZ.css} +1 -1
- package/dist/web/assets/PersonalProjectsPage-BwaXR62K.js +1 -0
- package/dist/web/assets/PublicProjectsPage-egKBulOq.js +1 -0
- package/dist/web/assets/ReviewPage-B3vnZ6gn.js +1 -0
- package/dist/web/assets/SearchableSelect-ih69qbcS.js +1 -0
- package/dist/web/assets/SettingsPage-C6ouU0sR.css +1 -0
- package/dist/web/assets/SettingsPage-oLE8mNs5.js +1 -0
- package/dist/web/assets/_plugin-vue_export-helper-BDNMzG2s.js +1 -0
- package/dist/web/assets/console-DE40hXGC.js +1 -0
- package/dist/web/assets/fuli-logo-Bu9WBuQe.js +1 -0
- package/dist/web/assets/fuli-logo-ER1wQ8Kk.png +0 -0
- package/dist/web/assets/i18n-CDxBs1sz.js +5 -0
- package/dist/web/assets/identity-BCxb1mcy.js +1 -0
- package/dist/web/assets/index-BzhNfzU_.js +2 -0
- package/dist/web/assets/index-CCOGfZzE.css +1 -0
- package/dist/web/assets/model-CCMdt10Q.js +1 -0
- package/dist/web/assets/paths-DwHeiGMT.js +1 -0
- package/dist/web/assets/useMinimumLoadingDisplay-BpCyBeko.css +1 -0
- package/dist/web/assets/useMinimumLoadingDisplay-HdI7XAmu.js +1 -0
- package/dist/web/assets/vue-router-Drfl1F8i.js +1 -0
- package/dist/web/index.html +9 -6
- package/docs/external-knowledge-architecture.md +279 -0
- package/examples/external-knowledge/markdown-folder.mjs +235 -0
- package/graph-provider/fuli_graph/app.py +57 -1
- package/graph-provider/fuli_graph/graph_models.py +3 -0
- package/graph-provider/fuli_graph/graph_query.py +62 -16
- package/graph-provider/fuli_graph/knowledge_review.py +657 -0
- package/graph-provider/fuli_graph/knowledge_review_models.py +133 -0
- package/graph-provider/fuli_graph/knowledge_search.py +51 -4
- package/graph-provider/fuli_graph/models.py +19 -0
- package/graph-provider/fuli_graph/runtime.py +15 -0
- package/graph-provider/fuli_graph/store_knowledge.py +2 -1
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +5 -407
- package/package.json +7 -5
- package/skills/capturing-session-knowledge/SKILL.md +24 -4
- package/skills/flreview/SKILL.md +100 -0
- package/skills/flreview/agents/openai.yaml +6 -0
- package/src/agent-tools/graph-definitions.js +81 -6
- package/src/agent-tools/graph-handlers.js +12 -0
- package/src/cli/command-registry.js +3 -3
- package/src/cli/local-runtime-command.js +51 -28
- package/src/cli/local-runtime-options.js +14 -8
- package/src/cli/setup-agent-selection.js +12 -12
- package/src/cli/setup-command.js +41 -18
- package/src/cli/shell-argument.js +10 -0
- package/src/cli/uninstall-command.js +17 -15
- package/src/cli/update-command.js +38 -30
- package/src/external-knowledge/catalog.js +61 -0
- package/src/external-knowledge/conflict-policy.js +58 -0
- package/src/external-knowledge/connected-search.js +166 -0
- package/src/external-knowledge/connectors/custom.js +133 -0
- package/src/external-knowledge/connectors/feishu.js +461 -0
- package/src/external-knowledge/connectors/mcp.js +438 -0
- package/src/external-knowledge/connectors/notion.js +307 -0
- package/src/external-knowledge/connectors/retrieval-api.js +222 -0
- package/src/external-knowledge/document-mapping.js +151 -0
- package/src/external-knowledge/graph-projection.js +17 -0
- package/src/external-knowledge/index.js +8 -0
- package/src/external-knowledge/registry.js +91 -0
- package/src/external-knowledge/runtime.js +68 -0
- package/src/external-knowledge/safe-diagnostic.js +14 -0
- package/src/external-knowledge/service.js +811 -0
- package/src/graphiti/agent-knowledge-workflows.js +7 -2
- package/src/graphiti/federated-application.js +68 -42
- package/src/graphiti/knowledge-item-role.js +21 -0
- package/src/graphiti/knowledge-review.js +43 -0
- package/src/graphiti/project-profile-mapping.js +32 -0
- package/src/graphiti/provider-client.js +22 -1
- package/src/graphiti/source-marker.js +54 -3
- package/src/graphiti/task-knowledge-recall.js +250 -0
- package/src/http/api-router.js +23 -108
- package/src/http/external-knowledge-api-router.js +104 -0
- package/src/http/graph-api-router.js +12 -1
- package/src/http/request-policy.js +1 -1
- package/src/local-runtime/lifecycle.js +26 -15
- package/src/mcp/create-mcp-server.js +4 -1
- package/src/mcp/instructions.js +7 -7
- package/src/mcp/tool-annotations.js +6 -0
- package/src/mcp/tool-result.js +1 -0
- package/src/server/application-lifecycle.js +2 -11
- package/src/server/blocked-ports.js +11 -0
- package/src/server.js +36 -17
- package/src/setup/agent-installation-status.js +2 -1
- package/src/setup/agents.js +2 -1
- package/src/setup/claude-code-config.js +2 -1
- package/src/setup/codex-bootstrap.js +12 -7
- package/src/setup/container-runtime.js +25 -21
- package/src/setup/graph-runtime.js +148 -56
- package/src/setup/node-runtime.js +3 -3
- package/src/setup/options.js +2 -4
- package/src/setup/paths.js +18 -3
- package/src/setup/review-skill-adapters.js +49 -0
- package/src/setup/setup.js +26 -2
- package/src/setup/uninstall.js +4 -2
- package/src/system/resource-monitor.js +317 -0
- package/src/system/runtime-settings.js +131 -0
- package/src/system/system-service.js +119 -0
- package/README.en.md +0 -336
- package/dist/web/assets/ConnectionsPage-CCKWm-6p.js +0 -1
- package/dist/web/assets/KnowledgeInspector-BZkB2wJn.js +0 -1
- package/dist/web/assets/KnowledgeInspector-CrGYxEob.css +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-CZAF_OlN.css +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-DlvcLwlL.js +0 -1
- package/dist/web/assets/KnowledgePage-CNQXd15y.js +0 -1
- package/dist/web/assets/KnowledgeWorkspace-CXPE4GCD.js +0 -4
- package/dist/web/assets/OverviewPage-ul7g7HXh.js +0 -1
- package/dist/web/assets/PersonalProfilePage-CC40Pw2L.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-CPIEcShD.js +0 -1
- package/dist/web/assets/PublicProjectsPage-C700sR7z.js +0 -1
- package/dist/web/assets/ReviewPage-7MDDUDgA.js +0 -1
- package/dist/web/assets/console-B_Ena2DS.js +0 -5
- package/dist/web/assets/fuli-logo-DGuyqchQ.png +0 -0
- package/dist/web/assets/identity-CjBwYSMX.js +0 -1
- package/dist/web/assets/index-CpLDx3of.css +0 -1
- package/dist/web/assets/index-DAzeFJSc.js +0 -2
- package/dist/web/assets/model-C-5RVIJ2.js +0 -1
- package/dist/web/assets/paths-BkULqmGI.js +0 -1
- package/dist/web/assets/vue-router-DnD3hUm7.js +0 -1
- package/src/agent/candidate-read-service.js +0 -53
- package/src/agent/context-pack-service.js +0 -83
- package/src/agent/public-read-policy.js +0 -39
- package/src/agent/public-read-service.js +0 -69
- package/src/agent/read-projection.js +0 -107
- package/src/agent/search-service.js +0 -61
- package/src/agent/space-boundary.js +0 -33
- package/src/app/bootstrap.js +0 -8
- package/src/app/create-application.js +0 -143
- package/src/app/state-service.js +0 -38
- package/src/candidates.js +0 -78
- package/src/classifier.js +0 -63
- package/src/cli/command-arguments.js +0 -14
- package/src/context-pack.js +0 -206
- package/src/extractor.js +0 -77
- package/src/fact-history.js +0 -39
- package/src/facts/fact-service.js +0 -89
- package/src/http/bounded-json-array.js +0 -19
- package/src/http/lens-route.js +0 -50
- package/src/ingestion.js +0 -161
- package/src/lens/lens-correction-service.js +0 -81
- package/src/lens/lens-fact-writer.js +0 -85
- package/src/lens/lens-input.js +0 -62
- package/src/lens/lens-query-projection.js +0 -87
- package/src/lens/lens-query-ranking.js +0 -62
- package/src/lens/lens-query.js +0 -143
- package/src/lens/lens-resource-projection.js +0 -93
- package/src/lens/lens-resource-selection.js +0 -45
- package/src/lens/lens-resource-service.js +0 -103
- package/src/lens/lens-search-query.js +0 -122
- package/src/lens/lens-service.js +0 -183
- package/src/models.js +0 -44
- package/src/observer.js +0 -83
- package/src/project-rules.js +0 -33
- package/src/publication/outbox-service.js +0 -46
- package/src/publication/publication-envelope-schema.js +0 -75
- package/src/publication/publication-envelope.js +0 -37
- package/src/publication/publication-policy.js +0 -82
- package/src/publication/publication-service.js +0 -48
- package/src/router.js +0 -58
- package/src/runtime-options.js +0 -138
- package/src/security/episode-visibility.js +0 -14
- package/src/security/fact-visibility.js +0 -15
- package/src/security/source-metadata-policy.js +0 -8
- package/src/storage/episode-evidence-preview.js +0 -100
- package/src/storage/fact-search-order.js +0 -18
- package/src/storage/file/episode-evidence.js +0 -37
- package/src/storage/file/episode-index.js +0 -59
- package/src/storage/file/fact-search.js +0 -60
- package/src/storage/file-store.js +0 -437
- package/src/storage/migrate.js +0 -128
- package/src/storage/migrations/001-initial.sql +0 -83
- package/src/storage/migrations/002-storage-integrity.sql +0 -113
- package/src/storage/record-validation.js +0 -46
- package/src/storage/snapshot-defaults.js +0 -54
- package/src/storage/sqlite/candidates-repository.js +0 -84
- package/src/storage/sqlite/episode-evidence-repository.js +0 -154
- package/src/storage/sqlite/episode-privacy-sql.js +0 -33
- package/src/storage/sqlite/episodes-repository.js +0 -52
- package/src/storage/sqlite/fact-search-repository.js +0 -162
- package/src/storage/sqlite/facts-repository.js +0 -146
- package/src/storage/sqlite/imports-repository.js +0 -39
- package/src/storage/sqlite/mapper.js +0 -84
- package/src/storage/sqlite/open-database.js +0 -15
- package/src/storage/sqlite/outbox-repository.js +0 -103
- package/src/storage/sqlite/snapshot-repository.js +0 -69
- package/src/storage/sqlite/spaces-repository.js +0 -52
- package/src/storage/sqlite/subscriptions-repository.js +0 -54
- package/src/storage/sqlite-store.js +0 -159
- package/src/storage/stable-json.js +0 -24
- package/src/storage/store-port.js +0 -20
- package/src/store.js +0 -2
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
from pydantic import Field, model_validator
|
|
5
|
+
|
|
6
|
+
from .models import (
|
|
7
|
+
ConfirmationStatus,
|
|
8
|
+
EpistemicQuadrant,
|
|
9
|
+
KnowledgeFeedbackKind,
|
|
10
|
+
KnowledgeItemKind,
|
|
11
|
+
PersonalProfileAspect,
|
|
12
|
+
PreferenceScope,
|
|
13
|
+
StrictModel,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
KnowledgeReviewScope = Literal[
|
|
17
|
+
'all',
|
|
18
|
+
'preferences_global',
|
|
19
|
+
'preferences_project',
|
|
20
|
+
'projects_all',
|
|
21
|
+
'project',
|
|
22
|
+
]
|
|
23
|
+
KnowledgeReviewStatus = Literal['active', 'paused', 'completed']
|
|
24
|
+
KnowledgeReviewDisposition = Literal['paused', 'completed']
|
|
25
|
+
KnowledgeReviewOutcome = Literal[
|
|
26
|
+
'confirmed', 'updated', 'invalidated', 'deferred', 'delegated_to_ai'
|
|
27
|
+
]
|
|
28
|
+
KnowledgeReviewReason = Literal[
|
|
29
|
+
'changed_since_last',
|
|
30
|
+
'deferred_from_previous',
|
|
31
|
+
'conflict_or_attention',
|
|
32
|
+
'low_weight',
|
|
33
|
+
'repeated_cross_session',
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class KnowledgeReviewStart(StrictModel):
|
|
38
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
39
|
+
scope: KnowledgeReviewScope
|
|
40
|
+
personal_project_id: str | None = Field(default=None, min_length=1, max_length=128)
|
|
41
|
+
|
|
42
|
+
@model_validator(mode='after')
|
|
43
|
+
def validate_scope_project(self):
|
|
44
|
+
needs_project = self.scope in {'preferences_project', 'project'}
|
|
45
|
+
if needs_project and not self.personal_project_id:
|
|
46
|
+
raise ValueError(f'{self.scope} requires personal_project_id')
|
|
47
|
+
if not needs_project and self.personal_project_id:
|
|
48
|
+
raise ValueError(f'{self.scope} does not accept personal_project_id')
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class KnowledgeReviewRun(StrictModel):
|
|
53
|
+
review_id: str
|
|
54
|
+
personal_space_id: str
|
|
55
|
+
scope: KnowledgeReviewScope
|
|
56
|
+
personal_project_id: str | None = None
|
|
57
|
+
scope_key: str
|
|
58
|
+
status: KnowledgeReviewStatus
|
|
59
|
+
previous_completed_at: datetime | None = None
|
|
60
|
+
review_cutoff_at: datetime
|
|
61
|
+
started_at: datetime
|
|
62
|
+
updated_at: datetime
|
|
63
|
+
completed_at: datetime | None = None
|
|
64
|
+
resumed: bool = False
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class KnowledgeReviewCandidate(StrictModel):
|
|
68
|
+
candidate_key: str
|
|
69
|
+
item_id: str
|
|
70
|
+
item_kind: KnowledgeItemKind
|
|
71
|
+
title: str
|
|
72
|
+
content: str
|
|
73
|
+
# Keep the decision-critical ranking context near the front of the wire
|
|
74
|
+
# payload. Older MCP clients may project a bounded prefix of the Provider
|
|
75
|
+
# response, and the user must still see why a candidate was selected.
|
|
76
|
+
priority: int = Field(ge=1, le=4)
|
|
77
|
+
reasons: list[KnowledgeReviewReason]
|
|
78
|
+
confirmation_status: ConfirmationStatus
|
|
79
|
+
current_quadrant: EpistemicQuadrant
|
|
80
|
+
project_ids: list[str] = Field(default_factory=list)
|
|
81
|
+
profile_aspect: PersonalProfileAspect | None = None
|
|
82
|
+
preference_scope: PreferenceScope | None = None
|
|
83
|
+
preference_project_id: str | None = None
|
|
84
|
+
utility_score: float = Field(ge=0, le=1)
|
|
85
|
+
confidence_score: float = Field(ge=0, le=1)
|
|
86
|
+
qualified_use_count: int = Field(ge=0)
|
|
87
|
+
distinct_task_count: int = Field(ge=0)
|
|
88
|
+
negative_evidence_count: int = Field(ge=0)
|
|
89
|
+
requires_attention: bool
|
|
90
|
+
last_feedback_kind: KnowledgeFeedbackKind | None = None
|
|
91
|
+
distinct_session_count: int = Field(ge=0)
|
|
92
|
+
changed_at: datetime | None = None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class KnowledgeReviewCandidateRequest(StrictModel):
|
|
96
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
97
|
+
review_id: str = Field(min_length=1, max_length=256)
|
|
98
|
+
limit: int = Field(default=10, ge=1, le=50)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class KnowledgeReviewCandidatePage(StrictModel):
|
|
102
|
+
review: KnowledgeReviewRun
|
|
103
|
+
candidates: list[KnowledgeReviewCandidate]
|
|
104
|
+
total_candidate_count: int = Field(ge=0)
|
|
105
|
+
remaining_candidate_count: int = Field(ge=0)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class KnowledgeReviewProgress(StrictModel):
|
|
109
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
110
|
+
review_id: str = Field(min_length=1, max_length=256)
|
|
111
|
+
candidate_key: str = Field(
|
|
112
|
+
min_length=3,
|
|
113
|
+
max_length=520,
|
|
114
|
+
pattern=r'^(entity|relationship):.+$',
|
|
115
|
+
)
|
|
116
|
+
outcome: KnowledgeReviewOutcome
|
|
117
|
+
note: str | None = Field(default=None, min_length=1, max_length=2000)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class KnowledgeReviewDecision(StrictModel):
|
|
121
|
+
decision_id: str
|
|
122
|
+
review_id: str
|
|
123
|
+
candidate_key: str
|
|
124
|
+
outcome: KnowledgeReviewOutcome
|
|
125
|
+
note: str | None = None
|
|
126
|
+
created_at: datetime
|
|
127
|
+
updated_at: datetime
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class KnowledgeReviewFinish(StrictModel):
|
|
131
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
132
|
+
review_id: str = Field(min_length=1, max_length=256)
|
|
133
|
+
disposition: KnowledgeReviewDisposition
|
|
@@ -358,6 +358,7 @@ async def _personal_entities(
|
|
|
358
358
|
AS confirmation_status,
|
|
359
359
|
node.fuli_confirmation_basis_json AS confirmation_basis_json,
|
|
360
360
|
node.fuli_reasoning_summary AS reasoning_summary,
|
|
361
|
+
node.fuli_attributes_json AS attributes_json,
|
|
361
362
|
node.fuli_profile_aspect AS profile_aspect,
|
|
362
363
|
CASE WHEN node.fuli_profile_aspect IS NULL THEN NULL
|
|
363
364
|
ELSE coalesce(node.fuli_preference_scope, 'global') END
|
|
@@ -650,6 +651,7 @@ def _entity_search_result(record, score: float, space_id: str) -> EntitySearchRe
|
|
|
650
651
|
value.pop('last_feedback_at', None)
|
|
651
652
|
)
|
|
652
653
|
for field in (
|
|
654
|
+
'attributes_json',
|
|
653
655
|
'assignment_project_id',
|
|
654
656
|
'episode_project_ids',
|
|
655
657
|
'has_global_episode',
|
|
@@ -699,6 +701,7 @@ def _relevance(query: str, record) -> float:
|
|
|
699
701
|
if not needle:
|
|
700
702
|
return 0.0
|
|
701
703
|
score = 8.0 if needle in haystack else 0.0
|
|
704
|
+
score = max(score, _alias_relevance(needle, _retrieval_aliases(record)))
|
|
702
705
|
terms = _terms(needle)
|
|
703
706
|
if terms:
|
|
704
707
|
coverage = len(terms & _terms(haystack)) / len(terms)
|
|
@@ -733,13 +736,57 @@ def _terms(value: str) -> set[str]:
|
|
|
733
736
|
term for term in re.findall(r'[a-z0-9_]+', value)
|
|
734
737
|
if term not in LATIN_QUERY_FILLERS
|
|
735
738
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
739
|
+
chinese_segments = re.findall(r'[\u4e00-\u9fff]+', value)
|
|
740
|
+
grams = set()
|
|
741
|
+
for chinese in chinese_segments:
|
|
742
|
+
for filler in CHINESE_QUERY_FILLERS:
|
|
743
|
+
chinese = chinese.replace(filler, '')
|
|
744
|
+
grams.update(
|
|
745
|
+
chinese[index:index + 2]
|
|
746
|
+
for index in range(max(0, len(chinese) - 1))
|
|
747
|
+
)
|
|
740
748
|
return latin | grams
|
|
741
749
|
|
|
742
750
|
|
|
751
|
+
def _retrieval_aliases(record) -> list[str]:
|
|
752
|
+
attributes = record.get('attributes')
|
|
753
|
+
if not isinstance(attributes, dict):
|
|
754
|
+
attributes = json_object(record.get('attributes_json'))
|
|
755
|
+
values = (
|
|
756
|
+
attributes.get('searchTerms')
|
|
757
|
+
or attributes.get('search_terms')
|
|
758
|
+
or []
|
|
759
|
+
)
|
|
760
|
+
if isinstance(values, str):
|
|
761
|
+
values = [values]
|
|
762
|
+
if not isinstance(values, list):
|
|
763
|
+
return []
|
|
764
|
+
return [
|
|
765
|
+
value.strip()
|
|
766
|
+
for value in values[:32]
|
|
767
|
+
if isinstance(value, str) and 0 < len(value.strip()) <= 256
|
|
768
|
+
]
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
def _alias_relevance(query: str, aliases: list[str]) -> float:
|
|
772
|
+
query_terms = _terms(query)
|
|
773
|
+
best = 0.0
|
|
774
|
+
for alias in aliases:
|
|
775
|
+
normalized_alias = _normalized(alias)
|
|
776
|
+
if not normalized_alias:
|
|
777
|
+
continue
|
|
778
|
+
if normalized_alias in query:
|
|
779
|
+
best = max(best, 8.0)
|
|
780
|
+
continue
|
|
781
|
+
alias_terms = _terms(normalized_alias)
|
|
782
|
+
if len(alias_terms) < 2:
|
|
783
|
+
continue
|
|
784
|
+
coverage = len(alias_terms & query_terms) / len(alias_terms)
|
|
785
|
+
if coverage >= 0.75:
|
|
786
|
+
best = max(best, 6.0 + coverage * 2.0)
|
|
787
|
+
return round(best, 4)
|
|
788
|
+
|
|
789
|
+
|
|
743
790
|
def _timestamp(value) -> float:
|
|
744
791
|
native = _native_datetime(value)
|
|
745
792
|
return native.timestamp() if isinstance(native, datetime) else 0.0
|
|
@@ -471,6 +471,25 @@ class EntityInput(StrictModel):
|
|
|
471
471
|
def bound_attributes(cls, value: dict[str, Any]) -> dict[str, Any]:
|
|
472
472
|
if len(value) > 32:
|
|
473
473
|
raise ValueError('an entity may contain at most 32 attributes')
|
|
474
|
+
for key in ('searchTerms', 'search_terms'):
|
|
475
|
+
if key not in value:
|
|
476
|
+
continue
|
|
477
|
+
terms = value[key]
|
|
478
|
+
if (
|
|
479
|
+
not isinstance(terms, list)
|
|
480
|
+
or not terms
|
|
481
|
+
or len(terms) > 32
|
|
482
|
+
or any(
|
|
483
|
+
not isinstance(term, str)
|
|
484
|
+
or not term.strip()
|
|
485
|
+
or len(term) > 256
|
|
486
|
+
for term in terms
|
|
487
|
+
)
|
|
488
|
+
):
|
|
489
|
+
raise ValueError(
|
|
490
|
+
'entity search terms must be 1 to 32 non-empty strings '
|
|
491
|
+
'of at most 256 characters'
|
|
492
|
+
)
|
|
474
493
|
return value
|
|
475
494
|
|
|
476
495
|
@model_validator(mode='after')
|
|
@@ -169,6 +169,18 @@ class GraphitiRuntime:
|
|
|
169
169
|
'CREATE CONSTRAINT fuli_knowledge_audit_id IF NOT EXISTS '
|
|
170
170
|
'FOR (n:FuliKnowledgeAudit) REQUIRE n.id IS UNIQUE'
|
|
171
171
|
)
|
|
172
|
+
await self.driver.execute_query(
|
|
173
|
+
'CREATE CONSTRAINT fuli_knowledge_review_id IF NOT EXISTS '
|
|
174
|
+
'FOR (n:FuliKnowledgeReviewRun) REQUIRE n.id IS UNIQUE'
|
|
175
|
+
)
|
|
176
|
+
await self.driver.execute_query(
|
|
177
|
+
'CREATE CONSTRAINT fuli_knowledge_review_active IF NOT EXISTS '
|
|
178
|
+
'FOR (n:FuliKnowledgeReviewRun) REQUIRE n.active_key IS UNIQUE'
|
|
179
|
+
)
|
|
180
|
+
await self.driver.execute_query(
|
|
181
|
+
'CREATE CONSTRAINT fuli_knowledge_review_decision_id IF NOT EXISTS '
|
|
182
|
+
'FOR (n:FuliKnowledgeReviewDecision) REQUIRE n.id IS UNIQUE'
|
|
183
|
+
)
|
|
172
184
|
for query in (
|
|
173
185
|
'CREATE INDEX fuli_entity_confirmation IF NOT EXISTS '
|
|
174
186
|
'FOR (n:Entity) ON (n.group_id, n.fuli_confirmation_status)',
|
|
@@ -188,6 +200,9 @@ class GraphitiRuntime:
|
|
|
188
200
|
'CREATE INDEX fuli_knowledge_audit_lookup IF NOT EXISTS '
|
|
189
201
|
'FOR (n:FuliKnowledgeAudit) '
|
|
190
202
|
'ON (n.space_id, n.item_id, n.usage_generation)',
|
|
203
|
+
'CREATE INDEX fuli_knowledge_review_scope IF NOT EXISTS '
|
|
204
|
+
'FOR (n:FuliKnowledgeReviewRun) '
|
|
205
|
+
'ON (n.personal_space_id, n.scope_key, n.status)',
|
|
191
206
|
'CREATE INDEX fuli_personal_project_relation_type IF NOT EXISTS '
|
|
192
207
|
'FOR ()-[r:PERSONAL_PROJECT_RELATION]-() ON (r.relation_type)',
|
|
193
208
|
):
|
|
@@ -44,9 +44,10 @@ class StoreKnowledge:
|
|
|
44
44
|
space_id: str,
|
|
45
45
|
limit: int | None = None,
|
|
46
46
|
personal_project_id: str | None = None,
|
|
47
|
+
offset: int | None = None,
|
|
47
48
|
) -> GraphResult:
|
|
48
49
|
return await read_graph(
|
|
49
|
-
self, actor, space_id, limit, personal_project_id
|
|
50
|
+
self, actor, space_id, limit, personal_project_id, offset
|
|
50
51
|
)
|
|
51
52
|
|
|
52
53
|
async def collaboration_context(
|