contextsynapse 1.0.0__py3-none-any.whl
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.
- contextsynapse/__init__.py +107 -0
- contextsynapse/__main__.py +9 -0
- contextsynapse/a2a/__init__.py +28 -0
- contextsynapse/a2a/client.py +120 -0
- contextsynapse/a2a/discovery.py +128 -0
- contextsynapse/a2a/handlers.py +164 -0
- contextsynapse/a2a/models.py +246 -0
- contextsynapse/a2a/streaming.py +92 -0
- contextsynapse/a2a/task_manager.py +275 -0
- contextsynapse/adapters/__init__.py +98 -0
- contextsynapse/adapters/_base.py +298 -0
- contextsynapse/adapters/autogen/__init__.py +4 -0
- contextsynapse/adapters/autogen/tools.py +34 -0
- contextsynapse/adapters/crewai/__init__.py +4 -0
- contextsynapse/adapters/crewai/tools.py +63 -0
- contextsynapse/adapters/langchain/__init__.py +19 -0
- contextsynapse/adapters/langchain/message_history.py +17 -0
- contextsynapse/adapters/langchain/retriever.py +158 -0
- contextsynapse/adapters/langchain/tools.py +43 -0
- contextsynapse/adapters/langgraph/__init__.py +21 -0
- contextsynapse/adapters/langgraph/checkpoint.py +223 -0
- contextsynapse/adapters/langgraph/context_tools.py +341 -0
- contextsynapse/adapters/langgraph/message_history.py +138 -0
- contextsynapse/adapters/langgraph/tools.py +43 -0
- contextsynapse/adapters/llamaindex/__init__.py +4 -0
- contextsynapse/adapters/llamaindex/tools.py +64 -0
- contextsynapse/adapters/openai/__init__.py +24 -0
- contextsynapse/adapters/openai/tools.py +206 -0
- contextsynapse/adapters/pydantic_ai/__init__.py +4 -0
- contextsynapse/adapters/pydantic_ai/tools.py +36 -0
- contextsynapse/adapters/swarm/__init__.py +4 -0
- contextsynapse/adapters/swarm/tools.py +44 -0
- contextsynapse/agents/__init__.py +6 -0
- contextsynapse/agents/auto_capture.py +80 -0
- contextsynapse/agents/dispatcher.py +299 -0
- contextsynapse/agents/notifications.py +112 -0
- contextsynapse/aiql/__init__.py +71 -0
- contextsynapse/aiql/cache.py +341 -0
- contextsynapse/aiql/compiler/__init__.py +62 -0
- contextsynapse/aiql/compiler/optimizer.py +126 -0
- contextsynapse/aiql/compiler/planner.py +366 -0
- contextsynapse/aiql/compiler/statistics.py +235 -0
- contextsynapse/aiql/compiler/validator.py +425 -0
- contextsynapse/aiql/engine/__init__.py +11 -0
- contextsynapse/aiql/engine/chunk_storage.py +2584 -0
- contextsynapse/aiql/engine/executor.py +7737 -0
- contextsynapse/aiql/engine/extraction_integration.py +442 -0
- contextsynapse/aiql/engine/graph_builder.py +405 -0
- contextsynapse/aiql/engine/node_creation_from_normalized.py +691 -0
- contextsynapse/aiql/engine/performance_monitor.py +289 -0
- contextsynapse/aiql/engine/postprocessing.py +365 -0
- contextsynapse/aiql/engine/ray_stage_executors.py +918 -0
- contextsynapse/aiql/engine/redis_cache.py +106 -0
- contextsynapse/aiql/engine/streaming_json.py +366 -0
- contextsynapse/aiql/engine/streaming_parquet.py +568 -0
- contextsynapse/aiql/engine/streaming_ray_chunking.py +419 -0
- contextsynapse/aiql/grammar/__init__.py +14 -0
- contextsynapse/aiql/grammar/aiql_grammar.py +1822 -0
- contextsynapse/aiql/grammar/base.py +71 -0
- contextsynapse/aiql/parser/__init__.py +46 -0
- contextsynapse/aiql/parser/aiql_parser.py +11330 -0
- contextsynapse/aiql/parser/base_parser.py +47 -0
- contextsynapse/api/__init__.py +5 -0
- contextsynapse/api/a2a_router.py +233 -0
- contextsynapse/api/admin_router.py +140 -0
- contextsynapse/api/agent_worker_router.py +978 -0
- contextsynapse/api/algorithms_router.py +317 -0
- contextsynapse/api/api.py +4144 -0
- contextsynapse/api/audit.py +204 -0
- contextsynapse/api/auth.py +441 -0
- contextsynapse/api/auth_router.py +537 -0
- contextsynapse/api/billing.py +261 -0
- contextsynapse/api/billing_router.py +275 -0
- contextsynapse/api/boundary_router.py +452 -0
- contextsynapse/api/cognition_router.py +116 -0
- contextsynapse/api/connector_router.py +237 -0
- contextsynapse/api/context_router.py +1619 -0
- contextsynapse/api/dashboard_router.py +11367 -0
- contextsynapse/api/errors.py +183 -0
- contextsynapse/api/events.py +88 -0
- contextsynapse/api/experiment_bootstrap.py +321 -0
- contextsynapse/api/experiment_orchestrator.py +1078 -0
- contextsynapse/api/experiment_router.py +2089 -0
- contextsynapse/api/feature_gate.py +89 -0
- contextsynapse/api/federation_router.py +108 -0
- contextsynapse/api/integrations.py +567 -0
- contextsynapse/api/integrations_router.py +461 -0
- contextsynapse/api/intelligence_router.py +1028 -0
- contextsynapse/api/metering.py +155 -0
- contextsynapse/api/metrics.py +112 -0
- contextsynapse/api/models.py +38 -0
- contextsynapse/api/monitoring_router.py +174 -0
- contextsynapse/api/pipeline_router.py +1437 -0
- contextsynapse/api/playground_conn.py +116 -0
- contextsynapse/api/projects_router.py +131 -0
- contextsynapse/api/queries_router.py +282 -0
- contextsynapse/api/quota.py +95 -0
- contextsynapse/api/rate_limit.py +64 -0
- contextsynapse/api/search_router.py +261 -0
- contextsynapse/api/shield_router.py +447 -0
- contextsynapse/api/tenant_guard.py +103 -0
- contextsynapse/api/tenant_quotas.py +231 -0
- contextsynapse/api/tenants.py +305 -0
- contextsynapse/api/users.py +646 -0
- contextsynapse/api/v1.py +167 -0
- contextsynapse/api/vertical_builder_router.py +387 -0
- contextsynapse/benchmark/__init__.py +15 -0
- contextsynapse/benchmark/__main__.py +64 -0
- contextsynapse/benchmark/agents.py +338 -0
- contextsynapse/benchmark/live_ab.py +338 -0
- contextsynapse/benchmark/reporter.py +149 -0
- contextsynapse/benchmark/runner.py +264 -0
- contextsynapse/benchmark/savings.py +266 -0
- contextsynapse/benchmark/token_counter.py +212 -0
- contextsynapse/benchmark/workloads.py +289 -0
- contextsynapse/buffer/__init__.py +154 -0
- contextsynapse/buffer/base.py +257 -0
- contextsynapse/buffer/duckdb_buffer.py +246 -0
- contextsynapse/buffer/file_buffer.py +229 -0
- contextsynapse/buffer/lmdb_buffer.py +286 -0
- contextsynapse/buffer/local_buffer.py +154 -0
- contextsynapse/buffer/redis_buffer.py +211 -0
- contextsynapse/buffer/sqlite_buffer.py +266 -0
- contextsynapse/cache.py +2 -0
- contextsynapse/cli/__init__.py +40 -0
- contextsynapse/cli/cli.py +475 -0
- contextsynapse/cli/config_cli.py +177 -0
- contextsynapse/cli/scaffold.py +465 -0
- contextsynapse/cognition/__init__.py +31 -0
- contextsynapse/cognition/derivation.py +55 -0
- contextsynapse/cognition/events.py +135 -0
- contextsynapse/cognition/feedback.py +52 -0
- contextsynapse/cognition/hallucination.py +90 -0
- contextsynapse/cognition/invalidation.py +70 -0
- contextsynapse/cognition/read_tracker.py +50 -0
- contextsynapse/collaboration.py +2 -0
- contextsynapse/comparison.py +2 -0
- contextsynapse/config/__init__.py +10 -0
- contextsynapse/config/connectors/amfi_nav.yaml +18 -0
- contextsynapse/config/connectors/auto_sector.yaml +20 -0
- contextsynapse/config/connectors/banking_sector.yaml +20 -0
- contextsynapse/config/connectors/energy_sector.yaml +20 -0
- contextsynapse/config/connectors/fmcg_sector.yaml +20 -0
- contextsynapse/config/connectors/nsdl_fpi.yaml +9 -0
- contextsynapse/config/connectors/nse_price.yaml +61 -0
- contextsynapse/config/connectors/pharma_sector.yaml +20 -0
- contextsynapse/config/connectors/rbi_dbie.yaml +12 -0
- contextsynapse/config/context_presets/ai_research.json +25 -0
- contextsynapse/config/context_presets/chatgpt_conversations.json +19 -0
- contextsynapse/config/context_presets/claude_conversations.json +19 -0
- contextsynapse/config/context_presets/legal_compliance.json +21 -0
- contextsynapse/config/context_presets/meeting_notes.json +21 -0
- contextsynapse/config/context_presets/slack_engineering.json +21 -0
- contextsynapse/config/context_presets/tech_climate.json +24 -0
- contextsynapse/config/context_presets/toi_politics.json +25 -0
- contextsynapse/config/database_config.py +453 -0
- contextsynapse/config/deployment.py +221 -0
- contextsynapse/config/gpt_action_schema.json +164 -0
- contextsynapse/config/indicators/india_macro.yaml +213 -0
- contextsynapse/config/logging_config.py +88 -0
- contextsynapse/config/mode_config.py +223 -0
- contextsynapse/config/schemas/api_spec.yaml +48 -0
- contextsynapse/config/schemas/architecture_doc.yaml +51 -0
- contextsynapse/config/schemas/chat_history.yaml +90 -0
- contextsynapse/config/schemas/chatgpt_conversation.yaml +101 -0
- contextsynapse/config/schemas/claude_conversation.yaml +148 -0
- contextsynapse/config/schemas/contract.yaml +48 -0
- contextsynapse/config/schemas/conversation.yaml +167 -0
- contextsynapse/config/schemas/database.yaml +74 -0
- contextsynapse/config/schemas/decision.yaml +72 -0
- contextsynapse/config/schemas/ecommerce.yaml +56 -0
- contextsynapse/config/schemas/education.yaml +42 -0
- contextsynapse/config/schemas/healthcare.yaml +133 -0
- contextsynapse/config/schemas/hr_document.yaml +48 -0
- contextsynapse/config/schemas/invoice.yaml +40 -0
- contextsynapse/config/schemas/knowledge_base.yaml +75 -0
- contextsynapse/config/schemas/legal.yaml +42 -0
- contextsynapse/config/schemas/marketing_content.yaml +48 -0
- contextsynapse/config/schemas/meeting_notes.yaml +51 -0
- contextsynapse/config/schemas/news_article.yaml +61 -0
- contextsynapse/config/schemas/real_estate.yaml +49 -0
- contextsynapse/config/schemas/requirements_doc.yaml +48 -0
- contextsynapse/config/schemas/research_paper.yaml +56 -0
- contextsynapse/config/schemas/resume.yaml +49 -0
- contextsynapse/config/schemas/retail.yaml +42 -0
- contextsynapse/config/schemas/rule_meta.yaml +173 -0
- contextsynapse/config/schemas/rules.yaml +72 -0
- contextsynapse/config/schemas/screener_meta.yaml +236 -0
- contextsynapse/config/schemas/sdlc.yaml +103 -0
- contextsynapse/config/schemas/session_graph.yaml +172 -0
- contextsynapse/config/schemas/support_ticket.yaml +48 -0
- contextsynapse/config/schemas/web.yaml +64 -0
- contextsynapse/config/sensors/earnings_calendar.yaml +52 -0
- contextsynapse/config/sensors/global_risk.yaml +53 -0
- contextsynapse/config/sensors/government_policy.yaml +54 -0
- contextsynapse/config/sensors/supply_chain.yaml +50 -0
- contextsynapse/config/sensors/templates/behavioral.yaml +56 -0
- contextsynapse/config/sensors/templates/equity_sentiment.yaml +48 -0
- contextsynapse/config/sensors/templates/global_macro.yaml +47 -0
- contextsynapse/config/sensors/templates/market_data.yaml +118 -0
- contextsynapse/config/sensors/templates/sector_technical.yaml +47 -0
- contextsynapse/config/sensors/weather.yaml +52 -0
- contextsynapse/config/storage_strategy.py +202 -0
- contextsynapse/config/templates/competitive_intel.yaml +39 -0
- contextsynapse/config/templates/geopolitical_risk.yaml +46 -0
- contextsynapse/config/templates/market_analysis.yaml +58 -0
- contextsynapse/connectors/__init__.py +15 -0
- contextsynapse/connectors/api_router.py +121 -0
- contextsynapse/connectors/base.py +357 -0
- contextsynapse/connectors/financial/audio.py +170 -0
- contextsynapse/connectors/financial/youtube.py +272 -0
- contextsynapse/connectors/github.py +164 -0
- contextsynapse/connectors/jira.py +120 -0
- contextsynapse/connectors/kafka_connector.py +124 -0
- contextsynapse/connectors/pipeline_connector.py +747 -0
- contextsynapse/connectors/registry.py +116 -0
- contextsynapse/connectors/scheduler.py +87 -0
- contextsynapse/connectors/universal.py +360 -0
- contextsynapse/context/__init__.py +96 -0
- contextsynapse/context/__main__.py +4 -0
- contextsynapse/context/acl.py +125 -0
- contextsynapse/context/agent_card.py +201 -0
- contextsynapse/context/agent_memory.py +814 -0
- contextsynapse/context/agents.py +472 -0
- contextsynapse/context/agents_redis.py +391 -0
- contextsynapse/context/assembled.py +204 -0
- contextsynapse/context/attribution.py +113 -0
- contextsynapse/context/blob.py +184 -0
- contextsynapse/context/boundaries.py +187 -0
- contextsynapse/context/boundary.py +507 -0
- contextsynapse/context/bundle.py +155 -0
- contextsynapse/context/cli.py +519 -0
- contextsynapse/context/collaboration.py +165 -0
- contextsynapse/context/compiler.py +604 -0
- contextsynapse/context/composite.py +536 -0
- contextsynapse/context/compression.py +147 -0
- contextsynapse/context/context_manager.py +888 -0
- contextsynapse/context/context_schema.py +90 -0
- contextsynapse/context/context_schema.yaml +105 -0
- contextsynapse/context/context_units.py +891 -0
- contextsynapse/context/conversation.py +488 -0
- contextsynapse/context/dedup.py +207 -0
- contextsynapse/context/document_processor.py +698 -0
- contextsynapse/context/embedding_hooks.py +338 -0
- contextsynapse/context/execution_schema.py +274 -0
- contextsynapse/context/fan_out.py +138 -0
- contextsynapse/context/frozen.py +80 -0
- contextsynapse/context/gravity.py +227 -0
- contextsynapse/context/hub.py +1401 -0
- contextsynapse/context/ingest.py +391 -0
- contextsynapse/context/injection.py +226 -0
- contextsynapse/context/interaction_graphifier.py +562 -0
- contextsynapse/context/layers.py +574 -0
- contextsynapse/context/projection.py +1195 -0
- contextsynapse/context/promotion.py +634 -0
- contextsynapse/context/proof.py +131 -0
- contextsynapse/context/propagation.py +577 -0
- contextsynapse/context/pubsub.py +135 -0
- contextsynapse/context/quality.py +1054 -0
- contextsynapse/context/quality_tracker.py +270 -0
- contextsynapse/context/scoping.py +370 -0
- contextsynapse/context/seed.py +992 -0
- contextsynapse/context/session.py +1142 -0
- contextsynapse/context/session_graph.py +593 -0
- contextsynapse/context/session_memory.py +309 -0
- contextsynapse/context/session_resolver.py +111 -0
- contextsynapse/context/skill_learning.py +237 -0
- contextsynapse/context/smart_budget.py +129 -0
- contextsynapse/context/source_policy.py +242 -0
- contextsynapse/context/store_factory.py +53 -0
- contextsynapse/context/sync.py +648 -0
- contextsynapse/context/token.py +236 -0
- contextsynapse/context/vector_integration.py +297 -0
- contextsynapse/context/webhooks.py +194 -0
- contextsynapse/context/working_memory.py +224 -0
- contextsynapse/core/__init__.py +18 -0
- contextsynapse/core/archiver.py +237 -0
- contextsynapse/core/change_stream.py +282 -0
- contextsynapse/core/checkpoint.py +310 -0
- contextsynapse/core/cloud_storage.py +387 -0
- contextsynapse/core/context_state.py +651 -0
- contextsynapse/core/cron.py +324 -0
- contextsynapse/core/datasource.py +643 -0
- contextsynapse/core/db.py +289 -0
- contextsynapse/core/federation.py +283 -0
- contextsynapse/core/graph_coordinator.py +201 -0
- contextsynapse/core/graph_intelligence.py +388 -0
- contextsynapse/core/graph_structures.py +106 -0
- contextsynapse/core/graph_sync.py +157 -0
- contextsynapse/core/hybrid_graph_storage.py +2998 -0
- contextsynapse/core/lifecycle.py +691 -0
- contextsynapse/core/multiworker.py +378 -0
- contextsynapse/core/pruning.py +312 -0
- contextsynapse/core/redis_registry.py +524 -0
- contextsynapse/core/registry.py +1043 -0
- contextsynapse/core/registry_factory.py +51 -0
- contextsynapse/core/registry_metadata.py +294 -0
- contextsynapse/core/replay.py +354 -0
- contextsynapse/core/replication.py +339 -0
- contextsynapse/core/time_travel.py +260 -0
- contextsynapse/core/write_behind.py +152 -0
- contextsynapse/core/write_context.py +39 -0
- contextsynapse/db/__init__.py +1 -0
- contextsynapse/db/postgres.py +267 -0
- contextsynapse/db/profile.py +236 -0
- contextsynapse/db/rules.py +328 -0
- contextsynapse/demo/__init__.py +0 -0
- contextsynapse/demo/report.py +147 -0
- contextsynapse/demo/runner.py +520 -0
- contextsynapse/demo/scenario.py +165 -0
- contextsynapse/demo/session_demo.py +280 -0
- contextsynapse/demo/session_report.py +143 -0
- contextsynapse/demo/universal_runner.py +257 -0
- contextsynapse/engine/__init__.py +15 -0
- contextsynapse/engine/core.py +555 -0
- contextsynapse/extraction/__init__.py +69 -0
- contextsynapse/extraction/cli.py +274 -0
- contextsynapse/extraction/config.py +107 -0
- contextsynapse/extraction/examples/example_usage.py +118 -0
- contextsynapse/extraction/examples/sample_manifest.json +53 -0
- contextsynapse/extraction/examples/sample_normalized.json +185 -0
- contextsynapse/extraction/extract_engine.py +440 -0
- contextsynapse/extraction/extractors/__init__.py +37 -0
- contextsynapse/extraction/extractors/chat_export_extractor.py +189 -0
- contextsynapse/extraction/extractors/csv_extractor.py +83 -0
- contextsynapse/extraction/extractors/docx_extractor.py +129 -0
- contextsynapse/extraction/extractors/excel_extractor.py +152 -0
- contextsynapse/extraction/extractors/html_extractor.py +146 -0
- contextsynapse/extraction/extractors/pdf_extractor.py +635 -0
- contextsynapse/extraction/extractors/pdf_extractor_layoutparser.py +408 -0
- contextsynapse/extraction/extractors/register_extractors.py +63 -0
- contextsynapse/extraction/extractors/text_extractor.py +65 -0
- contextsynapse/extraction/extractors/txt_extractor.py +120 -0
- contextsynapse/extraction/extractors/website_extractor.py +246 -0
- contextsynapse/extraction/fact_extractor.py +236 -0
- contextsynapse/extraction/file_manager.py +353 -0
- contextsynapse/extraction/hierarchy.py +239 -0
- contextsynapse/extraction/id_generator.py +450 -0
- contextsynapse/extraction/layout_detector.py +409 -0
- contextsynapse/extraction/llm_entity_extractor.py +301 -0
- contextsynapse/extraction/normalized_store.py +480 -0
- contextsynapse/extraction/normalizer.py +594 -0
- contextsynapse/extraction/parquet_writer.py +598 -0
- contextsynapse/extraction/post_processors/__init__.py +40 -0
- contextsynapse/extraction/post_processors/column_reorganizer.py +507 -0
- contextsynapse/extraction/ray_normalization.py +233 -0
- contextsynapse/extraction/ray_runner.py +207 -0
- contextsynapse/extraction/redis_schema_registry.py +222 -0
- contextsynapse/extraction/registry.py +204 -0
- contextsynapse/extraction/schema_loader.py +663 -0
- contextsynapse/extraction/schema_registry.py +230 -0
- contextsynapse/extraction/semantic_normalizer.py +245 -0
- contextsynapse/extraction/version_manager.py +314 -0
- contextsynapse/gateway/__init__.py +24 -0
- contextsynapse/gateway/action_emitter.py +212 -0
- contextsynapse/gateway/cost_tracker.py +508 -0
- contextsynapse/gateway/gateway.py +377 -0
- contextsynapse/gateway/policy.py +303 -0
- contextsynapse/governance/__init__.py +13 -0
- contextsynapse/governance/layer.py +513 -0
- contextsynapse/ingestion/__init__.py +15 -0
- contextsynapse/ingestion/amplifier.py +288 -0
- contextsynapse/ingestion/async_ingest.py +463 -0
- contextsynapse/ingestion/chunker.py +303 -0
- contextsynapse/ingestion/chunking.py +58 -0
- contextsynapse/ingestion/cleaner.py +190 -0
- contextsynapse/ingestion/cleanse.py +252 -0
- contextsynapse/ingestion/connectors/__init__.py +38 -0
- contextsynapse/ingestion/connectors/base.py +300 -0
- contextsynapse/ingestion/connectors/chatgpt_memory.py +247 -0
- contextsynapse/ingestion/connectors/claude_memory.py +274 -0
- contextsynapse/ingestion/connectors/sap_ingestor.py +208 -0
- contextsynapse/ingestion/content_detector.py +80 -0
- contextsynapse/ingestion/content_monitor.py +502 -0
- contextsynapse/ingestion/dedup.py +106 -0
- contextsynapse/ingestion/feed.py +640 -0
- contextsynapse/ingestion/filters.py +461 -0
- contextsynapse/ingestion/graph_builder.py +705 -0
- contextsynapse/ingestion/input_classifier.py +307 -0
- contextsynapse/ingestion/job_manager.py +571 -0
- contextsynapse/ingestion/llm_extractor.py +610 -0
- contextsynapse/ingestion/orchestrator.py +116 -0
- contextsynapse/ingestion/parsers/__init__.py +19 -0
- contextsynapse/ingestion/parsers/graph_parser_registry.py +103 -0
- contextsynapse/ingestion/parsers/graphml_parser.py +141 -0
- contextsynapse/ingestion/parsers/jsonld_parser.py +171 -0
- contextsynapse/ingestion/parsers/rdf_parser.py +150 -0
- contextsynapse/ingestion/pipeline_context.py +228 -0
- contextsynapse/ingestion/pipeline_store.py +1195 -0
- contextsynapse/ingestion/queue.py +133 -0
- contextsynapse/ingestion/reprocess.py +179 -0
- contextsynapse/ingestion/scenario_router.py +224 -0
- contextsynapse/ingestion/schema_extractor.py +759 -0
- contextsynapse/ingestion/schema_validator.py +274 -0
- contextsynapse/ingestion/sdlc_ingest.py +87 -0
- contextsynapse/ingestion/smart_ingest.py +2451 -0
- contextsynapse/ingestion/source_connector.py +171 -0
- contextsynapse/ingestion/stage_executor.py +2095 -0
- contextsynapse/ingestion/stages/__init__.py +9 -0
- contextsynapse/ingestion/stages/tabular_to_graph.py +289 -0
- contextsynapse/ingestion/strategies.py +386 -0
- contextsynapse/ingestion/universal/__init__.py +4 -0
- contextsynapse/ingestion/universal/_operator_registry.py +59 -0
- contextsynapse/ingestion/universal/ingest_content.py +32 -0
- contextsynapse/ingestion/universal/operators/__init__.py +1 -0
- contextsynapse/ingestion/universal/operators/base.py +19 -0
- contextsynapse/ingestion/universal/operators/build_edges.py +75 -0
- contextsynapse/ingestion/universal/operators/cluster_topics.py +397 -0
- contextsynapse/ingestion/universal/operators/deduplicate.py +45 -0
- contextsynapse/ingestion/universal/operators/detect_signals.py +90 -0
- contextsynapse/ingestion/universal/operators/embed.py +80 -0
- contextsynapse/ingestion/universal/operators/extract_entities.py +253 -0
- contextsynapse/ingestion/universal/operators/extract_preferences.py +117 -0
- contextsynapse/ingestion/universal/operators/filter_content.py +69 -0
- contextsynapse/ingestion/universal/operators/index_bm25.py +52 -0
- contextsynapse/ingestion/universal/operators/infer_domains.py +69 -0
- contextsynapse/ingestion/universal/operators/link_cross_reference.py +210 -0
- contextsynapse/ingestion/universal/operators/parse_records.py +66 -0
- contextsynapse/ingestion/universal/operators/resolve_entities.py +261 -0
- contextsynapse/ingestion/universal/operators/scanners/__init__.py +16 -0
- contextsynapse/ingestion/universal/operators/scanners/edges.py +173 -0
- contextsynapse/ingestion/universal/operators/scanners/git.py +187 -0
- contextsynapse/ingestion/universal/operators/scanners/github.py +135 -0
- contextsynapse/ingestion/universal/operators/scanners/github_api.py +509 -0
- contextsynapse/ingestion/universal/operators/scanners/helpers.py +67 -0
- contextsynapse/ingestion/universal/operators/scanners/jira.py +65 -0
- contextsynapse/ingestion/universal/operators/scanners/llm_enrichment.py +82 -0
- contextsynapse/ingestion/universal/operators/scanners/repo.py +149 -0
- contextsynapse/ingestion/universal/operators/sdlc_scan.py +213 -0
- contextsynapse/ingestion/universal/operators/spec_scanner.py +149 -0
- contextsynapse/ingestion/universal/operators/store_documents.py +72 -0
- contextsynapse/ingestion/universal/operators/synthesize_cu.py +180 -0
- contextsynapse/ingestion/universal/operators/validate_gate.py +65 -0
- contextsynapse/ingestion/universal/parsers/__init__.py +5 -0
- contextsynapse/ingestion/universal/parsers/record_parser.py +203 -0
- contextsynapse/ingestion/universal/parsers/turn_parser.py +329 -0
- contextsynapse/ingestion/universal/shared_signals.py +161 -0
- contextsynapse/ingestion/universal/stage_executor.py +219 -0
- contextsynapse/ingestion/web_crawler.py +265 -0
- contextsynapse/intelligence/__init__.py +53 -0
- contextsynapse/intelligence/alerts.py +198 -0
- contextsynapse/intelligence/collector.py +655 -0
- contextsynapse/intelligence/comparison.py +198 -0
- contextsynapse/intelligence/config.py +56 -0
- contextsynapse/intelligence/conflict_detector.py +182 -0
- contextsynapse/intelligence/context_gaps.py +192 -0
- contextsynapse/intelligence/context_radar.py +135 -0
- contextsynapse/intelligence/correlation_engine.py +416 -0
- contextsynapse/intelligence/correlation_template.py +120 -0
- contextsynapse/intelligence/dedup.py +296 -0
- contextsynapse/intelligence/event_bus.py +91 -0
- contextsynapse/intelligence/feedback_loop.py +101 -0
- contextsynapse/intelligence/freshness.py +307 -0
- contextsynapse/intelligence/fundamental_feed.py +551 -0
- contextsynapse/intelligence/geo_data.py +170 -0
- contextsynapse/intelligence/geo_reference.py +112 -0
- contextsynapse/intelligence/graph_fusion.py +465 -0
- contextsynapse/intelligence/heuristics.py +176 -0
- contextsynapse/intelligence/impact_tracker.py +336 -0
- contextsynapse/intelligence/macro_indicators.py +319 -0
- contextsynapse/intelligence/ocr.py +104 -0
- contextsynapse/intelligence/persistence.py +267 -0
- contextsynapse/intelligence/pipeline_health.py +130 -0
- contextsynapse/intelligence/price_feed.py +221 -0
- contextsynapse/intelligence/rate_limiter.py +130 -0
- contextsynapse/intelligence/reactive.py +411 -0
- contextsynapse/intelligence/runtime_context.py +390 -0
- contextsynapse/intelligence/sentiment_decay.py +426 -0
- contextsynapse/intelligence/session.py +277 -0
- contextsynapse/intelligence/signal_hierarchy.py +438 -0
- contextsynapse/intelligence/signals.py +185 -0
- contextsynapse/intelligence/source_watcher.py +132 -0
- contextsynapse/intelligence/table_enricher.py +256 -0
- contextsynapse/intelligence/tagger.py +319 -0
- contextsynapse/intelligence/timeseries.py +209 -0
- contextsynapse/intelligence/tracker.py +318 -0
- contextsynapse/intelligence/watchdog.py +392 -0
- contextsynapse/intelligence/watchdog_manager.py +263 -0
- contextsynapse/intelligence/webhook_receiver.py +165 -0
- contextsynapse/intelligence/weight_learner.py +234 -0
- contextsynapse/llm/__init__.py +8 -0
- contextsynapse/llm/client.py +348 -0
- contextsynapse/llm/rate_limiter.py +166 -0
- contextsynapse/logging_config.py +2 -0
- contextsynapse/marketplace/__init__.py +7 -0
- contextsynapse/marketplace/registry.py +173 -0
- contextsynapse/mcp/__init__.py +11 -0
- contextsynapse/mcp/__main__.py +4 -0
- contextsynapse/mcp/auth_middleware.py +212 -0
- contextsynapse/mcp/connection_pool.py +128 -0
- contextsynapse/mcp/server.py +986 -0
- contextsynapse/mcp/session_context.py +67 -0
- contextsynapse/memory/__init__.py +34 -0
- contextsynapse/memory/engine.py +475 -0
- contextsynapse/memory/temporal.py +327 -0
- contextsynapse/metadata/__init__.py +12 -0
- contextsynapse/metadata/metadata_db.py +272 -0
- contextsynapse/metadata/metadata_query_tool.py +300 -0
- contextsynapse/metadata/metadata_tracker.py +425 -0
- contextsynapse/models/__init__.py +27 -0
- contextsynapse/models/embedding_service.py +360 -0
- contextsynapse/models/model_registry.py +228 -0
- contextsynapse/multiworker.py +2 -0
- contextsynapse/pipelines/__init__.py +1 -0
- contextsynapse/pipelines/executor.py +851 -0
- contextsynapse/pipelines/filters.py +189 -0
- contextsynapse/pipelines/models.py +176 -0
- contextsynapse/pipelines/scheduler.py +268 -0
- contextsynapse/playground/__init__.py +1 -0
- contextsynapse/playground/templates.py +85 -0
- contextsynapse/plugins/__init__.py +43 -0
- contextsynapse/plugins/api.py +66 -0
- contextsynapse/plugins/base.py +350 -0
- contextsynapse/plugins/domain_interface.py +508 -0
- contextsynapse/plugins/domain_loader.py +241 -0
- contextsynapse/plugins/loader.py +148 -0
- contextsynapse/plugins/registry.py +265 -0
- contextsynapse/project/__init__.py +11 -0
- contextsynapse/project/code_context.py +807 -0
- contextsynapse/project/connectors/__init__.py +4 -0
- contextsynapse/project/connectors/github_connector.py +113 -0
- contextsynapse/project/connectors/jira_connector.py +160 -0
- contextsynapse/project/graph.py +1023 -0
- contextsynapse/project/project_context.py +545 -0
- contextsynapse/project/scanner_registry.py +61 -0
- contextsynapse/project/schema_manager.py +322 -0
- contextsynapse/project/schemas/knowledge.yaml +59 -0
- contextsynapse/project/schemas/sdlc.yaml +369 -0
- contextsynapse/project/sdlc_schema.py +172 -0
- contextsynapse/project/spec_parser.py +85 -0
- contextsynapse/project/task_lock.py +181 -0
- contextsynapse/project/task_stream.py +203 -0
- contextsynapse/project/team_tools.py +537 -0
- contextsynapse/py.typed +0 -0
- contextsynapse/realtime/__init__.py +6 -0
- contextsynapse/realtime/collaboration.py +147 -0
- contextsynapse/rules/__init__.py +10 -0
- contextsynapse/rules/engine.py +116 -0
- contextsynapse/rules/evaluators/__init__.py +6 -0
- contextsynapse/rules/evaluators/aggregate.py +205 -0
- contextsynapse/rules/evaluators/custom.py +170 -0
- contextsynapse/rules/evaluators/pre_action.py +125 -0
- contextsynapse/rules/evaluators/temporal.py +129 -0
- contextsynapse/rules/loader.py +52 -0
- contextsynapse/rules/models.py +124 -0
- contextsynapse/rules/universal.py +393 -0
- contextsynapse/scheduler.py +229 -0
- contextsynapse/schema/__init__.py +42 -0
- contextsynapse/schema/compiler.py +252 -0
- contextsynapse/schema/composer.py +158 -0
- contextsynapse/schema/dedup.py +73 -0
- contextsynapse/schema/derivation.py +172 -0
- contextsynapse/schema/sdl.py +326 -0
- contextsynapse/schema/validation_gate.py +124 -0
- contextsynapse/sdk/__init__.py +63 -0
- contextsynapse/sdk/agent.py +214 -0
- contextsynapse/sdk/client.py +269 -0
- contextsynapse/sdk/exceptions.py +23 -0
- contextsynapse/sdk/models.py +78 -0
- contextsynapse/sdk/session.py +408 -0
- contextsynapse/sdk/tracked.py +218 -0
- contextsynapse/sdk/worker.py +266 -0
- contextsynapse/sdk/workspace_client.py +98 -0
- contextsynapse/sdk/ws.py +41 -0
- contextsynapse/search/__init__.py +20 -0
- contextsynapse/search/embedding_cache.py +140 -0
- contextsynapse/search/enhanced_search.py +152 -0
- contextsynapse/search/fulltext.py +130 -0
- contextsynapse/search/graph_search.py +634 -0
- contextsynapse/search/lmdb_index.py +1218 -0
- contextsynapse/search/nl_to_aiql.py +199 -0
- contextsynapse/search/rag.py +1346 -0
- contextsynapse/search/rag_cache.py +167 -0
- contextsynapse/search/reasoning_chain.py +231 -0
- contextsynapse/search/redis_search.py +207 -0
- contextsynapse/search/retrieval_quality.py +314 -0
- contextsynapse/search/semantic_query.py +455 -0
- contextsynapse/search/text_resolver.py +159 -0
- contextsynapse/search/whoosh_search.py +373 -0
- contextsynapse/security/__init__.py +17 -0
- contextsynapse/security/audit.py +297 -0
- contextsynapse/security/audit_logger.py +97 -0
- contextsynapse/security/audit_trail.py +270 -0
- contextsynapse/security/auth_unified.py +284 -0
- contextsynapse/security/auto_tagger.py +230 -0
- contextsynapse/security/data_security.py +218 -0
- contextsynapse/security/encryption.py +207 -0
- contextsynapse/security/identity.py +447 -0
- contextsynapse/security/jwt_identity.py +59 -0
- contextsynapse/security/middleware.py +336 -0
- contextsynapse/security/pii.py +233 -0
- contextsynapse/security/rbac.py +96 -0
- contextsynapse/security/rls.py +205 -0
- contextsynapse/security/sanitize.py +233 -0
- contextsynapse/security/scoped_encryption.py +131 -0
- contextsynapse/security/tenant.py +401 -0
- contextsynapse/shield/__init__.py +21 -0
- contextsynapse/shield/anomaly.py +56 -0
- contextsynapse/shield/permissions.py +99 -0
- contextsynapse/shield/profile.py +103 -0
- contextsynapse/shield/shield.py +108 -0
- contextsynapse/shield/trust_engine.py +69 -0
- contextsynapse/skills/__init__.py +14 -0
- contextsynapse/skills/engine.py +233 -0
- contextsynapse/skills/loader.py +59 -0
- contextsynapse/skills/models.py +139 -0
- contextsynapse/storage/__init__.py +7 -0
- contextsynapse/storage/cache.py +208 -0
- contextsynapse/storage/columnar_store_v2.py +178 -0
- contextsynapse/storage/csr_graph_storage.py +587 -0
- contextsynapse/storage/csr_store.py +388 -0
- contextsynapse/storage/document_store.py +491 -0
- contextsynapse/storage/hnsw_index.py +294 -0
- contextsynapse/storage/hybrid_store_v2.py +278 -0
- contextsynapse/storage/lmdb_graph_storage.py +366 -0
- contextsynapse/storage/migration.py +279 -0
- contextsynapse/storage/namespace_store.py +346 -0
- contextsynapse/storage/pure_graph_storage.py +185 -0
- contextsynapse/storage/redis_graph_adapter.py +186 -0
- contextsynapse/storage/redis_graph_storage.py +375 -0
- contextsynapse/storage/router/__init__.py +29 -0
- contextsynapse/storage/router/duckdb_store.py +398 -0
- contextsynapse/storage/router/factory.py +83 -0
- contextsynapse/storage/router/interface.py +125 -0
- contextsynapse/storage/router/postgres_store.py +339 -0
- contextsynapse/storage/router/resolver.py +192 -0
- contextsynapse/storage/router/router.py +300 -0
- contextsynapse/storage/single_file_storage.py +391 -0
- contextsynapse/storage/storage_manager.py +214 -0
- contextsynapse/storage/storage_query_optimizer.py +314 -0
- contextsynapse/storage/wal.py +359 -0
- contextsynapse/temporal/__init__.py +0 -0
- contextsynapse/temporal/storage.py +106 -0
- contextsynapse/tests/__init__.py +11 -0
- contextsynapse/tests/regression/__init__.py +1 -0
- contextsynapse/tests/regression/add_metadata.py +395 -0
- contextsynapse/tests/regression/add_skip_flags.py +85 -0
- contextsynapse/tests/regression/cases/test_basic_create_node.yaml +20 -0
- contextsynapse/tests/regression/cases/test_basic_select.yaml +21 -0
- contextsynapse/tests/regression/cases/test_blockchain_audit_trail.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_audit_trail_filtered.yaml +39 -0
- contextsynapse/tests/regression/cases/test_blockchain_blocks_range.yaml +39 -0
- contextsynapse/tests/regression/cases/test_blockchain_get_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_latest_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_length.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_merkle_root.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_verify.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_verify_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_create_edge.yaml +28 -0
- contextsynapse/tests/regression/cases/test_delete_edge_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_delete_node_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_evaluation_mrr.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_ndcg.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_precision.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_recall.yaml +40 -0
- contextsynapse/tests/regression/cases/test_group_by_basic.yaml +56 -0
- contextsynapse/tests/regression/cases/test_match_node_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_match_node_with_order_limit.yaml +31 -0
- contextsynapse/tests/regression/cases/test_namespace_switch.yaml +18 -0
- contextsynapse/tests/regression/cases/test_pipeline_cascaded.yaml +61 -0
- contextsynapse/tests/regression/cases/test_pipeline_fixed_size_chunking.yaml +48 -0
- contextsynapse/tests/regression/cases/test_pipeline_gpt4_chunking.yaml +54 -0
- contextsynapse/tests/regression/cases/test_pipeline_hybrid_indexing.yaml +57 -0
- contextsynapse/tests/regression/cases/test_pipeline_large_embedding.yaml +52 -0
- contextsynapse/tests/regression/cases/test_pipeline_paragraph_chunking.yaml +49 -0
- contextsynapse/tests/regression/cases/test_pipeline_recursive_chunking.yaml +47 -0
- contextsynapse/tests/regression/cases/test_pipeline_run_pipeline.yaml +56 -0
- contextsynapse/tests/regression/cases/test_pipeline_section_based_chunking.yaml +53 -0
- contextsynapse/tests/regression/cases/test_pipeline_semantic_chunking.yaml +51 -0
- contextsynapse/tests/regression/cases/test_pipeline_with_entity_extraction.yaml +57 -0
- contextsynapse/tests/regression/cases/test_pipeline_with_relationships.yaml +62 -0
- contextsynapse/tests/regression/cases/test_rag_evaluation.yaml +38 -0
- contextsynapse/tests/regression/cases/test_rag_graph_bfs_with_eval.yaml +48 -0
- contextsynapse/tests/regression/cases/test_rag_graph_centrality.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_centrality_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_community.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_community_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_dfs_with_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_multi_hop_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_path.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_basic.yaml +38 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_bfs.yaml +52 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_dfs.yaml +41 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_multi_hop.yaml +43 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_shortest_path.yaml +41 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_weighted.yaml +43 -0
- contextsynapse/tests/regression/cases/test_rag_graph_shortest_path_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_traversal.yaml +30 -0
- contextsynapse/tests/regression/cases/test_rag_graph_weighted_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_hybrid_search.yaml +33 -0
- contextsynapse/tests/regression/cases/test_rag_hybrid_with_prompt_embedding.yaml +44 -0
- contextsynapse/tests/regression/cases/test_rag_keyword_search.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_multi_hop_graph.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_path_based.yaml +34 -0
- contextsynapse/tests/regression/cases/test_rag_profile_based.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_vector_search.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_weighted_graph.yaml +34 -0
- contextsynapse/tests/regression/cases/test_rag_weighted_hybrid.yaml +31 -0
- contextsynapse/tests/regression/cases/test_semantic_boundary_chunking.yaml +57 -0
- contextsynapse/tests/regression/cases/test_semantic_boundary_detection.yaml +33 -0
- contextsynapse/tests/regression/cases/test_semantic_hash_function.yaml +30 -0
- contextsynapse/tests/regression/cases/test_semantic_hash_with_model.yaml +31 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_fixed_size.yaml +44 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_recursive.yaml +46 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_section.yaml +46 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_semantic.yaml +44 -0
- contextsynapse/tests/regression/cases/test_time_travel_as_of.yaml +35 -0
- contextsynapse/tests/regression/cases/test_time_travel_at_commit.yaml +33 -0
- contextsynapse/tests/regression/cases/test_time_travel_at_timestamp.yaml +33 -0
- contextsynapse/tests/regression/cases/test_time_travel_for_system_time_all.yaml +37 -0
- contextsynapse/tests/regression/cases/test_time_travel_versions_between.yaml +39 -0
- contextsynapse/tests/regression/cases/test_traverse_basic.yaml +31 -0
- contextsynapse/tests/regression/cases/test_traverse_max_depth.yaml +34 -0
- contextsynapse/tests/regression/cases/test_update_edge_basic.yaml +29 -0
- contextsynapse/tests/regression/evaluation_metrics.py +227 -0
- contextsynapse/tests/regression/regression_runner.py +1081 -0
- contextsynapse/tests/regression/setup_regression_data.py +212 -0
- contextsynapse/tests/regression/test_basic_only.py +84 -0
- contextsynapse/tests/regression/test_namespace_creation.py +29 -0
- contextsynapse/tests/regression/test_single_fix.py +61 -0
- contextsynapse/tests/regression/test_single_query.py +20 -0
- contextsynapse/tests/regression/validate_test_syntax.py +179 -0
- contextsynapse/tests/test_advanced_features.py +347 -0
- contextsynapse/tests/test_aiql_summary.py +283 -0
- contextsynapse/tests/test_all_aiql_queries.py +948 -0
- contextsynapse/tests/test_all_create_queries.py +213 -0
- contextsynapse/tests/test_api_vs_native.py +280 -0
- contextsynapse/tests/test_chunking_dedup.py +199 -0
- contextsynapse/tests/test_connectors.py +171 -0
- contextsynapse/tests/test_edges_and_match.py +202 -0
- contextsynapse/tests/test_extraction_pipeline_integration.py +581 -0
- contextsynapse/tests/test_name_property.py +224 -0
- contextsynapse/tests/test_node_edge_metadata.py +250 -0
- contextsynapse/tests/test_playground_conn.py +114 -0
- contextsynapse/tests/test_query_cache.py +213 -0
- contextsynapse/tests/test_source_policy_auth.py +348 -0
- contextsynapse/tests/test_temporal_and_domain.py +224 -0
- contextsynapse/tests/test_time_travel_e2e.py +571 -0
- contextsynapse/tests/test_traversal_and_aggregation.py +275 -0
- contextsynapse/tools/__init__.py +36 -0
- contextsynapse/tools/a2a_tools.py +106 -0
- contextsynapse/tools/cognition_tools.py +118 -0
- contextsynapse/tools/context.py +905 -0
- contextsynapse/tools/formatting.py +92 -0
- contextsynapse/tools/gateway_tools.py +186 -0
- contextsynapse/tools/graph.py +1700 -0
- contextsynapse/tools/intelligence.py +235 -0
- contextsynapse/tools/memory.py +118 -0
- contextsynapse/tools/registry.py +373 -0
- contextsynapse/tools/shield_tools.py +159 -0
- contextsynapse/tools/tasks.py +341 -0
- contextsynapse/tools/workspace_tools.py +124 -0
- contextsynapse/utils/__init__.py +15 -0
- contextsynapse/utils/config_loader.py +198 -0
- contextsynapse/utils/env_loader.py +156 -0
- contextsynapse/utils/file_utils.py +288 -0
- contextsynapse/utils/logging_optimizer.py +119 -0
- contextsynapse/vector/__init__.py +30 -0
- contextsynapse/vector/chroma_vector_store.py +152 -0
- contextsynapse/vector/custom_vector_store.py +537 -0
- contextsynapse/vector/faiss_vector_store.py +296 -0
- contextsynapse/vector/qdrant_vector_store.py +163 -0
- contextsynapse/vector/vector_db.py +953 -0
- contextsynapse/vector/vector_db_manager.py +197 -0
- contextsynapse/workspace/__init__.py +27 -0
- contextsynapse/workspace/base.py +94 -0
- contextsynapse/workspace/git.py +228 -0
- contextsynapse/workspace/github.py +78 -0
- contextsynapse/workspace/local.py +73 -0
- contextsynapse/workspace/tools.py +222 -0
- contextsynapse-1.0.0.dist-info/METADATA +847 -0
- contextsynapse-1.0.0.dist-info/RECORD +776 -0
- contextsynapse-1.0.0.dist-info/WHEEL +5 -0
- contextsynapse-1.0.0.dist-info/entry_points.txt +4 -0
- contextsynapse-1.0.0.dist-info/licenses/LICENSE +200 -0
- contextsynapse-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Domain Plugin Loader — discovers and loads domain plugins.
|
|
2
|
+
|
|
3
|
+
Searches for domain.yaml files in:
|
|
4
|
+
1. plugins/ directory (built-in)
|
|
5
|
+
2. verticals/*/config/ (vertical-specific)
|
|
6
|
+
3. ~/.contextsynapse/plugins/ (user-installed)
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
loader = PluginLoader()
|
|
10
|
+
finance = loader.get_domain("finance")
|
|
11
|
+
life_sci = loader.get_domain("life_science")
|
|
12
|
+
all_domains = loader.list_domains()
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import os
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any, Dict, List, Optional
|
|
21
|
+
|
|
22
|
+
from contextsynapse.plugins.domain_interface import DomainPlugin
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# Project root — two levels up from this file (contextsynapse/plugins/ -> project root)
|
|
27
|
+
_PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
|
28
|
+
|
|
29
|
+
# Search paths for domain.yaml files, in priority order
|
|
30
|
+
_SEARCH_DIRS = [
|
|
31
|
+
_PROJECT_ROOT / "plugins", # top-level domain plugins
|
|
32
|
+
_PROJECT_ROOT / "contextsynapse" / "plugins", # built-in
|
|
33
|
+
_PROJECT_ROOT / "verticals", # vertical-specific (*/config/)
|
|
34
|
+
Path.home() / ".contextsynapse" / "plugins", # user-installed
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class PluginLoader:
|
|
39
|
+
"""Discovers, loads, and caches domain plugins.
|
|
40
|
+
|
|
41
|
+
The loader scans known directories for ``domain.yaml`` files,
|
|
42
|
+
parses them into ``DomainPlugin`` instances, and caches them
|
|
43
|
+
by ``domain_id``. Plugins can also be registered at runtime.
|
|
44
|
+
|
|
45
|
+
The active domain is determined by the ``CONTEXTSYNAPSE_DOMAIN``
|
|
46
|
+
environment variable, defaulting to ``"finance"``.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self) -> None:
|
|
50
|
+
self._domains: Dict[str, DomainPlugin] = {}
|
|
51
|
+
self._scan_complete = False
|
|
52
|
+
self._scan_and_load()
|
|
53
|
+
|
|
54
|
+
# ------------------------------------------------------------------
|
|
55
|
+
# Public API
|
|
56
|
+
# ------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
def get_domain(self, domain_id: str) -> Optional[DomainPlugin]:
|
|
59
|
+
"""Get a loaded domain plugin by its ID.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
domain_id: The domain identifier (e.g. "finance", "life_science").
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
DomainPlugin instance or None if not found.
|
|
66
|
+
"""
|
|
67
|
+
return self._domains.get(domain_id)
|
|
68
|
+
|
|
69
|
+
def list_domains(self) -> List[Dict[str, Any]]:
|
|
70
|
+
"""List all loaded domain plugins with summary metadata.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
List of dicts with keys: domain_id, domain_name, version,
|
|
74
|
+
entity_count, sensor_count.
|
|
75
|
+
"""
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
"domain_id": plugin.domain_id,
|
|
79
|
+
"domain_name": plugin.domain_name,
|
|
80
|
+
"version": plugin.version,
|
|
81
|
+
"entity_count": len(plugin.entity_types),
|
|
82
|
+
"sensor_count": len(plugin.sensors),
|
|
83
|
+
}
|
|
84
|
+
for plugin in self._domains.values()
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
def get_active_domain(self) -> Optional[DomainPlugin]:
|
|
88
|
+
"""Get the currently active domain plugin.
|
|
89
|
+
|
|
90
|
+
Determined by the ``CONTEXTSYNAPSE_DOMAIN`` environment variable.
|
|
91
|
+
Falls back to ``"finance"`` if not set. Returns None if the
|
|
92
|
+
requested domain is not loaded.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
The active DomainPlugin, or None.
|
|
96
|
+
"""
|
|
97
|
+
domain_id = os.environ.get("CONTEXTSYNAPSE_DOMAIN", "finance")
|
|
98
|
+
plugin = self.get_domain(domain_id)
|
|
99
|
+
if plugin is None:
|
|
100
|
+
logger.warning(
|
|
101
|
+
"Active domain '%s' not found among loaded domains: %s",
|
|
102
|
+
domain_id,
|
|
103
|
+
list(self._domains.keys()),
|
|
104
|
+
)
|
|
105
|
+
return plugin
|
|
106
|
+
|
|
107
|
+
def register_domain(self, plugin: DomainPlugin) -> None:
|
|
108
|
+
"""Register a domain plugin at runtime.
|
|
109
|
+
|
|
110
|
+
If a plugin with the same ``domain_id`` is already loaded it
|
|
111
|
+
will be replaced (with a warning).
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
plugin: A fully configured DomainPlugin instance.
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
ValueError: If the plugin has no domain_id.
|
|
118
|
+
"""
|
|
119
|
+
if not plugin.domain_id:
|
|
120
|
+
raise ValueError("Cannot register a domain plugin without a domain_id")
|
|
121
|
+
|
|
122
|
+
if plugin.domain_id in self._domains:
|
|
123
|
+
logger.warning(
|
|
124
|
+
"Replacing already-loaded domain '%s' (v%s -> v%s)",
|
|
125
|
+
plugin.domain_id,
|
|
126
|
+
self._domains[plugin.domain_id].version,
|
|
127
|
+
plugin.version,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
self._domains[plugin.domain_id] = plugin
|
|
131
|
+
logger.info(
|
|
132
|
+
"Registered domain '%s' v%s (%d entity types, %d sensors)",
|
|
133
|
+
plugin.domain_id,
|
|
134
|
+
plugin.version,
|
|
135
|
+
len(plugin.entity_types),
|
|
136
|
+
len(plugin.sensors),
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def load_yaml(self, yaml_path: str) -> DomainPlugin:
|
|
140
|
+
"""Explicitly load a domain YAML file and register it.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
yaml_path: Path to a domain.yaml file.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
The loaded DomainPlugin instance.
|
|
147
|
+
"""
|
|
148
|
+
plugin = DomainPlugin.from_yaml(yaml_path)
|
|
149
|
+
self.register_domain(plugin)
|
|
150
|
+
return plugin
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def domain_count(self) -> int:
|
|
154
|
+
"""Number of loaded domain plugins."""
|
|
155
|
+
return len(self._domains)
|
|
156
|
+
|
|
157
|
+
# ------------------------------------------------------------------
|
|
158
|
+
# Internal — scanning and loading
|
|
159
|
+
# ------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
def _scan_and_load(self) -> None:
|
|
162
|
+
"""Scan all search directories for domain.yaml files and load them."""
|
|
163
|
+
if self._scan_complete:
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
yaml_files = self._discover_yaml_files()
|
|
167
|
+
|
|
168
|
+
for yf in yaml_files:
|
|
169
|
+
try:
|
|
170
|
+
plugin = DomainPlugin.from_yaml(str(yf))
|
|
171
|
+
if plugin.domain_id in self._domains:
|
|
172
|
+
existing = self._domains[plugin.domain_id]
|
|
173
|
+
logger.debug(
|
|
174
|
+
"Domain '%s' already loaded from earlier path (keeping first, "
|
|
175
|
+
"skipping %s)",
|
|
176
|
+
plugin.domain_id,
|
|
177
|
+
yf,
|
|
178
|
+
)
|
|
179
|
+
continue
|
|
180
|
+
self._domains[plugin.domain_id] = plugin
|
|
181
|
+
except Exception:
|
|
182
|
+
logger.exception("Failed to load domain YAML: %s", yf)
|
|
183
|
+
|
|
184
|
+
self._scan_complete = True
|
|
185
|
+
|
|
186
|
+
if self._domains:
|
|
187
|
+
logger.info(
|
|
188
|
+
"Domain loader ready: %d domain(s) loaded — %s",
|
|
189
|
+
len(self._domains),
|
|
190
|
+
", ".join(sorted(self._domains.keys())),
|
|
191
|
+
)
|
|
192
|
+
else:
|
|
193
|
+
logger.info("Domain loader ready: no domain YAML files found")
|
|
194
|
+
|
|
195
|
+
def _discover_yaml_files(self) -> List[Path]:
|
|
196
|
+
"""Find all domain.yaml files across search directories.
|
|
197
|
+
|
|
198
|
+
Search order:
|
|
199
|
+
1. contextsynapse/plugins/domain.yaml, contextsynapse/plugins/*/domain.yaml
|
|
200
|
+
2. verticals/*/config/domain.yaml
|
|
201
|
+
3. ~/.contextsynapse/plugins/domain.yaml, ~/.contextsynapse/plugins/*/domain.yaml
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Deduplicated list of Path objects.
|
|
205
|
+
"""
|
|
206
|
+
found: List[Path] = []
|
|
207
|
+
seen: set = set()
|
|
208
|
+
|
|
209
|
+
for search_dir in _SEARCH_DIRS:
|
|
210
|
+
if not search_dir.exists():
|
|
211
|
+
continue
|
|
212
|
+
|
|
213
|
+
# Direct domain.yaml in the directory
|
|
214
|
+
direct = search_dir / "domain.yaml"
|
|
215
|
+
if direct.exists() and direct.resolve() not in seen:
|
|
216
|
+
found.append(direct)
|
|
217
|
+
seen.add(direct.resolve())
|
|
218
|
+
|
|
219
|
+
# Subdirectories: look for domain.yaml or config/domain.yaml
|
|
220
|
+
try:
|
|
221
|
+
for child in sorted(search_dir.iterdir()):
|
|
222
|
+
if not child.is_dir():
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
candidates = [
|
|
226
|
+
child / "domain.yaml",
|
|
227
|
+
child / "config" / "domain.yaml",
|
|
228
|
+
]
|
|
229
|
+
for candidate in candidates:
|
|
230
|
+
if candidate.exists() and candidate.resolve() not in seen:
|
|
231
|
+
found.append(candidate)
|
|
232
|
+
seen.add(candidate.resolve())
|
|
233
|
+
except PermissionError:
|
|
234
|
+
logger.debug("Permission denied scanning: %s", search_dir)
|
|
235
|
+
|
|
236
|
+
logger.debug("Discovered %d domain YAML file(s): %s", len(found), found)
|
|
237
|
+
return found
|
|
238
|
+
|
|
239
|
+
def __repr__(self) -> str:
|
|
240
|
+
domains = ", ".join(sorted(self._domains.keys())) or "none"
|
|
241
|
+
return f"PluginLoader(domains=[{domains}])"
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Plugin discovery and loading via Python entry points.
|
|
2
|
+
|
|
3
|
+
Plugins register themselves in pyproject.toml:
|
|
4
|
+
|
|
5
|
+
[project.entry-points."contextsynapse.plugins"]
|
|
6
|
+
finance = "qgraph_finance.plugin:FinanceVertical"
|
|
7
|
+
|
|
8
|
+
The loader discovers all installed plugins and instantiates them.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
import time
|
|
15
|
+
from typing import Dict, List, Optional, Type
|
|
16
|
+
|
|
17
|
+
from contextsynapse.plugins.base import PluginState, VerticalPlugin
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
ENTRY_POINT_GROUP = "contextsynapse.plugins"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def discover_plugins(
|
|
25
|
+
exclude: Optional[List[str]] = None,
|
|
26
|
+
) -> List[VerticalPlugin]:
|
|
27
|
+
"""Discover and instantiate all installed plugins.
|
|
28
|
+
|
|
29
|
+
Uses Python entry points (PEP 621) to find plugins registered
|
|
30
|
+
under the 'contextsynapse.plugins' group.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
exclude: List of plugin names to skip.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
List of instantiated plugin objects.
|
|
37
|
+
"""
|
|
38
|
+
exclude = set(exclude or [])
|
|
39
|
+
plugins: List[VerticalPlugin] = []
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
from importlib.metadata import entry_points
|
|
43
|
+
except ImportError:
|
|
44
|
+
from importlib_metadata import entry_points # Python 3.9 fallback
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
eps = entry_points(group=ENTRY_POINT_GROUP)
|
|
48
|
+
except TypeError:
|
|
49
|
+
# Python 3.9: entry_points() returns a dict
|
|
50
|
+
all_eps = entry_points()
|
|
51
|
+
eps = all_eps.get(ENTRY_POINT_GROUP, [])
|
|
52
|
+
|
|
53
|
+
for ep in eps:
|
|
54
|
+
if ep.name in exclude:
|
|
55
|
+
logger.info("Skipping excluded plugin: %s", ep.name)
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
t0 = time.monotonic()
|
|
60
|
+
cls = ep.load()
|
|
61
|
+
if not (isinstance(cls, type) and issubclass(cls, VerticalPlugin)):
|
|
62
|
+
logger.warning(
|
|
63
|
+
"Entry point '%s' does not point to a VerticalPlugin subclass, skipping",
|
|
64
|
+
ep.name,
|
|
65
|
+
)
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
instance = cls()
|
|
69
|
+
elapsed = (time.monotonic() - t0) * 1000
|
|
70
|
+
logger.info(
|
|
71
|
+
"Discovered plugin '%s' v%s (loaded in %.1fms)",
|
|
72
|
+
instance.name,
|
|
73
|
+
instance.version,
|
|
74
|
+
elapsed,
|
|
75
|
+
)
|
|
76
|
+
plugins.append(instance)
|
|
77
|
+
|
|
78
|
+
except Exception:
|
|
79
|
+
logger.exception("Failed to load plugin '%s'", ep.name)
|
|
80
|
+
|
|
81
|
+
return plugins
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def load_plugin(
|
|
85
|
+
module_path: str, class_name: str
|
|
86
|
+
) -> Optional[VerticalPlugin]:
|
|
87
|
+
"""Load a single plugin by module path and class name.
|
|
88
|
+
|
|
89
|
+
For explicit loading without entry points (e.g. dev/testing).
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
module_path: e.g. "qgraph_finance.plugin"
|
|
93
|
+
class_name: e.g. "FinanceVertical"
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Instantiated plugin or None on failure.
|
|
97
|
+
"""
|
|
98
|
+
try:
|
|
99
|
+
import importlib
|
|
100
|
+
|
|
101
|
+
module = importlib.import_module(module_path)
|
|
102
|
+
cls = getattr(module, class_name)
|
|
103
|
+
|
|
104
|
+
if not (isinstance(cls, type) and issubclass(cls, VerticalPlugin)):
|
|
105
|
+
logger.error("%s.%s is not a VerticalPlugin subclass", module_path, class_name)
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
instance = cls()
|
|
109
|
+
logger.info("Loaded plugin '%s' v%s", instance.name, instance.version)
|
|
110
|
+
return instance
|
|
111
|
+
|
|
112
|
+
except Exception:
|
|
113
|
+
logger.exception("Failed to load plugin %s.%s", module_path, class_name)
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def validate_plugin(plugin: VerticalPlugin) -> List[str]:
|
|
118
|
+
"""Validate a plugin's configuration. Returns list of issues (empty = valid)."""
|
|
119
|
+
issues: List[str] = []
|
|
120
|
+
|
|
121
|
+
if not plugin.name or not plugin.name.strip():
|
|
122
|
+
issues.append("Plugin name is empty")
|
|
123
|
+
elif not plugin.name.replace("_", "").replace("-", "").isalnum():
|
|
124
|
+
issues.append(f"Plugin name '{plugin.name}' contains invalid characters")
|
|
125
|
+
if not plugin.version:
|
|
126
|
+
issues.append("Plugin version is empty")
|
|
127
|
+
|
|
128
|
+
seen_sensor_names = set()
|
|
129
|
+
for sensor in plugin.sensors():
|
|
130
|
+
if sensor.name in seen_sensor_names:
|
|
131
|
+
issues.append(f"Duplicate sensor name: '{sensor.name}'")
|
|
132
|
+
seen_sensor_names.add(sensor.name)
|
|
133
|
+
if sensor.interval_seconds < 10:
|
|
134
|
+
issues.append(f"Sensor '{sensor.name}' interval too short ({sensor.interval_seconds}s, min 10s)")
|
|
135
|
+
|
|
136
|
+
seen_schema_names = set()
|
|
137
|
+
for schema in plugin.schemas():
|
|
138
|
+
if schema.name in seen_schema_names:
|
|
139
|
+
issues.append(f"Duplicate schema name: '{schema.name}'")
|
|
140
|
+
seen_schema_names.add(schema.name)
|
|
141
|
+
|
|
142
|
+
for card in plugin.dashboard_cards():
|
|
143
|
+
if not card.id:
|
|
144
|
+
issues.append("Dashboard card has empty id")
|
|
145
|
+
if not card.route:
|
|
146
|
+
issues.append(f"Dashboard card '{card.id}' has empty route")
|
|
147
|
+
|
|
148
|
+
return issues
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"""Plugin registry — manages plugin lifecycle and provides access to loaded plugins."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
import threading
|
|
8
|
+
import time
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
from contextsynapse.plugins.base import (
|
|
12
|
+
DashboardCard,
|
|
13
|
+
PluginMCPTool,
|
|
14
|
+
PluginRoute,
|
|
15
|
+
PluginSchema,
|
|
16
|
+
PluginState,
|
|
17
|
+
Sensor,
|
|
18
|
+
VerticalPlugin,
|
|
19
|
+
)
|
|
20
|
+
from contextsynapse.plugins.loader import discover_plugins, validate_plugin
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
_global_registry: Optional["PluginRegistry"] = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PluginRegistry:
|
|
28
|
+
"""Central registry for all loaded plugins.
|
|
29
|
+
|
|
30
|
+
The registry manages plugin lifecycle (discovery → validation →
|
|
31
|
+
startup → shutdown) and provides aggregated access to all
|
|
32
|
+
schemas, sensors, routes, MCP tools, and dashboard cards
|
|
33
|
+
across all plugins.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self._plugins: Dict[str, VerticalPlugin] = {}
|
|
38
|
+
self._sensor_tasks: Dict[str, asyncio.Task] = {}
|
|
39
|
+
self._started = False
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def plugins(self) -> Dict[str, VerticalPlugin]:
|
|
43
|
+
return dict(self._plugins)
|
|
44
|
+
|
|
45
|
+
def register(self, plugin: VerticalPlugin) -> bool:
|
|
46
|
+
"""Register a plugin manually (without entry point discovery)."""
|
|
47
|
+
issues = validate_plugin(plugin)
|
|
48
|
+
if issues:
|
|
49
|
+
logger.error(
|
|
50
|
+
"Plugin '%s' validation failed: %s", plugin.name, "; ".join(issues)
|
|
51
|
+
)
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
if plugin.name in self._plugins:
|
|
55
|
+
logger.warning("Plugin '%s' already registered, replacing", plugin.name)
|
|
56
|
+
|
|
57
|
+
self._plugins[plugin.name] = plugin
|
|
58
|
+
logger.info("Registered plugin '%s' v%s", plugin.name, plugin.version)
|
|
59
|
+
return True
|
|
60
|
+
|
|
61
|
+
def discover_and_register(self, exclude: Optional[List[str]] = None) -> int:
|
|
62
|
+
"""Discover plugins via entry points and register them.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Number of plugins successfully registered.
|
|
66
|
+
"""
|
|
67
|
+
plugins = discover_plugins(exclude=exclude)
|
|
68
|
+
count = 0
|
|
69
|
+
for plugin in plugins:
|
|
70
|
+
if self.register(plugin):
|
|
71
|
+
count += 1
|
|
72
|
+
return count
|
|
73
|
+
|
|
74
|
+
async def startup_all(self, db: Any) -> None:
|
|
75
|
+
"""Start all registered plugins.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
db: AIContextDB instance or GraphRegistry.
|
|
79
|
+
"""
|
|
80
|
+
for name, plugin in self._plugins.items():
|
|
81
|
+
try:
|
|
82
|
+
plugin._state = PluginState.STARTING
|
|
83
|
+
t0 = time.monotonic()
|
|
84
|
+
await plugin.on_startup(db)
|
|
85
|
+
elapsed = (time.monotonic() - t0) * 1000
|
|
86
|
+
plugin._state = PluginState.RUNNING
|
|
87
|
+
logger.info("Started plugin '%s' in %.1fms", name, elapsed)
|
|
88
|
+
except Exception:
|
|
89
|
+
plugin._state = PluginState.ERROR
|
|
90
|
+
logger.exception("Failed to start plugin '%s'", name)
|
|
91
|
+
|
|
92
|
+
self._started = True
|
|
93
|
+
self._start_sensors(db)
|
|
94
|
+
|
|
95
|
+
async def shutdown_all(self) -> None:
|
|
96
|
+
"""Shut down all plugins and cancel sensor tasks."""
|
|
97
|
+
# Cancel sensor tasks first
|
|
98
|
+
for task_name, task in self._sensor_tasks.items():
|
|
99
|
+
task.cancel()
|
|
100
|
+
try:
|
|
101
|
+
await asyncio.wait_for(asyncio.shield(task), timeout=5.0)
|
|
102
|
+
except (asyncio.CancelledError, asyncio.TimeoutError):
|
|
103
|
+
pass
|
|
104
|
+
self._sensor_tasks.clear()
|
|
105
|
+
|
|
106
|
+
for name, plugin in self._plugins.items():
|
|
107
|
+
try:
|
|
108
|
+
await plugin.on_shutdown()
|
|
109
|
+
logger.info("Stopped plugin '%s'", name)
|
|
110
|
+
except Exception:
|
|
111
|
+
logger.exception("Error stopping plugin '%s'", name)
|
|
112
|
+
|
|
113
|
+
self._started = False
|
|
114
|
+
|
|
115
|
+
def _start_sensors(self, db: Any) -> None:
|
|
116
|
+
"""Start background sensor collection tasks."""
|
|
117
|
+
for plugin in self._plugins.values():
|
|
118
|
+
if plugin.state != PluginState.RUNNING:
|
|
119
|
+
continue
|
|
120
|
+
for sensor in plugin.sensors():
|
|
121
|
+
if not sensor.enabled:
|
|
122
|
+
continue
|
|
123
|
+
task_name = f"{plugin.name}.{sensor.name}"
|
|
124
|
+
task = asyncio.create_task(
|
|
125
|
+
self._sensor_loop(plugin, sensor, db),
|
|
126
|
+
name=task_name,
|
|
127
|
+
)
|
|
128
|
+
self._sensor_tasks[task_name] = task
|
|
129
|
+
logger.info(
|
|
130
|
+
"Started sensor '%s' (every %ds)",
|
|
131
|
+
task_name,
|
|
132
|
+
sensor.interval_seconds,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
async def _sensor_loop(
|
|
136
|
+
self, plugin: VerticalPlugin, sensor: Sensor, db: Any
|
|
137
|
+
) -> None:
|
|
138
|
+
"""Run a sensor's collect() on its interval.
|
|
139
|
+
|
|
140
|
+
Uses the StorageRouter to route data to the right store:
|
|
141
|
+
- Entities + edges -> Graph (thin nodes)
|
|
142
|
+
- Passages, facts -> DuckDB (content)
|
|
143
|
+
- Prices -> DuckDB (time-series, no graph nodes)
|
|
144
|
+
"""
|
|
145
|
+
from contextsynapse.storage.router import get_storage_router
|
|
146
|
+
|
|
147
|
+
router = get_storage_router(graph=db, namespace=plugin.name)
|
|
148
|
+
|
|
149
|
+
while True:
|
|
150
|
+
try:
|
|
151
|
+
if not sensor.enabled:
|
|
152
|
+
await asyncio.sleep(sensor.interval_seconds)
|
|
153
|
+
continue
|
|
154
|
+
|
|
155
|
+
t0 = time.monotonic()
|
|
156
|
+
results = await sensor.collect(db)
|
|
157
|
+
elapsed_collect = (time.monotonic() - t0) * 1000
|
|
158
|
+
|
|
159
|
+
# Route all items through the storage router
|
|
160
|
+
t1 = time.monotonic()
|
|
161
|
+
items = results[:sensor.batch_size]
|
|
162
|
+
counts = router.ingest(items, namespace=plugin.name)
|
|
163
|
+
elapsed_store = (time.monotonic() - t1) * 1000
|
|
164
|
+
|
|
165
|
+
logger.debug(
|
|
166
|
+
"Sensor '%s.%s' collected %d items in %.1fms, stored in %.1fms "
|
|
167
|
+
"(graph: %d nodes + %d edges, content: %d rows, prices: %d)",
|
|
168
|
+
plugin.name, sensor.name, len(items),
|
|
169
|
+
elapsed_collect, elapsed_store,
|
|
170
|
+
counts["graph_nodes"], counts["graph_edges"],
|
|
171
|
+
counts["content_rows"], counts["prices"],
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Sleep AFTER collection so first run is immediate
|
|
175
|
+
await asyncio.sleep(sensor.interval_seconds)
|
|
176
|
+
|
|
177
|
+
except asyncio.CancelledError:
|
|
178
|
+
raise
|
|
179
|
+
except Exception:
|
|
180
|
+
logger.exception(
|
|
181
|
+
"Sensor '%s.%s' collection failed", plugin.name, sensor.name
|
|
182
|
+
)
|
|
183
|
+
await asyncio.sleep(60)
|
|
184
|
+
|
|
185
|
+
# ── Aggregated access ──
|
|
186
|
+
|
|
187
|
+
def get_plugin(self, name: str) -> Optional[VerticalPlugin]:
|
|
188
|
+
return self._plugins.get(name)
|
|
189
|
+
|
|
190
|
+
def all_schemas(self) -> List[PluginSchema]:
|
|
191
|
+
"""All schemas from all plugins."""
|
|
192
|
+
schemas = []
|
|
193
|
+
for plugin in self._plugins.values():
|
|
194
|
+
schemas.extend(plugin.schemas())
|
|
195
|
+
return schemas
|
|
196
|
+
|
|
197
|
+
def all_sensors(self) -> List[tuple]:
|
|
198
|
+
"""All sensors as (plugin_name, sensor) tuples."""
|
|
199
|
+
result = []
|
|
200
|
+
for plugin in self._plugins.values():
|
|
201
|
+
for sensor in plugin.sensors():
|
|
202
|
+
result.append((plugin.name, sensor))
|
|
203
|
+
return result
|
|
204
|
+
|
|
205
|
+
def all_api_routers(self) -> List[tuple]:
|
|
206
|
+
"""All API routers as (plugin_name, PluginRoute) tuples."""
|
|
207
|
+
result = []
|
|
208
|
+
for plugin in self._plugins.values():
|
|
209
|
+
for route in plugin.api_routers():
|
|
210
|
+
result.append((plugin.name, route))
|
|
211
|
+
return result
|
|
212
|
+
|
|
213
|
+
def all_mcp_tools(self) -> List[tuple]:
|
|
214
|
+
"""All MCP tools as (plugin_name, PluginMCPTool) tuples."""
|
|
215
|
+
result = []
|
|
216
|
+
for plugin in self._plugins.values():
|
|
217
|
+
for tool in plugin.mcp_tools():
|
|
218
|
+
result.append((plugin.name, tool))
|
|
219
|
+
return result
|
|
220
|
+
|
|
221
|
+
def all_dashboard_cards(self) -> List[DashboardCard]:
|
|
222
|
+
"""All dashboard cards from all plugins, sorted by order."""
|
|
223
|
+
cards = []
|
|
224
|
+
for plugin in self._plugins.values():
|
|
225
|
+
cards.extend(plugin.dashboard_cards())
|
|
226
|
+
return sorted(cards, key=lambda c: c.order)
|
|
227
|
+
|
|
228
|
+
def status(self) -> Dict[str, Any]:
|
|
229
|
+
"""Return registry status."""
|
|
230
|
+
return {
|
|
231
|
+
"plugins_registered": len(self._plugins),
|
|
232
|
+
"plugins_running": sum(
|
|
233
|
+
1 for p in self._plugins.values() if p.state == PluginState.RUNNING
|
|
234
|
+
),
|
|
235
|
+
"sensors_active": len(self._sensor_tasks),
|
|
236
|
+
"plugins": {
|
|
237
|
+
name: plugin.info() for name, plugin in self._plugins.items()
|
|
238
|
+
},
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
def emit_graph_event(self, event_type: str, payload: Dict[str, Any]) -> None:
|
|
242
|
+
"""Forward a graph event to all running plugins."""
|
|
243
|
+
for plugin in self._plugins.values():
|
|
244
|
+
if plugin.state == PluginState.RUNNING:
|
|
245
|
+
try:
|
|
246
|
+
plugin.on_graph_event(event_type, payload)
|
|
247
|
+
except Exception:
|
|
248
|
+
logger.exception(
|
|
249
|
+
"Plugin '%s' failed handling event '%s'",
|
|
250
|
+
plugin.name,
|
|
251
|
+
event_type,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
_registry_lock = threading.Lock()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def get_plugin_registry() -> PluginRegistry:
|
|
259
|
+
"""Get or create the global plugin registry singleton."""
|
|
260
|
+
global _global_registry
|
|
261
|
+
if _global_registry is None:
|
|
262
|
+
with _registry_lock:
|
|
263
|
+
if _global_registry is None:
|
|
264
|
+
_global_registry = PluginRegistry()
|
|
265
|
+
return _global_registry
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Knowledge Graph
|
|
3
|
+
========================
|
|
4
|
+
Structures a codebase as a knowledge graph with tasks, documents,
|
|
5
|
+
decisions, and code files — enabling multi-agent collaboration
|
|
6
|
+
where Claude and Codex work as a team.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .graph import ProjectGraph
|
|
10
|
+
|
|
11
|
+
__all__ = ["ProjectGraph"]
|