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.
- package/README.md +69 -13
- package/README.zh-CN.md +60 -14
- package/dist/web/assets/{AboutPage-sLV9WChi.js → AboutPage-9CVX91tr.js} +1 -1
- package/dist/web/assets/{ConnectionsPage-BWn4ywGJ.js → ConnectionsPage-CWbCVFdv.js} +1 -1
- package/dist/web/assets/EmployeeRecruitDialog-CQgNpGJ_.js +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-CfFlyKSh.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-CWg4WJhr.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-CwU4qBgD.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-B6TGAcFH.js +1 -0
- package/dist/web/assets/{KnowledgeEditDialog-DWUV_NPp.css → KnowledgeEditDialog-iv-dgUeD.css} +1 -1
- package/dist/web/assets/{KnowledgeInspector-CRQWOaos.js → KnowledgeInspector-M2pLY0bR.js} +1 -1
- package/dist/web/assets/{KnowledgeOrganizerPage-Dfj3vIpU.js → KnowledgeOrganizerPage-DzeAlk9b.js} +1 -1
- package/dist/web/assets/KnowledgePage-BJu9w0fF.js +1 -0
- package/dist/web/assets/{KnowledgeWorkspace-ChEB5Bwk.js → KnowledgeWorkspace-CCt8rnBb.js} +1 -1
- package/dist/web/assets/{OverviewPage-Cd66M0RT.js → OverviewPage-CZswVqui.js} +1 -1
- package/dist/web/assets/{PersonalProfilePage-RCFHL0Wz.js → PersonalProfilePage-f1nSF6kx.js} +1 -1
- package/dist/web/assets/PersonalProjectsPage-D__eJf0t.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-C3vW6wmk.css +1 -0
- package/dist/web/assets/ProjectAgentsPage-LrwagMGj.js +11 -0
- package/dist/web/assets/{PublicProjectsPage-mstPEjHe.js → PublicProjectsPage-BdC2Qk4n.js} +1 -1
- package/dist/web/assets/{ReviewPage-6Y1SmfZy.js → ReviewPage-Cbgl8_Si.js} +1 -1
- package/dist/web/assets/SearchableSelect-ERm-k4KI.js +1 -0
- package/dist/web/assets/{SettingsPage--LdTMUm7.js → SettingsPage-DWso4x29.js} +1 -1
- package/dist/web/assets/{WritingTastePage-CIpKswvs.js → WritingTastePage-CFpCjmIY.js} +1 -1
- package/dist/web/assets/catalog-WGLn7ERJ.js +1 -0
- package/dist/web/assets/{console-BT1P2Db4.js → console-DQgu0JIA.js} +1 -1
- package/dist/web/assets/conversation-launcher-settings-0KtlG_LV.js +1 -0
- package/dist/web/assets/{i18n-js6gfc7j.js → i18n-ByRiA3pJ.js} +3 -3
- package/dist/web/assets/{identity-CfDfanpa.js → identity-CxdPRMwH.js} +1 -1
- package/dist/web/assets/index-JAZe6lfX.js +2 -0
- package/dist/web/assets/index-wcXzzggp.css +1 -0
- package/dist/web/assets/{model-DJkLAJsg.js → model-Db4-KefQ.js} +1 -1
- package/dist/web/assets/{useApi-CROJJdhE-BdSti7Y2.js → useApi-CROJJdhE-CePMjc08.js} +1 -1
- package/dist/web/assets/{vue-router-Kk67EaCP.js → vue-router-CzX-hn3P.js} +1 -1
- package/dist/web/index.html +7 -6
- package/docs/employee-agents.md +99 -0
- package/docs/project-agent-memory.md +479 -0
- package/graph-provider/fuli_graph/knowledge_audit_models.py +171 -0
- package/graph-provider/fuli_graph/model_base.py +5 -0
- package/graph-provider/fuli_graph/model_validation.py +32 -0
- package/graph-provider/fuli_graph/models.py +26 -170
- package/graph-provider/fuli_graph/project_agent_context_models.py +29 -0
- package/graph-provider/fuli_graph/project_agent_executor_models.py +35 -7
- package/graph-provider/fuli_graph/project_agent_memory_models.py +79 -0
- package/graph-provider/fuli_graph/project_agent_memory_routes.py +46 -0
- package/graph-provider/fuli_graph/project_agent_models.py +9 -0
- package/graph-provider/fuli_graph/project_agent_recruitment_values.py +48 -0
- package/graph-provider/fuli_graph/project_agent_routes.py +21 -1
- package/graph-provider/fuli_graph/project_agent_task_models.py +217 -29
- package/graph-provider/fuli_graph/runtime.py +37 -1
- package/graph-provider/fuli_graph/store.py +6 -0
- package/graph-provider/fuli_graph/store_project_agent_context.py +65 -0
- package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +175 -11
- package/graph-provider/fuli_graph/store_project_agent_executor_routing.py +33 -10
- package/graph-provider/fuli_graph/store_project_agent_executors.py +181 -14
- package/graph-provider/fuli_graph/store_project_agent_memory.py +174 -0
- package/graph-provider/fuli_graph/store_project_agent_task_activity.py +423 -0
- package/graph-provider/fuli_graph/store_project_agent_task_persistence.py +152 -0
- package/graph-provider/fuli_graph/store_project_agent_task_reads.py +187 -21
- package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +748 -162
- package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +230 -18
- package/graph-provider/fuli_graph/store_project_agent_tasks.py +261 -468
- package/graph-provider/fuli_graph/store_project_agents.py +214 -46
- package/graph-provider/fuli_graph/store_task_contexts.py +217 -0
- package/graph-provider/fuli_graph/store_transactions.py +40 -0
- package/graph-provider/fuli_graph/task_context_models.py +50 -0
- package/graph-provider/fuli_graph/task_context_routes.py +31 -0
- package/graph-provider/fuli_graph/workflow_observation_models.py +1 -1
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +8 -8
- package/package.json +5 -2
- package/skills/capturing-session-knowledge/SKILL.md +18 -6
- package/src/adaptive-runtime/executor-pool.js +46 -5
- package/src/adaptive-runtime/graph-services.js +10 -3
- package/src/adaptive-runtime/lease-client.js +66 -14
- package/src/adaptive-runtime/runtime-broker.js +24 -9
- package/src/agent-tools/employee-definitions.js +43 -0
- package/src/agent-tools/graph-definitions.js +25 -6
- package/src/agent-tools/graph-handlers.js +11 -0
- package/src/agent-tools/project-agent-definitions.js +35 -4
- package/src/agent-tools/project-agent-memory-definitions.js +36 -0
- package/src/agent-tools.js +6 -2
- package/src/agents/codex/lifecycle-hook.js +107 -0
- package/src/agents/codex/lifecycle-hooks.js +231 -0
- package/src/agents/cursor/lifecycle-hook.js +133 -0
- package/src/agents/cursor/lifecycle-hooks.js +50 -0
- package/src/agents/lifecycle-message.js +19 -0
- package/src/app/agent-request-context.js +23 -0
- package/src/cli/command-registry.js +2 -0
- package/src/cli/employee-command.js +17 -0
- package/src/cli/remote-mcp-command.js +282 -0
- package/src/cli/setup-command.js +5 -0
- package/src/cli/update-command.js +6 -43
- package/src/cli.js +10 -0
- package/src/employees/catalog/jefa.json +21 -0
- package/src/employees/install-package.js +77 -0
- package/src/employees/management-policy.js +88 -0
- package/src/employees/manifest.js +53 -0
- package/src/employees/package-registry.js +107 -0
- package/src/employees/project-selection.js +50 -0
- package/src/employees/recruitment.js +199 -0
- package/src/employees/service.js +83 -0
- package/src/employees/task-entry.js +39 -0
- package/src/graphiti/agent-knowledge-workflows.js +135 -25
- package/src/graphiti/federated-application.js +78 -35
- package/src/graphiti/project-agent-control-plane.js +20 -3
- package/src/graphiti/project-agent-mapping.js +155 -5
- package/src/graphiti/project-agent-memory.js +115 -0
- package/src/graphiti/project-agent-task-entry.js +126 -0
- package/src/graphiti/project-agent-workflows.js +30 -14
- package/src/graphiti/provider-client.js +66 -4
- package/src/http/api-router.js +30 -5
- package/src/http/employee-api-router.js +64 -0
- package/src/http/error-mapping.js +4 -0
- package/src/http/graph-api-router.js +2 -0
- package/src/http/request-policy.js +6 -3
- package/src/http/static-handler.js +4 -3
- package/src/mcp/create-mcp-server.js +98 -37
- package/src/mcp/direct-call.js +38 -0
- package/src/mcp/instructions.js +8 -7
- package/src/mcp/provider-task-context-registry.js +74 -0
- package/src/mcp/remote-http-server.js +761 -0
- package/src/mcp/session-id.js +29 -3
- package/src/mcp/task-context-registry.js +88 -29
- package/src/mcp/tool-annotations.js +10 -2
- package/src/mcp/tool-result.js +8 -3
- package/src/mcp-server.js +20 -8
- package/src/native-runtime/runtime.js +58 -8
- package/src/semantic-version.js +42 -0
- package/src/server.js +76 -28
- package/src/setup/agent-installation-status.js +38 -6
- package/src/setup/agents.js +20 -8
- package/src/setup/claude-code-config.js +55 -13
- package/src/setup/codex-bootstrap.js +11 -10
- package/src/setup/codex-config.js +74 -7
- package/src/setup/config-backup.js +18 -2
- package/src/setup/cursor-config.js +22 -5
- package/src/setup/setup.js +30 -22
- package/src/storage/json-file.js +11 -3
- package/src/system/package-version-checker.js +72 -0
- package/src/system/system-service.js +3 -0
- package/dist/web/assets/KnowledgeEditDialog-CZ5ziPrD.js +0 -1
- package/dist/web/assets/KnowledgePage-BRYC9S5Y.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-DEh8XWby.js +0 -1
- package/dist/web/assets/ProjectAgentsPage-Crh7PrXa.css +0 -1
- package/dist/web/assets/ProjectAgentsPage-DPnaH-TR.js +0 -11
- package/dist/web/assets/SearchableSelect-D3HM8YF8.js +0 -1
- package/dist/web/assets/conversation-launcher-settings-DrJEotdf.js +0 -1
- package/dist/web/assets/index-BnH5mcZx.css +0 -1
- package/dist/web/assets/index-GqJf1xqg.js +0 -2
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Transport boundary for host-independent Agent working memory."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
from fastapi import HTTPException, Query
|
|
6
|
+
|
|
7
|
+
from .project_agent_memory_models import (
|
|
8
|
+
ProjectAgentMemoryRecord,
|
|
9
|
+
ProjectAgentMemoryView,
|
|
10
|
+
ProjectAgentMemoryWrite,
|
|
11
|
+
)
|
|
12
|
+
from .project_agent_context_models import (
|
|
13
|
+
ProjectAgentContextRequest, ProjectAgentContextResolution,
|
|
14
|
+
)
|
|
15
|
+
from .task_context_routes import register_task_context_routes
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register_project_agent_memory_routes(application, store, Actor):
|
|
19
|
+
register_task_context_routes(application, store, Actor)
|
|
20
|
+
@application.post(
|
|
21
|
+
'/v1/project-agent-context/resolve', response_model=ProjectAgentContextResolution,
|
|
22
|
+
)
|
|
23
|
+
async def resolve_context(request: ProjectAgentContextRequest, actor: Actor):
|
|
24
|
+
return await store.resolve_project_agent_context(actor, request)
|
|
25
|
+
|
|
26
|
+
@application.get(
|
|
27
|
+
'/v1/project-agents/{agent_id}/memory', response_model=ProjectAgentMemoryView,
|
|
28
|
+
)
|
|
29
|
+
async def get_memory(
|
|
30
|
+
agent_id: str,
|
|
31
|
+
actor: Actor,
|
|
32
|
+
personal_space_id: Annotated[str, Query(min_length=1, max_length=128)],
|
|
33
|
+
personal_project_id: Annotated[str, Query(min_length=1, max_length=128)],
|
|
34
|
+
limit: Annotated[int, Query(ge=1, le=10)] = 1,
|
|
35
|
+
):
|
|
36
|
+
return await store.get_project_agent_memory(
|
|
37
|
+
actor, personal_space_id, personal_project_id, agent_id, limit=limit,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
@application.put(
|
|
41
|
+
'/v1/project-agents/{agent_id}/memory', response_model=ProjectAgentMemoryRecord,
|
|
42
|
+
)
|
|
43
|
+
async def write_memory(agent_id: str, request: ProjectAgentMemoryWrite, actor: Actor):
|
|
44
|
+
if request.agent_id != agent_id:
|
|
45
|
+
raise HTTPException(status_code=422, detail='Agent memory target does not match path')
|
|
46
|
+
return await store.write_project_agent_memory(actor, request)
|
|
@@ -27,6 +27,7 @@ ProjectAgentReasoningEffort = Literal['default', 'low', 'medium', 'high']
|
|
|
27
27
|
ProjectAgentExecutorPolicyMode = Literal['flexible', 'locked']
|
|
28
28
|
PROJECT_AGENT_CLIENTS: tuple[SourceApplication, ...] = (
|
|
29
29
|
'codex',
|
|
30
|
+
'claude',
|
|
30
31
|
'claude_code',
|
|
31
32
|
'cursor',
|
|
32
33
|
'kiro',
|
|
@@ -162,6 +163,14 @@ class ProjectAgentUpsert(StrictModel):
|
|
|
162
163
|
agent_id: str = Field(min_length=1, max_length=128)
|
|
163
164
|
profile: ProjectAgentProfile
|
|
164
165
|
|
|
166
|
+
@model_validator(mode='after')
|
|
167
|
+
def require_dedicated_archive_operation(self):
|
|
168
|
+
if self.profile.status == 'archived':
|
|
169
|
+
raise ValueError(
|
|
170
|
+
'archive Project Agents through the dedicated archive operation'
|
|
171
|
+
)
|
|
172
|
+
return self
|
|
173
|
+
|
|
165
174
|
|
|
166
175
|
class ProjectAgentAssignmentCreate(StrictModel):
|
|
167
176
|
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Value conversion helpers for durable project Agent recruitment records."""
|
|
2
|
+
|
|
3
|
+
from .project_agent_models import ProjectAgentProfile
|
|
4
|
+
from .project_agent_task_models import ProjectAgentRecruitmentRecord
|
|
5
|
+
from .provider_values import native_datetime
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def project_agent_recruitment_record(raw):
|
|
9
|
+
proposed_profile = ProjectAgentProfile.model_validate_json(
|
|
10
|
+
raw['proposed_profile_json']
|
|
11
|
+
)
|
|
12
|
+
occupation_emoji = raw.get('occupation_emoji') or raw.get(
|
|
13
|
+
'occupationEmoji'
|
|
14
|
+
)
|
|
15
|
+
if not proposed_profile.occupation_emoji and occupation_emoji:
|
|
16
|
+
proposed_profile = proposed_profile.model_copy(
|
|
17
|
+
update={'occupation_emoji': occupation_emoji}
|
|
18
|
+
)
|
|
19
|
+
fields = {
|
|
20
|
+
'recruitment_id': raw.get('recruitment_id') or raw['id'],
|
|
21
|
+
'personal_space_id': raw['personal_space_id'],
|
|
22
|
+
'personal_project_id': raw['personal_project_id'],
|
|
23
|
+
'task_id': raw['task_id'],
|
|
24
|
+
'coordinator_agent_id': raw['coordinator_agent_id'],
|
|
25
|
+
'hr_agent_id': raw.get('hr_agent_id'),
|
|
26
|
+
'position_kind': raw['position_kind'],
|
|
27
|
+
'work_kind': raw['work_kind'],
|
|
28
|
+
'required_capabilities': list(raw.get('required_capabilities') or []),
|
|
29
|
+
'reason_code': raw['reason_code'],
|
|
30
|
+
'reason': raw['reason'],
|
|
31
|
+
'status': raw['status'],
|
|
32
|
+
'confirmation_mode': raw['confirmation_mode'],
|
|
33
|
+
'proposed_agent_id': raw['proposed_agent_id'],
|
|
34
|
+
'proposed_profile': proposed_profile,
|
|
35
|
+
'participant_role': raw.get('participant_role') or 'lead',
|
|
36
|
+
'recruitment_slot': raw.get('recruitment_slot') or 'lead',
|
|
37
|
+
'trigger_source_application': raw.get('trigger_source_application'),
|
|
38
|
+
'trigger_source_session_id': raw.get('trigger_source_session_id'),
|
|
39
|
+
'revision': int(raw.get('revision') or 0),
|
|
40
|
+
'recruited_agent_id': raw.get('recruited_agent_id'),
|
|
41
|
+
'created_at': native_datetime(raw['created_at']),
|
|
42
|
+
'updated_at': native_datetime(raw['updated_at']),
|
|
43
|
+
'fulfilled_at': native_datetime(raw.get('fulfilled_at')),
|
|
44
|
+
}
|
|
45
|
+
for name in ('test_source', 'cleanup_eligible'):
|
|
46
|
+
if name in ProjectAgentRecruitmentRecord.model_fields:
|
|
47
|
+
fields[name] = raw.get(name)
|
|
48
|
+
return ProjectAgentRecruitmentRecord(**fields)
|
|
@@ -5,6 +5,8 @@ from typing import Annotated, Any
|
|
|
5
5
|
|
|
6
6
|
from fastapi import FastAPI, HTTPException, Query
|
|
7
7
|
|
|
8
|
+
from .project_agent_memory_routes import register_project_agent_memory_routes
|
|
9
|
+
|
|
8
10
|
from .project_agent_models import (
|
|
9
11
|
ProjectAgentAssignmentCreate,
|
|
10
12
|
ProjectAgentAssignmentEnd,
|
|
@@ -57,6 +59,8 @@ def register_project_agent_routes(
|
|
|
57
59
|
) -> None:
|
|
58
60
|
"""Attach Project Agent routes while keeping ``create_app`` orchestration small."""
|
|
59
61
|
|
|
62
|
+
register_project_agent_memory_routes(application, store, Actor)
|
|
63
|
+
|
|
60
64
|
@application.put('/v1/project-agents', response_model=ProjectAgentRecord)
|
|
61
65
|
async def upsert_project_agent(
|
|
62
66
|
request: ProjectAgentUpsert,
|
|
@@ -233,8 +237,17 @@ def register_project_agent_routes(
|
|
|
233
237
|
task_id: str,
|
|
234
238
|
actor: Actor,
|
|
235
239
|
personal_space_id: Annotated[str, Query(min_length=1, max_length=128)],
|
|
240
|
+
personal_project_id: Annotated[
|
|
241
|
+
str | None,
|
|
242
|
+
Query(min_length=1, max_length=128),
|
|
243
|
+
] = None,
|
|
236
244
|
) -> ProjectAgentTaskRecord:
|
|
237
|
-
return await store.get_project_agent_task(
|
|
245
|
+
return await store.get_project_agent_task(
|
|
246
|
+
actor,
|
|
247
|
+
personal_space_id,
|
|
248
|
+
task_id,
|
|
249
|
+
personal_project_id=personal_project_id,
|
|
250
|
+
)
|
|
238
251
|
|
|
239
252
|
@application.post(
|
|
240
253
|
'/v1/project-agent-tasks/{task_id}/events',
|
|
@@ -259,6 +272,10 @@ def register_project_agent_routes(
|
|
|
259
272
|
personal_space_id: Annotated[str, Query(min_length=1, max_length=128)],
|
|
260
273
|
from_date: Annotated[date, Query(alias='from')],
|
|
261
274
|
to_date: Annotated[date, Query(alias='to')],
|
|
275
|
+
personal_project_id: Annotated[
|
|
276
|
+
str | None,
|
|
277
|
+
Query(min_length=1, max_length=128),
|
|
278
|
+
] = None,
|
|
262
279
|
) -> ProjectAgentActivityResult:
|
|
263
280
|
return await store.get_project_agent_activity(
|
|
264
281
|
actor,
|
|
@@ -266,6 +283,7 @@ def register_project_agent_routes(
|
|
|
266
283
|
agent_id,
|
|
267
284
|
from_date,
|
|
268
285
|
to_date,
|
|
286
|
+
personal_project_id=personal_project_id,
|
|
269
287
|
)
|
|
270
288
|
|
|
271
289
|
@application.get(
|
|
@@ -296,6 +314,7 @@ def register_project_agent_routes(
|
|
|
296
314
|
@application.get(
|
|
297
315
|
'/v1/project-agent-recruitment-policy',
|
|
298
316
|
response_model=ProjectAgentRecruitmentPolicyRecord,
|
|
317
|
+
deprecated=True,
|
|
299
318
|
)
|
|
300
319
|
async def get_project_agent_recruitment_policy(
|
|
301
320
|
actor: Actor,
|
|
@@ -309,6 +328,7 @@ def register_project_agent_routes(
|
|
|
309
328
|
@application.put(
|
|
310
329
|
'/v1/project-agent-recruitment-policy',
|
|
311
330
|
response_model=ProjectAgentRecruitmentPolicyRecord,
|
|
331
|
+
deprecated=True,
|
|
312
332
|
)
|
|
313
333
|
async def update_project_agent_recruitment_policy(
|
|
314
334
|
request: ProjectAgentRecruitmentPolicyUpdate,
|
|
@@ -3,7 +3,11 @@ from typing import Literal
|
|
|
3
3
|
|
|
4
4
|
from pydantic import AliasChoices, Field, field_validator, model_validator
|
|
5
5
|
|
|
6
|
-
from .model_validation import
|
|
6
|
+
from .model_validation import (
|
|
7
|
+
normalize_source_session_url,
|
|
8
|
+
reject_credentials,
|
|
9
|
+
validate_emoji_sequence,
|
|
10
|
+
)
|
|
7
11
|
from .models import SourceApplication, StrictModel
|
|
8
12
|
from .project_agent_models import (
|
|
9
13
|
ProjectAgentExecutorPolicy,
|
|
@@ -42,6 +46,7 @@ ProjectAgentRoutingOutcome = Literal[
|
|
|
42
46
|
ProjectAgentRoutingReason = Literal[
|
|
43
47
|
'explicit_agent',
|
|
44
48
|
'project_continuity',
|
|
49
|
+
'project_default',
|
|
45
50
|
'sole_active_assignment',
|
|
46
51
|
'manual_agent_selection',
|
|
47
52
|
'exact_work_kind',
|
|
@@ -72,6 +77,16 @@ ProjectAgentOptimizationPriority = Literal[
|
|
|
72
77
|
'token_and_cost',
|
|
73
78
|
'time',
|
|
74
79
|
]
|
|
80
|
+
ProjectAgentTokenUsageSource = Literal['executor', 'host', 'dingdong']
|
|
81
|
+
|
|
82
|
+
_WORKER_EVIDENCE_ALIASES = {
|
|
83
|
+
'worker_id': 'workerId',
|
|
84
|
+
'worker_label': 'workerLabel',
|
|
85
|
+
'worker_occupation_emoji': 'workerOccupationEmoji',
|
|
86
|
+
'worker_status': 'workerStatus',
|
|
87
|
+
'token_usage': 'tokenUsage',
|
|
88
|
+
'worker_runtime': 'workerRuntime',
|
|
89
|
+
}
|
|
75
90
|
|
|
76
91
|
|
|
77
92
|
def _unique_text(value: list[str], label: str) -> list[str]:
|
|
@@ -83,6 +98,19 @@ def _unique_text(value: list[str], label: str) -> list[str]:
|
|
|
83
98
|
return normalized
|
|
84
99
|
|
|
85
100
|
|
|
101
|
+
def _normalize_worker_evidence_aliases(value):
|
|
102
|
+
if not isinstance(value, dict):
|
|
103
|
+
return value
|
|
104
|
+
normalized = dict(value)
|
|
105
|
+
for field_name, alias in _WORKER_EVIDENCE_ALIASES.items():
|
|
106
|
+
if alias not in normalized:
|
|
107
|
+
continue
|
|
108
|
+
if field_name in normalized and normalized[field_name] != normalized[alias]:
|
|
109
|
+
raise ValueError(f'conflicting {field_name} and {alias} values')
|
|
110
|
+
normalized[field_name] = normalized.pop(alias)
|
|
111
|
+
return normalized
|
|
112
|
+
|
|
113
|
+
|
|
86
114
|
class ProjectAgentParallelPlan(StrictModel):
|
|
87
115
|
enabled: bool = False
|
|
88
116
|
independent_verification: bool = False
|
|
@@ -120,6 +148,10 @@ class ProjectAgentTaskSubmit(StrictModel):
|
|
|
120
148
|
objective: str = Field(min_length=1, max_length=4096)
|
|
121
149
|
work_kind: str = Field(min_length=1, max_length=128)
|
|
122
150
|
required_capabilities: list[str] = Field(default_factory=list, max_length=16)
|
|
151
|
+
executor_capability_hints: list[str] = Field(
|
|
152
|
+
default_factory=list,
|
|
153
|
+
max_length=16,
|
|
154
|
+
)
|
|
123
155
|
duration: ProjectAgentTaskDuration = 'ongoing'
|
|
124
156
|
staffing_intent: ProjectAgentStaffingIntent = 'reuse_preferred'
|
|
125
157
|
lead_agent_id: str | None = Field(default=None, min_length=1, max_length=128)
|
|
@@ -143,6 +175,14 @@ class ProjectAgentTaskSubmit(StrictModel):
|
|
|
143
175
|
def validate_capabilities(cls, value: list[str]) -> list[str]:
|
|
144
176
|
return _unique_text(value, 'required capabilities')
|
|
145
177
|
|
|
178
|
+
@field_validator('executor_capability_hints')
|
|
179
|
+
@classmethod
|
|
180
|
+
def validate_executor_capability_hints(
|
|
181
|
+
cls,
|
|
182
|
+
value: list[str],
|
|
183
|
+
) -> list[str]:
|
|
184
|
+
return _unique_text(value, 'executor capability hints')
|
|
185
|
+
|
|
146
186
|
@field_validator('collaborator_agent_ids')
|
|
147
187
|
@classmethod
|
|
148
188
|
def validate_collaborators(cls, value: list[str]) -> list[str]:
|
|
@@ -185,6 +225,80 @@ class ProjectAgentTaskParticipantRecord(StrictModel):
|
|
|
185
225
|
ended_at: datetime | None = None
|
|
186
226
|
|
|
187
227
|
|
|
228
|
+
class ProjectAgentTokenUsage(StrictModel):
|
|
229
|
+
"""Cumulative token snapshot reported for one concrete worker run."""
|
|
230
|
+
|
|
231
|
+
source: ProjectAgentTokenUsageSource
|
|
232
|
+
total_tokens: int = Field(
|
|
233
|
+
ge=0,
|
|
234
|
+
validation_alias=AliasChoices('total_tokens', 'totalTokens'),
|
|
235
|
+
)
|
|
236
|
+
input_tokens: int | None = Field(
|
|
237
|
+
default=None,
|
|
238
|
+
ge=0,
|
|
239
|
+
validation_alias=AliasChoices('input_tokens', 'inputTokens'),
|
|
240
|
+
)
|
|
241
|
+
output_tokens: int | None = Field(
|
|
242
|
+
default=None,
|
|
243
|
+
ge=0,
|
|
244
|
+
validation_alias=AliasChoices('output_tokens', 'outputTokens'),
|
|
245
|
+
)
|
|
246
|
+
cached_input_tokens: int | None = Field(
|
|
247
|
+
default=None,
|
|
248
|
+
ge=0,
|
|
249
|
+
validation_alias=AliasChoices(
|
|
250
|
+
'cached_input_tokens',
|
|
251
|
+
'cachedInputTokens',
|
|
252
|
+
),
|
|
253
|
+
)
|
|
254
|
+
cache_write_input_tokens: int | None = Field(
|
|
255
|
+
default=None,
|
|
256
|
+
ge=0,
|
|
257
|
+
validation_alias=AliasChoices(
|
|
258
|
+
'cache_write_input_tokens',
|
|
259
|
+
'cacheWriteInputTokens',
|
|
260
|
+
),
|
|
261
|
+
)
|
|
262
|
+
reasoning_output_tokens: int | None = Field(
|
|
263
|
+
default=None,
|
|
264
|
+
ge=0,
|
|
265
|
+
validation_alias=AliasChoices(
|
|
266
|
+
'reasoning_output_tokens',
|
|
267
|
+
'reasoningOutputTokens',
|
|
268
|
+
),
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class ProjectAgentWorkerRuntime(StrictModel):
|
|
273
|
+
"""Host-reported worker location, never the reporter's trusted identity."""
|
|
274
|
+
|
|
275
|
+
application: SourceApplication
|
|
276
|
+
session_id: str | None = Field(
|
|
277
|
+
default=None, min_length=1, max_length=256,
|
|
278
|
+
validation_alias=AliasChoices('session_id', 'sessionId'),
|
|
279
|
+
)
|
|
280
|
+
session_url: str | None = Field(
|
|
281
|
+
default=None, max_length=2048,
|
|
282
|
+
validation_alias=AliasChoices('session_url', 'sessionUrl'),
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
_validate_session_url = field_validator('session_url')(
|
|
286
|
+
normalize_source_session_url
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
@field_validator('session_id')
|
|
290
|
+
@classmethod
|
|
291
|
+
def validate_session_id(cls, value):
|
|
292
|
+
if value is not None and not value.strip():
|
|
293
|
+
raise ValueError('worker session ID must not be blank')
|
|
294
|
+
return value.strip() if value is not None else None
|
|
295
|
+
|
|
296
|
+
@model_validator(mode='after')
|
|
297
|
+
def validate_evidence(self):
|
|
298
|
+
reject_credentials(self, 'worker runtime')
|
|
299
|
+
return self
|
|
300
|
+
|
|
301
|
+
|
|
188
302
|
class ProjectAgentTaskExecutionSummary(StrictModel):
|
|
189
303
|
"""Auditable execution evidence projected onto a real task participant.
|
|
190
304
|
|
|
@@ -203,17 +317,31 @@ class ProjectAgentTaskExecutionSummary(StrictModel):
|
|
|
203
317
|
source_application: SourceApplication | None = None
|
|
204
318
|
actual_model_provider: str | None = None
|
|
205
319
|
actual_model: str | None = None
|
|
320
|
+
source_session_id: str | None = None
|
|
321
|
+
source_session_url: str | None = None
|
|
322
|
+
tools_used: list[str] | None = Field(default=None, max_length=32)
|
|
323
|
+
token_usage: ProjectAgentTokenUsage | None = None
|
|
206
324
|
work_summary: str | None = None
|
|
207
325
|
status: ProjectAgentTaskStatus
|
|
208
326
|
worker_id: str | None = None
|
|
209
327
|
worker_label: str | None = None
|
|
210
328
|
worker_occupation_emoji: str | None = None
|
|
329
|
+
worker_runtime: ProjectAgentWorkerRuntime | None = None
|
|
211
330
|
|
|
212
331
|
@field_validator('occupation_emoji', 'worker_occupation_emoji', mode='before')
|
|
213
332
|
@classmethod
|
|
214
333
|
def validate_emojis(cls, value):
|
|
215
334
|
return validate_emoji_sequence(value, 'occupation emoji')
|
|
216
335
|
|
|
336
|
+
_validate_session_url = field_validator('source_session_url')(
|
|
337
|
+
normalize_source_session_url
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
@field_validator('tools_used')
|
|
341
|
+
@classmethod
|
|
342
|
+
def validate_tools_used(cls, value):
|
|
343
|
+
return _unique_text(value, 'tools used') if value is not None else None
|
|
344
|
+
|
|
217
345
|
|
|
218
346
|
class ProjectAgentTaskEventRecord(StrictModel):
|
|
219
347
|
event_id: str
|
|
@@ -224,6 +352,8 @@ class ProjectAgentTaskEventRecord(StrictModel):
|
|
|
224
352
|
summary: str
|
|
225
353
|
source_application: SourceApplication | None = None
|
|
226
354
|
source_session_id: str | None = None
|
|
355
|
+
source_session_url: str | None = None
|
|
356
|
+
tools_used: list[str] | None = Field(default=None, max_length=32)
|
|
227
357
|
actual_model_provider: str | None = None
|
|
228
358
|
actual_model: str | None = None
|
|
229
359
|
actual_executor_id: str | None = None
|
|
@@ -232,32 +362,32 @@ class ProjectAgentTaskEventRecord(StrictModel):
|
|
|
232
362
|
executor_selection_reason: str | None = None
|
|
233
363
|
executor_fallback_reason: str | None = None
|
|
234
364
|
executor_blocked_reason: str | None = None
|
|
235
|
-
worker_id: str | None =
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
validation_alias=AliasChoices('worker_label', 'workerLabel'),
|
|
242
|
-
)
|
|
243
|
-
worker_occupation_emoji: str | None = Field(
|
|
244
|
-
default=None,
|
|
245
|
-
validation_alias=AliasChoices(
|
|
246
|
-
'worker_occupation_emoji',
|
|
247
|
-
'workerOccupationEmoji',
|
|
248
|
-
),
|
|
249
|
-
)
|
|
250
|
-
worker_status: ProjectAgentTaskStatus | None = Field(
|
|
251
|
-
default=None,
|
|
252
|
-
validation_alias=AliasChoices('worker_status', 'workerStatus'),
|
|
253
|
-
)
|
|
365
|
+
worker_id: str | None = None
|
|
366
|
+
worker_label: str | None = None
|
|
367
|
+
worker_occupation_emoji: str | None = None
|
|
368
|
+
worker_status: ProjectAgentTaskStatus | None = None
|
|
369
|
+
token_usage: ProjectAgentTokenUsage | None = None
|
|
370
|
+
worker_runtime: ProjectAgentWorkerRuntime | None = None
|
|
254
371
|
created_at: datetime
|
|
255
372
|
|
|
373
|
+
_normalize_worker_aliases = model_validator(mode='before')(
|
|
374
|
+
_normalize_worker_evidence_aliases
|
|
375
|
+
)
|
|
376
|
+
|
|
256
377
|
@field_validator('worker_occupation_emoji', mode='before')
|
|
257
378
|
@classmethod
|
|
258
379
|
def validate_worker_occupation_emoji(cls, value):
|
|
259
380
|
return validate_emoji_sequence(value, 'worker occupation emoji')
|
|
260
381
|
|
|
382
|
+
_validate_session_url = field_validator('source_session_url')(
|
|
383
|
+
normalize_source_session_url
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
@field_validator('tools_used')
|
|
387
|
+
@classmethod
|
|
388
|
+
def validate_tools_used(cls, value):
|
|
389
|
+
return _unique_text(value, 'tools used') if value is not None else None
|
|
390
|
+
|
|
261
391
|
|
|
262
392
|
class ProjectAgentRoutingDecisionRecord(StrictModel):
|
|
263
393
|
decision_id: str
|
|
@@ -302,6 +432,7 @@ class ProjectAgentTaskRecord(StrictModel):
|
|
|
302
432
|
objective: str
|
|
303
433
|
work_kind: str
|
|
304
434
|
required_capabilities: list[str]
|
|
435
|
+
executor_capability_hints: list[str] = Field(default_factory=list)
|
|
305
436
|
duration: ProjectAgentTaskDuration
|
|
306
437
|
staffing_intent: ProjectAgentStaffingIntent
|
|
307
438
|
status: ProjectAgentTaskStatus
|
|
@@ -366,6 +497,8 @@ class ProjectAgentTaskActivityCreate(StrictModel):
|
|
|
366
497
|
actor_kind: Literal['agent', 'human'] = 'agent'
|
|
367
498
|
source_application: SourceApplication | None = None
|
|
368
499
|
source_session_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
500
|
+
source_session_url: str | None = Field(default=None, max_length=2048)
|
|
501
|
+
tools_used: list[str] | None = Field(default=None, max_length=32)
|
|
369
502
|
actual_model_provider: str | None = Field(default=None, min_length=1, max_length=128)
|
|
370
503
|
actual_model: str | None = Field(default=None, min_length=1, max_length=256)
|
|
371
504
|
actual_executor_id: str | None = Field(default=None, min_length=1, max_length=128)
|
|
@@ -393,33 +526,46 @@ class ProjectAgentTaskActivityCreate(StrictModel):
|
|
|
393
526
|
default=None,
|
|
394
527
|
min_length=1,
|
|
395
528
|
max_length=128,
|
|
396
|
-
validation_alias=AliasChoices('worker_id', 'workerId'),
|
|
397
529
|
)
|
|
398
530
|
worker_label: str | None = Field(
|
|
399
531
|
default=None,
|
|
400
532
|
min_length=1,
|
|
401
533
|
max_length=160,
|
|
402
|
-
validation_alias=AliasChoices('worker_label', 'workerLabel'),
|
|
403
534
|
)
|
|
404
535
|
worker_occupation_emoji: str | None = Field(
|
|
405
536
|
default=None,
|
|
406
537
|
min_length=1,
|
|
407
538
|
max_length=32,
|
|
408
|
-
validation_alias=AliasChoices(
|
|
409
|
-
'worker_occupation_emoji',
|
|
410
|
-
'workerOccupationEmoji',
|
|
411
|
-
),
|
|
412
539
|
)
|
|
413
|
-
worker_status: ProjectAgentTaskStatus | None =
|
|
414
|
-
|
|
415
|
-
|
|
540
|
+
worker_status: ProjectAgentTaskStatus | None = None
|
|
541
|
+
token_usage: ProjectAgentTokenUsage | None = None
|
|
542
|
+
worker_runtime: ProjectAgentWorkerRuntime | None = None
|
|
543
|
+
|
|
544
|
+
_normalize_worker_aliases = model_validator(mode='before')(
|
|
545
|
+
_normalize_worker_evidence_aliases
|
|
416
546
|
)
|
|
417
547
|
|
|
548
|
+
@property
|
|
549
|
+
def reported_client_applications(self):
|
|
550
|
+
# Worker claims can impose another restriction, never replace the
|
|
551
|
+
# host identity used for authorization and audit attribution.
|
|
552
|
+
return (self.source_application, self.worker_runtime.application) \
|
|
553
|
+
if self.worker_runtime else (self.source_application,)
|
|
554
|
+
|
|
418
555
|
@field_validator('worker_occupation_emoji', mode='before')
|
|
419
556
|
@classmethod
|
|
420
557
|
def validate_worker_occupation_emoji(cls, value):
|
|
421
558
|
return validate_emoji_sequence(value, 'worker occupation emoji')
|
|
422
559
|
|
|
560
|
+
_validate_session_url = field_validator('source_session_url')(
|
|
561
|
+
normalize_source_session_url
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
@field_validator('tools_used')
|
|
565
|
+
@classmethod
|
|
566
|
+
def validate_tools_used(cls, value):
|
|
567
|
+
return _unique_text(value, 'tools used') if value is not None else None
|
|
568
|
+
|
|
423
569
|
@model_validator(mode='after')
|
|
424
570
|
def validate_actual_model(self):
|
|
425
571
|
if self.status in {'completed', 'failed'} and not self.agent_id:
|
|
@@ -436,6 +582,24 @@ class ProjectAgentTaskActivityCreate(StrictModel):
|
|
|
436
582
|
raise ValueError('actual execution report requires the participating Agent ID')
|
|
437
583
|
if self.worker_id and not self.agent_id:
|
|
438
584
|
raise ValueError('worker execution report requires the participating Agent ID')
|
|
585
|
+
if self.worker_status and not self.worker_id:
|
|
586
|
+
raise ValueError('worker status requires a worker ID')
|
|
587
|
+
if self.worker_runtime and not self.worker_id:
|
|
588
|
+
raise ValueError('worker runtime requires a worker ID')
|
|
589
|
+
if self.token_usage and not self.agent_id:
|
|
590
|
+
raise ValueError('token usage report requires the participating Agent ID')
|
|
591
|
+
if (self.source_session_url or self.tools_used) and not self.agent_id:
|
|
592
|
+
raise ValueError(
|
|
593
|
+
'execution evidence requires the participating Agent ID'
|
|
594
|
+
)
|
|
595
|
+
if (
|
|
596
|
+
self.token_usage
|
|
597
|
+
and self.token_usage.source == 'executor'
|
|
598
|
+
and not self.actual_executor_id
|
|
599
|
+
):
|
|
600
|
+
raise ValueError(
|
|
601
|
+
'executor token usage requires the actual executor report'
|
|
602
|
+
)
|
|
439
603
|
if (self.worker_label or self.worker_occupation_emoji) and not self.worker_id:
|
|
440
604
|
raise ValueError(
|
|
441
605
|
'worker label or occupation emoji requires a worker ID'
|
|
@@ -460,6 +624,8 @@ class ProjectAgentRecruitmentRecord(StrictModel):
|
|
|
460
624
|
confirmation_mode: ProjectAgentRecruitmentConfirmationMode
|
|
461
625
|
proposed_agent_id: str
|
|
462
626
|
proposed_profile: ProjectAgentProfile
|
|
627
|
+
participant_role: ProjectAgentParticipantRole = 'lead'
|
|
628
|
+
recruitment_slot: str = Field(default='lead', min_length=1, max_length=128)
|
|
463
629
|
trigger_source_application: SourceApplication | None = None
|
|
464
630
|
trigger_source_session_id: str | None = None
|
|
465
631
|
revision: int = Field(ge=0)
|
|
@@ -475,6 +641,7 @@ class ProjectAgentTaskRouteResult(StrictModel):
|
|
|
475
641
|
task: ProjectAgentTaskRecord
|
|
476
642
|
assigned_agent: ProjectAgentRecord | None = None
|
|
477
643
|
recruitment: ProjectAgentRecruitmentRecord | None = None
|
|
644
|
+
recruitments: list[ProjectAgentRecruitmentRecord] = Field(default_factory=list)
|
|
478
645
|
decision: Literal[
|
|
479
646
|
'reused',
|
|
480
647
|
'recruited',
|
|
@@ -490,6 +657,13 @@ class ProjectAgentRecruitmentPolicyRecord(StrictModel):
|
|
|
490
657
|
personal_space_id: str
|
|
491
658
|
confirmation_mode: ProjectAgentRecruitmentConfirmationMode = 'automatic'
|
|
492
659
|
updated_at: datetime | None = None
|
|
660
|
+
policy_status: Literal['superseded'] = 'superseded'
|
|
661
|
+
applies_to_recruitment: Literal[False] = False
|
|
662
|
+
warning: str = (
|
|
663
|
+
'Legacy storage only; this setting does not control recruitment. '
|
|
664
|
+
'Use update_project_agent_coordination_policy with the exact project '
|
|
665
|
+
'and askBeforeRecruitment to change effective authorization.'
|
|
666
|
+
)
|
|
493
667
|
|
|
494
668
|
|
|
495
669
|
class ProjectAgentRecruitmentPolicyUpdate(StrictModel):
|
|
@@ -521,12 +695,26 @@ class ProjectAgentActivityTask(StrictModel):
|
|
|
521
695
|
actual_model_provider: str | None = None
|
|
522
696
|
actual_model: str | None = None
|
|
523
697
|
actual_executor_id: str | None = None
|
|
698
|
+
source_session_id: str | None = None
|
|
699
|
+
source_session_url: str | None = Field(default=None, max_length=2048)
|
|
700
|
+
tools_used: list[str] | None = Field(default=None, max_length=32)
|
|
701
|
+
token_usage: ProjectAgentTokenUsage | None = None
|
|
702
|
+
worker_runtime: ProjectAgentWorkerRuntime | None = None
|
|
524
703
|
matched_executor_rule_id: str | None = None
|
|
525
704
|
worker_id: str | None = None
|
|
526
705
|
worker_label: str | None = None
|
|
527
706
|
worker_occupation_emoji: str | None = None
|
|
528
707
|
worker_status: ProjectAgentTaskStatus | None = None
|
|
529
708
|
|
|
709
|
+
_validate_session_url = field_validator('source_session_url')(
|
|
710
|
+
normalize_source_session_url
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
@field_validator('tools_used')
|
|
714
|
+
@classmethod
|
|
715
|
+
def validate_tools_used(cls, value):
|
|
716
|
+
return _unique_text(value, 'tools used') if value is not None else None
|
|
717
|
+
|
|
530
718
|
|
|
531
719
|
class ProjectAgentActivityDay(StrictModel):
|
|
532
720
|
date: date
|
|
@@ -108,11 +108,37 @@ class LocalLexicalReranker(CrossEncoderClient):
|
|
|
108
108
|
)
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
class ManagedNeo4jDriver(Neo4jDriver):
|
|
112
|
+
"""Let GraphitiRuntime own index initialization exactly once.
|
|
113
|
+
|
|
114
|
+
graphiti-core schedules an eager background index build whenever its driver
|
|
115
|
+
is constructed inside a running event loop. Fuli has an explicit awaited
|
|
116
|
+
initialization sequence, so the dependency's untracked task would race it
|
|
117
|
+
and can leak unawaited query coroutines when one index request fails.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def __init__(self, *args, **kwargs):
|
|
121
|
+
self._fuli_constructing = True
|
|
122
|
+
try:
|
|
123
|
+
super().__init__(*args, **kwargs)
|
|
124
|
+
finally:
|
|
125
|
+
self._fuli_constructing = False
|
|
126
|
+
|
|
127
|
+
def build_indices_and_constraints(self, delete_existing: bool = False):
|
|
128
|
+
if self._fuli_constructing:
|
|
129
|
+
return _completed_index_build()
|
|
130
|
+
return super().build_indices_and_constraints(delete_existing)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
async def _completed_index_build() -> None:
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
|
|
111
137
|
class GraphitiRuntime:
|
|
112
138
|
def __init__(self, settings: Settings):
|
|
113
139
|
self.settings = settings
|
|
114
140
|
self.embedder = LocalHashEmbedder(settings.embedding_dim)
|
|
115
|
-
driver =
|
|
141
|
+
driver = ManagedNeo4jDriver(
|
|
116
142
|
uri=settings.neo4j_uri,
|
|
117
143
|
user=settings.neo4j_user,
|
|
118
144
|
password=settings.neo4j_password,
|
|
@@ -247,6 +273,16 @@ class GraphitiRuntime:
|
|
|
247
273
|
'FOR (n:FuliProjectAgent) REQUIRE n.id IS UNIQUE',
|
|
248
274
|
'CREATE CONSTRAINT fuli_project_agent_assignment_id IF NOT EXISTS '
|
|
249
275
|
'FOR (n:FuliProjectAgentAssignment) REQUIRE n.id IS UNIQUE',
|
|
276
|
+
'CREATE CONSTRAINT fuli_project_agent_memory_id IF NOT EXISTS '
|
|
277
|
+
'FOR (n:FuliProjectAgentMemory) REQUIRE n.id IS UNIQUE',
|
|
278
|
+
'CREATE CONSTRAINT fuli_project_agent_memory_checkpoint_id IF NOT EXISTS '
|
|
279
|
+
'FOR (n:FuliProjectAgentMemoryCheckpoint) REQUIRE n.id IS UNIQUE',
|
|
280
|
+
'CREATE CONSTRAINT fuli_task_context_session_id IF NOT EXISTS '
|
|
281
|
+
'FOR (n:FuliTaskContextSession) REQUIRE n.id IS UNIQUE',
|
|
282
|
+
'CREATE CONSTRAINT fuli_task_context_id IF NOT EXISTS '
|
|
283
|
+
'FOR (n:FuliTaskContext) REQUIRE n.id IS UNIQUE',
|
|
284
|
+
'CREATE INDEX fuli_task_context_agent_scope IF NOT EXISTS '
|
|
285
|
+
'FOR (n:FuliTaskContext) ON (n.personal_space_id, n.project_agent_id)',
|
|
250
286
|
'CREATE CONSTRAINT fuli_project_agent_task_id IF NOT EXISTS '
|
|
251
287
|
'FOR (n:FuliProjectAgentTask) REQUIRE n.id IS UNIQUE',
|
|
252
288
|
'CREATE CONSTRAINT fuli_project_agent_task_event_id IF NOT EXISTS '
|
|
@@ -4,17 +4,23 @@ from .runtime import GraphitiRuntime
|
|
|
4
4
|
from .store_identity import StoreIdentity
|
|
5
5
|
from .store_knowledge import StoreKnowledge
|
|
6
6
|
from .store_project_agent_executors import StoreProjectAgentExecutors
|
|
7
|
+
from .store_project_agent_memory import StoreProjectAgentMemory
|
|
8
|
+
from .store_project_agent_context import StoreProjectAgentContext
|
|
7
9
|
from .store_project_agents import StoreProjectAgents
|
|
8
10
|
from .store_project_agent_tasks import StoreProjectAgentTasks
|
|
9
11
|
from .store_projects import StoreProjects
|
|
10
12
|
from .store_publication import StorePublication
|
|
11
13
|
from .store_records import StoreRecords
|
|
14
|
+
from .store_task_contexts import StoreTaskContexts
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class GraphStore(
|
|
15
18
|
StoreIdentity,
|
|
16
19
|
StoreProjects,
|
|
17
20
|
StoreProjectAgents,
|
|
21
|
+
StoreProjectAgentMemory,
|
|
22
|
+
StoreProjectAgentContext,
|
|
23
|
+
StoreTaskContexts,
|
|
18
24
|
StoreProjectAgentExecutors,
|
|
19
25
|
StoreProjectAgentTasks,
|
|
20
26
|
StorePublication,
|