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
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* 对话与输入区状态:模式 / 附件 / 图片 / 摄入任务 / 消息流 / SSE */
|
|
2
1
|
import { reactive } from 'vue'
|
|
3
2
|
import { API, delJSON, getJSON, getRaw, postForm, postFormRaw, postJSON } from '../api.js'
|
|
4
3
|
import { loadSessions, state as app } from './app.js'
|
|
@@ -14,12 +13,9 @@ export const chat = reactive({
|
|
|
14
13
|
ingest: null, // {name,pct,status,ku,msg}
|
|
15
14
|
toast: '',
|
|
16
15
|
|
|
17
|
-
/* 对话 */
|
|
18
16
|
messages: [], // [{role,content,thinking,evidence,error,ts,streaming,stage,plan}]
|
|
19
17
|
sessionId: null,
|
|
20
18
|
streamState: 'idle', // idle | streaming | done | error
|
|
21
|
-
/* 错误落在具体那条消息的 m.error 上(界面上能看到 + 能点重试),
|
|
22
|
-
这里不再留一个没人读的 lastError */
|
|
23
19
|
})
|
|
24
20
|
|
|
25
21
|
let toastTimer = 0
|
|
@@ -35,7 +31,6 @@ export function setMode(m) {
|
|
|
35
31
|
localStorage.setItem(MODE_KEY, m)
|
|
36
32
|
}
|
|
37
33
|
|
|
38
|
-
/* ── 附件:POST /api/upload → {id,name,size,mime,url,text} ── */
|
|
39
34
|
export async function attachFile(file) {
|
|
40
35
|
if (!file) return
|
|
41
36
|
if (file.size > MAX_MB * 1048576) return say(`${file.name} 超过 ${MAX_MB}MB`)
|
|
@@ -50,7 +45,6 @@ export async function attachFile(file) {
|
|
|
50
45
|
}
|
|
51
46
|
}
|
|
52
47
|
|
|
53
|
-
/* ── 图片:本地转 dataURL,不落盘 ── */
|
|
54
48
|
export function attachImage(file) {
|
|
55
49
|
if (!file) return
|
|
56
50
|
if (!file.type.startsWith('image/')) return say('不是图片文件')
|
|
@@ -67,8 +61,6 @@ export function dropImage(i) {
|
|
|
67
61
|
chat.images.splice(i, 1)
|
|
68
62
|
}
|
|
69
63
|
|
|
70
|
-
/* ── 摄入知识库:POST /knowledge/ingest/file/async → 轮询 /knowledge/ingest/jobs/{id}
|
|
71
|
-
注意路径无 /api 前缀:vendor/hkc 的 knowledge router 是根路径挂载的。 ── */
|
|
72
64
|
export async function ingestFile(file, collection = '') {
|
|
73
65
|
if (!file) return
|
|
74
66
|
if (chat.ingest) return say('等当前文件摄入完成再传下一个')
|
|
@@ -90,7 +82,6 @@ export async function ingestFolder(files) {
|
|
|
90
82
|
const list = [...files].filter(Boolean)
|
|
91
83
|
for (const f of list) {
|
|
92
84
|
await ingestFile(f)
|
|
93
|
-
/* ingestFile 内部已串行守卫:等当前 job 结束再投下一个 */
|
|
94
85
|
while (chat.ingest && chat.ingest.status !== 'error') {
|
|
95
86
|
if (chat.ingest.status === 'done') break
|
|
96
87
|
await new Promise((r) => setTimeout(r, 600))
|
|
@@ -123,8 +114,6 @@ async function pollIngest(jobId) {
|
|
|
123
114
|
say('摄入超时,后台可能仍在跑')
|
|
124
115
|
}
|
|
125
116
|
|
|
126
|
-
/* ══════════ 会话 ══════════ */
|
|
127
|
-
|
|
128
117
|
const STAGE_CN = {
|
|
129
118
|
perceive: '感知', recall: '召回', meta_check: '自检', schedule: '排程',
|
|
130
119
|
route: '路由', plan: '规划', dispatch: '分发', act: '执行',
|
|
@@ -150,7 +139,6 @@ function adoptSession(id) {
|
|
|
150
139
|
localStorage.setItem(SID_KEY, id)
|
|
151
140
|
}
|
|
152
141
|
|
|
153
|
-
/* 启动时恢复上次会话(后端 sessions 落盘,thinking/evidence 不落盘) */
|
|
154
142
|
export async function bootChat() {
|
|
155
143
|
const saved = localStorage.getItem(SID_KEY)
|
|
156
144
|
if (saved) await loadSession(saved, { quiet: true })
|
|
@@ -173,14 +161,11 @@ export async function loadSession(id, { quiet = false } = {}) {
|
|
|
173
161
|
}
|
|
174
162
|
}
|
|
175
163
|
|
|
176
|
-
/* 组件间的一次性信号:斜杠命令要调 ToolMenu 里的文件选择,又不能硬耦合。
|
|
177
|
-
(/设置 不再走这里 —— 它现在直接切到设置面板,见 ChatDock 的命令表) */
|
|
178
164
|
export const ui = reactive({ ingestTick: 0 })
|
|
179
165
|
export function requestIngest() {
|
|
180
166
|
ui.ingestTick += 1
|
|
181
167
|
}
|
|
182
168
|
|
|
183
|
-
/* 纯本地消息(/帮助 之类),不经过后端 */
|
|
184
169
|
export function pushLocal(content) {
|
|
185
170
|
chat.messages.push({
|
|
186
171
|
role: 'assistant', content, ts: Date.now(),
|
|
@@ -188,7 +173,6 @@ export function pushLocal(content) {
|
|
|
188
173
|
})
|
|
189
174
|
}
|
|
190
175
|
|
|
191
|
-
/* 认知搜索(HSR):POST /api/search/query,结果作为一张证据卡挂在消息流里 */
|
|
192
176
|
export async function runSearch(rawQuery) {
|
|
193
177
|
const query = String(rawQuery || '').trim()
|
|
194
178
|
if (!query) return say('用法:/搜索 关键词')
|
|
@@ -205,7 +189,6 @@ export async function runSearch(rawQuery) {
|
|
|
205
189
|
const msg = chat.messages[chat.messages.length - 1]
|
|
206
190
|
|
|
207
191
|
try {
|
|
208
|
-
/* internal_only=true:只查 HMR 记忆 + HKC 知识 + Agent 态势,不联网 —— 联网分支实测返回空图 */
|
|
209
192
|
const d = await postJSON('/search/query', { query, agent_id: 'supervisor', internal_only: true })
|
|
210
193
|
const nodes = (d.graph && d.graph.nodes) || []
|
|
211
194
|
msg.search = {
|
|
@@ -242,7 +225,6 @@ export async function newSession() {
|
|
|
242
225
|
}
|
|
243
226
|
}
|
|
244
227
|
|
|
245
|
-
/* 改标题:后端 rename 会把空串兜回「新会话」,这里先挡掉空提交,避免误清标题 */
|
|
246
228
|
export async function renameSession(id, title) {
|
|
247
229
|
const t = String(title || '').trim().slice(0, 60)
|
|
248
230
|
if (!id || !t) return
|
|
@@ -255,8 +237,6 @@ export async function renameSession(id, title) {
|
|
|
255
237
|
}
|
|
256
238
|
}
|
|
257
239
|
|
|
258
|
-
/* 删会话。删的是当前会话时落回列表里的下一条;一条不剩就新开一个 ——
|
|
259
|
-
否则界面会停在一个已经不存在的 sessionId 上,下一条消息直接 404。 */
|
|
260
240
|
export async function deleteSession(id) {
|
|
261
241
|
if (!id) return
|
|
262
242
|
try {
|
|
@@ -271,7 +251,6 @@ export async function deleteSession(id) {
|
|
|
271
251
|
else await newSession()
|
|
272
252
|
}
|
|
273
253
|
|
|
274
|
-
/* 重发:把这条回复对应的提问找回来,截断到它之前再投一次(附件/图片一起还原) */
|
|
275
254
|
export async function retry(msg) {
|
|
276
255
|
if (chat.streamState === 'streaming') return say('正在生成,先点停止')
|
|
277
256
|
const i = chat.messages.indexOf(msg)
|
|
@@ -301,28 +280,20 @@ async function ensureSession() {
|
|
|
301
280
|
adoptSession(saved)
|
|
302
281
|
return saved
|
|
303
282
|
} catch {
|
|
304
|
-
/* 后端已无此会话 → 落到下面新建 */
|
|
305
283
|
}
|
|
306
284
|
}
|
|
307
285
|
return newSession()
|
|
308
286
|
}
|
|
309
287
|
|
|
310
|
-
/* ══════════ 发送 / 流式 ══════════ */
|
|
311
|
-
|
|
312
288
|
let ctrl = null
|
|
313
|
-
/* 每次 send 领一个代号。切会话 / 新建会话时把代号推进,在跑的那一路回来发现
|
|
314
|
-
代号变了就不再碰全局状态 —— 否则它会把新会话的 streamState 覆盖掉、还把 ctrl
|
|
315
|
-
清空,导致新流停不下来,两路 token 同时往不同消息里写。 */
|
|
316
289
|
let gen = 0
|
|
317
290
|
|
|
318
|
-
/* 掐断在跑的流:切会话、新建会话、重试前都先调一次 */
|
|
319
291
|
function cutStream() {
|
|
320
292
|
gen += 1
|
|
321
293
|
if (ctrl) {
|
|
322
294
|
try {
|
|
323
295
|
ctrl.abort()
|
|
324
296
|
} catch {
|
|
325
|
-
/* 已经收尾了 */
|
|
326
297
|
}
|
|
327
298
|
ctrl = null
|
|
328
299
|
}
|
|
@@ -351,7 +322,6 @@ export async function send(rawText) {
|
|
|
351
322
|
const attachments = chat.attachments.map((a) => ({
|
|
352
323
|
name: a.name, size: a.size, mime: a.mime, url: a.url, text: a.text || '',
|
|
353
324
|
}))
|
|
354
|
-
/* 后端只用最近 12 条拼上下文,与旧前端保持一致 */
|
|
355
325
|
const history = chat.messages
|
|
356
326
|
.filter((m) => m.content && m.role && !m.error)
|
|
357
327
|
.slice(-12)
|
|
@@ -359,15 +329,12 @@ export async function send(rawText) {
|
|
|
359
329
|
|
|
360
330
|
chat.messages.push({
|
|
361
331
|
role: 'user', content: text, ts: Date.now(), attachments, streaming: false, thinking: '',
|
|
362
|
-
/* 存一份图片快照:重试时 send() 从 chat.images 取图,不带上就丢图了 */
|
|
363
332
|
images: chat.images.map((im) => ({ ...im })),
|
|
364
333
|
})
|
|
365
334
|
chat.messages.push({
|
|
366
335
|
role: 'assistant', content: '', thinking: '', evidence: [], error: '', notice: '',
|
|
367
336
|
ts: Date.now(), streaming: true, stage: '', plan: null,
|
|
368
337
|
})
|
|
369
|
-
/* 必须拿回数组里的响应式代理:直接改 push 进去的原始对象不会触发重渲染,
|
|
370
|
-
表现就是气泡永远停在「···」而内容其实早到了 */
|
|
371
338
|
const reply = chat.messages[chat.messages.length - 1]
|
|
372
339
|
chat.attachments = []
|
|
373
340
|
chat.images = []
|
|
@@ -412,7 +379,6 @@ export async function send(rawText) {
|
|
|
412
379
|
}
|
|
413
380
|
|
|
414
381
|
function applyEvent(msg, name, ev) {
|
|
415
|
-
/* 命名事件与 JSON 键双判据:后端明确要求两者都认 */
|
|
416
382
|
if (name === 'thinking' || ev.thinking) {
|
|
417
383
|
msg.thinking += ev.thinking || ''
|
|
418
384
|
return
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* 模型选择:全部走 /api/llm/*(llm_admin.py),切换后服务端立即生效,无需重启。 */
|
|
2
1
|
import { reactive } from 'vue'
|
|
3
2
|
import { delJSON, getJSON, postJSON, putJSON } from '../api.js'
|
|
4
3
|
|
|
@@ -28,7 +27,6 @@ export async function loadModels(force = false) {
|
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
/* 当前 pill 上显示的名字与色点 */
|
|
32
30
|
export function currentLabel() {
|
|
33
31
|
const c = model.current
|
|
34
32
|
if (!c) return { name: 'Auto', color: '#7e93b8', sub: '跟随 .env 默认' }
|
|
@@ -49,9 +47,6 @@ export async function selectModel({ source, provider = null, name = null }) {
|
|
|
49
47
|
return r
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
/* 设置面板里的模型清单:auto / 预设 / 自定义摊平成同一形状。
|
|
53
|
-
active 的判定必须和上面的 currentLabel 一致 —— 两处各写一套,切换后 pill 和
|
|
54
|
-
列表就会各说各的(这类"同一状态两套判定"是回归温床)。 */
|
|
55
50
|
export function modelOptions() {
|
|
56
51
|
const c = model.current
|
|
57
52
|
const out = [{
|
|
@@ -81,13 +76,10 @@ export async function addCustom(payload) {
|
|
|
81
76
|
await loadModels(true)
|
|
82
77
|
}
|
|
83
78
|
|
|
84
|
-
/* 连通性测试:后端发一个 "hi" 走真实客户端,失败时 **不抛** 而是返回 {ok:false,error}
|
|
85
|
-
—— 那正是要显示给用户看的东西,别当异常吞掉。 */
|
|
86
79
|
export async function testModel(payload) {
|
|
87
80
|
return postJSON('/llm/test', payload)
|
|
88
81
|
}
|
|
89
82
|
|
|
90
|
-
/* 单个自定义模型详情:api_key 永不出网,只回 has_key(编辑表单里留空即保留原值) */
|
|
91
83
|
export async function getCustom(name) {
|
|
92
84
|
return getJSON(`/llm/custom/${encodeURIComponent(name)}`)
|
|
93
85
|
}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/* 左栏菜单 8 项的数据层。
|
|
2
|
-
一项一个 loader,内部每个端点单独 .catch —— 某个子系统挂了只让对应区块空着,
|
|
3
|
-
不让整个面板变「后端未连接」。组件只负责渲染,不各自写 fetch。 */
|
|
4
1
|
import { reactive } from 'vue'
|
|
5
2
|
import { getJSON, getRaw, delJSON, patchJSON, postJSON } from '../api.js'
|
|
6
3
|
import { openDoc } from './app.js'
|
|
@@ -15,15 +12,10 @@ export const panels = reactive({
|
|
|
15
12
|
usage: { state: 'idle', tokens: null, gateway: {}, metrics: null, slow: [] },
|
|
16
13
|
knowledge: {
|
|
17
14
|
state: 'idle', stats: {}, index: {}, sources: [], abilities: [],
|
|
18
|
-
/* 最近录入的知识单元:右栏只读前 10 条,面板看全量 */
|
|
19
15
|
recent: [], recentTotal: 0,
|
|
20
|
-
/* 录入是同步 LLM 抽取,可能几十秒 —— 状态提到 store 里,
|
|
21
|
-
切到别的面板再回来时不会以为「没提交过」 */
|
|
22
16
|
ingest: 'idle', ingestMsg: '', ingestErr: '',
|
|
23
17
|
},
|
|
24
18
|
memory: { state: 'idle', stats: {}, recent: [], prefs: [] },
|
|
25
|
-
/* SM-2 复习:stats 是全局账本,queue 是「今天这一轮要过的卡」。
|
|
26
|
-
session 放 store 是因为复习到一半点开文档再回来,不能让进度归零。 */
|
|
27
19
|
review: {
|
|
28
20
|
state: 'idle',
|
|
29
21
|
stats: { cards: 0, learned: 0, fresh: 0, due: 0, avg_mastery: 0, load7: {}, risk: [] },
|
|
@@ -36,7 +28,6 @@ export const panels = reactive({
|
|
|
36
28
|
})
|
|
37
29
|
|
|
38
30
|
const LOADERS = {
|
|
39
|
-
/* 活动 = 事件总线(系统发生了什么) + 请求链路(哪次调用慢) + 思考链健康度 */
|
|
40
31
|
async activity(p) {
|
|
41
32
|
const [bus, traces, thought] = await Promise.all([
|
|
42
33
|
safe(getJSON('/bus/history?limit=40')),
|
|
@@ -49,7 +40,6 @@ const LOADERS = {
|
|
|
49
40
|
return !!(bus || traces || thought)
|
|
50
41
|
},
|
|
51
42
|
|
|
52
|
-
/* 任务 = 调度器记账 + 进程生命周期(后端把每个任务建模成进程) */
|
|
53
43
|
async tasks(p) {
|
|
54
44
|
const [sched, proc] = await Promise.all([
|
|
55
45
|
safe(getJSON('/scheduler/stats')),
|
|
@@ -61,7 +51,6 @@ const LOADERS = {
|
|
|
61
51
|
return !!(sched || proc)
|
|
62
52
|
},
|
|
63
53
|
|
|
64
|
-
/* 代理 = /api/status(全部 Agent 的 harness + 思考链) + 系统信息 */
|
|
65
54
|
async agents(p) {
|
|
66
55
|
const [all, info] = await Promise.all([
|
|
67
56
|
safe(getJSON('/status')),
|
|
@@ -72,7 +61,6 @@ const LOADERS = {
|
|
|
72
61
|
return !!(all || info)
|
|
73
62
|
},
|
|
74
63
|
|
|
75
|
-
/* 技能 = 内置/HTTP/MCP 技能表 + 指令技能(SKILL.md) + 熔断器 */
|
|
76
64
|
async tools(p) {
|
|
77
65
|
const [sk, md, br] = await Promise.all([
|
|
78
66
|
safe(getJSON('/ahs/skills')),
|
|
@@ -85,7 +73,6 @@ const LOADERS = {
|
|
|
85
73
|
return !!(sk || md || br)
|
|
86
74
|
},
|
|
87
75
|
|
|
88
|
-
/* 使用情况 = token 计量 + 网关配额 + 端点延迟(p95 最慢的几条) */
|
|
89
76
|
async usage(p) {
|
|
90
77
|
const [tk, gw, mt] = await Promise.all([
|
|
91
78
|
safe(getJSON('/tokens')),
|
|
@@ -102,8 +89,6 @@ const LOADERS = {
|
|
|
102
89
|
return !!(tk || gw || mt)
|
|
103
90
|
},
|
|
104
91
|
|
|
105
|
-
/* 知识库 = HKC 根路径 /stats 与 /knowledge/sources,加 Foxclaw 侧能力清单
|
|
106
|
-
与最近录入的 KU(右栏和面板共用这一份) */
|
|
107
92
|
async knowledge(p) {
|
|
108
93
|
const [st, src, ab, rc] = await Promise.all([
|
|
109
94
|
safe(getRaw('/stats')),
|
|
@@ -120,8 +105,6 @@ const LOADERS = {
|
|
|
120
105
|
return !!(st || src || ab || rc)
|
|
121
106
|
},
|
|
122
107
|
|
|
123
|
-
/* 复习 = SM-2 账本 + 今日队列。会话进行中只更新账本,不动队列 ——
|
|
124
|
-
否则右栏刷新一次就把当前卡片换掉了。 */
|
|
125
108
|
async review(p) {
|
|
126
109
|
const [st, q] = await Promise.all([
|
|
127
110
|
safe(getJSON('/review/stats')),
|
|
@@ -137,7 +120,6 @@ const LOADERS = {
|
|
|
137
120
|
return !!(st || q)
|
|
138
121
|
},
|
|
139
122
|
|
|
140
|
-
/* 记忆中心 = HMR 统计 + 最近记忆 + 用户偏好 */
|
|
141
123
|
async memory(p) {
|
|
142
124
|
const [st, rc, pf] = await Promise.all([
|
|
143
125
|
safe(getJSON('/memory/stats')),
|
|
@@ -154,7 +136,6 @@ const LOADERS = {
|
|
|
154
136
|
export async function loadPanel(id, force = false) {
|
|
155
137
|
const p = panels[id]
|
|
156
138
|
if (!p || !LOADERS[id]) return
|
|
157
|
-
/* 已有数据就不重拉:切换菜单来回点不重复打后端;要新数据显式刷新 */
|
|
158
139
|
if (!force && p.state !== 'idle' && p.state !== 'error') return
|
|
159
140
|
p.state = 'loading'
|
|
160
141
|
let ok = false
|
|
@@ -164,18 +145,11 @@ export async function loadPanel(id, force = false) {
|
|
|
164
145
|
|
|
165
146
|
export const refreshPanel = (id) => loadPanel(id, true)
|
|
166
147
|
|
|
167
|
-
/* ── 面板内的写操作(都是真实端点,不是本地假删除) ── */
|
|
168
|
-
|
|
169
|
-
/* 指令技能启停:PATCH /ahs/md-skills/{id} → 全量重拉一次保证和服务端一致 */
|
|
170
148
|
export async function toggleMdSkill(id, enabled) {
|
|
171
149
|
await patchJSON(`/ahs/md-skills/${encodeURIComponent(id)}`, { enabled })
|
|
172
150
|
await refreshPanel('tools')
|
|
173
151
|
}
|
|
174
152
|
|
|
175
|
-
/* 录入一段短知识:POST /knowledge/ingest → KDE 抽取成 KU → KEE 演化。
|
|
176
|
-
同步 LLM 抽取,可能几十秒,所以状态挂在 store 上而不是组件里。
|
|
177
|
-
成功后**静默重拉**:走 refreshPanel 会把 state 置回 loading,整面板闪骨架,
|
|
178
|
-
而这里只想要新数据。 */
|
|
179
153
|
export async function ingestKnowledge({ text, title = '', domain = '' }) {
|
|
180
154
|
const p = panels.knowledge
|
|
181
155
|
const body = (text || '').trim()
|
|
@@ -197,8 +171,6 @@ export async function ingestKnowledge({ text, title = '', domain = '' }) {
|
|
|
197
171
|
const n = d?.ku_count ?? 0
|
|
198
172
|
p.ingestMsg = n
|
|
199
173
|
? `已抽取 ${n} 条知识单元${counts ? ` · ${counts}` : ''}`
|
|
200
|
-
/* 走到这里说明 LLM 调用是成功的(全失败会 502 进 catch),只是这段文字里
|
|
201
|
-
没抽出 Concept/Fact/Claim/Entity。别提示"没配模型"误导用户去改 key。 */
|
|
202
174
|
: '模型没从这段文字里抽出知识条目 —— 试试写得更具体(谁 / 是什么 / 为什么)'
|
|
203
175
|
try { await LOADERS.knowledge(p); p.state = 'ok' } catch {}
|
|
204
176
|
return d
|
|
@@ -209,9 +181,6 @@ export async function ingestKnowledge({ text, title = '', domain = '' }) {
|
|
|
209
181
|
}
|
|
210
182
|
}
|
|
211
183
|
|
|
212
|
-
/* ── SM-2 复习会话 ── */
|
|
213
|
-
|
|
214
|
-
/* 开一轮:队列空了就先拉一次。会话状态在 store 里,点开文档再回来不丢进度。 */
|
|
215
184
|
export async function startReview() {
|
|
216
185
|
const p = panels.review
|
|
217
186
|
if (!p.queue.length) await loadPanel('review', true)
|
|
@@ -226,9 +195,6 @@ export function revealCard() {
|
|
|
226
195
|
panels.review.revealed = true
|
|
227
196
|
}
|
|
228
197
|
|
|
229
|
-
/* 评分 → 服务端按 SM-2 算下一次间隔 → 翻到下一张。
|
|
230
|
-
四档对应 SM-2 的 0/3/4/5:0 完全忘记(重置)、3 勉强、4 记住、5 轻松。
|
|
231
|
-
只更新账本不动队列 —— 队列是这一轮的现场。 */
|
|
232
198
|
export async function gradeCard(grade) {
|
|
233
199
|
const p = panels.review
|
|
234
200
|
const card = p.queue[p.index]
|
|
@@ -244,13 +210,11 @@ export async function gradeCard(grade) {
|
|
|
244
210
|
return d
|
|
245
211
|
}
|
|
246
212
|
|
|
247
|
-
/* 删除一条误存的偏好:DELETE /preferences/{id} */
|
|
248
213
|
export async function dropPreference(id) {
|
|
249
214
|
await delJSON(`/preferences/${encodeURIComponent(id)}`)
|
|
250
215
|
await refreshPanel('memory')
|
|
251
216
|
}
|
|
252
217
|
|
|
253
|
-
/* 技能 / KU 正文 → 中间舞台。kind 决定皮肤:code 走 CLI 黑底,text 走排版正文 */
|
|
254
218
|
export async function openMdSkill(id) {
|
|
255
219
|
const d = await getJSON(`/ahs/md-skills/${encodeURIComponent(id)}`)
|
|
256
220
|
openDoc({
|
|
@@ -264,8 +228,6 @@ export async function openMdSkill(id) {
|
|
|
264
228
|
})
|
|
265
229
|
}
|
|
266
230
|
|
|
267
|
-
/* extra 里的业务字段逐类型不同(Fact 有 statement、Evidence 有 source、Entity 有 aliases),
|
|
268
|
-
按类型硬编码会漏;这里统一按「有值就列出来」处理,任何 KU 打开都有内容可读。 */
|
|
269
231
|
const KU_FIELDS = [
|
|
270
232
|
['statement', '陈述'],
|
|
271
233
|
['definition', '定义'],
|
|
@@ -289,8 +251,6 @@ const kuVal = (v) => {
|
|
|
289
251
|
return v === 0 || v === '' || v == null ? '' : String(v)
|
|
290
252
|
}
|
|
291
253
|
|
|
292
|
-
/* 单个 KU 的正文 → 中间舞台。走 HKC 根路径 /knowledge/ku/{id}
|
|
293
|
-
(那条路径带 source_text,列表/图谱的响应为了瘦身把它剔掉了) */
|
|
294
254
|
export async function openKu(id) {
|
|
295
255
|
const d = await getRaw(`/knowledge/ku/${encodeURIComponent(id)}`)
|
|
296
256
|
const extra = d.extra || {}
|
|
@@ -298,7 +258,6 @@ export async function openKu(id) {
|
|
|
298
258
|
const rows = KU_FIELDS
|
|
299
259
|
.map(([k, label]) => [label, kuVal(extra[k])])
|
|
300
260
|
.filter(([, v]) => v)
|
|
301
|
-
/* statement 已经在标题下一行重复过一次,正文里不再复读 */
|
|
302
261
|
const body = rows.filter(([, v]) => v !== d.summary && v !== d.name)
|
|
303
262
|
|
|
304
263
|
const parts = []
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { reactive } from 'vue'
|
|
2
|
+
import { getJSON, putJSON } from '../api.js'
|
|
3
|
+
|
|
4
|
+
export const profile = reactive({
|
|
5
|
+
nickname: '',
|
|
6
|
+
loaded: false,
|
|
7
|
+
saving: false,
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export async function loadProfile(force = false) {
|
|
11
|
+
if (profile.loaded && !force) return profile
|
|
12
|
+
try {
|
|
13
|
+
const d = await getJSON('/profile')
|
|
14
|
+
profile.nickname = d.nickname || ''
|
|
15
|
+
profile.loaded = true
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
return profile
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function saveNickname(nick) {
|
|
22
|
+
profile.saving = true
|
|
23
|
+
try {
|
|
24
|
+
const d = await putJSON('/profile', { nickname: nick || '' })
|
|
25
|
+
profile.nickname = d.nickname || ''
|
|
26
|
+
profile.loaded = true
|
|
27
|
+
return profile.nickname
|
|
28
|
+
} finally {
|
|
29
|
+
profile.saving = false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { reactive } from 'vue'
|
|
2
|
+
import { getJSON } from '../api.js'
|
|
3
|
+
|
|
4
|
+
export const system = reactive({
|
|
5
|
+
version: '',
|
|
6
|
+
update: null, // { enabled, current, latest, update_available, checked_at, error }
|
|
7
|
+
loaded: false,
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
let inflight = null
|
|
11
|
+
|
|
12
|
+
export function loadSystemInfo(force = false) {
|
|
13
|
+
if (system.loaded && !force) return Promise.resolve(system)
|
|
14
|
+
if (inflight) return inflight
|
|
15
|
+
inflight = getJSON('/system/info')
|
|
16
|
+
.then((d) => {
|
|
17
|
+
system.version = d.version || ''
|
|
18
|
+
system.update = d.update || null
|
|
19
|
+
system.loaded = true
|
|
20
|
+
return system
|
|
21
|
+
})
|
|
22
|
+
.catch(() => system) // 拿不到就维持旧值:顶栏不显示版本,不显示更新
|
|
23
|
+
.finally(() => { inflight = null })
|
|
24
|
+
return inflight
|
|
25
|
+
}
|
|
@@ -3,8 +3,6 @@ import { defineConfig } from 'vite'
|
|
|
3
3
|
import vue from '@vitejs/plugin-vue'
|
|
4
4
|
import { fileURLToPath, URL } from 'node:url'
|
|
5
5
|
|
|
6
|
-
/* 设置面板底部的版本行照 OpenClaw 写成 git@<sha> · <N 天前>。
|
|
7
|
-
构建时抓一次 git 信息;没有 git(打包机 / 压缩包)就退回 dev,不让构建失败。 */
|
|
8
6
|
function gitInfo() {
|
|
9
7
|
try {
|
|
10
8
|
const sha = execSync('git rev-parse --short HEAD', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim()
|
|
@@ -15,9 +13,6 @@ function gitInfo() {
|
|
|
15
13
|
}
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
/* 产物直接写进 frontend/v3/,后端 (StaticFiles(directory=frontend, html=True)) 零改动:
|
|
19
|
-
/v3/ -> frontend/v3/index.html
|
|
20
|
-
base 必须是 '/v3/',否则 assets 会打到站点根。 */
|
|
21
16
|
export default defineConfig({
|
|
22
17
|
base: '/v3/',
|
|
23
18
|
plugins: [vue()],
|
|
@@ -34,12 +29,10 @@ export default defineConfig({
|
|
|
34
29
|
},
|
|
35
30
|
server: {
|
|
36
31
|
port: 5173,
|
|
37
|
-
/* dev 时把 API 与 WS 透到本地后端,前端代码里一律用相对路径 /api */
|
|
38
32
|
proxy: {
|
|
39
33
|
'/api': { target: 'http://127.0.0.1:8000', changeOrigin: true },
|
|
40
34
|
'/ws': { target: 'ws://127.0.0.1:8000', ws: true },
|
|
41
35
|
'/planet': { target: 'http://127.0.0.1:8000', changeOrigin: true },
|
|
42
|
-
/* /knowledge/* 无 /api 前缀:HKC 自带 router 由后端根路径挂载 */
|
|
43
36
|
'/knowledge': { target: 'http://127.0.0.1:8000', changeOrigin: true },
|
|
44
37
|
},
|
|
45
38
|
},
|
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.3"
|
|
8
8
|
description = "Foxclaw - a personal agent with memory, built on the HMR memory runtime"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
|
|
@@ -134,12 +134,12 @@ python_version = "3.11"
|
|
|
134
134
|
ignore_missing_imports = true
|
|
135
135
|
check_untyped_defs = true
|
|
136
136
|
# 渐进式:mypy 存量错误用棘轮门管理(tools/mypy_ratchet.py + tools/mypy_baseline.txt)。
|
|
137
|
-
# 2026-11 实测
|
|
137
|
+
# 2026-11 实测 152 errors in 45 files,已冻结:CI 中错误数一旦增加即失败,
|
|
138
138
|
# 下降后用 `python tools/mypy_ratchet.py --update` 调低基线。只降不升。
|
|
139
139
|
|
|
140
140
|
[tool.pytest.ini_options]
|
|
141
141
|
testpaths = ["tests"]
|
|
142
|
-
# S2
|
|
142
|
+
# S2 迁移完成:全部测试文件均已迁移为 pytest(无顶层 import 副作用,可安全收集)。
|
|
143
143
|
# 注意:网关/内置MCP/流式限流等少数测试依赖模块级单例(FOXCLAW_GATEWAY、FOXCLAW_MCP_SERVER、
|
|
144
144
|
# _STREAM_LIMITER 均在 import 时按 env 固化),单进程 `pytest tests/` 会让这些单例被首个
|
|
145
145
|
# import 定死、相互污染。故全量执行统一走 tests/run_all.py(每个文件独立子进程
|
|
@@ -214,6 +214,7 @@ python_files = [
|
|
|
214
214
|
"test_plan_visible.py",
|
|
215
215
|
"test_planner.py",
|
|
216
216
|
"test_policy_gate.py",
|
|
217
|
+
"test_profile.py",
|
|
217
218
|
"test_reasoner.py",
|
|
218
219
|
"test_release_check.py",
|
|
219
220
|
"test_resume_checkpoint.py",
|
|
@@ -229,6 +230,7 @@ python_files = [
|
|
|
229
230
|
"test_secrets.py",
|
|
230
231
|
"test_skill_taint_gate.py",
|
|
231
232
|
"test_skills.py",
|
|
233
|
+
"test_skills_fetch.py",
|
|
232
234
|
"test_stats_and_events.py",
|
|
233
235
|
"test_streaming.py",
|
|
234
236
|
"test_supervisor_pipeline.py",
|
|
@@ -246,6 +248,7 @@ python_files = [
|
|
|
246
248
|
"test_tracing.py",
|
|
247
249
|
"test_truth_crystallizer.py",
|
|
248
250
|
"test_truth_flow.py",
|
|
251
|
+
"test_update_check.py",
|
|
249
252
|
"test_url_policy.py",
|
|
250
253
|
"test_version_sync.py",
|
|
251
254
|
"test_web_trigger.py",
|