jarvis-ai-assistant 0.7.0__py3-none-any.whl → 0.7.8__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 (159) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +243 -139
  3. jarvis/jarvis_agent/agent_manager.py +5 -10
  4. jarvis/jarvis_agent/builtin_input_handler.py +2 -6
  5. jarvis/jarvis_agent/config_editor.py +2 -7
  6. jarvis/jarvis_agent/event_bus.py +82 -12
  7. jarvis/jarvis_agent/file_context_handler.py +265 -15
  8. jarvis/jarvis_agent/file_methodology_manager.py +3 -4
  9. jarvis/jarvis_agent/jarvis.py +113 -98
  10. jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
  11. jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
  12. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
  13. jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
  14. jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
  15. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
  16. jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
  17. jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
  18. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
  19. jarvis/jarvis_agent/language_support_info.py +486 -0
  20. jarvis/jarvis_agent/main.py +6 -12
  21. jarvis/jarvis_agent/memory_manager.py +7 -16
  22. jarvis/jarvis_agent/methodology_share_manager.py +10 -16
  23. jarvis/jarvis_agent/prompt_manager.py +1 -1
  24. jarvis/jarvis_agent/prompts.py +193 -171
  25. jarvis/jarvis_agent/protocols.py +8 -12
  26. jarvis/jarvis_agent/run_loop.py +77 -14
  27. jarvis/jarvis_agent/session_manager.py +2 -3
  28. jarvis/jarvis_agent/share_manager.py +12 -21
  29. jarvis/jarvis_agent/shell_input_handler.py +1 -2
  30. jarvis/jarvis_agent/task_analyzer.py +26 -4
  31. jarvis/jarvis_agent/task_manager.py +11 -27
  32. jarvis/jarvis_agent/tool_executor.py +2 -3
  33. jarvis/jarvis_agent/tool_share_manager.py +12 -24
  34. jarvis/jarvis_agent/web_server.py +55 -20
  35. jarvis/jarvis_c2rust/__init__.py +5 -5
  36. jarvis/jarvis_c2rust/cli.py +461 -499
  37. jarvis/jarvis_c2rust/collector.py +45 -53
  38. jarvis/jarvis_c2rust/constants.py +26 -0
  39. jarvis/jarvis_c2rust/library_replacer.py +264 -132
  40. jarvis/jarvis_c2rust/llm_module_agent.py +162 -190
  41. jarvis/jarvis_c2rust/loaders.py +207 -0
  42. jarvis/jarvis_c2rust/models.py +28 -0
  43. jarvis/jarvis_c2rust/optimizer.py +1592 -395
  44. jarvis/jarvis_c2rust/transpiler.py +1722 -1064
  45. jarvis/jarvis_c2rust/utils.py +385 -0
  46. jarvis/jarvis_code_agent/build_validation_config.py +2 -3
  47. jarvis/jarvis_code_agent/code_agent.py +394 -320
  48. jarvis/jarvis_code_agent/code_analyzer/__init__.py +3 -0
  49. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +4 -0
  50. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +17 -2
  51. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +3 -0
  52. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +36 -4
  53. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +9 -0
  54. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +9 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +12 -1
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +22 -5
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +57 -32
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +62 -6
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +8 -9
  60. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +290 -5
  61. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -0
  62. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +21 -3
  63. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +72 -4
  64. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +35 -3
  65. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
  66. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
  67. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +52 -2
  68. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +73 -1
  69. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
  70. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +306 -152
  71. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
  72. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +193 -18
  73. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +18 -8
  74. jarvis/jarvis_code_agent/lint.py +258 -27
  75. jarvis/jarvis_code_agent/utils.py +0 -1
  76. jarvis/jarvis_code_analysis/code_review.py +19 -24
  77. jarvis/jarvis_data/config_schema.json +53 -26
  78. jarvis/jarvis_git_squash/main.py +4 -5
  79. jarvis/jarvis_git_utils/git_commiter.py +44 -49
  80. jarvis/jarvis_mcp/sse_mcp_client.py +20 -27
  81. jarvis/jarvis_mcp/stdio_mcp_client.py +11 -12
  82. jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
  83. jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
  84. jarvis/jarvis_methodology/main.py +32 -48
  85. jarvis/jarvis_multi_agent/__init__.py +79 -61
  86. jarvis/jarvis_multi_agent/main.py +3 -7
  87. jarvis/jarvis_platform/base.py +469 -199
  88. jarvis/jarvis_platform/human.py +7 -8
  89. jarvis/jarvis_platform/kimi.py +30 -36
  90. jarvis/jarvis_platform/openai.py +65 -27
  91. jarvis/jarvis_platform/registry.py +26 -10
  92. jarvis/jarvis_platform/tongyi.py +24 -25
  93. jarvis/jarvis_platform/yuanbao.py +31 -42
  94. jarvis/jarvis_platform_manager/main.py +66 -77
  95. jarvis/jarvis_platform_manager/service.py +8 -13
  96. jarvis/jarvis_rag/cli.py +49 -51
  97. jarvis/jarvis_rag/embedding_manager.py +13 -18
  98. jarvis/jarvis_rag/llm_interface.py +8 -9
  99. jarvis/jarvis_rag/query_rewriter.py +10 -21
  100. jarvis/jarvis_rag/rag_pipeline.py +24 -27
  101. jarvis/jarvis_rag/reranker.py +4 -5
  102. jarvis/jarvis_rag/retriever.py +28 -30
  103. jarvis/jarvis_sec/__init__.py +220 -3520
  104. jarvis/jarvis_sec/agents.py +143 -0
  105. jarvis/jarvis_sec/analysis.py +276 -0
  106. jarvis/jarvis_sec/cli.py +29 -6
  107. jarvis/jarvis_sec/clustering.py +1439 -0
  108. jarvis/jarvis_sec/file_manager.py +427 -0
  109. jarvis/jarvis_sec/parsers.py +73 -0
  110. jarvis/jarvis_sec/prompts.py +268 -0
  111. jarvis/jarvis_sec/report.py +83 -4
  112. jarvis/jarvis_sec/review.py +453 -0
  113. jarvis/jarvis_sec/utils.py +499 -0
  114. jarvis/jarvis_sec/verification.py +848 -0
  115. jarvis/jarvis_sec/workflow.py +7 -0
  116. jarvis/jarvis_smart_shell/main.py +38 -87
  117. jarvis/jarvis_stats/cli.py +1 -1
  118. jarvis/jarvis_stats/stats.py +7 -7
  119. jarvis/jarvis_stats/storage.py +15 -21
  120. jarvis/jarvis_tools/clear_memory.py +3 -20
  121. jarvis/jarvis_tools/cli/main.py +20 -23
  122. jarvis/jarvis_tools/edit_file.py +1066 -0
  123. jarvis/jarvis_tools/execute_script.py +42 -21
  124. jarvis/jarvis_tools/file_analyzer.py +6 -9
  125. jarvis/jarvis_tools/generate_new_tool.py +11 -20
  126. jarvis/jarvis_tools/lsp_client.py +1552 -0
  127. jarvis/jarvis_tools/methodology.py +2 -3
  128. jarvis/jarvis_tools/read_code.py +1525 -87
  129. jarvis/jarvis_tools/read_symbols.py +2 -3
  130. jarvis/jarvis_tools/read_webpage.py +7 -10
  131. jarvis/jarvis_tools/registry.py +370 -181
  132. jarvis/jarvis_tools/retrieve_memory.py +20 -19
  133. jarvis/jarvis_tools/rewrite_file.py +105 -0
  134. jarvis/jarvis_tools/save_memory.py +3 -15
  135. jarvis/jarvis_tools/search_web.py +3 -7
  136. jarvis/jarvis_tools/sub_agent.py +17 -6
  137. jarvis/jarvis_tools/sub_code_agent.py +14 -16
  138. jarvis/jarvis_tools/virtual_tty.py +54 -32
  139. jarvis/jarvis_utils/clipboard.py +7 -10
  140. jarvis/jarvis_utils/config.py +98 -63
  141. jarvis/jarvis_utils/embedding.py +5 -5
  142. jarvis/jarvis_utils/fzf.py +8 -8
  143. jarvis/jarvis_utils/git_utils.py +81 -67
  144. jarvis/jarvis_utils/input.py +24 -49
  145. jarvis/jarvis_utils/jsonnet_compat.py +465 -0
  146. jarvis/jarvis_utils/methodology.py +33 -35
  147. jarvis/jarvis_utils/utils.py +245 -202
  148. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.8.dist-info}/METADATA +205 -70
  149. jarvis_ai_assistant-0.7.8.dist-info/RECORD +218 -0
  150. jarvis/jarvis_agent/edit_file_handler.py +0 -584
  151. jarvis/jarvis_agent/rewrite_file_handler.py +0 -141
  152. jarvis/jarvis_agent/task_planner.py +0 -496
  153. jarvis/jarvis_platform/ai8.py +0 -332
  154. jarvis/jarvis_tools/ask_user.py +0 -54
  155. jarvis_ai_assistant-0.7.0.dist-info/RECORD +0 -192
  156. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.8.dist-info}/WHEEL +0 -0
  157. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.8.dist-info}/entry_points.txt +0 -0
  158. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.8.dist-info}/licenses/LICENSE +0 -0
  159. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.8.dist-info}/top_level.txt +0 -0
@@ -3,24 +3,25 @@
3
3
  LLM 驱动的 Rust Crate 模块规划 Agent
4
4
 
5
5
  目标:
6
- - 复用 scanner 中的 find_root_function_ids 与调用图信息,构造“以根函数为起点”的上下文
7
- - 通过 jarvis_agent.Agent 调用 LLM,基于上下文生成 Rust crate 的目录规划(YAML
6
+ - 复用 scanner 中的 find_root_function_ids 与调用图信息,构造"以根函数为起点"的上下文
7
+ - 通过 jarvis_agent.Agent 调用 LLM,基于上下文生成 Rust crate 的目录规划(JSON
8
8
 
9
9
  设计要点:
10
10
  - 与现有 scanner/cli 解耦,最小侵入新增模块
11
11
  - 使用 jarvis_agent.Agent 的平台与系统提示管理能力,但不走完整工具循环,直接进行一次性对话生成
12
- - 对输出格式进行强约束:仅输出 YAML,无解释文本
12
+ - 对输出格式进行强约束:仅输出 JSON,无解释文本
13
13
 
14
14
  用法:
15
- from jarvis.jarvis_c2rust.llm_module_agent import plan_crate_yaml_llm
16
- print(plan_crate_yaml_llm(project_root="."))
15
+ from jarvis.jarvis_c2rust.llm_module_agent import plan_crate_json_llm
16
+ print(plan_crate_json_llm(project_root="."))
17
17
 
18
18
  CLI 集成建议:
19
- 可在 jarvis_c2rust/cli.py 中新增 llm-plan 子命令调用本模块的 plan_crate_yaml_llm(已独立封装,便于后续补充)
19
+ 可在 jarvis_c2rust/cli.py 中新增 llm-plan 子命令调用本模块的 plan_crate_json_llm(已独立封装,便于后续补充)
20
20
  """
21
21
 
22
22
  from __future__ import annotations
23
23
 
24
+ from jarvis.jarvis_utils.jsonnet_compat import loads as json_loads
24
25
  import json
25
26
  # removed sqlite3 (migrated to JSONL/JSON)
26
27
  from dataclasses import dataclass
@@ -111,8 +112,8 @@ class _GraphLoader:
111
112
  if not line:
112
113
  continue
113
114
  try:
114
- obj = json.loads(line)
115
- except (json.JSONDecodeError, ValueError):
115
+ obj = json_loads(line)
116
+ except Exception:
116
117
  # 跳过无效的 JSON 行,但记录以便调试
117
118
  continue
118
119
  # 不区分函数与类型,统一处理 symbols.jsonl 中的所有记录
@@ -301,7 +302,7 @@ def _resolve_created_dir(target_root: Union[Path, str]) -> Path:
301
302
 
302
303
  class LLMRustCratePlannerAgent:
303
304
  """
304
- 使用 jarvis_agent.Agent 调用 LLM 来生成 Rust crate 规划(YAML)。
305
+ 使用 jarvis_agent.Agent 调用 LLM 来生成 Rust crate 规划(JSON)。
305
306
  """
306
307
 
307
308
  def __init__(
@@ -318,6 +319,36 @@ class LLMRustCratePlannerAgent:
318
319
  )
319
320
  self.llm_group = llm_group
320
321
  self.loader = _GraphLoader(self.db_path, self.project_root)
322
+ # 读取附加说明
323
+ self.additional_notes = self._load_additional_notes()
324
+
325
+ def _load_additional_notes(self) -> str:
326
+ """从配置文件加载附加说明"""
327
+ try:
328
+ from jarvis.jarvis_c2rust.constants import CONFIG_JSON
329
+ config_path = self.project_root / ".jarvis" / "c2rust" / CONFIG_JSON
330
+ if config_path.exists():
331
+ with config_path.open("r", encoding="utf-8") as f:
332
+ config = json.load(f)
333
+ if isinstance(config, dict):
334
+ return str(config.get("additional_notes", "") or "").strip()
335
+ except Exception:
336
+ pass
337
+ return ""
338
+
339
+ def _append_additional_notes(self, prompt: str) -> str:
340
+ """
341
+ 在提示词末尾追加附加说明(如果存在)。
342
+
343
+ Args:
344
+ prompt: 原始提示词
345
+
346
+ Returns:
347
+ 追加了附加说明的提示词
348
+ """
349
+ if self.additional_notes and self.additional_notes.strip():
350
+ return prompt + "\n\n" + "【附加说明(用户自定义)】\n" + self.additional_notes.strip()
351
+ return prompt
321
352
 
322
353
  def _crate_name(self) -> str:
323
354
  """
@@ -366,7 +397,7 @@ class LLMRustCratePlannerAgent:
366
397
  - 跳过无 roots 标签的 residual 步骤(仅保留明确 root 的上下文)
367
398
  - 若最终未收集到任何 root 组,则回退为单组 'project',包含所有 items 的函数名集合
368
399
  """
369
- import json
400
+ from jarvis.jarvis_utils.jsonnet_compat import loads as json_loads
370
401
  order_path = self._order_path()
371
402
  if not order_path.exists():
372
403
  raise FileNotFoundError(f"未找到 translation_order.jsonl: {order_path}")
@@ -398,8 +429,8 @@ class LLMRustCratePlannerAgent:
398
429
  if not line:
399
430
  continue
400
431
  try:
401
- obj = json.loads(line)
402
- except (json.JSONDecodeError, ValueError):
432
+ obj = json_loads(line)
433
+ except Exception:
403
434
  continue
404
435
 
405
436
  roots = obj.get("roots") or []
@@ -453,21 +484,22 @@ class LLMRustCratePlannerAgent:
453
484
  ensure_ascii=False,
454
485
  indent=2,
455
486
  )
456
- return f"""
457
- 下面提供了项目的调用图上下文(JSON),请先通读理解,不要输出任何规划或YAML内容:
487
+ prompt = f"""
488
+ 下面提供了项目的调用图上下文(JSON),请先通读理解,不要输出任何规划或JSON内容:
458
489
  <context>
459
490
  {context_json}
460
491
  </context>
461
492
 
462
493
  如果已准备好进入总结阶段以生成完整输出,请仅输出:<!!!COMPLETE!!!>
463
494
  """.strip()
495
+ return self._append_additional_notes(prompt)
464
496
 
465
497
  def _build_system_prompt(self) -> str:
466
498
  """
467
499
  系统提示:描述如何基于依赖关系进行 crate 规划的原则(不涉及对话流程或输出方式)
468
500
  """
469
501
  crate_name = self._crate_name()
470
- return (
502
+ prompt = (
471
503
  "你是资深 Rust 架构师。任务:根据给定的函数级调用关系(仅包含 root_function 及其可达的函数名列表),为目标项目规划合理的 Rust crate 结构。\n"
472
504
  "\n"
473
505
  "规划原则:\n"
@@ -487,14 +519,15 @@ class LLMRustCratePlannerAgent:
487
519
  " * 多可执行仅在确有多个清晰入口时才使用 src/bin/<name>.rs;每个 bin 文件仅做入口,尽量调用库;\n"
488
520
  " * 二进制命名:<name> 使用小写下划线,体现入口意图,避免与模块/文件重名。\n"
489
521
  )
522
+ return self._append_additional_notes(prompt)
490
523
 
491
524
  def _build_summary_prompt(self, roots_context: List[Dict[str, Any]]) -> str:
492
525
  """
493
- 总结阶段:只输出目录结构的 YAML
526
+ 总结阶段:只输出目录结构的 JSON
494
527
  要求:
495
528
  - 仅输出一个 <PROJECT> 块
496
- - <PROJECT> 与 </PROJECT> 之间必须是可解析的 YAML 列表,使用两空格缩进
497
- - 目录以 '目录名/' 表示,子项为列表;文件为纯字符串
529
+ - <PROJECT> 与 </PROJECT> 之间必须是可解析的 JSON 数组
530
+ - 目录以对象表示,键为 '目录名/',值为子项数组;文件为字符串
498
531
  - 块外不得有任何字符(包括空行、注释、Markdown、解释文字、schema等)
499
532
  - 不要输出 crate 名称或其他多余字段
500
533
  """
@@ -504,10 +537,11 @@ class LLMRustCratePlannerAgent:
504
537
  输出规范:
505
538
  - 只输出一个 <PROJECT> 块
506
539
  - 块外不得有任何字符(包括空行、注释、Markdown 等)
507
- - 块内必须是 YAML 列表:
508
- - 目录项使用 '<name>/' 作为键,并在后面加冒号 ':',其值为子项列表
509
- - 文件为字符串项(例如 'lib.rs'
540
+ - 块内必须是 JSON 数组:
541
+ - 目录项使用对象表示,键为 '<name>/',值为子项数组
542
+ - 文件为字符串项(例如 "lib.rs"
510
543
  - 不要创建与入口无关的占位文件
544
+ - 支持jsonnet语法(如尾随逗号、注释、||| 或 ``` 分隔符多行字符串等)
511
545
  """.strip()
512
546
  if has_main:
513
547
  entry_rule = f"""
@@ -516,13 +550,21 @@ class LLMRustCratePlannerAgent:
516
550
  - 不要包含 src/main.rs;
517
551
  - 必须包含 src/bin/{crate_name}.rs,作为唯一可执行入口(仅做入口,调用库逻辑);
518
552
  - 如无明确多个入口,不要创建额外 bin 文件。
519
- 正确示例(标准 YAML,带冒号):
553
+ 正确示例(JSON格式):
520
554
  <PROJECT>
521
- - Cargo.toml
522
- - src/:
523
- - lib.rs
524
- - bin/:
525
- - {crate_name}.rs
555
+ [
556
+ "Cargo.toml",
557
+ {{
558
+ "src/": [
559
+ "lib.rs",
560
+ {{
561
+ "bin/": [
562
+ "{crate_name}.rs"
563
+ ]
564
+ }}
565
+ ]
566
+ }}
567
+ ]
526
568
  </PROJECT>
527
569
  """.strip()
528
570
  else:
@@ -531,28 +573,34 @@ class LLMRustCratePlannerAgent:
531
573
  - 必须包含 src/lib.rs;
532
574
  - 不要包含 src/main.rs;
533
575
  - 不要包含 src/bin/ 目录。
534
- 正确示例(标准 YAML,带冒号):
576
+ 正确示例(JSON格式):
535
577
  <PROJECT>
536
- - Cargo.toml
537
- - src/:
538
- - lib.rs
578
+ [
579
+ "Cargo.toml",
580
+ {
581
+ "src/": [
582
+ "lib.rs"
583
+ ]
584
+ }
585
+ ]
539
586
  </PROJECT>
540
587
  """.strip()
541
588
  guidance = f"{guidance_common}\n{entry_rule}"
542
- return f"""
543
- 请基于之前对话中已提供的<context>信息,生成总结输出(项目目录结构的 YAML)。严格遵循以下要求:
589
+ prompt = f"""
590
+ 请基于之前对话中已提供的<context>信息,生成总结输出(项目目录结构的 JSON)。严格遵循以下要求:
544
591
 
545
592
  {guidance}
546
593
 
547
594
  你的输出必须仅包含以下单个块(用项目的真实目录结构替换块内内容):
548
595
  <PROJECT>
549
- - ...
596
+ [...]
550
597
  </PROJECT>
551
598
  """.strip()
599
+ return self._append_additional_notes(prompt)
552
600
 
553
- def _extract_yaml_from_project(self, text: str) -> str:
601
+ def _extract_json_from_project(self, text: str) -> str:
554
602
  """
555
- 从 <PROJECT> 块中提取内容作为最终 YAML;若未匹配,返回原文本(兜底)。
603
+ 从 <PROJECT> 块中提取内容作为最终 JSON;若未匹配,返回原文本(兜底)。
556
604
  """
557
605
  if not isinstance(text, str) or not text:
558
606
  return ""
@@ -574,7 +622,7 @@ class LLMRustCratePlannerAgent:
574
622
  返回 (是否通过, 错误原因)
575
623
  """
576
624
  if not isinstance(entries, list) or not entries:
577
- return False, "YAML 不可解析或为空列表"
625
+ return False, "JSON 不可解析或为空数组"
578
626
 
579
627
  # 提取 src 目录子项
580
628
  src_children: Optional[List[Any]] = None
@@ -644,13 +692,13 @@ class LLMRustCratePlannerAgent:
644
692
  "\n\n[格式校验失败,必须重试]\n"
645
693
  f"- 失败原因:{error_reason}\n"
646
694
  "- 请严格遵循上述“输出规范”与“入口约定”,重新输出;\n"
647
- "- 仅输出一个 <PROJECT> 块,块内为可解析的 YAML 列表;块外不得有任何字符。\n"
695
+ "- 仅输出一个 <PROJECT> 块,块内为可解析的 JSON 数组;块外不得有任何字符。\n"
648
696
  )
649
697
  return base_summary_prompt + feedback
650
698
 
651
- def _get_project_yaml_text(self, max_retries: int = 10) -> str:
699
+ def _get_project_json_text(self, max_retries: int = 10) -> str:
652
700
  """
653
- 执行主流程并返回原始 <PROJECT> YAML 文本,不进行解析。
701
+ 执行主流程并返回原始 <PROJECT> JSON 文本,不进行解析。
654
702
  若格式校验失败,将自动重试,直到满足为止或达到最大重试次数。
655
703
 
656
704
  Args:
@@ -687,23 +735,22 @@ class LLMRustCratePlannerAgent:
687
735
  summary_prompt=summary_prompt,
688
736
  need_summary=True,
689
737
  auto_complete=True,
690
- use_tools=["execute_script", "read_code", "retrieve_memory", "save_memory"],
691
- plan=False, # 关闭内置任务规划
738
+ use_tools=["execute_script", "read_code"],
692
739
  non_interactive=True, # 非交互
693
740
  use_methodology=False,
694
741
  use_analysis=False,
695
742
  )
696
743
 
697
- # 进入主循环:第一轮仅输出 <!!!COMPLETE!!!> 触发自动完成;随后 summary 输出 <PROJECT> 块(仅含 YAML
744
+ # 进入主循环:第一轮仅输出 <!!!COMPLETE!!!> 触发自动完成;随后 summary 输出 <PROJECT> 块(仅含 JSON
698
745
  if use_direct_model:
699
746
  # 格式校验失败后,直接调用模型接口
700
747
  # 构造包含摘要提示词和具体错误信息的完整提示
701
748
  error_guidance = ""
702
749
  if last_error and last_error != "未知错误":
703
- if "YAML解析失败" in last_error:
704
- error_guidance = f"\n\n**格式错误详情(请根据以下错误修复输出格式):**\n- {last_error}\n\n请确保输出的YAML格式正确,包括正确的缩进、引号、冒号等。仅输出一个 <PROJECT> 块,块内仅包含 YAML 格式的项目结构定义。"
750
+ if "JSON解析失败" in last_error:
751
+ error_guidance = f"\n\n**格式错误详情(请根据以下错误修复输出格式):**\n- {last_error}\n\n请确保输出的JSON格式正确,包括正确的引号、逗号、大括号等。仅输出一个 <PROJECT> 块,块内仅包含 JSON 格式的项目结构定义。支持jsonnet语法(如尾随逗号、注释、||| 或 ``` 分隔符多行字符串等)。"
705
752
  else:
706
- error_guidance = f"\n\n**格式错误详情(请根据以下错误修复输出格式):**\n- {last_error}\n\n请确保输出格式正确:仅输出一个 <PROJECT> 块,块内仅包含 YAML 格式的项目结构定义。"
753
+ error_guidance = f"\n\n**格式错误详情(请根据以下错误修复输出格式):**\n- {last_error}\n\n请确保输出格式正确:仅输出一个 <PROJECT> 块,块内仅包含 JSON 格式的项目结构定义。支持jsonnet语法(如尾随逗号、注释、||| 或 ``` 分隔符多行字符串等)。"
707
754
 
708
755
  full_prompt = f"{user_prompt}{error_guidance}\n\n{summary_prompt}"
709
756
  try:
@@ -717,20 +764,20 @@ class LLMRustCratePlannerAgent:
717
764
  summary_output = agent.run(user_prompt) # type: ignore
718
765
 
719
766
  project_text = str(summary_output) if summary_output is not None else ""
720
- yaml_text = self._extract_yaml_from_project(project_text)
767
+ json_text = self._extract_json_from_project(project_text)
721
768
 
722
769
  # 尝试解析并校验
723
- entries, parse_error_yaml = _parse_project_yaml_entries(yaml_text)
724
- if parse_error_yaml:
725
- # YAML解析失败,记录错误并重试
726
- last_error = parse_error_yaml
770
+ entries, parse_error_json = _parse_project_json_entries(json_text)
771
+ if parse_error_json:
772
+ # JSON解析失败,记录错误并重试
773
+ last_error = parse_error_json
727
774
  use_direct_model = True # 格式校验失败,后续重试使用直接模型调用
728
- print(f"[c2rust-llm-planner] YAML解析失败: {parse_error_yaml}")
775
+ print(f"[c2rust-llm-planner] JSON解析失败: {parse_error_json}")
729
776
  continue
730
777
 
731
778
  ok, reason = self._validate_project_entries(entries)
732
779
  if ok:
733
- return yaml_text
780
+ return json_text
734
781
  else:
735
782
  last_error = reason
736
783
  use_direct_model = True # 格式校验失败,后续重试使用直接模型调用
@@ -741,35 +788,35 @@ class LLMRustCratePlannerAgent:
741
788
  f"最后一次错误: {last_error}"
742
789
  )
743
790
 
744
- def plan_crate_yaml_with_project(self) -> List[Any]:
791
+ def plan_crate_json_with_project(self) -> List[Any]:
745
792
  """
746
- 执行主流程并返回解析后的 YAML 对象(列表):
793
+ 执行主流程并返回解析后的 JSON 对象(列表):
747
794
  - 列表项:
748
795
  * 字符串:文件,如 "lib.rs"
749
- * 字典:目录及其子项,如 {"src": [ ... ]}
796
+ * 字典:目录及其子项,如 {"src/": [ ... ]}
750
797
  """
751
- yaml_text = self._get_project_yaml_text()
752
- yaml_entries, parse_error = _parse_project_yaml_entries(yaml_text)
798
+ json_text = self._get_project_json_text()
799
+ json_entries, parse_error = _parse_project_json_entries(json_text)
753
800
  if parse_error:
754
- raise RuntimeError(f"YAML解析失败: {parse_error}")
755
- return yaml_entries
801
+ raise RuntimeError(f"JSON解析失败: {parse_error}")
802
+ return json_entries
756
803
 
757
- def plan_crate_yaml_text(self) -> str:
804
+ def plan_crate_json_text(self) -> str:
758
805
  """
759
- 执行主流程但返回原始 <PROJECT> YAML 文本,不进行解析。
806
+ 执行主流程但返回原始 <PROJECT> JSON 文本,不进行解析。
760
807
  便于后续按原样应用目录结构,避免早期解析失败导致信息丢失。
761
808
  """
762
- return self._get_project_yaml_text()
809
+ return self._get_project_json_text()
763
810
 
764
811
 
765
- def plan_crate_yaml_text(
812
+ def plan_crate_json_text(
766
813
  project_root: Union[Path, str] = ".",
767
814
  db_path: Optional[Union[Path, str]] = None,
768
815
  llm_group: Optional[str] = None,
769
816
  skip_cleanup: bool = False,
770
817
  ) -> str:
771
818
  """
772
- 返回 LLM 生成的目录结构原始 YAML 文本(来自 <PROJECT> 块)。
819
+ 返回 LLM 生成的目录结构原始 JSON 文本(来自 <PROJECT> 块)。
773
820
  在规划前执行预清理并征询用户确认:删除将要生成的 crate 目录、当前目录的 Cargo.toml 工作区文件,以及 .jarvis/c2rust 下的 progress.json 与 symbol_map.jsonl。
774
821
  用户不同意则退出程序。
775
822
  当 skip_cleanup=True 时,跳过清理与确认(用于外层已处理的场景)。
@@ -777,15 +824,15 @@ def plan_crate_yaml_text(
777
824
  # 若外层已处理清理确认,则跳过本函数的清理与确认(避免重复询问)
778
825
  if skip_cleanup:
779
826
  agent = LLMRustCratePlannerAgent(project_root=project_root, db_path=db_path, llm_group=llm_group)
780
- return agent.plan_crate_yaml_text()
827
+ return agent.plan_crate_json_text()
781
828
 
782
829
  _perform_pre_cleanup_for_planner(project_root)
783
830
 
784
831
  agent = LLMRustCratePlannerAgent(project_root=project_root, db_path=db_path, llm_group=llm_group)
785
- return agent.plan_crate_yaml_text()
832
+ return agent.plan_crate_json_text()
786
833
 
787
834
 
788
- def plan_crate_yaml_llm(
835
+ def plan_crate_json_llm(
789
836
  project_root: Union[Path, str] = ".",
790
837
  db_path: Optional[Union[Path, str]] = None,
791
838
  skip_cleanup: bool = False,
@@ -799,135 +846,60 @@ def plan_crate_yaml_llm(
799
846
  # 若外层已处理清理确认,则跳过本函数的清理与确认(避免重复询问)
800
847
  if skip_cleanup:
801
848
  agent = LLMRustCratePlannerAgent(project_root=project_root, db_path=db_path)
802
- return agent.plan_crate_yaml_with_project()
849
+ return agent.plan_crate_json_with_project()
803
850
 
804
851
  _perform_pre_cleanup_for_planner(project_root)
805
852
 
806
853
  agent = LLMRustCratePlannerAgent(project_root=project_root, db_path=db_path)
807
- return agent.plan_crate_yaml_with_project()
854
+ return agent.plan_crate_json_with_project()
808
855
 
809
856
 
810
- def entries_to_yaml(entries: List[Any]) -> str:
857
+ def entries_to_json(entries: List[Any]) -> str:
811
858
  """
812
- 将解析后的 entries 列表序列化为 YAML 文本(目录使用 'name/:' 形式,文件为字符串)
859
+ 将解析后的 entries 列表序列化为 JSON 文本(目录使用对象表示,文件为字符串)
813
860
  """
814
- def _entries_to_yaml(items, indent=0):
815
- lines: List[str] = []
816
- for it in (items or []):
817
- if isinstance(it, str):
818
- lines.append(" " * indent + f"- {it}")
819
- elif isinstance(it, dict) and len(it) == 1:
820
- name, children = next(iter(it.items()))
821
- name = str(name).rstrip("/")
822
- lines.append(" " * indent + f"- {name}/:")
823
- lines.extend(_entries_to_yaml(children or [], indent + 1))
824
- return lines
825
-
826
- return "\n".join(_entries_to_yaml(entries))
827
-
828
-
829
- def _parse_project_yaml_entries_fallback(yaml_text: str) -> List[Any]:
861
+ return json.dumps(entries, ensure_ascii=False, indent=2)
862
+
863
+
864
+ def _parse_project_json_entries_fallback(json_text: str) -> List[Any]:
830
865
  """
831
- Fallback 解析器:当 PyYAML 不可用或解析失败时,按约定的缩进/列表语法解析 <PROJECT> 块。
832
- 支持的子集:
833
- - 列表项以 "- " 开头
834
- - 目录项以 "- <name>/:", 其子项为下一层缩进(+2 空格)的列表
835
- - 文件项为 "- <filename>"
866
+ Fallback 解析器:当 jsonnet 解析失败时,尝试使用标准 json 解析。
867
+ 注意:此函数主要用于兼容性,正常情况下应使用 jsonnet 解析。
836
868
  """
837
- def leading_spaces(s: str) -> int:
838
- return len(s) - len(s.lstrip(" "))
839
-
840
- lines = [ln.rstrip() for ln in str(yaml_text or "").splitlines()]
841
- idx = 0
842
- n = len(lines)
843
-
844
- # 跳过非列表起始行
845
- while idx < n and not lines[idx].lstrip().startswith("- "):
846
- idx += 1
847
-
848
- def parse_list(expected_indent: int) -> List[Any]:
849
- nonlocal idx
850
- items: List[Any] = []
851
- while idx < n:
852
- line = lines[idx]
853
- if not line.strip():
854
- idx += 1
855
- continue
856
- indent = leading_spaces(line)
857
- if indent < expected_indent:
858
- break
859
- if not line.lstrip().startswith("- "):
860
- break
861
-
862
- # 去掉 "- "
863
- content = line[indent + 2 :].strip()
864
-
865
- # 目录项:以 ":" 结尾(形如 "src/:")
866
- if content.endswith(":"):
867
- key = content[:-1].strip()
868
- idx += 1 # 消费当前目录行
869
- children = parse_list(expected_indent + 2)
870
- # 规范化目录键为以 "/" 结尾(apply 时会 rstrip("/"),二者均可)
871
- if not str(key).endswith("/"):
872
- key = f"{str(key).rstrip('/')}/"
873
- items.append({key: children})
874
- else:
875
- # 文件项
876
- items.append(content)
877
- idx += 1
878
- return items
879
-
880
- base_indent = leading_spaces(lines[idx]) if idx < n else 0
881
- return parse_list(base_indent)
869
+ try:
870
+ import json as std_json
871
+ data = std_json.loads(json_text)
872
+ if isinstance(data, list):
873
+ return data
874
+ return []
875
+ except Exception:
876
+ return []
882
877
 
883
878
 
884
- def _parse_project_yaml_entries(yaml_text: str) -> Tuple[List[Any], Optional[str]]:
879
+ def _parse_project_json_entries(json_text: str) -> Tuple[List[Any], Optional[str]]:
885
880
  """
886
- 使用 PyYAML 解析 <PROJECT> 块中的目录结构 YAML 为列表结构:
881
+ 使用 jsonnet 解析 <PROJECT> 块中的目录结构 JSON 为列表结构:
887
882
  - 文件项: 字符串,如 "lib.rs"
888
883
  - 目录项: 字典,形如 {"src/": [ ... ]} 或 {"src": [ ... ]}
889
884
  返回(解析结果, 错误信息)
890
885
  如果解析成功,返回(data, None)
891
886
  如果解析失败,返回([], 错误信息)
892
- 优先使用 PyYAML;若不可用或解析失败,则回退到轻量解析器以最大化兼容性。
887
+ 使用 jsonnet 解析,支持更宽松的 JSON 语法(如尾随逗号、注释等)。
893
888
  """
894
889
  try:
895
- import yaml # type: ignore
896
890
  try:
897
- data = yaml.safe_load(yaml_text)
891
+ data = json_loads(json_text)
898
892
  if isinstance(data, list):
899
893
  return data, None
900
- # 如果解析结果不是列表,回退到轻量解析器
901
- return [], f"YAML 解析结果不是列表,而是 {type(data).__name__}"
902
- except (yaml.YAMLError, ValueError) as yaml_err:
903
- # YAML 解析错误,记录错误信息
904
- error_msg = f"YAML 解析失败: {str(yaml_err)}"
905
- # 回退到轻量解析器
906
- try:
907
- fallback_result = _parse_project_yaml_entries_fallback(yaml_text)
908
- return fallback_result, None # 回退解析器成功,不返回错误
909
- except Exception:
910
- return [], error_msg
911
- except ImportError:
912
- # PyYAML 未安装,使用回退解析器
913
- try:
914
- fallback_result = _parse_project_yaml_entries_fallback(yaml_text)
915
- return fallback_result, None
916
- except Exception as e:
917
- return [], f"PyYAML 未安装且回退解析器失败: {str(e)}"
918
- except Exception as e:
919
- # 其他未知错误,回退到轻量解析器
920
- try:
921
- fallback_result = _parse_project_yaml_entries_fallback(yaml_text)
922
- return fallback_result, None
923
- except Exception:
924
- return [], f"解析过程发生异常: {str(e)}"
925
- # 回退
926
- try:
927
- fallback_result = _parse_project_yaml_entries_fallback(yaml_text)
928
- return fallback_result, None
894
+ # 如果解析结果不是列表
895
+ return [], f"JSON 解析结果不是数组,而是 {type(data).__name__}"
896
+ except Exception as json_err:
897
+ # JSON 解析错误
898
+ error_msg = f"JSON 解析失败: {str(json_err)}"
899
+ return [], error_msg
929
900
  except Exception as e:
930
- return [], f"回退解析器失败: {str(e)}"
901
+ # 其他未知错误
902
+ return [], f"解析过程发生异常: {str(e)}"
931
903
 
932
904
 
933
905
  def _ensure_pub_mod_declarations(existing_text: str, child_mods: List[str]) -> str:
@@ -1024,7 +996,7 @@ def _apply_entries_with_mods(entries: List[Any], base_path: Path) -> None:
1024
996
 
1025
997
  # 非 src 目录:
1026
998
  # 为避免覆盖现有实现,当前阶段不创建或更新 mod.rs 内容。
1027
- # 如需创建 mod.rs,应在 YAML 中显式指定为文件项;
999
+ # 如需创建 mod.rs,应在 JSON 中显式指定为文件项;
1028
1000
  # 如需补齐模块声明,将由后续的 CodeAgent 阶段根据目录结构自动补齐。
1029
1001
  return
1030
1002
 
@@ -1049,15 +1021,15 @@ def _ensure_cargo_toml(base_dir: Path, package_name: str) -> None:
1049
1021
  pass
1050
1022
 
1051
1023
 
1052
- def apply_project_structure_from_yaml(yaml_text: str, project_root: Union[Path, str] = ".") -> None:
1024
+ def apply_project_structure_from_json(json_text: str, project_root: Union[Path, str] = ".") -> None:
1053
1025
  """
1054
- 基于 Agent 返回的 <PROJECT> 中的目录结构 YAML,创建实际目录与文件(不在此阶段写入或更新任何 Rust 源文件内容)。
1055
- - project_root: 目标应用路径;当为 "."(默认)时,将使用“父目录/当前目录名_rs”作为crate根目录
1026
+ 基于 Agent 返回的 <PROJECT> 中的目录结构 JSON,创建实际目录与文件(不在此阶段写入或更新任何 Rust 源文件内容)。
1027
+ - project_root: 目标应用路径;当为 "."(默认)时,将使用"父目录/当前目录名_rs"作为crate根目录
1056
1028
  注意:模块声明(mod/pub mod)补齐将在后续的 CodeAgent 步骤中完成。按新策略不再创建或更新 workspace(构建直接在 crate 目录内进行)。
1057
1029
  """
1058
- entries, parse_error = _parse_project_yaml_entries(yaml_text)
1030
+ entries, parse_error = _parse_project_json_entries(json_text)
1059
1031
  if parse_error:
1060
- raise ValueError(f"YAML解析失败: {parse_error}")
1032
+ raise ValueError(f"JSON解析失败: {parse_error}")
1061
1033
  if not entries:
1062
1034
  # 严格模式:解析失败直接报错并退出,由上层 CLI 捕获打印错误
1063
1035
  raise ValueError("[c2rust-llm-planner] 从LLM输出解析目录结构失败。正在中止。")
@@ -1090,15 +1062,15 @@ def execute_llm_plan(
1090
1062
  non_interactive: bool = True,
1091
1063
  ) -> List[Any]:
1092
1064
  """
1093
- 返回 LLM 生成的目录结构原始 YAML 文本(来自 <PROJECT> 块)。
1065
+ 返回 LLM 生成的目录结构原始 JSON 文本(来自 <PROJECT> 块)。
1094
1066
  不进行解析,便于后续按原样应用并在需要时使用更健壮的解析器处理。
1095
1067
  """
1096
1068
  # execute_llm_plan 是顶层入口,需要执行清理(skip_cleanup=False)
1097
- # plan_crate_yaml_text 内部会根据 skip_cleanup 决定是否执行清理
1098
- yaml_text = plan_crate_yaml_text(llm_group=llm_group, skip_cleanup=False)
1099
- entries, parse_error = _parse_project_yaml_entries(yaml_text)
1069
+ # plan_crate_json_text 内部会根据 skip_cleanup 决定是否执行清理
1070
+ json_text = plan_crate_json_text(llm_group=llm_group, skip_cleanup=False)
1071
+ entries, parse_error = _parse_project_json_entries(json_text)
1100
1072
  if parse_error:
1101
- raise ValueError(f"YAML解析失败: {parse_error}")
1073
+ raise ValueError(f"JSON解析失败: {parse_error}")
1102
1074
  if not entries:
1103
1075
  raise ValueError("[c2rust-llm-planner] 从LLM输出解析目录结构失败。正在中止。")
1104
1076
 
@@ -1106,7 +1078,7 @@ def execute_llm_plan(
1106
1078
  if apply:
1107
1079
  target_root = crate_name if crate_name else "."
1108
1080
  try:
1109
- apply_project_structure_from_yaml(yaml_text, project_root=target_root)
1081
+ apply_project_structure_from_json(json_text, project_root=target_root)
1110
1082
  print("[c2rust-llm-planner] 项目结构已应用。")
1111
1083
  except Exception as e:
1112
1084
  print(f"[c2rust-llm-planner] 应用项目结构失败: {e}")
@@ -1217,7 +1189,7 @@ def execute_llm_plan(
1217
1189
  print(f"[c2rust-llm-planner] 警告: 无法验证模型配置: {e}")
1218
1190
 
1219
1191
  try:
1220
- agent = CodeAgent(need_summary=False, non_interactive=non_interactive, plan=False, model_group=llm_group)
1192
+ agent = CodeAgent(need_summary=False, non_interactive=non_interactive, model_group=llm_group)
1221
1193
  # 验证 agent 内部的模型配置
1222
1194
  if hasattr(agent, 'model') and agent.model:
1223
1195
  actual_model = getattr(agent.model, 'model_name', 'unknown')
@@ -1276,7 +1248,7 @@ def execute_llm_plan(
1276
1248
  if llm_group:
1277
1249
  print(f"[c2rust-llm-planner][iter={iter_count}] 使用模型组: {llm_group}")
1278
1250
  try:
1279
- repair_agent = CodeAgent(need_summary=False, non_interactive=non_interactive, plan=False, model_group=llm_group)
1251
+ repair_agent = CodeAgent(need_summary=False, non_interactive=non_interactive, model_group=llm_group)
1280
1252
  repair_agent.run(repair_prompt, prefix=f"[c2rust-llm-planner][iter={iter_count}]", suffix="")
1281
1253
  except Exception as e:
1282
1254
  error_msg = str(e)
@@ -1289,12 +1261,12 @@ def execute_llm_plan(
1289
1261
  # 恢复之前的工作目录
1290
1262
  os.chdir(prev_cwd)
1291
1263
 
1292
- # 3) 输出 YAML 到文件(如指定),并返回解析后的 entries
1264
+ # 3) 输出 JSON 到文件(如指定),并返回解析后的 entries
1293
1265
  if out is not None:
1294
1266
  out_path = Path(out)
1295
1267
  out_path.parent.mkdir(parents=True, exist_ok=True)
1296
1268
  # 使用原始文本写出,便于可读
1297
- out_path.write_text(yaml_text, encoding="utf-8")
1298
- print(f"[c2rust-llm-planner] YAML 已写入: {out_path}")
1269
+ out_path.write_text(json_text, encoding="utf-8")
1270
+ print(f"[c2rust-llm-planner] JSON 已写入: {out_path}")
1299
1271
 
1300
1272
  return entries