fuli-context 0.7.4-beta.2 → 0.7.5
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 +93 -7
- package/README.zh-CN.md +84 -7
- package/compose.graphiti.yml +6 -6
- package/dist/web/assets/AboutPage-ByCUor-j.js +1 -0
- package/dist/web/assets/ConnectionsPage-DkdkZ40Q.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-DSe3Gwep.js +1 -0
- package/dist/web/assets/KnowledgeInspector-CYAjAb9J.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-CV4F54R_.js +1 -0
- package/dist/web/assets/KnowledgePage-vYYXipOi.js +1 -0
- package/dist/web/assets/KnowledgeWorkspace-z4u5mXOG.js +4 -0
- package/dist/web/assets/OverviewPage-BWOfeS6k.js +1 -0
- package/dist/web/assets/PersonalProfilePage-c3w4-h7a.js +1 -0
- package/dist/web/assets/PersonalProjectsPage-B7AlLEwf.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-CgftpIPB.css +1 -0
- package/dist/web/assets/ProjectAgentsPage-DTHcL_ox.js +11 -0
- package/dist/web/assets/PublicProjectsPage-DdH0oGB3.js +1 -0
- package/dist/web/assets/ReviewPage-BYIpcIHG.js +1 -0
- package/dist/web/assets/SearchableSelect-Dz13ClQb.js +1 -0
- package/dist/web/assets/SettingsPage-2VkbXgZi.js +1 -0
- package/dist/web/assets/SettingsPage-CwZp2ka4.css +1 -0
- package/dist/web/assets/WritingTastePage-BOPQZuva.js +1 -0
- package/dist/web/assets/{console-DMvHxKf9.js → console-BlAhujsH.js} +1 -1
- package/dist/web/assets/{conversation-launcher-settings-Dnlcw7Rj.js → conversation-launcher-settings-DTYxiLJt.js} +1 -1
- package/dist/web/assets/i18n-Ci3heuiL.js +9 -0
- package/dist/web/assets/{identity-C9mLdR8L.js → identity-4_-v6cB7.js} +1 -1
- package/dist/web/assets/index-BnH5mcZx.css +1 -0
- package/dist/web/assets/index-C67Q0JY2.js +2 -0
- package/dist/web/assets/{model-CsYAR8O3.js → model-yG0YqUyZ.js} +1 -1
- package/dist/web/assets/{useApi-CROJJdhE-BLQiPVw0.js → useApi-CROJJdhE-twhdZArA.js} +1 -1
- package/dist/web/assets/vue-router-C-wot_Di.js +1 -0
- package/dist/web/index.html +6 -6
- package/docs/public-personal-architecture.md +73 -0
- package/graph-provider/fuli_graph/app.py +8 -0
- package/graph-provider/fuli_graph/collaboration_context.py +69 -6
- package/graph-provider/fuli_graph/knowledge_search.py +84 -5
- package/graph-provider/fuli_graph/model_validation.py +134 -0
- package/graph-provider/fuli_graph/models.py +24 -5
- package/graph-provider/fuli_graph/project_agent_access.py +54 -0
- package/graph-provider/fuli_graph/project_agent_executor_models.py +635 -0
- package/graph-provider/fuli_graph/project_agent_models.py +278 -0
- package/graph-provider/fuli_graph/project_agent_routes.py +597 -0
- package/graph-provider/fuli_graph/project_agent_task_models.py +542 -0
- package/graph-provider/fuli_graph/runtime.py +259 -0
- package/graph-provider/fuli_graph/search_projection.py +3 -0
- package/graph-provider/fuli_graph/store.py +6 -0
- package/graph-provider/fuli_graph/store_knowledge.py +62 -9
- package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +756 -0
- package/graph-provider/fuli_graph/store_project_agent_executor_routing.py +601 -0
- package/graph-provider/fuli_graph/store_project_agent_executors.py +1087 -0
- package/graph-provider/fuli_graph/store_project_agent_task_reads.py +458 -0
- package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +699 -0
- package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +409 -0
- package/graph-provider/fuli_graph/store_project_agent_tasks.py +1144 -0
- package/graph-provider/fuli_graph/store_project_agents.py +965 -0
- package/graph-provider/pyproject.toml +2 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -1
- package/skills/capturing-session-knowledge/SKILL.md +43 -2
- package/src/adaptive-runtime/executor-pool.js +127 -0
- package/src/adaptive-runtime/graph-services.js +166 -0
- package/src/adaptive-runtime/lease-client.js +335 -0
- package/src/adaptive-runtime/runtime-broker.js +318 -0
- package/src/adaptive-runtime/settings.js +111 -0
- package/src/adaptive-runtime/state.js +74 -0
- package/src/agent-tools/graph-definitions.js +396 -0
- package/src/agent-tools/graph-handlers.js +61 -0
- package/src/agent-tools/project-agent-definitions.js +307 -0
- package/src/backup/graph-backup.js +289 -0
- package/src/backup/identity-reconciliation.js +208 -0
- package/src/backup/runtime-adapters.js +269 -0
- package/src/cli/command-registry.js +7 -2
- package/src/cli/graph-data-command.js +112 -0
- package/src/cli/local-runtime-command.js +16 -2
- package/src/cli/setup-command.js +19 -3
- package/src/cli/update-command.js +4 -0
- package/src/cli/workspace-connection-command.js +333 -0
- package/src/cli.js +11 -0
- package/src/graphiti/collaboration-preference-projection.js +29 -1
- package/src/graphiti/collaboration-preference-workflow.js +121 -0
- package/src/graphiti/federated-application.js +74 -112
- package/src/graphiti/knowledge-provider-mapping.js +7 -1
- package/src/graphiti/project-agent-control-plane.js +263 -0
- package/src/graphiti/project-agent-mapping.js +1003 -0
- package/src/graphiti/project-agent-workflows.js +557 -0
- package/src/graphiti/provider-client.js +270 -1
- package/src/graphiti/runtime-config.js +6 -1
- package/src/graphiti/workspace-provider-client.js +403 -0
- package/src/http/api-router.js +63 -9
- package/src/http/graph-api-router.js +278 -0
- package/src/local-runtime/lifecycle.js +46 -10
- package/src/mcp/context-resources.js +15 -6
- package/src/mcp/create-mcp-server.js +51 -16
- package/src/mcp/instructions.js +7 -5
- package/src/mcp/runtime.js +17 -5
- package/src/mcp/session-id.js +38 -1
- package/src/mcp/tool-annotations.js +69 -0
- package/src/mcp-server.js +23 -6
- package/src/native-runtime/runtime.js +717 -0
- package/src/server.js +6 -2
- package/src/setup/agent-installation-status.js +7 -1
- package/src/setup/agents.js +3 -1
- package/src/setup/claude-code-config.js +3 -1
- package/src/setup/codex-bootstrap.js +11 -10
- package/src/setup/codex-config.js +7 -1
- package/src/setup/cursor-config.js +3 -1
- package/src/setup/graph-runtime.js +158 -13
- package/src/setup/neo4j-memory-profile.js +43 -0
- package/src/setup/options.js +38 -2
- package/src/setup/paths.js +14 -0
- package/src/setup/setup.js +37 -1
- package/src/system/resource-monitor.js +181 -16
- package/src/system/runtime-settings.js +10 -1
- package/src/system/system-service.js +27 -2
- package/dist/web/assets/AboutPage-CftRexSY.js +0 -1
- package/dist/web/assets/ConnectionsPage-D5J91x6d.js +0 -1
- package/dist/web/assets/KnowledgeEditDialog-wotVahvr.js +0 -1
- package/dist/web/assets/KnowledgeInspector-BzkW0mVs.js +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-BebUDiHt.js +0 -1
- package/dist/web/assets/KnowledgePage-OUT07aKH.js +0 -1
- package/dist/web/assets/KnowledgeWorkspace-1pHJ0MNZ.js +0 -4
- package/dist/web/assets/OverviewPage-CHE6XhdS.js +0 -1
- package/dist/web/assets/PersonalProfilePage-CXXiabUy.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-d2wYGW8n.js +0 -1
- package/dist/web/assets/PublicProjectsPage-hxLShtnZ.js +0 -1
- package/dist/web/assets/ReviewPage-DUeyu7E8.js +0 -1
- package/dist/web/assets/SearchableSelect-C5RiB5F8.js +0 -1
- package/dist/web/assets/SettingsPage-BMuASSzQ.js +0 -1
- package/dist/web/assets/SettingsPage-CAfz4qiV.css +0 -1
- package/dist/web/assets/WritingTastePage-B9BCYIwQ.js +0 -1
- package/dist/web/assets/i18n-CWfd8Dtt.js +0 -5
- package/dist/web/assets/index-X2j29j8i.css +0 -1
- package/dist/web/assets/index-nP5p5OaY.js +0 -2
- package/dist/web/assets/vue-router-DN8x6iY1.js +0 -1
|
@@ -18,6 +18,9 @@ from graphiti_core.prompts.models import Message
|
|
|
18
18
|
from pydantic import BaseModel
|
|
19
19
|
|
|
20
20
|
from .config import Settings
|
|
21
|
+
from .store_project_agent_executor_learning import (
|
|
22
|
+
project_agent_executor_outcome_bucket_id,
|
|
23
|
+
)
|
|
21
24
|
|
|
22
25
|
|
|
23
26
|
class AgentStructuredLLM(LLMClient):
|
|
@@ -235,6 +238,42 @@ class GraphitiRuntime:
|
|
|
235
238
|
'FOR (n:FuliPersonalProjectRelationReview) '
|
|
236
239
|
'REQUIRE n.id IS UNIQUE'
|
|
237
240
|
)
|
|
241
|
+
# Legacy learning caches were keyed only by a composite property map.
|
|
242
|
+
# Collapse those buckets before adding ID uniqueness so startup remains
|
|
243
|
+
# safe for upgraded stores as well as fresh databases.
|
|
244
|
+
await self._migrate_project_agent_executor_learning_buckets()
|
|
245
|
+
for query in (
|
|
246
|
+
'CREATE CONSTRAINT fuli_project_agent_id IF NOT EXISTS '
|
|
247
|
+
'FOR (n:FuliProjectAgent) REQUIRE n.id IS UNIQUE',
|
|
248
|
+
'CREATE CONSTRAINT fuli_project_agent_assignment_id IF NOT EXISTS '
|
|
249
|
+
'FOR (n:FuliProjectAgentAssignment) REQUIRE n.id IS UNIQUE',
|
|
250
|
+
'CREATE CONSTRAINT fuli_project_agent_task_id IF NOT EXISTS '
|
|
251
|
+
'FOR (n:FuliProjectAgentTask) REQUIRE n.id IS UNIQUE',
|
|
252
|
+
'CREATE CONSTRAINT fuli_project_agent_task_event_id IF NOT EXISTS '
|
|
253
|
+
'FOR (n:FuliProjectAgentTaskEvent) REQUIRE n.id IS UNIQUE',
|
|
254
|
+
'CREATE CONSTRAINT fuli_project_agent_routing_decision_id IF NOT EXISTS '
|
|
255
|
+
'FOR (n:FuliProjectAgentRoutingDecision) REQUIRE n.id IS UNIQUE',
|
|
256
|
+
'CREATE CONSTRAINT fuli_project_agent_recruitment_id IF NOT EXISTS '
|
|
257
|
+
'FOR (n:FuliProjectAgentRecruitment) REQUIRE n.id IS UNIQUE',
|
|
258
|
+
'CREATE CONSTRAINT fuli_project_agent_recruitment_policy_space '
|
|
259
|
+
'IF NOT EXISTS FOR (n:FuliProjectAgentRecruitmentPolicy) '
|
|
260
|
+
'REQUIRE n.personal_space_id IS UNIQUE',
|
|
261
|
+
'CREATE CONSTRAINT fuli_project_agent_executor_id IF NOT EXISTS '
|
|
262
|
+
'FOR (n:FuliProjectAgentExecutor) REQUIRE n.id IS UNIQUE',
|
|
263
|
+
'CREATE CONSTRAINT fuli_project_agent_executor_routing_rule_id IF NOT EXISTS '
|
|
264
|
+
'FOR (n:FuliProjectAgentExecutorRoutingRule) REQUIRE n.id IS UNIQUE',
|
|
265
|
+
'CREATE CONSTRAINT fuli_project_agent_executor_decision_id IF NOT EXISTS '
|
|
266
|
+
'FOR (n:FuliProjectAgentExecutorDecision) REQUIRE n.id IS UNIQUE',
|
|
267
|
+
'CREATE CONSTRAINT fuli_project_agent_executor_outcome_evidence_id IF NOT EXISTS '
|
|
268
|
+
'FOR (n:FuliProjectAgentExecutorOutcomeEvidence) REQUIRE n.id IS UNIQUE',
|
|
269
|
+
'CREATE CONSTRAINT fuli_project_agent_executor_outcome_aggregate_id IF NOT EXISTS '
|
|
270
|
+
'FOR (n:FuliProjectAgentExecutorOutcomeAggregate) REQUIRE n.id IS UNIQUE',
|
|
271
|
+
'CREATE CONSTRAINT fuli_project_agent_executor_outcome_reset_id IF NOT EXISTS '
|
|
272
|
+
'FOR (n:FuliProjectAgentExecutorOutcomeReset) REQUIRE n.id IS UNIQUE',
|
|
273
|
+
'CREATE CONSTRAINT fuli_project_agent_executor_observation_id IF NOT EXISTS '
|
|
274
|
+
'FOR (n:FuliProjectAgentExecutorObservation) REQUIRE n.id IS UNIQUE',
|
|
275
|
+
):
|
|
276
|
+
await self.driver.execute_query(query)
|
|
238
277
|
for query in (
|
|
239
278
|
'CREATE INDEX fuli_entity_confirmation IF NOT EXISTS '
|
|
240
279
|
'FOR (n:Entity) ON (n.group_id, n.fuli_confirmation_status)',
|
|
@@ -259,14 +298,234 @@ class GraphitiRuntime:
|
|
|
259
298
|
'ON (n.personal_space_id, n.scope_key, n.status)',
|
|
260
299
|
'CREATE INDEX fuli_personal_project_relation_type IF NOT EXISTS '
|
|
261
300
|
'FOR ()-[r:PERSONAL_PROJECT_RELATION]-() ON (r.relation_type)',
|
|
301
|
+
'CREATE INDEX fuli_project_agent_assignment_lookup IF NOT EXISTS '
|
|
302
|
+
'FOR (n:FuliProjectAgentAssignment) '
|
|
303
|
+
'ON (n.status, n.assigned_at)',
|
|
304
|
+
'CREATE INDEX fuli_project_agent_task_lookup IF NOT EXISTS '
|
|
305
|
+
'FOR (n:FuliProjectAgentTask) '
|
|
306
|
+
'ON (n.personal_space_id, n.personal_project_id, n.status)',
|
|
307
|
+
'CREATE INDEX fuli_project_agent_event_activity IF NOT EXISTS '
|
|
308
|
+
'FOR (n:FuliProjectAgentTaskEvent) '
|
|
309
|
+
'ON (n.agent_id, n.activity_date, n.status)',
|
|
310
|
+
'CREATE INDEX fuli_project_agent_executor_eligibility IF NOT EXISTS '
|
|
311
|
+
'FOR (n:FuliProjectAgentExecutor) '
|
|
312
|
+
'ON (n.personal_space_id, n.registration_status, n.preflight_status, n.health_status)',
|
|
313
|
+
'CREATE INDEX fuli_project_agent_executor_rule_scope IF NOT EXISTS '
|
|
314
|
+
'FOR (n:FuliProjectAgentExecutorRoutingRule) '
|
|
315
|
+
'ON (n.personal_space_id, n.scope, n.personal_project_id, n.task_id)',
|
|
316
|
+
'CREATE INDEX fuli_project_agent_executor_evidence_lookup IF NOT EXISTS '
|
|
317
|
+
'FOR (n:FuliProjectAgentExecutorOutcomeEvidence) '
|
|
318
|
+
'ON (n.personal_space_id, n.agent_id, n.work_kind, n.executor_id, n.occurred_at)',
|
|
319
|
+
'CREATE INDEX fuli_project_agent_aggregate_lookup IF NOT EXISTS '
|
|
320
|
+
'FOR (n:FuliProjectAgentExecutorOutcomeAggregate) '
|
|
321
|
+
'ON (n.personal_space_id, n.personal_project_id, n.agent_id, '
|
|
322
|
+
'n.work_kind, n.executor_id, n.model_strategy_key)',
|
|
262
323
|
):
|
|
263
324
|
await self.driver.execute_query(query)
|
|
325
|
+
await self._migrate_project_agent_control_plane()
|
|
264
326
|
await self._migrate_knowledge_lifecycle_defaults()
|
|
265
327
|
await self._migrate_personal_project_relation_review_defaults()
|
|
266
328
|
await self._migrate_space_visibility_and_owners()
|
|
267
329
|
await self._migrate_project_releases()
|
|
268
330
|
await self._migrate_legacy_group_ids()
|
|
269
331
|
|
|
332
|
+
async def _migrate_project_agent_executor_learning_buckets(self) -> None:
|
|
333
|
+
"""Give legacy learning caches stable IDs and collapse duplicates.
|
|
334
|
+
|
|
335
|
+
Aggregates and resets are replaceable projections. For each complete
|
|
336
|
+
provider/space bucket we keep the newest projection, remove only older
|
|
337
|
+
projection nodes, and leave immutable outcome evidence untouched.
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
bucket_properties = (
|
|
341
|
+
'personal_space_id',
|
|
342
|
+
'personal_project_id',
|
|
343
|
+
'work_kind',
|
|
344
|
+
'agent_id',
|
|
345
|
+
'executor_id',
|
|
346
|
+
'model_strategy_key',
|
|
347
|
+
)
|
|
348
|
+
migrations = (
|
|
349
|
+
(
|
|
350
|
+
'FuliProjectAgentExecutorOutcomeAggregate',
|
|
351
|
+
'aggregate',
|
|
352
|
+
'bucket.as_of',
|
|
353
|
+
'aggregate_id',
|
|
354
|
+
),
|
|
355
|
+
(
|
|
356
|
+
'FuliProjectAgentExecutorOutcomeReset',
|
|
357
|
+
'reset',
|
|
358
|
+
'bucket.reset_at',
|
|
359
|
+
'reset_id',
|
|
360
|
+
),
|
|
361
|
+
)
|
|
362
|
+
for label, bucket_kind, latest_property, public_id_property in migrations:
|
|
363
|
+
projections = ', '.join(
|
|
364
|
+
f'bucket.{property_name} AS {property_name}'
|
|
365
|
+
for property_name in bucket_properties
|
|
366
|
+
)
|
|
367
|
+
completeness = ' AND '.join(
|
|
368
|
+
f'bucket.{property_name} IS NOT NULL'
|
|
369
|
+
for property_name in bucket_properties
|
|
370
|
+
)
|
|
371
|
+
records, _, _ = await self.driver.execute_query(
|
|
372
|
+
f'''
|
|
373
|
+
MATCH (bucket:{label})
|
|
374
|
+
WHERE {completeness}
|
|
375
|
+
RETURN DISTINCT {projections}
|
|
376
|
+
''',
|
|
377
|
+
routing_='r',
|
|
378
|
+
)
|
|
379
|
+
for record in records:
|
|
380
|
+
bucket = {
|
|
381
|
+
property_name: str(record[property_name])
|
|
382
|
+
for property_name in bucket_properties
|
|
383
|
+
}
|
|
384
|
+
bucket_id = project_agent_executor_outcome_bucket_id(
|
|
385
|
+
self.settings.provider_id,
|
|
386
|
+
bucket['personal_space_id'],
|
|
387
|
+
bucket['personal_project_id'],
|
|
388
|
+
bucket['work_kind'],
|
|
389
|
+
bucket['agent_id'],
|
|
390
|
+
bucket['executor_id'],
|
|
391
|
+
bucket['model_strategy_key'],
|
|
392
|
+
bucket_kind=bucket_kind,
|
|
393
|
+
)
|
|
394
|
+
property_match = ', '.join(
|
|
395
|
+
f'{property_name}: ${property_name}'
|
|
396
|
+
for property_name in bucket_properties
|
|
397
|
+
)
|
|
398
|
+
await self.driver.execute_query(
|
|
399
|
+
f'''
|
|
400
|
+
MATCH (bucket:{label} {{{property_match}}})
|
|
401
|
+
WITH bucket
|
|
402
|
+
ORDER BY coalesce(
|
|
403
|
+
{latest_property},
|
|
404
|
+
bucket.updated_at,
|
|
405
|
+
bucket.created_at,
|
|
406
|
+
datetime({{epochMillis: 0}})
|
|
407
|
+
) DESC, elementId(bucket) DESC
|
|
408
|
+
WITH collect(bucket) AS buckets
|
|
409
|
+
WITH head(buckets) AS keeper, tail(buckets) AS duplicates
|
|
410
|
+
CALL {{
|
|
411
|
+
WITH duplicates
|
|
412
|
+
UNWIND duplicates AS duplicate
|
|
413
|
+
DETACH DELETE duplicate
|
|
414
|
+
RETURN count(*) AS removed_count
|
|
415
|
+
}}
|
|
416
|
+
SET keeper.id = $bucket_id,
|
|
417
|
+
keeper.{public_id_property} = $bucket_id
|
|
418
|
+
RETURN removed_count
|
|
419
|
+
''',
|
|
420
|
+
**bucket,
|
|
421
|
+
bucket_id=bucket_id,
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
async def _migrate_project_agent_control_plane(self) -> None:
|
|
425
|
+
"""Preserve legacy project-bound records while adding space identities.
|
|
426
|
+
|
|
427
|
+
The migration does not merge Agents by name or rewrite any existing
|
|
428
|
+
knowledge namespace. It only creates explicit assignment history and
|
|
429
|
+
the one system coordinator required by the lightweight control plane.
|
|
430
|
+
"""
|
|
431
|
+
await self.driver.execute_query(
|
|
432
|
+
'''
|
|
433
|
+
MATCH (space:FuliSpace {kind: 'personal'})-[:CONTAINS_PROJECT]->
|
|
434
|
+
(project:FuliPersonalProject)-[:HAS_PROJECT_AGENT]->
|
|
435
|
+
(agent:FuliProjectAgent)
|
|
436
|
+
MERGE (space)-[:HAS_PROJECT_AGENT_IDENTITY]->(agent)
|
|
437
|
+
SET agent.agent_id = coalesce(agent.agent_id, agent.id),
|
|
438
|
+
agent.agent_type = coalesce(agent.agent_type, 'durable'),
|
|
439
|
+
agent.memory_scope = coalesce(agent.memory_scope, 'reviewed_agent'),
|
|
440
|
+
agent.status = coalesce(agent.status, 'active')
|
|
441
|
+
WITH project, agent,
|
|
442
|
+
agent.id + ':legacy-assignment:' + project.id AS assignment_id
|
|
443
|
+
MERGE (assignment:FuliProjectAgentAssignment {id: assignment_id})
|
|
444
|
+
ON CREATE SET assignment.assignment_id = assignment_id,
|
|
445
|
+
assignment.responsibility =
|
|
446
|
+
coalesce(agent.responsibility, agent.name),
|
|
447
|
+
assignment.work_kinds =
|
|
448
|
+
coalesce(agent.work_kinds, []),
|
|
449
|
+
assignment.capabilities =
|
|
450
|
+
coalesce(agent.capabilities, []),
|
|
451
|
+
assignment.reason = 'legacy Project Agent migration',
|
|
452
|
+
assignment.status = CASE agent.status
|
|
453
|
+
WHEN 'active' THEN 'active' ELSE 'ended' END,
|
|
454
|
+
assignment.revision = 0,
|
|
455
|
+
assignment.assigned_at = agent.created_at,
|
|
456
|
+
assignment.updated_at =
|
|
457
|
+
coalesce(agent.updated_at, agent.created_at),
|
|
458
|
+
assignment.legacy_assignment = true
|
|
459
|
+
MERGE (project)-[:HAS_PROJECT_AGENT_ASSIGNMENT]->(assignment)
|
|
460
|
+
MERGE (assignment)-[:ASSIGNED_AGENT]->(agent)
|
|
461
|
+
'''
|
|
462
|
+
)
|
|
463
|
+
await self.driver.execute_query(
|
|
464
|
+
'''
|
|
465
|
+
MATCH (space:FuliSpace {kind: 'personal'})
|
|
466
|
+
MERGE (policy:FuliProjectAgentRecruitmentPolicy {
|
|
467
|
+
personal_space_id: space.id
|
|
468
|
+
})
|
|
469
|
+
ON CREATE SET policy.confirmation_mode = 'automatic',
|
|
470
|
+
policy.updated_at = datetime()
|
|
471
|
+
MERGE (space)-[:HAS_PROJECT_AGENT_RECRUITMENT_POLICY]->(policy)
|
|
472
|
+
'''
|
|
473
|
+
)
|
|
474
|
+
records, _, _ = await self.driver.execute_query(
|
|
475
|
+
"MATCH (space:FuliSpace {kind: 'personal'}) RETURN space.id AS space_id",
|
|
476
|
+
routing_='r',
|
|
477
|
+
)
|
|
478
|
+
if not records:
|
|
479
|
+
return
|
|
480
|
+
from .project_agent_models import ProjectAgentProfile
|
|
481
|
+
from .provider_values import now_utc, stable_uuid
|
|
482
|
+
|
|
483
|
+
profile = ProjectAgentProfile(
|
|
484
|
+
name='项目协调人',
|
|
485
|
+
responsibility='评估任务、应用用户配置并路由已有 Agent。',
|
|
486
|
+
agent_type='coordinator',
|
|
487
|
+
work_kinds=['task-coordination'],
|
|
488
|
+
capabilities=['任务评估', '策略应用', 'Agent 路由'],
|
|
489
|
+
initial_preferences=['质量与可验收完成优先于成本和时间'],
|
|
490
|
+
status='active',
|
|
491
|
+
)
|
|
492
|
+
updated_at = now_utc()
|
|
493
|
+
for record in records:
|
|
494
|
+
space_id = record['space_id']
|
|
495
|
+
node_id = stable_uuid(
|
|
496
|
+
self.settings.provider_id,
|
|
497
|
+
space_id,
|
|
498
|
+
'project-agent',
|
|
499
|
+
'fuli-project-coordinator',
|
|
500
|
+
)
|
|
501
|
+
await self.driver.execute_query(
|
|
502
|
+
'''
|
|
503
|
+
MATCH (space:FuliSpace {id: $space_id, kind: 'personal'})
|
|
504
|
+
MERGE (agent:FuliProjectAgent {id: $id})
|
|
505
|
+
ON CREATE SET agent.agent_id = 'fuli-project-coordinator',
|
|
506
|
+
agent.profile_json = $profile_json,
|
|
507
|
+
agent.name = $name,
|
|
508
|
+
agent.responsibility = $responsibility,
|
|
509
|
+
agent.capabilities = $capabilities,
|
|
510
|
+
agent.work_kinds = $work_kinds,
|
|
511
|
+
agent.agent_type = 'coordinator',
|
|
512
|
+
agent.memory_scope = 'reviewed_agent',
|
|
513
|
+
agent.status = 'active',
|
|
514
|
+
agent.system_managed = true,
|
|
515
|
+
agent.created_at = $updated_at,
|
|
516
|
+
agent.updated_at = $updated_at
|
|
517
|
+
MERGE (space)-[:HAS_PROJECT_AGENT_IDENTITY]->(agent)
|
|
518
|
+
''',
|
|
519
|
+
space_id=space_id,
|
|
520
|
+
id=node_id,
|
|
521
|
+
profile_json=profile.model_dump_json(),
|
|
522
|
+
name=profile.name,
|
|
523
|
+
responsibility=profile.responsibility,
|
|
524
|
+
capabilities=profile.capabilities,
|
|
525
|
+
work_kinds=profile.work_kinds,
|
|
526
|
+
updated_at=updated_at,
|
|
527
|
+
)
|
|
528
|
+
|
|
270
529
|
async def _migrate_personal_project_relation_review_defaults(self) -> None:
|
|
271
530
|
await self.driver.execute_query(
|
|
272
531
|
'''
|
|
@@ -57,6 +57,7 @@ async def read_edge_epistemic_metadata(store, edge_ids: list[str]) -> dict[str,
|
|
|
57
57
|
ELSE coalesce(edge.fuli_preference_scope, 'global') END
|
|
58
58
|
AS preference_scope,
|
|
59
59
|
edge.fuli_preference_project_id AS preference_project_id,
|
|
60
|
+
edge.fuli_preference_agent_id AS preference_agent_id,
|
|
60
61
|
edge.fuli_key AS key,
|
|
61
62
|
edge.fuli_attributes_json AS attributes_json,
|
|
62
63
|
coalesce(edge.fuli_inheritance_mode, 'local_only')
|
|
@@ -140,6 +141,7 @@ def fact_result(
|
|
|
140
141
|
profile_aspect=metadata.get('profile_aspect'),
|
|
141
142
|
preference_scope=metadata.get('preference_scope'),
|
|
142
143
|
preference_project_id=metadata.get('preference_project_id'),
|
|
144
|
+
preference_agent_id=metadata.get('preference_agent_id'),
|
|
143
145
|
key=metadata.get('key'),
|
|
144
146
|
preference_key=(
|
|
145
147
|
attributes.get('preferenceKey')
|
|
@@ -149,6 +151,7 @@ def fact_result(
|
|
|
149
151
|
),
|
|
150
152
|
preference_qualifiers=preference_qualifiers(attributes),
|
|
151
153
|
defined_project_id=metadata.get('defined_project_id'),
|
|
154
|
+
project_agent_id=metadata.get('project_agent_id'),
|
|
152
155
|
inheritance_mode=metadata.get('inheritance_mode') or 'local_only',
|
|
153
156
|
inherited_project_ids=metadata.get('inherited_project_ids') or [],
|
|
154
157
|
human_edited=metadata.get('human_edited') is True,
|
|
@@ -3,6 +3,9 @@ from .provider_values import graphiti_group_id, native_datetime
|
|
|
3
3
|
from .runtime import GraphitiRuntime
|
|
4
4
|
from .store_identity import StoreIdentity
|
|
5
5
|
from .store_knowledge import StoreKnowledge
|
|
6
|
+
from .store_project_agent_executors import StoreProjectAgentExecutors
|
|
7
|
+
from .store_project_agents import StoreProjectAgents
|
|
8
|
+
from .store_project_agent_tasks import StoreProjectAgentTasks
|
|
6
9
|
from .store_projects import StoreProjects
|
|
7
10
|
from .store_publication import StorePublication
|
|
8
11
|
from .store_records import StoreRecords
|
|
@@ -11,6 +14,9 @@ from .store_records import StoreRecords
|
|
|
11
14
|
class GraphStore(
|
|
12
15
|
StoreIdentity,
|
|
13
16
|
StoreProjects,
|
|
17
|
+
StoreProjectAgents,
|
|
18
|
+
StoreProjectAgentExecutors,
|
|
19
|
+
StoreProjectAgentTasks,
|
|
14
20
|
StorePublication,
|
|
15
21
|
StoreKnowledge,
|
|
16
22
|
StoreRecords,
|
|
@@ -16,6 +16,7 @@ from .models import (
|
|
|
16
16
|
StructuredEpisode,
|
|
17
17
|
)
|
|
18
18
|
from .personal_project_access import authorize_personal_project
|
|
19
|
+
from .project_agent_access import authorize_project_agent
|
|
19
20
|
from .provider_values import now_utc, stable_uuid
|
|
20
21
|
from .workflow_candidates import materialize_workflow_candidates
|
|
21
22
|
|
|
@@ -30,10 +31,21 @@ class StoreKnowledge:
|
|
|
30
31
|
await authorize_personal_project(
|
|
31
32
|
self, actor, space, request.personal_project_id
|
|
32
33
|
)
|
|
34
|
+
if request.project_agent_id:
|
|
35
|
+
await authorize_project_agent(
|
|
36
|
+
self,
|
|
37
|
+
actor,
|
|
38
|
+
space,
|
|
39
|
+
request.personal_project_id,
|
|
40
|
+
request.project_agent_id,
|
|
41
|
+
require_active=True,
|
|
42
|
+
require_memory=True,
|
|
43
|
+
)
|
|
33
44
|
return await self._commit_episode(
|
|
34
45
|
space,
|
|
35
46
|
request.episode,
|
|
36
47
|
personal_project_id=request.personal_project_id,
|
|
48
|
+
project_agent_id=request.project_agent_id,
|
|
37
49
|
)
|
|
38
50
|
|
|
39
51
|
async def commit_workflow_observation(
|
|
@@ -52,10 +64,21 @@ class StoreKnowledge:
|
|
|
52
64
|
await authorize_personal_project(
|
|
53
65
|
self, actor, space, request.personal_project_id
|
|
54
66
|
)
|
|
67
|
+
if request.project_agent_id:
|
|
68
|
+
await authorize_project_agent(
|
|
69
|
+
self,
|
|
70
|
+
actor,
|
|
71
|
+
space,
|
|
72
|
+
request.personal_project_id,
|
|
73
|
+
request.project_agent_id,
|
|
74
|
+
require_active=True,
|
|
75
|
+
require_memory=True,
|
|
76
|
+
)
|
|
55
77
|
return await self._commit_episode(
|
|
56
78
|
space,
|
|
57
79
|
request.episode,
|
|
58
80
|
personal_project_id=request.personal_project_id,
|
|
81
|
+
project_agent_id=request.project_agent_id,
|
|
59
82
|
workflow_session_authority='mcp_host',
|
|
60
83
|
)
|
|
61
84
|
|
|
@@ -80,6 +103,7 @@ class StoreKnowledge:
|
|
|
80
103
|
space_id: str,
|
|
81
104
|
personal_project_id: str | None = None,
|
|
82
105
|
limit: int = 100,
|
|
106
|
+
project_agent_id: str | None = None,
|
|
83
107
|
) -> CollaborationContextResult:
|
|
84
108
|
return await read_collaboration_context(
|
|
85
109
|
self,
|
|
@@ -87,6 +111,7 @@ class StoreKnowledge:
|
|
|
87
111
|
space_id,
|
|
88
112
|
personal_project_id,
|
|
89
113
|
limit,
|
|
114
|
+
project_agent_id,
|
|
90
115
|
)
|
|
91
116
|
|
|
92
117
|
async def _commit_episode(
|
|
@@ -95,6 +120,7 @@ class StoreKnowledge:
|
|
|
95
120
|
episode: StructuredEpisode,
|
|
96
121
|
*,
|
|
97
122
|
personal_project_id: str | None = None,
|
|
123
|
+
project_agent_id: str | None = None,
|
|
98
124
|
workflow_session_authority: str | None = None,
|
|
99
125
|
) -> CommitResult:
|
|
100
126
|
group_id = space['group_id']
|
|
@@ -112,6 +138,7 @@ class StoreKnowledge:
|
|
|
112
138
|
space['kind'],
|
|
113
139
|
personal_project_id,
|
|
114
140
|
entity.key,
|
|
141
|
+
project_agent_id=project_agent_id,
|
|
115
142
|
)
|
|
116
143
|
for entity in episode.entities
|
|
117
144
|
]
|
|
@@ -129,6 +156,7 @@ class StoreKnowledge:
|
|
|
129
156
|
relationship.key,
|
|
130
157
|
relationship.fact,
|
|
131
158
|
(relationship.valid_at or episode.reference_time).isoformat(),
|
|
159
|
+
project_agent_id=project_agent_id,
|
|
132
160
|
workflow_session_authority=workflow_session_authority,
|
|
133
161
|
)
|
|
134
162
|
for relationship in episode.relationships
|
|
@@ -208,12 +236,16 @@ class StoreKnowledge:
|
|
|
208
236
|
'inheritance_mode': entity.inheritance_mode,
|
|
209
237
|
'inherited_project_ids': entity.inherited_project_ids,
|
|
210
238
|
'preference_scope': (
|
|
211
|
-
'
|
|
239
|
+
'agent' if entity.profile_aspect and project_agent_id
|
|
240
|
+
else 'project' if entity.profile_aspect and personal_project_id
|
|
212
241
|
else 'global' if entity.profile_aspect else None
|
|
213
242
|
),
|
|
214
243
|
'preference_project_id': (
|
|
215
244
|
personal_project_id if entity.profile_aspect else None
|
|
216
245
|
),
|
|
246
|
+
'preference_agent_id': (
|
|
247
|
+
project_agent_id if entity.profile_aspect else None
|
|
248
|
+
),
|
|
217
249
|
'attributes_json': json.dumps(
|
|
218
250
|
entity.attributes, ensure_ascii=False, sort_keys=True
|
|
219
251
|
),
|
|
@@ -262,12 +294,16 @@ class StoreKnowledge:
|
|
|
262
294
|
'inheritance_mode': relationship.inheritance_mode,
|
|
263
295
|
'inherited_project_ids': relationship.inherited_project_ids,
|
|
264
296
|
'preference_scope': (
|
|
265
|
-
'
|
|
297
|
+
'agent' if relationship.profile_aspect and project_agent_id
|
|
298
|
+
else 'project' if relationship.profile_aspect and personal_project_id
|
|
266
299
|
else 'global' if relationship.profile_aspect else None
|
|
267
300
|
),
|
|
268
301
|
'preference_project_id': (
|
|
269
302
|
personal_project_id if relationship.profile_aspect else None
|
|
270
303
|
),
|
|
304
|
+
'preference_agent_id': (
|
|
305
|
+
project_agent_id if relationship.profile_aspect else None
|
|
306
|
+
),
|
|
271
307
|
'attributes_json': json.dumps(
|
|
272
308
|
relationship.attributes, ensure_ascii=False, sort_keys=True
|
|
273
309
|
),
|
|
@@ -325,6 +361,7 @@ class StoreKnowledge:
|
|
|
325
361
|
entity.fuli_inherited_project_ids = row.inherited_project_ids,
|
|
326
362
|
entity.fuli_preference_scope = row.preference_scope,
|
|
327
363
|
entity.fuli_preference_project_id = row.preference_project_id,
|
|
364
|
+
entity.fuli_preference_agent_id = row.preference_agent_id,
|
|
328
365
|
entity.fuli_attributes_json = row.attributes_json
|
|
329
366
|
WITH count(entity) AS entity_count
|
|
330
367
|
CREATE (episode:Episodic {
|
|
@@ -346,6 +383,7 @@ class StoreKnowledge:
|
|
|
346
383
|
fuli_summary: $summary,
|
|
347
384
|
fuli_sensitivity: $sensitivity,
|
|
348
385
|
fuli_personal_project_id: $personal_project_id,
|
|
386
|
+
fuli_project_agent_id: $project_agent_id,
|
|
349
387
|
fuli_idempotency_key: $idempotency_key,
|
|
350
388
|
fuli_workflow_session_authority:
|
|
351
389
|
$workflow_session_authority
|
|
@@ -388,6 +426,7 @@ class StoreKnowledge:
|
|
|
388
426
|
edge.fuli_inherited_project_ids = row.inherited_project_ids,
|
|
389
427
|
edge.fuli_preference_scope = row.preference_scope,
|
|
390
428
|
edge.fuli_preference_project_id = row.preference_project_id,
|
|
429
|
+
edge.fuli_preference_agent_id = row.preference_agent_id,
|
|
391
430
|
edge.fuli_attributes_json = row.attributes_json,
|
|
392
431
|
edge.fuli_workflow_condition_json =
|
|
393
432
|
row.workflow_condition_json,
|
|
@@ -436,6 +475,17 @@ class StoreKnowledge:
|
|
|
436
475
|
}
|
|
437
476
|
)
|
|
438
477
|
)
|
|
478
|
+
AND EXISTS {
|
|
479
|
+
MATCH (agent_episode:Episodic {group_id: $group_id})
|
|
480
|
+
WHERE agent_episode.uuid IN coalesce(old.episodes, [])
|
|
481
|
+
AND (
|
|
482
|
+
agent_episode.fuli_project_agent_id = $project_agent_id
|
|
483
|
+
OR (
|
|
484
|
+
agent_episode.fuli_project_agent_id IS NULL
|
|
485
|
+
AND $project_agent_id IS NULL
|
|
486
|
+
)
|
|
487
|
+
)
|
|
488
|
+
}
|
|
439
489
|
AND any(
|
|
440
490
|
replacement IN $superseded_relationships
|
|
441
491
|
WHERE replacement.key = old.fuli_key
|
|
@@ -478,6 +528,7 @@ class StoreKnowledge:
|
|
|
478
528
|
summary=episode.summary,
|
|
479
529
|
sensitivity=episode.sensitivity,
|
|
480
530
|
personal_project_id=personal_project_id,
|
|
531
|
+
project_agent_id=project_agent_id,
|
|
481
532
|
workflow_session_authority=workflow_session_authority,
|
|
482
533
|
idempotency_key=episode.idempotency_key,
|
|
483
534
|
)
|
|
@@ -531,15 +582,14 @@ def _entity_id(
|
|
|
531
582
|
space_kind: str,
|
|
532
583
|
personal_project_id: str | None,
|
|
533
584
|
key: str,
|
|
585
|
+
*,
|
|
586
|
+
project_agent_id: str | None = None,
|
|
534
587
|
) -> str:
|
|
535
588
|
if space_kind == 'personal' and personal_project_id:
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
'
|
|
539
|
-
|
|
540
|
-
personal_project_id,
|
|
541
|
-
key,
|
|
542
|
-
)
|
|
589
|
+
parts = [group_id, 'entity', 'personal-project', personal_project_id]
|
|
590
|
+
if project_agent_id:
|
|
591
|
+
parts.extend(['project-agent', project_agent_id])
|
|
592
|
+
return stable_uuid(*parts, key)
|
|
543
593
|
return stable_uuid(group_id, 'entity', key)
|
|
544
594
|
|
|
545
595
|
|
|
@@ -551,11 +601,14 @@ def _relationship_id(
|
|
|
551
601
|
fact: str,
|
|
552
602
|
reference_time: str,
|
|
553
603
|
*,
|
|
604
|
+
project_agent_id: str | None = None,
|
|
554
605
|
workflow_session_authority: str | None = None,
|
|
555
606
|
) -> str:
|
|
556
607
|
parts = [group_id, 'relationship']
|
|
557
608
|
if space_kind == 'personal' and personal_project_id:
|
|
558
609
|
parts.extend(['personal-project', personal_project_id])
|
|
610
|
+
if project_agent_id:
|
|
611
|
+
parts.extend(['project-agent', project_agent_id])
|
|
559
612
|
if workflow_session_authority:
|
|
560
613
|
parts.extend([
|
|
561
614
|
'workflow-session-authority',
|