jarvis-ai-assistant 0.7.8__py3-none-any.whl → 1.0.2__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 (279) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +567 -222
  3. jarvis/jarvis_agent/agent_manager.py +19 -12
  4. jarvis/jarvis_agent/builtin_input_handler.py +79 -11
  5. jarvis/jarvis_agent/config_editor.py +7 -2
  6. jarvis/jarvis_agent/event_bus.py +24 -13
  7. jarvis/jarvis_agent/events.py +19 -1
  8. jarvis/jarvis_agent/file_context_handler.py +67 -64
  9. jarvis/jarvis_agent/file_methodology_manager.py +38 -24
  10. jarvis/jarvis_agent/jarvis.py +186 -114
  11. jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
  12. jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
  13. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
  14. jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
  15. jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
  16. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
  17. jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
  18. jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
  19. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
  20. jarvis/jarvis_agent/language_support_info.py +250 -219
  21. jarvis/jarvis_agent/main.py +19 -23
  22. jarvis/jarvis_agent/memory_manager.py +9 -6
  23. jarvis/jarvis_agent/methodology_share_manager.py +21 -15
  24. jarvis/jarvis_agent/output_handler.py +4 -2
  25. jarvis/jarvis_agent/prompt_builder.py +7 -6
  26. jarvis/jarvis_agent/prompt_manager.py +113 -8
  27. jarvis/jarvis_agent/prompts.py +317 -85
  28. jarvis/jarvis_agent/protocols.py +5 -2
  29. jarvis/jarvis_agent/run_loop.py +192 -32
  30. jarvis/jarvis_agent/session_manager.py +7 -3
  31. jarvis/jarvis_agent/share_manager.py +23 -13
  32. jarvis/jarvis_agent/shell_input_handler.py +12 -8
  33. jarvis/jarvis_agent/stdio_redirect.py +25 -26
  34. jarvis/jarvis_agent/task_analyzer.py +29 -23
  35. jarvis/jarvis_agent/task_list.py +869 -0
  36. jarvis/jarvis_agent/task_manager.py +26 -23
  37. jarvis/jarvis_agent/tool_executor.py +6 -5
  38. jarvis/jarvis_agent/tool_share_manager.py +24 -14
  39. jarvis/jarvis_agent/user_interaction.py +3 -3
  40. jarvis/jarvis_agent/utils.py +9 -1
  41. jarvis/jarvis_agent/web_bridge.py +37 -17
  42. jarvis/jarvis_agent/web_output_sink.py +5 -2
  43. jarvis/jarvis_agent/web_server.py +165 -36
  44. jarvis/jarvis_c2rust/__init__.py +1 -1
  45. jarvis/jarvis_c2rust/cli.py +260 -141
  46. jarvis/jarvis_c2rust/collector.py +37 -18
  47. jarvis/jarvis_c2rust/constants.py +60 -0
  48. jarvis/jarvis_c2rust/library_replacer.py +242 -1010
  49. jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
  50. jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
  51. jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
  52. jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
  53. jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
  54. jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
  55. jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
  56. jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
  57. jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
  58. jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
  59. jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
  60. jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
  61. jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
  62. jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
  63. jarvis/jarvis_c2rust/loaders.py +28 -10
  64. jarvis/jarvis_c2rust/models.py +5 -2
  65. jarvis/jarvis_c2rust/optimizer.py +192 -1974
  66. jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
  67. jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
  68. jarvis/jarvis_c2rust/optimizer_config.py +49 -0
  69. jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
  70. jarvis/jarvis_c2rust/optimizer_options.py +48 -0
  71. jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
  72. jarvis/jarvis_c2rust/optimizer_report.py +52 -0
  73. jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
  74. jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
  75. jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
  76. jarvis/jarvis_c2rust/scanner.py +229 -166
  77. jarvis/jarvis_c2rust/transpiler.py +531 -2732
  78. jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
  79. jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
  80. jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
  81. jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
  82. jarvis/jarvis_c2rust/transpiler_config.py +178 -0
  83. jarvis/jarvis_c2rust/transpiler_context.py +122 -0
  84. jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
  85. jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
  86. jarvis/jarvis_c2rust/transpiler_git.py +163 -0
  87. jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
  88. jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
  89. jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
  90. jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
  91. jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
  92. jarvis/jarvis_c2rust/utils.py +269 -79
  93. jarvis/jarvis_code_agent/after_change.py +233 -0
  94. jarvis/jarvis_code_agent/build_validation_config.py +37 -30
  95. jarvis/jarvis_code_agent/builtin_rules.py +68 -0
  96. jarvis/jarvis_code_agent/code_agent.py +976 -1517
  97. jarvis/jarvis_code_agent/code_agent_build.py +227 -0
  98. jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
  99. jarvis/jarvis_code_agent/code_agent_git.py +525 -0
  100. jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
  101. jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
  102. jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
  103. jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
  104. jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
  105. jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
  106. jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
  107. jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
  108. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
  109. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
  110. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
  111. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
  112. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
  113. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
  114. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
  115. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
  116. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
  117. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
  118. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
  119. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
  120. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
  121. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
  122. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
  123. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
  124. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
  125. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
  126. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
  127. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
  128. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
  129. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
  130. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
  131. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
  132. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
  133. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
  134. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
  135. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
  136. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
  137. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
  138. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
  139. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
  140. jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
  141. jarvis/jarvis_code_agent/lint.py +223 -524
  142. jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
  143. jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
  144. jarvis/jarvis_code_agent/rules/code_review.md +115 -0
  145. jarvis/jarvis_code_agent/rules/documentation.md +165 -0
  146. jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
  147. jarvis/jarvis_code_agent/rules/performance.md +158 -0
  148. jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
  149. jarvis/jarvis_code_agent/rules/security.md +160 -0
  150. jarvis/jarvis_code_agent/rules/tdd.md +78 -0
  151. jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
  152. jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
  153. jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
  154. jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
  155. jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
  156. jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
  157. jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
  158. jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
  159. jarvis/jarvis_code_agent/utils.py +36 -26
  160. jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
  161. jarvis/jarvis_code_analysis/code_review.py +64 -33
  162. jarvis/jarvis_data/config_schema.json +285 -192
  163. jarvis/jarvis_git_squash/main.py +8 -6
  164. jarvis/jarvis_git_utils/git_commiter.py +53 -76
  165. jarvis/jarvis_mcp/__init__.py +5 -2
  166. jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
  167. jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
  168. jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
  169. jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
  170. jarvis/jarvis_methodology/main.py +48 -39
  171. jarvis/jarvis_multi_agent/__init__.py +56 -23
  172. jarvis/jarvis_multi_agent/main.py +15 -18
  173. jarvis/jarvis_platform/base.py +179 -111
  174. jarvis/jarvis_platform/human.py +27 -16
  175. jarvis/jarvis_platform/kimi.py +52 -45
  176. jarvis/jarvis_platform/openai.py +101 -40
  177. jarvis/jarvis_platform/registry.py +51 -33
  178. jarvis/jarvis_platform/tongyi.py +68 -38
  179. jarvis/jarvis_platform/yuanbao.py +59 -43
  180. jarvis/jarvis_platform_manager/main.py +68 -76
  181. jarvis/jarvis_platform_manager/service.py +24 -14
  182. jarvis/jarvis_rag/README_CONFIG.md +314 -0
  183. jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
  184. jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
  185. jarvis/jarvis_rag/__init__.py +57 -4
  186. jarvis/jarvis_rag/cache.py +3 -1
  187. jarvis/jarvis_rag/cli.py +48 -68
  188. jarvis/jarvis_rag/embedding_interface.py +39 -0
  189. jarvis/jarvis_rag/embedding_manager.py +7 -230
  190. jarvis/jarvis_rag/embeddings/__init__.py +41 -0
  191. jarvis/jarvis_rag/embeddings/base.py +114 -0
  192. jarvis/jarvis_rag/embeddings/cohere.py +66 -0
  193. jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
  194. jarvis/jarvis_rag/embeddings/local.py +260 -0
  195. jarvis/jarvis_rag/embeddings/openai.py +62 -0
  196. jarvis/jarvis_rag/embeddings/registry.py +293 -0
  197. jarvis/jarvis_rag/llm_interface.py +8 -6
  198. jarvis/jarvis_rag/query_rewriter.py +8 -9
  199. jarvis/jarvis_rag/rag_pipeline.py +61 -52
  200. jarvis/jarvis_rag/reranker.py +7 -75
  201. jarvis/jarvis_rag/reranker_interface.py +32 -0
  202. jarvis/jarvis_rag/rerankers/__init__.py +41 -0
  203. jarvis/jarvis_rag/rerankers/base.py +109 -0
  204. jarvis/jarvis_rag/rerankers/cohere.py +67 -0
  205. jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
  206. jarvis/jarvis_rag/rerankers/jina.py +79 -0
  207. jarvis/jarvis_rag/rerankers/local.py +89 -0
  208. jarvis/jarvis_rag/rerankers/registry.py +293 -0
  209. jarvis/jarvis_rag/retriever.py +58 -43
  210. jarvis/jarvis_sec/__init__.py +66 -141
  211. jarvis/jarvis_sec/agents.py +21 -17
  212. jarvis/jarvis_sec/analysis.py +80 -33
  213. jarvis/jarvis_sec/checkers/__init__.py +7 -13
  214. jarvis/jarvis_sec/checkers/c_checker.py +356 -164
  215. jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
  216. jarvis/jarvis_sec/cli.py +43 -21
  217. jarvis/jarvis_sec/clustering.py +430 -272
  218. jarvis/jarvis_sec/file_manager.py +99 -55
  219. jarvis/jarvis_sec/parsers.py +9 -6
  220. jarvis/jarvis_sec/prompts.py +4 -3
  221. jarvis/jarvis_sec/report.py +44 -22
  222. jarvis/jarvis_sec/review.py +180 -107
  223. jarvis/jarvis_sec/status.py +50 -41
  224. jarvis/jarvis_sec/types.py +3 -0
  225. jarvis/jarvis_sec/utils.py +160 -83
  226. jarvis/jarvis_sec/verification.py +411 -181
  227. jarvis/jarvis_sec/workflow.py +132 -21
  228. jarvis/jarvis_smart_shell/main.py +28 -41
  229. jarvis/jarvis_stats/cli.py +14 -12
  230. jarvis/jarvis_stats/stats.py +28 -19
  231. jarvis/jarvis_stats/storage.py +14 -8
  232. jarvis/jarvis_stats/visualizer.py +12 -7
  233. jarvis/jarvis_tools/base.py +5 -2
  234. jarvis/jarvis_tools/clear_memory.py +13 -9
  235. jarvis/jarvis_tools/cli/main.py +23 -18
  236. jarvis/jarvis_tools/edit_file.py +572 -873
  237. jarvis/jarvis_tools/execute_script.py +10 -7
  238. jarvis/jarvis_tools/file_analyzer.py +7 -8
  239. jarvis/jarvis_tools/meta_agent.py +287 -0
  240. jarvis/jarvis_tools/methodology.py +5 -3
  241. jarvis/jarvis_tools/read_code.py +305 -1438
  242. jarvis/jarvis_tools/read_symbols.py +50 -17
  243. jarvis/jarvis_tools/read_webpage.py +19 -18
  244. jarvis/jarvis_tools/registry.py +435 -156
  245. jarvis/jarvis_tools/retrieve_memory.py +16 -11
  246. jarvis/jarvis_tools/save_memory.py +8 -6
  247. jarvis/jarvis_tools/search_web.py +31 -31
  248. jarvis/jarvis_tools/sub_agent.py +32 -28
  249. jarvis/jarvis_tools/sub_code_agent.py +44 -60
  250. jarvis/jarvis_tools/task_list_manager.py +1811 -0
  251. jarvis/jarvis_tools/virtual_tty.py +29 -19
  252. jarvis/jarvis_utils/__init__.py +4 -0
  253. jarvis/jarvis_utils/builtin_replace_map.py +2 -1
  254. jarvis/jarvis_utils/clipboard.py +9 -8
  255. jarvis/jarvis_utils/collections.py +331 -0
  256. jarvis/jarvis_utils/config.py +699 -194
  257. jarvis/jarvis_utils/dialogue_recorder.py +294 -0
  258. jarvis/jarvis_utils/embedding.py +6 -3
  259. jarvis/jarvis_utils/file_processors.py +7 -1
  260. jarvis/jarvis_utils/fzf.py +9 -3
  261. jarvis/jarvis_utils/git_utils.py +71 -42
  262. jarvis/jarvis_utils/globals.py +116 -32
  263. jarvis/jarvis_utils/http.py +6 -2
  264. jarvis/jarvis_utils/input.py +318 -83
  265. jarvis/jarvis_utils/jsonnet_compat.py +119 -104
  266. jarvis/jarvis_utils/methodology.py +37 -28
  267. jarvis/jarvis_utils/output.py +201 -44
  268. jarvis/jarvis_utils/utils.py +986 -628
  269. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
  270. jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
  271. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
  272. jarvis/jarvis_tools/generate_new_tool.py +0 -205
  273. jarvis/jarvis_tools/lsp_client.py +0 -1552
  274. jarvis/jarvis_tools/rewrite_file.py +0 -105
  275. jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -5,10 +5,17 @@ import json
5
5
  import mimetypes
6
6
  import os
7
7
  import time
8
- from typing import Dict, Generator, List, Tuple
8
+ from typing import Any
9
+ from typing import Dict
10
+ from typing import Generator
11
+ from typing import List
12
+ from typing import Optional
13
+ from typing import Tuple
14
+ from typing import cast
9
15
 
10
16
  from jarvis.jarvis_platform.base import BasePlatform
11
17
  from jarvis.jarvis_utils import http
18
+ from jarvis.jarvis_utils.output import PrettyOutput
12
19
  from jarvis.jarvis_utils.utils import while_success
13
20
 
14
21
 
@@ -28,17 +35,23 @@ class KimiModel(BasePlatform):
28
35
  ("k2", "基于网页的 Kimi,深度思考模型 K2"),
29
36
  ]
30
37
 
31
- def __init__(self):
38
+ def __init__(self, llm_config: Optional[Dict[str, Any]] = None):
32
39
  """
33
40
  Initialize Kimi model
41
+
42
+ 参数:
43
+ llm_config: LLM配置字典,包含 kimi_api_key 等
34
44
  """
35
45
  super().__init__()
36
46
  self.chat_id = "" # 当前会话ID
37
- self.api_key = os.getenv("KIMI_API_KEY") # 从环境变量获取API密钥
47
+ llm_config = llm_config or {}
48
+
49
+ # 从 llm_config 获取配置,如果没有则从环境变量获取(向后兼容)
50
+ self.api_key = llm_config.get("kimi_api_key") or os.getenv("KIMI_API_KEY")
38
51
  if not self.api_key:
39
- print("⚠️ KIMI_API_KEY 未设置")
52
+ PrettyOutput.auto_print("⚠️ KIMI_API_KEY 未设置")
40
53
  self.auth_header = f"Bearer {self.api_key}" # 认证头信息
41
- self.uploaded_files = [] # 存储已上传文件的信息
54
+ self.uploaded_files: List[Dict[str, Any]] = [] # 存储已上传文件的信息
42
55
  self.chat_id = "" # 当前会话ID
43
56
  self.first_chat = True # 标记是否是第一次对话
44
57
  self.system_message = "" # 系统提示消息
@@ -67,12 +80,12 @@ class KimiModel(BasePlatform):
67
80
  lambda: http.post(url, headers=headers, data=payload)
68
81
  )
69
82
  if response.status_code != 200:
70
- print(f"❌ 错误:创建会话失败:{response.json()}")
83
+ PrettyOutput.auto_print(f"❌ 错误:创建会话失败:{response.json()}")
71
84
  return False
72
- self.chat_id = response.json()["id"]
85
+ self.chat_id = cast(str, cast(Dict[str, Any], response.json())["id"])
73
86
  return True
74
87
  except Exception as e:
75
- print(f"❌ 错误:创建会话失败:{e}")
88
+ PrettyOutput.auto_print(f"❌ 错误:创建会话失败:{e}")
76
89
  return False
77
90
 
78
91
  def _get_presigned_url(self, filename: str, action: str) -> Dict:
@@ -88,9 +101,8 @@ class KimiModel(BasePlatform):
88
101
  "Content-Type": "application/json",
89
102
  }
90
103
 
91
- response = while_success(
92
- lambda: http.post(url, headers=headers, data=payload) )
93
- return response.json()
104
+ response = while_success(lambda: http.post(url, headers=headers, data=payload))
105
+ return cast(Dict[str, Any], response.json())
94
106
 
95
107
  def support_upload_files(self) -> bool:
96
108
  """Check if platform supports upload files"""
@@ -101,12 +113,10 @@ class KimiModel(BasePlatform):
101
113
  try:
102
114
  with open(file_path, "rb") as f:
103
115
  content = f.read()
104
- response = while_success(
105
- lambda: http.put(presigned_url, data=content)
106
- )
107
- return response.status_code == 200
116
+ response = while_success(lambda: http.put(presigned_url, data=content))
117
+ return bool(response.status_code == 200)
108
118
  except Exception as e:
109
- print(f"❌ 错误:上传文件失败:{e}")
119
+ PrettyOutput.auto_print(f"❌ 错误:上传文件失败:{e}")
110
120
  return False
111
121
 
112
122
  def _get_file_info(self, file_data: Dict, name: str, file_type: str) -> Dict:
@@ -128,9 +138,8 @@ class KimiModel(BasePlatform):
128
138
  "Content-Type": "application/json",
129
139
  }
130
140
 
131
- response = while_success(
132
- lambda: http.post(url, headers=headers, data=payload) )
133
- return response.json()
141
+ response = while_success(lambda: http.post(url, headers=headers, data=payload))
142
+ return cast(Dict[str, Any], response.json())
134
143
 
135
144
  def _wait_for_parse(self, file_id: str) -> bool:
136
145
  """Wait for file parsing to complete"""
@@ -178,11 +187,11 @@ class KimiModel(BasePlatform):
178
187
  return True
179
188
 
180
189
  if not self.chat_id:
181
- print("ℹ️ 正在创建聊天会话...")
190
+ PrettyOutput.auto_print("ℹ️ 正在创建聊天会话...")
182
191
  if not self._create_chat():
183
- print("❌ 创建聊天会话失败")
192
+ PrettyOutput.auto_print("❌ 创建聊天会话失败")
184
193
  return False
185
- print("✅ 创建聊天会话成功")
194
+ PrettyOutput.auto_print("✅ 创建聊天会话成功")
186
195
 
187
196
  uploaded_files = []
188
197
  for index, file_path in enumerate(file_list, 1):
@@ -213,26 +222,26 @@ class KimiModel(BasePlatform):
213
222
  log_lines.append(f"文件处理完成: {file_name}")
214
223
  else:
215
224
  log_lines.append(f"文件解析失败: {file_name}")
216
- joined_logs = '\n'.join(log_lines)
217
- print(f"❌ {joined_logs}")
225
+ joined_logs = "\n".join(log_lines)
226
+ PrettyOutput.auto_print(f"❌ {joined_logs}")
218
227
  return False
219
228
  else:
220
229
  uploaded_files.append(file_info)
221
230
  log_lines.append(f"图片处理完成: {file_name}")
222
231
  else:
223
232
  log_lines.append(f"文件上传失败: {file_name}")
224
- joined_logs = '\n'.join(log_lines)
225
- print(f"❌ {joined_logs}")
233
+ joined_logs = "\n".join(log_lines)
234
+ PrettyOutput.auto_print(f"❌ {joined_logs}")
226
235
  return False
227
236
 
228
237
  # 成功路径统一输出本文件的处理日志
229
- joined_logs = '\n'.join(log_lines)
230
- print(f"ℹ️ {joined_logs}")
238
+ joined_logs = "\n".join(log_lines)
239
+ PrettyOutput.auto_print(f"ℹ️ {joined_logs}")
231
240
 
232
241
  except Exception as e:
233
242
  log_lines.append(f"处理文件出错 {file_path}: {str(e)}")
234
- joined_logs = '\n'.join(log_lines)
235
- print(f"❌ {joined_logs}")
243
+ joined_logs = "\n".join(log_lines)
244
+ PrettyOutput.auto_print(f"❌ {joined_logs}")
236
245
  return False
237
246
 
238
247
  self.uploaded_files = uploaded_files
@@ -322,25 +331,23 @@ class KimiModel(BasePlatform):
322
331
  }
323
332
 
324
333
  try:
325
- response = while_success(
326
- lambda: http.delete(url, headers=headers)
327
- )
334
+ response = while_success(lambda: http.delete(url, headers=headers))
328
335
  if response.status_code == 200:
329
336
  self.chat_id = ""
330
337
  self.uploaded_files = []
331
338
  self.first_chat = True # 重置first_chat标记
332
339
  return True
333
340
  else:
334
- print(f"⚠️ 删除会话失败: HTTP {response.status_code}")
341
+ PrettyOutput.auto_print(f"⚠️ 删除会话失败: HTTP {response.status_code}")
335
342
  return False
336
343
  except Exception as e:
337
- print(f"❌ 删除会话时发生错误: {str(e)}")
344
+ PrettyOutput.auto_print(f"❌ 删除会话时发生错误: {str(e)}")
338
345
  return False
339
346
 
340
347
  def save(self, file_path: str) -> bool:
341
348
  """Save chat session to a file."""
342
349
  if not self.chat_id:
343
- print("⚠️ 没有活动的会话可供保存")
350
+ PrettyOutput.auto_print("⚠️ 没有活动的会话可供保存")
344
351
  return False
345
352
 
346
353
  state = {
@@ -355,10 +362,10 @@ class KimiModel(BasePlatform):
355
362
  with open(file_path, "w", encoding="utf-8") as f:
356
363
  json.dump(state, f, ensure_ascii=False, indent=4)
357
364
  self._saved = True
358
- print(f"✅ 会话已成功保存到 {file_path}")
365
+ PrettyOutput.auto_print(f"✅ 会话已成功保存到 {file_path}")
359
366
  return True
360
367
  except Exception as e:
361
- print(f"❌ 保存会话失败: {str(e)}")
368
+ PrettyOutput.auto_print(f"❌ 保存会话失败: {str(e)}")
362
369
  return False
363
370
 
364
371
  def restore(self, file_path: str) -> bool:
@@ -374,13 +381,13 @@ class KimiModel(BasePlatform):
374
381
  self.uploaded_files = state.get("uploaded_files", [])
375
382
  self._saved = True
376
383
 
377
- print(f"✅ 从 {file_path} 成功恢复会话")
384
+ PrettyOutput.auto_print(f"✅ 从 {file_path} 成功恢复会话")
378
385
  return True
379
386
  except FileNotFoundError:
380
- print(f"❌ 会话文件未找到: {file_path}")
387
+ PrettyOutput.auto_print(f"❌ 会话文件未找到: {file_path}")
381
388
  return False
382
389
  except Exception as e:
383
- print(f"❌ 恢复会话失败: {str(e)}")
390
+ PrettyOutput.auto_print(f"❌ 恢复会话失败: {str(e)}")
384
391
  return False
385
392
 
386
393
  def name(self) -> str:
@@ -399,20 +406,20 @@ class KimiModel(BasePlatform):
399
406
  @classmethod
400
407
  def get_required_env_keys(cls) -> List[str]:
401
408
  """
402
- 获取Kimi平台所需的环境变量键列表
409
+ 获取Kimi平台所需的配置键列表(已弃用:建议使用 llm_config 配置)
403
410
 
404
411
  返回:
405
- List[str]: 环境变量键的列表
412
+ List[str]: 配置键的列表(对应 llm_config 中的 kimi_api_key)
406
413
  """
407
414
  return ["KIMI_API_KEY"]
408
415
 
409
416
  @classmethod
410
417
  def get_env_config_guide(cls) -> Dict[str, str]:
411
418
  """
412
- 获取环境变量配置指导
419
+ 获取配置指导(已弃用:建议使用 llm_config 配置)
413
420
 
414
421
  返回:
415
- Dict[str, str]: 环境变量名到配置指导的映射
422
+ Dict[str, str]: 配置键名到配置指导的映射
416
423
  """
417
424
  return {
418
425
  "KIMI_API_KEY": (
@@ -1,55 +1,90 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import json
3
3
  import os
4
- from typing import Dict, Generator, List, Tuple
4
+ from typing import Any
5
+ from typing import Dict
6
+ from typing import Generator
7
+ from typing import List
8
+ from typing import Optional
9
+ from typing import Tuple
5
10
 
6
11
  from openai import OpenAI
12
+ from openai.types.chat import ChatCompletionMessageParam
7
13
 
8
14
  from jarvis.jarvis_platform.base import BasePlatform
15
+ from jarvis.jarvis_utils.output import PrettyOutput
9
16
 
10
17
 
11
18
  class OpenAIModel(BasePlatform):
12
-
13
- def __init__(self):
19
+ def __init__(self, llm_config: Optional[Dict[str, Any]] = None):
14
20
  """
15
21
  Initialize OpenAI model
22
+
23
+ 参数:
24
+ llm_config: LLM配置字典,包含 openai_api_key, openai_api_base, openai_extra_headers 等
16
25
  """
17
26
  super().__init__()
18
27
  self.system_message = ""
19
- self.api_key = os.getenv("OPENAI_API_KEY")
20
- if not self.api_key:
21
- print("⚠️ OPENAI_API_KEY 未设置")
28
+ llm_config = llm_config or {}
22
29
 
23
- self.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
24
- self.model_name = os.getenv("JARVIS_MODEL") or "gpt-4o"
30
+ # llm_config 获取配置,如果没有则从环境变量获取(向后兼容)
31
+ self.api_key = llm_config.get("openai_api_key") or os.getenv("OPENAI_API_KEY")
32
+ if not self.api_key:
33
+ PrettyOutput.auto_print("⚠️ OPENAI_API_KEY 未设置")
34
+
35
+ self.base_url = llm_config.get("openai_api_base") or os.getenv(
36
+ "OPENAI_API_BASE", "https://api.openai.com/v1"
37
+ )
38
+ self.model_name = os.getenv("model") or "gpt-4o"
39
+
40
+ # Optional: Inject extra HTTP headers via llm_config or environment variable
41
+ # Expected format: openai_extra_headers='{"Header-Name": "value", "X-Trace": "abc"}'
42
+ headers_value = llm_config.get("openai_extra_headers")
43
+ if headers_value is None:
44
+ headers_str = os.getenv("OPENAI_EXTRA_HEADERS")
45
+ else:
46
+ headers_str = (
47
+ headers_value
48
+ if isinstance(headers_value, str)
49
+ else json.dumps(headers_value)
50
+ )
25
51
 
26
- # Optional: Inject extra HTTP headers via environment variable
27
- # Expected format: OPENAI_EXTRA_HEADERS='{"Header-Name": "value", "X-Trace": "abc"}'
28
- headers_str = os.getenv("OPENAI_EXTRA_HEADERS")
29
52
  self.extra_headers: Dict[str, str] = {}
30
53
  if headers_str:
31
54
  try:
32
- parsed = json.loads(headers_str)
55
+ parsed = (
56
+ json.loads(headers_str)
57
+ if isinstance(headers_str, str)
58
+ else headers_str
59
+ )
33
60
  if isinstance(parsed, dict):
34
61
  # Ensure all header keys/values are strings
35
62
  self.extra_headers = {str(k): str(v) for k, v in parsed.items()}
36
63
  else:
37
- print("⚠️ OPENAI_EXTRA_HEADERS 应为 JSON 对象,如 {'X-Source':'jarvis'}")
64
+ PrettyOutput.auto_print(
65
+ "⚠️ openai_extra_headers 应为 JSON 对象,如 {'X-Source':'jarvis'}"
66
+ )
38
67
  except Exception as e:
39
- print(f"⚠️ 解析 OPENAI_EXTRA_HEADERS 失败: {e}")
68
+ PrettyOutput.auto_print(f"⚠️ 解析 openai_extra_headers 失败: {e}")
40
69
 
41
70
  # Initialize OpenAI client, try to pass default headers if SDK supports it
42
71
  try:
43
72
  if self.extra_headers:
44
- self.client = OpenAI(api_key=self.api_key, base_url=self.base_url, default_headers=self.extra_headers)
73
+ self.client = OpenAI(
74
+ api_key=self.api_key,
75
+ base_url=self.base_url,
76
+ default_headers=self.extra_headers,
77
+ )
45
78
  else:
46
79
  self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
47
80
  except TypeError:
48
81
  # Fallback: SDK version may not support default_headers
49
82
  self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
50
83
  if self.extra_headers:
51
- print("⚠️ 当前 OpenAI SDK 不支持 default_headers,未能注入额外 HTTP 头")
52
- self.messages: List[Dict[str, str]] = []
84
+ PrettyOutput.auto_print(
85
+ "⚠️ 当前 OpenAI SDK 不支持 default_headers,未能注入额外 HTTP 头"
86
+ )
87
+ self.messages: List[ChatCompletionMessageParam] = []
53
88
  self.system_message = ""
54
89
 
55
90
  def upload_files(self, file_list: List[str]) -> bool:
@@ -81,7 +116,7 @@ class OpenAIModel(BasePlatform):
81
116
  model_list.append((model.id, model.id))
82
117
  return model_list
83
118
  except Exception as e:
84
- print(f"❌ 获取模型列表失败:{str(e)}")
119
+ PrettyOutput.auto_print(f"❌ 获取模型列表失败:{str(e)}")
85
120
  return []
86
121
 
87
122
  def set_model_name(self, model_name: str):
@@ -126,26 +161,26 @@ class OpenAIModel(BasePlatform):
126
161
 
127
162
  # 累计完整响应
128
163
  accumulated_response = ""
129
-
164
+
130
165
  # 循环处理,直到不是因为长度限制而结束
131
166
  while True:
132
167
  response = self.client.chat.completions.create(
133
168
  model=self.model_name, # Use the configured model name
134
- messages=self.messages, # type: ignore
169
+ messages=self.messages,
135
170
  stream=True,
136
- ) # type: ignore
171
+ )
137
172
 
138
173
  full_response = ""
139
174
  finish_reason = None
140
-
175
+
141
176
  for chunk in response:
142
177
  if chunk.choices and len(chunk.choices) > 0:
143
178
  choice = chunk.choices[0]
144
-
179
+
145
180
  # 检查 finish_reason(通常在最后一个 chunk 中)
146
181
  if choice.finish_reason:
147
182
  finish_reason = choice.finish_reason
148
-
183
+
149
184
  # 获取内容增量
150
185
  if choice.delta and choice.delta.content:
151
186
  text = choice.delta.content
@@ -158,11 +193,20 @@ class OpenAIModel(BasePlatform):
158
193
  # 将已获取的内容追加到消息历史中,以便下次请求时模型知道已生成的内容
159
194
  if self.messages and self.messages[-1].get("role") == "assistant":
160
195
  # 追加到现有的 assistant 消息
161
- self.messages[-1]["content"] += full_response
196
+ last_content = self.messages[-1]["content"]
197
+ if isinstance(last_content, str):
198
+ self.messages[-1]["content"] = last_content + full_response
199
+ else:
200
+ # 如果content不是字符串,创建新的消息
201
+ self.messages.append(
202
+ {"role": "assistant", "content": full_response}
203
+ )
162
204
  else:
163
205
  # 创建新的 assistant 消息
164
- self.messages.append({"role": "assistant", "content": full_response})
165
-
206
+ self.messages.append(
207
+ {"role": "assistant", "content": full_response}
208
+ )
209
+
166
210
  # 添加一个继续请求的用户消息,让模型继续生成
167
211
  self.messages.append({"role": "user", "content": "请继续。"})
168
212
  # 继续循环,获取剩余内容
@@ -171,18 +215,35 @@ class OpenAIModel(BasePlatform):
171
215
  # 正常结束(stop、null 或其他原因)
172
216
  # 将完整响应添加到消息历史
173
217
  if accumulated_response:
174
- if self.messages and self.messages[-1].get("role") == "assistant":
218
+ if (
219
+ self.messages
220
+ and self.messages[-1].get("role") == "assistant"
221
+ ):
175
222
  # 如果最后一条是 assistant 消息,追加本次的内容
176
- self.messages[-1]["content"] += full_response
223
+ last_content = self.messages[-1]["content"]
224
+ if isinstance(last_content, str):
225
+ self.messages[-1]["content"] = (
226
+ last_content + full_response
227
+ )
228
+ else:
229
+ # 如果content不是字符串,创建新的消息
230
+ self.messages.append(
231
+ {
232
+ "role": "assistant",
233
+ "content": accumulated_response,
234
+ }
235
+ )
177
236
  else:
178
237
  # 创建新的 assistant 消息,使用累计的完整响应
179
- self.messages.append({"role": "assistant", "content": accumulated_response})
238
+ self.messages.append(
239
+ {"role": "assistant", "content": accumulated_response}
240
+ )
180
241
  break
181
242
 
182
243
  return None
183
244
 
184
245
  except Exception as e:
185
- print(f"❌ 对话失败:{str(e)}")
246
+ PrettyOutput.auto_print(f"❌ 对话失败:{str(e)}")
186
247
  raise Exception(f"Chat failed: {str(e)}")
187
248
 
188
249
  def name(self) -> str:
@@ -231,10 +292,10 @@ class OpenAIModel(BasePlatform):
231
292
  with open(file_path, "w", encoding="utf-8") as f:
232
293
  json.dump(state, f, ensure_ascii=False, indent=4)
233
294
  self._saved = True
234
- print(f"✅ 会话已成功保存到 {file_path}")
295
+ PrettyOutput.auto_print(f"✅ 会话已成功保存到 {file_path}")
235
296
  return True
236
297
  except Exception as e:
237
- print(f"❌ 保存会话失败: {str(e)}")
298
+ PrettyOutput.auto_print(f"❌ 保存会话失败: {str(e)}")
238
299
  return False
239
300
 
240
301
  def restore(self, file_path: str) -> bool:
@@ -248,13 +309,13 @@ class OpenAIModel(BasePlatform):
248
309
  # atexit.register(self.delete_chat)
249
310
  self._saved = True
250
311
 
251
- print(f"✅ 从 {file_path} 成功恢复会话")
312
+ PrettyOutput.auto_print(f"✅ 从 {file_path} 成功恢复会话")
252
313
  return True
253
314
  except FileNotFoundError:
254
- print(f"❌ 会话文件未找到: {file_path}")
315
+ PrettyOutput.auto_print(f"❌ 会话文件未找到: {file_path}")
255
316
  return False
256
317
  except Exception as e:
257
- print(f"❌ 恢复会话失败: {str(e)}")
318
+ PrettyOutput.auto_print(f"❌ 恢复会话失败: {str(e)}")
258
319
  return False
259
320
 
260
321
  def support_web(self) -> bool:
@@ -278,20 +339,20 @@ class OpenAIModel(BasePlatform):
278
339
  @classmethod
279
340
  def get_required_env_keys(cls) -> List[str]:
280
341
  """
281
- 获取OpenAI平台所需的环境变量键列表
342
+ 获取OpenAI平台所需的配置键列表(已弃用:建议使用 llm_config 配置)
282
343
 
283
344
  返回:
284
- List[str]: 环境变量键的列表
345
+ List[str]: 配置键的列表(对应 llm_config 中的 openai_api_key, openai_api_base)
285
346
  """
286
347
  return ["OPENAI_API_KEY", "OPENAI_API_BASE"]
287
348
 
288
349
  @classmethod
289
350
  def get_env_config_guide(cls) -> Dict[str, str]:
290
351
  """
291
- 获取环境变量配置指导
352
+ 获取配置指导(已弃用:建议使用 llm_config 配置)
292
353
 
293
354
  返回:
294
- Dict[str, str]: 环境变量名到配置指导的映射
355
+ Dict[str, str]: 配置键名到配置指导的映射
295
356
  """
296
357
  return {
297
358
  "OPENAI_API_KEY": (
@@ -3,18 +3,22 @@ import importlib
3
3
  import inspect
4
4
  import os
5
5
  import sys
6
- from typing import Dict, List, Optional, Type
6
+ from typing import Any
7
+ from typing import Dict
8
+ from typing import List
9
+ from typing import Optional
10
+ from typing import Type
7
11
 
8
12
  from jarvis.jarvis_platform.base import BasePlatform
9
- from jarvis.jarvis_utils.config import (
10
- get_cheap_model_name,
11
- get_cheap_platform_name,
12
- get_data_dir,
13
- get_normal_model_name,
14
- get_normal_platform_name,
15
- get_smart_model_name,
16
- get_smart_platform_name,
17
- )
13
+ from jarvis.jarvis_utils.config import get_cheap_model_name
14
+ from jarvis.jarvis_utils.config import get_cheap_platform_name
15
+ from jarvis.jarvis_utils.config import get_data_dir
16
+ from jarvis.jarvis_utils.config import get_llm_config
17
+ from jarvis.jarvis_utils.config import get_normal_model_name
18
+ from jarvis.jarvis_utils.config import get_normal_platform_name
19
+ from jarvis.jarvis_utils.config import get_smart_model_name
20
+ from jarvis.jarvis_utils.config import get_smart_platform_name
21
+ from jarvis.jarvis_utils.output import PrettyOutput
18
22
 
19
23
  REQUIRED_METHODS = [
20
24
  ("chat", ["message"]), # 方法名和参数列表
@@ -45,7 +49,7 @@ class PlatformRegistry:
45
49
  ):
46
50
  pass
47
51
  except Exception as e:
48
- print(f"❌ 创建平台目录失败: {str(e)}")
52
+ PrettyOutput.auto_print(f"❌ 创建平台目录失败: {str(e)}")
49
53
  return ""
50
54
  return user_platform_dir
51
55
 
@@ -80,7 +84,9 @@ class PlatformRegistry:
80
84
  missing_methods.append(f"{method_name}(parameter mismatch)")
81
85
 
82
86
  if missing_methods:
83
- print(f"⚠️ 平台 {platform_class.__name__} 缺少必要的方法: {', '.join(missing_methods)}")
87
+ PrettyOutput.auto_print(
88
+ f"⚠️ 平台 {platform_class.__name__} 缺少必要的方法: {', '.join(missing_methods)}"
89
+ )
84
90
  return False
85
91
 
86
92
  return True
@@ -99,7 +105,7 @@ class PlatformRegistry:
99
105
 
100
106
  # 确保目录存在
101
107
  if not os.path.exists(directory):
102
- print(f"⚠️ 平台目录不存在: {directory}")
108
+ PrettyOutput.auto_print(f"⚠️ 平台目录不存在: {directory}")
103
109
  return platforms
104
110
 
105
111
  # 获取目录的包名
@@ -149,8 +155,8 @@ class PlatformRegistry:
149
155
  error_lines.append(f"加载平台 {module_name} 失败: {str(e)}")
150
156
 
151
157
  if error_lines:
152
- joined_errors = '\n'.join(error_lines)
153
- print(f"❌ {joined_errors}")
158
+ joined_errors = "\n".join(error_lines)
159
+ PrettyOutput.auto_print(f"❌ {joined_errors}")
154
160
  return platforms
155
161
 
156
162
  @staticmethod
@@ -179,28 +185,39 @@ class PlatformRegistry:
179
185
  ) in PlatformRegistry.load_platform_from_dir(platform_dir).items():
180
186
  self.register_platform(platform_name, platform_class)
181
187
 
182
- def get_normal_platform(self) -> BasePlatform:
188
+ def get_normal_platform(
189
+ self, model_group_override: Optional[str] = None
190
+ ) -> BasePlatform:
183
191
  """获取正常操作的平台实例"""
184
- platform_name = get_normal_platform_name()
185
- model_name = get_normal_model_name()
186
- platform = self.create_platform(platform_name)
192
+ platform_name = get_normal_platform_name(model_group_override)
193
+ model_name = get_normal_model_name(model_group_override)
194
+ llm_config = get_llm_config("normal", model_group_override)
195
+ platform = self.create_platform(platform_name, llm_config)
187
196
  platform.set_model_name(model_name) # type: ignore
188
197
  return platform # type: ignore
189
198
 
190
- def get_cheap_platform(self) -> BasePlatform:
199
+ def get_cheap_platform(
200
+ self, model_group_override: Optional[str] = None
201
+ ) -> BasePlatform:
191
202
  """获取廉价操作的平台实例"""
192
- platform_name = get_cheap_platform_name()
193
- model_name = get_cheap_model_name()
194
- platform = self.create_platform(platform_name)
203
+ platform_name = get_cheap_platform_name(model_group_override)
204
+ model_name = get_cheap_model_name(model_group_override)
205
+ llm_config = get_llm_config("cheap", model_group_override)
206
+ platform = self.create_platform(platform_name, llm_config)
195
207
  platform.set_model_name(model_name) # type: ignore
208
+ platform.set_platform_type("cheap") # type: ignore
196
209
  return platform # type: ignore
197
210
 
198
- def get_smart_platform(self) -> BasePlatform:
211
+ def get_smart_platform(
212
+ self, model_group_override: Optional[str] = None
213
+ ) -> BasePlatform:
199
214
  """获取智能操作的平台实例"""
200
- platform_name = get_smart_platform_name()
201
- model_name = get_smart_model_name()
202
- platform = self.create_platform(platform_name)
215
+ platform_name = get_smart_platform_name(model_group_override)
216
+ model_name = get_smart_model_name(model_group_override)
217
+ llm_config = get_llm_config("smart", model_group_override)
218
+ platform = self.create_platform(platform_name, llm_config)
203
219
  platform.set_model_name(model_name) # type: ignore
220
+ platform.set_platform_type("smart") # type: ignore
204
221
  return platform # type: ignore
205
222
 
206
223
  def register_platform(self, name: str, platform_class: Type[BasePlatform]) -> None:
@@ -212,26 +229,27 @@ class PlatformRegistry:
212
229
  """
213
230
  self.platforms[name] = platform_class
214
231
 
215
- def create_platform(self, name: str) -> Optional[BasePlatform]:
216
- """Create platform instance"""
232
+ def create_platform(
233
+ self, name: str, llm_config: Optional[Dict[str, Any]] = None
234
+ ) -> Optional[BasePlatform]:
217
235
  """Create platform instance
218
236
 
219
237
  Args:
220
238
  name: Platform name
239
+ llm_config: LLM配置字典,包含平台特定的配置参数(如 api_key, base_url 等)
221
240
 
222
241
  Returns:
223
242
  BasePlatform: Platform instance
224
243
  """
225
244
  if name not in self.platforms:
226
- print(f"⚠️ 未找到平台: {name}")
245
+ PrettyOutput.auto_print(f"⚠️ 未找到平台: {name}")
227
246
  return None
228
247
 
229
248
  try:
230
-
231
- platform = self.platforms[name]()
249
+ platform = self.platforms[name](llm_config=llm_config or {})
232
250
  return platform
233
251
  except Exception as e:
234
- print(f"❌ 创建平台失败: {str(e)}")
252
+ PrettyOutput.auto_print(f"❌ 创建平台失败: {str(e)}")
235
253
  return None
236
254
 
237
255
  def get_available_platforms(self) -> List[str]: