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,502 @@
1
+ """Content Monitor — auto-discovers and ingests relevant content.
2
+
3
+ Instead of FM manually pasting YouTube links, the system:
4
+ 1. Monitors YouTube channels per stock (company IR, analyst channels)
5
+ 2. Monitors RSS feeds for new analyst reports, earnings transcripts
6
+ 3. Auto-classifies content type (earnings_call, analyst_opinion, conference)
7
+ 4. Auto-queues for ingestion via AsyncIngestManager
8
+ 5. Runs on a schedule (every 6 hours by default)
9
+
10
+ Sources monitored per stock:
11
+ - Company's official YouTube channel (IR presentations, AGMs)
12
+ - Financial YouTube channels (ET Now, CNBC-TV18, Moneycontrol)
13
+ - Earnings transcript sites (seekingalpha, tickertape)
14
+ - Broker research portals
15
+
16
+ Usage:
17
+ monitor = ContentMonitor(registry)
18
+ monitor.run_scan() # scans all stocks for new content
19
+ # Or schedule:
20
+ monitor.start_scheduler(interval_hours=6)
21
+ """
22
+ import logging
23
+ import json
24
+ import re
25
+ import threading
26
+ import time
27
+ import uuid
28
+ from datetime import datetime, timezone, timedelta
29
+ from dataclasses import dataclass, field
30
+ from typing import Any, Dict, List, Optional
31
+ from pathlib import Path
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+ MONITOR_STATE_DIR = Path(__file__).parent.parent.parent / ".content_monitor"
36
+
37
+
38
+ # ── YouTube channel registry per stock ────────────────────────────────
39
+ # Company IR channels + major financial channels
40
+ STOCK_YOUTUBE_CHANNELS = {
41
+ "tcs": {
42
+ "company": ["TCS"], # YouTube channel name search
43
+ "keywords": ["TCS earnings", "TCS quarterly results", "TCS Q1", "TCS Q2", "TCS Q3", "TCS Q4",
44
+ "TCS management commentary", "TCS investor call"],
45
+ },
46
+ "reliance": {
47
+ "company": ["Reliance Industries"],
48
+ "keywords": ["Reliance AGM", "Reliance earnings", "Reliance quarterly",
49
+ "Mukesh Ambani speech", "Jio earnings"],
50
+ },
51
+ "hdfcbank": {
52
+ "company": ["HDFC Bank"],
53
+ "keywords": ["HDFC Bank earnings", "HDFC Bank results", "HDFC Bank quarterly"],
54
+ },
55
+ "icicibank": {
56
+ "company": ["ICICI Bank"],
57
+ "keywords": ["ICICI Bank earnings", "ICICI Bank results", "ICICI quarterly"],
58
+ },
59
+ "infosys": {
60
+ "company": ["Infosys"],
61
+ "keywords": ["Infosys earnings", "Infosys results", "Infosys guidance",
62
+ "Salil Parekh", "Infosys quarterly"],
63
+ },
64
+ "sunpharma": {
65
+ "company": ["Sun Pharma"],
66
+ "keywords": ["Sun Pharma earnings", "Sun Pharma results", "Dilip Shanghvi"],
67
+ },
68
+ "titan": {
69
+ "company": ["Titan Company"],
70
+ "keywords": ["Titan earnings", "Titan results", "Tanishq", "Titan quarterly"],
71
+ },
72
+ "bajfinance": {
73
+ "company": ["Bajaj Finance"],
74
+ "keywords": ["Bajaj Finance earnings", "Bajaj Finance results"],
75
+ },
76
+ "kotakbank": {
77
+ "company": ["Kotak Bank", "Kotak Mahindra"],
78
+ "keywords": ["Kotak Bank earnings", "Kotak results"],
79
+ },
80
+ "hindunilvr": {
81
+ "company": ["Hindustan Unilever", "HUL"],
82
+ "keywords": ["HUL earnings", "Hindustan Unilever results"],
83
+ },
84
+ "bhartiartl": {
85
+ "company": ["Bharti Airtel", "Airtel"],
86
+ "keywords": ["Airtel earnings", "Airtel results", "Airtel quarterly", "Sunil Mittal"],
87
+ },
88
+ "adanient": {
89
+ "company": ["Adani"],
90
+ "keywords": ["Adani earnings", "Adani results", "Gautam Adani"],
91
+ },
92
+ "asianpaint": {
93
+ "company": ["Asian Paints"],
94
+ "keywords": ["Asian Paints earnings", "Asian Paints results"],
95
+ },
96
+ }
97
+
98
+ # Financial YouTube channels to monitor for ALL stocks
99
+ FINANCIAL_CHANNELS = [
100
+ {"name": "ET Now", "keywords": ["earnings", "quarterly results", "management commentary"]},
101
+ {"name": "CNBC-TV18", "keywords": ["earnings call", "results review", "stock analysis"]},
102
+ {"name": "Moneycontrol", "keywords": ["quarterly results", "earnings", "management speak"]},
103
+ {"name": "Zerodha Varsity", "keywords": ["stock analysis", "fundamental analysis"]},
104
+ {"name": "SOIC", "keywords": ["stock analysis", "company analysis"]},
105
+ ]
106
+
107
+ # Transcript/research RSS sources
108
+ TRANSCRIPT_FEEDS = {
109
+ "seekingalpha": "https://seekingalpha.com/feed",
110
+ "tickertape": "https://www.tickertape.in/blog/feed",
111
+ "moneycontrol_research": "https://www.moneycontrol.com/rss/results.xml",
112
+ }
113
+
114
+
115
+ @dataclass
116
+ class DiscoveredContent:
117
+ """A piece of content discovered by the monitor."""
118
+ content_id: str = ""
119
+ entity: str = "" # which stock this relates to
120
+ source: str = "" # youtube, rss, web
121
+ url: str = ""
122
+ title: str = ""
123
+ published_at: str = ""
124
+ channel: str = ""
125
+ job_type: str = "general" # auto-classified: earnings_call, analyst_opinion, etc.
126
+ confidence: float = 0.0 # how confident we are this is relevant
127
+ ingested: bool = False
128
+ job_id: str = "" # if ingested, the async job ID
129
+ discovered_at: str = ""
130
+
131
+ def __post_init__(self):
132
+ if not self.content_id:
133
+ self.content_id = f"disc_{uuid.uuid4().hex[:8]}"
134
+ if not self.discovered_at:
135
+ self.discovered_at = datetime.now(timezone.utc).isoformat()
136
+
137
+
138
+ def _classify_content(title: str, description: str = "") -> dict:
139
+ """Auto-classify content type from title/description.
140
+
141
+ Returns: {job_type, confidence}
142
+ """
143
+ text = f"{title} {description}".lower()
144
+
145
+ patterns = [
146
+ (r"q[1-4]\s*(fy)?\d{2}.*?(result|earn|review)", "earnings_call", 0.9),
147
+ (r"quarterly\s*(result|earn|review|update)", "earnings_call", 0.85),
148
+ (r"(management|con\s*call|investor)\s*(call|commentary|meet)", "earnings_call", 0.85),
149
+ (r"(agm|annual\s*general\s*meet)", "conference", 0.9),
150
+ (r"(analyst|broker)\s*(meet|day|present)", "analyst_opinion", 0.8),
151
+ (r"(upgrade|downgrade|target\s*price|initiating)", "analyst_opinion", 0.85),
152
+ (r"(conference|summit|investor\s*day)", "conference", 0.8),
153
+ (r"(interview|speaks|exclusive|in\s*conversation)", "management_interview", 0.75),
154
+ (r"(ceo|cfo|md|chairman)\s*(speak|interview|comment)", "management_interview", 0.8),
155
+ (r"(research|deep\s*dive|analysis|fundamental)", "research", 0.7),
156
+ (r"(stock\s*pick|buy|sell|hold|outperform)", "analyst_opinion", 0.7),
157
+ ]
158
+
159
+ best_type = "general"
160
+ best_conf = 0.0
161
+
162
+ for pattern, job_type, confidence in patterns:
163
+ if re.search(pattern, text):
164
+ if confidence > best_conf:
165
+ best_type = job_type
166
+ best_conf = confidence
167
+
168
+ return {"job_type": best_type, "confidence": best_conf}
169
+
170
+
171
+ class ContentMonitor:
172
+ """Monitors YouTube channels and RSS feeds for new content to auto-ingest."""
173
+
174
+ def __init__(self, registry):
175
+ self._registry = registry
176
+ self._scheduler_thread = None
177
+ self._running = False
178
+
179
+ def _get_seen_ids(self) -> set:
180
+ """Load set of already-seen content IDs (to avoid re-ingesting)."""
181
+ MONITOR_STATE_DIR.mkdir(parents=True, exist_ok=True)
182
+ seen_path = MONITOR_STATE_DIR / "seen_ids.json"
183
+ if seen_path.exists():
184
+ try:
185
+ return set(json.loads(seen_path.read_text()))
186
+ except Exception:
187
+ pass
188
+ return set()
189
+
190
+ def _save_seen_ids(self, seen: set):
191
+ MONITOR_STATE_DIR.mkdir(parents=True, exist_ok=True)
192
+ seen_path = MONITOR_STATE_DIR / "seen_ids.json"
193
+ # Keep only last 5000 IDs
194
+ ids = sorted(seen)[-5000:]
195
+ seen_path.write_text(json.dumps(ids))
196
+
197
+ def _save_discovery(self, item: DiscoveredContent):
198
+ MONITOR_STATE_DIR.mkdir(parents=True, exist_ok=True)
199
+ log_path = MONITOR_STATE_DIR / "discoveries.jsonl"
200
+ with open(log_path, "a") as f:
201
+ f.write(json.dumps(item.__dict__) + "\n")
202
+
203
+ # ── YouTube Discovery ────────────────────────────────────────
204
+
205
+ def scan_youtube(self, entity: str = None, max_results: int = 5,
206
+ days_back: int = 7) -> List[DiscoveredContent]:
207
+ """Scan YouTube for new videos related to portfolio stocks.
208
+
209
+ Uses yt-dlp to search YouTube (no API key needed).
210
+ """
211
+ try:
212
+ import yt_dlp
213
+ except ImportError:
214
+ logger.warning("yt-dlp not installed — YouTube monitoring unavailable")
215
+ return []
216
+
217
+ seen = self._get_seen_ids()
218
+ discoveries = []
219
+ stocks_to_scan = {entity: STOCK_YOUTUBE_CHANNELS.get(entity, {})} if entity else STOCK_YOUTUBE_CHANNELS
220
+
221
+ for stock, config in stocks_to_scan.items():
222
+ keywords = config.get("keywords", [])
223
+ if not keywords:
224
+ continue
225
+
226
+ for kw in keywords[:3]: # limit searches per stock
227
+ try:
228
+ ydl_opts = {
229
+ "quiet": True,
230
+ "no_warnings": True,
231
+ "extract_flat": True,
232
+ "playlistend": max_results,
233
+ "socket_timeout": 15,
234
+ }
235
+
236
+ search_url = f"ytsearch{max_results}:{kw}"
237
+
238
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
239
+ result = ydl.extract_info(search_url, download=False)
240
+
241
+ entries = result.get("entries", []) if result else []
242
+
243
+ for entry in entries:
244
+ video_id = entry.get("id", "")
245
+ if not video_id or video_id in seen:
246
+ continue
247
+
248
+ title = entry.get("title", "")
249
+ upload_date = entry.get("upload_date", "")
250
+ channel = entry.get("channel", entry.get("uploader", ""))
251
+
252
+ # Check recency
253
+ if upload_date:
254
+ try:
255
+ vdate = datetime.strptime(upload_date, "%Y%m%d")
256
+ if (datetime.now() - vdate).days > days_back:
257
+ continue
258
+ except Exception:
259
+ pass
260
+
261
+ # Check relevance — title must mention the stock or related terms
262
+ stock_name = stock.replace("_", " ")
263
+ title_lower = title.lower()
264
+ company_names = config.get("company", [stock_name])
265
+ relevant = any(cn.lower() in title_lower for cn in company_names)
266
+ if not relevant:
267
+ # Check if any keyword matches in title
268
+ relevant = any(k.lower() in title_lower for k in keywords)
269
+
270
+ if not relevant:
271
+ continue
272
+
273
+ # Classify
274
+ classification = _classify_content(title)
275
+
276
+ url = f"https://www.youtube.com/watch?v={video_id}"
277
+ disc = DiscoveredContent(
278
+ content_id=video_id,
279
+ entity=stock,
280
+ source="youtube",
281
+ url=url,
282
+ title=title,
283
+ published_at=upload_date,
284
+ channel=channel,
285
+ job_type=classification["job_type"],
286
+ confidence=classification["confidence"],
287
+ )
288
+ discoveries.append(disc)
289
+ seen.add(video_id)
290
+
291
+ except Exception as e:
292
+ logger.debug("[MONITOR] YouTube search failed for '%s': %s", kw, e)
293
+
294
+ self._save_seen_ids(seen)
295
+ return discoveries
296
+
297
+ # ── RSS Discovery ────────────────────────────────────────────
298
+
299
+ def scan_rss_transcripts(self, entity: str = None) -> List[DiscoveredContent]:
300
+ """Scan RSS feeds for earnings transcripts and research articles."""
301
+ import urllib.request
302
+
303
+ seen = self._get_seen_ids()
304
+ discoveries = []
305
+
306
+ for feed_name, feed_url in TRANSCRIPT_FEEDS.items():
307
+ try:
308
+ req = urllib.request.Request(feed_url, headers={"User-Agent": "ContextSynapse/1.0"})
309
+ with urllib.request.urlopen(req, timeout=10) as resp:
310
+ content = resp.read().decode("utf-8", errors="ignore")
311
+
312
+ # Simple RSS parsing (title + link extraction)
313
+ titles = re.findall(r"<title[^>]*>(.*?)</title>", content, re.DOTALL)
314
+ links = re.findall(r"<link[^>]*>(.*?)</link>", content, re.DOTALL)
315
+
316
+ for title, link in zip(titles, links):
317
+ title = title.strip().replace("<![CDATA[", "").replace("]]>", "")
318
+ link = link.strip()
319
+ content_id = f"{feed_name}_{hash(link) % 100000}"
320
+
321
+ if content_id in seen:
322
+ continue
323
+
324
+ # Check if this article relates to any portfolio stock
325
+ matched_entity = self._match_article_to_entity(title, entity)
326
+ if not matched_entity:
327
+ continue
328
+
329
+ classification = _classify_content(title)
330
+
331
+ disc = DiscoveredContent(
332
+ content_id=content_id,
333
+ entity=matched_entity,
334
+ source="rss",
335
+ url=link,
336
+ title=title,
337
+ channel=feed_name,
338
+ job_type=classification["job_type"],
339
+ confidence=classification["confidence"],
340
+ )
341
+ discoveries.append(disc)
342
+ seen.add(content_id)
343
+
344
+ except Exception as e:
345
+ logger.debug("[MONITOR] RSS scan failed for %s: %s", feed_name, e)
346
+
347
+ self._save_seen_ids(seen)
348
+ return discoveries
349
+
350
+ def _match_article_to_entity(self, title: str, filter_entity: str = None) -> Optional[str]:
351
+ """Check if an article title matches any portfolio stock."""
352
+ title_lower = title.lower()
353
+
354
+ stocks_to_check = {filter_entity: STOCK_YOUTUBE_CHANNELS.get(filter_entity, {})} if filter_entity else STOCK_YOUTUBE_CHANNELS
355
+
356
+ for stock, config in stocks_to_check.items():
357
+ company_names = config.get("company", [stock.replace("_", " ")])
358
+ if any(cn.lower() in title_lower for cn in company_names):
359
+ return stock
360
+ if stock.lower() in title_lower:
361
+ return stock
362
+
363
+ return None
364
+
365
+ # ── Full Scan + Auto-Ingest ──────────────────────────────────
366
+
367
+ def run_scan(self, auto_ingest: bool = True, min_confidence: float = 0.6) -> Dict[str, Any]:
368
+ """Run a full content scan across all sources.
369
+
370
+ If auto_ingest=True, automatically queue high-confidence discoveries for ingestion.
371
+ """
372
+ logger.info("[MONITOR] Starting content scan...")
373
+ start = datetime.now(timezone.utc)
374
+
375
+ # Scan all sources
376
+ yt_discoveries = self.scan_youtube(days_back=3)
377
+ rss_discoveries = self.scan_rss_transcripts()
378
+
379
+ all_discoveries = yt_discoveries + rss_discoveries
380
+ logger.info("[MONITOR] Found %d new items (%d YouTube, %d RSS)",
381
+ len(all_discoveries), len(yt_discoveries), len(rss_discoveries))
382
+
383
+ # Auto-ingest high-confidence items
384
+ ingested = []
385
+ skipped = []
386
+
387
+ if auto_ingest and all_discoveries:
388
+ try:
389
+ from contextsynapse.ingestion.async_ingest import AsyncIngestManager
390
+ mgr = AsyncIngestManager(self._registry)
391
+
392
+ for disc in all_discoveries:
393
+ if disc.confidence < min_confidence:
394
+ skipped.append(disc)
395
+ continue
396
+
397
+ try:
398
+ if disc.source == "youtube":
399
+ job = mgr.submit_youtube(
400
+ disc.url, entity=disc.entity, job_type=disc.job_type,
401
+ )
402
+ else:
403
+ # For RSS, we'd need to crawl the article first
404
+ # For now, skip RSS auto-ingest (needs web crawler)
405
+ skipped.append(disc)
406
+ continue
407
+
408
+ disc.ingested = True
409
+ disc.job_id = job.job_id
410
+ ingested.append(disc)
411
+ logger.info("[MONITOR] Auto-ingested: %s → %s (%s, conf=%.2f)",
412
+ disc.title[:50], disc.entity, disc.job_type, disc.confidence)
413
+
414
+ except Exception as e:
415
+ logger.warning("[MONITOR] Auto-ingest failed for %s: %s", disc.title[:50], e)
416
+ skipped.append(disc)
417
+
418
+ except Exception as e:
419
+ logger.warning("[MONITOR] AsyncIngestManager unavailable: %s", e)
420
+
421
+ # Save discoveries log
422
+ for disc in all_discoveries:
423
+ self._save_discovery(disc)
424
+
425
+ elapsed = (datetime.now(timezone.utc) - start).total_seconds()
426
+
427
+ result = {
428
+ "scan_time_seconds": round(elapsed, 1),
429
+ "total_discovered": len(all_discoveries),
430
+ "youtube_discovered": len(yt_discoveries),
431
+ "rss_discovered": len(rss_discoveries),
432
+ "auto_ingested": len(ingested),
433
+ "skipped_low_confidence": len(skipped),
434
+ "ingested_items": [
435
+ {"entity": d.entity, "title": d.title[:60], "type": d.job_type,
436
+ "confidence": d.confidence, "job_id": d.job_id}
437
+ for d in ingested
438
+ ],
439
+ "discovered_items": [
440
+ {"entity": d.entity, "title": d.title[:60], "type": d.job_type,
441
+ "source": d.source, "confidence": d.confidence, "url": d.url}
442
+ for d in all_discoveries[:20]
443
+ ],
444
+ }
445
+
446
+ logger.info("[MONITOR] Scan complete: %d found, %d ingested in %.1fs",
447
+ len(all_discoveries), len(ingested), elapsed)
448
+ return result
449
+
450
+ # ── Scheduler ────────────────────────────────────────────────
451
+
452
+ def start_scheduler(self, interval_hours: int = 6):
453
+ """Start background scheduler that scans for new content periodically."""
454
+ if self._running:
455
+ return
456
+
457
+ self._running = True
458
+
459
+ def _loop():
460
+ while self._running:
461
+ try:
462
+ self.run_scan(auto_ingest=True, min_confidence=0.7)
463
+ except Exception as e:
464
+ logger.exception("[MONITOR] Scheduled scan failed: %s", e)
465
+ # Sleep for interval
466
+ for _ in range(interval_hours * 3600):
467
+ if not self._running:
468
+ break
469
+ time.sleep(1)
470
+
471
+ self._scheduler_thread = threading.Thread(target=_loop, daemon=True)
472
+ self._scheduler_thread.start()
473
+ logger.info("[MONITOR] Content monitor scheduler started (every %dh)", interval_hours)
474
+
475
+ def stop_scheduler(self):
476
+ """Stop the background scheduler."""
477
+ self._running = False
478
+ logger.info("[MONITOR] Content monitor scheduler stopped")
479
+
480
+ def get_discoveries(self, entity: str = None, limit: int = 50) -> List[Dict]:
481
+ """Get recent discoveries from the log."""
482
+ log_path = MONITOR_STATE_DIR / "discoveries.jsonl"
483
+ if not log_path.exists():
484
+ return []
485
+
486
+ items = []
487
+ try:
488
+ with open(log_path) as f:
489
+ for line in f:
490
+ try:
491
+ item = json.loads(line.strip())
492
+ if entity and item.get("entity") != entity:
493
+ continue
494
+ items.append(item)
495
+ except Exception:
496
+ continue
497
+ except Exception:
498
+ pass
499
+
500
+ # Return most recent first
501
+ items.reverse()
502
+ return items[:limit]
@@ -0,0 +1,106 @@
1
+ """Duplicate detection for ingestion pipeline.
2
+
3
+ Provides exact and fuzzy matching against existing graph nodes
4
+ to prevent duplicate data from being ingested.
5
+ """
6
+
7
+ from typing import Any, Dict, List, Optional, Set
8
+
9
+
10
+ def _keywords(text: str) -> Set[str]:
11
+ """Extract lowercase keyword tokens from text, stripping punctuation."""
12
+ if not text:
13
+ return set()
14
+ # Split on whitespace, strip non-alpha chars, lowercase, drop empties
15
+ return {
16
+ w.strip(".,;:!?()[]{}\"'").lower()
17
+ for w in text.split()
18
+ if w.strip(".,;:!?()[]{}\"'")
19
+ }
20
+
21
+
22
+ def _keyword_overlap(a: str, b: str) -> float:
23
+ """Jaccard similarity between keyword sets of two strings."""
24
+ ka = _keywords(a)
25
+ kb = _keywords(b)
26
+ if not ka or not kb:
27
+ return 0.0
28
+ intersection = ka & kb
29
+ union = ka | kb
30
+ return len(intersection) / len(union)
31
+
32
+
33
+ def dedup_check(
34
+ node: Dict[str, Any],
35
+ db: Any,
36
+ fuzzy_threshold: float = 0.8,
37
+ ) -> Optional[Dict[str, Any]]:
38
+ """Check whether *node* duplicates an existing node in *db*.
39
+
40
+ Parameters
41
+ ----------
42
+ node : dict
43
+ Candidate node with ``label`` and ``properties.name``.
44
+ db : object
45
+ Database instance exposing ``db.csr_adapter.get_all_nodes()``.
46
+ fuzzy_threshold : float
47
+ Minimum keyword-overlap ratio to consider a fuzzy match.
48
+
49
+ Returns
50
+ -------
51
+ dict or None
52
+ ``{"match_type": "exact"|"fuzzy", "existing_id": str}`` if a
53
+ duplicate is found, otherwise ``None``.
54
+ """
55
+ candidate_label = node.get("label", "")
56
+ candidate_name = (node.get("properties") or {}).get("name", "")
57
+ if not candidate_name:
58
+ return None
59
+
60
+ # Get all nodes — handle both CSR and Redis adapter APIs
61
+ try:
62
+ existing_nodes = db.get_all_nodes()
63
+ except Exception:
64
+ try:
65
+ existing_nodes = db.csr_adapter.get_all_nodes()
66
+ except Exception:
67
+ return None
68
+
69
+ best_fuzzy: Optional[Dict[str, Any]] = None
70
+ best_score: float = 0.0
71
+
72
+ for existing in existing_nodes:
73
+ ex_label = getattr(existing, "node_type", None) or getattr(existing, "label", "")
74
+ if ex_label.lower() != candidate_label.lower():
75
+ continue
76
+
77
+ ex_name = (getattr(existing, "properties", None) or {}).get("name", "")
78
+ if not ex_name:
79
+ continue
80
+
81
+ # Exact match: case-insensitive name comparison
82
+ if candidate_name.strip().lower() == ex_name.strip().lower():
83
+ return {"match_type": "exact", "existing_id": existing.id}
84
+
85
+ # Fuzzy match: keyword overlap
86
+ score = _keyword_overlap(candidate_name, ex_name)
87
+ if score >= fuzzy_threshold and score > best_score:
88
+ best_score = score
89
+ best_fuzzy = {"match_type": "fuzzy", "existing_id": existing.id}
90
+
91
+ return best_fuzzy
92
+
93
+
94
+ def dedup_check_batch(
95
+ nodes: List[Dict[str, Any]],
96
+ db: Any,
97
+ fuzzy_threshold: float = 0.8,
98
+ ) -> List[Dict[str, Any]]:
99
+ """Run :func:`dedup_check` on each node, adding ``_dedup_match`` key.
100
+
101
+ Returns the same list (mutated in-place) with ``_dedup_match`` set to the
102
+ match dict or ``None``.
103
+ """
104
+ for node in nodes:
105
+ node["_dedup_match"] = dedup_check(node, db, fuzzy_threshold=fuzzy_threshold)
106
+ return nodes