@riotprompt/riotprompt 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitcarve/config.yaml +10 -0
- package/.gitcarve/context/content.md +11 -0
- package/.markdown-doctest-setup.mjs +23 -0
- package/.nvmrc +1 -0
- package/LICENSE +190 -0
- package/README.md +513 -0
- package/dist/builder.cjs +152 -0
- package/dist/builder.cjs.map +1 -0
- package/dist/builder.d.ts +37 -0
- package/dist/builder.js +148 -0
- package/dist/builder.js.map +1 -0
- package/dist/chat.cjs +26 -0
- package/dist/chat.cjs.map +1 -0
- package/dist/chat.d.ts +14 -0
- package/dist/chat.js +21 -0
- package/dist/chat.js.map +1 -0
- package/dist/constants.cjs +34 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.ts +13 -0
- package/dist/constants.js +23 -0
- package/dist/constants.js.map +1 -0
- package/dist/formatter.cjs +139 -0
- package/dist/formatter.cjs.map +1 -0
- package/dist/formatter.d.ts +88 -0
- package/dist/formatter.js +131 -0
- package/dist/formatter.js.map +1 -0
- package/dist/items/content.cjs +14 -0
- package/dist/items/content.cjs.map +1 -0
- package/dist/items/content.d.ts +3 -0
- package/dist/items/content.js +10 -0
- package/dist/items/content.js.map +1 -0
- package/dist/items/context.cjs +13 -0
- package/dist/items/context.cjs.map +1 -0
- package/dist/items/context.d.ts +3 -0
- package/dist/items/context.js +9 -0
- package/dist/items/context.js.map +1 -0
- package/dist/items/instruction.cjs +13 -0
- package/dist/items/instruction.cjs.map +1 -0
- package/dist/items/instruction.d.ts +3 -0
- package/dist/items/instruction.js +9 -0
- package/dist/items/instruction.js.map +1 -0
- package/dist/items/parameters.cjs +53 -0
- package/dist/items/parameters.cjs.map +1 -0
- package/dist/items/parameters.d.ts +5 -0
- package/dist/items/parameters.js +47 -0
- package/dist/items/parameters.js.map +1 -0
- package/dist/items/section.cjs +120 -0
- package/dist/items/section.cjs.map +1 -0
- package/dist/items/section.d.ts +33 -0
- package/dist/items/section.js +115 -0
- package/dist/items/section.js.map +1 -0
- package/dist/items/trait.cjs +13 -0
- package/dist/items/trait.cjs.map +1 -0
- package/dist/items/trait.d.ts +3 -0
- package/dist/items/trait.js +9 -0
- package/dist/items/trait.js.map +1 -0
- package/dist/items/weighted.cjs +27 -0
- package/dist/items/weighted.cjs.map +1 -0
- package/dist/items/weighted.d.ts +24 -0
- package/dist/items/weighted.js +22 -0
- package/dist/items/weighted.js.map +1 -0
- package/dist/loader.cjs +167 -0
- package/dist/loader.cjs.map +1 -0
- package/dist/loader.d.ts +35 -0
- package/dist/loader.js +161 -0
- package/dist/loader.js.map +1 -0
- package/dist/logger.cjs +51 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.ts +11 -0
- package/dist/logger.js +46 -0
- package/dist/logger.js.map +1 -0
- package/dist/override.cjs +109 -0
- package/dist/override.cjs.map +1 -0
- package/dist/override.d.ts +31 -0
- package/dist/override.js +105 -0
- package/dist/override.js.map +1 -0
- package/dist/parse/markdown.cjs +114 -0
- package/dist/parse/markdown.cjs.map +1 -0
- package/dist/parse/markdown.d.ts +3 -0
- package/dist/parse/markdown.js +110 -0
- package/dist/parse/markdown.js.map +1 -0
- package/dist/parse/text.cjs +33 -0
- package/dist/parse/text.cjs.map +1 -0
- package/dist/parse/text.d.ts +3 -0
- package/dist/parse/text.js +29 -0
- package/dist/parse/text.js.map +1 -0
- package/dist/parser.cjs +99 -0
- package/dist/parser.cjs.map +1 -0
- package/dist/parser.d.ts +21 -0
- package/dist/parser.js +75 -0
- package/dist/parser.js.map +1 -0
- package/dist/prompt.cjs +15 -0
- package/dist/prompt.cjs.map +1 -0
- package/dist/prompt.d.ts +16 -0
- package/dist/prompt.js +11 -0
- package/dist/prompt.js.map +1 -0
- package/dist/riotprompt.cjs +1359 -0
- package/dist/riotprompt.cjs.map +1 -0
- package/dist/riotprompt.d.ts +25 -0
- package/dist/riotprompt.js +21 -0
- package/dist/riotprompt.js.map +1 -0
- package/dist/util/general.cjs +52 -0
- package/dist/util/general.cjs.map +1 -0
- package/dist/util/general.d.ts +4 -0
- package/dist/util/general.js +47 -0
- package/dist/util/general.js.map +1 -0
- package/dist/util/markdown.cjs +115 -0
- package/dist/util/markdown.cjs.map +1 -0
- package/dist/util/markdown.d.ts +7 -0
- package/dist/util/markdown.js +111 -0
- package/dist/util/markdown.js.map +1 -0
- package/dist/util/storage.cjs +155 -0
- package/dist/util/storage.cjs.map +1 -0
- package/dist/util/storage.d.ts +32 -0
- package/dist/util/storage.js +132 -0
- package/dist/util/storage.js.map +1 -0
- package/dist/util/text.cjs +42 -0
- package/dist/util/text.cjs.map +1 -0
- package/dist/util/text.d.ts +1 -0
- package/dist/util/text.js +38 -0
- package/dist/util/text.js.map +1 -0
- package/docs/loader.md +237 -0
- package/docs/override.md +323 -0
- package/docs/parser.md +130 -0
- package/eslint.config.mjs +82 -0
- package/nodemon.json +14 -0
- package/package.json +72 -0
- package/vite.config.ts +114 -0
- package/vitest.config.ts +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
# riotprompt
|
|
2
|
+
|
|
3
|
+
A structured prompt engineering library for LLMs - because you have better things to do than worry about prompt formatting.
|
|
4
|
+
|
|
5
|
+
> "I don't wanna hear it, know you're full of sh*t" - Minor Threat
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
- [Why riotprompt?](#why-riotprompt)
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Basic Usage](#basic-usage)
|
|
11
|
+
- [Core Concepts](#core-concepts)
|
|
12
|
+
- [WeightedText](#weightedtext)
|
|
13
|
+
- [Prompt Structure Elements](#prompt-structure-elements)
|
|
14
|
+
- [Sections](#sections)
|
|
15
|
+
- [Advanced Usage](#advanced-usage)
|
|
16
|
+
- [Creating Sections](#creating-sections)
|
|
17
|
+
- [Setting Section and Item Weights](#setting-section-and-item-weights)
|
|
18
|
+
- [Using Parameters for Customization](#using-parameters-for-customization)
|
|
19
|
+
- [Parsing Markdown for Section Creation](#parsing-markdown-for-section-creation)
|
|
20
|
+
- [Overriding Prompt Content](#overriding-prompt-content)
|
|
21
|
+
- [Building Prompts](#building-prompts)
|
|
22
|
+
- [Manipulating Section Contents](#manipulating-section-contents)
|
|
23
|
+
- [Using the riotprompt Loader for File-Based Prompts](#using-the-riotprompt-loader-for-file-based-prompts)
|
|
24
|
+
- [Customizing Format Options](#customizing-format-options)
|
|
25
|
+
- [Model Support](#model-support)
|
|
26
|
+
- [Why the Name?](#why-the-name)
|
|
27
|
+
- [Contributing](#contributing)
|
|
28
|
+
- [License](#license)
|
|
29
|
+
|
|
30
|
+
## Why riotprompt?
|
|
31
|
+
|
|
32
|
+
Tired of spending hours crafting and formatting the perfect LLM prompt? riotprompt provides a structured way to organize your prompts, allowing you to focus on the content rather than the formatting.
|
|
33
|
+
|
|
34
|
+
riotprompt helps you:
|
|
35
|
+
- Organize prompt elements into logical categories (instructions, content, context)
|
|
36
|
+
- Create reusable persona definitions with traits and instructions
|
|
37
|
+
- Group related items into sections
|
|
38
|
+
- Format everything consistently for different LLM models
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install @riotprompt
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Basic Usage
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import { createSection, createPrompt, Formatter, Section, Instruction } from '@riotprompt';
|
|
50
|
+
|
|
51
|
+
// Create a new prompt
|
|
52
|
+
const section: Section<Instruction> = createSection<Instruction>({ title: "Instructions" });
|
|
53
|
+
|
|
54
|
+
// Add instructions
|
|
55
|
+
section.add("Answer in a concise manner");
|
|
56
|
+
section.add("Provide code examples when appropriate");
|
|
57
|
+
|
|
58
|
+
// Verify parts of the output
|
|
59
|
+
console.log('Number of instructions:', section.items.length);
|
|
60
|
+
// Output: Number of instructions: 2
|
|
61
|
+
|
|
62
|
+
// Formatting a Section using Tags
|
|
63
|
+
const formatterTags = Formatter.create();
|
|
64
|
+
const formattedTags = formatterTags.format(section);
|
|
65
|
+
console.log(formattedTags);
|
|
66
|
+
// Output: <Instructions>
|
|
67
|
+
// Answer in a concise manner
|
|
68
|
+
//
|
|
69
|
+
// Provide code examples when appropriate
|
|
70
|
+
// </Instructions>
|
|
71
|
+
|
|
72
|
+
// Formatting a Section using Markdown
|
|
73
|
+
const formatterMarkdown = Formatter.create({ formatOptions: { sectionSeparator: "markdown" }});
|
|
74
|
+
const formattedMarkdown = formatterMarkdown.format(section)
|
|
75
|
+
console.log(formattedMarkdown);
|
|
76
|
+
// Output: # Instructions
|
|
77
|
+
//
|
|
78
|
+
// Answer in a concise manner
|
|
79
|
+
//
|
|
80
|
+
// Provide code examples when appropriate
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Core Concepts
|
|
86
|
+
|
|
87
|
+
riotprompt is built around several key concepts:
|
|
88
|
+
|
|
89
|
+
### WeightedText
|
|
90
|
+
|
|
91
|
+
The base type for all prompt elements. Each element has:
|
|
92
|
+
- `text`: The actual content
|
|
93
|
+
- `weight`: Optional weight value (for potential future ranking/prioritization)
|
|
94
|
+
|
|
95
|
+
### Prompt Structure Elements
|
|
96
|
+
|
|
97
|
+
riotprompt organizes prompts into four main categories:
|
|
98
|
+
|
|
99
|
+
1. **Personas**: Define who the LLM should be
|
|
100
|
+
- `name`: The persona's identifier
|
|
101
|
+
- `traits`: Characteristics the persona should embody (e.g., "You are a developer working on a project who needs to create a commit message")
|
|
102
|
+
- `instructions`: Specific guidance for the persona
|
|
103
|
+
|
|
104
|
+
2. **Instructions**: Tell the LLM how to respond
|
|
105
|
+
- General guidelines for response format, tone, etc.
|
|
106
|
+
|
|
107
|
+
3. **Content**: What the LLM should respond to
|
|
108
|
+
- The actual query or task
|
|
109
|
+
|
|
110
|
+
4. **Context**: Provide background information
|
|
111
|
+
- Additional context that helps the LLM understand the request
|
|
112
|
+
|
|
113
|
+
### Sections
|
|
114
|
+
|
|
115
|
+
Groups related items together:
|
|
116
|
+
- `title`: Section name
|
|
117
|
+
- `items`: Collection of related elements
|
|
118
|
+
|
|
119
|
+
## Advanced Usage
|
|
120
|
+
|
|
121
|
+
### Creating Sections
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
import { createSection, Formatter, Section, Instruction, Context } from '@riotprompt';
|
|
125
|
+
|
|
126
|
+
// Create a section for coding best practices
|
|
127
|
+
const instructions: Section<Instruction> = createSection<Instruction>({ title: "Instructions" });
|
|
128
|
+
instructions.add("Follow DRY (Don't Repeat Yourself) principles");
|
|
129
|
+
instructions.add("Write readable code with clear variable names");
|
|
130
|
+
instructions.add("Add comments for complex logic");
|
|
131
|
+
|
|
132
|
+
const writerPersona: Section<Instruction> = createSection<Instruction>({ title: "Writer Persona" });
|
|
133
|
+
writerPersona.add("You are an amazingly talented writer who is awesome.");
|
|
134
|
+
|
|
135
|
+
const literatureContext: Section<Context> = createSection<Context>({ title: "Literature Context" });
|
|
136
|
+
literatureContext.add("Here is the full text of a really long book.");
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Setting Section and Item Weights
|
|
140
|
+
|
|
141
|
+
riotprompt allows you to assign weights to sections and individual items within those sections. This can be useful for future enhancements where prompt elements might be prioritized or selected based on their weight.
|
|
142
|
+
|
|
143
|
+
You can define `weight` for the section itself and a default `itemWeight` for items added to that section using `SectionOptions`. Additionally, `parameters` can be defined at the section level and will be passed down to items added to that section.
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
import { createSection, Formatter, Section, Instruction } from '@riotprompt';
|
|
147
|
+
|
|
148
|
+
// Create a section with specific weights and parameters
|
|
149
|
+
const weightedSection: Section<Instruction> = createSection<Instruction>({
|
|
150
|
+
title: "Weighted Topics",
|
|
151
|
+
weight: 10, // Weight for the entire section
|
|
152
|
+
itemWeight: 5, // Default weight for items in this section
|
|
153
|
+
parameters: { topic: "advanced" } // Parameters passed to items
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Items added to this section will inherit the itemWeight and parameters
|
|
157
|
+
// unless overridden individually.
|
|
158
|
+
weightedSection.add("Discuss {{topic}} caching strategies");
|
|
159
|
+
weightedSection.add("Explain {{topic}} database indexing", { weight: 7 }); // Override itemWeight
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Using Parameters for Customization
|
|
163
|
+
|
|
164
|
+
riotprompt supports dynamic content in your prompts through the use of parameters. Parameters allow you to define placeholders in your prompt text (e.g., `{{variable}}`) and replace them with specific values when the prompt is created or formatted. This is a simple yet powerful way to customize prompts for different scenarios without altering the core structure.
|
|
165
|
+
|
|
166
|
+
Parameters can be passed when creating a prompt, a persona, or a section. They can also be supplied directly when adding individual items like instructions, content, or context if those items are strings with placeholders.
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
import { createSection, createParameters, Formatter, Section, Instruction, Parameters } from '@riotprompt';
|
|
170
|
+
|
|
171
|
+
const parameters: Parameters = createParameters({
|
|
172
|
+
"targetLanguage": "Spanish",
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
const instructions: Section<Instruction> = createSection({ title: "Instructions", parameters });
|
|
176
|
+
instructions.add("Translate the following text to {{targetLanguage}}.");
|
|
177
|
+
|
|
178
|
+
const formatter = Formatter.create({ formatOptions: { sectionSeparator: "markdown" }});
|
|
179
|
+
const formatted = formatter.format(instructions);
|
|
180
|
+
console.log(formatted);
|
|
181
|
+
// Output: # Instructions
|
|
182
|
+
// Translate the following text to Spanish
|
|
183
|
+
//
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Parsing Markdown for Section Creation
|
|
187
|
+
|
|
188
|
+
riotprompt can simplify the process of structuring your prompts by parsing Markdown content. When you provide Markdown text, riotprompt can automatically convert Markdown headers (e.g., `# Title`, `## Subtitle`) into `Section` objects. The text of the header becomes the title of the `Section`.
|
|
189
|
+
|
|
190
|
+
This allows you to draft complex prompt structures in a familiar Markdown format and then easily import them into riotprompt. For instance, a document like this:
|
|
191
|
+
|
|
192
|
+
```markdown
|
|
193
|
+
# Main Topic
|
|
194
|
+
Some general instructions or content.
|
|
195
|
+
|
|
196
|
+
## Sub-Topic 1
|
|
197
|
+
Details about the first sub-topic.
|
|
198
|
+
|
|
199
|
+
### Sub-Sub-Topic A
|
|
200
|
+
Further details.
|
|
201
|
+
|
|
202
|
+
## Sub-Topic 2
|
|
203
|
+
Details about the second sub-topic.
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Could be parsed into a main section titled "Main Topic" containing text and two sub-sections: "Sub-Topic 1" (which itself contains a nested section "Sub-Sub-Topic A") and "Sub-Topic 2". The content under each header would become items within the respective sections.
|
|
207
|
+
|
|
208
|
+
```js
|
|
209
|
+
import { Parser, Formatter } from '@riotprompt';
|
|
210
|
+
|
|
211
|
+
// Markdown content with sections
|
|
212
|
+
const markdownContent = `
|
|
213
|
+
# Instructions
|
|
214
|
+
Follow these guidelines when writing code.
|
|
215
|
+
|
|
216
|
+
## Best Practices
|
|
217
|
+
- Keep functions small and focused
|
|
218
|
+
- Use meaningful variable names
|
|
219
|
+
|
|
220
|
+
## Documentation
|
|
221
|
+
- Comment complex logic
|
|
222
|
+
- Document public APIs thoroughly
|
|
223
|
+
`;
|
|
224
|
+
|
|
225
|
+
// Parse the Markdown into a Section structure
|
|
226
|
+
const parser = Parser.create();
|
|
227
|
+
|
|
228
|
+
const parsedSection = parser.parse(markdownContent);
|
|
229
|
+
|
|
230
|
+
// Now you can manipulate the parsed sections
|
|
231
|
+
const bestPracticesSection = parsedSection.items[1]; // Accessing the "Best Practices" section
|
|
232
|
+
bestPracticesSection.add("- Write tests for your code");
|
|
233
|
+
|
|
234
|
+
// Format the resulting section structure
|
|
235
|
+
const formatter = Formatter.create();
|
|
236
|
+
const formattedPrompt = formatter.format(parsedSection);
|
|
237
|
+
console.log(formattedPrompt);
|
|
238
|
+
/* Output:
|
|
239
|
+
<Instructions>
|
|
240
|
+
Follow these guidelines when writing code.
|
|
241
|
+
|
|
242
|
+
<section title="Best Practices">
|
|
243
|
+
- Keep functions small and focused
|
|
244
|
+
- Use meaningful variable names
|
|
245
|
+
- Write tests for your code
|
|
246
|
+
</section>
|
|
247
|
+
|
|
248
|
+
<section title="Documentation">
|
|
249
|
+
- Comment complex logic
|
|
250
|
+
- Document public APIs thoroughly
|
|
251
|
+
</section>
|
|
252
|
+
</Instructions>
|
|
253
|
+
*/
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
For more information, see the [riotprompt Parser Documentation](docs/parser.md)
|
|
257
|
+
|
|
258
|
+
### Overriding Prompt Content
|
|
259
|
+
|
|
260
|
+
riotprompt's Override utility allows you to customize or replace parts of a prompt without altering the original prompt files. This is particularly useful in larger applications where you have default prompt templates but want to adjust certain sections for specific use cases, users, or environments. By using overrides, you can maintain a clean separation between core prompt content and custom modifications.
|
|
261
|
+
|
|
262
|
+
The override system works by looking for specially-named files in an override directory that correspond to your prompt files. You can completely override a section (replace it entirely), prepend content (insert before the original), or append content (insert after the original). This is all done through a simple file naming convention where files with the same name fully override, files ending in `-pre.md` prepend content, and files ending in `-post.md` append content.
|
|
263
|
+
|
|
264
|
+
For more information, see the [riotprompt Override Documentation](docs/override.md)
|
|
265
|
+
|
|
266
|
+
### Building Prompts
|
|
267
|
+
|
|
268
|
+
The riotprompt library provides a powerful Builder pattern for constructing complex prompts programmatically. The Builder allows you to assemble prompts from various sources including files, directories, and inline content.
|
|
269
|
+
|
|
270
|
+
#### Using the Builder
|
|
271
|
+
|
|
272
|
+
The Builder provides a fluent interface for assembling prompts from various sources:
|
|
273
|
+
|
|
274
|
+
<!-- skip-example -->
|
|
275
|
+
```js
|
|
276
|
+
import { Builder } from '@riotprompt';
|
|
277
|
+
|
|
278
|
+
// Create a builder instance
|
|
279
|
+
const builder = Builder.create({
|
|
280
|
+
basePath: './prompts', // Base directory for prompt files
|
|
281
|
+
overridePath: './overrides', // Optional directory for override files
|
|
282
|
+
overrides: true, // Whether to apply overrides
|
|
283
|
+
parameters: { role: 'expert' } // Optional parameters for substitution
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Build a prompt from various sources
|
|
287
|
+
const prompt: Prompt = await builder
|
|
288
|
+
.addPersonaPath('personas/developer.md')
|
|
289
|
+
.addInstructionPath('instructions/code-review.md')
|
|
290
|
+
.loadContext(['./context/people', './context/projects'])
|
|
291
|
+
.addContent('Here is some code I want you to look at.')
|
|
292
|
+
.build();
|
|
293
|
+
|
|
294
|
+
// Format and use the prompt with your LLM API
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### Builder Methods
|
|
298
|
+
|
|
299
|
+
The Builder supports the following methods:
|
|
300
|
+
|
|
301
|
+
- **`addPersonaPath(path)`**: Load a persona from a file
|
|
302
|
+
- **`addContextPath(path)`**: Load context from a file
|
|
303
|
+
- **`addInstructionPath(path)`**: Load instructions from a file
|
|
304
|
+
- **`addContentPath(path)`**: Load content from a file
|
|
305
|
+
- **`addContent(text)`**: Add content directly as a string
|
|
306
|
+
- **`addContext(text)`**: Add context directly as a string
|
|
307
|
+
- **`loadContext(directories)`**: Load context from multiple directories
|
|
308
|
+
- **`loadContent(directories)`**: Load content from multiple directories
|
|
309
|
+
- **`build()`**: Assemble the final prompt
|
|
310
|
+
|
|
311
|
+
All methods return the builder instance for chaining, and the `build()` method returns a Promise that resolves to a `Prompt` object.
|
|
312
|
+
|
|
313
|
+
#### Loading from Directories
|
|
314
|
+
|
|
315
|
+
The Builder can load content from entire directories:
|
|
316
|
+
|
|
317
|
+
<!-- skip-example -->
|
|
318
|
+
```js
|
|
319
|
+
import { Builder } from '@riotprompt/builder';
|
|
320
|
+
|
|
321
|
+
const builder = Builder.create({
|
|
322
|
+
basePath: './prompts',
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Load all files from specific directories
|
|
326
|
+
const prompt = await builder
|
|
327
|
+
.loadContext(['context/user', 'context/project'])
|
|
328
|
+
.loadContent(['content/queries'])
|
|
329
|
+
.build();
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Manipulating Section Contents
|
|
333
|
+
|
|
334
|
+
Once you have a `Section` object, whether created directly, through Markdown parsing, or as part of a `riotprompt` instance (e.g., `prompt.instructionsSection`), you have several methods to manage its contents. These methods allow for dynamic construction and modification of your prompt structure.
|
|
335
|
+
|
|
336
|
+
The `Section` interface provides the following methods for item manipulation:
|
|
337
|
+
|
|
338
|
+
- **`add(item: T | Section<T> | string, options?: WeightedOptions): Section<T>`**
|
|
339
|
+
Appends a new item or a nested section to the end of the section's item list. If a string is provided, it's typically converted into an appropriate `WeightedText` object (e.g., `Instruction`, `ContentText`).
|
|
340
|
+
```typescript
|
|
341
|
+
mySection.add("New item at the end");
|
|
342
|
+
const nestedSection = createSection("Nested");
|
|
343
|
+
mySection.add(nestedSection);
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
- **`append(item: T | Section<T> | string, options?: WeightedOptions): Section<T>`**
|
|
347
|
+
Alias for `add`. Appends an item or nested section to the end.
|
|
348
|
+
```typescript
|
|
349
|
+
mySection.append("Another item at the end");
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
- **`prepend(item: T | Section<T> | string, options?: WeightedOptions): Section<T>`**
|
|
353
|
+
Adds a new item or a nested section to the beginning of the section's item list.
|
|
354
|
+
```typescript
|
|
355
|
+
mySection.prepend("Item at the very beginning");
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
- **`insert(index: number, item: T | Section<T> | string, options?: WeightedOptions): Section<T>`**
|
|
359
|
+
Inserts an item or nested section at a specific zero-based `index` within the item list.
|
|
360
|
+
```typescript
|
|
361
|
+
mySection.insert(1, "Item at index 1"); // Inserts after the first item
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
- **`replace(index: number, item: T | Section<T> | string, options?: WeightedOptions): Section<T>`**
|
|
365
|
+
Replaces the item at the specified `index` with a new item or nested section.
|
|
366
|
+
```typescript
|
|
367
|
+
mySection.replace(0, "Replaced first item");
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
- **`remove(index: number): Section<T>`**
|
|
371
|
+
Removes the item at the specified `index` from the item list.
|
|
372
|
+
```typescript
|
|
373
|
+
mySection.remove(0); // Removes the first item
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
These methods return the `Section` instance itself, allowing for fluent chaining of operations:
|
|
377
|
+
|
|
378
|
+
```js
|
|
379
|
+
import { createSection, Formatter, Section, Instruction } from '@riotprompt';
|
|
380
|
+
|
|
381
|
+
const mySection: Section<Instruction> = createSection({ title: "Example" });
|
|
382
|
+
|
|
383
|
+
mySection
|
|
384
|
+
.add("First item")
|
|
385
|
+
.prepend("Actually, this is first")
|
|
386
|
+
.insert(1, "This goes second")
|
|
387
|
+
.remove(2); // Removes "First item"
|
|
388
|
+
|
|
389
|
+
const formatter = Formatter.create({ formatOptions: { sectionSeparator: "markdown" }})
|
|
390
|
+
const formatted = formatter.format( mySection );
|
|
391
|
+
console.log( formatted );
|
|
392
|
+
// Output: # Example
|
|
393
|
+
//
|
|
394
|
+
// Actually, this is first
|
|
395
|
+
//
|
|
396
|
+
// This goes second
|
|
397
|
+
```
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Using the riotprompt Loader for File-Based Prompts
|
|
401
|
+
|
|
402
|
+
riotprompt provides a Loader utility that allows you to load prompt templates from external files. This is particularly useful when you want to:
|
|
403
|
+
|
|
404
|
+
- Store complex prompts as separate files
|
|
405
|
+
- Share prompt templates across different parts of your application
|
|
406
|
+
- Keep your prompt content separate from your application code
|
|
407
|
+
|
|
408
|
+
The Loader supports various file formats and can automatically parse the content into the appropriate Section structures.
|
|
409
|
+
|
|
410
|
+
The Loader works seamlessly with the Parser to convert structured content into riotprompt's internal representation, allowing you to focus on writing clear prompts rather than managing their implementation details.
|
|
411
|
+
|
|
412
|
+
For more documentation on the Loader, see the [riotprompt Loader Documentation](docs/loader.md)
|
|
413
|
+
|
|
414
|
+
### Customizing Format Options
|
|
415
|
+
|
|
416
|
+
riotprompt supports various formatting styles to organize your prompt elements:
|
|
417
|
+
|
|
418
|
+
#### Available Formatting Options
|
|
419
|
+
|
|
420
|
+
- **areaSeparator**: Determines how major areas (Instructions, Content, Context) are formatted
|
|
421
|
+
- `"tag"`: Uses XML-style tags `<instructions>...</instructions>`
|
|
422
|
+
- `"markdown"`: Uses markdown headers `#### Instructions`
|
|
423
|
+
|
|
424
|
+
- **sectionSeparator**: Determines how sections within areas are formatted
|
|
425
|
+
- `"tag"`: Uses XML-style tags `<section title="Best Practices">...</section>`
|
|
426
|
+
- `"markdown"`: Uses markdown subheaders `#### Section : Best Practices`
|
|
427
|
+
|
|
428
|
+
#### Examples of Different Separator Styles
|
|
429
|
+
|
|
430
|
+
Here's how the same prompt would be formatted using different separator styles:
|
|
431
|
+
|
|
432
|
+
**Tag Style (Default)**
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
<instructions>
|
|
436
|
+
Answer in a concise manner
|
|
437
|
+
Provide code examples when appropriate
|
|
438
|
+
|
|
439
|
+
<section title="Best Practices">
|
|
440
|
+
Follow DRY (Don't Repeat Yourself) principles
|
|
441
|
+
Write readable code with clear variable names
|
|
442
|
+
Add comments for complex logic
|
|
443
|
+
</section>
|
|
444
|
+
</instructions>
|
|
445
|
+
|
|
446
|
+
<contents>
|
|
447
|
+
Explain how promises work in JavaScript
|
|
448
|
+
</contents>
|
|
449
|
+
|
|
450
|
+
<context>
|
|
451
|
+
This is for a beginner JavaScript tutorial
|
|
452
|
+
</context>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Markdown Style**
|
|
456
|
+
|
|
457
|
+
```
|
|
458
|
+
#### Instructions
|
|
459
|
+
|
|
460
|
+
Answer in a concise manner
|
|
461
|
+
Provide code examples when appropriate
|
|
462
|
+
|
|
463
|
+
#### Section : Best Practices
|
|
464
|
+
|
|
465
|
+
Follow DRY (Don't Repeat Yourself) principles
|
|
466
|
+
Write readable code with clear variable names
|
|
467
|
+
Add comments for complex logic
|
|
468
|
+
|
|
469
|
+
#### Contents
|
|
470
|
+
|
|
471
|
+
Explain how promises work in JavaScript
|
|
472
|
+
|
|
473
|
+
#### Context
|
|
474
|
+
|
|
475
|
+
This is for a beginner JavaScript tutorial
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Different LLM providers have different recommendations for prompt formatting:
|
|
479
|
+
|
|
480
|
+
- **Anthropic (Claude)** generally recommends using XML-style tags to clearly delineate sections of prompts
|
|
481
|
+
- **OpenAI (GPT)** models work well with both markdown-style formatting and XML tags
|
|
482
|
+
|
|
483
|
+
The field of prompt engineering is rapidly evolving, with new research and best practices emerging regularly. riotprompt's flexible formatting system allows you to adapt to these changes without rewriting your prompts entirely.
|
|
484
|
+
|
|
485
|
+
By separating the structure of your prompt (instructions, context, content) from its formatting, riotprompt makes it easier to experiment with different formatting approaches to find what works best for your specific use case and model.
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
## Model Support
|
|
489
|
+
|
|
490
|
+
The initial version of riotprompt is designed specifically for the OpenAI API with models such as:
|
|
491
|
+
- gpt-4o
|
|
492
|
+
- gpt-4o-mini
|
|
493
|
+
- o1-mini
|
|
494
|
+
- o1
|
|
495
|
+
- o1-preview
|
|
496
|
+
- o1-pro
|
|
497
|
+
- o3-mini
|
|
498
|
+
|
|
499
|
+
Future versions will be expanded to support other LLM providers and their respective models.
|
|
500
|
+
|
|
501
|
+
The formatter automatically adapts the prompt structure based on the model's requirements (e.g., using system messages for models that support them).
|
|
502
|
+
|
|
503
|
+
## Why the Name?
|
|
504
|
+
|
|
505
|
+
Why not? Who are you to even ask that question?
|
|
506
|
+
|
|
507
|
+
## Contributing
|
|
508
|
+
|
|
509
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
510
|
+
|
|
511
|
+
## License
|
|
512
|
+
|
|
513
|
+
Apache 2.0
|
package/dist/builder.cjs
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const zod = require('zod');
|
|
7
|
+
const parameters = require('./items/parameters.cjs');
|
|
8
|
+
const section = require('./items/section.cjs');
|
|
9
|
+
const logger = require('./logger.cjs');
|
|
10
|
+
require('./items/weighted.cjs');
|
|
11
|
+
const prompt = require('./prompt.cjs');
|
|
12
|
+
require('./formatter.cjs');
|
|
13
|
+
const parser = require('./parser.cjs');
|
|
14
|
+
const loader = require('./loader.cjs');
|
|
15
|
+
const override = require('./override.cjs');
|
|
16
|
+
|
|
17
|
+
const OptionSchema = zod.z.object({
|
|
18
|
+
logger: zod.z.any().optional().default(logger.DEFAULT_LOGGER),
|
|
19
|
+
basePath: zod.z.string(),
|
|
20
|
+
overridePath: zod.z.string().optional().default("./"),
|
|
21
|
+
overrides: zod.z.boolean().optional().default(false),
|
|
22
|
+
parameters: parameters.ParametersSchema.optional().default({})
|
|
23
|
+
});
|
|
24
|
+
const create = (builderOptions)=>{
|
|
25
|
+
const options = OptionSchema.parse(builderOptions);
|
|
26
|
+
const logger$1 = logger.wrapLogger(options.logger, 'Builder');
|
|
27
|
+
const parser$1 = parser.create({
|
|
28
|
+
logger: logger$1
|
|
29
|
+
});
|
|
30
|
+
const override$1 = override.create({
|
|
31
|
+
logger: logger$1,
|
|
32
|
+
configDir: options.overridePath || "./",
|
|
33
|
+
overrides: options.overrides || false
|
|
34
|
+
});
|
|
35
|
+
const loader$1 = loader.create({
|
|
36
|
+
logger: logger$1
|
|
37
|
+
});
|
|
38
|
+
const personaSection = section.create({
|
|
39
|
+
title: "Persona"
|
|
40
|
+
});
|
|
41
|
+
const contextSection = section.create({
|
|
42
|
+
title: "Context"
|
|
43
|
+
});
|
|
44
|
+
const instructionSection = section.create({
|
|
45
|
+
title: "Instruction"
|
|
46
|
+
});
|
|
47
|
+
const contentSection = section.create({
|
|
48
|
+
title: "Content"
|
|
49
|
+
});
|
|
50
|
+
const parameters = options.parameters;
|
|
51
|
+
const instance = {};
|
|
52
|
+
const loadOptions = (sectionOptions = {})=>{
|
|
53
|
+
const currentOptions = section.SectionOptionsSchema.parse(sectionOptions);
|
|
54
|
+
return {
|
|
55
|
+
...currentOptions,
|
|
56
|
+
parameters: {
|
|
57
|
+
...parameters,
|
|
58
|
+
...currentOptions.parameters
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
const loadDirectories = async (directories, sectionOptions = {})=>{
|
|
63
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
64
|
+
logger$1.debug("Loading directories", directories);
|
|
65
|
+
const sections = await loader$1.load(directories, currentOptions);
|
|
66
|
+
return sections;
|
|
67
|
+
};
|
|
68
|
+
const loadContext = async (contextDirectories, sectionOptions = {})=>{
|
|
69
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
70
|
+
logger$1.debug('Loading context', contextDirectories);
|
|
71
|
+
const context = await loadDirectories(contextDirectories, currentOptions);
|
|
72
|
+
contextSection.add(context);
|
|
73
|
+
return instance;
|
|
74
|
+
};
|
|
75
|
+
instance.loadContext = loadContext;
|
|
76
|
+
const loadContent = async (contentDirectories, sectionOptions = {})=>{
|
|
77
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
78
|
+
const content = await loadDirectories(contentDirectories, currentOptions);
|
|
79
|
+
contentSection.add(content);
|
|
80
|
+
return instance;
|
|
81
|
+
};
|
|
82
|
+
instance.loadContent = loadContent;
|
|
83
|
+
const loadPath = async (contentPath, sectionOptions = {})=>{
|
|
84
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
85
|
+
const defaultPath = path.join(options.basePath, contentPath);
|
|
86
|
+
const section = await parser$1.parseFile(defaultPath, currentOptions);
|
|
87
|
+
const overrideSection = await override$1.customize(contentPath, section, currentOptions);
|
|
88
|
+
return overrideSection;
|
|
89
|
+
};
|
|
90
|
+
const addPersonaPath = async (contentPath, sectionOptions = {})=>{
|
|
91
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
92
|
+
const persona = await loadPath(contentPath, currentOptions);
|
|
93
|
+
personaSection.add(persona);
|
|
94
|
+
return instance;
|
|
95
|
+
};
|
|
96
|
+
instance.addPersonaPath = addPersonaPath;
|
|
97
|
+
const addContextPath = async (contentPath, sectionOptions = {})=>{
|
|
98
|
+
logger$1.debug("Adding context path", contentPath);
|
|
99
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
100
|
+
const context = await loadPath(contentPath, currentOptions);
|
|
101
|
+
contextSection.add(context);
|
|
102
|
+
return instance;
|
|
103
|
+
};
|
|
104
|
+
instance.addContextPath = addContextPath;
|
|
105
|
+
const addInstructionPath = async (contentPath, sectionOptions = {})=>{
|
|
106
|
+
logger$1.debug("Adding instruction path", contentPath);
|
|
107
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
108
|
+
const instruction = await loadPath(contentPath, currentOptions);
|
|
109
|
+
instructionSection.add(instruction);
|
|
110
|
+
return instance;
|
|
111
|
+
};
|
|
112
|
+
instance.addInstructionPath = addInstructionPath;
|
|
113
|
+
const addContentPath = async (contentPath, sectionOptions = {})=>{
|
|
114
|
+
logger$1.debug("Adding content path", contentPath);
|
|
115
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
116
|
+
const content = await loadPath(contentPath, currentOptions);
|
|
117
|
+
contentSection.add(content);
|
|
118
|
+
return instance;
|
|
119
|
+
};
|
|
120
|
+
instance.addContentPath = addContentPath;
|
|
121
|
+
const addContent = async (content, sectionOptions = {})=>{
|
|
122
|
+
logger$1.debug("Adding content", typeof content);
|
|
123
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
124
|
+
const parsedContentSection = parser$1.parse(content, currentOptions);
|
|
125
|
+
contentSection.add(parsedContentSection);
|
|
126
|
+
return instance;
|
|
127
|
+
};
|
|
128
|
+
instance.addContent = addContent;
|
|
129
|
+
const addContext = async (context, sectionOptions = {})=>{
|
|
130
|
+
logger$1.debug("Adding context", typeof context);
|
|
131
|
+
const currentOptions = loadOptions(sectionOptions);
|
|
132
|
+
const parsedContextSection = parser$1.parse(context, currentOptions);
|
|
133
|
+
contextSection.add(parsedContextSection);
|
|
134
|
+
return instance;
|
|
135
|
+
};
|
|
136
|
+
instance.addContext = addContext;
|
|
137
|
+
const build = async ()=>{
|
|
138
|
+
logger$1.debug("Building prompt", {});
|
|
139
|
+
const prompt$1 = prompt.create({
|
|
140
|
+
persona: personaSection,
|
|
141
|
+
contexts: contextSection,
|
|
142
|
+
instructions: instructionSection,
|
|
143
|
+
contents: contentSection
|
|
144
|
+
});
|
|
145
|
+
return prompt$1;
|
|
146
|
+
};
|
|
147
|
+
instance.build = build;
|
|
148
|
+
return instance;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
exports.create = create;
|
|
152
|
+
//# sourceMappingURL=builder.cjs.map
|