agentic-kit-common 0.0.10__py3-none-any.whl → 0.0.12__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 agentic-kit-common might be problematic. Click here for more details.

File without changes
@@ -0,0 +1,16 @@
1
+ import logging
2
+
3
+
4
+ def setup_logger(tag, level):
5
+ logger = logging.getLogger(tag)
6
+ logger.setLevel(level)
7
+
8
+ if not logger.handlers:
9
+ handler = logging.StreamHandler()
10
+ formatter = logging.Formatter(
11
+ '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
12
+ )
13
+ handler.setFormatter(formatter)
14
+ logger.addHandler(handler)
15
+
16
+ return logger
@@ -1,53 +1,90 @@
1
- from typing import List, Union
1
+ from typing import List, Union, Optional, Set
2
2
 
3
- import sqlparse
3
+ import sqlglot
4
4
  from sqlalchemy import text
5
5
  from sqlalchemy.orm import Session
6
+ from sqlglot import expressions
6
7
 
7
8
 
8
- def is_readonly_sql(sql: str) -> bool:
9
+ def get_operation_type(statement) -> str:
10
+ """获取SQL操作类型"""
11
+ return type(statement).__name__.upper()
12
+
13
+
14
+ def get_sql_operation_info(sql: str) -> Optional[dict]:
9
15
  """
10
- 只允许:
11
- SELECT / WITH / VALUES / EXPLAIN / DESCRIBE / SHOW
12
- 拒绝:
13
- INSERT/UPDATE/DELETE/CREATE/ALTER/DROP/TRUNCATE/LOAD/REPLACE/LOCK/UNLOCK/GRANT/REVOKE/EXECUTE/CALL
16
+ 获取SQL操作信息(用于调试和日志记录)
17
+
18
+ Returns:
19
+ dict: 包含操作类型、涉及表等信息
14
20
  """
15
- sql_clean = sqlparse.format(sql.strip(), strip_comments=True)
16
- tokens = [t.normalized for t in sqlparse.parse(sql_clean)[0].flatten()
17
- if t.ttype in (sqlparse.tokens.Keyword, sqlparse.tokens.DML, sqlparse.tokens.DDL)]
21
+ try:
22
+ statement = sqlglot.parse_one(sql, read="mysql")
23
+ operation_type = get_operation_type(statement)
24
+
25
+ tables = []
26
+ for table in statement.find_all(expressions.Table):
27
+ table_name = table.name
28
+ if table_name.startswith('`') and table_name.endswith('`'):
29
+ table_name = table_name[1:-1]
30
+ tables.append(table_name)
31
+
32
+ return {
33
+ 'operation': operation_type,
34
+ 'tables': tables,
35
+ 'has_wildcard': bool(statement.find(expressions.Star)) if isinstance(statement, expressions.Select) else False
36
+ }
37
+ except Exception as e:
38
+ print(f"获取SQL操作信息失败: {e}")
39
+ return None
40
+
41
+
42
+ def is_readonly_expression(node: expressions.Expression, allowed_operations: Optional[Set[str]] = None, enable_wildcard_check: bool = True):
43
+ """递归检查表达式树中是否出现写操作节点"""
44
+ # 写操作黑名单节点类型
45
+ write_types = {
46
+ expressions.Insert,
47
+ expressions.Update,
48
+ expressions.Delete,
49
+ expressions.Create,
50
+ expressions.Alter,
51
+ expressions.Drop,
52
+ expressions.Replace,
53
+ expressions.Merge
54
+ }
55
+ for descendant in node.walk():
56
+ if type(descendant) in write_types:
57
+ return False, type(descendant)
58
+
59
+ if allowed_operations:
60
+ op_type = get_operation_type(node)
61
+ # 检查操作类型
62
+ if op_type not in allowed_operations:
63
+ return False, op_type
64
+
65
+ if enable_wildcard_check and isinstance(node, expressions.Select) and node.find(expressions.Star):
66
+ return False, expressions.Star
18
67
 
19
- forbidden = {"INSERT", "UPDATE", "DELETE", "CREATE", "ALTER", "DROP", "TRUNCATE",
20
- "LOAD", "REPLACE", "LOCK", "UNLOCK", "GRANT", "REVOKE", "EXEC", "CALL"}
21
- allowed_root = {"SELECT", "WITH", "EXPLAIN", "DESCRIBE", "SHOW", "VALUES"}
68
+ return True, None
22
69
 
23
- root = tokens[0].upper() if tokens else ""
24
- if root not in allowed_root:
25
- return False
26
- if any(k in forbidden for k in tokens):
27
- return False
28
- return True
29
70
 
71
+ def session_sql_execute(db_session: Session, sql_text: Union[str, List], format_result: bool = True):
72
+ def __do_execute(_sql: str):
73
+ _result = db_session.execute(text(f"{sql_text}"))
74
+ if format_result:
75
+ columns = list(_result.keys())
76
+ rows = [dict(zip(columns, r)) for r in _result.fetchall()]
77
+ return rows
78
+ else:
79
+ return _result
30
80
 
31
- def session_sql_execute(db_session: Session, sql_text: Union[str, List], query_only: bool = True):
32
81
  if isinstance(sql_text, str):
33
- # 处理单条SQL语句
34
- if query_only:
35
- if not is_readonly_sql(sql_text):
36
- return []
37
- result = db_session.execute(text(f"{sql_text}"))
38
- columns = list(result.keys())
39
- rows = [dict(zip(columns, r)) for r in result.fetchall()]
40
- return rows
82
+ return __do_execute(sql_text)
41
83
  elif isinstance(sql_text, list):
42
84
  results = []
43
85
  for sub_sql_text in sql_text:
44
- if query_only:
45
- if not is_readonly_sql(sub_sql_text):
46
- continue
47
- result = db_session.execute(text(f"{sub_sql_text}"))
48
- columns = list(result.keys())
49
- rows = [dict(zip(columns, r)) for r in result.fetchall()]
50
- results.append(rows)
86
+ result = __do_execute(sub_sql_text)
87
+ results.append(result)
51
88
  return results
52
89
  else:
53
90
  return []
@@ -64,9 +64,11 @@ class DatabaseEngineManager:
64
64
  def add_engine(self, engine_info: DatabaseEngineModel) -> bool:
65
65
  """添加数据库引擎"""
66
66
  with self._lock:
67
+ resource_uid = engine_info.resource_uid
67
68
  engine_name = engine_info.engine_name
68
69
  database_uri = engine_info.database_uri
69
70
  database_name = engine_info.database_name
71
+ database_desc = engine_info.database_desc
70
72
  config = engine_info.config.model_dump().copy()
71
73
 
72
74
  if engine_name in self._engines:
@@ -91,8 +93,10 @@ class DatabaseEngineManager:
91
93
  self._engines[engine_name] = engine
92
94
  self._sessions[engine_name] = session_factory
93
95
  self._engine_configs[engine_name] = {
96
+ "resource_uid": resource_uid,
94
97
  "database_uri": database_uri,
95
98
  "database_name": database_name,
99
+ "database_desc": database_desc,
96
100
  "config": config or self._default_config.copy()
97
101
  }
98
102
 
@@ -13,7 +13,9 @@ _DEFAULT_CONFIG = DatabaseEngineConfigModel()
13
13
 
14
14
 
15
15
  class DatabaseEngineModel(BaseModel):
16
+ resource_uid: str = Field("", description="数据库唯一ID")
16
17
  engine_name: str = Field(..., description="数据库引擎名字")
17
18
  database_uri: str = Field(..., description="数据库uir地址")
18
19
  database_name: str = Field(..., description="数据库名称")
20
+ database_desc: str = Field("", description="数据库描述信息")
19
21
  config: DatabaseEngineConfigModel = Field(_DEFAULT_CONFIG, description="配置信息")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-kit-common
3
- Version: 0.0.10
3
+ Version: 0.0.12
4
4
  Summary: Common utilities and tools for agentic kit ecosystem
5
5
  Home-page:
6
6
  Author: manson
@@ -26,6 +26,7 @@ Requires-Dist: langchain_community
26
26
  Requires-Dist: langchain_experimental
27
27
  Requires-Dist: mysql-connector-python
28
28
  Requires-Dist: sqlalchemy
29
+ Requires-Dist: sqlglot
29
30
  Requires-Dist: pymilvus
30
31
  Requires-Dist: xinference_client
31
32
  Dynamic: author
@@ -1,12 +1,14 @@
1
1
  agentic_kit_common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ agentic_kit_common/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ agentic_kit_common/log/logger.py,sha256=EH8pOW6KVpb-c4RdK2sohpHgfs3_hBcaAletRs1O23k,391
2
4
  agentic_kit_common/minio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
5
  agentic_kit_common/minio/minio_manager.py,sha256=PzoUWn0YqXTHx1UClbkwLkIUmv5O4aSDc7eVf08qOzs,21494
4
6
  agentic_kit_common/orm/__init__.py,sha256=wqY81g3P7FftFvLK5SaxFJzNNxrQwtmcb4RCXOSAZa8,71
5
7
  agentic_kit_common/orm/base.py,sha256=QIura_i2nIY2XeA3-KkO2loLNbEAoJK2qx0hu_8nhYU,2277
6
- agentic_kit_common/orm/execution.py,sha256=sCEcInFGFZ9ZiIs0eHKbQPtN4Z02v7vGdFMyVEWygcU,1951
8
+ agentic_kit_common/orm/execution.py,sha256=beyRJqVGY5nOqMDpvLcfwimUzP6eSz8ayNHLwh1hGOo,2858
7
9
  agentic_kit_common/orm/manager.py,sha256=lWgFk5fUu_9m6yN_fskWHSYGaW30ty--KZKj8AuvIh0,4852
8
- agentic_kit_common/orm/multi_session.py,sha256=CAEnOLl0I-r77JAknKQ2sERF40OkHD7BOrYVYoHuQV4,8814
9
- agentic_kit_common/orm/schema.py,sha256=ukdVP71NE_JO5_HOe_FApJjBAKUsDluoElVn5vNSGJQ,1023
10
+ agentic_kit_common/orm/multi_session.py,sha256=xESwEeQw1UdR-5jqywbmI_Z0jxUn_l-cMyagnm7fc3c,9023
11
+ agentic_kit_common/orm/schema.py,sha256=RfVoJ7RD9ZckogLfLWh9P9x3JkZRURnsIw50scBp75Y,1162
10
12
  agentic_kit_common/orm/session.py,sha256=LX4ZUKJNXdcQ0KqRt5L0pJX-QG-tDyKXEDijcPUkGD0,2716
11
13
  agentic_kit_common/vector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
14
  agentic_kit_common/vector/embedding/__init__.py,sha256=mp--cfCDzTn5hNxzcIAU4m0g4F0d0rrZErFVWsGDvx4,40
@@ -26,7 +28,7 @@ test/test_embedding.py,sha256=xcfHDHGL2_tpXp_VaLnNDAWvKdkc1K1BjiYoV5WxtFY,900
26
28
  test/test_minio.py,sha256=TOkX8A2pPkjrwAIH88xBZmFpDc1ZgTk1QS6mtubOZ-Y,2308
27
29
  test/test_orm.py,sha256=8fGCU7BWaD5sDbg0fgYN0Saf_hi7t-q8svHCHLQDceo,1620
28
30
  test/test_vector.py,sha256=Z3Bwvrw0XGBWXHYXk9pkF1cjnUZSZk0gmLsgQIIaZuY,1717
29
- agentic_kit_common-0.0.10.dist-info/METADATA,sha256=KIp7HPRyzygUBrXu8H9B4xu8NOFiD6_B5PTaYVN20Fc,7497
30
- agentic_kit_common-0.0.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
- agentic_kit_common-0.0.10.dist-info/top_level.txt,sha256=nEKDlp84vqKSVWssGcxyuIsTqWLhMo45xqMs2GK4Dgg,24
32
- agentic_kit_common-0.0.10.dist-info/RECORD,,
31
+ agentic_kit_common-0.0.12.dist-info/METADATA,sha256=1HdcutDJ_PjZvfGs6cQx_SRxmHKGgY7u2y-0-y1KmLs,7520
32
+ agentic_kit_common-0.0.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ agentic_kit_common-0.0.12.dist-info/top_level.txt,sha256=nEKDlp84vqKSVWssGcxyuIsTqWLhMo45xqMs2GK4Dgg,24
34
+ agentic_kit_common-0.0.12.dist-info/RECORD,,