MindsDB 25.6.2.0__py3-none-any.whl → 25.6.3.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 (30) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/api/a2a/agent.py +25 -4
  3. mindsdb/api/a2a/task_manager.py +68 -6
  4. mindsdb/api/executor/datahub/datanodes/mindsdb_tables.py +91 -84
  5. mindsdb/api/http/namespaces/knowledge_bases.py +132 -154
  6. mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +219 -28
  7. mindsdb/integrations/handlers/llama_index_handler/requirements.txt +1 -1
  8. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +3 -0
  9. mindsdb/integrations/handlers/openai_handler/openai_handler.py +277 -356
  10. mindsdb/integrations/handlers/salesforce_handler/salesforce_handler.py +94 -8
  11. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +19 -1
  12. mindsdb/integrations/libs/api_handler.py +19 -1
  13. mindsdb/integrations/libs/base.py +86 -2
  14. mindsdb/interfaces/agents/agents_controller.py +32 -6
  15. mindsdb/interfaces/agents/constants.py +1 -0
  16. mindsdb/interfaces/agents/mindsdb_database_agent.py +23 -18
  17. mindsdb/interfaces/data_catalog/data_catalog_loader.py +22 -6
  18. mindsdb/interfaces/data_catalog/data_catalog_reader.py +4 -0
  19. mindsdb/interfaces/database/integrations.py +4 -2
  20. mindsdb/interfaces/knowledge_base/controller.py +3 -15
  21. mindsdb/interfaces/knowledge_base/evaluate.py +0 -3
  22. mindsdb/interfaces/skills/skills_controller.py +0 -23
  23. mindsdb/interfaces/skills/sql_agent.py +8 -4
  24. mindsdb/interfaces/storage/db.py +20 -4
  25. mindsdb/utilities/config.py +5 -1
  26. {mindsdb-25.6.2.0.dist-info → mindsdb-25.6.3.0.dist-info}/METADATA +250 -250
  27. {mindsdb-25.6.2.0.dist-info → mindsdb-25.6.3.0.dist-info}/RECORD +30 -30
  28. {mindsdb-25.6.2.0.dist-info → mindsdb-25.6.3.0.dist-info}/WHEEL +0 -0
  29. {mindsdb-25.6.2.0.dist-info → mindsdb-25.6.3.0.dist-info}/licenses/LICENSE +0 -0
  30. {mindsdb-25.6.2.0.dist-info → mindsdb-25.6.3.0.dist-info}/top_level.txt +0 -0
@@ -6,8 +6,6 @@ from sqlalchemy.orm.attributes import flag_modified
6
6
 
7
7
  from mindsdb.interfaces.storage import db
8
8
  from mindsdb.interfaces.database.projects import ProjectController
9
- from mindsdb.interfaces.data_catalog.data_catalog_loader import DataCatalogLoader
10
- from mindsdb.interfaces.skills.skill_tool import SkillType
11
9
  from mindsdb.utilities.config import config
12
10
  from mindsdb.utilities import log
13
11
 
@@ -99,27 +97,6 @@ class SkillsController:
99
97
  if skill is not None:
100
98
  raise ValueError(f"Skill with name already exists: {name}")
101
99
 
102
- # Load metadata to data catalog (if enabled) if the skill is Text-to-SQL.
103
- if config.get("data_catalog", {}).get("enabled", False):
104
- if type == SkillType.TEXT2SQL.value and "include_tables" in params:
105
- # TODO: Is it possible to create a skill with complete access to the database with the new agent syntax?
106
- # TODO: Handle the case where `ignore_tables` is provided. Is this a valid parameter?
107
- # TODO: Knowledge Bases?
108
- database_table_map = {}
109
- for table in params["include_tables"]:
110
- parts = table.split(".", 1)
111
- database_table_map[parts[0]] = database_table_map.get(parts[0], []) + [parts[1]]
112
-
113
- for database_name, table_names in database_table_map.items():
114
- data_catalog_loader = DataCatalogLoader(database_name=database_name, table_names=table_names)
115
- data_catalog_loader.load_metadata()
116
-
117
- elif type in [SkillType.TEXT2SQL.value, SkillType.TEXT2SQL_LEGACY.value] and "database" in params:
118
- data_catalog_loader = DataCatalogLoader(
119
- database_name=params["database"], table_names=params["tables"] if "tables" in params else None
120
- )
121
- data_catalog_loader.load_metadata()
122
-
123
100
  new_skill = db.Skills(
124
101
  name=name,
125
102
  project_id=project.id,
@@ -402,11 +402,15 @@ class SQLAgent:
402
402
  """
403
403
  if config.get("data_catalog", {}).get("enabled", False):
404
404
  database_table_map = {}
405
- for name in self.get_usable_table_names():
405
+ for name in table_names or self.get_usable_table_names():
406
406
  name = name.replace("`", "")
407
407
 
408
- # TODO: Can there be situations where the database name is returned from the above method?
409
408
  parts = name.split(".", 1)
409
+ # TODO: Will there be situations where parts has more than 2 elements? Like a schema?
410
+ # This is unlikely given that we default to a single schema per database.
411
+ if len(parts) == 1:
412
+ raise ValueError(f"Invalid table name: {name}. Expected format is 'database.table'.")
413
+
410
414
  database_table_map[parts[0]] = database_table_map.get(parts[0], []) + [parts[1]]
411
415
 
412
416
  data_catalog_str = ""
@@ -430,8 +434,8 @@ class SQLAgent:
430
434
  else:
431
435
  all_tables.append(Identifier(name))
432
436
 
433
- # if table_names is not None:
434
- # all_tables = self._resolve_table_names(table_names, all_tables)
437
+ if table_names is not None:
438
+ all_tables = self._resolve_table_names(table_names, all_tables)
435
439
 
436
440
  tables_info = []
437
441
  for table in all_tables:
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  import datetime
3
- from typing import Dict, List
3
+ from typing import Dict, List, Optional
4
4
 
5
5
  import numpy as np
6
6
  from sqlalchemy import (
@@ -494,17 +494,33 @@ class KnowledgeBase(Base):
494
494
 
495
495
  __table_args__ = (UniqueConstraint("name", "project_id", name="unique_knowledge_base_name_project_id"),)
496
496
 
497
- def as_dict(self) -> Dict:
497
+ def as_dict(self, with_secrets: Optional[bool] = True) -> Dict:
498
+ params = self.params.copy()
499
+ embedding_model = params.pop("embedding_model", None)
500
+ reranking_model = params.pop("reranking_model", None)
501
+
502
+ if not with_secrets:
503
+ if embedding_model and "api_key" in embedding_model:
504
+ embedding_model["api_key"] = "******"
505
+
506
+ if reranking_model and "api_key" in reranking_model:
507
+ reranking_model["api_key"] = "******"
508
+
498
509
  return {
499
510
  "id": self.id,
500
511
  "name": self.name,
501
512
  "project_id": self.project_id,
502
- "embedding_model": None if self.embedding_model is None else self.embedding_model.name,
503
513
  "vector_database": None if self.vector_database is None else self.vector_database.name,
504
514
  "vector_database_table": self.vector_database_table,
505
515
  "updated_at": self.updated_at,
506
516
  "created_at": self.created_at,
507
- "params": self.params,
517
+ "query_id": self.query_id,
518
+ "embedding_model": embedding_model,
519
+ "reranking_model": reranking_model,
520
+ "metadata_columns": params.pop("metadata_columns", None),
521
+ "content_columns": params.pop("content_columns", None),
522
+ "id_column": params.pop("id_column", None),
523
+ "params": params,
508
524
  }
509
525
 
510
526
 
@@ -400,7 +400,11 @@ class Config:
400
400
  bool: True if config was loaded or updated
401
401
  """
402
402
 
403
- if self.auto_config_path.is_file() and self.auto_config_mtime != self.auto_config_path.stat().st_mtime:
403
+ if (
404
+ self.auto_config_path.is_file()
405
+ and self.auto_config_path.read_text() != ""
406
+ and self.auto_config_mtime != self.auto_config_path.stat().st_mtime
407
+ ):
404
408
  try:
405
409
  self._auto_config = json.loads(self.auto_config_path.read_text())
406
410
  except json.JSONDecodeError as e: