MindsDB 25.4.5.0__py3-none-any.whl → 25.5.4.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.

Potentially problematic release.


This version of MindsDB might be problematic. Click here for more details.

Files changed (350) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +215 -185
  3. mindsdb/api/a2a/__init__.py +0 -0
  4. mindsdb/api/a2a/__main__.py +114 -0
  5. mindsdb/api/a2a/a2a_client.py +439 -0
  6. mindsdb/api/a2a/agent.py +308 -0
  7. mindsdb/api/a2a/common/__init__.py +0 -0
  8. mindsdb/api/a2a/common/client/__init__.py +4 -0
  9. mindsdb/api/a2a/common/client/card_resolver.py +21 -0
  10. mindsdb/api/a2a/common/client/client.py +86 -0
  11. mindsdb/api/a2a/common/server/__init__.py +4 -0
  12. mindsdb/api/a2a/common/server/server.py +164 -0
  13. mindsdb/api/a2a/common/server/task_manager.py +287 -0
  14. mindsdb/api/a2a/common/server/utils.py +28 -0
  15. mindsdb/api/a2a/common/types.py +365 -0
  16. mindsdb/api/a2a/constants.py +9 -0
  17. mindsdb/api/a2a/run_a2a.py +129 -0
  18. mindsdb/api/a2a/task_manager.py +594 -0
  19. mindsdb/api/executor/command_executor.py +49 -28
  20. mindsdb/api/executor/datahub/classes/response.py +5 -2
  21. mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +8 -0
  22. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +39 -72
  23. mindsdb/api/executor/datahub/datanodes/system_tables.py +10 -13
  24. mindsdb/api/executor/planner/query_planner.py +14 -2
  25. mindsdb/api/executor/sql_query/result_set.py +185 -52
  26. mindsdb/api/executor/sql_query/sql_query.py +1 -1
  27. mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +11 -13
  28. mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +8 -10
  29. mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +5 -44
  30. mindsdb/api/executor/sql_query/steps/insert_step.py +24 -15
  31. mindsdb/api/executor/sql_query/steps/join_step.py +1 -1
  32. mindsdb/api/executor/sql_query/steps/project_step.py +1 -1
  33. mindsdb/api/executor/sql_query/steps/sql_steps.py +1 -1
  34. mindsdb/api/executor/sql_query/steps/subselect_step.py +4 -8
  35. mindsdb/api/executor/sql_query/steps/union_step.py +1 -3
  36. mindsdb/api/http/initialize.py +118 -85
  37. mindsdb/api/http/namespaces/analysis.py +17 -4
  38. mindsdb/api/http/namespaces/file.py +8 -2
  39. mindsdb/api/http/namespaces/sql.py +13 -27
  40. mindsdb/api/http/namespaces/tree.py +1 -1
  41. mindsdb/api/http/start.py +7 -2
  42. mindsdb/api/mcp/start.py +42 -5
  43. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packet.py +0 -1
  44. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/binary_resultset_row_package.py +52 -19
  45. mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +8 -10
  46. mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +54 -38
  47. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +86 -123
  48. mindsdb/api/mysql/mysql_proxy/utilities/dump.py +351 -0
  49. mindsdb/api/mysql/mysql_proxy/utilities/exceptions.py +0 -4
  50. mindsdb/api/postgres/postgres_proxy/executor/executor.py +1 -1
  51. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_formats.py +2 -2
  52. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +5 -6
  53. mindsdb/integrations/handlers/altibase_handler/altibase_handler.py +26 -27
  54. mindsdb/integrations/handlers/altibase_handler/connection_args.py +13 -13
  55. mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler.py +8 -8
  56. mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler_dsn.py +13 -13
  57. mindsdb/integrations/handlers/anthropic_handler/__init__.py +2 -2
  58. mindsdb/integrations/handlers/anthropic_handler/anthropic_handler.py +1 -3
  59. mindsdb/integrations/handlers/aurora_handler/aurora_handler.py +1 -0
  60. mindsdb/integrations/handlers/autosklearn_handler/autosklearn_handler.py +1 -1
  61. mindsdb/integrations/handlers/autosklearn_handler/config.py +0 -1
  62. mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +1 -1
  63. mindsdb/integrations/handlers/bigquery_handler/requirements.txt +1 -0
  64. mindsdb/integrations/handlers/bigquery_handler/tests/test_bigquery_handler.py +1 -1
  65. mindsdb/integrations/handlers/binance_handler/binance_handler.py +1 -0
  66. mindsdb/integrations/handlers/binance_handler/binance_tables.py +3 -4
  67. mindsdb/integrations/handlers/byom_handler/__init__.py +0 -1
  68. mindsdb/integrations/handlers/chromadb_handler/requirements.txt +1 -0
  69. mindsdb/integrations/handlers/ckan_handler/ckan_handler.py +3 -0
  70. mindsdb/integrations/handlers/clickhouse_handler/__init__.py +1 -1
  71. mindsdb/integrations/handlers/cloud_spanner_handler/tests/test_cloud_spanner_handler.py +0 -2
  72. mindsdb/integrations/handlers/cloud_sql_handler/cloud_sql_handler.py +0 -1
  73. mindsdb/integrations/handlers/cohere_handler/__init__.py +1 -1
  74. mindsdb/integrations/handlers/cohere_handler/cohere_handler.py +11 -13
  75. mindsdb/integrations/handlers/confluence_handler/confluence_tables.py +6 -0
  76. mindsdb/integrations/handlers/databend_handler/connection_args.py +1 -1
  77. mindsdb/integrations/handlers/databend_handler/databend_handler.py +4 -4
  78. mindsdb/integrations/handlers/databend_handler/tests/__init__.py +0 -1
  79. mindsdb/integrations/handlers/databend_handler/tests/test_databend_handler.py +1 -1
  80. mindsdb/integrations/handlers/derby_handler/connection_args.py +1 -1
  81. mindsdb/integrations/handlers/derby_handler/derby_handler.py +14 -22
  82. mindsdb/integrations/handlers/derby_handler/tests/test_derby_handler.py +6 -6
  83. mindsdb/integrations/handlers/discord_handler/discord_handler.py +5 -5
  84. mindsdb/integrations/handlers/discord_handler/discord_tables.py +3 -3
  85. mindsdb/integrations/handlers/discord_handler/tests/test_discord.py +5 -3
  86. mindsdb/integrations/handlers/dockerhub_handler/dockerhub.py +3 -3
  87. mindsdb/integrations/handlers/dockerhub_handler/dockerhub_handler.py +2 -2
  88. mindsdb/integrations/handlers/dockerhub_handler/dockerhub_tables.py +57 -54
  89. mindsdb/integrations/handlers/dremio_handler/__init__.py +2 -2
  90. mindsdb/integrations/handlers/druid_handler/__init__.py +1 -1
  91. mindsdb/integrations/handlers/druid_handler/druid_handler.py +2 -2
  92. mindsdb/integrations/handlers/edgelessdb_handler/tests/test_edgelessdb_handler.py +9 -9
  93. mindsdb/integrations/handlers/email_handler/email_client.py +1 -1
  94. mindsdb/integrations/handlers/email_handler/email_ingestor.py +1 -1
  95. mindsdb/integrations/handlers/email_handler/email_tables.py +0 -1
  96. mindsdb/integrations/handlers/email_handler/settings.py +0 -1
  97. mindsdb/integrations/handlers/eventstoredb_handler/eventstoredb_handler.py +2 -1
  98. mindsdb/integrations/handlers/firebird_handler/firebird_handler.py +1 -1
  99. mindsdb/integrations/handlers/flaml_handler/flaml_handler.py +9 -9
  100. mindsdb/integrations/handlers/frappe_handler/frappe_client.py +5 -5
  101. mindsdb/integrations/handlers/frappe_handler/frappe_handler.py +6 -5
  102. mindsdb/integrations/handlers/frappe_handler/frappe_tables.py +2 -2
  103. mindsdb/integrations/handlers/github_handler/connection_args.py +2 -2
  104. mindsdb/integrations/handlers/github_handler/github_handler.py +1 -8
  105. mindsdb/integrations/handlers/github_handler/github_tables.py +13 -24
  106. mindsdb/integrations/handlers/gitlab_handler/gitlab_handler.py +2 -1
  107. mindsdb/integrations/handlers/gitlab_handler/gitlab_tables.py +1 -4
  108. mindsdb/integrations/handlers/gmail_handler/gmail_handler.py +6 -13
  109. mindsdb/integrations/handlers/gmail_handler/requirements.txt +1 -0
  110. mindsdb/integrations/handlers/google_analytics_handler/requirements.txt +2 -1
  111. mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +2 -1
  112. mindsdb/integrations/handlers/google_books_handler/google_books_tables.py +0 -3
  113. mindsdb/integrations/handlers/google_books_handler/requirements.txt +1 -1
  114. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +4 -4
  115. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_tables.py +2 -6
  116. mindsdb/integrations/handlers/google_calendar_handler/requirements.txt +1 -0
  117. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +3 -2
  118. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_tables.py +0 -3
  119. mindsdb/integrations/handlers/google_content_shopping_handler/requirements.txt +1 -1
  120. mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +10 -12
  121. mindsdb/integrations/handlers/google_fit_handler/google_fit_tables.py +11 -13
  122. mindsdb/integrations/handlers/google_fit_handler/requirements.txt +2 -0
  123. mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +2 -1
  124. mindsdb/integrations/handlers/google_search_handler/google_search_tables.py +0 -3
  125. mindsdb/integrations/handlers/google_search_handler/requirements.txt +1 -1
  126. mindsdb/integrations/handlers/groq_handler/__init__.py +3 -3
  127. mindsdb/integrations/handlers/hackernews_handler/hn_handler.py +5 -7
  128. mindsdb/integrations/handlers/hackernews_handler/hn_table.py +6 -7
  129. mindsdb/integrations/handlers/hive_handler/tests/test_hive_handler.py +1 -1
  130. mindsdb/integrations/handlers/hsqldb_handler/connection_args.py +6 -6
  131. mindsdb/integrations/handlers/hsqldb_handler/hsqldb_handler.py +4 -3
  132. mindsdb/integrations/handlers/huggingface_api_handler/exceptions.py +1 -1
  133. mindsdb/integrations/handlers/huggingface_api_handler/huggingface_api_handler.py +1 -8
  134. mindsdb/integrations/handlers/huggingface_handler/huggingface_handler.py +6 -6
  135. mindsdb/integrations/handlers/huggingface_handler/requirements.txt +1 -1
  136. mindsdb/integrations/handlers/huggingface_handler/requirements_cpu.txt +1 -1
  137. mindsdb/integrations/handlers/ignite_handler/ignite_handler.py +2 -1
  138. mindsdb/integrations/handlers/impala_handler/impala_handler.py +9 -12
  139. mindsdb/integrations/handlers/impala_handler/tests/test_impala_handler.py +11 -11
  140. mindsdb/integrations/handlers/influxdb_handler/influxdb_handler.py +10 -13
  141. mindsdb/integrations/handlers/influxdb_handler/influxdb_tables.py +20 -20
  142. mindsdb/integrations/handlers/informix_handler/__about__.py +8 -8
  143. mindsdb/integrations/handlers/informix_handler/__init__.py +12 -5
  144. mindsdb/integrations/handlers/informix_handler/informix_handler.py +99 -133
  145. mindsdb/integrations/handlers/informix_handler/tests/test_informix_handler.py +13 -11
  146. mindsdb/integrations/handlers/ingres_handler/__about__.py +0 -1
  147. mindsdb/integrations/handlers/ingres_handler/ingres_handler.py +1 -0
  148. mindsdb/integrations/handlers/jira_handler/jira_handler.archived.py +75 -0
  149. mindsdb/integrations/handlers/jira_handler/jira_handler.py +113 -38
  150. mindsdb/integrations/handlers/jira_handler/jira_tables.py +229 -0
  151. mindsdb/integrations/handlers/jira_handler/requirements.txt +1 -0
  152. mindsdb/integrations/handlers/kinetica_handler/__init__.py +0 -1
  153. mindsdb/integrations/handlers/langchain_handler/langchain_handler.py +4 -4
  154. mindsdb/integrations/handlers/langchain_handler/tools.py +9 -10
  155. mindsdb/integrations/handlers/leonardoai_handler/__init__.py +1 -1
  156. mindsdb/integrations/handlers/lightfm_handler/requirements.txt +1 -0
  157. mindsdb/integrations/handlers/lightwood_handler/functions.py +2 -2
  158. mindsdb/integrations/handlers/lightwood_handler/lightwood_handler.py +0 -3
  159. mindsdb/integrations/handlers/lightwood_handler/requirements.txt +4 -4
  160. mindsdb/integrations/handlers/lightwood_handler/tests/test_lightwood_handler.py +11 -11
  161. mindsdb/integrations/handlers/lindorm_handler/requirements.txt +1 -0
  162. mindsdb/integrations/handlers/llama_index_handler/llama_index_handler.py +4 -4
  163. mindsdb/integrations/handlers/llama_index_handler/settings.py +10 -9
  164. mindsdb/integrations/handlers/materialize_handler/tests/test_materialize_handler.py +8 -10
  165. mindsdb/integrations/handlers/matrixone_handler/matrixone_handler.py +4 -4
  166. mindsdb/integrations/handlers/matrixone_handler/tests/test_matrixone_handler.py +8 -9
  167. mindsdb/integrations/handlers/maxdb_handler/connection_args.py +25 -25
  168. mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +1 -0
  169. mindsdb/integrations/handlers/mediawiki_handler/mediawiki_handler.py +3 -2
  170. mindsdb/integrations/handlers/mediawiki_handler/mediawiki_tables.py +1 -1
  171. mindsdb/integrations/handlers/mendeley_handler/__about__.py +1 -1
  172. mindsdb/integrations/handlers/mendeley_handler/__init__.py +2 -2
  173. mindsdb/integrations/handlers/mendeley_handler/mendeley_handler.py +48 -56
  174. mindsdb/integrations/handlers/mendeley_handler/mendeley_tables.py +24 -29
  175. mindsdb/integrations/handlers/mendeley_handler/tests/test_mendeley_handler.py +19 -17
  176. mindsdb/integrations/handlers/merlion_handler/merlion_handler.py +5 -4
  177. mindsdb/integrations/handlers/minds_endpoint_handler/__init__.py +3 -3
  178. mindsdb/integrations/handlers/mlflow_handler/mlflow_handler.py +58 -36
  179. mindsdb/integrations/handlers/monetdb_handler/__about__.py +8 -8
  180. mindsdb/integrations/handlers/monetdb_handler/__init__.py +15 -5
  181. mindsdb/integrations/handlers/monetdb_handler/connection_args.py +17 -18
  182. mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +40 -57
  183. mindsdb/integrations/handlers/monetdb_handler/tests/test_monetdb_handler.py +7 -8
  184. mindsdb/integrations/handlers/monetdb_handler/utils/monet_get_id.py +13 -14
  185. mindsdb/integrations/handlers/monkeylearn_handler/__about__.py +1 -1
  186. mindsdb/integrations/handlers/monkeylearn_handler/__init__.py +1 -1
  187. mindsdb/integrations/handlers/monkeylearn_handler/monkeylearn_handler.py +2 -5
  188. mindsdb/integrations/handlers/ms_one_drive_handler/ms_graph_api_one_drive_client.py +1 -0
  189. mindsdb/integrations/handlers/ms_one_drive_handler/ms_one_drive_handler.py +1 -1
  190. mindsdb/integrations/handlers/ms_one_drive_handler/requirements.txt +2 -0
  191. mindsdb/integrations/handlers/ms_teams_handler/ms_graph_api_teams_client.py +23 -23
  192. mindsdb/integrations/handlers/ms_teams_handler/ms_teams_handler.py +3 -3
  193. mindsdb/integrations/handlers/ms_teams_handler/ms_teams_tables.py +10 -5
  194. mindsdb/integrations/handlers/ms_teams_handler/requirements.txt +3 -1
  195. mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +73 -8
  196. mindsdb/integrations/handlers/mysql_handler/__about__.py +8 -8
  197. mindsdb/integrations/handlers/mysql_handler/__init__.py +15 -5
  198. mindsdb/integrations/handlers/mysql_handler/connection_args.py +43 -47
  199. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +101 -34
  200. mindsdb/integrations/handlers/mysql_handler/settings.py +15 -13
  201. mindsdb/integrations/handlers/neuralforecast_handler/neuralforecast_handler.py +1 -1
  202. mindsdb/integrations/handlers/newsapi_handler/newsapi_handler.py +1 -1
  203. mindsdb/integrations/handlers/newsapi_handler/tests/test_newsapi_handler.py +4 -4
  204. mindsdb/integrations/handlers/nuo_jdbc_handler/connection_args.py +2 -2
  205. mindsdb/integrations/handlers/nuo_jdbc_handler/nuo_jdbc_handler.py +28 -36
  206. mindsdb/integrations/handlers/nuo_jdbc_handler/tests/test_nuo_handler.py +5 -5
  207. mindsdb/integrations/handlers/oceanbase_handler/oceanbase_handler.py +0 -1
  208. mindsdb/integrations/handlers/oceanbase_handler/tests/test_oceanbase_handler.py +8 -10
  209. mindsdb/integrations/handlers/ollama_handler/ollama_handler.py +3 -3
  210. mindsdb/integrations/handlers/openai_handler/openai_handler.py +5 -4
  211. mindsdb/integrations/handlers/opengauss_handler/tests/test_opengauss_handler.py +1 -2
  212. mindsdb/integrations/handlers/openstreetmap_handler/__init__.py +7 -7
  213. mindsdb/integrations/handlers/oracle_handler/connection_args.py +6 -0
  214. mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +77 -11
  215. mindsdb/integrations/handlers/orioledb_handler/tests/test_orioledb_handler.py +8 -10
  216. mindsdb/integrations/handlers/palm_handler/__about__.py +1 -1
  217. mindsdb/integrations/handlers/palm_handler/__init__.py +1 -1
  218. mindsdb/integrations/handlers/palm_handler/palm_handler.py +1 -3
  219. mindsdb/integrations/handlers/paypal_handler/paypal_handler.py +2 -2
  220. mindsdb/integrations/handlers/paypal_handler/paypal_tables.py +15 -14
  221. mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +53 -10
  222. mindsdb/integrations/handlers/phoenix_handler/__init__.py +1 -1
  223. mindsdb/integrations/handlers/phoenix_handler/phoenix_handler.py +1 -0
  224. mindsdb/integrations/handlers/pinot_handler/__init__.py +1 -1
  225. mindsdb/integrations/handlers/pinot_handler/pinot_handler.py +3 -2
  226. mindsdb/integrations/handlers/plaid_handler/plaid_handler.py +13 -13
  227. mindsdb/integrations/handlers/plaid_handler/plaid_tables.py +10 -12
  228. mindsdb/integrations/handlers/plaid_handler/utils.py +4 -6
  229. mindsdb/integrations/handlers/planetscale_handler/planetscale_handler.py +1 -4
  230. mindsdb/integrations/handlers/portkey_handler/__init__.py +2 -2
  231. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +105 -24
  232. mindsdb/integrations/handlers/postgres_handler/tests/test_postgres_handler.py +11 -6
  233. mindsdb/integrations/handlers/questdb_handler/questdb_handler.py +1 -2
  234. mindsdb/integrations/handlers/questdb_handler/tests/test_questdb_handler.py +2 -3
  235. mindsdb/integrations/handlers/quickbooks_handler/quickbooks_handler.py +6 -8
  236. mindsdb/integrations/handlers/quickbooks_handler/quickbooks_table.py +10 -10
  237. mindsdb/integrations/handlers/rag_handler/ingest.py +2 -2
  238. mindsdb/integrations/handlers/rag_handler/rag_handler.py +1 -1
  239. mindsdb/integrations/handlers/rag_handler/settings.py +1 -1
  240. mindsdb/integrations/handlers/reddit_handler/reddit_handler.py +2 -7
  241. mindsdb/integrations/handlers/reddit_handler/reddit_tables.py +2 -3
  242. mindsdb/integrations/handlers/replicate_handler/replicate_handler.py +6 -6
  243. mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_handler.py +1 -2
  244. mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_tables.py +0 -3
  245. mindsdb/integrations/handlers/rockset_handler/connection_args.py +14 -14
  246. mindsdb/integrations/handlers/rockset_handler/tests/test_rockset_handler.py +1 -0
  247. mindsdb/integrations/handlers/scylla_handler/scylla_handler.py +6 -5
  248. mindsdb/integrations/handlers/sendinblue_handler/sendinblue_handler.py +2 -1
  249. mindsdb/integrations/handlers/sendinblue_handler/sendinblue_tables.py +16 -16
  250. mindsdb/integrations/handlers/sentence_transformers_handler/__init__.py +1 -1
  251. mindsdb/integrations/handlers/sheets_handler/connection_args.py +1 -1
  252. mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +7 -6
  253. mindsdb/integrations/handlers/shopify_handler/shopify_tables.py +38 -41
  254. mindsdb/integrations/handlers/singlestore_handler/__about__.py +1 -1
  255. mindsdb/integrations/handlers/singlestore_handler/__init__.py +0 -1
  256. mindsdb/integrations/handlers/singlestore_handler/singlestore_handler.py +1 -0
  257. mindsdb/integrations/handlers/singlestore_handler/tests/test_singlestore_handler.py +3 -3
  258. mindsdb/integrations/handlers/slack_handler/__init__.py +3 -3
  259. mindsdb/integrations/handlers/snowflake_handler/requirements.txt +1 -1
  260. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +100 -6
  261. mindsdb/integrations/handlers/solr_handler/connection_args.py +7 -7
  262. mindsdb/integrations/handlers/solr_handler/solr_handler.py +2 -1
  263. mindsdb/integrations/handlers/solr_handler/tests/test_solr_handler.py +2 -1
  264. mindsdb/integrations/handlers/sqlany_handler/sqlany_handler.py +3 -2
  265. mindsdb/integrations/handlers/sqlite_handler/sqlite_handler.py +1 -0
  266. mindsdb/integrations/handlers/sqreamdb_handler/connection_args.py +1 -1
  267. mindsdb/integrations/handlers/sqreamdb_handler/sqreamdb_handler.py +15 -20
  268. mindsdb/integrations/handlers/sqreamdb_handler/tests/test_sqreamdb_handler.py +4 -4
  269. mindsdb/integrations/handlers/stabilityai_handler/__init__.py +1 -1
  270. mindsdb/integrations/handlers/starrocks_handler/starrocks_handler.py +0 -1
  271. mindsdb/integrations/handlers/starrocks_handler/tests/test_starrocks_handler.py +8 -10
  272. mindsdb/integrations/handlers/statsforecast_handler/statsforecast_handler.py +2 -2
  273. mindsdb/integrations/handlers/strava_handler/strava_handler.py +4 -8
  274. mindsdb/integrations/handlers/strava_handler/strava_tables.py +22 -30
  275. mindsdb/integrations/handlers/stripe_handler/stripe_handler.py +3 -2
  276. mindsdb/integrations/handlers/stripe_handler/stripe_tables.py +11 -27
  277. mindsdb/integrations/handlers/supabase_handler/tests/test_supabase_handler.py +1 -1
  278. mindsdb/integrations/handlers/surrealdb_handler/surrealdb_handler.py +4 -4
  279. mindsdb/integrations/handlers/tdengine_handler/tdengine_handler.py +25 -27
  280. mindsdb/integrations/handlers/tdengine_handler/tests/test_tdengine_handler.py +8 -8
  281. mindsdb/integrations/handlers/tidb_handler/tests/test_tidb_handler.py +1 -2
  282. mindsdb/integrations/handlers/timegpt_handler/timegpt_handler.py +5 -5
  283. mindsdb/integrations/handlers/tpot_handler/tpot_handler.py +21 -26
  284. mindsdb/integrations/handlers/trino_handler/trino_handler.py +14 -14
  285. mindsdb/integrations/handlers/twitter_handler/twitter_handler.py +2 -4
  286. mindsdb/integrations/handlers/unify_handler/tests/test_unify_handler.py +7 -8
  287. mindsdb/integrations/handlers/unify_handler/unify_handler.py +9 -9
  288. mindsdb/integrations/handlers/vertex_handler/requirements.txt +1 -0
  289. mindsdb/integrations/handlers/vertex_handler/vertex_client.py +1 -1
  290. mindsdb/integrations/handlers/vertica_handler/tests/test_vertica_handler.py +11 -11
  291. mindsdb/integrations/handlers/vertica_handler/vertica_handler.py +11 -14
  292. mindsdb/integrations/handlers/vitess_handler/tests/test_vitess_handler.py +9 -11
  293. mindsdb/integrations/handlers/vitess_handler/vitess_handler.py +0 -1
  294. mindsdb/integrations/handlers/web_handler/web_handler.py +1 -0
  295. mindsdb/integrations/handlers/whatsapp_handler/__init__.py +3 -3
  296. mindsdb/integrations/handlers/writer_handler/evaluate.py +1 -1
  297. mindsdb/integrations/handlers/writer_handler/settings.py +0 -1
  298. mindsdb/integrations/handlers/writer_handler/writer_handler.py +1 -0
  299. mindsdb/integrations/handlers/youtube_handler/requirements.txt +1 -0
  300. mindsdb/integrations/handlers/youtube_handler/youtube_handler.py +5 -5
  301. mindsdb/integrations/handlers/youtube_handler/youtube_tables.py +26 -27
  302. mindsdb/integrations/handlers/yugabyte_handler/tests/test_yugabyte_handler.py +3 -3
  303. mindsdb/integrations/handlers/yugabyte_handler/yugabyte_handler.py +0 -6
  304. mindsdb/integrations/libs/response.py +67 -52
  305. mindsdb/integrations/libs/vectordatabase_handler.py +6 -0
  306. mindsdb/integrations/utilities/files/file_reader.py +5 -2
  307. mindsdb/integrations/utilities/handler_utils.py +15 -3
  308. mindsdb/integrations/utilities/handlers/api_utilities/__init__.py +0 -1
  309. mindsdb/integrations/utilities/handlers/auth_utilities/__init__.py +0 -2
  310. mindsdb/integrations/utilities/utils.py +3 -3
  311. mindsdb/interfaces/agents/agents_controller.py +164 -1
  312. mindsdb/interfaces/agents/constants.py +29 -2
  313. mindsdb/interfaces/agents/langchain_agent.py +18 -8
  314. mindsdb/interfaces/agents/mindsdb_database_agent.py +101 -2
  315. mindsdb/interfaces/database/projects.py +1 -7
  316. mindsdb/interfaces/functions/controller.py +11 -14
  317. mindsdb/interfaces/functions/to_markdown.py +9 -124
  318. mindsdb/interfaces/knowledge_base/controller.py +47 -19
  319. mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +41 -15
  320. mindsdb/interfaces/knowledge_base/preprocessing/json_chunker.py +434 -0
  321. mindsdb/interfaces/knowledge_base/preprocessing/models.py +54 -0
  322. mindsdb/interfaces/knowledge_base/utils.py +10 -15
  323. mindsdb/interfaces/model/model_controller.py +0 -2
  324. mindsdb/interfaces/query_context/context_controller.py +66 -10
  325. mindsdb/interfaces/skills/custom/text2sql/mindsdb_kb_tools.py +190 -0
  326. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +92 -0
  327. mindsdb/interfaces/skills/skill_tool.py +202 -57
  328. mindsdb/interfaces/skills/sql_agent.py +238 -28
  329. mindsdb/interfaces/storage/fs.py +1 -0
  330. mindsdb/interfaces/variables/__init__.py +0 -0
  331. mindsdb/interfaces/variables/variables_controller.py +97 -0
  332. mindsdb/migrations/env.py +5 -7
  333. mindsdb/migrations/migrate.py +47 -9
  334. mindsdb/migrations/versions/2025-05-21_9f150e4f9a05_checkpoint_1.py +360 -0
  335. mindsdb/utilities/config.py +333 -220
  336. mindsdb/utilities/context.py +1 -1
  337. mindsdb/utilities/functions.py +0 -36
  338. mindsdb/utilities/langfuse.py +19 -10
  339. mindsdb/utilities/otel/__init__.py +9 -193
  340. mindsdb/utilities/otel/metric_handlers/__init__.py +5 -1
  341. mindsdb/utilities/otel/prepare.py +198 -0
  342. mindsdb/utilities/sql.py +83 -0
  343. mindsdb/utilities/starters.py +13 -0
  344. {mindsdb-25.4.5.0.dist-info → mindsdb-25.5.4.0.dist-info}/METADATA +351 -338
  345. {mindsdb-25.4.5.0.dist-info → mindsdb-25.5.4.0.dist-info}/RECORD +348 -322
  346. {mindsdb-25.4.5.0.dist-info → mindsdb-25.5.4.0.dist-info}/WHEEL +1 -1
  347. mindsdb/api/mysql/mysql_proxy/classes/sql_statement_parser.py +0 -151
  348. mindsdb/integrations/handlers/monkeylearn_handler/requirements.txt +0 -1
  349. {mindsdb-25.4.5.0.dist-info → mindsdb-25.5.4.0.dist-info}/licenses/LICENSE +0 -0
  350. {mindsdb-25.4.5.0.dist-info → mindsdb-25.5.4.0.dist-info}/top_level.txt +0 -0
@@ -19,9 +19,10 @@ from mindsdb.utilities.exception import EntityExistsError, EntityNotExistsError
19
19
  from .constants import ASSISTANT_COLUMN, SUPPORTED_PROVIDERS, PROVIDER_TO_MODELS
20
20
  from .langchain_agent import get_llm_provider
21
21
 
22
-
23
22
  default_project = config.get('default_project')
24
23
 
24
+ DEFAULT_TEXT2SQL_DATABASE = 'mindsdb'
25
+
25
26
 
26
27
  class AgentsController:
27
28
  '''Handles CRUD operations at the database level for Agents'''
@@ -158,6 +159,13 @@ class AgentsController:
158
159
  with one of keys is "name", and other is additional parameters for relationship agent<>skill
159
160
  provider (str): The provider of the model
160
161
  params (Dict[str, str]): Parameters to use when running the agent
162
+ database: The database to use for text2sql skills (default is 'mindsdb')
163
+ knowledge_base_database: The database to use for knowledge base queries (default is 'mindsdb')
164
+ include_tables: List of tables to include for text2sql skills
165
+ ignore_tables: List of tables to ignore for text2sql skills
166
+ include_knowledge_bases: List of knowledge bases to include for text2sql skills
167
+ ignore_knowledge_bases: List of knowledge bases to ignore for text2sql skills
168
+ <provider>_api_key: API key for the provider (e.g., openai_api_key)
161
169
 
162
170
  Returns:
163
171
  agent (db.Agents): The created agent
@@ -176,6 +184,128 @@ class AgentsController:
176
184
 
177
185
  _, provider = self.check_model_provider(model_name, provider)
178
186
 
187
+ # Extract API key if provided in the format <provider>_api_key
188
+ provider_api_key_param = f"{provider.lower()}_api_key"
189
+ if provider_api_key_param in params:
190
+ # Keep the API key in params for the agent to use
191
+ # It will be picked up by get_api_key() in handler_utils.py
192
+ pass
193
+
194
+ # Extract table and knowledge base parameters from params
195
+ database = params.pop('database', None)
196
+ knowledge_base_database = params.pop('knowledge_base_database', DEFAULT_TEXT2SQL_DATABASE)
197
+ include_tables = params.pop('include_tables', None)
198
+ ignore_tables = params.pop('ignore_tables', None)
199
+ include_knowledge_bases = params.pop('include_knowledge_bases', None)
200
+ ignore_knowledge_bases = params.pop('ignore_knowledge_bases', None)
201
+
202
+ # Save the extracted parameters back to params for API responses only if they were explicitly provided
203
+ # or if they're needed for skills
204
+ need_params = include_tables or ignore_tables or include_knowledge_bases or ignore_knowledge_bases
205
+
206
+ if 'database' in params or need_params:
207
+ params['database'] = database
208
+
209
+ if 'knowledge_base_database' in params or include_knowledge_bases or ignore_knowledge_bases:
210
+ params['knowledge_base_database'] = knowledge_base_database
211
+
212
+ if include_tables is not None:
213
+ params['include_tables'] = include_tables
214
+ if ignore_tables is not None:
215
+ params['ignore_tables'] = ignore_tables
216
+ if include_knowledge_bases is not None:
217
+ params['include_knowledge_bases'] = include_knowledge_bases
218
+ if ignore_knowledge_bases is not None:
219
+ params['ignore_knowledge_bases'] = ignore_knowledge_bases
220
+
221
+ # Convert string parameters to lists if needed
222
+ if isinstance(include_tables, str):
223
+ include_tables = [t.strip() for t in include_tables.split(',')]
224
+ if isinstance(ignore_tables, str):
225
+ ignore_tables = [t.strip() for t in ignore_tables.split(',')]
226
+ if isinstance(include_knowledge_bases, str):
227
+ include_knowledge_bases = [kb.strip() for kb in include_knowledge_bases.split(',')]
228
+ if isinstance(ignore_knowledge_bases, str):
229
+ ignore_knowledge_bases = [kb.strip() for kb in ignore_knowledge_bases.split(',')]
230
+
231
+ # Auto-create SQL skill if no skills are provided but include_tables or include_knowledge_bases params are provided
232
+ if not skills and (include_tables or include_knowledge_bases):
233
+ # Determine database to use (default to 'mindsdb')
234
+ db_name = database
235
+ kb_db_name = knowledge_base_database
236
+
237
+ # If database is not explicitly provided but tables are, try to extract the database name from the first table
238
+ if not database and include_tables and len(include_tables) > 0:
239
+ parts = include_tables[0].split('.')
240
+ if len(parts) >= 2:
241
+ db_name = parts[0]
242
+ elif not database and ignore_tables and len(ignore_tables) > 0:
243
+ parts = ignore_tables[0].split('.')
244
+ if len(parts) >= 2:
245
+ db_name = parts[0]
246
+
247
+ # Create a default SQL skill
248
+ skill_name = f"{name}_sql_skill"
249
+ skill_params = {
250
+ 'type': 'sql',
251
+ 'database': db_name,
252
+ 'description': f'Auto-generated SQL skill for agent {name}'
253
+ }
254
+
255
+ # Add knowledge base database if provided
256
+ if knowledge_base_database:
257
+ skill_params['knowledge_base_database'] = knowledge_base_database
258
+
259
+ # Add knowledge base parameters if provided
260
+ if include_knowledge_bases:
261
+ skill_params['include_knowledge_bases'] = include_knowledge_bases
262
+ if ignore_knowledge_bases:
263
+ skill_params['ignore_knowledge_bases'] = ignore_knowledge_bases
264
+
265
+ try:
266
+ # Check if skill already exists
267
+ existing_skill = self.skills_controller.get_skill(skill_name, project_name)
268
+ if existing_skill is None:
269
+ # Create the skill
270
+ skill_type = skill_params.pop('type')
271
+ self.skills_controller.add_skill(
272
+ name=skill_name,
273
+ project_name=project_name,
274
+ type=skill_type,
275
+ params=skill_params
276
+ )
277
+ else:
278
+ # Update the skill if parameters have changed
279
+ params_changed = False
280
+
281
+ # Check if database has changed
282
+ if existing_skill.params.get('database') != db_name:
283
+ existing_skill.params['database'] = db_name
284
+ params_changed = True
285
+
286
+ # Check if knowledge base database has changed
287
+ if knowledge_base_database and existing_skill.params.get('knowledge_base_database') != kb_db_name:
288
+ existing_skill.params['knowledge_base_database'] = kb_db_name
289
+ params_changed = True
290
+
291
+ # Check if knowledge base parameters have changed
292
+ if include_knowledge_bases and existing_skill.params.get('include_knowledge_bases') != include_knowledge_bases:
293
+ existing_skill.params['include_knowledge_bases'] = include_knowledge_bases
294
+ params_changed = True
295
+
296
+ if ignore_knowledge_bases and existing_skill.params.get('ignore_knowledge_bases') != ignore_knowledge_bases:
297
+ existing_skill.params['ignore_knowledge_bases'] = ignore_knowledge_bases
298
+ params_changed = True
299
+
300
+ # Update the skill if needed
301
+ if params_changed:
302
+ flag_modified(existing_skill, 'params')
303
+ db.session.commit()
304
+
305
+ skills = [skill_name]
306
+ except Exception as e:
307
+ raise ValueError(f"Failed to auto-create or update SQL skill: {str(e)}")
308
+
179
309
  agent = db.Agents(
180
310
  name=name,
181
311
  project_id=project.id,
@@ -193,10 +323,43 @@ class AgentsController:
193
323
  else:
194
324
  parameters = skill.copy()
195
325
  skill_name = parameters.pop('name')
326
+
196
327
  existing_skill = self.skills_controller.get_skill(skill_name, project_name)
197
328
  if existing_skill is None:
198
329
  db.session.rollback()
199
330
  raise ValueError(f'Skill with name does not exist: {skill_name}')
331
+
332
+ # Add table restrictions if this is a text2sql skill
333
+ if existing_skill.type == 'sql' and (include_tables or ignore_tables):
334
+ parameters['tables'] = include_tables or ignore_tables
335
+
336
+ # Add knowledge base restrictions if this is a text2sql skill
337
+ if existing_skill.type == 'sql':
338
+ # Pass database parameter if provided
339
+ if database and 'database' not in parameters:
340
+ parameters['database'] = database
341
+
342
+ # Pass knowledge base database parameter if provided
343
+ if knowledge_base_database and 'knowledge_base_database' not in parameters:
344
+ parameters['knowledge_base_database'] = knowledge_base_database
345
+
346
+ # Add knowledge base parameters to both the skill and the association parameters
347
+ if include_knowledge_bases:
348
+ parameters['include_knowledge_bases'] = include_knowledge_bases
349
+ if 'include_knowledge_bases' not in existing_skill.params:
350
+ existing_skill.params['include_knowledge_bases'] = include_knowledge_bases
351
+ flag_modified(existing_skill, 'params')
352
+ elif ignore_knowledge_bases:
353
+ parameters['ignore_knowledge_bases'] = ignore_knowledge_bases
354
+ if 'ignore_knowledge_bases' not in existing_skill.params:
355
+ existing_skill.params['ignore_knowledge_bases'] = ignore_knowledge_bases
356
+ flag_modified(existing_skill, 'params')
357
+
358
+ # Ensure knowledge_base_database is set in the skill's params
359
+ if knowledge_base_database and 'knowledge_base_database' not in existing_skill.params:
360
+ existing_skill.params['knowledge_base_database'] = knowledge_base_database
361
+ flag_modified(existing_skill, 'params')
362
+
200
363
  association = db.AgentSkillsAssociation(
201
364
  parameters=parameters,
202
365
  agent=agent,
@@ -4,8 +4,20 @@ from langchain.agents import AgentType
4
4
  from langchain_openai import OpenAIEmbeddings
5
5
 
6
6
  from types import MappingProxyType
7
- from mindsdb.integrations.handlers.openai_handler.constants import (
8
- CHAT_MODELS as OPEN_AI_CHAT_MODELS,
7
+
8
+ # the same as
9
+ # from mindsdb.integrations.handlers.openai_handler.constants import CHAT_MODELS
10
+ OPEN_AI_CHAT_MODELS = (
11
+ 'gpt-3.5-turbo',
12
+ 'gpt-3.5-turbo-16k',
13
+ 'gpt-3.5-turbo-instruct',
14
+ 'gpt-4',
15
+ 'gpt-4-32k',
16
+ 'gpt-4-1106-preview',
17
+ 'gpt-4-0125-preview',
18
+ 'gpt-4o',
19
+ 'o3-mini',
20
+ 'o1-mini'
9
21
  )
10
22
 
11
23
  SUPPORTED_PROVIDERS = {
@@ -190,3 +202,18 @@ DEFAULT_EMBEDDINGS_MODEL_PROVIDER = "openai"
190
202
  DEFAULT_EMBEDDINGS_MODEL_CLASS = OpenAIEmbeddings
191
203
  DEFAULT_TIKTOKEN_MODEL_NAME = os.getenv('DEFAULT_TIKTOKEN_MODEL_NAME', 'gpt-4')
192
204
  AGENT_CHUNK_POLLING_INTERVAL_SECONDS = os.getenv('AGENT_CHUNK_POLLING_INTERVAL_SECONDS', 1.0)
205
+ DEFAULT_TEXT2SQL_DATABASE = "mindsdb"
206
+ DEFAULT_AGENT_SYSTEM_PROMPT = """
207
+ You are an AI assistant powered by MindsDB. When answering questions, follow these guidelines:
208
+
209
+ 1. For factual questions about specific topics, use the knowledge base tools in this sequence:
210
+ - First use kb_list_tool to see available knowledge bases
211
+ - Then use kb_info_tool to understand the structure of relevant knowledge bases
212
+ - Finally use kb_query_tool to query the knowledge base for specific information
213
+
214
+ 2. For questions about database tables and their contents:
215
+ - Use the sql_tool to query the tables directly
216
+ - You can join tables if needed to get comprehensive information
217
+
218
+ For factual questions, ALWAYS use the available tools to look up information rather than relying on your internal knowledge.
219
+ """
@@ -24,9 +24,6 @@ from langchain_core.messages.base import BaseMessage
24
24
  from langchain_core.prompts import PromptTemplate
25
25
  from langchain_core.tools import Tool
26
26
 
27
- from mindsdb.integrations.handlers.openai_handler.constants import (
28
- CHAT_MODELS as OPEN_AI_CHAT_MODELS,
29
- )
30
27
  from mindsdb.integrations.libs.llm.utils import get_llm_config
31
28
  from mindsdb.integrations.utilities.handler_utils import get_api_key
32
29
  from mindsdb.integrations.utilities.rag.settings import DEFAULT_RAG_PROMPT_TEMPLATE
@@ -42,7 +39,8 @@ from .callback_handlers import LogCallbackHandler, ContextCaptureCallback
42
39
  from .langfuse_callback_handler import LangfuseCallbackHandler, get_skills
43
40
  from .safe_output_parser import SafeOutputParser
44
41
 
45
- from .constants import (
42
+ from mindsdb.interfaces.agents.constants import (
43
+ OPEN_AI_CHAT_MODELS,
46
44
  DEFAULT_AGENT_TIMEOUT_SECONDS,
47
45
  DEFAULT_AGENT_TYPE,
48
46
  DEFAULT_EMBEDDINGS_MODEL_PROVIDER,
@@ -56,7 +54,8 @@ from .constants import (
56
54
  NVIDIA_NIM_CHAT_MODELS,
57
55
  USER_COLUMN,
58
56
  ASSISTANT_COLUMN,
59
- CONTEXT_COLUMN, TRACE_ID_COLUMN
57
+ CONTEXT_COLUMN, TRACE_ID_COLUMN,
58
+ DEFAULT_AGENT_SYSTEM_PROMPT
60
59
  )
61
60
  from mindsdb.interfaces.skills.skill_tool import skill_tool, SkillData
62
61
  from langchain_anthropic import ChatAnthropic
@@ -175,6 +174,10 @@ def create_chat_model(args: Dict):
175
174
 
176
175
  def prepare_prompts(df, base_template, input_variables, user_column=USER_COLUMN):
177
176
  empty_prompt_ids = np.where(df[input_variables].isna().all(axis=1).values)[0]
177
+
178
+ # Combine system prompt with user-provided template
179
+ base_template = f"{DEFAULT_AGENT_SYSTEM_PROMPT}\n\n{base_template}"
180
+
178
181
  base_template = base_template.replace('{{', '{').replace('}}', '}')
179
182
  prompts = []
180
183
 
@@ -196,8 +199,9 @@ def prepare_callbacks(self, args):
196
199
  return callbacks, context_callback
197
200
 
198
201
 
199
- def handle_agent_error(e):
200
- error_message = f"An error occurred during agent execution: {str(e)}"
202
+ def handle_agent_error(e, error_message=None):
203
+ if error_message is None:
204
+ error_message = f"An error occurred during agent execution: {str(e)}"
201
205
  logger.error(error_message, exc_info=True)
202
206
  return error_message
203
207
 
@@ -526,7 +530,13 @@ AI: {response}"""
526
530
  output = result['output'] if isinstance(result, dict) and 'output' in result else str(result)
527
531
  return {CONTEXT_COLUMN: captured_context, ASSISTANT_COLUMN: output}
528
532
  except Exception as e:
529
- return {CONTEXT_COLUMN: [], ASSISTANT_COLUMN: handle_agent_error(e)}
533
+ error_message = str(e)
534
+ # Special handling for API key errors
535
+ if "API key" in error_message and ("not found" in error_message or "missing" in error_message):
536
+ # Format API key error more clearly
537
+ logger.error(f"API Key Error: {error_message}")
538
+ error_message = f"API Key Error: {error_message}"
539
+ return {CONTEXT_COLUMN: [], ASSISTANT_COLUMN: handle_agent_error(e, error_message)}
530
540
 
531
541
  completions = []
532
542
  contexts = []
@@ -2,6 +2,7 @@
2
2
  Wrapper around MindsDB's executor and integration controller following the implementation of the original
3
3
  langchain.sql_database.SQLDatabase class to partly replicate its behavior.
4
4
  """
5
+ import traceback
5
6
  from typing import Any, Iterable, List, Optional
6
7
 
7
8
  from mindsdb.utilities import log
@@ -57,8 +58,20 @@ class MindsDBSQL(SQLDatabase):
57
58
  """Information about all tables in the database."""
58
59
  return self._sql_agent.get_table_info()
59
60
 
61
+ @property
62
+ def kb_info(self) -> str:
63
+ """Information about all knowledge bases in the database."""
64
+ return self._sql_agent.get_knowledge_base_info()
65
+
60
66
  def get_usable_table_names(self) -> Iterable[str]:
61
- return self._sql_agent.get_usable_table_names()
67
+ """Information about all tables in the database."""
68
+ try:
69
+ return self._sql_agent.get_usable_table_names()
70
+ except Exception as e:
71
+ # If there's an error accessing tables through the integration, handle it gracefully
72
+ logger.warning(f"Error getting usable table names: {str(e)}")
73
+ # Return an empty list instead of raising an exception
74
+ return []
62
75
 
63
76
  def get_table_info_no_throw(self, table_names: Optional[List[str]] = None) -> str:
64
77
  for i in range(len(table_names)):
@@ -66,5 +79,91 @@ class MindsDBSQL(SQLDatabase):
66
79
  return self._sql_agent.get_table_info_safe(table_names)
67
80
 
68
81
  def run_no_throw(self, command: str, fetch: str = "all") -> str:
82
+ """Execute a SQL command and return the result as a string.
83
+
84
+ This method catches any exceptions and returns an error message instead of raising an exception.
85
+
86
+ Args:
87
+ command: The SQL command to execute
88
+ fetch: Whether to fetch 'all' results or just 'one'
89
+
90
+ Returns:
91
+ A string representation of the result or an error message
92
+ """
69
93
  command = extract_essential(command)
70
- return self._sql_agent.query_safe(command)
94
+
95
+ try:
96
+
97
+ # Log the query for debugging
98
+ logger.info(f"Executing SQL query: {command}")
99
+
100
+ # remove backticks
101
+ command = command.replace('`', '')
102
+
103
+ # Parse the SQL string to an AST object first
104
+ from mindsdb_sql_parser import parse_sql
105
+ ast_query = parse_sql(command)
106
+
107
+ # Now execute the parsed query
108
+ result = self._sql_agent.skill_tool.get_command_executor().execute_command(ast_query, database_name="mindsdb")
109
+
110
+ # Convert ExecuteAnswer to a DataFrame for easier manipulation
111
+ df = None
112
+ if hasattr(result, 'data') and hasattr(result.data, 'data_frame'):
113
+ df = result.data.data_frame
114
+ else:
115
+ # Fallback to to_df when data_frame attr not available
116
+ try:
117
+ df = result.data.to_df()
118
+ except Exception:
119
+ df = None
120
+
121
+ # Default behaviour (string)
122
+ if df is not None:
123
+ if not df.empty:
124
+ return df.to_string(index=False)
125
+ else:
126
+ return "Query executed successfully, but returned no data."
127
+
128
+ return str(result)
129
+
130
+ except Exception as e:
131
+ logger.error(f"Error executing SQL command: {str(e)}\n{traceback.format_exc()}")
132
+ # If this is a knowledge base query, provide a more helpful error message
133
+ if "knowledge_base" in command.lower() or any(kb in command for kb in self._sql_agent.get_usable_knowledge_base_names()):
134
+ return f"Error executing knowledge base query: {str(e)}. Please check that the knowledge base exists and your query syntax is correct."
135
+ return f"Error: {str(e)}"
136
+
137
+ # def run_no_throw(self, command: str, fetch: str = "all") -> str:
138
+ # """Execute a SQL command and return the result as a string.
139
+ #
140
+ # This method catches any exceptions and returns an error message instead of raising an exception.
141
+ #
142
+ # Args:
143
+ # command: The SQL command to execute
144
+ # fetch: Whether to fetch 'all' results or just 'one'
145
+ #
146
+ # Returns:
147
+ # A string representation of the result or an error message
148
+ # """
149
+ # command = extract_essential(command)
150
+ # try:
151
+ # return self._sql_agent.query_safe(command)
152
+ # except Exception as e:
153
+ # logger.error(f"Error executing SQL command: {str(e)}")
154
+ # # If this is a knowledge base query, provide a more helpful error message
155
+ # if "knowledge_base" in command.lower() or any(kb in command for kb in self._sql_agent.get_usable_knowledge_base_names()):
156
+ # return f"Error executing knowledge base query: {str(e)}. Please check that the knowledge base exists and your query syntax is correct."
157
+ # return f"Error: {str(e)}"
158
+
159
+ def get_usable_knowledge_base_names(self) -> List[str]:
160
+ """Get a list of usable knowledge base names.
161
+
162
+ Returns:
163
+ A list of knowledge base names that can be used in queries
164
+ """
165
+ try:
166
+ return self._sql_agent.get_usable_knowledge_base_names()
167
+ except Exception as e:
168
+ logger.error(f"Error getting usable knowledge base names: {str(e)}")
169
+ return []
@@ -4,7 +4,6 @@ from typing import List, Optional
4
4
  from collections import OrderedDict
5
5
 
6
6
  import sqlalchemy as sa
7
- from sqlalchemy.orm.attributes import flag_modified
8
7
  import numpy as np
9
8
 
10
9
  from mindsdb_sql_parser.ast.base import ASTNode
@@ -457,7 +456,7 @@ class ProjectController:
457
456
  project.create(name=name)
458
457
  return project
459
458
 
460
- def update(self, id: Optional[int] = None, name: Optional[str] = None, new_name: str = None, new_metadata: dict = None) -> Project:
459
+ def update(self, id: Optional[int] = None, name: Optional[str] = None, new_name: str = None) -> Project:
461
460
  if id is not None and name is not None:
462
461
  raise ValueError("Both 'id' and 'name' can't be provided at the same time")
463
462
 
@@ -470,10 +469,5 @@ class ProjectController:
470
469
  project.name = new_name
471
470
  project.record.name = new_name
472
471
 
473
- if new_metadata is not None:
474
- project.metadata = new_metadata
475
- project.record.metadata_ = new_metadata
476
- flag_modified(project.record, 'metadata_')
477
-
478
472
  db.session.commit()
479
473
  return project
@@ -1,7 +1,7 @@
1
1
  import os
2
+ import copy
2
3
 
3
4
  from duckdb.typing import BIGINT, DOUBLE, VARCHAR, BLOB, BOOLEAN
4
- from mindsdb.interfaces.functions.to_markdown import ToMarkdown
5
5
  from mindsdb.interfaces.storage.model_fs import HandlerStorage
6
6
  from mindsdb.utilities.config import config
7
7
 
@@ -159,31 +159,28 @@ class FunctionController(BYOMFunctionsController):
159
159
  return meta
160
160
 
161
161
  def to_markdown_call_function(self, node):
162
+ # load on-demand because lib is heavy
163
+ from mindsdb.interfaces.functions.to_markdown import ToMarkdown
162
164
  name = node.op.lower()
163
165
 
164
166
  if name in self.callbacks:
165
167
  return self.callbacks[name]
166
168
 
167
- def callback(file_path_or_url, use_llm):
169
+ def callback(file_path_or_url):
168
170
  chat_model_params = self._parse_chat_model_params('TO_MARKDOWN_FUNCTION_')
169
171
 
170
- llm_client = None
171
- llm_model = None
172
- try:
173
- from mindsdb.interfaces.agents.langchain_agent import create_chat_model
174
- llm = create_chat_model(chat_model_params)
175
- llm_client = llm.root_client
176
- llm_model = llm.model_name
177
- except Exception:
178
- pass
172
+ params_copy = copy.deepcopy(chat_model_params)
173
+ params_copy['model'] = params_copy.pop('model_name')
174
+ params_copy.pop('api_keys')
175
+ params_copy.pop('provider')
179
176
 
180
- to_markdown = ToMarkdown(use_llm, llm_client, llm_model)
181
- return to_markdown.call(file_path_or_url)
177
+ to_markdown = ToMarkdown()
178
+ return to_markdown.call(file_path_or_url, **params_copy)
182
179
 
183
180
  meta = {
184
181
  'name': name,
185
182
  'callback': callback,
186
- 'input_types': ['str', 'bool'],
183
+ 'input_types': ['str'],
187
184
  'output_type': 'str'
188
185
  }
189
186
  self.callbacks[name] = meta
@@ -1,13 +1,10 @@
1
- import base64
2
1
  from io import BytesIO
3
2
  import os
4
3
  from typing import Union
5
4
  from urllib.parse import urlparse
6
5
 
7
- import fitz # PyMuPDF
8
- from markitdown import MarkItDown
6
+ from aipdf import ocr
9
7
  import mimetypes
10
- from openai import OpenAI
11
8
  import requests
12
9
 
13
10
 
@@ -15,41 +12,22 @@ class ToMarkdown:
15
12
  """
16
13
  Extracts the content of documents of various formats in markdown format.
17
14
  """
18
- def __init__(self, use_llm: bool, llm_client: OpenAI = None, llm_model: str = None):
15
+ def __init__(self):
19
16
  """
20
17
  Initializes the ToMarkdown class.
21
18
  """
22
- # If use_llm is True, llm_client and llm_model must be provided.
23
- if use_llm and (llm_client is None or llm_model is None):
24
- raise ValueError('LLM client and model must be provided when use_llm is True.')
25
19
 
26
- # If use_llm is False, set llm_client and llm_model to None even if they are provided.
27
- if not use_llm:
28
- llm_client = None
29
- llm_model = None
30
-
31
- # Only OpenAI is supported for now.
32
- # TODO: Add support for other LLMs.
33
- if llm_client is not None and not isinstance(llm_client, OpenAI):
34
- raise ValueError('Only OpenAI models are supported at the moment.')
35
-
36
- self.use_llm = use_llm
37
- self.llm_client = llm_client
38
- self.llm_model = llm_model
39
-
40
- def call(self, file_path_or_url: str) -> str:
20
+ def call(self, file_path_or_url: str, **kwargs) -> str:
41
21
  """
42
22
  Converts a file to markdown.
43
23
  """
44
24
  file_extension = self._get_file_extension(file_path_or_url)
45
- file = self._get_file_content(file_path_or_url)
25
+ file_content = self._get_file_content(file_path_or_url)
46
26
 
47
27
  if file_extension == '.pdf':
48
- return self._pdf_to_markdown(file)
49
- elif file_extension in ['.jpg', '.jpeg', '.png', '.gif']:
50
- return self._image_to_markdown(file)
28
+ return self._pdf_to_markdown(file_content, **kwargs)
51
29
  else:
52
- return self._other_to_markdown(file)
30
+ raise ValueError(f"Unsupported file type: {file_extension}.")
53
31
 
54
32
  def _get_file_content(self, file_path_or_url: str) -> str:
55
33
  """
@@ -90,105 +68,12 @@ class ToMarkdown:
90
68
  else:
91
69
  return os.path.splitext(file_path_or_url)[1]
92
70
 
93
- def _pdf_to_markdown(self, file_content: Union[requests.Response, bytes]) -> str:
71
+ def _pdf_to_markdown(self, file_content: Union[requests.Response, bytes], **kwargs) -> str:
94
72
  """
95
73
  Converts a PDF file to markdown.
96
74
  """
97
- if self.llm_client is None:
98
- return self._pdf_to_markdown_no_llm(file_content)
99
- else:
100
- return self._pdf_to_markdown_llm(file_content)
101
-
102
- def _pdf_to_markdown_llm(self, file_content: Union[requests.Response, BytesIO]) -> str:
103
- """
104
- Converts a PDF file to markdown using LLM.
105
- The LLM is used mainly for the purpose of generating descriptions of any images in the PDF.
106
- """
107
75
  if isinstance(file_content, requests.Response):
108
76
  file_content = BytesIO(file_content.content)
109
77
 
110
- document = fitz.open(stream=file_content, filetype="pdf")
111
-
112
- markdown_content = []
113
- for page_num in range(len(document)):
114
- page = document.load_page(page_num)
115
-
116
- # Get text blocks with coordinates.
117
- page_content = []
118
- blocks = page.get_text("blocks")
119
- for block in blocks:
120
- x0, y0, x1, y1, text, _, _ = block
121
- if text.strip(): # Skip empty or whitespace blocks.
122
- page_content.append((y0, text.strip()))
123
-
124
- # Extract images from the page.
125
- image_list = page.get_images(full=True)
126
- for img_index, img in enumerate(image_list):
127
- xref = img[0]
128
- base_image = document.extract_image(xref)
129
- image_bytes = base_image["image"]
130
-
131
- # Use actual image y-coordinate if available.
132
- y0 = float(base_image.get("y", 0))
133
- image_description = self._generate_image_description(image_bytes)
134
- page_content.append((y0, f"![{image_description}](image_{page_num + 1}_{img_index + 1}.png)"))
135
-
136
- # Sort the content by y0 coordinate
137
- page_content.sort(key=lambda x: x[0])
138
-
139
- # Add sorted content to the markdown
140
- for _, text in page_content:
141
- markdown_content.append(text)
142
- markdown_content.append("\n")
143
-
144
- document.close()
145
-
146
- return "\n".join(markdown_content)
147
-
148
- def _generate_image_description(self, image_bytes: bytes) -> str:
149
- """
150
- Generates a description of the image using LLM.
151
- """
152
- image_base64 = base64.b64encode(image_bytes).decode("utf-8")
153
-
154
- response = self.llm_client.chat.completions.create(
155
- model=self.llm_model,
156
- messages=[
157
- {
158
- "role": "user",
159
- "content": [
160
- {"type": "text", "text": "Describe this image"},
161
- {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_base64}"}},
162
- ],
163
- }
164
- ],
165
- )
166
- description = response.choices[0].message.content
167
- return description
168
-
169
- def _pdf_to_markdown_no_llm(self, file_content: Union[requests.Response, BytesIO]) -> str:
170
- """
171
- Converts a PDF file to markdown without using LLM.
172
- """
173
- md = MarkItDown(enable_plugins=True)
174
- result = md.convert(file_content)
175
- return result.markdown
176
-
177
- def _image_to_markdown(self, file_content: Union[requests.Response, BytesIO]) -> str:
178
- """
179
- Converts images to markdown.
180
- """
181
- if not self.use_llm or self.llm_client is None:
182
- raise ValueError('LLM client must be enabled to convert images to markdown.')
183
-
184
- md = MarkItDown(llm_client=self.llm_client, llm_model=self.llm_model, enable_plugins=True)
185
- result = md.convert(file_content)
186
- return result.markdown
187
-
188
- def _other_to_markdown(self, file_content: Union[requests.Response, BytesIO]) -> str:
189
- """
190
- Converts other file formats to markdown.
191
- """
192
- md = MarkItDown(enable_plugins=True)
193
- result = md.convert(file_content)
194
- return result.markdown
78
+ markdown_pages = ocr(file_content, **kwargs)
79
+ return "\n\n---\n\n".join(markdown_pages)