feat: complete P0/P1/P2 — WebUI SPA, OpenClaw sidecar+simulator, healthcheck auto-sched+perf

P0: WebUI重构
- 完整 SPA 仪表盘 (7标签页), //go:embed dashboard.html
P1: OpenClaw兼容 (三通道: SKILL.md / sidecar / simulator)
- Node.js 模拟进程统一加载任意 OpenClaw 插件
- JSON-RPC 2.0 over stdio 协议, go:embed 内嵌
P2: Healthcheck 优化
- 定时自动执行 (startAutoCheck, 30min)
- healthcheck_perf 性能监控工具

其他: agentcli/cmd 插件, integration_test, status.go,
      test_deepseek 清理, 多项 bug 修复
This commit is contained in:
root
2026-07-04 12:51:32 +08:00
parent 77e12f7329
commit fab58e709a
30 changed files with 4956 additions and 578 deletions

View File

@ -605,6 +605,22 @@ func (m *ProviderManager) Default() Provider {
return m.providers[m.default_]
}
// QuickChat 向默认 LLM Provider 发送一条简短消息并返回回复。
// 这是一个"非记忆"调用——直接通过 Provider HTTP 调用,不经过 Agent 的记忆/蒸馏管线。
// 适用于健康检查、系统自检等不需要产生记忆碎片的场景。
func (m *ProviderManager) QuickChat(ctx context.Context, prompt string) (*CompletionResponse, error) {
p := m.Default()
if p == nil {
return nil, fmt.Errorf("no default provider")
}
return p.Chat(ctx, &CompletionRequest{
Messages: []Message{
{Role: "user", Content: prompt},
},
MaxTokens: 128,
})
}
func (m *ProviderManager) List() []string {
m.mu.RLock()
defer m.mu.RUnlock()

View File

@ -0,0 +1,54 @@
package api
import (
"context"
"os"
"testing"
"time"
luaVM "gitcode.com/JianFeeeee/HomeAgent/internal/lua"
)
func TestQuickChatWithRealKey(t *testing.T) {
apiKey := os.Getenv("DEEPSEEK_API_KEY")
if apiKey == "" {
t.Skip("DEEPSEEK_API_KEY not set — skipping real LLM test")
}
tmpDir := t.TempDir()
vm := luaVM.NewVM(tmpDir + "/adapters")
if err := vm.Start(); err != nil {
t.Fatal(err)
}
defer vm.Stop()
pm := NewProviderManager()
pm.Register("deepseek", NewLuaAdaptedProvider(BaseConfig{
Model: "deepseek-v4-flash",
BaseURL: "https://api.deepseek.com",
APIKey: apiKey,
}, vm, "deepseek"))
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
start := time.Now()
resp, err := pm.QuickChat(ctx, "请回复'OK',不要输出其他内容")
elapsed := time.Since(start)
if err != nil {
t.Fatalf("QuickChat failed: %v", err)
}
if resp.Content == "" {
t.Fatal("empty response")
}
t.Logf("Response: %q", resp.Content)
t.Logf("Time: %v", elapsed.Round(time.Millisecond))
if resp.TokenUsage.Total > 0 {
t.Logf("Tokens: %d (prompt %d + completion %d)",
resp.TokenUsage.Total, resp.TokenUsage.Prompt, resp.TokenUsage.Completion)
}
}