MindsDB 25.5.4.2__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.
- mindsdb/__about__.py +1 -1
- mindsdb/api/a2a/agent.py +50 -26
- mindsdb/api/a2a/common/server/server.py +32 -26
- mindsdb/api/a2a/task_manager.py +68 -6
- mindsdb/api/executor/command_executor.py +69 -14
- mindsdb/api/executor/datahub/datanodes/integration_datanode.py +49 -65
- mindsdb/api/executor/datahub/datanodes/mindsdb_tables.py +91 -84
- mindsdb/api/executor/datahub/datanodes/project_datanode.py +29 -48
- mindsdb/api/executor/datahub/datanodes/system_tables.py +35 -61
- mindsdb/api/executor/planner/plan_join.py +67 -77
- mindsdb/api/executor/planner/query_planner.py +176 -155
- mindsdb/api/executor/planner/steps.py +37 -12
- mindsdb/api/executor/sql_query/result_set.py +45 -64
- mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +14 -18
- mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +17 -18
- mindsdb/api/executor/sql_query/steps/insert_step.py +13 -33
- mindsdb/api/executor/sql_query/steps/subselect_step.py +43 -35
- mindsdb/api/executor/utilities/sql.py +42 -48
- mindsdb/api/http/namespaces/config.py +1 -1
- mindsdb/api/http/namespaces/file.py +14 -23
- mindsdb/api/http/namespaces/knowledge_bases.py +132 -154
- mindsdb/api/mysql/mysql_proxy/data_types/mysql_datum.py +12 -28
- mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/binary_resultset_row_package.py +59 -50
- mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/resultset_row_package.py +9 -8
- mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +449 -461
- mindsdb/api/mysql/mysql_proxy/utilities/dump.py +87 -36
- mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +219 -28
- mindsdb/integrations/handlers/file_handler/file_handler.py +15 -9
- mindsdb/integrations/handlers/file_handler/tests/test_file_handler.py +43 -24
- mindsdb/integrations/handlers/litellm_handler/litellm_handler.py +10 -3
- mindsdb/integrations/handlers/llama_index_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +29 -33
- mindsdb/integrations/handlers/openai_handler/openai_handler.py +277 -356
- mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +74 -51
- mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +305 -98
- mindsdb/integrations/handlers/salesforce_handler/salesforce_handler.py +145 -40
- mindsdb/integrations/handlers/salesforce_handler/salesforce_tables.py +136 -6
- mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +352 -83
- mindsdb/integrations/libs/api_handler.py +279 -57
- mindsdb/integrations/libs/base.py +185 -30
- mindsdb/integrations/utilities/files/file_reader.py +99 -73
- mindsdb/integrations/utilities/handler_utils.py +23 -8
- mindsdb/integrations/utilities/sql_utils.py +35 -40
- mindsdb/interfaces/agents/agents_controller.py +226 -196
- mindsdb/interfaces/agents/constants.py +8 -1
- mindsdb/interfaces/agents/langchain_agent.py +42 -11
- mindsdb/interfaces/agents/mcp_client_agent.py +29 -21
- mindsdb/interfaces/agents/mindsdb_database_agent.py +23 -18
- mindsdb/interfaces/data_catalog/__init__.py +0 -0
- mindsdb/interfaces/data_catalog/base_data_catalog.py +54 -0
- mindsdb/interfaces/data_catalog/data_catalog_loader.py +375 -0
- mindsdb/interfaces/data_catalog/data_catalog_reader.py +38 -0
- mindsdb/interfaces/database/database.py +81 -57
- mindsdb/interfaces/database/integrations.py +222 -234
- mindsdb/interfaces/database/log.py +72 -104
- mindsdb/interfaces/database/projects.py +156 -193
- mindsdb/interfaces/file/file_controller.py +21 -65
- mindsdb/interfaces/knowledge_base/controller.py +66 -25
- mindsdb/interfaces/knowledge_base/evaluate.py +516 -0
- mindsdb/interfaces/knowledge_base/llm_client.py +75 -0
- mindsdb/interfaces/skills/custom/text2sql/mindsdb_kb_tools.py +83 -43
- mindsdb/interfaces/skills/skills_controller.py +31 -36
- mindsdb/interfaces/skills/sql_agent.py +113 -86
- mindsdb/interfaces/storage/db.py +242 -82
- mindsdb/migrations/versions/2025-05-28_a44643042fe8_added_data_catalog_tables.py +118 -0
- mindsdb/migrations/versions/2025-06-09_608e376c19a7_updated_data_catalog_data_types.py +58 -0
- mindsdb/utilities/config.py +13 -2
- mindsdb/utilities/log.py +35 -26
- mindsdb/utilities/ml_task_queue/task.py +19 -22
- mindsdb/utilities/render/sqlalchemy_render.py +129 -181
- mindsdb/utilities/starters.py +40 -0
- {mindsdb-25.5.4.2.dist-info → mindsdb-25.6.3.0.dist-info}/METADATA +257 -257
- {mindsdb-25.5.4.2.dist-info → mindsdb-25.6.3.0.dist-info}/RECORD +76 -68
- {mindsdb-25.5.4.2.dist-info → mindsdb-25.6.3.0.dist-info}/WHEEL +0 -0
- {mindsdb-25.5.4.2.dist-info → mindsdb-25.6.3.0.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.5.4.2.dist-info → mindsdb-25.6.3.0.dist-info}/top_level.txt +0 -0
|
@@ -39,22 +39,36 @@ def get_api_key(
|
|
|
39
39
|
if "using" in create_args and f"{api_name.lower()}_api_key" in create_args["using"]:
|
|
40
40
|
return create_args["using"][f"{api_name.lower()}_api_key"]
|
|
41
41
|
|
|
42
|
+
# 1.5 - Check for generic api_key in using
|
|
43
|
+
if "using" in create_args and "api_key" in create_args["using"]:
|
|
44
|
+
return create_args["using"]["api_key"]
|
|
45
|
+
|
|
42
46
|
# 2
|
|
43
47
|
if f"{api_name.lower()}_api_key" in create_args:
|
|
44
48
|
return create_args[f"{api_name.lower()}_api_key"]
|
|
45
49
|
|
|
46
|
-
# 2.5 - Check
|
|
50
|
+
# 2.5 - Check for generic api_key
|
|
51
|
+
if "api_key" in create_args:
|
|
52
|
+
return create_args["api_key"]
|
|
53
|
+
|
|
54
|
+
# 3 - Check in params dictionary if it exists (for agents)
|
|
47
55
|
if "params" in create_args and create_args["params"] is not None:
|
|
48
56
|
if f"{api_name.lower()}_api_key" in create_args["params"]:
|
|
49
57
|
return create_args["params"][f"{api_name.lower()}_api_key"]
|
|
58
|
+
# 3.5 - Check for generic api_key in params
|
|
59
|
+
if "api_key" in create_args["params"]:
|
|
60
|
+
return create_args["params"]["api_key"]
|
|
50
61
|
|
|
51
|
-
#
|
|
62
|
+
# 4
|
|
52
63
|
if engine_storage is not None:
|
|
53
64
|
connection_args = engine_storage.get_connection_args()
|
|
54
65
|
if f"{api_name.lower()}_api_key" in connection_args:
|
|
55
66
|
return connection_args[f"{api_name.lower()}_api_key"]
|
|
67
|
+
# 4.5 - Check for generic api_key in connection_args
|
|
68
|
+
if "api_key" in connection_args:
|
|
69
|
+
return connection_args["api_key"]
|
|
56
70
|
|
|
57
|
-
#
|
|
71
|
+
# 5
|
|
58
72
|
api_key = os.getenv(f"{api_name.lower()}_api_key")
|
|
59
73
|
if api_key is not None:
|
|
60
74
|
return api_key
|
|
@@ -62,15 +76,15 @@ def get_api_key(
|
|
|
62
76
|
if api_key is not None:
|
|
63
77
|
return api_key
|
|
64
78
|
|
|
65
|
-
#
|
|
79
|
+
# 6
|
|
66
80
|
config = Config()
|
|
67
81
|
api_cfg = config.get(api_name, {})
|
|
68
82
|
if f"{api_name.lower()}_api_key" in api_cfg:
|
|
69
83
|
return api_cfg[f"{api_name.lower()}_api_key"]
|
|
70
84
|
|
|
71
|
-
#
|
|
72
|
-
if
|
|
73
|
-
return create_args[
|
|
85
|
+
# 7
|
|
86
|
+
if "api_keys" in create_args and api_name in create_args["api_keys"]:
|
|
87
|
+
return create_args["api_keys"][api_name]
|
|
74
88
|
|
|
75
89
|
if strict:
|
|
76
90
|
provider_upper = api_name.upper()
|
|
@@ -79,8 +93,9 @@ def get_api_key(
|
|
|
79
93
|
error_message = (
|
|
80
94
|
f"API key for {api_name} not found. Please provide it using one of the following methods:\n"
|
|
81
95
|
f"1. Set the {api_key_env_var} environment variable\n"
|
|
82
|
-
f"2. Provide it as '{api_key_arg}' parameter when creating an agent using the CREATE AGENT syntax\n"
|
|
96
|
+
f"2. Provide it as '{api_key_arg}' parameter or 'api_key' parameter when creating an agent using the CREATE AGENT syntax\n"
|
|
83
97
|
f" Example: CREATE AGENT my_agent USING model='gpt-4', provider='{api_name}', {api_key_arg}='your-api-key';\n"
|
|
98
|
+
f" Or: CREATE AGENT my_agent USING model='gpt-4', provider='{api_name}', api_key='your-api-key';\n"
|
|
84
99
|
)
|
|
85
100
|
raise Exception(error_message)
|
|
86
101
|
return None
|
|
@@ -46,11 +46,7 @@ class FilterCondition:
|
|
|
46
46
|
|
|
47
47
|
def __eq__(self, __value: object) -> bool:
|
|
48
48
|
if isinstance(__value, FilterCondition):
|
|
49
|
-
return
|
|
50
|
-
self.column == __value.column
|
|
51
|
-
and self.op == __value.op
|
|
52
|
-
and self.value == __value.value
|
|
53
|
-
)
|
|
49
|
+
return self.column == __value.column and self.op == __value.op and self.value == __value.value
|
|
54
50
|
else:
|
|
55
51
|
return False
|
|
56
52
|
|
|
@@ -75,7 +71,7 @@ def make_sql_session():
|
|
|
75
71
|
from mindsdb.api.executor.controllers.session_controller import SessionController
|
|
76
72
|
|
|
77
73
|
sql_session = SessionController()
|
|
78
|
-
sql_session.database = config.get(
|
|
74
|
+
sql_session.database = config.get("default_project")
|
|
79
75
|
return sql_session
|
|
80
76
|
|
|
81
77
|
|
|
@@ -84,44 +80,50 @@ def conditions_to_filter(binary_op: ASTNode):
|
|
|
84
80
|
|
|
85
81
|
filters = {}
|
|
86
82
|
for op, arg1, arg2 in conditions:
|
|
87
|
-
if op !=
|
|
83
|
+
if op != "=":
|
|
88
84
|
raise NotImplementedError
|
|
89
85
|
filters[arg1] = arg2
|
|
90
86
|
return filters
|
|
91
87
|
|
|
92
88
|
|
|
93
|
-
def extract_comparison_conditions(binary_op: ASTNode):
|
|
94
|
-
|
|
89
|
+
def extract_comparison_conditions(binary_op: ASTNode, ignore_functions=False):
|
|
90
|
+
"""Extracts all simple comparison conditions that must be true from an AST node.
|
|
95
91
|
Does NOT support 'or' conditions.
|
|
96
|
-
|
|
92
|
+
"""
|
|
97
93
|
conditions = []
|
|
98
94
|
|
|
99
95
|
def _extract_comparison_conditions(node: ASTNode, **kwargs):
|
|
100
96
|
if isinstance(node, ast.BinaryOperation):
|
|
101
97
|
op = node.op.lower()
|
|
102
|
-
if op ==
|
|
98
|
+
if op == "and":
|
|
103
99
|
# Want to separate individual conditions, not include 'and' as its own condition.
|
|
104
100
|
return
|
|
105
|
-
|
|
101
|
+
|
|
102
|
+
arg1, arg2 = node.args
|
|
103
|
+
if ignore_functions and isinstance(arg1, ast.Function):
|
|
104
|
+
# handle lower/upper
|
|
105
|
+
if arg1.op.lower() in ("lower", "upper"):
|
|
106
|
+
if isinstance(arg1.args[0], ast.Identifier):
|
|
107
|
+
arg1 = arg1.args[0]
|
|
108
|
+
|
|
109
|
+
if not isinstance(arg1, ast.Identifier):
|
|
106
110
|
# Only support [identifier] =/</>/>=/<=/etc [constant] comparisons.
|
|
107
|
-
raise NotImplementedError(f
|
|
111
|
+
raise NotImplementedError(f"Not implemented arg1: {arg1}")
|
|
108
112
|
|
|
109
|
-
if isinstance(
|
|
110
|
-
value =
|
|
111
|
-
elif isinstance(
|
|
112
|
-
value = [i.value for i in
|
|
113
|
+
if isinstance(arg2, ast.Constant):
|
|
114
|
+
value = arg2.value
|
|
115
|
+
elif isinstance(arg2, ast.Tuple):
|
|
116
|
+
value = [i.value for i in arg2.items]
|
|
113
117
|
else:
|
|
114
|
-
raise NotImplementedError(f
|
|
118
|
+
raise NotImplementedError(f"Not implemented arg2: {arg2}")
|
|
115
119
|
|
|
116
|
-
conditions.append([op,
|
|
120
|
+
conditions.append([op, arg1.parts[-1], value])
|
|
117
121
|
if isinstance(node, ast.BetweenOperation):
|
|
118
122
|
var, up, down = node.args
|
|
119
123
|
if not (
|
|
120
|
-
isinstance(var, ast.Identifier)
|
|
121
|
-
and isinstance(up, ast.Constant)
|
|
122
|
-
and isinstance(down, ast.Constant)
|
|
124
|
+
isinstance(var, ast.Identifier) and isinstance(up, ast.Constant) and isinstance(down, ast.Constant)
|
|
123
125
|
):
|
|
124
|
-
raise NotImplementedError(f
|
|
126
|
+
raise NotImplementedError(f"Not implemented: {node}")
|
|
125
127
|
|
|
126
128
|
op = node.op.lower()
|
|
127
129
|
conditions.append([op, var.parts[-1], (up.value, down.value)])
|
|
@@ -131,16 +133,13 @@ def extract_comparison_conditions(binary_op: ASTNode):
|
|
|
131
133
|
|
|
132
134
|
|
|
133
135
|
def project_dataframe(df, targets, table_columns):
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
"""
|
|
137
|
+
case-insensitive projection
|
|
138
|
+
'select A' and 'select a' return different column case but with the same content
|
|
139
|
+
"""
|
|
138
140
|
|
|
139
141
|
columns = []
|
|
140
|
-
df_cols_idx = {
|
|
141
|
-
col.lower(): col
|
|
142
|
-
for col in df.columns
|
|
143
|
-
}
|
|
142
|
+
df_cols_idx = {col.lower(): col for col in df.columns}
|
|
144
143
|
df_col_rename = {}
|
|
145
144
|
|
|
146
145
|
for target in targets:
|
|
@@ -156,10 +155,7 @@ def project_dataframe(df, targets, table_columns):
|
|
|
156
155
|
col = target.parts[-1]
|
|
157
156
|
col_df = df_cols_idx.get(col.lower())
|
|
158
157
|
if col_df is not None:
|
|
159
|
-
if (
|
|
160
|
-
hasattr(target, 'alias')
|
|
161
|
-
and isinstance(target.alias, ast.Identifier)
|
|
162
|
-
):
|
|
158
|
+
if hasattr(target, "alias") and isinstance(target.alias, ast.Identifier):
|
|
163
159
|
df_col_rename[col_df] = target.alias.parts[0]
|
|
164
160
|
else:
|
|
165
161
|
df_col_rename[col_df] = col
|
|
@@ -184,14 +180,13 @@ def project_dataframe(df, targets, table_columns):
|
|
|
184
180
|
|
|
185
181
|
|
|
186
182
|
def filter_dataframe(df: pd.DataFrame, conditions: list):
|
|
187
|
-
|
|
188
183
|
# convert list of conditions to ast.
|
|
189
184
|
# assumes that list was got from extract_comparison_conditions
|
|
190
185
|
where_query = None
|
|
191
186
|
for op, arg1, arg2 in conditions:
|
|
192
187
|
op = op.lower()
|
|
193
188
|
|
|
194
|
-
if op ==
|
|
189
|
+
if op == "between":
|
|
195
190
|
item = ast.BetweenOperation(args=[ast.Identifier(arg1), ast.Constant(arg2[0]), ast.Constant(arg2[1])])
|
|
196
191
|
else:
|
|
197
192
|
if isinstance(arg2, (tuple, list)):
|
|
@@ -201,9 +196,9 @@ def filter_dataframe(df: pd.DataFrame, conditions: list):
|
|
|
201
196
|
if where_query is None:
|
|
202
197
|
where_query = item
|
|
203
198
|
else:
|
|
204
|
-
where_query = ast.BinaryOperation(op=
|
|
199
|
+
where_query = ast.BinaryOperation(op="and", args=[where_query, item])
|
|
205
200
|
|
|
206
|
-
query = ast.Select(targets=[ast.Star()], from_table=ast.Identifier(
|
|
201
|
+
query = ast.Select(targets=[ast.Star()], from_table=ast.Identifier("df"), where=where_query)
|
|
207
202
|
|
|
208
203
|
return query_df(df, query)
|
|
209
204
|
|
|
@@ -220,7 +215,7 @@ def sort_dataframe(df, order_by: list):
|
|
|
220
215
|
continue
|
|
221
216
|
|
|
222
217
|
cols.append(col)
|
|
223
|
-
ascending.append(False if order.direction.lower() ==
|
|
218
|
+
ascending.append(False if order.direction.lower() == "desc" else True)
|
|
224
219
|
if len(cols) > 0:
|
|
225
220
|
df = df.sort_values(by=cols, ascending=ascending)
|
|
226
221
|
return df
|