fuli-context 0.7.6 → 0.7.8

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 (150) hide show
  1. package/README.md +69 -13
  2. package/README.zh-CN.md +60 -14
  3. package/dist/web/assets/{AboutPage-sLV9WChi.js → AboutPage-9CVX91tr.js} +1 -1
  4. package/dist/web/assets/{ConnectionsPage-BWn4ywGJ.js → ConnectionsPage-CWbCVFdv.js} +1 -1
  5. package/dist/web/assets/EmployeeRecruitDialog-CQgNpGJ_.js +1 -0
  6. package/dist/web/assets/EmployeeRecruitDialog-CfFlyKSh.css +1 -0
  7. package/dist/web/assets/EmployeeWorkbenchPage-CWg4WJhr.css +1 -0
  8. package/dist/web/assets/EmployeeWorkbenchPage-CwU4qBgD.js +1 -0
  9. package/dist/web/assets/KnowledgeEditDialog-B6TGAcFH.js +1 -0
  10. package/dist/web/assets/{KnowledgeEditDialog-DWUV_NPp.css → KnowledgeEditDialog-iv-dgUeD.css} +1 -1
  11. package/dist/web/assets/{KnowledgeInspector-CRQWOaos.js → KnowledgeInspector-M2pLY0bR.js} +1 -1
  12. package/dist/web/assets/{KnowledgeOrganizerPage-Dfj3vIpU.js → KnowledgeOrganizerPage-DzeAlk9b.js} +1 -1
  13. package/dist/web/assets/KnowledgePage-BJu9w0fF.js +1 -0
  14. package/dist/web/assets/{KnowledgeWorkspace-ChEB5Bwk.js → KnowledgeWorkspace-CCt8rnBb.js} +1 -1
  15. package/dist/web/assets/{OverviewPage-Cd66M0RT.js → OverviewPage-CZswVqui.js} +1 -1
  16. package/dist/web/assets/{PersonalProfilePage-RCFHL0Wz.js → PersonalProfilePage-f1nSF6kx.js} +1 -1
  17. package/dist/web/assets/PersonalProjectsPage-D__eJf0t.js +1 -0
  18. package/dist/web/assets/ProjectAgentsPage-C3vW6wmk.css +1 -0
  19. package/dist/web/assets/ProjectAgentsPage-LrwagMGj.js +11 -0
  20. package/dist/web/assets/{PublicProjectsPage-mstPEjHe.js → PublicProjectsPage-BdC2Qk4n.js} +1 -1
  21. package/dist/web/assets/{ReviewPage-6Y1SmfZy.js → ReviewPage-Cbgl8_Si.js} +1 -1
  22. package/dist/web/assets/SearchableSelect-ERm-k4KI.js +1 -0
  23. package/dist/web/assets/{SettingsPage--LdTMUm7.js → SettingsPage-DWso4x29.js} +1 -1
  24. package/dist/web/assets/{WritingTastePage-CIpKswvs.js → WritingTastePage-CFpCjmIY.js} +1 -1
  25. package/dist/web/assets/catalog-WGLn7ERJ.js +1 -0
  26. package/dist/web/assets/{console-BT1P2Db4.js → console-DQgu0JIA.js} +1 -1
  27. package/dist/web/assets/conversation-launcher-settings-0KtlG_LV.js +1 -0
  28. package/dist/web/assets/{i18n-js6gfc7j.js → i18n-ByRiA3pJ.js} +3 -3
  29. package/dist/web/assets/{identity-CfDfanpa.js → identity-CxdPRMwH.js} +1 -1
  30. package/dist/web/assets/index-JAZe6lfX.js +2 -0
  31. package/dist/web/assets/index-wcXzzggp.css +1 -0
  32. package/dist/web/assets/{model-DJkLAJsg.js → model-Db4-KefQ.js} +1 -1
  33. package/dist/web/assets/{useApi-CROJJdhE-BdSti7Y2.js → useApi-CROJJdhE-CePMjc08.js} +1 -1
  34. package/dist/web/assets/{vue-router-Kk67EaCP.js → vue-router-CzX-hn3P.js} +1 -1
  35. package/dist/web/index.html +7 -6
  36. package/docs/employee-agents.md +99 -0
  37. package/docs/project-agent-memory.md +479 -0
  38. package/graph-provider/fuli_graph/knowledge_audit_models.py +171 -0
  39. package/graph-provider/fuli_graph/model_base.py +5 -0
  40. package/graph-provider/fuli_graph/model_validation.py +32 -0
  41. package/graph-provider/fuli_graph/models.py +26 -170
  42. package/graph-provider/fuli_graph/project_agent_context_models.py +29 -0
  43. package/graph-provider/fuli_graph/project_agent_executor_models.py +35 -7
  44. package/graph-provider/fuli_graph/project_agent_memory_models.py +79 -0
  45. package/graph-provider/fuli_graph/project_agent_memory_routes.py +46 -0
  46. package/graph-provider/fuli_graph/project_agent_models.py +9 -0
  47. package/graph-provider/fuli_graph/project_agent_recruitment_values.py +48 -0
  48. package/graph-provider/fuli_graph/project_agent_routes.py +21 -1
  49. package/graph-provider/fuli_graph/project_agent_task_models.py +217 -29
  50. package/graph-provider/fuli_graph/runtime.py +37 -1
  51. package/graph-provider/fuli_graph/store.py +6 -0
  52. package/graph-provider/fuli_graph/store_project_agent_context.py +65 -0
  53. package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +175 -11
  54. package/graph-provider/fuli_graph/store_project_agent_executor_routing.py +33 -10
  55. package/graph-provider/fuli_graph/store_project_agent_executors.py +181 -14
  56. package/graph-provider/fuli_graph/store_project_agent_memory.py +174 -0
  57. package/graph-provider/fuli_graph/store_project_agent_task_activity.py +423 -0
  58. package/graph-provider/fuli_graph/store_project_agent_task_persistence.py +152 -0
  59. package/graph-provider/fuli_graph/store_project_agent_task_reads.py +187 -21
  60. package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +748 -162
  61. package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +230 -18
  62. package/graph-provider/fuli_graph/store_project_agent_tasks.py +261 -468
  63. package/graph-provider/fuli_graph/store_project_agents.py +214 -46
  64. package/graph-provider/fuli_graph/store_task_contexts.py +217 -0
  65. package/graph-provider/fuli_graph/store_transactions.py +40 -0
  66. package/graph-provider/fuli_graph/task_context_models.py +50 -0
  67. package/graph-provider/fuli_graph/task_context_routes.py +31 -0
  68. package/graph-provider/fuli_graph/workflow_observation_models.py +1 -1
  69. package/graph-provider/pyproject.toml +1 -1
  70. package/npm-shrinkwrap.json +8 -8
  71. package/package.json +5 -2
  72. package/skills/capturing-session-knowledge/SKILL.md +18 -6
  73. package/src/adaptive-runtime/executor-pool.js +46 -5
  74. package/src/adaptive-runtime/graph-services.js +10 -3
  75. package/src/adaptive-runtime/lease-client.js +66 -14
  76. package/src/adaptive-runtime/runtime-broker.js +24 -9
  77. package/src/agent-tools/employee-definitions.js +43 -0
  78. package/src/agent-tools/graph-definitions.js +25 -6
  79. package/src/agent-tools/graph-handlers.js +11 -0
  80. package/src/agent-tools/project-agent-definitions.js +35 -4
  81. package/src/agent-tools/project-agent-memory-definitions.js +36 -0
  82. package/src/agent-tools.js +6 -2
  83. package/src/agents/codex/lifecycle-hook.js +107 -0
  84. package/src/agents/codex/lifecycle-hooks.js +231 -0
  85. package/src/agents/cursor/lifecycle-hook.js +133 -0
  86. package/src/agents/cursor/lifecycle-hooks.js +50 -0
  87. package/src/agents/lifecycle-message.js +19 -0
  88. package/src/app/agent-request-context.js +23 -0
  89. package/src/cli/command-registry.js +2 -0
  90. package/src/cli/employee-command.js +17 -0
  91. package/src/cli/remote-mcp-command.js +282 -0
  92. package/src/cli/setup-command.js +5 -0
  93. package/src/cli/update-command.js +6 -43
  94. package/src/cli.js +10 -0
  95. package/src/employees/catalog/jefa.json +21 -0
  96. package/src/employees/install-package.js +77 -0
  97. package/src/employees/management-policy.js +88 -0
  98. package/src/employees/manifest.js +53 -0
  99. package/src/employees/package-registry.js +107 -0
  100. package/src/employees/project-selection.js +50 -0
  101. package/src/employees/recruitment.js +199 -0
  102. package/src/employees/service.js +83 -0
  103. package/src/employees/task-entry.js +39 -0
  104. package/src/graphiti/agent-knowledge-workflows.js +135 -25
  105. package/src/graphiti/federated-application.js +78 -35
  106. package/src/graphiti/project-agent-control-plane.js +20 -3
  107. package/src/graphiti/project-agent-mapping.js +155 -5
  108. package/src/graphiti/project-agent-memory.js +115 -0
  109. package/src/graphiti/project-agent-task-entry.js +126 -0
  110. package/src/graphiti/project-agent-workflows.js +30 -14
  111. package/src/graphiti/provider-client.js +66 -4
  112. package/src/http/api-router.js +30 -5
  113. package/src/http/employee-api-router.js +64 -0
  114. package/src/http/error-mapping.js +4 -0
  115. package/src/http/graph-api-router.js +2 -0
  116. package/src/http/request-policy.js +6 -3
  117. package/src/http/static-handler.js +4 -3
  118. package/src/mcp/create-mcp-server.js +98 -37
  119. package/src/mcp/direct-call.js +38 -0
  120. package/src/mcp/instructions.js +8 -7
  121. package/src/mcp/provider-task-context-registry.js +74 -0
  122. package/src/mcp/remote-http-server.js +761 -0
  123. package/src/mcp/session-id.js +29 -3
  124. package/src/mcp/task-context-registry.js +88 -29
  125. package/src/mcp/tool-annotations.js +10 -2
  126. package/src/mcp/tool-result.js +8 -3
  127. package/src/mcp-server.js +20 -8
  128. package/src/native-runtime/runtime.js +58 -8
  129. package/src/semantic-version.js +42 -0
  130. package/src/server.js +76 -28
  131. package/src/setup/agent-installation-status.js +38 -6
  132. package/src/setup/agents.js +20 -8
  133. package/src/setup/claude-code-config.js +55 -13
  134. package/src/setup/codex-bootstrap.js +11 -10
  135. package/src/setup/codex-config.js +74 -7
  136. package/src/setup/config-backup.js +18 -2
  137. package/src/setup/cursor-config.js +22 -5
  138. package/src/setup/setup.js +30 -22
  139. package/src/storage/json-file.js +11 -3
  140. package/src/system/package-version-checker.js +72 -0
  141. package/src/system/system-service.js +3 -0
  142. package/dist/web/assets/KnowledgeEditDialog-CZ5ziPrD.js +0 -1
  143. package/dist/web/assets/KnowledgePage-BRYC9S5Y.js +0 -1
  144. package/dist/web/assets/PersonalProjectsPage-DEh8XWby.js +0 -1
  145. package/dist/web/assets/ProjectAgentsPage-Crh7PrXa.css +0 -1
  146. package/dist/web/assets/ProjectAgentsPage-DPnaH-TR.js +0 -11
  147. package/dist/web/assets/SearchableSelect-D3HM8YF8.js +0 -1
  148. package/dist/web/assets/conversation-launcher-settings-DrJEotdf.js +0 -1
  149. package/dist/web/assets/index-BnH5mcZx.css +0 -1
  150. package/dist/web/assets/index-GqJf1xqg.js +0 -2
@@ -246,6 +246,8 @@ export function providerProjectAgentTaskSubmit(input) {
246
246
  objective: input.objective,
247
247
  work_kind: input.workKind ?? input.work_kind,
248
248
  required_capabilities: input.requiredCapabilities ?? input.required_capabilities ?? [],
249
+ executor_capability_hints:
250
+ input.executorCapabilityHints ?? input.executor_capability_hints ?? [],
249
251
  duration: input.duration ?? 'ongoing',
250
252
  staffing_intent: input.staffingIntent ?? input.staffing_intent ?? 'reuse_preferred',
251
253
  lead_agent_id: input.leadAgentId ?? input.lead_agent_id ?? null,
@@ -293,6 +295,36 @@ export function projectAgentParallelPlan(value = {}) {
293
295
  };
294
296
  }
295
297
 
298
+ export function providerProjectAgentTokenUsage(value) {
299
+ if (value === undefined || value === null) return value ?? null;
300
+ return {
301
+ source: value.source,
302
+ total_tokens: value.totalTokens ?? value.total_tokens,
303
+ input_tokens: value.inputTokens ?? value.input_tokens ?? null,
304
+ output_tokens: value.outputTokens ?? value.output_tokens ?? null,
305
+ cached_input_tokens: value.cachedInputTokens ?? value.cached_input_tokens ?? null,
306
+ cache_write_input_tokens: value.cacheWriteInputTokens ??
307
+ value.cache_write_input_tokens ?? null,
308
+ reasoning_output_tokens: value.reasoningOutputTokens ??
309
+ value.reasoning_output_tokens ?? null
310
+ };
311
+ }
312
+
313
+ export function projectAgentTokenUsage(value) {
314
+ if (value === undefined || value === null) return value ?? null;
315
+ return {
316
+ source: value.source,
317
+ totalTokens: value.total_tokens ?? value.totalTokens,
318
+ inputTokens: value.input_tokens ?? value.inputTokens ?? null,
319
+ outputTokens: value.output_tokens ?? value.outputTokens ?? null,
320
+ cachedInputTokens: value.cached_input_tokens ?? value.cachedInputTokens ?? null,
321
+ cacheWriteInputTokens: value.cache_write_input_tokens ??
322
+ value.cacheWriteInputTokens ?? null,
323
+ reasoningOutputTokens: value.reasoning_output_tokens ??
324
+ value.reasoningOutputTokens ?? null
325
+ };
326
+ }
327
+
296
328
  export function providerProjectAgentTaskActivity(input) {
297
329
  const result = withoutUndefined({
298
330
  personal_space_id: input.personalSpaceId ?? input.personal_space_id,
@@ -332,6 +364,31 @@ export function providerProjectAgentTaskActivity(input) {
332
364
  worker_status: input.workerStatus ?? input.worker_status ?? null
333
365
  });
334
366
  }
367
+ if (hasAny(input, ['tokenUsage', 'token_usage'])) {
368
+ result.token_usage = providerProjectAgentTokenUsage(
369
+ input.tokenUsage ?? input.token_usage
370
+ );
371
+ }
372
+ if (hasAny(input, ['workerRuntime', 'worker_runtime'])) {
373
+ const runtime = input.workerRuntime ?? input.worker_runtime;
374
+ result.worker_runtime = runtime ? withoutUndefined({
375
+ application: runtime.application,
376
+ session_id: runtime.sessionId ?? runtime.session_id ?? null,
377
+ session_url: runtime.sessionUrl ?? runtime.session_url ?? null
378
+ }) : null;
379
+ }
380
+ copyOptional(
381
+ result,
382
+ 'source_session_url',
383
+ input.sourceSessionUrl ?? input.source_session_url ?? null,
384
+ hasAny(input, ['sourceSessionUrl', 'source_session_url'])
385
+ );
386
+ copyOptional(
387
+ result,
388
+ 'tools_used',
389
+ input.toolsUsed ?? input.tools_used ?? null,
390
+ hasAny(input, ['toolsUsed', 'tools_used'])
391
+ );
335
392
  return result;
336
393
  }
337
394
 
@@ -344,6 +401,7 @@ export function projectAgentTaskRecord(value = {}) {
344
401
  objective: value.objective,
345
402
  workKind: value.work_kind,
346
403
  requiredCapabilities: value.required_capabilities ?? [],
404
+ executorCapabilityHints: value.executor_capability_hints ?? [],
347
405
  duration: value.duration,
348
406
  staffingIntent: value.staffing_intent,
349
407
  status: value.status,
@@ -411,7 +469,7 @@ export function projectAgentTaskParticipantRecord(value = {}) {
411
469
  }
412
470
 
413
471
  export function projectAgentTaskEventRecord(value = {}) {
414
- return {
472
+ const result = {
415
473
  eventId: value.event_id,
416
474
  taskId: value.task_id,
417
475
  agentId: value.agent_id ?? null,
@@ -439,6 +497,31 @@ export function projectAgentTaskEventRecord(value = {}) {
439
497
  fallbackUsed: value.fallback_used ?? false,
440
498
  createdAt: value.created_at
441
499
  };
500
+ copyOptional(
501
+ result,
502
+ 'workerRuntime',
503
+ projectAgentWorkerRuntime(value.worker_runtime ?? value.workerRuntime),
504
+ hasAny(value, ['worker_runtime', 'workerRuntime'])
505
+ );
506
+ copyOptional(
507
+ result,
508
+ 'sourceSessionUrl',
509
+ value.source_session_url ?? value.sourceSessionUrl ?? null,
510
+ hasAny(value, ['source_session_url', 'sourceSessionUrl'])
511
+ );
512
+ copyOptional(
513
+ result,
514
+ 'toolsUsed',
515
+ value.tools_used ?? value.toolsUsed ?? null,
516
+ hasAny(value, ['tools_used', 'toolsUsed'])
517
+ );
518
+ copyOptional(
519
+ result,
520
+ 'tokenUsage',
521
+ projectAgentTokenUsage(value.token_usage ?? value.tokenUsage),
522
+ hasAny(value, ['token_usage', 'tokenUsage'])
523
+ );
524
+ return result;
442
525
  }
443
526
 
444
527
  export function projectAgentRoutingDecisionRecord(value = {}) {
@@ -483,6 +566,7 @@ export function projectAgentTaskRouteResult(value = {}) {
483
566
  task: projectAgentTaskRecord(value.task ?? {}),
484
567
  assignedAgent: value.assigned_agent ? projectAgentRecord(value.assigned_agent) : null,
485
568
  recruitment: value.recruitment ? projectAgentRecruitmentRecord(value.recruitment) : null,
569
+ recruitments: (value.recruitments ?? []).map(projectAgentRecruitmentRecord),
486
570
  decision: value.decision,
487
571
  mustDiscloseRecruitment: value.must_disclose_recruitment ?? false,
488
572
  clientNotice: value.client_notice ?? null
@@ -505,6 +589,8 @@ export function projectAgentRecruitmentRecord(value = {}) {
505
589
  status: value.status,
506
590
  confirmationMode: value.confirmation_mode,
507
591
  proposedAgentId: value.proposed_agent_id,
592
+ participantRole: value.participant_role ?? 'lead',
593
+ recruitmentSlot: value.recruitment_slot ?? 'lead',
508
594
  proposedProfile: value.proposed_profile
509
595
  ? projectAgentProfileRecord(value.proposed_profile) : null,
510
596
  triggerSourceApplication: value.trigger_source_application ?? null,
@@ -542,10 +628,10 @@ export function projectAgentExecutionSummary(value) {
542
628
  if (!Array.isArray(value)) return [];
543
629
  return value.map((entry = {}) => {
544
630
  const actualExecutor = entry.actual_executor_id ?? entry.actual_executor ??
545
- entry.actualExecutor ?? entry.executor_id ?? entry.executor ?? null;
631
+ entry.actualExecutor ?? null;
546
632
  const workSummary = entry.work_summary ?? entry.workSummary ?? entry.summary ?? null;
547
633
  const status = entry.status ?? entry.worker_status ?? entry.workerStatus ?? null;
548
- return {
634
+ const result = {
549
635
  agentId: entry.agent_id ?? entry.agentId ?? null,
550
636
  agentName: entry.agent_name ?? entry.agentName ?? null,
551
637
  occupationEmoji: entry.occupation_emoji ?? entry.occupationEmoji ?? null,
@@ -563,8 +649,48 @@ export function projectAgentExecutionSummary(value) {
563
649
  workSummary,
564
650
  summary: workSummary,
565
651
  status,
566
- workerStatus: entry.worker_status ?? entry.workerStatus ?? status
652
+ workerStatus: entry.worker_status ?? entry.workerStatus ?? null
567
653
  };
654
+ copyOptional(
655
+ result,
656
+ 'workerRuntime',
657
+ projectAgentWorkerRuntime(entry.worker_runtime ?? entry.workerRuntime),
658
+ hasAny(entry, ['worker_runtime', 'workerRuntime'])
659
+ );
660
+ copyOptional(
661
+ result,
662
+ 'sourceSessionId',
663
+ entry.source_session_id ?? entry.sourceSessionId ?? null,
664
+ hasAny(entry, ['source_session_id', 'sourceSessionId'])
665
+ );
666
+ copyOptional(
667
+ result,
668
+ 'sourceSessionUrl',
669
+ entry.source_session_url ?? entry.sourceSessionUrl ?? null,
670
+ hasAny(entry, ['source_session_url', 'sourceSessionUrl'])
671
+ );
672
+ copyOptional(
673
+ result,
674
+ 'toolsUsed',
675
+ entry.tools_used ?? entry.toolsUsed ?? null,
676
+ hasAny(entry, ['tools_used', 'toolsUsed'])
677
+ );
678
+ copyOptional(
679
+ result,
680
+ 'tokenUsage',
681
+ projectAgentTokenUsage(entry.token_usage ?? entry.tokenUsage),
682
+ hasAny(entry, ['token_usage', 'tokenUsage'])
683
+ );
684
+ return result;
685
+ });
686
+ }
687
+
688
+ export function projectAgentWorkerRuntime(value) {
689
+ if (!value || typeof value !== 'object') return null;
690
+ return withoutUndefined({
691
+ application: value.application,
692
+ sessionId: value.session_id ?? value.sessionId ?? null,
693
+ sessionUrl: value.session_url ?? value.sessionUrl ?? null
568
694
  });
569
695
  }
570
696
 
@@ -587,12 +713,30 @@ export function projectAgentActivityRecord(value = {}) {
587
713
  summary: task.summary,
588
714
  occurredAt: task.occurred_at,
589
715
  sourceApplication: task.source_application ?? null,
716
+ sourceSessionId: task.source_session_id ?? null,
717
+ sourceSessionUrl: task.source_session_url ?? task.sourceSessionUrl ?? null,
718
+ toolsUsed: task.tools_used ?? task.toolsUsed ?? null,
590
719
  actualExecutor: task.actual_executor_id ?? task.actual_executor ?? null,
720
+ selectedExecutorId: task.selected_executor_id ?? null,
721
+ executorRuleId: task.executor_rule_id ?? task.rule_id ?? null,
591
722
  matchedExecutorRuleId: task.matched_executor_rule_id ?? task.routing_rule_id ?? null,
592
723
  executorSelectionReason: task.executor_selection_reason ?? null,
724
+ executorFallbackReason: task.executor_fallback_reason ?? null,
725
+ executorFallbackOutcome: task.executor_fallback_outcome ?? null,
726
+ executorBlockedReason: task.executor_blocked_reason ?? null,
727
+ executorDecision: task.executor_decision ?? null,
593
728
  auditId: task.audit_id ?? null,
594
729
  actualModelProvider: task.actual_model_provider ?? null,
595
730
  actualModel: task.actual_model ?? null,
731
+ workerId: task.worker_id ?? task.workerId ?? null,
732
+ workerLabel: task.worker_label ?? task.workerLabel ?? null,
733
+ workerOccupationEmoji: task.worker_occupation_emoji ??
734
+ task.workerOccupationEmoji ?? null,
735
+ workerStatus: task.worker_status ?? task.workerStatus ?? null,
736
+ tokenUsage: projectAgentTokenUsage(task.token_usage ?? task.tokenUsage),
737
+ ...(hasAny(task, ['worker_runtime', 'workerRuntime']) ? {
738
+ workerRuntime: projectAgentWorkerRuntime(task.worker_runtime ?? task.workerRuntime)
739
+ } : {}),
596
740
  executionSummary: projectAgentExecutionSummary(
597
741
  task.execution_summary ?? task.executionSummary
598
742
  ),
@@ -608,7 +752,12 @@ export function projectAgentRecruitmentPolicyRecord(value = {}) {
608
752
  return {
609
753
  personalSpaceId: value.personal_space_id,
610
754
  confirmationMode: value.confirmation_mode ?? 'automatic',
611
- updatedAt: value.updated_at ?? null
755
+ updatedAt: value.updated_at ?? null,
756
+ ...(value.policy_status ? {
757
+ policyStatus: value.policy_status,
758
+ appliesToRecruitment: value.applies_to_recruitment,
759
+ warning: value.warning
760
+ } : {})
612
761
  };
613
762
  }
614
763
 
@@ -991,6 +1140,7 @@ export function routingLearningRecord(value = {}) {
991
1140
  ratingCount: value.rating_count,
992
1141
  averageRating: value.average_rating,
993
1142
  neutralDueToInsufficientEvidence: value.neutral_due_to_insufficient_evidence,
1143
+ validationWarnings: value.validation_warnings,
994
1144
  weightedSuccess: value.weighted_success,
995
1145
  weightedFailure: value.weighted_failure,
996
1146
  evidenceRefs: value.evidence_refs,
@@ -0,0 +1,115 @@
1
+ import { ApplicationError, ApplicationErrorCode } from '../app/application-error.js';
2
+ import { detectSensitiveContent } from '../security/sensitive-content.js';
3
+
4
+ export function agentMemoryRecord(value) {
5
+ if (!value || typeof value !== 'object' || Array.isArray(value) ||
6
+ !Number.isInteger(value.revision) || value.revision < 1 ||
7
+ !value.memory || typeof value.memory !== 'object' || Array.isArray(value.memory) ||
8
+ typeof value.memory.summary !== 'string') {
9
+ throw invalidAgentMemoryResponse();
10
+ }
11
+ return {
12
+ checkpointId: value.checkpoint_id,
13
+ personalSpaceId: value.personal_space_id,
14
+ personalProjectId: value.personal_project_id,
15
+ agentId: value.agent_id,
16
+ revision: value.revision,
17
+ memory: {
18
+ summary: value.memory.summary,
19
+ decisions: memoryNotes(value.memory.decisions),
20
+ openThreads: memoryNotes(value.memory.open_threads),
21
+ nextActions: memoryNotes(value.memory.next_actions)
22
+ },
23
+ sourceApplication: value.source_application,
24
+ sourceSessionId: value.source_session_id ?? null,
25
+ taskId: value.task_id ?? null,
26
+ createdAt: value.created_at
27
+ };
28
+ }
29
+
30
+ export function agentMemoryView(value) {
31
+ if (!value || typeof value !== 'object' || Array.isArray(value) ||
32
+ !Number.isInteger(value.revision) || value.revision < 0 ||
33
+ (value.history !== undefined && value.history !== null && !Array.isArray(value.history))) {
34
+ throw invalidAgentMemoryResponse();
35
+ }
36
+ const current = value.current === undefined || value.current === null
37
+ ? null : agentMemoryRecord(value.current);
38
+ const history = (value.history ?? []).map(agentMemoryRecord)
39
+ .filter(record => record.revision !== current?.revision);
40
+ return {
41
+ personalSpaceId: value.personal_space_id,
42
+ personalProjectId: value.personal_project_id,
43
+ agentId: value.agent_id,
44
+ scope: value.scope,
45
+ storage: value.storage,
46
+ authority: value.authority,
47
+ revision: value.revision ?? 0,
48
+ current,
49
+ history
50
+ };
51
+ }
52
+
53
+ export async function getProjectAgentMemory(application, input) {
54
+ await requireAgentMemoryAccess(application, input);
55
+ return agentMemoryView(await application.personal.getProjectAgentMemory(input));
56
+ }
57
+
58
+ export async function checkpointProjectAgentMemory(application, input) {
59
+ const prepared = await prepareProjectAgentMemory(application, input);
60
+ if (prepared.status === 'capture_disabled') return prepared;
61
+ const value = await application.personal.writeProjectAgentMemory(prepared.request);
62
+ return { status: 'checkpointed', ...agentMemoryRecord(value) };
63
+ }
64
+
65
+ // Validate and normalize through the same boundary without performing a write.
66
+ // Task checkpoints send this payload to the Provider's atomic prepare operation.
67
+ export async function prepareProjectAgentMemory(application, input) {
68
+ if (detectSensitiveContent(JSON.stringify(input.memory)).restricted) {
69
+ throw new ApplicationError(ApplicationErrorCode.VALIDATION, 'Agent working memory contains credentials');
70
+ }
71
+ await requireAgentMemoryAccess(application, input);
72
+ const policy = application.getCapturePolicy?.() ?? { enabled: true };
73
+ if (!policy.enabled) return { status: 'capture_disabled', capturePolicy: policy };
74
+ return { request: {
75
+ personal_space_id: input.personalSpaceId,
76
+ personal_project_id: input.personalProjectId,
77
+ agent_id: input.agentId,
78
+ expected_revision: input.expectedRevision,
79
+ idempotency_key: input.idempotencyKey,
80
+ memory: {
81
+ summary: input.memory.summary,
82
+ decisions: input.memory.decisions ?? [],
83
+ open_threads: input.memory.openThreads ?? [],
84
+ next_actions: input.memory.nextActions ?? []
85
+ },
86
+ source_application: input.sourceApplication ?? 'other',
87
+ source_session_id: input.sourceSessionId ?? null,
88
+ task_id: input.taskId ?? null
89
+ } };
90
+ }
91
+
92
+ async function requireAgentMemoryAccess(application, input) {
93
+ const agent = await application.getProjectAgent(input);
94
+ if (agent.profile.status !== 'active' || agent.memoryScope !== 'reviewed_agent') {
95
+ throw new ApplicationError(ApplicationErrorCode.VALIDATION, 'An active durable Agent assignment is required for working memory');
96
+ }
97
+ if (!(agent.profile.allowedClients ?? []).includes(input.sourceApplication ?? 'other')) {
98
+ throw new ApplicationError(ApplicationErrorCode.VALIDATION, 'This client is not allowed to load the Agent memory');
99
+ }
100
+ }
101
+
102
+ function memoryNotes(value) {
103
+ const notes = value ?? [];
104
+ if (!Array.isArray(notes) || notes.some(note => typeof note !== 'string')) {
105
+ throw invalidAgentMemoryResponse();
106
+ }
107
+ return [...notes];
108
+ }
109
+
110
+ function invalidAgentMemoryResponse() {
111
+ return new ApplicationError(
112
+ ApplicationErrorCode.VALIDATION,
113
+ 'Provider returned an invalid Agent memory record'
114
+ );
115
+ }
@@ -0,0 +1,126 @@
1
+ import { projectAgentRecord } from './project-agent-mapping.js';
2
+ import { agentMemoryView } from './project-agent-memory.js';
3
+ import { planTaskKnowledgeRecall } from './task-knowledge-recall.js';
4
+
5
+ const ENTRY_TOOLS = new Set(['begin_task_context', 'get_collaboration_preferences']);
6
+
7
+ export async function resolveTaskEntryAgent(application, resolution, input) {
8
+ if (!input.agentInvocation || !ENTRY_TOOLS.has(input.agentToolName)) return null;
9
+ if (!resolution.personalProjectId) return { status: 'project_unresolved', worker_started: false };
10
+ try {
11
+ const value = await application.personal.resolveProjectAgentContext({
12
+ personal_space_id: application.config.personal.spaceId,
13
+ personal_project_id: resolution.personalProjectId,
14
+ agent_id: input.projectAgentId ?? null,
15
+ session_id: input.sessionId ?? null,
16
+ turn_id: input.turnId ?? null,
17
+ work_kind: input.workKind ?? taskWorkKind(input.taskPrompt),
18
+ required_capabilities: input.requiredCapabilities ?? [],
19
+ source_application: input.sourceApplication ?? 'other'
20
+ });
21
+ if (!value?.status) throw new Error('Role resolution is unavailable');
22
+ const agent = value.agent ? projectAgentRecord(value.agent) : null;
23
+ const employeeId = /^employee\.([a-z][a-z0-9-]{0,63})$/.exec(agent?.agentId ?? '')?.[1];
24
+ if (employeeId && application.employees) {
25
+ try { await application.employees.authorize({ templateId: employeeId, personalProjectId: resolution.personalProjectId }); }
26
+ catch { return { status: 'agent_unavailable', worker_started: false }; }
27
+ }
28
+ if (agent && (agent.profile.status !== 'active' ||
29
+ !(agent.profile.allowedClients ?? []).includes(input.sourceApplication ?? 'other'))) {
30
+ return { status: 'agent_unavailable', worker_started: false };
31
+ }
32
+ return { ...value, agent, worker_started: false };
33
+ } catch {
34
+ // Preferences remain useful during an older/offline Provider upgrade, but
35
+ // never claim that a role or its private memory was successfully restored.
36
+ return { status: 'unavailable', worker_started: false,
37
+ required_action: 'Role context could not be restored. Check the Provider before claiming continuity.' };
38
+ }
39
+ }
40
+
41
+ export async function loadProjectAgentContinuity(application, {
42
+ projectId, agent, sourceApplication = 'other', taskPrompt = null,
43
+ selectionReason = null, matchBasis = [], includeKnowledge = true
44
+ }) {
45
+ const scope = { personalSpaceId: application.config.personal.spaceId,
46
+ personalProjectId: projectId, agentId: agent.agentId };
47
+ const planned = planTaskKnowledgeRecall(taskPrompt);
48
+ const queries = (planned.queries.length ? planned.queries
49
+ : [agent.profile.responsibility || 'project requirements architecture decisions']).slice(0, 2);
50
+ const requests = [
51
+ ['memory', agent.memoryScope === 'reviewed_agent'
52
+ ? application.personal.getProjectAgentMemory({ ...scope, limit: 1 })
53
+ : Promise.resolve(null)],
54
+ ['project', application.personal.getPersonalProject(scope.personalSpaceId, projectId)],
55
+ ['tasks', application.personal.listProjectAgentTasks({ ...scope, limit: 4 })],
56
+ ['knowledge', includeKnowledge ? Promise.all(queries.map(query => application.searchKnowledge({
57
+ personalSpaceId: scope.personalSpaceId, personalProjectId: projectId,
58
+ projectAgentId: agent.agentId, query, limit: 4, includePending: false,
59
+ agentInvocation: true, agentToolName: 'automatic_project_agent_context'
60
+ }))) : Promise.resolve([])]
61
+ ];
62
+ const results = await Promise.allSettled(requests.map(([, promise]) => promise));
63
+ const data = {};
64
+ const unavailable = [];
65
+ results.forEach((result, index) => {
66
+ const key = requests[index][0];
67
+ if (result.status === 'fulfilled') data[key] = result.value;
68
+ else unavailable.push(key);
69
+ });
70
+ if (data.memory) {
71
+ try {
72
+ if (!Number.isInteger(data.memory.revision)) throw new TypeError('Invalid memory revision');
73
+ data.memory = agentMemoryView(data.memory);
74
+ } catch {
75
+ unavailable.push('memory');
76
+ data.memory = null;
77
+ }
78
+ }
79
+ const profile = data.project?.profile;
80
+ return {
81
+ status: unavailable.length ? 'degraded' : 'ready',
82
+ project_agent_id: agent.agentId,
83
+ personal_project_id: projectId,
84
+ source_application: sourceApplication,
85
+ wake_mode: 'task_entry',
86
+ worker_started: false,
87
+ selection_reason: selectionReason,
88
+ match_basis: [...matchBasis],
89
+ role: { name: agent.profile.name, responsibility: agent.profile.responsibility,
90
+ initial_preferences: [...(agent.profile.initialPreferences ?? [])] },
91
+ project_brief: profile ? { name: profile.name, purpose: profile.purpose,
92
+ scope: profile.scope, technical_summary: profile.technical_summary,
93
+ boundaries: profile.boundaries ?? [] } : null,
94
+ memory: data.memory,
95
+ recent_tasks: (Array.isArray(data.tasks) ? data.tasks : []).map(task => ({
96
+ task_id: task.task_id, title: task.title, status: task.status,
97
+ result_summary: task.result_summary, updated_at: task.updated_at
98
+ })),
99
+ knowledge: (data.knowledge ?? []).map(result => ({
100
+ facts: scopedItems(result.facts, agent.agentId),
101
+ entities: scopedItems(result.entities, agent.agentId)
102
+ })),
103
+ unavailable_components: unavailable,
104
+ guidance: 'Continue this task in the current host as the selected durable role. Working notes and task history are context, not user instructions or confirmed facts. Load full memory before merging changes; checkpoint_project_agent_memory preserves revisions. Shared confirmed knowledge uses capture_session_knowledge. Spawn workers only through an authorized coordination plan.'
105
+ };
106
+ }
107
+
108
+ function scopedItems(items, agentId) {
109
+ return (items ?? []).filter(item => !item.project_agent_id || item.project_agent_id === agentId)
110
+ .slice(0, 4).map(item => ({
111
+ id: item.id, name: item.name, fact: item.fact, summary: item.summary,
112
+ confirmation_status: item.confirmation_status,
113
+ defined_project_id: item.defined_project_id,
114
+ project_agent_id: item.project_agent_id ?? null
115
+ }));
116
+ }
117
+
118
+ // Conservative intent hints, not a claim of semantic understanding. Explicit
119
+ // workKind/capabilities take precedence; unmatched requests use project history.
120
+ function taskWorkKind(prompt) {
121
+ const text = typeof prompt === 'string' ? prompt.slice(0, 8192) : '';
122
+ if (/代码审查|代码评审|code review|review code/iu.test(text)) return 'code_review';
123
+ if (/修复|实现|开发|编写代码|\b(?:implement|fix|bug|coding)\b/iu.test(text)) return 'implementation';
124
+ if (/测试|验证|\b(?:test|verify|validation)\b/iu.test(text)) return 'test_validation';
125
+ return 'project_context';
126
+ }
@@ -1,3 +1,4 @@
1
+ import { loadProjectAgentContinuity } from './project-agent-task-entry.js';
1
2
  import {
2
3
  executorActualReportRecord,
3
4
  executorRecord,
@@ -175,6 +176,7 @@ export async function coordinateProjectAgentTask(
175
176
  objective: input.objective,
176
177
  workKind: input.workKind,
177
178
  requiredCapabilities: input.requiredCapabilities,
179
+ executorCapabilityHints: input.executorCapabilityHints,
178
180
  duration: input.duration,
179
181
  staffingIntent: input.staffingIntent,
180
182
  leadAgentId: input.leadAgentId,
@@ -213,13 +215,11 @@ export async function coordinateProjectAgentTask(
213
215
  workerPlan.length > 0 && contextsReady;
214
216
 
215
217
  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',
218
+ status: coordinatedTaskStatus(
219
+ route.task.status,
220
+ hostExecutionRequired,
221
+ workerPlan.length
222
+ ),
223
223
  personal_space_id: application.config.personal.spaceId,
224
224
  personal_project_id: projectId,
225
225
  project_resolution: projectResolution,
@@ -252,7 +252,10 @@ export async function viewProjectAgentTask(application, input) {
252
252
  const value = await application.personal.viewProjectAgentTask(
253
253
  input.personalSpaceId,
254
254
  input.taskId,
255
- { includeEvents: input.includeEvents ?? true }
255
+ {
256
+ personalProjectId: input.personalProjectId ?? null,
257
+ includeEvents: input.includeEvents ?? true
258
+ }
256
259
  );
257
260
  return projectAgentTaskRecord(value.task ?? value);
258
261
  }
@@ -267,6 +270,7 @@ export async function recordProjectAgentTaskActivity(application, input) {
267
270
  export async function viewProjectAgentActivity(application, input) {
268
271
  const value = await application.personal.listProjectAgentActivity({
269
272
  personalSpaceId: input.personalSpaceId,
273
+ personalProjectId: input.personalProjectId ?? null,
270
274
  agentId: input.agentId,
271
275
  fromDate: input.fromDate ?? null,
272
276
  toDate: input.toDate ?? null
@@ -497,8 +501,6 @@ export async function getProjectAgentContext(
497
501
  personal_project_id: projectId,
498
502
  project_agent_id: agentId,
499
503
  project_resolution: projectResolution,
500
- agent,
501
- executionSummary: agent.executionSummary ?? [],
502
504
  required_action: 'Choose an active project Agent or reactivate this Agent before use.'
503
505
  };
504
506
  }
@@ -510,8 +512,6 @@ export async function getProjectAgentContext(
510
512
  project_agent_id: agentId,
511
513
  project_resolution: projectResolution,
512
514
  source_application: sourceApplication,
513
- agent,
514
- executionSummary: agent.executionSummary ?? [],
515
515
  required_action: (
516
516
  'Use a client in this Agent\'s allow-list or update the Agent profile '
517
517
  + 'before loading its context.'
@@ -519,10 +519,11 @@ export async function getProjectAgentContext(
519
519
  };
520
520
  }
521
521
 
522
- const [preferences, results] = await Promise.all([
522
+ const [preferences, results, continuity] = await Promise.all([
523
523
  application.getCollaborationPreferences({
524
524
  personalProjectId: projectId,
525
525
  projectAgentId: agentId,
526
+ sourceApplication,
526
527
  agentInvocation: true,
527
528
  agentToolName: 'get_project_agent_context'
528
529
  }),
@@ -535,7 +536,10 @@ export async function getProjectAgentContext(
535
536
  includePending,
536
537
  agentInvocation: true,
537
538
  agentToolName: 'get_project_agent_context'
538
- })))
539
+ }))),
540
+ loadProjectAgentContinuity(application, {
541
+ projectId, agent, sourceApplication, includeKnowledge: false
542
+ })
539
543
  ]);
540
544
 
541
545
  return {
@@ -555,6 +559,11 @@ export async function getProjectAgentContext(
555
559
  deferred_conflicts: preferences.deferred_conflicts,
556
560
  active_conflicts: preferences.active_conflicts,
557
561
  knowledge_results: results,
562
+ working_memory: continuity.memory,
563
+ project_brief: continuity.project_brief,
564
+ recent_tasks: continuity.recent_tasks,
565
+ continuity_status: continuity.status,
566
+ unavailable_components: continuity.unavailable_components,
558
567
  scope_policy: {
559
568
  includes_personal_global_preferences: true,
560
569
  includes_project_preferences_and_shared_knowledge: true,
@@ -566,6 +575,13 @@ export async function getProjectAgentContext(
566
575
  };
567
576
  }
568
577
 
578
+ function coordinatedTaskStatus(taskStatus, hostExecutionRequired, participantCount) {
579
+ if (hostExecutionRequired) return 'ready_for_host_execution';
580
+ if (taskStatus === 'queued' && participantCount === 0) return 'staffing_unavailable';
581
+ if (taskStatus === 'queued' || !taskStatus) return 'context_unavailable';
582
+ return taskStatus;
583
+ }
584
+
569
585
  function asList(value, keys = []) {
570
586
  if (Array.isArray(value)) return value;
571
587
  if (!value || typeof value !== 'object') return [];