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
package/index.js CHANGED
@@ -1,11 +1,4 @@
1
- /**
2
- * FoxClaw - a personal agent with memory.
3
- *
4
- * The npm package bundles the full Python project under `python/`; the CLI
5
- * (`npx foxclaw`) forwards to it. This module exposes the package metadata for
6
- * programs that only need the name/version.
7
- */
8
1
  export const name = "foxclaw";
9
- export const version = "0.1.2";
2
+ export const version = "0.1.3";
10
3
 
11
4
  export default { name, version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foxclaw",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "A personal agent with memory - a fox living in your device",
5
5
  "keywords": [
6
6
  "agent",
@@ -100,6 +100,9 @@ FOXCLAW_MEMORY_CHAIN=0
100
100
  # ---------- 运行参数(可选)----------
101
101
  # 数据目录
102
102
  FOXCLAW_DATA_DIR=./foxclaw_data
103
+ # `foxclaw skills install @owner/slug` 走的 ClawHub 地址。默认 https://clawhub.ai;
104
+ # 内网镜像或自建 registry 填这里。只在装技能时访问,平时不发任何请求。
105
+ FOXCLAW_CLAWHUB_REGISTRY=
103
106
  # 导入白名单:/api/{finance,learning,itinerary}/import 的 csv_path 只允许数据目录内的文件。
104
107
  # 要从别处导入(如下载目录),把目录填进来,逗号分隔。
105
108
  FOXCLAW_IMPORT_ROOTS=
@@ -107,6 +110,11 @@ FOXCLAW_IMPORT_ROOTS=
107
110
  # Harness 影子校准轮数(越小越快进入拦截模式)
108
111
  FOXCLAW_SHADOW_ROUNDS=20
109
112
 
113
+ # 新版本检查。默认关:foxclaw 本地优先,不该在你不说的情况下外呼。
114
+ # 设 1 后启动/首次打开界面时查一次 PyPI(pypi.org/pypi/foxclaw/json),24h 缓存,
115
+ # 有新版时顶栏版本号旁出现提示;只发这一个 GET,不带任何本机信息。
116
+ FOXCLAW_UPDATE_CHECK=0
117
+
110
118
  # 不联网校验模型版本。模型已缓存但机器连不上 huggingface.co 时打开,可跳过
111
119
  # 每次构造前 5 次重试的空等(约 20-40s);模型还没下载过时别开,否则无法自动下载。
112
120
  # HF_HUB_OFFLINE=1
@@ -40,7 +40,19 @@ jobs:
40
40
  with:
41
41
  python-version: ${{ matrix.python-version }}
42
42
 
43
- - name: Install toolchain
43
+ - name: Install toolchain (pinned, py3.12)
44
+ if: matrix.python-version == '3.12'
45
+ # 基线版本按 requirements.txt 装:那是 uv 从 pyproject 解析出的完整闭包,
46
+ # 与本机 .venv 一致。dev extra 随后补装,pip 不会改写已满足的 pin。
47
+ run: |
48
+ python -m pip install --upgrade pip
49
+ pip install -r requirements.txt
50
+ pip install -e ".[dev]"
51
+
52
+ - name: Install toolchain (latest, py3.14)
53
+ if: matrix.python-version == '3.14'
54
+ # 3.14 腿刻意不读 requirements.txt:它的职责是发现「依赖在新解释器上解析/安装失败」,
55
+ # 跟着 pin 会把这个信号一起锁死。
44
56
  run: |
45
57
  python -m pip install --upgrade pip
46
58
  pip install -e ".[dev]"
@@ -92,9 +104,11 @@ jobs:
92
104
  - name: Install dependencies
93
105
  run: |
94
106
  python -m pip install --upgrade pip
95
- # 单源安装:依赖以 pyproject.toml 为唯一来源,避免手写清单与它双份漂移。
107
+ # 单源:pyproject.toml 声明依赖,requirements.txt 是它解析出的锁定闭包(uv 生成)。
108
+ # 先装锁再装本体,回归跑的就是本机 .venv 同一套版本,而不是当天 PyPI 的最新版。
96
109
  # HMR/HKC 是 vendor 内嵌、走 sys.path 加载,不是 PyPI 依赖(已在 pyproject 注明)。
97
110
  # dev extra 提供 pytest + openpyxl/python-docx(默认回归 test_file_ingest/test_domain_import 硬依赖)。
111
+ pip install -r requirements.txt
98
112
  pip install -e ".[dev]"
99
113
 
100
114
  - name: Warm embedding cache
@@ -120,3 +134,34 @@ jobs:
120
134
  coverage combine
121
135
  coverage report
122
136
  coverage xml
137
+
138
+ audit:
139
+ # 依赖漏洞门。此前 SCA 只覆盖 Dockerfile 与前端 package.json,Python 侧完全空白 ——
140
+ # 实测全局环境 34 个包挂着 278 条已知漏洞(pyjwt 15、starlette 14、filelock 9…),
141
+ # 而同一份 pyproject 干净解析出来是 0 条,说明问题在"从不升级的运行环境"而非依赖声明。
142
+ #
143
+ # 审计 requirements.txt 而非运行环境:它是「实际会被装出来的东西」,结果可复现,
144
+ # 且不依赖扫描机的环境状态。此门红了怎么修:
145
+ # 1) 升级 pyproject 里对应依赖的下限/上限;
146
+ # 2) uv pip compile pyproject.toml --universal -o requirements.txt 重新生成并提交
147
+ # (--universal 必须带:否则 Windows 专属包会写成无条件依赖,本作业在 Linux 上装不动);
148
+ # 3) 确无可用修复版本时,在下面 --ignore-vuln 逐条登记 ID + 原因,不要整门关掉。
149
+ runs-on: ubuntu-latest
150
+ timeout-minutes: 10
151
+ steps:
152
+ - uses: actions/checkout@v4
153
+
154
+ - name: Set up Python
155
+ uses: actions/setup-python@v5
156
+ with:
157
+ python-version: "3.12"
158
+
159
+ - name: Install pip-audit
160
+ run: |
161
+ python -m pip install --upgrade pip
162
+ pip install "pip-audit>=2.7"
163
+
164
+ - name: Audit pinned runtime dependencies
165
+ # --no-deps:requirements.txt 已是 uv 解析好的完整闭包(含全部传递依赖),
166
+ # 不需要 pip-audit 再解析一遍 —— 不加会静默跑几分钟且可能超时。
167
+ run: pip-audit -r requirements.txt --no-deps --progress-spinner off
@@ -0,0 +1,57 @@
1
+ # Changelog
2
+
3
+ Changes from the first public release 0.1.0 to the current version, newest first.
4
+
5
+ Chinese version: [CHANGELOG_CN.md](CHANGELOG_CN.md).
6
+
7
+ ## 0.1.3 — 2026-11-11
8
+
9
+ Bilingual interface, and Settings moved where it belongs.
10
+
11
+ **Interface**
12
+
13
+ - New i18n layer (`lib/i18n.js` plus en/zh dictionaries): sidebar, menus, chat, stage, settings and toast strings all resolve through the dictionaries; a missing key falls back to the key, so nothing renders blank.
14
+ - Settings gains "Interface → Language" with instant Chinese / English switching, persisted in `localStorage` (`foxclawLang`) and kept across reloads.
15
+ - Date and number formatting follow the language (`zh-CN` / `en-US`), and `<html lang>` stays in sync.
16
+ - Settings moved out of the "More" popover into a pinned entry at the bottom of the left rail, separated by a rule and left unaffected by session-list scrolling.
17
+ - The version badge in the top bar reads `/api/system/info`; it no longer falls back to a hard-coded `v3.0`.
18
+
19
+ **Docs**
20
+
21
+ - README reconciled with the repository as it actually is: agent count, channels, ingest caps, chunk geometry, supported formats and internal links all verified one by one, with a test to keep them from drifting again.
22
+
23
+ ## 0.1.2 — 2026-11-10
24
+
25
+ Version consolidation and skill installation.
26
+
27
+ - Version number unified across five places (`pyproject.toml` / `foxclaw/__init__.py` / `npm/package.json` / `npm/index.js` / `frontend_src/package.json`), guarded by `tests/test_version_sync.py` so npm and PyPI cannot drift apart.
28
+ - `foxclaw skills install` accepts ClawHub / GitHub / URL / local archives; the tools panel can install an instruction skill straight from an uploaded `SKILL.md` or OpenClaw package.
29
+ - First run asks how to address you (editable in settings); an optional new-version check was added.
30
+ - `tools/sync_public.ps1` now builds the public tree directly instead of relying on a local clone.
31
+ - Type annotations closed out: mypy went from 645 to 0, and CI turned into a ratchet that may only go down.
32
+ - Explanatory comments stripped repo-wide, so the public tree no longer carries internal notes.
33
+
34
+ ## 0.1.1 — 2026-11-09
35
+
36
+ npm-only republish; there is no matching version bump in the repository.
37
+
38
+ - The npm package excludes internal docs (`docs/reports` and friends) and debug leftovers, aborting the pack when any are detected — 0.1.1 had shipped internal documents in the public package.
39
+ - `build.cjs` now runs before `npm pack`, fixing GitHub Release assets that were 2 KB empty shells.
40
+ - `pyproject` gained a readme, so the PyPI page is no longer description-less.
41
+ - `requirements.txt` is compiled with `uv pip compile --universal` so platform-specific dependencies carry markers; CI gained a dependency audit gate.
42
+ - MIT license and metadata added.
43
+
44
+ ## 0.1.0 — 2026-11-06
45
+
46
+ First public release, on both channels: PyPI `foxclaw` and npm `foxclaw`.
47
+
48
+ - Runtime: FastAPI service plus the `foxclaw` command-line entry point.
49
+ - Agents: multiple agents collapsed into three (assistant / office / knowledge); the rest were demoted to instruction skills.
50
+ - Knowledge (HKC) and memory (HMR) embedded via `vendor/`: knowledge is extractable and searchable, and review scheduling runs on SM-2.
51
+ - Governance: policy gate, audit hash chain, shadow learning and circuit breaker; import paths are allow-listed and skill side effects default to fail-closed.
52
+ - Config: typed reads instead of raw `.env`, and `foxclaw config check` turns a misconfiguration from a crash into a message.
53
+ - Security: DNS rebinding, browser SSRF and untrusted channel instructions closed off; channel path signatures plus one-shot nonces for sensitive actions.
54
+ - Pipeline: visible plans, reasoning emitted as its own SSE event, step-level checkpoints for resume-after-interrupt.
55
+ - Frontend: Vue3 three-column renderer, persistent feature entries in the left rail, dual-state inspector on the right.
56
+
57
+ > Both packages are **placeholders**: `vendor/` (HKC / HMR) is not shipped, so a fresh install only gets the importable skeleton. See [docs/RELEASE.md](docs/RELEASE.md).
@@ -0,0 +1,57 @@
1
+ # 更新日志
2
+
3
+ 从 0.1.0 首次公开到当前版本的变更记录,最新的排在最前面。
4
+
5
+ 英文版:[CHANGELOG.md](CHANGELOG.md)。
6
+
7
+ ## 0.1.3 — 2026-11-11
8
+
9
+ 界面双语化,并把「设置」放到该在的位置。
10
+
11
+ **界面**
12
+
13
+ - 新增 i18n 基建(`lib/i18n.js` + 中英字典),侧栏、菜单、对话、舞台、设置、提示文案统一走字典;缺词回退 key,不会渲染成空白。
14
+ - 设置面板新增「界面 → 语言」,中文 / English 即时切换,写入 `localStorage`(`foxclawLang`),刷新后保持。
15
+ - 日期与数字格式随语言切换(`zh-CN` / `en-US`),`<html lang>` 同步。
16
+ - 「设置」从「更多」弹层移到左栏底部常驻入口,带分隔线,不随会话列表滚动。
17
+ - 顶栏版本号改为读后端 `/api/system/info`,取不到时不再显示硬编码的 `v3.0`。
18
+
19
+ **文档**
20
+
21
+ - README 按仓库实际校准:智能体数量、渠道、摄取上限、分块几何、支持格式、内部链接全部逐条核对,并加测试防止再次漂移。
22
+
23
+ ## 0.1.2 — 2026-11-10
24
+
25
+ 版本号收口、技能安装成型。
26
+
27
+ - 版本号五处统一(`pyproject.toml` / `foxclaw/__init__.py` / `npm/package.json` / `npm/index.js` / `frontend_src/package.json`),并由 `tests/test_version_sync.py` 盯住,防 npm 与 PyPI 漂移。
28
+ - `foxclaw skills install` 支持 ClawHub / GitHub / URL / 本地包;工具面板可直接上传 `SKILL.md` 或 OpenClaw 包安装指令技能。
29
+ - 首次启动引导询问称呼,可在设置中修改;新增可选的新版本检查提示。
30
+ - `tools/sync_public.ps1` 改为直接构造公开树推远端,不再依赖本地克隆。
31
+ - 类型标注收口:mypy 从 645 降到 0,CI 改为棘轮门(只降不升)。
32
+ - 全仓剥离解释性注释,公开树下不再混入内部说明。
33
+
34
+ ## 0.1.1 — 2026-11-09
35
+
36
+ 只在 npm 通道补发,仓库内没有对应版本号的提交记录。
37
+
38
+ - npm 包排除 `docs/reports` 等内部文档与调试残留,自检命中即中止打包(0.1.1 曾把内部文档打进公开包)。
39
+ - `npm pack` 前先跑 `build.cjs`,修 GitHub Release 附件只有 2KB 空壳。
40
+ - 修 `pyproject` 缺 `readme`,PyPI 项目页不再没有项目描述。
41
+ - `requirements.txt` 改用 `uv pip compile --universal`,平台相关依赖带上 marker;CI 增加依赖审计门。
42
+ - 补 MIT 许可证与 metadata。
43
+
44
+ ## 0.1.0 — 2026-11-06
45
+
46
+ 首个公开版本,PyPI `foxclaw` 与 npm `foxclaw` 双通道。
47
+
48
+ - 运行时:FastAPI 服务 + `foxclaw` 命令行入口。
49
+ - 智能体:多智能体收敛为三(助手 / 办公 / 知识),其余能力下放为指令技能。
50
+ - 知识库(HKC)与记忆(HMR)以内嵌 `vendor/` 形式接入:知识可抽取、可检索,复习走 SM-2 排程。
51
+ - 治理层:策略门、审计哈希链、影子学习与断路器;导入路径白名单,技能副作用默认 fail-closed。
52
+ - 配置:从 `.env` 改为类型化读取,`foxclaw config check` 把「配置写错」从崩溃变成提示。
53
+ - 安全:堵 DNS rebinding、浏览器 SSRF、渠道陌生指令三个可利用面;渠道路径签名 + 动作一次性 nonce 确认。
54
+ - 链路:计划可见化、推理过程独立 SSE 事件、步骤级 checkpoint 断点续跑。
55
+ - 前端:Vue3 三栏渲染层,左栏功能入口常驻,右栏双态检视。
56
+
57
+ > 两个包都是**占位包**:`vendor/`(HKC / HMR)不入包,装完只能 import 骨架,完整运行时从仓库获取。详见 [docs/RELEASE.md](docs/RELEASE.md)。
package/python/README.md CHANGED
@@ -46,13 +46,22 @@ Keeps the system reliable under message redelivery, crashes, long tasks, and loo
46
46
  ## Quick start
47
47
 
48
48
  ```bash
49
- pip install fastapi uvicorn "httpx<0.28" openai cryptography websockets pyyaml numpy scikit-learn rich pydantic
49
+ python -m venv .venv # isolated env — don't pollute the system Python
50
+ .venv\Scripts\activate # macOS / Linux: source .venv/bin/activate
51
+ pip install -r requirements.txt # pinned closure generated from pyproject.toml
52
+ pip install -e . --no-deps # foxclaw itself, without re-resolving deps
50
53
  python tests/run_all.py # full regression (all green)
51
54
  export DEEPSEEK_API_KEY=sk-... # or ANTHROPIC_API_KEY; unset → stub
52
55
  python -m uvicorn foxclaw.api:app --port 8000
53
56
  ```
54
57
 
55
- See [docs/RUN.md](docs/RUN.md). Chinese docs: [README_CN.md](README_CN.md).
58
+ > `requirements.txt` is generated by `uv pip compile pyproject.toml --universal -o requirements.txt` — don't hand-edit.
59
+ > `--universal` is required: without it the compile is platform-specific and drags Windows-only packages
60
+ > (e.g. `pywin32`) into the list, which breaks installation on Linux CI. With it, platform deps carry
61
+ > `; sys_platform == ...` markers and pip skips what doesn't apply.
62
+ > Re-run after changing dependencies in `pyproject.toml`, otherwise the lock lags behind the declaration.
63
+
64
+ See [docs/RUN.md](docs/RUN.md). Chinese docs: [README_CN.md](README_CN.md). Release history: [CHANGELOG.md](CHANGELOG.md).
56
65
 
57
66
  > **Windows**: don't place the project under OneDrive-managed folders (Documents/Desktop/Pictures); Python can't create dirs inside redirect placeholders. Use a path like `C:\foxclaw`.
58
67
 
@@ -9,14 +9,16 @@ Foxclaw: 记忆 = 持续认知运行时,智能体 = 会推理 · 会学
9
9
 
10
10
  ## 一、这是什么
11
11
 
12
- Foxclaw 不是"又一个智能体框架",而是一个真正记得住事的个人智能体;技术上它是一个智能体运行时。它建立在 HMR(Foxclaw 记忆运行时)之上,核心护城河独立于任何大模型:
12
+ 主流智能体框架把记忆当存储:开新会话就归零,记忆只是检索。Foxclaw 把记忆做成**持续运行的认知层**——推理、校准、学习都发生在这一层,并且与 LLM 彻底解耦:换模型不影响判断力。
13
+
14
+ 它建立在 HMR(Foxclaw 记忆运行时)之上,四件事构成护城河:
13
15
 
14
16
  - **推理链(ThoughtChain)** —— 每个智能体的推理轨迹是可审计、可对比的有向图,不是普通日志
15
- - **线束(Harness)** —— 跨层约束与校准:三维漂移检测(语义/工具/范围)+ 影子模式自校准 + 策略自学习
16
- - **演化(Evolution)** —— 每次线束截断都让策略学习,系统越用越准
17
- - **运行时治理** —— 幂等、崩溃恢复、循环检测等,保证系统在真实运行中可靠、可审计、不丢不重
17
+ - **线束(Harness)** —— 跨层约束与校准:三维漂移检测(语义 / 工具 / 范围)+ 影子模式自校准 + 策略自学习
18
+ - **演化(Evolution)** —— 每次线束截断都喂给策略,系统越用越准
19
+ - **运行时治理** —— 幂等、崩溃恢复、循环检测,保证真实运行中可靠、可审计、不丢不重
18
20
 
19
- 三个智能体:主管(协调)、财务(理财)、办公学习(学习 + 日程行程)。每个拥有独立记忆与策略演化,通过 Skill 接入层挂载外部生态,通过渠道层接入主流消息平台。原「助手」「行政」已**下放为指令技能**(`skills/general-assistant`、`skills/schedule-itinerary`),按需挂载,不再单列 Agent。
21
+ 三个智能体:**主管**(协调)、**财务**(理财)、**办公学习**(学习 + 日程行程)。各自持有隔离记忆与策略演化,通过 Skill 层挂载外部生态,通过渠道层接入四个消息平台。早期的「助手」「行政」已**下放为指令技能**(`skills/general-assistant`、`skills/schedule-itinerary`),按需挂载,不再单列 Agent。
20
22
 
21
23
  ## 二、三个智能体与领域内核
22
24
 
@@ -69,11 +71,12 @@ foxclaw/
69
71
  │ ├── core/ thought_chain / memory_adapter / model_router /
70
72
  │ │ system_bus / truth_pipeline / token_meter /
71
73
  │ │ web_search / compaction / idempotency / recovery
72
- │ ├── kernel/ 运行时内核:调度 / 事件 / 能力 / 生命周期 / 准入
74
+ │ ├── kernel/ 运行时内核:调度 / 进程 / 能力 / 准入(spine + sentinel)
73
75
  │ ├── pipeline/ planning/ 任务执行管线 + 规划原语
74
- │ ├── cognitive/ knowledge/ 领域推理 + 知识接入
75
- │ ├── agents/ base.py(统一 run_task 模板) + agents.py(五智能体)
76
- │ ├── harness/ harness.py(三维漂移) + loop_detection.py
76
+ │ ├── cognitive/ knowledge/ 领域推理 + 真相结晶
77
+ │ ├── agents/ base.py(CognitiveAgent 模板)+ agents.py
78
+ │ │ + impl/(财务 / 办公 / 主管 —— 三个智能体)
79
+ │ ├── harness/ harness.py(三维漂移)+ loop_detection.py + 策略自学习
77
80
  │ ├── finance/ 财务内核 + 三件套(evidence/graph/reconcile)
78
81
  │ ├── learning/ 学习内核(SM-2 + 知识图谱)
79
82
  │ ├── itinerary/ 行程内核(TSP + 高德)
@@ -81,12 +84,11 @@ foxclaw/
81
84
  │ ├── skills/ Skill 接入层 + 权限(permission)/钩子/断路器/循环防护
82
85
  │ ├── search/ HSR 认知搜索(HMR 记忆 + HKC 知识 + 联网,融入)
83
86
  │ ├── browser/ HIR 浏览器子系统(AI 用的浏览器,融入)
84
- │ ├── orchestration/ 跨 Agent 编排(P3 已去领域硬编码,通用)
85
87
  │ ├── capability/ governance/ embedding 单例 / 治理中间件
86
88
  ├── vendor/hmr/ vendor/hkc/ HMR v2.0 记忆运行时 + HKC 知识核心(已内嵌)
87
89
  ├── examples/ 样例数据
88
- ├── tests/ 76 个测试文件(全部 pytest)+ run_all.py
89
- └── docs/ RUN / CHANNELS / GOVERNANCE / 配置指南(公开)
90
+ ├── tests/ 全部 pytest 组织 + run_all.py 一键跑全量回归
91
+ └── docs/ RUN / RUN_CN / CHANNELS / GOVERNANCE / RELEASE / 配置指南
90
92
  ```
91
93
 
92
94
  ## 六、环境要求
@@ -97,12 +99,13 @@ foxclaw/
97
99
  ## 七、快速开始
98
100
 
99
101
  ```bash
100
- # 1. 安装依赖
101
- pip install fastapi uvicorn "httpx<0.28" openai cryptography websockets pyyaml numpy scikit-learn rich pydantic
102
- # (Windows 上 pip 装系统包可能需要 --break-system-packages)
102
+ # 1. 建隔离环境 —— 不要直接装进系统 Python,否则会和机器上其它项目互相污染
103
+ python -m venv .venv
104
+ .venv\Scripts\activate # macOS / Linux: source .venv/bin/activate
103
105
 
104
- # 2. 可选:更精确的语义检测(约 800MB,不装则降级 n-gram)
105
- pip install sentence-transformers
106
+ # 2. 安装锁定版本的依赖(含 torch / faiss,约 1GB)
107
+ pip install -r requirements.txt
108
+ pip install -e . --no-deps # 装 foxclaw 本体,不再重解析依赖
106
109
 
107
110
  # 3. 验证认知运行时(无需 API key)
108
111
  python tests/run_all.py # 全量回归(全绿)
@@ -112,7 +115,14 @@ export DEEPSEEK_API_KEY=sk-... # 或 ANTHROPIC_API_KEY;Windows: $env:DEEPSEEK_A
112
115
  python -m uvicorn foxclaw.api:app --port 8000
113
116
  ```
114
117
 
115
- 详见 [docs/RUN_CN.md](docs/RUN_CN.md)。
118
+ > `requirements.txt` 由 `uv pip compile pyproject.toml --universal -o requirements.txt` 从 `pyproject.toml` 生成,
119
+ > **不要手改**。`--universal` 不能省:不加的话解析结果只针对当前平台,会把 Windows 专属包
120
+ > (如 `pywin32`)写成无条件依赖,Linux CI 直接装不上。加了它平台相关的包才带
121
+ > `; sys_platform == ...` 标记,pip 会自动跳过不适用项。
122
+ > 改完 `pyproject.toml` 里的依赖后重跑一次,否则锁定清单会滞后于声明,
123
+ > SCA 扫描和 CI 装的都会是旧版本。
124
+
125
+ 详见 [docs/RUN_CN.md](docs/RUN_CN.md)。版本变更:[CHANGELOG_CN.md](CHANGELOG_CN.md)。
116
126
 
117
127
  ### 开发常用命令(Windows / PowerShell 一行重启)
118
128
 
@@ -127,7 +137,9 @@ function restart-foxclaw {
127
137
  $p=(Get-NetTCPConnection -LocalPort 8000 -State Listen -EA SilentlyContinue).OwningProcess
128
138
  if($p){Stop-Process -Id $p -Force; Start-Sleep 1}
129
139
  Set-Location <你的项目目录>
130
- foxclaw serve
140
+ # 显式走 .venv,别用 PATH 里那个系统 Python 的 foxclaw.exe ——
141
+ # 系统环境常常是很久以前装的,挂着已知漏洞(实测 278 条)。
142
+ .\.venv\Scripts\foxclaw.exe serve
131
143
  }
132
144
 
133
145
  # ③ 重开 PowerShell 让配置生效(只在改了 $PROFILE 后需要)
@@ -167,7 +179,7 @@ docker run -d --name foxclaw \
167
179
  -v foxclaw_data:/app/foxclaw_data \
168
180
  foxclaw
169
181
 
170
- # 容器内跑全量回归(76 项,验证镜像健康)
182
+ # 容器内跑全量回归(验证镜像健康)
171
183
  docker run --rm foxclaw python tests/run_all.py
172
184
  ```
173
185
 
@@ -39,28 +39,23 @@ def audit_float_accumulation():
39
39
  print("\n[1/5] 浮点累加精度对比 (build 一次 vs 累加 1000 次) ...")
40
40
  corpus = gen_corpus(1000)
41
41
 
42
- # 方法 A: build 一次
43
42
  idx_a = NewBM25()
44
43
  idx_a.build(corpus)
45
44
 
46
- # 方法 B: 1000 次 append_ku
47
45
  idx_b = NewBM25()
48
46
  for ku in corpus:
49
47
  idx_b.append_ku(ku)
50
48
 
51
- # 比 avgdl
52
49
  print(f" build 一次 avgdl = {idx_a._avgdl:.10f}")
53
50
  print(f" 1000 次累加 avgdl = {idx_b._avgdl:.10f}")
54
51
  diff_avgdl = abs(idx_a._avgdl - idx_b._avgdl)
55
52
  print(f" 差 = {diff_avgdl:.2e} (rel {diff_avgdl/idx_a._avgdl:.2e})")
56
53
 
57
- # 比 _idf_sum
58
54
  print(f" build 一次 _idf_sum = {idx_a._idf_sum:.10f}")
59
55
  print(f" 1000 次累加 _idf_sum = {idx_b._idf_sum:.10f}")
60
56
  diff_idf = abs(idx_a._idf_sum - idx_b._idf_sum)
61
57
  print(f" 差 = {diff_idf:.2e} (rel {diff_idf/max(abs(idx_a._idf_sum),1e-10):.2e})")
62
58
 
63
- # 搜同一 query,top-3 是否一致
64
59
  q = "topic0_3 topic1_7"
65
60
  r_a = sorted([(r.ku_id, round(r.score, 8)) for r in idx_a.search(q, 10)])
66
61
  r_b = sorted([(r.ku_id, round(r.score, 8)) for r in idx_b.search(q, 10)])
@@ -76,7 +71,6 @@ def audit_pickle_schema_fallback():
76
71
  """2: pickle schema 兼容(老 pickle / 损坏 pickle fallback)"""
77
72
  print("\n[2/5] pickle schema 兼容 + 损坏文件 fallback ...")
78
73
  tmp = "_tmp_audit.pkl"
79
- # 正常 save/load
80
74
  idx = NewBM25()
81
75
  idx.build(gen_corpus(100))
82
76
  idx.save(tmp)
@@ -84,7 +78,6 @@ def audit_pickle_schema_fallback():
84
78
  ok = idx2.load(tmp)
85
79
  print(f" 正常 save/load: ok={ok}, size={idx2.size()} {'PASS' if ok and idx2.size()==100 else 'FAIL'}")
86
80
 
87
- # 损坏文件
88
81
  with open(tmp, 'wb') as f:
89
82
  f.write(b'garbage data not a pickle')
90
83
  idx3 = NewBM25()
@@ -92,14 +85,12 @@ def audit_pickle_schema_fallback():
92
85
  print(f" 损坏文件 load: ok={ok3} (应该返 False, 不抛异常) {'PASS' if ok3 == False else 'FAIL'}")
93
86
  print(f" 损坏后 idx3.size() = {idx3.size()} (应该 0, 已 fallback) {'PASS' if idx3.size() == 0 else 'FAIL'}")
94
87
 
95
- # schema 不匹配(手写一个旧版结构)
96
88
  with open(tmp, 'wb') as f:
97
89
  pickle.dump({'old_version': True, 'ku_ids': [], 'corpus': []}, f)
98
90
  idx4 = NewBM25()
99
91
  ok4 = idx4.load(tmp)
100
92
  print(f" schema 不匹配: ok={ok4} (应该返 False) {'PASS' if ok4 == False else 'FAIL'}")
101
93
 
102
- # 不存在文件
103
94
  if os.path.exists(tmp):
104
95
  os.remove(tmp)
105
96
  idx5 = NewBM25()
@@ -158,19 +149,15 @@ def audit_clear_idempotent():
158
149
  idx.clear()
159
150
  print(f" clear 后: {idx.size()} (应该 0) {'PASS' if idx.size()==0 else 'FAIL'}")
160
151
 
161
- # 空 search 不抛
162
152
  r = idx.search("any query", 10)
163
153
  print(f" 空 search: {len(r)} 个结果 (应该 0) {'PASS' if len(r)==0 else 'FAIL'}")
164
154
 
165
- # 二次 clear
166
155
  idx.clear()
167
156
  print(f" 二次 clear: size={idx.size()} (应该 0) {'PASS' if idx.size()==0 else 'FAIL'}")
168
157
 
169
- # 删不存在
170
158
  r = idx.remove_ku("ku_99999999")
171
159
  print(f" remove_ku 不存在: 返 {r} (应该 False) {'PASS' if r == False else 'FAIL'}")
172
160
 
173
- # search 空 query
174
161
  r = idx.search("", 10)
175
162
  print(f" search 空 query: {len(r)} 个结果 (应该 0) {'PASS' if len(r)==0 else 'FAIL'}")
176
163
 
@@ -186,7 +173,7 @@ def main():
186
173
 
187
174
  r1 = audit_float_accumulation()
188
175
  r2 = audit_pickle_schema_fallback()
189
- audit_append_ku_latency() # 打印即可
176
+ audit_append_ku_latency()
190
177
  r4 = audit_search_consistency()
191
178
  r5 = audit_clear_idempotent()
192
179
 
@@ -155,7 +155,6 @@ def main():
155
155
  else:
156
156
  print("\n[4/4] 跳过一致率(无 rank_bm25 对照)")
157
157
 
158
- # save/load roundtrip
159
158
  print("\n[bonus] save/load roundtrip ...")
160
159
  tmp = "_tmp_bm25.pkl"
161
160
  new_idx.save(tmp)
@@ -116,7 +116,6 @@ def main():
116
116
  print("BM25 压测: 5万/10万 corpus build + search + remove + save/load")
117
117
  print("=" * 60)
118
118
 
119
- # 5万
120
119
  idx, corpus = bench_build(50_000)
121
120
  queries = gen_queries(200)
122
121
  bench_search(idx, queries)
@@ -125,11 +124,8 @@ def main():
125
124
  bench_save_load(idx, tmp)
126
125
  os.remove(tmp)
127
126
 
128
- # 10万 (增量:在 5万 上 append 5万,模拟冷构建期分批)
129
127
  print(f"\n[build] +5万 增量 (5万 -> 10万) ...")
130
128
  extra_corpus = gen_corpus(50_000, seed=43)
131
- # 取后 5万 (id 范围 0-49999 是 5万 corpus;这里 gen 同一 seed 重叠,改 seed)
132
- # 实际:重新 gen 5万不同 id
133
129
  extra_corpus = []
134
130
  rng = random.Random(43)
135
131
  for i in range(50_000, 100_000):
@@ -14,8 +14,6 @@ from hkc.hkc_kde.extractor import Extractor
14
14
  from hkc.hkc_api.ingest_jobs import IngestJobRegistry
15
15
 
16
16
 
17
- # ── D1: IngestJobRegistry 4 thread 并发 ────────────────
18
-
19
17
  def d1_ingest_4_workers():
20
18
  """D1. 4 worker 真并发 peak=4,4 任务 ~0.3s 完成"""
21
19
  reg = IngestJobRegistry(max_workers=4)
@@ -36,7 +34,6 @@ def d1_ingest_4_workers():
36
34
  t0 = time.time()
37
35
  for j in jobs:
38
36
  reg.submit(j, work)
39
- # wait done
40
37
  while True:
41
38
  statuses = [reg.get(j.job_id)["status"] for j in jobs]
42
39
  if all(s == "done" for s in statuses):
@@ -49,8 +46,6 @@ def d1_ingest_4_workers():
49
46
  print(f" D1 PASS: peak={peak[0]}, 4 jobs in {elapsed*1000:.0f}ms (串行需 1.2s)")
50
47
 
51
48
 
52
- # ── D2: Extractor 16 chunk 限流雪崩 ────────────────────
53
-
54
49
  def d2_429_snowball():
55
50
  """D2. 16 chunk × 4 worker × 100% 429 永不成功,验证不死循环 + 总调用有上界"""
56
51
  state = {"calls": 0}
@@ -62,8 +57,6 @@ def d2_429_snowball():
62
57
  raise err
63
58
 
64
59
  ext = Extractor(provider="anthropic", model="m")
65
- # 替换 _extract_chunk:走 _retry_llm 但传极小 base_delay 测试用
66
- # 同时 monkey-patch time.sleep 避免真睡
67
60
  import hkc.hkc_kde.extractor as ex_mod
68
61
  orig_sleep = ex_mod.time.sleep
69
62
  sleeps = []
@@ -88,7 +81,6 @@ def d2_429_snowball():
88
81
  result = ext.extract(chunks)
89
82
  elapsed = time.time() - t0
90
83
 
91
- # 期望:16 chunk 全 fail,总调用 = 16 * (1+3 retry) = 64,无死循环
92
84
  success = sum(1 for item in result.items if item is not None)
93
85
  assert success == 0, f"expected 0 success, got {success}"
94
86
  assert state["calls"] == 64, f"snowball: expected 64 calls, got {state['calls']}"
@@ -99,17 +91,13 @@ def d2_429_snowball():
99
91
  ex_mod.time.sleep = orig_sleep
100
92
 
101
93
 
102
- # ── D3: progress_cb 线程安全 ─────────────────────────
103
-
104
94
  def d3_progress_cb_thread_safe():
105
95
  """D3. progress_cb 在 as_completed 循环调,主线程串行;16 chunk 计数无重复无漏"""
106
96
  ext = Extractor(provider="anthropic", model="m")
107
97
 
108
- # 替换 _extract_chunk 为 fast mock:50% 概率 fail(模拟 chunk 失败)
109
98
  import random
110
99
  random.seed(42)
111
100
  def mock_extract(chunk, timeout=60.0):
112
- # 永远返 RawExtraction
113
101
  from hkc.hkc_kde.models import RawExtraction
114
102
  return RawExtraction()
115
103
  ext._extract_chunk = mock_extract
@@ -131,21 +119,16 @@ def d3_progress_cb_thread_safe():
131
119
  chunks = [MockChunk(i) for i in range(16)]
132
120
  result = ext.extract(chunks, progress_cb=cb)
133
121
 
134
- # 验证:done_calls 长度 16(每个 chunk 一次)
135
122
  assert len(done_calls) == 16, f"expected 16 callbacks, got {len(done_calls)}"
136
- # 验证:1..16 各一次(set 大小 = 16,排序后 1..16)
137
123
  assert sorted(done_calls) == list(range(1, 17)), \
138
124
  f"expected processed 1..16, got {sorted(done_calls)}"
139
125
  print(f" D3 PASS: {len(done_calls)} callbacks, all 1..16 unique")
140
126
 
141
127
 
142
- # ── D4: max_retries 可调 ──────────────────────────────
143
-
144
128
  def d4_max_retries_configurable():
145
129
  """D4. _retry_llm 的 max_retries 真的生效"""
146
130
  ext = Extractor(provider="mock", model="m")
147
131
 
148
- # 测 max_retries=2(默认 3):4 次后 raise
149
132
  call_count = [0]
150
133
  def always_fail():
151
134
  call_count[0] += 1
@@ -153,7 +136,6 @@ def d4_max_retries_configurable():
153
136
  err.status_code = 429
154
137
  raise err
155
138
 
156
- # 用 monkey-patch 把 time.sleep 替换掉,这样不会真睡
157
139
  import hkc.hkc_kde.extractor as ex_mod
158
140
  orig_sleep = ex_mod.time.sleep
159
141
  sleeps = []
@@ -164,7 +146,6 @@ def d4_max_retries_configurable():
164
146
  assert False, "expected raise"
165
147
  except Exception:
166
148
  pass
167
- # max_retries=2 + 1 = 3 次尝试
168
149
  assert call_count[0] == 3, f"max_retries=2 expected 3 calls, got {call_count[0]}"
169
150
  assert len(sleeps) == 2, f"max_retries=2 expected 2 sleeps, got {len(sleeps)}"
170
151
  print(f" D4 PASS: max_retries=2 -> 3 calls, 2 sleeps")
@@ -172,8 +153,6 @@ def d4_max_retries_configurable():
172
153
  ex_mod.time.sleep = orig_sleep
173
154
 
174
155
 
175
- # ── D5: retry + progress_cb 顺序 ─────────────────────
176
-
177
156
  def d5_retry_no_progress_leak():
178
157
  """D5. retry 期间 progress_cb 仍只调 1 次/chunk(不管 retry 几次)"""
179
158
  import time as time_mod
@@ -209,9 +188,7 @@ def d5_retry_no_progress_leak():
209
188
  cb_count[0] += 1
210
189
  chunks = [MockChunk(i) for i in range(8)]
211
190
  result = ext.extract(chunks, progress_cb=cb)
212
- # 不管 retry 几次,每个 chunk 调 1 次 progress_cb
213
191
  assert cb_count[0] == 8, f"expected 8 progress, got {cb_count[0]}"
214
- # 8 chunk 全 fail,总调用 = 8 * 4 = 32
215
192
  assert state["calls"] == 32, f"expected 32 calls, got {state['calls']}"
216
193
  success = sum(1 for item in result.items if item is not None)
217
194
  assert success == 0
@@ -21,7 +21,6 @@ from pathlib import Path
21
21
 
22
22
  sys.path.insert(0, str(Path(__file__).parent.parent))
23
23
 
24
- # 关闭联网触发(chaos 只测 LLM 咽喉,不触发搜索)
25
24
  import foxclaw.core.web_search as ws # noqa: E402
26
25
  ws.needs_search = lambda q: False
27
26
 
@@ -37,7 +36,7 @@ def _make_router(primary="deepseek", fallback=None):
37
36
  if fallback:
38
37
  os.environ[PROVIDER_ENV[fallback]] = "chaos-test-key"
39
38
  r = ModelRouter(provider=primary)
40
- r._client = object() # 使 is_stub == False
39
+ r._client = object()
41
40
  r._clients[primary] = object()
42
41
  if fallback:
43
42
  r._clients[fallback] = object()
@@ -87,11 +86,11 @@ def case4_circuit_breaker():
87
86
  """[4] 断路器:provider 失败后进入冷却,立即重试被跳过(不再紧密重试)。"""
88
87
  r = _make_router("deepseek")
89
88
  r._call_provider = _boom
90
- r.complete(_SYS, _MSG) # 第一次失败 → 进入 cooldown
89
+ r.complete(_SYS, _MSG)
91
90
  cooled = "deepseek" in r._cooldown
92
91
  t0 = time.perf_counter()
93
- r.complete(_SYS, _MSG) # 第二次:cooldown 未过期 → 直接跳过,不等超时
94
- fast = (time.perf_counter() - t0) < 0.5 # 跳过热 provider,应远快于真实超时
92
+ r.complete(_SYS, _MSG)
93
+ fast = (time.perf_counter() - t0) < 0.5
95
94
  ok = cooled and fast and r.is_degraded()
96
95
  return ok, (f"冷却中={cooled} 跳过耗时={((time.perf_counter()-t0)*1000):.0f}ms"), "断路器生效"
97
96
 
@@ -101,11 +100,10 @@ def case5_recovery():
101
100
  r = _make_router("deepseek")
102
101
  r._call_provider = _boom
103
102
  r.complete(_SYS, _MSG)
104
- assert "deepseek" in r._cooldown # 先确认在冷却
105
- r._cooldown["deepseek"] = 0 # 模拟冷却过期
103
+ assert "deepseek" in r._cooldown
104
+ r._cooldown["deepseek"] = 0
106
105
  r._call_provider = lambda *a, **k: ("恢复后的正常回复", None)
107
106
  out = r.complete(_SYS, _MSG)
108
- # 注:degraded 是「曾降级」的累积运维标志(不因恢复清零),恢复语义看「解冻 + 成功返回」。
109
107
  ok = (out == "恢复后的正常回复") and ("deepseek" not in r._cooldown)
110
108
  return ok, ("解冻=" + str("deepseek" not in r._cooldown)), out[:40]
111
109
 
@@ -26,7 +26,6 @@ from foxclaw.core.model_router import ModelRouter # noqa: E402
26
26
  _SYS = "你是 Foxclaw 助手。"
27
27
  _MSG = [{"role": "user", "content": "请只回复两个字:你好"}]
28
28
  _MAX_TOKENS = 64
29
- # stub/故障 的特征文案(出现即视为"非真实成功")
30
29
  _BAD_MARKERS = ("【未执行】", "【模型返回为空】", "【全部模型失败】", "【模型流式中断】", "STUB")
31
30
 
32
31