-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathCreateFileTool.swift
More file actions
101 lines (88 loc) · 3.75 KB
/
CreateFileTool.swift
File metadata and controls
101 lines (88 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import JSONRPC
import AppKit
import ConversationServiceProvider
import Foundation
import Logger
public class CreateFileTool: ICopilotTool {
public static let name = ToolName.createFile
public func invokeTool(
_ request: InvokeClientToolRequest,
completion: @escaping (AnyJSONRPCResponse) -> Void,
chatHistoryUpdater: ChatHistoryUpdater?,
contextProvider: (any ToolContextProvider)?
) -> Bool {
guard let params = request.params,
let input = params.input,
let filePath = input["filePath"]?.value as? String,
let content = input["content"]?.value as? String
else {
completeResponse(request, status: .error, response: "Invalid parameters", completion: completion)
return true
}
let fileURL = URL(fileURLWithPath: filePath)
guard !FileManager.default.fileExists(atPath: filePath)
else {
Logger.client.info("CreateFileTool: File already exists at \(filePath)")
completeResponse(request, status: .error, response: "File already exists at \(filePath)", completion: completion)
return true
}
do {
// Create intermediate directories if they don't exist
let parentDirectory = fileURL.deletingLastPathComponent()
try FileManager.default.createDirectory(at: parentDirectory, withIntermediateDirectories: true, attributes: nil)
try content.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
Logger.client.error("CreateFileTool: Failed to write content to file at \(filePath): \(error)")
completeResponse(request, status: .error, response: "Failed to write content to file: \(error)", completion: completion)
return true
}
guard FileManager.default.fileExists(atPath: filePath),
let writtenContent = try? String(contentsOf: fileURL, encoding: .utf8)
else {
Logger.client.info("CreateFileTool: Failed to verify file creation at \(filePath)")
completeResponse(request, status: .error, response: "Failed to verify file creation.", completion: completion)
return true
}
contextProvider?.updateFileEdits(by: .init(
fileURL: URL(fileURLWithPath: filePath),
originalContent: "",
modifiedContent: writtenContent,
toolName: CreateFileTool.name
))
NSWorkspace.openFileInXcode(fileURL: URL(fileURLWithPath: filePath)) { _, error in
if let error = error {
Logger.client.info("Failed to open file at \(filePath), \(error)")
}
}
let editAgentRounds: [AgentRound] = [
.init(
roundId: params.roundId,
reply: "",
toolCalls: [
.init(
id: params.toolCallId,
name: params.name,
status: .completed,
invokeParams: params
)
]
)
]
if let chatHistoryUpdater {
chatHistoryUpdater(params.turnId, editAgentRounds)
}
completeResponse(
request,
response: "File created at \(filePath).",
completion: completion
)
return true
}
public static func undo(for fileURL: URL) throws {
var isDirectory: ObjCBool = false
guard FileManager.default.fileExists(atPath: fileURL.path, isDirectory: &isDirectory),
!isDirectory.boolValue
else { return }
try FileManager.default.removeItem(at: fileURL)
}
}