MindsDB 25.5.3.0__py3-none-any.whl → 25.5.4.1__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 (313) hide show
  1. mindsdb/__about__.py +8 -8
  2. mindsdb/__main__.py +127 -79
  3. mindsdb/api/a2a/__init__.py +0 -0
  4. mindsdb/api/a2a/__main__.py +144 -0
  5. mindsdb/api/a2a/agent.py +308 -0
  6. mindsdb/api/a2a/common/__init__.py +0 -0
  7. mindsdb/api/a2a/common/server/__init__.py +4 -0
  8. mindsdb/api/a2a/common/server/server.py +164 -0
  9. mindsdb/api/a2a/common/server/task_manager.py +287 -0
  10. mindsdb/api/a2a/common/server/utils.py +28 -0
  11. mindsdb/api/a2a/common/types.py +365 -0
  12. mindsdb/api/a2a/constants.py +9 -0
  13. mindsdb/api/a2a/run_a2a.py +86 -0
  14. mindsdb/api/a2a/task_manager.py +560 -0
  15. mindsdb/api/executor/command_executor.py +185 -309
  16. mindsdb/api/executor/datahub/classes/response.py +5 -2
  17. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +39 -72
  18. mindsdb/api/executor/planner/query_planner.py +10 -1
  19. mindsdb/api/executor/sql_query/result_set.py +185 -52
  20. mindsdb/api/executor/sql_query/sql_query.py +1 -1
  21. mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +9 -12
  22. mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +8 -10
  23. mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +5 -44
  24. mindsdb/api/executor/sql_query/steps/insert_step.py +24 -15
  25. mindsdb/api/executor/sql_query/steps/join_step.py +1 -1
  26. mindsdb/api/executor/sql_query/steps/project_step.py +1 -1
  27. mindsdb/api/executor/sql_query/steps/sql_steps.py +1 -1
  28. mindsdb/api/executor/sql_query/steps/subselect_step.py +4 -8
  29. mindsdb/api/executor/sql_query/steps/union_step.py +1 -3
  30. mindsdb/api/http/initialize.py +99 -83
  31. mindsdb/api/http/namespaces/analysis.py +3 -3
  32. mindsdb/api/http/namespaces/config.py +61 -86
  33. mindsdb/api/http/namespaces/file.py +8 -2
  34. mindsdb/api/http/namespaces/sql.py +13 -27
  35. mindsdb/api/mcp/start.py +42 -5
  36. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packet.py +0 -1
  37. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/binary_resultset_row_package.py +52 -19
  38. mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +8 -10
  39. mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +54 -38
  40. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +82 -115
  41. mindsdb/api/mysql/mysql_proxy/utilities/dump.py +351 -0
  42. mindsdb/api/postgres/postgres_proxy/executor/executor.py +1 -1
  43. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +5 -6
  44. mindsdb/integrations/handlers/altibase_handler/altibase_handler.py +26 -27
  45. mindsdb/integrations/handlers/altibase_handler/connection_args.py +13 -13
  46. mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler.py +8 -8
  47. mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler_dsn.py +13 -13
  48. mindsdb/integrations/handlers/anthropic_handler/__init__.py +2 -2
  49. mindsdb/integrations/handlers/anthropic_handler/anthropic_handler.py +1 -3
  50. mindsdb/integrations/handlers/aurora_handler/aurora_handler.py +1 -0
  51. mindsdb/integrations/handlers/autosklearn_handler/autosklearn_handler.py +1 -1
  52. mindsdb/integrations/handlers/autosklearn_handler/config.py +0 -1
  53. mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +1 -1
  54. mindsdb/integrations/handlers/bigquery_handler/tests/test_bigquery_handler.py +1 -1
  55. mindsdb/integrations/handlers/binance_handler/binance_handler.py +1 -0
  56. mindsdb/integrations/handlers/binance_handler/binance_tables.py +3 -4
  57. mindsdb/integrations/handlers/byom_handler/__init__.py +0 -1
  58. mindsdb/integrations/handlers/byom_handler/requirements.txt +1 -2
  59. mindsdb/integrations/handlers/ckan_handler/ckan_handler.py +3 -0
  60. mindsdb/integrations/handlers/clickhouse_handler/__init__.py +1 -1
  61. mindsdb/integrations/handlers/cloud_spanner_handler/tests/test_cloud_spanner_handler.py +0 -2
  62. mindsdb/integrations/handlers/cloud_sql_handler/cloud_sql_handler.py +0 -1
  63. mindsdb/integrations/handlers/cohere_handler/__init__.py +1 -1
  64. mindsdb/integrations/handlers/cohere_handler/cohere_handler.py +11 -13
  65. mindsdb/integrations/handlers/confluence_handler/confluence_tables.py +6 -0
  66. mindsdb/integrations/handlers/databend_handler/connection_args.py +1 -1
  67. mindsdb/integrations/handlers/databend_handler/databend_handler.py +4 -4
  68. mindsdb/integrations/handlers/databend_handler/tests/__init__.py +0 -1
  69. mindsdb/integrations/handlers/databend_handler/tests/test_databend_handler.py +1 -1
  70. mindsdb/integrations/handlers/derby_handler/connection_args.py +1 -1
  71. mindsdb/integrations/handlers/derby_handler/derby_handler.py +14 -22
  72. mindsdb/integrations/handlers/derby_handler/tests/test_derby_handler.py +6 -6
  73. mindsdb/integrations/handlers/discord_handler/discord_handler.py +5 -5
  74. mindsdb/integrations/handlers/discord_handler/discord_tables.py +3 -3
  75. mindsdb/integrations/handlers/discord_handler/tests/test_discord.py +5 -3
  76. mindsdb/integrations/handlers/dockerhub_handler/dockerhub.py +3 -3
  77. mindsdb/integrations/handlers/dockerhub_handler/dockerhub_handler.py +2 -2
  78. mindsdb/integrations/handlers/dockerhub_handler/dockerhub_tables.py +57 -54
  79. mindsdb/integrations/handlers/dremio_handler/__init__.py +2 -2
  80. mindsdb/integrations/handlers/druid_handler/__init__.py +1 -1
  81. mindsdb/integrations/handlers/druid_handler/druid_handler.py +2 -2
  82. mindsdb/integrations/handlers/edgelessdb_handler/tests/test_edgelessdb_handler.py +9 -9
  83. mindsdb/integrations/handlers/email_handler/email_client.py +1 -1
  84. mindsdb/integrations/handlers/email_handler/email_ingestor.py +1 -1
  85. mindsdb/integrations/handlers/email_handler/email_tables.py +0 -1
  86. mindsdb/integrations/handlers/email_handler/settings.py +0 -1
  87. mindsdb/integrations/handlers/eventstoredb_handler/eventstoredb_handler.py +2 -1
  88. mindsdb/integrations/handlers/firebird_handler/firebird_handler.py +1 -1
  89. mindsdb/integrations/handlers/flaml_handler/flaml_handler.py +9 -9
  90. mindsdb/integrations/handlers/frappe_handler/frappe_client.py +5 -5
  91. mindsdb/integrations/handlers/frappe_handler/frappe_handler.py +6 -5
  92. mindsdb/integrations/handlers/frappe_handler/frappe_tables.py +2 -2
  93. mindsdb/integrations/handlers/github_handler/connection_args.py +2 -2
  94. mindsdb/integrations/handlers/github_handler/github_handler.py +1 -8
  95. mindsdb/integrations/handlers/github_handler/github_tables.py +13 -24
  96. mindsdb/integrations/handlers/gitlab_handler/gitlab_handler.py +2 -1
  97. mindsdb/integrations/handlers/gitlab_handler/gitlab_tables.py +1 -4
  98. mindsdb/integrations/handlers/gmail_handler/gmail_handler.py +6 -13
  99. mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +2 -1
  100. mindsdb/integrations/handlers/google_books_handler/google_books_tables.py +0 -3
  101. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +4 -4
  102. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_tables.py +2 -6
  103. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +3 -2
  104. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_tables.py +0 -3
  105. mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +10 -12
  106. mindsdb/integrations/handlers/google_fit_handler/google_fit_tables.py +11 -13
  107. mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +2 -1
  108. mindsdb/integrations/handlers/google_search_handler/google_search_tables.py +0 -3
  109. mindsdb/integrations/handlers/groq_handler/__init__.py +3 -3
  110. mindsdb/integrations/handlers/hackernews_handler/hn_handler.py +5 -7
  111. mindsdb/integrations/handlers/hackernews_handler/hn_table.py +6 -7
  112. mindsdb/integrations/handlers/hive_handler/tests/test_hive_handler.py +1 -1
  113. mindsdb/integrations/handlers/hsqldb_handler/connection_args.py +6 -6
  114. mindsdb/integrations/handlers/hsqldb_handler/hsqldb_handler.py +4 -3
  115. mindsdb/integrations/handlers/huggingface_api_handler/exceptions.py +1 -1
  116. mindsdb/integrations/handlers/huggingface_api_handler/huggingface_api_handler.py +1 -8
  117. mindsdb/integrations/handlers/huggingface_handler/huggingface_handler.py +6 -6
  118. mindsdb/integrations/handlers/huggingface_handler/requirements.txt +1 -1
  119. mindsdb/integrations/handlers/huggingface_handler/requirements_cpu.txt +1 -1
  120. mindsdb/integrations/handlers/ignite_handler/ignite_handler.py +2 -1
  121. mindsdb/integrations/handlers/impala_handler/impala_handler.py +9 -12
  122. mindsdb/integrations/handlers/impala_handler/tests/test_impala_handler.py +11 -11
  123. mindsdb/integrations/handlers/influxdb_handler/influxdb_handler.py +10 -13
  124. mindsdb/integrations/handlers/influxdb_handler/influxdb_tables.py +20 -20
  125. mindsdb/integrations/handlers/informix_handler/__about__.py +8 -8
  126. mindsdb/integrations/handlers/informix_handler/__init__.py +12 -5
  127. mindsdb/integrations/handlers/informix_handler/informix_handler.py +99 -133
  128. mindsdb/integrations/handlers/informix_handler/tests/test_informix_handler.py +13 -11
  129. mindsdb/integrations/handlers/ingres_handler/__about__.py +0 -1
  130. mindsdb/integrations/handlers/ingres_handler/ingres_handler.py +1 -0
  131. mindsdb/integrations/handlers/jira_handler/jira_handler.py +4 -4
  132. mindsdb/integrations/handlers/jira_handler/jira_tables.py +9 -9
  133. mindsdb/integrations/handlers/kinetica_handler/__init__.py +0 -1
  134. mindsdb/integrations/handlers/lancedb_handler/requirements.txt +0 -1
  135. mindsdb/integrations/handlers/langchain_handler/langchain_handler.py +4 -4
  136. mindsdb/integrations/handlers/langchain_handler/tools.py +9 -10
  137. mindsdb/integrations/handlers/leonardoai_handler/__init__.py +1 -1
  138. mindsdb/integrations/handlers/lightwood_handler/functions.py +2 -2
  139. mindsdb/integrations/handlers/lightwood_handler/lightwood_handler.py +0 -1
  140. mindsdb/integrations/handlers/lightwood_handler/tests/test_lightwood_handler.py +11 -11
  141. mindsdb/integrations/handlers/litellm_handler/litellm_handler.py +37 -20
  142. mindsdb/integrations/handlers/llama_index_handler/llama_index_handler.py +4 -4
  143. mindsdb/integrations/handlers/llama_index_handler/settings.py +10 -9
  144. mindsdb/integrations/handlers/materialize_handler/tests/test_materialize_handler.py +8 -10
  145. mindsdb/integrations/handlers/matrixone_handler/matrixone_handler.py +4 -4
  146. mindsdb/integrations/handlers/matrixone_handler/tests/test_matrixone_handler.py +8 -9
  147. mindsdb/integrations/handlers/maxdb_handler/connection_args.py +25 -25
  148. mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +1 -0
  149. mindsdb/integrations/handlers/mediawiki_handler/mediawiki_handler.py +3 -2
  150. mindsdb/integrations/handlers/mediawiki_handler/mediawiki_tables.py +1 -1
  151. mindsdb/integrations/handlers/mendeley_handler/__about__.py +1 -1
  152. mindsdb/integrations/handlers/mendeley_handler/__init__.py +2 -2
  153. mindsdb/integrations/handlers/mendeley_handler/mendeley_handler.py +48 -56
  154. mindsdb/integrations/handlers/mendeley_handler/mendeley_tables.py +24 -29
  155. mindsdb/integrations/handlers/mendeley_handler/tests/test_mendeley_handler.py +19 -17
  156. mindsdb/integrations/handlers/merlion_handler/merlion_handler.py +5 -4
  157. mindsdb/integrations/handlers/minds_endpoint_handler/__init__.py +3 -3
  158. mindsdb/integrations/handlers/mlflow_handler/mlflow_handler.py +58 -36
  159. mindsdb/integrations/handlers/monetdb_handler/__about__.py +8 -8
  160. mindsdb/integrations/handlers/monetdb_handler/__init__.py +15 -5
  161. mindsdb/integrations/handlers/monetdb_handler/connection_args.py +17 -18
  162. mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +40 -57
  163. mindsdb/integrations/handlers/monetdb_handler/tests/test_monetdb_handler.py +7 -8
  164. mindsdb/integrations/handlers/monetdb_handler/utils/monet_get_id.py +13 -14
  165. mindsdb/integrations/handlers/monkeylearn_handler/__about__.py +1 -1
  166. mindsdb/integrations/handlers/monkeylearn_handler/__init__.py +1 -1
  167. mindsdb/integrations/handlers/monkeylearn_handler/monkeylearn_handler.py +2 -5
  168. mindsdb/integrations/handlers/ms_one_drive_handler/ms_graph_api_one_drive_client.py +1 -0
  169. mindsdb/integrations/handlers/ms_one_drive_handler/ms_one_drive_handler.py +1 -1
  170. mindsdb/integrations/handlers/ms_teams_handler/ms_graph_api_teams_client.py +23 -23
  171. mindsdb/integrations/handlers/ms_teams_handler/ms_teams_handler.py +3 -3
  172. mindsdb/integrations/handlers/ms_teams_handler/ms_teams_tables.py +10 -5
  173. mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +73 -8
  174. mindsdb/integrations/handlers/mysql_handler/__about__.py +8 -8
  175. mindsdb/integrations/handlers/mysql_handler/__init__.py +15 -5
  176. mindsdb/integrations/handlers/mysql_handler/connection_args.py +43 -47
  177. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +101 -34
  178. mindsdb/integrations/handlers/mysql_handler/settings.py +15 -13
  179. mindsdb/integrations/handlers/neuralforecast_handler/neuralforecast_handler.py +1 -1
  180. mindsdb/integrations/handlers/newsapi_handler/newsapi_handler.py +1 -1
  181. mindsdb/integrations/handlers/newsapi_handler/tests/test_newsapi_handler.py +4 -4
  182. mindsdb/integrations/handlers/nuo_jdbc_handler/connection_args.py +2 -2
  183. mindsdb/integrations/handlers/nuo_jdbc_handler/nuo_jdbc_handler.py +28 -36
  184. mindsdb/integrations/handlers/nuo_jdbc_handler/tests/test_nuo_handler.py +5 -5
  185. mindsdb/integrations/handlers/oceanbase_handler/oceanbase_handler.py +0 -1
  186. mindsdb/integrations/handlers/oceanbase_handler/tests/test_oceanbase_handler.py +8 -10
  187. mindsdb/integrations/handlers/ollama_handler/ollama_handler.py +3 -3
  188. mindsdb/integrations/handlers/opengauss_handler/tests/test_opengauss_handler.py +1 -2
  189. mindsdb/integrations/handlers/openstreetmap_handler/__init__.py +7 -7
  190. mindsdb/integrations/handlers/oracle_handler/connection_args.py +6 -0
  191. mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +77 -11
  192. mindsdb/integrations/handlers/orioledb_handler/tests/test_orioledb_handler.py +8 -10
  193. mindsdb/integrations/handlers/palm_handler/__about__.py +1 -1
  194. mindsdb/integrations/handlers/palm_handler/__init__.py +1 -1
  195. mindsdb/integrations/handlers/palm_handler/palm_handler.py +1 -3
  196. mindsdb/integrations/handlers/paypal_handler/paypal_handler.py +2 -2
  197. mindsdb/integrations/handlers/paypal_handler/paypal_tables.py +15 -14
  198. mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +53 -10
  199. mindsdb/integrations/handlers/phoenix_handler/__init__.py +1 -1
  200. mindsdb/integrations/handlers/phoenix_handler/phoenix_handler.py +1 -0
  201. mindsdb/integrations/handlers/pinot_handler/__init__.py +1 -1
  202. mindsdb/integrations/handlers/pinot_handler/pinot_handler.py +3 -2
  203. mindsdb/integrations/handlers/plaid_handler/plaid_handler.py +13 -13
  204. mindsdb/integrations/handlers/plaid_handler/plaid_tables.py +10 -12
  205. mindsdb/integrations/handlers/plaid_handler/utils.py +4 -6
  206. mindsdb/integrations/handlers/planetscale_handler/planetscale_handler.py +1 -4
  207. mindsdb/integrations/handlers/portkey_handler/__init__.py +2 -2
  208. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +105 -24
  209. mindsdb/integrations/handlers/postgres_handler/tests/test_postgres_handler.py +11 -6
  210. mindsdb/integrations/handlers/questdb_handler/questdb_handler.py +1 -2
  211. mindsdb/integrations/handlers/questdb_handler/tests/test_questdb_handler.py +2 -3
  212. mindsdb/integrations/handlers/quickbooks_handler/quickbooks_handler.py +6 -8
  213. mindsdb/integrations/handlers/quickbooks_handler/quickbooks_table.py +10 -10
  214. mindsdb/integrations/handlers/rag_handler/ingest.py +2 -2
  215. mindsdb/integrations/handlers/rag_handler/rag_handler.py +1 -1
  216. mindsdb/integrations/handlers/rag_handler/settings.py +1 -1
  217. mindsdb/integrations/handlers/reddit_handler/reddit_handler.py +2 -7
  218. mindsdb/integrations/handlers/reddit_handler/reddit_tables.py +2 -3
  219. mindsdb/integrations/handlers/replicate_handler/replicate_handler.py +6 -6
  220. mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_handler.py +1 -2
  221. mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_tables.py +0 -3
  222. mindsdb/integrations/handlers/rockset_handler/connection_args.py +14 -14
  223. mindsdb/integrations/handlers/rockset_handler/tests/test_rockset_handler.py +1 -0
  224. mindsdb/integrations/handlers/scylla_handler/scylla_handler.py +6 -5
  225. mindsdb/integrations/handlers/sendinblue_handler/sendinblue_handler.py +2 -1
  226. mindsdb/integrations/handlers/sendinblue_handler/sendinblue_tables.py +16 -16
  227. mindsdb/integrations/handlers/sentence_transformers_handler/__init__.py +1 -1
  228. mindsdb/integrations/handlers/sheets_handler/connection_args.py +1 -1
  229. mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +7 -6
  230. mindsdb/integrations/handlers/shopify_handler/shopify_tables.py +38 -41
  231. mindsdb/integrations/handlers/singlestore_handler/__about__.py +1 -1
  232. mindsdb/integrations/handlers/singlestore_handler/__init__.py +0 -1
  233. mindsdb/integrations/handlers/singlestore_handler/singlestore_handler.py +1 -0
  234. mindsdb/integrations/handlers/singlestore_handler/tests/test_singlestore_handler.py +3 -3
  235. mindsdb/integrations/handlers/slack_handler/__init__.py +3 -3
  236. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +100 -6
  237. mindsdb/integrations/handlers/solr_handler/connection_args.py +7 -7
  238. mindsdb/integrations/handlers/solr_handler/solr_handler.py +2 -1
  239. mindsdb/integrations/handlers/solr_handler/tests/test_solr_handler.py +2 -1
  240. mindsdb/integrations/handlers/sqlany_handler/sqlany_handler.py +3 -2
  241. mindsdb/integrations/handlers/sqlite_handler/sqlite_handler.py +1 -0
  242. mindsdb/integrations/handlers/sqreamdb_handler/connection_args.py +1 -1
  243. mindsdb/integrations/handlers/sqreamdb_handler/sqreamdb_handler.py +15 -20
  244. mindsdb/integrations/handlers/sqreamdb_handler/tests/test_sqreamdb_handler.py +4 -4
  245. mindsdb/integrations/handlers/stabilityai_handler/__init__.py +1 -1
  246. mindsdb/integrations/handlers/starrocks_handler/starrocks_handler.py +0 -1
  247. mindsdb/integrations/handlers/starrocks_handler/tests/test_starrocks_handler.py +8 -10
  248. mindsdb/integrations/handlers/statsforecast_handler/statsforecast_handler.py +2 -2
  249. mindsdb/integrations/handlers/strava_handler/strava_handler.py +4 -8
  250. mindsdb/integrations/handlers/strava_handler/strava_tables.py +22 -30
  251. mindsdb/integrations/handlers/stripe_handler/stripe_handler.py +3 -2
  252. mindsdb/integrations/handlers/stripe_handler/stripe_tables.py +11 -27
  253. mindsdb/integrations/handlers/supabase_handler/tests/test_supabase_handler.py +1 -1
  254. mindsdb/integrations/handlers/surrealdb_handler/surrealdb_handler.py +4 -4
  255. mindsdb/integrations/handlers/tdengine_handler/tdengine_handler.py +25 -27
  256. mindsdb/integrations/handlers/tdengine_handler/tests/test_tdengine_handler.py +8 -8
  257. mindsdb/integrations/handlers/tidb_handler/tests/test_tidb_handler.py +1 -2
  258. mindsdb/integrations/handlers/timegpt_handler/timegpt_handler.py +5 -5
  259. mindsdb/integrations/handlers/tpot_handler/tpot_handler.py +21 -26
  260. mindsdb/integrations/handlers/trino_handler/trino_handler.py +14 -14
  261. mindsdb/integrations/handlers/twitter_handler/twitter_handler.py +2 -4
  262. mindsdb/integrations/handlers/unify_handler/tests/test_unify_handler.py +7 -8
  263. mindsdb/integrations/handlers/unify_handler/unify_handler.py +9 -9
  264. mindsdb/integrations/handlers/vertex_handler/vertex_client.py +1 -1
  265. mindsdb/integrations/handlers/vertica_handler/tests/test_vertica_handler.py +11 -11
  266. mindsdb/integrations/handlers/vertica_handler/vertica_handler.py +11 -14
  267. mindsdb/integrations/handlers/vitess_handler/tests/test_vitess_handler.py +9 -11
  268. mindsdb/integrations/handlers/vitess_handler/vitess_handler.py +0 -1
  269. mindsdb/integrations/handlers/web_handler/web_handler.py +1 -0
  270. mindsdb/integrations/handlers/whatsapp_handler/__init__.py +3 -3
  271. mindsdb/integrations/handlers/writer_handler/evaluate.py +1 -1
  272. mindsdb/integrations/handlers/writer_handler/settings.py +0 -1
  273. mindsdb/integrations/handlers/writer_handler/writer_handler.py +1 -0
  274. mindsdb/integrations/handlers/youtube_handler/youtube_handler.py +5 -5
  275. mindsdb/integrations/handlers/youtube_handler/youtube_tables.py +26 -27
  276. mindsdb/integrations/handlers/yugabyte_handler/tests/test_yugabyte_handler.py +3 -3
  277. mindsdb/integrations/handlers/yugabyte_handler/yugabyte_handler.py +0 -6
  278. mindsdb/integrations/libs/llm/config.py +13 -0
  279. mindsdb/integrations/libs/llm/utils.py +37 -65
  280. mindsdb/integrations/libs/response.py +67 -52
  281. mindsdb/integrations/libs/vectordatabase_handler.py +6 -0
  282. mindsdb/integrations/utilities/handler_utils.py +15 -3
  283. mindsdb/integrations/utilities/handlers/api_utilities/__init__.py +0 -1
  284. mindsdb/integrations/utilities/handlers/auth_utilities/__init__.py +0 -2
  285. mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +230 -227
  286. mindsdb/integrations/utilities/utils.py +3 -3
  287. mindsdb/interfaces/agents/agents_controller.py +164 -1
  288. mindsdb/interfaces/agents/constants.py +32 -13
  289. mindsdb/interfaces/agents/langchain_agent.py +106 -95
  290. mindsdb/interfaces/agents/mindsdb_database_agent.py +101 -2
  291. mindsdb/interfaces/knowledge_base/controller.py +250 -216
  292. mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +13 -10
  293. mindsdb/interfaces/knowledge_base/preprocessing/json_chunker.py +434 -0
  294. mindsdb/interfaces/knowledge_base/preprocessing/models.py +54 -0
  295. mindsdb/interfaces/query_context/context_controller.py +66 -10
  296. mindsdb/interfaces/skills/custom/text2sql/mindsdb_kb_tools.py +190 -0
  297. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +92 -0
  298. mindsdb/interfaces/skills/skill_tool.py +202 -57
  299. mindsdb/interfaces/skills/sql_agent.py +205 -17
  300. mindsdb/interfaces/storage/fs.py +1 -0
  301. mindsdb/interfaces/variables/__init__.py +0 -0
  302. mindsdb/interfaces/variables/variables_controller.py +97 -0
  303. mindsdb/migrations/env.py +5 -7
  304. mindsdb/migrations/migrate.py +47 -7
  305. mindsdb/migrations/versions/2025-05-21_9f150e4f9a05_checkpoint_1.py +360 -0
  306. mindsdb/utilities/config.py +287 -216
  307. mindsdb/utilities/starters.py +13 -0
  308. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/METADATA +646 -698
  309. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/RECORD +312 -295
  310. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/WHEEL +1 -1
  311. mindsdb/integrations/handlers/monkeylearn_handler/requirements.txt +0 -1
  312. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/licenses/LICENSE +0 -0
  313. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env python
2
+ import os
3
+ import sys
4
+ import logging
5
+ from dotenv import load_dotenv
6
+ from typing import Dict, Any, Optional
7
+
8
+ # Configure logging
9
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ def setup_python_path():
14
+ """Ensure the repository root directory is on *sys.path* so that the
15
+ ``mindsdb`` package (located at <repo>/mindsdb) can be imported when this
16
+ helper script is executed from inside *mindsdb/api/a2a*.
17
+ """
18
+
19
+ # Absolute path to *this* file
20
+ this_file_dir = os.path.dirname(os.path.abspath(__file__))
21
+
22
+ # Walk three levels up: a2a/ -> api/ -> mindsdb/ -> <repo_root>
23
+ repo_root = os.path.abspath(os.path.join(this_file_dir, os.pardir, os.pardir, os.pardir))
24
+
25
+ # Prepend to PYTHONPATH if not already present
26
+ if repo_root not in sys.path:
27
+ sys.path.insert(0, repo_root)
28
+
29
+ # Add the a2a directory to the Python path so that 'common' can be imported
30
+ if this_file_dir not in sys.path:
31
+ sys.path.insert(0, this_file_dir)
32
+
33
+ logger.info("Added %s to PYTHONPATH", repo_root)
34
+
35
+
36
+ def main(config_override: Optional[Dict[str, Any]] = None, *args, **kwargs):
37
+ """
38
+ Run the a2a module with the correct Python path.
39
+ First set up the Python path, then import and run __main__.py
40
+
41
+ Args:
42
+ config_override: Optional configuration dictionary to override settings
43
+ args: Additional positional arguments
44
+ kwargs: Additional keyword arguments
45
+ """
46
+ # Set up Python path first
47
+ setup_python_path()
48
+
49
+ # Load environment variables
50
+ load_dotenv()
51
+
52
+ try:
53
+ # Import the main_with_config function from __main__.py
54
+ from mindsdb.api.a2a.__main__ import main_with_config
55
+ from mindsdb.utilities.config import config
56
+
57
+ logger.info("Successfully imported a2a module")
58
+
59
+ # Get configuration from config system or use provided override
60
+ a2a_config = config_override if config_override is not None else config.get("a2a", {})
61
+
62
+ # Set log level if specified
63
+ if a2a_config.get("log_level"):
64
+ log_level = getattr(logging, a2a_config["log_level"].upper(), None)
65
+ if log_level:
66
+ logger.setLevel(log_level)
67
+ logger.info(f"Set log level to {a2a_config['log_level'].upper()}")
68
+
69
+ logger.info(f"Starting A2A with configuration: {a2a_config}")
70
+
71
+ # Call the main_with_config function with the configuration
72
+ main_with_config(a2a_config, *args, **kwargs)
73
+
74
+ except ImportError as e:
75
+ logger.error(f"Error importing a2a module: {e}")
76
+ sys.exit(1)
77
+ except Exception as e:
78
+ logger.error(f"Error running a2a module: {e}")
79
+ import traceback
80
+
81
+ logger.error(traceback.format_exc())
82
+ sys.exit(1)
83
+
84
+
85
+ if __name__ == "__main__":
86
+ main()
@@ -0,0 +1,560 @@
1
+ from typing import AsyncIterable
2
+ from mindsdb.api.a2a.common.types import (
3
+ SendTaskRequest,
4
+ TaskSendParams,
5
+ Message,
6
+ TaskStatus,
7
+ Artifact,
8
+ TaskStatusUpdateEvent,
9
+ TaskArtifactUpdateEvent,
10
+ TaskState,
11
+ Task,
12
+ SendTaskResponse,
13
+ InternalError,
14
+ JSONRPCResponse,
15
+ SendTaskStreamingRequest,
16
+ SendTaskStreamingResponse,
17
+ InvalidRequestError,
18
+ )
19
+ from mindsdb.api.a2a.common.server.task_manager import InMemoryTaskManager
20
+ from mindsdb.api.a2a.agent import MindsDBAgent
21
+
22
+ from typing import Union
23
+ import logging
24
+ import asyncio
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class AgentTaskManager(InMemoryTaskManager):
30
+ def __init__(
31
+ self,
32
+ project_name: str,
33
+ mindsdb_host: str,
34
+ mindsdb_port: int,
35
+ agent_name: str = None,
36
+ ):
37
+ super().__init__()
38
+ self.project_name = project_name
39
+ self.mindsdb_host = mindsdb_host
40
+ self.mindsdb_port = mindsdb_port
41
+ self.agent_name = agent_name
42
+ self.tasks = {} # Task storage
43
+ self.lock = asyncio.Lock() # Lock for task operations
44
+
45
+ def _create_agent(self, agent_name: str = None) -> MindsDBAgent:
46
+ """Create a new MindsDBAgent instance for the given agent name."""
47
+ if not agent_name:
48
+ raise ValueError("Agent name is required but was not provided in the request")
49
+
50
+ return MindsDBAgent(
51
+ agent_name=agent_name,
52
+ project_name=self.project_name,
53
+ host=self.mindsdb_host,
54
+ port=self.mindsdb_port,
55
+ )
56
+
57
+ async def _stream_generator(self, request: SendTaskStreamingRequest) -> AsyncIterable[SendTaskStreamingResponse]:
58
+ task_send_params: TaskSendParams = request.params
59
+ query = self._get_user_query(task_send_params)
60
+ params = self._get_task_params(task_send_params)
61
+ agent_name = params["agent_name"]
62
+ streaming = params["streaming"]
63
+
64
+ # Create and store the task first to ensure it exists
65
+ try:
66
+ await self.upsert_task(task_send_params)
67
+ except Exception as e:
68
+ logger.error(f"Error creating task: {str(e)}")
69
+ yield SendTaskStreamingResponse(
70
+ id=request.id,
71
+ error=InternalError(message=f"Error creating task: {str(e)}"),
72
+ )
73
+ return # Early return from generator
74
+
75
+ agent = self._create_agent(agent_name)
76
+
77
+ if not streaming:
78
+ # If streaming is disabled, use invoke and return a single response
79
+ try:
80
+ result = agent.invoke(query, task_send_params.sessionId)
81
+
82
+ # Use the parts from the agent response if available, or create them
83
+ if "parts" in result:
84
+ parts = result["parts"]
85
+ else:
86
+ result_text = result.get("content", "No response from MindsDB")
87
+ parts = [{"type": "text", "text": result_text}]
88
+
89
+ # Check if we have structured data
90
+ if "data" in result and result["data"]:
91
+ parts.append(
92
+ {
93
+ "type": "data",
94
+ "data": result["data"],
95
+ "metadata": {"subtype": "json"},
96
+ }
97
+ )
98
+
99
+ # Create and yield the final response
100
+ task_state = TaskState.COMPLETED
101
+ artifact = Artifact(parts=parts, index=0, append=False)
102
+ task_status = TaskStatus(state=task_state)
103
+
104
+ # Update the task store
105
+ await self._update_store(task_send_params.id, task_status, [artifact])
106
+
107
+ # Yield the artifact update
108
+ yield SendTaskStreamingResponse(
109
+ id=request.id,
110
+ result=TaskArtifactUpdateEvent(id=task_send_params.id, artifact=artifact),
111
+ )
112
+
113
+ # Yield the final status update
114
+ yield SendTaskStreamingResponse(
115
+ id=request.id,
116
+ result=TaskStatusUpdateEvent(
117
+ id=task_send_params.id,
118
+ status=TaskStatus(state=task_status.state),
119
+ final=True,
120
+ ),
121
+ )
122
+ return
123
+
124
+ except Exception as e:
125
+ logger.error(f"Error invoking agent: {e}")
126
+ yield JSONRPCResponse(
127
+ id=request.id,
128
+ error=InternalError(message=f"Error invoking agent: {str(e)}"),
129
+ )
130
+ return
131
+
132
+ # If streaming is enabled (default), use the streaming implementation
133
+ try:
134
+ # Track the chunks we've seen to avoid duplicates
135
+ seen_chunks = set()
136
+
137
+ async for item in agent.stream(query, task_send_params.sessionId):
138
+ # Ensure item has the required fields or provide defaults
139
+ is_task_complete = item.get("is_task_complete", False)
140
+
141
+ # Create a structured thought dictionary to encapsulate the agent's thought process
142
+ thought_dict = {}
143
+ parts = []
144
+
145
+ # Handle different chunk formats to extract text content
146
+ if "actions" in item:
147
+ # Extract thought process from actions
148
+ thought_dict["type"] = "thought"
149
+ thought_dict["actions"] = item["actions"]
150
+
151
+ for action in item.get("actions", []):
152
+ if "log" in action:
153
+ # Use "text" type for all parts, but add a thought_type in metadata
154
+ parts.append(
155
+ {
156
+ "type": "text",
157
+ "text": action["log"],
158
+ "metadata": {"thought_type": "thought"},
159
+ }
160
+ )
161
+ if "tool_input" in action:
162
+ # Include SQL queries
163
+ tool_input = action.get("tool_input", "")
164
+ if "$START$" in tool_input and "$STOP$" in tool_input:
165
+ sql = tool_input.replace("$START$", "").replace("$STOP$", "")
166
+ parts.append(
167
+ {
168
+ "type": "text",
169
+ "text": sql,
170
+ "metadata": {"thought_type": "sql"},
171
+ }
172
+ )
173
+
174
+ elif "steps" in item:
175
+ # Extract observations from steps
176
+ thought_dict["type"] = "observation"
177
+ thought_dict["steps"] = item["steps"]
178
+
179
+ for step in item.get("steps", []):
180
+ if "observation" in step:
181
+ parts.append(
182
+ {
183
+ "type": "text",
184
+ "text": step["observation"],
185
+ "metadata": {"thought_type": "observation"},
186
+ }
187
+ )
188
+ if "action" in step and "log" in step["action"]:
189
+ parts.append(
190
+ {
191
+ "type": "text",
192
+ "text": step["action"]["log"],
193
+ "metadata": {"thought_type": "thought"},
194
+ }
195
+ )
196
+
197
+ elif "output" in item:
198
+ # Final answer
199
+ thought_dict["type"] = "answer"
200
+ thought_dict["output"] = item["output"]
201
+ parts.append({"type": "text", "text": item["output"]})
202
+
203
+ elif "parts" in item and item["parts"]:
204
+ # Use existing parts, but ensure they have valid types
205
+ for part in item["parts"]:
206
+ if part.get("type") in ["text", "file", "data"]:
207
+ # Valid type, use as is
208
+ parts.append(part)
209
+ else:
210
+ # Invalid type, convert to text
211
+ text_content = part.get("text", "")
212
+ if not text_content and "content" in part:
213
+ text_content = part["content"]
214
+
215
+ new_part = {"type": "text", "text": text_content}
216
+
217
+ # Preserve metadata if it exists
218
+ if "metadata" in part:
219
+ new_part["metadata"] = part["metadata"]
220
+ else:
221
+ new_part["metadata"] = {"thought_type": part.get("type", "text")}
222
+
223
+ parts.append(new_part)
224
+
225
+ # Try to determine the type from parts for the thought dictionary
226
+ for part in item["parts"]:
227
+ if part.get("type") == "text" and part.get("text", "").startswith("$START$"):
228
+ thought_dict["type"] = "sql"
229
+ thought_dict["query"] = part.get("text")
230
+ else:
231
+ thought_dict["type"] = "text"
232
+
233
+ elif "content" in item:
234
+ # Simple content
235
+ thought_dict["type"] = "text"
236
+ thought_dict["content"] = item["content"]
237
+ parts.append({"type": "text", "text": item["content"]})
238
+
239
+ elif "messages" in item:
240
+ # Extract content from messages
241
+ thought_dict["type"] = "message"
242
+ thought_dict["messages"] = item["messages"]
243
+
244
+ for message in item.get("messages", []):
245
+ if "content" in message:
246
+ parts.append(
247
+ {
248
+ "type": "text",
249
+ "text": message["content"],
250
+ "metadata": {"thought_type": "message"},
251
+ }
252
+ )
253
+
254
+ # Skip if we have no parts to send
255
+ if not parts:
256
+ continue
257
+
258
+ # Process each part individually to ensure true streaming
259
+ for part in parts:
260
+ # Generate a unique key for this part to avoid duplicates
261
+ part_key = str(part)
262
+ if part_key in seen_chunks:
263
+ continue
264
+ seen_chunks.add(part_key)
265
+
266
+ # Ensure metadata exists
267
+ metadata = item.get("metadata", {})
268
+
269
+ # Add the thought dictionary to metadata for frontend parsing
270
+ if thought_dict:
271
+ metadata["thought_process"] = thought_dict
272
+
273
+ # Handle error field if present
274
+ if "error" in item and not is_task_complete:
275
+ logger.warning(f"Error in streaming response: {item['error']}")
276
+ # Mark as complete if there's an error
277
+ is_task_complete = True
278
+
279
+ if not is_task_complete:
280
+ # Create a message with just this part and send it immediately
281
+ task_state = TaskState.WORKING
282
+ message = Message(role="agent", parts=[part], metadata=metadata)
283
+ task_status = TaskStatus(state=task_state, message=message)
284
+ await self._update_store(task_send_params.id, task_status, [])
285
+ task_update_event = TaskStatusUpdateEvent(
286
+ id=task_send_params.id,
287
+ status=task_status,
288
+ final=False,
289
+ )
290
+ yield SendTaskStreamingResponse(id=request.id, result=task_update_event)
291
+
292
+ # If this is the final chunk, send a completion message
293
+ if is_task_complete:
294
+ task_state = TaskState.COMPLETED
295
+ artifact = Artifact(parts=parts, index=0, append=False)
296
+ task_status = TaskStatus(state=task_state)
297
+ yield SendTaskStreamingResponse(
298
+ id=request.id,
299
+ result=TaskArtifactUpdateEvent(id=task_send_params.id, artifact=artifact),
300
+ )
301
+ await self._update_store(task_send_params.id, task_status, [artifact])
302
+ yield SendTaskStreamingResponse(
303
+ id=request.id,
304
+ result=TaskStatusUpdateEvent(
305
+ id=task_send_params.id,
306
+ status=TaskStatus(
307
+ state=task_status.state,
308
+ ),
309
+ final=True,
310
+ ),
311
+ )
312
+
313
+ except Exception as e:
314
+ logger.error(f"An error occurred while streaming the response: {e}")
315
+ error_text = f"An error occurred while streaming the response: {str(e)}"
316
+ parts = [{"type": "text", "text": error_text}]
317
+
318
+ # First send the error as an artifact
319
+ artifact = Artifact(parts=parts, index=0, append=False)
320
+ yield SendTaskStreamingResponse(
321
+ id=request.id,
322
+ result=TaskArtifactUpdateEvent(id=task_send_params.id, artifact=artifact),
323
+ )
324
+
325
+ # Then mark the task as completed with an error
326
+ task_state = TaskState.FAILED
327
+ task_status = TaskStatus(state=task_state)
328
+ await self._update_store(task_send_params.id, task_status, [artifact])
329
+
330
+ # Send the final status update
331
+ yield SendTaskStreamingResponse(
332
+ id=request.id,
333
+ result=TaskStatusUpdateEvent(
334
+ id=task_send_params.id,
335
+ status=TaskStatus(
336
+ state=task_status.state,
337
+ ),
338
+ final=True,
339
+ ),
340
+ )
341
+
342
+ async def upsert_task(self, task_send_params: TaskSendParams) -> Task:
343
+ """Create or update a task in the task store.
344
+
345
+ Args:
346
+ task_send_params: The parameters for the task.
347
+
348
+ Returns:
349
+ The created or updated task.
350
+ """
351
+ logger.info(f"Upserting task {task_send_params.id}")
352
+ async with self.lock:
353
+ task = self.tasks.get(task_send_params.id)
354
+ if task is None:
355
+ # Convert the message to a dict if it's not already one
356
+ message = task_send_params.message
357
+ message_dict = message.dict() if hasattr(message, "dict") else message
358
+
359
+ # Create a new task
360
+ task = Task(
361
+ id=task_send_params.id,
362
+ sessionId=task_send_params.sessionId,
363
+ messages=[message_dict],
364
+ status=TaskStatus(state=TaskState.SUBMITTED),
365
+ history=[message_dict],
366
+ artifacts=[],
367
+ )
368
+ self.tasks[task_send_params.id] = task
369
+ else:
370
+ # Convert the message to a dict if it's not already one
371
+ message = task_send_params.message
372
+ message_dict = message.dict() if hasattr(message, "dict") else message
373
+
374
+ # Update the existing task
375
+ task.history.append(message_dict)
376
+ return task
377
+
378
+ def _validate_request(
379
+ self, request: Union[SendTaskRequest, SendTaskStreamingRequest]
380
+ ) -> Union[None, JSONRPCResponse]:
381
+ """Validate the request and return an error response if invalid."""
382
+ # Check if the request has the required parameters
383
+ if not hasattr(request, "params") or not request.params:
384
+ return JSONRPCResponse(
385
+ id=request.id,
386
+ error=InvalidRequestError(message="Missing params"),
387
+ )
388
+
389
+ # Check if the request has a message
390
+ if not hasattr(request.params, "message") or not request.params.message:
391
+ return JSONRPCResponse(
392
+ id=request.id,
393
+ error=InvalidRequestError(message="Missing message in params"),
394
+ )
395
+
396
+ # Check if the message has metadata
397
+ if not hasattr(request.params.message, "metadata") or not request.params.message.metadata:
398
+ return JSONRPCResponse(
399
+ id=request.id,
400
+ error=InvalidRequestError(message="Missing metadata in message"),
401
+ )
402
+
403
+ # Check if the agent name is provided in the metadata
404
+ metadata = request.params.message.metadata
405
+ agent_name = metadata.get("agent_name", metadata.get("agentName"))
406
+ if not agent_name:
407
+ return JSONRPCResponse(
408
+ id=request.id,
409
+ error=InvalidRequestError(
410
+ message="Agent name is required but was not provided in the request metadata"
411
+ ),
412
+ )
413
+
414
+ return None
415
+
416
+ async def on_send_task(self, request: SendTaskRequest) -> SendTaskResponse:
417
+ error = self._validate_request(request)
418
+ if error:
419
+ return error
420
+
421
+ return await self._invoke(request)
422
+
423
+ async def on_send_task_subscribe(
424
+ self, request: SendTaskStreamingRequest
425
+ ) -> AsyncIterable[SendTaskStreamingResponse]:
426
+ error = self._validate_request(request)
427
+ if error:
428
+ # Convert JSONRPCResponse to SendTaskStreamingResponse
429
+ yield SendTaskStreamingResponse(id=request.id, error=error.error)
430
+ return
431
+
432
+ # We can't await an async generator directly, so we need to use it as is
433
+ try:
434
+ async for response in self._stream_generator(request):
435
+ yield response
436
+ except Exception as e:
437
+ # If an error occurs, yield an error response
438
+ logger.error(f"Error in on_send_task_subscribe: {str(e)}")
439
+ yield SendTaskStreamingResponse(
440
+ id=request.id,
441
+ error=InternalError(message=f"Error processing streaming request: {str(e)}"),
442
+ )
443
+
444
+ async def _update_store(self, task_id: str, status: TaskStatus, artifacts: list[Artifact]) -> Task:
445
+ async with self.lock:
446
+ try:
447
+ task = self.tasks[task_id]
448
+ except KeyError:
449
+ logger.error(f"Task {task_id} not found for updating the task")
450
+ # Create a new task with the provided ID if it doesn't exist
451
+ # This ensures we don't fail when a task is not found
452
+ task = Task(
453
+ id=task_id,
454
+ sessionId="recovery-session", # Use a placeholder session ID
455
+ messages=[], # No messages available
456
+ status=status, # Use the provided status
457
+ history=[], # No history available
458
+ )
459
+ self.tasks[task_id] = task
460
+
461
+ task.status = status
462
+ if artifacts is not None:
463
+ for artifact in artifacts:
464
+ if artifact.append and len(task.artifacts) > 0:
465
+ # Append to the last artifact
466
+ last_artifact = task.artifacts[-1]
467
+ for part in artifact.parts:
468
+ last_artifact.parts.append(part)
469
+ else:
470
+ # Add as a new artifact
471
+ task.artifacts.append(artifact)
472
+ return task
473
+
474
+ def _get_user_query(self, task_send_params: TaskSendParams) -> str:
475
+ """Extract the user query from the task parameters."""
476
+ message = task_send_params.message
477
+ if not message.parts:
478
+ return ""
479
+
480
+ # Find the first text part
481
+ for part in message.parts:
482
+ if part.type == "text":
483
+ return part.text
484
+
485
+ # If no text part found, return empty string
486
+ return ""
487
+
488
+ def _get_task_params(self, task_send_params: TaskSendParams) -> dict:
489
+ """Extract common parameters from task metadata."""
490
+ metadata = task_send_params.message.metadata or {}
491
+ # Check for both agent_name and agentName in the metadata
492
+ agent_name = metadata.get("agent_name", metadata.get("agentName"))
493
+ return {
494
+ "agent_name": agent_name,
495
+ "streaming": metadata.get("streaming", True),
496
+ "session_id": task_send_params.sessionId,
497
+ }
498
+
499
+ async def _invoke(self, request: SendTaskRequest) -> SendTaskResponse:
500
+ task_send_params: TaskSendParams = request.params
501
+ query = self._get_user_query(task_send_params)
502
+ params = self._get_task_params(task_send_params)
503
+ agent_name = params["agent_name"]
504
+ streaming = params["streaming"]
505
+ agent = self._create_agent(agent_name)
506
+
507
+ try:
508
+ # Always use streaming internally, but handle the response differently based on the streaming parameter
509
+ all_parts = []
510
+ final_metadata = {}
511
+
512
+ # Create a streaming generator
513
+ stream_gen = agent.stream(query, task_send_params.sessionId)
514
+
515
+ if streaming:
516
+ # For streaming mode, we'll use the streaming endpoint instead
517
+ # Just create a minimal response to acknowledge the request
518
+ task_state = TaskState.WORKING
519
+ task = await self._update_store(task_send_params.id, TaskStatus(state=task_state), [])
520
+ return SendTaskResponse(id=request.id, result=task)
521
+ else:
522
+ # For non-streaming mode, collect all chunks into a single response
523
+ async for chunk in stream_gen:
524
+ # Extract parts if they exist
525
+ if "parts" in chunk and chunk["parts"]:
526
+ all_parts.extend(chunk["parts"])
527
+ elif "content" in chunk:
528
+ all_parts.append({"type": "text", "text": chunk["content"]})
529
+
530
+ # Extract metadata if it exists
531
+ if "metadata" in chunk:
532
+ final_metadata.update(chunk["metadata"])
533
+
534
+ # If we didn't get any parts, create a default part
535
+ if not all_parts:
536
+ all_parts = [{"type": "text", "text": "No response from MindsDB"}]
537
+
538
+ # Create the final response
539
+ task_state = TaskState.COMPLETED
540
+ task = await self._update_store(
541
+ task_send_params.id,
542
+ TaskStatus(
543
+ state=task_state,
544
+ message=Message(role="agent", parts=all_parts, metadata=final_metadata),
545
+ ),
546
+ [Artifact(parts=all_parts)],
547
+ )
548
+ return SendTaskResponse(id=request.id, result=task)
549
+ except Exception as e:
550
+ logger.error(f"Error invoking agent: {e}")
551
+ result_text = f"Error invoking agent: {e}"
552
+ parts = [{"type": "text", "text": result_text}]
553
+
554
+ task_state = TaskState.FAILED
555
+ task = await self._update_store(
556
+ task_send_params.id,
557
+ TaskStatus(state=task_state, message=Message(role="agent", parts=parts)),
558
+ [Artifact(parts=parts)],
559
+ )
560
+ return SendTaskResponse(id=request.id, result=task)