diff --git a/cmd/homed/main.go b/cmd/homed/main.go index 4264d7c..e318ea9 100644 --- a/cmd/homed/main.go +++ b/cmd/homed/main.go @@ -42,7 +42,7 @@ import ( func main() { dataDir := flag.String("data", "", "data directory (default: auto-detect next to binary)") - httpAddr := flag.String("webui", ":8080", "webui listen address") + httpAddr := flag.String("webui", "", "webui listen address (default: webui.listen_addr from config)") cliSocket := flag.String("socket", "", "cli unix socket path (default: /cli.sock)") flag.Parse() @@ -395,7 +395,11 @@ func main() { // 为内置插件注入内核依赖(各插件通过 init() 自注册工厂) cli.DefaultSocket = *cliSocket openclaw.SkillsDir = filepath.Join(cfg.Daemon.DataDir, "skills") - webui.Configure(*httpAddr, + webuiListenAddr := *httpAddr + if webuiListenAddr == "" { + webuiListenAddr = cfgReg.GetString("webui.listen_addr", ":8080") + } + webui.Configure(webuiListenAddr, sup, memDB, skMgr, luaVM, cfg, iom, textMem, ks, trk, cfgReg, pluginReg, evBus, agent, providerMgr, baseAPIKey, ) diff --git a/docs/en/PLUGIN_DEV.md b/docs/en/PLUGIN_DEV.md index e26614d..eac42a0 100644 --- a/docs/en/PLUGIN_DEV.md +++ b/docs/en/PLUGIN_DEV.md @@ -299,6 +299,37 @@ s.LLM().ListSources() []SourceInfo s.LLM().SetSource(name string) error ``` +#### Event Subscription (built-in plugins) + +```go +// Subscribe to system events, returns unsubscribe function +unsub := s.Subscribe("tool_call", func(evt *events.Event) { + log.Printf("Tool was called: %v", evt.Payload) +}) +defer unsub() + +// Publish event +s.Publish(&events.Event{ + Type: "custom_event", + Payload: map[string]interface{}{"key": "value"}, +}) +``` + +#### IO Channel Management (built-in plugins) + +```go +// Register a channel (bind device driver) +s.RegisterChannel("mydevice", deviceImpl) + +// Unregister a channel +s.UnregisterChannel("mydevice") + +// List all channels +channels := s.ListChannels() +``` + +> **Note**: `Subscribe`, `Publish`, `RegisterChannel`, `UnregisterChannel`, `ListChannels`, `InjectInput`, `InjectInputSync`, `InjectInterrupt`, `InjectTextSync`, `InjectTextSyncNoMemory`, `OutputChan` are only available in built-in plugins (`internal/sdk` package). External dynamic plugins should use the public APIs: `InjectText`, `InjectInterruptText`, `InjectTextNoMemory`. + --- ## 3. Lua Plugin Development in Detail @@ -367,6 +398,8 @@ When running inside the kernel, `sdk.*` global variables are injected by the Go | `sdk.http.get(url)` | HTTP GET request (`-- !impl`) | | `sdk.http.post(url, body, content_type)` | HTTP POST request (`-- !impl`) | +> **Note**: Lua plugin's `sdk.register_stage` callback currently only receives `raw_message`, `user_id`, `phase` fields. The functionality is limited. For complex stage handling logic, use Go plugins. + --- ## 4. Built-in Plugins diff --git a/docs/zh/PLUGIN_DEV.md b/docs/zh/PLUGIN_DEV.md index e691d0c..80465fa 100644 --- a/docs/zh/PLUGIN_DEV.md +++ b/docs/zh/PLUGIN_DEV.md @@ -300,6 +300,37 @@ s.LLM().ListSources() []SourceInfo s.LLM().SetSource(name string) error ``` +#### 事件订阅(内置插件) + +```go +// 订阅系统事件,返回取消订阅函数 +unsub := s.Subscribe("tool_call", func(evt *events.Event) { + log.Printf("工具被调用: %v", evt.Payload) +}) +defer unsub() + +// 发布事件 +s.Publish(&events.Event{ + Type: "custom_event", + Payload: map[string]interface{}{"key": "value"}, +}) +``` + +#### IO 通道管理(内置插件) + +```go +// 注册通道(绑定设备驱动) +s.RegisterChannel("mydevice", deviceImpl) + +// 注销通道 +s.UnregisterChannel("mydevice") + +// 列出所有通道 +channels := s.ListChannels() +``` + +> **注意**:`Subscribe`、`Publish`、`RegisterChannel`、`UnregisterChannel`、`ListChannels`、`InjectInput`、`InjectInputSync`、`InjectInterrupt`、`InjectTextSync`、`InjectTextSyncNoMemory`、`OutputChan` 这些方法仅在内置插件中可用(`internal/sdk` 包),外部动态插件无法访问。外部插件请使用 `InjectText`、`InjectInterruptText`、`InjectTextNoMemory` 等公共 API。 + --- ## 三、Lua 插件开发详解 @@ -368,6 +399,8 @@ lua main.lua | `sdk.http.get(url)` | HTTP GET 请求(`-- !impl`) | | `sdk.http.post(url, body, content_type)` | HTTP POST 请求(`-- !impl`) | +> **注意**:Lua 插件的 `sdk.register_stage` 阶段回调目前仅传递 `raw_message`、`user_id`、`phase` 三个字段,功能受限。复杂的阶段处理逻辑建议使用 Go 插件。 + --- ## 四、内置插件 diff --git a/go.mod b/go.mod index 2153a8a..c4ad398 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,8 @@ require ( require gitcode.com/JianFeeeee/homeagent-sdk v0.0.0-20260708004841-e9bdcf9304b0 // direct +replace gitcode.com/JianFeeeee/homeagent-sdk => ../homeagentsdk + require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/google/uuid v1.6.0 // indirect diff --git a/internal/agent/core/agent.go b/internal/agent/core/agent.go index 3309b08..536a9cb 100644 --- a/internal/agent/core/agent.go +++ b/internal/agent/core/agent.go @@ -1522,6 +1522,9 @@ func (a *Agent) buildSystemPrompt(memContext string, userInput string) string { prompt += "\n\n" + a.indexer.BuildToolPrompt() } + // 动态工具目录 + prompt += a.buildToolCatalog() + return prompt } @@ -1549,6 +1552,41 @@ func cleanParams(params map[string]interface{}) map[string]interface{} { return cleaned } +func (a *Agent) buildToolCatalog() string { + defs := a.buildToolDefs() + if len(defs) == 0 { + return "" + } + var sb strings.Builder + sb.WriteString("\n\n【可用工具列表】") + seen := make(map[string]bool) + for _, d := range defs { + t, ok := d.(map[string]interface{}) + if !ok { + continue + } + fn, ok := t["function"].(map[string]interface{}) + if !ok { + continue + } + name, _ := fn["name"].(string) + if name == "" || seen[name] { + continue + } + seen[name] = true + desc, _ := fn["description"].(string) + sb.WriteString(fmt.Sprintf("\n- %s", name)) + if desc != "" { + // only first 80 chars of description + if len(desc) > 80 { + desc = desc[:80] + "..." + } + sb.WriteString(": " + desc) + } + } + return sb.String() +} + func (a *Agent) buildToolDefs() []interface{} { var tools []interface{} diff --git a/internal/agent/core/stages.go b/internal/agent/core/stages.go index a42e7ec..a16a328 100644 --- a/internal/agent/core/stages.go +++ b/internal/agent/core/stages.go @@ -2,6 +2,7 @@ package core import ( "fmt" + "log" "sync" sdk "gitcode.com/JianFeeeee/HomeAgent/internal/sdk" @@ -85,6 +86,7 @@ func inferToolPlugin(name string) string { // - 只读操作先调用 ctx.RLock() / defer ctx.RUnlock() // - 写操作(如设置 ctx.Response)先调用 ctx.Lock() / defer ctx.Unlock() // 如果任意 handler 设置了 Response,后续 handler 可通过 ctx.IsResponded() 判断后提前返回。 +// handler 返回的 error 会被收集到 ctx.Errors 中并记录日志,不会中断其他 handler 的执行。 func (h *StageHost) RunStage(stage sdk.Stage, ctx *sdk.StageContext) { h.mu.RLock() handlers := h.stages[stage] @@ -93,14 +95,29 @@ func (h *StageHost) RunStage(stage sdk.Stage, ctx *sdk.StageContext) { return } var wg sync.WaitGroup + errCh := make(chan error, len(handlers)) for _, handler := range handlers { wg.Add(1) go func(fn sdk.StageHandler) { defer wg.Done() - fn(ctx) + if err := fn(ctx); err != nil { + errCh <- err + } }(handler) } wg.Wait() + close(errCh) + + var errs []string + for err := range errCh { + errs = append(errs, err.Error()) + log.Printf("[stage] %s handler error: %v", stage, err) + } + if len(errs) > 0 { + ctx.Lock() + ctx.Errors = append(ctx.Errors, errs...) + ctx.Unlock() + } } func (h *StageHost) ToolCount() int { diff --git a/internal/agent/core/status.go b/internal/agent/core/status.go index e54c27e..77d8808 100644 --- a/internal/agent/core/status.go +++ b/internal/agent/core/status.go @@ -68,32 +68,32 @@ func channelInfoFromIO(ch agentIO.ChannelInfo) ChannelInfo { } type MemoryStatus struct { - Available bool `json:"available"` - EntityCount int `json:"entity_count,omitempty"` - RelationCount int `json:"relation_count,omitempty"` - EntityTypes int `json:"entity_types,omitempty"` + Available bool `json:"available"` + EntityCount int `json:"entity_count"` + RelationCount int `json:"relation_count"` + EntityTypes int `json:"entity_types"` } type KnowledgeStatus struct { Available bool `json:"available"` - ItemCount int `json:"item_count,omitempty"` + ItemCount int `json:"item_count"` Items []string `json:"items,omitempty"` } type DocumentStatus struct { Available bool `json:"available"` - DocCount int `json:"doc_count,omitempty"` - VectorCount int `json:"vector_count,omitempty"` + DocCount int `json:"doc_count"` + VectorCount int `json:"vector_count"` } type TextMemoryStatus struct { Available bool `json:"available"` - FileCount int `json:"file_count,omitempty"` + FileCount int `json:"file_count"` } type SocialStatus struct { Available bool `json:"available"` - PersonCount int `json:"person_count,omitempty"` + PersonCount int `json:"person_count"` } type SkillsStatus struct { diff --git a/internal/config/registry.go b/internal/config/registry.go index 3dffeb5..86f0090 100644 --- a/internal/config/registry.go +++ b/internal/config/registry.go @@ -298,7 +298,7 @@ func (r *ConfigRegistry) seedDBValues(dataDir string) { set := func(k, v string) { stmt.Exec(k, v) } - set("core.daemon.listen_addr", ":8080") + set("webui.listen_addr", ":8080") set("core.daemon.data_dir", dataDir) set("core.daemon.heartbeat_interval", "15s") set("core.daemon.check_interval", "30s") @@ -349,26 +349,11 @@ func (r *ConfigRegistry) seedDBValues(dataDir string) { set("core.agent.distill_interval", "30m") set("core.agent.workdir", "") set("core.agent.system_prompt", `你是 HomeAgent,一个持续运行的个人管家。 -你的每次回复会自动发送到当前输出通道(默认=输入源),无需额外工具。 -如需切换回复通道,使用 output_set_channel。 -如需异步发送消息或通知,使用 output_send 指定通道和内容。 -使用 output_list_channels 查看可用通道及其能力。 +你的回复默认发送到用户的输入来源,无需额外工具。 +如需异步发送消息到其他通道,使用 output_send。 +使用 output_list_channels 查看可用通道。 -可用工具列表会由系统自动传入,按需使用即可。以下是你尤其需要关注的几类工具: -- memory_* — 图记忆(长期记忆,记录和查询个人信息/事实) -- knowledge_* — 知识库(查阅预设知识文档) -- doc_* — 文档记忆(近期对话的存档,查询后自动清除) -- person_* — 人物特质与社交关系网 -- llm_* — LLM 源管理(列出/切换模型提供商) -- output_* — 输出通道管理(切换/发送消息) -- timer_set — 设置定时提醒 -- plgreload — 热重载插件 -- spawn_child — 生成子 Agent 执行独立任务 -- describe_image — 描述用户上传的图片 -- transcribe_audio — 转写用户上传的音频 -- ocr_image — 识别图片中的文字 - -当用户上传图片或音频时,系统会自动附着媒体内容。如果模型不支持直接处理多媒体,请使用上述工具。 +当用户上传图片或音频时,系统会自动附着媒体内容。如果模型不支持直接处理多媒体,请调用对应的媒体处理工具。 回复你的真实想法,用自然语言与用户交流。`) @@ -387,7 +372,7 @@ func (r *ConfigRegistry) seedDBValues(dataDir string) { func (r *ConfigRegistry) seedCoreDefs(dataDir string) { reg := func(d ConfigDef) { r.defs[d.Key] = &d } - reg(ConfigDef{Key: "core.daemon.listen_addr", Default: ":8080", Type: "string", DisplayName: "监听地址", Description: "WebUI HTTP 监听地址", Category: "daemon"}) + reg(ConfigDef{Key: "webui.listen_addr", Default: ":8080", Type: "string", DisplayName: "监听地址", Description: "WebUI HTTP 监听地址", Category: "webui"}) reg(ConfigDef{Key: "core.daemon.data_dir", Default: dataDir, Type: "string", DisplayName: "数据目录", Description: "数据存储根目录", Category: "daemon"}) reg(ConfigDef{Key: "core.daemon.heartbeat_interval", Default: "15s", Type: "duration", DisplayName: "心跳间隔", Description: "Agent 心跳检查间隔", Category: "daemon"}) reg(ConfigDef{Key: "core.daemon.check_interval", Default: "30s", Type: "duration", DisplayName: "检查间隔", Description: "网络状态检查间隔", Category: "daemon"}) @@ -568,7 +553,6 @@ func (r *ConfigRegistry) ToConfig() *types.Config { return b } - cfg.Daemon.ListenAddr = read("core.daemon.listen_addr", cfg.Daemon.ListenAddr) cfg.Daemon.DataDir = read("core.daemon.data_dir", cfg.Daemon.DataDir) cfg.Daemon.HeartbeatInterval = readDur("core.daemon.heartbeat_interval", cfg.Daemon.HeartbeatInterval) cfg.Daemon.CheckInterval = readDur("core.daemon.check_interval", cfg.Daemon.CheckInterval) diff --git a/internal/config/registry_test.go b/internal/config/registry_test.go index 52ab542..817aa79 100644 --- a/internal/config/registry_test.go +++ b/internal/config/registry_test.go @@ -168,8 +168,8 @@ func TestSeedDefaultsToConfig(t *testing.T) { // Reconstruct config from DB cfg2 := r.ToConfig() - if cfg2.Daemon.ListenAddr != ":8080" { - t.Fatalf("expected :8080, got %s", cfg2.Daemon.ListenAddr) + if v := r.GetString("webui.listen_addr", ""); v != ":8080" { + t.Fatalf("expected :8080, got %s", v) } if cfg2.LLM.Provider != "deepseek" { t.Fatalf("expected deepseek, got %s", cfg2.LLM.Provider) diff --git a/internal/lua/vm.go b/internal/lua/vm.go index 106bdeb..bc7adbd 100644 --- a/internal/lua/vm.go +++ b/internal/lua/vm.go @@ -4,7 +4,6 @@ import ( "embed" "encoding/json" "fmt" - "io/fs" "os" "path/filepath" "sync" @@ -324,42 +323,24 @@ func (v *VM) GetAdapterHeaders(name string) map[string]string { } func (v *VM) writeBundledAdapters() error { - // Try multiple paths for compatibility - tryPaths := []string{"adapters", ".", "lua/adapters"} - var entries []fs.DirEntry - var err error - for _, p := range tryPaths { - entries, err = bundledAdapters.ReadDir(p) - if err == nil && len(entries) > 0 { - break - } + known := []string{ + "openai", "anthropic", "deepseek", "gemini", + "github", "groq", "mistral", "ollama", } - if err != nil || len(entries) == 0 { - return nil - } - for _, entry := range entries { - if entry.IsDir() { - continue - } - if filepath.Ext(entry.Name()) != ".lua" { - continue - } - dstPath := filepath.Join(v.adapterDir, entry.Name()) + for _, name := range known { + srcPath := "adapters/" + name + ".lua" + dstPath := filepath.Join(v.adapterDir, name+".lua") if _, err := os.Stat(dstPath); err == nil { continue } - data, err := bundledAdapters.ReadFile(filepath.Join("adapters", entry.Name())) + data, err := bundledAdapters.ReadFile(srcPath) if err != nil { - // try alternative paths - data, err = bundledAdapters.ReadFile(entry.Name()) - if err != nil { - continue - } + continue } if err := os.WriteFile(dstPath, data, 0644); err != nil { - return fmt.Errorf("write %s: %w", entry.Name(), err) + return fmt.Errorf("write %s: %w", name+".lua", err) } - fmt.Printf("[lua] installed bundled adapter: %s\n", entry.Name()) + fmt.Printf("[lua] installed bundled adapter: %s\n", name+".lua") } return nil } diff --git a/internal/plugins/cmd/plugin.go b/internal/plugins/cmd/plugin.go index a339d38..27b5576 100644 --- a/internal/plugins/cmd/plugin.go +++ b/internal/plugins/cmd/plugin.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "os/exec" + "runtime" "strings" "sync" "time" @@ -13,6 +14,9 @@ import ( sdk "gitcode.com/JianFeeeee/HomeAgent/internal/sdk" ) +// isWindows 缓存运行时检测结果 +var isWindows = runtime.GOOS == "windows" + // shellUnquote 拆解命令字符串,处理单引号/双引号包裹的参数 func shellUnquote(s string) []string { var args []string @@ -152,7 +156,12 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() - parts := shellUnquote(command) + // Windows 上预置 chcp 65001 确保控制台输出为 UTF-8,避免 GBK 乱码 + execCmd := command + if isWindows { + execCmd = "chcp 65001>nul & " + command + } + parts := shellUnquote(execCmd) if len(parts) == 0 { return map[string]interface{}{"error": "command is required"}, nil } diff --git a/internal/plugins/webui/dashboard.html b/internal/plugins/webui/dashboard.html index 5764052..d19be2c 100644 --- a/internal/plugins/webui/dashboard.html +++ b/internal/plugins/webui/dashboard.html @@ -1,4 +1,4 @@ - + @@ -8,330 +8,1664 @@ - +
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/internal/plugins/webui/handler.go b/internal/plugins/webui/handler.go index b37c358..962a876 100644 --- a/internal/plugins/webui/handler.go +++ b/internal/plugins/webui/handler.go @@ -950,7 +950,7 @@ func (h *Handler) handleChatEvents(w http.ResponseWriter, r *http.Request) { } }() - subTypes := []string{"agent_output", "reasoning", "agent_error"} + subTypes := []string{"agent_output", "reasoning", "agent_error", "tool_call"} for _, t := range subTypes { t2 := t _ = h.eventBus.Subscribe(events.EventType(t2), func(evt *events.Event) { diff --git a/internal/plugins/webui/handler_test.go b/internal/plugins/webui/handler_test.go index 4998a66..f2353df 100644 --- a/internal/plugins/webui/handler_test.go +++ b/internal/plugins/webui/handler_test.go @@ -34,7 +34,7 @@ func newTestHandler(t *testing.T) (*Handler, *supervisor.Daemon) { sup := supervisor.New(cfg) sup.Start() - return NewHandler(sup, nil, nil, nil, cfg, nil, nil, nil, nil, nil, nil, events.NewBus(), nil), sup + return NewHandler(sup, nil, nil, nil, cfg, nil, nil, nil, nil, nil, nil, events.NewBus(), nil, nil, ""), sup } func TestAuthMiddleware(t *testing.T) { @@ -194,7 +194,7 @@ func TestHandleKnowledgeSearch(t *testing.T) { sup.Start() defer sup.Shutdown() - h := NewHandler(sup, nil, nil, nil, cfg, nil, nil, ks, nil, nil, nil, events.NewBus(), nil) + h := NewHandler(sup, nil, nil, nil, cfg, nil, nil, ks, nil, nil, nil, events.NewBus(), nil, nil, "") req := httptest.NewRequest(http.MethodGet, "/api/v1/knowledge?q=test", nil) w := httptest.NewRecorder() @@ -226,7 +226,7 @@ func TestHandleKnowledgeCreate(t *testing.T) { sup.Start() defer sup.Shutdown() - h := NewHandler(sup, nil, nil, nil, cfg, nil, nil, ks, nil, nil, nil, events.NewBus(), nil) + h := NewHandler(sup, nil, nil, nil, cfg, nil, nil, ks, nil, nil, nil, events.NewBus(), nil, nil, "") body := `{"name":"new_doc","content":"fresh content"}` req := httptest.NewRequest(http.MethodPost, "/api/v1/knowledge", strings.NewReader(body)) @@ -291,7 +291,7 @@ func TestHandleTrackerStats(t *testing.T) { sup.Start() defer sup.Shutdown() - h := NewHandler(sup, nil, nil, nil, cfg, nil, nil, nil, tr, nil, nil, events.NewBus(), nil) + h := NewHandler(sup, nil, nil, nil, cfg, nil, nil, nil, tr, nil, nil, events.NewBus(), nil, nil, "") req := httptest.NewRequest(http.MethodGet, "/api/v1/tracker", nil) w := httptest.NewRecorder() @@ -458,7 +458,7 @@ func TestSettingsAPIFlow(t *testing.T) { cfgReg := internalConfig.NewConfigRegistry("") cfgReg.Register("core.llm.model", "deepseek-v4-flash") cfgReg.Register("core.llm.base_url", "https://api.deepseek.com") - cfgReg.Register("core.daemon.listen_addr", ":8080") + cfgReg.Register("webui.listen_addr", ":8080") cfgReg.Register("plugin.qq.access_token", "secret123") sup := supervisor.New(&types.Config{ @@ -471,7 +471,7 @@ func TestSettingsAPIFlow(t *testing.T) { defer sup.Shutdown() pluginReg := plugin.NewRegistry() - h := NewHandler(sup, nil, nil, nil, &types.Config{}, nil, nil, nil, nil, cfgReg, pluginReg, events.NewBus(), nil) + h := NewHandler(sup, nil, nil, nil, &types.Config{}, nil, nil, nil, nil, cfgReg, pluginReg, events.NewBus(), nil, nil, "") t.Run("GET_settings_lists_keys_and_plugins", func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/api/v1/settings", nil) @@ -505,7 +505,7 @@ func TestSettingsAPIFlow(t *testing.T) { }) t.Run("GET_settings_with_prefix", func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/api/v1/settings?prefix=core.daemon", nil) + req := httptest.NewRequest(http.MethodGet, "/api/v1/settings?prefix=webui", nil) w := httptest.NewRecorder() h.handleSettings(w, req) @@ -513,11 +513,11 @@ func TestSettingsAPIFlow(t *testing.T) { json.NewDecoder(w.Body).Decode(&resp) settings := resp["settings"].(map[string]interface{}) - if _, ok := settings["core.daemon.listen_addr"]; !ok { - t.Fatal("expected core.daemon.listen_addr in filtered results") + if _, ok := settings["webui.listen_addr"]; !ok { + t.Fatal("expected webui.listen_addr in filtered results") } if _, ok := settings["core.llm.model"]; ok { - t.Fatal("core.llm.model should not be in core.daemon filtered results") + t.Fatal("core.llm.model should not be in webui filtered results") } }) @@ -578,7 +578,7 @@ func TestSettingsAPIFlow(t *testing.T) { }) t.Run("settings_not_available_without_registry", func(t *testing.T) { - h2 := NewHandler(sup, nil, nil, nil, &types.Config{}, nil, nil, nil, nil, nil, nil, events.NewBus(), nil) + h2 := NewHandler(sup, nil, nil, nil, &types.Config{}, nil, nil, nil, nil, nil, nil, events.NewBus(), nil, nil, "") req := httptest.NewRequest(http.MethodGet, "/api/v1/settings", nil) w := httptest.NewRecorder() h2.handleSettings(w, req) @@ -604,7 +604,7 @@ func TestSettingsWithPluginRegistry(t *testing.T) { defer sup.Shutdown() pluginReg := plugin.NewRegistry() - h := NewHandler(sup, nil, nil, nil, &types.Config{}, nil, nil, nil, nil, cfgReg, pluginReg, events.NewBus(), nil) + h := NewHandler(sup, nil, nil, nil, &types.Config{}, nil, nil, nil, nil, cfgReg, pluginReg, events.NewBus(), nil, nil, "") req := httptest.NewRequest(http.MethodGet, "/api/v1/settings", nil) w := httptest.NewRecorder() @@ -677,7 +677,7 @@ func TestHandleCompletionsEndToEnd(t *testing.T) { sup.Start() defer sup.Shutdown() - h := NewHandler(sup, nil, nil, nil, &types.Config{}, iom, nil, nil, nil, nil, nil, events.NewBus(), nil) + h := NewHandler(sup, nil, nil, nil, &types.Config{}, iom, nil, nil, nil, nil, nil, events.NewBus(), nil, nil, "") t.Run("POST_chat_completions_returns_echo", func(t *testing.T) { body := `{"model":"test","messages":[{"role":"user","content":"你好"}]}` @@ -710,7 +710,7 @@ func TestHandleCompletionsEndToEnd(t *testing.T) { }) t.Run("POST_chat_completions_no_iom_returns_503", func(t *testing.T) { - h2 := NewHandler(sup, nil, nil, nil, &types.Config{}, nil, nil, nil, nil, nil, nil, events.NewBus(), nil) + h2 := NewHandler(sup, nil, nil, nil, &types.Config{}, nil, nil, nil, nil, nil, nil, events.NewBus(), nil, nil, "") body := `{"messages":[{"role":"user","content":"hi"}]}` req := httptest.NewRequest(http.MethodPost, "/v1/chat/completions", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") diff --git a/pkg/types/types.go b/pkg/types/types.go index 73ff7de..c6ca2a9 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -150,7 +150,6 @@ type Config struct { } type DaemonConfig struct { - ListenAddr string `json:"listen_addr"` DataDir string `json:"data_dir"` HeartbeatInterval time.Duration `json:"heartbeat_interval"` CheckInterval time.Duration `json:"check_interval"`