Rubberduck comes with handy built-in commands, such as Explain Code, Edit Code, Generate Tests, etc.
But what if you have a specific need that isn't entirely covered? What if you want to craft an AI Chat that knows specifically about your project or your conventions? How cool would it be to have the answers in your language?
That's what you can get with Rubberduck Templates! 🌈
Here are some ideas of what you can do with them:
- Have conversations in a different language, e.g., in French
- Let Shakespeare write a sonnet about your code
- Define dedicated tasks, e.g., improving code readability
- Create project, language, or framework-specific templates
The best part is that you can share them with your colleagues, friends, or enemies.
Add Rubberduck Template File (.rdt.md
) files to the .rubberduck/template
folder in your workspace. See the templates in the Rubberduck repository for examples.
Run the "Rubberduck: Start Custom Chat… 💬" command to use your custom conversations.
After you have changed a template, use the "Rubberduck: Reload Templates" command to see your updates.
To help you debug, use the "Rubberduck: Show logs" command to open the Output panel and see the prompt that is sent to OpenAI.
The "Drunken Pirate" template will expose a new custom conversation: Ask a drunken pirate to describe your code.
To see it in action:
- Save the template as
.rubberduck/template/drunken-pirate.rdt.md
in your workspace - Use "Rubberduck: Reload Templates"
- Use "Rubberduck: Start Custom Chat… 💬"
- Pick "Ask a drunken pirate"
This template is a conversation between a developer and a drunken pirate. The drunken pirate starts by describing the selected code.
Want to craft your own? Let's dig into how Rubberduck Templates are structured.
Rubberduck Templates are GitHub-flavored Markdown files with special fenced code sections. You can use regular markdown to document your template and the fenced code sections to define it.
There are two types of fenced code sections:
- the
json conversation-template
configuration section - the
template-initial-message
andtemplate-response
prompt template sections
The configuration section is a JSON object that defines the template. It is a fenced code block with the language json conversation-template
:
```json conversation-template { "id": "drunken-pirate", "engineVersion": 0, "label": "Ask a drunken pirate", "description": "Ask a drunken pirate about the meaning of your code", "tags": ["fun"], "header": { "title": "Drunken Pirate ({{location}})", "icon": { "type": "codicon", "value": "feedback" } }, … } ```
Configuration sections have the following basic properties:
id
: Id of the conversation type. It needs to be unique.engineVersion
: Must be 0 for now. Warning: we might make breaking changes to the template format while we are on version 0.label
: Short description of the conversation type. It will be displayed when you run the "Rubberduck: Start Custom Chat… 💬" command.description
: Longer description of the conversation type. It will be displayed when you run the "Rubberduck: Start Custom Chat… 💬" command.tags
: An optional list of tags that can be used to filter the conversation types in the "Rubberduck: Start Custom Chat… 💬" command. Defaults to[]
.header
: The header that is shown in the Rubberduck side panel for conversations of this type. It has 3 properties:title
: The title of the conversation. It will be shown in the Rubberduck side panel. You can use template variables here with{{variableName}}
.useFirstMessageAsTitle
: An optional boolean value. Defaults tofalse
. If it istrue
, the first message of the conversation will be used as the title once there is a message.icon
: The icon that is shown in the Rubberduck side panel for conversations of this type. Only the Codicontype
is supported at the moment. You can set thevalue
property to the codicon that you want to show.
isEnabled
: Whether the conversation type is enabled. If it is disabled, it will not be shown in the "Rubberduck: Start Custom Chat… 💬" command. Defaults totrue
.chatInterface
: Optional. The chat interface that is used for this conversation type. Defaults tomessage-exchange
. Set toinstruction-refinement
if you want to show a single edit box that the user can change instead of a message exchange.
Variables are values that you can expand in the header title and in the prompt templates using the {{variableName}}
syntax. Here is an example:
… "variables": [ { "name": "selectedText", "type": "selected-text", "constraints": [{ "type": "text-length", "min": 1 }] }, { "name": "location", "type": "selected-location-text" }, { "name": "lastMessage", "type": "message", "property": "content", "index": -1 }, { "name": "botRole", "type": "constant", "value": "drunken pirate" } ], …
They are defined in the variables
property of the configuration section. The property contains an array of variable definitions. There are the following kinds of variables:
- Selected text (
type: selected-text
): The currently selected text in the active editor. The resolutiontime
isconversation-start
ormessage
. - Selected text with diagnostics (
type: selected-text-with-diagnostics
): The currently selected text in the active editor, with diagnostics. The resolutiontime
isconversation-start
. Theseverities
property contains an array of the included severities (possible values:error
,warning
,information
,hint
). - Constants (
type: constant
): A constant value that is always the same. You can use it to extract common parts from your templates, e.g. the bot role, and tweak it quickly to explore different responses while you are developing the template. Thetime
property needs to be set toconversation-start
. - Message: (
type: message
): Get properties of a message at an index. Only the message content (property: content
) is supported at the moment. You can e.g. use it to access the first (index 0) or the last (index -1) message of the conversation. Thetime
property needs to be set tomessage
. - Language (
type: language
): The language of the active editor. The resolutiontime
can beconversation-start
. - Filename (
type: filename
): The name of the active editor. The resolutiontime
can beconversation-start
. - Location of the selected text (
type: selected-location-text
): The filename and the start/end lines of the selection. This is useful for including in the header title. The resolutiontime
can beconversation-start
.
The time
property defines when the variable is resolved. It can be one of the following values (it depends on the variable type which values are supported):
conversation-start
: The variable is resolved when the conversation is started. It is not resolved again when the user sends a message.message
: The variable is resolved when the user sends a message.
You can also add constraints to the variables. Right now only a minimal text length constraint is available (type: text-length
). It is useful to make sure that the user has selected some text before starting the conversation. If the constraint is not met, an error popup is shown and the conversation will not be started.
In addition to user-defined variables, there are some predefined variables that are always available:
- Messages: The messages of the conversation. It is an array of messages. Each message has an
author
property (eitheruser
orbot
) and acontent
property.
There are two properties where you can define the prompts for the conversation:
initialMessage
: The initial message that is sent by the bot. It is optional. If it is not defined, the conversation starts with a user message.response
: The response that is sent by the bot after the user message.
Example:
… "initialMessage": { "placeholder": "Drinking rum", "maxTokens": 512, "temperature": 0.8 }, "response": { "maxTokens": 1024, "stop": ["Drunken Pirate:", "Developer:"], "temperature": 0.7 }
Prompts describe how a user message in a chat (or the initial analysis) is processed. The prompt definitions contain parameters for a call to the OpenAI API and additional properties. Rubberduck calls the OpenAI Completion API with the text-davinci-003
model.
placeholder
: The placeholder text that is shown in the chat while the message is being processed.maxTokens
: Upper bound on how many tokens will be returned.stop
: Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. Optional.temperature
: The randomness of the model. Higher values will make the model more random, lower values will make it more predictable. Optional, defaults to 0.completionHandler
: Defines how the completion result is handled. There are currently 2 handlers: "message" (default) and "update-temporary-editor".message
: The completion result is added as a new message to the chat."completionHandler": { "type": "message" }
update-temporary-editor
: The completion result is shown in a temporary editor. The handle has abotMessage
property for the message that is shown in the chat, and an optional 'language' template property that can be used to the the VS Code language id of the temporary editor."completionHandler": { "type": "update-temporary-editor", "botMessage": "Test generated.", "language": "typescript" }
active-editor-diff
: The completion result is shown in a diff editor. It requires an active editor with a selection. The selection at the conversation start will be diffed against the completion result."completionHandler": { "type": "active-editor-diff" }
The prompt templates are defined in fenced code sections with the language info template-initial-message
and template-response
. The name must match the prompt definition, i.e. for initialMessage
you need to define a template-initial-message
section, and for response
you need to define a template-response
section.
They use the Handlebars templating language. Variables that you have defined can be expanded using the {{variableName}}
syntax.
There are a few additional extensions to Handlebars:
- \`\`\` is replaced with ``` in the template. This is useful to create markdown code snippets section in the template.
eq
,neq
,lt
,gt
,lte
,gte
are added as comparison operators. They can be used to create if statements in the template.
Example:
```template-analysis ## Instructions You are a {{botRole}}. Describe the code below. ## Selected Code \`\`\` {{selectedText}} \`\`\` ## Task You are a {{botRole}}. Describe the code. You pirate speak and refer to sailing and the sea where possible. ## Description ```
The easiest way to get started with templates is to copy some example templates and start modifying them.
Run the "Rubberduck: Start Custom Chat… 💬" command to use your custom conversations.
After you have changed a Rubberduck template, use the "Rubberduck: Reload Templates" command to see your updates.
To help you debug, use the "Rubberduck: Show logs" command to open the Output panel and see the prompt that is sent to OpenAI.