auto-coder 0.1.397__py3-none-any.whl → 0.1.399__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 auto-coder might be problematic. Click here for more details.

Files changed (85) hide show
  1. auto_coder-0.1.399.dist-info/METADATA +396 -0
  2. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info}/RECORD +81 -28
  3. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info}/WHEEL +1 -1
  4. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info}/entry_points.txt +2 -0
  5. autocoder/agent/base_agentic/base_agent.py +2 -2
  6. autocoder/agent/base_agentic/tools/replace_in_file_tool_resolver.py +1 -1
  7. autocoder/agent/entry_command_agent/__init__.py +29 -0
  8. autocoder/agent/entry_command_agent/auto_tool.py +61 -0
  9. autocoder/agent/entry_command_agent/chat.py +475 -0
  10. autocoder/agent/entry_command_agent/designer.py +53 -0
  11. autocoder/agent/entry_command_agent/generate_command.py +50 -0
  12. autocoder/agent/entry_command_agent/project_reader.py +58 -0
  13. autocoder/agent/entry_command_agent/voice2text.py +71 -0
  14. autocoder/auto_coder.py +23 -548
  15. autocoder/auto_coder_rag.py +1 -0
  16. autocoder/auto_coder_runner.py +510 -8
  17. autocoder/chat/rules_command.py +1 -1
  18. autocoder/chat_auto_coder.py +8 -0
  19. autocoder/common/ac_style_command_parser/__init__.py +15 -0
  20. autocoder/common/ac_style_command_parser/example.py +7 -0
  21. autocoder/{command_parser.py → common/ac_style_command_parser/parser.py} +1 -33
  22. autocoder/common/ac_style_command_parser/test_parser.py +516 -0
  23. autocoder/common/command_completer_v2.py +1 -1
  24. autocoder/common/command_file_manager/examples.py +22 -8
  25. autocoder/common/command_file_manager/manager.py +37 -6
  26. autocoder/common/conversations/__init__.py +84 -39
  27. autocoder/common/conversations/backup/__init__.py +14 -0
  28. autocoder/common/conversations/backup/backup_manager.py +564 -0
  29. autocoder/common/conversations/backup/restore_manager.py +546 -0
  30. autocoder/common/conversations/cache/__init__.py +16 -0
  31. autocoder/common/conversations/cache/base_cache.py +89 -0
  32. autocoder/common/conversations/cache/cache_manager.py +368 -0
  33. autocoder/common/conversations/cache/memory_cache.py +224 -0
  34. autocoder/common/conversations/config.py +195 -0
  35. autocoder/common/conversations/exceptions.py +72 -0
  36. autocoder/common/conversations/file_locker.py +145 -0
  37. autocoder/common/conversations/get_conversation_manager.py +143 -0
  38. autocoder/common/conversations/manager.py +1028 -0
  39. autocoder/common/conversations/models.py +154 -0
  40. autocoder/common/conversations/search/__init__.py +15 -0
  41. autocoder/common/conversations/search/filter_manager.py +431 -0
  42. autocoder/common/conversations/search/text_searcher.py +366 -0
  43. autocoder/common/conversations/storage/__init__.py +16 -0
  44. autocoder/common/conversations/storage/base_storage.py +82 -0
  45. autocoder/common/conversations/storage/file_storage.py +267 -0
  46. autocoder/common/conversations/storage/index_manager.py +406 -0
  47. autocoder/common/v2/agent/agentic_edit.py +131 -18
  48. autocoder/common/v2/agent/agentic_edit_types.py +10 -0
  49. autocoder/common/v2/code_auto_generate_editblock.py +10 -2
  50. autocoder/dispacher/__init__.py +10 -0
  51. autocoder/rags.py +73 -50
  52. autocoder/run_context.py +1 -0
  53. autocoder/sdk/__init__.py +188 -0
  54. autocoder/sdk/cli/__init__.py +15 -0
  55. autocoder/sdk/cli/__main__.py +26 -0
  56. autocoder/sdk/cli/completion_wrapper.py +38 -0
  57. autocoder/sdk/cli/formatters.py +211 -0
  58. autocoder/sdk/cli/handlers.py +174 -0
  59. autocoder/sdk/cli/install_completion.py +301 -0
  60. autocoder/sdk/cli/main.py +284 -0
  61. autocoder/sdk/cli/options.py +72 -0
  62. autocoder/sdk/constants.py +102 -0
  63. autocoder/sdk/core/__init__.py +20 -0
  64. autocoder/sdk/core/auto_coder_core.py +867 -0
  65. autocoder/sdk/core/bridge.py +497 -0
  66. autocoder/sdk/example.py +0 -0
  67. autocoder/sdk/exceptions.py +72 -0
  68. autocoder/sdk/models/__init__.py +19 -0
  69. autocoder/sdk/models/messages.py +209 -0
  70. autocoder/sdk/models/options.py +194 -0
  71. autocoder/sdk/models/responses.py +311 -0
  72. autocoder/sdk/session/__init__.py +32 -0
  73. autocoder/sdk/session/session.py +106 -0
  74. autocoder/sdk/session/session_manager.py +56 -0
  75. autocoder/sdk/utils/__init__.py +24 -0
  76. autocoder/sdk/utils/formatters.py +216 -0
  77. autocoder/sdk/utils/io_utils.py +302 -0
  78. autocoder/sdk/utils/validators.py +287 -0
  79. autocoder/version.py +2 -1
  80. auto_coder-0.1.397.dist-info/METADATA +0 -111
  81. autocoder/common/conversations/compatibility.py +0 -303
  82. autocoder/common/conversations/conversation_manager.py +0 -502
  83. autocoder/common/conversations/example.py +0 -152
  84. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info/licenses}/LICENSE +0 -0
  85. {auto_coder-0.1.397.dist-info → auto_coder-0.1.399.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,267 @@
1
+ """
2
+ 文件存储实现
3
+
4
+ 基于JSON文件的对话存储实现,支持原子写入和数据完整性检查。
5
+ """
6
+
7
+ import os
8
+ import json
9
+ import tempfile
10
+ import re
11
+ from typing import Optional, List, Dict, Any
12
+ from pathlib import Path
13
+
14
+ from .base_storage import BaseStorage
15
+ from ..exceptions import DataIntegrityError
16
+
17
+
18
+ class FileStorage(BaseStorage):
19
+ """基于文件的存储实现"""
20
+
21
+ def __init__(self, storage_path: str):
22
+ """
23
+ 初始化文件存储
24
+
25
+ Args:
26
+ storage_path: 存储目录路径
27
+ """
28
+ self.storage_path = Path(storage_path)
29
+ self._ensure_storage_directory()
30
+
31
+ def _ensure_storage_directory(self):
32
+ """确保存储目录存在"""
33
+ self.storage_path.mkdir(parents=True, exist_ok=True)
34
+
35
+ def _get_conversation_file_path(self, conversation_id: str) -> Path:
36
+ """
37
+ 获取对话文件路径
38
+
39
+ Args:
40
+ conversation_id: 对话ID
41
+
42
+ Returns:
43
+ Path: 对话文件路径
44
+ """
45
+ # 清理文件名中的特殊字符
46
+ safe_filename = self._sanitize_filename(conversation_id)
47
+ return self.storage_path / f"{safe_filename}.json"
48
+
49
+ def _sanitize_filename(self, filename: str) -> str:
50
+ """
51
+ 清理文件名,移除或替换特殊字符
52
+
53
+ Args:
54
+ filename: 原始文件名
55
+
56
+ Returns:
57
+ str: 安全的文件名
58
+ """
59
+ # 移除或替换不安全的字符
60
+ safe_filename = re.sub(r'[<>:"/\\|?*]', '_', filename)
61
+ # 确保文件名不为空
62
+ if not safe_filename or safe_filename.isspace():
63
+ safe_filename = 'unnamed'
64
+ return safe_filename
65
+
66
+ def _validate_conversation_data(self, conversation_data: Dict[str, Any]) -> bool:
67
+ """
68
+ 验证对话数据的完整性
69
+
70
+ Args:
71
+ conversation_data: 对话数据
72
+
73
+ Returns:
74
+ bool: 数据有效返回True
75
+ """
76
+ if not isinstance(conversation_data, dict):
77
+ return False
78
+
79
+ # 检查必需字段
80
+ required_fields = ['conversation_id']
81
+ for field in required_fields:
82
+ if field not in conversation_data:
83
+ return False
84
+ if not conversation_data[field]:
85
+ return False
86
+
87
+ return True
88
+
89
+ def _atomic_write_file(self, file_path: Path, data: Dict[str, Any]) -> bool:
90
+ """
91
+ 原子写入文件
92
+
93
+ Args:
94
+ file_path: 目标文件路径
95
+ data: 要写入的数据
96
+
97
+ Returns:
98
+ bool: 写入成功返回True
99
+ """
100
+ temp_fd = None
101
+ temp_path = None
102
+
103
+ try:
104
+ # 创建临时文件
105
+ temp_fd, temp_path = tempfile.mkstemp(
106
+ suffix='.tmp',
107
+ prefix=file_path.name + '.',
108
+ dir=file_path.parent
109
+ )
110
+
111
+ # 写入数据到临时文件
112
+ with os.fdopen(temp_fd, 'w', encoding='utf-8') as temp_file:
113
+ temp_fd = None # 文件已关闭,避免重复关闭
114
+ json.dump(data, temp_file, ensure_ascii=False, indent=2)
115
+
116
+ # 原子重命名
117
+ os.rename(temp_path, file_path)
118
+ return True
119
+
120
+ except (OSError, IOError, PermissionError, TypeError, ValueError):
121
+ # 清理临时文件
122
+ if temp_fd is not None:
123
+ try:
124
+ os.close(temp_fd)
125
+ except OSError:
126
+ pass
127
+
128
+ if temp_path and os.path.exists(temp_path):
129
+ try:
130
+ os.unlink(temp_path)
131
+ except OSError:
132
+ pass
133
+
134
+ return False
135
+
136
+ def save_conversation(self, conversation_data: Dict[str, Any]) -> bool:
137
+ """
138
+ 保存对话数据
139
+
140
+ Args:
141
+ conversation_data: 对话数据字典
142
+
143
+ Returns:
144
+ bool: 保存成功返回True
145
+ """
146
+ if not self._validate_conversation_data(conversation_data):
147
+ return False
148
+
149
+ conversation_id = conversation_data['conversation_id']
150
+ file_path = self._get_conversation_file_path(conversation_id)
151
+
152
+ return self._atomic_write_file(file_path, conversation_data)
153
+
154
+ def load_conversation(self, conversation_id: str) -> Optional[Dict[str, Any]]:
155
+ """
156
+ 加载对话数据
157
+
158
+ Args:
159
+ conversation_id: 对话ID
160
+
161
+ Returns:
162
+ Optional[Dict[str, Any]]: 对话数据,不存在返回None
163
+ """
164
+ file_path = self._get_conversation_file_path(conversation_id)
165
+
166
+ if not file_path.exists():
167
+ return None
168
+
169
+ try:
170
+ with open(file_path, 'r', encoding='utf-8') as f:
171
+ data = json.load(f)
172
+
173
+ # 验证加载的数据
174
+ if not self._validate_conversation_data(data):
175
+ raise DataIntegrityError(f"对话数据无效: {conversation_id}")
176
+
177
+ return data
178
+
179
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
180
+ raise DataIntegrityError(f"对话文件损坏: {conversation_id}, 错误: {str(e)}")
181
+ except (OSError, IOError) as e:
182
+ # 文件读取错误,返回None
183
+ return None
184
+
185
+ def delete_conversation(self, conversation_id: str) -> bool:
186
+ """
187
+ 删除对话数据
188
+
189
+ Args:
190
+ conversation_id: 对话ID
191
+
192
+ Returns:
193
+ bool: 删除成功返回True
194
+ """
195
+ file_path = self._get_conversation_file_path(conversation_id)
196
+
197
+ if not file_path.exists():
198
+ return False
199
+
200
+ try:
201
+ file_path.unlink()
202
+ return True
203
+ except (OSError, IOError):
204
+ return False
205
+
206
+ def conversation_exists(self, conversation_id: str) -> bool:
207
+ """
208
+ 检查对话是否存在
209
+
210
+ Args:
211
+ conversation_id: 对话ID
212
+
213
+ Returns:
214
+ bool: 存在返回True
215
+ """
216
+ file_path = self._get_conversation_file_path(conversation_id)
217
+ return file_path.exists()
218
+
219
+ def list_conversations(
220
+ self,
221
+ limit: Optional[int] = None,
222
+ offset: int = 0
223
+ ) -> List[Dict[str, Any]]:
224
+ """
225
+ 列出对话
226
+
227
+ Args:
228
+ limit: 限制返回数量
229
+ offset: 偏移量
230
+
231
+ Returns:
232
+ List[Dict[str, Any]]: 对话数据列表
233
+ """
234
+ conversations = []
235
+
236
+ try:
237
+ # 获取所有JSON文件
238
+ json_files = list(self.storage_path.glob("*.json"))
239
+
240
+ # 按修改时间排序(最新的在前)
241
+ json_files.sort(key=lambda x: x.stat().st_mtime, reverse=True)
242
+
243
+ # 应用偏移量和限制
244
+ if limit is not None:
245
+ json_files = json_files[offset:offset + limit]
246
+ else:
247
+ json_files = json_files[offset:]
248
+
249
+ # 加载对话数据
250
+ for file_path in json_files:
251
+ try:
252
+ with open(file_path, 'r', encoding='utf-8') as f:
253
+ data = json.load(f)
254
+
255
+ # 验证数据
256
+ if self._validate_conversation_data(data):
257
+ conversations.append(data)
258
+
259
+ except (json.JSONDecodeError, UnicodeDecodeError, OSError, IOError):
260
+ # 跳过损坏的文件
261
+ continue
262
+
263
+ except OSError:
264
+ # 目录访问错误,返回空列表
265
+ pass
266
+
267
+ return conversations
@@ -0,0 +1,406 @@
1
+ """
2
+ 索引管理器实现
3
+
4
+ 提供对话索引管理功能,支持快速查询、搜索和过滤。
5
+ """
6
+
7
+ import os
8
+ import json
9
+ import time
10
+ from typing import Optional, List, Dict, Any
11
+ from pathlib import Path
12
+
13
+ from ..file_locker import FileLocker
14
+ from ..exceptions import DataIntegrityError
15
+
16
+
17
+ class IndexManager:
18
+ """索引管理器,用于管理对话索引"""
19
+
20
+ def __init__(self, index_path: str):
21
+ """
22
+ 初始化索引管理器
23
+
24
+ Args:
25
+ index_path: 索引目录路径
26
+ """
27
+ self.index_path = Path(index_path)
28
+ self.index_file = self.index_path / "conversations.idx"
29
+ self.config_file = self.index_path / "config.json"
30
+ self.lock_file = self.index_path / "index.lock"
31
+
32
+ self._ensure_index_directory()
33
+ self._load_index()
34
+ self._load_config()
35
+
36
+ def _ensure_index_directory(self):
37
+ """确保索引目录存在"""
38
+ self.index_path.mkdir(parents=True, exist_ok=True)
39
+
40
+ def _load_index(self):
41
+ """加载索引数据"""
42
+ try:
43
+ if self.index_file.exists():
44
+ with open(self.index_file, 'r', encoding='utf-8') as f:
45
+ self._index_data = json.load(f)
46
+ else:
47
+ self._index_data = {}
48
+ except (json.JSONDecodeError, OSError, IOError):
49
+ # 如果索引损坏,重建空索引
50
+ self._index_data = {}
51
+
52
+ def _load_config(self):
53
+ """加载配置数据"""
54
+ try:
55
+ if self.config_file.exists():
56
+ with open(self.config_file, 'r', encoding='utf-8') as f:
57
+ self._config_data = json.load(f)
58
+ else:
59
+ self._config_data = {}
60
+ except (json.JSONDecodeError, OSError, IOError):
61
+ # 如果配置损坏,重建空配置
62
+ self._config_data = {}
63
+
64
+ def _save_index(self) -> bool:
65
+ """
66
+ 保存索引数据
67
+
68
+ Returns:
69
+ bool: 保存成功返回True
70
+ """
71
+ try:
72
+ # 使用临时文件进行原子写入
73
+ temp_file = self.index_file.with_suffix('.tmp')
74
+
75
+ with open(temp_file, 'w', encoding='utf-8') as f:
76
+ json.dump(self._index_data, f, ensure_ascii=False, indent=2)
77
+
78
+ # 原子重命名
79
+ temp_file.replace(self.index_file)
80
+ return True
81
+
82
+ except (OSError, IOError):
83
+ return False
84
+
85
+ def _save_config(self) -> bool:
86
+ """
87
+ 保存配置数据
88
+
89
+ Returns:
90
+ bool: 保存成功返回True
91
+ """
92
+ try:
93
+ # 使用临时文件进行原子写入
94
+ temp_file = self.config_file.with_suffix('.tmp')
95
+
96
+ with open(temp_file, 'w', encoding='utf-8') as f:
97
+ json.dump(self._config_data, f, ensure_ascii=False, indent=2)
98
+
99
+ # 原子重命名
100
+ temp_file.replace(self.config_file)
101
+ return True
102
+
103
+ except (OSError, IOError):
104
+ return False
105
+
106
+ def set_current_conversation(self, conversation_id: Optional[str]) -> bool:
107
+ """
108
+ 设置当前对话ID
109
+
110
+ Args:
111
+ conversation_id: 对话ID,None表示清除当前对话
112
+
113
+ Returns:
114
+ bool: 设置成功返回True
115
+ """
116
+ try:
117
+ # 重新加载配置以获取最新数据
118
+ self._load_config()
119
+
120
+ # 设置或清除当前对话ID
121
+ if conversation_id is None:
122
+ self._config_data.pop('current_conversation_id', None)
123
+ else:
124
+ self._config_data['current_conversation_id'] = conversation_id
125
+
126
+ # 更新时间戳
127
+ self._config_data['last_updated'] = time.time()
128
+
129
+ # 保存配置
130
+ return self._save_config()
131
+
132
+ except Exception:
133
+ return False
134
+
135
+ def get_current_conversation_id(self) -> Optional[str]:
136
+ """
137
+ 获取当前对话ID
138
+
139
+ Returns:
140
+ Optional[str]: 当前对话ID,未设置返回None
141
+ """
142
+ try:
143
+ # 重新加载配置以获取最新数据
144
+ self._load_config()
145
+
146
+ return self._config_data.get('current_conversation_id')
147
+
148
+ except Exception:
149
+ return None
150
+
151
+ def clear_current_conversation(self) -> bool:
152
+ """
153
+ 清除当前对话设置
154
+
155
+ Returns:
156
+ bool: 清除成功返回True
157
+ """
158
+ return self.set_current_conversation(None)
159
+
160
+ def add_conversation(self, conversation_metadata: Dict[str, Any]) -> bool:
161
+ """
162
+ 添加对话到索引
163
+
164
+ Args:
165
+ conversation_metadata: 对话元数据
166
+
167
+ Returns:
168
+ bool: 添加成功返回True
169
+ """
170
+ if not conversation_metadata.get('conversation_id'):
171
+ return False
172
+
173
+ conversation_id = conversation_metadata['conversation_id']
174
+
175
+ try:
176
+ # 重新加载索引以获取最新数据
177
+ self._load_index()
178
+
179
+ # 添加或更新对话元数据
180
+ self._index_data[conversation_id] = conversation_metadata.copy()
181
+
182
+ # 保存索引
183
+ return self._save_index()
184
+
185
+ except Exception:
186
+ return False
187
+
188
+ def update_conversation(self, conversation_metadata: Dict[str, Any]) -> bool:
189
+ """
190
+ 更新索引中的对话
191
+
192
+ Args:
193
+ conversation_metadata: 对话元数据
194
+
195
+ Returns:
196
+ bool: 更新成功返回True
197
+ """
198
+ if not conversation_metadata.get('conversation_id'):
199
+ return False
200
+
201
+ conversation_id = conversation_metadata['conversation_id']
202
+
203
+ try:
204
+ # 重新加载索引以获取最新数据
205
+ self._load_index()
206
+
207
+ # 检查对话是否存在
208
+ if conversation_id not in self._index_data:
209
+ return False
210
+
211
+ # 更新对话元数据
212
+ self._index_data[conversation_id] = conversation_metadata.copy()
213
+
214
+ # 保存索引
215
+ return self._save_index()
216
+
217
+ except Exception:
218
+ return False
219
+
220
+ def remove_conversation(self, conversation_id: str) -> bool:
221
+ """
222
+ 从索引中删除对话
223
+
224
+ Args:
225
+ conversation_id: 对话ID
226
+
227
+ Returns:
228
+ bool: 删除成功返回True
229
+ """
230
+ try:
231
+ # 重新加载索引以获取最新数据
232
+ self._load_index()
233
+
234
+ # 检查对话是否存在
235
+ if conversation_id not in self._index_data:
236
+ return False
237
+
238
+ # 删除对话
239
+ del self._index_data[conversation_id]
240
+
241
+ # 保存索引
242
+ return self._save_index()
243
+
244
+ except Exception:
245
+ return False
246
+
247
+ def get_conversation(self, conversation_id: str) -> Optional[Dict[str, Any]]:
248
+ """
249
+ 从索引获取对话信息
250
+
251
+ Args:
252
+ conversation_id: 对话ID
253
+
254
+ Returns:
255
+ Optional[Dict[str, Any]]: 对话元数据,不存在返回None
256
+ """
257
+ try:
258
+ # 重新加载索引以获取最新数据
259
+ self._load_index()
260
+
261
+ return self._index_data.get(conversation_id)
262
+
263
+ except Exception:
264
+ return None
265
+
266
+ def conversation_exists(self, conversation_id: str) -> bool:
267
+ """
268
+ 检查对话是否在索引中存在
269
+
270
+ Args:
271
+ conversation_id: 对话ID
272
+
273
+ Returns:
274
+ bool: 存在返回True
275
+ """
276
+ return self.get_conversation(conversation_id) is not None
277
+
278
+ def list_conversations(
279
+ self,
280
+ limit: Optional[int] = None,
281
+ offset: int = 0,
282
+ sort_by: str = 'updated_at',
283
+ sort_order: str = 'desc'
284
+ ) -> List[Dict[str, Any]]:
285
+ """
286
+ 列出对话
287
+
288
+ Args:
289
+ limit: 限制返回数量
290
+ offset: 偏移量
291
+ sort_by: 排序字段
292
+ sort_order: 排序顺序 ('asc' 或 'desc')
293
+
294
+ Returns:
295
+ List[Dict[str, Any]]: 对话元数据列表
296
+ """
297
+ try:
298
+ # 重新加载索引以获取最新数据
299
+ self._load_index()
300
+
301
+ # 获取所有对话
302
+ conversations = list(self._index_data.values())
303
+
304
+ # 排序
305
+ reverse = (sort_order.lower() == 'desc')
306
+
307
+ if sort_by == 'name':
308
+ conversations.sort(
309
+ key=lambda x: x.get('name', ''),
310
+ reverse=reverse
311
+ )
312
+ elif sort_by == 'created_at':
313
+ conversations.sort(
314
+ key=lambda x: x.get('created_at', 0),
315
+ reverse=reverse
316
+ )
317
+ elif sort_by == 'updated_at':
318
+ conversations.sort(
319
+ key=lambda x: x.get('updated_at', 0),
320
+ reverse=reverse
321
+ )
322
+
323
+ # 应用分页
324
+ if limit is not None:
325
+ return conversations[offset:offset + limit]
326
+ else:
327
+ return conversations[offset:]
328
+
329
+ except Exception:
330
+ return []
331
+
332
+ def search_conversations(
333
+ self,
334
+ query: Optional[str] = None,
335
+ filters: Optional[Dict[str, Any]] = None
336
+ ) -> List[Dict[str, Any]]:
337
+ """
338
+ 搜索对话
339
+
340
+ Args:
341
+ query: 搜索查询字符串
342
+ filters: 过滤条件
343
+
344
+ Returns:
345
+ List[Dict[str, Any]]: 匹配的对话元数据列表
346
+ """
347
+ try:
348
+ # 重新加载索引以获取最新数据
349
+ self._load_index()
350
+
351
+ conversations = list(self._index_data.values())
352
+ results = []
353
+
354
+ for conv in conversations:
355
+ # 文本搜索
356
+ if query:
357
+ query_lower = query.lower()
358
+ name_match = query_lower in conv.get('name', '').lower()
359
+ desc_match = query_lower in conv.get('description', '').lower()
360
+
361
+ if not (name_match or desc_match):
362
+ continue
363
+
364
+ # 应用过滤器
365
+ if filters:
366
+ match = True
367
+
368
+ # 时间范围过滤
369
+ # created_after: 大于等于这个时间的记录
370
+ if 'created_after' in filters:
371
+ created_at = conv.get('created_at', 0)
372
+ if created_at < filters['created_after']:
373
+ match = False
374
+
375
+ # created_before: 小于这个时间的记录(不包含边界)
376
+ if 'created_before' in filters:
377
+ created_at = conv.get('created_at', float('inf'))
378
+ if created_at >= filters['created_before']:
379
+ match = False
380
+
381
+ # 消息数量过滤
382
+ if 'min_message_count' in filters:
383
+ message_count = conv.get('message_count', 0)
384
+ if message_count < filters['min_message_count']:
385
+ match = False
386
+
387
+ if 'max_message_count' in filters:
388
+ message_count = conv.get('message_count', float('inf'))
389
+ if message_count > filters['max_message_count']:
390
+ match = False
391
+
392
+ if not match:
393
+ continue
394
+
395
+ results.append(conv)
396
+
397
+ # 按相关性或更新时间排序
398
+ results.sort(
399
+ key=lambda x: x.get('updated_at', 0),
400
+ reverse=True
401
+ )
402
+
403
+ return results
404
+
405
+ except Exception:
406
+ return []