fuli-context 0.7.4-beta.3 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +77 -6
  2. package/README.zh-CN.md +69 -6
  3. package/compose.graphiti.yml +6 -6
  4. package/dist/web/assets/AboutPage-sLV9WChi.js +1 -0
  5. package/dist/web/assets/ConnectionsPage-BWn4ywGJ.js +1 -0
  6. package/dist/web/assets/KnowledgeEditDialog-CZ5ziPrD.js +1 -0
  7. package/dist/web/assets/KnowledgeInspector-CRQWOaos.js +1 -0
  8. package/dist/web/assets/KnowledgeOrganizerPage-Dfj3vIpU.js +1 -0
  9. package/dist/web/assets/KnowledgePage-BRYC9S5Y.js +1 -0
  10. package/dist/web/assets/KnowledgeWorkspace-ChEB5Bwk.js +4 -0
  11. package/dist/web/assets/OverviewPage-Cd66M0RT.js +1 -0
  12. package/dist/web/assets/PersonalProfilePage-RCFHL0Wz.js +1 -0
  13. package/dist/web/assets/PersonalProjectsPage-DEh8XWby.js +1 -0
  14. package/dist/web/assets/ProjectAgentsPage-Crh7PrXa.css +1 -0
  15. package/dist/web/assets/ProjectAgentsPage-DPnaH-TR.js +11 -0
  16. package/dist/web/assets/PublicProjectsPage-mstPEjHe.js +1 -0
  17. package/dist/web/assets/ReviewPage-6Y1SmfZy.js +1 -0
  18. package/dist/web/assets/SearchableSelect-D3HM8YF8.js +1 -0
  19. package/dist/web/assets/SettingsPage--LdTMUm7.js +1 -0
  20. package/dist/web/assets/SettingsPage-CwZp2ka4.css +1 -0
  21. package/dist/web/assets/WritingTastePage-CIpKswvs.js +1 -0
  22. package/dist/web/assets/{console-D_2zC4lm.js → console-BT1P2Db4.js} +1 -1
  23. package/dist/web/assets/{conversation-launcher-settings-DQmMH2j7.js → conversation-launcher-settings-DrJEotdf.js} +1 -1
  24. package/dist/web/assets/i18n-js6gfc7j.js +9 -0
  25. package/dist/web/assets/{identity-DmGcY3Y6.js → identity-CfDfanpa.js} +1 -1
  26. package/dist/web/assets/index-BnH5mcZx.css +1 -0
  27. package/dist/web/assets/index-GqJf1xqg.js +2 -0
  28. package/dist/web/assets/{model-CVoOdRsL.js → model-DJkLAJsg.js} +1 -1
  29. package/dist/web/assets/{useApi-CROJJdhE-CBNg4CdH.js → useApi-CROJJdhE-BdSti7Y2.js} +1 -1
  30. package/dist/web/assets/vue-router-Kk67EaCP.js +1 -0
  31. package/dist/web/index.html +6 -6
  32. package/graph-provider/fuli_graph/app.py +8 -0
  33. package/graph-provider/fuli_graph/collaboration_context.py +69 -6
  34. package/graph-provider/fuli_graph/knowledge_search.py +84 -5
  35. package/graph-provider/fuli_graph/model_validation.py +130 -0
  36. package/graph-provider/fuli_graph/models.py +24 -5
  37. package/graph-provider/fuli_graph/project_agent_access.py +54 -0
  38. package/graph-provider/fuli_graph/project_agent_coordination_models.py +22 -0
  39. package/graph-provider/fuli_graph/project_agent_executor_models.py +635 -0
  40. package/graph-provider/fuli_graph/project_agent_models.py +278 -0
  41. package/graph-provider/fuli_graph/project_agent_routes.py +626 -0
  42. package/graph-provider/fuli_graph/project_agent_task_models.py +545 -0
  43. package/graph-provider/fuli_graph/runtime.py +259 -0
  44. package/graph-provider/fuli_graph/search_projection.py +3 -0
  45. package/graph-provider/fuli_graph/store.py +6 -0
  46. package/graph-provider/fuli_graph/store_knowledge.py +62 -9
  47. package/graph-provider/fuli_graph/store_project_agent_coordination_policy.py +122 -0
  48. package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +756 -0
  49. package/graph-provider/fuli_graph/store_project_agent_executor_routing.py +601 -0
  50. package/graph-provider/fuli_graph/store_project_agent_executors.py +1087 -0
  51. package/graph-provider/fuli_graph/store_project_agent_task_reads.py +458 -0
  52. package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +705 -0
  53. package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +586 -0
  54. package/graph-provider/fuli_graph/store_project_agent_tasks.py +1151 -0
  55. package/graph-provider/fuli_graph/store_project_agents.py +965 -0
  56. package/graph-provider/pyproject.toml +2 -1
  57. package/npm-shrinkwrap.json +2 -2
  58. package/package.json +1 -1
  59. package/skills/capturing-session-knowledge/SKILL.md +39 -0
  60. package/src/adaptive-runtime/executor-pool.js +127 -0
  61. package/src/adaptive-runtime/graph-services.js +166 -0
  62. package/src/adaptive-runtime/lease-client.js +335 -0
  63. package/src/adaptive-runtime/runtime-broker.js +318 -0
  64. package/src/adaptive-runtime/settings.js +111 -0
  65. package/src/adaptive-runtime/state.js +74 -0
  66. package/src/agent-tools/graph-definitions.js +419 -0
  67. package/src/agent-tools/graph-handlers.js +65 -0
  68. package/src/agent-tools/project-agent-definitions.js +307 -0
  69. package/src/backup/graph-backup.js +289 -0
  70. package/src/backup/identity-reconciliation.js +208 -0
  71. package/src/backup/runtime-adapters.js +269 -0
  72. package/src/cli/command-registry.js +6 -2
  73. package/src/cli/graph-data-command.js +112 -0
  74. package/src/cli/local-runtime-command.js +16 -2
  75. package/src/cli/setup-command.js +19 -3
  76. package/src/cli/update-command.js +4 -0
  77. package/src/cli.js +6 -0
  78. package/src/graphiti/collaboration-preference-projection.js +29 -1
  79. package/src/graphiti/collaboration-preference-workflow.js +121 -0
  80. package/src/graphiti/federated-application.js +53 -90
  81. package/src/graphiti/project-agent-control-plane.js +275 -0
  82. package/src/graphiti/project-agent-mapping.js +1024 -0
  83. package/src/graphiti/project-agent-workflows.js +576 -0
  84. package/src/graphiti/provider-client.js +282 -1
  85. package/src/http/api-router.js +63 -9
  86. package/src/http/graph-api-router.js +290 -0
  87. package/src/local-runtime/lifecycle.js +46 -10
  88. package/src/mcp/context-resources.js +15 -6
  89. package/src/mcp/create-mcp-server.js +51 -16
  90. package/src/mcp/instructions.js +7 -5
  91. package/src/mcp/runtime.js +17 -5
  92. package/src/mcp/session-id.js +38 -1
  93. package/src/mcp/tool-annotations.js +71 -0
  94. package/src/mcp-server.js +23 -6
  95. package/src/native-runtime/runtime.js +717 -0
  96. package/src/server.js +6 -2
  97. package/src/setup/agent-installation-status.js +7 -1
  98. package/src/setup/agents.js +3 -1
  99. package/src/setup/claude-code-config.js +3 -1
  100. package/src/setup/codex-bootstrap.js +11 -10
  101. package/src/setup/codex-config.js +7 -1
  102. package/src/setup/cursor-config.js +3 -1
  103. package/src/setup/graph-runtime.js +158 -13
  104. package/src/setup/neo4j-memory-profile.js +43 -0
  105. package/src/setup/options.js +38 -2
  106. package/src/setup/paths.js +14 -0
  107. package/src/setup/setup.js +37 -1
  108. package/src/system/resource-monitor.js +181 -16
  109. package/src/system/runtime-settings.js +10 -1
  110. package/src/system/system-service.js +27 -2
  111. package/dist/web/assets/AboutPage-Dpf5fRWv.js +0 -1
  112. package/dist/web/assets/ConnectionsPage-D21aUDCP.js +0 -1
  113. package/dist/web/assets/KnowledgeEditDialog-u7lpfN3j.js +0 -1
  114. package/dist/web/assets/KnowledgeInspector-k4xnHtXd.js +0 -1
  115. package/dist/web/assets/KnowledgeOrganizerPage-Bdj7Rn84.js +0 -1
  116. package/dist/web/assets/KnowledgePage-UHVAbC1W.js +0 -1
  117. package/dist/web/assets/KnowledgeWorkspace-Lq3d-MeC.js +0 -4
  118. package/dist/web/assets/OverviewPage-CycAgA1V.js +0 -1
  119. package/dist/web/assets/PersonalProfilePage-U9oIV5FT.js +0 -1
  120. package/dist/web/assets/PersonalProjectsPage-C5RpXKcA.js +0 -1
  121. package/dist/web/assets/PublicProjectsPage-DiWxm35E.js +0 -1
  122. package/dist/web/assets/ReviewPage-jxRfGSJK.js +0 -1
  123. package/dist/web/assets/SearchableSelect-B3-5IPup.js +0 -1
  124. package/dist/web/assets/SettingsPage-BqfGDOho.js +0 -1
  125. package/dist/web/assets/SettingsPage-CAfz4qiV.css +0 -1
  126. package/dist/web/assets/WritingTastePage-BJxhMqJR.js +0 -1
  127. package/dist/web/assets/i18n-CwqXDI1C.js +0 -5
  128. package/dist/web/assets/index-IUGLt4lG.js +0 -2
  129. package/dist/web/assets/index-X2j29j8i.css +0 -1
  130. package/dist/web/assets/vue-router-CWSsUUio.js +0 -1
@@ -0,0 +1,576 @@
1
+ import {
2
+ executorActualReportRecord,
3
+ executorRecord,
4
+ executorRoutingRuleRecord,
5
+ projectAgentActivityRecord,
6
+ projectAgentAssignmentRecord,
7
+ projectAgentCoordinationPolicyRecord,
8
+ projectAgentRecruitmentPolicyRecord,
9
+ projectAgentRecruitmentRecord,
10
+ projectAgentTaskRecord,
11
+ projectAgentTaskOutcomeRecord,
12
+ projectAgentTaskRouteResult,
13
+ providerExecutor,
14
+ providerExecutorActualReport,
15
+ providerExecutorAuthorization,
16
+ providerExecutorHealth,
17
+ providerExecutorPreflight,
18
+ providerExecutorRoutingRule,
19
+ providerExecutorRoutingRuleUpdate,
20
+ providerModelStrategy,
21
+ providerProjectAgentAssignment,
22
+ providerProjectAgentAssignmentEnd,
23
+ providerProjectAgentAssignmentReplace,
24
+ providerProjectAgentCoordinationPolicy,
25
+ providerProjectAgentRecruitmentDecision,
26
+ providerProjectAgentTaskActivity,
27
+ providerProjectAgentTaskOutcome,
28
+ providerProjectAgentTaskSubmit,
29
+ projectAgentRecord,
30
+ providerProjectAgentProfile,
31
+ routingLearningRecord
32
+ } from './project-agent-mapping.js';
33
+
34
+ export async function upsertProjectAgent(application, input) {
35
+ const value = await application.personal.upsertProjectAgent({
36
+ personal_space_id: input.personalSpaceId,
37
+ personal_project_id: input.personalProjectId ?? null,
38
+ agent_id: input.agentId,
39
+ profile: providerProjectAgentProfile(input.profile)
40
+ });
41
+ return projectAgentRecord(value);
42
+ }
43
+
44
+ export async function listProjectAgents(application, input) {
45
+ const value = await application.personal.listProjectAgents(
46
+ input.personalSpaceId,
47
+ input.personalProjectId,
48
+ {
49
+ status: input.status ?? null,
50
+ capability: input.capability ?? null
51
+ }
52
+ );
53
+ return asList(value, ['agents', 'items']).map(projectAgentRecord);
54
+ }
55
+
56
+ export async function listCurrentProjectAgents(
57
+ application,
58
+ projectResolution,
59
+ input
60
+ ) {
61
+ const projectId = projectResolution.personal_project_id;
62
+ if (!projectId) {
63
+ return {
64
+ status: 'project_unresolved',
65
+ personal_space_id: application.config.personal.spaceId,
66
+ personal_project_id: null,
67
+ project_resolution: projectResolution,
68
+ agents: []
69
+ };
70
+ }
71
+ return {
72
+ status: 'listed',
73
+ personal_space_id: application.config.personal.spaceId,
74
+ personal_project_id: projectId,
75
+ project_resolution: projectResolution,
76
+ agents: await listProjectAgents(application, {
77
+ personalSpaceId: application.config.personal.spaceId,
78
+ personalProjectId: projectId,
79
+ status: input.status,
80
+ capability: input.capability
81
+ })
82
+ };
83
+ }
84
+
85
+ export async function getProjectAgent(application, input) {
86
+ return projectAgentRecord(await application.personal.getProjectAgent(
87
+ input.personalSpaceId,
88
+ input.personalProjectId,
89
+ input.agentId
90
+ ));
91
+ }
92
+
93
+ export async function deleteProjectAgent(application, input) {
94
+ return projectAgentRecord(await application.personal.deleteProjectAgent(
95
+ input.personalSpaceId,
96
+ input.agentId,
97
+ input.reason
98
+ ));
99
+ }
100
+
101
+ export async function cleanupProjectAgentTestRoles(application, input) {
102
+ return application.personal.cleanupProjectAgentTestRoles(
103
+ input.personalSpaceId,
104
+ input.testSource
105
+ );
106
+ }
107
+
108
+ export async function createProjectAgentAssignment(application, input) {
109
+ const value = await application.personal.createProjectAgentAssignment(
110
+ providerProjectAgentAssignment(input)
111
+ );
112
+ return projectAgentAssignmentRecord(value);
113
+ }
114
+
115
+ export async function listProjectAgentAssignments(application, input) {
116
+ const value = await application.personal.listProjectAgentAssignments({
117
+ personalSpaceId: input.personalSpaceId,
118
+ personalProjectId: input.personalProjectId ?? null,
119
+ agentId: input.agentId ?? null,
120
+ status: input.status ?? null
121
+ });
122
+ return asList(value, ['assignments', 'items']).map(projectAgentAssignmentRecord);
123
+ }
124
+
125
+ export async function endProjectAgentAssignment(application, input) {
126
+ const value = await application.personal.endProjectAgentAssignment(
127
+ providerProjectAgentAssignmentEnd(input)
128
+ );
129
+ return projectAgentAssignmentRecord(value);
130
+ }
131
+
132
+ export async function replaceProjectAgentAssignment(application, input) {
133
+ const value = await application.personal.replaceProjectAgentAssignment(
134
+ providerProjectAgentAssignmentReplace(input)
135
+ );
136
+ return {
137
+ ended: projectAgentAssignmentRecord(value.ended),
138
+ replacement: projectAgentAssignmentRecord(value.replacement)
139
+ };
140
+ }
141
+
142
+ export async function submitProjectAgentTask(application, input) {
143
+ const value = await application.personal.submitProjectAgentTask(
144
+ providerProjectAgentTaskSubmit(input)
145
+ );
146
+ return projectAgentTaskRouteResult(value);
147
+ }
148
+
149
+ export async function coordinateProjectAgentTask(
150
+ application,
151
+ projectResolution,
152
+ input
153
+ ) {
154
+ const projectId = projectResolution.personalProjectId ??
155
+ projectResolution.personal_project_id ?? null;
156
+ if (!projectId) {
157
+ return {
158
+ status: 'project_unresolved',
159
+ personal_space_id: application.config.personal.spaceId,
160
+ personal_project_id: null,
161
+ project_resolution: projectResolution,
162
+ required_action: projectResolution.status === 'ambiguous'
163
+ ? 'Run from the exact project directory; Fuli will not guess among workspace children.'
164
+ : 'Register this repository or directory as one local personal project first.',
165
+ host_execution_required: false,
166
+ worker_plan: []
167
+ };
168
+ }
169
+
170
+ const route = await submitProjectAgentTask(application, {
171
+ personalSpaceId: application.config.personal.spaceId,
172
+ personalProjectId: projectId,
173
+ idempotencyKey: input.idempotencyKey,
174
+ title: input.title,
175
+ objective: input.objective,
176
+ workKind: input.workKind,
177
+ requiredCapabilities: input.requiredCapabilities,
178
+ duration: input.duration,
179
+ staffingIntent: input.staffingIntent,
180
+ leadAgentId: input.leadAgentId,
181
+ collaboratorAgentIds: input.collaboratorAgentIds,
182
+ coordinatorAgentId: input.coordinatorAgentId,
183
+ complexityHint: input.complexityHint,
184
+ parallelPlan: input.parallelPlan,
185
+ modelStrategyOverride: input.modelStrategyOverride,
186
+ executorPolicyOverride: input.executorPolicyOverride,
187
+ sourceApplication: input.sourceApplication,
188
+ sourceSessionId: input.sourceSessionId,
189
+ routingReason: input.routingReason,
190
+ recruitmentProfile: input.recruitmentProfile
191
+ });
192
+ const participants = route.task.participants ?? [];
193
+ const boundaries = route.task.routingDecision?.parallelPlan?.workstreamBoundaries ?? [];
194
+ const contexts = await Promise.all(participants.map((participant) => (
195
+ getProjectAgentContext(application, projectResolution, {
196
+ agentId: participant.agentId,
197
+ queries: input.contextQueries,
198
+ limitPerQuery: input.contextLimitPerQuery ?? 8,
199
+ includePending: input.includePendingContext ?? false,
200
+ sourceApplication: input.sourceApplication
201
+ })
202
+ )));
203
+ const workerPlan = participants.map((participant, index) => ({
204
+ agent_id: participant.agentId,
205
+ participant_role: participant.role,
206
+ assignment_summary: participant.assignmentSummary ?? null,
207
+ workstream_boundary: boundaries[index] ?? null,
208
+ context_status: contexts[index]?.status ?? 'unavailable',
209
+ context: contexts[index]
210
+ }));
211
+ const contextsReady = workerPlan.every(({ context_status: status }) => status === 'ready');
212
+ const hostExecutionRequired = route.task.status === 'queued' &&
213
+ workerPlan.length > 0 && contextsReady;
214
+
215
+ return {
216
+ status: hostExecutionRequired
217
+ ? 'ready_for_host_execution'
218
+ : route.task.status === 'awaiting_recruitment'
219
+ ? 'awaiting_recruitment'
220
+ : route.task.status === 'blocked'
221
+ ? 'blocked'
222
+ : 'context_unavailable',
223
+ personal_space_id: application.config.personal.spaceId,
224
+ personal_project_id: projectId,
225
+ project_resolution: projectResolution,
226
+ route,
227
+ host_execution_required: hostExecutionRequired,
228
+ host_execution_policy: {
229
+ fuli_is_control_plane_only: true,
230
+ start_only_returned_workers: true,
231
+ report_worker_start_and_terminal_events: true,
232
+ report_actual_executor_only_after_real_use: true,
233
+ release_runtime_lease_in_finally: true
234
+ },
235
+ worker_plan: workerPlan,
236
+ unassigned_workstream_boundaries: boundaries.slice(workerPlan.length)
237
+ };
238
+ }
239
+
240
+ export async function listProjectAgentTasks(application, input) {
241
+ const value = await application.personal.listProjectAgentTasks({
242
+ personalSpaceId: input.personalSpaceId,
243
+ personalProjectId: input.personalProjectId ?? null,
244
+ agentId: input.agentId ?? null,
245
+ status: input.status ?? null,
246
+ limit: input.limit ?? null
247
+ });
248
+ return asList(value, ['tasks', 'items']).map(projectAgentTaskRecord);
249
+ }
250
+
251
+ export async function viewProjectAgentTask(application, input) {
252
+ const value = await application.personal.viewProjectAgentTask(
253
+ input.personalSpaceId,
254
+ input.taskId,
255
+ { includeEvents: input.includeEvents ?? true }
256
+ );
257
+ return projectAgentTaskRecord(value.task ?? value);
258
+ }
259
+
260
+ export async function recordProjectAgentTaskActivity(application, input) {
261
+ const value = await application.personal.recordProjectAgentTaskActivity(
262
+ providerProjectAgentTaskActivity(input)
263
+ );
264
+ return value?.task ? projectAgentTaskRecord(value.task) : projectAgentTaskRecord(value);
265
+ }
266
+
267
+ export async function viewProjectAgentActivity(application, input) {
268
+ const value = await application.personal.listProjectAgentActivity({
269
+ personalSpaceId: input.personalSpaceId,
270
+ agentId: input.agentId,
271
+ fromDate: input.fromDate ?? null,
272
+ toDate: input.toDate ?? null
273
+ });
274
+ return projectAgentActivityRecord(value);
275
+ }
276
+
277
+ export async function getProjectAgentCoordinationPolicy(application, input) {
278
+ return projectAgentCoordinationPolicyRecord(
279
+ await application.personal.getProjectAgentCoordinationPolicy(
280
+ input.personalSpaceId,
281
+ input.personalProjectId
282
+ )
283
+ );
284
+ }
285
+
286
+ export async function updateProjectAgentCoordinationPolicy(application, input) {
287
+ return projectAgentCoordinationPolicyRecord(
288
+ await application.personal.updateProjectAgentCoordinationPolicy(
289
+ providerProjectAgentCoordinationPolicy(input)
290
+ )
291
+ );
292
+ }
293
+
294
+ export async function getProjectAgentRecruitmentPolicy(application, input) {
295
+ return projectAgentRecruitmentPolicyRecord(
296
+ await application.personal.getProjectAgentRecruitmentPolicy(input.personalSpaceId)
297
+ );
298
+ }
299
+
300
+ export async function updateProjectAgentRecruitmentPolicy(application, input) {
301
+ return projectAgentRecruitmentPolicyRecord(
302
+ await application.personal.updateProjectAgentRecruitmentPolicy({
303
+ personal_space_id: input.personalSpaceId,
304
+ confirmation_mode: input.confirmationMode
305
+ })
306
+ );
307
+ }
308
+
309
+ export async function listProjectAgentRecruitments(application, input) {
310
+ const value = await application.personal.listProjectAgentRecruitments({
311
+ personalSpaceId: input.personalSpaceId,
312
+ personalProjectId: input.personalProjectId ?? null,
313
+ taskId: input.taskId ?? null,
314
+ status: input.status ?? null
315
+ });
316
+ return asList(value, ['recruitments', 'items']).map(projectAgentRecruitmentRecord);
317
+ }
318
+
319
+ export async function decideProjectAgentRecruitment(application, input) {
320
+ const value = await application.personal.decideProjectAgentRecruitment(
321
+ providerProjectAgentRecruitmentDecision(input)
322
+ );
323
+ return projectAgentRecruitmentRecord(
324
+ value?.recruitment ?? value?.record ?? value
325
+ );
326
+ }
327
+
328
+ export async function upsertExecutor(application, input) {
329
+ return executorRecord(await application.personal.upsertExecutor(providerExecutor(input)));
330
+ }
331
+
332
+ export async function listExecutors(application, input) {
333
+ const value = await application.personal.listExecutors(input.personalSpaceId, {
334
+ capability: input.capability ?? null,
335
+ availableOnly: input.availableOnly ?? false
336
+ });
337
+ return asList(value, ['executors', 'items']).map(executorRecord);
338
+ }
339
+
340
+ export async function getExecutor(application, input) {
341
+ return executorRecord(await application.personal.getExecutor(
342
+ input.personalSpaceId,
343
+ input.executorId
344
+ ));
345
+ }
346
+
347
+ export async function deleteExecutor(application, input) {
348
+ return application.personal.deleteExecutor(input.personalSpaceId, input.executorId);
349
+ }
350
+
351
+ export async function preflightExecutor(application, input) {
352
+ return executorRecord(await application.personal.preflightExecutor(
353
+ providerExecutorPreflight(input)
354
+ ));
355
+ }
356
+
357
+ export async function authorizeExecutor(application, input) {
358
+ return executorRecord(await application.personal.authorizeExecutor(
359
+ providerExecutorAuthorization(input)
360
+ ));
361
+ }
362
+
363
+ export async function reportExecutorHealth(application, input) {
364
+ return executorRecord(await application.personal.reportExecutorHealth(
365
+ providerExecutorHealth(input)
366
+ ));
367
+ }
368
+
369
+ export async function recordProjectAgentExecutorActual(application, input) {
370
+ return executorActualReportRecord(
371
+ await application.personal.recordProjectAgentExecutorActual(
372
+ providerExecutorActualReport(input)
373
+ )
374
+ );
375
+ }
376
+
377
+ export async function upsertExecutorRoutingRule(application, input) {
378
+ return executorRoutingRuleRecord(
379
+ await application.personal.upsertExecutorRoutingRule(
380
+ providerExecutorRoutingRule(input)
381
+ )
382
+ );
383
+ }
384
+
385
+ export async function updateExecutorRoutingRule(application, input) {
386
+ return executorRoutingRuleRecord(
387
+ await application.personal.updateExecutorRoutingRule(
388
+ providerExecutorRoutingRuleUpdate(input)
389
+ )
390
+ );
391
+ }
392
+
393
+ export async function listExecutorRoutingRules(application, input) {
394
+ const value = await application.personal.listExecutorRoutingRules({
395
+ personalSpaceId: input.personalSpaceId,
396
+ scope: input.scope ?? null,
397
+ personalProjectId: input.personalProjectId ?? null,
398
+ taskId: input.taskId ?? null,
399
+ status: input.status ?? null,
400
+ enabled: input.enabled ?? null
401
+ });
402
+ return asList(value, ['rules', 'items']).map(executorRoutingRuleRecord);
403
+ }
404
+
405
+ export async function getExecutorRoutingRule(application, input) {
406
+ return executorRoutingRuleRecord(await application.personal.getExecutorRoutingRule(
407
+ input.personalSpaceId,
408
+ input.ruleId
409
+ ));
410
+ }
411
+
412
+ export async function deleteExecutorRoutingRule(application, input) {
413
+ return application.personal.deleteExecutorRoutingRule(
414
+ input.personalSpaceId,
415
+ input.ruleId
416
+ );
417
+ }
418
+
419
+ export async function recordProjectAgentTaskOutcome(application, input) {
420
+ const value = await application.personal.recordProjectAgentTaskOutcome(
421
+ providerProjectAgentTaskOutcome(input)
422
+ );
423
+ return projectAgentTaskOutcomeRecord(value?.evidence ?? value?.record ?? value);
424
+ }
425
+
426
+ export async function listProjectAgentRoutingLearning(application, input) {
427
+ const value = await application.personal.listProjectAgentRoutingLearning({
428
+ personalSpaceId: input.personalSpaceId,
429
+ personalProjectId: input.personalProjectId ?? null,
430
+ workKind: input.workKind ?? null,
431
+ agentId: input.agentId ?? null,
432
+ executorId: input.executorId ?? null
433
+ });
434
+ return asList(value, ['learning', 'evidence', 'items']).map(routingLearningRecord);
435
+ }
436
+
437
+ export async function ignoreProjectAgentRoutingLearning(application, input) {
438
+ return application.personal.ignoreProjectAgentRoutingLearning({
439
+ personal_space_id: input.personalSpaceId,
440
+ personal_project_id: input.personalProjectId,
441
+ agent_id: input.agentId,
442
+ evidence_id: input.evidenceId ?? input.learningId,
443
+ idempotency_key: input.idempotencyKey,
444
+ reason: input.reason
445
+ });
446
+ }
447
+
448
+ export async function resetProjectAgentRoutingLearning(application, input) {
449
+ return application.personal.resetProjectAgentRoutingLearning({
450
+ personal_space_id: input.personalSpaceId,
451
+ personal_project_id: input.personalProjectId,
452
+ work_kind: input.workKind,
453
+ agent_id: input.agentId,
454
+ executor_id: input.executorId,
455
+ model_strategy: providerModelStrategy(input.modelStrategy ?? input.model_strategy ?? {}),
456
+ model_strategy_key: input.modelStrategyKey ?? input.model_strategy_key,
457
+ idempotency_key: input.idempotencyKey,
458
+ reset_at: input.resetAt,
459
+ reason: input.reason
460
+ });
461
+ }
462
+
463
+ export async function getProjectAgentContext(
464
+ application,
465
+ projectResolution,
466
+ {
467
+ agentId,
468
+ queries,
469
+ limitPerQuery = 12,
470
+ includePending = false,
471
+ sourceApplication = 'other'
472
+ }
473
+ ) {
474
+ const projectId = projectResolution.personalProjectId ??
475
+ projectResolution.personal_project_id ?? null;
476
+ if (!projectId) {
477
+ return {
478
+ status: 'project_unresolved',
479
+ personal_space_id: application.config.personal.spaceId,
480
+ personal_project_id: null,
481
+ project_resolution: projectResolution,
482
+ required_action: projectResolution.status === 'ambiguous'
483
+ ? 'Run from the exact project directory; Fuli will not guess among workspace children.'
484
+ : 'Register this repository or directory as one local personal project first.'
485
+ };
486
+ }
487
+
488
+ const agent = await application.getProjectAgent({
489
+ personalSpaceId: application.config.personal.spaceId,
490
+ personalProjectId: projectId,
491
+ agentId
492
+ });
493
+ if (agent.profile.status !== 'active') {
494
+ return {
495
+ status: 'agent_unavailable',
496
+ personal_space_id: application.config.personal.spaceId,
497
+ personal_project_id: projectId,
498
+ project_agent_id: agentId,
499
+ project_resolution: projectResolution,
500
+ agent,
501
+ executionSummary: agent.executionSummary ?? [],
502
+ required_action: 'Choose an active project Agent or reactivate this Agent before use.'
503
+ };
504
+ }
505
+ if (!(agent.profile.allowedClients ?? []).includes(sourceApplication)) {
506
+ return {
507
+ status: 'client_not_allowed',
508
+ personal_space_id: application.config.personal.spaceId,
509
+ personal_project_id: projectId,
510
+ project_agent_id: agentId,
511
+ project_resolution: projectResolution,
512
+ source_application: sourceApplication,
513
+ agent,
514
+ executionSummary: agent.executionSummary ?? [],
515
+ required_action: (
516
+ 'Use a client in this Agent\'s allow-list or update the Agent profile '
517
+ + 'before loading its context.'
518
+ )
519
+ };
520
+ }
521
+
522
+ const [preferences, results] = await Promise.all([
523
+ application.getCollaborationPreferences({
524
+ personalProjectId: projectId,
525
+ projectAgentId: agentId,
526
+ agentInvocation: true,
527
+ agentToolName: 'get_project_agent_context'
528
+ }),
529
+ Promise.all(queries.map((query) => application.searchKnowledge({
530
+ personalSpaceId: application.config.personal.spaceId,
531
+ personalProjectId: projectId,
532
+ projectAgentId: agentId,
533
+ query,
534
+ limit: limitPerQuery,
535
+ includePending,
536
+ agentInvocation: true,
537
+ agentToolName: 'get_project_agent_context'
538
+ })))
539
+ ]);
540
+
541
+ return {
542
+ status: 'ready',
543
+ personal_space_id: application.config.personal.spaceId,
544
+ personal_project_id: projectId,
545
+ project_agent_id: agentId,
546
+ source_application: sourceApplication,
547
+ project_resolution: projectResolution,
548
+ agent,
549
+ executionSummary: agent.executionSummary ?? [],
550
+ role_instructions: {
551
+ responsibility: agent.profile.responsibility,
552
+ initial_preferences: agent.profile.initialPreferences
553
+ },
554
+ effective_preferences: preferences.effective_preferences,
555
+ deferred_conflicts: preferences.deferred_conflicts,
556
+ active_conflicts: preferences.active_conflicts,
557
+ knowledge_results: results,
558
+ scope_policy: {
559
+ includes_personal_global_preferences: true,
560
+ includes_project_preferences_and_shared_knowledge: true,
561
+ includes_only_selected_agent_preferences_and_memory: true,
562
+ excludes_other_project_agents: true,
563
+ inherited_project_relation_types: ['PART_OF', 'USES_KNOWLEDGE_FROM'],
564
+ max_project_inheritance_hops: 2
565
+ }
566
+ };
567
+ }
568
+
569
+ function asList(value, keys = []) {
570
+ if (Array.isArray(value)) return value;
571
+ if (!value || typeof value !== 'object') return [];
572
+ for (const key of keys) {
573
+ if (Array.isArray(value[key])) return value[key];
574
+ }
575
+ return [];
576
+ }