diff options
Diffstat (limited to 'lua/99')
| -rw-r--r-- | lua/99/ops/make-prompt.lua | 18 | ||||
| -rw-r--r-- | lua/99/ops/over-range.lua | 23 | ||||
| -rw-r--r-- | lua/99/prompt-settings.lua | 29 | ||||
| -rw-r--r-- | lua/99/prompt.lua | 21 | ||||
| -rw-r--r-- | lua/99/providers.lua | 147 |
5 files changed, 109 insertions, 129 deletions
diff --git a/lua/99/ops/make-prompt.lua b/lua/99/ops/make-prompt.lua index f60904b..cd19dcd 100644 --- a/lua/99/ops/make-prompt.lua +++ b/lua/99/ops/make-prompt.lua @@ -4,7 +4,7 @@ local Agents = require("99.extensions.agents") --- @param context _99.Prompt --- @param prompt string --- @param opts _99.ops.Opts ---- @return string, _99.Reference[] +--- @return string return function(context, prompt, opts) local user_prompt @@ -19,20 +19,6 @@ return function(context, prompt, opts) end local full_prompt = prompt - full_prompt = context._99.prompts.prompts.prompt(user_prompt, full_prompt) - local refs = Completions.parse(user_prompt) - local additional_rules = opts.additional_rules - if additional_rules then - for _, r in ipairs(additional_rules) do - local content = Agents.get_rule_content(r) - if content then - table.insert(refs, { - content = content, - }) - end - end - end - - return full_prompt, refs + return full_prompt end diff --git a/lua/99/ops/over-range.lua b/lua/99/ops/over-range.lua index 0562a7d..c1fca2a 100644 --- a/lua/99/ops/over-range.lua +++ b/lua/99/ops/over-range.lua @@ -3,6 +3,7 @@ local RequestStatus = require("99.ops.request_status") local Mark = require("99.ops.marks") +local BaseProvider = require("99.providers") local geo = require("99.geo") local make_prompt = require("99.ops.make-prompt") local CleanUp = require("99.ops.clean-up") @@ -48,10 +49,9 @@ local function over_range(context, opts) end) local system_cmd = context._99.prompts.prompts.visual_selection(range) - local prompt, refs = make_prompt(context, system_cmd, opts) + local prompt = make_prompt(context, system_cmd, opts) context:add_prompt_content(prompt) - context:add_references(refs) context:add_clean_up(clean_up) top_status:start() @@ -64,7 +64,7 @@ local function over_range(context, opts) ) elseif status == "failed" then logger:error( - "request failed for visual_selection", + "request failed for visual selection", "error response", response or "no response provided" ) @@ -78,16 +78,27 @@ local function over_range(context, opts) return end - if vim.trim(response) == "" then - print("response was empty, visual replacement aborted") + local dt = + BaseProvider.BareMetalProvider._parse_openai_response( + vim.json.decode(response) + ) --[[ @as _A4.OpenAIResponse ]] + + dt.completion.message.content = + BaseProvider.BareMetalProvider._clean_response( + dt.completion.message.content + ) + + if vim.trim(dt.completion.message.content) == "" then logger:debug( "response was empty, visual replacement aborted" ) return end + context.req_response = dt.completion.message.content + local new_range = Range.from_marks(top_mark, bottom_mark) - local lines = vim.split(response, "\n") + local lines = vim.split(dt.completion.message.content, "\n") --- HACK: i am adding a new line here because above range will add a mark to the line above. --- that way this appears to be added to "the same line" as the visual selection was diff --git a/lua/99/prompt-settings.lua b/lua/99/prompt-settings.lua index c221995..a311d68 100644 --- a/lua/99/prompt-settings.lua +++ b/lua/99/prompt-settings.lua @@ -115,36 +115,13 @@ Always use the temporary file as the place to describe your actions according to </TaskDescription> ]] end, - --- @param prompt string --- @param action string - --- @param name? string defaults to DIRECTIONS --- @return string - prompt = function(prompt, action, name) - name = name or "Prompt" - return string.format( - [[ -<Context> -%s -</Context> -<%s> -%s -</%s> -]], - action, - name, - prompt, - name - ) + prompt = function(action) + return string.format([[%s]], action) end, visual_selection = function(range) - return string.format( - [[ -<SELECTION_CONTENT> -%s -</SELECTION_CONTENT> -]], - range:to_text() - ) + return string.format([[%s]], range:to_text()) end, } diff --git a/lua/99/prompt.lua b/lua/99/prompt.lua index 6623987..347db0d 100644 --- a/lua/99/prompt.lua +++ b/lua/99/prompt.lua @@ -300,8 +300,6 @@ function Prompt:start_request(observer) local ok = self:finalize() l:assert(ok, "context failed to finalize") - --- TODO: create a prompt context class that can actually organize. - --- do not do this during the request context refactoring, but next local prompt = table.concat(self.agent_context, "\n") local obs = self:_observer(observer) local provider = self._99.provider_override @@ -499,18 +497,13 @@ function Prompt:finalize() end self:_read_md_files() - local ok, visual_data = pcall(self.visual_data, self) - if ok then - local f_loc = self._99.prompts.get_file_location( - self.full_path, - visual_data.range - ) - table.insert(self.agent_context, f_loc) - table.insert( - self.agent_context, - self._99.prompts.get_range_text(visual_data.range) - ) - end + --local ok, visual_data = pcall(self.visual_data, self) + --if ok then + -- table.insert( + -- self.agent_context, + -- self._99.prompts.get_range_text(visual_data.range) + -- ) + --end return true, self end diff --git a/lua/99/providers.lua b/lua/99/providers.lua index 8875ca8..63e64aa 100644 --- a/lua/99/providers.lua +++ b/lua/99/providers.lua @@ -1,7 +1,7 @@ --- @class _99.Providers.Observer --- @field on_stdout fun(line: string): nil --- @field on_stderr fun(line: string): nil ---- @field on_complete fun(status: _99.Prompt.EndingState, res: string): nil +--- @field on_complete fun(status: _99.Prompt.EndingState, res: string|table): nil --- @field on_start fun(): nil --- @param fn fun(...: any): nil @@ -62,54 +62,6 @@ end --- @field predictedPerTkMs number --- @field predictedPerSec number ---- @param raw table ---- @return _A4.OpenAIResponse -local function parse_openai_response(raw) - local choice = raw.choices[1] - - --- @type _A4.OpenAIResponse - local response = { - completion = { - finishReason = choice.finish_reason, - index = choice.index, - message = { - role = choice.message.role, - content = choice.message.content, - }, - }, - metadata = { - created = raw.created, - model = raw.model, - systemFingerPrint = raw.system_fingerprint, - object = raw.object, - usage = { - completionTks = raw.usage.completion_tokens, - promptTks = raw.usage.prompt_tokens, - totalTks = raw.usage.total_tokens, - promptTksDetails = { - cachedTks = raw.usage.prompt_tokens_details.cached_tokens, - }, - }, - }, - id = { - id = raw.id, - }, - timings = { - cacheN = raw.timings.cache_n, - promptN = raw.timings.prompt_n, - promptMs = raw.timings.prompt_ms, - promptPerTkMs = raw.timings.prompt_per_token_ms, - promptPerSec = raw.timings.prompt_per_second, - predictedN = raw.timings.predicted_n, - predictedMs = raw.timings.predicted_ms, - predictedPerTkMs = raw.timings.predicted_per_token_ms, - predictedPerSec = raw.timings.predicted_per_second, - }, - } - - return response -end - --- @class _99.Providers.BaseProvider --- @field _build_command fun(self: _99.Providers.BaseProvider, query: string, context: _99.Prompt): string[] --- @field _get_provider_name fun(self: _99.Providers.BaseProvider): string @@ -123,8 +75,8 @@ end --- @param data string --- @return string -function BaseProvider:_clean_response(data) - local _data, _ = data:gsub("```[a-z]*\n", ""):gsub(" ```", "") +function BaseProvider._clean_response(data) + local _data, _ = data:gsub("```[a-z]*\n", ""):gsub("```", "") return _data end @@ -164,9 +116,6 @@ function BaseProvider:_retrieve_response(context) end end --- TODO: Remember that we are ditching the tmp_file; likely 90% --- You can just grab the json data and dump it in logs honestly --- files only make sense for agentic flows --- @param query string --- @param context _99.Prompt --- @param observer _99.Providers.Observer @@ -192,21 +141,25 @@ function BaseProvider:make_request(query, context, observer) command, { text = true }, vim.schedule_wrap(function(obj) - if obj.code ~= 0 then - once_complete("failed", obj.stderr) + logger:debug("exit callback fired", "code", tostring(obj.code)) + logger:debug("schedule_wrap", "stdout", tostring(obj.stdout)) + logger:debug("schedule_wrap", "stderr", tostring(obj.stderr)) + + if context:is_cancelled() then + once_complete("cancelled", "") return end - local data = parse_openai_response(vim.json.decode(obj.stdout)) - if self._get_provider_name == "BareMetalProvider" then - data.completion.message.content = - self:_clean_response(data.completion.message.content) - context.req_response = data.completion.message.content + if obj.code ~= 0 then + once_complete("failed", obj.stderr or "") + return end - once_complete("success", data.completion.message.content) + + once_complete("success", obj.stdout) end) ) + logger:debug("proc spawned", "proc_id", tostring(proc)) context:_set_process(proc) end @@ -400,7 +353,8 @@ function GeminiCLIProvider._get_default_model() end --- @class BareMetalProvider : _99.Providers.BaseProvider ---- @field _clean_response fun(self: _99.Providers.BaseProvider, data : string): string +--- @field _clean_response fun(data : string): string +--- @field _parse_openai_response fun(raw: table): _A4.OpenAIResponse local BareMetalProvider = setmetatable({}, { __index = BaseProvider }) --- @param query string @@ -412,11 +366,22 @@ function BareMetalProvider._build_command(_, query, context) "-s", context.endpoint, "-H", - '"Content-Type: applications/json"', + "Content-Type: application/json", "-d", - '"{"messages":[{"role":"system","content":"You are a strict code completion backend for Neovim. Your input will be a code snippet, function signature, or a comment requesting code. CRITICAL DIRECTIONS: 1. Output ONLY valid, executable programming code. 2. Do NOT wrap your response in markdown code blocks. 3. Do NOT include any conversational filler, explanations, greetings, or sign-offs. 4. If you cannot fulfill the request, output nothing or a code comment explaining why."},{"role":"user","content":"' - .. query - .. '"}],"temperature":0.0,"stream":false}"', + vim.json.encode({ + messages = { + { + role = "system", + content = "You are a strict code completion backend for Neovim. Your input will be a code snippet, function signature, or a comment requesting code. CRITICAL DIRECTIONS: 1. Output ONLY valid, executable programming code. 2. Do NOT wrap your response in markdown code blocks. 3. Do NOT include any conversational filler, explanations, greetings, or sign-offs. 4. If you cannot fulfill the request, output nothing or a code comment explaining why.", + }, + { + role = "user", + content = query, + }, + }, + temperature = 0.0, + stream = false, + }), } end @@ -436,6 +401,54 @@ function BareMetalProvider.fetch_models(callback) }, nil) end +--- @param raw table +--- @return _A4.OpenAIResponse +function BareMetalProvider._parse_openai_response(raw) + local choice = raw.choices[1] + + --- @type _A4.OpenAIResponse + local response = { + completion = { + finishReason = choice.finish_reason, + index = choice.index, + message = { + role = choice.message.role, + content = choice.message.content, + }, + }, + metadata = { + created = raw.created, + model = raw.model, + systemFingerPrint = raw.system_fingerprint, + object = raw.object, + usage = { + completionTks = raw.usage.completion_tokens, + promptTks = raw.usage.prompt_tokens, + totalTks = raw.usage.total_tokens, + promptTksDetails = { + cachedTks = raw.usage.prompt_tokens_details.cached_tokens, + }, + }, + }, + id = { + id = raw.id, + }, + timings = { + cacheN = raw.timings.cache_n, + promptN = raw.timings.prompt_n, + promptMs = raw.timings.prompt_ms, + promptPerTkMs = raw.timings.prompt_per_token_ms, + promptPerSec = raw.timings.prompt_per_second, + predictedN = raw.timings.predicted_n, + predictedMs = raw.timings.predicted_ms, + predictedPerTkMs = raw.timings.predicted_per_token_ms, + predictedPerSec = raw.timings.predicted_per_second, + }, + } + + return response +end + return { BaseProvider = BaseProvider, OpenCodeProvider = OpenCodeProvider, |
