camel-ai 0.2.67__py3-none-any.whl → 0.2.80a2__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.
Files changed (224) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/_types.py +6 -2
  3. camel/agents/_utils.py +38 -0
  4. camel/agents/chat_agent.py +4014 -410
  5. camel/agents/mcp_agent.py +30 -27
  6. camel/agents/repo_agent.py +2 -1
  7. camel/benchmarks/browsecomp.py +6 -6
  8. camel/configs/__init__.py +15 -0
  9. camel/configs/aihubmix_config.py +88 -0
  10. camel/configs/amd_config.py +70 -0
  11. camel/configs/cometapi_config.py +104 -0
  12. camel/configs/minimax_config.py +93 -0
  13. camel/configs/nebius_config.py +103 -0
  14. camel/configs/vllm_config.py +2 -0
  15. camel/data_collectors/alpaca_collector.py +15 -6
  16. camel/datagen/self_improving_cot.py +1 -1
  17. camel/datasets/base_generator.py +39 -10
  18. camel/environments/__init__.py +12 -0
  19. camel/environments/rlcards_env.py +860 -0
  20. camel/environments/single_step.py +28 -3
  21. camel/environments/tic_tac_toe.py +1 -1
  22. camel/interpreters/__init__.py +2 -0
  23. camel/interpreters/docker/Dockerfile +4 -16
  24. camel/interpreters/docker_interpreter.py +3 -2
  25. camel/interpreters/e2b_interpreter.py +34 -1
  26. camel/interpreters/internal_python_interpreter.py +51 -2
  27. camel/interpreters/microsandbox_interpreter.py +395 -0
  28. camel/loaders/__init__.py +11 -2
  29. camel/loaders/base_loader.py +85 -0
  30. camel/loaders/chunkr_reader.py +9 -0
  31. camel/loaders/firecrawl_reader.py +4 -4
  32. camel/logger.py +1 -1
  33. camel/memories/agent_memories.py +84 -1
  34. camel/memories/base.py +34 -0
  35. camel/memories/blocks/chat_history_block.py +122 -4
  36. camel/memories/blocks/vectordb_block.py +8 -1
  37. camel/memories/context_creators/score_based.py +29 -237
  38. camel/memories/records.py +88 -8
  39. camel/messages/base.py +166 -40
  40. camel/messages/func_message.py +32 -5
  41. camel/models/__init__.py +10 -0
  42. camel/models/aihubmix_model.py +83 -0
  43. camel/models/aiml_model.py +1 -16
  44. camel/models/amd_model.py +101 -0
  45. camel/models/anthropic_model.py +117 -18
  46. camel/models/aws_bedrock_model.py +2 -33
  47. camel/models/azure_openai_model.py +205 -91
  48. camel/models/base_audio_model.py +3 -1
  49. camel/models/base_model.py +189 -24
  50. camel/models/cohere_model.py +5 -17
  51. camel/models/cometapi_model.py +83 -0
  52. camel/models/crynux_model.py +1 -16
  53. camel/models/deepseek_model.py +6 -16
  54. camel/models/fish_audio_model.py +6 -0
  55. camel/models/gemini_model.py +71 -20
  56. camel/models/groq_model.py +1 -17
  57. camel/models/internlm_model.py +1 -16
  58. camel/models/litellm_model.py +49 -32
  59. camel/models/lmstudio_model.py +1 -17
  60. camel/models/minimax_model.py +83 -0
  61. camel/models/mistral_model.py +1 -16
  62. camel/models/model_factory.py +27 -1
  63. camel/models/model_manager.py +24 -6
  64. camel/models/modelscope_model.py +1 -16
  65. camel/models/moonshot_model.py +185 -19
  66. camel/models/nebius_model.py +83 -0
  67. camel/models/nemotron_model.py +0 -5
  68. camel/models/netmind_model.py +1 -16
  69. camel/models/novita_model.py +1 -16
  70. camel/models/nvidia_model.py +1 -16
  71. camel/models/ollama_model.py +4 -19
  72. camel/models/openai_compatible_model.py +171 -46
  73. camel/models/openai_model.py +205 -77
  74. camel/models/openrouter_model.py +1 -17
  75. camel/models/ppio_model.py +1 -16
  76. camel/models/qianfan_model.py +1 -16
  77. camel/models/qwen_model.py +1 -16
  78. camel/models/reka_model.py +1 -16
  79. camel/models/samba_model.py +34 -47
  80. camel/models/sglang_model.py +64 -31
  81. camel/models/siliconflow_model.py +1 -16
  82. camel/models/stub_model.py +0 -4
  83. camel/models/togetherai_model.py +1 -16
  84. camel/models/vllm_model.py +1 -16
  85. camel/models/volcano_model.py +0 -17
  86. camel/models/watsonx_model.py +1 -16
  87. camel/models/yi_model.py +1 -16
  88. camel/models/zhipuai_model.py +60 -16
  89. camel/parsers/__init__.py +18 -0
  90. camel/parsers/mcp_tool_call_parser.py +176 -0
  91. camel/retrievers/auto_retriever.py +1 -0
  92. camel/runtimes/configs.py +11 -11
  93. camel/runtimes/daytona_runtime.py +15 -16
  94. camel/runtimes/docker_runtime.py +6 -6
  95. camel/runtimes/remote_http_runtime.py +5 -5
  96. camel/services/agent_openapi_server.py +380 -0
  97. camel/societies/__init__.py +2 -0
  98. camel/societies/role_playing.py +26 -28
  99. camel/societies/workforce/__init__.py +2 -0
  100. camel/societies/workforce/events.py +122 -0
  101. camel/societies/workforce/prompts.py +249 -38
  102. camel/societies/workforce/role_playing_worker.py +82 -20
  103. camel/societies/workforce/single_agent_worker.py +634 -34
  104. camel/societies/workforce/structured_output_handler.py +512 -0
  105. camel/societies/workforce/task_channel.py +169 -23
  106. camel/societies/workforce/utils.py +176 -9
  107. camel/societies/workforce/worker.py +77 -23
  108. camel/societies/workforce/workflow_memory_manager.py +772 -0
  109. camel/societies/workforce/workforce.py +3168 -478
  110. camel/societies/workforce/workforce_callback.py +74 -0
  111. camel/societies/workforce/workforce_logger.py +203 -175
  112. camel/societies/workforce/workforce_metrics.py +33 -0
  113. camel/storages/__init__.py +4 -0
  114. camel/storages/key_value_storages/json.py +15 -2
  115. camel/storages/key_value_storages/mem0_cloud.py +48 -47
  116. camel/storages/object_storages/google_cloud.py +1 -1
  117. camel/storages/vectordb_storages/__init__.py +6 -0
  118. camel/storages/vectordb_storages/chroma.py +731 -0
  119. camel/storages/vectordb_storages/oceanbase.py +13 -13
  120. camel/storages/vectordb_storages/pgvector.py +349 -0
  121. camel/storages/vectordb_storages/qdrant.py +3 -3
  122. camel/storages/vectordb_storages/surreal.py +365 -0
  123. camel/storages/vectordb_storages/tidb.py +8 -6
  124. camel/tasks/task.py +244 -27
  125. camel/toolkits/__init__.py +46 -8
  126. camel/toolkits/aci_toolkit.py +64 -19
  127. camel/toolkits/arxiv_toolkit.py +6 -6
  128. camel/toolkits/base.py +63 -5
  129. camel/toolkits/code_execution.py +28 -1
  130. camel/toolkits/context_summarizer_toolkit.py +684 -0
  131. camel/toolkits/craw4ai_toolkit.py +93 -0
  132. camel/toolkits/dappier_toolkit.py +10 -6
  133. camel/toolkits/dingtalk.py +1135 -0
  134. camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
  135. camel/toolkits/excel_toolkit.py +901 -67
  136. camel/toolkits/file_toolkit.py +1402 -0
  137. camel/toolkits/function_tool.py +30 -6
  138. camel/toolkits/github_toolkit.py +107 -20
  139. camel/toolkits/gmail_toolkit.py +1839 -0
  140. camel/toolkits/google_calendar_toolkit.py +38 -4
  141. camel/toolkits/google_drive_mcp_toolkit.py +54 -0
  142. camel/toolkits/human_toolkit.py +34 -10
  143. camel/toolkits/hybrid_browser_toolkit/__init__.py +18 -0
  144. camel/toolkits/hybrid_browser_toolkit/config_loader.py +185 -0
  145. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +246 -0
  146. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +1973 -0
  147. camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
  148. camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +3749 -0
  149. camel/toolkits/hybrid_browser_toolkit/ts/package.json +32 -0
  150. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
  151. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1815 -0
  152. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
  153. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +590 -0
  154. camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
  155. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  156. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  157. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  158. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +130 -0
  159. camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +26 -0
  160. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +319 -0
  161. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1032 -0
  162. camel/toolkits/hybrid_browser_toolkit_py/__init__.py +17 -0
  163. camel/toolkits/hybrid_browser_toolkit_py/actions.py +575 -0
  164. camel/toolkits/hybrid_browser_toolkit_py/agent.py +311 -0
  165. camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +787 -0
  166. camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +490 -0
  167. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +2390 -0
  168. camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +233 -0
  169. camel/toolkits/hybrid_browser_toolkit_py/stealth_script.js +0 -0
  170. camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +1043 -0
  171. camel/toolkits/image_generation_toolkit.py +390 -0
  172. camel/toolkits/jina_reranker_toolkit.py +3 -4
  173. camel/toolkits/klavis_toolkit.py +5 -1
  174. camel/toolkits/markitdown_toolkit.py +104 -0
  175. camel/toolkits/math_toolkit.py +64 -10
  176. camel/toolkits/mcp_toolkit.py +370 -45
  177. camel/toolkits/memory_toolkit.py +5 -1
  178. camel/toolkits/message_agent_toolkit.py +608 -0
  179. camel/toolkits/message_integration.py +724 -0
  180. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  181. camel/toolkits/note_taking_toolkit.py +277 -0
  182. camel/toolkits/notion_mcp_toolkit.py +224 -0
  183. camel/toolkits/openbb_toolkit.py +5 -1
  184. camel/toolkits/origene_mcp_toolkit.py +56 -0
  185. camel/toolkits/playwright_mcp_toolkit.py +12 -31
  186. camel/toolkits/pptx_toolkit.py +25 -12
  187. camel/toolkits/resend_toolkit.py +168 -0
  188. camel/toolkits/screenshot_toolkit.py +213 -0
  189. camel/toolkits/search_toolkit.py +437 -142
  190. camel/toolkits/slack_toolkit.py +104 -50
  191. camel/toolkits/sympy_toolkit.py +1 -1
  192. camel/toolkits/task_planning_toolkit.py +3 -3
  193. camel/toolkits/terminal_toolkit/__init__.py +18 -0
  194. camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
  195. camel/toolkits/terminal_toolkit/utils.py +532 -0
  196. camel/toolkits/thinking_toolkit.py +1 -1
  197. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  198. camel/toolkits/video_analysis_toolkit.py +106 -26
  199. camel/toolkits/video_download_toolkit.py +17 -14
  200. camel/toolkits/web_deploy_toolkit.py +1219 -0
  201. camel/toolkits/wechat_official_toolkit.py +483 -0
  202. camel/toolkits/zapier_toolkit.py +5 -1
  203. camel/types/__init__.py +2 -2
  204. camel/types/agents/tool_calling_record.py +4 -1
  205. camel/types/enums.py +316 -40
  206. camel/types/openai_types.py +2 -2
  207. camel/types/unified_model_type.py +31 -4
  208. camel/utils/commons.py +36 -5
  209. camel/utils/constants.py +3 -0
  210. camel/utils/context_utils.py +1003 -0
  211. camel/utils/mcp.py +138 -4
  212. camel/utils/mcp_client.py +45 -1
  213. camel/utils/message_summarizer.py +148 -0
  214. camel/utils/token_counting.py +43 -20
  215. camel/utils/tool_result.py +44 -0
  216. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +296 -85
  217. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +219 -146
  218. camel/loaders/pandas_reader.py +0 -368
  219. camel/toolkits/dalle_toolkit.py +0 -175
  220. camel/toolkits/file_write_toolkit.py +0 -444
  221. camel/toolkits/openai_agent_toolkit.py +0 -135
  222. camel/toolkits/terminal_toolkit.py +0 -1037
  223. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
  224. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
@@ -74,7 +74,6 @@ class OceanBaseStorage(BaseVectorStorage):
74
74
  ObVecClient,
75
75
  )
76
76
  from pyobvector.client.index_param import (
77
- IndexParam,
78
77
  IndexParams,
79
78
  )
80
79
  from pyobvector.schema import VECTOR
@@ -112,20 +111,21 @@ class OceanBaseStorage(BaseVectorStorage):
112
111
 
113
112
  # Create vector index
114
113
  index_params: IndexParams = IndexParams()
115
- index_params.add_index_param(
116
- IndexParam(
117
- index_name="embedding_idx",
118
- field_name="embedding",
119
- distance=self.distance,
120
- type="hnsw",
121
- m=16,
122
- ef_construction=256,
123
- )
114
+ index_params.add_index(
115
+ field_name="embedding",
116
+ index_type="hnsw",
117
+ index_name="embedding_idx",
118
+ distance=self.distance,
119
+ m=16,
120
+ ef_construction=256,
124
121
  )
125
122
 
126
- self._client.create_vidx_with_vec_index_param(
127
- table_name=self.table_name, vidx_param=index_params.params[0]
128
- )
123
+ # Get the first index parameter
124
+ first_index_param = next(iter(index_params), None)
125
+ if first_index_param is not None:
126
+ self._client.create_vidx_with_vec_index_param(
127
+ table_name=self.table_name, vidx_param=first_index_param
128
+ )
129
129
 
130
130
  logger.info(f"Created table {self.table_name} with vector index")
131
131
  else:
@@ -0,0 +1,349 @@
1
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+
15
+ import json
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ from camel.logger import get_logger
19
+ from camel.storages.vectordb_storages import (
20
+ BaseVectorStorage,
21
+ VectorDBQuery,
22
+ VectorDBQueryResult,
23
+ VectorDBStatus,
24
+ VectorRecord,
25
+ )
26
+ from camel.types import VectorDistance
27
+ from camel.utils import dependencies_required
28
+
29
+ logger = get_logger(__name__)
30
+
31
+
32
+ class PgVectorStorage(BaseVectorStorage):
33
+ r"""PgVectorStorage is an implementation of BaseVectorStorage for
34
+ PostgreSQL with pgvector extension.
35
+
36
+ This class provides methods to add, delete, query, and manage vector
37
+ records in a PostgreSQL database using the pgvector extension.
38
+ It supports different distance metrics for similarity search.
39
+
40
+ Args:
41
+ vector_dim (int): The dimension of the vectors to be stored.
42
+ conn_info (Dict[str, Any]): Connection information for
43
+ psycopg2.connect.
44
+ table_name (str, optional): Name of the table to store vectors.
45
+ (default: :obj:`None`)
46
+ distance (VectorDistance, optional): Distance metric for vector
47
+ comparison. (default: :obj:`VectorDistance.COSINE`)
48
+ """
49
+
50
+ @dependencies_required('psycopg', 'pgvector')
51
+ def __init__(
52
+ self,
53
+ vector_dim: int,
54
+ conn_info: Dict[str, Any],
55
+ table_name: Optional[str] = None,
56
+ distance: VectorDistance = VectorDistance.COSINE,
57
+ **kwargs: Any,
58
+ ) -> None:
59
+ r"""Initialize PgVectorStorage.
60
+
61
+ Args:
62
+ vector_dim (int): The dimension of the vectors.
63
+ conn_info (Dict[str, Any]): Connection info for psycopg2.connect.
64
+ table_name (str, optional): Table name. (default: :obj:`None`)
65
+ distance (VectorDistance, optional): Distance metric.
66
+ (default: :obj:`VectorDistance.COSINE`)
67
+ """
68
+ import psycopg
69
+ from pgvector.psycopg import register_vector
70
+
71
+ if vector_dim <= 0:
72
+ raise ValueError("vector_dim must be positive")
73
+
74
+ self.vector_dim = vector_dim
75
+ self.conn_info = conn_info
76
+ self.table_name = table_name or 'vectors'
77
+ self.distance = distance
78
+
79
+ try:
80
+ self._conn = psycopg.connect(**conn_info)
81
+ register_vector(self._conn)
82
+ self._ensure_table()
83
+ self._ensure_index()
84
+ except Exception as e:
85
+ logger.error(f"Failed to initialize PgVectorStorage: {e}")
86
+ raise
87
+
88
+ def _ensure_table(self) -> None:
89
+ r"""Ensure the vector table exists in the database.
90
+ Creates the table if it does not exist.
91
+ """
92
+ try:
93
+ from psycopg.sql import SQL, Identifier, Literal
94
+
95
+ with self._conn.cursor() as cur:
96
+ query = SQL("""
97
+ CREATE TABLE IF NOT EXISTS {table} (
98
+ id VARCHAR PRIMARY KEY,
99
+ vector vector({dim}),
100
+ payload JSONB
101
+ )
102
+ """).format(
103
+ table=Identifier(self.table_name),
104
+ dim=Literal(self.vector_dim),
105
+ )
106
+ cur.execute(query)
107
+ self._conn.commit()
108
+ except Exception as e:
109
+ logger.error(f"Failed to create table {self.table_name}: {e}")
110
+ raise
111
+
112
+ def _ensure_index(self) -> None:
113
+ r"""Ensure vector similarity search index exists for better
114
+ performance.
115
+ """
116
+ try:
117
+ from psycopg.sql import SQL, Identifier
118
+
119
+ with self._conn.cursor() as cur:
120
+ index_name = f"{self.table_name}_vector_idx"
121
+ query = SQL("""
122
+ CREATE INDEX IF NOT EXISTS {index_name}
123
+ ON {table}
124
+ USING hnsw (vector vector_cosine_ops)
125
+ """).format(
126
+ index_name=Identifier(index_name),
127
+ table=Identifier(self.table_name),
128
+ )
129
+ cur.execute(query)
130
+ self._conn.commit()
131
+ except Exception as e:
132
+ logger.warning(f"Failed to create vector index: {e}")
133
+
134
+ def add(self, records: List[VectorRecord], **kwargs: Any) -> None:
135
+ r"""Add or update vector records in the database.
136
+
137
+ Args:
138
+ records (List[VectorRecord]): List of vector records to
139
+ add or update.
140
+ """
141
+ if not records:
142
+ return
143
+
144
+ try:
145
+ with self._conn.cursor() as cur:
146
+ # Use batch insert for better performance
147
+ batch_data = []
148
+ for rec in records:
149
+ if len(rec.vector) != self.vector_dim:
150
+ raise ValueError(
151
+ f"Vector dimension mismatch: expected "
152
+ f"{self.vector_dim}, got {len(rec.vector)}"
153
+ )
154
+
155
+ batch_data.append(
156
+ (
157
+ rec.id,
158
+ rec.vector,
159
+ json.dumps(rec.payload)
160
+ if rec.payload is not None
161
+ else None,
162
+ )
163
+ )
164
+
165
+ # Use executemany for efficient batch insert
166
+ from psycopg.sql import SQL, Identifier
167
+
168
+ query = SQL("""
169
+ INSERT INTO {table} (id, vector, payload)
170
+ VALUES (%s, %s, %s)
171
+ ON CONFLICT (id) DO UPDATE SET
172
+ vector=EXCLUDED.vector,
173
+ payload=EXCLUDED.payload
174
+ """).format(table=Identifier(self.table_name))
175
+
176
+ cur.executemany(query, batch_data)
177
+ self._conn.commit()
178
+ except Exception as e:
179
+ self._conn.rollback()
180
+ logger.error(f"Failed to add records: {e}")
181
+ raise
182
+
183
+ def delete(self, ids: List[str], **kwargs: Any) -> None:
184
+ r"""Delete vector records from the database by their IDs.
185
+
186
+ Args:
187
+ ids (List[str]): List of record IDs to delete.
188
+ """
189
+ from psycopg.sql import SQL, Identifier
190
+
191
+ if not ids:
192
+ return
193
+
194
+ try:
195
+ with self._conn.cursor() as cur:
196
+ query = SQL("DELETE FROM {table} WHERE id = ANY(%s)").format(
197
+ table=Identifier(self.table_name)
198
+ )
199
+ cur.execute(query, (ids,))
200
+ self._conn.commit()
201
+ except Exception as e:
202
+ self._conn.rollback()
203
+ logger.error(f"Failed to delete records: {e}")
204
+ raise
205
+
206
+ def query(
207
+ self, query: VectorDBQuery, **kwargs: Any
208
+ ) -> List[VectorDBQueryResult]:
209
+ r"""Query the database for the most similar vectors to the given
210
+ query vector.
211
+
212
+ Args:
213
+ query (VectorDBQuery): Query object containing the query
214
+ vector and top_k.
215
+ **kwargs (Any): Additional keyword arguments for the query.
216
+
217
+ Returns:
218
+ List[VectorDBQueryResult]: List of query results sorted by
219
+ similarity.
220
+ """
221
+ if len(query.query_vector) != self.vector_dim:
222
+ raise ValueError(
223
+ f"Query vector dimension mismatch: "
224
+ f"expected {self.vector_dim}, got {len(query.query_vector)}"
225
+ )
226
+
227
+ try:
228
+ with self._conn.cursor() as cur:
229
+ # Fix distance metric mapping
230
+ metric_info = {
231
+ VectorDistance.COSINE: ('<=>', 'ASC'), # Cosine distance
232
+ VectorDistance.EUCLIDEAN: (
233
+ '<->',
234
+ 'ASC',
235
+ ), # Euclidean distance
236
+ VectorDistance.DOT: (
237
+ '<#>',
238
+ 'DESC',
239
+ ), # Negative dot product (higher is better)
240
+ }
241
+
242
+ if self.distance not in metric_info:
243
+ raise ValueError(
244
+ f"Unsupported distance metric: {self.distance}"
245
+ )
246
+
247
+ metric, order = metric_info[self.distance]
248
+
249
+ from psycopg.sql import SQL, Identifier, Literal
250
+
251
+ query_sql = SQL("""
252
+ SELECT id, vector, payload, (vector {} %s::vector)
253
+ AS similarity
254
+ FROM {}
255
+ ORDER BY similarity {}
256
+ LIMIT %s
257
+ """).format(
258
+ Literal(metric),
259
+ Identifier(self.table_name),
260
+ Literal(order),
261
+ )
262
+
263
+ cur.execute(query_sql, (query.query_vector, query.top_k))
264
+ results = []
265
+ for row in cur.fetchall():
266
+ id, vector, payload, similarity = row
267
+ results.append(
268
+ VectorDBQueryResult.create(
269
+ similarity=float(similarity),
270
+ vector=list(vector),
271
+ id=id,
272
+ payload=payload,
273
+ )
274
+ )
275
+ return results
276
+ except Exception as e:
277
+ logger.error(f"Failed to query vectors: {e}")
278
+ raise
279
+
280
+ def status(self, **kwargs: Any) -> VectorDBStatus:
281
+ r"""Get the status of the vector database, including vector
282
+ dimension and count.
283
+
284
+ Args:
285
+ **kwargs (Any): Additional keyword arguments for the query.
286
+
287
+ Returns:
288
+ VectorDBStatus: Status object with vector dimension and count.
289
+ """
290
+ try:
291
+ with self._conn.cursor() as cur:
292
+ from psycopg.sql import SQL, Identifier
293
+
294
+ query = SQL('SELECT COUNT(*) FROM {}').format(
295
+ Identifier(self.table_name)
296
+ )
297
+ cur.execute(query)
298
+ result = cur.fetchone()
299
+ count = result[0] if result else 0
300
+ return VectorDBStatus(
301
+ vector_dim=self.vector_dim, vector_count=count
302
+ )
303
+ except Exception as e:
304
+ logger.error(f"Failed to get status: {e}")
305
+ raise
306
+
307
+ def clear(self) -> None:
308
+ r"""Remove all vectors from the storage by truncating the table."""
309
+ try:
310
+ with self._conn.cursor() as cur:
311
+ from psycopg.sql import SQL, Identifier
312
+
313
+ query = SQL("TRUNCATE TABLE {table}").format(
314
+ table=Identifier(self.table_name)
315
+ )
316
+ cur.execute(query)
317
+ self._conn.commit()
318
+ except Exception as e:
319
+ self._conn.rollback()
320
+ logger.error(f"Failed to clear table: {e}")
321
+ raise
322
+
323
+ def load(self) -> None:
324
+ r"""Load the collection hosted on cloud service (no-op for pgvector).
325
+ This method is provided for interface compatibility.
326
+ """
327
+ # For PostgreSQL local/managed instances, no loading is required
328
+ pass
329
+
330
+ def close(self) -> None:
331
+ r"""Close the database connection."""
332
+ if hasattr(self, '_conn') and self._conn:
333
+ try:
334
+ self._conn.close()
335
+ except Exception as e:
336
+ logger.warning(f"Error closing connection: {e}")
337
+
338
+ def __del__(self) -> None:
339
+ r"""Ensure connection is closed when object is destroyed."""
340
+ self.close()
341
+
342
+ @property
343
+ def client(self) -> Any:
344
+ r"""Provides access to the underlying vector database client.
345
+
346
+ Returns:
347
+ Any: The underlying psycopg connection object.
348
+ """
349
+ return self._conn
@@ -14,6 +14,7 @@
14
14
  import logging
15
15
  from datetime import datetime
16
16
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast
17
+ from uuid import UUID
17
18
 
18
19
  if TYPE_CHECKING:
19
20
  from qdrant_client import QdrantClient
@@ -251,7 +252,6 @@ class QdrantStorage(BaseVectorStorage):
251
252
  else None,
252
253
  "vector_count": collection_info.points_count,
253
254
  "status": collection_info.status,
254
- "vectors_count": collection_info.vectors_count,
255
255
  "config": collection_info.config,
256
256
  }
257
257
 
@@ -304,7 +304,7 @@ class QdrantStorage(BaseVectorStorage):
304
304
  """
305
305
  from qdrant_client.http.models import PointIdsList, UpdateStatus
306
306
 
307
- points = cast(List[Union[str, int]], ids)
307
+ points = cast(List[Union[int, str, UUID]], ids)
308
308
 
309
309
  op_info = self._client.set_payload(
310
310
  collection_name=self.collection_name,
@@ -376,7 +376,7 @@ class QdrantStorage(BaseVectorStorage):
376
376
  op_info = self._client.delete(
377
377
  collection_name=self.collection_name,
378
378
  points_selector=PointIdsList(
379
- points=cast(List[Union[int, str]], ids)
379
+ points=cast(List[Union[int, str, UUID]], ids)
380
380
  ),
381
381
  **kwargs,
382
382
  )