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,116 @@
1
+ """
2
+ PlaygroundConn — Shared connection wrapper for playground simulation endpoints.
3
+
4
+ Bridges the gap between the ToolContext interface (used by MCP tools) and the
5
+ graph registry. Resolves tenant-scoped namespaces to bare graph names, loads
6
+ graphs from disk, and proxies query/build_context/get_edges/get_node calls.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ from typing import Any, Optional
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class PlaygroundConn:
18
+ """Connection wrapper that MCP tools can use via ToolContext.conn."""
19
+
20
+ def __init__(self, namespace: str, registry):
21
+ self.namespace = namespace
22
+ self._namespace = namespace # context tools use _namespace
23
+ self.graph_registry = registry
24
+ self._graph_registry = registry # context tools use _graph_registry
25
+
26
+ # Resolve graph: try scoped name, then bare name after ":"
27
+ self.db = None
28
+ self._resolved_ns = namespace
29
+ if namespace and registry:
30
+ self.db = registry.get_graph(namespace, load_if_missing=True)
31
+ if self.db is None and ":" in namespace:
32
+ bare = namespace.split(":", 1)[1]
33
+ self.db = registry.get_graph(bare, load_if_missing=True)
34
+ if self.db:
35
+ self._resolved_ns = bare
36
+ if self.db is None:
37
+ self.db = registry.get_graph_for_request(namespace)
38
+
39
+ self.executor = None
40
+ try:
41
+ from ..aiql import AIQLExecutor
42
+ self.executor = AIQLExecutor(contextcore=self.db, graph_registry=registry)
43
+ if self._resolved_ns:
44
+ self.executor.active_namespace = self._resolved_ns
45
+ except Exception:
46
+ pass
47
+
48
+ def get_graph(self):
49
+ return self.db
50
+
51
+ def query(self, q: str):
52
+ if self.executor:
53
+ return self.executor.execute(q)
54
+ raise RuntimeError("No executor available — select a graph first")
55
+
56
+ def build_context(self, **kwargs):
57
+ if self.executor:
58
+ return self.executor.build_context(**kwargs)
59
+ raise RuntimeError("No executor available")
60
+
61
+ def get_edges(self, label: Optional[str] = None):
62
+ if self.db and hasattr(self.db, "get_all_edges"):
63
+ edges = self.db.get_all_edges()
64
+ if label:
65
+ edges = [e for e in edges if getattr(e, "label", "") == label]
66
+ return edges
67
+ return []
68
+
69
+ def get_node(self, node_id: str):
70
+ if self.db and hasattr(self.db, "get_node"):
71
+ return self.db.get_node(node_id)
72
+ return None
73
+
74
+ def get_nodes(self, label: str = None, where: dict = None):
75
+ """Return nodes from the graph, optionally filtered by label and properties.
76
+
77
+ Required by ProjectGraph.__init__ to find/create the Project node.
78
+ """
79
+ if not self.db or not hasattr(self.db, "get_all_nodes"):
80
+ return []
81
+ nodes = self.db.get_all_nodes()
82
+ if label:
83
+ nodes = [n for n in nodes if getattr(n, "label", "") == label]
84
+ if where:
85
+ filtered = []
86
+ for n in nodes:
87
+ props = getattr(n, "properties", {}) or {}
88
+ if all(props.get(k) == v for k, v in where.items()):
89
+ filtered.append(n)
90
+ nodes = filtered
91
+ return nodes
92
+
93
+ def add_edge(self, source_id: str, target_id: str, label: str, properties: dict = None):
94
+ """Add an edge between two nodes. Required by ProjectGraph."""
95
+ if self.executor:
96
+ if properties:
97
+ props_str = ", ".join(f'{k}: "{v}"' for k, v in properties.items())
98
+ self.executor.execute(
99
+ f'CREATE EDGE {label} FROM "{source_id}" TO "{target_id}" {{{props_str}}}'
100
+ )
101
+ else:
102
+ self.executor.execute(
103
+ f'CREATE EDGE {label} FROM "{source_id}" TO "{target_id}"'
104
+ )
105
+
106
+
107
+ def create_tool_context(conn: PlaygroundConn, agent_id: str, agent_name: str):
108
+ """Create a ToolContext with all required attributes for playground tools."""
109
+ from ..tools.registry import ToolContext
110
+ ctx = ToolContext(
111
+ conn=conn,
112
+ agent_id=agent_id,
113
+ agent_name=agent_name,
114
+ )
115
+ ctx.db = conn.db # intelligence tools use ctx.db
116
+ return ctx
@@ -0,0 +1,131 @@
1
+ """
2
+ Projects Router
3
+ =================
4
+ REST API for SDLC context projects. Each project is one namespace with
5
+ typed SDLC nodes. Delegates to ProjectContext.
6
+ """
7
+ import logging
8
+ from typing import Any, Dict, List
9
+
10
+ from fastapi import APIRouter, HTTPException, Query
11
+ from pydantic import BaseModel
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ try:
16
+ from ..project.code_context import CodeContext
17
+ except Exception:
18
+ CodeContext = None # type: ignore
19
+
20
+
21
+ class CreateProjectRequest(BaseModel):
22
+ name: str
23
+
24
+
25
+ def create_projects_router(user_auth=None, base_path: str = "contextcore_data") -> APIRouter:
26
+ """Create the /dashboard/projects router."""
27
+ from ..project.project_context import ProjectContext
28
+
29
+ router = APIRouter(prefix="/dashboard/projects", tags=["Projects"])
30
+
31
+ def _load(name: str) -> ProjectContext:
32
+ try:
33
+ return ProjectContext.load(name, base_path=base_path)
34
+ except KeyError as exc:
35
+ raise HTTPException(status_code=404, detail=str(exc))
36
+
37
+ def _list_project_names() -> List[str]:
38
+ return ProjectContext.list_names(base_path=base_path)
39
+
40
+ # ── CRUD ─────────────────────────────────────────────────────────────────
41
+
42
+ @router.post("", status_code=201)
43
+ async def create_project(req: CreateProjectRequest) -> Dict[str, Any]:
44
+ """Create (or open) a project namespace."""
45
+ pc = ProjectContext.create(req.name, base_path=base_path)
46
+ return {"name": pc.name, "status": "created"}
47
+
48
+ @router.get("")
49
+ async def list_projects() -> List[Dict[str, str]]:
50
+ """List all project namespaces."""
51
+ return [{"name": name} for name in sorted(_list_project_names())]
52
+
53
+ @router.get("/{name}")
54
+ async def get_project(name: str) -> Dict[str, Any]:
55
+ """Project overview including coverage scores."""
56
+ pc = _load(name)
57
+ return {"name": pc.name, "coverage": pc.coverage_score()}
58
+
59
+ # ── SDLC endpoints ───────────────────────────────────────────────────────
60
+
61
+ @router.get("/{name}/coverage")
62
+ async def get_coverage(name: str) -> Dict[str, Any]:
63
+ """Per-layer SDLC coverage scores."""
64
+ return _load(name).coverage_score()
65
+
66
+ @router.get("/{name}/stale")
67
+ async def get_stale(name: str) -> List[Dict[str, Any]]:
68
+ """All stale SDLC nodes in the project namespace."""
69
+ return _load(name).stale_report()
70
+
71
+ @router.get("/{name}/brief")
72
+ async def get_brief(
73
+ name: str,
74
+ topic: str = Query(default=""),
75
+ phase: str = Query(default=""),
76
+ ) -> Dict[str, Any]:
77
+ """Scoped context package for an agent about to work."""
78
+ return _load(name).agent_brief(topic=topic, phase=phase)
79
+
80
+ @router.get("/{name}/timeline")
81
+ async def get_timeline(
82
+ name: str,
83
+ limit: int = Query(default=50, ge=1, le=500),
84
+ ) -> List[Dict[str, Any]]:
85
+ """Recent graph changes in the project namespace."""
86
+ pc = _load(name)
87
+ try:
88
+ from ..core.time_travel import GraphTimeTraveler
89
+ tt = GraphTimeTraveler(pc.db)
90
+ events = tt.get_graph_timeline(limit=limit)
91
+ return events if isinstance(events, list) else []
92
+ except Exception:
93
+ return []
94
+
95
+ # ── Spec / Requirements ──────────────────────────────────
96
+
97
+ def _get_cc(name: str):
98
+ """Load a CodeContext by name."""
99
+ return CodeContext.load(name)
100
+
101
+ @router.post("/{name}/spec/ingest")
102
+ async def ingest_spec(name: str):
103
+ """Parse the project spec into Requirement/Feature/Constraint graph nodes."""
104
+ cc = _get_cc(name)
105
+ spec_text = cc.ns.get_metadata("spec") or ""
106
+ try:
107
+ ids = cc.ingest_spec(spec_text)
108
+ return {"ingested": ids, "count": len(ids)}
109
+ except Exception as e:
110
+ raise HTTPException(500, f"Spec ingestion failed: {e}")
111
+
112
+ @router.get("/{name}/spec/requirements")
113
+ async def get_requirements(name: str):
114
+ """Return all Requirement/Feature/Constraint nodes for the project."""
115
+ cc = _get_cc(name)
116
+ try:
117
+ nodes = cc.get_requirements()
118
+ return {"nodes": nodes, "total": len(nodes)}
119
+ except Exception as e:
120
+ raise HTTPException(500, f"Failed to load requirements: {e}")
121
+
122
+ @router.get("/{name}/spec/coverage")
123
+ async def get_coverage_spec(name: str):
124
+ """Return traceability coverage for the project's requirements."""
125
+ cc = _get_cc(name)
126
+ try:
127
+ return cc.check_coverage()
128
+ except Exception as e:
129
+ raise HTTPException(500, f"Coverage check failed: {e}")
130
+
131
+ return router
@@ -0,0 +1,282 @@
1
+ """
2
+ Queries Router
3
+ ==============
4
+ AIQL query execution, saved queries, and query history.
5
+
6
+ POST /dashboard/query/execute — Execute AIQL query
7
+ GET /dashboard/queries/saved — List saved queries
8
+ POST /dashboard/queries/saved — Save a query
9
+ DELETE /dashboard/queries/saved/{id} — Delete saved query
10
+ GET /dashboard/queries/history — Query execution history
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import json
16
+ import logging
17
+ import secrets
18
+ import time
19
+ from datetime import datetime, timezone
20
+ from typing import Any, Dict, List, Optional
21
+
22
+ from fastapi import APIRouter, Depends, HTTPException, Query
23
+ from .models import paginate
24
+ from pydantic import BaseModel, Field
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ # ---------------------------------------------------------------------------
30
+ # Request models
31
+ # ---------------------------------------------------------------------------
32
+
33
+ class ExecuteQueryRequest(BaseModel):
34
+ query: str = Field(..., min_length=1, description="AIQL query")
35
+ graph: Optional[str] = Field(None, description="Target graph name")
36
+
37
+
38
+ class SaveQueryRequest(BaseModel):
39
+ name: str = Field(..., min_length=1, max_length=100)
40
+ query: str = Field(..., min_length=1)
41
+ description: Optional[str] = None
42
+
43
+
44
+ # ---------------------------------------------------------------------------
45
+ # Router factory
46
+ # ---------------------------------------------------------------------------
47
+
48
+ def create_queries_router(
49
+ user_registry,
50
+ tenant_registry,
51
+ graph_registry,
52
+ usage_meter=None,
53
+ ) -> APIRouter:
54
+ """Create the /dashboard/query and /dashboard/queries routers."""
55
+
56
+ from .auth import UserAuth
57
+ from ..aiql.engine import AIQLExecutor
58
+
59
+ router = APIRouter(tags=["queries"])
60
+ user_auth = UserAuth(user_registry)
61
+
62
+ def _get_tenant(user):
63
+ tenant_id = user_registry.get_primary_tenant_id(user.user_id)
64
+ if not tenant_id:
65
+ raise HTTPException(status_code=404, detail="No workspace found")
66
+ tenant = tenant_registry.get(tenant_id)
67
+ if not tenant:
68
+ raise HTTPException(status_code=404, detail="Workspace not found")
69
+ return tenant
70
+
71
+ # ------------------------------------------------------------------
72
+ # POST /dashboard/query/execute
73
+ # ------------------------------------------------------------------
74
+ @router.post("/dashboard/query/execute")
75
+ async def execute_query(req: ExecuteQueryRequest, user=Depends(user_auth)):
76
+ tenant = _get_tenant(user)
77
+
78
+ try:
79
+ executor = AIQLExecutor(graph_registry=graph_registry)
80
+
81
+ # Scope to tenant's graph if specified
82
+ if req.graph:
83
+ scoped_name = f"{tenant.tenant_id}:{req.graph}"
84
+ try:
85
+ executor.execute(f"USE GRAPH {scoped_name}")
86
+ except Exception:
87
+ # Try without namespace prefix
88
+ executor.execute(f"USE GRAPH {req.graph}")
89
+
90
+ start = time.time()
91
+ result = executor.execute(req.query)
92
+ duration_ms = int((time.time() - start) * 1000)
93
+
94
+ # Record in metering
95
+ if usage_meter:
96
+ try:
97
+ usage_meter.record(tenant.tenant_id, "query")
98
+ except Exception:
99
+ pass
100
+
101
+ # Record in query history
102
+ _record_history(tenant.tenant_id, user.user_id, req.query, duration_ms, "success")
103
+
104
+ # Normalize result for frontend
105
+ if isinstance(result, list):
106
+ data = result
107
+ elif isinstance(result, dict):
108
+ data = result
109
+ else:
110
+ data = str(result)
111
+
112
+ # Also return graph nodes/edges for visualization
113
+ nodes_out = []
114
+ edges_out = []
115
+ try:
116
+ scoped_name = f"{tenant.tenant_id}:{req.graph}" if req.graph else None
117
+ graph = graph_registry.get_graph(scoped_name) if scoped_name else None
118
+ if not graph and req.graph:
119
+ graph = graph_registry.get_graph(req.graph)
120
+ if graph:
121
+ for n in graph.get_all_nodes():
122
+ nodes_out.append({
123
+ "id": n.id, "label": n.label,
124
+ "name": n.name or (n.properties or {}).get("name", ""),
125
+ "properties": n.properties or {},
126
+ })
127
+ for e in graph.get_all_edges():
128
+ edges_out.append({
129
+ "id": e.id, "source": e.source, "target": e.target,
130
+ "label": e.label, "properties": e.properties or {},
131
+ })
132
+ except Exception:
133
+ pass
134
+
135
+ return {
136
+ "data": data,
137
+ "query": req.query,
138
+ "duration_ms": duration_ms,
139
+ "row_count": len(data) if isinstance(data, list) else None,
140
+ "nodes": nodes_out,
141
+ "edges": edges_out,
142
+ }
143
+
144
+ except Exception as e:
145
+ _record_history(tenant.tenant_id, user.user_id, req.query, 0, "error", str(e))
146
+ raise HTTPException(status_code=400, detail=str(e))
147
+
148
+ # ------------------------------------------------------------------
149
+ # Saved queries — stored in user_registry's DB
150
+ # ------------------------------------------------------------------
151
+
152
+ @router.get("/dashboard/queries/saved")
153
+ async def list_saved(
154
+ limit: int = Query(50, ge=1, le=500),
155
+ offset: int = Query(0, ge=0),
156
+ user=Depends(user_auth),
157
+ ):
158
+ tenant = _get_tenant(user)
159
+ queries = _get_saved_queries(tenant.tenant_id, user.user_id)
160
+ page = paginate(queries, limit, offset)
161
+ return {"queries": page["items"], "total": page["total"], "limit": page["limit"], "offset": page["offset"]}
162
+
163
+ @router.post("/dashboard/queries/saved")
164
+ async def save_query(req: SaveQueryRequest, user=Depends(user_auth)):
165
+ tenant = _get_tenant(user)
166
+ query_id = secrets.token_hex(12)
167
+ now = datetime.now(timezone.utc).isoformat()
168
+ _insert_saved_query(query_id, tenant.tenant_id, user.user_id, req.name, req.query, req.description, now)
169
+ return {"query_id": query_id, "message": "Query saved"}
170
+
171
+ @router.delete("/dashboard/queries/saved/{query_id}")
172
+ async def delete_saved(query_id: str, user=Depends(user_auth)):
173
+ tenant = _get_tenant(user)
174
+ _delete_saved_query(query_id, tenant.tenant_id)
175
+ return {"message": "Query deleted"}
176
+
177
+ # ------------------------------------------------------------------
178
+ # Query history
179
+ # ------------------------------------------------------------------
180
+
181
+ @router.get("/dashboard/queries/history")
182
+ async def get_history(
183
+ limit: int = Query(50, ge=1, le=500),
184
+ offset: int = Query(0, ge=0),
185
+ user=Depends(user_auth),
186
+ ):
187
+ tenant = _get_tenant(user)
188
+ history = _get_query_history(tenant.tenant_id, user.user_id)
189
+ page = paginate(history, limit, offset)
190
+ return {"history": page["items"], "total": page["total"], "limit": page["limit"], "offset": page["offset"]}
191
+
192
+ # ------------------------------------------------------------------
193
+ # SQLite helpers (reuse user_registry's DB connection pattern)
194
+ # ------------------------------------------------------------------
195
+ import sqlite3
196
+ from pathlib import Path
197
+
198
+ _db_path = Path(__file__).resolve().parents[2] / "contextcore_data" / "queries.db"
199
+ _db_path.parent.mkdir(parents=True, exist_ok=True)
200
+
201
+ def _get_conn():
202
+ conn = sqlite3.connect(str(_db_path))
203
+ conn.row_factory = sqlite3.Row
204
+ conn.execute("PRAGMA journal_mode=WAL")
205
+ return conn
206
+
207
+ # Init tables
208
+ with _get_conn() as conn:
209
+ conn.executescript("""
210
+ CREATE TABLE IF NOT EXISTS saved_queries (
211
+ query_id TEXT PRIMARY KEY,
212
+ tenant_id TEXT NOT NULL,
213
+ user_id TEXT NOT NULL,
214
+ name TEXT NOT NULL,
215
+ query TEXT NOT NULL,
216
+ description TEXT,
217
+ created_at TEXT NOT NULL
218
+ );
219
+ CREATE INDEX IF NOT EXISTS idx_saved_queries_tenant
220
+ ON saved_queries(tenant_id, user_id);
221
+
222
+ CREATE TABLE IF NOT EXISTS query_history (
223
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
224
+ tenant_id TEXT NOT NULL,
225
+ user_id TEXT NOT NULL,
226
+ query TEXT NOT NULL,
227
+ duration_ms INTEGER DEFAULT 0,
228
+ status TEXT DEFAULT 'success',
229
+ error TEXT,
230
+ timestamp TEXT NOT NULL
231
+ );
232
+ CREATE INDEX IF NOT EXISTS idx_query_history_tenant
233
+ ON query_history(tenant_id, user_id);
234
+ """)
235
+
236
+ def _get_saved_queries(tenant_id, user_id):
237
+ with _get_conn() as conn:
238
+ rows = conn.execute(
239
+ "SELECT * FROM saved_queries WHERE tenant_id = ? AND user_id = ? ORDER BY created_at DESC",
240
+ (tenant_id, user_id),
241
+ ).fetchall()
242
+ return [dict(r) for r in rows]
243
+
244
+ def _insert_saved_query(query_id, tenant_id, user_id, name, query, description, created_at):
245
+ with _get_conn() as conn:
246
+ conn.execute(
247
+ "INSERT INTO saved_queries (query_id, tenant_id, user_id, name, query, description, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
248
+ (query_id, tenant_id, user_id, name, query, description, created_at),
249
+ )
250
+
251
+ def _delete_saved_query(query_id, tenant_id):
252
+ with _get_conn() as conn:
253
+ conn.execute("DELETE FROM saved_queries WHERE query_id = ? AND tenant_id = ?", (query_id, tenant_id))
254
+
255
+ def _record_history(tenant_id, user_id, query, duration_ms, status, error=None):
256
+ try:
257
+ now = datetime.now(timezone.utc).isoformat()
258
+ with _get_conn() as conn:
259
+ conn.execute(
260
+ "INSERT INTO query_history (tenant_id, user_id, query, duration_ms, status, error, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?)",
261
+ (tenant_id, user_id, query, duration_ms, status, error, now),
262
+ )
263
+ # Keep only last 100 entries per user
264
+ conn.execute(
265
+ """DELETE FROM query_history WHERE id NOT IN (
266
+ SELECT id FROM query_history WHERE tenant_id = ? AND user_id = ?
267
+ ORDER BY timestamp DESC LIMIT 100
268
+ ) AND tenant_id = ? AND user_id = ?""",
269
+ (tenant_id, user_id, tenant_id, user_id),
270
+ )
271
+ except Exception:
272
+ pass
273
+
274
+ def _get_query_history(tenant_id, user_id):
275
+ with _get_conn() as conn:
276
+ rows = conn.execute(
277
+ "SELECT query, duration_ms, status, error, timestamp FROM query_history WHERE tenant_id = ? AND user_id = ? ORDER BY timestamp DESC LIMIT 20",
278
+ (tenant_id, user_id),
279
+ ).fetchall()
280
+ return [dict(r) for r in rows]
281
+
282
+ return router
@@ -0,0 +1,95 @@
1
+ """
2
+ Quota Enforcer
3
+ ==============
4
+ FastAPI dependency that checks tenant usage against plan limits before
5
+ allowing resource creation.
6
+
7
+ Usage::
8
+
9
+ quota = QuotaEnforcer(billing_manager, usage_meter)
10
+
11
+ @app.post("/graphs")
12
+ async def create_graph(..., _=Depends(quota.check_graphs(tenant))):
13
+ ...
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import logging
19
+ from typing import Optional
20
+
21
+ from fastapi import HTTPException
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ class QuotaEnforcer:
27
+ """Checks current usage against plan limits and raises 429 if over quota."""
28
+
29
+ def __init__(self, billing_manager, usage_meter):
30
+ self._billing = billing_manager
31
+ self._meter = usage_meter
32
+
33
+ def check(self, tenant_id: str, resource: str, current_count: int = 0) -> None:
34
+ """
35
+ Check if tenant is within quota for a given resource.
36
+
37
+ Args:
38
+ tenant_id: The tenant to check.
39
+ resource: One of 'graphs', 'api_calls', 'agents', 'nodes'.
40
+ current_count: Current count of the resource (for graphs/agents/nodes).
41
+
42
+ Raises:
43
+ HTTPException 429 if over quota.
44
+ """
45
+ limits = self._billing.get_limits(tenant_id)
46
+
47
+ limit_map = {
48
+ "graphs": "max_graphs",
49
+ "api_calls": "max_api_calls",
50
+ "agents": "max_agents",
51
+ "nodes": "max_nodes",
52
+ }
53
+
54
+ limit_key = limit_map.get(resource)
55
+ if not limit_key:
56
+ return # unknown resource, allow
57
+
58
+ max_val = limits.get(limit_key, -1)
59
+ if max_val == -1:
60
+ return # unlimited
61
+
62
+ # For api_calls, check monthly usage
63
+ if resource == "api_calls":
64
+ usage = self._meter.get_summary(tenant_id)
65
+ current_count = usage.get("api_call", 0)
66
+
67
+ if current_count >= max_val:
68
+ plan = limits.get("plan", "free")
69
+ raise HTTPException(
70
+ status_code=429,
71
+ detail={
72
+ "error": "quota_exceeded",
73
+ "resource": resource,
74
+ "current": current_count,
75
+ "limit": max_val,
76
+ "plan": plan,
77
+ "message": f"You've reached the {resource} limit ({max_val}) on the {plan} plan. "
78
+ f"Upgrade your plan to increase limits.",
79
+ },
80
+ )
81
+
82
+ def check_feature(self, tenant_id: str, feature: str) -> None:
83
+ """Check if tenant's plan includes a feature. Raises 403 if not."""
84
+ if not self._billing.has_feature(tenant_id, feature):
85
+ plan = self._billing.get_or_create(tenant_id).plan
86
+ raise HTTPException(
87
+ status_code=403,
88
+ detail={
89
+ "error": "feature_not_available",
90
+ "feature": feature,
91
+ "plan": plan,
92
+ "message": f"The '{feature}' feature is not available on the {plan} plan. "
93
+ f"Upgrade to access this feature.",
94
+ },
95
+ )
@@ -0,0 +1,64 @@
1
+ """
2
+ Rate Limiting
3
+ =============
4
+ Per-tenant rate limiting using slowapi. Reads ``rate_limit_rpm`` from the
5
+ tenant's config dict (default: 60 req/min).
6
+
7
+ Usage::
8
+
9
+ from .rate_limit import install_rate_limiter
10
+
11
+ install_rate_limiter(app)
12
+ """
13
+
14
+ import logging
15
+ import os
16
+
17
+ from fastapi import FastAPI, Request
18
+ from fastapi.responses import JSONResponse
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ # Default rates (requests per minute)
23
+ _DEFAULT_RPM = int(os.environ.get("CONTEXTSYNAPSE_RATE_LIMIT_RPM") or os.environ.get("AICONTEXTDB_RATE_LIMIT_RPM", "300"))
24
+ _PRO_RPM = 600
25
+
26
+
27
+ def _key_func(request: Request) -> str:
28
+ """Rate-limit key: tenant_id if authenticated, else client IP."""
29
+ tenant = getattr(request.state, "tenant", None)
30
+ if tenant:
31
+ return f"tenant:{tenant.tenant_id}"
32
+ user = getattr(request.state, "user", None)
33
+ if user:
34
+ return f"user:{user.user_id}"
35
+ return f"ip:{request.client.host if request.client else 'unknown'}"
36
+
37
+
38
+ def install_rate_limiter(app: FastAPI):
39
+ """Install rate limiting middleware on the FastAPI app."""
40
+ try:
41
+ from slowapi import Limiter, _rate_limit_exceeded_handler
42
+ from slowapi.errors import RateLimitExceeded
43
+ except ImportError:
44
+ logger.warning("slowapi not installed — rate limiting is disabled. Run: pip install slowapi")
45
+ return
46
+
47
+ limiter = Limiter(key_func=_key_func, default_limits=[f"{_DEFAULT_RPM}/minute"])
48
+ app.state.limiter = limiter
49
+
50
+ @app.exception_handler(RateLimitExceeded)
51
+ async def rate_limit_handler(request: Request, exc: RateLimitExceeded):
52
+ return JSONResponse(
53
+ status_code=429,
54
+ content={
55
+ "error_code": "RATE_LIMITED",
56
+ "message": f"Rate limit exceeded. Try again later.",
57
+ "detail": str(exc.detail) if hasattr(exc, "detail") else None,
58
+ },
59
+ )
60
+
61
+ # Apply limiter as middleware
62
+ from slowapi.middleware import SlowAPIMiddleware
63
+ app.add_middleware(SlowAPIMiddleware)
64
+ logger.info(f"Rate limiting enabled: {_DEFAULT_RPM} req/min default")