nomnivore / ollama.nvim

A plugin for managing and integrating your ollama workflows in neovim.
MIT License
311 stars 22 forks source link

implemented display_prompt action #8

Closed gerazov closed 7 months ago

gerazov commented 7 months ago

It can be useful to have the prompt displayed in the floating window as well, e.g. for the Raw input, but also can give a sense of the exact prompt that is used to query the LLM. To this end I'v added a display_prompt action that is a bit more involved than making a custom action - it needs the parsed_prompt as input, and the show_spinner needs to be modified as well.

Here it is in action:

ollama display prompt

gerazov commented 7 months ago

Here's how it looks for code:

ollama code

nomnivore commented 7 months ago

For greater flexibility, would it be better if the util.show_spinner method allowed for full customization of all text around the spinner itself? Accepting a table with pre and post keys.

E.g. to achieve current functionality (prior to this PR) you would do something like:

local timer = require("ollama.util").show_spinner(bufnr, { pre = "Generating... " })

Then for an action to display the prompt as its created, you could do something like:

show_spinner(bufnr, { pre = parsed_prompt .. "\nGenerating... " })

post key would be an optional string just like pre in case, for instance, someone wanted an action that displayed the spinner during the entire generation task - instead of just before the first streamed token.

gerazov commented 7 months ago

That makes sense - it would be cool to know when the generation process has ended. I was also thinking that after it's done the > Generating ... could turn into > model_name so it visibly splits the prompt from the output. But then we're going towards chat :slightly_smiling_face:

btw I put the > in Generating so it's formatted nicely - it's more visible at least in catpuccin.

Feel free to shape it as you will - I implemented it because I needed it to be able to copy and save/edit my prompts :wink:

nomnivore commented 7 months ago

In what other context do you need to know when generation has ended? The ollama API sends a done property in its final response - you can see it being used in other actions.

nomnivore commented 7 months ago

Thinking on it, it might be better if show_spinner is (optionally) given a line number to display the spinner on, instead of rewriting the entire buffer on each loop. I'll fuss around with it and see what I come up with.

gerazov commented 7 months ago

Looks good :love_you_gesture: - maybe have the model name when it's done (even generating?), like: > zephyr in X s

nomnivore commented 7 months ago

The model name is already in the floating window's title, so I don't think it needs that.

The last thing keeping me from merging this at this point is I'm not sure we should extend the list of built-in actions too much. This seems like a more specific-use case (vs the generalized display, insert/replace, and previews). I wanted to set it up so that users could craft their own highly specialized actions that do exactly what they want.

So what now:

I would highly value your input on this as a user and contributor of the plugin, @gerazov. Let me know what you think!

gerazov commented 7 months ago

First the important thing - displaying the prompt is a necessary feature that is currently lacking.

  1. It allows users to see the prompt, which is great especially for complex prompts involving selected text/code.
  2. It allows users to copy the interaction and keep it for reference - that's why it's important to have > modelname leading the response.

On increasing the complexity of the code - the actions can really be optimized into one function that displays if needed and includes the prompt in the display if chosen. Because I would have _prompt work with display_replace too.

About the roadmap. To tell you the truth I'm leaning even more away from specialized prompts. Currently I have 18 prompts - 12 for text which I forward to a general language model and 6 for code which I forward to codellama. And at some point it get's hard to remember what exact prompt each of them spawns - any input you have to enter is in a blank input field.

As a user I wouldn't mind having to type a bit of extra words to use less prompts - so in other words fewer generic prompts that you can use for anything you like, and they should be built around the $sel, $ftype and $buf - and one set for text another for code:

  1. just user input
  2. user input + selection
  3. user input + selection + buffer for context

Another thing that's currently a problem is that there is no way to iterate on the response, i.e. you can't modify the prompt if you don't like the output. Without the display_prompt you don't even get to see/copy the prompt you've typed :smile:

And keeping the model name there before the response would make it easy to copy paste the prompt and response for reference. Plus visually it separates the two nicely - if you have a large prompt that includes text/code.

The optimal workflow would be:

  1. to have a pop-up or a split window, or even better a dedicated LLM tab (based on opts)
  2. be able to input/modify the prompt directly in the pop-up (so it should be modifiable) - in these terms the hard coded prompts would be like prompt snippets where the user can <Tab> between different parts and be able to modify them
  3. on a key stroke - the finished prompt is sent to the LLM and there is a > model name leading the response
  4. after this the user can re-edit the prompt in the same window and re-send the modified version to the LLM (with the same key stroke) - this something that can be easily done in the web UIs.

One step ahead of this would be a full on chat where the user can follow a response with another prompt in the same popup window and the previous answers get transferred as context (if needed - currently no context is kept between calls to the api no?)

I ramble. Hope it helps :+1:

nomnivore commented 7 months ago

Good call on reducing the actions into a single configurable base action. As a side effect of that, creating a sort of action 'factory' to achieve this might make it easier for users to tune things with less effort/custom code required.

I also really appreciate you sharing your experiences and workflows. I'm not yet sure how I would implement certain features of your 'optimal workflow' as I'm still fairly new to the neovim APIs, but I will keep it in mind as I continue to R&D.

On the more generic prompts - this was actually my intent with the default prompts: have a small handful of generalized prompts for most tasks, and let users extend the list with their own specialized ones. I admit there's a lot to be improved there. Feel free to open an issue or PR if you have more ideas on that.

In the meantime, I'll update & finally merge this PR with the model name leading the response as you suggested, and then I'll work on refactoring the actions to be less verbose in code.

gerazov commented 7 months ago

Awesome :love_you_gesture: keep up the good work :rocket: