fuli-context 0.7.9 → 0.7.10-beta.7
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 +5 -2
- package/README.zh-CN.md +5 -3
- package/dist/web/assets/{AboutPage-Bp-Xz6yo.js → AboutPage-EtWPOSpz.js} +1 -1
- package/dist/web/assets/AboutPage-vYIBifKw.css +1 -0
- package/dist/web/assets/AgentHand-D5pOgVjJ.js +1 -0
- package/dist/web/assets/AgentHand-DvdNtJ3_.css +1 -0
- package/dist/web/assets/ConnectionsPage-DXkvMuyK.js +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-B59X3rOi.css +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-DONxXnd2.js +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-Cd4hd4bf.js +3 -0
- package/dist/web/assets/EmployeeWorkbenchPage-Cz7y-IFD.css +1 -0
- package/dist/web/assets/GrowthLoading-B_Hh0CRS.css +1 -0
- package/dist/web/assets/GrowthLoading-CCYPgE2f.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-BUqMfa0a.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-D9NuRHvp.css +1 -0
- package/dist/web/assets/KnowledgeInspector-DlVPDGP3.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-DhthZGKZ.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-h2iKvQpO.css +1 -0
- package/dist/web/assets/KnowledgePage-B6RDVxq-.js +1 -0
- package/dist/web/assets/KnowledgeWorkspace-mVFHQcxr.js +4 -0
- package/dist/web/assets/KnowledgeWorkspace-sb8OJ97I.css +1 -0
- package/dist/web/assets/NotFoundPage-CCeEdBy9.js +1 -0
- package/dist/web/assets/{OverviewPage-HwoSW-5z.js → OverviewPage-CnYWoZ3r.js} +1 -1
- package/dist/web/assets/PersonalProfilePage-Bz4zpTPC.js +1 -0
- package/dist/web/assets/PersonalProfilePage-yQRCBude.css +1 -0
- package/dist/web/assets/PersonalProjectsPage-2u1o6dvA.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-8tci631q.js +11 -0
- package/dist/web/assets/ProjectAgentsPage-BN4k3ubu.css +1 -0
- package/dist/web/assets/ProjectScopePicker-BcPtIcv8.js +1 -0
- package/dist/web/assets/ProjectScopePicker-BvaGTMFx.css +1 -0
- package/dist/web/assets/PublicProjectsPage-BmBHfnud.js +1 -0
- package/dist/web/assets/ReviewPage-tvt2eqhw.js +1 -0
- package/dist/web/assets/{SearchableSelect-CFZNdtlY.js → SearchableSelect-BjBDBVuZ.js} +1 -1
- package/dist/web/assets/SettingsPage-Brl-SL33.css +1 -0
- package/dist/web/assets/SettingsPage-D9mNzBg-.js +1 -0
- package/dist/web/assets/SharedJefaReportPage-DXbj_JhO.css +1 -0
- package/dist/web/assets/SharedJefaReportPage-Dn_HBgaa.js +1 -0
- package/dist/web/assets/WritingTastePage-BCwimXC-.js +1 -0
- package/dist/web/assets/WritingTastePage-tb_pgude.css +1 -0
- package/dist/web/assets/bole-avatar-CVIr-bU_.webp +0 -0
- package/dist/web/assets/client-v8XKgQji.js +1 -0
- package/dist/web/assets/console-C9HS-zbd.js +1 -0
- package/dist/web/assets/conversation-launcher-settings-DMDCpf_N.js +1 -0
- package/dist/web/assets/employee-dialog-Bh5ccIbK.css +1 -0
- package/dist/web/assets/{i18n-DQH9D35M.js → i18n-BkJjUsz_.js} +3 -3
- package/dist/web/assets/{identity-JjZG6aS5.js → identity-74yGiMzO.js} +1 -1
- package/dist/web/assets/index-CwjxeHGk.css +1 -0
- package/dist/web/assets/index-Dioqmmvf.js +2 -0
- package/dist/web/assets/{model-zL97NJ-U.js → model-86tZgY0r.js} +1 -1
- package/dist/web/assets/shared-report-CLg82y4D.js +1 -0
- package/dist/web/assets/shared-report-ezeb8dW4.css +1 -0
- package/dist/web/assets/{useApi-CROJJdhE-CElDxEZI.js → useApi-CROJJdhE-BBUO_YEu.js} +1 -1
- package/dist/web/assets/useModalDialog-DrLhqtjR.js +1 -0
- package/dist/web/assets/{vue-router-F7MnkVlW.js → vue-router-Cw4QZxM1.js} +1 -1
- package/dist/web/index.html +14 -8
- package/docs/agent-interface-architecture.md +97 -0
- package/docs/employee-agents.md +58 -2
- package/graph-provider/fuli_graph/collaboration_context.py +2 -1
- package/graph-provider/fuli_graph/graph_models.py +5 -3
- package/graph-provider/fuli_graph/graph_query.py +4 -0
- package/graph-provider/fuli_graph/knowledge_search.py +2 -1
- package/graph-provider/fuli_graph/project_agent_access.py +2 -0
- package/graph-provider/fuli_graph/project_agent_attention_models.py +64 -0
- package/graph-provider/fuli_graph/project_agent_attention_routes.py +38 -0
- package/graph-provider/fuli_graph/project_agent_models.py +2 -0
- package/graph-provider/fuli_graph/project_agent_names.py +33 -0
- package/graph-provider/fuli_graph/project_agent_routes.py +12 -0
- package/graph-provider/fuli_graph/runtime.py +49 -20
- package/graph-provider/fuli_graph/store.py +2 -0
- package/graph-provider/fuli_graph/store_knowledge.py +4 -2
- package/graph-provider/fuli_graph/store_project_agent_attention.py +138 -0
- package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +8 -0
- package/graph-provider/fuli_graph/store_project_agent_memory.py +40 -13
- package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +4 -1
- package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +4 -1
- package/graph-provider/fuli_graph/store_project_agent_tasks.py +3 -0
- package/graph-provider/fuli_graph/store_project_agents.py +109 -0
- package/graph-provider/fuli_graph/store_task_contexts.py +1 -1
- package/graph-provider/fuli_graph/system_hr_identity.py +218 -0
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +52 -60
- package/package.json +2 -2
- package/skills/operating-fuli/SKILL.md +47 -0
- package/skills/operating-fuli/agents/openai.yaml +4 -0
- package/skills/operating-fuli/references/workflow-recipes.md +33 -0
- package/src/agent-tools/agent-attention-definitions.js +33 -0
- package/src/agent-tools/graph-definitions.js +8 -2
- package/src/agent-tools/graph-handlers.js +41 -0
- package/src/agent-tools/interface-catalog.js +101 -0
- package/src/agent-tools/interface-definitions.js +184 -0
- package/src/agent-tools/project-agent-definitions.js +1 -0
- package/src/cli/local-runtime-command.js +2 -1
- package/src/employees/catalog/bole.json +19 -0
- package/src/employees/install-package.js +3 -0
- package/src/employees/manifest.js +4 -0
- package/src/employees/package-registry.js +2 -0
- package/src/employees/recruitment.js +3 -0
- package/src/employees/service.js +10 -0
- package/src/external-knowledge/registry.js +24 -0
- package/src/external-knowledge/service.js +34 -1
- package/src/graphiti/agent-attention.js +26 -0
- package/src/graphiti/agent-knowledge-workflows.js +1 -0
- package/src/graphiti/project-agent-control-plane.js +21 -0
- package/src/graphiti/project-agent-mapping.js +6 -0
- package/src/graphiti/provider-client.js +13 -0
- package/src/graphiti/workspace-provider-client.js +9 -1
- package/src/http/agent-attention-api-router.js +28 -0
- package/src/http/error-mapping.js +3 -0
- package/src/http/graph-api-router.js +2 -0
- package/src/local-runtime/lifecycle.js +8 -2
- package/src/mcp/create-mcp-server.js +10 -1
- package/src/mcp/tool-annotations.js +31 -0
- package/src/mcp/tool-result.js +4 -4
- package/src/setup/agent-installation-status.js +2 -1
- package/src/setup/agents.js +4 -0
- package/src/setup/graph-runtime.js +4 -0
- package/src/setup/paths.js +2 -1
- package/src/setup/setup.js +4 -2
- package/src/setup/uninstall.js +4 -2
- package/src/system/resource-monitor.js +11 -1
- package/src/system/runtime-settings.js +7 -0
- package/dist/web/assets/AboutPage-DXh7Fwxt.css +0 -1
- package/dist/web/assets/ConnectionsPage-BMpkYeSE.js +0 -1
- package/dist/web/assets/EmployeeRecruitDialog-CnA7rOnB.css +0 -1
- package/dist/web/assets/EmployeeRecruitDialog-DbMVuLAI.js +0 -1
- package/dist/web/assets/EmployeeWorkbenchPage-BpkqpEs7.css +0 -1
- package/dist/web/assets/EmployeeWorkbenchPage-DtXSJOpq.js +0 -1
- package/dist/web/assets/KnowledgeEditDialog-DADXj_BT.js +0 -1
- package/dist/web/assets/KnowledgeEditDialog-iv-dgUeD.css +0 -1
- package/dist/web/assets/KnowledgeInspector-Xs4VCUg8.js +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-B_Ct4bB2.js +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-Cx1w1jb2.css +0 -1
- package/dist/web/assets/KnowledgePage-RG9Ttnrp.js +0 -1
- package/dist/web/assets/KnowledgeWorkspace-DI8YqTVI.js +0 -4
- package/dist/web/assets/PersonalProfilePage-B7T09bow.css +0 -1
- package/dist/web/assets/PersonalProfilePage-DCoG52SW.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-CNb9mlbp.js +0 -1
- package/dist/web/assets/ProjectAgentsPage-C3vW6wmk.css +0 -1
- package/dist/web/assets/ProjectAgentsPage-zQ9BZW9v.js +0 -11
- package/dist/web/assets/PublicProjectsPage-BuLqkZ8g.js +0 -1
- package/dist/web/assets/ReviewPage-8A7N5pJs.js +0 -1
- package/dist/web/assets/SettingsPage-4ah1u906.js +0 -1
- package/dist/web/assets/SettingsPage-CwZp2ka4.css +0 -1
- package/dist/web/assets/WritingTastePage-DSgvTH6x.css +0 -1
- package/dist/web/assets/WritingTastePage-DztRj6MK.js +0 -1
- package/dist/web/assets/avatars-LvVKbDF7.js +0 -1
- package/dist/web/assets/console-B7dWYAoU.js +0 -1
- package/dist/web/assets/conversation-launcher-settings-D1xhW1S5.js +0 -1
- package/dist/web/assets/index-Ch1jmkyO.css +0 -1
- package/dist/web/assets/index-DRd-2Tii.js +0 -2
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""Lossless, exact-ID upgrade of the original HR into the built-in Bole.
|
|
2
|
+
|
|
3
|
+
The old node and its original edges remain an audit source, not another active
|
|
4
|
+
Agent. Only this reserved legacy ID is eligible; names never establish identity.
|
|
5
|
+
The caller owns a transaction so any conflicting reference rolls everything back.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
from fastapi import HTTPException
|
|
12
|
+
|
|
13
|
+
from .project_agent_models import ProjectAgentProfile
|
|
14
|
+
from .provider_values import now_utc
|
|
15
|
+
|
|
16
|
+
SYSTEM_HR_AGENT_ID = 'employee.bole'
|
|
17
|
+
LEGACY_HR_AGENT_ID = 'fuli-project-hr'
|
|
18
|
+
REFERENCE_FIELDS = (
|
|
19
|
+
'agent_id', 'hr_agent_id', 'lead_agent_id', 'coordinator_agent_id',
|
|
20
|
+
'project_agent_id', 'recruited_agent_id', 'proposed_agent_id',
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def resolve_hr_alias(store, space_id, agent_id):
|
|
25
|
+
if agent_id != LEGACY_HR_AGENT_ID:
|
|
26
|
+
return agent_id
|
|
27
|
+
rows, _, _ = await store.runtime.driver.execute_query(
|
|
28
|
+
'''MATCH (:FuliSpace {id: $space_id, kind: 'personal'})-
|
|
29
|
+
[:HAS_PROJECT_AGENT_IDENTITY]->(alias:FuliProjectAgentAlias {
|
|
30
|
+
agent_id: $legacy_id, canonical_agent_id: $canonical_id
|
|
31
|
+
})-[:MERGED_INTO]->(agent:FuliProjectAgent {agent_id: $canonical_id})
|
|
32
|
+
RETURN agent.agent_id AS agent_id''',
|
|
33
|
+
space_id=space_id, legacy_id=LEGACY_HR_AGENT_ID,
|
|
34
|
+
canonical_id=SYSTEM_HR_AGENT_ID, routing_='r',
|
|
35
|
+
)
|
|
36
|
+
return rows[0]['agent_id'] if rows else agent_id
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def merged_hr_profile(canonical, legacy):
|
|
40
|
+
"""Keep current Bole settings and old role knowledge without widening clients."""
|
|
41
|
+
profile = {**legacy, **canonical, 'name': 'Bole', 'display_name': 'Bole',
|
|
42
|
+
'agent_type': 'hr', 'status': 'active'}
|
|
43
|
+
for field in ('capabilities', 'work_kinds', 'initial_preferences'):
|
|
44
|
+
profile[field] = list(dict.fromkeys([*canonical.get(field, []), *legacy.get(field, [])]))
|
|
45
|
+
old_clients = legacy.get('allowed_clients')
|
|
46
|
+
if old_clients is not None:
|
|
47
|
+
profile['allowed_clients'] = [c for c in profile.get('allowed_clients', []) if c in old_clients]
|
|
48
|
+
old_policy = legacy.get('executor_policy') or {}
|
|
49
|
+
policy = canonical.get('executor_policy') or {}
|
|
50
|
+
if old_policy.get('mode') == 'locked':
|
|
51
|
+
if policy.get('mode') == 'locked' and policy != old_policy:
|
|
52
|
+
raise HTTPException(409, 'Bole identities have conflicting locked executor policies')
|
|
53
|
+
profile['executor_policy'] = old_policy
|
|
54
|
+
return ProjectAgentProfile.model_validate(profile)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
async def merge_legacy_hr(store, space_id):
|
|
58
|
+
driver = store.runtime.driver
|
|
59
|
+
# Serialize all upgrades of this space, including two simultaneous setups.
|
|
60
|
+
rows, _, _ = await driver.execute_query(
|
|
61
|
+
'''MATCH (space:FuliSpace {id: $space_id, kind: 'personal'})
|
|
62
|
+
SET space._hr_identity_lock = coalesce(space._hr_identity_lock, 0) + 1
|
|
63
|
+
WITH space
|
|
64
|
+
MATCH (space)-[:HAS_PROJECT_AGENT_IDENTITY]->
|
|
65
|
+
(legacy:FuliProjectAgent {agent_id: $legacy_id})
|
|
66
|
+
MATCH (space)-[:HAS_PROJECT_AGENT_IDENTITY]->
|
|
67
|
+
(canonical:FuliProjectAgent {agent_id: $canonical_id})
|
|
68
|
+
SET legacy._task_lifecycle_lock = true, canonical._task_lifecycle_lock = true
|
|
69
|
+
REMOVE legacy._task_lifecycle_lock, canonical._task_lifecycle_lock
|
|
70
|
+
RETURN legacy, canonical, elementId(legacy) AS legacy_element,
|
|
71
|
+
elementId(canonical) AS canonical_element''',
|
|
72
|
+
space_id=space_id, legacy_id=LEGACY_HR_AGENT_ID, canonical_id=SYSTEM_HR_AGENT_ID,
|
|
73
|
+
)
|
|
74
|
+
if not rows:
|
|
75
|
+
return
|
|
76
|
+
row = rows[0]
|
|
77
|
+
legacy, canonical = dict(row['legacy']), dict(row['canonical'])
|
|
78
|
+
if legacy.get('agent_type') != 'hr' or canonical.get('agent_type') != 'hr':
|
|
79
|
+
raise HTTPException(409, 'Reserved Bole identity is occupied by a different role')
|
|
80
|
+
profile = merged_hr_profile(json.loads(canonical['profile_json']), json.loads(legacy['profile_json']))
|
|
81
|
+
scope = dict(space_id=space_id, legacy_id=LEGACY_HR_AGENT_ID, canonical_id=SYSTEM_HR_AGENT_ID)
|
|
82
|
+
memory_rows, _, _ = await driver.execute_query(
|
|
83
|
+
'''MATCH (:FuliSpace {id: $space_id})-[:HAS_PROJECT_AGENT_IDENTITY]->
|
|
84
|
+
(agent:FuliProjectAgent)-[:HAS_WORKING_MEMORY]->(head:FuliProjectAgentMemory)
|
|
85
|
+
WHERE agent.agent_id IN [$legacy_id, $canonical_id]
|
|
86
|
+
WITH head.personal_project_id AS project_id, collect(DISTINCT head.id) AS heads
|
|
87
|
+
WHERE size(heads) > 1 RETURN project_id''', **scope,
|
|
88
|
+
)
|
|
89
|
+
if memory_rows:
|
|
90
|
+
raise HTTPException(409, 'Bole identities have separate memory histories in one project; no data was changed')
|
|
91
|
+
# Keep original relationships on the alias. Create equivalent canonical
|
|
92
|
+
# relationships, refusing to overwrite a different existing relationship.
|
|
93
|
+
edges, _, _ = await driver.execute_query(
|
|
94
|
+
'''MATCH (:FuliSpace {id: $space_id})-[:HAS_PROJECT_AGENT_IDENTITY]->
|
|
95
|
+
(legacy:FuliProjectAgent {agent_id: $legacy_id})
|
|
96
|
+
MATCH (legacy)-[edge]-(other)
|
|
97
|
+
WHERE type(edge) <> 'HAS_PROJECT_AGENT_IDENTITY'
|
|
98
|
+
RETURN DISTINCT type(edge) AS kind, properties(edge) AS props,
|
|
99
|
+
elementId(startNode(edge)) AS start_id,
|
|
100
|
+
elementId(endNode(edge)) AS end_id''',
|
|
101
|
+
space_id=space_id, legacy_id=LEGACY_HR_AGENT_ID,
|
|
102
|
+
)
|
|
103
|
+
for edge in edges:
|
|
104
|
+
kind = edge['kind']
|
|
105
|
+
if not re.fullmatch(r'[A-Z][A-Z0-9_]*', kind):
|
|
106
|
+
raise HTTPException(409, 'Unsupported HR relationship; no data was changed')
|
|
107
|
+
start_id = row['canonical_element'] if edge['start_id'] == row['legacy_element'] else edge['start_id']
|
|
108
|
+
end_id = row['canonical_element'] if edge['end_id'] == row['legacy_element'] else edge['end_id']
|
|
109
|
+
copied, _, _ = await driver.execute_query(
|
|
110
|
+
f'''MATCH (source), (target)
|
|
111
|
+
WHERE elementId(source) = $start_id AND elementId(target) = $end_id
|
|
112
|
+
MERGE (source)-[edge:{kind}]->(target)
|
|
113
|
+
ON CREATE SET edge = $props
|
|
114
|
+
RETURN properties(edge) AS props''',
|
|
115
|
+
start_id=start_id, end_id=end_id, props=dict(edge['props']),
|
|
116
|
+
)
|
|
117
|
+
if not copied or dict(copied[0]['props']) != dict(edge['props']):
|
|
118
|
+
raise HTTPException(409, 'Bole identities have conflicting relationship history; no data was changed')
|
|
119
|
+
# Scalar routing references follow the canonical identity. Immutable JSON
|
|
120
|
+
# evidence and hashes remain unchanged; original references are retained.
|
|
121
|
+
references, _, _ = await driver.execute_query(
|
|
122
|
+
'''MATCH (space:FuliSpace {id: $space_id, kind: 'personal'})
|
|
123
|
+
CALL {
|
|
124
|
+
WITH space MATCH (n) WHERE n.personal_space_id = space.id RETURN n
|
|
125
|
+
UNION
|
|
126
|
+
WITH space MATCH (space)-[:HAS_PROJECT_AGENT_TASK]->(:FuliProjectAgentTask)-
|
|
127
|
+
[:HAS_TASK_EVENT]->(n:FuliProjectAgentTaskEvent) RETURN n
|
|
128
|
+
}
|
|
129
|
+
WITH DISTINCT n WHERE NOT n:FuliProjectAgent
|
|
130
|
+
AND any(key IN $fields WHERE n[key] = $legacy_id)
|
|
131
|
+
RETURN elementId(n) AS element_id,
|
|
132
|
+
[key IN $fields WHERE n[key] = $legacy_id] AS fields''',
|
|
133
|
+
space_id=space_id, legacy_id=LEGACY_HR_AGENT_ID, fields=list(REFERENCE_FIELDS),
|
|
134
|
+
)
|
|
135
|
+
for reference in references:
|
|
136
|
+
fields = reference['fields']
|
|
137
|
+
# Keys come from our constant whitelist, never arbitrary query input.
|
|
138
|
+
assignments = ', '.join(f'n.{key} = $canonical_id' for key in fields)
|
|
139
|
+
await driver.execute_query(
|
|
140
|
+
f'''MATCH (n) WHERE elementId(n) = $element_id
|
|
141
|
+
SET {assignments}, n.hr_identity_original_refs_json = $original''',
|
|
142
|
+
element_id=reference['element_id'], canonical_id=SYSTEM_HR_AGENT_ID,
|
|
143
|
+
original=json.dumps({key: LEGACY_HR_AGENT_ID for key in fields}),
|
|
144
|
+
)
|
|
145
|
+
await _move_learning_buckets(store, space_id)
|
|
146
|
+
# Knowledge UUIDs and evidence payloads are immutable. Only their mutable
|
|
147
|
+
# visibility metadata follows the identity, within this space's graph group.
|
|
148
|
+
await driver.execute_query(
|
|
149
|
+
'''MATCH (space:FuliSpace {id: $space_id, kind: 'personal'})
|
|
150
|
+
MATCH (n) WHERE n.group_id = space.group_id
|
|
151
|
+
AND (n:Entity OR n:Episodic)
|
|
152
|
+
FOREACH (_ IN CASE WHEN n.fuli_project_agent_id = $legacy_id THEN [1] ELSE [] END |
|
|
153
|
+
SET n.fuli_project_agent_id = $canonical_id, n.hr_identity_original_agent_id = $legacy_id)
|
|
154
|
+
FOREACH (_ IN CASE WHEN n.fuli_preference_agent_id = $legacy_id THEN [1] ELSE [] END |
|
|
155
|
+
SET n.fuli_preference_agent_id = $canonical_id, n.hr_identity_original_agent_id = $legacy_id)''',
|
|
156
|
+
**scope,
|
|
157
|
+
)
|
|
158
|
+
await driver.execute_query(
|
|
159
|
+
'''MATCH (space:FuliSpace {id: $space_id, kind: 'personal'})
|
|
160
|
+
MATCH ()-[edge:RELATES_TO]->() WHERE edge.group_id = space.group_id
|
|
161
|
+
AND edge.fuli_preference_agent_id = $legacy_id
|
|
162
|
+
SET edge.fuli_preference_agent_id = $canonical_id,
|
|
163
|
+
edge.hr_identity_original_agent_id = $legacy_id''', **scope,
|
|
164
|
+
)
|
|
165
|
+
await driver.execute_query(
|
|
166
|
+
'''MATCH (:FuliSpace {id: $space_id})-[:HAS_PROJECT_AGENT_IDENTITY]->
|
|
167
|
+
(legacy:FuliProjectAgent {agent_id: $legacy_id})
|
|
168
|
+
MATCH (:FuliSpace {id: $space_id})-[:HAS_PROJECT_AGENT_IDENTITY]->
|
|
169
|
+
(canonical:FuliProjectAgent {agent_id: $canonical_id})
|
|
170
|
+
SET canonical.profile_json = $profile_json, canonical.name = 'Bole',
|
|
171
|
+
canonical.status = 'active',
|
|
172
|
+
canonical.created_at = CASE WHEN legacy.created_at < canonical.created_at
|
|
173
|
+
THEN legacy.created_at ELSE canonical.created_at END,
|
|
174
|
+
canonical.recruited_at = coalesce(canonical.recruited_at, legacy.recruited_at),
|
|
175
|
+
canonical.recruitment_reason = coalesce(canonical.recruitment_reason, legacy.recruitment_reason),
|
|
176
|
+
canonical.recruitment_source_application = coalesce(
|
|
177
|
+
canonical.recruitment_source_application, legacy.recruitment_source_application),
|
|
178
|
+
canonical.capabilities = $capabilities, canonical.work_kinds = $work_kinds,
|
|
179
|
+
canonical.legacy_agent_ids = [$legacy_id], canonical.updated_at = $timestamp,
|
|
180
|
+
legacy:FuliProjectAgentAlias, legacy.canonical_agent_id = $canonical_id,
|
|
181
|
+
legacy.merged_at = $timestamp
|
|
182
|
+
REMOVE legacy:FuliProjectAgent
|
|
183
|
+
MERGE (legacy)-[:MERGED_INTO]->(canonical)''',
|
|
184
|
+
**scope, profile_json=profile.model_dump_json(), capabilities=profile.capabilities,
|
|
185
|
+
work_kinds=profile.work_kinds, timestamp=now_utc(),
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
async def _move_learning_buckets(store, space_id):
|
|
190
|
+
# These are derived cache/reset keys, not evidence or checkpoint IDs. Keep
|
|
191
|
+
# the original key for audit and refuse ambiguous overlapping buckets.
|
|
192
|
+
from .store_project_agent_executor_learning import project_agent_executor_outcome_bucket_id
|
|
193
|
+
|
|
194
|
+
for kind, label in (
|
|
195
|
+
('aggregate', 'FuliProjectAgentExecutorOutcomeAggregate'),
|
|
196
|
+
('reset', 'FuliProjectAgentExecutorOutcomeReset'),
|
|
197
|
+
):
|
|
198
|
+
rows, _, _ = await store.runtime.driver.execute_query(
|
|
199
|
+
f'''MATCH (n:{label} {{personal_space_id: $space_id,
|
|
200
|
+
hr_identity_original_refs_json: $original}}) RETURN n''',
|
|
201
|
+
space_id=space_id, original=json.dumps({'agent_id': LEGACY_HR_AGENT_ID}),
|
|
202
|
+
)
|
|
203
|
+
for row in rows:
|
|
204
|
+
node = dict(row['n'])
|
|
205
|
+
new_id = project_agent_executor_outcome_bucket_id(
|
|
206
|
+
store.settings.provider_id, space_id, node['personal_project_id'],
|
|
207
|
+
node['work_kind'], SYSTEM_HR_AGENT_ID, node['executor_id'],
|
|
208
|
+
node['model_strategy_key'], bucket_kind=kind,
|
|
209
|
+
)
|
|
210
|
+
conflicts, _, _ = await store.runtime.driver.execute_query(
|
|
211
|
+
f'MATCH (n:{label} {{id: $id}}) RETURN n.id AS id', id=new_id)
|
|
212
|
+
if conflicts:
|
|
213
|
+
raise HTTPException(409, 'Bole identities have overlapping executor learning histories; no data was changed')
|
|
214
|
+
await store.runtime.driver.execute_query(
|
|
215
|
+
f'''MATCH (n:{label} {{id: $old_id}})
|
|
216
|
+
SET n.hr_identity_original_id = n.id,
|
|
217
|
+
n.id = $new_id, n.{kind}_id = $new_id''',
|
|
218
|
+
old_id=node['id'], new_id=new_id)
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fuli-context",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.10-beta.7",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "fuli-context",
|
|
9
|
-
"version": "0.7.
|
|
9
|
+
"version": "0.7.10-beta.7",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@hono/node-server": "2.0.12",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"@vue/test-utils": "^2.4.11",
|
|
25
25
|
"brace-expansion": "5.0.9",
|
|
26
26
|
"d3": "^7.9.0",
|
|
27
|
-
"gsap": "^3.15.0",
|
|
28
27
|
"jsdom": "^29.1.1",
|
|
29
28
|
"linkedom": "^0.18.12",
|
|
30
29
|
"npm-run-all2": "^9.0.2",
|
|
@@ -1280,16 +1279,16 @@
|
|
|
1280
1279
|
}
|
|
1281
1280
|
},
|
|
1282
1281
|
"node_modules/@vitest/expect": {
|
|
1283
|
-
"version": "4.1.
|
|
1284
|
-
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.
|
|
1285
|
-
"integrity": "sha512-
|
|
1282
|
+
"version": "4.1.11",
|
|
1283
|
+
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz",
|
|
1284
|
+
"integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==",
|
|
1286
1285
|
"dev": true,
|
|
1287
1286
|
"license": "MIT",
|
|
1288
1287
|
"dependencies": {
|
|
1289
1288
|
"@standard-schema/spec": "^1.1.0",
|
|
1290
1289
|
"@types/chai": "^5.2.2",
|
|
1291
|
-
"@vitest/spy": "4.1.
|
|
1292
|
-
"@vitest/utils": "4.1.
|
|
1290
|
+
"@vitest/spy": "4.1.11",
|
|
1291
|
+
"@vitest/utils": "4.1.11",
|
|
1293
1292
|
"chai": "^6.2.2",
|
|
1294
1293
|
"tinyrainbow": "^3.1.0"
|
|
1295
1294
|
},
|
|
@@ -1298,13 +1297,13 @@
|
|
|
1298
1297
|
}
|
|
1299
1298
|
},
|
|
1300
1299
|
"node_modules/@vitest/mocker": {
|
|
1301
|
-
"version": "4.1.
|
|
1302
|
-
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.
|
|
1303
|
-
"integrity": "sha512-
|
|
1300
|
+
"version": "4.1.11",
|
|
1301
|
+
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz",
|
|
1302
|
+
"integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==",
|
|
1304
1303
|
"dev": true,
|
|
1305
1304
|
"license": "MIT",
|
|
1306
1305
|
"dependencies": {
|
|
1307
|
-
"@vitest/spy": "4.1.
|
|
1306
|
+
"@vitest/spy": "4.1.11",
|
|
1308
1307
|
"estree-walker": "^3.0.3",
|
|
1309
1308
|
"magic-string": "^0.30.21"
|
|
1310
1309
|
},
|
|
@@ -1335,9 +1334,9 @@
|
|
|
1335
1334
|
}
|
|
1336
1335
|
},
|
|
1337
1336
|
"node_modules/@vitest/pretty-format": {
|
|
1338
|
-
"version": "4.1.
|
|
1339
|
-
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.
|
|
1340
|
-
"integrity": "sha512-
|
|
1337
|
+
"version": "4.1.11",
|
|
1338
|
+
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz",
|
|
1339
|
+
"integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==",
|
|
1341
1340
|
"dev": true,
|
|
1342
1341
|
"license": "MIT",
|
|
1343
1342
|
"dependencies": {
|
|
@@ -1348,13 +1347,13 @@
|
|
|
1348
1347
|
}
|
|
1349
1348
|
},
|
|
1350
1349
|
"node_modules/@vitest/runner": {
|
|
1351
|
-
"version": "4.1.
|
|
1352
|
-
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.
|
|
1353
|
-
"integrity": "sha512-
|
|
1350
|
+
"version": "4.1.11",
|
|
1351
|
+
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz",
|
|
1352
|
+
"integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==",
|
|
1354
1353
|
"dev": true,
|
|
1355
1354
|
"license": "MIT",
|
|
1356
1355
|
"dependencies": {
|
|
1357
|
-
"@vitest/utils": "4.1.
|
|
1356
|
+
"@vitest/utils": "4.1.11",
|
|
1358
1357
|
"pathe": "^2.0.3"
|
|
1359
1358
|
},
|
|
1360
1359
|
"funding": {
|
|
@@ -1362,14 +1361,14 @@
|
|
|
1362
1361
|
}
|
|
1363
1362
|
},
|
|
1364
1363
|
"node_modules/@vitest/snapshot": {
|
|
1365
|
-
"version": "4.1.
|
|
1366
|
-
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.
|
|
1367
|
-
"integrity": "sha512-
|
|
1364
|
+
"version": "4.1.11",
|
|
1365
|
+
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz",
|
|
1366
|
+
"integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==",
|
|
1368
1367
|
"dev": true,
|
|
1369
1368
|
"license": "MIT",
|
|
1370
1369
|
"dependencies": {
|
|
1371
|
-
"@vitest/pretty-format": "4.1.
|
|
1372
|
-
"@vitest/utils": "4.1.
|
|
1370
|
+
"@vitest/pretty-format": "4.1.11",
|
|
1371
|
+
"@vitest/utils": "4.1.11",
|
|
1373
1372
|
"magic-string": "^0.30.21",
|
|
1374
1373
|
"pathe": "^2.0.3"
|
|
1375
1374
|
},
|
|
@@ -1378,9 +1377,9 @@
|
|
|
1378
1377
|
}
|
|
1379
1378
|
},
|
|
1380
1379
|
"node_modules/@vitest/spy": {
|
|
1381
|
-
"version": "4.1.
|
|
1382
|
-
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.
|
|
1383
|
-
"integrity": "sha512-
|
|
1380
|
+
"version": "4.1.11",
|
|
1381
|
+
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz",
|
|
1382
|
+
"integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==",
|
|
1384
1383
|
"dev": true,
|
|
1385
1384
|
"license": "MIT",
|
|
1386
1385
|
"funding": {
|
|
@@ -1388,13 +1387,13 @@
|
|
|
1388
1387
|
}
|
|
1389
1388
|
},
|
|
1390
1389
|
"node_modules/@vitest/utils": {
|
|
1391
|
-
"version": "4.1.
|
|
1392
|
-
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.
|
|
1393
|
-
"integrity": "sha512-
|
|
1390
|
+
"version": "4.1.11",
|
|
1391
|
+
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz",
|
|
1392
|
+
"integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==",
|
|
1394
1393
|
"dev": true,
|
|
1395
1394
|
"license": "MIT",
|
|
1396
1395
|
"dependencies": {
|
|
1397
|
-
"@vitest/pretty-format": "4.1.
|
|
1396
|
+
"@vitest/pretty-format": "4.1.11",
|
|
1398
1397
|
"convert-source-map": "^2.0.0",
|
|
1399
1398
|
"tinyrainbow": "^3.1.0"
|
|
1400
1399
|
},
|
|
@@ -3133,13 +3132,6 @@
|
|
|
3133
3132
|
"url": "https://github.com/sponsors/ljharb"
|
|
3134
3133
|
}
|
|
3135
3134
|
},
|
|
3136
|
-
"node_modules/gsap": {
|
|
3137
|
-
"version": "3.15.0",
|
|
3138
|
-
"resolved": "https://registry.npmjs.org/gsap/-/gsap-3.15.0.tgz",
|
|
3139
|
-
"integrity": "sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==",
|
|
3140
|
-
"dev": true,
|
|
3141
|
-
"license": "Standard 'no charge' license: https://gsap.com/standard-license."
|
|
3142
|
-
},
|
|
3143
3135
|
"node_modules/has-symbols": {
|
|
3144
3136
|
"version": "1.1.0",
|
|
3145
3137
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
|
@@ -3165,9 +3157,9 @@
|
|
|
3165
3157
|
}
|
|
3166
3158
|
},
|
|
3167
3159
|
"node_modules/hono": {
|
|
3168
|
-
"version": "4.13.
|
|
3169
|
-
"resolved": "https://registry.npmjs.org/hono/-/hono-4.13.
|
|
3170
|
-
"integrity": "sha512-
|
|
3160
|
+
"version": "4.13.7",
|
|
3161
|
+
"resolved": "https://registry.npmjs.org/hono/-/hono-4.13.7.tgz",
|
|
3162
|
+
"integrity": "sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==",
|
|
3171
3163
|
"license": "MIT",
|
|
3172
3164
|
"engines": {
|
|
3173
3165
|
"node": ">=16.9.0"
|
|
@@ -4953,9 +4945,9 @@
|
|
|
4953
4945
|
}
|
|
4954
4946
|
},
|
|
4955
4947
|
"node_modules/tinyrainbow": {
|
|
4956
|
-
"version": "3.1.
|
|
4957
|
-
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.
|
|
4958
|
-
"integrity": "sha512-
|
|
4948
|
+
"version": "3.1.1",
|
|
4949
|
+
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz",
|
|
4950
|
+
"integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==",
|
|
4959
4951
|
"dev": true,
|
|
4960
4952
|
"license": "MIT",
|
|
4961
4953
|
"engines": {
|
|
@@ -5270,19 +5262,19 @@
|
|
|
5270
5262
|
}
|
|
5271
5263
|
},
|
|
5272
5264
|
"node_modules/vitest": {
|
|
5273
|
-
"version": "4.1.
|
|
5274
|
-
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.
|
|
5275
|
-
"integrity": "sha512-
|
|
5265
|
+
"version": "4.1.11",
|
|
5266
|
+
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz",
|
|
5267
|
+
"integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==",
|
|
5276
5268
|
"dev": true,
|
|
5277
5269
|
"license": "MIT",
|
|
5278
5270
|
"dependencies": {
|
|
5279
|
-
"@vitest/expect": "4.1.
|
|
5280
|
-
"@vitest/mocker": "4.1.
|
|
5281
|
-
"@vitest/pretty-format": "4.1.
|
|
5282
|
-
"@vitest/runner": "4.1.
|
|
5283
|
-
"@vitest/snapshot": "4.1.
|
|
5284
|
-
"@vitest/spy": "4.1.
|
|
5285
|
-
"@vitest/utils": "4.1.
|
|
5271
|
+
"@vitest/expect": "4.1.11",
|
|
5272
|
+
"@vitest/mocker": "4.1.11",
|
|
5273
|
+
"@vitest/pretty-format": "4.1.11",
|
|
5274
|
+
"@vitest/runner": "4.1.11",
|
|
5275
|
+
"@vitest/snapshot": "4.1.11",
|
|
5276
|
+
"@vitest/spy": "4.1.11",
|
|
5277
|
+
"@vitest/utils": "4.1.11",
|
|
5286
5278
|
"es-module-lexer": "^2.0.0",
|
|
5287
5279
|
"expect-type": "^1.3.0",
|
|
5288
5280
|
"magic-string": "^0.30.21",
|
|
@@ -5310,12 +5302,12 @@
|
|
|
5310
5302
|
"@edge-runtime/vm": "*",
|
|
5311
5303
|
"@opentelemetry/api": "^1.9.0",
|
|
5312
5304
|
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
|
5313
|
-
"@vitest/browser-playwright": "4.1.
|
|
5314
|
-
"@vitest/browser-preview": "4.1.
|
|
5315
|
-
"@vitest/browser-webdriverio": "4.1.
|
|
5316
|
-
"@vitest/coverage-istanbul": "4.1.
|
|
5317
|
-
"@vitest/coverage-v8": "4.1.
|
|
5318
|
-
"@vitest/ui": "4.1.
|
|
5305
|
+
"@vitest/browser-playwright": "4.1.11",
|
|
5306
|
+
"@vitest/browser-preview": "4.1.11",
|
|
5307
|
+
"@vitest/browser-webdriverio": "4.1.11",
|
|
5308
|
+
"@vitest/coverage-istanbul": "4.1.11",
|
|
5309
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
5310
|
+
"@vitest/ui": "4.1.11",
|
|
5319
5311
|
"happy-dom": "*",
|
|
5320
5312
|
"jsdom": "*",
|
|
5321
5313
|
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fuli-context",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.10-beta.7",
|
|
4
4
|
"description": "Local-first collaboration relationship graph for AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"docs/public-personal-architecture.md",
|
|
13
13
|
"docs/project-agent-memory.md",
|
|
14
14
|
"docs/employee-agents.md",
|
|
15
|
+
"docs/agent-interface-architecture.md",
|
|
15
16
|
"examples/external-knowledge/markdown-folder.mjs",
|
|
16
17
|
"graph-provider/Dockerfile",
|
|
17
18
|
"graph-provider/pyproject.toml",
|
|
@@ -83,7 +84,6 @@
|
|
|
83
84
|
"@vue/test-utils": "^2.4.11",
|
|
84
85
|
"brace-expansion": "5.0.9",
|
|
85
86
|
"d3": "^7.9.0",
|
|
86
|
-
"gsap": "^3.15.0",
|
|
87
87
|
"jsdom": "^29.1.1",
|
|
88
88
|
"linkedom": "^0.18.12",
|
|
89
89
|
"npm-run-all2": "^9.0.2",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: operating-fuli
|
|
3
|
+
description: Use when an AI Agent needs to inspect or change FULI knowledge, personal projects, Project Agents, specialist Agents, public-project subscriptions, reviews, capture policy, or external-knowledge connections through structured tools instead of browser automation. Also use to check whether a FULI UI action has an Agent interface and to explain a deliberate local-user-only boundary.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Operating FULI
|
|
7
|
+
|
|
8
|
+
Operate FULI through its structured Agent interfaces. Treat the UI and Agent tools as two clients of the same application services; never use browser clicks as a data mutation fallback.
|
|
9
|
+
|
|
10
|
+
## Required workflow
|
|
11
|
+
|
|
12
|
+
1. Establish the exact scope from the current task. Resolve real `personalSpaceId`, `personalProjectId`, item IDs, and versions through read tools. Never guess an identifier or infer one from a display name.
|
|
13
|
+
2. Call `list_agent_interfaces` before the first mutation. Use its catalog to determine whether the UI capability is `agent` accessible or intentionally `local_user_only`.
|
|
14
|
+
3. Inspect the exact input schema for the selected tool. Prefer one domain-specific tool over generic HTTP, shell, database, or browser access.
|
|
15
|
+
4. Read the current record immediately before changing it. Preserve fields the user did not ask to change.
|
|
16
|
+
5. Check the safety boundary below. Stop if the action needs missing user authority or is marked `local_user_only`.
|
|
17
|
+
6. Execute the smallest scoped mutation. Supply `expectedRevision`, `expectedUpdatedAt`, `idempotencyKey`, or request IDs whenever the tool supports them.
|
|
18
|
+
7. Re-read through the corresponding structured read tool. Report the actual resulting scope, version, status, and any partial failure.
|
|
19
|
+
|
|
20
|
+
If an expected capability is absent from `list_agent_interfaces`, report an Agent-interface parity gap. Do not hide the gap by opening Chrome, clicking the UI, writing storage directly, or searching outside the current repository.
|
|
21
|
+
|
|
22
|
+
## Safety boundary
|
|
23
|
+
|
|
24
|
+
- Never enable or weaken Agent access through an Agent tool. The Agent-access kill switch remains a local-user control.
|
|
25
|
+
- Never change device/runtime settings or complete human confirmation queues on the user's behalf when the catalog marks them `local_user_only`.
|
|
26
|
+
- Never mark a Jefa work item complete through its human-acceptance workbench route; use an Agent task-update tool only for non-acceptance workflow changes.
|
|
27
|
+
- Require explicit user authorization for deletes, publication, subscription changes, destructive conflict decisions, or changes that affect another project. An unambiguous request already authorizes that exact action; do not ask again unless the target or consequences remain unclear.
|
|
28
|
+
- Use environment-variable references for connector secrets. Never request, print, store, or copy secret values into knowledge records, logs, Skill files, or tool arguments that expect only a reference.
|
|
29
|
+
- Stay inside the exact FULI workspace and registered project scopes. Do not use home-directory-wide discovery as a fallback.
|
|
30
|
+
- Browser automation may be used only for optional visual verification after a structured operation. It must not be the mechanism that changes FULI data.
|
|
31
|
+
|
|
32
|
+
## Selecting tools
|
|
33
|
+
|
|
34
|
+
Start from `list_agent_interfaces`; names and schemas can evolve. Common workflows and verification pairs are summarized in [workflow-recipes.md](references/workflow-recipes.md). Load that reference only when choosing or sequencing tools is not obvious from the catalog.
|
|
35
|
+
|
|
36
|
+
For read-only questions, use the narrowest list/get/search tool and return source and scope information. For writes, keep the user-requested scope explicit and verify after mutation. For multi-step operations, stop on the first failed invariant rather than continuing with a partially stale plan.
|
|
37
|
+
|
|
38
|
+
## Handling conflicts and failures
|
|
39
|
+
|
|
40
|
+
- On revision or timestamp conflict, re-read, explain what changed, and recompute the intended patch. Do not blindly retry stale input.
|
|
41
|
+
- On permission or `local_user_only` errors, identify the exact local UI action required. Do not bypass the boundary.
|
|
42
|
+
- On partial external sync, preserve the binding, report per-target/source failures, and let the user choose whether to retry.
|
|
43
|
+
- On an unknown tool or missing parity mapping, record the missing capability as a product defect instead of substituting browser automation.
|
|
44
|
+
|
|
45
|
+
## Completion response
|
|
46
|
+
|
|
47
|
+
State what changed, the exact project or item scope, the verification result, and any remaining human-only action. Do not claim success from a configured capability or submitted request alone.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# FULI Agent workflow recipes
|
|
2
|
+
|
|
3
|
+
Use these as sequencing hints only. Always call `list_agent_interfaces` and inspect the current tool schema first.
|
|
4
|
+
|
|
5
|
+
| Intent | Read before | Mutation | Verify after |
|
|
6
|
+
| --- | --- | --- | --- |
|
|
7
|
+
| Move an external-knowledge connection between projects | `list_external_knowledge_bindings` | `update_external_knowledge_binding_targets` | `check_external_knowledge_binding`, then `retrieve_external_knowledge_binding` or `sync_external_knowledge_binding` when requested |
|
|
8
|
+
| Create an external-knowledge connection | `list_external_knowledge_connectors`, `discover_external_knowledge_sources` | `create_external_knowledge_binding` | `check_external_knowledge_binding` |
|
|
9
|
+
| Change capture behavior | `get_capture_policy` | `update_capture_policy` | `get_capture_policy` |
|
|
10
|
+
| Add or change durable knowledge | the narrowest knowledge search/read tool | the matching knowledge submission or decision tool | read the exact item and confirm scope/version |
|
|
11
|
+
| Manage Project Agents | `list_project_agents`, `list_project_agent_tasks`, assignments or recruitment state | the matching Agent/assignment/task/recruitment tool | re-list the same Agent/task and inspect status/events |
|
|
12
|
+
| Defer or resolve a preference conflict | `list_preference_conflicts` and both exact knowledge items | `defer_preference_conflict` or `resolve_deferred_preference_conflict` | re-read the conflict and affected items; never claim human confirmation |
|
|
13
|
+
| Manage a specialist Agent | `list_employee_templates` and the current responsibility scope | recruit or update the specialist scope with its dedicated tool | re-list the template and effective managed projects |
|
|
14
|
+
| Publish or remove a public project | read the personal project and current publication | publish/update/delete tool | re-read publication status and release metadata |
|
|
15
|
+
|
|
16
|
+
For the external-knowledge move example, prefer updating the existing binding targets. Do not delete and recreate the binding merely to change project membership: recreation can lose revision history, connector state, and audit continuity.
|
|
17
|
+
|
|
18
|
+
Always inspect the complete `targets` array, not the legacy first-target aliases (`target`, `mode`, `sync`). When a user excludes project B, preserve other authorized targets, remove B explicitly, verify the saved array, and synchronize only the requested target/project. An unscoped sync covers every syncable target.
|
|
19
|
+
|
|
20
|
+
Pass the last-read `targetsVersion` as `expectedTargetsVersion` when changing targets. On `external_knowledge_conflict` or `external_knowledge_busy`, re-read after the other operation completes; do not replay a stale target array. The registry serializes mutations across console/MCP processes; an interrupted process releases its reservation automatically.
|
|
21
|
+
|
|
22
|
+
Bole is provisioned by the Provider as a fixed native role, not recruited through `recruit_employee`. Inspect staffing through the Project Agent read tools.
|
|
23
|
+
|
|
24
|
+
The following controls are deliberately local-user-only unless the current interface catalog says otherwise:
|
|
25
|
+
|
|
26
|
+
- Agent-access policy
|
|
27
|
+
- device/runtime settings
|
|
28
|
+
- human preference-conflict completion
|
|
29
|
+
- preference-scope confirmation
|
|
30
|
+
- batch knowledge confirmation
|
|
31
|
+
- Jefa work-item completion that records explicit human acceptance
|
|
32
|
+
|
|
33
|
+
Explain the precise UI action when one of these boundaries blocks the request. Never work around it through direct HTTP, storage, browser scripting, or a shell command.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { objectSchema, stringSchema, enumSchema, integerSchema } from './schema.js';
|
|
2
|
+
|
|
3
|
+
const text = (maxLength) => ({ ...stringSchema(), minLength: 1, maxLength });
|
|
4
|
+
const scope = { personalSpaceId: text(128), personalProjectId: text(128) };
|
|
5
|
+
const decision = objectSchema({
|
|
6
|
+
...scope, requestId: text(128), expectedRevision: integerSchema({ minimum: 0 }), response: text(4096)
|
|
7
|
+
}, ['personalSpaceId', 'personalProjectId', 'requestId', 'expectedRevision', 'response']);
|
|
8
|
+
|
|
9
|
+
export const AGENT_ATTENTION_DEFINITIONS = [
|
|
10
|
+
{
|
|
11
|
+
name: 'request_agent_attention',
|
|
12
|
+
description: 'Raise a hand only when a person must answer, review, decide or supply permission. Explain the requested action explicitly; do not use for routine running, queueing or retrying. Idempotent, project-scoped; does not execute approvals.',
|
|
13
|
+
inputSchema: objectSchema({
|
|
14
|
+
...scope, agentId: text(128), taskId: text(128),
|
|
15
|
+
idempotencyKey: { ...text(256), minLength: 8 },
|
|
16
|
+
kind: enumSchema(['question', 'approval', 'review', 'permission', 'blocked']),
|
|
17
|
+
title: text(160), detail: text(4096), requestedAction: text(2048)
|
|
18
|
+
}, ['personalSpaceId', 'personalProjectId', 'agentId', 'idempotencyKey', 'kind', 'title', 'detail', 'requestedAction'])
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'list_agent_attention',
|
|
22
|
+
description: 'Read human-action requests or responses in one personal space, optionally filtered by project and Agent. Open counts cover the complete filtered set, not only this page. Use resolved status to read human replies.',
|
|
23
|
+
inputSchema: objectSchema({
|
|
24
|
+
...scope, agentId: text(128), status: enumSchema(['open', 'resolved', 'cancelled']),
|
|
25
|
+
limit: integerSchema({ minimum: 1, maximum: 200 }), offset: integerSchema({ minimum: 0 })
|
|
26
|
+
}, ['personalSpaceId'])
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'cancel_agent_attention',
|
|
30
|
+
description: 'Withdraw an obsolete request with a reason and its latest revision. Records Agent cancellation, never impersonates a human response or acceptance.',
|
|
31
|
+
inputSchema: decision
|
|
32
|
+
}
|
|
33
|
+
];
|
|
@@ -33,6 +33,8 @@ import {
|
|
|
33
33
|
} from './project-agent-definitions.js';
|
|
34
34
|
import { PROJECT_AGENT_MEMORY_DEFINITIONS, workingMemorySchema } from './project-agent-memory-definitions.js';
|
|
35
35
|
import { EMPLOYEE_TOOL_DEFINITIONS } from './employee-definitions.js';
|
|
36
|
+
import { AGENT_INTERFACE_DEFINITIONS } from './interface-definitions.js';
|
|
37
|
+
import { AGENT_ATTENTION_DEFINITIONS } from './agent-attention-definitions.js';
|
|
36
38
|
|
|
37
39
|
const id = boundedString(256);
|
|
38
40
|
const label = boundedString(512);
|
|
@@ -278,6 +280,8 @@ const workflowObservedStep = objectSchema({
|
|
|
278
280
|
}, ['actionId', 'name']);
|
|
279
281
|
|
|
280
282
|
export const GRAPH_TOOL_DEFINITIONS = [
|
|
283
|
+
...AGENT_ATTENTION_DEFINITIONS,
|
|
284
|
+
...AGENT_INTERFACE_DEFINITIONS,
|
|
281
285
|
...EMPLOYEE_TOOL_DEFINITIONS,
|
|
282
286
|
{
|
|
283
287
|
name: 'begin_task_context',
|
|
@@ -1106,13 +1110,15 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
1106
1110
|
},
|
|
1107
1111
|
{
|
|
1108
1112
|
name: 'revise_personal_knowledge',
|
|
1109
|
-
description: 'Confirm, correct, invalidate, or
|
|
1113
|
+
description: 'Confirm, correct, invalidate, restore, or link a replacement for one personal entity or relationship while preserving revision history and original evidence. A replacement link requires an invalidated item and an exact replacement item ID and kind. This is the same personal-only operation used by the management UI; Agent attribution is always retained.',
|
|
1110
1114
|
inputSchema: objectSchema({
|
|
1111
1115
|
personalSpaceId: id,
|
|
1112
1116
|
personalProjectId: nullableStringSchema(),
|
|
1113
1117
|
itemKind: knowledgeItemKind,
|
|
1114
1118
|
itemId: id,
|
|
1115
|
-
action: enumSchema(['confirm', 'update', 'invalidate', 'restore']),
|
|
1119
|
+
action: enumSchema(['confirm', 'update', 'invalidate', 'restore', 'link_replacement']),
|
|
1120
|
+
replacementItemId: nullableStringSchema(),
|
|
1121
|
+
replacementItemKind: knowledgeItemKind,
|
|
1116
1122
|
reason: shortText,
|
|
1117
1123
|
name: nullableStringSchema(),
|
|
1118
1124
|
summary: nullableStringSchema(),
|