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