x: request access for all commands, add welcome message (#13662)

This commit is contained in:
Parth Sareen
2026-01-09 18:20:39 -08:00
committed by GitHub
parent 68fafd3002
commit 1ef4241727
5 changed files with 77 additions and 13 deletions

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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")
}
}