foxclaw 0.1.2 → 0.1.4
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/.github/workflows/release.yml +5 -0
- package/python/CHANGELOG.md +100 -0
- package/python/CHANGELOG_CN.md +100 -0
- package/python/README.md +17 -2
- package/python/README_CN.md +38 -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/CONTENT_GUARD.md +189 -0
- package/python/docs/CONTENT_GUARD_CN.md +189 -0
- package/python/docs/RELEASE.md +78 -37
- 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 +74 -152
- package/python/foxclaw/agents/base.py +82 -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 +23 -3
- package/python/foxclaw/agents/mixins/preference.py +58 -8
- package/python/foxclaw/agents/mixins/prompt.py +59 -12
- package/python/foxclaw/agents/mixins/skillbox.py +6 -6
- package/python/foxclaw/agents/mixins/tool_exec.py +16 -42
- package/python/foxclaw/agents/rules/finance/RULES.md +131 -0
- package/python/foxclaw/api/__init__.py +18 -77
- package/python/foxclaw/api/_state.py +43 -0
- package/python/foxclaw/api/bootstrap.py +114 -0
- 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 +50 -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/behavior/__init__.py +20 -0
- package/python/foxclaw/behavior/behavior.yaml +62 -0
- package/python/foxclaw/behavior/spec.py +287 -0
- 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/content_guard.py +341 -0
- 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 +53 -60
- package/python/foxclaw/core/metrics.py +4 -5
- package/python/foxclaw/core/model_router.py +74 -150
- 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/sensitive_write.py +283 -0
- 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 +18 -201
- package/python/frontend/v3/assets/index-JKfHlb-a.css +1 -0
- package/python/frontend/v3/assets/index-tN90dpUH.js +34 -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 +42 -3
- 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 +16 -44
- 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 +17 -3
- package/python/requirements.txt +311 -0
- package/python/tests/conftest.py +0 -22
- package/python/tests/run_all.py +4 -66
- package/python/tests/test_agent_lifecycle.py +4 -38
- package/python/tests/test_agent_rules.py +81 -0
- 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_behavior_spec.py +198 -0
- 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_conflict_dismiss.py +143 -0
- package/python/tests/test_content_guard.py +177 -0
- 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_sensitive_write.py +181 -0
- 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/build_content_lexicon.py +218 -0
- package/python/tools/bundle_web.py +98 -0
- 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/recheck_conflicts.py +156 -0
- package/python/tools/release_check.py +24 -15
- 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/vendor/hkc/hkc_api/routes/ability.py +31 -0
- package/python/vendor/hkc/hkc_api/schemas.py +11 -0
- package/python/vendor/hkc/hkc_kee/kee.py +124 -3
- package/python/vendor/hkc/hkc_sdk/base.py +22 -0
- package/python/vendor/hkc/hkc_sdk/direct_client.py +10 -0
- package/python/vendor/hkc/hkc_sdk/http_client.py +19 -0
- package/python/foxclaw/api/app.py +0 -123
- package/python/frontend/v3/assets/index-BD7VPbMV.js +0 -33
- package/python/frontend/v3/assets/index-CAvnYWGH.css +0 -1
package/python/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "foxclaw"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.4"
|
|
8
8
|
description = "Foxclaw - a personal agent with memory, built on the HMR memory runtime"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
|
|
@@ -70,6 +70,13 @@ foxclaw = "foxclaw.cli:main"
|
|
|
70
70
|
# 这里把它们真正打进 wheel,并让 package-data 一并带上 LICENSE/JSON 等非 .py 资源。
|
|
71
71
|
include-package-data = true
|
|
72
72
|
|
|
73
|
+
[tool.setuptools.package-data]
|
|
74
|
+
# frontend/ 在仓库根、不属于任何包,packages.find 收不到;构建前由
|
|
75
|
+
# tools/bundle_web.py 复制成 foxclaw/web/(已 gitignore),这里再把它带进 wheel/sdist。
|
|
76
|
+
# 不复制的话 pip install 之后 foxclaw serve 首页 404(只有 API/CLI)。
|
|
77
|
+
"foxclaw.web" = ["**/*"]
|
|
78
|
+
|
|
79
|
+
|
|
73
80
|
[tool.setuptools.packages.find]
|
|
74
81
|
# foxclaw 在仓库根;hmr 在 vendor/ 下;hkc_* 在 vendor/hkc/ 下 —— 三个搜索根都要给。
|
|
75
82
|
where = [".", "vendor", "vendor/hkc"]
|
|
@@ -134,18 +141,22 @@ python_version = "3.11"
|
|
|
134
141
|
ignore_missing_imports = true
|
|
135
142
|
check_untyped_defs = true
|
|
136
143
|
# 渐进式:mypy 存量错误用棘轮门管理(tools/mypy_ratchet.py + tools/mypy_baseline.txt)。
|
|
137
|
-
# 2026-11 实测
|
|
144
|
+
# 2026-11 实测 152 errors in 45 files,已冻结:CI 中错误数一旦增加即失败,
|
|
138
145
|
# 下降后用 `python tools/mypy_ratchet.py --update` 调低基线。只降不升。
|
|
139
146
|
|
|
140
147
|
[tool.pytest.ini_options]
|
|
141
148
|
testpaths = ["tests"]
|
|
142
|
-
# S2
|
|
149
|
+
# S2 迁移完成:全部测试文件均已迁移为 pytest(无顶层 import 副作用,可安全收集)。
|
|
143
150
|
# 注意:网关/内置MCP/流式限流等少数测试依赖模块级单例(FOXCLAW_GATEWAY、FOXCLAW_MCP_SERVER、
|
|
144
151
|
# _STREAM_LIMITER 均在 import 时按 env 固化),单进程 `pytest tests/` 会让这些单例被首个
|
|
145
152
|
# import 定死、相互污染。故全量执行统一走 tests/run_all.py(每个文件独立子进程
|
|
146
153
|
# `python -m pytest <file> -q` 隔离)。本白名单确保任意单文件可被 pytest 收集/运行。
|
|
147
154
|
python_files = [
|
|
148
155
|
"test_agent_lifecycle.py",
|
|
156
|
+
"test_sensitive_write.py",
|
|
157
|
+
"test_content_guard.py",
|
|
158
|
+
"test_behavior_spec.py",
|
|
159
|
+
"test_agent_rules.py",
|
|
149
160
|
"test_ahs_p2.py",
|
|
150
161
|
"test_anthropic_tools.py",
|
|
151
162
|
"test_api.py",
|
|
@@ -214,6 +225,7 @@ python_files = [
|
|
|
214
225
|
"test_plan_visible.py",
|
|
215
226
|
"test_planner.py",
|
|
216
227
|
"test_policy_gate.py",
|
|
228
|
+
"test_profile.py",
|
|
217
229
|
"test_reasoner.py",
|
|
218
230
|
"test_release_check.py",
|
|
219
231
|
"test_resume_checkpoint.py",
|
|
@@ -229,6 +241,7 @@ python_files = [
|
|
|
229
241
|
"test_secrets.py",
|
|
230
242
|
"test_skill_taint_gate.py",
|
|
231
243
|
"test_skills.py",
|
|
244
|
+
"test_skills_fetch.py",
|
|
232
245
|
"test_stats_and_events.py",
|
|
233
246
|
"test_streaming.py",
|
|
234
247
|
"test_supervisor_pipeline.py",
|
|
@@ -246,6 +259,7 @@ python_files = [
|
|
|
246
259
|
"test_tracing.py",
|
|
247
260
|
"test_truth_crystallizer.py",
|
|
248
261
|
"test_truth_flow.py",
|
|
262
|
+
"test_update_check.py",
|
|
249
263
|
"test_url_policy.py",
|
|
250
264
|
"test_version_sync.py",
|
|
251
265
|
"test_web_trigger.py",
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# This file was autogenerated by uv via the following command:
|
|
2
|
+
# uv pip compile pyproject.toml --universal -o requirements.txt
|
|
3
|
+
annotated-doc==0.0.5
|
|
4
|
+
# via
|
|
5
|
+
# fastapi
|
|
6
|
+
# typer
|
|
7
|
+
annotated-types==0.8.0
|
|
8
|
+
# via pydantic
|
|
9
|
+
anthropic==2.6.0
|
|
10
|
+
# via foxclaw (pyproject.toml)
|
|
11
|
+
anyio==4.16.0
|
|
12
|
+
# via
|
|
13
|
+
# anthropic
|
|
14
|
+
# httpx
|
|
15
|
+
# httpx2
|
|
16
|
+
# mcp
|
|
17
|
+
# openai
|
|
18
|
+
# sse-starlette
|
|
19
|
+
# starlette
|
|
20
|
+
attrs==26.1.0
|
|
21
|
+
# via
|
|
22
|
+
# jsonschema
|
|
23
|
+
# referencing
|
|
24
|
+
certifi==2026.10.23
|
|
25
|
+
# via
|
|
26
|
+
# httpcore
|
|
27
|
+
# httpx
|
|
28
|
+
cffi==2.1.1 ; platform_python_implementation != 'PyPy'
|
|
29
|
+
# via cryptography
|
|
30
|
+
click==8.5.1
|
|
31
|
+
# via
|
|
32
|
+
# huggingface-hub
|
|
33
|
+
# uvicorn
|
|
34
|
+
cloudpickle==3.1.2
|
|
35
|
+
# via joblib
|
|
36
|
+
colorama==0.4.6 ; sys_platform == 'win32'
|
|
37
|
+
# via
|
|
38
|
+
# tqdm
|
|
39
|
+
# typer
|
|
40
|
+
cryptography==50.0.2
|
|
41
|
+
# via
|
|
42
|
+
# foxclaw (pyproject.toml)
|
|
43
|
+
# pyjwt
|
|
44
|
+
cuda-bindings==13.5.0 ; python_full_version < '3.15' and sys_platform == 'linux'
|
|
45
|
+
# via torch
|
|
46
|
+
cuda-pathfinder==1.8.6 ; python_full_version < '3.15' and sys_platform == 'linux'
|
|
47
|
+
# via cuda-bindings
|
|
48
|
+
cuda-toolkit==13.2.2 ; sys_platform == 'linux'
|
|
49
|
+
# via torch
|
|
50
|
+
docstring-parser==0.18.0
|
|
51
|
+
# via anthropic
|
|
52
|
+
faiss-cpu==1.15.1
|
|
53
|
+
# via foxclaw (pyproject.toml)
|
|
54
|
+
fastapi==0.162.2
|
|
55
|
+
# via foxclaw (pyproject.toml)
|
|
56
|
+
filelock==4.2.9
|
|
57
|
+
# via
|
|
58
|
+
# huggingface-hub
|
|
59
|
+
# torch
|
|
60
|
+
fsspec==2026.9.0
|
|
61
|
+
# via
|
|
62
|
+
# huggingface-hub
|
|
63
|
+
# torch
|
|
64
|
+
h11==0.16.0
|
|
65
|
+
# via
|
|
66
|
+
# httpcore
|
|
67
|
+
# httpcore2
|
|
68
|
+
# uvicorn
|
|
69
|
+
hf-xet==1.8.0 ; platform_machine == 'AMD64' or platform_machine == 'ARM64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
|
|
70
|
+
# via huggingface-hub
|
|
71
|
+
httpcore==1.0.9
|
|
72
|
+
# via httpx
|
|
73
|
+
httpcore2==2.16.0 ; sys_platform != 'emscripten'
|
|
74
|
+
# via httpx2
|
|
75
|
+
httpx==0.27.2
|
|
76
|
+
# via
|
|
77
|
+
# foxclaw (pyproject.toml)
|
|
78
|
+
# mcp
|
|
79
|
+
httpx-sse==0.4.3
|
|
80
|
+
# via mcp
|
|
81
|
+
httpx2==2.16.0
|
|
82
|
+
# via
|
|
83
|
+
# anthropic
|
|
84
|
+
# huggingface-hub
|
|
85
|
+
# openai
|
|
86
|
+
httpx2-jsfetch==1.0 ; sys_platform == 'emscripten'
|
|
87
|
+
# via httpx2
|
|
88
|
+
huggingface-hub==2.4.0
|
|
89
|
+
# via
|
|
90
|
+
# sentence-transformers
|
|
91
|
+
# tokenizers
|
|
92
|
+
# transformers
|
|
93
|
+
idna==3.20
|
|
94
|
+
# via
|
|
95
|
+
# anyio
|
|
96
|
+
# httpx
|
|
97
|
+
# httpx2
|
|
98
|
+
jinja2==3.1.6
|
|
99
|
+
# via torch
|
|
100
|
+
jiter==0.19.0
|
|
101
|
+
# via
|
|
102
|
+
# anthropic
|
|
103
|
+
# openai
|
|
104
|
+
joblib==1.6.0
|
|
105
|
+
# via scikit-learn
|
|
106
|
+
jsonschema==4.26.0
|
|
107
|
+
# via mcp
|
|
108
|
+
jsonschema-specifications==2025.9.1
|
|
109
|
+
# via jsonschema
|
|
110
|
+
markdown-it-py==4.2.0
|
|
111
|
+
# via rich
|
|
112
|
+
markupsafe==3.0.4
|
|
113
|
+
# via jinja2
|
|
114
|
+
mcp==1.30.0
|
|
115
|
+
# via foxclaw (pyproject.toml)
|
|
116
|
+
mdurl==0.1.2
|
|
117
|
+
# via markdown-it-py
|
|
118
|
+
mpmath==1.3.0
|
|
119
|
+
# via sympy
|
|
120
|
+
narwhals==2.28.0
|
|
121
|
+
# via scikit-learn
|
|
122
|
+
networkx==3.7
|
|
123
|
+
# via torch
|
|
124
|
+
numpy==2.5.4
|
|
125
|
+
# via
|
|
126
|
+
# foxclaw (pyproject.toml)
|
|
127
|
+
# faiss-cpu
|
|
128
|
+
# scikit-learn
|
|
129
|
+
# scipy
|
|
130
|
+
# sentence-transformers
|
|
131
|
+
# transformers
|
|
132
|
+
nvidia-cublas==13.4.1.3 ; sys_platform == 'linux'
|
|
133
|
+
# via
|
|
134
|
+
# cuda-toolkit
|
|
135
|
+
# nvidia-cudnn-cu13
|
|
136
|
+
# nvidia-cusolver
|
|
137
|
+
nvidia-cuda-cccl==13.3.5.0.6 ; sys_platform == 'linux'
|
|
138
|
+
# via nvidia-nvshmem-cu13
|
|
139
|
+
nvidia-cuda-cupti==13.2.86 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
|
|
140
|
+
# via cuda-toolkit
|
|
141
|
+
nvidia-cuda-nvrtc==13.2.86 ; sys_platform == 'linux'
|
|
142
|
+
# via
|
|
143
|
+
# cuda-toolkit
|
|
144
|
+
# nvidia-cublas
|
|
145
|
+
nvidia-cuda-runtime==13.2.86 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
|
|
146
|
+
# via cuda-toolkit
|
|
147
|
+
nvidia-cudnn-cu13==9.26.0.51 ; sys_platform == 'linux'
|
|
148
|
+
# via torch
|
|
149
|
+
nvidia-cufft==12.2.0.57 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
|
|
150
|
+
# via cuda-toolkit
|
|
151
|
+
nvidia-cufile==1.17.1.22 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
|
|
152
|
+
# via cuda-toolkit
|
|
153
|
+
nvidia-cusolver==12.2.0.11 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
|
|
154
|
+
# via cuda-toolkit
|
|
155
|
+
nvidia-cusparse==12.7.10.12 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
|
|
156
|
+
# via
|
|
157
|
+
# cuda-toolkit
|
|
158
|
+
# nvidia-cusolver
|
|
159
|
+
nvidia-cusparselt-cu13==0.8.1 ; sys_platform == 'linux'
|
|
160
|
+
# via torch
|
|
161
|
+
nvidia-nccl-cu13==2.30.7 ; sys_platform == 'linux'
|
|
162
|
+
# via torch
|
|
163
|
+
nvidia-nvjitlink==13.5.37 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
|
|
164
|
+
# via
|
|
165
|
+
# cuda-toolkit
|
|
166
|
+
# nvidia-cufft
|
|
167
|
+
# nvidia-cusolver
|
|
168
|
+
# nvidia-cusparse
|
|
169
|
+
nvidia-nvshmem-cu13==3.7.2 ; sys_platform == 'linux'
|
|
170
|
+
# via torch
|
|
171
|
+
nvidia-nvtx==13.2.86 ; (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
|
|
172
|
+
# via cuda-toolkit
|
|
173
|
+
openai==3.46.0
|
|
174
|
+
# via foxclaw (pyproject.toml)
|
|
175
|
+
opentelemetry-api==1.45.2
|
|
176
|
+
# via
|
|
177
|
+
# anthropic
|
|
178
|
+
# fastapi
|
|
179
|
+
packaging==26.3
|
|
180
|
+
# via
|
|
181
|
+
# faiss-cpu
|
|
182
|
+
# huggingface-hub
|
|
183
|
+
# transformers
|
|
184
|
+
pycparser==3.12 ; implementation_name != 'PyPy' and platform_python_implementation != 'PyPy'
|
|
185
|
+
# via cffi
|
|
186
|
+
pydantic==2.14.3
|
|
187
|
+
# via
|
|
188
|
+
# foxclaw (pyproject.toml)
|
|
189
|
+
# anthropic
|
|
190
|
+
# fastapi
|
|
191
|
+
# mcp
|
|
192
|
+
# openai
|
|
193
|
+
# pydantic-settings
|
|
194
|
+
pydantic-core==2.50.4
|
|
195
|
+
# via pydantic
|
|
196
|
+
pydantic-settings==2.16.2
|
|
197
|
+
# via mcp
|
|
198
|
+
pygments==2.21.0
|
|
199
|
+
# via rich
|
|
200
|
+
pyjwt==2.15.1
|
|
201
|
+
# via mcp
|
|
202
|
+
python-dotenv==1.2.4
|
|
203
|
+
# via
|
|
204
|
+
# foxclaw (pyproject.toml)
|
|
205
|
+
# pydantic-settings
|
|
206
|
+
python-multipart==0.0.33
|
|
207
|
+
# via mcp
|
|
208
|
+
pywin32==312 ; sys_platform == 'win32'
|
|
209
|
+
# via mcp
|
|
210
|
+
pyyaml==6.0.3
|
|
211
|
+
# via
|
|
212
|
+
# foxclaw (pyproject.toml)
|
|
213
|
+
# huggingface-hub
|
|
214
|
+
# transformers
|
|
215
|
+
referencing==0.37.0
|
|
216
|
+
# via
|
|
217
|
+
# jsonschema
|
|
218
|
+
# jsonschema-specifications
|
|
219
|
+
regex==2026.11.9
|
|
220
|
+
# via transformers
|
|
221
|
+
rich==15.0.0
|
|
222
|
+
# via
|
|
223
|
+
# foxclaw (pyproject.toml)
|
|
224
|
+
# typer
|
|
225
|
+
rpds-py==2026.9.1
|
|
226
|
+
# via
|
|
227
|
+
# jsonschema
|
|
228
|
+
# referencing
|
|
229
|
+
safetensors==0.8.0
|
|
230
|
+
# via transformers
|
|
231
|
+
scikit-learn==1.9.1
|
|
232
|
+
# via
|
|
233
|
+
# foxclaw (pyproject.toml)
|
|
234
|
+
# sentence-transformers
|
|
235
|
+
scipy==1.18.1
|
|
236
|
+
# via
|
|
237
|
+
# scikit-learn
|
|
238
|
+
# sentence-transformers
|
|
239
|
+
sentence-transformers==6.2.0
|
|
240
|
+
# via foxclaw (pyproject.toml)
|
|
241
|
+
setuptools==84.2.1
|
|
242
|
+
# via torch
|
|
243
|
+
shellingham==1.5.4
|
|
244
|
+
# via typer
|
|
245
|
+
sniffio==1.3.1
|
|
246
|
+
# via
|
|
247
|
+
# anthropic
|
|
248
|
+
# httpx
|
|
249
|
+
# openai
|
|
250
|
+
sse-starlette==3.7.0
|
|
251
|
+
# via mcp
|
|
252
|
+
starlette==1.10.0
|
|
253
|
+
# via
|
|
254
|
+
# fastapi
|
|
255
|
+
# mcp
|
|
256
|
+
# sse-starlette
|
|
257
|
+
sympy==1.14.0
|
|
258
|
+
# via torch
|
|
259
|
+
threadpoolctl==3.8.0
|
|
260
|
+
# via scikit-learn
|
|
261
|
+
tokenizers==0.23.3
|
|
262
|
+
# via
|
|
263
|
+
# sentence-transformers
|
|
264
|
+
# transformers
|
|
265
|
+
torch==2.15.0
|
|
266
|
+
# via sentence-transformers
|
|
267
|
+
tqdm==4.70.1
|
|
268
|
+
# via
|
|
269
|
+
# huggingface-hub
|
|
270
|
+
# sentence-transformers
|
|
271
|
+
# transformers
|
|
272
|
+
transformers==5.22.2
|
|
273
|
+
# via sentence-transformers
|
|
274
|
+
triton==3.9.0 ; python_full_version < '3.16' and sys_platform == 'linux'
|
|
275
|
+
# via torch
|
|
276
|
+
truststore==0.10.5 ; sys_platform != 'emscripten'
|
|
277
|
+
# via
|
|
278
|
+
# httpcore2
|
|
279
|
+
# httpx2
|
|
280
|
+
typer==0.28.0
|
|
281
|
+
# via transformers
|
|
282
|
+
typing-extensions==4.16.0
|
|
283
|
+
# via
|
|
284
|
+
# anthropic
|
|
285
|
+
# anyio
|
|
286
|
+
# fastapi
|
|
287
|
+
# httpx2
|
|
288
|
+
# huggingface-hub
|
|
289
|
+
# mcp
|
|
290
|
+
# openai
|
|
291
|
+
# opentelemetry-api
|
|
292
|
+
# pydantic
|
|
293
|
+
# pydantic-core
|
|
294
|
+
# pydantic-settings
|
|
295
|
+
# referencing
|
|
296
|
+
# sentence-transformers
|
|
297
|
+
# starlette
|
|
298
|
+
# torch
|
|
299
|
+
# typing-inspection
|
|
300
|
+
typing-inspection==0.4.5
|
|
301
|
+
# via
|
|
302
|
+
# fastapi
|
|
303
|
+
# mcp
|
|
304
|
+
# pydantic
|
|
305
|
+
# pydantic-settings
|
|
306
|
+
uvicorn==0.54.0
|
|
307
|
+
# via
|
|
308
|
+
# foxclaw (pyproject.toml)
|
|
309
|
+
# mcp
|
|
310
|
+
websockets==17.4
|
|
311
|
+
# via foxclaw (pyproject.toml)
|
package/python/tests/conftest.py
CHANGED
|
@@ -16,26 +16,10 @@ _REPO_ROOT = Path(__file__).parent.parent
|
|
|
16
16
|
if str(_REPO_ROOT) not in sys.path:
|
|
17
17
|
sys.path.insert(0, str(_REPO_ROOT))
|
|
18
18
|
|
|
19
|
-
# ── HKC vendor 隔离 ────────────────────────────────────────────────────────────
|
|
20
|
-
# IDE/Cursor 等 shim 常把 `C:\GitHub\foxclaw-hkc\src` 注入到 sys.path 第一位,
|
|
21
|
-
# 而那是上游低质量代码、跟本项目 vendor/hkc/ 是不同等级。**测试必须打 vendor 真代码**,
|
|
22
|
-
# 否则会出现 tests/test_vendor_path_isolation.py 里那类「绿了但打错对象」的事故。
|
|
23
|
-
# 把 vendor/hkc 强制插到 sys.path[0](即使 shim 在前也覆盖之),后续 `import hkc_*`
|
|
24
|
-
# 全部解析到本仓库 vendor 副本。foxclaw.knowledge 自身也调 _ensure_hkc_importable()
|
|
25
|
-
# 做同样事,但那只在 import foxclaw.knowledge 之后才生效;本测试文件顶层直接
|
|
26
|
-
# import hkc_search 早于它,故在 conftest 阶段就注入更稳。
|
|
27
19
|
_VENDOR_HKC = _REPO_ROOT / "vendor" / "hkc"
|
|
28
20
|
if _VENDOR_HKC.exists() and str(_VENDOR_HKC) not in sys.path:
|
|
29
21
|
sys.path.insert(0, str(_VENDOR_HKC))
|
|
30
22
|
|
|
31
|
-
# ── 规避 pytest 在 Windows + Python 3.14 下的 junction 清理 bug ────────────────
|
|
32
|
-
# pytest 用 Path.symlink_to() 创建 `pytest-current` / `test_*current` 目录 junction
|
|
33
|
-
# 作为「指向最新临时目录」的便利链接。Windows 会把这类 junction 标记为
|
|
34
|
-
# 「不受信任的装入点(untrusted mount point)」,Python 3.14 的 ntpath.realpath 在
|
|
35
|
-
# pytest_sessionfinish 的 cleanup_dead_symlinks 里对它调用 Path.resolve() 时抛
|
|
36
|
-
# WinError 448,并令 pytest 退出码变 1(测试本身全通过)。该 junction 仅作调试便利,
|
|
37
|
-
# 不影响任何测试功能,故在 Windows 上禁用其创建(必须在 basetemp 建立前生效,
|
|
38
|
-
# 而 conftest 的模块级代码早于 basetemp 创建执行,时序安全)。
|
|
39
23
|
if sys.platform == "win32":
|
|
40
24
|
import _pytest.pathlib as _ppl
|
|
41
25
|
|
|
@@ -44,10 +28,7 @@ if sys.platform == "win32":
|
|
|
44
28
|
|
|
45
29
|
_ppl._force_symlink = _skip_force_symlink
|
|
46
30
|
|
|
47
|
-
# ── 环境隔离(与 run_all.py 的 env 注入保持一致,强制覆盖继承环境)──────────────
|
|
48
|
-
# FOXCLAW_SKIP_DOTENV=1:让 api.py 完全不读项目根 .env,防止真实 Key 灌回 / 写真实数据目录。
|
|
49
31
|
os.environ["FOXCLAW_SKIP_DOTENV"] = "1"
|
|
50
|
-
# 锁 shadow 轮数、stub 嵌入、关 MCP、清 provider/model:回归保持离线/免费/确定性。
|
|
51
32
|
os.environ["FOXCLAW_SHADOW_ROUNDS"] = "50"
|
|
52
33
|
os.environ["HF_HUB_OFFLINE"] = "1"
|
|
53
34
|
os.environ["TRANSFORMERS_OFFLINE"] = "1"
|
|
@@ -55,13 +36,10 @@ os.environ["HKC_EMBEDDING"] = "stub"
|
|
|
55
36
|
os.environ["FOXCLAW_MCP_SERVER"] = "0"
|
|
56
37
|
os.environ["FOXCLAW_PROVIDER"] = ""
|
|
57
38
|
os.environ["FOXCLAW_MODEL"] = ""
|
|
58
|
-
# 清空外部 API key(第二道防线):鉴权/网关测试要自行控制 FOXCLAW_API_KEY。
|
|
59
39
|
for _k in ("DEEPSEEK_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY",
|
|
60
40
|
"GOOGLE_API_KEY", "DASHSCOPE_API_KEY", "FOXCLAW_API_KEY"):
|
|
61
41
|
os.environ[_k] = ""
|
|
62
42
|
|
|
63
|
-
# 兜底:为未自设 FOXCLAW_DATA_DIR 的测试提供一个临时目录,避免 KeyError。
|
|
64
|
-
# (各测试文件顶层通常会自行 mkdtemp 覆盖此值,此处仅作安全网。)
|
|
65
43
|
os.environ.setdefault("FOXCLAW_DATA_DIR", tempfile.mkdtemp(prefix="foxclaw_test_"))
|
|
66
44
|
|
|
67
45
|
|
package/python/tests/run_all.py
CHANGED
|
@@ -11,11 +11,6 @@ import tempfile
|
|
|
11
11
|
import time
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
|
|
14
|
-
# Windows GBK 控制台无法编码 ✓/✗(✓/✗)等字符 → 运行器自己把 stdout/stderr 切到
|
|
15
|
-
# utf-8,不依赖调用者预先 set PYTHONUTF8。否则打印结果时 UnicodeEncodeError 直接崩掉汇总。
|
|
16
|
-
# line_buffering=True:本文件由 run_all 汇总输出,单个测试跑满 300s 时整轮可达十余分钟;
|
|
17
|
-
# 若不开行缓冲,`python tests/run_all.py > log.txt` 会因块缓冲而**全程看不到进度**,
|
|
18
|
-
# 只能等结束。开启后每条结果即时落盘,可 tail -f 观察。
|
|
19
14
|
for _s in (sys.stdout, sys.stderr):
|
|
20
15
|
try:
|
|
21
16
|
_s.reconfigure(encoding="utf-8", line_buffering=True)
|
|
@@ -32,11 +27,10 @@ TESTS = [
|
|
|
32
27
|
("test_itinerary.py", "B · 行程内核"),
|
|
33
28
|
("test_orchestration.py","主管编排 + 跨 Agent"),
|
|
34
29
|
("test_skills.py", "助手 Skill 接入层"),
|
|
30
|
+
("test_skills_fetch.py", "技能安装(ClawHub/GitHub/URL/本地包)"),
|
|
35
31
|
("test_kernel.py", "内核新模块回归"),
|
|
36
32
|
("test_governance.py", "运行时治理(幂等/恢复/队列/压缩/循环/钩子)"),
|
|
37
|
-
# —— M5 新增:压缩器工具消息配对(防孤立 tool_call 致 provider 400)——
|
|
38
33
|
("test_compaction_toolpair.py", "M5·压缩器工具消息配对(原子组切分+畸形输入安全降级)"),
|
|
39
|
-
# —— M4 新增:工具入参校验 + permission Stage 1 真正生效 ——
|
|
40
34
|
("test_tool_params.py", "M4·工具入参校验(执行侧 schema/Stage1/解析失败可见)"),
|
|
41
35
|
("test_shared_write.py", "P0-3 · 共享层写入策略(audit/warn/enforce)"),
|
|
42
36
|
("test_audit_sink.py", "P0-3 · 审计落盘 sink(环形缓冲外的持久样本)"),
|
|
@@ -97,29 +91,24 @@ TESTS = [
|
|
|
97
91
|
("test_evidence_semantic.py", "证据融合语义化(否定词边界·幻影矛盾·语义支持边·降级)"),
|
|
98
92
|
("test_domain_evals.py", "领域推理评测(漏报/误报率+误报归因到规则+规则实例隔离)"),
|
|
99
93
|
("test_negotiation.py", "智能体层·跨域协商闭环(被拒→让步→再裁决·有界·拒绝不降级)"),
|
|
100
|
-
# —— 以下 4 项此前遗漏于本运行器(P4-4 修复)——
|
|
101
94
|
("test_tool_use.py", "P2·function-calling 工具化(多轮工具循环/注册表/降级)"),
|
|
102
95
|
("test_injection_guard.py", "提示词注入纵深防御(检出/wrap_untrusted/内核前缀/隔离)"),
|
|
96
|
+
("test_agent_rules.py", "Agent 规则文件启动注入(按 AGENT_ID 读盘/顺序/回退开关/包内路径)"),
|
|
103
97
|
("test_sessions.py", "会话存储(增删改查/标题提炼/路径穿越/并发追加)"),
|
|
104
98
|
("test_stats_and_events.py","记忆统计 + 活动事件(hmr.stats 计数修复/chat.completed)"),
|
|
105
|
-
# —— 以下 4 项为近期新功能测试,此前遗漏于本运行器(接线)——
|
|
106
99
|
("test_llm_planner.py", "P0-1·LLM 驱动规划器(llm_plan/replan·opt-in+fail-safe+sv_replan)"),
|
|
107
100
|
("test_anthropic_tools.py", "P0-2·Anthropic tool_use 原生接入(格式转换/解析/回灌/降级)"),
|
|
108
101
|
("test_taint.py", "数据污点追踪+动态审批门槛(污点分级/传播/TAINT_CONFIRM)"),
|
|
109
102
|
("test_mcp_guardian_discovery.py", "MCP 发现进守门人(凭证不出主进程·代发现·序列化)"),
|
|
110
103
|
("test_verify_evidence.py", "三个薄点·失败策略表/执行后核验/执行证据(重试只限只读)"),
|
|
111
104
|
("test_evidence_sse.py", "执行凭据 SSE 命名事件(与正文分离·纯对话不发)"),
|
|
105
|
+
("test_profile.py", "称呼(user profile)存取:写入/替换/清空/不误删偏好"),
|
|
106
|
+
("test_update_check.py", "新版本检查:默认关/版本比较/24h 缓存/失败静默"),
|
|
112
107
|
]
|
|
113
108
|
|
|
114
|
-
# S2 迁移完成:全部测试均已迁移为 pytest(见 pyproject [tool.pytest.ini_options] 白名单)。
|
|
115
|
-
# 故下面所有文件统一用 `python -m pytest <file> -q` 跑,且**每个文件独立子进程**:
|
|
116
|
-
# 网关/内置MCP/流式限流等测试依赖模块级单例,同一进程内会被首个 import 定死、相互污染。
|
|
117
109
|
|
|
118
110
|
def main():
|
|
119
111
|
here = Path(__file__).parent
|
|
120
|
-
# ── 命令行:支持 --list / --only <substr>(M7)──────────────────────
|
|
121
|
-
# 为什么需要:全量回归 6-7 分钟,改一行代码后只想验 1-2 个文件时成本过高。
|
|
122
|
-
# 此前只能整跑,拖慢了「改完立刻验」的内循环(这也是很多缺陷被放过的原因之一)。
|
|
123
112
|
_argv = sys.argv[1:]
|
|
124
113
|
global TESTS
|
|
125
114
|
if "--list" in _argv:
|
|
@@ -137,41 +126,14 @@ def main():
|
|
|
137
126
|
_before = len(TESTS)
|
|
138
127
|
TESTS = [(f, d) for f, d in TESTS if _only in f or _only in d]
|
|
139
128
|
print(f"[filter] '{_only}' 匹配 {len(TESTS)}/{_before} 项\n")
|
|
140
|
-
# HF_HUB_OFFLINE:装了 sentence-transformers 时,每个 Foxclaw() 会载入 all-MiniLM
|
|
141
|
-
# 模型 6 次(5 Harness + 1 HMR embedding),且每次都向 HF Hub 发未认证网络请求——
|
|
142
|
-
# 即便模型已缓存。实测让单次 init 从 ~44s 降到 ~7s,并去除网络抖动(否则被 HF 限流时
|
|
143
|
-
# 某个子测试会顶穿 300s 超时)。模型已本地缓存,离线读取即可;未缓存时 Harness 会自动
|
|
144
|
-
# 降级 n-gram 哈希嵌入,不影响测试判定。PYTHONUTF8:防 Windows GBK 控制台的 ✓/✗ 编码错。
|
|
145
|
-
# ── 测试环境隔离(必须放在最前,否则回归不可复现)────────────────────────
|
|
146
|
-
# FOXCLAW_SKIP_DOTENV=1:让 api.py 完全不读项目根目录的 .env。
|
|
147
|
-
# 为什么不能只靠下面那些空字符串:.env 的加载是 load_dotenv(override=False),
|
|
148
|
-
# 它只保护「当前进程里已存在的键」。但测试常常要 pop 掉某键来验证「未设时的行为」
|
|
149
|
-
# (如 test_gateway.py / test_api_auth.py pop FOXCLAW_API_KEY),pop 完再 import api,
|
|
150
|
-
# .env 就会把键灌回来 —— 空字符串挡不住这种路径。
|
|
151
|
-
# 实测证据:对照树(0 改动)+ 含 FOXCLAW_API_KEY 的 .env → test_gateway 报
|
|
152
|
-
# KeyError: 'enabled';同树删掉 .env → 通过。故必须在源头关掉 .env。
|
|
153
|
-
# 另:开发者 .env 里有真实 Key 与 FOXCLAW_DATA_DIR=./foxclaw_data,不隔离会让测试
|
|
154
|
-
# 真的打外部 API(花钱)并写进真实数据目录。
|
|
155
|
-
# 下面显式置空的 key 作为**第二道防线**,覆盖那些会 import 本运行器 env dict
|
|
156
|
-
# 或直接读 os.environ 的路径(且便于单独运行单个测试文件时也保持确定性)。
|
|
157
129
|
env = dict(os.environ, FOXCLAW_SHADOW_ROUNDS="50",
|
|
158
130
|
HF_HUB_OFFLINE="1", TRANSFORMERS_OFFLINE="1",
|
|
159
131
|
PYTHONUTF8="1", PYTHONIOENCODING="utf-8",
|
|
160
132
|
FOXCLAW_SKIP_DOTENV="1",
|
|
161
|
-
# 强制 stub:回归保持离线/免费/确定性。鉴权与网关必须为「未设」态——
|
|
162
|
-
# test_api_auth / test_gateway 要自行控制 FOXCLAW_API_KEY,这里先兜底清空。
|
|
163
133
|
DEEPSEEK_API_KEY="", ANTHROPIC_API_KEY="", OPENAI_API_KEY="",
|
|
164
134
|
GOOGLE_API_KEY="", DASHSCOPE_API_KEY="", FOXCLAW_API_KEY="",
|
|
165
|
-
# .env 里 FOXCLAW_MCP_SERVER=1 会让 api.py 在 import 时构建 MCP 服务器,
|
|
166
|
-
# 而 test_tracing.py 有两处 `with TestClient(app)`(82/189 行),第二次进
|
|
167
|
-
# lifespan 会撞 StreamableHTTPSessionManager「.run() can only be called
|
|
168
|
-
# once per instance」。回归默认关;test_mcp_server.py 自己会置 1。
|
|
169
135
|
FOXCLAW_MCP_SERVER="0",
|
|
170
|
-
# 锁 stub 模型路由:.env 里 FOXCLAW_PROVIDER=openai/FOXCLAW_MODEL=abab6.5s-chat
|
|
171
|
-
# 是开发者的真实配置,回归不继承(否则路由判定随机器变化)。
|
|
172
136
|
FOXCLAW_PROVIDER="", FOXCLAW_MODEL="",
|
|
173
|
-
# 产品默认 HKC_EMBEDDING=auto(真语义),但回归锁 stub 保确定+快;
|
|
174
|
-
# 真语义单独由 test_semantic.py 显式验证。
|
|
175
137
|
HKC_EMBEDDING="stub")
|
|
176
138
|
print("=" * 64)
|
|
177
139
|
print("Foxclaw · 全量回归测试")
|
|
@@ -194,34 +156,16 @@ def main():
|
|
|
194
156
|
if not path.exists():
|
|
195
157
|
results.append((desc, "缺失", 0)); continue
|
|
196
158
|
t0 = time.time()
|
|
197
|
-
# 每个文件用**独立的 basetemp**,不共用 %TEMP%\pytest-of-<user> 根目录。
|
|
198
|
-
# 为什么:Windows 上该根目录一旦留下损坏的 reparse point(实测 pytest-current
|
|
199
|
-
# unlink 报 WinError 5),pytest 会在 sessionfinish 的 cleanup_numbered_dir 阶段
|
|
200
|
-
# 抛 PermissionError —— 断言全过也返回非 0,7 个文件同时假红,真回归被淹没。
|
|
201
|
-
# 显式 basetemp 后 pytest 不再遍历/清理共用根目录;目录必须预先存在(pytest 不会
|
|
202
|
-
# 为 --basetemp 建父目录,缺了直接 FileNotFoundError),故用 mkdtemp 建好再传。
|
|
203
159
|
_bt = Path(tempfile.mkdtemp(prefix="foxclaw-pt-"))
|
|
204
160
|
try:
|
|
205
|
-
# 统一走 pytest(每文件独立子进程,隔离模块级单例)。
|
|
206
161
|
_cmd = [sys.executable, "-m", "pytest", str(path), "-q",
|
|
207
162
|
f"--basetemp={_bt}"]
|
|
208
|
-
# 显式 utf-8 解码子进程输出:子进程已被 PYTHONUTF8=1 强制输出 utf-8,
|
|
209
|
-
# 父进程若用 Windows 默认 GBK 解码会 UnicodeDecodeError(模型加载进度条等
|
|
210
|
-
# 含非 GBK 字节)→ r.stdout 变 None → 后续拼接 TypeError。errors=replace 兜底。
|
|
211
163
|
r = subprocess.run(_cmd,
|
|
212
164
|
capture_output=True, text=True, timeout=300, env=env,
|
|
213
165
|
encoding="utf-8", errors="replace")
|
|
214
166
|
ok = r.returncode == 0
|
|
215
|
-
# 简单判定:退出码 0 且输出里没有 Traceback
|
|
216
167
|
if "Traceback" in (r.stdout + r.stderr):
|
|
217
168
|
ok = False
|
|
218
|
-
# 原生库偶发崩溃的精准重试:Windows 访问冲突 0xC0000005
|
|
219
|
-
# 是 torch/FAISS/ST 在模型重加载或解释器 teardown 阶段的进程级崩溃——
|
|
220
|
-
# 无 Python Traceback、与断言失败(exit=1)互不混淆,故只对它在同一干净
|
|
221
|
-
# 环境下重试一次(批次4/7 均实锤:基线对照同样崩溃,与业务改动无关;
|
|
222
|
-
# 手动小范围跑全绿,全量回归高内存压力下概率显著升高)。
|
|
223
|
-
# 注意:subprocess 在 Windows 返回无符号 DWORD(0xC0000005=3221225477),
|
|
224
|
-
# PowerShell $LASTEXITCODE 则按有符号显示(-1073741819),两种都表示同一崩溃。
|
|
225
169
|
_ACCESS_VIOLATION = (3221225477, -1073741819)
|
|
226
170
|
if not ok and r.returncode in _ACCESS_VIOLATION and \
|
|
227
171
|
"Traceback" not in (r.stdout + r.stderr):
|
|
@@ -233,20 +177,14 @@ def main():
|
|
|
233
177
|
print(f" ↻ {desc} 首次 0xC0000005 原生崩溃,重试通过(已知环境性偶发)")
|
|
234
178
|
results.append((desc, "通过" if ok else "失败", time.time() - t0))
|
|
235
179
|
if not ok:
|
|
236
|
-
# 打印 15 行而非 3 行:pytest 的 collection error(如缺依赖)把原因
|
|
237
|
-
# 放在 traceback 中段,只截最后 3 行会只剩「ERROR xxx.py」+「Interrupted」,
|
|
238
|
-
# 在 CI 里完全无法定位(2026-10-17 实际踩过:CI 红但日志看不出缺 faiss)。
|
|
239
180
|
tail = (r.stdout + r.stderr).strip().splitlines()[-15:]
|
|
240
181
|
print(f" ✗ {desc} 失败:")
|
|
241
182
|
for line in tail: print(f" {line}")
|
|
242
|
-
# 失败时落盘完整输出,便于复现/定位偶发失败(尤其 teardown 期崩溃)。
|
|
243
183
|
(here / f"_fail_{fn}.txt").write_text(
|
|
244
184
|
r.stdout + r.stderr, encoding="utf-8")
|
|
245
185
|
except subprocess.TimeoutExpired:
|
|
246
186
|
results.append((desc, "超时", 300))
|
|
247
187
|
finally:
|
|
248
|
-
# basetemp 是本文件专用的一次性目录:正常结束由 pytest 自己清,
|
|
249
|
-
# 子进程崩溃/超时会残留,这里统一回收。ignore_errors 兜 Windows 文件占用。
|
|
250
188
|
shutil.rmtree(_bt, ignore_errors=True)
|
|
251
189
|
print(f" {'✓' if results[-1][1]=='通过' else '✗'} {desc:<28} [{results[-1][1]}] {results[-1][2]:.0f}s")
|
|
252
190
|
|