Skip to content

fix: Looks like model does not get errors #20

@alexzk1

Description

@alexzk1

Bug Description

I made custom extension (AI wrote it when I asked advice by reading your sources :D )
Problem is, AI does not understand tool is blocked, I guess it does not see error message:
Image

//go:build ignore

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"kit/ext"
)

// Init sets up the read-only enforcement and adds safe tools.
func Init(api ext.API) {
	api.OnToolCall(func(tc ext.ToolCallEvent, ctx ext.Context) *ext.ToolCallResult {
		// 1. BAN BASH
		if tc.ToolName == "bash" {
			return &ext.ToolCallResult{
				Block:  true,
				Reason: "The 'bash' tool is banned in read-only mode for security.",
			}
		}

		// 2. RESTRICT FILE ACCESS (read, write, edit)
		if tc.ToolName == "read" || tc.ToolName == "write" || tc.ToolName == "edit" {
			var input struct {
				Path string `json:"path"`
			}
			// Try to unmarshal the path from various potential JSON structures
			// edit tool has 'path' at top level, write also.
			if err := json.Unmarshal([]byte(tc.Input), &input); err != nil {
				// If it fails (e.g., if input is not a simple object with 'path'), 
				// we might be looking at an edit tool in multi-mode or something else.
				// But usually, the path is required and present.
			}

			if input.Path != "" {
				absInputPath, err := filepath.Abs(input.Path)
				if err == nil {
					tempDir := os.TempDir() // Usually /tmp on Linux
					rel, relErr := filepath.Rel(tempDir, absInputPath)
					isInsideTmp := relErr == nil && !strings.HasPrefix(rel, "..")

					// If it's write or edit, enforce tmp directory restriction
					if tc.ToolName == "write" || tc.ToolName == "edit" {
						if !isInsideTmp {
							return &ext.ToolCallResult{
								Block:  true,
								Reason: fmt.Sprintf("File access restricted. You can only write/edit files inside %s (requested: %s)", tempDir, input.Path),
							}
						}
					}
				}
			}
		}

		return nil // Allow other tools (like ls, grep, find)
	})

	// 3. ADD SAFE ALTERNATIVE TO BASH/LS (e.g., a python-based or native list_dir)
	api.RegisterTool(ext.ToolDef{
		Name:        "list_files",
		Description: "List files in a directory safely without using bash.",
		Parameters:  `{"type":"object","properties":{"directory":{"type":"string","description":"Path to the directory"}},"required":["directory"]}`,
		Execute: func(input string) (string, error) {
			var args struct {
				Directory string `json:"directory"`
			}
			if err := json.Unmarshal([]byte(input), &args); err != nil {
				return "", fmt.Errorf("invalid input: %w", err)
			}

			entries, err := os.ReadDir(args.Directory)
			if err != nil {
				return "", fmt.Errorf("failed to list directory: %v", err)
			}

			var sb strings.Builder
			sb.WriteString(fmt.Sprintf("Contents of %s:\n", args.Directory))
			for _, e := range entries {
				typeStr := ""
				if e.IsDir() {
					typeStr = "/"
				}
				sb.WriteString(fmt.Sprintf("- %s%s\n", typeStr, e.Name()))
			}
			return sb.String(), nil
		},
	})
}

Steps to Reproduce

1. Save attached extension.
2. Use attached extension.
3. Ask AI to execute bash.

Relevant Code / Configuration

Affected Component

No response

Kit Version

No response

Additional Context

No response

Checklist

  • I've searched existing issues and this hasn't been reported yet
  • I've tested with the latest version of Kit

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions