MindsDB 25.4.3.2__py3-none-any.whl → 25.4.5.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 (68) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +18 -4
  3. mindsdb/api/executor/command_executor.py +12 -2
  4. mindsdb/api/executor/data_types/response_type.py +1 -0
  5. mindsdb/api/executor/datahub/classes/tables_row.py +3 -10
  6. mindsdb/api/executor/datahub/datanodes/datanode.py +7 -2
  7. mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +44 -10
  8. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +57 -38
  9. mindsdb/api/executor/datahub/datanodes/mindsdb_tables.py +2 -1
  10. mindsdb/api/executor/datahub/datanodes/project_datanode.py +39 -7
  11. mindsdb/api/executor/datahub/datanodes/system_tables.py +116 -109
  12. mindsdb/api/executor/planner/query_plan.py +1 -0
  13. mindsdb/api/executor/planner/query_planner.py +15 -1
  14. mindsdb/api/executor/planner/steps.py +8 -2
  15. mindsdb/api/executor/sql_query/sql_query.py +24 -8
  16. mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +25 -8
  17. mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +4 -2
  18. mindsdb/api/executor/sql_query/steps/insert_step.py +2 -1
  19. mindsdb/api/executor/sql_query/steps/prepare_steps.py +2 -3
  20. mindsdb/api/http/namespaces/config.py +19 -11
  21. mindsdb/api/litellm/start.py +82 -0
  22. mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +133 -0
  23. mindsdb/integrations/handlers/chromadb_handler/chromadb_handler.py +7 -2
  24. mindsdb/integrations/handlers/chromadb_handler/settings.py +1 -0
  25. mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +13 -4
  26. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +14 -5
  27. mindsdb/integrations/handlers/openai_handler/helpers.py +3 -5
  28. mindsdb/integrations/handlers/openai_handler/openai_handler.py +20 -8
  29. mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +14 -4
  30. mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +34 -19
  31. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +21 -18
  32. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +14 -4
  33. mindsdb/integrations/handlers/togetherai_handler/__about__.py +9 -0
  34. mindsdb/integrations/handlers/togetherai_handler/__init__.py +20 -0
  35. mindsdb/integrations/handlers/togetherai_handler/creation_args.py +14 -0
  36. mindsdb/integrations/handlers/togetherai_handler/icon.svg +15 -0
  37. mindsdb/integrations/handlers/togetherai_handler/model_using_args.py +5 -0
  38. mindsdb/integrations/handlers/togetherai_handler/requirements.txt +2 -0
  39. mindsdb/integrations/handlers/togetherai_handler/settings.py +33 -0
  40. mindsdb/integrations/handlers/togetherai_handler/togetherai_handler.py +234 -0
  41. mindsdb/integrations/handlers/web_handler/urlcrawl_helpers.py +1 -1
  42. mindsdb/integrations/libs/response.py +80 -32
  43. mindsdb/integrations/utilities/handler_utils.py +4 -0
  44. mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +360 -0
  45. mindsdb/integrations/utilities/rag/rerankers/reranker_compressor.py +8 -153
  46. mindsdb/interfaces/agents/litellm_server.py +345 -0
  47. mindsdb/interfaces/agents/mcp_client_agent.py +252 -0
  48. mindsdb/interfaces/agents/run_mcp_agent.py +205 -0
  49. mindsdb/interfaces/functions/controller.py +3 -2
  50. mindsdb/interfaces/knowledge_base/controller.py +106 -82
  51. mindsdb/interfaces/query_context/context_controller.py +55 -15
  52. mindsdb/interfaces/query_context/query_task.py +19 -0
  53. mindsdb/interfaces/skills/skill_tool.py +7 -1
  54. mindsdb/interfaces/skills/sql_agent.py +8 -3
  55. mindsdb/interfaces/storage/db.py +2 -2
  56. mindsdb/interfaces/tasks/task_monitor.py +5 -1
  57. mindsdb/interfaces/tasks/task_thread.py +6 -0
  58. mindsdb/migrations/versions/2025-04-22_53502b6d63bf_query_database.py +27 -0
  59. mindsdb/utilities/config.py +20 -2
  60. mindsdb/utilities/context.py +1 -0
  61. mindsdb/utilities/starters.py +7 -0
  62. {mindsdb-25.4.3.2.dist-info → mindsdb-25.4.5.0.dist-info}/METADATA +226 -221
  63. {mindsdb-25.4.3.2.dist-info → mindsdb-25.4.5.0.dist-info}/RECORD +67 -53
  64. {mindsdb-25.4.3.2.dist-info → mindsdb-25.4.5.0.dist-info}/WHEEL +1 -1
  65. mindsdb/integrations/handlers/snowflake_handler/tests/test_snowflake_handler.py +0 -230
  66. /mindsdb/{integrations/handlers/snowflake_handler/tests → api/litellm}/__init__.py +0 -0
  67. {mindsdb-25.4.3.2.dist-info → mindsdb-25.4.5.0.dist-info}/licenses/LICENSE +0 -0
  68. {mindsdb-25.4.3.2.dist-info → mindsdb-25.4.5.0.dist-info}/top_level.txt +0 -0
@@ -15,6 +15,7 @@ from mindsdb.utilities.cache import get_cache
15
15
 
16
16
  from mindsdb.interfaces.storage import db
17
17
  from mindsdb.utilities.context import context as ctx
18
+ from mindsdb.utilities.config import config
18
19
 
19
20
  from .last_query import LastQuery
20
21
 
@@ -24,9 +25,12 @@ class RunningQuery:
24
25
  Query in progres
25
26
  """
26
27
 
28
+ OBJECT_TYPE = 'query'
29
+
27
30
  def __init__(self, record: db.Queries):
28
31
  self.record = record
29
32
  self.sql = record.sql
33
+ self.database = record.database or config.get('default_project')
30
34
 
31
35
  def get_partition_query(self, step_num: int, query: Select) -> Select:
32
36
  """
@@ -67,6 +71,44 @@ class RunningQuery:
67
71
 
68
72
  return query
69
73
 
74
+ def get_info(self):
75
+ record = self.record
76
+ return {
77
+ 'id': record.id,
78
+ 'sql': record.sql,
79
+ 'database': record.database,
80
+ 'started_at': record.started_at,
81
+ 'finished_at': record.finished_at,
82
+ 'parameters': record.parameters,
83
+ 'context': record.context,
84
+ 'processed_rows': record.processed_rows,
85
+ 'error': record.error,
86
+ 'updated_at': record.updated_at,
87
+ }
88
+
89
+ def add_to_task(self):
90
+
91
+ task_record = db.Tasks(
92
+ company_id=ctx.company_id,
93
+ user_class=ctx.user_class,
94
+
95
+ object_type=self.OBJECT_TYPE,
96
+ object_id=self.record.id,
97
+ )
98
+ db.session.add(task_record)
99
+ db.session.commit()
100
+
101
+ def remove_from_task(self):
102
+ task = db.Tasks.query.filter(
103
+ db.Tasks.object_type == self.OBJECT_TYPE,
104
+ db.Tasks.object_id == self.record.id,
105
+ db.Tasks.company_id == ctx.company_id,
106
+ ).first()
107
+
108
+ if task is not None:
109
+ db.session.delete(task)
110
+ db.session.commit()
111
+
70
112
  def set_params(self, params: dict):
71
113
  """
72
114
  Store parameters of the step which is about to be split into partitions
@@ -126,14 +168,21 @@ class RunningQuery:
126
168
 
127
169
  db.session.commit()
128
170
 
129
- def clear_error(self):
171
+ def mark_as_run(self):
130
172
  """
131
- Reset error of the query in database
173
+ Mark query as running and reset error of the query
132
174
  """
175
+ if self.record.finished_at is not None:
176
+ raise RuntimeError('The query already finished')
133
177
 
134
- if self.record.error is not None:
178
+ if self.record.started_at is None:
179
+ self.record.started_at = dt.datetime.now()
180
+ db.session.commit()
181
+ elif self.record.error is not None:
135
182
  self.record.error = None
136
183
  db.session.commit()
184
+ else:
185
+ raise RuntimeError('The query might be running already')
137
186
 
138
187
  def get_state(self) -> dict:
139
188
  """
@@ -448,7 +497,7 @@ class QueryContextController:
448
497
  raise RuntimeError(f'Query not found: {query_id}')
449
498
  return RunningQuery(rec)
450
499
 
451
- def create_query(self, query: ASTNode) -> RunningQuery:
500
+ def create_query(self, query: ASTNode, database: str = None) -> RunningQuery:
452
501
  """
453
502
  Create a new running query from AST query
454
503
  """
@@ -463,6 +512,7 @@ class QueryContextController:
463
512
 
464
513
  rec = db.Queries(
465
514
  sql=str(query),
515
+ database=database,
466
516
  company_id=ctx.company_id,
467
517
  )
468
518
 
@@ -479,17 +529,7 @@ class QueryContextController:
479
529
  db.Queries.company_id == ctx.company_id
480
530
  )
481
531
  return [
482
- {
483
- 'id': record.id,
484
- 'sql': record.sql,
485
- 'started_at': record.started_at,
486
- 'finished_at': record.finished_at,
487
- 'parameters': record.parameters,
488
- 'context': record.context,
489
- 'processed_rows': record.processed_rows,
490
- 'error': record.error,
491
- 'updated_at': record.updated_at,
492
- }
532
+ RunningQuery(record).get_info()
493
533
  for record in query
494
534
  ]
495
535
 
@@ -0,0 +1,19 @@
1
+ from mindsdb.api.executor.sql_query import SQLQuery
2
+ from mindsdb.interfaces.query_context.context_controller import query_context_controller
3
+ from mindsdb.api.executor.controllers.session_controller import SessionController
4
+ from mindsdb.interfaces.tasks.task import BaseTask
5
+
6
+
7
+ class QueryTask(BaseTask):
8
+ def __init__(self, *args, **kwargs):
9
+ super().__init__(*args, **kwargs)
10
+ self.query_id = self.object_id
11
+
12
+ def run(self, stop_event):
13
+
14
+ try:
15
+ session = SessionController()
16
+ SQLQuery(None, query_id=self.query_id, session=session, stop_event=stop_event)
17
+ finally:
18
+ # clear task
19
+ query_context_controller.get_query(self.query_id).remove_from_task()
@@ -243,7 +243,13 @@ class SkillToolController:
243
243
  kb_table = session_controller.kb_controller.get_table(knowledge_base_name, skill.project_id)
244
244
 
245
245
  res = kb_table.select_query(query)
246
- return '\n'.join(res.content)
246
+ # Handle both chunk_content and content column names
247
+ if hasattr(res, 'chunk_content'):
248
+ return '\n'.join(res.chunk_content)
249
+ elif hasattr(res, 'content'):
250
+ return '\n'.join(res.content)
251
+ else:
252
+ return "No content or chunk_content found in knowledge base response"
247
253
 
248
254
  return _answer_question
249
255
 
@@ -12,6 +12,7 @@ from mindsdb_sql_parser.ast import Select, Show, Describe, Explain, Identifier
12
12
  from mindsdb.utilities import log
13
13
  from mindsdb.utilities.context import context as ctx
14
14
  from mindsdb.integrations.utilities.query_traversal import query_traversal
15
+ from mindsdb.integrations.libs.response import INF_SCHEMA_COLUMNS_NAMES
15
16
 
16
17
  logger = log.getLogger(__name__)
17
18
 
@@ -275,9 +276,13 @@ class SQLAgent:
275
276
  dn = self._command_executor.session.datahub.get(integration)
276
277
 
277
278
  fields, dtypes = [], []
278
- for column in dn.get_table_columns(table_name, schema_name):
279
- fields.append(column['name'])
280
- dtypes.append(column.get('type', ''))
279
+ for df in dn.get_table_columns_df(table_name, schema_name):
280
+ df_records = df.to_dict(orient='records')
281
+ fields.append(df_records[INF_SCHEMA_COLUMNS_NAMES.COLUMN_NAME])
282
+ if df_records[INF_SCHEMA_COLUMNS_NAMES.MYSQL_DATA_TYPE] is not None:
283
+ dtypes.append(df_records[INF_SCHEMA_COLUMNS_NAMES.MYSQL_DATA_TYPE].value)
284
+ else:
285
+ dtypes.append(df_records[INF_SCHEMA_COLUMNS_NAMES.DATA_TYPE])
281
286
 
282
287
  info = f'Table named `{table_str}`:\n'
283
288
  info += f"\nSample with first {self._sample_rows_in_table_info} rows from table {table_str} in CSV format (dialect is 'excel'):\n"
@@ -571,9 +571,9 @@ class Queries(Base):
571
571
  company_id: int = Column(Integer, nullable=True)
572
572
 
573
573
  sql: str = Column(String, nullable=False)
574
- # step_data: JSON = Column(JSON, nullable=True)
574
+ database: str = Column(String, nullable=True)
575
575
 
576
- started_at: datetime.datetime = Column(DateTime, default=datetime.datetime.now)
576
+ started_at: datetime.datetime = Column(DateTime)
577
577
  finished_at: datetime.datetime = Column(DateTime)
578
578
 
579
579
  parameters = Column(JSON, default={})
@@ -2,6 +2,7 @@ import datetime as dt
2
2
  import os
3
3
  import socket
4
4
  import time
5
+ from threading import Event
5
6
 
6
7
  import sqlalchemy as sa
7
8
 
@@ -22,7 +23,7 @@ class TaskMonitor:
22
23
  def __init__(self):
23
24
  self._active_tasks = {}
24
25
 
25
- def start(self):
26
+ def start(self, stop_event: Event = None):
26
27
  config = Config()
27
28
  db.init()
28
29
  self.config = config
@@ -42,6 +43,9 @@ class TaskMonitor:
42
43
  logger.error(e)
43
44
  db.session.rollback()
44
45
 
46
+ if stop_event is not None and stop_event.is_set():
47
+ return
48
+
45
49
  def stop_all_tasks(self):
46
50
 
47
51
  active_tasks = list(self._active_tasks.keys())
@@ -6,6 +6,7 @@ from mindsdb.utilities import log
6
6
 
7
7
  from mindsdb.interfaces.triggers.trigger_task import TriggerTask
8
8
  from mindsdb.interfaces.chatbot.chatbot_task import ChatBotTask
9
+ from mindsdb.interfaces.query_context.query_task import QueryTask
9
10
 
10
11
  logger = log.getLogger(__name__)
11
12
 
@@ -28,6 +29,7 @@ class TaskThread(threading.Thread):
28
29
  ctx.company_id = task_record.company_id
29
30
  if task_record.user_class is not None:
30
31
  ctx.user_class = task_record.user_class
32
+ ctx.task_id = task_record.id
31
33
 
32
34
  self.object_type = task_record.object_type
33
35
  self.object_id = task_record.object_id
@@ -43,6 +45,10 @@ class TaskThread(threading.Thread):
43
45
  bot = ChatBotTask(self.task_id, self.object_id)
44
46
  bot.run(self._stop_event)
45
47
 
48
+ elif self.object_type == 'query':
49
+ query = QueryTask(self.task_id, self.object_id)
50
+ query.run(self._stop_event)
51
+
46
52
  except Exception:
47
53
  logger.error(traceback.format_exc())
48
54
  task_record.last_error = str(traceback.format_exc())
@@ -0,0 +1,27 @@
1
+ """query_database
2
+
3
+ Revision ID: 53502b6d63bf
4
+ Revises: fda503400e43
5
+ Create Date: 2025-04-22 16:30:15.139978
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+ import mindsdb.interfaces.storage.db # noqa
11
+
12
+
13
+ # revision identifiers, used by Alembic.
14
+ revision = '53502b6d63bf'
15
+ down_revision = 'fda503400e43'
16
+ branch_labels = None
17
+ depends_on = None
18
+
19
+
20
+ def upgrade():
21
+ with op.batch_alter_table('queries', schema=None) as batch_op:
22
+ batch_op.add_column(sa.Column('database', sa.String(), nullable=True))
23
+
24
+
25
+ def downgrade():
26
+ with op.batch_alter_table('queries', schema=None) as batch_op:
27
+ batch_op.drop_column('database')
@@ -209,6 +209,10 @@ class Config:
209
209
  "restart_on_failure": True,
210
210
  "max_restart_count": 1,
211
211
  "max_restart_interval_seconds": 60
212
+ },
213
+ "litellm": {
214
+ "host": "0.0.0.0", # API server binds to all interfaces by default
215
+ "port": "8000"
212
216
  }
213
217
  },
214
218
  "cache": {
@@ -226,7 +230,9 @@ class Config:
226
230
  "tasks": {
227
231
  "disable": False
228
232
  },
229
- "default_project": "mindsdb"
233
+ "default_project": "mindsdb",
234
+ "default_llm": {},
235
+ "default_embedding_model": {}
230
236
  }
231
237
  # endregion
232
238
 
@@ -365,6 +371,15 @@ class Config:
365
371
  if os.environ.get('MINDSDB_DEFAULT_PROJECT', '') != '':
366
372
  self._env_config['default_project'] = os.environ['MINDSDB_DEFAULT_PROJECT'].lower()
367
373
 
374
+ if os.environ.get('MINDSDB_DEFAULT_LLM_API_KEY', '') != '':
375
+ self._env_config['default_llm'] = {
376
+ 'api_key': os.environ['MINDSDB_DEFAULT_LLM_API_KEY']
377
+ }
378
+ if os.environ.get('MINDSDB_DEFAULT_EMBEDDING_MODEL_API_KEY', '') != '':
379
+ self._env_config['default_embedding_model'] = {
380
+ 'api_key': os.environ['MINDSDB_DEFAULT_EMBEDDING_MODEL_API_KEY']
381
+ }
382
+
368
383
  def parse_cmd_args(self) -> None:
369
384
  """Collect cmd args to self._cmd_args (accessable as self.cmd_args)
370
385
  """
@@ -378,7 +393,8 @@ class Config:
378
393
  ):
379
394
  self._cmd_args = argparse.Namespace(
380
395
  api=None, config=None, install_handlers=None, verbose=False,
381
- no_studio=False, version=False, ml_task_queue_consumer=None
396
+ no_studio=False, version=False, ml_task_queue_consumer=None,
397
+ agent=None, project=None
382
398
  )
383
399
  return
384
400
 
@@ -390,6 +406,8 @@ class Config:
390
406
  parser.add_argument('--no_studio', action='store_true')
391
407
  parser.add_argument('-v', '--version', action='store_true')
392
408
  parser.add_argument('--ml_task_queue_consumer', action='store_true', default=None)
409
+ parser.add_argument('--agent', type=str, default=None, help='Name of the agent to use with litellm APIs')
410
+ parser.add_argument('--project', type=str, default=None, help='Project containing the agent (default: mindsdb)')
393
411
  self._cmd_args = parser.parse_args()
394
412
 
395
413
  def fetch_auto_config(self) -> bool:
@@ -18,6 +18,7 @@ class Context:
18
18
  'user_id': None,
19
19
  'company_id': None,
20
20
  'session_id': "",
21
+ 'task_id': None,
21
22
  'user_class': 0,
22
23
  'profiling': {
23
24
  'level': 0,
@@ -38,3 +38,10 @@ def start_mcp(*args, **kwargs):
38
38
  from mindsdb.api.mcp.start import start
39
39
 
40
40
  start(*args, **kwargs)
41
+
42
+
43
+ def start_litellm(*args, **kwargs):
44
+ """Start the LiteLLM server"""
45
+ from mindsdb.api.litellm.start import start
46
+
47
+ start(*args, **kwargs)