From c069deccca6553e5df0a9680b35c947e42a45d26 Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Sun, 3 May 2026 14:58:42 +0200 Subject: [PATCH] config: add tools bool to disable tool collection per agent When tools is false in agent config, BuildAgentEnv skips ListTools entirely so no tool schemas are sent to the backend. Models without tool support now work cleanly. --- pkg/agent/core.go | 22 +++++++++++++--------- pkg/agent/core_test.go | 13 +++++++++++++ pkg/config/config.go | 7 +++++++ pkg/config/config_test.go | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/pkg/agent/core.go b/pkg/agent/core.go index 408b803..24bf290 100644 --- a/pkg/agent/core.go +++ b/pkg/agent/core.go @@ -47,18 +47,22 @@ type AgentEnv struct { func BuildAgentEnv(cfg *config.Config, d tools.Dispatcher, cwd string) AgentEnv { var messages []string - allToolInfos, listErr := d.ListTools() - if listErr != nil { - messages = append(messages, fmt.Sprintf("list tools: %v", listErr)) - } + var allToolInfos []tools.ToolInfo + var allTools []backend.Tool + serverOf := make(map[string]string) - serverOf := make(map[string]string, len(allToolInfos)) - for _, t := range allToolInfos { - serverOf[t.Name] = t.Server + if cfg == nil || cfg.ToolsEnabled() { + var listErr error + allToolInfos, listErr = d.ListTools() + if listErr != nil { + messages = append(messages, fmt.Sprintf("list tools: %v", listErr)) + } + for _, t := range allToolInfos { + serverOf[t.Name] = t.Server + } + allTools = toolInfosToBackend(allToolInfos) } - allTools := toolInfosToBackend(allToolInfos) - hooks := Hooks{} var preamble string var genParams backend.GenerationParams diff --git a/pkg/agent/core_test.go b/pkg/agent/core_test.go index ed1ccbf..beb7fd8 100644 --- a/pkg/agent/core_test.go +++ b/pkg/agent/core_test.go @@ -2335,6 +2335,19 @@ func TestBuildAgentEnv_ToolsPopulated(t *testing.T) { } } +func TestBuildAgentEnv_ToolsDisabled(t *testing.T) { + setupCfgDir(t) + d := &mockDispatcher{ + tools: []tools.ToolInfo{{Server: "s1", Name: "mytool", Description: "desc", InputSchema: json.RawMessage(`{}`)}}, + } + f := false + cfg := &config.Config{Tools: &f} + env := BuildAgentEnv(cfg, d, t.TempDir()) + if len(env.tools) != 0 { + t.Errorf("expected no tools when disabled; got %+v", env.tools) + } +} + func TestBuildAgentEnv_TrustedTools(t *testing.T) { setupCfgDir(t) setter := &mockTrustedSetter{} diff --git a/pkg/config/config.go b/pkg/config/config.go index c3bcc3f..608af02 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -61,6 +61,7 @@ func (p Prompt) MarshalJSON() ([]byte, error) { type Config struct { Hooks map[string]HookCmds `json:"hooks,omitempty"` Prompt Prompt `json:"prompt,omitempty"` + Tools *bool `json:"tools,omitempty"` TrustedTools []string `json:"trustedTools,omitempty"` MaxTokens int `json:"maxTokens,omitempty"` Temperature *float64 `json:"temperature,omitempty"` @@ -76,3 +77,9 @@ func Load(r io.Reader) (*Config, error) { } return &cfg, nil } + +// ToolsEnabled reports whether tool use is enabled. Defaults to true when +// the field is omitted from the config. +func (c *Config) ToolsEnabled() bool { + return c.Tools == nil || *c.Tools +} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 62f54f4..3a0b449 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -121,3 +121,21 @@ func TestLoadAllFields(t *testing.T) { t.Errorf("PresencePenalty = %v", cfg.PresencePenalty) } } + +func TestToolsEnabled(t *testing.T) { + // Omitted: defaults to true. + cfg, _ := Load(strings.NewReader(`{}`)) + if !cfg.ToolsEnabled() { + t.Error("expected ToolsEnabled()=true when omitted") + } + // Explicit false. + cfg, _ = Load(strings.NewReader(`{"tools": false}`)) + if cfg.ToolsEnabled() { + t.Error("expected ToolsEnabled()=false") + } + // Explicit true. + cfg, _ = Load(strings.NewReader(`{"tools": true}`)) + if !cfg.ToolsEnabled() { + t.Error("expected ToolsEnabled()=true") + } +} \ No newline at end of file