diff options
| author | ThePrimeAgain <theprimeagain@theprimeagain.com> | 2025-11-26 09:21:53 -0700 |
|---|---|---|
| committer | ThePrimeAgain <theprimeagain@theprimeagain.com> | 2025-11-26 09:21:53 -0700 |
| commit | 82b05b232f6a8a2f26432a68759633783efb05ab (patch) | |
| tree | 3644a2dba6be9a2832880d076199d7553eac91dd /lua/99/request | |
| parent | f901b32322e22f4cd2bf3c01896cbbcb37fecea8 (diff) | |
| download | a4-82b05b232f6a8a2f26432a68759633783efb05ab.tar.xz a4-82b05b232f6a8a2f26432a68759633783efb05ab.zip | |
fill in the function
Diffstat (limited to 'lua/99/request')
| -rw-r--r-- | lua/99/request/init.lua | 135 | ||||
| -rw-r--r-- | lua/99/request/system-rules.lua | 40 |
2 files changed, 175 insertions, 0 deletions
diff --git a/lua/99/request/init.lua b/lua/99/request/init.lua new file mode 100644 index 0000000..d020caa --- /dev/null +++ b/lua/99/request/init.lua @@ -0,0 +1,135 @@ +local Logger = require("99.logger.logger") +local editor = require("99.editor") +local geo = require("99.geo") +local Point = geo.Point + +--- TODO: some people change their current working directory as they open new +--- directories. if this is still the case in neovim land, then we will need +--- to make the _99_state have the project directory. +--- @return string +local function random_file() + return string.format("%s/tmp/99-%d", vim.uv.cwd(), math.floor(math.random() * 10000)) +end + +--- no, i am not going to use a uuid, in case of collision, call the police +--- @return string +local function get_id() + return tostring(math.floor(math.random() * 100000000)) +end + +--- @alias _99.Request.State "ready" | "calling-model" | "parsing-result" | "updating-file" + +--- @class _99.Request.Opts +--- @field model string +--- @field md_files string[] + +--- @class _99.Request +--- @field query string +--- @field tmp_name string +--- @field state _99.Request.State +--- @field buffer number +--- @field model string +--- @field id string +--- @field mark string +--- @field scopes Scope +--- @field system_prompt string +local Request = {} +Request.__index = Request + +--- @param opts _99.Request.Opts +function Request.new(opts) + assert(opts.model, "you must provide a model for hange requests to work") + + local ts = editor.treesitter + local cursor = Point:from_cursor() + local scopes = ts.function_scopes(cursor) + local buffer = vim.api.nvim_get_current_buf() + + return setmetatable({ + cursor = cursor, + scopes = scopes, + buffer = buffer, + model = opts.model, + tmp_name = random_file(), + id = get_id(), + state = "ready", + mark = "", + }, Request) +end + +function Request:has_scopes() + return self.scopes ~= nil and #self.scopes > 0 +end + +function Request:get_inner_scope() + assert(self:has_scopes(), "you cannot get inner scope if you dont have scopes") + return self.scopes.range[#self.scopes.range] +end + +--- @param prompt string +function Request:set_system_prompt(prompt) + self.system_prompt = prompt +end + +function Request:_retrieve_response() + local success, result = pcall(function() + return vim.fn.readfile(self.tmp_name) + end) + + if not success then + Logger:error("retrieve_results: failed to read file", "tmp_name", self.tmp_name, "error", result) + return false, "" + end + + return true, table.concat(result, "\n") +end + +--- @param res string +function Request:_update_file_with_changes(res) + local mark_pos = vim.api.nvim_buf_get_mark(self.buffer, self.mark) + local mark_point = Point:new(mark_pos[1], mark_pos[2] + 1) + + local ts = editor.treesitter + local scopes = ts.function_scopes(mark_point) + + if not scopes or not scopes:has_scope() then + Logger:error("update_file_with_changes: unable to find function at mark location") + return + end + + local range = scopes.range[#scopes.range] + + local function_start_row, _ = range.start:to_vim() + local function_end_row, _ = range.end_:to_vim() + + local lines = vim.split(res, "\n") + vim.api.nvim_buf_set_lines(self.buffer, function_start_row, function_end_row + 1, false, lines) +end + +function Request:start() + Logger:debug("99#make_query", "id", self.id, "query", self.query) + vim.system({ "opencode", "run", "-m", "anthropic/claude-sonnet-4-5", self.query }, { + text = true, + stdout = vim.schedule_wrap(function(err, data) + Logger:debug("STDOUT#data", "id", self.id, "data", data) + Logger:debug("STDOUT#error", "id", self.id, "err", err) + end), + stderr = vim.schedule_wrap(function(err, data) + Logger:debug("STDERR#data", "id", self.id, "data", data) + Logger:debug("STDERR#error", "id", self.id, "err", err) + end), + }, function(obj) + if obj.code ~= 0 then + Logger:fatal("opencode make_query failed", "request", self, "obj from results", obj) + return + end + vim.schedule(function() + local ok, res = self:_retrieve_response() + if ok then + self:_update_file_with_changes(res) + end + end) + end) +end + +return Request diff --git a/lua/99/request/system-rules.lua b/lua/99/request/system-rules.lua new file mode 100644 index 0000000..b1eaf7b --- /dev/null +++ b/lua/99/request/system-rules.lua @@ -0,0 +1,40 @@ +local _99_settings = { + output_file = "you must NEVER alter the file given. You must provide the desired change to TEMP_FILE. Do NOT inspec the TEMP_FILE. It is for you to write into, never read. TEMP_FILE previous contents do not matter.", + fill_in_function = "fill in the function. dont change the function signature. do not edit anything outside of this function. prioritize using internal functions for work that has already been done. any NOTE's left in the function should be removed but instructions followed", +} + +--- @param tmp_file string +--- @return string +local function system_rules(tmp_file) + return string.format( + "<MustObey>\n%s\n%s\n</MustObey><TEMP_FILE>%s</TEMP_FILE>", + _99_settings.output_file, + _99_settings.fill_in_function, + tmp_file + ) +end + +--- @param buffer number +---@param range Range +---@return string +local function get_file_location(buffer, range) + local full_path = vim.fn.expand("%:p") + return string.format("<Location><File>%s</File><Function>%s</Function></Location>", full_path, range:to_string()) +end + +--- @param range Range +local function get_range_text(range) + return string.format("<FunctionText>%s</FunctionText>", range:to_text()) +end + +--- @param request _99.Request +--- @return string +return function(request) + local range = request:get_inner_scope() + local buffer = request.buffer + return table.concat({ + system_rules(request.tmp_name), + get_file_location(buffer, range), + get_range_text(range), + }) +end |
