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,201 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph Coordinator
|
|
3
|
+
==================
|
|
4
|
+
Redis-coordinated graph access for multi-worker deployments.
|
|
5
|
+
|
|
6
|
+
Each API worker holds its own in-memory CSR graph. Redis provides:
|
|
7
|
+
- Version counter per namespace (detect stale cache)
|
|
8
|
+
- Distributed write lock (prevent concurrent saves)
|
|
9
|
+
- Pub/Sub invalidation (notify workers of changes)
|
|
10
|
+
|
|
11
|
+
The graph engine stays in-memory per-worker (fast reads). Redis is
|
|
12
|
+
NOT the graph store — it's the coordination layer.
|
|
13
|
+
|
|
14
|
+
Read path (hot — must be fast):
|
|
15
|
+
1. Check local version vs Redis version (1 GET, ~0.1ms)
|
|
16
|
+
2. If match → serve from memory (zero I/O)
|
|
17
|
+
3. If mismatch → reload from disk
|
|
18
|
+
|
|
19
|
+
Write path:
|
|
20
|
+
1. Acquire lock (SETNX with 30s TTL)
|
|
21
|
+
2. Write to CSR + save to disk
|
|
22
|
+
3. INCR version counter
|
|
23
|
+
4. PUBLISH invalidation
|
|
24
|
+
5. Release lock
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
coordinator = GraphCoordinator(registry)
|
|
28
|
+
graph = coordinator.get_graph("my-namespace") # version-checked
|
|
29
|
+
coordinator.save_graph("my-namespace") # locked + versioned
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import logging
|
|
35
|
+
import os
|
|
36
|
+
import time
|
|
37
|
+
import uuid
|
|
38
|
+
from typing import Optional
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
_WORKER_ID = str(uuid.uuid4())[:8]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class GraphCoordinator:
|
|
46
|
+
"""Redis-coordinated graph access for multi-worker scaling.
|
|
47
|
+
|
|
48
|
+
Wraps a GraphRegistry with version checking and distributed locking.
|
|
49
|
+
Falls back to direct registry access when Redis is not available.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self, registry, redis_url: Optional[str] = None, prefix: str = "contextsynapse"):
|
|
53
|
+
self._registry = registry
|
|
54
|
+
self._prefix = prefix
|
|
55
|
+
self._redis = None
|
|
56
|
+
self._local_versions: dict[str, int] = {}
|
|
57
|
+
|
|
58
|
+
url = redis_url or os.environ.get("CONTEXTSYNAPSE_REDIS_URL") or os.environ.get("AICONTEXTDB_REDIS_URL")
|
|
59
|
+
if url:
|
|
60
|
+
try:
|
|
61
|
+
import redis
|
|
62
|
+
self._redis = redis.Redis.from_url(url, decode_responses=True)
|
|
63
|
+
self._redis.ping()
|
|
64
|
+
logger.info("GraphCoordinator: Redis connected (%s)", url.split("@")[-1])
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.warning("GraphCoordinator: Redis unavailable (%s), using single-worker mode", e)
|
|
67
|
+
self._redis = None
|
|
68
|
+
|
|
69
|
+
def _k(self, *parts: str) -> str:
|
|
70
|
+
return ":".join([self._prefix, *parts])
|
|
71
|
+
|
|
72
|
+
# ==================================================================
|
|
73
|
+
# Read path (hot — must be fast)
|
|
74
|
+
# ==================================================================
|
|
75
|
+
|
|
76
|
+
def get_graph(self, namespace: str, load_if_missing: bool = True):
|
|
77
|
+
"""Get a graph, reloading from disk if the version is stale.
|
|
78
|
+
|
|
79
|
+
This is the main read path — called on every API request.
|
|
80
|
+
"""
|
|
81
|
+
if not self._redis:
|
|
82
|
+
# No Redis → direct registry access (single-worker mode)
|
|
83
|
+
return self._registry.get_graph(namespace, load_if_missing=load_if_missing)
|
|
84
|
+
|
|
85
|
+
# Check version
|
|
86
|
+
remote_version = self._get_remote_version(namespace)
|
|
87
|
+
local_version = self._local_versions.get(namespace, -1)
|
|
88
|
+
|
|
89
|
+
if local_version == remote_version:
|
|
90
|
+
# Cache hit — serve from memory
|
|
91
|
+
cached = self._registry.get_graph(namespace, load_if_missing=False)
|
|
92
|
+
if cached:
|
|
93
|
+
return cached
|
|
94
|
+
|
|
95
|
+
# Cache miss or stale — reload from disk
|
|
96
|
+
graph = self._registry.get_graph(namespace, load_if_missing=load_if_missing)
|
|
97
|
+
if graph:
|
|
98
|
+
self._local_versions[namespace] = remote_version
|
|
99
|
+
logger.debug("GraphCoordinator: reloaded %s (version %s)", namespace, remote_version)
|
|
100
|
+
return graph
|
|
101
|
+
|
|
102
|
+
# ==================================================================
|
|
103
|
+
# Write path (locked + versioned)
|
|
104
|
+
# ==================================================================
|
|
105
|
+
|
|
106
|
+
def save_graph(self, namespace: str, create_checkpoint: bool = False) -> bool:
|
|
107
|
+
"""Save a graph with distributed locking and version increment.
|
|
108
|
+
|
|
109
|
+
Only one worker can save a namespace at a time.
|
|
110
|
+
"""
|
|
111
|
+
if not self._redis:
|
|
112
|
+
return self._registry.save_graph(namespace, create_checkpoint=create_checkpoint)
|
|
113
|
+
|
|
114
|
+
lock_key = self._k("graph", "lock", namespace)
|
|
115
|
+
lock_acquired = False
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
# Acquire distributed lock (SETNX with 30s TTL)
|
|
119
|
+
lock_acquired = self._redis.set(lock_key, _WORKER_ID, nx=True, ex=30)
|
|
120
|
+
if not lock_acquired:
|
|
121
|
+
holder = self._redis.get(lock_key)
|
|
122
|
+
logger.warning("GraphCoordinator: namespace %s locked by worker %s", namespace, holder)
|
|
123
|
+
# Wait briefly and retry once
|
|
124
|
+
time.sleep(0.5)
|
|
125
|
+
lock_acquired = self._redis.set(lock_key, _WORKER_ID, nx=True, ex=30)
|
|
126
|
+
if not lock_acquired:
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
# Save to disk
|
|
130
|
+
result = self._registry.save_graph(namespace, create_checkpoint=create_checkpoint)
|
|
131
|
+
|
|
132
|
+
if result:
|
|
133
|
+
# Increment version counter
|
|
134
|
+
new_version = self._redis.incr(self._k("graph", "version", namespace))
|
|
135
|
+
self._local_versions[namespace] = new_version
|
|
136
|
+
|
|
137
|
+
# Publish invalidation to other workers
|
|
138
|
+
self._redis.publish(
|
|
139
|
+
self._k("graph", "invalidate"),
|
|
140
|
+
f"{namespace}:{new_version}",
|
|
141
|
+
)
|
|
142
|
+
logger.debug("GraphCoordinator: saved %s (version %s)", namespace, new_version)
|
|
143
|
+
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
finally:
|
|
147
|
+
# Release lock (only if we hold it)
|
|
148
|
+
if lock_acquired:
|
|
149
|
+
current_holder = self._redis.get(lock_key)
|
|
150
|
+
if current_holder == _WORKER_ID:
|
|
151
|
+
self._redis.delete(lock_key)
|
|
152
|
+
|
|
153
|
+
def create_graph(self, namespace: str, **kwargs):
|
|
154
|
+
"""Create a new graph with version tracking."""
|
|
155
|
+
graph = self._registry.create_graph(namespace, **kwargs)
|
|
156
|
+
if self._redis:
|
|
157
|
+
self._redis.setnx(self._k("graph", "version", namespace), 0)
|
|
158
|
+
return graph
|
|
159
|
+
|
|
160
|
+
# ==================================================================
|
|
161
|
+
# Invalidation (handle messages from other workers)
|
|
162
|
+
# ==================================================================
|
|
163
|
+
|
|
164
|
+
def invalidate(self, namespace: str):
|
|
165
|
+
"""Force reload of a namespace on next access."""
|
|
166
|
+
if namespace in self._local_versions:
|
|
167
|
+
del self._local_versions[namespace]
|
|
168
|
+
|
|
169
|
+
def handle_invalidation(self, message: str):
|
|
170
|
+
"""Handle a pub/sub invalidation message from another worker."""
|
|
171
|
+
try:
|
|
172
|
+
ns, version = message.rsplit(":", 1)
|
|
173
|
+
self.invalidate(ns)
|
|
174
|
+
logger.debug("GraphCoordinator: invalidated %s (remote version %s)", ns, version)
|
|
175
|
+
except Exception:
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
# ==================================================================
|
|
179
|
+
# Internals
|
|
180
|
+
# ==================================================================
|
|
181
|
+
|
|
182
|
+
def _get_remote_version(self, namespace: str) -> int:
|
|
183
|
+
try:
|
|
184
|
+
val = self._redis.get(self._k("graph", "version", namespace))
|
|
185
|
+
return int(val) if val else 0
|
|
186
|
+
except Exception:
|
|
187
|
+
return 0
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def is_coordinated(self) -> bool:
|
|
191
|
+
"""True if Redis coordination is active."""
|
|
192
|
+
return self._redis is not None
|
|
193
|
+
|
|
194
|
+
def info(self) -> dict:
|
|
195
|
+
"""Get coordinator status."""
|
|
196
|
+
return {
|
|
197
|
+
"coordinated": self.is_coordinated,
|
|
198
|
+
"worker_id": _WORKER_ID,
|
|
199
|
+
"cached_namespaces": list(self._local_versions.keys()),
|
|
200
|
+
"local_versions": dict(self._local_versions),
|
|
201
|
+
}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph Intelligence — auto-enrichment on node creation.
|
|
3
|
+
|
|
4
|
+
Runs inline on every node add (<10ms target). Three capabilities:
|
|
5
|
+
1. Auto-link: match entity names in text → create MENTIONS edges
|
|
6
|
+
2. Quality scoring: assign _quality_score based on node type + metadata
|
|
7
|
+
3. Topic tagging: assign _topics from cached keyword index
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
gi = GraphIntelligence(db)
|
|
11
|
+
gi.on_node_added(node) # called after node persists to storage
|
|
12
|
+
|
|
13
|
+
# Or register as callback:
|
|
14
|
+
db.register_node_callback(gi.on_node_added)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
import re
|
|
21
|
+
import time
|
|
22
|
+
from typing import Any, Dict, List, Optional, Set
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# ── Quality scores by node type ────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
QUALITY_SCORES = {
|
|
29
|
+
"Document": 1.0,
|
|
30
|
+
"WebPage": 1.0,
|
|
31
|
+
"Passage": 0.85,
|
|
32
|
+
"TextChunk": 0.85,
|
|
33
|
+
"Fact": 0.8,
|
|
34
|
+
"Statistic": 0.8,
|
|
35
|
+
"Claim": 0.75,
|
|
36
|
+
"Article": 0.75,
|
|
37
|
+
"Entity": 0.7,
|
|
38
|
+
"Organization": 0.7,
|
|
39
|
+
"Author": 0.7,
|
|
40
|
+
"Date": 0.6,
|
|
41
|
+
"Finding": 0.5,
|
|
42
|
+
"Decision": 0.5,
|
|
43
|
+
"Insight": 0.4,
|
|
44
|
+
"Task": 0.3,
|
|
45
|
+
"Action": 0.2,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Labels that should NOT be processed (infrastructure/noise)
|
|
49
|
+
SKIP_LABELS = {
|
|
50
|
+
"AgentThought", "AgentAction", "AgentMessage", "AgentPresence",
|
|
51
|
+
"ExperimentRun", "ExperimentScore", "PipelineRun",
|
|
52
|
+
"VectorIndex", "BM25Index", "Session", "ContextRef",
|
|
53
|
+
"Context", "ContextIntelligence", "Project", "KnowledgeBase", "CodeBase",
|
|
54
|
+
"SystemStore", "UserStore", "WebStore", "GeneratedStore",
|
|
55
|
+
"MemoryStore", "ArtifactStore", "ToolStore",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Minimum entity name length to match (avoids false positives)
|
|
59
|
+
MIN_ENTITY_NAME_LEN = 3
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class GraphIntelligence:
|
|
63
|
+
"""Inline graph enrichment — runs on every node add.
|
|
64
|
+
|
|
65
|
+
Designed for speed: no LLM calls, no network I/O.
|
|
66
|
+
Uses cached entity names and keyword index.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(self, db):
|
|
70
|
+
self._db = db
|
|
71
|
+
self._entity_cache: Optional[Dict[str, str]] = None # name_lower → node_id
|
|
72
|
+
self._entity_cache_ts: float = 0
|
|
73
|
+
self._cache_ttl: float = 120.0 # rebuild entity cache every 2 min
|
|
74
|
+
|
|
75
|
+
def on_node_added(self, node, namespace: str = "") -> None:
|
|
76
|
+
"""Called after a node is persisted. Enriches it inline.
|
|
77
|
+
|
|
78
|
+
Must complete in <10ms for normal nodes.
|
|
79
|
+
"""
|
|
80
|
+
label = getattr(node, "label", "")
|
|
81
|
+
if label in SKIP_LABELS:
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
props = getattr(node, "properties", {}) or {}
|
|
85
|
+
node_id = getattr(node, "id", "")
|
|
86
|
+
if not node_id:
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
t0 = time.time()
|
|
90
|
+
|
|
91
|
+
# 1. Quality scoring
|
|
92
|
+
self._score_quality(node_id, label, props)
|
|
93
|
+
|
|
94
|
+
# 2. Topic tagging
|
|
95
|
+
self._tag_topics(node_id, label, props, namespace)
|
|
96
|
+
|
|
97
|
+
# 3. Auto-link entities (only for content nodes with text)
|
|
98
|
+
if label in ("Fact", "Passage", "TextChunk", "Claim", "Finding",
|
|
99
|
+
"Insight", "Document", "Article", "Statistic"):
|
|
100
|
+
self._auto_link_entities(node_id, props)
|
|
101
|
+
|
|
102
|
+
# 4. Auto-embed to vector store (for content-rich nodes)
|
|
103
|
+
self._auto_embed(node_id, label, props, namespace)
|
|
104
|
+
|
|
105
|
+
# 5. Schedule debounced index rebuild (batches multiple node adds)
|
|
106
|
+
self._schedule_index_rebuild(namespace)
|
|
107
|
+
|
|
108
|
+
# 6. Update context state (incremental — Findings/Insights only)
|
|
109
|
+
if label in ("Finding", "Insight"):
|
|
110
|
+
try:
|
|
111
|
+
from .context_state import get_context_state
|
|
112
|
+
state = get_context_state(self._db, namespace)
|
|
113
|
+
state.on_node_added(node)
|
|
114
|
+
except Exception:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
elapsed_ms = (time.time() - t0) * 1000
|
|
118
|
+
if elapsed_ms > 50:
|
|
119
|
+
logger.debug("[INTELLIGENCE] on_node_added took %.1fms for %s:%s", elapsed_ms, label, node_id[:12])
|
|
120
|
+
|
|
121
|
+
# ── Quality Scoring ─────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
def _score_quality(self, node_id: str, label: str, props: dict):
|
|
124
|
+
"""Assign _quality_score based on node type + metadata."""
|
|
125
|
+
score = QUALITY_SCORES.get(label, 0.3)
|
|
126
|
+
|
|
127
|
+
# Boost if node has source attribution
|
|
128
|
+
if props.get("source") or props.get("source_url") or props.get("url"):
|
|
129
|
+
score = min(1.0, score + 0.1)
|
|
130
|
+
|
|
131
|
+
# Boost if node was verified
|
|
132
|
+
if props.get("_verified") or props.get("verified"):
|
|
133
|
+
score = min(1.0, score + 0.1)
|
|
134
|
+
|
|
135
|
+
# Penalize if agent-generated without source
|
|
136
|
+
if props.get("_agent_id") and not props.get("source"):
|
|
137
|
+
score = max(0.1, score - 0.1)
|
|
138
|
+
|
|
139
|
+
props["_quality_score"] = round(score, 2)
|
|
140
|
+
|
|
141
|
+
# ── Topic Tagging ───────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
def _tag_topics(self, node_id: str, label: str, props: dict, namespace: str):
|
|
144
|
+
"""Assign _topics from keyword frequency in cached index."""
|
|
145
|
+
# Get text content
|
|
146
|
+
text = self._get_text(props).lower()
|
|
147
|
+
if not text or len(text) < 10:
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
# Use topic_scan's cached index if available
|
|
151
|
+
try:
|
|
152
|
+
from ..search.rag import topic_scan
|
|
153
|
+
result = topic_scan(self._db, namespace, max_topics=10, samples_per_topic=0)
|
|
154
|
+
topics = result.get("topics", [])
|
|
155
|
+
if not topics:
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
# Match node text against topic keywords
|
|
159
|
+
matched = []
|
|
160
|
+
for t in topics:
|
|
161
|
+
topic_name = t.get("name", "")
|
|
162
|
+
if topic_name and topic_name in text:
|
|
163
|
+
matched.append(topic_name)
|
|
164
|
+
|
|
165
|
+
if matched:
|
|
166
|
+
props["_topics"] = ",".join(matched[:3])
|
|
167
|
+
except Exception:
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
# ── Auto-Link Entities ──────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
def _auto_link_entities(self, node_id: str, props: dict):
|
|
173
|
+
"""Find entity names mentioned in node text, create MENTIONS edges."""
|
|
174
|
+
text = self._get_text(props)
|
|
175
|
+
if not text or len(text) < 20:
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
text_lower = text.lower()
|
|
179
|
+
entities = self._get_entity_cache()
|
|
180
|
+
if not entities:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
linked = 0
|
|
184
|
+
from .graph_structures import GraphEdge
|
|
185
|
+
import uuid as _uuid
|
|
186
|
+
|
|
187
|
+
for entity_name_lower, entity_id in entities.items():
|
|
188
|
+
if entity_id == node_id:
|
|
189
|
+
continue # don't self-link
|
|
190
|
+
if entity_name_lower in text_lower:
|
|
191
|
+
try:
|
|
192
|
+
# Check word boundary — avoid matching "India" inside "Indiana"
|
|
193
|
+
pattern = r'\b' + re.escape(entity_name_lower) + r'\b'
|
|
194
|
+
if re.search(pattern, text_lower):
|
|
195
|
+
edge = GraphEdge(
|
|
196
|
+
id=str(_uuid.uuid4()),
|
|
197
|
+
source=node_id,
|
|
198
|
+
target=entity_id,
|
|
199
|
+
label="MENTIONS",
|
|
200
|
+
properties={"auto_linked": True},
|
|
201
|
+
)
|
|
202
|
+
self._db.add_edge(edge)
|
|
203
|
+
linked += 1
|
|
204
|
+
if linked >= 5:
|
|
205
|
+
break # cap at 5 links per node
|
|
206
|
+
except Exception:
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
def _get_entity_cache(self) -> Dict[str, str]:
|
|
210
|
+
"""Get or rebuild the entity name → id cache."""
|
|
211
|
+
now = time.time()
|
|
212
|
+
if self._entity_cache is not None and (now - self._entity_cache_ts) < self._cache_ttl:
|
|
213
|
+
return self._entity_cache
|
|
214
|
+
|
|
215
|
+
# Rebuild cache
|
|
216
|
+
cache: Dict[str, str] = {}
|
|
217
|
+
try:
|
|
218
|
+
all_nodes = self._db.get_all_nodes()
|
|
219
|
+
for n in all_nodes:
|
|
220
|
+
label = getattr(n, "label", "")
|
|
221
|
+
if label in ("Entity", "Organization", "Author"):
|
|
222
|
+
name = (getattr(n, "properties", {}) or {}).get("name", "")
|
|
223
|
+
if name and len(name) >= MIN_ENTITY_NAME_LEN:
|
|
224
|
+
cache[name.lower()] = getattr(n, "id", "")
|
|
225
|
+
except Exception:
|
|
226
|
+
pass
|
|
227
|
+
|
|
228
|
+
self._entity_cache = cache
|
|
229
|
+
self._entity_cache_ts = now
|
|
230
|
+
logger.debug("[INTELLIGENCE] Entity cache rebuilt: %d entities", len(cache))
|
|
231
|
+
return cache
|
|
232
|
+
|
|
233
|
+
# ── Auto-Embed ──────────────────────────────────────────────
|
|
234
|
+
|
|
235
|
+
# Labels worth embedding (have meaningful text)
|
|
236
|
+
_EMBED_LABELS = {"Fact", "Passage", "TextChunk", "Claim", "Finding",
|
|
237
|
+
"Insight", "Article", "Document", "Statistic"}
|
|
238
|
+
_MIN_EMBED_LENGTH = 50
|
|
239
|
+
|
|
240
|
+
# Embed queue — limits concurrent Ollama calls during bulk ingest
|
|
241
|
+
_embed_semaphore = None
|
|
242
|
+
|
|
243
|
+
def _auto_embed(self, node_id: str, label: str, props: dict, namespace: str):
|
|
244
|
+
"""Embed content-rich nodes to vector store asynchronously (fire-and-forget).
|
|
245
|
+
|
|
246
|
+
Uses a semaphore to limit concurrent embed calls (prevents overloading Ollama
|
|
247
|
+
during bulk ingest of 500+ nodes).
|
|
248
|
+
"""
|
|
249
|
+
if label not in self._EMBED_LABELS:
|
|
250
|
+
return
|
|
251
|
+
if not namespace:
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
# Skip if already embedded (pipeline STORE_VECTORS stage may have done it)
|
|
255
|
+
if props.get("vector_ref"):
|
|
256
|
+
return
|
|
257
|
+
|
|
258
|
+
text = props.get("content") or props.get("statement") or props.get("name") or ""
|
|
259
|
+
text = str(text)
|
|
260
|
+
if len(text) < self._MIN_EMBED_LENGTH:
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
# Set vector_ref optimistically
|
|
264
|
+
props["vector_ref"] = f"{namespace}_passages:{node_id}"
|
|
265
|
+
|
|
266
|
+
# Init semaphore once (max 3 concurrent embeds)
|
|
267
|
+
import threading
|
|
268
|
+
if GraphIntelligence._embed_semaphore is None:
|
|
269
|
+
GraphIntelligence._embed_semaphore = threading.Semaphore(3)
|
|
270
|
+
|
|
271
|
+
def _do_embed():
|
|
272
|
+
GraphIntelligence._embed_semaphore.acquire()
|
|
273
|
+
try:
|
|
274
|
+
from ..context.vector_integration import SessionVectorStore, get_session_vector_store
|
|
275
|
+
svs = get_session_vector_store()
|
|
276
|
+
if svs.available:
|
|
277
|
+
svs.add_text(
|
|
278
|
+
namespace, text[:500], node_id=node_id,
|
|
279
|
+
metadata={"label": label, "name": props.get("name", "")[:100]},
|
|
280
|
+
)
|
|
281
|
+
except Exception:
|
|
282
|
+
pass
|
|
283
|
+
finally:
|
|
284
|
+
GraphIntelligence._embed_semaphore.release()
|
|
285
|
+
|
|
286
|
+
t = threading.Thread(target=_do_embed, daemon=True)
|
|
287
|
+
t.start()
|
|
288
|
+
|
|
289
|
+
# ── Index Rebuild (debounced) ─────────────────────────────
|
|
290
|
+
|
|
291
|
+
_rebuild_timers: Dict[str, Any] = {} # namespace → Timer
|
|
292
|
+
|
|
293
|
+
def _schedule_index_rebuild(self, namespace: str):
|
|
294
|
+
"""Schedule a debounced index rebuild. Waits 2s after last node add before rebuilding.
|
|
295
|
+
|
|
296
|
+
This batches rapid node additions (e.g. pipeline ingest of 500 nodes)
|
|
297
|
+
into a single rebuild at the end.
|
|
298
|
+
"""
|
|
299
|
+
import threading
|
|
300
|
+
ns = namespace or getattr(self._db, "name", "")
|
|
301
|
+
if not ns:
|
|
302
|
+
return
|
|
303
|
+
|
|
304
|
+
# Cancel previous timer for this namespace
|
|
305
|
+
old_timer = GraphIntelligence._rebuild_timers.get(ns)
|
|
306
|
+
if old_timer:
|
|
307
|
+
old_timer.cancel()
|
|
308
|
+
|
|
309
|
+
# Schedule new rebuild in 2 seconds
|
|
310
|
+
def _do_rebuild():
|
|
311
|
+
try:
|
|
312
|
+
build_indexes(self._db, ns)
|
|
313
|
+
except Exception:
|
|
314
|
+
pass
|
|
315
|
+
GraphIntelligence._rebuild_timers.pop(ns, None)
|
|
316
|
+
|
|
317
|
+
timer = threading.Timer(2.0, _do_rebuild)
|
|
318
|
+
timer.daemon = True
|
|
319
|
+
timer.start()
|
|
320
|
+
GraphIntelligence._rebuild_timers[ns] = timer
|
|
321
|
+
|
|
322
|
+
# ── Helpers ──────────────────────────────────────────────────
|
|
323
|
+
|
|
324
|
+
def _get_text(self, props: dict) -> str:
|
|
325
|
+
"""Extract searchable text from node properties."""
|
|
326
|
+
parts = []
|
|
327
|
+
for field in ("name", "content", "statement", "description", "title"):
|
|
328
|
+
val = props.get(field, "")
|
|
329
|
+
if val:
|
|
330
|
+
parts.append(str(val))
|
|
331
|
+
return " ".join(parts)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
# ── Index Builder (called from ingest, background, on-demand) ──
|
|
335
|
+
|
|
336
|
+
def build_indexes(db, namespace: str = "") -> Dict[str, Any]:
|
|
337
|
+
"""Build all search indexes for a graph. Called after ingest or on demand.
|
|
338
|
+
|
|
339
|
+
Builds: keyword index, BM25 index, context state.
|
|
340
|
+
Fast: ~2-3s for 800 nodes. Indexes are cached after build.
|
|
341
|
+
"""
|
|
342
|
+
ns = namespace or getattr(db, "name", "")
|
|
343
|
+
results = {}
|
|
344
|
+
t0 = time.time()
|
|
345
|
+
|
|
346
|
+
# 1. Keyword index
|
|
347
|
+
try:
|
|
348
|
+
from ..search.rag import _build_keyword_index
|
|
349
|
+
node_map, inv = _build_keyword_index(db, ns)
|
|
350
|
+
results["keyword"] = {"nodes": len(node_map), "terms": len(inv)}
|
|
351
|
+
except Exception as e:
|
|
352
|
+
results["keyword"] = {"error": str(e)}
|
|
353
|
+
|
|
354
|
+
# 2. BM25 index
|
|
355
|
+
try:
|
|
356
|
+
from ..search.rag import _get_bm25_engine
|
|
357
|
+
engine = _get_bm25_engine(db, ns)
|
|
358
|
+
if engine:
|
|
359
|
+
results["bm25"] = {"documents": len(engine._documents)}
|
|
360
|
+
except Exception as e:
|
|
361
|
+
results["bm25"] = {"error": str(e)}
|
|
362
|
+
|
|
363
|
+
# 3. Context state (rebuild + save as graph node)
|
|
364
|
+
try:
|
|
365
|
+
from .context_state import get_context_state
|
|
366
|
+
state = get_context_state(db, ns)
|
|
367
|
+
state.rebuild() # this also saves to ContextIntelligence node
|
|
368
|
+
results["context_state"] = {"status": state.status, "topics": len(state.coverage)}
|
|
369
|
+
except Exception as e:
|
|
370
|
+
results["context_state"] = {"error": str(e)}
|
|
371
|
+
|
|
372
|
+
elapsed = int((time.time() - t0) * 1000)
|
|
373
|
+
results["total_ms"] = elapsed
|
|
374
|
+
logger.info("[INDEX] Built all indexes for '%s' in %dms: %s", ns, elapsed, results)
|
|
375
|
+
return results
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
# ── Singleton per graph ─────────────────────────────────────────
|
|
379
|
+
|
|
380
|
+
_instances: Dict[str, GraphIntelligence] = {}
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def get_graph_intelligence(db) -> GraphIntelligence:
|
|
384
|
+
"""Get or create a GraphIntelligence instance for a graph."""
|
|
385
|
+
name = getattr(db, "name", id(db))
|
|
386
|
+
if name not in _instances:
|
|
387
|
+
_instances[name] = GraphIntelligence(db)
|
|
388
|
+
return _instances[name]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph data structures for AIContextDB
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Dict, Any, Optional
|
|
7
|
+
import uuid
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class GraphNode:
|
|
11
|
+
"""Represents a node in the graph.
|
|
12
|
+
|
|
13
|
+
The node.id is the UUID - single identifier used throughout the system.
|
|
14
|
+
The uuid field is kept for backward compatibility but node.id is the source of truth.
|
|
15
|
+
UUID is NOT stored in properties to avoid duplication - use node.id directly.
|
|
16
|
+
"""
|
|
17
|
+
id: str # This is the UUID - single identifier
|
|
18
|
+
label: str
|
|
19
|
+
properties: Dict[str, Any] = None
|
|
20
|
+
name: Optional[str] = None
|
|
21
|
+
uuid: Optional[str] = None # Deprecated - use id instead
|
|
22
|
+
alias: Optional[str] = None
|
|
23
|
+
|
|
24
|
+
def __post_init__(self):
|
|
25
|
+
if self.properties is None:
|
|
26
|
+
self.properties = {}
|
|
27
|
+
# If id is not a UUID format, generate one
|
|
28
|
+
# Otherwise, id is already the UUID
|
|
29
|
+
if not self.id or (not self.uuid and len(self.id) != 36): # UUID format is 36 chars
|
|
30
|
+
generated_uuid = str(uuid.uuid4())
|
|
31
|
+
if not self.id:
|
|
32
|
+
self.id = generated_uuid
|
|
33
|
+
if not self.uuid:
|
|
34
|
+
self.uuid = generated_uuid
|
|
35
|
+
|
|
36
|
+
# Ensure uuid field matches id (id is the source of truth)
|
|
37
|
+
if not self.uuid:
|
|
38
|
+
self.uuid = self.id
|
|
39
|
+
elif self.uuid != self.id:
|
|
40
|
+
# If uuid doesn't match id, use id as source of truth
|
|
41
|
+
self.uuid = self.id
|
|
42
|
+
|
|
43
|
+
# Don't store UUID in properties - node.id is the single source of truth
|
|
44
|
+
# UUID will be added explicitly in query results using node.id
|
|
45
|
+
# Remove uuid from properties if it exists (to avoid duplication)
|
|
46
|
+
self.properties.pop('uuid', None)
|
|
47
|
+
|
|
48
|
+
# Store name in properties if provided
|
|
49
|
+
if self.name and 'name' not in self.properties:
|
|
50
|
+
self.properties['name'] = self.name
|
|
51
|
+
# Store alias in properties if provided
|
|
52
|
+
if self.alias and 'alias' not in self.properties:
|
|
53
|
+
self.properties['alias'] = self.alias
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class GraphEdge:
|
|
57
|
+
"""Represents an edge in the graph.
|
|
58
|
+
|
|
59
|
+
The edge.id is the UUID - single identifier used throughout the system.
|
|
60
|
+
The uuid field is kept for backward compatibility but edge.id is the source of truth.
|
|
61
|
+
UUID is NOT stored in properties to avoid duplication - use edge.id directly.
|
|
62
|
+
"""
|
|
63
|
+
id: str # This is the UUID - single identifier
|
|
64
|
+
source: str # Source node UUID
|
|
65
|
+
target: str # Target node UUID
|
|
66
|
+
label: str
|
|
67
|
+
properties: Dict[str, Any] = None
|
|
68
|
+
name: Optional[str] = None
|
|
69
|
+
uuid: Optional[str] = None # Deprecated - use id instead
|
|
70
|
+
alias: Optional[str] = None
|
|
71
|
+
|
|
72
|
+
def __post_init__(self):
|
|
73
|
+
if self.properties is None:
|
|
74
|
+
self.properties = {}
|
|
75
|
+
# If id is not a UUID format, generate one
|
|
76
|
+
# Otherwise, id is already the UUID
|
|
77
|
+
if not self.id or (not self.uuid and len(self.id) != 36): # UUID format is 36 chars
|
|
78
|
+
generated_uuid = str(uuid.uuid4())
|
|
79
|
+
if not self.id:
|
|
80
|
+
self.id = generated_uuid
|
|
81
|
+
if not self.uuid:
|
|
82
|
+
self.uuid = generated_uuid
|
|
83
|
+
|
|
84
|
+
# Ensure uuid field matches id (id is the source of truth)
|
|
85
|
+
if not self.uuid:
|
|
86
|
+
self.uuid = self.id
|
|
87
|
+
elif self.uuid != self.id:
|
|
88
|
+
# If uuid doesn't match id, use id as source of truth
|
|
89
|
+
self.uuid = self.id
|
|
90
|
+
|
|
91
|
+
# Don't store UUID in properties - edge.id is the single source of truth
|
|
92
|
+
# UUID will be added explicitly in query results using edge.id
|
|
93
|
+
# Remove uuid from properties if it exists (to avoid duplication)
|
|
94
|
+
self.properties.pop('uuid', None)
|
|
95
|
+
|
|
96
|
+
# Store name in properties if provided
|
|
97
|
+
if self.name and 'name' not in self.properties:
|
|
98
|
+
self.properties['name'] = self.name
|
|
99
|
+
# Store alias in properties if provided
|
|
100
|
+
if self.alias and 'alias' not in self.properties:
|
|
101
|
+
self.properties['alias'] = self.alias
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|