summaryrefslogtreecommitdiff
path: root/agent/tools/write.lua
blob: ee1b2aef4e83c9810f0851919e832a45bee07fab (plain)
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
-- Write text to a file, creating parent directories as needed. Keep the
-- description terse because every byte of every tool description rides
-- in the system prompt on every turn.

local std = require("_std")

local tool = {
    name = "std.write",
    description = "Save content to a path. Overwrites existing files; missing parent directories are created automatically.",
    schema = {
        type = "object",
        properties = {
            path = { type = "string", description = "Path to the file (relative or absolute)." },
            content = { type = "string", description = "Exact bytes to write. No newline is added." },
        },
        required = { "path", "content" },
    },
}

tool.handler = function(input)
    local path = input.path
    local content = input.content

    if type(path) ~= "string" or path == "" then
        return "Error: `path` must be a non-empty string."
    end
    if type(content) ~= "string" then
        return "Error: `content` must be a string."
    end

    local parent = std.dirname(path)
    if parent then
        local ok, err = std.mkdir_p_async(parent)
        if not ok then
            return "Error: could not create parent directory " .. parent .. ": " .. tostring(err)
        end
    end

    local open_err, fd = std.fs_open(path, "w", tonumber("644", 8))
    if not fd then
        return "Error: " .. (open_err or ("could not open " .. path .. " for writing"))
    end

    -- A single `fs_write` may short-write; loop until all bytes land.
    local offset = 0
    while offset < #content do
        local werr, n = std.fs_write(fd, content:sub(offset + 1), offset)
        if not n then
            std.fs_close(fd)
            return "Error: write failed: " .. tostring(werr)
        end
        offset = offset + n
    end

    local close_err = std.fs_close(fd)
    if close_err then
        return "Error: close failed: " .. tostring(close_err)
    end

    return string.format("Wrote %d bytes to %s.", #content, path)
end

std.install_renderer(tool.name, function(st)
    local obj = std.decode(st.input)
    return "write " .. tostring(obj and obj.path or "")
end)

return tool