foxclaw 0.1.2 → 0.1.3

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 (344) hide show
  1. package/index.js +1 -8
  2. package/package.json +1 -1
  3. package/python/.env.example +8 -0
  4. package/python/.github/workflows/ci.yml +47 -2
  5. package/python/CHANGELOG.md +57 -0
  6. package/python/CHANGELOG_CN.md +57 -0
  7. package/python/README.md +11 -2
  8. package/python/README_CN.md +32 -20
  9. package/python/bench/bm25_audit.py +1 -14
  10. package/python/bench/bm25_regression.py +0 -1
  11. package/python/bench/bm25_stress.py +0 -4
  12. package/python/bench/cd_audit.py +0 -23
  13. package/python/bench/chaos.py +6 -8
  14. package/python/bench/e2e_real_models.py +0 -1
  15. package/python/bench/llm_retry_test.py +2 -9
  16. package/python/bench/load_test.py +5 -8
  17. package/python/bench/vector_ivf_upgrade.py +1 -7
  18. package/python/docs/RELEASE.md +4 -3
  19. package/python/docs/RUN_CN.md +2 -2
  20. package/python/evals/governance/cases.py +0 -37
  21. package/python/evals/governance/run_evals.py +5 -37
  22. package/python/examples/governance_middleware_demo.py +1 -6
  23. package/python/examples/langgraph_governance_demo.py +7 -11
  24. package/python/foxclaw/__init__.py +34 -152
  25. package/python/foxclaw/agents/base.py +65 -136
  26. package/python/foxclaw/agents/impl/_helpers.py +2 -10
  27. package/python/foxclaw/agents/impl/finance.py +4 -21
  28. package/python/foxclaw/agents/impl/office.py +7 -24
  29. package/python/foxclaw/agents/impl/supervisor.py +12 -79
  30. package/python/foxclaw/agents/mixins/_context.py +0 -23
  31. package/python/foxclaw/agents/mixins/augment.py +10 -16
  32. package/python/foxclaw/agents/mixins/llm.py +7 -6
  33. package/python/foxclaw/agents/mixins/memory.py +7 -1
  34. package/python/foxclaw/agents/mixins/preference.py +58 -8
  35. package/python/foxclaw/agents/mixins/prompt.py +0 -6
  36. package/python/foxclaw/agents/mixins/skillbox.py +6 -6
  37. package/python/foxclaw/agents/mixins/tool_exec.py +16 -42
  38. package/python/foxclaw/api/__init__.py +18 -77
  39. package/python/foxclaw/api/_state.py +43 -0
  40. package/python/foxclaw/api/{app.py → bootstrap.py} +5 -32
  41. package/python/foxclaw/api/middleware.py +5 -28
  42. package/python/foxclaw/api/routes/ahs.py +60 -73
  43. package/python/foxclaw/api/routes/attachments.py +5 -6
  44. package/python/foxclaw/api/routes/browser.py +7 -11
  45. package/python/foxclaw/api/routes/domain.py +18 -26
  46. package/python/foxclaw/api/routes/knowledge.py +3 -21
  47. package/python/foxclaw/api/routes/llm_admin.py +21 -33
  48. package/python/foxclaw/api/routes/memory.py +28 -12
  49. package/python/foxclaw/api/routes/orchestration.py +3 -5
  50. package/python/foxclaw/api/routes/recovery.py +4 -3
  51. package/python/foxclaw/api/routes/review.py +2 -11
  52. package/python/foxclaw/api/routes/search.py +3 -7
  53. package/python/foxclaw/api/routes/system.py +33 -49
  54. package/python/foxclaw/api/routes/task.py +31 -49
  55. package/python/foxclaw/api/routes/ws.py +2 -6
  56. package/python/foxclaw/api/spine.py +1 -4
  57. package/python/foxclaw/browser/action/action_executor.py +1 -5
  58. package/python/foxclaw/browser/action/action_types.py +0 -1
  59. package/python/foxclaw/browser/action/url_policy.py +1 -5
  60. package/python/foxclaw/browser/adapter/web_adapter.py +1 -1
  61. package/python/foxclaw/browser/driver/playwright_driver.py +20 -16
  62. package/python/foxclaw/browser/perception/dom_extractor.py +0 -1
  63. package/python/foxclaw/browser/perception/element_indexer.py +1 -2
  64. package/python/foxclaw/browser/service.py +7 -11
  65. package/python/foxclaw/capability/embedding_service.py +4 -6
  66. package/python/foxclaw/channels/__init__.py +9 -11
  67. package/python/foxclaw/channels/discord.py +4 -13
  68. package/python/foxclaw/channels/dispatcher.py +2 -27
  69. package/python/foxclaw/channels/feishu.py +10 -20
  70. package/python/foxclaw/channels/openclaw_bridge.py +4 -9
  71. package/python/foxclaw/channels/signing.py +9 -9
  72. package/python/foxclaw/channels/telegram.py +3 -4
  73. package/python/foxclaw/channels/weixin.py +7 -17
  74. package/python/foxclaw/cli.py +42 -13
  75. package/python/foxclaw/cognitive/reasoner.py +9 -10
  76. package/python/foxclaw/cognitive/state.py +18 -24
  77. package/python/foxclaw/core/audit_chain.py +1 -3
  78. package/python/foxclaw/core/audit_sink.py +3 -3
  79. package/python/foxclaw/core/compaction.py +8 -26
  80. package/python/foxclaw/core/config.py +2 -2
  81. package/python/foxclaw/core/confirm_nonce.py +6 -12
  82. package/python/foxclaw/core/envfile.py +2 -2
  83. package/python/foxclaw/core/failure_policy.py +17 -26
  84. package/python/foxclaw/core/gateway.py +6 -10
  85. package/python/foxclaw/core/governance_audit.py +3 -7
  86. package/python/foxclaw/core/idempotency.py +15 -22
  87. package/python/foxclaw/core/injection_guard.py +10 -29
  88. package/python/foxclaw/core/memory_adapter.py +30 -57
  89. package/python/foxclaw/core/metrics.py +4 -5
  90. package/python/foxclaw/core/model_router.py +36 -148
  91. package/python/foxclaw/core/paths.py +1 -1
  92. package/python/foxclaw/core/recovery.py +21 -34
  93. package/python/foxclaw/core/scheduler.py +23 -26
  94. package/python/foxclaw/core/secrets.py +0 -3
  95. package/python/foxclaw/core/sessions.py +4 -6
  96. package/python/foxclaw/core/settings.py +16 -32
  97. package/python/foxclaw/core/shared_write.py +11 -23
  98. package/python/foxclaw/core/steering_queue.py +12 -11
  99. package/python/foxclaw/core/system_bus.py +1 -1
  100. package/python/foxclaw/core/thought_chain.py +30 -32
  101. package/python/foxclaw/core/token_meter.py +9 -13
  102. package/python/foxclaw/core/tools.py +4 -12
  103. package/python/foxclaw/core/tracing.py +25 -40
  104. package/python/foxclaw/core/truth_pipeline.py +5 -9
  105. package/python/foxclaw/core/update_check.py +149 -0
  106. package/python/foxclaw/core/vec_recall_adapter.py +11 -37
  107. package/python/foxclaw/core/verify.py +6 -14
  108. package/python/foxclaw/core/web_search.py +4 -28
  109. package/python/foxclaw/finance/evidence.py +14 -18
  110. package/python/foxclaw/finance/fx.py +1 -3
  111. package/python/foxclaw/finance/graph.py +9 -18
  112. package/python/foxclaw/finance/models.py +20 -24
  113. package/python/foxclaw/finance/nlparse.py +12 -72
  114. package/python/foxclaw/finance/policy.py +8 -36
  115. package/python/foxclaw/finance/reasoner.py +3 -11
  116. package/python/foxclaw/finance/reasoning.py +13 -34
  117. package/python/foxclaw/finance/reconcile.py +5 -10
  118. package/python/foxclaw/finance/runtime.py +19 -46
  119. package/python/foxclaw/governance/middleware.py +13 -21
  120. package/python/foxclaw/harness/_base.py +2 -8
  121. package/python/foxclaw/harness/_policy.py +19 -38
  122. package/python/foxclaw/harness/drift.py +1 -13
  123. package/python/foxclaw/harness/event_bus.py +2 -5
  124. package/python/foxclaw/harness/harness.py +9 -97
  125. package/python/foxclaw/harness/loop_detection.py +11 -18
  126. package/python/foxclaw/itinerary/amap_client.py +2 -5
  127. package/python/foxclaw/itinerary/models.py +7 -7
  128. package/python/foxclaw/itinerary/reasoner.py +1 -6
  129. package/python/foxclaw/itinerary/reasoning.py +15 -21
  130. package/python/foxclaw/itinerary/runtime.py +8 -12
  131. package/python/foxclaw/kernel/capabilities.py +5 -6
  132. package/python/foxclaw/kernel/policy_gate.py +4 -10
  133. package/python/foxclaw/kernel/process_manager.py +17 -36
  134. package/python/foxclaw/kernel/scheduler.py +3 -9
  135. package/python/foxclaw/kernel/sentinel.py +13 -23
  136. package/python/foxclaw/kernel/sentinel_client.py +12 -15
  137. package/python/foxclaw/kernel/spine.py +9 -9
  138. package/python/foxclaw/knowledge/__init__.py +4 -20
  139. package/python/foxclaw/knowledge/truth_crystallizer.py +5 -8
  140. package/python/foxclaw/learning/knowledge_graph.py +4 -9
  141. package/python/foxclaw/learning/models.py +13 -13
  142. package/python/foxclaw/learning/reasoner.py +1 -4
  143. package/python/foxclaw/learning/runtime.py +19 -31
  144. package/python/foxclaw/learning/spaced_repetition.py +2 -7
  145. package/python/foxclaw/mcp_server.py +2 -3
  146. package/python/foxclaw/orchestration/__init__.py +16 -33
  147. package/python/foxclaw/pipeline/cognitive_pipeline.py +45 -97
  148. package/python/foxclaw/pipeline/stage_meta.py +21 -0
  149. package/python/foxclaw/pipeline/supervisor_stages.py +13 -42
  150. package/python/foxclaw/planning/llm_planner.py +3 -3
  151. package/python/foxclaw/planning/planner.py +6 -11
  152. package/python/foxclaw/search/agent_port.py +7 -11
  153. package/python/foxclaw/search/evidence.py +0 -4
  154. package/python/foxclaw/search/internal_search.py +3 -5
  155. package/python/foxclaw/search/models.py +11 -13
  156. package/python/foxclaw/search/planner.py +3 -3
  157. package/python/foxclaw/search/retriever.py +1 -1
  158. package/python/foxclaw/search/runtime.py +1 -8
  159. package/python/foxclaw/skills/__init__.py +46 -100
  160. package/python/foxclaw/skills/archive.py +111 -0
  161. package/python/foxclaw/skills/fetch.py +226 -0
  162. package/python/foxclaw/skills/hooks_spec.py +21 -25
  163. package/python/foxclaw/skills/install_cmd.py +216 -0
  164. package/python/foxclaw/skills/lifecycle.py +16 -42
  165. package/python/foxclaw/skills/markdown_skill.py +10 -9
  166. package/python/foxclaw/skills/mcp_client.py +5 -11
  167. package/python/foxclaw/skills/mcp_store.py +0 -3
  168. package/python/foxclaw/skills/permission.py +13 -48
  169. package/python/foxclaw/skills/pipeline.py +21 -53
  170. package/python/foxclaw/skills/policy.py +4 -10
  171. package/python/foxclaw/skills/review.py +3 -3
  172. package/python/frontend/deck/auth.js +0 -7
  173. package/python/frontend/deck/chat_model_picker.js +0 -54
  174. package/python/frontend/deck/domain.js +0 -20
  175. package/python/frontend/deck/main.js +0 -144
  176. package/python/frontend/deck/markdown.js +0 -4
  177. package/python/frontend/deck/settings.js +1 -18
  178. package/python/frontend/deck/state.js +0 -1
  179. package/python/frontend/deck/util.js +0 -2
  180. package/python/frontend/deck/visuals.js +0 -22
  181. package/python/frontend/planet/planet.js +0 -201
  182. package/python/frontend/v3/assets/index-CQSBdxk4.js +34 -0
  183. package/python/frontend/v3/assets/index-D5nIsjms.css +1 -0
  184. package/python/frontend/v3/index.html +3 -3
  185. package/python/frontend/widget_runtime.js +0 -43
  186. package/python/frontend/widgets.js +0 -57
  187. package/python/frontend_src/index.html +1 -1
  188. package/python/frontend_src/package-lock.json +2 -2
  189. package/python/frontend_src/package.json +1 -1
  190. package/python/frontend_src/src/App.vue +3 -7
  191. package/python/frontend_src/src/api.js +0 -7
  192. package/python/frontend_src/src/components/ChatDock.vue +27 -39
  193. package/python/frontend_src/src/components/DocViewer.vue +0 -9
  194. package/python/frontend_src/src/components/Inspector.vue +0 -6
  195. package/python/frontend_src/src/components/LeftRail.vue +60 -39
  196. package/python/frontend_src/src/components/MenuPopover.vue +9 -11
  197. package/python/frontend_src/src/components/MessageStream.vue +18 -30
  198. package/python/frontend_src/src/components/ModelPicker.vue +0 -5
  199. package/python/frontend_src/src/components/QuickIngest.vue +0 -6
  200. package/python/frontend_src/src/components/Stage.vue +71 -25
  201. package/python/frontend_src/src/components/ToolMenu.vue +0 -3
  202. package/python/frontend_src/src/components/TopBar.vue +38 -10
  203. package/python/frontend_src/src/components/panels/ActivityPanel.vue +0 -2
  204. package/python/frontend_src/src/components/panels/AgentsPanel.vue +2 -5
  205. package/python/frontend_src/src/components/panels/KnowledgePanel.vue +0 -16
  206. package/python/frontend_src/src/components/panels/MemoryPanel.vue +0 -1
  207. package/python/frontend_src/src/components/panels/PanelBox.vue +6 -7
  208. package/python/frontend_src/src/components/panels/ReviewPanel.vue +0 -16
  209. package/python/frontend_src/src/components/panels/SettingsPanel.vue +142 -38
  210. package/python/frontend_src/src/components/panels/TasksPanel.vue +0 -1
  211. package/python/frontend_src/src/components/panels/ToolsPanel.vue +125 -19
  212. package/python/frontend_src/src/lib/fmt.js +0 -4
  213. package/python/frontend_src/src/lib/i18n.js +53 -0
  214. package/python/frontend_src/src/lib/locales/en.js +173 -0
  215. package/python/frontend_src/src/lib/locales/zh.js +174 -0
  216. package/python/frontend_src/src/lib/md.js +0 -14
  217. package/python/frontend_src/src/main.js +2 -0
  218. package/python/frontend_src/src/stores/app.js +17 -32
  219. package/python/frontend_src/src/stores/chat.js +0 -34
  220. package/python/frontend_src/src/stores/model.js +0 -8
  221. package/python/frontend_src/src/stores/panels.js +0 -41
  222. package/python/frontend_src/src/stores/profile.js +31 -0
  223. package/python/frontend_src/src/stores/system.js +25 -0
  224. package/python/frontend_src/vite.config.js +0 -7
  225. package/python/pyproject.toml +6 -3
  226. package/python/requirements.txt +311 -0
  227. package/python/tests/conftest.py +0 -22
  228. package/python/tests/run_all.py +3 -66
  229. package/python/tests/test_agent_lifecycle.py +4 -38
  230. package/python/tests/test_ahs_p2.py +4 -25
  231. package/python/tests/test_anthropic_tools.py +1 -15
  232. package/python/tests/test_api.py +19 -9
  233. package/python/tests/test_api_auth.py +1 -5
  234. package/python/tests/test_attachments.py +9 -25
  235. package/python/tests/test_audit_chain.py +2 -7
  236. package/python/tests/test_audit_sink.py +0 -6
  237. package/python/tests/test_browser.py +2 -6
  238. package/python/tests/test_browser_request_guard.py +0 -4
  239. package/python/tests/test_capabilities.py +0 -6
  240. package/python/tests/test_channel_signing.py +2 -9
  241. package/python/tests/test_channels.py +1 -11
  242. package/python/tests/test_config_layering.py +0 -4
  243. package/python/tests/test_confirm_nonce.py +1 -12
  244. package/python/tests/test_context_compaction_wiring.py +1 -7
  245. package/python/tests/test_dispatch.py +0 -6
  246. package/python/tests/test_domain_evals.py +11 -80
  247. package/python/tests/test_domain_import.py +0 -6
  248. package/python/tests/test_domain_reasoners.py +0 -14
  249. package/python/tests/test_e2e.py +0 -17
  250. package/python/tests/test_emb_cache.py +7 -17
  251. package/python/tests/test_embedding_singleton.py +1 -3
  252. package/python/tests/test_evals_smoke.py +0 -24
  253. package/python/tests/test_event_spine.py +10 -18
  254. package/python/tests/test_evidence_semantic.py +1 -14
  255. package/python/tests/test_evidence_sse.py +3 -6
  256. package/python/tests/test_file_ingest.py +0 -11
  257. package/python/tests/test_finance.py +0 -9
  258. package/python/tests/test_finance_ledger.py +5 -12
  259. package/python/tests/test_finance_persist.py +8 -12
  260. package/python/tests/test_gateway.py +3 -22
  261. package/python/tests/test_governance.py +5 -52
  262. package/python/tests/test_governance_audit.py +4 -39
  263. package/python/tests/test_governance_middleware.py +1 -7
  264. package/python/tests/test_hkc.py +6 -24
  265. package/python/tests/test_hkc_index_build_manager.py +0 -33
  266. package/python/tests/test_hkc_manifest_reuse.py +4 -27
  267. package/python/tests/test_hkc_search_event_sync.py +3 -54
  268. package/python/tests/test_import_path_guard.py +0 -6
  269. package/python/tests/test_injection_guard.py +18 -36
  270. package/python/tests/test_integration.py +5 -29
  271. package/python/tests/test_itinerary.py +0 -3
  272. package/python/tests/test_kee_semantic.py +0 -5
  273. package/python/tests/test_kernel.py +1 -11
  274. package/python/tests/test_learning.py +3 -12
  275. package/python/tests/test_llm_admin.py +4 -19
  276. package/python/tests/test_llm_planner.py +1 -23
  277. package/python/tests/test_markdown_skills.py +3 -14
  278. package/python/tests/test_markdown_skills_openclaw.py +4 -9
  279. package/python/tests/test_mcp_connectors.py +3 -15
  280. package/python/tests/test_mcp_guardian_discovery.py +2 -6
  281. package/python/tests/test_mcp_no_memory.py +3 -3
  282. package/python/tests/test_mcp_policy_gate.py +0 -1
  283. package/python/tests/test_mcp_server.py +6 -9
  284. package/python/tests/test_memory_recall.py +1 -4
  285. package/python/tests/test_metrics.py +0 -8
  286. package/python/tests/test_multi_chain.py +1 -13
  287. package/python/tests/test_multimodal.py +5 -18
  288. package/python/tests/test_negotiation.py +3 -13
  289. package/python/tests/test_orchestration.py +1 -11
  290. package/python/tests/test_orchestration_decoupled.py +0 -6
  291. package/python/tests/test_p3_p5_hardening.py +3 -17
  292. package/python/tests/test_parallel_dispatch.py +4 -12
  293. package/python/tests/test_pipeline.py +17 -58
  294. package/python/tests/test_plan_visible.py +4 -4
  295. package/python/tests/test_planner.py +0 -7
  296. package/python/tests/test_policy_gate.py +2 -3
  297. package/python/tests/test_profile.py +67 -0
  298. package/python/tests/test_readme_claims.py +163 -0
  299. package/python/tests/test_reasoner.py +2 -17
  300. package/python/tests/test_release_check.py +2 -13
  301. package/python/tests/test_resume_checkpoint.py +7 -15
  302. package/python/tests/test_routing.py +2 -12
  303. package/python/tests/test_scheduler.py +7 -10
  304. package/python/tests/test_search.py +1 -11
  305. package/python/tests/test_secrets.py +4 -10
  306. package/python/tests/test_semantic.py +1 -10
  307. package/python/tests/test_sessions.py +3 -4
  308. package/python/tests/test_settings.py +2 -18
  309. package/python/tests/test_shadow_learning.py +3 -43
  310. package/python/tests/test_shared_write.py +0 -7
  311. package/python/tests/test_skill_taint_gate.py +1 -10
  312. package/python/tests/test_skills.py +2 -18
  313. package/python/tests/test_skills_fetch.py +282 -0
  314. package/python/tests/test_stats_and_events.py +2 -5
  315. package/python/tests/test_streaming.py +2 -7
  316. package/python/tests/test_supervisor_pipeline.py +4 -5
  317. package/python/tests/test_supervisor_triage.py +4 -10
  318. package/python/tests/test_taint.py +2 -7
  319. package/python/tests/test_task_stream.py +1 -12
  320. package/python/tests/test_thinking_sse.py +0 -1
  321. package/python/tests/test_tool_center.py +1 -17
  322. package/python/tests/test_tool_parallel.py +2 -2
  323. package/python/tests/test_tool_params.py +1 -5
  324. package/python/tests/test_tool_use.py +0 -13
  325. package/python/tests/test_toplevel_concurrency.py +3 -4
  326. package/python/tests/test_tracing.py +7 -41
  327. package/python/tests/test_truth_crystallizer.py +4 -6
  328. package/python/tests/test_truth_flow.py +2 -7
  329. package/python/tests/test_update_check.py +95 -0
  330. package/python/tests/test_verify_evidence.py +8 -21
  331. package/python/tests/test_version_sync.py +35 -6
  332. package/python/tests/test_web_trigger.py +0 -17
  333. package/python/tools/check_faiss_type.py +0 -1
  334. package/python/tools/check_log.ps1 +0 -8
  335. package/python/tools/mypy_baseline.txt +12 -4
  336. package/python/tools/mypy_ratchet.py +52 -6
  337. package/python/tools/pack.py +0 -5
  338. package/python/tools/release_check.py +7 -7
  339. package/python/tools/restart_foxclaw.ps1 +5 -8
  340. package/python/tools/shared_write_audit.py +1 -15
  341. package/python/tools/size_check.py +1 -1
  342. package/python/tools/strip_comments.py +228 -0
  343. package/python/frontend/v3/assets/index-BD7VPbMV.js +0 -33
  344. package/python/frontend/v3/assets/index-CAvnYWGH.css +0 -1
@@ -0,0 +1,311 @@
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv pip compile pyproject.toml --universal -o requirements.txt
3
+ annotated-doc==0.0.5
4
+ # via
5
+ # fastapi
6
+ # typer
7
+ annotated-types==0.8.0
8
+ # via pydantic
9
+ anthropic==2.6.0
10
+ # via foxclaw (pyproject.toml)
11
+ anyio==4.16.0
12
+ # via
13
+ # anthropic
14
+ # httpx
15
+ # httpx2
16
+ # mcp
17
+ # openai
18
+ # sse-starlette
19
+ # starlette
20
+ attrs==26.1.0
21
+ # via
22
+ # jsonschema
23
+ # referencing
24
+ certifi==2026.10.23
25
+ # via
26
+ # httpcore
27
+ # httpx
28
+ cffi==2.1.1 ; platform_python_implementation != 'PyPy'
29
+ # via cryptography
30
+ click==8.5.1
31
+ # via
32
+ # huggingface-hub
33
+ # uvicorn
34
+ cloudpickle==3.1.2
35
+ # via joblib
36
+ colorama==0.4.6 ; sys_platform == 'win32'
37
+ # via
38
+ # tqdm
39
+ # typer
40
+ cryptography==50.0.2
41
+ # via
42
+ # foxclaw (pyproject.toml)
43
+ # pyjwt
44
+ cuda-bindings==13.5.0 ; python_full_version < '3.15' and sys_platform == 'linux'
45
+ # via torch
46
+ cuda-pathfinder==1.8.6 ; python_full_version < '3.15' and sys_platform == 'linux'
47
+ # via cuda-bindings
48
+ cuda-toolkit==13.2.2 ; sys_platform == 'linux'
49
+ # via torch
50
+ docstring-parser==0.18.0
51
+ # via anthropic
52
+ faiss-cpu==1.15.1
53
+ # via foxclaw (pyproject.toml)
54
+ fastapi==0.162.2
55
+ # via foxclaw (pyproject.toml)
56
+ filelock==4.2.9
57
+ # via
58
+ # huggingface-hub
59
+ # torch
60
+ fsspec==2026.9.0
61
+ # via
62
+ # huggingface-hub
63
+ # torch
64
+ h11==0.16.0
65
+ # via
66
+ # httpcore
67
+ # httpcore2
68
+ # uvicorn
69
+ hf-xet==1.8.0 ; platform_machine == 'AMD64' or platform_machine == 'ARM64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
70
+ # via huggingface-hub
71
+ httpcore==1.0.9
72
+ # via httpx
73
+ httpcore2==2.16.0 ; sys_platform != 'emscripten'
74
+ # via httpx2
75
+ httpx==0.27.2
76
+ # via
77
+ # foxclaw (pyproject.toml)
78
+ # mcp
79
+ httpx-sse==0.4.3
80
+ # via mcp
81
+ httpx2==2.16.0
82
+ # via
83
+ # anthropic
84
+ # huggingface-hub
85
+ # openai
86
+ httpx2-jsfetch==1.0 ; sys_platform == 'emscripten'
87
+ # via httpx2
88
+ huggingface-hub==2.4.0
89
+ # via
90
+ # sentence-transformers
91
+ # tokenizers
92
+ # transformers
93
+ idna==3.20
94
+ # via
95
+ # anyio
96
+ # httpx
97
+ # httpx2
98
+ jinja2==3.1.6
99
+ # via torch
100
+ jiter==0.19.0
101
+ # via
102
+ # anthropic
103
+ # openai
104
+ joblib==1.6.0
105
+ # via scikit-learn
106
+ jsonschema==4.26.0
107
+ # via mcp
108
+ jsonschema-specifications==2025.9.1
109
+ # via jsonschema
110
+ markdown-it-py==4.2.0
111
+ # via rich
112
+ markupsafe==3.0.4
113
+ # via jinja2
114
+ mcp==1.30.0
115
+ # via foxclaw (pyproject.toml)
116
+ mdurl==0.1.2
117
+ # via markdown-it-py
118
+ mpmath==1.3.0
119
+ # via sympy
120
+ narwhals==2.28.0
121
+ # via scikit-learn
122
+ networkx==3.7
123
+ # via torch
124
+ numpy==2.5.4
125
+ # via
126
+ # foxclaw (pyproject.toml)
127
+ # faiss-cpu
128
+ # scikit-learn
129
+ # scipy
130
+ # sentence-transformers
131
+ # transformers
132
+ nvidia-cublas==13.4.1.3 ; sys_platform == 'linux'
133
+ # via
134
+ # cuda-toolkit
135
+ # nvidia-cudnn-cu13
136
+ # nvidia-cusolver
137
+ nvidia-cuda-cccl==13.3.5.0.6 ; sys_platform == 'linux'
138
+ # via nvidia-nvshmem-cu13
139
+ nvidia-cuda-cupti==13.2.86 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
140
+ # via cuda-toolkit
141
+ nvidia-cuda-nvrtc==13.2.86 ; sys_platform == 'linux'
142
+ # via
143
+ # cuda-toolkit
144
+ # nvidia-cublas
145
+ nvidia-cuda-runtime==13.2.86 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
146
+ # via cuda-toolkit
147
+ nvidia-cudnn-cu13==9.26.0.51 ; sys_platform == 'linux'
148
+ # via torch
149
+ nvidia-cufft==12.2.0.57 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
150
+ # via cuda-toolkit
151
+ nvidia-cufile==1.17.1.22 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
152
+ # via cuda-toolkit
153
+ nvidia-cusolver==12.2.0.11 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
154
+ # via cuda-toolkit
155
+ nvidia-cusparse==12.7.10.12 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
156
+ # via
157
+ # cuda-toolkit
158
+ # nvidia-cusolver
159
+ nvidia-cusparselt-cu13==0.8.1 ; sys_platform == 'linux'
160
+ # via torch
161
+ nvidia-nccl-cu13==2.30.7 ; sys_platform == 'linux'
162
+ # via torch
163
+ nvidia-nvjitlink==13.5.37 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
164
+ # via
165
+ # cuda-toolkit
166
+ # nvidia-cufft
167
+ # nvidia-cusolver
168
+ # nvidia-cusparse
169
+ nvidia-nvshmem-cu13==3.7.2 ; sys_platform == 'linux'
170
+ # via torch
171
+ nvidia-nvtx==13.2.86 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
172
+ # via cuda-toolkit
173
+ openai==3.46.0
174
+ # via foxclaw (pyproject.toml)
175
+ opentelemetry-api==1.45.2
176
+ # via
177
+ # anthropic
178
+ # fastapi
179
+ packaging==26.3
180
+ # via
181
+ # faiss-cpu
182
+ # huggingface-hub
183
+ # transformers
184
+ pycparser==3.12 ; implementation_name != 'PyPy' and platform_python_implementation != 'PyPy'
185
+ # via cffi
186
+ pydantic==2.14.3
187
+ # via
188
+ # foxclaw (pyproject.toml)
189
+ # anthropic
190
+ # fastapi
191
+ # mcp
192
+ # openai
193
+ # pydantic-settings
194
+ pydantic-core==2.50.4
195
+ # via pydantic
196
+ pydantic-settings==2.16.2
197
+ # via mcp
198
+ pygments==2.21.0
199
+ # via rich
200
+ pyjwt==2.15.1
201
+ # via mcp
202
+ python-dotenv==1.2.4
203
+ # via
204
+ # foxclaw (pyproject.toml)
205
+ # pydantic-settings
206
+ python-multipart==0.0.33
207
+ # via mcp
208
+ pywin32==312 ; sys_platform == 'win32'
209
+ # via mcp
210
+ pyyaml==6.0.3
211
+ # via
212
+ # foxclaw (pyproject.toml)
213
+ # huggingface-hub
214
+ # transformers
215
+ referencing==0.37.0
216
+ # via
217
+ # jsonschema
218
+ # jsonschema-specifications
219
+ regex==2026.11.9
220
+ # via transformers
221
+ rich==15.0.0
222
+ # via
223
+ # foxclaw (pyproject.toml)
224
+ # typer
225
+ rpds-py==2026.9.1
226
+ # via
227
+ # jsonschema
228
+ # referencing
229
+ safetensors==0.8.0
230
+ # via transformers
231
+ scikit-learn==1.9.1
232
+ # via
233
+ # foxclaw (pyproject.toml)
234
+ # sentence-transformers
235
+ scipy==1.18.1
236
+ # via
237
+ # scikit-learn
238
+ # sentence-transformers
239
+ sentence-transformers==6.2.0
240
+ # via foxclaw (pyproject.toml)
241
+ setuptools==84.2.1
242
+ # via torch
243
+ shellingham==1.5.4
244
+ # via typer
245
+ sniffio==1.3.1
246
+ # via
247
+ # anthropic
248
+ # httpx
249
+ # openai
250
+ sse-starlette==3.7.0
251
+ # via mcp
252
+ starlette==1.10.0
253
+ # via
254
+ # fastapi
255
+ # mcp
256
+ # sse-starlette
257
+ sympy==1.14.0
258
+ # via torch
259
+ threadpoolctl==3.8.0
260
+ # via scikit-learn
261
+ tokenizers==0.23.3
262
+ # via
263
+ # sentence-transformers
264
+ # transformers
265
+ torch==2.15.0
266
+ # via sentence-transformers
267
+ tqdm==4.70.1
268
+ # via
269
+ # huggingface-hub
270
+ # sentence-transformers
271
+ # transformers
272
+ transformers==5.22.2
273
+ # via sentence-transformers
274
+ triton==3.9.0 ; python_full_version < '3.16' and sys_platform == 'linux'
275
+ # via torch
276
+ truststore==0.10.5 ; sys_platform != 'emscripten'
277
+ # via
278
+ # httpcore2
279
+ # httpx2
280
+ typer==0.28.0
281
+ # via transformers
282
+ typing-extensions==4.16.0
283
+ # via
284
+ # anthropic
285
+ # anyio
286
+ # fastapi
287
+ # httpx2
288
+ # huggingface-hub
289
+ # mcp
290
+ # openai
291
+ # opentelemetry-api
292
+ # pydantic
293
+ # pydantic-core
294
+ # pydantic-settings
295
+ # referencing
296
+ # sentence-transformers
297
+ # starlette
298
+ # torch
299
+ # typing-inspection
300
+ typing-inspection==0.4.5
301
+ # via
302
+ # fastapi
303
+ # mcp
304
+ # pydantic
305
+ # pydantic-settings
306
+ uvicorn==0.54.0
307
+ # via
308
+ # foxclaw (pyproject.toml)
309
+ # mcp
310
+ websockets==17.4
311
+ # via foxclaw (pyproject.toml)
@@ -16,26 +16,10 @@ _REPO_ROOT = Path(__file__).parent.parent
16
16
  if str(_REPO_ROOT) not in sys.path:
17
17
  sys.path.insert(0, str(_REPO_ROOT))
18
18
 
19
- # ── HKC vendor 隔离 ────────────────────────────────────────────────────────────
20
- # IDE/Cursor 等 shim 常把 `C:\GitHub\foxclaw-hkc\src` 注入到 sys.path 第一位,
21
- # 而那是上游低质量代码、跟本项目 vendor/hkc/ 是不同等级。**测试必须打 vendor 真代码**,
22
- # 否则会出现 tests/test_vendor_path_isolation.py 里那类「绿了但打错对象」的事故。
23
- # 把 vendor/hkc 强制插到 sys.path[0](即使 shim 在前也覆盖之),后续 `import hkc_*`
24
- # 全部解析到本仓库 vendor 副本。foxclaw.knowledge 自身也调 _ensure_hkc_importable()
25
- # 做同样事,但那只在 import foxclaw.knowledge 之后才生效;本测试文件顶层直接
26
- # import hkc_search 早于它,故在 conftest 阶段就注入更稳。
27
19
  _VENDOR_HKC = _REPO_ROOT / "vendor" / "hkc"
28
20
  if _VENDOR_HKC.exists() and str(_VENDOR_HKC) not in sys.path:
29
21
  sys.path.insert(0, str(_VENDOR_HKC))
30
22
 
31
- # ── 规避 pytest 在 Windows + Python 3.14 下的 junction 清理 bug ────────────────
32
- # pytest 用 Path.symlink_to() 创建 `pytest-current` / `test_*current` 目录 junction
33
- # 作为「指向最新临时目录」的便利链接。Windows 会把这类 junction 标记为
34
- # 「不受信任的装入点(untrusted mount point)」,Python 3.14 的 ntpath.realpath 在
35
- # pytest_sessionfinish 的 cleanup_dead_symlinks 里对它调用 Path.resolve() 时抛
36
- # WinError 448,并令 pytest 退出码变 1(测试本身全通过)。该 junction 仅作调试便利,
37
- # 不影响任何测试功能,故在 Windows 上禁用其创建(必须在 basetemp 建立前生效,
38
- # 而 conftest 的模块级代码早于 basetemp 创建执行,时序安全)。
39
23
  if sys.platform == "win32":
40
24
  import _pytest.pathlib as _ppl
41
25
 
@@ -44,10 +28,7 @@ if sys.platform == "win32":
44
28
 
45
29
  _ppl._force_symlink = _skip_force_symlink
46
30
 
47
- # ── 环境隔离(与 run_all.py 的 env 注入保持一致,强制覆盖继承环境)──────────────
48
- # FOXCLAW_SKIP_DOTENV=1:让 api.py 完全不读项目根 .env,防止真实 Key 灌回 / 写真实数据目录。
49
31
  os.environ["FOXCLAW_SKIP_DOTENV"] = "1"
50
- # 锁 shadow 轮数、stub 嵌入、关 MCP、清 provider/model:回归保持离线/免费/确定性。
51
32
  os.environ["FOXCLAW_SHADOW_ROUNDS"] = "50"
52
33
  os.environ["HF_HUB_OFFLINE"] = "1"
53
34
  os.environ["TRANSFORMERS_OFFLINE"] = "1"
@@ -55,13 +36,10 @@ os.environ["HKC_EMBEDDING"] = "stub"
55
36
  os.environ["FOXCLAW_MCP_SERVER"] = "0"
56
37
  os.environ["FOXCLAW_PROVIDER"] = ""
57
38
  os.environ["FOXCLAW_MODEL"] = ""
58
- # 清空外部 API key(第二道防线):鉴权/网关测试要自行控制 FOXCLAW_API_KEY。
59
39
  for _k in ("DEEPSEEK_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY",
60
40
  "GOOGLE_API_KEY", "DASHSCOPE_API_KEY", "FOXCLAW_API_KEY"):
61
41
  os.environ[_k] = ""
62
42
 
63
- # 兜底:为未自设 FOXCLAW_DATA_DIR 的测试提供一个临时目录,避免 KeyError。
64
- # (各测试文件顶层通常会自行 mkdtemp 覆盖此值,此处仅作安全网。)
65
43
  os.environ.setdefault("FOXCLAW_DATA_DIR", tempfile.mkdtemp(prefix="foxclaw_test_"))
66
44
 
67
45
 
@@ -11,11 +11,6 @@ import tempfile
11
11
  import time
12
12
  from pathlib import Path
13
13
 
14
- # Windows GBK 控制台无法编码 ✓/✗(✓/✗)等字符 → 运行器自己把 stdout/stderr 切到
15
- # utf-8,不依赖调用者预先 set PYTHONUTF8。否则打印结果时 UnicodeEncodeError 直接崩掉汇总。
16
- # line_buffering=True:本文件由 run_all 汇总输出,单个测试跑满 300s 时整轮可达十余分钟;
17
- # 若不开行缓冲,`python tests/run_all.py > log.txt` 会因块缓冲而**全程看不到进度**,
18
- # 只能等结束。开启后每条结果即时落盘,可 tail -f 观察。
19
14
  for _s in (sys.stdout, sys.stderr):
20
15
  try:
21
16
  _s.reconfigure(encoding="utf-8", line_buffering=True)
@@ -32,11 +27,10 @@ TESTS = [
32
27
  ("test_itinerary.py", "B · 行程内核"),
33
28
  ("test_orchestration.py","主管编排 + 跨 Agent"),
34
29
  ("test_skills.py", "助手 Skill 接入层"),
30
+ ("test_skills_fetch.py", "技能安装(ClawHub/GitHub/URL/本地包)"),
35
31
  ("test_kernel.py", "内核新模块回归"),
36
32
  ("test_governance.py", "运行时治理(幂等/恢复/队列/压缩/循环/钩子)"),
37
- # —— M5 新增:压缩器工具消息配对(防孤立 tool_call 致 provider 400)——
38
33
  ("test_compaction_toolpair.py", "M5·压缩器工具消息配对(原子组切分+畸形输入安全降级)"),
39
- # —— M4 新增:工具入参校验 + permission Stage 1 真正生效 ——
40
34
  ("test_tool_params.py", "M4·工具入参校验(执行侧 schema/Stage1/解析失败可见)"),
41
35
  ("test_shared_write.py", "P0-3 · 共享层写入策略(audit/warn/enforce)"),
42
36
  ("test_audit_sink.py", "P0-3 · 审计落盘 sink(环形缓冲外的持久样本)"),
@@ -97,29 +91,23 @@ TESTS = [
97
91
  ("test_evidence_semantic.py", "证据融合语义化(否定词边界·幻影矛盾·语义支持边·降级)"),
98
92
  ("test_domain_evals.py", "领域推理评测(漏报/误报率+误报归因到规则+规则实例隔离)"),
99
93
  ("test_negotiation.py", "智能体层·跨域协商闭环(被拒→让步→再裁决·有界·拒绝不降级)"),
100
- # —— 以下 4 项此前遗漏于本运行器(P4-4 修复)——
101
94
  ("test_tool_use.py", "P2·function-calling 工具化(多轮工具循环/注册表/降级)"),
102
95
  ("test_injection_guard.py", "提示词注入纵深防御(检出/wrap_untrusted/内核前缀/隔离)"),
103
96
  ("test_sessions.py", "会话存储(增删改查/标题提炼/路径穿越/并发追加)"),
104
97
  ("test_stats_and_events.py","记忆统计 + 活动事件(hmr.stats 计数修复/chat.completed)"),
105
- # —— 以下 4 项为近期新功能测试,此前遗漏于本运行器(接线)——
106
98
  ("test_llm_planner.py", "P0-1·LLM 驱动规划器(llm_plan/replan·opt-in+fail-safe+sv_replan)"),
107
99
  ("test_anthropic_tools.py", "P0-2·Anthropic tool_use 原生接入(格式转换/解析/回灌/降级)"),
108
100
  ("test_taint.py", "数据污点追踪+动态审批门槛(污点分级/传播/TAINT_CONFIRM)"),
109
101
  ("test_mcp_guardian_discovery.py", "MCP 发现进守门人(凭证不出主进程·代发现·序列化)"),
110
102
  ("test_verify_evidence.py", "三个薄点·失败策略表/执行后核验/执行证据(重试只限只读)"),
111
103
  ("test_evidence_sse.py", "执行凭据 SSE 命名事件(与正文分离·纯对话不发)"),
104
+ ("test_profile.py", "称呼(user profile)存取:写入/替换/清空/不误删偏好"),
105
+ ("test_update_check.py", "新版本检查:默认关/版本比较/24h 缓存/失败静默"),
112
106
  ]
113
107
 
114
- # S2 迁移完成:全部测试均已迁移为 pytest(见 pyproject [tool.pytest.ini_options] 白名单)。
115
- # 故下面所有文件统一用 `python -m pytest <file> -q` 跑,且**每个文件独立子进程**:
116
- # 网关/内置MCP/流式限流等测试依赖模块级单例,同一进程内会被首个 import 定死、相互污染。
117
108
 
118
109
  def main():
119
110
  here = Path(__file__).parent
120
- # ── 命令行:支持 --list / --only <substr>(M7)──────────────────────
121
- # 为什么需要:全量回归 6-7 分钟,改一行代码后只想验 1-2 个文件时成本过高。
122
- # 此前只能整跑,拖慢了「改完立刻验」的内循环(这也是很多缺陷被放过的原因之一)。
123
111
  _argv = sys.argv[1:]
124
112
  global TESTS
125
113
  if "--list" in _argv:
@@ -137,41 +125,14 @@ def main():
137
125
  _before = len(TESTS)
138
126
  TESTS = [(f, d) for f, d in TESTS if _only in f or _only in d]
139
127
  print(f"[filter] '{_only}' 匹配 {len(TESTS)}/{_before} 项\n")
140
- # HF_HUB_OFFLINE:装了 sentence-transformers 时,每个 Foxclaw() 会载入 all-MiniLM
141
- # 模型 6 次(5 Harness + 1 HMR embedding),且每次都向 HF Hub 发未认证网络请求——
142
- # 即便模型已缓存。实测让单次 init 从 ~44s 降到 ~7s,并去除网络抖动(否则被 HF 限流时
143
- # 某个子测试会顶穿 300s 超时)。模型已本地缓存,离线读取即可;未缓存时 Harness 会自动
144
- # 降级 n-gram 哈希嵌入,不影响测试判定。PYTHONUTF8:防 Windows GBK 控制台的 ✓/✗ 编码错。
145
- # ── 测试环境隔离(必须放在最前,否则回归不可复现)────────────────────────
146
- # FOXCLAW_SKIP_DOTENV=1:让 api.py 完全不读项目根目录的 .env。
147
- # 为什么不能只靠下面那些空字符串:.env 的加载是 load_dotenv(override=False),
148
- # 它只保护「当前进程里已存在的键」。但测试常常要 pop 掉某键来验证「未设时的行为」
149
- # (如 test_gateway.py / test_api_auth.py pop FOXCLAW_API_KEY),pop 完再 import api,
150
- # .env 就会把键灌回来 —— 空字符串挡不住这种路径。
151
- # 实测证据:对照树(0 改动)+ 含 FOXCLAW_API_KEY 的 .env → test_gateway 报
152
- # KeyError: 'enabled';同树删掉 .env → 通过。故必须在源头关掉 .env。
153
- # 另:开发者 .env 里有真实 Key 与 FOXCLAW_DATA_DIR=./foxclaw_data,不隔离会让测试
154
- # 真的打外部 API(花钱)并写进真实数据目录。
155
- # 下面显式置空的 key 作为**第二道防线**,覆盖那些会 import 本运行器 env dict
156
- # 或直接读 os.environ 的路径(且便于单独运行单个测试文件时也保持确定性)。
157
128
  env = dict(os.environ, FOXCLAW_SHADOW_ROUNDS="50",
158
129
  HF_HUB_OFFLINE="1", TRANSFORMERS_OFFLINE="1",
159
130
  PYTHONUTF8="1", PYTHONIOENCODING="utf-8",
160
131
  FOXCLAW_SKIP_DOTENV="1",
161
- # 强制 stub:回归保持离线/免费/确定性。鉴权与网关必须为「未设」态——
162
- # test_api_auth / test_gateway 要自行控制 FOXCLAW_API_KEY,这里先兜底清空。
163
132
  DEEPSEEK_API_KEY="", ANTHROPIC_API_KEY="", OPENAI_API_KEY="",
164
133
  GOOGLE_API_KEY="", DASHSCOPE_API_KEY="", FOXCLAW_API_KEY="",
165
- # .env 里 FOXCLAW_MCP_SERVER=1 会让 api.py 在 import 时构建 MCP 服务器,
166
- # 而 test_tracing.py 有两处 `with TestClient(app)`(82/189 行),第二次进
167
- # lifespan 会撞 StreamableHTTPSessionManager「.run() can only be called
168
- # once per instance」。回归默认关;test_mcp_server.py 自己会置 1。
169
134
  FOXCLAW_MCP_SERVER="0",
170
- # 锁 stub 模型路由:.env 里 FOXCLAW_PROVIDER=openai/FOXCLAW_MODEL=abab6.5s-chat
171
- # 是开发者的真实配置,回归不继承(否则路由判定随机器变化)。
172
135
  FOXCLAW_PROVIDER="", FOXCLAW_MODEL="",
173
- # 产品默认 HKC_EMBEDDING=auto(真语义),但回归锁 stub 保确定+快;
174
- # 真语义单独由 test_semantic.py 显式验证。
175
136
  HKC_EMBEDDING="stub")
176
137
  print("=" * 64)
177
138
  print("Foxclaw · 全量回归测试")
@@ -194,34 +155,16 @@ def main():
194
155
  if not path.exists():
195
156
  results.append((desc, "缺失", 0)); continue
196
157
  t0 = time.time()
197
- # 每个文件用**独立的 basetemp**,不共用 %TEMP%\pytest-of-<user> 根目录。
198
- # 为什么:Windows 上该根目录一旦留下损坏的 reparse point(实测 pytest-current
199
- # unlink 报 WinError 5),pytest 会在 sessionfinish 的 cleanup_numbered_dir 阶段
200
- # 抛 PermissionError —— 断言全过也返回非 0,7 个文件同时假红,真回归被淹没。
201
- # 显式 basetemp 后 pytest 不再遍历/清理共用根目录;目录必须预先存在(pytest 不会
202
- # 为 --basetemp 建父目录,缺了直接 FileNotFoundError),故用 mkdtemp 建好再传。
203
158
  _bt = Path(tempfile.mkdtemp(prefix="foxclaw-pt-"))
204
159
  try:
205
- # 统一走 pytest(每文件独立子进程,隔离模块级单例)。
206
160
  _cmd = [sys.executable, "-m", "pytest", str(path), "-q",
207
161
  f"--basetemp={_bt}"]
208
- # 显式 utf-8 解码子进程输出:子进程已被 PYTHONUTF8=1 强制输出 utf-8,
209
- # 父进程若用 Windows 默认 GBK 解码会 UnicodeDecodeError(模型加载进度条等
210
- # 含非 GBK 字节)→ r.stdout 变 None → 后续拼接 TypeError。errors=replace 兜底。
211
162
  r = subprocess.run(_cmd,
212
163
  capture_output=True, text=True, timeout=300, env=env,
213
164
  encoding="utf-8", errors="replace")
214
165
  ok = r.returncode == 0
215
- # 简单判定:退出码 0 且输出里没有 Traceback
216
166
  if "Traceback" in (r.stdout + r.stderr):
217
167
  ok = False
218
- # 原生库偶发崩溃的精准重试:Windows 访问冲突 0xC0000005
219
- # 是 torch/FAISS/ST 在模型重加载或解释器 teardown 阶段的进程级崩溃——
220
- # 无 Python Traceback、与断言失败(exit=1)互不混淆,故只对它在同一干净
221
- # 环境下重试一次(批次4/7 均实锤:基线对照同样崩溃,与业务改动无关;
222
- # 手动小范围跑全绿,全量回归高内存压力下概率显著升高)。
223
- # 注意:subprocess 在 Windows 返回无符号 DWORD(0xC0000005=3221225477),
224
- # PowerShell $LASTEXITCODE 则按有符号显示(-1073741819),两种都表示同一崩溃。
225
168
  _ACCESS_VIOLATION = (3221225477, -1073741819)
226
169
  if not ok and r.returncode in _ACCESS_VIOLATION and \
227
170
  "Traceback" not in (r.stdout + r.stderr):
@@ -233,20 +176,14 @@ def main():
233
176
  print(f" ↻ {desc} 首次 0xC0000005 原生崩溃,重试通过(已知环境性偶发)")
234
177
  results.append((desc, "通过" if ok else "失败", time.time() - t0))
235
178
  if not ok:
236
- # 打印 15 行而非 3 行:pytest 的 collection error(如缺依赖)把原因
237
- # 放在 traceback 中段,只截最后 3 行会只剩「ERROR xxx.py」+「Interrupted」,
238
- # 在 CI 里完全无法定位(2026-10-17 实际踩过:CI 红但日志看不出缺 faiss)。
239
179
  tail = (r.stdout + r.stderr).strip().splitlines()[-15:]
240
180
  print(f" ✗ {desc} 失败:")
241
181
  for line in tail: print(f" {line}")
242
- # 失败时落盘完整输出,便于复现/定位偶发失败(尤其 teardown 期崩溃)。
243
182
  (here / f"_fail_{fn}.txt").write_text(
244
183
  r.stdout + r.stderr, encoding="utf-8")
245
184
  except subprocess.TimeoutExpired:
246
185
  results.append((desc, "超时", 300))
247
186
  finally:
248
- # basetemp 是本文件专用的一次性目录:正常结束由 pytest 自己清,
249
- # 子进程崩溃/超时会残留,这里统一回收。ignore_errors 兜 Windows 文件占用。
250
187
  shutil.rmtree(_bt, ignore_errors=True)
251
188
  print(f" {'✓' if results[-1][1]=='通过' else '✗'} {desc:<28} [{results[-1][1]}] {results[-1][2]:.0f}s")
252
189