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