nexforge-cli 0.2.18__tar.gz → 0.3.0__tar.gz

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 (311) hide show
  1. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/PKG-INFO +8 -5
  2. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/README.md +8 -5
  3. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/config.example.toml +30 -42
  4. nexforge_cli-0.3.0/docs/decisions/2026-09-11-deepseek/346/241/243/344/275/215/347/256/200/345/214/226.md +42 -0
  5. nexforge_cli-0.3.0/docs/decisions/2026-09-11-/346/241/243/344/275/215/347/256/200/345/214/226/344/270/272/345/215/225/346/241/243flash.md +90 -0
  6. nexforge_cli-0.3.0/docs/decisions/2026-09-11-/347/273/210/347/253/257/347/212/266/346/200/201/345/205/234/345/272/225/346/201/242/345/244/215.md +91 -0
  7. nexforge_cli-0.3.0/docs/decisions/2026-09-11-/351/207/215/350/257/225/345/275/222/344/270/200/345/261/202.md +62 -0
  8. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/decisions/README.md +4 -0
  9. nexforge_cli-0.3.0/docs/evidence/exit-cost.log +9 -0
  10. nexforge_cli-0.3.0/docs/evidence/final_check_fulltest.log +7 -0
  11. nexforge_cli-0.3.0/docs/evidence/final_check_pypi.log +11 -0
  12. nexforge_cli-0.3.0/docs/evidence/final_check_report.log +22 -0
  13. nexforge_cli-0.3.0/docs/evidence/model-sidebar-dot.log +54 -0
  14. nexforge_cli-0.3.0/docs/evidence/model_rename_check.log +52 -0
  15. nexforge_cli-0.3.0/docs/evidence/provider-family-check.log +42 -0
  16. nexforge_cli-0.3.0/docs/evidence/release_0218_pypi.log +9 -0
  17. nexforge_cli-0.3.0/docs/evidence/simplify_tier_fulltest.log +7 -0
  18. nexforge_cli-0.3.0/docs/evidence/terminal-leak-conditions.log +11 -0
  19. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/01-/345/256/211/350/243/205/344/270/216/351/205/215/347/275/256.md +1 -1
  20. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/02-/347/225/214/351/235/242/344/270/216/345/277/253/346/215/267/351/224/256.md +2 -2
  21. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/03-/346/250/241/345/236/213/351/205/215/347/275/256.md +43 -24
  22. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/05-/346/225/260/346/215/256/344/270/216/346/220/234/347/264/242.md +2 -2
  23. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/07-/344/274/232/350/257/235/344/270/216/350/256/260/345/277/206.md +4 -0
  24. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/08-/350/207/252/345/256/232/344/271/211/351/205/215/347/275/256.md +1 -1
  25. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/09-/345/270/270/350/247/201/351/227/256/351/242/230.md +33 -0
  26. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/11-/345/274/200/345/217/221/346/240/241/351/252/214.md +17 -0
  27. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/README.md +1 -2
  28. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual//351/231/204/345/275/225-/345/257/271/346/257/224/345/210/206/346/236/220.md +1 -1
  29. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/pyproject.toml +1 -1
  30. nexforge_cli-0.3.0/scripts/exit_cost_probe.py +76 -0
  31. nexforge_cli-0.3.0/scripts/exit_smoke.py +113 -0
  32. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/publish.sh +41 -36
  33. nexforge_cli-0.3.0/scripts/smoke_tui.py +102 -0
  34. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/__init__.py +1 -1
  35. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/app.py +41 -1
  36. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/cli.py +29 -5
  37. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/config.py +55 -34
  38. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/agent.py +22 -6
  39. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/session_feature.py +26 -0
  40. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/i18n.py +2 -0
  41. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/provider/anthropic.py +1 -1
  42. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/provider/deepseek.py +32 -6
  43. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/provider/openai.py +7 -2
  44. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/provider/qianwen.py +7 -2
  45. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/store/session_store.py +41 -11
  46. nexforge_cli-0.3.0/src/nexforge/terminal_guard.py +281 -0
  47. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/image_tools.py +53 -27
  48. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/screens/chat.py +19 -22
  49. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/slash_handler.py +3 -3
  50. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/model_sidebar.py +87 -25
  51. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/plan_sidebar.py +2 -0
  52. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/sidebar.py +2 -0
  53. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/statusbar.py +1 -1
  54. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/web/server.py +1 -1
  55. nexforge_cli-0.3.0/tests/test_archive_integrity.py +176 -0
  56. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_config.py +113 -35
  57. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_deepseek_provider.py +4 -5
  58. nexforge_cli-0.3.0/tests/test_exit_smoke.py +121 -0
  59. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_manual_consistency.py +2 -2
  60. nexforge_cli-0.3.0/tests/test_model_sidebar_dot.py +254 -0
  61. nexforge_cli-0.3.0/tests/test_quit_paths.py +109 -0
  62. nexforge_cli-0.3.0/tests/test_retry_policy.py +180 -0
  63. nexforge_cli-0.3.0/tests/test_session_save_safety.py +146 -0
  64. nexforge_cli-0.3.0/tests/test_sidebar_align.py +39 -0
  65. nexforge_cli-0.3.0/tests/test_terminal_guard.py +326 -0
  66. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_tui.py +56 -50
  67. nexforge_cli-0.3.0/tests/test_vision_capability.py +86 -0
  68. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_vision_model.py +40 -11
  69. nexforge_cli-0.2.18/scripts/smoke_tui.py +0 -45
  70. nexforge_cli-0.2.18/src/nexforge/core/router.py +0 -62
  71. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/.gitignore +0 -0
  72. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/INSTALL.md +0 -0
  73. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/STATS_API.md +0 -0
  74. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/agent.svg +0 -0
  75. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/cost.svg +0 -0
  76. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/edit.svg +0 -0
  77. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/err.svg +0 -0
  78. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/file.svg +0 -0
  79. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/model.svg +0 -0
  80. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/ok.svg +0 -0
  81. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/read.svg +0 -0
  82. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/running.svg +0 -0
  83. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/search.svg +0 -0
  84. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/shell.svg +0 -0
  85. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/thinking.svg +0 -0
  86. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/web.svg +0 -0
  87. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/assets/icons/write.svg +0 -0
  88. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/devlog/2026-07-07.md +0 -0
  89. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/doc//344/273/243/347/240/201/344/274/230/345/214/226/350/256/241/345/210/222.md" +0 -0
  90. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/doc//347/211/271/346/200/247/346/250/241/345/235/227/346/263/250/345/206/214/345/210/266-/345/256/236/346/226/275/350/256/241/345/210/222.md" +0 -0
  91. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/doc//351/241/271/347/233/256/346/200/273/347/233/221/345/276/252/347/216/257-/345/274/200/345/217/221/350/256/241/345/210/222.md" +0 -0
  92. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/decisions/2026-09-10-fails-loud/345/210/206/347/272/247.md" +0 -0
  93. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/decisions/2026-09-10-/344/274/232/350/257/235/344/270/215/345/217/230/351/207/217.md" +0 -0
  94. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/decisions/2026-09-10-/344/276/235/350/265/226/344/270/200/350/207/264/346/200/247.md" +0 -0
  95. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/decisions/2026-09-10-/345/233/236/346/224/276/350/214/203/345/233/264/351/207/215/345/256/232/344/271/211.md" +0 -0
  96. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/decisions/2026-09-10-/345/256/241/350/256/241/344/273/245/350/260/203/347/224/250/351/223/276/344/270/272/345/207/206.md" +0 -0
  97. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/decisions/2026-09-10-/350/203/275/345/212/233/345/217/257/347/224/250/346/200/247/344/270/212/346/212/245.md" +0 -0
  98. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/decisions/2026-09-10-/350/264/250/351/207/217gate/344/275/223/347/263/273.md" +0 -0
  99. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D10_acceptance.log +0 -0
  100. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D10_full_test.log +0 -0
  101. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D11_a4.log +0 -0
  102. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D11_full_test.log +0 -0
  103. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D12_audit.md +0 -0
  104. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D12_gap.log +0 -0
  105. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D13_break.log +0 -0
  106. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D13_e2e.log +0 -0
  107. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D13_full_test.log +0 -0
  108. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D13_gaps.log +0 -0
  109. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D14_audit.md +0 -0
  110. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D14_full_test.log +0 -0
  111. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D14_recheck.log +0 -0
  112. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D15_audit.md +0 -0
  113. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D4_fast.log +0 -0
  114. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D4_full_test.log +0 -0
  115. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D4_hook.log +0 -0
  116. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D4_scene_c.log +0 -0
  117. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D4_scene_d.log +0 -0
  118. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D4_scene_e.log +0 -0
  119. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D5_audit.md +0 -0
  120. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D5_b2_plugin.log +0 -0
  121. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D5_full_test.log +0 -0
  122. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D6_b3_a.log +0 -0
  123. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D6_b3_b.log +0 -0
  124. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D6_b3_c.log +0 -0
  125. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D6_b4_provider.log +0 -0
  126. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D6_full_test.log +0 -0
  127. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D7_dedup.log +0 -0
  128. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D7_full_test.log +0 -0
  129. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D8_audit.md +0 -0
  130. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D8_invariant.log +0 -0
  131. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D9_after.log +0 -0
  132. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D9_before.log +0 -0
  133. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D9_decision.md +0 -0
  134. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D9_full_test.log +0 -0
  135. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/D9_rebuild.log +0 -0
  136. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_cap_fulltest.log +0 -0
  137. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_capabilities.log +0 -0
  138. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_engines.log +0 -0
  139. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_engines_fulltest.log +0 -0
  140. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_tts_availability.log +0 -0
  141. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_tts_fulltest.log +0 -0
  142. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_tts_installer.log +0 -0
  143. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_vision_channels.log +0 -0
  144. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/E_vision_fulltest.log +0 -0
  145. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/F_decisions_fulltest.log +0 -0
  146. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/deps_fulltest.log +0 -0
  147. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/deps_reverse.log +0 -0
  148. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/fix_fulltest.log +0 -0
  149. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/health_fulltest.log +0 -0
  150. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/health_report.md +0 -0
  151. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/health_scan.log +0 -0
  152. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/evidence/release_0218_fulltest.log +0 -0
  153. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/session-invariant.md +0 -0
  154. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/submission/README-/346/212/225/347/250/277/350/257/264/346/230/216.md" +0 -0
  155. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/submission/nexforge.md +0 -0
  156. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/docs/submission/nexforge.zh-CN.md +0 -0
  157. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/04-/345/267/245/345/205/267/345/217/202/350/200/203.md" +0 -0
  158. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/06-/346/235/203/351/231/220/344/270/216/346/250/241/345/274/217.md" +0 -0
  159. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/manual/10-/346/217/222/344/273/266/345/274/200/345/217/221.md" +0 -0
  160. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/README.md +0 -0
  161. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/guiauto/__init__.py +0 -0
  162. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/guiauto/action.py +0 -0
  163. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/guiauto/base.py +0 -0
  164. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/guiauto/tools.py +0 -0
  165. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/guiauto/vision.py +0 -0
  166. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/guiauto/window.py +0 -0
  167. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/install_plugin.py +0 -0
  168. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/requirements.txt +0 -0
  169. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/smoke_safe.py +0 -0
  170. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/verify_final.py +0 -0
  171. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/verify_host.py +0 -0
  172. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_gui_auto/verify_plugin.py +0 -0
  173. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_speech_summary/README.md +0 -0
  174. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_speech_summary/install_plugin.py +0 -0
  175. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/plugin_speech_summary/speech_summary.py +0 -0
  176. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/__init__.py +0 -0
  177. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/check.py +0 -0
  178. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/gates/__init__.py +0 -0
  179. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/gates/base.py +0 -0
  180. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/gates/hygiene.py +0 -0
  181. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/gates/manual_consistency.py +0 -0
  182. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/gates/registry_consistency.py +0 -0
  183. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/gates/version_sync.py +0 -0
  184. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/install_hooks.py +0 -0
  185. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/scripts/smoke_provider.py +0 -0
  186. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/__main__.py +0 -0
  187. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/__init__.py +0 -0
  188. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/capability.py +0 -0
  189. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/context.py +0 -0
  190. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/federation.py +0 -0
  191. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/goal_manager.py +0 -0
  192. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/jobs.py +0 -0
  193. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/knowledge_base.py +0 -0
  194. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/memory_engine.py +0 -0
  195. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/model_catalog.py +0 -0
  196. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/permissions.py +0 -0
  197. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/plugin.py +0 -0
  198. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/project_mapper.py +0 -0
  199. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/provider.py +0 -0
  200. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/session.py +0 -0
  201. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/summarizer.py +0 -0
  202. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/system_inject.py +0 -0
  203. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/tool_manifest.py +0 -0
  204. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/types.py +0 -0
  205. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/core/update_check.py +0 -0
  206. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/__init__.py +0 -0
  207. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/auto_skills.py +0 -0
  208. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/base.py +0 -0
  209. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/federation_feature.py +0 -0
  210. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/kb_feature.py +0 -0
  211. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/map_feature.py +0 -0
  212. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/memory_feature.py +0 -0
  213. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/mode_features.py +0 -0
  214. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/plan_feature.py +0 -0
  215. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/registry.py +0 -0
  216. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/slash_feature.py +0 -0
  217. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/stats_feature.py +0 -0
  218. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/features/tool_manifest_feature.py +0 -0
  219. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/icons.py +0 -0
  220. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/mcp/__init__.py +0 -0
  221. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/provider/__init__.py +0 -0
  222. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/provider/_retry.py +0 -0
  223. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/provider/balance.py +0 -0
  224. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/skills/loader.py +0 -0
  225. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/stats/__init__.py +0 -0
  226. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/stats/heartbeat.py +0 -0
  227. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/store/__init__.py +0 -0
  228. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/store/director_store.py +0 -0
  229. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/store/plan_store.py +0 -0
  230. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/theme.tcss +0 -0
  231. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/__init__.py +0 -0
  232. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/_paths.py +0 -0
  233. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/background.py +0 -0
  234. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/base.py +0 -0
  235. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/data_tools.py +0 -0
  236. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/edit_file.py +0 -0
  237. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/federation.py +0 -0
  238. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/fs_ops.py +0 -0
  239. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/git.py +0 -0
  240. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/kb_tools.py +0 -0
  241. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/list_dir.py +0 -0
  242. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/multi_edit.py +0 -0
  243. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/ops_tools.py +0 -0
  244. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/read_file.py +0 -0
  245. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/registry.py +0 -0
  246. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/screenshot_tools.py +0 -0
  247. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/search.py +0 -0
  248. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/search_content.py +0 -0
  249. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/search_files.py +0 -0
  250. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/shell.py +0 -0
  251. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/web.py +0 -0
  252. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/tools/write_file.py +0 -0
  253. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/__init__.py +0 -0
  254. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/clipboard_image.py +0 -0
  255. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/screen_api.py +0 -0
  256. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/screens/__init__.py +0 -0
  257. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/screens/chat_actions.py +0 -0
  258. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/screens/splash.py +0 -0
  259. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/__init__.py +0 -0
  260. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/apikey_modal.py +0 -0
  261. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/banner.py +0 -0
  262. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/confirm_modal.py +0 -0
  263. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/diff_modal.py +0 -0
  264. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/file_browser.py +0 -0
  265. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/file_menu.py +0 -0
  266. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/image_sidebar.py +0 -0
  267. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/messages.py +0 -0
  268. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/mode_warning.py +0 -0
  269. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/multiline_modal.py +0 -0
  270. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/ui/widgets/multiline_prompt.py +0 -0
  271. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/utils/__init__.py +0 -0
  272. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/utils/logging.py +0 -0
  273. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/web/__init__.py +0 -0
  274. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/src/nexforge/web/static/index.html +0 -0
  275. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/conftest.py +0 -0
  276. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_app_mouse.py +0 -0
  277. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_approval.py +0 -0
  278. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_capability.py +0 -0
  279. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_check_gates.py +0 -0
  280. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_cross_platform.py +0 -0
  281. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_deps.py +0 -0
  282. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_director_loop.py +0 -0
  283. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_director_store.py +0 -0
  284. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_dual_panel.py +0 -0
  285. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_federation.py +0 -0
  286. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_file_browser.py +0 -0
  287. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_goal_confirm.py +0 -0
  288. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_i18n.py +0 -0
  289. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_icons.py +0 -0
  290. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_lang_cmd.py +0 -0
  291. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_m2_tools.py +0 -0
  292. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_model_catalog.py +0 -0
  293. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_p2_core.py +0 -0
  294. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_plugin.py +0 -0
  295. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_plugin_example_tts.py +0 -0
  296. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_project_map_prune.py +0 -0
  297. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_provider_errors.py +0 -0
  298. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_sanitize.py +0 -0
  299. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_screenshot_tools.py +0 -0
  300. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_session_invariant.py +0 -0
  301. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_session_repair.py +0 -0
  302. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_session_store.py +0 -0
  303. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_sidebar.py +0 -0
  304. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_sidebar_actions.py +0 -0
  305. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_splash_modal.py +0 -0
  306. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_statusbar.py +0 -0
  307. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_system_inject.py +0 -0
  308. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_tool_iters.py +0 -0
  309. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_tools.py +0 -0
  310. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_update_check.py +0 -0
  311. {nexforge_cli-0.2.18 → nexforge_cli-0.3.0}/tests/test_vision_tool_retention.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: nexforge-cli
3
- Version: 0.2.18
3
+ Version: 0.3.0
4
4
  Summary: NexForgeCLI — 一个面向 DeepSeek V4 的终端智能体(TUI + CLI 双模式)
5
5
  Project-URL: Homepage, https://gitee.com/Lighthorn/nexforgecli
6
6
  Author: NexForge
@@ -51,11 +51,14 @@ Description-Content-Type: text/markdown
51
51
 
52
52
  NexForgeCLI 是一个运行在终端里的智能体助手,既支持 DeepSeek/千问等多模型,也是**插件宿主**(plugins 目录即插即用)。既能作为全屏 TUI 交互式对话/编码,也能作为 one-shot 命令行工具嵌进脚本和管道。
53
53
 
54
- > 当前版本:**v0.2.18** · PyPI: `pip install nexforge-cli`
54
+ > 当前版本:**v0.3.0** · PyPI: `pip install nexforge-cli`
55
55
 
56
- **v0.2.18 要点**:新增 `/capabilities`(一眼看清各能力是否可用、为何不可用);
57
- 会话可重建(恢复/切换后模型看到的历史与当初一致,工具链不再丢失);
58
- 插件与配置的静默失败治理(出错必可见);敏感文件硬拦截;push 前质量门禁。
56
+ **v0.3.0 要点**(**含破坏性变更**):档位简化为单档 `flash`——`/model pro`、`/model auto`、
57
+ `/model vision` 不再可用(`pro` 档与 `vision` 档模型均已下线;`deepseek-flash` 原生多模态,
58
+ 文本与读图一档搞定);旧配置里的档位值会自动迁移为 `flash` 并给出可见提醒。
59
+ 另含:终端状态兜底恢复 + 退出看门狗(进程被硬中断时不再留下被鼠标序列刷屏的终端)、
60
+ 模型侧边栏绿点恒为一个(只标当前在用的模型)、历史归档不再静默丢批次、
61
+ 两层重试放大修复(429 时由最多 12 次请求降为 `1 + max_retries` 次)。
59
62
 
60
63
  ---
61
64
 
@@ -8,11 +8,14 @@
8
8
 
9
9
  NexForgeCLI 是一个运行在终端里的智能体助手,既支持 DeepSeek/千问等多模型,也是**插件宿主**(plugins 目录即插即用)。既能作为全屏 TUI 交互式对话/编码,也能作为 one-shot 命令行工具嵌进脚本和管道。
10
10
 
11
- > 当前版本:**v0.2.18** · PyPI: `pip install nexforge-cli`
12
-
13
- **v0.2.18 要点**:新增 `/capabilities`(一眼看清各能力是否可用、为何不可用);
14
- 会话可重建(恢复/切换后模型看到的历史与当初一致,工具链不再丢失);
15
- 插件与配置的静默失败治理(出错必可见);敏感文件硬拦截;push 前质量门禁。
11
+ > 当前版本:**v0.3.0** · PyPI: `pip install nexforge-cli`
12
+
13
+ **v0.3.0 要点**(**含破坏性变更**):档位简化为单档 `flash`——`/model pro`、`/model auto`、
14
+ `/model vision` 不再可用(`pro` 档与 `vision` 档模型均已下线;`deepseek-flash` 原生多模态,
15
+ 文本与读图一档搞定);旧配置里的档位值会自动迁移为 `flash` 并给出可见提醒。
16
+ 另含:终端状态兜底恢复 + 退出看门狗(进程被硬中断时不再留下被鼠标序列刷屏的终端)、
17
+ 模型侧边栏绿点恒为一个(只标当前在用的模型)、历史归档不再静默丢批次、
18
+ 两层重试放大修复(429 时由最多 12 次请求降为 `1 + max_retries` 次)。
16
19
 
17
20
  ---
18
21
 
@@ -1,42 +1,30 @@
1
- # NexForgeCLI 配置示例。
2
- # 复制到 ~/.nexforge/config.toml 后按需修改;所有字段都有内置默认值,可只写要覆盖的项。
3
- # DeepSeek V4 参数已核实自 api-docs.deepseek.com(2026-04)。
4
-
5
- [provider]
6
- base_url = "https://api.deepseek.com" # OpenAI 格式;Anthropic 格式加 /anthropic
7
- api_key_env = "DEEPSEEK_API_KEY" # 优先从此环境变量读 key
8
- # api_key = "sk-..." # 次选:直接写这里(不建议入库)
9
- timeout = 120.0
10
- max_retries = 2
11
-
12
- [models]
13
- flash = "deepseek-v4-flash"
14
- pro = "deepseek-v4-pro"
15
- default_tier = "auto" # flash | pro | auto
16
- thinking = true # 思考模式,默认开
17
- reasoning_effort = "high" # high | max
18
- max_output_tokens = 8192 # 上限 384K
19
-
20
- # 定价(每百万 token,USD)—— 已核实
21
- [models.pricing.flash]
22
- input_cache_hit = 0.0028
23
- input_cache_miss = 0.14
24
- output = 0.28
25
-
26
- [models.pricing.pro]
27
- input_cache_hit = 0.003625
28
- input_cache_miss = 0.435
29
- output = 0.87
30
-
31
- [router] # auto 档位的客户端路由
32
- entry = "flash" # auto 默认从 flash 起步
33
- escalate_to = "pro"
34
- escalate_on_tool_failures = 2
35
- escalate_context_tokens = 200000
36
-
37
- [ui]
38
- theme = "dark" # dark | light
39
- show_thinking = true
40
- icons = "auto" # auto | image | glyph | ascii
41
- accent = "#6D5EF5"
42
- accent2 = "#22D3EE"
1
+ # NexForgeCLI 配置示例。
2
+ # 复制到 ~/.nexforge/config.toml 后按需修改;所有字段都有内置默认值,可只写要覆盖的项。
3
+ # DeepSeek V4 参数已核实自 api-docs.deepseek.com(2026-04)。
4
+
5
+ [provider]
6
+ base_url = "https://api.deepseek.com" # OpenAI 格式;Anthropic 格式加 /anthropic
7
+ api_key_env = "DEEPSEEK_API_KEY" # 优先从此环境变量读 key
8
+ # api_key = "sk-..." # 次选:直接写这里(不建议入库)
9
+ timeout = 120.0
10
+ max_retries = 2
11
+
12
+ [models]
13
+ flash = "deepseek-flash" # 原生多模态(文本+读图), 取代原 v4-flash + vision 双档位
14
+ default_tier = "flash" # 档位只剩 flash(pro/auto/vision 均已移除)
15
+ thinking = true # 思考模式,默认开
16
+ reasoning_effort = "high" # high | max
17
+ max_output_tokens = 8192 # 上限 384K
18
+
19
+ # 定价(每百万 token,USD)—— 已核实
20
+ [models.pricing.flash]
21
+ input_cache_hit = 0.0028
22
+ input_cache_miss = 0.14
23
+ output = 0.28
24
+
25
+ [ui]
26
+ theme = "dark" # dark | light
27
+ show_thinking = true
28
+ icons = "auto" # auto | image | glyph | ascii
29
+ accent = "#6D5EF5"
30
+ accent2 = "#22D3EE"
@@ -0,0 +1,42 @@
1
+ # 决策:DeepSeek 档位简化为 flash / vision(移除 pro 与 auto)
2
+
3
+ > 日期:2026-09-11 · 状态:生效 · **破坏性变更**
4
+
5
+ ## 背景
6
+
7
+ DeepSeek 调整模型阵容后,`pro` 档基本无用;而 `auto` 档的唯一作用是"命中升级信号时自动升到 pro"。
8
+ 用户要求简化 DS 的模型列表("只保留 flash,包括 pro 在内全部删掉")。
9
+
10
+ 同期实测(`docs/evidence/model_rename_check.log`):官方 `GET /models` 只剩 `deepseek-flash` 与 `deepseek-v4-pro`。
11
+
12
+ ## 决策
13
+
14
+ 1. `Tier` 从 `flash / pro / auto / vision` 简化为 **`flash / vision`**。
15
+ 2. 删 `ModelsConfig.pro` 与其计价项。
16
+ 3. **删除 `RouterConfig` 与整个 `core/router.py`**(`Router` 类)——
17
+ `agent.py` 改为直接按用户选定档位构造 `RouteDecision`。
18
+ 4. `vision` **保留**:识图与贴图直达模型的必需档位。
19
+
20
+ ## 理由
21
+
22
+ - **pro 已无用**(用户判断 + 实测支持),保留只会增加配置面与认知负担。
23
+ - **auto 是死逻辑**:它存在的意义是"升级到 pro",没有 pro 就无从升级。
24
+ - **否决"保留 auto 但降级为 flash"**:那等于给一个不存在的选择留按钮,纯误导。
25
+ - **否决"保留 pro 但改指向别的模型"**:用户诉求就是删掉它。
26
+
27
+ ## 代价与边界
28
+
29
+ - **破坏性**:`/model pro` 与 `/model auto` 不再可用(会提示未知档位);
30
+ 配置文件里残留的 `[router]` 段与 `models.pro` 将被"未知字段"检查提示(见 B 工程)。
31
+ 已写入的 `models.default_tier = "pro"/"auto"` 会自动迁移为 `flash` 并告警(见下一条 ADR)。
32
+ - **恢复成本**:若 DeepSeek 未来重启 pro/推理档,需要重新加档位 + 计价,
33
+ 并视情况恢复路由机制。
34
+ (数据载体 `RouteDecision` 仍在,但已内联到 `core/agent.py` 并退化为"固定档位"记录;
35
+ `Router` 与 `core/router.py` 已随单档化删除 —— 恢复路由需重写,不是改开关。)
36
+ - `reasoning_effort` / `thinking` 仍由 `[models]` 控制,效果不变——**只是不再自动切换**。
37
+
38
+ ## 关联
39
+
40
+ `src/nexforge/config.py`、`src/nexforge/core/agent.py`(`router.py` 已删)、
41
+ `ui/widgets/model_sidebar.py`、`ui/widgets/statusbar.py`、`ui/slash_handler.py`、`cli.py`、`web/server.py`、
42
+ `manual/02`、`manual/03`、`manual/08`、`config.example.toml`
@@ -0,0 +1,90 @@
1
+ # ADR: 档位简化为单档 flash
2
+
3
+ - 日期: 2026-09-11
4
+ - 状态: 已采纳
5
+ - 类型: **破坏性变更**
6
+
7
+ ## 背景
8
+
9
+ DeepSeek 于 2026-09 调整模型阵容:
10
+
11
+ 1. `deepseek-v4-pro` 处于更新前的尴尬期,实际可用性差 → 此前(2026-09)已删除 `pro` 与 `auto` 档位。
12
+ 2. 当时保留 `vision` 档位(模型 `deepseek-v4-flash-vision-exp`)用于识图。
13
+ 3. 现在官方新模型 **`deepseek-flash`** 已**原生多模态**(实测可准确读图),而原 flash 档位模型 `deepseek-v4-flash` **不支持读图**。
14
+
15
+ 实测证据(`docs/evidence/model_rename_check.log`):
16
+
17
+ | 模型 | 文本 | 读图 |
18
+ |---|---|---|
19
+ | `deepseek-v4-flash-vision-exp` | OK | 蓝圆 + 红三角 |
20
+ | `deepseek-flash` | OK | 蓝圆、红 |
21
+ | `deepseek-v4-flash` | OK | 空(不支持) |
22
+
23
+ ## 决策
24
+
25
+ **档位从 `flash / vision` 简化为单一 `flash`**,且 `flash` 档位模型由 `deepseek-v4-flash` 改为 `deepseek-flash`。
26
+
27
+ 具体改动:
28
+
29
+ 1. `Tier = Literal["flash"]`;删除 `ModelsConfig.vision` 与 `pricing.vision`。
30
+ 2. `models.flash` 默认值 → `deepseek-flash`(原生多模态)。
31
+ 3. 删除 F6 侧边栏的档位子按钮渲染与 `ms-tier-*` 分支(只剩单档,子选项失去意义)。
32
+ 4. 识图能力探测(`VisionCapability`)与 `_provider_vision_channel` 不再回退 `cfg.models.vision`,改为当前档位模型。
33
+ 5. CLI / 斜杠命令 / web 的档位白名单只保留 `flash`。
34
+
35
+ ## 理由
36
+
37
+ - **避免静默失败**(核心):若只删 vision 档位而不改 flash 模型名,用户切到 flash 后贴图会因 `deepseek-v4-flash` 不支持读图而**静默失败**——正是本项目持续根治的病(见 ADR-2026-09-10-fails-loud分级)。
38
+ - **消除冗余**:`deepseek-flash` 一档同时覆盖文本与读图,独立视觉档位不再必要。
39
+ - **代价可控**:旧档位名(`pro`/`vision`)写错会被明确拒绝,而非静默降级到错误模型。
40
+
41
+ ## 复盘:改名漏改一处判定,贴图静默退化(2026-09-11 第五轮复核)
42
+
43
+ **症状**:默认档位下贴图只发出 `[图片附件: 路径]` **文本占位符**,模型根本看不到图;
44
+ 识图工具通道报"模型 deepseek-flash 不支持图片输入"(与实测相反);而 `/capabilities`
45
+ **又报"可用"** —— 三者互相矛盾。
46
+
47
+ **根因**:多模态判定只有两条规则 —— ①模型名含 `"vision"`;②`models.toml` 里该
48
+ provider 显式 `multimodal = true`。而内置 deepseek **没有 pdef**(不在 `providers` 表里),
49
+ 新档位模型 `deepseek-flash` 名字里**也没有 "vision"**(旧档位模型
50
+ `deepseek-v4-flash-vision-exp` 靠名字就能过)→ 判定为纯文本。
51
+ `/capabilities` 之所以说"可用",是因为它的判据里有个 `or cfg.model_id()`,而
52
+ `model_id()` 恒非空 —— 于是"上报与实际"分叉。
53
+
54
+ **修法**:
55
+ 1. `provider/deepseek.py` 增加显式名单 `NATIVE_MULTIMODAL_MODELS = {"deepseek-flash"}`
56
+ (与既有 `"vision"` 名字规则并列);
57
+ 2. 抽出 `image_tools.vision_channel(cfg)` 作为**唯一**判定,供贴图通道、识图工具
58
+ 与 `VisionCapability` 三处共用(消除"上报说可用、实际跑不通")。
59
+
60
+ **为什么不用"配置开关"代替名单**:若让 `models.flash` 一律视为多模态,用户把它改成
61
+ 纯文本模型(如 `deepseek-v4-flash`)时会被错误放行 → 又把图片发给看不懂的模型。
62
+ 名单式规则与既有 `"vision"` 规则同构,代价小。
63
+
64
+ **维护纪律**:**DeepSeek 再次改名时,`NATIVE_MULTIMODAL_MODELS` 必须与本文同步更新。**
65
+ 这也解释了为什么"档位模型名"不是一个纯配置项 —— 它同时是多模态判定的输入。
66
+
67
+ ## 代价与边界
68
+
69
+ - **破坏性**:`/model pro`、`/model auto`、`/model vision` 不再可用。
70
+ - 用户 `config.toml` 若残留 `models.vision` 或 `[models.pricing.vision]`,启动时会有"未知字段"提示(这是 B 工程配置校验在提醒),删掉即可。
71
+ - **升级残留的档位值会自动迁移**(2026-09-11 三轮复核补充):旧版本的 `/model pro`
72
+ 会把 `default_tier = "pro"` **写进 config.toml**(`slash_handler` 的持久化),
73
+ 若不处理,升级后会在校验阶段直接中止启动(exit 2)——用户被挡在门外、只能手改 TOML。
74
+ 现按既有 `mode: review → supervised` 的迁移先例处理:`pro`/`auto`/`vision` 三个**已知被移除**
75
+ 的档位名 → 自动改为 `flash` 并**发出可见告警**;真正的拼写错误(如 `flsh`)仍照常报错中止。
76
+ 实现在 `config.py:_migrate_removed_tier()`(用户级与项目级两条路径都覆盖)。
77
+ - `supports_model_multimodal` 仍保留 `"vision" in 模型名` 判定——用于**兼容外部显式传入的 vision 系模型名**(如用户自挂的 exp 模型),不属档位概念。
78
+
79
+ ## 备选方案(未采纳)
80
+
81
+ | 方案 | 未采纳原因 |
82
+ |---|---|
83
+ | 保留 vision 档位,仅改 flash 模型名 | 两档模型实际相同(都是多模态),用户需无谓切换 |
84
+ | flash 仍用 `deepseek-v4-flash` | 该模型不支持读图,会引入静默失败 |
85
+ | 用 `deepseek-v4-flash-vision-exp` 作 flash | exp 为实验版、名字带过期语义,非长期选择 |
86
+
87
+ ## 相关
88
+
89
+ - ADR-2026-09-11-deepseek档位简化(本轮,pro/auto 删除)
90
+ - ADR-2026-09-10-能力可用性上报(vision 能力探测同源)
@@ -0,0 +1,91 @@
1
+ # 决策:终端状态兜底恢复 + 退出看门狗
2
+
3
+ > 日期:2026-09-11 · 状态:生效
4
+
5
+ ## 背景
6
+
7
+ **现象**:nf TUI 非正常结束后,命令行被持续刷屏——移动鼠标就喷出 `[555;x;yM`
8
+ 之类的原始转义序列,终端看起来"坏掉了"。
9
+
10
+ **已查证的事实**(源码级 + 本机实测):
11
+
12
+ 1. 那串字符是**鼠标追踪的 SGR 上报**(`ESC[<b;x;yM`)。终端一旦停在"鼠标追踪开启"
13
+ 状态,鼠标一动就会把上报序列当普通字符打进命令行。
14
+ 2. Textual 只在**正常退出 / 被捕获的异常**路径恢复终端
15
+ (`textual/app.py:3495-3514` 的 `finally: driver.stop_application_mode()`)。
16
+ 3. **硬杀无人收尾**:Windows `CTRL_BREAK_EVENT` → Python `SIGBREAK` 默认动作是直接
17
+ 终止进程;`taskkill /F`、直接关闭控制台窗口同理。Textual 在 Windows 下
18
+ **不安装任何信号处理器**(只给 Linux 驱动装了 SIGTSTP/SIGCONT/SIGWINCH)。
19
+ 4. 本机 `WT_SESSION` 存在(Windows Terminal)→ `_mouse_enabled()` 为 True
20
+ → 鼠标追踪**确实处于开启状态**,泄漏条件成立
21
+ (`docs/evidence/terminal-leak-conditions.log`)。
22
+
23
+ **直接触发**:一次复现脚本用 `CTRL_BREAK_EVENT` 结束子进程,却没有建独立进程组 ——
24
+ Windows 控制台事件是**按进程组**投递的,于是这次 CTRL_BREAK 同时打中了宿主 TUI 自己,
25
+ TUI 被硬杀,终端留在鼠标追踪模式。
26
+
27
+ **被实测否掉的假设**(不是推测,每条都有数据):
28
+
29
+ | 假设 | 实测结论 | 证据 |
30
+ |---|---|---|
31
+ | 余额轮询卡在网络 → 退出卡住 | **否**:挂起定时器(可取消 / 不可取消)与基线**同量级**(0.6~1.5s,随负载浮动;关键是相对结论) | `docs/evidence/exit-cost.log` |
32
+ | `Timer._stop_all` 会等待定时器回调 | 会 `await timer._task`,但 `cancel()` 立即打断 await(线程在后台继续) | `scripts/exit_cost_probe.py` |
33
+ | `Ctrl+Q`(App 级 priority 绑定)绕过清理 | **否**:`on_unmount` 兜底已覆盖该路径 | 两条退出路径的清理钩子均被调用 |
34
+ | 正常退出会漏清理 | **否**:作业/会话/隧道清理都执行了 | 同上 |
35
+
36
+ 结论:**不存在"退出卡住"缺陷**;真实缺口是"非 Python 异常路径缺少终端兜底恢复"。
37
+
38
+ ## 决策
39
+
40
+ 新增 `src/nexforge/terminal_guard.py`,提供三层保护:
41
+
42
+ 1. `restore_terminal()`:幂等写入"关鼠标(4 种模式)/ 关括号粘贴 / 关 kitty 键盘协议 /
43
+ 退备用屏 / 显示光标 / 复位 SGR",与 Textual 的 `stop_application_mode()` 对齐;
44
+ 非 TTY 默认不写,`force=True` 无条件写,且**绝不抛异常**。
45
+ 2. `install_signal_guard()`:Windows 下接管 `SIGBREAK`,恢复终端后再退出
46
+ (这正是本次事故缺的那一环)。
47
+ 3. **退出看门狗**:`run_tui` 运行期开启闸门;出现退出请求(`App.exit()`)即开始计时,
48
+ 超时(默认 8s,`NEXFORGE_EXIT_TIMEOUT` 可调)则恢复终端并 `os._exit(0)` ——
49
+ 把"卡退"从"用户只能强杀、终端报废"降级为"最多等 8 秒、终端自动恢复"。
50
+ 4. **能力缺失不静默**:`SIGBREAK` 接管失败时向 stderr 显式告警(含逃生舱指引),
51
+ 不允许"用户以为有保护、实际没有" —— 直接适用
52
+ `ADR-2026-09-10-fails-loud分级` 第 4 条。
53
+
54
+ `run_tui` 另加:崩溃路径 `force` 恢复后**继续抛出原异常**(不吞错);返回路径兜底恢复一次。
55
+
56
+ ## 理由
57
+
58
+ - 只靠 Textual 的 `finally` 覆盖不到硬杀,而用户遇到的正是硬杀后的坏终端。
59
+ - 三层里任一层单独都不够:看门狗管"退不掉",信号兜底管"被打断",
60
+ 返回路径兜底管"异常/正常都补一刀"。
61
+ - 全部标准库实现,非 Windows 平台自动降级为空操作。
62
+
63
+ ## 代价与边界
64
+
65
+ - **闸门是必须的**:无头测试 / 嵌入式调用 / 探针脚本都不走 `run_tui`,若 `App.exit()`
66
+ 无条件武装看门狗,就没人取消它 → 8 秒后 `os._exit()` 会把该进程直接带走。
67
+ 这个坑是**真踩到的**:`scripts/exit_cost_probe.py` 曾在打印结论前被截断。
68
+ 现在闸门关闭时 `arm_exit_watchdog()` 完全不动进程(有回归测试锁定)。
69
+ - **不可恢复场景**:`taskkill /F`(TerminateProcess)无法在进程内做任何事,
70
+ 只能靠终端自身;逃生舱为 `NEXFORGE_MOUSE=0`(跨平台强制关闭鼠标追踪)。
71
+ - 看门狗兜底 8 秒是宽限值;正常退出实测 0.6~1.5s(随机器负载浮动),留着充足余量。
72
+ - 兜底序列与 Textual 自身的恢复序列一致;在**未开启 VT 处理**的老式 conhost 上
73
+ 它们可能显示为可见字符(与 Textual 行为同源)。不过那种终端本来就不会启用鼠标
74
+ 追踪(`_mouse_enabled()` 已按此判定),所以实际影响可忽略。
75
+
76
+ ## 纪律(写给后续)
77
+
78
+ > **在 Windows 上向其他进程发控制台事件(CTRL_C / CTRL_BREAK)之前,必须
79
+ > `CREATE_NEW_PROCESS_GROUP`;若要独立控制台再加 `CREATE_NEW_CONSOLE`。
80
+ > 否则事件按进程组投递,会打中调用者自己。**
81
+
82
+ `scripts/exit_smoke.py` 里对这两个标志做了断言式自检,作为可执行的纪律。
83
+
84
+ ## 相关
85
+
86
+ - `src/nexforge/terminal_guard.py`、`src/nexforge/app.py`(`run_tui` / `NexForgeApp.exit`)
87
+ - ADR-2026-09-10-fails-loud分级(本模块的静默/可见边界按其裁定)
88
+ - `tests/test_terminal_guard.py`(19 项:恢复序列 / 看门狗 / 闸门 / 信号 / 可见降级 / run_tui 集成)
89
+ - `scripts/exit_cost_probe.py`(退出耗时对照探针)、`scripts/exit_smoke.py`(真实进程退出冒烟)
90
+ - 证据:`docs/evidence/exit-cost.log`、`docs/evidence/terminal-leak-conditions.log`
91
+ - 既有相关修复:`ad1fac6`(conhost 禁用鼠标追踪)、`25304a4`(VS Code 终端保留鼠标)
@@ -0,0 +1,62 @@
1
+ # 决策:重试只归一层(包装器负责,SDK 归零)
2
+
3
+ > 日期:2026-09-11 · 状态:生效
4
+
5
+ ## 背景
6
+
7
+ `provider/_retry.py` 的 `retry_on_rate_limit()` 包住 `chat.completions.create`,
8
+ 同时 openai SDK 客户端构造时也配了 `max_retries`(来自 `config.provider.max_retries`,
9
+ 默认 2)。两层各自重试,于是**放大**:
10
+
11
+ 用 `httpx.MockTransport` 实测(持续 429,退避打桩为瞬时):
12
+
13
+ | 层 | 次数 |
14
+ |---|---|
15
+ | 包装器 `retry_on_rate_limit`(调用点未传参 → 默认 3) | 4 次调用 |
16
+ | 每次调用内 SDK 自己重试(`max_retries=2`) | 3 次尝试 |
17
+ | **合计 HTTP 请求** | **12** |
18
+
19
+ 副作用:
20
+ 1. **配额与限流**:一次用户提问在 429 下打出 12 次请求 —— 既浪费,也可能加重限流;
21
+ 2. **配置失真**:`provider.max_retries` 只影响 SDK 层,对包装器**无效**,
22
+ 用户调它看不到预期效果;
23
+ 3. **最坏等待**:若每次都耗到 `timeout`(120s),上限是 12×120s(远超合理范围)。
24
+
25
+ ## 决策
26
+
27
+ **重试只保留一层,且以我们的包装器为准**:
28
+
29
+ 1. 包装器内用 `self._client.with_options(max_retries=0)` 调 SDK,
30
+ **关掉 SDK 的内层重试**;
31
+ 2. 包装器显式接收 `pdef.max_retries or config.provider.max_retries` ——
32
+ 配置项成为唯一权威;
33
+ 3. 三个走包装器的 provider(deepseek / openai / qianwen)一致处理。
34
+ (anthropic 不走该包装器,仍由自身 SDK 重试,不在本次范围。)
35
+
36
+ 修后实测:**3 次请求**(= 1 + `max_retries`),配置改动可观察。
37
+
38
+ ## 理由
39
+
40
+ - **单一职责**:重试是策略,属于我们可观测、可配置、可测试的那一层;
41
+ 两层叠加等价于"把重试次数相乘",而没人会期望这个乘法。
42
+ - **可测**:MockTransport 计数让"到底打了几次 API"变成可断言的事实,
43
+ 而不是靠读代码推断(本决策的证据即由此而来)。
44
+ - **否决"保留两层、只把配置传下去"**:那只是让乘法变得可配置,放大依旧。
45
+ - **否决"关掉包装器、只信 SDK"**:包装器提供了显式的 429/5xx 集合与
46
+ 统一的错误包装(`ProviderError` 便于上层显示),且我们能在其中加观测。
47
+
48
+ ## 代价与边界
49
+
50
+ - SDK 层原生的 `Retry-After` 处理随之失效 —— 退避改由包装器的
51
+ 指数退避 + 抖动(上限 15s)承担。若将来需要尊重 `Retry-After`,
52
+ 应加在包装器里(并在测试中覆盖)。
53
+ - 非流式调用(`models.list` 等)不走包装器,仍用 SDK 重试 —— 这属于
54
+ "另一条路径",本次未动;若要统一,需把这些调用也纳入包装器。
55
+ - 退避等待用 `await asyncio.sleep`(**可取消**),因此"停止/退出"不会被
56
+ 退避拖住 —— 与 `terminal_guard` 的退出兜底同源关切。
57
+
58
+ ## 验证
59
+
60
+ - `tests/test_retry_policy.py`(12 项):可重试/不可重试状态码、
61
+ `1 + max_retries` 次数、配置权威性、**两层不放大**(实测计数)、退避可取消。
62
+ - 复盘脚本证据:12 次 → 3 次。
@@ -61,3 +61,7 @@
61
61
  | 2026-09-10 | [能力可用性上报](2026-09-10-能力可用性上报.md) | 生效 |
62
62
  | 2026-09-10 | [审计以调用链为准](2026-09-10-审计以调用链为准.md) | 生效 |
63
63
  | 2026-09-10 | [依赖一致性](2026-09-10-依赖一致性.md) | 生效 |
64
+ | 2026-09-11 | [DeepSeek 档位简化(删除 pro/auto)](2026-09-11-deepseek档位简化.md) | 已取代 → 见下行 |
65
+ | 2026-09-11 | [档位简化为单档 flash](2026-09-11-档位简化为单档flash.md) | 生效 · 破坏性 |
66
+ | 2026-09-11 | [终端状态兜底恢复 + 退出看门狗](2026-09-11-终端状态兜底恢复.md) | 生效 |
67
+ | 2026-09-11 | [重试只归一层](2026-09-11-重试归一层.md) | 生效 |
@@ -0,0 +1,9 @@
1
+ === TUI exit cost probe (headless) ===
2
+ [A baseline] quit->shutdown = 1.32s
3
+ [B cancellable hang] quit->shutdown = 1.49s
4
+ [C blocking call] quit->shutdown = 1.06s
5
+
6
+ A baseline : 1.32s
7
+ B cancellable hang: 1.49s (delay +0.17s)
8
+ C blocking call : 1.06s (delay -0.26s)
9
+ >>> 无拖慢: 退出耗时与是否挂起无关
@@ -0,0 +1,7 @@
1
+ ........................................................................ [ 16%]
2
+ ................sss..................................................... [ 33%]
3
+ ........................................................................ [ 50%]
4
+ ........................................................................ [ 66%]
5
+ ........................................................................ [ 83%]
6
+ ...................................................................... [100%]
7
+ 427 passed, 3 skipped in 107.39s (0:01:47)
@@ -0,0 +1,11 @@
1
+ === 发布产物可用性验证 ===
2
+ === 11) 从 PyPI 真实安装 nexforge-cli==0.2.18 ===
3
+ pip 退出码: 0
4
+ 安装顶层条目: ['bin', 'nexforge', 'nexforge_cli-0.2.18.dist-info']
5
+ nexforge.__version__ = 0.2.18
6
+ === 12) 本版新增模块可用性 ===
7
+ capability OK
8
+ engines: ['bing', 'duckduckgo', 'google', 'searxng']
9
+ config-issue API OK
10
+ (临时安装目录已清理)
11
+ exit=0
@@ -0,0 +1,22 @@
1
+ === 发布后全量检查 ===
2
+ === 7) 静默捕获扫描(AST) ===
3
+ 裸 except: pass = 94 处 (体检时为 101 处)
4
+ 注: 经体检分类, 其中绝大多数为合理防御(清理/关闭/探测/UI 元素查找)
5
+
6
+ === 8) 文档索引完整性 ===
7
+ ADR 文件数: 7
8
+ 索引失效链接: 无
9
+ 未登记 ADR: 无
10
+
11
+ === 9) 其他文档 ===
12
+ OK docs/session-invariant.md
13
+ OK manual/11-开发校验.md
14
+ OK plugin_speech_summary/README.md
15
+
16
+ === 10) 发布产物抽检(whl) ===
17
+ 文件数: 128
18
+ OK nexforge/core/capability.py
19
+ OK nexforge/tools/search.py
20
+ OK nexforge/store/session_store.py
21
+ 插件示例是否误入包: False (应为 False)
22
+ exit=0
@@ -0,0 +1,54 @@
1
+ ============================================================
2
+ 真实配置 / 激活 deepseek [激活 provider = deepseek]
3
+ ============================================================
4
+ | deepseek |
5
+ | ● deepseek-flash | <-- 绿点
6
+ | kimi ⚪ |
7
+ | 🔍 验证 |
8
+ | kimi-k3 |
9
+ | 🔄 刷新模型 |
10
+ | local ⚪ |
11
+ | 🔍 验证 |
12
+ | D:\LocalModels\models\qwen2.5-14b-instruct-q4_k_m.gguf |
13
+ | 🔄 刷新模型 |
14
+ | 验证全部 |
15
+ 合计绿点 = 1
16
+
17
+ ============================================================
18
+ 真实配置 / 激活 kimi [激活 provider = kimi]
19
+ ============================================================
20
+ | deepseek |
21
+ | deepseek-flash |
22
+ | kimi ⚪ |
23
+ | 🔍 验证 |
24
+ | ● kimi-k3 | <-- 绿点
25
+ | 🔄 刷新模型 |
26
+ | local ⚪ |
27
+ | 🔍 验证 |
28
+ | D:\LocalModels\models\qwen2.5-14b-instruct-q4_k_m.gguf |
29
+ | 🔄 刷新模型 |
30
+ | 验证全部 |
31
+ 合计绿点 = 1
32
+
33
+ ============================================================
34
+ 合成配置 / 激活 anthropic 类 provider [激活 provider = claude]
35
+ ============================================================
36
+ | deepseek |
37
+ | deepseek-flash |
38
+ | claude ⚪ |
39
+ | 🔍 验证 |
40
+ | ● claude-sonnet-4 | <-- 绿点
41
+ | 验证全部 |
42
+ 合计绿点 = 1
43
+
44
+ ============================================================
45
+ 合成配置 / deepseek 激活, anthropic 未激活 [激活 provider = deepseek]
46
+ ============================================================
47
+ | deepseek |
48
+ | ● deepseek-flash | <-- 绿点
49
+ | claude ⚪ |
50
+ | 🔍 验证 |
51
+ | claude-sonnet-4 |
52
+ | 验证全部 |
53
+ 合计绿点 = 1
54
+
@@ -0,0 +1,52 @@
1
+ === DeepSeek 模型名实测 ===
2
+ === DeepSeek 模型名可用性实测 ===
3
+ [不可用] deepseek-v4.1-flash HTTP 400: The supported API model names are deepseek-flash, deepseek-v4-pro, but you passed deepseek-v4.1-flas
4
+ [可用] deepseek-v4.1-flash-expires-on-0910 -> 回复: ''
5
+ exit=0
6
+ === DeepSeek 模型名全面探测 ===
7
+ === 1) GET /models (官方可用模型列表, 最权威) ===
8
+ HTTP 200
9
+ - deepseek-flash
10
+ - deepseek-v4-pro
11
+
12
+ === 2) 逐个 chat 实测(max_tokens=64 避免空回复) ===
13
+ [200] deepseek-flash content='好的' finish=stop
14
+ [200] deepseek-v4-pro content='好的' finish=stop
15
+ [400] deepseek-v4.1-flash The supported API model names are deepseek-flash, deepseek-v4-pro, but you passed deepseek
16
+ [200] deepseek-v4.1-flash-expires-on-0910 content='好的' finish=stop
17
+ [200] deepseek-v4-flash content='好的' finish=stop
18
+ exit=0
19
+
20
+ === deepseek-flash 能力验证 ===
21
+ === 1) 文本能力 ===
22
+ HTTP 200 content=''
23
+
24
+ === 2) 读图能力(贴 base64 图片, 问它看到什么) ===
25
+ HTTP 200
26
+ 回答: '这张图是纯色背景,'
27
+ => 支持读图: True
28
+ exit=0
29
+
30
+ === 改名后端到端验证 ===
31
+ Traceback (most recent call last):
32
+ File "D:\DevelopProject\NexForge\NexForgeCLI\.nexforge\_v41_e2e.py", line 11, in <module>
33
+ from nexforge.core.provider import ChunkKind # noqa: E402
34
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35
+ ImportError: cannot import name 'ChunkKind' from 'nexforge.core.provider' (D:\DevelopProject\NexForge\NexForgeCLI\src\nexforge\core\provider.py)
36
+ exit=1
37
+
38
+ === 改名后端到端验证 ===
39
+ === 1) 配置加载 ===
40
+ provider name = deepseek-v41
41
+ models = ['deepseek-flash']
42
+ default_model = deepseek-flash
43
+ multimodal = True
44
+
45
+ === 2) provider 实例化 ===
46
+ 类型 = DeepSeekProvider
47
+ 支持读图 = True
48
+
49
+ === 3) 真实调用 ===
50
+ 回复 = '就绪'
51
+ => 端到端可用: True
52
+ exit=0
@@ -0,0 +1,42 @@
1
+ # 非默认 provider 验证(2026-09-11 专项)
2
+
3
+ > 目的: 补上"未覆盖角落——非默认 provider"。用本机真实的 `~/.nexforge/models.toml`
4
+ > 配置(kimi → 腾讯 MaaS 网关), 走 **OpenAI 兼容 provider** 的真实链路。
5
+ > 密钥已遮蔽, 不入库。
6
+
7
+ ## 1. 真实对话(走 openai.py 的流式路径)
8
+
9
+ ```
10
+ $ python -m nexforge --provider kimi --no-think -p '只回复四个字:你好世界'
11
+ 你好世界
12
+ — tokens: 6873+63 · ~$0.0010
13
+ rc=0
14
+ ```
15
+
16
+ 验证点:
17
+ - `create_provider(config)` 对非默认 provider(kimi) 正确构造;
18
+ - **OpenAI 兼容流式路径可用** —— 且这正是本轮刚改过的地方
19
+ (`with_options(max_retries=0)` 消除两层重试放大), 无回归;
20
+ - 非 deepseek provider 的**计价路径**可用(打印出 ~$0.0010)。
21
+
22
+ ## 2. 动态模型列表(F6「刷新模型」走的就是它)
23
+
24
+ ```
25
+ provider: kimi | base_url: https://tokenhub.tencentmaas.com/v1
26
+ 耗时 2.08s, 拉到 125 个模型
27
+ - hy4-preview / hy3 / glm-5.3-flash / glm-5.3
28
+ - deepseek/deepseek-flash / deepseek-v4-flash-vision-exp / deepseek-v4-pro-0813 ...
29
+ ```
30
+
31
+ 验证点: `fetch_models()` 对非默认 provider 可用; 网关确实暴露了
32
+ `deepseek/deepseek-flash` 等名字(与本项目档位改名一致)。
33
+
34
+ ## 3. 未能验证的部分(如实记录)
35
+
36
+ | 目标 | 原因 |
37
+ |---|---|
38
+ | anthropic 系 provider | models.toml 未配置, 且无可用 key |
39
+ | qianwen 型 provider(type=qianwen) | 未配置 |
40
+ | `local` provider | 需要本机 llama.cpp 服务在 `localhost:8080` 上运行, 当前未启动 |
41
+
42
+ → 这三条属于"环境不具备", 不计入"已验证"。
@@ -0,0 +1,9 @@
1
+ === PyPI 发布验证 ===
2
+ PyPI 最新版本 : 0.2.18
3
+ releases 含 0.2.18: True
4
+ 0.2.18 文件数 : 2
5
+ - nexforge_cli-0.2.18-py3-none-any.whl (279373 bytes)
6
+ - nexforge_cli-0.2.18.tar.gz (389819 bytes)
7
+ 上传时间 : 2026-09-10T15:59:20.940822Z
8
+ 页面 : https://pypi.org/pypi/nexforge-cli/0.2.18/
9
+ exit=0
@@ -0,0 +1,7 @@
1
+ ........................................................................ [ 16%]
2
+ ..............sss....................................................... [ 33%]
3
+ ........................................................................ [ 50%]
4
+ ........................................................................ [ 67%]
5
+ ........................................................................ [ 84%]
6
+ .................................................................... [100%]
7
+ 425 passed, 3 skipped in 113.04s (0:01:53)