89 lines
2.6 KiB
Cheetah
89 lines
2.6 KiB
Cheetah
// Package tools holds the plugin's chat tools.
|
|
package tools
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
|
|
"[[.SDKModule]]/pluginsdk"
|
|
)
|
|
|
|
// All returns every chat tool. Each is also listed in plugin.json.
|
|
func All() []pluginsdk.Tool {
|
|
return []pluginsdk.Tool{countLines, saveSummary}
|
|
}
|
|
|
|
var pathParam = map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"path": map[string]any{"type": "string", "description": "The text file, as the user named it."},
|
|
},
|
|
"required": []string{"path"},
|
|
}
|
|
|
|
var countLines = pluginsdk.Tool{
|
|
Name: "[[.Short]]_count_lines",
|
|
Description: "Count the lines in a text file. Use when the user asks how long a text file is. Returns the line count.",
|
|
Parameters: pathParam,
|
|
Run: func(ctx context.Context, h *pluginsdk.Host, call pluginsdk.ToolCall) pluginsdk.ToolResult {
|
|
path, lines, err := count(ctx, h, call)
|
|
if err != nil {
|
|
return pluginsdk.Fail("%v", err)
|
|
}
|
|
return pluginsdk.Text("%s has %d lines.", path, lines)
|
|
},
|
|
}
|
|
|
|
var saveSummary = pluginsdk.Tool{
|
|
Name: "[[.Short]]_save_summary",
|
|
Description: "Save a one-line summary (the line count) next to a text file, as <file>.summary.txt. Use only when the user asks to save it.",
|
|
Parameters: pathParam,
|
|
Mutating: true,
|
|
Run: func(ctx context.Context, h *pluginsdk.Host, call pluginsdk.ToolCall) pluginsdk.ToolResult {
|
|
path, lines, err := count(ctx, h, call)
|
|
if err != nil {
|
|
return pluginsdk.Fail("%v", err)
|
|
}
|
|
out := path + ".summary.txt"
|
|
allowed, err := h.CanWrite(ctx, out)
|
|
if err != nil {
|
|
return pluginsdk.Fail("%v", err)
|
|
}
|
|
if !allowed || !call.EditMode {
|
|
return pluginsdk.Fail("Cletus doesn't allow edits in this folder. Ask the user to allow edits, then try again.")
|
|
}
|
|
if err := os.WriteFile(out, []byte(fmt.Sprintf("%d lines\n", lines)), 0o644); err != nil {
|
|
return pluginsdk.Fail("Couldn't save the summary: %v", err)
|
|
}
|
|
return pluginsdk.Text("Saved %s.", out)
|
|
},
|
|
}
|
|
|
|
// count resolves the path through the host and counts its lines.
|
|
func count(ctx context.Context, h *pluginsdk.Host, call pluginsdk.ToolCall) (string, int, error) {
|
|
var args struct {
|
|
Path string `json:"path"`
|
|
}
|
|
if err := call.Decode(&args); err != nil {
|
|
return "", 0, err
|
|
}
|
|
if args.Path == "" {
|
|
return "", 0, fmt.Errorf("give the path of a text file")
|
|
}
|
|
path, err := h.ResolvePath(ctx, args.Path)
|
|
if err != nil {
|
|
return "", 0, err
|
|
}
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return "", 0, fmt.Errorf("couldn't read %s: %v", args.Path, err)
|
|
}
|
|
lines := bytes.Count(data, []byte("\n"))
|
|
if len(data) > 0 && data[len(data)-1] != '\n' {
|
|
lines++
|
|
}
|
|
return path, lines, nil
|
|
}
|