PraisonAI 3.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 (393) hide show
  1. praisonai/__init__.py +54 -0
  2. praisonai/__main__.py +15 -0
  3. praisonai/acp/__init__.py +54 -0
  4. praisonai/acp/config.py +159 -0
  5. praisonai/acp/server.py +587 -0
  6. praisonai/acp/session.py +219 -0
  7. praisonai/adapters/__init__.py +50 -0
  8. praisonai/adapters/readers.py +395 -0
  9. praisonai/adapters/rerankers.py +315 -0
  10. praisonai/adapters/retrievers.py +394 -0
  11. praisonai/adapters/vector_stores.py +409 -0
  12. praisonai/agent_scheduler.py +337 -0
  13. praisonai/agents_generator.py +903 -0
  14. praisonai/api/call.py +292 -0
  15. praisonai/auto.py +1197 -0
  16. praisonai/capabilities/__init__.py +275 -0
  17. praisonai/capabilities/a2a.py +140 -0
  18. praisonai/capabilities/assistants.py +283 -0
  19. praisonai/capabilities/audio.py +320 -0
  20. praisonai/capabilities/batches.py +469 -0
  21. praisonai/capabilities/completions.py +336 -0
  22. praisonai/capabilities/container_files.py +155 -0
  23. praisonai/capabilities/containers.py +93 -0
  24. praisonai/capabilities/embeddings.py +158 -0
  25. praisonai/capabilities/files.py +467 -0
  26. praisonai/capabilities/fine_tuning.py +293 -0
  27. praisonai/capabilities/guardrails.py +182 -0
  28. praisonai/capabilities/images.py +330 -0
  29. praisonai/capabilities/mcp.py +190 -0
  30. praisonai/capabilities/messages.py +270 -0
  31. praisonai/capabilities/moderations.py +154 -0
  32. praisonai/capabilities/ocr.py +217 -0
  33. praisonai/capabilities/passthrough.py +204 -0
  34. praisonai/capabilities/rag.py +207 -0
  35. praisonai/capabilities/realtime.py +160 -0
  36. praisonai/capabilities/rerank.py +165 -0
  37. praisonai/capabilities/responses.py +266 -0
  38. praisonai/capabilities/search.py +109 -0
  39. praisonai/capabilities/skills.py +133 -0
  40. praisonai/capabilities/vector_store_files.py +334 -0
  41. praisonai/capabilities/vector_stores.py +304 -0
  42. praisonai/capabilities/videos.py +141 -0
  43. praisonai/chainlit_ui.py +304 -0
  44. praisonai/chat/__init__.py +106 -0
  45. praisonai/chat/app.py +125 -0
  46. praisonai/cli/__init__.py +26 -0
  47. praisonai/cli/app.py +213 -0
  48. praisonai/cli/commands/__init__.py +75 -0
  49. praisonai/cli/commands/acp.py +70 -0
  50. praisonai/cli/commands/completion.py +333 -0
  51. praisonai/cli/commands/config.py +166 -0
  52. praisonai/cli/commands/debug.py +142 -0
  53. praisonai/cli/commands/diag.py +55 -0
  54. praisonai/cli/commands/doctor.py +166 -0
  55. praisonai/cli/commands/environment.py +179 -0
  56. praisonai/cli/commands/lsp.py +112 -0
  57. praisonai/cli/commands/mcp.py +210 -0
  58. praisonai/cli/commands/profile.py +457 -0
  59. praisonai/cli/commands/run.py +228 -0
  60. praisonai/cli/commands/schedule.py +150 -0
  61. praisonai/cli/commands/serve.py +97 -0
  62. praisonai/cli/commands/session.py +212 -0
  63. praisonai/cli/commands/traces.py +145 -0
  64. praisonai/cli/commands/version.py +101 -0
  65. praisonai/cli/configuration/__init__.py +18 -0
  66. praisonai/cli/configuration/loader.py +353 -0
  67. praisonai/cli/configuration/paths.py +114 -0
  68. praisonai/cli/configuration/schema.py +164 -0
  69. praisonai/cli/features/__init__.py +268 -0
  70. praisonai/cli/features/acp.py +236 -0
  71. praisonai/cli/features/action_orchestrator.py +546 -0
  72. praisonai/cli/features/agent_scheduler.py +773 -0
  73. praisonai/cli/features/agent_tools.py +474 -0
  74. praisonai/cli/features/agents.py +375 -0
  75. praisonai/cli/features/at_mentions.py +471 -0
  76. praisonai/cli/features/auto_memory.py +182 -0
  77. praisonai/cli/features/autonomy_mode.py +490 -0
  78. praisonai/cli/features/background.py +356 -0
  79. praisonai/cli/features/base.py +168 -0
  80. praisonai/cli/features/capabilities.py +1326 -0
  81. praisonai/cli/features/checkpoints.py +338 -0
  82. praisonai/cli/features/code_intelligence.py +652 -0
  83. praisonai/cli/features/compaction.py +294 -0
  84. praisonai/cli/features/compare.py +534 -0
  85. praisonai/cli/features/cost_tracker.py +514 -0
  86. praisonai/cli/features/debug.py +810 -0
  87. praisonai/cli/features/deploy.py +517 -0
  88. praisonai/cli/features/diag.py +289 -0
  89. praisonai/cli/features/doctor/__init__.py +63 -0
  90. praisonai/cli/features/doctor/checks/__init__.py +24 -0
  91. praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
  92. praisonai/cli/features/doctor/checks/config_checks.py +366 -0
  93. praisonai/cli/features/doctor/checks/db_checks.py +366 -0
  94. praisonai/cli/features/doctor/checks/env_checks.py +543 -0
  95. praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
  96. praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
  97. praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
  98. praisonai/cli/features/doctor/checks/network_checks.py +251 -0
  99. praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
  100. praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
  101. praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
  102. praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
  103. praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
  104. praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
  105. praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
  106. praisonai/cli/features/doctor/engine.py +266 -0
  107. praisonai/cli/features/doctor/formatters.py +310 -0
  108. praisonai/cli/features/doctor/handler.py +397 -0
  109. praisonai/cli/features/doctor/models.py +264 -0
  110. praisonai/cli/features/doctor/registry.py +239 -0
  111. praisonai/cli/features/endpoints.py +1019 -0
  112. praisonai/cli/features/eval.py +560 -0
  113. praisonai/cli/features/external_agents.py +231 -0
  114. praisonai/cli/features/fast_context.py +410 -0
  115. praisonai/cli/features/flow_display.py +566 -0
  116. praisonai/cli/features/git_integration.py +651 -0
  117. praisonai/cli/features/guardrail.py +171 -0
  118. praisonai/cli/features/handoff.py +185 -0
  119. praisonai/cli/features/hooks.py +583 -0
  120. praisonai/cli/features/image.py +384 -0
  121. praisonai/cli/features/interactive_runtime.py +585 -0
  122. praisonai/cli/features/interactive_tools.py +380 -0
  123. praisonai/cli/features/interactive_tui.py +603 -0
  124. praisonai/cli/features/jobs.py +632 -0
  125. praisonai/cli/features/knowledge.py +531 -0
  126. praisonai/cli/features/lite.py +244 -0
  127. praisonai/cli/features/lsp_cli.py +225 -0
  128. praisonai/cli/features/mcp.py +169 -0
  129. praisonai/cli/features/message_queue.py +587 -0
  130. praisonai/cli/features/metrics.py +211 -0
  131. praisonai/cli/features/n8n.py +673 -0
  132. praisonai/cli/features/observability.py +293 -0
  133. praisonai/cli/features/ollama.py +361 -0
  134. praisonai/cli/features/output_style.py +273 -0
  135. praisonai/cli/features/package.py +631 -0
  136. praisonai/cli/features/performance.py +308 -0
  137. praisonai/cli/features/persistence.py +636 -0
  138. praisonai/cli/features/profile.py +226 -0
  139. praisonai/cli/features/profiler/__init__.py +81 -0
  140. praisonai/cli/features/profiler/core.py +558 -0
  141. praisonai/cli/features/profiler/optimizations.py +652 -0
  142. praisonai/cli/features/profiler/suite.py +386 -0
  143. praisonai/cli/features/profiling.py +350 -0
  144. praisonai/cli/features/queue/__init__.py +73 -0
  145. praisonai/cli/features/queue/manager.py +395 -0
  146. praisonai/cli/features/queue/models.py +286 -0
  147. praisonai/cli/features/queue/persistence.py +564 -0
  148. praisonai/cli/features/queue/scheduler.py +484 -0
  149. praisonai/cli/features/queue/worker.py +372 -0
  150. praisonai/cli/features/recipe.py +1723 -0
  151. praisonai/cli/features/recipes.py +449 -0
  152. praisonai/cli/features/registry.py +229 -0
  153. praisonai/cli/features/repo_map.py +860 -0
  154. praisonai/cli/features/router.py +466 -0
  155. praisonai/cli/features/sandbox_executor.py +515 -0
  156. praisonai/cli/features/serve.py +829 -0
  157. praisonai/cli/features/session.py +222 -0
  158. praisonai/cli/features/skills.py +856 -0
  159. praisonai/cli/features/slash_commands.py +650 -0
  160. praisonai/cli/features/telemetry.py +179 -0
  161. praisonai/cli/features/templates.py +1384 -0
  162. praisonai/cli/features/thinking.py +305 -0
  163. praisonai/cli/features/todo.py +334 -0
  164. praisonai/cli/features/tools.py +680 -0
  165. praisonai/cli/features/tui/__init__.py +83 -0
  166. praisonai/cli/features/tui/app.py +580 -0
  167. praisonai/cli/features/tui/cli.py +566 -0
  168. praisonai/cli/features/tui/debug.py +511 -0
  169. praisonai/cli/features/tui/events.py +99 -0
  170. praisonai/cli/features/tui/mock_provider.py +328 -0
  171. praisonai/cli/features/tui/orchestrator.py +652 -0
  172. praisonai/cli/features/tui/screens/__init__.py +50 -0
  173. praisonai/cli/features/tui/screens/main.py +245 -0
  174. praisonai/cli/features/tui/screens/queue.py +174 -0
  175. praisonai/cli/features/tui/screens/session.py +124 -0
  176. praisonai/cli/features/tui/screens/settings.py +148 -0
  177. praisonai/cli/features/tui/widgets/__init__.py +56 -0
  178. praisonai/cli/features/tui/widgets/chat.py +261 -0
  179. praisonai/cli/features/tui/widgets/composer.py +224 -0
  180. praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
  181. praisonai/cli/features/tui/widgets/status.py +167 -0
  182. praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
  183. praisonai/cli/features/workflow.py +720 -0
  184. praisonai/cli/legacy.py +236 -0
  185. praisonai/cli/main.py +5559 -0
  186. praisonai/cli/schedule_cli.py +54 -0
  187. praisonai/cli/state/__init__.py +31 -0
  188. praisonai/cli/state/identifiers.py +161 -0
  189. praisonai/cli/state/sessions.py +313 -0
  190. praisonai/code/__init__.py +93 -0
  191. praisonai/code/agent_tools.py +344 -0
  192. praisonai/code/diff/__init__.py +21 -0
  193. praisonai/code/diff/diff_strategy.py +432 -0
  194. praisonai/code/tools/__init__.py +27 -0
  195. praisonai/code/tools/apply_diff.py +221 -0
  196. praisonai/code/tools/execute_command.py +275 -0
  197. praisonai/code/tools/list_files.py +274 -0
  198. praisonai/code/tools/read_file.py +206 -0
  199. praisonai/code/tools/search_replace.py +248 -0
  200. praisonai/code/tools/write_file.py +217 -0
  201. praisonai/code/utils/__init__.py +46 -0
  202. praisonai/code/utils/file_utils.py +307 -0
  203. praisonai/code/utils/ignore_utils.py +308 -0
  204. praisonai/code/utils/text_utils.py +276 -0
  205. praisonai/db/__init__.py +64 -0
  206. praisonai/db/adapter.py +531 -0
  207. praisonai/deploy/__init__.py +62 -0
  208. praisonai/deploy/api.py +231 -0
  209. praisonai/deploy/docker.py +454 -0
  210. praisonai/deploy/doctor.py +367 -0
  211. praisonai/deploy/main.py +327 -0
  212. praisonai/deploy/models.py +179 -0
  213. praisonai/deploy/providers/__init__.py +33 -0
  214. praisonai/deploy/providers/aws.py +331 -0
  215. praisonai/deploy/providers/azure.py +358 -0
  216. praisonai/deploy/providers/base.py +101 -0
  217. praisonai/deploy/providers/gcp.py +314 -0
  218. praisonai/deploy/schema.py +208 -0
  219. praisonai/deploy.py +185 -0
  220. praisonai/endpoints/__init__.py +53 -0
  221. praisonai/endpoints/a2u_server.py +410 -0
  222. praisonai/endpoints/discovery.py +165 -0
  223. praisonai/endpoints/providers/__init__.py +28 -0
  224. praisonai/endpoints/providers/a2a.py +253 -0
  225. praisonai/endpoints/providers/a2u.py +208 -0
  226. praisonai/endpoints/providers/agents_api.py +171 -0
  227. praisonai/endpoints/providers/base.py +231 -0
  228. praisonai/endpoints/providers/mcp.py +263 -0
  229. praisonai/endpoints/providers/recipe.py +206 -0
  230. praisonai/endpoints/providers/tools_mcp.py +150 -0
  231. praisonai/endpoints/registry.py +131 -0
  232. praisonai/endpoints/server.py +161 -0
  233. praisonai/inbuilt_tools/__init__.py +24 -0
  234. praisonai/inbuilt_tools/autogen_tools.py +117 -0
  235. praisonai/inc/__init__.py +2 -0
  236. praisonai/inc/config.py +96 -0
  237. praisonai/inc/models.py +155 -0
  238. praisonai/integrations/__init__.py +56 -0
  239. praisonai/integrations/base.py +303 -0
  240. praisonai/integrations/claude_code.py +270 -0
  241. praisonai/integrations/codex_cli.py +255 -0
  242. praisonai/integrations/cursor_cli.py +195 -0
  243. praisonai/integrations/gemini_cli.py +222 -0
  244. praisonai/jobs/__init__.py +67 -0
  245. praisonai/jobs/executor.py +425 -0
  246. praisonai/jobs/models.py +230 -0
  247. praisonai/jobs/router.py +314 -0
  248. praisonai/jobs/server.py +186 -0
  249. praisonai/jobs/store.py +203 -0
  250. praisonai/llm/__init__.py +66 -0
  251. praisonai/llm/registry.py +382 -0
  252. praisonai/mcp_server/__init__.py +152 -0
  253. praisonai/mcp_server/adapters/__init__.py +74 -0
  254. praisonai/mcp_server/adapters/agents.py +128 -0
  255. praisonai/mcp_server/adapters/capabilities.py +168 -0
  256. praisonai/mcp_server/adapters/cli_tools.py +568 -0
  257. praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
  258. praisonai/mcp_server/adapters/knowledge.py +93 -0
  259. praisonai/mcp_server/adapters/memory.py +104 -0
  260. praisonai/mcp_server/adapters/prompts.py +306 -0
  261. praisonai/mcp_server/adapters/resources.py +124 -0
  262. praisonai/mcp_server/adapters/tools_bridge.py +280 -0
  263. praisonai/mcp_server/auth/__init__.py +48 -0
  264. praisonai/mcp_server/auth/api_key.py +291 -0
  265. praisonai/mcp_server/auth/oauth.py +460 -0
  266. praisonai/mcp_server/auth/oidc.py +289 -0
  267. praisonai/mcp_server/auth/scopes.py +260 -0
  268. praisonai/mcp_server/cli.py +852 -0
  269. praisonai/mcp_server/elicitation.py +445 -0
  270. praisonai/mcp_server/icons.py +302 -0
  271. praisonai/mcp_server/recipe_adapter.py +573 -0
  272. praisonai/mcp_server/recipe_cli.py +824 -0
  273. praisonai/mcp_server/registry.py +703 -0
  274. praisonai/mcp_server/sampling.py +422 -0
  275. praisonai/mcp_server/server.py +490 -0
  276. praisonai/mcp_server/tasks.py +443 -0
  277. praisonai/mcp_server/transports/__init__.py +18 -0
  278. praisonai/mcp_server/transports/http_stream.py +376 -0
  279. praisonai/mcp_server/transports/stdio.py +132 -0
  280. praisonai/persistence/__init__.py +84 -0
  281. praisonai/persistence/config.py +238 -0
  282. praisonai/persistence/conversation/__init__.py +25 -0
  283. praisonai/persistence/conversation/async_mysql.py +427 -0
  284. praisonai/persistence/conversation/async_postgres.py +410 -0
  285. praisonai/persistence/conversation/async_sqlite.py +371 -0
  286. praisonai/persistence/conversation/base.py +151 -0
  287. praisonai/persistence/conversation/json_store.py +250 -0
  288. praisonai/persistence/conversation/mysql.py +387 -0
  289. praisonai/persistence/conversation/postgres.py +401 -0
  290. praisonai/persistence/conversation/singlestore.py +240 -0
  291. praisonai/persistence/conversation/sqlite.py +341 -0
  292. praisonai/persistence/conversation/supabase.py +203 -0
  293. praisonai/persistence/conversation/surrealdb.py +287 -0
  294. praisonai/persistence/factory.py +301 -0
  295. praisonai/persistence/hooks/__init__.py +18 -0
  296. praisonai/persistence/hooks/agent_hooks.py +297 -0
  297. praisonai/persistence/knowledge/__init__.py +26 -0
  298. praisonai/persistence/knowledge/base.py +144 -0
  299. praisonai/persistence/knowledge/cassandra.py +232 -0
  300. praisonai/persistence/knowledge/chroma.py +295 -0
  301. praisonai/persistence/knowledge/clickhouse.py +242 -0
  302. praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
  303. praisonai/persistence/knowledge/couchbase.py +286 -0
  304. praisonai/persistence/knowledge/lancedb.py +216 -0
  305. praisonai/persistence/knowledge/langchain_adapter.py +291 -0
  306. praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
  307. praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
  308. praisonai/persistence/knowledge/milvus.py +277 -0
  309. praisonai/persistence/knowledge/mongodb_vector.py +306 -0
  310. praisonai/persistence/knowledge/pgvector.py +335 -0
  311. praisonai/persistence/knowledge/pinecone.py +253 -0
  312. praisonai/persistence/knowledge/qdrant.py +301 -0
  313. praisonai/persistence/knowledge/redis_vector.py +291 -0
  314. praisonai/persistence/knowledge/singlestore_vector.py +299 -0
  315. praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
  316. praisonai/persistence/knowledge/upstash_vector.py +266 -0
  317. praisonai/persistence/knowledge/weaviate.py +223 -0
  318. praisonai/persistence/migrations/__init__.py +10 -0
  319. praisonai/persistence/migrations/manager.py +251 -0
  320. praisonai/persistence/orchestrator.py +406 -0
  321. praisonai/persistence/state/__init__.py +21 -0
  322. praisonai/persistence/state/async_mongodb.py +200 -0
  323. praisonai/persistence/state/base.py +107 -0
  324. praisonai/persistence/state/dynamodb.py +226 -0
  325. praisonai/persistence/state/firestore.py +175 -0
  326. praisonai/persistence/state/gcs.py +155 -0
  327. praisonai/persistence/state/memory.py +245 -0
  328. praisonai/persistence/state/mongodb.py +158 -0
  329. praisonai/persistence/state/redis.py +190 -0
  330. praisonai/persistence/state/upstash.py +144 -0
  331. praisonai/persistence/tests/__init__.py +3 -0
  332. praisonai/persistence/tests/test_all_backends.py +633 -0
  333. praisonai/profiler.py +1214 -0
  334. praisonai/recipe/__init__.py +134 -0
  335. praisonai/recipe/bridge.py +278 -0
  336. praisonai/recipe/core.py +893 -0
  337. praisonai/recipe/exceptions.py +54 -0
  338. praisonai/recipe/history.py +402 -0
  339. praisonai/recipe/models.py +266 -0
  340. praisonai/recipe/operations.py +440 -0
  341. praisonai/recipe/policy.py +422 -0
  342. praisonai/recipe/registry.py +849 -0
  343. praisonai/recipe/runtime.py +214 -0
  344. praisonai/recipe/security.py +711 -0
  345. praisonai/recipe/serve.py +859 -0
  346. praisonai/recipe/server.py +613 -0
  347. praisonai/scheduler/__init__.py +45 -0
  348. praisonai/scheduler/agent_scheduler.py +552 -0
  349. praisonai/scheduler/base.py +124 -0
  350. praisonai/scheduler/daemon_manager.py +225 -0
  351. praisonai/scheduler/state_manager.py +155 -0
  352. praisonai/scheduler/yaml_loader.py +193 -0
  353. praisonai/scheduler.py +194 -0
  354. praisonai/setup/__init__.py +1 -0
  355. praisonai/setup/build.py +21 -0
  356. praisonai/setup/post_install.py +23 -0
  357. praisonai/setup/setup_conda_env.py +25 -0
  358. praisonai/setup.py +16 -0
  359. praisonai/templates/__init__.py +116 -0
  360. praisonai/templates/cache.py +364 -0
  361. praisonai/templates/dependency_checker.py +358 -0
  362. praisonai/templates/discovery.py +391 -0
  363. praisonai/templates/loader.py +564 -0
  364. praisonai/templates/registry.py +511 -0
  365. praisonai/templates/resolver.py +206 -0
  366. praisonai/templates/security.py +327 -0
  367. praisonai/templates/tool_override.py +498 -0
  368. praisonai/templates/tools_doctor.py +256 -0
  369. praisonai/test.py +105 -0
  370. praisonai/train.py +562 -0
  371. praisonai/train_vision.py +306 -0
  372. praisonai/ui/agents.py +824 -0
  373. praisonai/ui/callbacks.py +57 -0
  374. praisonai/ui/chainlit_compat.py +246 -0
  375. praisonai/ui/chat.py +532 -0
  376. praisonai/ui/code.py +717 -0
  377. praisonai/ui/colab.py +474 -0
  378. praisonai/ui/colab_chainlit.py +81 -0
  379. praisonai/ui/components/aicoder.py +284 -0
  380. praisonai/ui/context.py +283 -0
  381. praisonai/ui/database_config.py +56 -0
  382. praisonai/ui/db.py +294 -0
  383. praisonai/ui/realtime.py +488 -0
  384. praisonai/ui/realtimeclient/__init__.py +756 -0
  385. praisonai/ui/realtimeclient/tools.py +242 -0
  386. praisonai/ui/sql_alchemy.py +710 -0
  387. praisonai/upload_vision.py +140 -0
  388. praisonai/version.py +1 -0
  389. praisonai-3.0.0.dist-info/METADATA +3493 -0
  390. praisonai-3.0.0.dist-info/RECORD +393 -0
  391. praisonai-3.0.0.dist-info/WHEEL +5 -0
  392. praisonai-3.0.0.dist-info/entry_points.txt +4 -0
  393. praisonai-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,253 @@
1
+ """
2
+ Pinecone implementation of KnowledgeStore.
3
+
4
+ Requires: pinecone-client
5
+ Install: pip install pinecone-client
6
+ """
7
+
8
+ import logging
9
+ import os
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from .base import KnowledgeStore, KnowledgeDocument
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class PineconeKnowledgeStore(KnowledgeStore):
18
+ """
19
+ Pinecone-based knowledge store for vector search.
20
+
21
+ Cloud-only managed vector database.
22
+
23
+ Example:
24
+ store = PineconeKnowledgeStore(
25
+ api_key="your-api-key",
26
+ index_name="praisonai"
27
+ )
28
+ """
29
+
30
+ def __init__(
31
+ self,
32
+ api_key: Optional[str] = None,
33
+ index_name: Optional[str] = None,
34
+ environment: Optional[str] = None,
35
+ namespace: str = "",
36
+ ):
37
+ try:
38
+ from pinecone import Pinecone
39
+ except ImportError:
40
+ raise ImportError(
41
+ "pinecone-client is required for Pinecone support. "
42
+ "Install with: pip install pinecone-client"
43
+ )
44
+
45
+ api_key = api_key or os.getenv("PINECONE_API_KEY")
46
+ if not api_key:
47
+ raise ValueError("Pinecone API key is required")
48
+
49
+ self._pc = Pinecone(api_key=api_key)
50
+ self._index_name = index_name or os.getenv("PINECONE_INDEX", "praisonai")
51
+ self._namespace = namespace
52
+ self._index = None
53
+
54
+ # Try to connect to existing index
55
+ try:
56
+ self._index = self._pc.Index(self._index_name)
57
+ logger.info(f"Connected to Pinecone index: {self._index_name}")
58
+ except Exception as e:
59
+ logger.warning(f"Index {self._index_name} not found: {e}")
60
+
61
+ def create_collection(
62
+ self,
63
+ name: str,
64
+ dimension: int,
65
+ distance: str = "cosine",
66
+ metadata: Optional[Dict[str, Any]] = None
67
+ ) -> None:
68
+ """Create a new index (Pinecone calls them indexes, not collections)."""
69
+ from pinecone import ServerlessSpec
70
+
71
+ metric_map = {"cosine": "cosine", "euclidean": "euclidean", "dot": "dotproduct"}
72
+
73
+ self._pc.create_index(
74
+ name=name,
75
+ dimension=dimension,
76
+ metric=metric_map.get(distance, "cosine"),
77
+ spec=ServerlessSpec(cloud="aws", region="us-east-1")
78
+ )
79
+ self._index_name = name
80
+ self._index = self._pc.Index(name)
81
+ logger.info(f"Created Pinecone index: {name}")
82
+
83
+ def delete_collection(self, name: str) -> bool:
84
+ """Delete an index."""
85
+ try:
86
+ self._pc.delete_index(name)
87
+ if name == self._index_name:
88
+ self._index = None
89
+ return True
90
+ except Exception as e:
91
+ logger.warning(f"Failed to delete index {name}: {e}")
92
+ return False
93
+
94
+ def collection_exists(self, name: str) -> bool:
95
+ """Check if an index exists."""
96
+ try:
97
+ indexes = self._pc.list_indexes()
98
+ return any(idx.name == name for idx in indexes)
99
+ except Exception:
100
+ return False
101
+
102
+ def list_collections(self) -> List[str]:
103
+ """List all indexes."""
104
+ indexes = self._pc.list_indexes()
105
+ return [idx.name for idx in indexes]
106
+
107
+ def insert(
108
+ self,
109
+ collection: str,
110
+ documents: List[KnowledgeDocument]
111
+ ) -> List[str]:
112
+ """Insert documents."""
113
+ if collection != self._index_name:
114
+ self._index = self._pc.Index(collection)
115
+ self._index_name = collection
116
+
117
+ vectors = []
118
+ ids = []
119
+
120
+ for doc in documents:
121
+ if doc.embedding is None:
122
+ raise ValueError(f"Document {doc.id} has no embedding")
123
+
124
+ vectors.append({
125
+ "id": doc.id,
126
+ "values": doc.embedding,
127
+ "metadata": {
128
+ "content": doc.content,
129
+ "content_hash": doc.content_hash or "",
130
+ "created_at": doc.created_at,
131
+ **(doc.metadata or {})
132
+ }
133
+ })
134
+ ids.append(doc.id)
135
+
136
+ self._index.upsert(vectors=vectors, namespace=self._namespace)
137
+ return ids
138
+
139
+ def upsert(
140
+ self,
141
+ collection: str,
142
+ documents: List[KnowledgeDocument]
143
+ ) -> List[str]:
144
+ """Insert or update documents."""
145
+ return self.insert(collection, documents)
146
+
147
+ def search(
148
+ self,
149
+ collection: str,
150
+ query_embedding: List[float],
151
+ limit: int = 5,
152
+ filters: Optional[Dict[str, Any]] = None,
153
+ score_threshold: Optional[float] = None
154
+ ) -> List[KnowledgeDocument]:
155
+ """Search for similar documents."""
156
+ if collection != self._index_name:
157
+ self._index = self._pc.Index(collection)
158
+ self._index_name = collection
159
+
160
+ results = self._index.query(
161
+ vector=query_embedding,
162
+ top_k=limit,
163
+ filter=filters,
164
+ include_metadata=True,
165
+ namespace=self._namespace,
166
+ )
167
+
168
+ documents = []
169
+ for match in results.matches:
170
+ if score_threshold and match.score < score_threshold:
171
+ continue
172
+
173
+ metadata = match.metadata or {}
174
+ content = metadata.pop("content", "")
175
+ content_hash = metadata.pop("content_hash", None)
176
+ created_at = metadata.pop("created_at", 0)
177
+
178
+ doc = KnowledgeDocument(
179
+ id=match.id,
180
+ content=content,
181
+ embedding=None,
182
+ metadata=metadata,
183
+ content_hash=content_hash,
184
+ created_at=created_at,
185
+ )
186
+ documents.append(doc)
187
+
188
+ return documents
189
+
190
+ def get(
191
+ self,
192
+ collection: str,
193
+ ids: List[str]
194
+ ) -> List[KnowledgeDocument]:
195
+ """Get documents by IDs."""
196
+ if collection != self._index_name:
197
+ self._index = self._pc.Index(collection)
198
+ self._index_name = collection
199
+
200
+ results = self._index.fetch(ids=ids, namespace=self._namespace)
201
+
202
+ documents = []
203
+ for doc_id, vector in results.vectors.items():
204
+ metadata = vector.metadata or {}
205
+ content = metadata.pop("content", "")
206
+ content_hash = metadata.pop("content_hash", None)
207
+ created_at = metadata.pop("created_at", 0)
208
+
209
+ doc = KnowledgeDocument(
210
+ id=doc_id,
211
+ content=content,
212
+ embedding=list(vector.values),
213
+ metadata=metadata,
214
+ content_hash=content_hash,
215
+ created_at=created_at,
216
+ )
217
+ documents.append(doc)
218
+
219
+ return documents
220
+
221
+ def delete(
222
+ self,
223
+ collection: str,
224
+ ids: Optional[List[str]] = None,
225
+ filters: Optional[Dict[str, Any]] = None
226
+ ) -> int:
227
+ """Delete documents."""
228
+ if collection != self._index_name:
229
+ self._index = self._pc.Index(collection)
230
+ self._index_name = collection
231
+
232
+ if ids:
233
+ self._index.delete(ids=ids, namespace=self._namespace)
234
+ return len(ids)
235
+ elif filters:
236
+ self._index.delete(filter=filters, namespace=self._namespace)
237
+ return -1
238
+ return 0
239
+
240
+ def count(self, collection: str) -> int:
241
+ """Count documents."""
242
+ if collection != self._index_name:
243
+ self._index = self._pc.Index(collection)
244
+ self._index_name = collection
245
+
246
+ stats = self._index.describe_index_stats()
247
+ if self._namespace:
248
+ return stats.namespaces.get(self._namespace, {}).get("vector_count", 0)
249
+ return stats.total_vector_count
250
+
251
+ def close(self) -> None:
252
+ """Close the store."""
253
+ self._index = None
@@ -0,0 +1,301 @@
1
+ """
2
+ Qdrant implementation of KnowledgeStore.
3
+
4
+ Requires: qdrant-client
5
+ Install: pip install qdrant-client
6
+ """
7
+
8
+ import logging
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from .base import KnowledgeStore, KnowledgeDocument
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class QdrantKnowledgeStore(KnowledgeStore):
17
+ """
18
+ Qdrant-based knowledge store for vector search.
19
+
20
+ Example:
21
+ store = QdrantKnowledgeStore(
22
+ url="http://localhost:6333"
23
+ )
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ url: Optional[str] = None,
29
+ host: str = "localhost",
30
+ port: int = 6333,
31
+ grpc_port: int = 6334,
32
+ api_key: Optional[str] = None,
33
+ prefer_grpc: bool = False,
34
+ timeout: int = 30,
35
+ ):
36
+ """
37
+ Initialize Qdrant knowledge store.
38
+
39
+ Args:
40
+ url: Full URL (overrides host/port)
41
+ host: Qdrant host
42
+ port: Qdrant HTTP port
43
+ grpc_port: Qdrant gRPC port
44
+ api_key: API key for Qdrant Cloud
45
+ prefer_grpc: Use gRPC instead of HTTP
46
+ timeout: Request timeout in seconds
47
+ """
48
+ try:
49
+ from qdrant_client import QdrantClient
50
+ from qdrant_client.models import (
51
+ Distance, VectorParams, PointStruct,
52
+ Filter, FieldCondition, MatchValue
53
+ )
54
+ except ImportError:
55
+ raise ImportError(
56
+ "qdrant-client is required for Qdrant support. "
57
+ "Install with: pip install qdrant-client"
58
+ )
59
+
60
+ self._QdrantClient = QdrantClient
61
+ self._Distance = Distance
62
+ self._VectorParams = VectorParams
63
+ self._PointStruct = PointStruct
64
+ self._Filter = Filter
65
+ self._FieldCondition = FieldCondition
66
+ self._MatchValue = MatchValue
67
+
68
+ if url:
69
+ self._client = QdrantClient(url=url, api_key=api_key, timeout=timeout)
70
+ else:
71
+ self._client = QdrantClient(
72
+ host=host,
73
+ port=port,
74
+ grpc_port=grpc_port,
75
+ api_key=api_key,
76
+ prefer_grpc=prefer_grpc,
77
+ timeout=timeout,
78
+ )
79
+
80
+ logger.info(f"Connected to Qdrant at {url or f'{host}:{port}'}")
81
+
82
+ def _get_distance(self, distance: str) -> Any:
83
+ """Convert distance string to Qdrant Distance enum."""
84
+ distance_map = {
85
+ "cosine": self._Distance.COSINE,
86
+ "euclidean": self._Distance.EUCLID,
87
+ "dot": self._Distance.DOT,
88
+ "manhattan": self._Distance.MANHATTAN,
89
+ }
90
+ return distance_map.get(distance.lower(), self._Distance.COSINE)
91
+
92
+ def create_collection(
93
+ self,
94
+ name: str,
95
+ dimension: int,
96
+ distance: str = "cosine",
97
+ metadata: Optional[Dict[str, Any]] = None
98
+ ) -> None:
99
+ """Create a new collection."""
100
+ self._client.create_collection(
101
+ collection_name=name,
102
+ vectors_config=self._VectorParams(
103
+ size=dimension,
104
+ distance=self._get_distance(distance)
105
+ )
106
+ )
107
+ logger.info(f"Created Qdrant collection: {name} (dim={dimension}, distance={distance})")
108
+
109
+ def delete_collection(self, name: str) -> bool:
110
+ """Delete a collection."""
111
+ try:
112
+ self._client.delete_collection(collection_name=name)
113
+ logger.info(f"Deleted Qdrant collection: {name}")
114
+ return True
115
+ except Exception as e:
116
+ logger.warning(f"Failed to delete collection {name}: {e}")
117
+ return False
118
+
119
+ def collection_exists(self, name: str) -> bool:
120
+ """Check if a collection exists."""
121
+ try:
122
+ collections = self._client.get_collections()
123
+ return any(c.name == name for c in collections.collections)
124
+ except Exception:
125
+ return False
126
+
127
+ def list_collections(self) -> List[str]:
128
+ """List all collections."""
129
+ collections = self._client.get_collections()
130
+ return [c.name for c in collections.collections]
131
+
132
+ def insert(
133
+ self,
134
+ collection: str,
135
+ documents: List[KnowledgeDocument]
136
+ ) -> List[str]:
137
+ """Insert documents into a collection."""
138
+ points = []
139
+ ids = []
140
+
141
+ for i, doc in enumerate(documents):
142
+ if doc.embedding is None:
143
+ raise ValueError(f"Document {doc.id} has no embedding")
144
+
145
+ point = self._PointStruct(
146
+ id=i, # Qdrant prefers numeric IDs for performance
147
+ vector=doc.embedding,
148
+ payload={
149
+ "doc_id": doc.id,
150
+ "content": doc.content,
151
+ "content_hash": doc.content_hash,
152
+ "created_at": doc.created_at,
153
+ **(doc.metadata or {})
154
+ }
155
+ )
156
+ points.append(point)
157
+ ids.append(doc.id)
158
+
159
+ self._client.upsert(collection_name=collection, points=points)
160
+ logger.debug(f"Inserted {len(documents)} documents into {collection}")
161
+ return ids
162
+
163
+ def upsert(
164
+ self,
165
+ collection: str,
166
+ documents: List[KnowledgeDocument]
167
+ ) -> List[str]:
168
+ """Insert or update documents."""
169
+ return self.insert(collection, documents)
170
+
171
+ def search(
172
+ self,
173
+ collection: str,
174
+ query_embedding: List[float],
175
+ limit: int = 5,
176
+ filters: Optional[Dict[str, Any]] = None,
177
+ score_threshold: Optional[float] = None
178
+ ) -> List[KnowledgeDocument]:
179
+ """Search for similar documents."""
180
+ search_filter = None
181
+ if filters:
182
+ conditions = [
183
+ self._FieldCondition(
184
+ key=k,
185
+ match=self._MatchValue(value=v)
186
+ )
187
+ for k, v in filters.items()
188
+ ]
189
+ search_filter = self._Filter(must=conditions)
190
+
191
+ results = self._client.query_points(
192
+ collection_name=collection,
193
+ query=query_embedding,
194
+ limit=limit,
195
+ query_filter=search_filter,
196
+ score_threshold=score_threshold,
197
+ )
198
+
199
+ documents = []
200
+ for point in results.points:
201
+ payload = point.payload or {}
202
+ doc = KnowledgeDocument(
203
+ id=payload.get("doc_id", str(point.id)),
204
+ content=payload.get("content", ""),
205
+ embedding=None, # Don't return embeddings by default
206
+ metadata={
207
+ k: v for k, v in payload.items()
208
+ if k not in ("doc_id", "content", "content_hash", "created_at")
209
+ },
210
+ content_hash=payload.get("content_hash"),
211
+ created_at=payload.get("created_at", 0),
212
+ )
213
+ documents.append(doc)
214
+
215
+ return documents
216
+
217
+ def get(
218
+ self,
219
+ collection: str,
220
+ ids: List[str]
221
+ ) -> List[KnowledgeDocument]:
222
+ """Get documents by IDs."""
223
+ # Qdrant uses numeric IDs internally, so we search by doc_id in payload
224
+ documents = []
225
+ for doc_id in ids:
226
+ results = self._client.scroll(
227
+ collection_name=collection,
228
+ scroll_filter=self._Filter(
229
+ must=[
230
+ self._FieldCondition(
231
+ key="doc_id",
232
+ match=self._MatchValue(value=doc_id)
233
+ )
234
+ ]
235
+ ),
236
+ limit=1,
237
+ )
238
+ for point in results[0]:
239
+ payload = point.payload or {}
240
+ doc = KnowledgeDocument(
241
+ id=payload.get("doc_id", str(point.id)),
242
+ content=payload.get("content", ""),
243
+ embedding=list(point.vector) if point.vector else None,
244
+ metadata={
245
+ k: v for k, v in payload.items()
246
+ if k not in ("doc_id", "content", "content_hash", "created_at")
247
+ },
248
+ content_hash=payload.get("content_hash"),
249
+ created_at=payload.get("created_at", 0),
250
+ )
251
+ documents.append(doc)
252
+
253
+ return documents
254
+
255
+ def delete(
256
+ self,
257
+ collection: str,
258
+ ids: Optional[List[str]] = None,
259
+ filters: Optional[Dict[str, Any]] = None
260
+ ) -> int:
261
+ """Delete documents by IDs or filters."""
262
+ if ids:
263
+ # Delete by doc_id in payload
264
+ for doc_id in ids:
265
+ self._client.delete(
266
+ collection_name=collection,
267
+ points_selector=self._Filter(
268
+ must=[
269
+ self._FieldCondition(
270
+ key="doc_id",
271
+ match=self._MatchValue(value=doc_id)
272
+ )
273
+ ]
274
+ )
275
+ )
276
+ return len(ids)
277
+ elif filters:
278
+ conditions = [
279
+ self._FieldCondition(
280
+ key=k,
281
+ match=self._MatchValue(value=v)
282
+ )
283
+ for k, v in filters.items()
284
+ ]
285
+ self._client.delete(
286
+ collection_name=collection,
287
+ points_selector=self._Filter(must=conditions)
288
+ )
289
+ return -1 # Unknown count
290
+ return 0
291
+
292
+ def count(self, collection: str) -> int:
293
+ """Count documents in a collection."""
294
+ info = self._client.get_collection(collection_name=collection)
295
+ return info.points_count or 0
296
+
297
+ def close(self) -> None:
298
+ """Close the store."""
299
+ if self._client:
300
+ self._client.close()
301
+ self._client = None