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.
Files changed (776) hide show
  1. contextsynapse/__init__.py +107 -0
  2. contextsynapse/__main__.py +9 -0
  3. contextsynapse/a2a/__init__.py +28 -0
  4. contextsynapse/a2a/client.py +120 -0
  5. contextsynapse/a2a/discovery.py +128 -0
  6. contextsynapse/a2a/handlers.py +164 -0
  7. contextsynapse/a2a/models.py +246 -0
  8. contextsynapse/a2a/streaming.py +92 -0
  9. contextsynapse/a2a/task_manager.py +275 -0
  10. contextsynapse/adapters/__init__.py +98 -0
  11. contextsynapse/adapters/_base.py +298 -0
  12. contextsynapse/adapters/autogen/__init__.py +4 -0
  13. contextsynapse/adapters/autogen/tools.py +34 -0
  14. contextsynapse/adapters/crewai/__init__.py +4 -0
  15. contextsynapse/adapters/crewai/tools.py +63 -0
  16. contextsynapse/adapters/langchain/__init__.py +19 -0
  17. contextsynapse/adapters/langchain/message_history.py +17 -0
  18. contextsynapse/adapters/langchain/retriever.py +158 -0
  19. contextsynapse/adapters/langchain/tools.py +43 -0
  20. contextsynapse/adapters/langgraph/__init__.py +21 -0
  21. contextsynapse/adapters/langgraph/checkpoint.py +223 -0
  22. contextsynapse/adapters/langgraph/context_tools.py +341 -0
  23. contextsynapse/adapters/langgraph/message_history.py +138 -0
  24. contextsynapse/adapters/langgraph/tools.py +43 -0
  25. contextsynapse/adapters/llamaindex/__init__.py +4 -0
  26. contextsynapse/adapters/llamaindex/tools.py +64 -0
  27. contextsynapse/adapters/openai/__init__.py +24 -0
  28. contextsynapse/adapters/openai/tools.py +206 -0
  29. contextsynapse/adapters/pydantic_ai/__init__.py +4 -0
  30. contextsynapse/adapters/pydantic_ai/tools.py +36 -0
  31. contextsynapse/adapters/swarm/__init__.py +4 -0
  32. contextsynapse/adapters/swarm/tools.py +44 -0
  33. contextsynapse/agents/__init__.py +6 -0
  34. contextsynapse/agents/auto_capture.py +80 -0
  35. contextsynapse/agents/dispatcher.py +299 -0
  36. contextsynapse/agents/notifications.py +112 -0
  37. contextsynapse/aiql/__init__.py +71 -0
  38. contextsynapse/aiql/cache.py +341 -0
  39. contextsynapse/aiql/compiler/__init__.py +62 -0
  40. contextsynapse/aiql/compiler/optimizer.py +126 -0
  41. contextsynapse/aiql/compiler/planner.py +366 -0
  42. contextsynapse/aiql/compiler/statistics.py +235 -0
  43. contextsynapse/aiql/compiler/validator.py +425 -0
  44. contextsynapse/aiql/engine/__init__.py +11 -0
  45. contextsynapse/aiql/engine/chunk_storage.py +2584 -0
  46. contextsynapse/aiql/engine/executor.py +7737 -0
  47. contextsynapse/aiql/engine/extraction_integration.py +442 -0
  48. contextsynapse/aiql/engine/graph_builder.py +405 -0
  49. contextsynapse/aiql/engine/node_creation_from_normalized.py +691 -0
  50. contextsynapse/aiql/engine/performance_monitor.py +289 -0
  51. contextsynapse/aiql/engine/postprocessing.py +365 -0
  52. contextsynapse/aiql/engine/ray_stage_executors.py +918 -0
  53. contextsynapse/aiql/engine/redis_cache.py +106 -0
  54. contextsynapse/aiql/engine/streaming_json.py +366 -0
  55. contextsynapse/aiql/engine/streaming_parquet.py +568 -0
  56. contextsynapse/aiql/engine/streaming_ray_chunking.py +419 -0
  57. contextsynapse/aiql/grammar/__init__.py +14 -0
  58. contextsynapse/aiql/grammar/aiql_grammar.py +1822 -0
  59. contextsynapse/aiql/grammar/base.py +71 -0
  60. contextsynapse/aiql/parser/__init__.py +46 -0
  61. contextsynapse/aiql/parser/aiql_parser.py +11330 -0
  62. contextsynapse/aiql/parser/base_parser.py +47 -0
  63. contextsynapse/api/__init__.py +5 -0
  64. contextsynapse/api/a2a_router.py +233 -0
  65. contextsynapse/api/admin_router.py +140 -0
  66. contextsynapse/api/agent_worker_router.py +978 -0
  67. contextsynapse/api/algorithms_router.py +317 -0
  68. contextsynapse/api/api.py +4144 -0
  69. contextsynapse/api/audit.py +204 -0
  70. contextsynapse/api/auth.py +441 -0
  71. contextsynapse/api/auth_router.py +537 -0
  72. contextsynapse/api/billing.py +261 -0
  73. contextsynapse/api/billing_router.py +275 -0
  74. contextsynapse/api/boundary_router.py +452 -0
  75. contextsynapse/api/cognition_router.py +116 -0
  76. contextsynapse/api/connector_router.py +237 -0
  77. contextsynapse/api/context_router.py +1619 -0
  78. contextsynapse/api/dashboard_router.py +11367 -0
  79. contextsynapse/api/errors.py +183 -0
  80. contextsynapse/api/events.py +88 -0
  81. contextsynapse/api/experiment_bootstrap.py +321 -0
  82. contextsynapse/api/experiment_orchestrator.py +1078 -0
  83. contextsynapse/api/experiment_router.py +2089 -0
  84. contextsynapse/api/feature_gate.py +89 -0
  85. contextsynapse/api/federation_router.py +108 -0
  86. contextsynapse/api/integrations.py +567 -0
  87. contextsynapse/api/integrations_router.py +461 -0
  88. contextsynapse/api/intelligence_router.py +1028 -0
  89. contextsynapse/api/metering.py +155 -0
  90. contextsynapse/api/metrics.py +112 -0
  91. contextsynapse/api/models.py +38 -0
  92. contextsynapse/api/monitoring_router.py +174 -0
  93. contextsynapse/api/pipeline_router.py +1437 -0
  94. contextsynapse/api/playground_conn.py +116 -0
  95. contextsynapse/api/projects_router.py +131 -0
  96. contextsynapse/api/queries_router.py +282 -0
  97. contextsynapse/api/quota.py +95 -0
  98. contextsynapse/api/rate_limit.py +64 -0
  99. contextsynapse/api/search_router.py +261 -0
  100. contextsynapse/api/shield_router.py +447 -0
  101. contextsynapse/api/tenant_guard.py +103 -0
  102. contextsynapse/api/tenant_quotas.py +231 -0
  103. contextsynapse/api/tenants.py +305 -0
  104. contextsynapse/api/users.py +646 -0
  105. contextsynapse/api/v1.py +167 -0
  106. contextsynapse/api/vertical_builder_router.py +387 -0
  107. contextsynapse/benchmark/__init__.py +15 -0
  108. contextsynapse/benchmark/__main__.py +64 -0
  109. contextsynapse/benchmark/agents.py +338 -0
  110. contextsynapse/benchmark/live_ab.py +338 -0
  111. contextsynapse/benchmark/reporter.py +149 -0
  112. contextsynapse/benchmark/runner.py +264 -0
  113. contextsynapse/benchmark/savings.py +266 -0
  114. contextsynapse/benchmark/token_counter.py +212 -0
  115. contextsynapse/benchmark/workloads.py +289 -0
  116. contextsynapse/buffer/__init__.py +154 -0
  117. contextsynapse/buffer/base.py +257 -0
  118. contextsynapse/buffer/duckdb_buffer.py +246 -0
  119. contextsynapse/buffer/file_buffer.py +229 -0
  120. contextsynapse/buffer/lmdb_buffer.py +286 -0
  121. contextsynapse/buffer/local_buffer.py +154 -0
  122. contextsynapse/buffer/redis_buffer.py +211 -0
  123. contextsynapse/buffer/sqlite_buffer.py +266 -0
  124. contextsynapse/cache.py +2 -0
  125. contextsynapse/cli/__init__.py +40 -0
  126. contextsynapse/cli/cli.py +475 -0
  127. contextsynapse/cli/config_cli.py +177 -0
  128. contextsynapse/cli/scaffold.py +465 -0
  129. contextsynapse/cognition/__init__.py +31 -0
  130. contextsynapse/cognition/derivation.py +55 -0
  131. contextsynapse/cognition/events.py +135 -0
  132. contextsynapse/cognition/feedback.py +52 -0
  133. contextsynapse/cognition/hallucination.py +90 -0
  134. contextsynapse/cognition/invalidation.py +70 -0
  135. contextsynapse/cognition/read_tracker.py +50 -0
  136. contextsynapse/collaboration.py +2 -0
  137. contextsynapse/comparison.py +2 -0
  138. contextsynapse/config/__init__.py +10 -0
  139. contextsynapse/config/connectors/amfi_nav.yaml +18 -0
  140. contextsynapse/config/connectors/auto_sector.yaml +20 -0
  141. contextsynapse/config/connectors/banking_sector.yaml +20 -0
  142. contextsynapse/config/connectors/energy_sector.yaml +20 -0
  143. contextsynapse/config/connectors/fmcg_sector.yaml +20 -0
  144. contextsynapse/config/connectors/nsdl_fpi.yaml +9 -0
  145. contextsynapse/config/connectors/nse_price.yaml +61 -0
  146. contextsynapse/config/connectors/pharma_sector.yaml +20 -0
  147. contextsynapse/config/connectors/rbi_dbie.yaml +12 -0
  148. contextsynapse/config/context_presets/ai_research.json +25 -0
  149. contextsynapse/config/context_presets/chatgpt_conversations.json +19 -0
  150. contextsynapse/config/context_presets/claude_conversations.json +19 -0
  151. contextsynapse/config/context_presets/legal_compliance.json +21 -0
  152. contextsynapse/config/context_presets/meeting_notes.json +21 -0
  153. contextsynapse/config/context_presets/slack_engineering.json +21 -0
  154. contextsynapse/config/context_presets/tech_climate.json +24 -0
  155. contextsynapse/config/context_presets/toi_politics.json +25 -0
  156. contextsynapse/config/database_config.py +453 -0
  157. contextsynapse/config/deployment.py +221 -0
  158. contextsynapse/config/gpt_action_schema.json +164 -0
  159. contextsynapse/config/indicators/india_macro.yaml +213 -0
  160. contextsynapse/config/logging_config.py +88 -0
  161. contextsynapse/config/mode_config.py +223 -0
  162. contextsynapse/config/schemas/api_spec.yaml +48 -0
  163. contextsynapse/config/schemas/architecture_doc.yaml +51 -0
  164. contextsynapse/config/schemas/chat_history.yaml +90 -0
  165. contextsynapse/config/schemas/chatgpt_conversation.yaml +101 -0
  166. contextsynapse/config/schemas/claude_conversation.yaml +148 -0
  167. contextsynapse/config/schemas/contract.yaml +48 -0
  168. contextsynapse/config/schemas/conversation.yaml +167 -0
  169. contextsynapse/config/schemas/database.yaml +74 -0
  170. contextsynapse/config/schemas/decision.yaml +72 -0
  171. contextsynapse/config/schemas/ecommerce.yaml +56 -0
  172. contextsynapse/config/schemas/education.yaml +42 -0
  173. contextsynapse/config/schemas/healthcare.yaml +133 -0
  174. contextsynapse/config/schemas/hr_document.yaml +48 -0
  175. contextsynapse/config/schemas/invoice.yaml +40 -0
  176. contextsynapse/config/schemas/knowledge_base.yaml +75 -0
  177. contextsynapse/config/schemas/legal.yaml +42 -0
  178. contextsynapse/config/schemas/marketing_content.yaml +48 -0
  179. contextsynapse/config/schemas/meeting_notes.yaml +51 -0
  180. contextsynapse/config/schemas/news_article.yaml +61 -0
  181. contextsynapse/config/schemas/real_estate.yaml +49 -0
  182. contextsynapse/config/schemas/requirements_doc.yaml +48 -0
  183. contextsynapse/config/schemas/research_paper.yaml +56 -0
  184. contextsynapse/config/schemas/resume.yaml +49 -0
  185. contextsynapse/config/schemas/retail.yaml +42 -0
  186. contextsynapse/config/schemas/rule_meta.yaml +173 -0
  187. contextsynapse/config/schemas/rules.yaml +72 -0
  188. contextsynapse/config/schemas/screener_meta.yaml +236 -0
  189. contextsynapse/config/schemas/sdlc.yaml +103 -0
  190. contextsynapse/config/schemas/session_graph.yaml +172 -0
  191. contextsynapse/config/schemas/support_ticket.yaml +48 -0
  192. contextsynapse/config/schemas/web.yaml +64 -0
  193. contextsynapse/config/sensors/earnings_calendar.yaml +52 -0
  194. contextsynapse/config/sensors/global_risk.yaml +53 -0
  195. contextsynapse/config/sensors/government_policy.yaml +54 -0
  196. contextsynapse/config/sensors/supply_chain.yaml +50 -0
  197. contextsynapse/config/sensors/templates/behavioral.yaml +56 -0
  198. contextsynapse/config/sensors/templates/equity_sentiment.yaml +48 -0
  199. contextsynapse/config/sensors/templates/global_macro.yaml +47 -0
  200. contextsynapse/config/sensors/templates/market_data.yaml +118 -0
  201. contextsynapse/config/sensors/templates/sector_technical.yaml +47 -0
  202. contextsynapse/config/sensors/weather.yaml +52 -0
  203. contextsynapse/config/storage_strategy.py +202 -0
  204. contextsynapse/config/templates/competitive_intel.yaml +39 -0
  205. contextsynapse/config/templates/geopolitical_risk.yaml +46 -0
  206. contextsynapse/config/templates/market_analysis.yaml +58 -0
  207. contextsynapse/connectors/__init__.py +15 -0
  208. contextsynapse/connectors/api_router.py +121 -0
  209. contextsynapse/connectors/base.py +357 -0
  210. contextsynapse/connectors/financial/audio.py +170 -0
  211. contextsynapse/connectors/financial/youtube.py +272 -0
  212. contextsynapse/connectors/github.py +164 -0
  213. contextsynapse/connectors/jira.py +120 -0
  214. contextsynapse/connectors/kafka_connector.py +124 -0
  215. contextsynapse/connectors/pipeline_connector.py +747 -0
  216. contextsynapse/connectors/registry.py +116 -0
  217. contextsynapse/connectors/scheduler.py +87 -0
  218. contextsynapse/connectors/universal.py +360 -0
  219. contextsynapse/context/__init__.py +96 -0
  220. contextsynapse/context/__main__.py +4 -0
  221. contextsynapse/context/acl.py +125 -0
  222. contextsynapse/context/agent_card.py +201 -0
  223. contextsynapse/context/agent_memory.py +814 -0
  224. contextsynapse/context/agents.py +472 -0
  225. contextsynapse/context/agents_redis.py +391 -0
  226. contextsynapse/context/assembled.py +204 -0
  227. contextsynapse/context/attribution.py +113 -0
  228. contextsynapse/context/blob.py +184 -0
  229. contextsynapse/context/boundaries.py +187 -0
  230. contextsynapse/context/boundary.py +507 -0
  231. contextsynapse/context/bundle.py +155 -0
  232. contextsynapse/context/cli.py +519 -0
  233. contextsynapse/context/collaboration.py +165 -0
  234. contextsynapse/context/compiler.py +604 -0
  235. contextsynapse/context/composite.py +536 -0
  236. contextsynapse/context/compression.py +147 -0
  237. contextsynapse/context/context_manager.py +888 -0
  238. contextsynapse/context/context_schema.py +90 -0
  239. contextsynapse/context/context_schema.yaml +105 -0
  240. contextsynapse/context/context_units.py +891 -0
  241. contextsynapse/context/conversation.py +488 -0
  242. contextsynapse/context/dedup.py +207 -0
  243. contextsynapse/context/document_processor.py +698 -0
  244. contextsynapse/context/embedding_hooks.py +338 -0
  245. contextsynapse/context/execution_schema.py +274 -0
  246. contextsynapse/context/fan_out.py +138 -0
  247. contextsynapse/context/frozen.py +80 -0
  248. contextsynapse/context/gravity.py +227 -0
  249. contextsynapse/context/hub.py +1401 -0
  250. contextsynapse/context/ingest.py +391 -0
  251. contextsynapse/context/injection.py +226 -0
  252. contextsynapse/context/interaction_graphifier.py +562 -0
  253. contextsynapse/context/layers.py +574 -0
  254. contextsynapse/context/projection.py +1195 -0
  255. contextsynapse/context/promotion.py +634 -0
  256. contextsynapse/context/proof.py +131 -0
  257. contextsynapse/context/propagation.py +577 -0
  258. contextsynapse/context/pubsub.py +135 -0
  259. contextsynapse/context/quality.py +1054 -0
  260. contextsynapse/context/quality_tracker.py +270 -0
  261. contextsynapse/context/scoping.py +370 -0
  262. contextsynapse/context/seed.py +992 -0
  263. contextsynapse/context/session.py +1142 -0
  264. contextsynapse/context/session_graph.py +593 -0
  265. contextsynapse/context/session_memory.py +309 -0
  266. contextsynapse/context/session_resolver.py +111 -0
  267. contextsynapse/context/skill_learning.py +237 -0
  268. contextsynapse/context/smart_budget.py +129 -0
  269. contextsynapse/context/source_policy.py +242 -0
  270. contextsynapse/context/store_factory.py +53 -0
  271. contextsynapse/context/sync.py +648 -0
  272. contextsynapse/context/token.py +236 -0
  273. contextsynapse/context/vector_integration.py +297 -0
  274. contextsynapse/context/webhooks.py +194 -0
  275. contextsynapse/context/working_memory.py +224 -0
  276. contextsynapse/core/__init__.py +18 -0
  277. contextsynapse/core/archiver.py +237 -0
  278. contextsynapse/core/change_stream.py +282 -0
  279. contextsynapse/core/checkpoint.py +310 -0
  280. contextsynapse/core/cloud_storage.py +387 -0
  281. contextsynapse/core/context_state.py +651 -0
  282. contextsynapse/core/cron.py +324 -0
  283. contextsynapse/core/datasource.py +643 -0
  284. contextsynapse/core/db.py +289 -0
  285. contextsynapse/core/federation.py +283 -0
  286. contextsynapse/core/graph_coordinator.py +201 -0
  287. contextsynapse/core/graph_intelligence.py +388 -0
  288. contextsynapse/core/graph_structures.py +106 -0
  289. contextsynapse/core/graph_sync.py +157 -0
  290. contextsynapse/core/hybrid_graph_storage.py +2998 -0
  291. contextsynapse/core/lifecycle.py +691 -0
  292. contextsynapse/core/multiworker.py +378 -0
  293. contextsynapse/core/pruning.py +312 -0
  294. contextsynapse/core/redis_registry.py +524 -0
  295. contextsynapse/core/registry.py +1043 -0
  296. contextsynapse/core/registry_factory.py +51 -0
  297. contextsynapse/core/registry_metadata.py +294 -0
  298. contextsynapse/core/replay.py +354 -0
  299. contextsynapse/core/replication.py +339 -0
  300. contextsynapse/core/time_travel.py +260 -0
  301. contextsynapse/core/write_behind.py +152 -0
  302. contextsynapse/core/write_context.py +39 -0
  303. contextsynapse/db/__init__.py +1 -0
  304. contextsynapse/db/postgres.py +267 -0
  305. contextsynapse/db/profile.py +236 -0
  306. contextsynapse/db/rules.py +328 -0
  307. contextsynapse/demo/__init__.py +0 -0
  308. contextsynapse/demo/report.py +147 -0
  309. contextsynapse/demo/runner.py +520 -0
  310. contextsynapse/demo/scenario.py +165 -0
  311. contextsynapse/demo/session_demo.py +280 -0
  312. contextsynapse/demo/session_report.py +143 -0
  313. contextsynapse/demo/universal_runner.py +257 -0
  314. contextsynapse/engine/__init__.py +15 -0
  315. contextsynapse/engine/core.py +555 -0
  316. contextsynapse/extraction/__init__.py +69 -0
  317. contextsynapse/extraction/cli.py +274 -0
  318. contextsynapse/extraction/config.py +107 -0
  319. contextsynapse/extraction/examples/example_usage.py +118 -0
  320. contextsynapse/extraction/examples/sample_manifest.json +53 -0
  321. contextsynapse/extraction/examples/sample_normalized.json +185 -0
  322. contextsynapse/extraction/extract_engine.py +440 -0
  323. contextsynapse/extraction/extractors/__init__.py +37 -0
  324. contextsynapse/extraction/extractors/chat_export_extractor.py +189 -0
  325. contextsynapse/extraction/extractors/csv_extractor.py +83 -0
  326. contextsynapse/extraction/extractors/docx_extractor.py +129 -0
  327. contextsynapse/extraction/extractors/excel_extractor.py +152 -0
  328. contextsynapse/extraction/extractors/html_extractor.py +146 -0
  329. contextsynapse/extraction/extractors/pdf_extractor.py +635 -0
  330. contextsynapse/extraction/extractors/pdf_extractor_layoutparser.py +408 -0
  331. contextsynapse/extraction/extractors/register_extractors.py +63 -0
  332. contextsynapse/extraction/extractors/text_extractor.py +65 -0
  333. contextsynapse/extraction/extractors/txt_extractor.py +120 -0
  334. contextsynapse/extraction/extractors/website_extractor.py +246 -0
  335. contextsynapse/extraction/fact_extractor.py +236 -0
  336. contextsynapse/extraction/file_manager.py +353 -0
  337. contextsynapse/extraction/hierarchy.py +239 -0
  338. contextsynapse/extraction/id_generator.py +450 -0
  339. contextsynapse/extraction/layout_detector.py +409 -0
  340. contextsynapse/extraction/llm_entity_extractor.py +301 -0
  341. contextsynapse/extraction/normalized_store.py +480 -0
  342. contextsynapse/extraction/normalizer.py +594 -0
  343. contextsynapse/extraction/parquet_writer.py +598 -0
  344. contextsynapse/extraction/post_processors/__init__.py +40 -0
  345. contextsynapse/extraction/post_processors/column_reorganizer.py +507 -0
  346. contextsynapse/extraction/ray_normalization.py +233 -0
  347. contextsynapse/extraction/ray_runner.py +207 -0
  348. contextsynapse/extraction/redis_schema_registry.py +222 -0
  349. contextsynapse/extraction/registry.py +204 -0
  350. contextsynapse/extraction/schema_loader.py +663 -0
  351. contextsynapse/extraction/schema_registry.py +230 -0
  352. contextsynapse/extraction/semantic_normalizer.py +245 -0
  353. contextsynapse/extraction/version_manager.py +314 -0
  354. contextsynapse/gateway/__init__.py +24 -0
  355. contextsynapse/gateway/action_emitter.py +212 -0
  356. contextsynapse/gateway/cost_tracker.py +508 -0
  357. contextsynapse/gateway/gateway.py +377 -0
  358. contextsynapse/gateway/policy.py +303 -0
  359. contextsynapse/governance/__init__.py +13 -0
  360. contextsynapse/governance/layer.py +513 -0
  361. contextsynapse/ingestion/__init__.py +15 -0
  362. contextsynapse/ingestion/amplifier.py +288 -0
  363. contextsynapse/ingestion/async_ingest.py +463 -0
  364. contextsynapse/ingestion/chunker.py +303 -0
  365. contextsynapse/ingestion/chunking.py +58 -0
  366. contextsynapse/ingestion/cleaner.py +190 -0
  367. contextsynapse/ingestion/cleanse.py +252 -0
  368. contextsynapse/ingestion/connectors/__init__.py +38 -0
  369. contextsynapse/ingestion/connectors/base.py +300 -0
  370. contextsynapse/ingestion/connectors/chatgpt_memory.py +247 -0
  371. contextsynapse/ingestion/connectors/claude_memory.py +274 -0
  372. contextsynapse/ingestion/connectors/sap_ingestor.py +208 -0
  373. contextsynapse/ingestion/content_detector.py +80 -0
  374. contextsynapse/ingestion/content_monitor.py +502 -0
  375. contextsynapse/ingestion/dedup.py +106 -0
  376. contextsynapse/ingestion/feed.py +640 -0
  377. contextsynapse/ingestion/filters.py +461 -0
  378. contextsynapse/ingestion/graph_builder.py +705 -0
  379. contextsynapse/ingestion/input_classifier.py +307 -0
  380. contextsynapse/ingestion/job_manager.py +571 -0
  381. contextsynapse/ingestion/llm_extractor.py +610 -0
  382. contextsynapse/ingestion/orchestrator.py +116 -0
  383. contextsynapse/ingestion/parsers/__init__.py +19 -0
  384. contextsynapse/ingestion/parsers/graph_parser_registry.py +103 -0
  385. contextsynapse/ingestion/parsers/graphml_parser.py +141 -0
  386. contextsynapse/ingestion/parsers/jsonld_parser.py +171 -0
  387. contextsynapse/ingestion/parsers/rdf_parser.py +150 -0
  388. contextsynapse/ingestion/pipeline_context.py +228 -0
  389. contextsynapse/ingestion/pipeline_store.py +1195 -0
  390. contextsynapse/ingestion/queue.py +133 -0
  391. contextsynapse/ingestion/reprocess.py +179 -0
  392. contextsynapse/ingestion/scenario_router.py +224 -0
  393. contextsynapse/ingestion/schema_extractor.py +759 -0
  394. contextsynapse/ingestion/schema_validator.py +274 -0
  395. contextsynapse/ingestion/sdlc_ingest.py +87 -0
  396. contextsynapse/ingestion/smart_ingest.py +2451 -0
  397. contextsynapse/ingestion/source_connector.py +171 -0
  398. contextsynapse/ingestion/stage_executor.py +2095 -0
  399. contextsynapse/ingestion/stages/__init__.py +9 -0
  400. contextsynapse/ingestion/stages/tabular_to_graph.py +289 -0
  401. contextsynapse/ingestion/strategies.py +386 -0
  402. contextsynapse/ingestion/universal/__init__.py +4 -0
  403. contextsynapse/ingestion/universal/_operator_registry.py +59 -0
  404. contextsynapse/ingestion/universal/ingest_content.py +32 -0
  405. contextsynapse/ingestion/universal/operators/__init__.py +1 -0
  406. contextsynapse/ingestion/universal/operators/base.py +19 -0
  407. contextsynapse/ingestion/universal/operators/build_edges.py +75 -0
  408. contextsynapse/ingestion/universal/operators/cluster_topics.py +397 -0
  409. contextsynapse/ingestion/universal/operators/deduplicate.py +45 -0
  410. contextsynapse/ingestion/universal/operators/detect_signals.py +90 -0
  411. contextsynapse/ingestion/universal/operators/embed.py +80 -0
  412. contextsynapse/ingestion/universal/operators/extract_entities.py +253 -0
  413. contextsynapse/ingestion/universal/operators/extract_preferences.py +117 -0
  414. contextsynapse/ingestion/universal/operators/filter_content.py +69 -0
  415. contextsynapse/ingestion/universal/operators/index_bm25.py +52 -0
  416. contextsynapse/ingestion/universal/operators/infer_domains.py +69 -0
  417. contextsynapse/ingestion/universal/operators/link_cross_reference.py +210 -0
  418. contextsynapse/ingestion/universal/operators/parse_records.py +66 -0
  419. contextsynapse/ingestion/universal/operators/resolve_entities.py +261 -0
  420. contextsynapse/ingestion/universal/operators/scanners/__init__.py +16 -0
  421. contextsynapse/ingestion/universal/operators/scanners/edges.py +173 -0
  422. contextsynapse/ingestion/universal/operators/scanners/git.py +187 -0
  423. contextsynapse/ingestion/universal/operators/scanners/github.py +135 -0
  424. contextsynapse/ingestion/universal/operators/scanners/github_api.py +509 -0
  425. contextsynapse/ingestion/universal/operators/scanners/helpers.py +67 -0
  426. contextsynapse/ingestion/universal/operators/scanners/jira.py +65 -0
  427. contextsynapse/ingestion/universal/operators/scanners/llm_enrichment.py +82 -0
  428. contextsynapse/ingestion/universal/operators/scanners/repo.py +149 -0
  429. contextsynapse/ingestion/universal/operators/sdlc_scan.py +213 -0
  430. contextsynapse/ingestion/universal/operators/spec_scanner.py +149 -0
  431. contextsynapse/ingestion/universal/operators/store_documents.py +72 -0
  432. contextsynapse/ingestion/universal/operators/synthesize_cu.py +180 -0
  433. contextsynapse/ingestion/universal/operators/validate_gate.py +65 -0
  434. contextsynapse/ingestion/universal/parsers/__init__.py +5 -0
  435. contextsynapse/ingestion/universal/parsers/record_parser.py +203 -0
  436. contextsynapse/ingestion/universal/parsers/turn_parser.py +329 -0
  437. contextsynapse/ingestion/universal/shared_signals.py +161 -0
  438. contextsynapse/ingestion/universal/stage_executor.py +219 -0
  439. contextsynapse/ingestion/web_crawler.py +265 -0
  440. contextsynapse/intelligence/__init__.py +53 -0
  441. contextsynapse/intelligence/alerts.py +198 -0
  442. contextsynapse/intelligence/collector.py +655 -0
  443. contextsynapse/intelligence/comparison.py +198 -0
  444. contextsynapse/intelligence/config.py +56 -0
  445. contextsynapse/intelligence/conflict_detector.py +182 -0
  446. contextsynapse/intelligence/context_gaps.py +192 -0
  447. contextsynapse/intelligence/context_radar.py +135 -0
  448. contextsynapse/intelligence/correlation_engine.py +416 -0
  449. contextsynapse/intelligence/correlation_template.py +120 -0
  450. contextsynapse/intelligence/dedup.py +296 -0
  451. contextsynapse/intelligence/event_bus.py +91 -0
  452. contextsynapse/intelligence/feedback_loop.py +101 -0
  453. contextsynapse/intelligence/freshness.py +307 -0
  454. contextsynapse/intelligence/fundamental_feed.py +551 -0
  455. contextsynapse/intelligence/geo_data.py +170 -0
  456. contextsynapse/intelligence/geo_reference.py +112 -0
  457. contextsynapse/intelligence/graph_fusion.py +465 -0
  458. contextsynapse/intelligence/heuristics.py +176 -0
  459. contextsynapse/intelligence/impact_tracker.py +336 -0
  460. contextsynapse/intelligence/macro_indicators.py +319 -0
  461. contextsynapse/intelligence/ocr.py +104 -0
  462. contextsynapse/intelligence/persistence.py +267 -0
  463. contextsynapse/intelligence/pipeline_health.py +130 -0
  464. contextsynapse/intelligence/price_feed.py +221 -0
  465. contextsynapse/intelligence/rate_limiter.py +130 -0
  466. contextsynapse/intelligence/reactive.py +411 -0
  467. contextsynapse/intelligence/runtime_context.py +390 -0
  468. contextsynapse/intelligence/sentiment_decay.py +426 -0
  469. contextsynapse/intelligence/session.py +277 -0
  470. contextsynapse/intelligence/signal_hierarchy.py +438 -0
  471. contextsynapse/intelligence/signals.py +185 -0
  472. contextsynapse/intelligence/source_watcher.py +132 -0
  473. contextsynapse/intelligence/table_enricher.py +256 -0
  474. contextsynapse/intelligence/tagger.py +319 -0
  475. contextsynapse/intelligence/timeseries.py +209 -0
  476. contextsynapse/intelligence/tracker.py +318 -0
  477. contextsynapse/intelligence/watchdog.py +392 -0
  478. contextsynapse/intelligence/watchdog_manager.py +263 -0
  479. contextsynapse/intelligence/webhook_receiver.py +165 -0
  480. contextsynapse/intelligence/weight_learner.py +234 -0
  481. contextsynapse/llm/__init__.py +8 -0
  482. contextsynapse/llm/client.py +348 -0
  483. contextsynapse/llm/rate_limiter.py +166 -0
  484. contextsynapse/logging_config.py +2 -0
  485. contextsynapse/marketplace/__init__.py +7 -0
  486. contextsynapse/marketplace/registry.py +173 -0
  487. contextsynapse/mcp/__init__.py +11 -0
  488. contextsynapse/mcp/__main__.py +4 -0
  489. contextsynapse/mcp/auth_middleware.py +212 -0
  490. contextsynapse/mcp/connection_pool.py +128 -0
  491. contextsynapse/mcp/server.py +986 -0
  492. contextsynapse/mcp/session_context.py +67 -0
  493. contextsynapse/memory/__init__.py +34 -0
  494. contextsynapse/memory/engine.py +475 -0
  495. contextsynapse/memory/temporal.py +327 -0
  496. contextsynapse/metadata/__init__.py +12 -0
  497. contextsynapse/metadata/metadata_db.py +272 -0
  498. contextsynapse/metadata/metadata_query_tool.py +300 -0
  499. contextsynapse/metadata/metadata_tracker.py +425 -0
  500. contextsynapse/models/__init__.py +27 -0
  501. contextsynapse/models/embedding_service.py +360 -0
  502. contextsynapse/models/model_registry.py +228 -0
  503. contextsynapse/multiworker.py +2 -0
  504. contextsynapse/pipelines/__init__.py +1 -0
  505. contextsynapse/pipelines/executor.py +851 -0
  506. contextsynapse/pipelines/filters.py +189 -0
  507. contextsynapse/pipelines/models.py +176 -0
  508. contextsynapse/pipelines/scheduler.py +268 -0
  509. contextsynapse/playground/__init__.py +1 -0
  510. contextsynapse/playground/templates.py +85 -0
  511. contextsynapse/plugins/__init__.py +43 -0
  512. contextsynapse/plugins/api.py +66 -0
  513. contextsynapse/plugins/base.py +350 -0
  514. contextsynapse/plugins/domain_interface.py +508 -0
  515. contextsynapse/plugins/domain_loader.py +241 -0
  516. contextsynapse/plugins/loader.py +148 -0
  517. contextsynapse/plugins/registry.py +265 -0
  518. contextsynapse/project/__init__.py +11 -0
  519. contextsynapse/project/code_context.py +807 -0
  520. contextsynapse/project/connectors/__init__.py +4 -0
  521. contextsynapse/project/connectors/github_connector.py +113 -0
  522. contextsynapse/project/connectors/jira_connector.py +160 -0
  523. contextsynapse/project/graph.py +1023 -0
  524. contextsynapse/project/project_context.py +545 -0
  525. contextsynapse/project/scanner_registry.py +61 -0
  526. contextsynapse/project/schema_manager.py +322 -0
  527. contextsynapse/project/schemas/knowledge.yaml +59 -0
  528. contextsynapse/project/schemas/sdlc.yaml +369 -0
  529. contextsynapse/project/sdlc_schema.py +172 -0
  530. contextsynapse/project/spec_parser.py +85 -0
  531. contextsynapse/project/task_lock.py +181 -0
  532. contextsynapse/project/task_stream.py +203 -0
  533. contextsynapse/project/team_tools.py +537 -0
  534. contextsynapse/py.typed +0 -0
  535. contextsynapse/realtime/__init__.py +6 -0
  536. contextsynapse/realtime/collaboration.py +147 -0
  537. contextsynapse/rules/__init__.py +10 -0
  538. contextsynapse/rules/engine.py +116 -0
  539. contextsynapse/rules/evaluators/__init__.py +6 -0
  540. contextsynapse/rules/evaluators/aggregate.py +205 -0
  541. contextsynapse/rules/evaluators/custom.py +170 -0
  542. contextsynapse/rules/evaluators/pre_action.py +125 -0
  543. contextsynapse/rules/evaluators/temporal.py +129 -0
  544. contextsynapse/rules/loader.py +52 -0
  545. contextsynapse/rules/models.py +124 -0
  546. contextsynapse/rules/universal.py +393 -0
  547. contextsynapse/scheduler.py +229 -0
  548. contextsynapse/schema/__init__.py +42 -0
  549. contextsynapse/schema/compiler.py +252 -0
  550. contextsynapse/schema/composer.py +158 -0
  551. contextsynapse/schema/dedup.py +73 -0
  552. contextsynapse/schema/derivation.py +172 -0
  553. contextsynapse/schema/sdl.py +326 -0
  554. contextsynapse/schema/validation_gate.py +124 -0
  555. contextsynapse/sdk/__init__.py +63 -0
  556. contextsynapse/sdk/agent.py +214 -0
  557. contextsynapse/sdk/client.py +269 -0
  558. contextsynapse/sdk/exceptions.py +23 -0
  559. contextsynapse/sdk/models.py +78 -0
  560. contextsynapse/sdk/session.py +408 -0
  561. contextsynapse/sdk/tracked.py +218 -0
  562. contextsynapse/sdk/worker.py +266 -0
  563. contextsynapse/sdk/workspace_client.py +98 -0
  564. contextsynapse/sdk/ws.py +41 -0
  565. contextsynapse/search/__init__.py +20 -0
  566. contextsynapse/search/embedding_cache.py +140 -0
  567. contextsynapse/search/enhanced_search.py +152 -0
  568. contextsynapse/search/fulltext.py +130 -0
  569. contextsynapse/search/graph_search.py +634 -0
  570. contextsynapse/search/lmdb_index.py +1218 -0
  571. contextsynapse/search/nl_to_aiql.py +199 -0
  572. contextsynapse/search/rag.py +1346 -0
  573. contextsynapse/search/rag_cache.py +167 -0
  574. contextsynapse/search/reasoning_chain.py +231 -0
  575. contextsynapse/search/redis_search.py +207 -0
  576. contextsynapse/search/retrieval_quality.py +314 -0
  577. contextsynapse/search/semantic_query.py +455 -0
  578. contextsynapse/search/text_resolver.py +159 -0
  579. contextsynapse/search/whoosh_search.py +373 -0
  580. contextsynapse/security/__init__.py +17 -0
  581. contextsynapse/security/audit.py +297 -0
  582. contextsynapse/security/audit_logger.py +97 -0
  583. contextsynapse/security/audit_trail.py +270 -0
  584. contextsynapse/security/auth_unified.py +284 -0
  585. contextsynapse/security/auto_tagger.py +230 -0
  586. contextsynapse/security/data_security.py +218 -0
  587. contextsynapse/security/encryption.py +207 -0
  588. contextsynapse/security/identity.py +447 -0
  589. contextsynapse/security/jwt_identity.py +59 -0
  590. contextsynapse/security/middleware.py +336 -0
  591. contextsynapse/security/pii.py +233 -0
  592. contextsynapse/security/rbac.py +96 -0
  593. contextsynapse/security/rls.py +205 -0
  594. contextsynapse/security/sanitize.py +233 -0
  595. contextsynapse/security/scoped_encryption.py +131 -0
  596. contextsynapse/security/tenant.py +401 -0
  597. contextsynapse/shield/__init__.py +21 -0
  598. contextsynapse/shield/anomaly.py +56 -0
  599. contextsynapse/shield/permissions.py +99 -0
  600. contextsynapse/shield/profile.py +103 -0
  601. contextsynapse/shield/shield.py +108 -0
  602. contextsynapse/shield/trust_engine.py +69 -0
  603. contextsynapse/skills/__init__.py +14 -0
  604. contextsynapse/skills/engine.py +233 -0
  605. contextsynapse/skills/loader.py +59 -0
  606. contextsynapse/skills/models.py +139 -0
  607. contextsynapse/storage/__init__.py +7 -0
  608. contextsynapse/storage/cache.py +208 -0
  609. contextsynapse/storage/columnar_store_v2.py +178 -0
  610. contextsynapse/storage/csr_graph_storage.py +587 -0
  611. contextsynapse/storage/csr_store.py +388 -0
  612. contextsynapse/storage/document_store.py +491 -0
  613. contextsynapse/storage/hnsw_index.py +294 -0
  614. contextsynapse/storage/hybrid_store_v2.py +278 -0
  615. contextsynapse/storage/lmdb_graph_storage.py +366 -0
  616. contextsynapse/storage/migration.py +279 -0
  617. contextsynapse/storage/namespace_store.py +346 -0
  618. contextsynapse/storage/pure_graph_storage.py +185 -0
  619. contextsynapse/storage/redis_graph_adapter.py +186 -0
  620. contextsynapse/storage/redis_graph_storage.py +375 -0
  621. contextsynapse/storage/router/__init__.py +29 -0
  622. contextsynapse/storage/router/duckdb_store.py +398 -0
  623. contextsynapse/storage/router/factory.py +83 -0
  624. contextsynapse/storage/router/interface.py +125 -0
  625. contextsynapse/storage/router/postgres_store.py +339 -0
  626. contextsynapse/storage/router/resolver.py +192 -0
  627. contextsynapse/storage/router/router.py +300 -0
  628. contextsynapse/storage/single_file_storage.py +391 -0
  629. contextsynapse/storage/storage_manager.py +214 -0
  630. contextsynapse/storage/storage_query_optimizer.py +314 -0
  631. contextsynapse/storage/wal.py +359 -0
  632. contextsynapse/temporal/__init__.py +0 -0
  633. contextsynapse/temporal/storage.py +106 -0
  634. contextsynapse/tests/__init__.py +11 -0
  635. contextsynapse/tests/regression/__init__.py +1 -0
  636. contextsynapse/tests/regression/add_metadata.py +395 -0
  637. contextsynapse/tests/regression/add_skip_flags.py +85 -0
  638. contextsynapse/tests/regression/cases/test_basic_create_node.yaml +20 -0
  639. contextsynapse/tests/regression/cases/test_basic_select.yaml +21 -0
  640. contextsynapse/tests/regression/cases/test_blockchain_audit_trail.yaml +37 -0
  641. contextsynapse/tests/regression/cases/test_blockchain_audit_trail_filtered.yaml +39 -0
  642. contextsynapse/tests/regression/cases/test_blockchain_blocks_range.yaml +39 -0
  643. contextsynapse/tests/regression/cases/test_blockchain_get_block.yaml +35 -0
  644. contextsynapse/tests/regression/cases/test_blockchain_latest_block.yaml +35 -0
  645. contextsynapse/tests/regression/cases/test_blockchain_length.yaml +37 -0
  646. contextsynapse/tests/regression/cases/test_blockchain_merkle_root.yaml +37 -0
  647. contextsynapse/tests/regression/cases/test_blockchain_verify.yaml +35 -0
  648. contextsynapse/tests/regression/cases/test_blockchain_verify_block.yaml +35 -0
  649. contextsynapse/tests/regression/cases/test_create_edge.yaml +28 -0
  650. contextsynapse/tests/regression/cases/test_delete_edge_basic.yaml +29 -0
  651. contextsynapse/tests/regression/cases/test_delete_node_basic.yaml +29 -0
  652. contextsynapse/tests/regression/cases/test_evaluation_mrr.yaml +40 -0
  653. contextsynapse/tests/regression/cases/test_evaluation_ndcg.yaml +40 -0
  654. contextsynapse/tests/regression/cases/test_evaluation_precision.yaml +40 -0
  655. contextsynapse/tests/regression/cases/test_evaluation_recall.yaml +40 -0
  656. contextsynapse/tests/regression/cases/test_group_by_basic.yaml +56 -0
  657. contextsynapse/tests/regression/cases/test_match_node_basic.yaml +29 -0
  658. contextsynapse/tests/regression/cases/test_match_node_with_order_limit.yaml +31 -0
  659. contextsynapse/tests/regression/cases/test_namespace_switch.yaml +18 -0
  660. contextsynapse/tests/regression/cases/test_pipeline_cascaded.yaml +61 -0
  661. contextsynapse/tests/regression/cases/test_pipeline_fixed_size_chunking.yaml +48 -0
  662. contextsynapse/tests/regression/cases/test_pipeline_gpt4_chunking.yaml +54 -0
  663. contextsynapse/tests/regression/cases/test_pipeline_hybrid_indexing.yaml +57 -0
  664. contextsynapse/tests/regression/cases/test_pipeline_large_embedding.yaml +52 -0
  665. contextsynapse/tests/regression/cases/test_pipeline_paragraph_chunking.yaml +49 -0
  666. contextsynapse/tests/regression/cases/test_pipeline_recursive_chunking.yaml +47 -0
  667. contextsynapse/tests/regression/cases/test_pipeline_run_pipeline.yaml +56 -0
  668. contextsynapse/tests/regression/cases/test_pipeline_section_based_chunking.yaml +53 -0
  669. contextsynapse/tests/regression/cases/test_pipeline_semantic_chunking.yaml +51 -0
  670. contextsynapse/tests/regression/cases/test_pipeline_with_entity_extraction.yaml +57 -0
  671. contextsynapse/tests/regression/cases/test_pipeline_with_relationships.yaml +62 -0
  672. contextsynapse/tests/regression/cases/test_rag_evaluation.yaml +38 -0
  673. contextsynapse/tests/regression/cases/test_rag_graph_bfs_with_eval.yaml +48 -0
  674. contextsynapse/tests/regression/cases/test_rag_graph_centrality.yaml +40 -0
  675. contextsynapse/tests/regression/cases/test_rag_graph_centrality_eval.yaml +35 -0
  676. contextsynapse/tests/regression/cases/test_rag_graph_community.yaml +40 -0
  677. contextsynapse/tests/regression/cases/test_rag_graph_community_eval.yaml +35 -0
  678. contextsynapse/tests/regression/cases/test_rag_graph_dfs_with_eval.yaml +35 -0
  679. contextsynapse/tests/regression/cases/test_rag_graph_multi_hop_eval.yaml +35 -0
  680. contextsynapse/tests/regression/cases/test_rag_graph_path.yaml +40 -0
  681. contextsynapse/tests/regression/cases/test_rag_graph_search_basic.yaml +38 -0
  682. contextsynapse/tests/regression/cases/test_rag_graph_search_bfs.yaml +52 -0
  683. contextsynapse/tests/regression/cases/test_rag_graph_search_dfs.yaml +41 -0
  684. contextsynapse/tests/regression/cases/test_rag_graph_search_multi_hop.yaml +43 -0
  685. contextsynapse/tests/regression/cases/test_rag_graph_search_shortest_path.yaml +41 -0
  686. contextsynapse/tests/regression/cases/test_rag_graph_search_weighted.yaml +43 -0
  687. contextsynapse/tests/regression/cases/test_rag_graph_shortest_path_eval.yaml +35 -0
  688. contextsynapse/tests/regression/cases/test_rag_graph_traversal.yaml +30 -0
  689. contextsynapse/tests/regression/cases/test_rag_graph_weighted_eval.yaml +35 -0
  690. contextsynapse/tests/regression/cases/test_rag_hybrid_search.yaml +33 -0
  691. contextsynapse/tests/regression/cases/test_rag_hybrid_with_prompt_embedding.yaml +44 -0
  692. contextsynapse/tests/regression/cases/test_rag_keyword_search.yaml +32 -0
  693. contextsynapse/tests/regression/cases/test_rag_multi_hop_graph.yaml +32 -0
  694. contextsynapse/tests/regression/cases/test_rag_path_based.yaml +34 -0
  695. contextsynapse/tests/regression/cases/test_rag_profile_based.yaml +32 -0
  696. contextsynapse/tests/regression/cases/test_rag_vector_search.yaml +32 -0
  697. contextsynapse/tests/regression/cases/test_rag_weighted_graph.yaml +34 -0
  698. contextsynapse/tests/regression/cases/test_rag_weighted_hybrid.yaml +31 -0
  699. contextsynapse/tests/regression/cases/test_semantic_boundary_chunking.yaml +57 -0
  700. contextsynapse/tests/regression/cases/test_semantic_boundary_detection.yaml +33 -0
  701. contextsynapse/tests/regression/cases/test_semantic_hash_function.yaml +30 -0
  702. contextsynapse/tests/regression/cases/test_semantic_hash_with_model.yaml +31 -0
  703. contextsynapse/tests/regression/cases/test_tcs_ingestion_fixed_size.yaml +44 -0
  704. contextsynapse/tests/regression/cases/test_tcs_ingestion_recursive.yaml +46 -0
  705. contextsynapse/tests/regression/cases/test_tcs_ingestion_section.yaml +46 -0
  706. contextsynapse/tests/regression/cases/test_tcs_ingestion_semantic.yaml +44 -0
  707. contextsynapse/tests/regression/cases/test_time_travel_as_of.yaml +35 -0
  708. contextsynapse/tests/regression/cases/test_time_travel_at_commit.yaml +33 -0
  709. contextsynapse/tests/regression/cases/test_time_travel_at_timestamp.yaml +33 -0
  710. contextsynapse/tests/regression/cases/test_time_travel_for_system_time_all.yaml +37 -0
  711. contextsynapse/tests/regression/cases/test_time_travel_versions_between.yaml +39 -0
  712. contextsynapse/tests/regression/cases/test_traverse_basic.yaml +31 -0
  713. contextsynapse/tests/regression/cases/test_traverse_max_depth.yaml +34 -0
  714. contextsynapse/tests/regression/cases/test_update_edge_basic.yaml +29 -0
  715. contextsynapse/tests/regression/evaluation_metrics.py +227 -0
  716. contextsynapse/tests/regression/regression_runner.py +1081 -0
  717. contextsynapse/tests/regression/setup_regression_data.py +212 -0
  718. contextsynapse/tests/regression/test_basic_only.py +84 -0
  719. contextsynapse/tests/regression/test_namespace_creation.py +29 -0
  720. contextsynapse/tests/regression/test_single_fix.py +61 -0
  721. contextsynapse/tests/regression/test_single_query.py +20 -0
  722. contextsynapse/tests/regression/validate_test_syntax.py +179 -0
  723. contextsynapse/tests/test_advanced_features.py +347 -0
  724. contextsynapse/tests/test_aiql_summary.py +283 -0
  725. contextsynapse/tests/test_all_aiql_queries.py +948 -0
  726. contextsynapse/tests/test_all_create_queries.py +213 -0
  727. contextsynapse/tests/test_api_vs_native.py +280 -0
  728. contextsynapse/tests/test_chunking_dedup.py +199 -0
  729. contextsynapse/tests/test_connectors.py +171 -0
  730. contextsynapse/tests/test_edges_and_match.py +202 -0
  731. contextsynapse/tests/test_extraction_pipeline_integration.py +581 -0
  732. contextsynapse/tests/test_name_property.py +224 -0
  733. contextsynapse/tests/test_node_edge_metadata.py +250 -0
  734. contextsynapse/tests/test_playground_conn.py +114 -0
  735. contextsynapse/tests/test_query_cache.py +213 -0
  736. contextsynapse/tests/test_source_policy_auth.py +348 -0
  737. contextsynapse/tests/test_temporal_and_domain.py +224 -0
  738. contextsynapse/tests/test_time_travel_e2e.py +571 -0
  739. contextsynapse/tests/test_traversal_and_aggregation.py +275 -0
  740. contextsynapse/tools/__init__.py +36 -0
  741. contextsynapse/tools/a2a_tools.py +106 -0
  742. contextsynapse/tools/cognition_tools.py +118 -0
  743. contextsynapse/tools/context.py +905 -0
  744. contextsynapse/tools/formatting.py +92 -0
  745. contextsynapse/tools/gateway_tools.py +186 -0
  746. contextsynapse/tools/graph.py +1700 -0
  747. contextsynapse/tools/intelligence.py +235 -0
  748. contextsynapse/tools/memory.py +118 -0
  749. contextsynapse/tools/registry.py +373 -0
  750. contextsynapse/tools/shield_tools.py +159 -0
  751. contextsynapse/tools/tasks.py +341 -0
  752. contextsynapse/tools/workspace_tools.py +124 -0
  753. contextsynapse/utils/__init__.py +15 -0
  754. contextsynapse/utils/config_loader.py +198 -0
  755. contextsynapse/utils/env_loader.py +156 -0
  756. contextsynapse/utils/file_utils.py +288 -0
  757. contextsynapse/utils/logging_optimizer.py +119 -0
  758. contextsynapse/vector/__init__.py +30 -0
  759. contextsynapse/vector/chroma_vector_store.py +152 -0
  760. contextsynapse/vector/custom_vector_store.py +537 -0
  761. contextsynapse/vector/faiss_vector_store.py +296 -0
  762. contextsynapse/vector/qdrant_vector_store.py +163 -0
  763. contextsynapse/vector/vector_db.py +953 -0
  764. contextsynapse/vector/vector_db_manager.py +197 -0
  765. contextsynapse/workspace/__init__.py +27 -0
  766. contextsynapse/workspace/base.py +94 -0
  767. contextsynapse/workspace/git.py +228 -0
  768. contextsynapse/workspace/github.py +78 -0
  769. contextsynapse/workspace/local.py +73 -0
  770. contextsynapse/workspace/tools.py +222 -0
  771. contextsynapse-1.0.0.dist-info/METADATA +847 -0
  772. contextsynapse-1.0.0.dist-info/RECORD +776 -0
  773. contextsynapse-1.0.0.dist-info/WHEEL +5 -0
  774. contextsynapse-1.0.0.dist-info/entry_points.txt +4 -0
  775. contextsynapse-1.0.0.dist-info/licenses/LICENSE +200 -0
  776. contextsynapse-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,905 @@
1
+ """
2
+ Context Tools — briefing, ask, session context.
3
+
4
+ These are the high-level tools agents use to understand the project
5
+ without needing to know graph structure or query syntax.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+
12
+ from .registry import ToolContext, ToolParam, tool
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def _record_shadow(ctx: ToolContext, tool_name: str, actual_result: str):
18
+ """Record shadow token count: actual result vs full graph dump baseline.
19
+
20
+ Controlled by AICONTEXTDB_SHADOW_COUNTING env var (default: on).
21
+ Set to 'off' or '0' to disable.
22
+ """
23
+ import os
24
+ if os.environ.get("CONTEXTSYNAPSE_SHADOW_COUNTING") or os.environ.get("AICONTEXTDB_SHADOW_COUNTING", "on").lower() in ("off", "0", "false", "no"):
25
+ return
26
+ try:
27
+ ns = ctx.conn._namespace if ctx.conn else ""
28
+ if not ns:
29
+ return
30
+ # Actual: what we're sending to the agent
31
+ actual_chars = len(actual_result)
32
+
33
+ # Baseline: what a full graph dump would be (without AIContextDB)
34
+ registry = getattr(ctx.conn, "_graph_registry", None)
35
+ if not registry:
36
+ return
37
+ db = registry.get_graph(ns)
38
+ if not db:
39
+ return
40
+ total_chars = 0
41
+ for node in db.get_all_nodes():
42
+ props = node.properties if hasattr(node, "properties") else {}
43
+ for v in props.values():
44
+ if isinstance(v, str):
45
+ total_chars += len(v)
46
+ if total_chars == 0:
47
+ return
48
+
49
+ from contextsynapse.gateway.cost_tracker import get_cost_tracker
50
+ get_cost_tracker().record_shadow(
51
+ namespace=ns,
52
+ agent_id=ctx.agent_id or "unknown",
53
+ tool_name=tool_name,
54
+ actual_chars=actual_chars,
55
+ baseline_chars=total_chars,
56
+ )
57
+ except Exception:
58
+ pass # shadow counting should never break the tool
59
+
60
+
61
+ @tool(
62
+ "briefing", "context",
63
+ "Get your full project briefing — requirements, tasks, decisions, "
64
+ "code files, attached context data, and what other agents have done. "
65
+ "Call this to understand the project before starting work.",
66
+ requires_project=True,
67
+ )
68
+ def _briefing(ctx: ToolContext) -> str:
69
+ # Inject manifest summary if available
70
+ manifest_text = ""
71
+ try:
72
+ from ..context.quality import get_manifest, ManifestBuilder
73
+ ns = getattr(ctx.conn, 'namespace', '') or getattr(ctx.conn, '_namespace', '')
74
+ redis_client = getattr(ctx.conn.db, '_redis', None) if hasattr(ctx.conn, 'db') else None
75
+ manifest = get_manifest(ns, redis_client)
76
+ if manifest:
77
+ manifest_text = ManifestBuilder.to_text(manifest)
78
+ except Exception:
79
+ pass
80
+
81
+ if not ctx.project:
82
+ # Fallback: build a basic briefing from the graph directly
83
+ try:
84
+ result = ctx.conn.query("SELECT *")
85
+ nodes = result.get("nodes", [])
86
+ if not nodes:
87
+ return "No data in the current graph. Ingest some content first."
88
+ type_counts = {}
89
+ for n in nodes:
90
+ label = n.get("label", "Unknown") if isinstance(n, dict) else getattr(n, "label", "Unknown")
91
+ type_counts[label] = type_counts.get(label, 0) + 1
92
+ lines = [f"Graph briefing ({len(nodes)} nodes):"]
93
+ for label, count in sorted(type_counts.items(), key=lambda x: -x[1]):
94
+ lines.append(f" - {label}: {count}")
95
+ edges = ctx.conn.get_edges()
96
+ if edges:
97
+ lines.append(f"\n{len(edges)} relationships in the graph.")
98
+ return "\n".join(lines)
99
+ except Exception:
100
+ return "No project loaded and could not read graph directly."
101
+ briefing = ctx.project.build_agent_context(
102
+ agent_id=ctx.agent_id, agent_name=ctx.agent_name,
103
+ )
104
+
105
+ # Apply Context Relevance Gravity — re-rank based on agent behavior
106
+ try:
107
+ from contextsynapse.context.gravity import get_gravity
108
+ intent = get_gravity().get_intent(ctx.agent_id or "")
109
+ if intent:
110
+ top_keywords = sorted(intent.items(), key=lambda x: x[1], reverse=True)[:5]
111
+ focus_terms = ", ".join(k for k, _ in top_keywords)
112
+ briefing += f"\n\n### Your Current Focus\nBased on your recent activity, you seem focused on: {focus_terms}"
113
+ except Exception:
114
+ pass
115
+
116
+ # Cross-Agent Propagation — inject updates from other agents
117
+ try:
118
+ from contextsynapse.context.propagation import get_propagator
119
+ ns = ctx.conn._namespace if ctx.conn else ""
120
+ updates = get_propagator().get_pending(ctx.agent_id or "", ns)
121
+ if updates:
122
+ briefing += "\n\n### Updates from Other Agents\n" + "\n".join(f"- {u}" for u in updates)
123
+ except Exception:
124
+ pass
125
+
126
+ # Append summary of attached contexts
127
+ try:
128
+ if ctx.conn and ctx.conn._graph_registry:
129
+ registry = ctx.conn._graph_registry
130
+ ns = ctx.conn._namespace
131
+ graph = registry.get_graph(ns)
132
+ if graph:
133
+ context_summaries = []
134
+ for node in graph.get_all_nodes():
135
+ label = node.label if hasattr(node, "label") else ""
136
+ if label == "ContextRef":
137
+ props = node.properties if hasattr(node, "properties") else {}
138
+ ctx_name = props.get("name", node.id[:12] if hasattr(node, "id") else "?")
139
+ ctx_type = props.get("context_type", "")
140
+ item_count = props.get("item_count", 0)
141
+ context_summaries.append(f"- {ctx_name} ({ctx_type}, {item_count} items)")
142
+ if context_summaries:
143
+ briefing += "\n\n### Attached Contexts\n" + "\n".join(context_summaries)
144
+ briefing += "\n\nUse ask(question) to search across these contexts."
145
+ except Exception:
146
+ pass
147
+
148
+ # Runtime Context Assembly — pull in linked upstream/lateral contexts
149
+ try:
150
+ from ..intelligence.runtime_context import RuntimeContextAssembler
151
+ from ..intelligence.signal_hierarchy import SignalHierarchy
152
+
153
+ ns = getattr(ctx.conn, '_namespace', '') or getattr(ctx.conn, 'namespace', '') or ''
154
+ if ns and hasattr(ctx.conn, '_graph_registry') and ctx.conn._graph_registry:
155
+ assembler = RuntimeContextAssembler(
156
+ graph_registry=ctx.conn._graph_registry,
157
+ )
158
+ # Auto-discover linked contexts from hierarchy
159
+ linked_contexts = [ns]
160
+ try:
161
+ from ..intelligence.persistence import IntelligencePersistence
162
+ # Try to load hierarchy and find upstream/lateral contexts
163
+ hierarchy = None
164
+ if hasattr(ctx.conn, '_context_manager'):
165
+ store = IntelligencePersistence(ctx.conn._context_manager)
166
+ hierarchy = store.load_hierarchy()
167
+ if hierarchy:
168
+ upstream = hierarchy.get_upstream(ns)
169
+ lateral = hierarchy.get_lateral(ns)
170
+ linked_contexts.extend(upstream[:3]) # top 3 upstream
171
+ linked_contexts.extend(lateral[:3]) # top 3 peers
172
+ except Exception:
173
+ pass
174
+
175
+ if len(linked_contexts) > 1:
176
+ view = assembler.assemble(contexts=linked_contexts, focus_entity=ns, days=7)
177
+ if view.facts or view.indicators:
178
+ runtime_lines = ["\n\n### Upstream & Peer Context"]
179
+ # Cross-context facts
180
+ external_facts = [f for f in view.facts if f.source_context != ns]
181
+ if external_facts:
182
+ runtime_lines.append(f"\n{len(external_facts)} recent signals from linked contexts:")
183
+ for fact in external_facts[:5]:
184
+ sent_tag = f" [{fact.sentiment}]" if fact.sentiment else ""
185
+ runtime_lines.append(f" [{fact.source_context}] {fact.statement[:100]}{sent_tag}")
186
+ # Cross-context indicators
187
+ external_indicators = [i for i in view.indicators if i.source_context != ns]
188
+ if external_indicators:
189
+ runtime_lines.append(f"\n{len(external_indicators)} indicators from linked contexts:")
190
+ for ind in external_indicators[:5]:
191
+ runtime_lines.append(f" [{ind.source_context}] {ind.name}: {ind.value} {ind.unit}")
192
+ # Sentiment comparison
193
+ if view.sentiment_comparison:
194
+ runtime_lines.append("\nSentiment across contexts:")
195
+ for entity, counts in list(view.sentiment_comparison.items())[:5]:
196
+ net = counts.get("net", 0)
197
+ arrow = "+" if net > 0 else "" if net < 0 else "~"
198
+ runtime_lines.append(f" {entity}: {arrow}{net} (pos={counts.get('positive',0)}, neg={counts.get('negative',0)})")
199
+ briefing += "\n".join(runtime_lines)
200
+ except Exception:
201
+ pass
202
+
203
+ ctx.record_provenance("read", "briefing", "")
204
+ if manifest_text:
205
+ return manifest_text + "\n\n---\n\n" + briefing
206
+ return briefing
207
+
208
+
209
+ @tool(
210
+ "ask", "context",
211
+ "Ask about the project in plain English. Searches the execution graph "
212
+ "AND all attached contexts (ingested documents, requirements, etc.). "
213
+ "Examples: 'What are the requirements?', 'What has codex done?', "
214
+ "'Show me the decisions', 'What tasks are open?'",
215
+ params=[ToolParam("question", "string", "Your question in plain English")],
216
+ )
217
+ def _ask(ctx: ToolContext, question: str) -> str:
218
+ from contextsynapse.search.semantic_query import semantic_search
219
+ # Track re-queries: if agent asks right after orient(), projection didn't surface this
220
+ try:
221
+ from contextsynapse.context.projection import record_requery
222
+ _ns = getattr(ctx.conn, 'namespace', '') or getattr(ctx.conn, '_namespace', '')
223
+ if _ns and ctx.agent_id:
224
+ record_requery(_ns, ctx.agent_id)
225
+ except Exception as _e:
226
+ import logging as _logging
227
+ _logging.getLogger(__name__).debug("record_requery call error: %s", _e)
228
+
229
+ # 1. Search the boundary's own graph
230
+ result = semantic_search(question, ctx.conn, ctx.project)
231
+ summary = result.get("summary", "")
232
+ all_nodes = result.get("nodes", [])
233
+
234
+ # 2. Also search all attached context graphs
235
+ try:
236
+ if ctx.conn and ctx.conn._graph_registry:
237
+ registry = ctx.conn._graph_registry
238
+ ns = ctx.conn._namespace
239
+
240
+ # Find attached contexts via ContextRef nodes or session_contexts table
241
+ context_namespaces = []
242
+ graph = registry.get_graph(ns)
243
+ if graph:
244
+ for node in graph.get_all_nodes():
245
+ label = node.label if hasattr(node, "label") else ""
246
+ if label == "ContextRef":
247
+ props = node.properties if hasattr(node, "properties") else {}
248
+ ctx_id = props.get("context_id") or node.id
249
+ # Try to find the context's graph namespace
250
+ try:
251
+ from contextsynapse.context.context_manager import ContextManager
252
+ cm = ContextManager(graph_registry=registry)
253
+ ctx_obj = cm.get_context(ctx_id)
254
+ if ctx_obj:
255
+ context_namespaces.append((ctx_obj.name, ctx_obj.graph_namespace))
256
+ except Exception:
257
+ pass
258
+
259
+ # Search each attached context
260
+ from contextsynapse.adapters._base import AIContextDBConnection
261
+ for ctx_name, ctx_ns in context_namespaces:
262
+ try:
263
+ ctx_conn = AIContextDBConnection(namespace=ctx_ns, graph_registry=registry)
264
+ ctx_result = semantic_search(question, ctx_conn, None)
265
+ ctx_summary = ctx_result.get("summary", "")
266
+ ctx_nodes = ctx_result.get("nodes", [])
267
+ if ctx_nodes and "No " not in ctx_summary and "not " not in ctx_summary.lower():
268
+ summary += f"\n\n--- From context '{ctx_name}' ---\n{ctx_summary}"
269
+ all_nodes.extend(ctx_nodes)
270
+ except Exception:
271
+ pass
272
+ except Exception as e:
273
+ logger.debug("Cross-context search failed: %s", e)
274
+
275
+ if not summary or summary.strip().startswith("No "):
276
+ # Fallback: keyword search across all graphs
277
+ try:
278
+ q_terms = question.lower().split()
279
+ found = []
280
+ if ctx.conn and ctx.conn._graph_registry:
281
+ for ctx_name, ctx_ns in context_namespaces:
282
+ try:
283
+ ctx_graph = registry.get_graph(ctx_ns)
284
+ if not ctx_graph:
285
+ continue
286
+ for node in ctx_graph.get_all_nodes():
287
+ props = node.properties if hasattr(node, "properties") else {}
288
+ text = " ".join(str(v) for v in props.values()).lower()
289
+ if any(t in text for t in q_terms):
290
+ name = props.get("name") or props.get("title") or ""
291
+ content = props.get("content") or props.get("description") or props.get("statement") or ""
292
+ label = node.label if hasattr(node, "label") else ""
293
+ if name or content:
294
+ found.append(f"[{label}] {name}: {content[:150]}")
295
+ except Exception:
296
+ pass
297
+ if found:
298
+ summary = f"Found {len(found)} results across attached contexts:\n" + "\n".join(f"- {f}" for f in found[:10])
299
+ except Exception:
300
+ pass
301
+
302
+ result = summary if summary.strip() else "No results found across any context."
303
+ _record_shadow(ctx, "ask", result)
304
+ return result
305
+
306
+
307
+ @tool(
308
+ "task_context", "context",
309
+ "Get everything about a specific task — its requirements, "
310
+ "related decisions, dependencies, and code files.",
311
+ params=[ToolParam("task_id", "string", "UUID or partial ID of the task")],
312
+ requires_project=True,
313
+ )
314
+ def _task_context(ctx: ToolContext, task_id: str) -> str:
315
+ if not ctx.project:
316
+ return "Error: No project loaded."
317
+
318
+ node = ctx.project._resolve_task_id(task_id)
319
+ if not node:
320
+ return f"Task {task_id} not found."
321
+
322
+ props = node.properties if hasattr(node, "properties") else {}
323
+ tid = node.id if hasattr(node, "id") else task_id
324
+
325
+ lines = [
326
+ f"Task: {props.get('title', '?')}",
327
+ f"Status: {props.get('status', '?')}",
328
+ f"Priority: {props.get('priority', '?')}",
329
+ f"Assigned to: {props.get('assigned_to', 'unassigned')}",
330
+ ]
331
+ if props.get("description"):
332
+ lines.append(f"Description: {props['description']}")
333
+
334
+ # Find related nodes via edges
335
+ edges = ctx.conn.get_edges()
336
+ for e in edges:
337
+ src = e.source if hasattr(e, "source") else ""
338
+ tgt = e.target if hasattr(e, "target") else ""
339
+ lbl = e.label if hasattr(e, "label") else ""
340
+ if src == tid or tgt == tid:
341
+ other_id = tgt if src == tid else src
342
+ other = ctx.conn.get_node(other_id)
343
+ if other:
344
+ other_label = other.label if hasattr(other, "label") else "?"
345
+ other_props = other.properties if hasattr(other, "properties") else {}
346
+ name = other_props.get("title", other_props.get("path", other_props.get("name", other_id[:8])))
347
+ lines.append(f" {lbl} -> [{other_label}] {name}")
348
+
349
+ return "\n".join(lines)
350
+
351
+
352
+ @tool(
353
+ "rag_query", "context",
354
+ "Ask a question and get an answer grounded in your graph data (RAG). "
355
+ "Uses vector similarity + keyword search to find relevant nodes, "
356
+ "then generates a cited answer via LLM. Best for questions about "
357
+ "ingested documents, knowledge bases, and detailed content.",
358
+ params=[
359
+ ToolParam("question", "string", "Your question in natural language"),
360
+ ToolParam("graph", "string", "Graph name to search (optional, defaults to current)", required=False, default=""),
361
+ ],
362
+ )
363
+ def _rag_query(ctx: ToolContext, question: str, graph: str = "") -> str:
364
+ import time as _t
365
+ steps = []
366
+
367
+ db, graph_name = _get_graph_db(ctx, graph)
368
+ if not db:
369
+ return "No graph data available. Ingest documents or add knowledge first."
370
+
371
+ try:
372
+ from contextsynapse.search.rag import graph_retrieve, generate_answer
373
+ except ImportError:
374
+ return "RAG retrieval not available."
375
+
376
+ # Step 1: Vector-first + BM25-first retrieval with graph expansion
377
+ t0 = _t.time()
378
+ top, sources = graph_retrieve(db, question, graph_name)
379
+ retrieve_ms = int((_t.time() - t0) * 1000)
380
+
381
+ signal_names = set()
382
+ all_entities = []
383
+ for r in top:
384
+ for s in r.get("signals_used", []):
385
+ signal_names.add(s)
386
+ for e in r.get("entities", []):
387
+ if e.get("name") and e["name"] not in [x["name"] for x in all_entities]:
388
+ all_entities.append(e)
389
+
390
+ steps.append(f"[Retrieve] {len(top)} content nodes via {', '.join(signal_names) or 'search'} ({retrieve_ms}ms)")
391
+ if all_entities:
392
+ entity_names = [f"{e['name']} ({e['label']})" for e in all_entities[:8]]
393
+ steps.append(f"[Expand] {len(all_entities)} entities: {', '.join(entity_names)}")
394
+
395
+ if not top:
396
+ return f"No relevant information found for: {question}"
397
+
398
+ # Step 2: Check answer cache
399
+ from contextsynapse.search.rag_cache import get_rag_cache, make_cache_key
400
+ cache = get_rag_cache()
401
+ node_ids = [r.get("node_id", "") for r in top]
402
+ cache_key = make_cache_key(graph_name, question, node_ids)
403
+
404
+ cached = cache.get(cache_key)
405
+ if cached:
406
+ answer = cached.get("answer", "")
407
+ steps.append(f"[Cache HIT] Answer served from cache")
408
+ else:
409
+ # Step 3: Generate answer with LLM
410
+ t0 = _t.time()
411
+ result = generate_answer(question, top, sources)
412
+ gen_ms = int((_t.time() - t0) * 1000)
413
+ answer = result.get("answer", "")
414
+ steps.append(f"[Generate] LLM answer ({gen_ms}ms)")
415
+
416
+ if result.get("llm_errors"):
417
+ steps.append(f"[Warning] {'; '.join(result['llm_errors'][:2])}")
418
+
419
+ # Cache the answer
420
+ if answer and not result.get("llm_errors"):
421
+ cache.put(cache_key, {"answer": answer, "sources": [s.get("label", "") for s in sources[:5]]})
422
+
423
+ # Build response
424
+ output = "— RAG Pipeline —\n" + "\n".join(steps) + "\n\n"
425
+ output += "— Answer —\n" + answer
426
+
427
+ if sources:
428
+ output += "\n\n— Sources —"
429
+ for s in sources[:5]:
430
+ sigs = s.get("signals", 1)
431
+ output += f"\n • [{s.get('node_type', '')}] {s.get('label', '')[:80]} ({s.get('score', 0):.0%}, {sigs} signal{'s' if sigs != 1 else ''})"
432
+
433
+ ctx.record_provenance("read", "rag_query", question[:100])
434
+ _record_shadow(ctx, "rag_query", answer)
435
+ return output
436
+
437
+
438
+ def _get_graph_db(ctx: ToolContext, graph: str = ""):
439
+ """Helper: resolve graph DB from tool context."""
440
+ graph_name = graph or (ctx.conn._namespace if ctx.conn else "")
441
+
442
+ # First: use the already-loaded db from conn (PlaygroundConn resolves scoped names)
443
+ db = getattr(ctx.conn, "db", None) if ctx.conn else None
444
+ if db:
445
+ return db, graph_name
446
+
447
+ # Fallback: try registry with scoped name, then bare name
448
+ if ctx.conn:
449
+ registry = getattr(ctx.conn, "_graph_registry", None)
450
+ if registry:
451
+ db = registry.get_graph(graph_name, load_if_missing=True)
452
+ if db is None and ":" in graph_name:
453
+ bare = graph_name.split(":", 1)[1]
454
+ db = registry.get_graph(bare, load_if_missing=True)
455
+ if db:
456
+ graph_name = bare
457
+ return db, graph_name
458
+
459
+
460
+ @tool(
461
+ "rag_graph", "context",
462
+ "Deep graph-aware RAG — searches using BM25 full-text, vector similarity, "
463
+ "AND entity extraction simultaneously. Nodes found by multiple signals "
464
+ "get boosted ranking (dedup scoring). Best for complex questions that "
465
+ "span multiple documents or topics.",
466
+ params=[
467
+ ToolParam("question", "string", "Your question in natural language"),
468
+ ToolParam("graph", "string", "Graph name to search (optional)", required=False, default=""),
469
+ ],
470
+ )
471
+ def _rag_graph(ctx: ToolContext, question: str, graph: str = "") -> str:
472
+ db, graph_name = _get_graph_db(ctx, graph)
473
+ if not db:
474
+ return "No graph data available."
475
+
476
+ from contextsynapse.search.rag import graph_retrieve, generate_answer
477
+
478
+ top, sources = graph_retrieve(db, question, graph_name)
479
+ if not top:
480
+ return f"No relevant information found for: {question}"
481
+
482
+ result = generate_answer(question, top, sources)
483
+ answer = result.get("answer", "")
484
+
485
+ # Append source citations with signal count
486
+ if sources:
487
+ answer += "\n\nSources:"
488
+ for s in sources[:8]:
489
+ sig = s.get("signals", 1)
490
+ sig_label = f", {sig} signals" if sig > 1 else ""
491
+ answer += f"\n - [{s.get('node_type', '')}] {s.get('label', '')} (relevance: {s.get('score', 0):.0%}{sig_label})"
492
+
493
+ ctx.record_provenance("read", "rag_graph", question[:100])
494
+ _record_shadow(ctx, "rag_graph", answer)
495
+ return answer
496
+
497
+
498
+ @tool(
499
+ "search", "context",
500
+ "Plain keyword search across graph nodes. No LLM, no vectors — just fast "
501
+ "text matching. Returns matching nodes with snippets. Use for quick lookups "
502
+ "when you know what you're looking for.",
503
+ params=[
504
+ ToolParam("query", "string", "Search keywords"),
505
+ ToolParam("graph", "string", "Graph name (optional)", required=False, default=""),
506
+ ToolParam("limit", "string", "Max results (default 10)", required=False, default="10"),
507
+ ],
508
+ )
509
+ def _plain_search(ctx: ToolContext, query: str = "", graph: str = "", limit: str = "10", keywords: str = "", **kwargs) -> str:
510
+ # Accept 'keywords' as alias for 'query' (LLMs sometimes use wrong param name)
511
+ query = query or keywords or kwargs.get("q", "")
512
+ if not query:
513
+ return "Please provide a query. Usage: search(query=\"your search terms\")"
514
+ db, _ = _get_graph_db(ctx, graph)
515
+ if not db:
516
+ return "No graph data available."
517
+
518
+ # Track previous searches to detect repeated queries
519
+ if not hasattr(ctx, '_search_history'):
520
+ ctx._search_history = []
521
+ query_lower = query.lower().strip()
522
+ similar_count = sum(1 for q in ctx._search_history if q in query_lower or query_lower in q)
523
+ ctx._search_history.append(query_lower)
524
+
525
+ from contextsynapse.search.rag import plain_search, hybrid_retrieve, parallel_retrieve
526
+
527
+ # Infrastructure labels — always hidden from search results
528
+ INFRA_LABELS = {
529
+ "AgentThought", "AgentAction", "AgentMessage", "AgentPresence",
530
+ "ExperimentRun", "ExperimentScore", "PipelineRun",
531
+ "VectorIndex", "BM25Index", "Session", "ContextRef",
532
+ "Context", "Project", "KnowledgeBase", "CodeBase",
533
+ "SystemStore", "UserStore", "WebStore", "GeneratedStore",
534
+ "MemoryStore", "ArtifactStore", "ToolStore",
535
+ }
536
+
537
+ k = min(int(limit) if limit.isdigit() else 15, 50)
538
+ ns = getattr(db, "name", "") or graph
539
+
540
+ # Fast mode: skip vector search (3-5s) when in experiment context or repeated search
541
+ # Use plain_search (keyword + BM25, ~200ms) as primary, parallel_retrieve as fallback
542
+ results = []
543
+ try:
544
+ raw = plain_search(db, query, k=k + 20)
545
+ results = [r for r in raw if r.get("label", "") not in INFRA_LABELS][:k]
546
+ except Exception:
547
+ pass
548
+
549
+ # If plain_search found nothing, try parallel (includes vector — slower but broader)
550
+ if not results:
551
+ try:
552
+ raw = parallel_retrieve(db, query, graph_name=ns, k=k)
553
+ results = [r for r in raw if r.get("label", "") not in INFRA_LABELS]
554
+ except Exception:
555
+ pass
556
+
557
+ if not results:
558
+ return f"No results for: {query}"
559
+
560
+ lines = [f"Found {len(results)} result(s):"]
561
+ for r in results:
562
+ label = r.get("label", "")
563
+ name = r.get("name", "")
564
+ content = r.get("content", "") or r.get("snippet", "")
565
+
566
+ # Show full content if available, otherwise name
567
+ if content and content != name:
568
+ text = str(content)[:250]
569
+ else:
570
+ text = name
571
+
572
+ signals = r.get("signals", 0)
573
+ sig_tag = f" [{signals}sig]" if signals and signals > 1 else ""
574
+ line = f"- [{label}]{sig_tag} {text}"
575
+ lines.append(line)
576
+
577
+ # 1-hop entity expansion: surface Person/Location/Event connected to result nodes
578
+ try:
579
+ ENTITY_TYPES = {"Person", "Organization", "Location", "Event"}
580
+ seen_entities = set()
581
+ entity_lines = []
582
+ adapter = getattr(db, 'csr_adapter', None) or db
583
+ for r in results[:5]: # expand top 5 results only
584
+ nid = r.get("node_id", "")
585
+ if not nid:
586
+ continue
587
+ try:
588
+ edges = adapter.get_edges_for_node(nid) if hasattr(adapter, 'get_edges_for_node') else []
589
+ for edge in edges[:20]:
590
+ target_id = edge.target if hasattr(edge, 'target') else edge.get('target', '')
591
+ if target_id == nid:
592
+ target_id = edge.source if hasattr(edge, 'source') else edge.get('source', '')
593
+ if target_id in seen_entities:
594
+ continue
595
+ try:
596
+ target = adapter.get_node(target_id)
597
+ if target:
598
+ t_label = getattr(target, 'label', getattr(target, 'node_type', ''))
599
+ if t_label in ENTITY_TYPES:
600
+ t_name = (target.properties or {}).get('name', '')
601
+ if t_name and t_name not in seen_entities:
602
+ seen_entities.add(t_name)
603
+ entity_lines.append(f"- [{t_label}] {t_name}")
604
+ except Exception:
605
+ pass
606
+ except Exception:
607
+ pass
608
+ if entity_lines:
609
+ lines.append("\nConnected entities:")
610
+ lines.extend(entity_lines[:8])
611
+ except Exception:
612
+ pass
613
+
614
+ ctx.record_provenance("read", "search", query[:100])
615
+ result = "\n".join(lines)
616
+
617
+ # Redirect if searching same thing repeatedly — suggest alternatives from manifest
618
+ if similar_count >= 1:
619
+ alt_lines = []
620
+ try:
621
+ from ..context.quality import get_manifest
622
+ import os as _os
623
+ _redis = None
624
+ try:
625
+ import redis as _redis_mod
626
+ _redis = _redis_mod.from_url(_os.environ.get("CONTEXTSYNAPSE_REDIS_URL") or os.environ.get("AICONTEXTDB_REDIS_URL", "redis://localhost:6379"))
627
+ except Exception:
628
+ pass
629
+ manifest = get_manifest(ns, _redis) if _redis else None
630
+ if manifest:
631
+ hints = manifest.get("tool_hints", [])
632
+ top_ents = manifest.get("top_entities", {})
633
+ # Suggest entity-type searches the agent hasn't tried
634
+ for label, entities in list(top_ents.items())[:3]:
635
+ top_name = entities[0]["name"] if entities else ""
636
+ alt_lines.append(f' - search_nodes(label="{label}") -> {top_name}...')
637
+ if not alt_lines:
638
+ for h in hints[:3]:
639
+ alt_lines.append(f' - {h["tool"]}({h["example"]})')
640
+ except Exception:
641
+ pass
642
+
643
+ if similar_count >= 2:
644
+ redirect = "\n\n>>> You searched this before. Try a DIFFERENT approach:"
645
+ if alt_lines:
646
+ redirect += "\n" + "\n".join(alt_lines)
647
+ redirect += "\n Or say done with what you have."
648
+ result += redirect
649
+ else:
650
+ redirect = "\n\n> Similar search done. Try different queries:"
651
+ if alt_lines:
652
+ redirect += "\n" + "\n".join(alt_lines)
653
+ result += redirect
654
+
655
+ _record_shadow(ctx, "search", result)
656
+ return result
657
+
658
+
659
+ @tool(
660
+ "web_fetch", "context",
661
+ "Fetch a web page and return its text content. Use this to get live, "
662
+ "fresh data from a URL. The content is NOT auto-saved to the graph — "
663
+ "use add_knowledge to save what's relevant.",
664
+ params=[
665
+ ToolParam("url", "string", "URL to fetch"),
666
+ ],
667
+ )
668
+ def _web_fetch(ctx: ToolContext, url: str) -> str:
669
+ from contextsynapse.ingestion.web_crawler import fetch_single_page
670
+
671
+ if not url.startswith("http"):
672
+ url = "https://" + url
673
+
674
+ page = fetch_single_page(url)
675
+ if not page:
676
+ return f"Failed to fetch content from {url}"
677
+
678
+ title = page.get("title", "")
679
+ content = page.get("content", "")
680
+ char_count = page.get("char_count", 0)
681
+
682
+ # Truncate for agent context window
683
+ if len(content) > 8000:
684
+ content = content[:8000] + f"\n\n... (truncated, {char_count} total chars)"
685
+
686
+ ctx.record_provenance("read", "web_fetch", url[:100])
687
+ return f"# {title}\nSource: {url}\n\n{content}"
688
+
689
+
690
+ @tool(
691
+ "ingest_url", "context",
692
+ "Ingest a web page into the knowledge graph. Runs the full smart pipeline: "
693
+ "clean HTML (Trafilatura) -> chunk into passages -> extract entities/facts/relationships "
694
+ "(LLM + regex) -> create graph edges -> embed for vector search -> BM25 index. "
695
+ "Produces Document, Passage, Entity, Fact, and Link nodes with full relationship edges.",
696
+ params=[
697
+ ToolParam("url", "string", "URL of the web page to ingest"),
698
+ ToolParam("pipeline", "string",
699
+ "Pipeline to use: 'smart_article' (default, full LLM extraction), "
700
+ "'fast_ingest' (regex only, no LLM, faster)",
701
+ required=False, default="smart_article"),
702
+ ToolParam("schema_id", "string",
703
+ "Schema to use for extraction (e.g. 'healthcare', 'finance', 'news_article'). "
704
+ "Controls entity types, edge types, and domain-aware context unit generation. "
705
+ "Use list_schemas to see available schemas.",
706
+ required=False, default=""),
707
+ ],
708
+ )
709
+ def _ingest_url(ctx: ToolContext, url: str, pipeline: str = "smart_article", schema_id: str = "") -> str:
710
+ if not url.startswith("http"):
711
+ url = "https://" + url
712
+
713
+ try:
714
+ from ..ingestion.smart_ingest import ingest_url
715
+
716
+ # Resolve schema if specified
717
+ schema = None
718
+ if schema_id:
719
+ from ..ingestion.schema_extractor import IngestionSchema
720
+ from ..extraction.schema_loader import load_schema as _load_ext_schema
721
+ from pathlib import Path as _Path
722
+ _schema_path = _Path(__file__).parent.parent / "config" / "schemas" / f"{schema_id}.yaml"
723
+ if _schema_path.exists():
724
+ ext_schema = _load_ext_schema(str(_schema_path))
725
+ schema = IngestionSchema.from_extraction_schema(ext_schema) if hasattr(IngestionSchema, 'from_extraction_schema') else None
726
+ if schema is None:
727
+ # Build IngestionSchema manually from ExtractionSchema
728
+ schema = IngestionSchema(
729
+ name=ext_schema.name,
730
+ node_types={k: {"fields": v.fields, "required": v.required, "description": v.description}
731
+ for k, v in ext_schema.node_types.items()},
732
+ edge_types={k: {"source": v.source, "target": v.target}
733
+ for k, v in ext_schema.edge_types.items()},
734
+ )
735
+
736
+ result = ingest_url(url, ctx.conn.contextcore, schema=schema, pipeline=pipeline)
737
+
738
+ if result.errors:
739
+ return f"Ingestion failed: {'; '.join(result.errors)}"
740
+
741
+ lines = [
742
+ f"Ingested: {url}",
743
+ f" Document: {result.document_id}",
744
+ f" Passages: {len(result.passage_ids)}",
745
+ f" Entities: {len(result.entity_ids)}",
746
+ f" Facts: {len(result.fact_ids)}",
747
+ f" Links: {len(result.link_ids)}",
748
+ f" Edges: {result.edge_count}",
749
+ f" Pipeline: {pipeline}",
750
+ f" Schema: {schema_id or 'default'}",
751
+ ]
752
+
753
+ # List extracted entities
754
+ if result.entity_ids:
755
+ lines.append("\n Entities found:")
756
+ for key, eid in list(result.entity_ids.items())[:10]:
757
+ node = ctx.conn.contextsynapse.csr_adapter.get_node(eid)
758
+ if node:
759
+ label = getattr(node, 'node_type', getattr(node, 'label', ''))
760
+ name = node.properties.get('name', '?')
761
+ lines.append(f" [{label}] {name}")
762
+
763
+ # Persist graph to disk and update metadata so it appears in graph listings
764
+ try:
765
+ ns = ctx.conn.namespace
766
+ reg = ctx.conn.graph_registry
767
+ if reg and ns:
768
+ reg.save_graph(ns, create_checkpoint=False)
769
+ except Exception:
770
+ pass # best-effort save
771
+
772
+ ctx.record_provenance("write", "ingest_url", url[:100])
773
+ return "\n".join(lines)
774
+ except Exception as e:
775
+ return f"Ingestion error: {e}"
776
+
777
+
778
+ @tool(
779
+ "list_pipelines", "context",
780
+ "List available ingestion pipelines with descriptions. "
781
+ "Use this to understand which pipeline to choose for different content types.",
782
+ params=[],
783
+ )
784
+ def _list_pipelines(ctx: ToolContext) -> str:
785
+ from ..ingestion.smart_ingest import list_pipelines
786
+ pipelines = list_pipelines()
787
+ lines = ["Available ingestion pipelines:\n"]
788
+ for name, info in pipelines.items():
789
+ lines.append(f"**{name}**: {info['name']}")
790
+ lines.append(f" {info['description']}")
791
+ lines.append(f" Input: {info['input_types']}")
792
+ lines.append(f" Produces: {', '.join(info['produces'])}")
793
+ lines.append(f" LLM required: {info['llm_required']}")
794
+ lines.append("")
795
+ return "\n".join(lines)
796
+
797
+
798
+ @tool(
799
+ "reason", "context",
800
+ "Answer complex questions by traversing the knowledge graph. Follows edges "
801
+ "between nodes to find multi-hop connections. Best for 'who/what/how' questions "
802
+ "that require understanding relationships. Example: 'Who is responsible for auth security?'",
803
+ params=[ToolParam("question", "string", "Your question")],
804
+ )
805
+ def _reason(ctx: ToolContext, question: str) -> str:
806
+ db, _ = _get_graph_db(ctx)
807
+ if not db:
808
+ return "No graph data available."
809
+ from contextsynapse.search.reasoning_chain import reason_over_graph
810
+ result = reason_over_graph(db, question)
811
+ answer = result.get("answer", "No path found.")
812
+ hops = result.get("hops", 0)
813
+ visited = result.get("nodes_visited", 0)
814
+ seeds = result.get("seeds", [])
815
+ footer = f"\n\n[Traversed {visited} nodes in {hops} hops from: {', '.join(seeds[:3])}]"
816
+ _record_shadow(ctx, "reason", answer)
817
+ return answer + footer
818
+
819
+
820
+ @tool(
821
+ "graph_timeline", "context",
822
+ "See the activity timeline for the current graph — what was created when, "
823
+ "by which agent. Use to understand project history and recent changes.",
824
+ params=[
825
+ ToolParam("hours", "string", "How many hours of history (default 24)", required=False, default="24"),
826
+ ],
827
+ )
828
+ def _graph_timeline(ctx: ToolContext, hours: str = "24") -> str:
829
+ db, graph_name = _get_graph_db(ctx)
830
+ if not db:
831
+ return "No graph data available."
832
+ from contextsynapse.core.time_travel import GraphTimeTraveler
833
+ h = int(hours) if hours.isdigit() else 24
834
+ timeline = GraphTimeTraveler(db).timeline(hours=h)
835
+ if not timeline:
836
+ return f"No activity in the last {h} hours."
837
+ lines = [f"Graph activity (last {h}h):"]
838
+ for bucket in timeline:
839
+ agents = ", ".join(a[:12] for a in bucket.get("agents", []))
840
+ labels = ", ".join(f"{k}:{v}" for k, v in bucket.get("labels", {}).items())
841
+ lines.append(f" {bucket['timestamp'][:16]} — {bucket['count']} nodes ({labels}) by {agents or 'system'}")
842
+ return "\n".join(lines)
843
+
844
+
845
+ @tool(
846
+ "graph_diff", "context",
847
+ "Compare the graph between two timestamps — what was added, removed, or modified. "
848
+ "Use to understand what changed between agent runs.",
849
+ params=[
850
+ ToolParam("from_time", "string", "Start timestamp (ISO format, e.g. 2026-03-24T10:00:00)"),
851
+ ToolParam("to_time", "string", "End timestamp (ISO format, e.g. 2026-03-25T10:00:00)"),
852
+ ],
853
+ )
854
+ def _graph_diff(ctx: ToolContext, from_time: str, to_time: str) -> str:
855
+ db, _ = _get_graph_db(ctx)
856
+ if not db:
857
+ return "No graph data available."
858
+ from contextsynapse.core.time_travel import GraphTimeTraveler
859
+ diff = GraphTimeTraveler(db).diff(from_time, to_time)
860
+ lines = [diff["summary"]]
861
+ if diff["added_nodes"]:
862
+ lines.append(f"\nAdded ({diff['added']}):")
863
+ for n in diff["added_nodes"][:10]:
864
+ lines.append(f" + [{n['label']}] {n['name']} (by {n.get('agent','')[:12]})")
865
+ if diff["modified_nodes"]:
866
+ lines.append(f"\nModified ({diff['modified']}):")
867
+ for n in diff["modified_nodes"][:5]:
868
+ lines.append(f" ~ [{n['label']}] {n['name']} (by {n.get('updated_by','')[:12]})")
869
+ return "\n".join(lines)
870
+
871
+
872
+ @tool(
873
+ "explain_context", "context",
874
+ "Show why context items were selected — scoring breakdowns and rankings.",
875
+ params=[],
876
+ )
877
+ def _explain_context(ctx: ToolContext) -> str:
878
+ from ..context.hub import ContextHub, ContextRole, ContextItem
879
+ from ..context.scoping import ContextScoper, ScopingConfig
880
+
881
+ hub = ContextHub(system_prompt="Context explanation", max_tokens=4000)
882
+ hub._db = ctx.conn.contextcore
883
+ nodes = ctx.conn.contextsynapse.csr_adapter.get_all_nodes()
884
+ content_nodes = [n for n in nodes if getattr(n, 'node_type', getattr(n, 'label', '')) not in
885
+ ("ContextMeta", "VectorIndex", "BM25Index", "Session", "ContextRef", "Agent")]
886
+ if not content_nodes:
887
+ return "No context available — graph is empty."
888
+ hub.add_nodes(content_nodes[:20])
889
+ hub.set_scoping(ScopingConfig(max_tokens=4000))
890
+ hub.to_prompt()
891
+ scored = hub.get_last_scored_items()
892
+ if not scored:
893
+ return "No scored items."
894
+
895
+ lines = [f"**Context Explanation** ({len(scored)} items)\n"]
896
+ for i, si in enumerate(scored[:15], 1):
897
+ preview = si.item.content[:60].replace('\n', ' ')
898
+ role = si.item.role.value if hasattr(si.item.role, 'value') else str(si.item.role)
899
+ bd = ", ".join(f"{k}: {v:.2f}" for k, v in si.breakdown.items() if v > 0) if si.breakdown else "n/a"
900
+ lines.append(f"{i}. **{role}** (score: {si.score:.3f}) — {preview}...")
901
+ lines.append(f" Breakdown: {bd}")
902
+ if si.reason:
903
+ lines.append(f" Reason: {si.reason}")
904
+ ctx.record_provenance("read", "explain_context", "")
905
+ return "\n".join(lines)