fuli-context 0.9.0 → 0.11.0
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 +29 -58
- package/README.zh-CN.md +24 -54
- package/dist/web/assets/AboutPage-CKq4IRHd.js +1 -0
- package/dist/web/assets/AgentConversations-DfXiFvBN.js +2 -0
- package/dist/web/assets/AgentConversations-XqNEBY_2.css +1 -0
- package/dist/web/assets/AgentHand-BBM-sKh2.js +1 -0
- package/dist/web/assets/AgentName-C_6R80nP.js +1 -0
- package/dist/web/assets/AgentProfilePage-Cz-i1fRD.js +1 -0
- package/dist/web/assets/AgentsDirectoryPage-BI0EFz6y.js +1 -0
- package/dist/web/assets/AgentsDirectoryPage-yRWktiin.css +1 -0
- package/dist/web/assets/ConnectionsPage-BoC6kXgs.js +1 -0
- package/dist/web/assets/ConnectionsPage-CM9C-zEI.css +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-BVyclQAJ.js +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-CVbqCzHb.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-D-c_Jm2z.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-D2GvYraI.js +3 -0
- package/dist/web/assets/KnowledgeEditDialog-a0AKWics.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-hT9znkoe.css +1 -0
- package/dist/web/assets/KnowledgeInspector-DMg9yJZ2.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-BgsHM3Qw.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-DeL7Jp34.css +1 -0
- package/dist/web/assets/KnowledgePage-kn8MqUCO.js +1 -0
- package/dist/web/assets/KnowledgeWorkspace-BtRq9fvC.js +4 -0
- package/dist/web/assets/KnowledgeWorkspace-D4a7FcAb.css +1 -0
- package/dist/web/assets/NotFoundPage-D-7jLz3o.js +1 -0
- package/dist/web/assets/OverviewPage-BHPc-XxY.js +1 -0
- package/dist/web/assets/OverviewPage-By-fUzSG.css +1 -0
- package/dist/web/assets/PersonalProfilePage-C00iV0Kx.js +1 -0
- package/dist/web/assets/PersonalProfilePage-DrMDAAdy.css +1 -0
- package/dist/web/assets/PersonalProjectsPage-CFNkdHSo.js +1 -0
- package/dist/web/assets/ProjectAgentFirstTask-Bi1ZsTC1.css +1 -0
- package/dist/web/assets/ProjectAgentFirstTask-CrCWEYgn.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-BzztLMH-.js +12 -0
- package/dist/web/assets/ProjectAgentsPage-DNLNjYp-.css +1 -0
- package/dist/web/assets/ProjectScopePicker-CMxn3txv.js +1 -0
- package/dist/web/assets/PublicProjectsPage-DKamXDV9.css +1 -0
- package/dist/web/assets/PublicProjectsPage-DQVtvhOS.js +1 -0
- package/dist/web/assets/ReviewPage-BZhvyDWc.js +1 -0
- package/dist/web/assets/RoundtablesPage-CVebTXQa.js +1 -0
- package/dist/web/assets/RoundtablesPage-Cb0R4GaM.css +1 -0
- package/dist/web/assets/SettingsPage-1knvfOW6.js +1 -0
- package/dist/web/assets/SettingsPage-BmYkLul4.css +1 -0
- package/dist/web/assets/SharedJefaReportPage-BCVq8u0P.js +1 -0
- package/dist/web/assets/UiDialog-Da1P10f4.js +1 -0
- package/dist/web/assets/UiDisclosure-8wE8YuE4.js +1 -0
- package/dist/web/assets/UiSegmented-BKZXc8QF.js +1 -0
- package/dist/web/assets/UiSelect-Bv6R0yr1.css +1 -0
- package/dist/web/assets/UiSelect-D5Xj5Ec4.js +1 -0
- package/dist/web/assets/WritingTastePage-B8-etOBn.js +1 -0
- package/dist/web/assets/WritingTastePage-B_zYD1df.css +1 -0
- package/dist/web/assets/agent-profile-BZj3ezWe.css +1 -0
- package/dist/web/assets/{attention-store-Dk-_P4Oi.js → attention-store-BfxtL9EV.js} +1 -1
- package/dist/web/assets/{catalog-DN72452f.js → catalog-6SN9i3WR.js} +1 -1
- package/dist/web/assets/client-CUTkF3t4.js +1 -0
- package/dist/web/assets/{console-BtPqo79j.js → console-CG8tdtSs.js} +1 -1
- package/dist/web/assets/{conversation-launcher-settings-jkHRmWai.js → conversation-launcher-settings-CyZkLJg7.js} +1 -1
- package/dist/web/assets/{i18n-D2CJkEYK.js → i18n-CCMR4gDS.js} +3 -3
- package/dist/web/assets/{identity-B3zEw-1u.js → identity-C1eN-FSB.js} +1 -1
- package/dist/web/assets/index-kPB0Cf8Q.css +1 -0
- package/dist/web/assets/index-sLDKI6R-.js +5 -0
- package/dist/web/assets/{model-S7ehAjky.js → model-l-sAqtW_.js} +1 -1
- package/dist/web/assets/{personal-profile-graph--GG3Mizo.js → personal-profile-graph-BD1Y6TDS.js} +1 -1
- package/dist/web/assets/shared-report-B46dxlCR.js +1 -0
- package/dist/web/assets/{useAgentRoster-BAPKWZ9y.js → useAgentRoster-DdxoKDEE.js} +1 -1
- package/dist/web/assets/{useApi-CROJJdhE-BtFMXFjw.js → useApi-CROJJdhE-DlOiu8lP.js} +1 -1
- package/dist/web/assets/{vue-router-DkaTtPn0.js → vue-router-DjqEU4W2.js} +1 -1
- package/dist/web/index.html +14 -16
- package/docs/agent-conversations-and-collaboration.md +9 -9
- package/docs/agent-roundtable.md +61 -0
- package/docs/employee-agents.md +2 -2
- package/docs/project-agent-memory.md +1 -1
- package/graph-provider/fuli_graph/agent_conversation_models.py +11 -2
- package/graph-provider/fuli_graph/conversation_context.py +40 -9
- package/graph-provider/fuli_graph/default_project_lead.py +88 -0
- package/graph-provider/fuli_graph/project_agent_memory_routes.py +7 -0
- package/graph-provider/fuli_graph/project_agent_task_models.py +3 -0
- package/graph-provider/fuli_graph/runtime.py +3 -76
- package/graph-provider/fuli_graph/store.py +2 -0
- package/graph-provider/fuli_graph/store_agent_conversations.py +60 -8
- package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +3 -1
- package/graph-provider/fuli_graph/store_project_agent_tasks.py +12 -8
- package/graph-provider/fuli_graph/store_project_agents.py +25 -124
- package/graph-provider/fuli_graph/store_task_contexts.py +26 -0
- package/graph-provider/fuli_graph/system_agents.py +128 -0
- package/graph-provider/fuli_graph/system_hr_identity.py +1 -1
- package/graph-provider/fuli_graph/task_context_routes.py +10 -0
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -4
- package/skills/capturing-session-knowledge/SKILL.md +1 -1
- package/src/agent-roundtable/http.js +14 -0
- package/src/agent-roundtable/service.js +218 -0
- package/src/agent-roundtable/store.js +86 -0
- package/src/agent-roundtable/tools.js +61 -0
- package/src/agent-roundtable/wake.js +99 -0
- package/src/agent-tools/agent-conversation-definitions.js +3 -3
- package/src/agent-tools/graph-definitions.js +3 -2
- package/src/agent-tools/interface-catalog.js +0 -5
- package/src/agent-tools.js +2 -2
- package/src/agents/claude-code/lifecycle-hook.js +6 -19
- package/src/agents/claude-code/wake.js +37 -0
- package/src/agents/codex/lifecycle-hook.js +51 -27
- package/src/agents/codex/token-usage.js +235 -0
- package/src/agents/codex/wake.js +47 -0
- package/src/agents/cursor/lifecycle-hook.js +3 -9
- package/src/agents/identity-receipt.js +16 -6
- package/src/agents/session-log.js +34 -0
- package/src/agents/token-usage-resolver.js +147 -0
- package/src/agents/wake-registry.js +14 -0
- package/src/cli/command-registry.js +0 -2
- package/src/cli/setup-command.js +2 -5
- package/src/cli/update-command.js +13 -2
- package/src/cli.js +0 -5
- package/src/employees/management-policy.js +4 -2
- package/src/employees/manifest.js +3 -0
- package/src/employees/recruitment.js +3 -2
- package/src/graphiti/agent-conversations.js +11 -9
- package/src/graphiti/agent-knowledge-workflows.js +34 -7
- package/src/graphiti/federated-application.js +18 -6
- package/src/graphiti/project-agent-mapping.js +1 -1
- package/src/graphiti/project-agent-task-entry.js +19 -7
- package/src/graphiti/project-agent-workflows.js +6 -1
- package/src/graphiti/project-path-context.js +7 -2
- package/src/graphiti/provider-client.js +8 -0
- package/src/graphiti/repository-project-registration.js +17 -0
- package/src/graphiti/task-entry-preferences.js +5 -0
- package/src/http/api-router.js +5 -3
- package/src/http/error-mapping.js +0 -2
- package/src/mcp/instructions.js +5 -5
- package/src/mcp/session-id.js +1 -1
- package/src/mcp/tool-annotations.js +3 -2
- package/src/setup/agents.js +1 -41
- package/src/setup/graph-runtime.js +15 -2
- package/src/setup/session-skill.js +22 -2
- package/dist/web/assets/AboutPage-D-GyJNv1.js +0 -1
- package/dist/web/assets/AgentConversations-DOuZgUeA.js +0 -2
- package/dist/web/assets/AgentConversations-DS8h3yKn.css +0 -1
- package/dist/web/assets/AgentHand-eGsXoGSq.js +0 -1
- package/dist/web/assets/AgentName-Dtmu9Ff5.js +0 -1
- package/dist/web/assets/AgentProfilePage-D8Tvayn7.js +0 -1
- package/dist/web/assets/AgentsDirectoryPage-BTEfKZjF.js +0 -1
- package/dist/web/assets/ConnectionsPage-C1w99yN3.css +0 -1
- package/dist/web/assets/ConnectionsPage-DwOIcvl9.js +0 -1
- package/dist/web/assets/EmployeeRecruitDialog-BrIMRblq.css +0 -1
- package/dist/web/assets/EmployeeRecruitDialog-D11blfwU.js +0 -1
- package/dist/web/assets/EmployeeWorkbenchPage-BcEzYt65.css +0 -1
- package/dist/web/assets/EmployeeWorkbenchPage-CK2BAoGt.js +0 -3
- package/dist/web/assets/GrowthLoading-KTjE2e50.js +0 -1
- package/dist/web/assets/KnowledgeEditDialog-B3x8vs3c.css +0 -1
- package/dist/web/assets/KnowledgeEditDialog-n9trHQ5d.js +0 -1
- package/dist/web/assets/KnowledgeInspector-BcNjgw9H.js +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-BzgxP-nG.css +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-DMBpGxLr.js +0 -1
- package/dist/web/assets/KnowledgePage-POkCMW8f.js +0 -1
- package/dist/web/assets/KnowledgeWorkspace-2FvQadhB.js +0 -4
- package/dist/web/assets/KnowledgeWorkspace-sb8OJ97I.css +0 -1
- package/dist/web/assets/NotFoundPage-BCMZbeB8.js +0 -1
- package/dist/web/assets/OverviewPage-0CFWCG9-.css +0 -1
- package/dist/web/assets/OverviewPage-0mYifpjp.js +0 -1
- package/dist/web/assets/PersonalProfilePage-Chv2a2pi.css +0 -1
- package/dist/web/assets/PersonalProfilePage-JW6Muix6.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-CRbi64JP.js +0 -1
- package/dist/web/assets/ProjectAgentFirstTask-6afJ8HUe.css +0 -1
- package/dist/web/assets/ProjectAgentFirstTask-DJ0wTbh8.js +0 -1
- package/dist/web/assets/ProjectAgentsPage-BgQLIpxg.css +0 -1
- package/dist/web/assets/ProjectAgentsPage-CQemHFxy.js +0 -12
- package/dist/web/assets/ProjectScopePicker-BwB7gK-7.js +0 -1
- package/dist/web/assets/PublicProjectsPage-CB272Sq-.js +0 -1
- package/dist/web/assets/ReviewPage-CelTZU4C.js +0 -1
- package/dist/web/assets/RoundtablesPage-ByVeZlgC.js +0 -2
- package/dist/web/assets/RoundtablesPage-DCbIBnBq.css +0 -1
- package/dist/web/assets/SearchableSelect-f7EHbyDL.js +0 -1
- package/dist/web/assets/SettingsPage-5g7mRN2F.css +0 -1
- package/dist/web/assets/SettingsPage-nAijmm5f.js +0 -1
- package/dist/web/assets/SharedJefaReportPage-CjpJ9bkk.js +0 -1
- package/dist/web/assets/UiDisclosure-CWlC91Zt.js +0 -1
- package/dist/web/assets/WritingTastePage-DaHWY61P.js +0 -1
- package/dist/web/assets/WritingTastePage-SMGF39mf.css +0 -1
- package/dist/web/assets/agent-profile-CBvJHGjt.css +0 -1
- package/dist/web/assets/client-B2cRl-7c.js +0 -1
- package/dist/web/assets/copy-D2LqwtPZ.js +0 -1
- package/dist/web/assets/index-CNp0tRNp.css +0 -1
- package/dist/web/assets/index-UygXwZDZ.js +0 -5
- package/dist/web/assets/shared-report-DEK9wvhl.js +0 -1
- package/dist/web/assets/useModalDialog-D8tiJfbc.js +0 -1
- package/docs/roundtable-beta-testing.md +0 -102
- package/docs/roundtable-beta-validation.md +0 -133
- package/docs/roundtable-research.md +0 -142
- package/src/agents/a2a/roundtable-participant.js +0 -374
- package/src/agents/claude-code/roundtable-participant.js +0 -24
- package/src/agents/codex/roundtable-config.js +0 -32
- package/src/agents/codex/roundtable-participant.js +0 -34
- package/src/agents/grok/roundtable-participant.js +0 -185
- package/src/agents/pi/roundtable-participant.js +0 -193
- package/src/agents/pi/roundtable-result-format.js +0 -183
- package/src/cli/roundtable-command.js +0 -79
- package/src/roundtables/application.js +0 -69
- package/src/roundtables/domain.js +0 -181
- package/src/roundtables/http-router.js +0 -56
- package/src/roundtables/mcp-server.js +0 -48
- package/src/roundtables/participant-registry.js +0 -12
- package/src/roundtables/process.js +0 -70
- package/src/roundtables/result-contract.js +0 -47
- package/src/roundtables/server.js +0 -52
- package/src/roundtables/service.js +0 -396
- package/src/roundtables/store.js +0 -59
- package/src/roundtables/tool-contract.js +0 -41
- package/src/roundtables/turn-prompt.js +0 -24
- package/src/roundtables/worker.js +0 -85
- /package/dist/web/assets/{GrowthLoading-CIuQ1icy.css → client-CIuQ1icy.css} +0 -0
|
@@ -347,13 +347,16 @@ class StoreProjectAgentTasks(
|
|
|
347
347
|
reason = 'hr_unavailable'
|
|
348
348
|
self._verify_parallel_plan(request.parallel_plan, participants)
|
|
349
349
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
350
|
+
# Staffing a default lead executes nothing, so it needs no executor.
|
|
351
|
+
executor_decision = None if request.staffing_intent == 'default_lead' else (
|
|
352
|
+
await self._resolve_executor_if_available(
|
|
353
|
+
actor,
|
|
354
|
+
request,
|
|
355
|
+
lead,
|
|
356
|
+
model_strategy,
|
|
357
|
+
model_source,
|
|
358
|
+
task_id,
|
|
359
|
+
)
|
|
357
360
|
)
|
|
358
361
|
if lead and executor_decision and self._executor_decision_blocked(executor_decision):
|
|
359
362
|
routing_outcome = 'blocked'
|
|
@@ -904,7 +907,8 @@ class StoreProjectAgentTasks(
|
|
|
904
907
|
lead_agent_id=lead_agent_id,
|
|
905
908
|
complexity=complexity,
|
|
906
909
|
complexity_basis=complexity_basis,
|
|
907
|
-
|
|
910
|
+
# A staffing record has no artifact to verify.
|
|
911
|
+
verification_required=request.staffing_intent != 'default_lead',
|
|
908
912
|
model_strategy_json=model_strategy.model_dump_json() if model_strategy else None,
|
|
909
913
|
task_model_strategy_override_json=(
|
|
910
914
|
request.model_strategy_override.model_dump_json()
|
|
@@ -20,146 +20,42 @@ from .project_agent_models import (
|
|
|
20
20
|
from .provider_values import native_datetime, now_utc, stable_uuid
|
|
21
21
|
from .project_agent_names import agent_display_name
|
|
22
22
|
from .store_transactions import query_store_transaction
|
|
23
|
+
from .system_agents import (
|
|
24
|
+
SYSTEM_COORDINATOR_AGENT_ID,
|
|
25
|
+
SYSTEM_HR_AGENT_ID,
|
|
26
|
+
ensure_system_agents,
|
|
27
|
+
)
|
|
23
28
|
from .system_hr_identity import LEGACY_HR_AGENT_ID, merge_legacy_hr, resolve_hr_alias
|
|
24
29
|
|
|
25
30
|
|
|
26
|
-
SYSTEM_COORDINATOR_AGENT_ID = 'fuli-project-coordinator'
|
|
27
|
-
SYSTEM_HR_AGENT_ID = 'employee.bole'
|
|
28
|
-
|
|
29
|
-
|
|
30
31
|
class StoreProjectAgents:
|
|
31
32
|
async def ensure_system_project_hr(
|
|
32
33
|
self,
|
|
33
34
|
actor: dict,
|
|
34
35
|
personal_space_id: str,
|
|
35
36
|
) -> ProjectAgentRecord:
|
|
36
|
-
self.
|
|
37
|
-
await self.authorize(actor, personal_space_id, 'maintainer')
|
|
38
|
-
async with query_store_transaction(self) as scoped:
|
|
39
|
-
await scoped._ensure_system_project_hr_identity(personal_space_id)
|
|
40
|
-
await merge_legacy_hr(scoped, personal_space_id)
|
|
37
|
+
await self._ensure_system_agents(actor, personal_space_id)
|
|
41
38
|
return await self.get_project_agent(actor, personal_space_id, None, SYSTEM_HR_AGENT_ID)
|
|
42
39
|
|
|
43
|
-
async def _ensure_system_project_hr_identity(self, personal_space_id):
|
|
44
|
-
profile = ProjectAgentProfile(
|
|
45
|
-
name='Bole',
|
|
46
|
-
occupation_emoji='🔎',
|
|
47
|
-
responsibility=(
|
|
48
|
-
'维护 Agent 人员分布、当前工作与可审计招募记录,'
|
|
49
|
-
'并在需要新角色时执行受策略约束的招募。'
|
|
50
|
-
),
|
|
51
|
-
agent_type='hr',
|
|
52
|
-
work_kinds=['agent-recruitment', 'staffing-review'],
|
|
53
|
-
capabilities=[
|
|
54
|
-
'Agent 招募', '人员分布', '工作状态', '招募审计',
|
|
55
|
-
'fuli.employee:bole',
|
|
56
|
-
],
|
|
57
|
-
initial_preferences=[
|
|
58
|
-
'每次招募保留任务、原因、触发来源与时间线。',
|
|
59
|
-
'只展示 Provider 已记录的人员状态,不推测未上报的工作。',
|
|
60
|
-
],
|
|
61
|
-
status='active',
|
|
62
|
-
)
|
|
63
|
-
updated_at = now_utc()
|
|
64
|
-
node_id = stable_uuid(
|
|
65
|
-
self.settings.provider_id,
|
|
66
|
-
personal_space_id,
|
|
67
|
-
'project-agent',
|
|
68
|
-
SYSTEM_HR_AGENT_ID,
|
|
69
|
-
)
|
|
70
|
-
await self.runtime.driver.execute_query(
|
|
71
|
-
'''
|
|
72
|
-
MATCH (space:FuliSpace {id: $personal_space_id, kind: 'personal'})
|
|
73
|
-
MERGE (agent:FuliProjectAgent {id: $id})
|
|
74
|
-
ON CREATE SET agent.agent_id = $agent_id,
|
|
75
|
-
agent.created_at = $updated_at,
|
|
76
|
-
agent.system_managed = true
|
|
77
|
-
ON CREATE SET agent.profile_json = $profile_json,
|
|
78
|
-
agent.name = $name,
|
|
79
|
-
agent.occupation_emoji = $occupation_emoji,
|
|
80
|
-
agent.responsibility = $responsibility,
|
|
81
|
-
agent.capabilities = $capabilities,
|
|
82
|
-
agent.work_kinds = $work_kinds,
|
|
83
|
-
agent.agent_type = 'hr',
|
|
84
|
-
agent.memory_scope = 'reviewed_agent',
|
|
85
|
-
agent.status = 'active',
|
|
86
|
-
agent.updated_at = $updated_at
|
|
87
|
-
MERGE (space)-[:HAS_PROJECT_AGENT_IDENTITY]->(agent)
|
|
88
|
-
RETURN agent
|
|
89
|
-
''',
|
|
90
|
-
personal_space_id=personal_space_id,
|
|
91
|
-
id=node_id,
|
|
92
|
-
agent_id=SYSTEM_HR_AGENT_ID,
|
|
93
|
-
profile_json=profile.model_dump_json(),
|
|
94
|
-
name=profile.name,
|
|
95
|
-
occupation_emoji=profile.occupation_emoji,
|
|
96
|
-
responsibility=profile.responsibility,
|
|
97
|
-
capabilities=profile.capabilities,
|
|
98
|
-
work_kinds=profile.work_kinds,
|
|
99
|
-
updated_at=updated_at,
|
|
100
|
-
)
|
|
101
|
-
|
|
102
40
|
async def ensure_system_project_coordinator(
|
|
103
41
|
self,
|
|
104
42
|
actor: dict,
|
|
105
43
|
personal_space_id: str,
|
|
106
44
|
) -> ProjectAgentRecord:
|
|
107
|
-
self.
|
|
108
|
-
await self.authorize(actor, personal_space_id, 'maintainer')
|
|
109
|
-
profile = ProjectAgentProfile(
|
|
110
|
-
name='项目协调人',
|
|
111
|
-
responsibility='评估任务、选择模型策略、路由已有 Agent,并审计职责缺口。',
|
|
112
|
-
agent_type='coordinator',
|
|
113
|
-
work_kinds=['task-coordination'],
|
|
114
|
-
capabilities=['任务评估', '模型策略', 'Agent 路由'],
|
|
115
|
-
initial_preferences=['质量与可验收完成优先于成本和时间'],
|
|
116
|
-
status='active',
|
|
117
|
-
)
|
|
118
|
-
updated_at = now_utc()
|
|
119
|
-
node_id = stable_uuid(
|
|
120
|
-
self.settings.provider_id,
|
|
121
|
-
personal_space_id,
|
|
122
|
-
'project-agent',
|
|
123
|
-
SYSTEM_COORDINATOR_AGENT_ID,
|
|
124
|
-
)
|
|
125
|
-
await self.runtime.driver.execute_query(
|
|
126
|
-
'''
|
|
127
|
-
MATCH (space:FuliSpace {id: $personal_space_id, kind: 'personal'})
|
|
128
|
-
MERGE (agent:FuliProjectAgent {id: $id})
|
|
129
|
-
ON CREATE SET agent.agent_id = $agent_id,
|
|
130
|
-
agent.created_at = $updated_at,
|
|
131
|
-
agent.system_managed = true
|
|
132
|
-
ON CREATE SET agent.profile_json = $profile_json,
|
|
133
|
-
agent.name = $name,
|
|
134
|
-
agent.occupation_emoji = $occupation_emoji,
|
|
135
|
-
agent.responsibility = $responsibility,
|
|
136
|
-
agent.capabilities = $capabilities,
|
|
137
|
-
agent.work_kinds = $work_kinds,
|
|
138
|
-
agent.agent_type = 'coordinator',
|
|
139
|
-
agent.memory_scope = 'reviewed_agent',
|
|
140
|
-
agent.status = 'active',
|
|
141
|
-
agent.updated_at = $updated_at
|
|
142
|
-
MERGE (space)-[:HAS_PROJECT_AGENT_IDENTITY]->(agent)
|
|
143
|
-
RETURN agent
|
|
144
|
-
''',
|
|
145
|
-
personal_space_id=personal_space_id,
|
|
146
|
-
id=node_id,
|
|
147
|
-
agent_id=SYSTEM_COORDINATOR_AGENT_ID,
|
|
148
|
-
profile_json=profile.model_dump_json(),
|
|
149
|
-
name=profile.name,
|
|
150
|
-
occupation_emoji=profile.occupation_emoji,
|
|
151
|
-
responsibility=profile.responsibility,
|
|
152
|
-
capabilities=profile.capabilities,
|
|
153
|
-
work_kinds=profile.work_kinds,
|
|
154
|
-
updated_at=updated_at,
|
|
155
|
-
)
|
|
45
|
+
await self._ensure_system_agents(actor, personal_space_id)
|
|
156
46
|
return await self.get_project_agent(
|
|
157
|
-
actor,
|
|
158
|
-
personal_space_id,
|
|
159
|
-
None,
|
|
160
|
-
SYSTEM_COORDINATOR_AGENT_ID,
|
|
47
|
+
actor, personal_space_id, None, SYSTEM_COORDINATOR_AGENT_ID,
|
|
161
48
|
)
|
|
162
49
|
|
|
50
|
+
async def _ensure_system_agents(self, actor, personal_space_id):
|
|
51
|
+
self._require_personal()
|
|
52
|
+
await self.authorize(actor, personal_space_id, 'maintainer')
|
|
53
|
+
async with query_store_transaction(self) as scoped:
|
|
54
|
+
await ensure_system_agents(
|
|
55
|
+
scoped.runtime.driver, scoped.settings.provider_id, personal_space_id,
|
|
56
|
+
)
|
|
57
|
+
await merge_legacy_hr(scoped, personal_space_id)
|
|
58
|
+
|
|
163
59
|
async def upsert_project_agent(
|
|
164
60
|
self,
|
|
165
61
|
actor: dict,
|
|
@@ -207,10 +103,13 @@ class StoreProjectAgents:
|
|
|
207
103
|
status_code=422,
|
|
208
104
|
detail='the system HR identity cannot change Agent type',
|
|
209
105
|
)
|
|
210
|
-
if
|
|
106
|
+
if (
|
|
107
|
+
request.agent_id in (SYSTEM_HR_AGENT_ID, SYSTEM_COORDINATOR_AGENT_ID)
|
|
108
|
+
and request.profile.status != 'active'
|
|
109
|
+
):
|
|
211
110
|
raise HTTPException(
|
|
212
111
|
status_code=422,
|
|
213
|
-
detail='the
|
|
112
|
+
detail='the project manager and HR must remain active',
|
|
214
113
|
)
|
|
215
114
|
space = await self.authorize(actor, request.personal_space_id, 'maintainer')
|
|
216
115
|
if request.personal_project_id:
|
|
@@ -488,7 +387,7 @@ class StoreProjectAgents:
|
|
|
488
387
|
if agent_id == SYSTEM_COORDINATOR_AGENT_ID:
|
|
489
388
|
raise HTTPException(
|
|
490
389
|
status_code=422,
|
|
491
|
-
detail='the
|
|
390
|
+
detail='the project manager cannot be archived',
|
|
492
391
|
)
|
|
493
392
|
if agent_id == SYSTEM_HR_AGENT_ID:
|
|
494
393
|
raise HTTPException(
|
|
@@ -571,6 +470,8 @@ class StoreProjectAgents:
|
|
|
571
470
|
[:HAS_PROJECT_AGENT_IDENTITY]->(agent:FuliProjectAgent)
|
|
572
471
|
WHERE ($agent_id IS NULL OR agent.agent_id = $agent_id)
|
|
573
472
|
AND ($status IS NULL OR agent.status = $status)
|
|
473
|
+
// A retired system identity stays readable by ID for history only.
|
|
474
|
+
AND ($agent_id IS NOT NULL OR agent.superseded_by IS NULL)
|
|
574
475
|
AND (
|
|
575
476
|
$personal_project_id IS NULL
|
|
576
477
|
OR EXISTS {
|
|
@@ -99,6 +99,32 @@ class StoreTaskContexts:
|
|
|
99
99
|
id=self._task_session_id(space_id, source_application, session_id))
|
|
100
100
|
return json.loads(rows[0]['record_json']) if rows else None
|
|
101
101
|
|
|
102
|
+
async def recent_agent_sessions(self, actor, space_id, agent_id, project_id, limit):
|
|
103
|
+
"""The host conversations an Agent most recently worked in, newest first."""
|
|
104
|
+
self._require_personal()
|
|
105
|
+
await self.authorize(actor, space_id, 'reader')
|
|
106
|
+
rows, _, _ = await self.runtime.driver.execute_query(
|
|
107
|
+
'''
|
|
108
|
+
MATCH (:FuliSpace {id: $space_id, kind: 'personal'})-
|
|
109
|
+
[:HAS_TASK_CONTEXT_SESSION]->(:FuliTaskContextSession)-
|
|
110
|
+
[:HAS_CONTEXT]->(task:FuliTaskContext {project_agent_id: $agent_id})
|
|
111
|
+
WHERE $project_id IS NULL OR task.personal_project_id = $project_id
|
|
112
|
+
RETURN task.record_json AS record_json, task.created_at AS created_at
|
|
113
|
+
ORDER BY task.created_at DESC LIMIT 200
|
|
114
|
+
''', space_id=space_id, agent_id=agent_id, project_id=project_id, routing_='r',
|
|
115
|
+
)
|
|
116
|
+
sessions = {}
|
|
117
|
+
for row in rows:
|
|
118
|
+
record = json.loads(row['record_json'])
|
|
119
|
+
key = (record['source_application'], record['session_id'])
|
|
120
|
+
if key not in sessions:
|
|
121
|
+
sessions[key] = {
|
|
122
|
+
'source_application': key[0], 'session_id': key[1],
|
|
123
|
+
'personal_project_id': record.get('personal_project_id'),
|
|
124
|
+
'last_active': str(row['created_at']),
|
|
125
|
+
}
|
|
126
|
+
return list(sessions.values())[:limit]
|
|
127
|
+
|
|
102
128
|
async def get_task_context(self, actor, space_id, token, source_application):
|
|
103
129
|
self._require_personal()
|
|
104
130
|
await self.authorize(actor, space_id, 'reader')
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""The two fixed roles every personal space has: Jefa (project manager) and Bole (HR).
|
|
2
|
+
|
|
3
|
+
Jefa also coordinates task routing, replacing the earlier separate coordinator
|
|
4
|
+
identity. That legacy node is retired, not deleted, so old tasks keep their
|
|
5
|
+
original coordinator reference.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
|
|
10
|
+
from .project_agent_models import ProjectAgentProfile
|
|
11
|
+
from .provider_values import now_utc, stable_uuid
|
|
12
|
+
|
|
13
|
+
SYSTEM_COORDINATOR_AGENT_ID = 'employee.jefa'
|
|
14
|
+
LEGACY_COORDINATOR_AGENT_ID = 'fuli-project-coordinator'
|
|
15
|
+
SYSTEM_HR_AGENT_ID = 'employee.bole'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def coordinator_profile() -> ProjectAgentProfile:
|
|
19
|
+
return ProjectAgentProfile(
|
|
20
|
+
name='Jefa',
|
|
21
|
+
occupation_emoji='🧭',
|
|
22
|
+
responsibility='项目经理:拆解目标、维护看板与进展,并为任务选择合适的 Agent。',
|
|
23
|
+
agent_type='coordinator',
|
|
24
|
+
work_kinds=['project_management', 'planning', 'review', 'task-coordination'],
|
|
25
|
+
capabilities=['项目规划', '任务拆解', '看板读写', 'Agent 路由', 'fuli.employee:jefa'],
|
|
26
|
+
initial_preferences=[
|
|
27
|
+
'质量与可验收完成优先于成本和时间。',
|
|
28
|
+
'Agent 认为完成时只移入待确认,最终完成由用户决定。',
|
|
29
|
+
],
|
|
30
|
+
status='active',
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def hr_profile() -> ProjectAgentProfile:
|
|
35
|
+
return ProjectAgentProfile(
|
|
36
|
+
name='Bole',
|
|
37
|
+
occupation_emoji='🔎',
|
|
38
|
+
responsibility='HR:维护 Agent 人员分布与工作状态,按需招募并保留招募记录。',
|
|
39
|
+
agent_type='hr',
|
|
40
|
+
work_kinds=['agent-recruitment', 'staffing-review'],
|
|
41
|
+
capabilities=['Agent 招募', '人员分布', '工作状态', '招募审计', 'fuli.employee:bole'],
|
|
42
|
+
initial_preferences=[
|
|
43
|
+
'每次招募保留任务、原因、触发来源与时间线。',
|
|
44
|
+
'只展示 Provider 已记录的人员状态,不推测未上报的工作。',
|
|
45
|
+
],
|
|
46
|
+
status='active',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
SYSTEM_PROFILES = {
|
|
51
|
+
SYSTEM_COORDINATOR_AGENT_ID: coordinator_profile,
|
|
52
|
+
SYSTEM_HR_AGENT_ID: hr_profile,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
async def ensure_system_identity(driver, provider_id, space_id, agent_id):
|
|
57
|
+
"""Create the fixed role once; an existing identity keeps the user's edits.
|
|
58
|
+
|
|
59
|
+
A Jefa recruited before it became a fixed role is adopted in place, keeping
|
|
60
|
+
its profile, assignments, memory and history.
|
|
61
|
+
"""
|
|
62
|
+
default = SYSTEM_PROFILES[agent_id]()
|
|
63
|
+
node_id = stable_uuid(provider_id, space_id, 'project-agent', agent_id)
|
|
64
|
+
rows, _, _ = await driver.execute_query(
|
|
65
|
+
'MATCH (agent:FuliProjectAgent {id: $id}) RETURN agent.profile_json AS profile_json',
|
|
66
|
+
id=node_id,
|
|
67
|
+
)
|
|
68
|
+
profile = default
|
|
69
|
+
if rows and rows[0]['profile_json']:
|
|
70
|
+
stored = json.loads(rows[0]['profile_json'])
|
|
71
|
+
profile = ProjectAgentProfile.model_validate(
|
|
72
|
+
{**stored, 'agent_type': default.agent_type, 'status': 'active'}
|
|
73
|
+
)
|
|
74
|
+
now = now_utc()
|
|
75
|
+
await driver.execute_query(
|
|
76
|
+
'''
|
|
77
|
+
MATCH (space:FuliSpace {id: $space_id, kind: 'personal'})
|
|
78
|
+
MERGE (agent:FuliProjectAgent {id: $id})
|
|
79
|
+
ON CREATE SET agent.agent_id = $agent_id,
|
|
80
|
+
agent.name = $name,
|
|
81
|
+
agent.occupation_emoji = $occupation_emoji,
|
|
82
|
+
agent.responsibility = $responsibility,
|
|
83
|
+
agent.capabilities = $capabilities,
|
|
84
|
+
agent.work_kinds = $work_kinds,
|
|
85
|
+
agent.memory_scope = 'reviewed_agent',
|
|
86
|
+
agent.created_at = $now,
|
|
87
|
+
agent.updated_at = $now
|
|
88
|
+
SET agent.profile_json = $profile_json,
|
|
89
|
+
agent.agent_type = $agent_type,
|
|
90
|
+
agent.status = 'active',
|
|
91
|
+
agent.system_managed = true
|
|
92
|
+
MERGE (space)-[:HAS_PROJECT_AGENT_IDENTITY]->(agent)
|
|
93
|
+
''',
|
|
94
|
+
space_id=space_id,
|
|
95
|
+
id=node_id,
|
|
96
|
+
agent_id=agent_id,
|
|
97
|
+
profile_json=profile.model_dump_json(),
|
|
98
|
+
name=profile.name,
|
|
99
|
+
occupation_emoji=profile.occupation_emoji,
|
|
100
|
+
responsibility=profile.responsibility,
|
|
101
|
+
capabilities=profile.capabilities,
|
|
102
|
+
work_kinds=profile.work_kinds,
|
|
103
|
+
agent_type=profile.agent_type,
|
|
104
|
+
now=now,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
async def retire_legacy_coordinator(driver, space_id):
|
|
109
|
+
await driver.execute_query(
|
|
110
|
+
'''
|
|
111
|
+
MATCH (:FuliSpace {id: $space_id, kind: 'personal'})-[:HAS_PROJECT_AGENT_IDENTITY]->
|
|
112
|
+
(agent:FuliProjectAgent {agent_id: $legacy_id})
|
|
113
|
+
WHERE agent.status <> 'archived'
|
|
114
|
+
SET agent.status = 'archived',
|
|
115
|
+
agent.superseded_by = $canonical_id,
|
|
116
|
+
agent.updated_at = $now
|
|
117
|
+
''',
|
|
118
|
+
space_id=space_id,
|
|
119
|
+
legacy_id=LEGACY_COORDINATOR_AGENT_ID,
|
|
120
|
+
canonical_id=SYSTEM_COORDINATOR_AGENT_ID,
|
|
121
|
+
now=now_utc(),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
async def ensure_system_agents(driver, provider_id, space_id):
|
|
126
|
+
for agent_id in SYSTEM_PROFILES:
|
|
127
|
+
await ensure_system_identity(driver, provider_id, space_id, agent_id)
|
|
128
|
+
await retire_legacy_coordinator(driver, space_id)
|
|
@@ -12,8 +12,8 @@ from fastapi import HTTPException
|
|
|
12
12
|
|
|
13
13
|
from .project_agent_models import ProjectAgentProfile
|
|
14
14
|
from .provider_values import now_utc
|
|
15
|
+
from .system_agents import SYSTEM_HR_AGENT_ID
|
|
15
16
|
|
|
16
|
-
SYSTEM_HR_AGENT_ID = 'employee.bole'
|
|
17
17
|
LEGACY_HR_AGENT_ID = 'fuli-project-hr'
|
|
18
18
|
REFERENCE_FIELDS = (
|
|
19
19
|
'agent_id', 'hr_agent_id', 'lead_agent_id', 'coordinator_agent_id',
|
|
@@ -7,6 +7,16 @@ from .task_context_models import TaskContextBegin, TaskContextCheckpoint, TaskCo
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def register_task_context_routes(application, store, Actor):
|
|
10
|
+
@application.get('/v1/task-context-sessions/recent')
|
|
11
|
+
async def recent_sessions(actor: Actor,
|
|
12
|
+
personal_space_id: Annotated[str, Query(min_length=1, max_length=128)],
|
|
13
|
+
project_agent_id: Annotated[str, Query(min_length=1, max_length=128)],
|
|
14
|
+
personal_project_id: Annotated[str | None, Query(min_length=1, max_length=128)] = None,
|
|
15
|
+
limit: Annotated[int, Query(ge=1, le=20)] = 5):
|
|
16
|
+
return await store.recent_agent_sessions(
|
|
17
|
+
actor, personal_space_id, project_agent_id, personal_project_id, limit,
|
|
18
|
+
)
|
|
19
|
+
|
|
10
20
|
@application.get('/v1/task-context-sessions/current')
|
|
11
21
|
async def current_context(actor: Actor,
|
|
12
22
|
personal_space_id: Annotated[str, Query(min_length=1, max_length=128)],
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fuli-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "fuli-context",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.11.0",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@a2a-js/sdk": "1.3.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fuli-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Local-first collaboration relationship graph for AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -14,9 +14,7 @@
|
|
|
14
14
|
"docs/agent-conversations-and-collaboration.md",
|
|
15
15
|
"docs/employee-agents.md",
|
|
16
16
|
"docs/agent-interface-architecture.md",
|
|
17
|
-
"docs/roundtable
|
|
18
|
-
"docs/roundtable-beta-validation.md",
|
|
19
|
-
"docs/roundtable-research.md",
|
|
17
|
+
"docs/agent-roundtable.md",
|
|
20
18
|
"examples/external-knowledge/markdown-folder.mjs",
|
|
21
19
|
"graph-provider/Dockerfile",
|
|
22
20
|
"graph-provider/pyproject.toml",
|
|
@@ -288,7 +288,7 @@ worker session (`workerRuntime.sessionId`, or a worker session link only when su
|
|
|
288
288
|
Label `sourceApplication` and `sourceSessionId` separately as the reporting host. They do not
|
|
289
289
|
identify an external worker; do not substitute them for missing worker evidence.
|
|
290
290
|
Use only the source-labelled cumulative `tokenUsage` reported for that worker. If it is absent,
|
|
291
|
-
show
|
|
291
|
+
show `-`; never estimate it or copy a conversation-wide total into a worker row. If no
|
|
292
292
|
worker session link exists, show `workerRuntime.sessionId` or `not reported`; never invent a link. This applies only
|
|
293
293
|
to Provider-reported actual workers. When empty `executionSummary` is returned, omit rows; an absent
|
|
294
294
|
`executionSummary` also omits rows. Configured, allowed, or available clients/executors are not evidence
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { sendJson } from '../http/response.js';
|
|
2
|
+
|
|
3
|
+
// Read-only console view of Agent-to-Agent threads.
|
|
4
|
+
export async function handleRoundtableApiRequest({ request, response, url, roundtable }) {
|
|
5
|
+
if (!roundtable || request.method !== 'GET') return false;
|
|
6
|
+
if (url.pathname === '/api/roundtable/threads') {
|
|
7
|
+
sendJson(response, 200, roundtable.threads({ limit: Math.min(Number(url.searchParams.get('limit')) || 50, 200) }));
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
const match = /^\/api\/roundtable\/threads\/([^/]+)$/.exec(url.pathname);
|
|
11
|
+
if (!match) return false;
|
|
12
|
+
sendJson(response, 200, roundtable.thread({ threadId: decodeURIComponent(match[1]) }));
|
|
13
|
+
return true;
|
|
14
|
+
}
|