foxclaw 0.1.0 → 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 (514) hide show
  1. package/README.md +54 -29
  2. package/bin/foxclaw.cjs +51 -0
  3. package/index.js +4 -10
  4. package/package.json +46 -38
  5. package/python/.dockerignore +35 -0
  6. package/python/.env.example +173 -0
  7. package/python/.gitattributes +46 -0
  8. package/python/.github/workflows/ci.yml +167 -0
  9. package/python/.github/workflows/release.yml +183 -0
  10. package/python/CHANGELOG.md +57 -0
  11. package/python/CHANGELOG_CN.md +57 -0
  12. package/python/Dockerfile +64 -0
  13. package/python/LICENSE +21 -0
  14. package/python/MANIFEST.in +14 -0
  15. package/python/README.md +201 -0
  16. package/python/README_CN.md +336 -0
  17. package/python/bench/bm25_audit.py +186 -0
  18. package/python/bench/bm25_regression.py +177 -0
  19. package/python/bench/bm25_stress.py +155 -0
  20. package/python/bench/cd_audit.py +215 -0
  21. package/python/bench/chaos.py +140 -0
  22. package/python/bench/concurrency.py +103 -0
  23. package/python/bench/e2e_real_models.py +94 -0
  24. package/python/bench/llm_retry_test.py +241 -0
  25. package/python/bench/load_test.py +193 -0
  26. package/python/bench/vector_ivf_upgrade.py +128 -0
  27. package/python/docs/CHANNELS.md +195 -0
  28. package/python/docs/GOVERNANCE.md +164 -0
  29. package/python/docs/RELEASE.md +110 -0
  30. package/python/docs/RUN.md +75 -0
  31. package/python/docs/RUN_CN.md +121 -0
  32. package/python/docs//351/205/215/347/275/256/346/214/207/345/215/227.md +152 -0
  33. package/python/evals/__init__.py +0 -0
  34. package/python/evals/governance/README.md +61 -0
  35. package/python/evals/governance/__init__.py +0 -0
  36. package/python/evals/governance/cases.py +115 -0
  37. package/python/evals/governance/compare_embeddings.py +94 -0
  38. package/python/evals/governance/convergence.svg +11 -0
  39. package/python/evals/governance/report.json +371 -0
  40. package/python/evals/governance/run_evals.py +368 -0
  41. package/python/examples/governance_middleware_demo.py +72 -0
  42. package/python/examples/langgraph_governance_demo.py +104 -0
  43. package/python/examples/sample_itinerary.csv +6 -0
  44. package/python/examples/sample_knowledge.csv +9 -0
  45. package/python/examples/sample_transactions.csv +14 -0
  46. package/python/foxclaw/__init__.py +408 -0
  47. package/python/foxclaw/agents/__init__.py +12 -0
  48. package/python/foxclaw/agents/agents.py +35 -0
  49. package/python/foxclaw/agents/base.py +794 -0
  50. package/python/foxclaw/agents/impl/__init__.py +1 -0
  51. package/python/foxclaw/agents/impl/_helpers.py +70 -0
  52. package/python/foxclaw/agents/impl/finance.py +231 -0
  53. package/python/foxclaw/agents/impl/office.py +350 -0
  54. package/python/foxclaw/agents/impl/supervisor.py +592 -0
  55. package/python/foxclaw/agents/mixins/_context.py +128 -0
  56. package/python/foxclaw/agents/mixins/augment.py +143 -0
  57. package/python/foxclaw/agents/mixins/llm.py +67 -0
  58. package/python/foxclaw/agents/mixins/memory.py +41 -0
  59. package/python/foxclaw/agents/mixins/preference.py +131 -0
  60. package/python/foxclaw/agents/mixins/prompt.py +71 -0
  61. package/python/foxclaw/agents/mixins/skillbox.py +58 -0
  62. package/python/foxclaw/agents/mixins/tool_exec.py +417 -0
  63. package/python/foxclaw/api/__init__.py +224 -0
  64. package/python/foxclaw/api/_state.py +43 -0
  65. package/python/foxclaw/api/bootstrap.py +96 -0
  66. package/python/foxclaw/api/middleware.py +294 -0
  67. package/python/foxclaw/api/routes/ahs.py +404 -0
  68. package/python/foxclaw/api/routes/attachments.py +116 -0
  69. package/python/foxclaw/api/routes/browser.py +35 -0
  70. package/python/foxclaw/api/routes/domain.py +306 -0
  71. package/python/foxclaw/api/routes/knowledge.py +145 -0
  72. package/python/foxclaw/api/routes/llm_admin.py +449 -0
  73. package/python/foxclaw/api/routes/memory.py +105 -0
  74. package/python/foxclaw/api/routes/orchestration.py +39 -0
  75. package/python/foxclaw/api/routes/recovery.py +44 -0
  76. package/python/foxclaw/api/routes/review.py +266 -0
  77. package/python/foxclaw/api/routes/search.py +33 -0
  78. package/python/foxclaw/api/routes/system.py +311 -0
  79. package/python/foxclaw/api/routes/task.py +263 -0
  80. package/python/foxclaw/api/routes/ws.py +64 -0
  81. package/python/foxclaw/api/spine.py +52 -0
  82. package/python/foxclaw/browser/__init__.py +13 -0
  83. package/python/foxclaw/browser/action/__init__.py +1 -0
  84. package/python/foxclaw/browser/action/action_executor.py +50 -0
  85. package/python/foxclaw/browser/action/action_types.py +44 -0
  86. package/python/foxclaw/browser/action/action_verifier.py +68 -0
  87. package/python/foxclaw/browser/action/url_policy.py +143 -0
  88. package/python/foxclaw/browser/adapter/__init__.py +1 -0
  89. package/python/foxclaw/browser/adapter/base_adapter.py +23 -0
  90. package/python/foxclaw/browser/adapter/web_adapter.py +46 -0
  91. package/python/foxclaw/browser/driver/__init__.py +1 -0
  92. package/python/foxclaw/browser/driver/base_driver.py +61 -0
  93. package/python/foxclaw/browser/driver/playwright_driver.py +170 -0
  94. package/python/foxclaw/browser/perception/__init__.py +1 -0
  95. package/python/foxclaw/browser/perception/dom_extractor.py +42 -0
  96. package/python/foxclaw/browser/perception/element_indexer.py +56 -0
  97. package/python/foxclaw/browser/perception/semantic_reducer.py +33 -0
  98. package/python/foxclaw/browser/perception/snapshot.py +29 -0
  99. package/python/foxclaw/browser/service.py +144 -0
  100. package/python/foxclaw/browser/session/__init__.py +1 -0
  101. package/python/foxclaw/browser/session/session_manager.py +57 -0
  102. package/python/foxclaw/capability/__init__.py +12 -0
  103. package/python/foxclaw/capability/embedding_service.py +65 -0
  104. package/python/foxclaw/channels/__init__.py +138 -0
  105. package/python/foxclaw/channels/discord.py +175 -0
  106. package/python/foxclaw/channels/dispatcher.py +179 -0
  107. package/python/foxclaw/channels/feishu.py +215 -0
  108. package/python/foxclaw/channels/openclaw_bridge.py +151 -0
  109. package/python/foxclaw/channels/signing.py +187 -0
  110. package/python/foxclaw/channels/telegram.py +120 -0
  111. package/python/foxclaw/channels/weixin.py +215 -0
  112. package/python/foxclaw/cli.py +183 -0
  113. package/python/foxclaw/cognitive/__init__.py +4 -0
  114. package/python/foxclaw/cognitive/reasoner.py +81 -0
  115. package/python/foxclaw/cognitive/state.py +141 -0
  116. package/python/foxclaw/core/__init__.py +9 -0
  117. package/python/foxclaw/core/audit_chain.py +131 -0
  118. package/python/foxclaw/core/audit_sink.py +100 -0
  119. package/python/foxclaw/core/compaction.py +265 -0
  120. package/python/foxclaw/core/config.py +65 -0
  121. package/python/foxclaw/core/confirm_nonce.py +151 -0
  122. package/python/foxclaw/core/dispatch.py +27 -0
  123. package/python/foxclaw/core/envfile.py +48 -0
  124. package/python/foxclaw/core/failure_policy.py +142 -0
  125. package/python/foxclaw/core/gateway.py +81 -0
  126. package/python/foxclaw/core/governance_audit.py +171 -0
  127. package/python/foxclaw/core/idempotency.py +282 -0
  128. package/python/foxclaw/core/injection_guard.py +202 -0
  129. package/python/foxclaw/core/memory_adapter.py +489 -0
  130. package/python/foxclaw/core/metrics.py +88 -0
  131. package/python/foxclaw/core/model_router.py +985 -0
  132. package/python/foxclaw/core/paths.py +103 -0
  133. package/python/foxclaw/core/recovery.py +349 -0
  134. package/python/foxclaw/core/scheduler.py +141 -0
  135. package/python/foxclaw/core/secrets.py +131 -0
  136. package/python/foxclaw/core/sessions.py +155 -0
  137. package/python/foxclaw/core/settings.py +414 -0
  138. package/python/foxclaw/core/shared_write.py +186 -0
  139. package/python/foxclaw/core/steering_queue.py +154 -0
  140. package/python/foxclaw/core/system_bus.py +84 -0
  141. package/python/foxclaw/core/thought_chain.py +316 -0
  142. package/python/foxclaw/core/token_meter.py +231 -0
  143. package/python/foxclaw/core/tools.py +164 -0
  144. package/python/foxclaw/core/tracing.py +375 -0
  145. package/python/foxclaw/core/truth_pipeline.py +110 -0
  146. package/python/foxclaw/core/update_check.py +149 -0
  147. package/python/foxclaw/core/vec_recall_adapter.py +477 -0
  148. package/python/foxclaw/core/verify.py +173 -0
  149. package/python/foxclaw/core/web_search.py +218 -0
  150. package/python/foxclaw/finance/__init__.py +15 -0
  151. package/python/foxclaw/finance/evidence.py +149 -0
  152. package/python/foxclaw/finance/fx.py +98 -0
  153. package/python/foxclaw/finance/graph.py +179 -0
  154. package/python/foxclaw/finance/models.py +146 -0
  155. package/python/foxclaw/finance/nlparse.py +515 -0
  156. package/python/foxclaw/finance/policy.py +301 -0
  157. package/python/foxclaw/finance/reasoner.py +121 -0
  158. package/python/foxclaw/finance/reasoning.py +319 -0
  159. package/python/foxclaw/finance/reconcile.py +175 -0
  160. package/python/foxclaw/finance/runtime.py +500 -0
  161. package/python/foxclaw/governance/__init__.py +24 -0
  162. package/python/foxclaw/governance/middleware.py +176 -0
  163. package/python/foxclaw/harness/__init__.py +17 -0
  164. package/python/foxclaw/harness/_base.py +66 -0
  165. package/python/foxclaw/harness/_policy.py +340 -0
  166. package/python/foxclaw/harness/drift.py +77 -0
  167. package/python/foxclaw/harness/event_bus.py +28 -0
  168. package/python/foxclaw/harness/harness.py +358 -0
  169. package/python/foxclaw/harness/loop_detection.py +145 -0
  170. package/python/foxclaw/itinerary/__init__.py +10 -0
  171. package/python/foxclaw/itinerary/amap_client.py +114 -0
  172. package/python/foxclaw/itinerary/models.py +80 -0
  173. package/python/foxclaw/itinerary/reasoner.py +96 -0
  174. package/python/foxclaw/itinerary/reasoning.py +168 -0
  175. package/python/foxclaw/itinerary/runtime.py +144 -0
  176. package/python/foxclaw/kernel/__init__.py +13 -0
  177. package/python/foxclaw/kernel/capabilities.py +72 -0
  178. package/python/foxclaw/kernel/policy_gate.py +108 -0
  179. package/python/foxclaw/kernel/process_manager.py +186 -0
  180. package/python/foxclaw/kernel/scheduler.py +125 -0
  181. package/python/foxclaw/kernel/sentinel.py +443 -0
  182. package/python/foxclaw/kernel/sentinel_client.py +243 -0
  183. package/python/foxclaw/kernel/spine.py +97 -0
  184. package/python/foxclaw/knowledge/__init__.py +360 -0
  185. package/python/foxclaw/knowledge/truth_crystallizer.py +89 -0
  186. package/python/foxclaw/learning/__init__.py +12 -0
  187. package/python/foxclaw/learning/knowledge_graph.py +144 -0
  188. package/python/foxclaw/learning/models.py +93 -0
  189. package/python/foxclaw/learning/reasoner.py +67 -0
  190. package/python/foxclaw/learning/runtime.py +351 -0
  191. package/python/foxclaw/learning/spaced_repetition.py +91 -0
  192. package/python/foxclaw/mcp_server.py +188 -0
  193. package/python/foxclaw/orchestration/__init__.py +167 -0
  194. package/python/foxclaw/pipeline/__init__.py +23 -0
  195. package/python/foxclaw/pipeline/cognitive_pipeline.py +429 -0
  196. package/python/foxclaw/pipeline/stage_meta.py +21 -0
  197. package/python/foxclaw/pipeline/supervisor_stages.py +201 -0
  198. package/python/foxclaw/planning/__init__.py +17 -0
  199. package/python/foxclaw/planning/llm_planner.py +232 -0
  200. package/python/foxclaw/planning/planner.py +94 -0
  201. package/python/foxclaw/search/__init__.py +24 -0
  202. package/python/foxclaw/search/agent_port.py +190 -0
  203. package/python/foxclaw/search/evidence.py +109 -0
  204. package/python/foxclaw/search/external_search.py +50 -0
  205. package/python/foxclaw/search/hkc_read_port.py +60 -0
  206. package/python/foxclaw/search/internal_search.py +71 -0
  207. package/python/foxclaw/search/models.py +127 -0
  208. package/python/foxclaw/search/planner.py +44 -0
  209. package/python/foxclaw/search/retriever.py +39 -0
  210. package/python/foxclaw/search/runtime.py +127 -0
  211. package/python/foxclaw/search/strategy.py +44 -0
  212. package/python/foxclaw/skills/__init__.py +559 -0
  213. package/python/foxclaw/skills/archive.py +111 -0
  214. package/python/foxclaw/skills/fetch.py +226 -0
  215. package/python/foxclaw/skills/hooks_spec.py +69 -0
  216. package/python/foxclaw/skills/install_cmd.py +216 -0
  217. package/python/foxclaw/skills/lifecycle.py +252 -0
  218. package/python/foxclaw/skills/markdown_skill.py +175 -0
  219. package/python/foxclaw/skills/markdown_store.py +39 -0
  220. package/python/foxclaw/skills/mcp_client.py +184 -0
  221. package/python/foxclaw/skills/mcp_store.py +40 -0
  222. package/python/foxclaw/skills/permission.py +145 -0
  223. package/python/foxclaw/skills/pipeline.py +354 -0
  224. package/python/foxclaw/skills/policy.py +74 -0
  225. package/python/foxclaw/skills/review.py +72 -0
  226. package/python/foxclaw/skills/store.py +57 -0
  227. package/python/frontend/assets/core_bg.jpg +0 -0
  228. package/python/frontend/deck/auth.js +25 -0
  229. package/python/frontend/deck/chat_model_picker.js +483 -0
  230. package/python/frontend/deck/domain.js +276 -0
  231. package/python/frontend/deck/main.js +1806 -0
  232. package/python/frontend/deck/markdown.js +44 -0
  233. package/python/frontend/deck/settings.js +307 -0
  234. package/python/frontend/deck/state.js +5 -0
  235. package/python/frontend/deck/util.js +4 -0
  236. package/python/frontend/deck/visuals.js +190 -0
  237. package/python/frontend/deck.css +855 -0
  238. package/python/frontend/deck.html +686 -0
  239. package/python/frontend/deck_v2.html +341 -0
  240. package/python/frontend/planet/index.html +266 -0
  241. package/python/frontend/planet/planet.css +579 -0
  242. package/python/frontend/planet/planet.js +1436 -0
  243. package/python/frontend/planet/vendor/three.core.min.js +6 -0
  244. package/python/frontend/planet/vendor/three.module.min.js +6 -0
  245. package/python/frontend/v3/assets/index-CQSBdxk4.js +34 -0
  246. package/python/frontend/v3/assets/index-D5nIsjms.css +1 -0
  247. package/python/frontend/v3/index.html +15 -0
  248. package/python/frontend/widget_runtime.js +252 -0
  249. package/python/frontend/widgets.js +639 -0
  250. package/python/frontend_src/index.html +14 -0
  251. package/python/frontend_src/package-lock.json +1376 -0
  252. package/python/frontend_src/package.json +19 -0
  253. package/python/frontend_src/src/App.vue +58 -0
  254. package/python/frontend_src/src/api.js +82 -0
  255. package/python/frontend_src/src/components/ChatDock.vue +365 -0
  256. package/python/frontend_src/src/components/ComposerMenu.vue +75 -0
  257. package/python/frontend_src/src/components/DocViewer.vue +162 -0
  258. package/python/frontend_src/src/components/Inspector.vue +235 -0
  259. package/python/frontend_src/src/components/LeftRail.vue +415 -0
  260. package/python/frontend_src/src/components/MenuPopover.vue +128 -0
  261. package/python/frontend_src/src/components/MessageStream.vue +389 -0
  262. package/python/frontend_src/src/components/ModelPicker.vue +350 -0
  263. package/python/frontend_src/src/components/QuickIngest.vue +112 -0
  264. package/python/frontend_src/src/components/Stage.vue +272 -0
  265. package/python/frontend_src/src/components/ToolMenu.vue +141 -0
  266. package/python/frontend_src/src/components/TopBar.vue +118 -0
  267. package/python/frontend_src/src/components/panels/ActivityPanel.vue +82 -0
  268. package/python/frontend_src/src/components/panels/AgentsPanel.vue +83 -0
  269. package/python/frontend_src/src/components/panels/KnowledgePanel.vue +425 -0
  270. package/python/frontend_src/src/components/panels/MemoryPanel.vue +117 -0
  271. package/python/frontend_src/src/components/panels/PanelBox.vue +50 -0
  272. package/python/frontend_src/src/components/panels/ReviewPanel.vue +292 -0
  273. package/python/frontend_src/src/components/panels/SettingsPanel.vue +358 -0
  274. package/python/frontend_src/src/components/panels/TasksPanel.vue +73 -0
  275. package/python/frontend_src/src/components/panels/ToolsPanel.vue +746 -0
  276. package/python/frontend_src/src/components/panels/UsagePanel.vue +105 -0
  277. package/python/frontend_src/src/lib/fmt.js +44 -0
  278. package/python/frontend_src/src/lib/i18n.js +53 -0
  279. package/python/frontend_src/src/lib/locales/en.js +173 -0
  280. package/python/frontend_src/src/lib/locales/zh.js +174 -0
  281. package/python/frontend_src/src/lib/md.js +190 -0
  282. package/python/frontend_src/src/main.js +9 -0
  283. package/python/frontend_src/src/stores/app.js +91 -0
  284. package/python/frontend_src/src/stores/chat.js +450 -0
  285. package/python/frontend_src/src/stores/model.js +96 -0
  286. package/python/frontend_src/src/stores/panels.js +289 -0
  287. package/python/frontend_src/src/stores/profile.js +31 -0
  288. package/python/frontend_src/src/stores/system.js +25 -0
  289. package/python/frontend_src/src/styles/base.css +138 -0
  290. package/python/frontend_src/src/styles/panel.css +117 -0
  291. package/python/frontend_src/src/styles/tokens.css +78 -0
  292. package/python/frontend_src/vite.config.js +39 -0
  293. package/python/pyproject.toml +268 -0
  294. package/python/requirements.txt +311 -0
  295. package/python/skills/README.md +123 -0
  296. package/python/skills/execution-contract/SKILL.md +30 -0
  297. package/python/skills/general-assistant/SKILL.md +34 -0
  298. package/python/skills/planner/SKILL.md +33 -0
  299. package/python/skills/schedule-itinerary/SKILL.md +35 -0
  300. package/python/skills/skill-composition/SKILL.md +31 -0
  301. package/python/skills/skill-guard/SKILL.md +67 -0
  302. package/python/skills/skill-memory/SKILL.md +50 -0
  303. package/python/skills/skill-router/SKILL.md +35 -0
  304. package/python/tests/conftest.py +54 -0
  305. package/python/tests/run_all.py +200 -0
  306. package/python/tests/test_agent_lifecycle.py +326 -0
  307. package/python/tests/test_ahs_p2.py +393 -0
  308. package/python/tests/test_anthropic_tools.py +192 -0
  309. package/python/tests/test_api.py +97 -0
  310. package/python/tests/test_api_auth.py +79 -0
  311. package/python/tests/test_api_host_guard.py +69 -0
  312. package/python/tests/test_attachments.py +151 -0
  313. package/python/tests/test_audit_chain.py +116 -0
  314. package/python/tests/test_audit_sink.py +130 -0
  315. package/python/tests/test_browser.py +149 -0
  316. package/python/tests/test_browser_request_guard.py +180 -0
  317. package/python/tests/test_capabilities.py +152 -0
  318. package/python/tests/test_channel_signing.py +185 -0
  319. package/python/tests/test_channel_trust.py +109 -0
  320. package/python/tests/test_channels.py +174 -0
  321. package/python/tests/test_cli.py +46 -0
  322. package/python/tests/test_compaction_toolpair.py +119 -0
  323. package/python/tests/test_config_layering.py +61 -0
  324. package/python/tests/test_confirm_nonce.py +186 -0
  325. package/python/tests/test_context_compaction_wiring.py +124 -0
  326. package/python/tests/test_dispatch.py +89 -0
  327. package/python/tests/test_domain_evals.py +334 -0
  328. package/python/tests/test_domain_import.py +72 -0
  329. package/python/tests/test_domain_reasoners.py +134 -0
  330. package/python/tests/test_e2e.py +161 -0
  331. package/python/tests/test_emb_cache.py +97 -0
  332. package/python/tests/test_embedding_singleton.py +87 -0
  333. package/python/tests/test_envfile.py +83 -0
  334. package/python/tests/test_evals_smoke.py +90 -0
  335. package/python/tests/test_event_spine.py +174 -0
  336. package/python/tests/test_evidence_semantic.py +88 -0
  337. package/python/tests/test_evidence_sse.py +94 -0
  338. package/python/tests/test_file_ingest.py +135 -0
  339. package/python/tests/test_finance.py +144 -0
  340. package/python/tests/test_finance_ledger.py +245 -0
  341. package/python/tests/test_finance_persist.py +174 -0
  342. package/python/tests/test_gateway.py +125 -0
  343. package/python/tests/test_governance.py +421 -0
  344. package/python/tests/test_governance_audit.py +324 -0
  345. package/python/tests/test_governance_middleware.py +137 -0
  346. package/python/tests/test_hkc.py +268 -0
  347. package/python/tests/test_hkc_index_build_manager.py +306 -0
  348. package/python/tests/test_hkc_manifest_reuse.py +294 -0
  349. package/python/tests/test_hkc_search_event_sync.py +482 -0
  350. package/python/tests/test_import_path_guard.py +155 -0
  351. package/python/tests/test_injection_guard.py +193 -0
  352. package/python/tests/test_integration.py +117 -0
  353. package/python/tests/test_itinerary.py +100 -0
  354. package/python/tests/test_kee_semantic.py +84 -0
  355. package/python/tests/test_kernel.py +212 -0
  356. package/python/tests/test_learning.py +101 -0
  357. package/python/tests/test_llm_admin.py +145 -0
  358. package/python/tests/test_llm_planner.py +344 -0
  359. package/python/tests/test_markdown_skills.py +62 -0
  360. package/python/tests/test_markdown_skills_openclaw.py +66 -0
  361. package/python/tests/test_mcp_connectors.py +97 -0
  362. package/python/tests/test_mcp_guardian_discovery.py +87 -0
  363. package/python/tests/test_mcp_no_memory.py +43 -0
  364. package/python/tests/test_mcp_policy_gate.py +76 -0
  365. package/python/tests/test_mcp_server.py +92 -0
  366. package/python/tests/test_memory_recall.py +92 -0
  367. package/python/tests/test_metrics.py +58 -0
  368. package/python/tests/test_multi_chain.py +90 -0
  369. package/python/tests/test_multimodal.py +122 -0
  370. package/python/tests/test_negotiation.py +136 -0
  371. package/python/tests/test_orchestration.py +109 -0
  372. package/python/tests/test_orchestration_decoupled.py +103 -0
  373. package/python/tests/test_p3_p5_hardening.py +324 -0
  374. package/python/tests/test_parallel_dispatch.py +207 -0
  375. package/python/tests/test_pipeline.py +492 -0
  376. package/python/tests/test_plan_visible.py +86 -0
  377. package/python/tests/test_planner.py +88 -0
  378. package/python/tests/test_policy_gate.py +108 -0
  379. package/python/tests/test_profile.py +67 -0
  380. package/python/tests/test_readme_claims.py +163 -0
  381. package/python/tests/test_reasoner.py +170 -0
  382. package/python/tests/test_release_check.py +252 -0
  383. package/python/tests/test_resume_checkpoint.py +148 -0
  384. package/python/tests/test_routing.py +85 -0
  385. package/python/tests/test_scheduler.py +138 -0
  386. package/python/tests/test_search.py +194 -0
  387. package/python/tests/test_secrets.py +153 -0
  388. package/python/tests/test_semantic.py +69 -0
  389. package/python/tests/test_sessions.py +90 -0
  390. package/python/tests/test_settings.py +265 -0
  391. package/python/tests/test_shadow_learning.py +290 -0
  392. package/python/tests/test_shared_write.py +200 -0
  393. package/python/tests/test_skill_taint_gate.py +145 -0
  394. package/python/tests/test_skills.py +117 -0
  395. package/python/tests/test_skills_fetch.py +282 -0
  396. package/python/tests/test_stats_and_events.py +162 -0
  397. package/python/tests/test_streaming.py +55 -0
  398. package/python/tests/test_supervisor_pipeline.py +176 -0
  399. package/python/tests/test_supervisor_triage.py +102 -0
  400. package/python/tests/test_taint.py +112 -0
  401. package/python/tests/test_task_stream.py +74 -0
  402. package/python/tests/test_thinking_sse.py +66 -0
  403. package/python/tests/test_thinking_stream.py +76 -0
  404. package/python/tests/test_tool_center.py +113 -0
  405. package/python/tests/test_tool_parallel.py +113 -0
  406. package/python/tests/test_tool_params.py +99 -0
  407. package/python/tests/test_tool_use.py +229 -0
  408. package/python/tests/test_toplevel_concurrency.py +116 -0
  409. package/python/tests/test_tracing.py +256 -0
  410. package/python/tests/test_truth_crystallizer.py +125 -0
  411. package/python/tests/test_truth_flow.py +88 -0
  412. package/python/tests/test_update_check.py +95 -0
  413. package/python/tests/test_url_policy.py +53 -0
  414. package/python/tests/test_verify_evidence.py +212 -0
  415. package/python/tests/test_version_sync.py +100 -0
  416. package/python/tests/test_web_trigger.py +82 -0
  417. package/python/tools/check_faiss_type.py +30 -0
  418. package/python/tools/check_log.ps1 +38 -0
  419. package/python/tools/ivf_status.py +72 -0
  420. package/python/tools/mypy_baseline.txt +13 -0
  421. package/python/tools/mypy_ratchet.py +143 -0
  422. package/python/tools/pack.py +173 -0
  423. package/python/tools/release_check.py +349 -0
  424. package/python/tools/restart_foxclaw.ps1 +71 -0
  425. package/python/tools/shared_write_audit.py +190 -0
  426. package/python/tools/size_baseline.txt +28 -0
  427. package/python/tools/size_check.py +102 -0
  428. package/python/tools/strip_comments.py +228 -0
  429. package/python/tools/verify_env.bat +2 -0
  430. package/python/tools/verify_env.py +25 -0
  431. package/python/vendor/HMR_LICENSE +37 -0
  432. package/python/vendor/HMR_README.md +65 -0
  433. package/python/vendor/hkc/LICENSE +37 -0
  434. package/python/vendor/hkc/hkc_ace/__init__.py +0 -0
  435. package/python/vendor/hkc/hkc_ace/ace.py +457 -0
  436. package/python/vendor/hkc/hkc_ace/skill_taxonomy.json +465 -0
  437. package/python/vendor/hkc/hkc_api/__init__.py +0 -0
  438. package/python/vendor/hkc/hkc_api/container.py +416 -0
  439. package/python/vendor/hkc/hkc_api/ingest_jobs.py +103 -0
  440. package/python/vendor/hkc/hkc_api/main.py +157 -0
  441. package/python/vendor/hkc/hkc_api/routes/__init__.py +0 -0
  442. package/python/vendor/hkc/hkc_api/routes/ability.py +151 -0
  443. package/python/vendor/hkc/hkc_api/routes/config.py +51 -0
  444. package/python/vendor/hkc/hkc_api/routes/knowledge.py +630 -0
  445. package/python/vendor/hkc/hkc_api/routes/search.py +88 -0
  446. package/python/vendor/hkc/hkc_api/schemas.py +153 -0
  447. package/python/vendor/hkc/hkc_api/synthesis.py +179 -0
  448. package/python/vendor/hkc/hkc_core/__init__.py +0 -0
  449. package/python/vendor/hkc/hkc_core/graph/__init__.py +0 -0
  450. package/python/vendor/hkc/hkc_core/graph/base.py +188 -0
  451. package/python/vendor/hkc/hkc_core/graph/sqlite_store.py +789 -0
  452. package/python/vendor/hkc/hkc_core/models/__init__.py +0 -0
  453. package/python/vendor/hkc/hkc_core/models/enums.py +65 -0
  454. package/python/vendor/hkc/hkc_core/models/ku.py +307 -0
  455. package/python/vendor/hkc/hkc_core/utils/__init__.py +0 -0
  456. package/python/vendor/hkc/hkc_core/utils/id_gen.py +113 -0
  457. package/python/vendor/hkc/hkc_crystallizer/__init__.py +44 -0
  458. package/python/vendor/hkc/hkc_crystallizer/adapters.py +94 -0
  459. package/python/vendor/hkc/hkc_crystallizer/candidate.py +145 -0
  460. package/python/vendor/hkc/hkc_crystallizer/crystallizer.py +179 -0
  461. package/python/vendor/hkc/hkc_crystallizer/ingress.py +90 -0
  462. package/python/vendor/hkc/hkc_kde/__init__.py +0 -0
  463. package/python/vendor/hkc/hkc_kde/chunker.py +197 -0
  464. package/python/vendor/hkc/hkc_kde/extractor.py +623 -0
  465. package/python/vendor/hkc/hkc_kde/kde.py +298 -0
  466. package/python/vendor/hkc/hkc_kde/loaders/__init__.py +0 -0
  467. package/python/vendor/hkc/hkc_kde/loaders/ebook_loader.py +153 -0
  468. package/python/vendor/hkc/hkc_kde/loaders/office_loader.py +194 -0
  469. package/python/vendor/hkc/hkc_kde/loaders/pdf_loader.py +162 -0
  470. package/python/vendor/hkc/hkc_kde/loaders/text_loader.py +157 -0
  471. package/python/vendor/hkc/hkc_kde/loaders/web_loader.py +91 -0
  472. package/python/vendor/hkc/hkc_kde/models.py +74 -0
  473. package/python/vendor/hkc/hkc_kde/packager.py +329 -0
  474. package/python/vendor/hkc/hkc_kde/relation_disc.py +151 -0
  475. package/python/vendor/hkc/hkc_kee/__init__.py +0 -0
  476. package/python/vendor/hkc/hkc_kee/dedup.py +227 -0
  477. package/python/vendor/hkc/hkc_kee/fingerprint.py +106 -0
  478. package/python/vendor/hkc/hkc_kee/kee.py +541 -0
  479. package/python/vendor/hkc/hkc_kep/__init__.py +0 -0
  480. package/python/vendor/hkc/hkc_kep/event_bus.py +205 -0
  481. package/python/vendor/hkc/hkc_sdk/__init__.py +63 -0
  482. package/python/vendor/hkc/hkc_sdk/base.py +151 -0
  483. package/python/vendor/hkc/hkc_sdk/direct_client.py +153 -0
  484. package/python/vendor/hkc/hkc_sdk/exceptions.py +39 -0
  485. package/python/vendor/hkc/hkc_sdk/http_client.py +166 -0
  486. package/python/vendor/hkc/hkc_sdk/models.py +171 -0
  487. package/python/vendor/hkc/hkc_search/__init__.py +0 -0
  488. package/python/vendor/hkc/hkc_search/bm25.py +325 -0
  489. package/python/vendor/hkc/hkc_search/embedding_backends.py +374 -0
  490. package/python/vendor/hkc/hkc_search/graph_search.py +132 -0
  491. package/python/vendor/hkc/hkc_search/hybrid.py +331 -0
  492. package/python/vendor/hkc/hkc_search/index_build_manager.py +378 -0
  493. package/python/vendor/hkc/hkc_search/vector_search.py +484 -0
  494. package/python/vendor/hmr/__init__.py +0 -0
  495. package/python/vendor/hmr/core/__init__.py +0 -0
  496. package/python/vendor/hmr/core/hmr.py +684 -0
  497. package/python/vendor/hmr/core/models.py +310 -0
  498. package/python/vendor/hmr/engines/__init__.py +0 -0
  499. package/python/vendor/hmr/engines/evolution.py +710 -0
  500. package/python/vendor/hmr/engines/jit_compiler.py +472 -0
  501. package/python/vendor/hmr/engines/lifecycle.py +264 -0
  502. package/python/vendor/hmr/engines/policy.py +625 -0
  503. package/python/vendor/hmr/engines/recall.py +260 -0
  504. package/python/vendor/hmr/engines/runtime_state.py +158 -0
  505. package/python/vendor/hmr/engines/scheduler.py +323 -0
  506. package/python/vendor/hmr/engines/semantic.py +150 -0
  507. package/python/vendor/hmr/engines/temporal.py +261 -0
  508. package/python/vendor/hmr/engines/thought_chain.py +635 -0
  509. package/python/vendor/hmr/graph/__init__.py +0 -0
  510. package/python/vendor/hmr/graph/cwg.py +338 -0
  511. package/python/vendor/hmr/graph/memory_graph.py +530 -0
  512. package/python/vendor/hmr/storage/__init__.py +0 -0
  513. package/python/vendor/hmr/storage/memory_fs.py +300 -0
  514. package/python/vendor/hmr/storage/vector_store.py +520 -0
@@ -0,0 +1,336 @@
1
+ # Foxclaw · 有记忆的个人智能体
2
+
3
+ **有记忆的个人智能体** —— 表面上是有记忆的智能体,往里看是智能体运行时:以 HMR 记忆运行时为内核,三个智能体协同,Harness 跨层治理,记忆/认知层与 LLM 彻底解耦。
4
+
5
+ ```
6
+ 传统智能体框架: 记忆 = 存储, 智能体 = 无状态执行
7
+ Foxclaw: 记忆 = 持续认知运行时,智能体 = 会推理 · 会学习 · 会演化
8
+ ```
9
+
10
+ ## 一、这是什么
11
+
12
+ 主流智能体框架把记忆当存储:开新会话就归零,记忆只是检索。Foxclaw 把记忆做成**持续运行的认知层**——推理、校准、学习都发生在这一层,并且与 LLM 彻底解耦:换模型不影响判断力。
13
+
14
+ 它建立在 HMR(Foxclaw 记忆运行时)之上,四件事构成护城河:
15
+
16
+ - **推理链(ThoughtChain)** —— 每个智能体的推理轨迹是可审计、可对比的有向图,不是普通日志
17
+ - **线束(Harness)** —— 跨层约束与校准:三维漂移检测(语义 / 工具 / 范围)+ 影子模式自校准 + 策略自学习
18
+ - **演化(Evolution)** —— 每次线束截断都喂给策略,系统越用越准
19
+ - **运行时治理** —— 幂等、崩溃恢复、循环检测,保证真实运行中可靠、可审计、不丢不重
20
+
21
+ 三个智能体:**主管**(协调)、**财务**(理财)、**办公学习**(学习 + 日程行程)。各自持有隔离记忆与策略演化,通过 Skill 层挂载外部生态,通过渠道层接入四个消息平台。早期的「助手」「行政」已**下放为指令技能**(`skills/general-assistant`、`skills/schedule-itinerary`),按需挂载,不再单列 Agent。
22
+
23
+ ## 二、三个智能体与领域内核
24
+
25
+ ### 领域专家(各挂一个领域内核)
26
+
27
+ 财务、办公学习两个智能体各挂一个**同构**的领域内核(纯算法层 + 外部工具接口 + 守门人);办公学习同时挂学习与行程两个内核:
28
+
29
+ - **财务内核**:预算推理、MAD 异常检测、订阅膨胀、现金流预测;守门人四权限(veto/freeze/确认/alert),只产出审批请求不自动动钱。**前沿三件套**:结构化证据链(可解释风险)、财务数据图(追溯"谁造成超支")、对账(三级匹配 + 疑似盗刷识别)。
30
+ - **学习内核**:SM-2 间隔重复(掌握度 + 遗忘风险)+ 知识图谱(知识簇发现)。
31
+ - **行程内核**:TSP 路线优化、可达性"赶不及"检测、时间冲突、地理聚类;接高德地图。
32
+
33
+ ### 协调 / 技能
34
+
35
+ - **主管智能体**:全局态势 + 跨智能体编排。综合决策路由,支持多 Agent 顺序执行(如"先查日程再分析理财"→ office + finance),跨智能体守门人裁决;无领域关键词命中时自行处理(不再有兜底 Agent)。
36
+ - **指令技能**:Skill 接入层(本地脚本 / MCP / Web API 三类)对所有 Agent 开放,有副作用的 skill 需确认后执行。
37
+
38
+ ## 三、消息平台接入
39
+
40
+ 通过统一的渠道抽象层接入四个主流平台,**每个适配器按各自官方规范实现**(不套一个模子):
41
+
42
+ | 渠道 | 接入模型 | 凭证 |
43
+ |------|---------|------|
44
+ | 微信 | iLink Bot API,长轮询 + context_token | 扫码登录 token |
45
+ | 飞书 | 事件订阅 webhook + 签名验签 + token 刷新 | App ID/Secret |
46
+ | Telegram | Bot API getUpdates 轮询 | bot token |
47
+ | Discord | Gateway WebSocket + REST | bot token |
48
+
49
+ 闭环调度(`ChannelDispatcher`):收消息 → 主管处理 → 回复原渠道,跨渠道会话隔离 + 幂等去重。详见 [docs/CHANNELS.md](docs/CHANNELS.md)。
50
+
51
+ ## 四、运行时治理
52
+
53
+ 保证系统在真实运行(消息重发、进程崩溃、长任务、死循环)中可靠。详见 [docs/GOVERNANCE.md](docs/GOVERNANCE.md):
54
+
55
+ - **幂等守卫** —— 消息重发只处理一次(已接入渠道闭环)
56
+ - **崩溃/重启恢复** —— 启动时识别上次被中断的任务并诚实交代(boot_id 防 pid 复用)
57
+ - **工具循环检测** —— 检测重复/横跳/轮询卡死,防无进展死循环烧 token
58
+ - **上下文压缩** —— 长对话渐进降级压缩,保留关键标识符
59
+ - **钩子标准化** —— 标准生命周期钩子 + 明确阻断权
60
+ - **干预队列** —— 租约机制安全回收子任务结果(为并行子 Agent 预留)
61
+
62
+ ## 五、目录结构
63
+
64
+ ```
65
+ foxclaw/
66
+ ├── README.md / README_CN.md 项目总览(英 / 中)
67
+ ├── pyproject.toml
68
+ ├── foxclaw/ 后端 Python 包
69
+ │ ├── __init__.py Foxclaw 系统入口(装配所有子系统)
70
+ │ ├── api.py FastAPI + WebSocket
71
+ │ ├── core/ thought_chain / memory_adapter / model_router /
72
+ │ │ system_bus / truth_pipeline / token_meter /
73
+ │ │ web_search / compaction / idempotency / recovery
74
+ │ ├── kernel/ 运行时内核:调度 / 进程 / 能力 / 准入(spine + sentinel)
75
+ │ ├── pipeline/ planning/ 任务执行管线 + 规划原语
76
+ │ ├── cognitive/ knowledge/ 领域推理 + 真相结晶
77
+ │ ├── agents/ base.py(CognitiveAgent 模板)+ agents.py
78
+ │ │ + impl/(财务 / 办公 / 主管 —— 三个智能体)
79
+ │ ├── harness/ harness.py(三维漂移)+ loop_detection.py + 策略自学习
80
+ │ ├── finance/ 财务内核 + 三件套(evidence/graph/reconcile)
81
+ │ ├── learning/ 学习内核(SM-2 + 知识图谱)
82
+ │ ├── itinerary/ 行程内核(TSP + 高德)
83
+ │ ├── channels/ 渠道抽象层 + 微信/飞书/Telegram/Discord + 闭环调度
84
+ │ ├── skills/ Skill 接入层 + 权限(permission)/钩子/断路器/循环防护
85
+ │ ├── search/ HSR 认知搜索(HMR 记忆 + HKC 知识 + 联网,融入)
86
+ │ ├── browser/ HIR 浏览器子系统(AI 用的浏览器,融入)
87
+ │ ├── capability/ governance/ embedding 单例 / 治理中间件
88
+ ├── vendor/hmr/ vendor/hkc/ HMR v2.0 记忆运行时 + HKC 知识核心(已内嵌)
89
+ ├── examples/ 样例数据
90
+ ├── tests/ 全部 pytest 组织 + run_all.py 一键跑全量回归
91
+ └── docs/ RUN / RUN_CN / CHANNELS / GOVERNANCE / RELEASE / 配置指南
92
+ ```
93
+
94
+ ## 六、环境要求
95
+
96
+ - **Python 3.11 及以上**(3.12 最稳定)
97
+ - ⚠ **Windows 用户**:不要把项目放在 OneDrive 接管的目录(文档/桌面/图片),Python 无法在重定向占位符里建目录。放到 `C:\foxclaw` 这类简单路径。
98
+
99
+ ## 七、快速开始
100
+
101
+ ```bash
102
+ # 1. 建隔离环境 —— 不要直接装进系统 Python,否则会和机器上其它项目互相污染
103
+ python -m venv .venv
104
+ .venv\Scripts\activate # macOS / Linux: source .venv/bin/activate
105
+
106
+ # 2. 安装锁定版本的依赖(含 torch / faiss,约 1GB)
107
+ pip install -r requirements.txt
108
+ pip install -e . --no-deps # 装 foxclaw 本体,不再重解析依赖
109
+
110
+ # 3. 验证认知运行时(无需 API key)
111
+ python tests/run_all.py # 全量回归(全绿)
112
+
113
+ # 4. 启动服务(配 key 则真实调模型,不配则 stub)
114
+ export DEEPSEEK_API_KEY=sk-... # 或 ANTHROPIC_API_KEY;Windows: $env:DEEPSEEK_API_KEY="sk-..."
115
+ python -m uvicorn foxclaw.api:app --port 8000
116
+ ```
117
+
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)。
126
+
127
+ ### 开发常用命令(Windows / PowerShell 一行重启)
128
+
129
+ 开发期改完 `.env`、装了新包、调了后端代码,都要重启 foxclaw 让改动生效。**最简一行函数**,配一次永远省事:
130
+
131
+ ```powershell
132
+ # ① 打开 PowerShell 启动脚本(只首次)
133
+ notepad $PROFILE
134
+
135
+ # ② 文件末尾粘这段,保存退出
136
+ function restart-foxclaw {
137
+ $p=(Get-NetTCPConnection -LocalPort 8000 -State Listen -EA SilentlyContinue).OwningProcess
138
+ if($p){Stop-Process -Id $p -Force; Start-Sleep 1}
139
+ Set-Location <你的项目目录>
140
+ # 显式走 .venv,别用 PATH 里那个系统 Python 的 foxclaw.exe ——
141
+ # 系统环境常常是很久以前装的,挂着已知漏洞(实测 278 条)。
142
+ .\.venv\Scripts\foxclaw.exe serve
143
+ }
144
+
145
+ # ③ 重开 PowerShell 让配置生效(只在改了 $PROFILE 后需要)
146
+ exit
147
+ ```
148
+
149
+ 之后**任何目录、任何时候**,一行搞定:
150
+
151
+ ```powershell
152
+ restart-foxclaw # 自动杀旧进程 → 切项目根 → 起新服务
153
+ ```
154
+
155
+ 如果 `notepad $PROFILE` 报"无法加载脚本",先放宽执行策略:
156
+
157
+ ```powershell
158
+ Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
159
+ ```
160
+
161
+ | 场景 | 命令 |
162
+ |---|---|
163
+ | 改完 `.env` 要生效 | `restart-foxclaw` |
164
+ | 装了新 pip 包 | `restart-foxclaw` |
165
+ | 改完 `foxclaw/*.py` | `restart-foxclaw` |
166
+ | 只想杀旧实例 | `$p=(Get-NetTCPConnection -LocalPort 8000 -State Listen -EA SilentlyContinue).OwningProcess; if($p){Stop-Process -Id $p -Force}` |
167
+ | 想边改边自动重启 | `python -m uvicorn foxclaw.api:app --port 8000 --reload`(开发期才用,生产关掉) |
168
+
169
+ ### 方式二 · Docker 部署
170
+
171
+ ```bash
172
+ # 构建镜像(含依赖 + 默认 embedding 预热,首次构建较慢、镜像较大)
173
+ docker build -t foxclaw .
174
+
175
+ # 启动服务(密钥经 --env-file 注入,勿写进镜像)
176
+ docker run -d --name foxclaw \
177
+ -p 8000:8000 \
178
+ --env-file .env \
179
+ -v foxclaw_data:/app/foxclaw_data \
180
+ foxclaw
181
+
182
+ # 容器内跑全量回归(验证镜像健康)
183
+ docker run --rm foxclaw python tests/run_all.py
184
+ ```
185
+
186
+ 要点:
187
+
188
+ - 默认命令为 `uvicorn foxclaw.api:app`,监听 `8000`;未配 `FOXCLAW_API_KEY` 时无鉴权,仅限回环安全。
189
+ - 数据目录 `FOXCLAW_DATA_DIR`(默认 `./foxclaw_data`)建议挂 volume 持久化。
190
+ - 密钥经 `--env-file .env` 或 `-e FOXCLAW_API_KEY=...` 注入;`.dockerignore` 已排除 `.env`,不会被打进镜像。
191
+
192
+ ## 八、知识库(HKC)模型配置
193
+
194
+ HKC 知识库用**两个不同类型的模型**各司其职,都在 `.env` 里配置,无需改代码:
195
+
196
+ | 环节 | 模型类型 | 作用 | 配置项 |
197
+ |------|---------|------|--------|
198
+ | 写入(摄入书籍/文件时) | **生成式 LLM**(会"读懂"并输出 JSON) | 把每个分段抽成实体/概念/事实/观点 | `HKC_LLM_*` |
199
+ | 检索(查询时) | **embedding**(文本 → 向量) | 把知识与查询向量化,算语义相似度召回 | `HKC_EMBEDDING_*` |
200
+
201
+ 两者不能互换:embedding 模型不会生成文本(抽不出 JSON),LLM 也不适合做向量检索。
202
+
203
+ ### 先确定你属于哪种情况
204
+
205
+ | 你的环境 | 抽取模型怎么配 | `HKC_LLM_API_KEY` 填什么 |
206
+ |---|---|---|
207
+ | 有本地 Ollama | `openai-compatible` + `base_url` 指向 Ollama | **任意非空**即可(Ollama 不校验,填 `ollama` 只是占位) |
208
+ | 无本地模型 | 用**云端公开模型**(DeepSeek / OpenAI / 通义等),见下表 | 填**对应平台的真实 API Key** |
209
+
210
+ ### 情况 A · 本地 Ollama
211
+
212
+ ```bash
213
+ HKC_LLM_PROVIDER=openai-compatible
214
+ HKC_LLM_API_KEY=ollama # 仅本地 Ollama 可这样占位;云端不能这么填
215
+ HKC_LLM_MODEL=my-qwen-32k:latest # 你 `ollama list` 里的模型名
216
+ HKC_LLM_BASE_URL=http://localhost:11434/v1 # Ollama 的 OpenAI 兼容端点
217
+ HKC_LLM_TIMEOUT=180 # 本地模型慢,超时放宽(默认 60 秒)
218
+ HKC_EXTRACT_CONCURRENCY=2 # 本地单卡 1~2;云端 API 可 5
219
+ HKC_EXTRACT_BATCH=8 # 批量抽取(可选):一次调用抽 N 段,省 token、提速;默认 1=逐段
220
+ HKC_MAX_CHUNKS_PER_DOC=800 # 单文档 chunk 上限:默认 800 段(约 125 万字符);0=不限制,详见下文「单文档分段上限」
221
+ ```
222
+
223
+ ### 情况 B · 云端公开模型(无本地模型时)
224
+
225
+ `HKC_LLM_MODEL` 填该平台的**公开模型号**(OpenAI 兼容接口透传任意字符串);`HKC_LLM_API_KEY` 填对应平台的**真实密钥**:
226
+
227
+ | 平台 | `HKC_LLM_PROVIDER` | `HKC_LLM_API_KEY` | `HKC_LLM_MODEL` 示例 | `HKC_LLM_BASE_URL` |
228
+ |---|---|---|---|---|
229
+ | DeepSeek | `deepseek` | `sk-...`(DeepSeek 官方 key) | `deepseek-chat` / `deepseek-reasoner` | 留空(自动用官方地址) |
230
+ | OpenAI | `openai` | `sk-...`(OpenAI key) | `gpt-4o-mini` / `gpt-4o` | 留空 |
231
+ | 通义千问 | `openai-compatible` | 阿里云 DashScope key | `qwen-max` / `qwen-plus` | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
232
+ | 智谱 / 月之暗面 / MiniMax 等 | `openai-compatible` | 该平台 key | 该平台公开模型号 | 该平台 OpenAI 兼容地址 |
233
+
234
+ 示例(DeepSeek):
235
+
236
+ ```bash
237
+ HKC_LLM_PROVIDER=deepseek
238
+ HKC_LLM_API_KEY=sk-你的DeepSeek密钥
239
+ HKC_LLM_MODEL=deepseek-chat
240
+ ```
241
+
242
+ ### 检索模型(embedding)
243
+
244
+ 检索模型**不走 Ollama**,而是 sentence-transformers;本地没有权重时会自动从 HuggingFace 下载:
245
+
246
+ ```bash
247
+ HKC_EMBEDDING=local
248
+ HKC_EMBEDDING_MODEL=BAAI/bge-m3 # 首次自动下载(约 2.2GB);或填本地路径 C:\...\bge-m3
249
+ ```
250
+
251
+ 不追求语义精度时可不配(默认 `stub` 伪语义,开箱能跑)。
252
+
253
+ ### key 在哪填、优先级
254
+
255
+ - **`.env` 是权威来源** —— 启动时读取,改完重启生效。
256
+ - 星球页「连接设置」里的「知识抽取模型」段是**可选的运行时覆盖**(存浏览器 localStorage,刷新可能覆盖 .env);想始终以 .env 为准,那段留空即可。
257
+ - 页面第一个「API Key」是访问后端的鉴权通行证(= `.env` 的 `FOXCLAW_API_KEY`),与模型 key 无关。
258
+
259
+ > 提示:换 embedding 模型会改变向量维度(如 384→1024),需重建知识库索引(清空后重新摄入)。
260
+
261
+ ### 一次能摄入多少内容
262
+
263
+ **上限是硬性的,超了直接报错,不会静默截断:**
264
+
265
+ | 入口 | 上限 | 超限表现 |
266
+ |------|------|----------|
267
+ | 上传文件(`/knowledge/ingest/file`、`/ingest/file/async`) | **20 MB / 个文件** | `413 文件过大` |
268
+ | 粘贴文本(`/knowledge/ingest/text`) | **2,000,000 字符**(中文约合 200 万字 / 6 MB) | `413 文本过大` |
269
+ | 单文档分段数 | **默认 800 段**(约 125 万字符);`HKC_MAX_CHUNKS_PER_DOC=0` 为不限 | 只处理前 N 段,日志输出「文档过大」警告 |
270
+
271
+ 支持格式:`.pdf` `.md` `.markdown` `.txt` `.epub` `.mobi` `.azw3` `.azw` `.docx` `.xlsx`。`.doc` 不支持;**扫描版 PDF 没有 OCR**,纯图片页面提不出任何文字。
272
+
273
+ **分块是计费和耗时的单位**,不是可调项:
274
+
275
+ ```
276
+ 每段上限 1792 字符,相邻重叠 224 字符
277
+ → 每 1568 个字符 ≈ 1 段(1 次 LLM 抽取单元)
278
+ ```
279
+
280
+ **耗时与费用参考**(batch=4、并发=8、云端 DeepSeek,中文内容实测口径):
281
+
282
+ | 中文内容 | 文件大小 | 段数 | 预计耗时 |
283
+ |---|---|---|---|
284
+ | 10 万字符 | 约 100 KB | 约 64 段 | 约 6 分钟 |
285
+ | 50 万字符 | 约 500 KB | 约 320 段 | 约 32 分钟 |
286
+ | 100 万字符 | 约 1 MB | 约 640 段 | 约 1 小时 |
287
+ | 700 万字符(上限) | 约 20 MB | 约 4400 段 | 约 7 小时 |
288
+
289
+ token 换算率:**每 1 万字符 ≈ 4 千输入 + 2 千输出 token**(批量抽取已摊薄系统提示),乘你所用平台的单价即可估费。英文按字符计是中文的 2–3 倍,耗时同比例增加。
290
+
291
+ **实践建议:**
292
+
293
+ - **单文件控制在 2–5 MB**。一本普通电子书就在这个区间,几十分钟内能跑完,中途可随时看进度。
294
+ - **`HKC_MAX_CHUNKS_PER_DOC` 保持默认 800。** 放宽到 0 之前先读下面那节,理由不只是"慢"。
295
+ - **超长内容用文件上传,不要用粘贴。** `/ingest/text` 是同步接口,大文本会一直占着请求;`/ingest/file/async` 才在后台线程跑,可轮询 `processed/total` 看真进度。
296
+ - **重复文件不收钱。** 上传前先算内容 SHA-256,同内容再传直接 `409 该文件内容已摄入过`。
297
+ - **抽取失败先看日志关键词。** 出现「JSON 解析失败」说明模型输出写到一半被截断(中文密集文档常见),调小 `HKC_EXTRACT_BATCH` 或调大 `HKC_EXTRACT_MAX_TOKENS`(默认 8192,即输出硬顶);没有这个关键词才去查 API Key / 网络。
298
+
299
+ ### 单文档分段上限:为什么默认是 800
300
+
301
+ `HKC_MAX_CHUNKS_PER_DOC` 默认 **800 段**,不是随手取的数,而是"能完整吞下常见文档"和"跑得完、账单可控"的交点:
302
+
303
+ | 上限取值 | 覆盖字符 | 段数 | 预计耗时 | 成本(云端) |
304
+ |---|---|---|---|---|
305
+ | **800(默认)** | 约 125 万 | 800 | 约 1.3 小时 | 约 3 元 |
306
+ | 2000 | 约 313 万 | 2000 | 约 3.3 小时 | 约 8 元 |
307
+ | 0(不限制,即吃满 20 MB) | 约 700 万 | 约 4400 | **7 小时起步** | 约 17 元 |
308
+
309
+ > 成本按 `deepseek-chat` 公开单价粗估(输入 2 元 / 输出 8 元 每百万 token),仅作量级参考;换平台按你的价目表折算。
310
+
311
+ **为什么不能设得太大(尤其别设 0):** 上传侧允许 20 MB,若分段不设防,一次误传(比如一份 20 MB 的扫描版 PDF 或一份日志转存)就会在后台连续跑大半天,并在这段时间里持续产生费用。摄入是后台线程执行的,发起后既没有断点也没有回退按钮,你只能看着它跑完或者杀掉整个服务。默认值的作用是"先拦住明显不合理的量",而不是"用得越少越安全"。
312
+
313
+ **为什么也不该设得太小:** 超出上限时只处理前 N 段,而**整文件的内容 SHA-256 已经入库**,同一个文件重新上传会被 `409` 去重拦下。也就是说截断之后不能靠"改大上限再传一次"来补齐——必须先把文件按章节拆成几份,分别上传。所以 800 段留了足够余量:绝大多数单篇文档和普通电子书都不会触发截断。
314
+
315
+ **真要整本摄入时**再针对单次操作临时调大(或设 0),跑完改回 800。日志里出现「文档过大:切出 N 个 chunk」就说明触发了截断,那条警告里会写明本次丢掉了多少内容。
316
+
317
+ ## 九、双层记忆架构(私有隔离 + 共享协调)
318
+
319
+ ```
320
+ 私有层(各智能体隔离,agent:<id> 标签)
321
+ └─ 财务的私人理财偏好 → 办公智能体看不到 ✓
322
+ 共享层(shared 标签,所有智能体可召回)
323
+ └─ 主管的调度决策记录 → 所有智能体都能看到 ✓
324
+ ```
325
+
326
+ 加了共享不等于打破隔离:其他智能体能召回主管的调度记录(协调),但拿不到财务的私有记忆(隔离)。
327
+
328
+ ## 十、架构哲学
329
+
330
+ 记忆与认知层和大模型彻底解耦。大模型只是可替换的文本生成器,真正的护城河(推理链审计 + 线束漂移检测 + 策略自学 + 领域内核)独立于任何模型而存在。这是品类竞争,不是功能竞争。
331
+
332
+ ## 十一、许可证
333
+
334
+ MIT,全文见 [LICENSE](LICENSE)。一句话:随便用、随便改、随便卖,保留版权声明即可。
335
+
336
+ `vendor/` 下内嵌的运行时保留各自的许可证(见 `vendor/hkc/LICENSE`)。
@@ -0,0 +1,186 @@
1
+ """
2
+ bench/bm25_audit.py
3
+ B 阶段 BM25 全重写 - 全面审核
4
+ - 浮点累加 vs 一次 sum 精度差
5
+ - pickle schema 兼容(老 pickle 读不到 fallback)
6
+ - append_ku 单条延迟
7
+ - search 一致性 (build vs append_batch)
8
+ - 与 service 数据集成(用 service 落盘 pickle 看 /stats 一致)
9
+ """
10
+ import os, sys, random, time, pickle
11
+ from dataclasses import dataclass
12
+
13
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'vendor'))
14
+ from hkc.hkc_search.bm25 import BM25Index as NewBM25, _tokenize
15
+
16
+
17
+ @dataclass
18
+ class MockKU:
19
+ ku_id: str
20
+ name: str
21
+ summary: str
22
+ tags: list[str]
23
+
24
+
25
+ def gen_corpus(n, seed=42):
26
+ rng = random.Random(seed)
27
+ corpus = []
28
+ for i in range(n):
29
+ topics = [f"topic{j}_{rng.randint(0, 9)}" for j in range(rng.randint(1, 3))]
30
+ corpus.append(MockKU(ku_id=f"ku_{i:08d}",
31
+ name=f"{' '.join(topics)} #{i}",
32
+ summary=f"summary about {' '.join(topics)}",
33
+ tags=topics + ["common"]))
34
+ return corpus
35
+
36
+
37
+ def audit_float_accumulation():
38
+ """1: 浮点累加 vs 一次 sum/len 精度差"""
39
+ print("\n[1/5] 浮点累加精度对比 (build 一次 vs 累加 1000 次) ...")
40
+ corpus = gen_corpus(1000)
41
+
42
+ idx_a = NewBM25()
43
+ idx_a.build(corpus)
44
+
45
+ idx_b = NewBM25()
46
+ for ku in corpus:
47
+ idx_b.append_ku(ku)
48
+
49
+ print(f" build 一次 avgdl = {idx_a._avgdl:.10f}")
50
+ print(f" 1000 次累加 avgdl = {idx_b._avgdl:.10f}")
51
+ diff_avgdl = abs(idx_a._avgdl - idx_b._avgdl)
52
+ print(f" 差 = {diff_avgdl:.2e} (rel {diff_avgdl/idx_a._avgdl:.2e})")
53
+
54
+ print(f" build 一次 _idf_sum = {idx_a._idf_sum:.10f}")
55
+ print(f" 1000 次累加 _idf_sum = {idx_b._idf_sum:.10f}")
56
+ diff_idf = abs(idx_a._idf_sum - idx_b._idf_sum)
57
+ print(f" 差 = {diff_idf:.2e} (rel {diff_idf/max(abs(idx_a._idf_sum),1e-10):.2e})")
58
+
59
+ q = "topic0_3 topic1_7"
60
+ r_a = sorted([(r.ku_id, round(r.score, 8)) for r in idx_a.search(q, 10)])
61
+ r_b = sorted([(r.ku_id, round(r.score, 8)) for r in idx_b.search(q, 10)])
62
+ same = (r_a == r_b)
63
+ print(f" top-10 一致 (build 一次 vs 1000 次累加): {'PASS' if same else 'FAIL'}")
64
+ if not same:
65
+ print(f" A: {r_a[:3]}")
66
+ print(f" B: {r_b[:3]}")
67
+ return same
68
+
69
+
70
+ def audit_pickle_schema_fallback():
71
+ """2: pickle schema 兼容(老 pickle / 损坏 pickle fallback)"""
72
+ print("\n[2/5] pickle schema 兼容 + 损坏文件 fallback ...")
73
+ tmp = "_tmp_audit.pkl"
74
+ idx = NewBM25()
75
+ idx.build(gen_corpus(100))
76
+ idx.save(tmp)
77
+ idx2 = NewBM25()
78
+ ok = idx2.load(tmp)
79
+ print(f" 正常 save/load: ok={ok}, size={idx2.size()} {'PASS' if ok and idx2.size()==100 else 'FAIL'}")
80
+
81
+ with open(tmp, 'wb') as f:
82
+ f.write(b'garbage data not a pickle')
83
+ idx3 = NewBM25()
84
+ ok3 = idx3.load(tmp)
85
+ print(f" 损坏文件 load: ok={ok3} (应该返 False, 不抛异常) {'PASS' if ok3 == False else 'FAIL'}")
86
+ print(f" 损坏后 idx3.size() = {idx3.size()} (应该 0, 已 fallback) {'PASS' if idx3.size() == 0 else 'FAIL'}")
87
+
88
+ with open(tmp, 'wb') as f:
89
+ pickle.dump({'old_version': True, 'ku_ids': [], 'corpus': []}, f)
90
+ idx4 = NewBM25()
91
+ ok4 = idx4.load(tmp)
92
+ print(f" schema 不匹配: ok={ok4} (应该返 False) {'PASS' if ok4 == False else 'FAIL'}")
93
+
94
+ if os.path.exists(tmp):
95
+ os.remove(tmp)
96
+ idx5 = NewBM25()
97
+ ok5 = idx5.load("_nonexistent_file.pkl")
98
+ print(f" 文件不存在: ok={ok5} (应该返 False) {'PASS' if ok5 == False else 'FAIL'}")
99
+
100
+ if os.path.exists(tmp):
101
+ os.remove(tmp)
102
+ return all([ok, ok3 == False, idx3.size() == 0, ok4 == False, ok5 == False])
103
+
104
+
105
+ def audit_append_ku_latency():
106
+ """3: append_ku 单条延迟"""
107
+ print("\n[3/5] append_ku 单条延迟 ...")
108
+ idx = NewBM25()
109
+ corpus = gen_corpus(1000)
110
+ t0 = time.time()
111
+ for ku in corpus:
112
+ idx.append_ku(ku)
113
+ dt = time.time() - t0
114
+ print(f" 1000 条 append_ku: {dt*1000:.0f} ms ({dt*1000/1000:.3f} ms/op)")
115
+ return dt
116
+
117
+
118
+ def audit_search_consistency():
119
+ """4: search 一致性 (build vs append_batch)"""
120
+ print("\n[4/5] search 一致性: build(1次) vs append_batch(2次) ...")
121
+ corpus = gen_corpus(1000, seed=42)
122
+
123
+ idx_a = NewBM25()
124
+ idx_a.build(corpus)
125
+
126
+ idx_b = NewBM25()
127
+ idx_b.build(corpus[:500])
128
+ idx_b.append_batch(corpus[500:])
129
+
130
+ queries = ["topic0_3 topic1_7", "topic2_5", "topic3_9 common"]
131
+ all_match = True
132
+ for q in queries:
133
+ r_a = sorted([(r.ku_id, round(r.score, 8)) for r in idx_a.search(q, 10)])
134
+ r_b = sorted([(r.ku_id, round(r.score, 8)) for r in idx_b.search(q, 10)])
135
+ match = r_a == r_b
136
+ if not match:
137
+ print(f" '{q}': NOT MATCH")
138
+ all_match = False
139
+ print(f" 3 query 一致: {'PASS' if all_match else 'FAIL'}")
140
+ return all_match
141
+
142
+
143
+ def audit_clear_idempotent():
144
+ """5: clear() 幂等性 + 空 corpus search"""
145
+ print("\n[5/5] clear() 幂等性 + 空 corpus search ...")
146
+ idx = NewBM25()
147
+ idx.build(gen_corpus(100))
148
+ print(f" size 前: {idx.size()}")
149
+ idx.clear()
150
+ print(f" clear 后: {idx.size()} (应该 0) {'PASS' if idx.size()==0 else 'FAIL'}")
151
+
152
+ r = idx.search("any query", 10)
153
+ print(f" 空 search: {len(r)} 个结果 (应该 0) {'PASS' if len(r)==0 else 'FAIL'}")
154
+
155
+ idx.clear()
156
+ print(f" 二次 clear: size={idx.size()} (应该 0) {'PASS' if idx.size()==0 else 'FAIL'}")
157
+
158
+ r = idx.remove_ku("ku_99999999")
159
+ print(f" remove_ku 不存在: 返 {r} (应该 False) {'PASS' if r == False else 'FAIL'}")
160
+
161
+ r = idx.search("", 10)
162
+ print(f" search 空 query: {len(r)} 个结果 (应该 0) {'PASS' if len(r)==0 else 'FAIL'}")
163
+
164
+ r = idx.search(" \t\n ", 10)
165
+ print(f" search 纯空白 query: {len(r)} 个结果 (应该 0) {'PASS' if len(r)==0 else 'FAIL'}")
166
+ return True
167
+
168
+
169
+ def main():
170
+ print("=" * 60)
171
+ print("B 阶段 BM25 - 全面审核 (5 项)")
172
+ print("=" * 60)
173
+
174
+ r1 = audit_float_accumulation()
175
+ r2 = audit_pickle_schema_fallback()
176
+ audit_append_ku_latency()
177
+ r4 = audit_search_consistency()
178
+ r5 = audit_clear_idempotent()
179
+
180
+ print("\n" + "=" * 60)
181
+ print(f"汇总: 浮点精度={'PASS' if r1 else 'FAIL'} pickle={'PASS' if r2 else 'FAIL'} search一致={'PASS' if r4 else 'FAIL'} clear/空={'PASS' if r5 else 'FAIL'}")
182
+ print("=" * 60)
183
+
184
+
185
+ if __name__ == "__main__":
186
+ main()