jarvis-ai-assistant 0.3.16__py3-none-any.whl → 0.3.18__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.
@@ -235,6 +235,30 @@
235
235
  },
236
236
  "default": []
237
237
  },
238
+ "JARVIS_AGENT_DEFINITION_DIRS": {
239
+ "type": "array",
240
+ "description": "agent 定义加载目录",
241
+ "items": {
242
+ "type": "string"
243
+ },
244
+ "default": []
245
+ },
246
+ "JARVIS_MULTI_AGENT_DIRS": {
247
+ "type": "array",
248
+ "description": "multi_agent 加载目录",
249
+ "items": {
250
+ "type": "string"
251
+ },
252
+ "default": []
253
+ },
254
+ "JARVIS_ROLES_DIRS": {
255
+ "type": "array",
256
+ "description": "roles 加载目录",
257
+ "items": {
258
+ "type": "string"
259
+ },
260
+ "default": []
261
+ },
238
262
  "JARVIS_CENTRAL_METHODOLOGY_REPO": {
239
263
  "type": "string",
240
264
  "description": "中心方法论Git仓库地址,该仓库会自动添加到方法论加载路径中",
@@ -260,6 +284,21 @@
260
284
  "description": "是否强制保存记忆",
261
285
  "default": true
262
286
  },
287
+ "JARVIS_ENABLE_GIT_JCA_SWITCH": {
288
+ "type": "boolean",
289
+ "description": "在初始化环境前检测Git仓库并提示可切换到代码开发模式(jca)",
290
+ "default": false
291
+ },
292
+ "JARVIS_ENABLE_STARTUP_CONFIG_SELECTOR": {
293
+ "type": "boolean",
294
+ "description": "在进入默认通用代理前,列出可用配置(agent/multi_agent/roles)供选择",
295
+ "default": false
296
+ },
297
+ "JARVIS_IMMEDIATE_ABORT": {
298
+ "type": "boolean",
299
+ "description": "是否启用立即中断:在对话迭代中检测到中断信号时立即返回",
300
+ "default": false
301
+ },
263
302
  "JARVIS_TOOL_GROUP": {
264
303
  "type": "string",
265
304
  "description": "选择一个预定义的工具配置组",
@@ -15,9 +15,10 @@ from jarvis.jarvis_utils.config import (
15
15
  get_max_input_token_count,
16
16
  get_pretty_output,
17
17
  is_print_prompt,
18
+ is_immediate_abort,
18
19
  )
19
20
  from jarvis.jarvis_utils.embedding import split_text_into_chunks
20
- from jarvis.jarvis_utils.globals import set_in_chat
21
+ from jarvis.jarvis_utils.globals import set_in_chat, get_interrupt
21
22
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
22
23
  from jarvis.jarvis_utils.tag import ct, ot
23
24
  from jarvis.jarvis_utils.utils import get_context_token_count, while_success, while_true
@@ -137,6 +138,8 @@ class BasePlatform(ABC):
137
138
  with Live(panel, refresh_per_second=10, transient=False) as live:
138
139
  for s in self.chat(message):
139
140
  response += s
141
+ if is_immediate_abort() and get_interrupt():
142
+ return response
140
143
  text_content.append(s, style="bright_white")
141
144
  panel.subtitle = "[yellow]正在回答...[/yellow]"
142
145
  live.update(panel)
@@ -150,10 +153,14 @@ class BasePlatform(ABC):
150
153
  for s in self.chat(message):
151
154
  print(s, end="", flush=True)
152
155
  response += s
156
+ if is_immediate_abort() and get_interrupt():
157
+ return response
153
158
  print()
154
159
  else:
155
160
  for s in self.chat(message):
156
161
  response += s
162
+ if is_immediate_abort() and get_interrupt():
163
+ return response
157
164
  # Keep original think tag handling
158
165
  response = re.sub(
159
166
  ot("think") + r".*?" + ct("think"), "", response, flags=re.DOTALL
@@ -26,9 +26,7 @@ app = typer.Typer(help="Jarvis AI 平台")
26
26
 
27
27
  @app.command("info")
28
28
  def list_platforms(
29
- platform: Optional[str] = typer.Option(
30
- None, "--platform", "-p", help="指定要查看的平台"
31
- )
29
+ platform: Optional[str] = typer.Option(None, "--platform", "-p", help="指定要查看的平台")
32
30
  ) -> None:
33
31
  """列出所有支持的平台和模型,或指定平台的详细信息。"""
34
32
  registry = PlatformRegistry.get_global_platform_registry()
@@ -219,13 +217,9 @@ def chat_with_model(
219
217
  for entry in conversation_history:
220
218
  file_obj.write(f"{entry['role']}: {entry['content']}\n\n")
221
219
 
222
- PrettyOutput.print(
223
- f"所有对话已保存到 {file_path}", OutputType.SUCCESS
224
- )
220
+ PrettyOutput.print(f"所有对话已保存到 {file_path}", OutputType.SUCCESS)
225
221
  except Exception as exc:
226
- PrettyOutput.print(
227
- f"保存所有对话失败: {str(exc)}", OutputType.ERROR
228
- )
222
+ PrettyOutput.print(f"保存所有对话失败: {str(exc)}", OutputType.ERROR)
229
223
  continue
230
224
 
231
225
  # Check if it is a save_session command
@@ -246,9 +240,7 @@ def chat_with_model(
246
240
  file_path = file_path[1:-1]
247
241
 
248
242
  if platform.save(file_path):
249
- PrettyOutput.print(
250
- f"会话已保存到 {file_path}", OutputType.SUCCESS
251
- )
243
+ PrettyOutput.print(f"会话已保存到 {file_path}", OutputType.SUCCESS)
252
244
  else:
253
245
  PrettyOutput.print("保存会话失败", OutputType.ERROR)
254
246
  except Exception as exc:
@@ -274,9 +266,7 @@ def chat_with_model(
274
266
 
275
267
  if platform.restore(file_path):
276
268
  conversation_history = [] # Clear local history after loading
277
- PrettyOutput.print(
278
- f"会话已从 {file_path} 加载", OutputType.SUCCESS
279
- )
269
+ PrettyOutput.print(f"会话已从 {file_path} 加载", OutputType.SUCCESS)
280
270
  else:
281
271
  PrettyOutput.print("加载会话失败", OutputType.ERROR)
282
272
  except Exception as exc:
@@ -356,9 +346,7 @@ def validate_platform_model(platform: Optional[str], model: Optional[str]) -> bo
356
346
 
357
347
  @app.command("chat")
358
348
  def chat_command(
359
- platform: Optional[str] = typer.Option(
360
- None, "--platform", "-p", help="指定要使用的平台"
361
- ),
349
+ platform: Optional[str] = typer.Option(None, "--platform", "-p", help="指定要使用的平台"),
362
350
  model: Optional[str] = typer.Option(None, "--model", "-m", help="指定要使用的模型"),
363
351
  llm_type: str = typer.Option(
364
352
  "normal",
@@ -441,9 +429,7 @@ def role_command(
441
429
  platform: Optional[str] = typer.Option(
442
430
  None, "--platform", "-p", help="指定要使用的平台,覆盖角色配置"
443
431
  ),
444
- model: Optional[str] = typer.Option(
445
- None, "--model", "-m", help="指定要使用的模型,覆盖角色配置"
446
- ),
432
+ model: Optional[str] = typer.Option(None, "--model", "-m", help="指定要使用的模型,覆盖角色配置"),
447
433
  llm_type: Optional[str] = typer.Option(
448
434
  None,
449
435
  "-t",
@@ -472,8 +458,12 @@ def role_command(
472
458
  PrettyOutput.print(output_str, OutputType.INFO)
473
459
 
474
460
  # 让用户选择角色
461
+ raw_choice = get_single_line_input("请选择角色(输入编号,直接回车退出): ")
462
+ if not raw_choice.strip():
463
+ PrettyOutput.print("已取消,退出程序", OutputType.INFO)
464
+ raise typer.Exit(code=0)
475
465
  try:
476
- choice = int(get_single_line_input("请选择角色(输入编号): "))
466
+ choice = int(raw_choice)
477
467
  selected_role = config["roles"][choice - 1]
478
468
  except (ValueError, IndexError):
479
469
  PrettyOutput.print("无效的选择", OutputType.ERROR)
@@ -3,6 +3,13 @@ from typing import Any, Dict
3
3
 
4
4
  from jarvis.jarvis_platform.registry import PlatformRegistry
5
5
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
6
+ from jarvis.jarvis_utils.config import (
7
+ get_web_search_platform_name,
8
+ get_web_search_model_name,
9
+ )
10
+ from jarvis.jarvis_utils.http import get as http_get
11
+ from markdownify import markdownify as md # type: ignore
12
+ import requests
6
13
 
7
14
 
8
15
  class WebpageTool:
@@ -22,28 +29,82 @@ class WebpageTool:
22
29
  }
23
30
 
24
31
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
25
- """Read webpage content using Yuanbao model"""
32
+ """
33
+ 读取网页内容。
34
+ 优先使用配置的 web_search_platform 与模型的原生web能力;若不支持,则使用requests抓取页面并调用模型进行分析。
35
+ """
26
36
  try:
27
- url = args["url"].strip()
28
- want = args.get("want", "请总结这个网页的主要内容")
37
+ url = str(args.get("url", "")).strip()
38
+ want = str(args.get("want", "请总结这个网页的主要内容"))
29
39
 
30
- # Create Yuanbao model instance
31
- model = PlatformRegistry().get_normal_platform()
32
- model.set_web(True)
33
- model.set_suppress_output(False) # type: ignore
40
+ if not url:
41
+ return {"success": False, "stdout": "", "stderr": "缺少必需参数:url"}
42
+
43
+ # 1) 优先使用配置的 Web 搜索平台与模型(若支持web)
44
+ web_search_platform = get_web_search_platform_name()
45
+ web_search_model = get_web_search_model_name()
46
+ if web_search_platform and web_search_model:
47
+ model = PlatformRegistry().create_platform(web_search_platform)
48
+ if model:
49
+ model.set_model_name(web_search_model)
50
+ if model.support_web():
51
+ PrettyOutput.print("▶️ 使用配置的 Web 搜索平台读取网页...", OutputType.INFO)
52
+ model.set_web(True)
53
+ model.set_suppress_output(False) # type: ignore
54
+ prompt = f"""请帮我处理这个网页:{url}
55
+ 用户的具体需求是:{want}
56
+ 请按照以下要求输出结果:
57
+ 1. 使用Markdown格式
58
+ 2. 包含网页标题
59
+ 3. 根据用户需求提供准确、完整的信息"""
60
+ response = model.chat_until_success(prompt) # type: ignore
61
+ return {"success": True, "stdout": response, "stderr": ""}
34
62
 
35
- # Construct prompt based on want parameter
36
- prompt = f"""请帮我处理这个网页:{url}
63
+ # 2) 然后尝试使用默认平台(normal)的 web 能力
64
+ model = PlatformRegistry().get_normal_platform()
65
+ if model.support_web():
66
+ PrettyOutput.print("▶️ 使用默认平台的 Web 能力读取网页...", OutputType.INFO)
67
+ model.set_web(True)
68
+ model.set_suppress_output(False) # type: ignore
69
+ prompt = f"""请帮我处理这个网页:{url}
37
70
  用户的具体需求是:{want}
38
71
  请按照以下要求输出结果:
39
72
  1. 使用Markdown格式
40
73
  2. 包含网页标题
41
74
  3. 根据用户需求提供准确、完整的信息"""
75
+ response = model.chat_until_success(prompt) # type: ignore
76
+ return {"success": True, "stdout": response, "stderr": ""}
77
+
78
+ # 3) 回退:使用 requests 抓取网页,再用模型分析
79
+ PrettyOutput.print("ℹ️ 当前模型不支持Web,使用requests抓取网页并进行分析。", OutputType.INFO)
80
+ try:
81
+ resp = http_get(url, timeout=10.0, allow_redirects=True)
82
+ content_md = md(resp.text, strip=["script", "style"])
83
+ except requests.exceptions.HTTPError as e:
84
+ PrettyOutput.print(f"⚠️ HTTP错误 {e.response.status_code} 访问 {url}", OutputType.WARNING)
85
+ return {"success": False, "stdout": "", "stderr": f"HTTP错误:{e.response.status_code}"}
86
+ except requests.exceptions.RequestException as e:
87
+ PrettyOutput.print(f"⚠️ 请求错误: {e}", OutputType.WARNING)
88
+ return {"success": False, "stdout": "", "stderr": f"请求错误:{e}"}
89
+
90
+ if not content_md or not content_md.strip():
91
+ return {"success": False, "stdout": "", "stderr": "无法从网页抓取有效内容。"}
42
92
 
43
- # Get response from Yuanbao model
44
- response = model.chat_until_success(prompt) # type: ignore
93
+ PrettyOutput.print("🧠 正在分析抓取到的网页内容...", OutputType.INFO)
94
+ summary_prompt = f"""以下是网页 {url} 的内容(已转换为Markdown):
95
+ ----------------
96
+ {content_md}
97
+ ----------------
98
+ 请根据用户的具体需求“{want}”进行总结与回答:
99
+ - 使用Markdown格式
100
+ - 包含网页标题(若可推断)
101
+ - 提供准确、完整的信息"""
102
+
103
+ model = PlatformRegistry().get_normal_platform()
104
+ model.set_suppress_output(False) # type: ignore
105
+ summary = model.chat_until_success(summary_prompt) # type: ignore
45
106
 
46
- return {"success": True, "stdout": response, "stderr": ""}
107
+ return {"success": True, "stdout": summary, "stderr": ""}
47
108
 
48
109
  except Exception as e:
49
110
  PrettyOutput.print(f"读取网页失败: {str(e)}", OutputType.ERROR)
@@ -55,5 +116,5 @@ class WebpageTool:
55
116
 
56
117
  @staticmethod
57
118
  def check() -> bool:
58
- """检查当前平台是否支持web功能"""
59
- return PlatformRegistry().get_normal_platform().support_web()
119
+ """工具可用性检查:始终可用;若模型不支持web将回退到requests抓取。"""
120
+ return True
@@ -309,6 +309,36 @@ def get_methodology_dirs() -> List[str]:
309
309
  return GLOBAL_CONFIG_DATA.get("JARVIS_METHODOLOGY_DIRS", [])
310
310
 
311
311
 
312
+ def get_agent_definition_dirs() -> List[str]:
313
+ """
314
+ 获取 agent 定义的加载目录。
315
+
316
+ 返回:
317
+ List[str]: agent 定义加载目录列表
318
+ """
319
+ return GLOBAL_CONFIG_DATA.get("JARVIS_AGENT_DEFINITION_DIRS", [])
320
+
321
+
322
+ def get_multi_agent_dirs() -> List[str]:
323
+ """
324
+ 获取 multi_agent 的加载目录。
325
+
326
+ 返回:
327
+ List[str]: multi_agent 加载目录列表
328
+ """
329
+ return GLOBAL_CONFIG_DATA.get("JARVIS_MULTI_AGENT_DIRS", [])
330
+
331
+
332
+ def get_roles_dirs() -> List[str]:
333
+ """
334
+ 获取 roles 的加载目录。
335
+
336
+ 返回:
337
+ List[str]: roles 加载目录列表
338
+ """
339
+ return GLOBAL_CONFIG_DATA.get("JARVIS_ROLES_DIRS", [])
340
+
341
+
312
342
  def get_central_methodology_repo() -> str:
313
343
  """
314
344
  获取中心方法论Git仓库地址。
@@ -576,3 +606,29 @@ def get_tool_dont_use_list() -> List[str]:
576
606
  """
577
607
  config = _get_resolved_tool_config()
578
608
  return config.get("dont_use", [])
609
+
610
+
611
+ def is_enable_git_repo_jca_switch() -> bool:
612
+ """
613
+ 是否启用:在初始化环境前检测Git仓库并提示可切换到代码开发模式(jca)
614
+ 默认关闭
615
+ """
616
+ return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_GIT_JCA_SWITCH", False) is True
617
+
618
+
619
+ def is_enable_builtin_config_selector() -> bool:
620
+ """
621
+ 是否启用:在进入默认通用代理前,列出可用配置(agent/multi_agent/roles)供选择
622
+ 默认关闭
623
+ """
624
+ return (
625
+ GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_STARTUP_CONFIG_SELECTOR", False) is True
626
+ )
627
+
628
+
629
+ def is_immediate_abort() -> bool:
630
+ """
631
+ 是否启用立即中断:当在对话过程中检测到用户中断信号时,立即停止输出并返回。
632
+ 默认关闭
633
+ """
634
+ return GLOBAL_CONFIG_DATA.get("JARVIS_IMMEDIATE_ABORT", False) is True
@@ -15,7 +15,7 @@ from colorama import Fore
15
15
  from colorama import Style as ColoramaStyle
16
16
  from fuzzywuzzy import process
17
17
  from prompt_toolkit import PromptSession
18
- from prompt_toolkit.application import Application
18
+ from prompt_toolkit.application import Application, run_in_terminal
19
19
  from prompt_toolkit.completion import CompleteEvent
20
20
  from prompt_toolkit.completion import (
21
21
  Completer,
@@ -40,6 +40,28 @@ from jarvis.jarvis_utils.tag import ot
40
40
  # Sentinel value to indicate that Ctrl+O was pressed
41
41
  CTRL_O_SENTINEL = "__CTRL_O_PRESSED__"
42
42
 
43
+ # Persistent hint marker for multiline input (shown only once across runs)
44
+ _MULTILINE_HINT_MARK_FILE = os.path.join(get_data_dir(), "multiline_enter_hint_shown")
45
+
46
+
47
+ def _multiline_hint_already_shown() -> bool:
48
+ """Check if the multiline Enter hint has been shown before (persisted)."""
49
+ try:
50
+ return os.path.exists(_MULTILINE_HINT_MARK_FILE)
51
+ except Exception:
52
+ return False
53
+
54
+
55
+ def _mark_multiline_hint_shown() -> None:
56
+ """Persist that the multiline Enter hint has been shown."""
57
+ try:
58
+ os.makedirs(os.path.dirname(_MULTILINE_HINT_MARK_FILE), exist_ok=True)
59
+ with open(_MULTILINE_HINT_MARK_FILE, "w", encoding="utf-8") as f:
60
+ f.write("1")
61
+ except Exception:
62
+ # Non-critical persistence failure; ignore to avoid breaking input flow
63
+ pass
64
+
43
65
 
44
66
  def get_single_line_input(tip: str, default: str = "") -> str:
45
67
  """
@@ -315,8 +337,32 @@ def _get_multiline_input_internal(tip: str) -> str:
315
337
  """
316
338
  bindings = KeyBindings()
317
339
 
340
+ # Show a one-time hint on the first Enter press in this invocation
341
+ first_enter_hint_shown = False
342
+
318
343
  @bindings.add("enter")
319
344
  def _(event):
345
+ nonlocal first_enter_hint_shown
346
+ if not first_enter_hint_shown and not _multiline_hint_already_shown():
347
+ first_enter_hint_shown = True
348
+
349
+ def _show_notice():
350
+ print(
351
+ f"{Fore.YELLOW}提示:当前支持多行输入。输入完成请使用 Ctrl+J 确认;Enter 仅用于换行。{ColoramaStyle.RESET_ALL}"
352
+ )
353
+ try:
354
+ input("按回车继续...")
355
+ except Exception:
356
+ pass
357
+ # Persist the hint so it won't be shown again in future runs
358
+ try:
359
+ _mark_multiline_hint_shown()
360
+ except Exception:
361
+ pass
362
+
363
+ run_in_terminal(_show_notice)
364
+ return
365
+
320
366
  if event.current_buffer.complete_state:
321
367
  completion = event.current_buffer.complete_state.current_completion
322
368
  if completion:
@@ -363,7 +409,7 @@ def get_multiline_input(tip: str) -> str:
363
409
  此函数处理控制流,允许在不破坏终端状态的情况下处理历史记录复制。
364
410
  """
365
411
  PrettyOutput.section(
366
- "用户输入 - 使用 @ 触发文件补全,Tab 选择补全项,Ctrl+J 提交,Ctrl+O 从历史记录中选择消息复制,按 Ctrl+C/D 取消输入",
412
+ "用户输入 - 使用 @ 触发文件补全,Tab 选择补全项,Ctrl+J 确认,Ctrl+O 从历史记录中选择消息复制,按 Ctrl+C/D 取消输入",
367
413
  OutputType.USER,
368
414
  )
369
415
 
@@ -372,7 +418,7 @@ def get_multiline_input(tip: str) -> str:
372
418
 
373
419
  if user_input == CTRL_O_SENTINEL:
374
420
  _show_history_and_copy()
375
- tip = "请继续输入(或按Ctrl+J提交):"
421
+ tip = "请继续输入(或按Ctrl+J确认):"
376
422
  continue
377
423
  else:
378
424
  if not user_input:
@@ -880,12 +880,163 @@ def _load_and_process_config(jarvis_dir: str, config_file: str) -> None:
880
880
  config_file: 配置文件路径
881
881
  """
882
882
  from jarvis.jarvis_utils.input import user_confirm as get_yes_no
883
+ from jarvis.jarvis_utils.input import get_single_line_input
883
884
 
884
885
  try:
885
886
  content, config_data = _load_config_file(config_file)
886
887
  _ensure_schema_declaration(jarvis_dir, config_file, content, config_data)
887
888
  set_global_env_data(config_data)
888
889
  _process_env_variables(config_data)
890
+
891
+ # 首次运行提示:为新功能开关询问用户(默认值见各配置的getter)
892
+ def _ask_and_set(_key, _tip, _default, _type="bool"):
893
+ try:
894
+ if _key in config_data:
895
+ return False
896
+ if _type == "bool":
897
+ val = get_yes_no(_tip, default=bool(_default))
898
+ config_data[_key] = bool(val)
899
+ else:
900
+ val = get_single_line_input(f"{_tip}", default=str(_default or ""))
901
+ config_data[_key] = val.strip()
902
+ return True
903
+ except Exception:
904
+ # 出现异常时按默认值设置,避免中断流程
905
+ config_data[_key] = (
906
+ bool(_default) if _type == "bool" else str(_default or "")
907
+ )
908
+ return True
909
+
910
+ changed = False
911
+ # 现有两个开关
912
+ changed = (
913
+ _ask_and_set(
914
+ "JARVIS_ENABLE_GIT_JCA_SWITCH",
915
+ "是否在检测到Git仓库时,提示并可自动切换到代码开发模式(jca)?",
916
+ False,
917
+ "bool",
918
+ )
919
+ or changed
920
+ )
921
+ changed = (
922
+ _ask_and_set(
923
+ "JARVIS_ENABLE_STARTUP_CONFIG_SELECTOR",
924
+ "在进入默认通用代理前,是否先列出可用配置(agent/multi_agent/roles)供选择?",
925
+ False,
926
+ "bool",
927
+ )
928
+ or changed
929
+ )
930
+
931
+ # 新增的配置项交互
932
+ changed = (
933
+ _ask_and_set(
934
+ "JARVIS_PRETTY_OUTPUT",
935
+ "是否启用更美观的终端输出(Pretty Output)?",
936
+ False,
937
+ "bool",
938
+ )
939
+ or changed
940
+ )
941
+ changed = (
942
+ _ask_and_set(
943
+ "JARVIS_PRINT_PROMPT",
944
+ "是否打印发送给模型的提示词(Prompt)?",
945
+ False,
946
+ "bool",
947
+ )
948
+ or changed
949
+ )
950
+ changed = (
951
+ _ask_and_set(
952
+ "JARVIS_IMMEDIATE_ABORT",
953
+ "是否启用立即中断?\n- 选择 是/true:在对话输出流的每次迭代中检测到用户中断(例如 Ctrl+C)时,立即返回当前已生成的内容并停止继续输出。\n- 选择 否/false:不会在输出过程中立刻返回,而是按既有流程处理(不中途打断输出)。",
954
+ False,
955
+ "bool",
956
+ )
957
+ or changed
958
+ )
959
+ changed = (
960
+ _ask_and_set(
961
+ "JARVIS_ENABLE_STATIC_ANALYSIS",
962
+ "是否启用静态代码分析(Static Analysis)?",
963
+ True,
964
+ "bool",
965
+ )
966
+ or changed
967
+ )
968
+ changed = (
969
+ _ask_and_set(
970
+ "JARVIS_USE_METHODOLOGY",
971
+ "是否启用方法论系统(Methodology)?",
972
+ True,
973
+ "bool",
974
+ )
975
+ or changed
976
+ )
977
+ changed = (
978
+ _ask_and_set(
979
+ "JARVIS_USE_ANALYSIS",
980
+ "是否启用分析流程(Analysis)?",
981
+ True,
982
+ "bool",
983
+ )
984
+ or changed
985
+ )
986
+ changed = (
987
+ _ask_and_set(
988
+ "JARVIS_FORCE_SAVE_MEMORY",
989
+ "是否强制保存会话记忆?",
990
+ True,
991
+ "bool",
992
+ )
993
+ or changed
994
+ )
995
+ changed = (
996
+ _ask_and_set(
997
+ "JARVIS_CENTRAL_METHODOLOGY_REPO",
998
+ "请输入中心方法论仓库地址(可留空跳过):",
999
+ "",
1000
+ "str",
1001
+ )
1002
+ or changed
1003
+ )
1004
+ changed = (
1005
+ _ask_and_set(
1006
+ "JARVIS_CENTRAL_TOOL_REPO",
1007
+ "请输入中心工具仓库地址(可留空跳过):",
1008
+ "",
1009
+ "str",
1010
+ )
1011
+ or changed
1012
+ )
1013
+
1014
+ if changed:
1015
+ # 保留schema声明,如无则自动补充
1016
+ header = ""
1017
+ try:
1018
+ with open(config_file, "r", encoding="utf-8") as rf:
1019
+ first_line = rf.readline()
1020
+ if first_line.startswith("# yaml-language-server: $schema="):
1021
+ header = first_line
1022
+ except Exception:
1023
+ header = ""
1024
+ yaml_str = yaml.dump(config_data, allow_unicode=True, sort_keys=False)
1025
+ if not header:
1026
+ schema_path = Path(
1027
+ os.path.relpath(
1028
+ Path(__file__).parent.parent
1029
+ / "jarvis_data"
1030
+ / "config_schema.json",
1031
+ start=jarvis_dir,
1032
+ )
1033
+ )
1034
+ header = f"# yaml-language-server: $schema={schema_path}\n"
1035
+ with open(config_file, "w", encoding="utf-8") as wf:
1036
+ wf.write(header)
1037
+ wf.write(yaml_str)
1038
+ # 更新全局配置
1039
+ set_global_env_data(config_data)
889
1040
  except Exception:
890
1041
  PrettyOutput.print("加载配置文件失败", OutputType.ERROR)
891
1042
  if get_yes_no("配置文件格式错误,是否删除并重新配置?"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.3.16
3
+ Version: 0.3.18
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire