mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-14 03:30:26 +00:00
c94edc929b
Thread ToolCallID, ToolKind, ParsedArgs, FileDiff metadata, StopReason, SessionID, and StructuredMessages across the SDK event bus, extension wrapper, app bridge, hooks, and ACP server layers. - Gap 1: ToolCallID from Fantasy's ToolCallContent threaded end-to-end - Gap 2: ToolKind via static lookup (execute/edit/read/search/agent) - Gap 3+4: FileDiffInfo with DiffBlocks via fantasy.ToolResponse.Metadata - Gap 5: StopReason from Fantasy FinishReason on TurnEndEvent/TurnResult - Gap 6: Subagent sessions now opt-out (NoSession); SessionID in JSON output - Gap 7: GetStructuredMessages() returns typed ContentParts - Gap 8: ParsedArgs map[string]any on tool events for convenience Edit/write tools attach structured diff metadata. ACP server uses real ToolCallIDs. Extension and SDK events kept in sync with matching fields.
99 lines
2.9 KiB
Go
99 lines
2.9 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"charm.land/fantasy"
|
|
)
|
|
|
|
type writeArgs struct {
|
|
Path string `json:"path"`
|
|
Content string `json:"content"`
|
|
}
|
|
|
|
// NewWriteTool creates the write core tool.
|
|
func NewWriteTool(opts ...ToolOption) fantasy.AgentTool {
|
|
cfg := ApplyOptions(opts)
|
|
return &coreTool{
|
|
info: fantasy.ToolInfo{
|
|
Name: "write",
|
|
Description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
|
|
Parameters: map[string]any{
|
|
"path": map[string]any{
|
|
"type": "string",
|
|
"description": "Path to the file to write (relative or absolute)",
|
|
},
|
|
"content": map[string]any{
|
|
"type": "string",
|
|
"description": "Content to write to the file",
|
|
},
|
|
},
|
|
Required: []string{"path", "content"},
|
|
},
|
|
handler: func(ctx context.Context, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
|
|
return executeWrite(ctx, call, cfg.WorkDir)
|
|
},
|
|
}
|
|
}
|
|
|
|
func executeWrite(ctx context.Context, call fantasy.ToolCall, workDir string) (fantasy.ToolResponse, error) {
|
|
var args writeArgs
|
|
if err := parseArgs(call.Input, &args); err != nil {
|
|
return fantasy.NewTextErrorResponse("path and content parameters are required"), nil
|
|
}
|
|
if args.Path == "" {
|
|
return fantasy.NewTextErrorResponse("path parameter is required"), nil
|
|
}
|
|
|
|
absPath, err := resolvePathWithWorkDir(args.Path, workDir)
|
|
if err != nil {
|
|
return fantasy.NewTextErrorResponse(fmt.Sprintf("invalid path: %v", err)), nil
|
|
}
|
|
|
|
// Read existing content before writing (for diff metadata).
|
|
var beforeContent string
|
|
isNew := true
|
|
if existing, readErr := os.ReadFile(absPath); readErr == nil {
|
|
beforeContent = string(existing)
|
|
isNew = false
|
|
}
|
|
|
|
// Create parent directories
|
|
dir := filepath.Dir(absPath)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return fantasy.NewTextErrorResponse(fmt.Sprintf("failed to create directories: %v", err)), nil
|
|
}
|
|
|
|
if err := os.WriteFile(absPath, []byte(args.Content), 0644); err != nil {
|
|
return fantasy.NewTextErrorResponse(fmt.Sprintf("failed to write file: %v", err)), nil
|
|
}
|
|
|
|
resp := fantasy.NewTextResponse(fmt.Sprintf("Wrote %d bytes to %s", len(args.Content), args.Path))
|
|
return fantasy.WithResponseMetadata(resp, writeDiffMeta(absPath, beforeContent, args.Content, isNew)), nil
|
|
}
|
|
|
|
// writeDiffMeta builds the structured metadata attached to write tool responses.
|
|
func writeDiffMeta(path, beforeContent, afterContent string, isNew bool) map[string]any {
|
|
additions := strings.Count(afterContent, "\n") + 1
|
|
deletions := 0
|
|
if !isNew {
|
|
deletions = strings.Count(beforeContent, "\n") + 1
|
|
}
|
|
return map[string]any{
|
|
"file_diffs": []map[string]any{{
|
|
"path": path,
|
|
"additions": additions,
|
|
"deletions": deletions,
|
|
"is_new": isNew,
|
|
"diff_blocks": []map[string]any{{
|
|
"old_text": beforeContent,
|
|
"new_text": afterContent,
|
|
}},
|
|
}},
|
|
}
|
|
}
|