fuli-context 0.11.1 → 0.12.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.
- package/README.md +6 -5
- package/README.zh-CN.md +5 -4
- package/dist/web/assets/AboutPage-Dized8Uz.js +1 -0
- package/dist/web/assets/AgentConversations-Ccy41mEA.js +2 -0
- package/dist/web/assets/AgentHand-UzVhbKUC.js +1 -0
- package/dist/web/assets/AgentName-DJpvkub2.js +1 -0
- package/dist/web/assets/AgentProfilePage-CFViQ8kj.js +1 -0
- package/dist/web/assets/AgentsDirectoryPage-CBFTg_IE.js +1 -0
- package/dist/web/assets/AgentsDirectoryPage-Cv-vxw2C.css +1 -0
- package/dist/web/assets/ConnectionsPage-uXcabab_.js +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-D8Hvhc-M.js +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-BQes4L1f.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-TBl_HNj6.js +3 -0
- package/dist/web/assets/KnowledgeEditDialog-HmiqLC-Y.js +1 -0
- package/dist/web/assets/KnowledgeInspector-Cj2yK4Qh.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-DT3BROZm.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-ccgscrPd.css +1 -0
- package/dist/web/assets/KnowledgePage-C4J4VueL.js +1 -0
- package/dist/web/assets/KnowledgeWorkspace-DA_dqVRG.js +4 -0
- package/dist/web/assets/NotFoundPage-x_Yd59mm.js +1 -0
- package/dist/web/assets/OverviewPage-3eZjQ26v.js +1 -0
- package/dist/web/assets/OverviewPage-8LBN8Shi.css +1 -0
- package/dist/web/assets/PersonalProfilePage-CDQk096L.js +1 -0
- package/dist/web/assets/PersonalProjectsPage-CJxp4Wyz.js +1 -0
- package/dist/web/assets/ProjectAgentFirstTask-BkRJ0zwO.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-BuNNqSEy.js +12 -0
- package/dist/web/assets/ProjectScopePicker-CiDxM2Yx.js +1 -0
- package/dist/web/assets/PublicProjectsPage-ByOT559r.js +1 -0
- package/dist/web/assets/ReviewPage-C0Vdr9uq.js +1 -0
- package/dist/web/assets/RoundtablesPage-Drou-B81.css +1 -0
- package/dist/web/assets/RoundtablesPage-L3ShEWS3.js +1 -0
- package/dist/web/assets/SettingsPage-BE8pWbI6.css +1 -0
- package/dist/web/assets/SettingsPage-McYuinGz.js +1 -0
- package/dist/web/assets/SharedJefaReportPage-Bg6lIk3E.js +1 -0
- package/dist/web/assets/UiButton-x8hiHNRM.js +1 -0
- package/dist/web/assets/UiDialog-mjletK0y.js +1 -0
- package/dist/web/assets/UiDisclosure-_IxeiexW.js +1 -0
- package/dist/web/assets/UiSegmented-WFfz9Evl.js +1 -0
- package/dist/web/assets/UiSelect-K29jnV-1.js +1 -0
- package/dist/web/assets/WritingTastePage-DCULB-d2.js +1 -0
- package/dist/web/assets/agent-pins-DS4mNsNt.js +1 -0
- package/dist/web/assets/agent-profile-Bh3MJGvb.css +1 -0
- package/dist/web/assets/agent-work-summary-C-yW7x7A.js +1 -0
- package/dist/web/assets/{attention-store-D-qIFRIb.js → attention-store-CA5y8j1R.js} +1 -1
- package/dist/web/assets/catalog-D0VEfOAV.js +1 -0
- package/dist/web/assets/client-DnwnUBQV.js +1 -0
- package/dist/web/assets/console-Cw7TzOSC.js +1 -0
- package/dist/web/assets/conversation-launcher-settings-Yc13viwr.js +1 -0
- package/dist/web/assets/{i18n-b14l2pQA.js → i18n-oJFlt8hW.js} +3 -3
- package/dist/web/assets/{identity-BWbPmZZf.js → identity-DSGS4CZc.js} +1 -1
- package/dist/web/assets/index-BfHCcUL2.css +1 -0
- package/dist/web/assets/index-DO10_fLc.js +5 -0
- package/dist/web/assets/judgment-types-DR931cZ7.js +1 -0
- package/dist/web/assets/model-BJ-UF4cs.js +1 -0
- package/dist/web/assets/{personal-profile-graph-BPTtMJTZ.js → personal-profile-graph-SOK0BR0w.js} +1 -1
- package/dist/web/assets/project-team-api-C_0qJk_B.js +1 -0
- package/dist/web/assets/shared-report-CiX64ZiD.js +1 -0
- package/dist/web/assets/{agent-work-summary-LeW-Al_S.js → task-evidence-DTiPCs7r.js} +1 -1
- package/dist/web/assets/useAgentRoster-B84mzZIg.js +1 -0
- package/dist/web/assets/{useApi-CROJJdhE-CEQAEuug.js → useApi-CROJJdhE-7gt0QyQ5.js} +1 -1
- package/dist/web/assets/vue-router-CCvPGaLD.js +1 -0
- package/dist/web/index.html +17 -12
- package/dist/web/licenses/ant-design-icons.txt +22 -0
- package/docs/agent-conversations-and-collaboration.md +3 -3
- package/docs/agent-roundtable.md +33 -0
- package/docs/client-connections.md +86 -0
- package/docs/employee-agents.md +3 -3
- package/docs/judgment-and-autonomy.md +33 -0
- package/docs/project-agent-memory.md +6 -6
- package/graph-provider/fuli_graph/ai_review.py +154 -0
- package/graph-provider/fuli_graph/common_knowledge.py +12 -0
- package/graph-provider/fuli_graph/default_project_lead.py +1 -1
- package/graph-provider/fuli_graph/graph_models.py +14 -0
- package/graph-provider/fuli_graph/graph_query.py +217 -0
- package/graph-provider/fuli_graph/knowledge_audit.py +6 -0
- package/graph-provider/fuli_graph/knowledge_batch_confirmation.py +6 -0
- package/graph-provider/fuli_graph/knowledge_management.py +23 -0
- package/graph-provider/fuli_graph/knowledge_review.py +383 -4
- package/graph-provider/fuli_graph/knowledge_review_models.py +61 -2
- package/graph-provider/fuli_graph/personal_global_preferences.py +5 -1
- package/graph-provider/fuli_graph/preference_conflicts.py +91 -1
- package/graph-provider/fuli_graph/project_agent_delegations.py +70 -2
- package/graph-provider/fuli_graph/project_agent_memory_routes.py +18 -1
- package/graph-provider/fuli_graph/project_agent_remote_origins.py +154 -0
- package/graph-provider/fuli_graph/project_agent_task_models.py +3 -1
- package/graph-provider/fuli_graph/project_knowledge.py +41 -0
- package/graph-provider/fuli_graph/runtime.py +15 -0
- package/graph-provider/fuli_graph/store_agent_verification.py +12 -5
- package/graph-provider/fuli_graph/store_knowledge.py +98 -58
- package/graph-provider/fuli_graph/store_project_agent_attention.py +1 -1
- package/graph-provider/fuli_graph/store_project_agent_context.py +3 -2
- package/graph-provider/fuli_graph/store_project_agent_coordination_policy.py +1 -1
- package/graph-provider/fuli_graph/store_project_agent_task_activity.py +26 -0
- package/graph-provider/fuli_graph/store_project_agent_task_reads.py +1 -1
- package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +5 -5
- package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +4 -3
- package/graph-provider/fuli_graph/store_project_agent_tasks.py +2 -2
- package/graph-provider/fuli_graph/store_project_agents.py +6 -6
- package/graph-provider/fuli_graph/system_agents.py +31 -2
- package/graph-provider/fuli_graph/system_hr_identity.py +21 -7
- package/graph-provider/pyproject.toml +2 -1
- package/npm-shrinkwrap.json +280 -5
- package/package.json +7 -2
- package/skills/operating-fuli/SKILL.md +3 -3
- package/src/agent-peer/coordinator-http.js +117 -0
- package/src/agent-peer/coordinator-service.js +258 -0
- package/src/agent-peer/coordinator-store.js +95 -0
- package/src/agent-peer/device-identity.js +70 -0
- package/src/agent-peer/http.js +47 -0
- package/src/agent-peer/node-store.js +127 -0
- package/src/agent-peer/origin-proof.js +56 -0
- package/src/agent-peer/peer-port.js +140 -0
- package/src/agent-peer/peer-runtime.js +298 -0
- package/src/agent-peer/peer-transport.js +78 -0
- package/src/agent-peer/protocol.js +161 -0
- package/src/agent-peer/runner.js +251 -0
- package/src/agent-roundtable/http.js +17 -3
- package/src/agent-roundtable/service.js +272 -43
- package/src/agent-roundtable/tools.js +15 -1
- package/src/agent-roundtable/wake.js +12 -3
- package/src/agent-tools/graph-definitions.js +16 -5
- package/src/agent-tools/graph-handlers.js +8 -0
- package/src/agent-tools/interface-catalog.js +16 -1
- package/src/agent-tools/judgment-definitions.js +12 -0
- package/src/agent-tools/project-agent-definitions.js +1 -1
- package/src/agents/claude-code/wake.js +7 -0
- package/src/agents/codex/wake.js +7 -0
- package/src/agents/identity-receipt.js +1 -1
- package/src/cli/command-registry.js +3 -0
- package/src/cli/connect-command.js +28 -0
- package/src/cli/mcp-command.js +99 -0
- package/src/cli/peer-command.js +100 -0
- package/src/cli/setup-agent-selection.js +2 -2
- package/src/cli/setup-command.js +7 -2
- package/src/cli.js +16 -0
- package/src/employees/catalog/bole.json +2 -2
- package/src/employees/catalog/tonborg.json +20 -0
- package/src/employees/manifest.js +2 -2
- package/src/employees/recruitment.js +20 -1
- package/src/graphiti/agent-collaboration.js +8 -2
- package/src/graphiti/federated-application.js +9 -1
- package/src/graphiti/knowledge-review.js +7 -3
- package/src/graphiti/project-agent-control-plane.js +7 -0
- package/src/graphiti/project-agent-mapping.js +2 -0
- package/src/graphiti/project-agent-task-entry.js +4 -4
- package/src/graphiti/project-agent-team-context.js +16 -18
- package/src/graphiti/project-team-view.js +82 -0
- package/src/graphiti/provider-client.js +9 -0
- package/src/graphiti/task-entry-preferences.js +6 -1
- package/src/http/api-router.js +12 -1
- package/src/http/graph-api-router.js +7 -0
- package/src/judgment/acceptance.js +91 -0
- package/src/judgment/engine.js +168 -0
- package/src/judgment/http.js +24 -0
- package/src/judgment/model.js +24 -0
- package/src/judgment/routing.js +96 -0
- package/src/judgment/scheduler.js +25 -0
- package/src/judgment/service.js +66 -0
- package/src/judgment/store.js +123 -0
- package/src/mcp/session-id.js +1 -0
- package/src/mcp/tool-annotations.js +8 -5
- package/src/mcp-server.js +2 -100
- package/src/server.js +22 -3
- package/src/setup/client-connection.js +16 -0
- package/src/system/system-service.js +5 -0
- package/dist/web/assets/AboutPage-cW9hDghN.js +0 -1
- package/dist/web/assets/AgentConversations-CGznTWuV.js +0 -2
- package/dist/web/assets/AgentHand-DkyF4vgk.js +0 -1
- package/dist/web/assets/AgentName-C1mAVr-v.js +0 -1
- package/dist/web/assets/AgentProfilePage-pKUR0rfj.js +0 -1
- package/dist/web/assets/AgentsDirectoryPage-CUlbT2hD.js +0 -1
- package/dist/web/assets/AgentsDirectoryPage-yRWktiin.css +0 -1
- package/dist/web/assets/ConnectionsPage-CuDHIJXu.js +0 -1
- package/dist/web/assets/EmployeeRecruitDialog-D9QfGipd.js +0 -1
- package/dist/web/assets/EmployeeWorkbenchPage-D-c_Jm2z.css +0 -1
- package/dist/web/assets/EmployeeWorkbenchPage-DAtvGney.js +0 -3
- package/dist/web/assets/KnowledgeEditDialog-a-5rasG0.js +0 -1
- package/dist/web/assets/KnowledgeInspector-BGsqjNY2.js +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-BndgUsHS.js +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-DeL7Jp34.css +0 -1
- package/dist/web/assets/KnowledgePage-CQweO0YJ.js +0 -1
- package/dist/web/assets/KnowledgeWorkspace-BtUjKTLb.js +0 -4
- package/dist/web/assets/NotFoundPage-BmQTTqQn.js +0 -1
- package/dist/web/assets/OverviewPage-By-fUzSG.css +0 -1
- package/dist/web/assets/OverviewPage-C73HyTsM.js +0 -1
- package/dist/web/assets/PersonalProfilePage-BMuOrppx.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-Cq9_kFvs.js +0 -1
- package/dist/web/assets/ProjectAgentFirstTask-CaHvOjkp.js +0 -1
- package/dist/web/assets/ProjectAgentsPage-WVcNdzVi.js +0 -12
- package/dist/web/assets/ProjectScopePicker-zAgiaZKL.js +0 -1
- package/dist/web/assets/PublicProjectsPage-DL093f65.js +0 -1
- package/dist/web/assets/ReviewPage-D_NIhPx8.js +0 -1
- package/dist/web/assets/RoundtablesPage-Cb0R4GaM.css +0 -1
- package/dist/web/assets/RoundtablesPage-CdVVyZE-.js +0 -1
- package/dist/web/assets/SettingsPage-BmYkLul4.css +0 -1
- package/dist/web/assets/SettingsPage-CbLaau8Q.js +0 -1
- package/dist/web/assets/SharedJefaReportPage-aygd6wvb.js +0 -1
- package/dist/web/assets/UiDialog-Q7fsJUoO.js +0 -1
- package/dist/web/assets/UiDisclosure-BS-muK5j.js +0 -1
- package/dist/web/assets/UiSegmented-CT28bxqw.js +0 -1
- package/dist/web/assets/UiSelect-DcGpPQQo.js +0 -1
- package/dist/web/assets/WritingTastePage-CYlwAFqV.js +0 -1
- package/dist/web/assets/agent-profile-BZj3ezWe.css +0 -1
- package/dist/web/assets/catalog-UDv854JN.js +0 -1
- package/dist/web/assets/client-DLS5FZBI.js +0 -1
- package/dist/web/assets/console-CqzwSo7a.js +0 -1
- package/dist/web/assets/conversation-launcher-settings-DRoIz42V.js +0 -1
- package/dist/web/assets/index-D1OHIz4c.js +0 -5
- package/dist/web/assets/index-kPB0Cf8Q.css +0 -1
- package/dist/web/assets/model-DupZy8Qb.js +0 -1
- package/dist/web/assets/shared-report-BYnLhmCZ.js +0 -1
- package/dist/web/assets/useAgentRoster-ep7SpKv1.js +0 -1
- package/dist/web/assets/vue-router-B6ZjK-Br.js +0 -1
|
@@ -4,6 +4,7 @@ from .graph_projection import (
|
|
|
4
4
|
management_projection,
|
|
5
5
|
personal_project_projection,
|
|
6
6
|
)
|
|
7
|
+
from .ai_review import effective_ai_review
|
|
7
8
|
from .graph_models import GraphEdge, GraphNode, GraphResult
|
|
8
9
|
from .models import (
|
|
9
10
|
ConfirmationBasis,
|
|
@@ -82,6 +83,7 @@ async def read_graph(
|
|
|
82
83
|
assignments = await _read_assignments(store, space_id, item_ids)
|
|
83
84
|
references = await read_project_references(store, space_id, item_ids)
|
|
84
85
|
conflicts = await read_knowledge_conflicts(store, space_id, item_ids)
|
|
86
|
+
preference_conflicts = await _read_preference_conflicts(store, space_id, item_ids)
|
|
85
87
|
audits = await read_knowledge_audits(store, space_id, item_ids)
|
|
86
88
|
knowledge_nodes = [
|
|
87
89
|
_graph_node(
|
|
@@ -92,6 +94,9 @@ async def read_graph(
|
|
|
92
94
|
references,
|
|
93
95
|
conflicts,
|
|
94
96
|
audits,
|
|
97
|
+
preference_conflicts=preference_conflicts,
|
|
98
|
+
review_scope='project' if project else 'all',
|
|
99
|
+
personal_project_id=personal_project_id,
|
|
95
100
|
)
|
|
96
101
|
for record in node_records
|
|
97
102
|
]
|
|
@@ -104,6 +109,9 @@ async def read_graph(
|
|
|
104
109
|
references,
|
|
105
110
|
conflicts,
|
|
106
111
|
audits,
|
|
112
|
+
preference_conflicts=preference_conflicts,
|
|
113
|
+
review_scope='project' if project else 'all',
|
|
114
|
+
personal_project_id=personal_project_id,
|
|
107
115
|
)
|
|
108
116
|
for record in edge_records
|
|
109
117
|
]
|
|
@@ -229,6 +237,13 @@ def _node_query(project_scoped: bool, paginated: bool = False) -> str:
|
|
|
229
237
|
node.fuli_last_human_changed_at AS last_human_changed_at,
|
|
230
238
|
node.fuli_last_agent_viewed_at AS last_agent_viewed_at,
|
|
231
239
|
node.fuli_last_agent_reviewed_at AS last_agent_reviewed_at,
|
|
240
|
+
node.fuli_ai_review_evidence_token AS ai_review_evidence_token,
|
|
241
|
+
node.fuli_ai_assessment_json AS ai_assessment_json,
|
|
242
|
+
node.fuli_ai_review_scope AS ai_review_scope,
|
|
243
|
+
node.fuli_ai_review_project_id AS ai_review_project_id,
|
|
244
|
+
node.fuli_ai_reviewed_at AS ai_reviewed_at,
|
|
245
|
+
node.fuli_ai_review_id AS ai_review_id,
|
|
246
|
+
node.fuli_ai_review_decision_id AS ai_review_decision_id,
|
|
232
247
|
coalesce(node.fuli_utility_score, 0.0) AS utility_score,
|
|
233
248
|
coalesce(node.fuli_confidence_score, 0.5) AS confidence_score,
|
|
234
249
|
coalesce(node.fuli_qualified_use_count, 0)
|
|
@@ -345,6 +360,13 @@ def _edge_query(project_scoped: bool, paginated: bool = False) -> str:
|
|
|
345
360
|
edge.fuli_last_human_changed_at AS last_human_changed_at,
|
|
346
361
|
edge.fuli_last_agent_viewed_at AS last_agent_viewed_at,
|
|
347
362
|
edge.fuli_last_agent_reviewed_at AS last_agent_reviewed_at,
|
|
363
|
+
edge.fuli_ai_review_evidence_token AS ai_review_evidence_token,
|
|
364
|
+
edge.fuli_ai_assessment_json AS ai_assessment_json,
|
|
365
|
+
edge.fuli_ai_review_scope AS ai_review_scope,
|
|
366
|
+
edge.fuli_ai_review_project_id AS ai_review_project_id,
|
|
367
|
+
edge.fuli_ai_reviewed_at AS ai_reviewed_at,
|
|
368
|
+
edge.fuli_ai_review_id AS ai_review_id,
|
|
369
|
+
edge.fuli_ai_review_decision_id AS ai_review_decision_id,
|
|
348
370
|
coalesce(edge.fuli_utility_score, 0.0) AS utility_score,
|
|
349
371
|
coalesce(edge.fuli_confidence_score, 0.5) AS confidence_score,
|
|
350
372
|
coalesce(edge.fuli_qualified_use_count, 0)
|
|
@@ -462,6 +484,31 @@ async def _read_assignments(store, space_id: str, item_ids: list[str]):
|
|
|
462
484
|
return result
|
|
463
485
|
|
|
464
486
|
|
|
487
|
+
async def _read_preference_conflicts(store, space_id: str, item_ids: list[str]):
|
|
488
|
+
if not item_ids:
|
|
489
|
+
return {}
|
|
490
|
+
records, _, _ = await store.runtime.driver.execute_query(
|
|
491
|
+
'''
|
|
492
|
+
MATCH (:FuliSpace {id: $space_id, kind: 'personal'})-
|
|
493
|
+
[:HAS_PREFERENCE_CONFLICT]->
|
|
494
|
+
(conflict:FuliPreferenceConflict {status: 'ai_pending'})
|
|
495
|
+
WHERE conflict.left_item_id IN $item_ids
|
|
496
|
+
OR conflict.right_item_id IN $item_ids
|
|
497
|
+
RETURN conflict
|
|
498
|
+
''',
|
|
499
|
+
space_id=space_id,
|
|
500
|
+
item_ids=item_ids,
|
|
501
|
+
routing_='r',
|
|
502
|
+
)
|
|
503
|
+
result = {}
|
|
504
|
+
for record in records:
|
|
505
|
+
value = dict(record['conflict'])
|
|
506
|
+
for item_id in (value.get('left_item_id'), value.get('right_item_id')):
|
|
507
|
+
if item_id in item_ids:
|
|
508
|
+
result.setdefault(item_id, []).append(value)
|
|
509
|
+
return result
|
|
510
|
+
|
|
511
|
+
|
|
465
512
|
def _graph_node(
|
|
466
513
|
record,
|
|
467
514
|
evidence,
|
|
@@ -470,12 +517,27 @@ def _graph_node(
|
|
|
470
517
|
references,
|
|
471
518
|
conflicts,
|
|
472
519
|
audits=None,
|
|
520
|
+
*,
|
|
521
|
+
preference_conflicts=None,
|
|
522
|
+
review_scope: str = 'all',
|
|
523
|
+
personal_project_id: str | None = None,
|
|
473
524
|
) -> GraphNode:
|
|
474
525
|
episode_ids = record.get('episodes') or []
|
|
475
526
|
status, basis, confidence, confirmation_explicit = _confirmation_projection(
|
|
476
527
|
record
|
|
477
528
|
)
|
|
478
529
|
attributes = json_object(record.get('attributes_json'))
|
|
530
|
+
ai_assessment = _effective_ai_projection(
|
|
531
|
+
record,
|
|
532
|
+
item_kind='entity',
|
|
533
|
+
evidence=evidence,
|
|
534
|
+
assignments=assignments,
|
|
535
|
+
references=references,
|
|
536
|
+
conflicts=conflicts,
|
|
537
|
+
preference_conflicts=preference_conflicts or {},
|
|
538
|
+
review_scope=review_scope,
|
|
539
|
+
personal_project_id=personal_project_id,
|
|
540
|
+
)
|
|
479
541
|
return GraphNode(
|
|
480
542
|
id=record['id'],
|
|
481
543
|
name=record['name'],
|
|
@@ -516,6 +578,14 @@ def _graph_node(
|
|
|
516
578
|
last_agent_reviewed_at=_native_datetime(
|
|
517
579
|
record.get('last_agent_reviewed_at')
|
|
518
580
|
),
|
|
581
|
+
ai_review_evidence_token=record.get('ai_review_evidence_token'),
|
|
582
|
+
ai_assessment=ai_assessment,
|
|
583
|
+
ai_review_scope=record.get('ai_review_scope'),
|
|
584
|
+
ai_review_project_id=record.get('ai_review_project_id'),
|
|
585
|
+
ai_reviewed_at=_native_datetime(record.get('ai_reviewed_at'))
|
|
586
|
+
if ai_assessment is not None else None,
|
|
587
|
+
ai_review_id=record.get('ai_review_id'),
|
|
588
|
+
ai_review_decision_id=record.get('ai_review_decision_id'),
|
|
519
589
|
utility_score=float(record.get('utility_score') or 0),
|
|
520
590
|
confidence_score=confidence,
|
|
521
591
|
qualified_use_count=int(record.get('qualified_use_count') or 0),
|
|
@@ -550,12 +620,27 @@ def _graph_edge(
|
|
|
550
620
|
references,
|
|
551
621
|
conflicts,
|
|
552
622
|
audits=None,
|
|
623
|
+
*,
|
|
624
|
+
preference_conflicts=None,
|
|
625
|
+
review_scope: str = 'all',
|
|
626
|
+
personal_project_id: str | None = None,
|
|
553
627
|
) -> GraphEdge:
|
|
554
628
|
episode_ids = record.get('episodes') or []
|
|
555
629
|
status, basis, confidence, confirmation_explicit = _confirmation_projection(
|
|
556
630
|
record
|
|
557
631
|
)
|
|
558
632
|
attributes = json_object(record.get('attributes_json'))
|
|
633
|
+
ai_assessment = _effective_ai_projection(
|
|
634
|
+
record,
|
|
635
|
+
item_kind='relationship',
|
|
636
|
+
evidence=evidence,
|
|
637
|
+
assignments=assignments,
|
|
638
|
+
references=references,
|
|
639
|
+
conflicts=conflicts,
|
|
640
|
+
preference_conflicts=preference_conflicts or {},
|
|
641
|
+
review_scope=review_scope,
|
|
642
|
+
personal_project_id=personal_project_id,
|
|
643
|
+
)
|
|
559
644
|
return GraphEdge(
|
|
560
645
|
id=record['id'],
|
|
561
646
|
source=record['source'],
|
|
@@ -598,6 +683,14 @@ def _graph_edge(
|
|
|
598
683
|
last_agent_reviewed_at=_native_datetime(
|
|
599
684
|
record.get('last_agent_reviewed_at')
|
|
600
685
|
),
|
|
686
|
+
ai_review_evidence_token=record.get('ai_review_evidence_token'),
|
|
687
|
+
ai_assessment=ai_assessment,
|
|
688
|
+
ai_review_scope=record.get('ai_review_scope'),
|
|
689
|
+
ai_review_project_id=record.get('ai_review_project_id'),
|
|
690
|
+
ai_reviewed_at=_native_datetime(record.get('ai_reviewed_at'))
|
|
691
|
+
if ai_assessment is not None else None,
|
|
692
|
+
ai_review_id=record.get('ai_review_id'),
|
|
693
|
+
ai_review_decision_id=record.get('ai_review_decision_id'),
|
|
601
694
|
utility_score=float(record.get('utility_score') or 0),
|
|
602
695
|
confidence_score=confidence,
|
|
603
696
|
qualified_use_count=int(record.get('qualified_use_count') or 0),
|
|
@@ -658,3 +751,127 @@ def _confirmation_projection(record) -> tuple[
|
|
|
658
751
|
and basis is not None
|
|
659
752
|
)
|
|
660
753
|
return status, basis, confidence, explicit
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
def _field_value(value, name: str, default=None):
|
|
757
|
+
if isinstance(value, dict):
|
|
758
|
+
return value.get(name, default)
|
|
759
|
+
return getattr(value, name, default)
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
def _effective_ai_projection(
|
|
763
|
+
record,
|
|
764
|
+
*,
|
|
765
|
+
item_kind: str,
|
|
766
|
+
evidence,
|
|
767
|
+
assignments,
|
|
768
|
+
references,
|
|
769
|
+
conflicts,
|
|
770
|
+
preference_conflicts,
|
|
771
|
+
review_scope: str,
|
|
772
|
+
personal_project_id: str | None,
|
|
773
|
+
) -> dict | None:
|
|
774
|
+
# The display scope may be broader than the scope used to produce the
|
|
775
|
+
# assessment. Validate against the persisted review scope so a
|
|
776
|
+
# project-bound token remains effective in an authorized all-space view.
|
|
777
|
+
stored_review_scope = record.get('ai_review_scope')
|
|
778
|
+
stored_review_project_id = record.get('ai_review_project_id')
|
|
779
|
+
validation_scope = stored_review_scope or review_scope
|
|
780
|
+
validation_project_id = (
|
|
781
|
+
stored_review_project_id
|
|
782
|
+
if stored_review_project_id is not None
|
|
783
|
+
else personal_project_id
|
|
784
|
+
)
|
|
785
|
+
if (
|
|
786
|
+
stored_review_project_id is not None
|
|
787
|
+
and review_scope in {'project', 'preferences_project'}
|
|
788
|
+
and personal_project_id != stored_review_project_id
|
|
789
|
+
):
|
|
790
|
+
return None
|
|
791
|
+
project_scoped_review = validation_scope in {'project', 'preferences_project'}
|
|
792
|
+
item_id = record['id']
|
|
793
|
+
project_ids = {
|
|
794
|
+
str(project_id)
|
|
795
|
+
for project_id in (record.get('project_ids') or [])
|
|
796
|
+
if project_id
|
|
797
|
+
}
|
|
798
|
+
preference_project_id = record.get('preference_project_id')
|
|
799
|
+
if preference_project_id:
|
|
800
|
+
project_ids.add(str(preference_project_id))
|
|
801
|
+
for assignment in assignments.get(item_id, []):
|
|
802
|
+
project_id = _field_value(assignment, 'project_id')
|
|
803
|
+
if project_id:
|
|
804
|
+
project_ids.add(str(project_id))
|
|
805
|
+
for reference in references.get(item_id, []):
|
|
806
|
+
project_id = _field_value(reference, 'project_id')
|
|
807
|
+
if project_id and _field_value(reference, 'status') == 'active':
|
|
808
|
+
project_ids.add(str(project_id))
|
|
809
|
+
for episode_id in record.get('episodes') or []:
|
|
810
|
+
project_id = _field_value(evidence.get(episode_id), 'personal_project_id')
|
|
811
|
+
if project_id:
|
|
812
|
+
project_ids.add(str(project_id))
|
|
813
|
+
|
|
814
|
+
scoped_conflict = False
|
|
815
|
+
for conflict in conflicts.get(item_id, []):
|
|
816
|
+
if _field_value(conflict, 'status') != 'pending':
|
|
817
|
+
continue
|
|
818
|
+
if not project_scoped_review or validation_project_id is None:
|
|
819
|
+
scoped_conflict = True
|
|
820
|
+
break
|
|
821
|
+
target_project_id = _field_value(conflict, 'target_project_id')
|
|
822
|
+
source_project_id = _field_value(conflict, 'source_project_id')
|
|
823
|
+
if validation_project_id in {target_project_id, source_project_id}:
|
|
824
|
+
scoped_conflict = True
|
|
825
|
+
break
|
|
826
|
+
if not scoped_conflict:
|
|
827
|
+
for conflict in preference_conflicts.get(item_id, []):
|
|
828
|
+
if _field_value(conflict, 'status') != 'ai_pending':
|
|
829
|
+
continue
|
|
830
|
+
if not project_scoped_review or validation_project_id is None:
|
|
831
|
+
scoped_conflict = True
|
|
832
|
+
break
|
|
833
|
+
if _field_value(conflict, 'preference_project_id') == validation_project_id:
|
|
834
|
+
scoped_conflict = True
|
|
835
|
+
break
|
|
836
|
+
|
|
837
|
+
item = {
|
|
838
|
+
'item_kind': item_kind,
|
|
839
|
+
'item_id': item_id,
|
|
840
|
+
'title': (
|
|
841
|
+
record.get('name') or item_id
|
|
842
|
+
if item_kind == 'entity'
|
|
843
|
+
else record.get('type') or 'RELATES_TO'
|
|
844
|
+
),
|
|
845
|
+
'content': (
|
|
846
|
+
record.get('summary') or ''
|
|
847
|
+
if item_kind == 'entity'
|
|
848
|
+
else record.get('fact') or ''
|
|
849
|
+
),
|
|
850
|
+
'valid_at': record.get('valid_at'),
|
|
851
|
+
'invalid_at': record.get('invalid_at'),
|
|
852
|
+
'confirmation_status': record.get('confirmation_status'),
|
|
853
|
+
'confirmation_basis_json': record.get('confirmation_basis_json'),
|
|
854
|
+
'profile_aspect': record.get('profile_aspect'),
|
|
855
|
+
'preference_scope': record.get('preference_scope'),
|
|
856
|
+
'preference_project_id': preference_project_id,
|
|
857
|
+
'preference_agent_id': record.get('preference_agent_id'),
|
|
858
|
+
'inheritance_mode': record.get('inheritance_mode') or 'local_only',
|
|
859
|
+
'current_quadrant': record.get('current_quadrant') or 'known_known',
|
|
860
|
+
'utility_score': record.get('utility_score'),
|
|
861
|
+
'confidence_score': record.get('confidence_score'),
|
|
862
|
+
'qualified_use_count': record.get('qualified_use_count'),
|
|
863
|
+
'distinct_task_count': record.get('distinct_task_count'),
|
|
864
|
+
'negative_evidence_count': record.get('negative_evidence_count'),
|
|
865
|
+
'requires_attention': record.get('requires_attention') is True,
|
|
866
|
+
'human_change_version': record.get('human_change_version') or 0,
|
|
867
|
+
'attributes_json': record.get('attributes_json'),
|
|
868
|
+
'project_ids': sorted(project_ids),
|
|
869
|
+
}
|
|
870
|
+
return effective_ai_review(
|
|
871
|
+
item,
|
|
872
|
+
stored_token=record.get('ai_review_evidence_token'),
|
|
873
|
+
stored_assessment=record.get('ai_assessment_json'),
|
|
874
|
+
scope=validation_scope,
|
|
875
|
+
personal_project_id=validation_project_id,
|
|
876
|
+
has_conflict=scoped_conflict,
|
|
877
|
+
)
|
|
@@ -630,6 +630,8 @@ def _human_change_query(item_kind: str) -> str:
|
|
|
630
630
|
return f'''
|
|
631
631
|
MATCH (space:FuliSpace {{id: $space_id, kind: 'personal'}})
|
|
632
632
|
{_item_match(item_kind)}
|
|
633
|
+
SET item.fuli_ai_review_lock_version =
|
|
634
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
633
635
|
SET item.fuli_human_edited = true,
|
|
634
636
|
item.fuli_human_change_version =
|
|
635
637
|
coalesce(item.fuli_human_change_version, 0) + 1,
|
|
@@ -797,6 +799,8 @@ def _knowledge_feedback_query(item_kind: str) -> str:
|
|
|
797
799
|
MATCH (space:FuliSpace {{id: $space_id, kind: 'personal'}})
|
|
798
800
|
{_item_match(item_kind)}
|
|
799
801
|
WHERE coalesce(item.fuli_usage_generation, 1) = $usage_generation
|
|
802
|
+
SET item.fuli_ai_review_lock_version =
|
|
803
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
800
804
|
MERGE (audit:FuliKnowledgeAudit {{id: $audit_id}})
|
|
801
805
|
ON CREATE SET audit.space_id = $space_id,
|
|
802
806
|
audit.item_id = $item_id,
|
|
@@ -850,6 +854,8 @@ def _usage_score_update_query(item_kind: str) -> str:
|
|
|
850
854
|
return f'''
|
|
851
855
|
{_item_match(item_kind)}
|
|
852
856
|
WHERE coalesce(item.fuli_usage_generation, 1) = $usage_generation
|
|
857
|
+
SET item.fuli_ai_review_lock_version =
|
|
858
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
853
859
|
SET item.fuli_utility_score = $utility_score,
|
|
854
860
|
item.fuli_confidence_score = $confidence_score,
|
|
855
861
|
item.fuli_qualified_use_count = $qualified_use_count,
|
|
@@ -201,6 +201,9 @@ CALL {
|
|
|
201
201
|
WITH space, valid_entities
|
|
202
202
|
UNWIND valid_entities AS valid
|
|
203
203
|
WITH space, valid.item AS item, valid.row AS row
|
|
204
|
+
ORDER BY 'entity:' + row.item_id
|
|
205
|
+
SET item.fuli_ai_review_lock_version =
|
|
206
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
204
207
|
SET item.fuli_epistemic_status = 'confirmed',
|
|
205
208
|
item.fuli_confirmation_status = 'confirmed',
|
|
206
209
|
item.fuli_confirmation_basis_json = row.confirmation_basis_json
|
|
@@ -223,6 +226,9 @@ CALL {
|
|
|
223
226
|
WITH space, valid_relationships
|
|
224
227
|
UNWIND valid_relationships AS valid
|
|
225
228
|
WITH space, valid.item AS item, valid.row AS row
|
|
229
|
+
ORDER BY 'relationship:' + row.item_id
|
|
230
|
+
SET item.fuli_ai_review_lock_version =
|
|
231
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
226
232
|
SET item.fuli_epistemic_status = 'confirmed',
|
|
227
233
|
item.fuli_confirmation_status = 'confirmed',
|
|
228
234
|
item.fuli_confirmation_basis_json = row.confirmation_basis_json
|
|
@@ -211,11 +211,25 @@ async def reassign_knowledge_item(
|
|
|
211
211
|
assignment_id = existing.id if existing else _stable_uuid(
|
|
212
212
|
space['id'], 'knowledge-assignment', request.item_kind, item_id
|
|
213
213
|
)
|
|
214
|
+
item_match = (
|
|
215
|
+
'MATCH (item:Entity {uuid: $item_id, group_id: $group_id})'
|
|
216
|
+
if request.item_kind == 'entity'
|
|
217
|
+
else (
|
|
218
|
+
'MATCH ()-[item:RELATES_TO '
|
|
219
|
+
'{uuid: $item_id, group_id: $group_id}]->()'
|
|
220
|
+
)
|
|
221
|
+
)
|
|
214
222
|
records, _, _ = await store.runtime.driver.execute_query(
|
|
215
223
|
'''
|
|
216
224
|
MATCH (space:FuliSpace {id: $space_id, kind: 'personal'})
|
|
217
225
|
MATCH (space)-[:CONTAINS_PROJECT]->
|
|
218
226
|
(target:FuliPersonalProject {project_id: $target_project_id})
|
|
227
|
+
'''
|
|
228
|
+
+ item_match
|
|
229
|
+
+ '''
|
|
230
|
+
SET item.fuli_ai_review_lock_version =
|
|
231
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
232
|
+
WITH space, target
|
|
219
233
|
MERGE (assignment:FuliKnowledgeAssignment {
|
|
220
234
|
space_id: $space_id,
|
|
221
235
|
item_kind: $item_kind,
|
|
@@ -236,6 +250,7 @@ async def reassign_knowledge_item(
|
|
|
236
250
|
RETURN assignment
|
|
237
251
|
''',
|
|
238
252
|
space_id=space['id'],
|
|
253
|
+
group_id=space['group_id'],
|
|
239
254
|
target_project_id=request.target_project_id,
|
|
240
255
|
item_kind=request.item_kind,
|
|
241
256
|
item_id=item_id,
|
|
@@ -712,6 +727,8 @@ async def _update_item(store, space, item_id, item_kind, value, embedding):
|
|
|
712
727
|
if item_kind == 'entity':
|
|
713
728
|
query = '''
|
|
714
729
|
MATCH (item:Entity {uuid: $item_id, group_id: $group_id})
|
|
730
|
+
SET item.fuli_ai_review_lock_version =
|
|
731
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
715
732
|
SET item.name = $name,
|
|
716
733
|
item.summary = $summary,
|
|
717
734
|
item.fuli_invalid_at = $invalid_at,
|
|
@@ -744,6 +761,8 @@ async def _update_item(store, space, item_id, item_kind, value, embedding):
|
|
|
744
761
|
else:
|
|
745
762
|
query = '''
|
|
746
763
|
MATCH ()-[item:RELATES_TO {uuid: $item_id, group_id: $group_id}]->()
|
|
764
|
+
SET item.fuli_ai_review_lock_version =
|
|
765
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
747
766
|
SET item.fact = $fact,
|
|
748
767
|
item.invalid_at = $invalid_at,
|
|
749
768
|
item.fuli_origin_quadrant = $origin_quadrant,
|
|
@@ -844,12 +863,16 @@ async def _update_preference_scope(
|
|
|
844
863
|
if item_kind == 'entity':
|
|
845
864
|
query = '''
|
|
846
865
|
MATCH (item:Entity {uuid: $item_id, group_id: $group_id})
|
|
866
|
+
SET item.fuli_ai_review_lock_version =
|
|
867
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
847
868
|
SET item.fuli_preference_scope = $scope,
|
|
848
869
|
item.fuli_preference_project_id = $project_id
|
|
849
870
|
'''
|
|
850
871
|
else:
|
|
851
872
|
query = '''
|
|
852
873
|
MATCH ()-[item:RELATES_TO {uuid: $item_id, group_id: $group_id}]->()
|
|
874
|
+
SET item.fuli_ai_review_lock_version =
|
|
875
|
+
coalesce(item.fuli_ai_review_lock_version, 0) + 1
|
|
853
876
|
SET item.fuli_preference_scope = $scope,
|
|
854
877
|
item.fuli_preference_project_id = $project_id
|
|
855
878
|
'''
|