jarvis-ai-assistant 0.1.222__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +1143 -245
  3. jarvis/jarvis_agent/agent_manager.py +97 -0
  4. jarvis/jarvis_agent/builtin_input_handler.py +12 -10
  5. jarvis/jarvis_agent/config_editor.py +57 -0
  6. jarvis/jarvis_agent/edit_file_handler.py +392 -99
  7. jarvis/jarvis_agent/event_bus.py +48 -0
  8. jarvis/jarvis_agent/events.py +157 -0
  9. jarvis/jarvis_agent/file_context_handler.py +79 -0
  10. jarvis/jarvis_agent/file_methodology_manager.py +117 -0
  11. jarvis/jarvis_agent/jarvis.py +1117 -147
  12. jarvis/jarvis_agent/main.py +78 -34
  13. jarvis/jarvis_agent/memory_manager.py +195 -0
  14. jarvis/jarvis_agent/methodology_share_manager.py +174 -0
  15. jarvis/jarvis_agent/prompt_manager.py +82 -0
  16. jarvis/jarvis_agent/prompts.py +46 -9
  17. jarvis/jarvis_agent/protocols.py +4 -1
  18. jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
  19. jarvis/jarvis_agent/run_loop.py +146 -0
  20. jarvis/jarvis_agent/session_manager.py +9 -9
  21. jarvis/jarvis_agent/share_manager.py +228 -0
  22. jarvis/jarvis_agent/shell_input_handler.py +23 -3
  23. jarvis/jarvis_agent/stdio_redirect.py +295 -0
  24. jarvis/jarvis_agent/task_analyzer.py +212 -0
  25. jarvis/jarvis_agent/task_manager.py +154 -0
  26. jarvis/jarvis_agent/task_planner.py +496 -0
  27. jarvis/jarvis_agent/tool_executor.py +8 -4
  28. jarvis/jarvis_agent/tool_share_manager.py +139 -0
  29. jarvis/jarvis_agent/user_interaction.py +42 -0
  30. jarvis/jarvis_agent/utils.py +54 -0
  31. jarvis/jarvis_agent/web_bridge.py +189 -0
  32. jarvis/jarvis_agent/web_output_sink.py +53 -0
  33. jarvis/jarvis_agent/web_server.py +751 -0
  34. jarvis/jarvis_c2rust/__init__.py +26 -0
  35. jarvis/jarvis_c2rust/cli.py +613 -0
  36. jarvis/jarvis_c2rust/collector.py +258 -0
  37. jarvis/jarvis_c2rust/library_replacer.py +1122 -0
  38. jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
  39. jarvis/jarvis_c2rust/optimizer.py +960 -0
  40. jarvis/jarvis_c2rust/scanner.py +1681 -0
  41. jarvis/jarvis_c2rust/transpiler.py +2325 -0
  42. jarvis/jarvis_code_agent/build_validation_config.py +133 -0
  43. jarvis/jarvis_code_agent/code_agent.py +1605 -178
  44. jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
  45. jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
  46. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
  47. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
  48. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
  49. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
  50. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
  51. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
  52. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
  53. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
  54. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
  60. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
  61. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
  62. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
  63. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
  64. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
  65. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
  66. jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
  67. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
  68. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
  69. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
  70. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
  71. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
  72. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
  73. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
  74. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
  75. jarvis/jarvis_code_agent/lint.py +275 -13
  76. jarvis/jarvis_code_agent/utils.py +142 -0
  77. jarvis/jarvis_code_analysis/checklists/loader.py +20 -6
  78. jarvis/jarvis_code_analysis/code_review.py +583 -548
  79. jarvis/jarvis_data/config_schema.json +339 -28
  80. jarvis/jarvis_git_squash/main.py +22 -13
  81. jarvis/jarvis_git_utils/git_commiter.py +171 -55
  82. jarvis/jarvis_mcp/sse_mcp_client.py +22 -15
  83. jarvis/jarvis_mcp/stdio_mcp_client.py +4 -4
  84. jarvis/jarvis_mcp/streamable_mcp_client.py +36 -16
  85. jarvis/jarvis_memory_organizer/memory_organizer.py +753 -0
  86. jarvis/jarvis_methodology/main.py +48 -63
  87. jarvis/jarvis_multi_agent/__init__.py +302 -43
  88. jarvis/jarvis_multi_agent/main.py +70 -24
  89. jarvis/jarvis_platform/ai8.py +40 -23
  90. jarvis/jarvis_platform/base.py +210 -49
  91. jarvis/jarvis_platform/human.py +11 -1
  92. jarvis/jarvis_platform/kimi.py +82 -76
  93. jarvis/jarvis_platform/openai.py +73 -1
  94. jarvis/jarvis_platform/registry.py +8 -15
  95. jarvis/jarvis_platform/tongyi.py +115 -101
  96. jarvis/jarvis_platform/yuanbao.py +89 -63
  97. jarvis/jarvis_platform_manager/main.py +194 -132
  98. jarvis/jarvis_platform_manager/service.py +122 -86
  99. jarvis/jarvis_rag/cli.py +156 -53
  100. jarvis/jarvis_rag/embedding_manager.py +155 -12
  101. jarvis/jarvis_rag/llm_interface.py +10 -13
  102. jarvis/jarvis_rag/query_rewriter.py +63 -12
  103. jarvis/jarvis_rag/rag_pipeline.py +222 -40
  104. jarvis/jarvis_rag/reranker.py +26 -3
  105. jarvis/jarvis_rag/retriever.py +270 -14
  106. jarvis/jarvis_sec/__init__.py +3605 -0
  107. jarvis/jarvis_sec/checkers/__init__.py +32 -0
  108. jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
  109. jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
  110. jarvis/jarvis_sec/cli.py +116 -0
  111. jarvis/jarvis_sec/report.py +257 -0
  112. jarvis/jarvis_sec/status.py +264 -0
  113. jarvis/jarvis_sec/types.py +20 -0
  114. jarvis/jarvis_sec/workflow.py +219 -0
  115. jarvis/jarvis_smart_shell/main.py +405 -137
  116. jarvis/jarvis_stats/__init__.py +13 -0
  117. jarvis/jarvis_stats/cli.py +387 -0
  118. jarvis/jarvis_stats/stats.py +711 -0
  119. jarvis/jarvis_stats/storage.py +612 -0
  120. jarvis/jarvis_stats/visualizer.py +282 -0
  121. jarvis/jarvis_tools/ask_user.py +1 -0
  122. jarvis/jarvis_tools/base.py +18 -2
  123. jarvis/jarvis_tools/clear_memory.py +239 -0
  124. jarvis/jarvis_tools/cli/main.py +220 -144
  125. jarvis/jarvis_tools/execute_script.py +52 -12
  126. jarvis/jarvis_tools/file_analyzer.py +17 -12
  127. jarvis/jarvis_tools/generate_new_tool.py +46 -24
  128. jarvis/jarvis_tools/read_code.py +277 -18
  129. jarvis/jarvis_tools/read_symbols.py +141 -0
  130. jarvis/jarvis_tools/read_webpage.py +86 -13
  131. jarvis/jarvis_tools/registry.py +294 -90
  132. jarvis/jarvis_tools/retrieve_memory.py +227 -0
  133. jarvis/jarvis_tools/save_memory.py +194 -0
  134. jarvis/jarvis_tools/search_web.py +62 -28
  135. jarvis/jarvis_tools/sub_agent.py +205 -0
  136. jarvis/jarvis_tools/sub_code_agent.py +217 -0
  137. jarvis/jarvis_tools/virtual_tty.py +330 -62
  138. jarvis/jarvis_utils/builtin_replace_map.py +4 -5
  139. jarvis/jarvis_utils/clipboard.py +90 -0
  140. jarvis/jarvis_utils/config.py +607 -50
  141. jarvis/jarvis_utils/embedding.py +3 -0
  142. jarvis/jarvis_utils/fzf.py +57 -0
  143. jarvis/jarvis_utils/git_utils.py +251 -29
  144. jarvis/jarvis_utils/globals.py +174 -17
  145. jarvis/jarvis_utils/http.py +58 -79
  146. jarvis/jarvis_utils/input.py +899 -153
  147. jarvis/jarvis_utils/methodology.py +210 -83
  148. jarvis/jarvis_utils/output.py +220 -137
  149. jarvis/jarvis_utils/utils.py +1906 -135
  150. jarvis_ai_assistant-0.7.0.dist-info/METADATA +465 -0
  151. jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
  152. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +8 -2
  153. jarvis/jarvis_git_details/main.py +0 -265
  154. jarvis/jarvis_platform/oyi.py +0 -357
  155. jarvis/jarvis_tools/edit_file.py +0 -255
  156. jarvis/jarvis_tools/rewrite_file.py +0 -195
  157. jarvis_ai_assistant-0.1.222.dist-info/METADATA +0 -767
  158. jarvis_ai_assistant-0.1.222.dist-info/RECORD +0 -110
  159. /jarvis/{jarvis_git_details → jarvis_memory_organizer}/__init__.py +0 -0
  160. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
  161. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
  162. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
@@ -3,33 +3,47 @@
3
3
 
4
4
  该模块提供了Jarvis平台管理器的主要入口点。
5
5
  """
6
- import argparse
7
6
  import os
7
+ import sys
8
8
  from typing import Any, Dict, List, Optional
9
9
 
10
+ import typer
11
+ from jarvis.jarvis_utils.config import (
12
+ get_normal_platform_name,
13
+ get_normal_model_name,
14
+ )
15
+
10
16
  from jarvis.jarvis_platform.registry import PlatformRegistry
11
17
  from jarvis.jarvis_utils.input import get_multiline_input, get_single_line_input
12
18
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
13
19
  from jarvis.jarvis_utils.utils import init_env
14
20
  from jarvis.jarvis_platform_manager.service import start_service
21
+ from jarvis.jarvis_utils.fzf import fzf_select
22
+
23
+ app = typer.Typer(help="Jarvis AI 平台")
15
24
 
16
25
 
17
- def list_platforms() -> None:
18
- """列出所有支持的平台和模型。"""
26
+ @app.command("info")
27
+ def list_platforms(
28
+ platform: Optional[str] = typer.Option(
29
+ None, "--platform", "-p", help="指定要查看的平台"
30
+ )
31
+ ) -> None:
32
+ """列出所有支持的平台和模型,或指定平台的详细信息。"""
19
33
  registry = PlatformRegistry.get_global_platform_registry()
20
- platforms = registry.get_available_platforms()
34
+ platform_names = [platform] if platform else registry.get_available_platforms()
21
35
 
22
36
  PrettyOutput.section("Supported platforms and models", OutputType.SUCCESS)
23
37
 
24
- for platform_name in platforms:
25
- # Create platform instance
26
- platform = registry.create_platform(platform_name)
27
- if not platform:
28
- continue
29
-
30
- # Get the list of models supported by the platform
38
+ for platform_name in platform_names:
31
39
  try:
32
- models = platform.get_model_list()
40
+ # Create platform instance
41
+ platform_instance = registry.create_platform(platform_name)
42
+ if not platform_instance:
43
+ continue
44
+
45
+ # Get the list of models supported by the platform
46
+ models = platform_instance.get_model_list()
33
47
 
34
48
  # Print platform name
35
49
  PrettyOutput.section(f"{platform_name}", OutputType.SUCCESS)
@@ -46,19 +60,29 @@ def list_platforms() -> None:
46
60
  else:
47
61
  PrettyOutput.print(" • 没有可用的模型信息", OutputType.WARNING)
48
62
 
49
- except Exception as exc:
50
- PrettyOutput.print(
51
- f"获取 {platform_name} 的模型列表失败: {str(exc)}", OutputType.WARNING
52
- )
63
+ except Exception:
64
+ PrettyOutput.print(f"创建 {platform_name} 平台失败", OutputType.WARNING)
65
+
53
66
 
67
+ def chat_with_model(
68
+ platform_name: str, model_name: str, system_prompt: str
69
+ ) -> None:
70
+ """与指定平台和模型进行对话。
54
71
 
55
- def chat_with_model(platform_name: str, model_name: str, system_prompt: str) -> None:
56
- """与指定平台和模型进行对话。"""
72
+ 参数:
73
+ platform_name: 平台名称
74
+ model_name: 模型名称
75
+ system_prompt: 系统提示语
76
+
77
+ """
57
78
  registry = PlatformRegistry.get_global_platform_registry()
58
79
  conversation_history: List[Dict[str, str]] = [] # 存储对话记录
59
80
 
60
81
  # Create platform instance
61
82
  platform = registry.create_platform(platform_name)
83
+ if platform:
84
+ platform.set_model_name(model_name)
85
+
62
86
  if not platform:
63
87
  PrettyOutput.print(f"创建平台 {platform_name} 失败", OutputType.WARNING)
64
88
  return
@@ -94,10 +118,16 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
94
118
  PrettyOutput.print("检测到空输入,退出聊天", OutputType.INFO)
95
119
  break
96
120
 
121
+ # Parse command and arguments
122
+ stripped_input = user_input.strip()
123
+ parts = stripped_input.split(None, 1)
124
+ command = parts[0] if parts else ""
125
+ args = parts[1] if len(parts) > 1 else ""
126
+
97
127
  # Check if it is a clear session command
98
- if user_input.strip() == "/clear":
128
+ if command == "/clear":
99
129
  try:
100
- platform.reset()
130
+ platform.reset() # type: ignore[no-untyped-call] # type: ignore[no-untyped-call] # type: ignore[no-untyped-call]
101
131
  platform.set_model_name(model_name) # Reinitialize session
102
132
  conversation_history = [] # 重置对话记录
103
133
  PrettyOutput.print("会话已清除", OutputType.SUCCESS)
@@ -106,9 +136,9 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
106
136
  continue
107
137
 
108
138
  # Check if it is an upload command
109
- if user_input.strip().startswith("/upload"):
139
+ if command == "/upload":
110
140
  try:
111
- file_path = user_input.strip()[8:].strip()
141
+ file_path = args
112
142
  if not file_path:
113
143
  PrettyOutput.print(
114
144
  '请指定要上传的文件路径,例如: /upload /path/to/file 或 /upload "/path/with spaces/file"',
@@ -136,9 +166,9 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
136
166
  continue
137
167
 
138
168
  # Check if it is a save command
139
- if user_input.strip().startswith("/save"):
169
+ if command == "/save":
140
170
  try:
141
- file_path = user_input.strip()[5:].strip()
171
+ file_path = args
142
172
  if not file_path:
143
173
  PrettyOutput.print(
144
174
  "请指定保存文件名,例如: /save last_message.txt",
@@ -167,9 +197,9 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
167
197
  continue
168
198
 
169
199
  # Check if it is a saveall command
170
- if user_input.strip().startswith("/saveall"):
200
+ if command == "/saveall":
171
201
  try:
172
- file_path = user_input.strip()[8:].strip()
202
+ file_path = args
173
203
  if not file_path:
174
204
  PrettyOutput.print(
175
205
  "请指定保存文件名,例如: /saveall all_conversations.txt",
@@ -188,15 +218,19 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
188
218
  for entry in conversation_history:
189
219
  file_obj.write(f"{entry['role']}: {entry['content']}\n\n")
190
220
 
191
- PrettyOutput.print(f"所有对话已保存到 {file_path}", OutputType.SUCCESS)
221
+ PrettyOutput.print(
222
+ f"所有对话已保存到 {file_path}", OutputType.SUCCESS
223
+ )
192
224
  except Exception as exc:
193
- PrettyOutput.print(f"保存所有对话失败: {str(exc)}", OutputType.ERROR)
225
+ PrettyOutput.print(
226
+ f"保存所有对话失败: {str(exc)}", OutputType.ERROR
227
+ )
194
228
  continue
195
229
 
196
230
  # Check if it is a save_session command
197
- if user_input.strip().startswith("/save_session"):
231
+ if command == "/save_session":
198
232
  try:
199
- file_path = user_input.strip()[14:].strip()
233
+ file_path = args
200
234
  if not file_path:
201
235
  PrettyOutput.print(
202
236
  "请指定保存会话的文件名,例如: /save_session session.json",
@@ -211,7 +245,9 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
211
245
  file_path = file_path[1:-1]
212
246
 
213
247
  if platform.save(file_path):
214
- PrettyOutput.print(f"会话已保存到 {file_path}", OutputType.SUCCESS)
248
+ PrettyOutput.print(
249
+ f"会话已保存到 {file_path}", OutputType.SUCCESS
250
+ )
215
251
  else:
216
252
  PrettyOutput.print("保存会话失败", OutputType.ERROR)
217
253
  except Exception as exc:
@@ -219,9 +255,9 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
219
255
  continue
220
256
 
221
257
  # Check if it is a load_session command
222
- if user_input.strip().startswith("/load_session"):
258
+ if command == "/load_session":
223
259
  try:
224
- file_path = user_input.strip()[14:].strip()
260
+ file_path = args
225
261
  if not file_path:
226
262
  PrettyOutput.print(
227
263
  "请指定加载会话的文件名,例如: /load_session session.json",
@@ -237,7 +273,9 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
237
273
 
238
274
  if platform.restore(file_path):
239
275
  conversation_history = [] # Clear local history after loading
240
- PrettyOutput.print(f"会话已从 {file_path} 加载", OutputType.SUCCESS)
276
+ PrettyOutput.print(
277
+ f"会话已从 {file_path} 加载", OutputType.SUCCESS
278
+ )
241
279
  else:
242
280
  PrettyOutput.print("加载会话失败", OutputType.ERROR)
243
281
  except Exception as exc:
@@ -245,18 +283,18 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
245
283
  continue
246
284
 
247
285
  # Check if it is a shell command
248
- if user_input.strip().startswith("/shell"):
286
+ if command == "/shell":
249
287
  try:
250
- command = user_input.strip()[6:].strip()
251
- if not command:
288
+ shell_command = args
289
+ if not shell_command:
252
290
  PrettyOutput.print(
253
291
  "请指定要执行的shell命令,例如: /shell ls -l",
254
292
  OutputType.WARNING,
255
293
  )
256
294
  continue
257
295
 
258
- PrettyOutput.print(f"执行命令: {command}", OutputType.INFO)
259
- return_code = os.system(command)
296
+ PrettyOutput.print(f"执行命令: {shell_command}", OutputType.INFO)
297
+ return_code = os.system(shell_command)
260
298
  if return_code == 0:
261
299
  PrettyOutput.print("命令执行完成", OutputType.SUCCESS)
262
300
  else:
@@ -283,8 +321,11 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
283
321
  except Exception as exc:
284
322
  PrettyOutput.print(f"聊天失败: {str(exc)}", OutputType.ERROR)
285
323
 
324
+ except typer.Exit:
325
+ raise
286
326
  except Exception as exc:
287
327
  PrettyOutput.print(f"初始化会话失败: {str(exc)}", OutputType.ERROR)
328
+ sys.exit(1)
288
329
  finally:
289
330
  # Clean up resources
290
331
  try:
@@ -293,16 +334,17 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
293
334
  pass
294
335
 
295
336
 
296
- def validate_platform_model(args: argparse.Namespace) -> bool:
337
+ def validate_platform_model(platform: Optional[str], model: Optional[str]) -> bool:
297
338
  """验证平台和模型参数。
298
339
 
299
340
  参数:
300
- args: 命令行参数。
341
+ platform: 平台名称。
342
+ model: 模型名称。
301
343
 
302
344
  返回:
303
345
  bool: 如果平台和模型有效返回True,否则返回False。
304
346
  """
305
- if not args.platform or not args.model:
347
+ if not platform or not model:
306
348
  PrettyOutput.print(
307
349
  "请指定平台和模型。使用 'jarvis info' 查看可用平台和模型。",
308
350
  OutputType.WARNING,
@@ -311,38 +353,43 @@ def validate_platform_model(args: argparse.Namespace) -> bool:
311
353
  return True
312
354
 
313
355
 
314
- def chat_command(args: argparse.Namespace) -> None:
315
- """处理聊天子命令。
316
-
317
- 参数:
318
- args: 命令行参数。
319
- """
320
- if not validate_platform_model(args):
321
- return
322
- chat_with_model(args.platform, args.model, "")
323
-
356
+ @app.command("chat")
357
+ def chat_command(
358
+ platform: Optional[str] = typer.Option(
359
+ None, "--platform", "-p", help="指定要使用的平台"
360
+ ),
361
+ model: Optional[str] = typer.Option(None, "--model", "-m", help="指定要使用的模型"),
324
362
 
325
- def info_command(args: argparse.Namespace) -> None:
326
- """处理信息子命令。
363
+ llm_group: Optional[str] = typer.Option(
364
+ None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
365
+ ),
366
+ ) -> None:
367
+ """与指定平台和模型聊天。"""
368
+ # 如果未提供平台或模型参数,则从config获取默认值
369
+ platform = platform or get_normal_platform_name(llm_group)
370
+ model = model or get_normal_model_name(llm_group)
327
371
 
328
- 参数:
329
- args: 命令行参数。
330
- """
331
- list_platforms()
332
-
333
-
334
- def service_command(args: argparse.Namespace) -> None:
335
- """处理服务子命令 - 启动OpenAI兼容的API服务。
336
-
337
- 参数:
338
- args: 命令行参数。
339
- """
340
- start_service(
341
- host=args.host,
342
- port=args.port,
343
- default_platform=args.platform,
344
- default_model=args.model,
345
- )
372
+ if not validate_platform_model(platform, model):
373
+ return
374
+ chat_with_model(platform, model, "")
375
+
376
+
377
+ @app.command("service")
378
+ def service_command(
379
+ host: str = typer.Option("127.0.0.1", help="服务主机地址 (默认: 127.0.0.1)"),
380
+ port: int = typer.Option(8000, help="服务端口 (默认: 8000)"),
381
+ platform: Optional[str] = typer.Option(
382
+ None, "-p", "--platform", help="指定默认平台,当客户端未指定平台时使用"
383
+ ),
384
+ model: Optional[str] = typer.Option(
385
+ None, "-m", "--model", help="指定默认模型,当客户端未指定平台时使用"
386
+ ),
387
+ ) -> None:
388
+ """启动OpenAI兼容的API服务。"""
389
+ # 如果未提供平台或模型参数,则从config获取默认值
390
+ platform = platform or get_normal_platform_name()
391
+ model = model or get_normal_model_name()
392
+ start_service(host=host, port=port, default_platform=platform, default_model=model)
346
393
 
347
394
 
348
395
  def load_role_config(config_path: str) -> Dict[str, Any]:
@@ -369,13 +416,28 @@ def load_role_config(config_path: str) -> Dict[str, Any]:
369
416
  return {}
370
417
 
371
418
 
372
- def role_command(args: argparse.Namespace) -> None:
373
- """Process role subcommand - load role config and start chat.
374
-
375
- Args:
376
- args: Command line arguments.
377
- """
378
- config = load_role_config(args.config)
419
+ @app.command("role")
420
+ def role_command(
421
+ config_file: str = typer.Option(
422
+ "~/.jarvis/roles.yaml",
423
+ "--config",
424
+ "-c",
425
+ help="角色配置文件路径(YAML格式,默认: ~/.jarvis/roles.yaml)",
426
+ ),
427
+ platform: Optional[str] = typer.Option(
428
+ None, "--platform", "-p", help="指定要使用的平台,覆盖角色配置"
429
+ ),
430
+ model: Optional[str] = typer.Option(
431
+ None, "--model", "-m", help="指定要使用的模型,覆盖角色配置"
432
+ ),
433
+
434
+ llm_group: Optional[str] = typer.Option(
435
+ None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
436
+ ),
437
+ ) -> None:
438
+ """加载角色配置文件并开始对话。"""
439
+ config_path = os.path.expanduser(config_file)
440
+ config = load_role_config(config_path)
379
441
  if not config or "roles" not in config:
380
442
  PrettyOutput.print("无效的角色配置文件", OutputType.ERROR)
381
443
  return
@@ -390,17 +452,60 @@ def role_command(args: argparse.Namespace) -> None:
390
452
  )
391
453
  PrettyOutput.print(output_str, OutputType.INFO)
392
454
 
393
- # 让用户选择角色
394
- try:
395
- choice = int(get_single_line_input("请选择角色(输入编号): "))
396
- selected_role = config["roles"][choice - 1]
397
- except (ValueError, IndexError):
398
- PrettyOutput.print("无效的选择", OutputType.ERROR)
399
- return
455
+ # 让用户选择角色(优先 fzf,回退编号输入)
456
+ selected_role = None # type: ignore[var-annotated]
457
+ fzf_options = [
458
+ f"{i:>3} | {role['name']} - {role.get('description', '')}"
459
+ for i, role in enumerate(config["roles"], 1)
460
+ ]
461
+ selected_str = fzf_select(fzf_options, prompt="选择角色编号 (Enter退出) > ")
462
+ if selected_str:
463
+ try:
464
+ num_part = selected_str.split("|", 1)[0].strip()
465
+ idx = int(num_part)
466
+ if 1 <= idx <= len(config["roles"]):
467
+ selected_role = config["roles"][idx - 1]
468
+ except Exception:
469
+ selected_role = None
470
+
471
+ if selected_role is None:
472
+ raw_choice = get_single_line_input("请选择角色(输入编号,直接回车退出): ")
473
+ if not raw_choice.strip():
474
+ PrettyOutput.print("已取消,退出程序", OutputType.INFO)
475
+ raise typer.Exit(code=0)
476
+ try:
477
+ choice = int(raw_choice)
478
+ selected_role = config["roles"][choice - 1]
479
+ except (ValueError, IndexError):
480
+ PrettyOutput.print("无效的选择", OutputType.ERROR)
481
+ return
482
+
483
+
400
484
 
401
485
  # 初始化平台和模型
402
- platform_name = args.platform or selected_role["platform"]
403
- model_name = args.model or selected_role["model"]
486
+ # 如果提供了platform或model参数,优先使用命令行参数
487
+ # 否则,如果提供了 llm_group,则从配置中获取
488
+ # 最后才使用角色配置中的platform和model
489
+ if platform:
490
+ platform_name = platform
491
+ elif llm_group:
492
+ platform_name = get_normal_platform_name(llm_group)
493
+ else:
494
+ platform_name = selected_role.get("platform")
495
+ if not platform_name:
496
+ # 如果角色配置中没有platform,使用默认配置
497
+ platform_name = get_normal_platform_name()
498
+
499
+ if model:
500
+ model_name = model
501
+ elif llm_group:
502
+ model_name = get_normal_model_name(llm_group)
503
+ else:
504
+ model_name = selected_role.get("model")
505
+ if not model_name:
506
+ # 如果角色配置中没有model,使用默认配置
507
+ model_name = get_normal_model_name()
508
+
404
509
  system_prompt = selected_role.get("system_prompt", "")
405
510
 
406
511
  # 开始对话
@@ -411,50 +516,7 @@ def role_command(args: argparse.Namespace) -> None:
411
516
  def main() -> None:
412
517
  """Jarvis平台管理器的主入口点。"""
413
518
  init_env("欢迎使用 Jarvis-PlatformManager,您的平台管理助手已准备就绪!")
414
-
415
- parser = argparse.ArgumentParser(description="Jarvis AI 平台")
416
- subparsers = parser.add_subparsers(dest="command", help="可用子命令")
417
-
418
- # info subcommand
419
- info_parser = subparsers.add_parser("info", help="显示支持的平台和模型信息")
420
- info_parser.set_defaults(func=info_command)
421
-
422
- # chat subcommand
423
- chat_parser = subparsers.add_parser("chat", help="与指定平台和模型聊天")
424
- chat_parser.add_argument("--platform", "-p", help="指定要使用的平台")
425
- chat_parser.add_argument("--model", "-m", help="指定要使用的模型")
426
- chat_parser.set_defaults(func=chat_command)
427
-
428
- # service subcommand
429
- service_parser = subparsers.add_parser("service", help="启动OpenAI兼容的API服务")
430
- service_parser.add_argument(
431
- "--host", default="127.0.0.1", help="服务主机地址 (默认: 127.0.0.1)"
432
- )
433
- service_parser.add_argument(
434
- "--port", type=int, default=8000, help="服务端口 (默认: 8000)"
435
- )
436
- service_parser.add_argument("--platform", "-p", help="指定默认平台,当客户端未指定平台时使用")
437
- service_parser.add_argument("--model", "-m", help="指定默认模型,当客户端未指定平台时使用")
438
- service_parser.set_defaults(func=service_command)
439
-
440
- # role subcommand
441
- role_parser = subparsers.add_parser("role", help="加载角色配置文件并开始对话")
442
- role_parser.add_argument(
443
- "--config",
444
- "-c",
445
- default="~/.jarvis/roles.yaml",
446
- help="角色配置文件路径(YAML格式,默认: ~/.jarvis/roles.yaml)",
447
- )
448
- role_parser.add_argument("--platform", "-p", help="指定要使用的平台,覆盖角色配置")
449
- role_parser.add_argument("--model", "-m", help="指定要使用的模型,覆盖角色配置")
450
- role_parser.set_defaults(func=role_command)
451
-
452
- args = parser.parse_args()
453
-
454
- if hasattr(args, "func"):
455
- args.func(args)
456
- else:
457
- parser.print_help()
519
+ app()
458
520
 
459
521
 
460
522
  if __name__ == "__main__":