claudetool: accept relative paths in patch tool
diff --git a/claudetool/patch.go b/claudetool/patch.go
index b40396a..b2b5db6 100644
--- a/claudetool/patch.go
+++ b/claudetool/patch.go
@@ -28,6 +28,8 @@
// PatchTool specifies an llm.Tool for patching files.
type PatchTool struct {
Callback PatchCallback // may be nil
+ // Pwd is the working directory for resolving relative paths
+ Pwd string
}
// Tool returns an llm.Tool based on p.
@@ -38,7 +40,7 @@
InputSchema: llm.MustSchema(PatchInputSchema),
Run: func(ctx context.Context, m json.RawMessage) llm.ToolOut {
var input PatchInput
- output := patchRun(ctx, m, &input)
+ output := p.patchRun(ctx, m, &input)
if p.Callback != nil {
return p.Callback(input, output)
}
@@ -71,7 +73,7 @@
"properties": {
"path": {
"type": "string",
- "description": "Absolute path to the file to patch"
+ "description": "Path to the file to patch"
},
"patches": {
"type": "array",
@@ -118,15 +120,19 @@
// patchRun implements the guts of the patch tool.
// It populates input from m.
-func patchRun(ctx context.Context, m json.RawMessage, input *PatchInput) llm.ToolOut {
+func (p *PatchTool) patchRun(ctx context.Context, m json.RawMessage, input *PatchInput) llm.ToolOut {
if err := json.Unmarshal(m, &input); err != nil {
return llm.ErrorfToolOut("failed to unmarshal user_patch input: %w", err)
}
- // Validate the input
+ path := input.Path
if !filepath.IsAbs(input.Path) {
- return llm.ErrorfToolOut("path %q is not absolute", input.Path)
+ if p.Pwd == "" {
+ return llm.ErrorfToolOut("path %q is not absolute and no working directory is set", input.Path)
+ }
+ path = filepath.Join(p.Pwd, input.Path)
}
+ input.Path = path
if len(input.Patches) == 0 {
return llm.ErrorToolOut(fmt.Errorf("no patches provided"))
}