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
@@ -10,19 +10,22 @@ CognitiveAgent — 认知增强 Agent 基类
10
10
 
11
11
  import threading
12
12
  import uuid
13
+ from typing import TYPE_CHECKING, Any
13
14
 
14
15
  from ..core.thought_chain import ThoughtChain, ThoughtNode
15
16
  from ..harness.harness import Harness, HarnessResult
16
17
 
17
- # 工具并行执行后,多个 worker 线程可能同时走 _think(web_search 命中 / 记忆召回节点),
18
- # 而 _parent_node_id 是共享可变指针。用模块级 RLock 串行化「建链 + 挪指针」两步,
19
- # 保证 thought 链仍是一条合法链(节点本身顺序由完成时刻决定,语义可接受)。
18
+ if TYPE_CHECKING:
19
+ from ..core.recovery import RestartRecovery
20
+ from ..core.system_bus import SystemBus
21
+ from ..kernel import ProcessManager
22
+ from ..skills.lifecycle import HookManager
23
+ from ..skills.markdown_skill import MarkdownSkillRegistry
24
+
20
25
  _THINK_LOCK = threading.RLock()
21
26
 
22
- # ── S3 步骤 2:按职责拆分到 mixin(纯搬移、零行为变更)────────────────────────
23
- # 会话状态基础设施(contextvar + 污点 + HarnessBlockedError)搬至 mixins/_context.py;
24
- # 各职责方法搬至 mixins/{llm,augment,memory,preference,prompt,tool_exec}.py;
25
- # 主循环(会话管理 / _think / stream_reply / run_task 生命周期)留在本文件。
27
+ _GATE_UNSET = object()
28
+
26
29
  from .mixins._context import (
27
30
  _agent_ctx_get,
28
31
  _agent_ctx_set,
@@ -46,7 +49,6 @@ from .mixins.preference import PreferenceMixin
46
49
  from .mixins.prompt import PromptMixin, KERNEL_PROMPT
47
50
  from .mixins.tool_exec import ToolExecMixin
48
51
 
49
- # 历史导入兼容:`from foxclaw.agents.base import X` 的 X 在此 re-export(测试/外部模块仍按此路径取符号)。
50
52
  __all__ = [
51
53
  "CognitiveAgent", "HarnessBlockedError", "KERNEL_PROMPT",
52
54
  "_suppress_memory", "_act_stream", "_taint_get", "_taint_raise", "_taint_reset",
@@ -92,28 +94,32 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
92
94
  AGENT_NAME: str = "Base Agent"
93
95
  ALLOWED_TOOL_CATEGORIES: set[str] = {"read"}
94
96
 
97
+ md_skills: "MarkdownSkillRegistry"
98
+ hooks: "HookManager"
99
+ _system_bus: "SystemBus"
100
+ _process_manager: "ProcessManager"
101
+ _recovery: "RestartRecovery"
102
+
95
103
  def __init__(
96
104
  self,
97
- hmr, # HMR 实例(从外部注入)
105
+ hmr,
98
106
  thought_chain: ThoughtChain,
99
107
  client=None,
100
108
  data_dir: str = "./foxclaw_data",
101
109
  shadow_rounds: int = 20,
102
- router=None, # ModelRouter(多模型路由,从外部注入)
103
- spine=None, # 【P0】全局 EventSpine(harness 事件汇入脊柱→统一 WS 投影)
104
- caps=None, # 【P1-3】CapabilityRegistry(按名解析同伴,不再直接互持)
110
+ router=None,
111
+ spine=None,
112
+ caps=None,
105
113
  ):
106
114
  self.hmr = hmr
107
115
  self.thought_chain = thought_chain
108
116
  self.client = client
109
- # 多模型路由:优先用注入的 router;否则惰性创建(自动探测可用模型)
110
117
  if router is None:
111
118
  from ..core.model_router import ModelRouter
112
119
  router = ModelRouter()
113
120
  self.router = router
114
121
  self.data_dir = data_dir
115
122
 
116
- # 独立 Harness
117
123
  self.harness = Harness(
118
124
  agent_id=self.AGENT_ID,
119
125
  thought_chain=thought_chain,
@@ -121,20 +127,12 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
121
127
  shadow_rounds=shadow_rounds,
122
128
  spine=spine,
123
129
  )
124
- # 调度层(主管)豁免语义漂移拦截:接收任意输入是其本职,不算异常。
125
- # 领域 Agent 保持语义拦截:执行业务时跑题(如财务去写诗)才该拦。
126
130
  self.harness.block_on_semantic = not getattr(self, "IS_ROUTER", False)
127
131
 
128
- # 获取或创建 HMR Workspace
129
132
  self.workspace = hmr.get_workspace(self.AGENT_ID)
130
133
 
131
- # 每任务会话状态改由 contextvars 承载(见文件顶部)。这里只需一个 per-实例 token
132
- # 作为分槽 key;_session_id / _parent_node_id 是路由到 contextvar 的 property,
133
- # 故 start_session / _think 里既有的读写代码完全无需改动。
134
134
  self._ctx_token = uuid.uuid4().hex
135
135
 
136
- # 【P1-3】能力注册中枢:Agent 不再直接持有 search_runtime,而是按名惰性解析
137
- # (打断 agents⇄search_runtime⇄agent_port⇄agents 的直接互持环)。
138
136
  self._caps = caps
139
137
 
140
138
  def search_internal(self, query: str, top_k: int = 5):
@@ -146,7 +144,7 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
146
144
  return None
147
145
  return rt.search(query, agent_id=self.AGENT_ID, internal_only=True)
148
146
 
149
- def available_abilities(self, keys: list = None) -> list:
147
+ def available_abilities(self, keys: list | None = None) -> list:
150
148
  """【HKC 第2档 Step2·能力自省】证据驱动地查 HKC 的 ACE 能力:哪些的知识覆盖已达标
151
149
  (可编译 sufficient=True)、哪些还差(sufficient=False + missing_skills)。
152
150
 
@@ -170,14 +168,12 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
170
168
  out.append({"ability_key": ab.ability_key, "display_name": ab.display_name,
171
169
  "domain": ab.domain, "sufficient": True, "coverage": ab.coverage})
172
170
  except Exception as e:
173
- if hasattr(e, "missing_skills"): # 覆盖不足=证据 gate(非错误)
171
+ if hasattr(e, "missing_skills"):
174
172
  out.append({"ability_key": key, "sufficient": False,
175
173
  "coverage": getattr(e, "coverage", {}),
176
174
  "missing_skills": getattr(e, "missing_skills", [])})
177
- # 其它异常(未知 key/图错误)→ 跳过该能力,不污染结果
178
175
  return out
179
176
 
180
- # ── 每任务会话指针(contextvar 支撑,property 透明路由)──────
181
177
  @property
182
178
  def _session_id(self):
183
179
  return _agent_ctx_get(self._ctx_token).get("session_id")
@@ -194,23 +190,20 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
194
190
  def _parent_node_id(self, value):
195
191
  _agent_ctx_set(self._ctx_token, parent_node_id=value)
196
192
 
197
- # ── 会话管理 ───────────────────────────────────────────
198
193
 
199
- def start_session(self, goal: str, entities: list[str] = None) -> str:
194
+ def start_session(self, goal: str, entities: list[str] | None = None) -> str:
200
195
  """开始一个新任务会话,注册目标基线"""
201
196
  self._session_id = f"sess_{uuid.uuid4().hex[:10]}"
202
197
  self._parent_node_id = None
203
- _taint_reset(self) # 新会话从无污点起算(数据敏感度清零)
204
- _evidence_reset(self) # 新会话不继承上一个任务的执行证据(否则证据串台)
198
+ _taint_reset(self)
199
+ _evidence_reset(self)
205
200
 
206
- # 注册 Harness 目标基线
207
201
  self.harness.register_goal(
208
202
  goal_text=goal,
209
203
  allowed_tool_categories=self.ALLOWED_TOOL_CATEGORIES,
210
204
  baseline_entities=set(entities or []),
211
205
  )
212
206
 
213
- # 在 ThoughtChain 里记录目标基线节点
214
207
  goal_node = ThoughtNode.create(
215
208
  session_id=self._session_id,
216
209
  agent_id=self.AGENT_ID,
@@ -223,22 +216,14 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
223
216
  self.thought_chain.update_harness(goal_node.id, "BASELINE")
224
217
  self._parent_node_id = goal_node.id
225
218
 
226
- # 【深审修复·移除惰性共享写】原先 `self.workspace.active_goal = goal` 把每任务目标
227
- # 写到 per-Agent **共享**的 HMR workspace 上,同一 Agent 实例并发多任务会互相覆盖。
228
- # 审计确认此写**完全惰性**:foxclaw 召回走显式 query(见 _recall_memory,从不读
229
- # workspace.active_goal),save_workspace 从未被调用(不持久化),无测试依赖它——
230
- # 故 race 零可观测影响。移除该误导性共享写:**每任务目标的权威来源**是会话隔离的
231
- # ThoughtChain(goal 节点,session_id 经 contextvar 隔离)+ 事件驱动的 CognitiveState
232
- # (execution.completed 的 active_goal)。共享单值 workspace 本就无法忠实承载 N 个并发目标。
233
219
  return self._session_id
234
220
 
235
- # ── ThoughtChain + Harness 集成推理步骤 ───────────────
236
221
 
237
222
  def _reasoning_result(self, node):
238
223
  """经统一 PolicyGate 做推理准入,返回 HarnessResult(与直接 harness.check 逐字一致)。
239
224
  gate 经能力中枢惰性解析并缓存;无 gate(standalone/治理场景)则直接 harness.check。"""
240
- gate = getattr(self, "_gate_cache", "unset")
241
- if gate == "unset":
225
+ gate: Any = getattr(self, "_gate_cache", _GATE_UNSET)
226
+ if gate is _GATE_UNSET:
242
227
  caps = getattr(self, "_caps", None)
243
228
  gate = caps.get("policy_gate") if caps is not None else None
244
229
  self._gate_cache = gate
@@ -251,10 +236,10 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
251
236
  content: str,
252
237
  node_type="reasoning",
253
238
  conf: float = 0.9,
254
- mem_refs: list[str] = None,
255
- tool_name: str = None,
256
- entities: list[str] = None,
257
- metadata: dict = None,
239
+ mem_refs: list[str] | None = None,
240
+ tool_name: str | None = None,
241
+ entities: list[str] | None = None,
242
+ metadata: dict | None = None,
258
243
  ) -> tuple[ThoughtNode, HarnessResult]:
259
244
  """
260
245
  记录一个推理步骤,经过 Harness 校验
@@ -272,17 +257,14 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
272
257
  entities=entities or [],
273
258
  metadata=metadata,
274
259
  )
275
- # 锁只护「链插入 + 父指针挪动」这两步共享状态;Harness 判定在锁外,避免钩子阻塞并发工具。
276
260
  with _THINK_LOCK:
277
261
  self.thought_chain.add_node(node)
278
262
 
279
- # Harness 校验(经统一 PolicyGate 做推理准入;拿到的仍是同一 HarnessResult,行为一致)
280
263
  result = self._reasoning_result(node)
281
264
 
282
265
  if result.is_blocked:
283
266
  raise HarnessBlockedError(result, node)
284
267
 
285
- # WARN:降低置信度但继续
286
268
  if result.is_warned:
287
269
  node.conf = max(node.conf - 0.15, 0.1)
288
270
 
@@ -364,8 +346,8 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
364
346
  f"但无法提取为可读文本;若需要其内容,请说明并提示用户改用文本/PDF 等可读格式。")
365
347
  return "\n\n" + "\n\n".join(parts) if parts else ""
366
348
 
367
- def stream_reply(self, task: str, stop_event=None, images: list = None, history: list = None,
368
- attachments: list = None, on_thinking=None, on_evidence=None):
349
+ def stream_reply(self, task: str, stop_event=None, images: list | None = None, history: list | None = None,
350
+ attachments: list | None = None, on_thinking=None, on_evidence=None):
369
351
  """流式直答路径(方案A):对话/问答/分析,不做多步编排(那走 run_task)。同步生成器,
370
352
  由端点在线程池迭代成 SSE。stop_event 置位(客户端断连)则提前终止,省 token。
371
353
  images(可选)= 多模态图片,随问题发给视觉模型(模型无关,非视觉模型 router 层降级)。
@@ -386,7 +368,7 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
386
368
  from ..core import injection_guard as _ig
387
369
  from ..core.model_router import _chunk_text
388
370
  task = str(task or "")
389
- _evidence_reset(self) # 每轮从零开账:上一轮的证据不能冒充这一轮
371
+ _evidence_reset(self)
390
372
  if attachments:
391
373
  ctx = self._attachments_context(attachments)
392
374
  if ctx:
@@ -395,7 +377,7 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
395
377
  messages = hist + [{"role": "user", "content": task}]
396
378
  parts = []
397
379
  used_tools = False
398
- guarded_out = False # 输出护栏是否触发(触发的污染回复不落库,防回流)
380
+ guarded_out = False
399
381
 
400
382
  def _emit_thinking(delta: str) -> None:
401
383
  """推理内容的最后一道关:思考也不许带密钥/系统提示原文(与正文同等级净化)。"""
@@ -411,26 +393,23 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
411
393
  try:
412
394
  on_thinking(delta)
413
395
  except Exception:
414
- pass # 前端断连/回调异常不得影响正文生成
396
+ pass
415
397
 
416
398
  if _tools.tool_use_enabled() and self.router.supports_tools() and not images:
417
- # 与 fallback 一致地注入偏好/技能/能力(否则开工具化会静默丢掉"总是注入偏好"的保证、
418
- # 丢掉 SKILL.md 与能力知识)。**唯独不做 web_augment**——联网交给 LLM 自主调 web_search 工具。
419
399
  try:
420
400
  tmsgs = self._ability_augment(task, messages)
421
401
  tmsgs = self._skill_augment(task, tmsgs)
422
402
  tmsgs = self._pref_augment(tmsgs)
423
403
  except Exception:
424
404
  tmsgs = messages
425
- _compact = getattr(self, "_compact_context", None) # 轻量替身对象无此方法
405
+ _compact = getattr(self, "_compact_context", None)
426
406
  if _compact is not None:
427
407
  tmsgs = _compact(tmsgs, "tools")
428
408
  try:
429
409
  final = self._reply_with_tools(task, tmsgs, stop_event=stop_event)
430
410
  except Exception:
431
411
  final = None
432
- if final is not None: # None = 端点不支持 → 落到 fallback
433
- # 工具路径有完整文本 → 流出前兜底(密钥脱敏/拦系统提示 dump);传 kernel 用逐字串比对更准
412
+ if final is not None:
434
413
  final, _oiss = _ig.guard_output(final, kernel=KERNEL_PROMPT)
435
414
  guarded_out = bool(_oiss)
436
415
  used_tools = True
@@ -439,25 +418,23 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
439
418
  break
440
419
  parts.append(chunk)
441
420
  yield chunk
442
- if not used_tools: # fallback:关键词增强链 + 真流式(行为逐字不变)
421
+ if not used_tools:
443
422
  try:
444
- messages = self._web_augment(task, messages) # 增强都合并进"最后一条 user",历史不受影响
423
+ messages = self._web_augment(task, messages)
445
424
  messages = self._ability_augment(task, messages)
446
425
  messages = self._skill_augment(task, messages)
447
426
  messages = self._pref_augment(messages)
448
427
  except Exception:
449
428
  messages = hist + [{"role": "user", "content": task}]
450
- _compact = getattr(self, "_compact_context", None) # 轻量替身对象无此方法
429
+ _compact = getattr(self, "_compact_context", None)
451
430
  if _compact is not None:
452
431
  messages = _compact(messages, "chat")
453
- _tail = "" # 滑窗尾缓冲:跨 chunk 边界的泄露检测只扫最近 _WIN 字,不再整段重扫(消 O(n²))
454
- _WIN = 256 # 覆盖最长敏感串(密钥)跨 chunk 边界的情况
432
+ _tail = ""
433
+ _WIN = 256
455
434
  for chunk in self.router.stream(self.system_prompt, messages,
456
435
  agent_id=self.AGENT_ID, stop_event=stop_event,
457
436
  images=images,
458
437
  on_thinking=_emit_thinking if on_thinking else None):
459
- # 流出前检测(而非"yield 后才检测"):密钥/泄露所在 chunk 不再已发给用户才中断。
460
- # 只扫"尾缓冲 + 新 chunk"(增量滑窗),命中则本 chunk 不发、整段 dump 止于此。
461
438
  _probe = _tail + chunk
462
439
  if _ig.scan_output(_probe):
463
440
  guarded_out = True
@@ -471,26 +448,19 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
471
448
  yield _notice
472
449
  reply = "".join(parts)
473
450
  stopped = stop_event is not None and stop_event.is_set()
474
- # 执行证据在正文之后一次性上报(晚于 delta、早于 done):前端拿到时答案已完整,
475
- # 可以挂在答案下方供人核对;没有工具步的纯对话不产生任何证据事件。
476
451
  if on_evidence is not None:
477
452
  try:
478
453
  _evs = _evidence_take(self)
479
454
  if _evs:
480
455
  on_evidence(_evs)
481
456
  except Exception:
482
- pass # 证据上报失败不得影响已生成的回答
483
- # 落库前最终兜底(仅 fallback 路径需要):fallback 增量检查(无 kernel、只抓明显 dump)可能漏过
484
- # 逐字复现的系统提示,这里用 kernel 逐字串比对再判一次,命中则不落库(防污染回流),不影响已流给
485
- # 用户的内容。工具路径在流出前已 guard_output(kernel) 完整防护,无需重复扫(消冗余)。
457
+ pass
486
458
  if reply and not guarded_out and not used_tools and _ig.scan_output(reply, kernel=KERNEL_PROMPT):
487
459
  guarded_out = True
488
460
  try:
489
461
  self._think(content=("流式直答:" + reply)[:500], node_type="reflection", conf=0.8)
490
462
  except Exception:
491
463
  pass
492
- # 活动可观测:对话路径此前**不发任何事件** → /bus/history 恒空、前端"活动"页永远没内容
493
- # (run_task 走 _emit_execution 会发,但直答/流式对话不经那条路)。这里补一条同源事件。
494
464
  try:
495
465
  _caps = getattr(self, "_caps", None)
496
466
  _spine = _caps.get("event_spine") if _caps is not None else None
@@ -503,12 +473,6 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
503
473
  }, source=self.AGENT_ID)
504
474
  except Exception:
505
475
  pass
506
- # 写入记忆(与 /api/task 一致;MCP 场景由 _suppress_memory 兜住);断连中止/触发输出护栏则不写
507
- #
508
- # A 类修复:故障降级回复**禁止写入长期记忆** —— 把「模型失败/未执行」当成
509
- # 「对话结论」沉淀,会让 HMR 后续召回持续复读故障文案(一次故障 → 长期污染)。
510
- # 判据用 take_call_degraded()(per-call)而非全局 is_stub:is_stub=True 是
511
- # 「从未配置模型」的离线态,那个场景下记录任务/占位仍有诊断价值,不该一刀切。
512
476
  _degraded = False
513
477
  try:
514
478
  _degraded = bool(self.router.take_call_degraded())
@@ -516,13 +480,12 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
516
480
  _degraded = False
517
481
  if reply and not stopped and not guarded_out and not _degraded:
518
482
  try:
519
- safe_reply = _ig.redact_secrets(reply) # 落库同样脱敏,防密钥沉进长期记忆
483
+ safe_reply = _ig.redact_secrets(reply)
520
484
  self._store_memory(f"对话:{task} → {safe_reply}"[:800], mem_type="conversation")
521
485
  except Exception:
522
486
  pass
523
- self._maybe_store_preference(task) # 对话里的偏好表达 → 持久记(preference 类型)
487
+ self._maybe_store_preference(task)
524
488
  elif _degraded and reply and not stopped:
525
- # 降级:只留事件痕迹(可观测、可归因),不写记忆内容
526
489
  try:
527
490
  _spine = _caps.get("event_spine") if _caps is not None else None
528
491
  if _spine is not None:
@@ -534,12 +497,8 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
534
497
  except Exception:
535
498
  pass
536
499
 
537
- # ── 统一任务生命周期(模板方法,P1:5 个 run_task 收敛为 1)──────
538
- # 领域 Agent 不再各自重写 run_task,只实现 _execute()(召回后的领域步骤)。
539
- # 会话开启、记忆召回、返回体结构、Harness 拦截处理都在此**唯一**定义,
540
- # 保证所有 Agent 生命周期一致(修复"每 Agent 各写一份、行为漂移")。
541
500
 
542
- _recall_topk: int = 5 # 召回条数(office 覆盖为 8)
501
+ _recall_topk: int = 5
543
502
 
544
503
  def _task_entities(self, task: str) -> list:
545
504
  """本任务的基线实体(用于 Harness 目标基线)。领域 Agent 覆盖。"""
@@ -549,12 +508,6 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
549
508
  """记忆召回查询(领域 Agent 可加前缀,如财务/行程)。默认用原任务。"""
550
509
  return task
551
510
 
552
- # ── 【P1-1】任务生命周期钩子 ────────────────────────────────
553
- # 崩溃/重启恢复记账(RestartRecovery)。会话开启后、管线执行前触发 started;任务终结时
554
- # 触发 settled(done=正常终态含 Harness 兜底/中断;failed=未兜底异常)。run_task 与
555
- # run_task_stream 共用 _run_task_core,故两条路径都会触发。
556
- # 实现放在基类(而不是只让主管覆盖):P1-1 时只有主管接了线,领域 Agent 跑一半崩掉
557
- # 在恢复扫描里根本不可见。没有 _recovery 的 standalone/测试 Agent → 直接跳过。
558
511
  def _on_session_started(self, session_id: str, task: str, context: dict) -> None:
559
512
  """会话已开、管线未跑:落 task_started(崩溃后才认得出"上次跑到一半")。"""
560
513
  rec = getattr(self, "_recovery", None)
@@ -618,7 +571,7 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
618
571
  pipe = self._pipeline_cache = CognitivePipeline(DEFAULT_STAGES)
619
572
  return pipe
620
573
 
621
- async def run_task(self, task: str, context: dict = None, stop_event=None) -> dict:
574
+ async def run_task(self, task: str, context: dict | None = None, stop_event=None) -> dict:
622
575
  """统一任务生命周期:开会话 → [认知管线:recall → act] → 组装返回。
623
576
  Harness BLOCK 统一在此兜底为结构化错误。返回
624
577
  {"result",...,"session_id","agent","thought_summary", **extra}。
@@ -633,7 +586,7 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
633
586
  说明续了哪一次、复用了多少步。"""
634
587
  return await self._run_task_core(task, context, stop_event=stop_event, on_stage=None)
635
588
 
636
- async def _run_task_core(self, task: str, context: dict = None,
589
+ async def _run_task_core(self, task: str, context: dict | None = None,
637
590
  stop_event=None, on_stage=None) -> dict:
638
591
  """run_task 的执行核心 —— 供同步 `run_task` 与流式 `run_task_stream` **共用**,避免两份
639
592
  生命周期逻辑漂移。`on_stage`(D1):逐 stage 进度回调,透传给管线;None=同步路径不回调,
@@ -641,29 +594,18 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
641
594
  from ..pipeline import PipelineContext
642
595
  context = context or {}
643
596
  session_id = self.start_session(goal=task, entities=self._task_entities(task))
644
- # 来源可信性:渠道入口会带 untrusted_source=True(见 channels/dispatcher)。本任务里的
645
- # 写/发送/外发动作据此强制 HITL;本地 HTTP 对话不带此键 → 行为逐字不变。
646
597
  _untrusted_set(self, bool(context.get("untrusted_source")))
647
- # 【P1-1】生命周期钩子:会话已开、管线未跑。默认 no-op;主管借此做崩溃/重启
648
- # 恢复记账(task_started)——恢复记账需先于执行落日志,故必须在管线之前。
649
598
  self._on_session_started(session_id, task, context)
650
- # E2:pre_reasoning(agent_start)钩子——推理开始前触发,可注入 additionalContext(前插进 act
651
- # 的 LLM 上下文,见 _call_llm)。默认无钩子/无注入 → 行为逐字不变。hooks 由 Foxclaw 装配注入;
652
- # standalone/测试 Agent 无 hooks 属性 → getattr None → 整个钩子逻辑跳过。
653
599
  _hooks = getattr(self, "hooks", None)
654
600
  _inject_parts = []
655
601
  if _hooks is not None:
656
602
  _hr = _hooks.fire("agent_start", "", {"task": task, "agent_id": self.AGENT_ID})
657
603
  if _hr.additional_context:
658
604
  _inject_parts.append(_hr.additional_context)
659
- _pref = self._prefs_context() # 偏好优先注入(独立于语义 query → 每次推理总是注入)
605
+ _pref = self._prefs_context()
660
606
  if _pref:
661
607
  _inject_parts.append(_pref)
662
- # 偏好 + agent_start 钩子上下文合并进同一 _reasoning_inject → _call_llm 前插(复用 E2 机制)
663
608
  _inject_tok = _reasoning_inject.set("\n\n".join(_inject_parts)) if _inject_parts else None
664
- # 【P1 断点续跑】context={"_resume_task_id": <上次的 task_id/session_id>} 时,把上次
665
- # 已完成的工具步骤装进 contextvar(root_key→结果):工具轮命中同指纹步骤直接复用结果、
666
- # 不再重复执行。opt-in——不带该键 → 不装载、行为逐字不变。
667
609
  _resume_tid = str(context.get("_resume_task_id") or "").strip()
668
610
  _resume_cache = self._load_resume_cache(_resume_tid) if _resume_tid else {}
669
611
  _resume_tok = _resume_steps.set(_resume_cache) if _resume_cache else None
@@ -685,19 +627,14 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
685
627
  "thought_summary": self.thought_chain.get_summary(self.AGENT_ID),
686
628
  **(ctx.extra or {}),
687
629
  }
688
- _plan = _plan_payload(ctx) # 计划可见:阻塞路径也回传,客户端无需再猜步骤
630
+ _plan = _plan_payload(ctx)
689
631
  if _plan:
690
632
  resp["plan"] = _plan
691
- if _resume_cache: # 续跑透明化:告诉调用方"用了几个已完成步骤、从哪续的"
633
+ if _resume_cache:
692
634
  resp["resumed_from"] = _resume_tid
693
635
  resp["resumed_steps"] = len(_resume_cache)
694
- if ctx.interrupted: # P3:被 stop_event 提前中断 → 让调用方识别"部分完成"
636
+ if ctx.interrupted:
695
637
  resp["interrupted"] = True
696
- # 【A·Step3·确认闸提升】act 若经 skill dispatch 且未成功(needs_confirmation/blocked/
697
- # circuit_open/error),把该态提升为 run_task **顶层 status**,让调用方无需深挖 result
698
- # 即可识别"待确认/未完成动作";needs_confirmation 附 pending_action(供确认后带
699
- # _confirmed 重跑恢复执行)。**未完成 ⇒ 不作为已完成真值沉淀**(blocked=True,呼应
700
- # "被拦截任务不沉淀记忆");成功/纯 LLM 路径行为逐字不变。
701
638
  skill_status = (ctx.extra or {}).get("skill_status")
702
639
  skill_incomplete = bool(skill_status) and skill_status != "done"
703
640
  if skill_incomplete:
@@ -711,41 +648,35 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
711
648
  "hint": "确认后带 context={'_confirmed': <skill_id>, ...} 重跑本任务以执行"
712
649
  "(绑定到 skill_id 更安全;_confirmed=True 为概括确认)",
713
650
  }
714
- # 「未完成 ⇒ 不作为已完成真值沉淀」的 blocked 判定,须同时覆盖两类未完成:
715
- # ① skill 未成功(needs_confirmation/blocked/circuit_open/error);
716
- # ② 被 stop_event **中断**(B3 深审 G2):流式任务客户端断连 → 中断,ctx.result 只是
717
- # 部分/空产物,绝不能当"已完成真值"沉淀进 HMR 共享记忆(呼应 P5/Principle07)。
718
- # P3 引入 interrupted 时未联动此处;B3 的 /api/task/stream 是首个真正会 set stop_event
719
- # 的生产调用方,才使这条路径可达。非中断路径 blocked 值与改前逐字一致。
720
651
  blocked = skill_incomplete or ctx.interrupted
721
652
  self._emit_execution(task, ctx.result, blocked=blocked, context=context)
722
- self._maybe_store_preference(task) # 用户偏好表达 → 持久记(preference 类型,下次总是注入)
723
- if _hooks is not None: # E2:task_complete(agent_end)——任务完成后只读观测/上报(对应范式 Stop)
653
+ self._maybe_store_preference(task)
654
+ if _hooks is not None:
724
655
  _hooks.fire("agent_end", "", {"task": task, "agent_id": self.AGENT_ID,
725
656
  "result": resp.get("result"),
726
657
  "interrupted": bool(ctx.interrupted)})
727
- self._on_task_settled(session_id, "done") # 【P1-1】正常终态(含中断/被拦提升)
658
+ self._on_task_settled(session_id, "done")
728
659
  return resp
729
660
  except HarnessBlockedError as e:
730
661
  self._emit_execution(
731
662
  task, {"error": "harness_blocked", "reason": e.result.reason},
732
663
  blocked=True, context=context)
733
- if _hooks is not None: # task_complete 也覆盖被拦截结束(带 error 供上报)
664
+ if _hooks is not None:
734
665
  _hooks.fire("agent_end", "", {"task": task, "agent_id": self.AGENT_ID,
735
666
  "error": "harness_blocked"})
736
- self._on_task_settled(session_id, "done") # 被拦截是已兜底的正常终态(非崩溃)
667
+ self._on_task_settled(session_id, "done")
737
668
  return {"error": "harness_blocked", "reason": e.result.reason,
738
669
  "session_id": session_id}
739
670
  except Exception:
740
- self._on_task_settled(session_id, "failed") # 【P1-1】未兜底异常 → failed(供恢复)
671
+ self._on_task_settled(session_id, "failed")
741
672
  raise
742
673
  finally:
743
674
  if _inject_tok is not None:
744
- _reasoning_inject.reset(_inject_tok) # 复位注入 contextvar,不泄漏到后续任务
675
+ _reasoning_inject.reset(_inject_tok)
745
676
  if _resume_tok is not None:
746
- _resume_steps.reset(_resume_tok) # 续跑缓存不泄漏到后续任务
677
+ _resume_steps.reset(_resume_tok)
747
678
 
748
- def run_task_stream(self, task: str, context: dict = None, stop_event=None):
679
+ def run_task_stream(self, task: str, context: dict | None = None, stop_event=None):
749
680
  """流式任务执行(D1):**同步 generator**,逐 stage 吐进度 + act 逐 token 出字 + 最终结果。
750
681
  产出事件(dict,逐条给 SSE):
751
682
  {"stage": name} 每完成一个认知 stage(perceive→…→reflect)
@@ -769,7 +700,7 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
769
700
 
770
701
  def _on_stage(name, _ctx):
771
702
  bridge.put({"stage": name})
772
- if name == "plan": # 计划显式化:steps 随事件送给前端/调用方
703
+ if name == "plan":
773
704
  _plan = _plan_payload(_ctx)
774
705
  if _plan:
775
706
  bridge.put({"plan": _plan})
@@ -783,11 +714,11 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
783
714
  resp = _asyncio.run(self._run_task_core(
784
715
  task, context, stop_event=stop_event, on_stage=_on_stage))
785
716
  bridge.put({"result": resp})
786
- except Exception as e: # 核心已兜底 HarnessBlock;此处兜其余意外
717
+ except Exception as e:
787
718
  bridge.put({"error": str(e)})
788
719
  finally:
789
720
  _act_stream.reset(token)
790
- bridge.put(_SENTINEL) # 结束哨兵:保证 generator 必定收尾
721
+ bridge.put(_SENTINEL)
791
722
 
792
723
  _threading.Thread(target=_worker, daemon=True, name="task-stream").start()
793
724
  while True:
@@ -824,7 +755,6 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
824
755
  (路由分发由 supervisor_stages 的 dispatch stage 承担),不会走到本钩子。"""
825
756
  raise NotImplementedError(f"{self.AGENT_ID} 未实现 _execute()")
826
757
 
827
- # ── 编排协作接口(P3:领域知识归属领域 Agent,编排层只做通用聚合/路由)──────
828
758
  def situation(self) -> dict:
829
759
  """本 Agent 的领域态势:声明自己的 domain + 状态 + 告警。默认无领域态势。
830
760
  领域 Agent 覆盖。编排层据此**通用聚合**,不需懂任何领域内部 API。
@@ -849,7 +779,6 @@ class CognitiveAgent(AugmentMixin, LlmMixin, MemoryMixin,
849
779
  req.status = "approved"
850
780
  req.verdict = "无需特殊审批"
851
781
 
852
- # ── 通用状态查询 ───────────────────────────────────────
853
782
 
854
783
  def get_status(self) -> dict:
855
784
  return {
@@ -2,10 +2,8 @@
2
2
 
3
3
  from ...core.dispatch import dispatch_failed as _dispatch_failed # noqa: F401 (re-export)
4
4
 
5
- # ── 多步链式上下文 ────────────────────────────────────────────
6
- # 注入的前序步数与单步字符必须封顶:长链会把提示词越滚越大(且越往后越贵/越容易超窗)。
7
- PRIOR_MAX_STEPS = 3 # 只带最近 N 步(更早的通常已被后续步骤消化)
8
- PRIOR_MAX_CHARS = 300 # 单步输出截断
5
+ PRIOR_MAX_STEPS = 3
6
+ PRIOR_MAX_CHARS = 300
9
7
 
10
8
 
11
9
  def _with_prior(subtask: str, prior: list) -> str:
@@ -49,12 +47,6 @@ def _fmt_mem(m: dict, max_chars: int | None = None) -> str:
49
47
  return f"{head}:{content}" if head else content
50
48
 
51
49
 
52
- # ── P0-1 反思重规划:执行结果判定 ────────────────────────────
53
- # 实现已下沉到 core.dispatch(见文件头 import):pipeline 的 replan stage 也要用它,
54
- # 而 pipeline 不能反向 import agents —— 两处都只依赖 core,依赖方向单一。
55
- # `_dispatch_failed` 在此保留为 re-export,历史导入路径(agents.agents / impl.supervisor)不变。
56
-
57
-
58
50
  def _extract_step_results(dr) -> list:
59
51
  """从 dispatch_result 提取各步结果(供 LLM 反思:含成功/失败状态与输出)。"""
60
52
  if not isinstance(dr, dict):