From 1ef42417275ea06df702b9f68a8ad5a8e1b8859e Mon Sep 17 00:00:00 2001 From: Parth Sareen Date: Fri, 9 Jan 2026 18:20:39 -0800 Subject: [PATCH] x: request access for all commands, add welcome message (#13662) --- cmd/cmd.go | 4 ++-- x/agent/approval.go | 6 +++--- x/cmd/run.go | 20 ++++++++++-------- x/tools/registry.go | 16 +++++++++++++++ x/tools/registry_test.go | 44 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index f56a1d4b7..34a773375 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -520,7 +520,7 @@ func RunHandler(cmd *cobra.Command, args []string) error { // Check for experimental flag isExperimental, _ := cmd.Flags().GetBool("experimental") - yoloMode, _ := cmd.Flags().GetBool("yolo") + yoloMode, _ := cmd.Flags().GetBool("experimental-yolo") if interactive { if err := loadOrUnloadModel(cmd, &opts); err != nil { @@ -1765,7 +1765,7 @@ func NewCLI() *cobra.Command { runCmd.Flags().Bool("truncate", false, "For embedding models: truncate inputs exceeding context length (default: true). Set --truncate=false to error instead") runCmd.Flags().Int("dimensions", 0, "Truncate output embeddings to specified dimension (embedding models only)") runCmd.Flags().Bool("experimental", false, "Enable experimental agent loop with tools") - runCmd.Flags().BoolP("yolo", "y", false, "Skip all tool approval prompts (use with caution)") + runCmd.Flags().Bool("experimental-yolo", false, "Skip all tool approval prompts (use with caution)") stopCmd := &cobra.Command{ Use: "stop MODEL", diff --git a/x/agent/approval.go b/x/agent/approval.go index 0094b923c..1e1f3f0d2 100644 --- a/x/agent/approval.go +++ b/x/agent/approval.go @@ -989,11 +989,11 @@ func FormatApprovalResult(toolName string, args map[string]any, result ApprovalR switch result.Decision { case ApprovalOnce: - label = "approved" + label = "Approved" case ApprovalAlways: - label = "always allowed" + label = "Always allowed" case ApprovalDeny: - label = "denied" + label = "Denied" } // Format based on tool type diff --git a/x/cmd/run.go b/x/cmd/run.go index 5ec2ef942..e8d59b976 100644 --- a/x/cmd/run.go +++ b/x/cmd/run.go @@ -364,10 +364,11 @@ func Chat(ctx context.Context, opts RunOptions) (*api.Message, error) { } // Check if command is auto-allowed (safe command) - if agent.IsAutoAllowed(cmd) { - fmt.Fprintf(os.Stderr, "\033[1mauto-allowed:\033[0m %s\n", formatToolShort(toolName, args)) - skipApproval = true - } + // TODO(parthsareen): re-enable with tighter scoped allowlist + // if agent.IsAutoAllowed(cmd) { + // fmt.Fprintf(os.Stderr, "\033[1mauto-allowed:\033[0m %s\n", formatToolShort(toolName, args)) + // skipApproval = true + // } } } @@ -658,14 +659,17 @@ func GenerateInteractive(cmd *cobra.Command, modelName string, wordWrap bool, op var toolRegistry *tools.Registry if supportsTools { toolRegistry = tools.DefaultRegistry() - if toolRegistry.Count() > 0 { - fmt.Fprintf(os.Stderr, "\033[90mtools available: %s\033[0m\n", strings.Join(toolRegistry.Names(), ", ")) + + if toolRegistry.Has("bash") { + fmt.Fprintln(os.Stderr) + fmt.Fprintln(os.Stderr, "This experimental version of Ollama has the \033[1mbash\033[0m tool enabled.") + fmt.Fprintln(os.Stderr, "Models can read files on your computer, or run commands (after you allow them).") + fmt.Fprintln(os.Stderr) } + if yoloMode { fmt.Fprintf(os.Stderr, "\033[1mwarning:\033[0m yolo mode - all tool approvals will be skipped\n") } - } else { - fmt.Fprintf(os.Stderr, "\033[1mnote:\033[0m model does not support tools - running in chat-only mode\n") } // Create approval manager for session diff --git a/x/tools/registry.go b/x/tools/registry.go index caab9e50b..881a61bb5 100644 --- a/x/tools/registry.go +++ b/x/tools/registry.go @@ -38,6 +38,22 @@ func (r *Registry) Register(tool Tool) { r.tools[tool.Name()] = tool } +// Unregister removes a tool from the registry by name. +func (r *Registry) Unregister(name string) { + delete(r.tools, name) +} + +// Has checks if a tool with the given name is registered. +func (r *Registry) Has(name string) bool { + _, ok := r.tools[name] + return ok +} + +// RegisterBash adds the bash tool to the registry. +func (r *Registry) RegisterBash() { + r.Register(&BashTool{}) +} + // Get retrieves a tool by name. func (r *Registry) Get(name string) (Tool, bool) { tool, ok := r.tools[name] diff --git a/x/tools/registry_test.go b/x/tools/registry_test.go index b65ce0047..959b3d542 100644 --- a/x/tools/registry_test.go +++ b/x/tools/registry_test.go @@ -177,3 +177,47 @@ func TestWebSearchTool_Schema(t *testing.T) { t.Error("expected 'query' property in schema") } } + +func TestRegistry_Unregister(t *testing.T) { + r := NewRegistry() + r.Register(&BashTool{}) + + if r.Count() != 1 { + t.Errorf("expected 1 tool, got %d", r.Count()) + } + + r.Unregister("bash") + + if r.Count() != 0 { + t.Errorf("expected 0 tools after unregister, got %d", r.Count()) + } + + _, ok := r.Get("bash") + if ok { + t.Error("expected bash tool to be removed") + } +} + +func TestRegistry_Has(t *testing.T) { + r := NewRegistry() + + if r.Has("bash") { + t.Error("expected Has to return false for unregistered tool") + } + + r.Register(&BashTool{}) + + if !r.Has("bash") { + t.Error("expected Has to return true for registered tool") + } +} + +func TestRegistry_RegisterBash(t *testing.T) { + r := NewRegistry() + + r.RegisterBash() + + if !r.Has("bash") { + t.Error("expected bash tool to be registered") + } +}