MindsDB 25.1.2.1__py3-none-any.whl → 25.1.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 (95) hide show
  1. {MindsDB-25.1.2.1.dist-info → MindsDB-25.1.5.0.dist-info}/METADATA +246 -255
  2. {MindsDB-25.1.2.1.dist-info → MindsDB-25.1.5.0.dist-info}/RECORD +94 -83
  3. mindsdb/__about__.py +1 -1
  4. mindsdb/__main__.py +5 -3
  5. mindsdb/api/executor/__init__.py +0 -1
  6. mindsdb/api/executor/command_executor.py +2 -1
  7. mindsdb/api/executor/data_types/answer.py +1 -1
  8. mindsdb/api/executor/datahub/datanodes/datanode.py +1 -1
  9. mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +1 -1
  10. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +8 -3
  11. mindsdb/api/executor/datahub/datanodes/project_datanode.py +9 -26
  12. mindsdb/api/executor/sql_query/__init__.py +1 -0
  13. mindsdb/api/executor/sql_query/result_set.py +36 -21
  14. mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +1 -1
  15. mindsdb/api/executor/sql_query/steps/join_step.py +4 -4
  16. mindsdb/api/executor/sql_query/steps/map_reduce_step.py +6 -39
  17. mindsdb/api/executor/utilities/sql.py +2 -10
  18. mindsdb/api/http/namespaces/agents.py +3 -1
  19. mindsdb/api/http/namespaces/knowledge_bases.py +3 -3
  20. mindsdb/api/http/namespaces/sql.py +3 -1
  21. mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +2 -1
  22. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +7 -0
  23. mindsdb/api/postgres/postgres_proxy/executor/executor.py +2 -1
  24. mindsdb/integrations/handlers/chromadb_handler/chromadb_handler.py +2 -2
  25. mindsdb/integrations/handlers/chromadb_handler/requirements.txt +1 -1
  26. mindsdb/integrations/handlers/databricks_handler/requirements.txt +1 -1
  27. mindsdb/integrations/handlers/file_handler/file_handler.py +1 -1
  28. mindsdb/integrations/handlers/file_handler/requirements.txt +0 -4
  29. mindsdb/integrations/handlers/file_handler/tests/test_file_handler.py +17 -1
  30. mindsdb/integrations/handlers/jira_handler/jira_handler.py +15 -1
  31. mindsdb/integrations/handlers/jira_handler/jira_table.py +52 -31
  32. mindsdb/integrations/handlers/langchain_embedding_handler/fastapi_embeddings.py +82 -0
  33. mindsdb/integrations/handlers/langchain_embedding_handler/langchain_embedding_handler.py +8 -1
  34. mindsdb/integrations/handlers/langchain_handler/requirements.txt +1 -1
  35. mindsdb/integrations/handlers/ms_one_drive_handler/ms_one_drive_handler.py +1 -1
  36. mindsdb/integrations/handlers/ms_one_drive_handler/ms_one_drive_tables.py +8 -0
  37. mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +50 -16
  38. mindsdb/integrations/handlers/pinecone_handler/pinecone_handler.py +123 -72
  39. mindsdb/integrations/handlers/pinecone_handler/requirements.txt +1 -1
  40. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +12 -6
  41. mindsdb/integrations/handlers/ray_serve_handler/ray_serve_handler.py +5 -3
  42. mindsdb/integrations/handlers/slack_handler/slack_handler.py +13 -2
  43. mindsdb/integrations/handlers/slack_handler/slack_tables.py +21 -1
  44. mindsdb/integrations/handlers/web_handler/requirements.txt +0 -1
  45. mindsdb/integrations/libs/ml_handler_process/learn_process.py +2 -2
  46. mindsdb/integrations/utilities/files/__init__.py +0 -0
  47. mindsdb/integrations/utilities/files/file_reader.py +258 -0
  48. mindsdb/integrations/utilities/handlers/api_utilities/microsoft/ms_graph_api_utilities.py +2 -1
  49. mindsdb/integrations/utilities/handlers/auth_utilities/microsoft/ms_graph_api_auth_utilities.py +8 -3
  50. mindsdb/integrations/utilities/rag/chains/map_reduce_summarizer_chain.py +5 -9
  51. mindsdb/integrations/utilities/rag/loaders/vector_store_loader/pgvector.py +76 -27
  52. mindsdb/integrations/utilities/rag/loaders/vector_store_loader/vector_store_loader.py +18 -1
  53. mindsdb/integrations/utilities/rag/pipelines/rag.py +74 -21
  54. mindsdb/integrations/utilities/rag/rerankers/reranker_compressor.py +166 -108
  55. mindsdb/integrations/utilities/rag/retrievers/sql_retriever.py +108 -78
  56. mindsdb/integrations/utilities/rag/settings.py +37 -16
  57. mindsdb/integrations/utilities/sql_utils.py +1 -1
  58. mindsdb/interfaces/agents/agents_controller.py +18 -8
  59. mindsdb/interfaces/agents/constants.py +1 -0
  60. mindsdb/interfaces/agents/langchain_agent.py +124 -157
  61. mindsdb/interfaces/agents/langfuse_callback_handler.py +4 -37
  62. mindsdb/interfaces/agents/mindsdb_database_agent.py +21 -13
  63. mindsdb/interfaces/chatbot/chatbot_controller.py +7 -11
  64. mindsdb/interfaces/chatbot/chatbot_task.py +16 -5
  65. mindsdb/interfaces/chatbot/memory.py +58 -13
  66. mindsdb/interfaces/database/integrations.py +5 -1
  67. mindsdb/interfaces/database/projects.py +55 -16
  68. mindsdb/interfaces/database/views.py +12 -25
  69. mindsdb/interfaces/knowledge_base/controller.py +39 -15
  70. mindsdb/interfaces/knowledge_base/preprocessing/document_loader.py +7 -26
  71. mindsdb/interfaces/model/functions.py +15 -4
  72. mindsdb/interfaces/model/model_controller.py +4 -7
  73. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +51 -40
  74. mindsdb/interfaces/skills/retrieval_tool.py +10 -3
  75. mindsdb/interfaces/skills/skill_tool.py +97 -54
  76. mindsdb/interfaces/skills/skills_controller.py +7 -3
  77. mindsdb/interfaces/skills/sql_agent.py +127 -41
  78. mindsdb/interfaces/storage/db.py +1 -1
  79. mindsdb/migrations/versions/2025-01-15_c06c35f7e8e1_project_company.py +88 -0
  80. mindsdb/utilities/cache.py +7 -4
  81. mindsdb/utilities/context.py +11 -1
  82. mindsdb/utilities/langfuse.py +279 -0
  83. mindsdb/utilities/log.py +20 -2
  84. mindsdb/utilities/otel/__init__.py +206 -0
  85. mindsdb/utilities/otel/logger.py +25 -0
  86. mindsdb/utilities/otel/meter.py +19 -0
  87. mindsdb/utilities/otel/metric_handlers/__init__.py +25 -0
  88. mindsdb/utilities/otel/tracer.py +16 -0
  89. mindsdb/utilities/partitioning.py +52 -0
  90. mindsdb/utilities/render/sqlalchemy_render.py +7 -1
  91. mindsdb/utilities/utils.py +34 -0
  92. mindsdb/utilities/otel.py +0 -72
  93. {MindsDB-25.1.2.1.dist-info → MindsDB-25.1.5.0.dist-info}/LICENSE +0 -0
  94. {MindsDB-25.1.2.1.dist-info → MindsDB-25.1.5.0.dist-info}/WHEEL +0 -0
  95. {MindsDB-25.1.2.1.dist-info → MindsDB-25.1.5.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  from typing import List
2
+ from textwrap import dedent
2
3
 
3
4
  from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
4
5
  from langchain_community.tools import ListSQLDatabaseTool, InfoSQLDatabaseTool, QuerySQLDataBaseTool
@@ -11,57 +12,67 @@ class MindsDBSQLToolkit(SQLDatabaseToolkit):
11
12
 
12
13
  def get_tools(self, prefix='') -> List[BaseTool]:
13
14
  """Get the tools in the toolkit."""
14
- list_sql_database_tool = ListSQLDatabaseTool(name=f'sql_db_list_tables{prefix}', db=self.db)
15
+ list_sql_database_tool = ListSQLDatabaseTool(
16
+ name=f'sql_db_list_tables{prefix}',
17
+ db=self.db,
18
+ description=(
19
+ "Input is an empty string, output is a comma-separated list of tables in the database. "
20
+ "Each table name in the list may be in one of two formats: database_name.table_name or "
21
+ "database_name.schema_name.table_name."
22
+ "If the table name is enclosed in backticks marks, then always use the table name with backticks marks in subsequent queries."
23
+ )
24
+ )
15
25
 
16
26
  info_sql_database_tool_description = (
17
- "Input: A comma-separated list of tables. Output: Schema and sample rows for those tables. "
27
+ "Input: A comma-separated list of tables enclosed between the symbols $START$ and $END$. Output: Schema and sample rows for those tables. "
18
28
  f"Ensure tables exist by calling {list_sql_database_tool.name} first. "
19
29
  "Use this tool to investigate table schemas for needed columns. "
20
30
  "Get sample data with 'SELECT * FROM table LIMIT 3' before answering questions. "
21
- "Example Input: table1, table2, table3"
31
+ "Example Input: $START$ table1, table2, table3 $END$"
22
32
  )
23
33
  info_sql_database_tool = InfoSQLDatabaseTool(
24
34
  name=f'sql_db_schema{prefix}',
25
35
  db=self.db, description=info_sql_database_tool_description
26
36
  )
27
37
 
28
- query_sql_database_tool_description = (
29
- "Input: A detailed SQL query. Output: Database result or error message. "
30
- "For errors, rewrite and retry the query. For 'Unknown column' errors, use "
31
- f"{info_sql_database_tool.name} to check table fields. "
32
- "This system is a highly intelligent and reliable PostgreSQL SQL skill designed to work with databases. "
33
- "Follow these instructions with utmost precision: "
34
- "1. Query Output Format: "
35
- " - Always return results in well-formatted **Markdown tables**. "
36
- " - Ensure clarity and proper structure for easy readability. "
37
- "2. Sample Data: "
38
- " - Before answering a question, if you don't have sample data about a table, **always** get sample data using `SELECT * FROM table LIMIT 3` from the tables you believe are relevant to formulating your answers. "
39
- "3. Categorical Data: "
40
- " - Whenever working with a column where values seem categorical, especially when filtering with `WHERE col = 'value'`, `WHERE col IN (list of values)`, or `WHERE col NOT IN (list of values)`, **always** retrieve the distinct values first. "
41
- " - Before writing your main query, always run `SELECT DISTINCT col` to fetch a list of unique values from that column. This step is mandatory to ensure accurate queries and responses. "
42
- "4. Result Limiting and Counting: "
43
- " - Unless instructed otherwise by the user, always run a count on the final query first using `SELECT COUNT(*)`. "
44
- " - If the count is greater than 10, limit the query to return only 10 results initially. "
45
- " - **Always** inform the user of the total number of results available and specify that you are providing the first 10 results. "
46
- " - Let the user know they can request additional results and/or specify how they would like the results ordered or grouped. "
47
- "5. Date Handling: "
48
- " - **Always** use PostgreSQL-compatible `CURRENT_DATE` or `NOW()` functions when working with dates—never assume or guess the current date. "
49
- " - For any date-related comparisons in the query, *always* ensure that your query casts the column being compared using `column_name::DATE [operator] ..` "
50
- " - Do not compare date values without casting columns to date. "
51
- " - For date interval operations, use Interval units as keywords. You can use keywords to specify units like days, hours, months, years, etc., directly without quotes. Examples: "
52
- " SELECT NOW() + INTERVAL 5 DAY; "
53
- " SELECT NOW() - INTERVAL 3 HOUR; "
54
- " SELECT NOW() + INTERVAL 2 MONTH + INTERVAL 3 DAY; "
55
- " SELECT NOW() - INTERVAL 1 YEAR; "
56
- "6. Query Best Practices: "
57
- " - Query only necessary columns, not all. "
58
- " - Use only existing column names from correct tables. "
59
- " - Use database-specific syntax for date operations. "
60
- "7. Error Handling: "
61
- " - For errors, rewrite and retry the query. "
62
- " - For 'Unknown column' errors, check table fields using info_sql_database_tool. "
63
- "Adhere to these guidelines for all queries and responses. Ask for clarification if needed."
64
- )
38
+ query_sql_database_tool_description = dedent(f"""\
39
+ Input: A detailed SQL query.
40
+ Output: Database result or error message. For errors, rewrite and retry the query. For 'Unknown column' errors, use '{info_sql_database_tool.name}' to check table fields.
41
+ This system is a highly intelligent and reliable PostgreSQL SQL skill designed to work with databases.
42
+ Follow these instructions with utmost precision:
43
+ 1. Query Output Format:
44
+ - Always return results in well-formatted **Markdown tables**.
45
+ - Ensure clarity and proper structure for easy readability.
46
+ 2. Sample Data:
47
+ - Before answering a question, if you don't have sample data about a table, **always** get sample data using `SELECT * FROM table LIMIT 3` from the tables you believe are relevant to formulating your answers.
48
+ 3. Categorical Data:
49
+ - Whenever working with a column where values seem categorical, especially when filtering with `WHERE col = 'value'`, `WHERE col IN (list of values)`, or `WHERE col NOT IN (list of values)`, **always** retrieve the distinct values first.
50
+ - Before writing your main query, always run `SELECT DISTINCT col` to fetch a list of unique values from that column. This step is mandatory to ensure accurate queries and responses.
51
+ 4. Result Limiting and Counting:
52
+ - Unless instructed otherwise by the user, always run a count on the final query first using `SELECT COUNT(*)`.
53
+ - If the count is greater than 10, limit the query to return only 10 results initially.
54
+ - **Always** inform the user of the total number of results available and specify that you are providing the first 10 results.
55
+ - Let the user know they can request additional results and/or specify how they would like the results ordered or grouped.
56
+ 5. Date Handling:
57
+ - **Always** use PostgreSQL-compatible `CURRENT_DATE` or `NOW()` functions when working with dates—never assume or guess the current date.
58
+ - For any date-related comparisons in the query, *always* ensure that your query casts the column being compared using `column_name::DATE [operator] ..`
59
+ - Do not compare date values without casting columns to date.
60
+ - For date interval operations, use Interval units as keywords. You can use keywords to specify units like days, hours, months, years, etc., directly without quotes. Examples:
61
+ SELECT NOW() + INTERVAL 5 DAY;
62
+ SELECT NOW() - INTERVAL 3 HOUR;
63
+ SELECT NOW() + INTERVAL 2 MONTH + INTERVAL 3 DAY;
64
+ SELECT NOW() - INTERVAL 1 YEAR;
65
+ 6. Query Best Practices:
66
+ - Always send only one query at a time.
67
+ - The input SQL query must end with a semicolon.
68
+ - Query only necessary columns, not all.
69
+ - Use only existing column names from correct tables.
70
+ - Use database-specific syntax for date operations.
71
+ 7. Error Handling:
72
+ - For errors, rewrite and retry the query.
73
+ - For 'Unknown column' errors, check table fields using info_sql_database_tool.
74
+ Adhere to these guidelines for all queries and responses. Ask for clarification if needed.
75
+ """)
65
76
 
66
77
  query_sql_database_tool = QuerySQLDataBaseTool(
67
78
  name=f'sql_db_query{prefix}',
@@ -43,10 +43,17 @@ def build_retrieval_tool(tool: dict, pred_args: dict, skill: db.Skills):
43
43
  raise ValueError(f"Knowledge base not found: {kb_name}")
44
44
 
45
45
  kb_table = executor.session.kb_controller.get_table(kb.name, kb.project_id)
46
+ vector_store_config = {
47
+ 'kb_table': kb_table
48
+ }
49
+ is_sparse = tools_config.pop('is_sparse', None)
50
+ vector_size = tools_config.pop('vector_size', None)
51
+ if is_sparse is not None:
52
+ vector_store_config['is_sparse'] = is_sparse
53
+ if vector_size is not None:
54
+ vector_store_config['vector_size'] = vector_size
46
55
  kb_params = {
47
- 'vector_store_config': {
48
- 'kb_table': kb_table
49
- }
56
+ 'vector_store_config': vector_store_config
50
57
  }
51
58
 
52
59
  # Get embedding model from knowledge base table
@@ -1,17 +1,18 @@
1
1
  import enum
2
- from collections import defaultdict
3
- from typing import List, Optional
2
+ import inspect
4
3
  from dataclasses import dataclass
4
+ from collections import defaultdict
5
+ from typing import List, Dict, Optional
5
6
 
6
7
  from langchain_core.embeddings import Embeddings
7
8
  from langchain_core.language_models import BaseChatModel
8
9
  from mindsdb_sql_parser.ast import Select, BinaryOperation, Identifier, Constant, Star
9
10
 
10
- from mindsdb.integrations.libs.vectordatabase_handler import TableField
11
- from mindsdb.interfaces.skills.sql_agent import SQLAgent
12
- from mindsdb.interfaces.storage import db
13
11
  from mindsdb.utilities import log
14
12
  from mindsdb.utilities.cache import get_cache
13
+ from mindsdb.interfaces.storage import db
14
+ from mindsdb.interfaces.skills.sql_agent import SQLAgent
15
+ from mindsdb.integrations.libs.vectordatabase_handler import TableField
15
16
 
16
17
 
17
18
  _DEFAULT_TOP_K_SIMILARITY_SEARCH = 5
@@ -45,27 +46,54 @@ class SkillData:
45
46
  agent_tables_list: Optional[List[str]]
46
47
 
47
48
  @property
48
- def tables_list(self) -> List[str]:
49
- """List of tables which may use this skill. If the list is empty, there are no restrictions.
50
- The result list is a combination of skill's and agent's tables lists.
49
+ def restriction_on_tables(self) -> Optional[Dict[str, set]]:
50
+ """Schemas and tables which agent+skill may use. The result is intersections of skill's and agent's tables lists.
51
51
 
52
52
  Returns:
53
- List[str]: List of tables.
53
+ Optional[Dict[str, set]]: allowed schemas and tables. Schemas - are keys in dict, tables - are values.
54
+ if result is None, then there are no restrictions
54
55
 
55
56
  Raises:
56
57
  ValueError: if there is no intersection between skill's and agent's list.
57
58
  This means that all tables restricted for use.
58
59
  """
59
- agent_tables_list = self.agent_tables_list or []
60
- skill_tables_list = self.params.get('tables', [])
61
- if len(skill_tables_list) > 0 and len(agent_tables_list) > 0:
62
- diff = set(skill_tables_list) & set(agent_tables_list)
63
- if len(diff) == 0:
64
- raise ValueError("There are no tables allowed for use.")
65
- return list(diff)
66
- if len(skill_tables_list) > 0:
67
- return skill_tables_list
68
- return agent_tables_list
60
+ def list_to_map(input: List) -> Dict:
61
+ agent_tables_map = defaultdict(set)
62
+ for x in input:
63
+ if isinstance(x, str):
64
+ table_name = x
65
+ schema_name = None
66
+ elif isinstance(x, dict):
67
+ table_name = x['table']
68
+ schema_name = x.get('schema')
69
+ else:
70
+ raise ValueError(f'Unexpected value in tables list: {x}')
71
+ agent_tables_map[schema_name].add(table_name)
72
+ return agent_tables_map
73
+
74
+ agent_tables_map = list_to_map(self.agent_tables_list or [])
75
+ skill_tables_map = list_to_map(self.params.get('tables', []))
76
+
77
+ if len(agent_tables_map) > 0 and len(skill_tables_map) > 0:
78
+ if len(set(agent_tables_map) & set(skill_tables_map)) == 0:
79
+ raise ValueError("Skill's and agent's allowed tables list have no shared schemas.")
80
+
81
+ intersection_tables_map = defaultdict(set)
82
+ has_intersection = False
83
+ for schema_name in agent_tables_map:
84
+ if schema_name not in skill_tables_map:
85
+ continue
86
+ intersection_tables_map[schema_name] = agent_tables_map[schema_name] & skill_tables_map[schema_name]
87
+ if len(intersection_tables_map[schema_name]) > 0:
88
+ has_intersection = True
89
+ if has_intersection is False:
90
+ raise ValueError("Skill's and agent's allowed tables list have no shared tables.")
91
+ return intersection_tables_map
92
+ if len(skill_tables_map) > 0:
93
+ return skill_tables_map
94
+ if len(agent_tables_map) > 0:
95
+ return agent_tables_map
96
+ return None
69
97
 
70
98
 
71
99
  class SkillToolController:
@@ -83,22 +111,6 @@ class SkillToolController:
83
111
  self.command_executor = ExecuteCommands(sql_session)
84
112
  return self.command_executor
85
113
 
86
- def get_sql_agent(
87
- self,
88
- database: str,
89
- include_tables: Optional[List[str]] = None,
90
- ignore_tables: Optional[List[str]] = None,
91
- sample_rows_in_table_info: int = 3,
92
- ):
93
- return SQLAgent(
94
- self.get_command_executor(),
95
- database,
96
- include_tables,
97
- ignore_tables,
98
- sample_rows_in_table_info,
99
- cache=get_cache('agent', max_size=_MAX_CACHE_SIZE)
100
- )
101
-
102
114
  def _make_text_to_sql_tools(self, skills: List[db.Skills], llm) -> List:
103
115
  '''
104
116
  Uses SQLAgent to execute tool
@@ -112,19 +124,47 @@ class SkillToolController:
112
124
  raise ImportError(
113
125
  'To use the text-to-SQL skill, please install langchain with `pip install mindsdb[langchain]`')
114
126
 
127
+ command_executor = self.get_command_executor()
128
+
115
129
  tables_list = []
116
130
  for skill in skills:
117
131
  database = skill.params['database']
118
- for table in skill.tables_list:
119
- tables_list.append(f'{database}.{table}')
120
-
121
- # use list databases
122
- database = ','.join(set(s.params['database'] for s in skills))
123
- db = MindsDBSQL(
124
- engine=self.get_command_executor(),
125
- database=database,
126
- metadata=self.get_command_executor().session.integration_controller,
127
- include_tables=tables_list
132
+ restriction_on_tables = skill.restriction_on_tables
133
+ if restriction_on_tables is None:
134
+ handler = command_executor.session.integration_controller.get_data_handler(database)
135
+ if 'all' in inspect.signature(handler.get_tables).parameters:
136
+ response = handler.get_tables(all=True)
137
+ else:
138
+ response = handler.get_tables()
139
+ # no restrictions
140
+ if 'table_schema' in response.data_frame.columns:
141
+ for _, row in response.data_frame.iterrows():
142
+ tables_list.append(f"{database}.{row['table_schema']}.{row['table_name']}")
143
+ else:
144
+ for _, row in response.data_frame.iterrows():
145
+ tables_list.append(f"{database}.{row['table_name']}")
146
+ continue
147
+ for schema_name, tables in restriction_on_tables.items():
148
+ for table in tables:
149
+ if schema_name is None:
150
+ tables_list.append(f'{database}.{table}')
151
+ else:
152
+ tables_list.append(f'{database}.{schema_name}.{table}')
153
+
154
+ sql_agent = SQLAgent(
155
+ command_executor=command_executor,
156
+ databases=list(set(s.params['database'] for s in skills)),
157
+ databases_struct={
158
+ skill.params['database']: skill.restriction_on_tables
159
+ for skill in skills
160
+ },
161
+ include_tables=tables_list,
162
+ ignore_tables=None,
163
+ sample_rows_in_table_info=3,
164
+ cache=get_cache('agent', max_size=_MAX_CACHE_SIZE)
165
+ )
166
+ db = MindsDBSQL.custom_init(
167
+ sql_agent=sql_agent
128
168
  )
129
169
 
130
170
  # Users probably don't need to configure this for now.
@@ -138,14 +178,18 @@ class SkillToolController:
138
178
  for i, tool in enumerate(sql_database_tools):
139
179
  if isinstance(tool, QuerySQLDataBaseTool):
140
180
  # Add our own custom description so our agent knows when to query this table.
141
- tool.description = (
142
- f'Use this tool if you need data about {" OR ".join(descriptions)}. '
143
- 'Use the conversation context to decide which table to query. '
144
- f'These are the available tables: {",".join(tables_list)}.\n' if len(tables_list) > 0 else '\n'
145
- f'ALWAYS consider these special cases:\n'
146
- f'- For TIMESTAMP type columns, make sure you include the time portion in your query (e.g. WHERE date_column = "2020-01-01 12:00:00")'
147
- f'Here are the rest of the instructions:\n'
148
- f'{tool.description}'
181
+ original_description = tool.description
182
+ tool.description = ''
183
+ if len(descriptions) > 0:
184
+ tool.description += f'Use this tool if you need data about {" OR ".join(descriptions)}.\n'
185
+ tool.description += 'Use the conversation context to decide which table to query.\n'
186
+ if len(tables_list) > 0:
187
+ f'These are the available tables: {",".join(tables_list)}.\n'
188
+ tool.description += (
189
+ 'ALWAYS consider these special cases:\n'
190
+ ' - For TIMESTAMP type columns, make sure you include the time portion in your query (e.g. WHERE date_column = "2020-01-01 12:00:00")\n'
191
+ 'Here are the rest of the instructions:\n'
192
+ f'{original_description}'
149
193
  )
150
194
  sql_database_tools[i] = tool
151
195
  return sql_database_tools
@@ -175,7 +219,6 @@ class SkillToolController:
175
219
  return build_retrieval_tool(tool, pred_args, skill)
176
220
 
177
221
  def _get_rag_query_function(self, skill: db.Skills):
178
-
179
222
  session_controller = self.get_command_executor().session
180
223
 
181
224
  def _answer_question(question: str) -> str:
@@ -1,5 +1,5 @@
1
1
  import datetime
2
- from typing import Dict, List
2
+ from typing import Dict, List, Optional
3
3
 
4
4
  from sqlalchemy import null
5
5
  from sqlalchemy.orm.attributes import flag_modified
@@ -16,7 +16,7 @@ class SkillsController:
16
16
  project_controller = ProjectController()
17
17
  self.project_controller = project_controller
18
18
 
19
- def get_skill(self, skill_name: str, project_name: str = 'mindsdb') -> db.Skills:
19
+ def get_skill(self, skill_name: str, project_name: str = 'mindsdb') -> Optional[db.Skills]:
20
20
  '''
21
21
  Gets a skill by name. Skills are expected to have unique names.
22
22
 
@@ -25,7 +25,7 @@ class SkillsController:
25
25
  project_name (str): The name of the containing project
26
26
 
27
27
  Returns:
28
- skill (db.Skills): The database skill object
28
+ skill (Optional[db.Skills]): The database skill object
29
29
 
30
30
  Raises:
31
31
  ValueError: If `project_name` does not exist
@@ -136,6 +136,8 @@ class SkillsController:
136
136
  existing_skill = self.get_skill(skill_name, project_name)
137
137
  if existing_skill is None:
138
138
  raise ValueError(f'Skill with name not found: {skill_name}')
139
+ if isinstance(existing_skill.params, dict) and existing_skill.params.get('is_demo') is True:
140
+ raise ValueError("It is forbidden to change properties of the demo object")
139
141
 
140
142
  if new_name is not None:
141
143
  existing_skill.name = new_name
@@ -171,5 +173,7 @@ class SkillsController:
171
173
  skill = self.get_skill(skill_name, project_name)
172
174
  if skill is None:
173
175
  raise ValueError(f"Skill with name doesn't exist: {skill_name}")
176
+ if isinstance(skill.params, dict) and skill.params.get('is_demo') is True:
177
+ raise ValueError("Unable to delete demo object")
174
178
  skill.deleted_at = datetime.datetime.now()
175
179
  db.session.commit()