@riotprompt/riotprompt 0.0.21 → 1.0.1-dev.0
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/CHANGELOG.md +74 -0
- package/MIGRATION.md +235 -0
- package/README.md +2 -0
- package/SECURITY.md +132 -0
- package/dist/builder.js +6 -0
- package/dist/builder.js.map +1 -1
- package/dist/cli.js +481 -22
- package/dist/context-manager.js +1 -1
- package/dist/conversation-logger.d.ts +17 -1
- package/dist/conversation-logger.js +21 -17
- package/dist/conversation-logger.js.map +1 -1
- package/dist/conversation.js +1 -1
- package/dist/error-handling.d.ts +52 -0
- package/dist/error-handling.js +132 -0
- package/dist/error-handling.js.map +1 -0
- package/dist/formatter.js +1 -1
- package/dist/iteration-strategy.js +1 -1
- package/dist/loader.js +60 -12
- package/dist/loader.js.map +1 -1
- package/dist/logger.d.ts +52 -0
- package/dist/logger.js +114 -14
- package/dist/logger.js.map +1 -1
- package/dist/logging-config.d.ts +84 -0
- package/dist/logging-config.js +116 -0
- package/dist/logging-config.js.map +1 -0
- package/dist/message-builder.js +1 -1
- package/dist/model-config.js +1 -1
- package/dist/override.js +10 -4
- package/dist/override.js.map +1 -1
- package/dist/recipes.js +6 -0
- package/dist/recipes.js.map +1 -1
- package/dist/reflection.js +1 -1
- package/dist/riotprompt.d.ts +9 -0
- package/dist/riotprompt.js +8 -0
- package/dist/riotprompt.js.map +1 -1
- package/dist/security/audit-logger.d.ts +61 -0
- package/dist/security/audit-logger.js +281 -0
- package/dist/security/audit-logger.js.map +1 -0
- package/dist/security/cli-security.d.ts +143 -0
- package/dist/security/cli-security.js +302 -0
- package/dist/security/cli-security.js.map +1 -0
- package/dist/security/defaults.d.ts +31 -0
- package/dist/security/defaults.js +72 -0
- package/dist/security/defaults.js.map +1 -0
- package/dist/security/events.d.ts +8 -0
- package/dist/security/index.d.ts +27 -0
- package/dist/security/index.js +22 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/path-guard.d.ts +161 -0
- package/dist/security/path-guard.js +327 -0
- package/dist/security/path-guard.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +117 -0
- package/dist/security/rate-limiter.js +165 -0
- package/dist/security/rate-limiter.js.map +1 -0
- package/dist/security/serialization-schemas.d.ts +183 -0
- package/dist/security/serialization-schemas.js +174 -0
- package/dist/security/serialization-schemas.js.map +1 -0
- package/dist/security/timeout-guard.d.ts +123 -0
- package/dist/security/timeout-guard.js +223 -0
- package/dist/security/timeout-guard.js.map +1 -0
- package/dist/security/types.d.ts +86 -0
- package/dist/security/types.js +80 -0
- package/dist/security/types.js.map +1 -0
- package/dist/token-budget.js +1 -1
- package/dist/tools.js +1 -1
- package/guide/index.md +2 -0
- package/guide/integration.md +1109 -0
- package/guide/security.md +237 -0
- package/package.json +18 -11
|
@@ -0,0 +1,1109 @@
|
|
|
1
|
+
# Integration Guide
|
|
2
|
+
|
|
3
|
+
**Purpose**: Comprehensive guide for integrating RiotPrompt into your application as a library.
|
|
4
|
+
|
|
5
|
+
This guide covers the core concepts, configuration options, and code patterns for using RiotPrompt programmatically. It is intended for developers building LLM-powered applications who want to leverage RiotPrompt's structured prompt engineering capabilities.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @riotprompt/riotprompt
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For lighter installs, you can use individual packages:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Core prompt engineering (no SDK dependencies)
|
|
17
|
+
npm install @riotprompt/riotprompt
|
|
18
|
+
|
|
19
|
+
# Provider-specific execution
|
|
20
|
+
npm install @riotprompt/execution-openai
|
|
21
|
+
npm install @riotprompt/execution-anthropic
|
|
22
|
+
npm install @riotprompt/execution-gemini
|
|
23
|
+
|
|
24
|
+
# Agentic features (tool registry, context management)
|
|
25
|
+
npm install @riotprompt/agentic
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Core Concepts
|
|
29
|
+
|
|
30
|
+
### Prompts as Structured Objects
|
|
31
|
+
|
|
32
|
+
RiotPrompt treats prompts as structured data objects rather than simple strings. A `Prompt` contains multiple specialized sections:
|
|
33
|
+
|
|
34
|
+
| Section | Purpose | Example |
|
|
35
|
+
|---------|---------|---------|
|
|
36
|
+
| `persona` | Who the AI is (system prompt) | "You are a senior code reviewer" |
|
|
37
|
+
| `instructions` | What the AI should do | "Review this pull request" |
|
|
38
|
+
| `content` | Input data to process | The actual PR diff |
|
|
39
|
+
| `context` | Background information | Project guidelines, coding standards |
|
|
40
|
+
| `constraints` | Hard rules and limitations | "Do not suggest refactoring" |
|
|
41
|
+
| `tone` | Style guidelines | "Be constructive and empathetic" |
|
|
42
|
+
| `examples` | Few-shot examples | Sample reviews |
|
|
43
|
+
| `reasoning` | Thinking instructions | "Think step-by-step" |
|
|
44
|
+
| `responseFormat` | Output structure | "Return as JSON" |
|
|
45
|
+
| `recap` | Final reminders | "Remember to check for security issues" |
|
|
46
|
+
| `safeguards` | Safety guidelines | "Do not execute code" |
|
|
47
|
+
|
|
48
|
+
### Section System
|
|
49
|
+
|
|
50
|
+
Sections are hierarchical containers that can hold items and nested sections:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { createSection, createInstruction } from '@riotprompt/riotprompt';
|
|
54
|
+
|
|
55
|
+
const instructions = createSection<Instruction>('Instructions');
|
|
56
|
+
instructions.add(createInstruction('Analyze the code for bugs'));
|
|
57
|
+
instructions.add(createInstruction('Check for security vulnerabilities'));
|
|
58
|
+
|
|
59
|
+
// Nested sections
|
|
60
|
+
const advanced = createSection<Instruction>('Advanced Checks');
|
|
61
|
+
advanced.add(createInstruction('Review performance implications'));
|
|
62
|
+
instructions.addSection(advanced);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Weighted Items
|
|
66
|
+
|
|
67
|
+
Items can have weights for prioritization:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { createWeighted } from '@riotprompt/riotprompt';
|
|
71
|
+
|
|
72
|
+
const highPriority = createWeighted('Critical security check', { weight: 1.0 });
|
|
73
|
+
const lowPriority = createWeighted('Style suggestions', { weight: 0.3 });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Creating Prompts
|
|
77
|
+
|
|
78
|
+
### Using the Recipes API (Recommended)
|
|
79
|
+
|
|
80
|
+
The `cook` function is the primary entry point for creating prompts:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { cook } from '@riotprompt/riotprompt';
|
|
84
|
+
|
|
85
|
+
const prompt = await cook({
|
|
86
|
+
basePath: __dirname,
|
|
87
|
+
persona: { content: 'You are a helpful AI assistant.' },
|
|
88
|
+
instructions: [
|
|
89
|
+
{ content: 'Summarize the provided text.' },
|
|
90
|
+
{ content: 'Extract key points.' }
|
|
91
|
+
],
|
|
92
|
+
content: [
|
|
93
|
+
{ content: 'Text to summarize goes here...' }
|
|
94
|
+
]
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Content Items
|
|
99
|
+
|
|
100
|
+
Content items can be specified in multiple ways:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const prompt = await cook({
|
|
104
|
+
basePath: __dirname,
|
|
105
|
+
persona: { content: 'You are an analyst.' },
|
|
106
|
+
|
|
107
|
+
// Simple string content
|
|
108
|
+
instructions: [
|
|
109
|
+
{ content: 'Analyze this data' }
|
|
110
|
+
],
|
|
111
|
+
|
|
112
|
+
// Content with title and weight
|
|
113
|
+
context: [
|
|
114
|
+
{ content: 'Background info', title: 'Context', weight: 0.8 }
|
|
115
|
+
],
|
|
116
|
+
|
|
117
|
+
// Load from file
|
|
118
|
+
examples: [
|
|
119
|
+
{ path: './examples/good-analysis.md', title: 'Example' }
|
|
120
|
+
],
|
|
121
|
+
|
|
122
|
+
// Load from directories
|
|
123
|
+
content: [
|
|
124
|
+
{ directories: ['./data'], title: 'Input Data' }
|
|
125
|
+
]
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Using the Fluent Builder API
|
|
130
|
+
|
|
131
|
+
For more dynamic prompt construction:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { recipe } from '@riotprompt/riotprompt';
|
|
135
|
+
|
|
136
|
+
const prompt = await recipe(__dirname)
|
|
137
|
+
.persona({ content: 'You are a code reviewer' })
|
|
138
|
+
.instructions({ content: 'Review this code' })
|
|
139
|
+
.constraints({ content: 'Focus on security' })
|
|
140
|
+
.content({ content: codeToReview })
|
|
141
|
+
.cook();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Using Templates
|
|
145
|
+
|
|
146
|
+
Register reusable templates for consistency:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { registerTemplates, cook, getTemplates, clearTemplates } from '@riotprompt/riotprompt';
|
|
150
|
+
|
|
151
|
+
// Register templates
|
|
152
|
+
registerTemplates({
|
|
153
|
+
'code-review': {
|
|
154
|
+
persona: { content: 'You are a senior code reviewer.' },
|
|
155
|
+
constraints: [{ content: 'Be constructive.' }],
|
|
156
|
+
tone: [{ content: 'Professional and helpful.' }]
|
|
157
|
+
},
|
|
158
|
+
'security-audit': {
|
|
159
|
+
persona: { content: 'You are a security auditor.' },
|
|
160
|
+
constraints: [{ content: 'Report only high-severity issues.' }]
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Use a template
|
|
165
|
+
const prompt = await cook({
|
|
166
|
+
basePath: __dirname,
|
|
167
|
+
template: 'code-review',
|
|
168
|
+
content: [{ content: prDiff }]
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Extend a template
|
|
172
|
+
const prompt2 = await cook({
|
|
173
|
+
basePath: __dirname,
|
|
174
|
+
extends: 'security-audit',
|
|
175
|
+
instructions: [{ content: 'Focus on SQL injection vulnerabilities.' }],
|
|
176
|
+
content: [{ content: sourceCode }]
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// List registered templates
|
|
180
|
+
const templates = getTemplates();
|
|
181
|
+
|
|
182
|
+
// Clear all templates
|
|
183
|
+
clearTemplates();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Structured Outputs
|
|
187
|
+
|
|
188
|
+
RiotPrompt supports portable structured outputs using Zod schemas:
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { cook } from '@riotprompt/riotprompt';
|
|
192
|
+
import { z } from 'zod';
|
|
193
|
+
|
|
194
|
+
// Define your schema
|
|
195
|
+
const AnalysisSchema = z.object({
|
|
196
|
+
sentiment: z.enum(['positive', 'negative', 'neutral']),
|
|
197
|
+
keyPoints: z.array(z.string()),
|
|
198
|
+
confidence: z.number().min(0).max(1),
|
|
199
|
+
summary: z.string()
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Pass to cook
|
|
203
|
+
const prompt = await cook({
|
|
204
|
+
basePath: __dirname,
|
|
205
|
+
persona: { content: 'You are a sentiment analyzer.' },
|
|
206
|
+
content: [{ content: textToAnalyze }],
|
|
207
|
+
schema: AnalysisSchema
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// The schema is automatically adapted for different providers
|
|
211
|
+
// (JSON Schema for OpenAI, Tool Use for Anthropic, etc.)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Model Configuration
|
|
215
|
+
|
|
216
|
+
### Default Model Mappings
|
|
217
|
+
|
|
218
|
+
RiotPrompt automatically handles model-specific formatting:
|
|
219
|
+
|
|
220
|
+
| Model Family | Persona Role | Encoding |
|
|
221
|
+
|--------------|--------------|----------|
|
|
222
|
+
| Claude | `system` | `cl100k_base` |
|
|
223
|
+
| GPT-4 | `system` | `gpt-4o` |
|
|
224
|
+
| O-series (o1, o2) | `developer` | `gpt-4o` |
|
|
225
|
+
|
|
226
|
+
### Custom Model Configuration
|
|
227
|
+
|
|
228
|
+
Register custom models:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { configureModel, getModelRegistry } from '@riotprompt/riotprompt';
|
|
232
|
+
|
|
233
|
+
// Register a custom model
|
|
234
|
+
configureModel({
|
|
235
|
+
exactMatch: 'my-local-llama',
|
|
236
|
+
personaRole: 'system',
|
|
237
|
+
encoding: 'cl100k_base',
|
|
238
|
+
family: 'llama',
|
|
239
|
+
supportsToolCalls: true
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Pattern-based matching
|
|
243
|
+
configureModel({
|
|
244
|
+
pattern: /^llama-\d+/,
|
|
245
|
+
personaRole: 'system',
|
|
246
|
+
encoding: 'cl100k_base',
|
|
247
|
+
family: 'llama'
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Access the registry
|
|
251
|
+
const registry = getModelRegistry();
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Formatting Prompts
|
|
255
|
+
|
|
256
|
+
### For Different Models
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { Formatter, cook } from '@riotprompt/riotprompt';
|
|
260
|
+
|
|
261
|
+
const prompt = await cook({
|
|
262
|
+
basePath: __dirname,
|
|
263
|
+
persona: { content: 'You are a helpful assistant.' },
|
|
264
|
+
instructions: [{ content: 'Help the user.' }]
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Create formatter
|
|
268
|
+
const formatter = Formatter.create();
|
|
269
|
+
|
|
270
|
+
// Format for specific model (handles role mapping automatically)
|
|
271
|
+
const openaiRequest = formatter.formatPrompt('gpt-4o', prompt);
|
|
272
|
+
const claudeRequest = formatter.formatPrompt('claude-3-opus', prompt);
|
|
273
|
+
const o1Request = formatter.formatPrompt('o1', prompt); // Uses 'developer' role
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Custom Format Options
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
const formatter = Formatter.create({
|
|
280
|
+
sectionSeparator: '\n\n---\n\n',
|
|
281
|
+
sectionTitleProperty: 'header',
|
|
282
|
+
includeWeights: true
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Serialization
|
|
287
|
+
|
|
288
|
+
### Export and Import Prompts
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { Serializer, cook } from '@riotprompt/riotprompt';
|
|
292
|
+
|
|
293
|
+
const prompt = await cook({
|
|
294
|
+
basePath: __dirname,
|
|
295
|
+
persona: { content: 'You are an assistant.' },
|
|
296
|
+
instructions: [{ content: 'Help users.' }]
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Export to JSON
|
|
300
|
+
const json = Serializer.toJSON(prompt);
|
|
301
|
+
|
|
302
|
+
// Export to XML
|
|
303
|
+
const xml = Serializer.toXML(prompt);
|
|
304
|
+
|
|
305
|
+
// Import from JSON
|
|
306
|
+
const restored = Serializer.fromJSON(json);
|
|
307
|
+
|
|
308
|
+
// Import from XML
|
|
309
|
+
const restoredXml = Serializer.fromXML(xml);
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Loading from Filesystem
|
|
313
|
+
|
|
314
|
+
### Directory Structure
|
|
315
|
+
|
|
316
|
+
RiotPrompt can load prompts from a structured directory:
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
my-prompt/
|
|
320
|
+
├── persona.md # OR persona/ directory
|
|
321
|
+
├── instructions.md # OR instructions/ directory
|
|
322
|
+
├── context/ # Reference files
|
|
323
|
+
│ ├── data.json
|
|
324
|
+
│ └── background.md
|
|
325
|
+
├── constraints.md
|
|
326
|
+
├── tone.md
|
|
327
|
+
└── examples.md
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Using the Loader
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
import { Loader } from '@riotprompt/riotprompt';
|
|
334
|
+
|
|
335
|
+
// Create loader
|
|
336
|
+
const loader = Loader.create({
|
|
337
|
+
basePath: './prompts/my-prompt',
|
|
338
|
+
ignorePatterns: ['*.test.md', 'drafts/**']
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// Load context from directories
|
|
342
|
+
const context = await loader.load(['./context', './reference']);
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Conversation Management
|
|
346
|
+
|
|
347
|
+
### ConversationBuilder
|
|
348
|
+
|
|
349
|
+
Manage multi-turn conversations:
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
import { ConversationBuilder, cook } from '@riotprompt/riotprompt';
|
|
353
|
+
|
|
354
|
+
// Create from prompt
|
|
355
|
+
const prompt = await cook({
|
|
356
|
+
basePath: __dirname,
|
|
357
|
+
persona: { content: 'You are a helpful assistant.' },
|
|
358
|
+
instructions: [{ content: 'Help users with their questions.' }]
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
const conversation = ConversationBuilder.create({ model: 'gpt-4o' })
|
|
362
|
+
.fromPrompt(prompt, 'gpt-4o')
|
|
363
|
+
.build();
|
|
364
|
+
|
|
365
|
+
// Add messages
|
|
366
|
+
conversation.addUserMessage('What is TypeScript?');
|
|
367
|
+
conversation.addAssistantMessage('TypeScript is a typed superset of JavaScript...');
|
|
368
|
+
conversation.addUserMessage('How do I install it?');
|
|
369
|
+
|
|
370
|
+
// Get messages for API call
|
|
371
|
+
const messages = conversation.toMessages();
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Semantic Message Methods
|
|
375
|
+
|
|
376
|
+
Use semantic methods for clearer code:
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
const conversation = ConversationBuilder.create({ model: 'gpt-4o' })
|
|
380
|
+
.fromPrompt(prompt, 'gpt-4o')
|
|
381
|
+
.asUser('Analyze this code')
|
|
382
|
+
.asAssistant('I see several issues...')
|
|
383
|
+
.asUser('Can you fix them?')
|
|
384
|
+
.build();
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Context Injection
|
|
388
|
+
|
|
389
|
+
Inject dynamic context into conversations:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
conversation.injectContext([
|
|
393
|
+
{
|
|
394
|
+
id: 'file-1',
|
|
395
|
+
content: 'Contents of main.ts...',
|
|
396
|
+
title: 'Source File',
|
|
397
|
+
category: 'code',
|
|
398
|
+
priority: 'high'
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: 'docs-1',
|
|
402
|
+
content: 'API documentation...',
|
|
403
|
+
title: 'Documentation',
|
|
404
|
+
category: 'reference',
|
|
405
|
+
priority: 'medium'
|
|
406
|
+
}
|
|
407
|
+
], {
|
|
408
|
+
position: 'after-system',
|
|
409
|
+
format: 'structured',
|
|
410
|
+
deduplicate: true,
|
|
411
|
+
deduplicateBy: 'id'
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Token Budget Management
|
|
416
|
+
|
|
417
|
+
Manage token usage:
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
const conversation = ConversationBuilder.create({ model: 'gpt-4o' })
|
|
421
|
+
.fromPrompt(prompt, 'gpt-4o')
|
|
422
|
+
.withTokenBudget({
|
|
423
|
+
max: 100000,
|
|
424
|
+
reserve: 4000, // Reserve for response
|
|
425
|
+
compressionStrategy: 'summarize'
|
|
426
|
+
})
|
|
427
|
+
.build();
|
|
428
|
+
|
|
429
|
+
// Check usage
|
|
430
|
+
const usage = conversation.getTokenUsage();
|
|
431
|
+
console.log(`Used: ${usage.used}/${usage.max} (${usage.percentage}%)`);
|
|
432
|
+
|
|
433
|
+
// Manually compress if needed
|
|
434
|
+
conversation.compress();
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Conversation Logging
|
|
438
|
+
|
|
439
|
+
Log conversations for debugging and replay:
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
const conversation = ConversationBuilder.create({ model: 'gpt-4o' })
|
|
443
|
+
.fromPrompt(prompt, 'gpt-4o')
|
|
444
|
+
.withLogging({
|
|
445
|
+
outputPath: './logs',
|
|
446
|
+
format: 'json',
|
|
447
|
+
includeMetadata: true
|
|
448
|
+
})
|
|
449
|
+
.build();
|
|
450
|
+
|
|
451
|
+
// ... use conversation ...
|
|
452
|
+
|
|
453
|
+
// Save log
|
|
454
|
+
const logPath = await conversation.saveLog();
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Serialization and Cloning
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
// Serialize for persistence
|
|
461
|
+
const json = conversation.toJSON();
|
|
462
|
+
|
|
463
|
+
// Restore later
|
|
464
|
+
const restored = ConversationBuilder.fromJSON(json, { model: 'gpt-4o' });
|
|
465
|
+
|
|
466
|
+
// Clone for parallel exploration
|
|
467
|
+
const branch = conversation.clone();
|
|
468
|
+
branch.addUserMessage('What if we tried a different approach?');
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
## Tool Integration
|
|
472
|
+
|
|
473
|
+
### ToolRegistry
|
|
474
|
+
|
|
475
|
+
Register and manage tools:
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
import { ToolRegistry } from '@riotprompt/riotprompt';
|
|
479
|
+
|
|
480
|
+
const registry = ToolRegistry.create({
|
|
481
|
+
workingDirectory: process.cwd()
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// Register a tool
|
|
485
|
+
registry.register({
|
|
486
|
+
name: 'read_file',
|
|
487
|
+
description: 'Read contents of a file',
|
|
488
|
+
category: 'filesystem',
|
|
489
|
+
cost: 'cheap',
|
|
490
|
+
parameters: {
|
|
491
|
+
type: 'object',
|
|
492
|
+
properties: {
|
|
493
|
+
path: {
|
|
494
|
+
type: 'string',
|
|
495
|
+
description: 'Path to the file'
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
required: ['path']
|
|
499
|
+
},
|
|
500
|
+
execute: async ({ path }) => {
|
|
501
|
+
const fs = await import('fs/promises');
|
|
502
|
+
return await fs.readFile(path, 'utf-8');
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// Register multiple tools
|
|
507
|
+
registry.registerAll([tool1, tool2, tool3]);
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Executing Tools
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
// Execute a single tool
|
|
514
|
+
const content = await registry.execute('read_file', { path: 'README.md' });
|
|
515
|
+
|
|
516
|
+
// Execute batch
|
|
517
|
+
const results = await registry.executeBatch([
|
|
518
|
+
{ name: 'read_file', params: { path: 'file1.ts' } },
|
|
519
|
+
{ name: 'read_file', params: { path: 'file2.ts' } }
|
|
520
|
+
]);
|
|
521
|
+
|
|
522
|
+
// Get usage statistics
|
|
523
|
+
const stats = registry.getUsageStats();
|
|
524
|
+
console.log(stats.get('read_file'));
|
|
525
|
+
// { calls: 3, failures: 0, successRate: 1, averageDuration: 5 }
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Export for Providers
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
// Export for OpenAI
|
|
532
|
+
const openaiTools = registry.toOpenAIFormat();
|
|
533
|
+
|
|
534
|
+
// Export for Anthropic
|
|
535
|
+
const anthropicTools = registry.toAnthropicFormat();
|
|
536
|
+
|
|
537
|
+
// Get definitions (without execute functions)
|
|
538
|
+
const definitions = registry.getDefinitions();
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Tool Guidance Generation
|
|
542
|
+
|
|
543
|
+
Generate tool usage instructions for prompts:
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
import { generateToolGuidance, cook } from '@riotprompt/riotprompt';
|
|
547
|
+
|
|
548
|
+
const guidance = generateToolGuidance(registry.getAll(), {
|
|
549
|
+
style: 'detailed', // 'minimal' | 'detailed' | 'auto'
|
|
550
|
+
includeExamples: true
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
const prompt = await cook({
|
|
554
|
+
basePath: __dirname,
|
|
555
|
+
persona: { content: 'You are an assistant with tools.' },
|
|
556
|
+
instructions: [{ content: guidance }],
|
|
557
|
+
tools: registry
|
|
558
|
+
});
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
## Agentic Interactions
|
|
562
|
+
|
|
563
|
+
### Iteration Strategies
|
|
564
|
+
|
|
565
|
+
Execute multi-step agentic workflows:
|
|
566
|
+
|
|
567
|
+
```typescript
|
|
568
|
+
import {
|
|
569
|
+
StrategyExecutor,
|
|
570
|
+
IterationStrategyFactory,
|
|
571
|
+
ConversationBuilder,
|
|
572
|
+
ToolRegistry
|
|
573
|
+
} from '@riotprompt/riotprompt';
|
|
574
|
+
|
|
575
|
+
// Create LLM client (provider-specific)
|
|
576
|
+
const llmClient = {
|
|
577
|
+
async complete(messages, tools) {
|
|
578
|
+
// Call your LLM provider
|
|
579
|
+
const response = await openai.chat.completions.create({
|
|
580
|
+
model: 'gpt-4o',
|
|
581
|
+
messages,
|
|
582
|
+
tools
|
|
583
|
+
});
|
|
584
|
+
return {
|
|
585
|
+
content: response.choices[0].message.content,
|
|
586
|
+
tool_calls: response.choices[0].message.tool_calls
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
// Create executor
|
|
592
|
+
const executor = new StrategyExecutor(llmClient);
|
|
593
|
+
|
|
594
|
+
// Execute with a strategy
|
|
595
|
+
const result = await executor.execute(
|
|
596
|
+
conversation,
|
|
597
|
+
toolRegistry,
|
|
598
|
+
IterationStrategyFactory.investigateThenRespond({
|
|
599
|
+
maxInvestigationSteps: 5,
|
|
600
|
+
requireMinimumTools: 1,
|
|
601
|
+
finalSynthesis: true
|
|
602
|
+
})
|
|
603
|
+
);
|
|
604
|
+
|
|
605
|
+
console.log('Completed in', result.totalIterations, 'iterations');
|
|
606
|
+
console.log('Used', result.toolCallsExecuted, 'tool calls');
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Pre-built Strategies
|
|
610
|
+
|
|
611
|
+
```typescript
|
|
612
|
+
// Investigate then respond (gather info, then synthesize)
|
|
613
|
+
const strategy1 = IterationStrategyFactory.investigateThenRespond({
|
|
614
|
+
maxInvestigationSteps: 5,
|
|
615
|
+
requireMinimumTools: 1
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// Multi-pass refinement (generate, critique, refine)
|
|
619
|
+
const strategy2 = IterationStrategyFactory.multiPassRefinement({
|
|
620
|
+
passes: 3,
|
|
621
|
+
critiqueBetweenPasses: true
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
// Breadth-first (explore broadly before going deep)
|
|
625
|
+
const strategy3 = IterationStrategyFactory.breadthFirst({
|
|
626
|
+
levelsDeep: 3,
|
|
627
|
+
toolsPerLevel: 4
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
// Depth-first (deep dive immediately)
|
|
631
|
+
const strategy4 = IterationStrategyFactory.depthFirst({
|
|
632
|
+
maxDepth: 5,
|
|
633
|
+
backtrackOnFailure: true
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
// Simple loop (basic tool-use iteration)
|
|
637
|
+
const strategy5 = IterationStrategyFactory.simple({
|
|
638
|
+
maxIterations: 10,
|
|
639
|
+
allowTools: true
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
// Adaptive (changes behavior based on progress)
|
|
643
|
+
const strategy6 = IterationStrategyFactory.adaptive();
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### Custom Strategies
|
|
647
|
+
|
|
648
|
+
Create custom iteration strategies:
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
import type { IterationStrategy, StrategyPhase } from '@riotprompt/riotprompt';
|
|
652
|
+
|
|
653
|
+
const customStrategy: IterationStrategy = {
|
|
654
|
+
name: 'custom-workflow',
|
|
655
|
+
description: 'My custom agentic workflow',
|
|
656
|
+
maxIterations: 15,
|
|
657
|
+
|
|
658
|
+
phases: [
|
|
659
|
+
{
|
|
660
|
+
name: 'discovery',
|
|
661
|
+
maxIterations: 5,
|
|
662
|
+
toolUsage: 'encouraged',
|
|
663
|
+
allowedTools: ['search', 'read_file'],
|
|
664
|
+
minToolCalls: 2
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
name: 'analysis',
|
|
668
|
+
maxIterations: 3,
|
|
669
|
+
toolUsage: 'optional',
|
|
670
|
+
instructions: 'Analyze what you discovered'
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
name: 'synthesis',
|
|
674
|
+
maxIterations: 1,
|
|
675
|
+
toolUsage: 'forbidden',
|
|
676
|
+
requireFinalAnswer: true
|
|
677
|
+
}
|
|
678
|
+
],
|
|
679
|
+
|
|
680
|
+
// Lifecycle hooks
|
|
681
|
+
onStart: async (context) => {
|
|
682
|
+
console.log('Starting workflow...');
|
|
683
|
+
},
|
|
684
|
+
|
|
685
|
+
onIteration: async (iteration, state) => {
|
|
686
|
+
if (state.errors.length > 3) {
|
|
687
|
+
return 'stop';
|
|
688
|
+
}
|
|
689
|
+
return 'continue';
|
|
690
|
+
},
|
|
691
|
+
|
|
692
|
+
onToolCall: async (toolCall, state) => {
|
|
693
|
+
// Skip expensive tools after 10 calls
|
|
694
|
+
if (state.toolCallsExecuted > 10) {
|
|
695
|
+
const tool = toolCall.function.name;
|
|
696
|
+
if (tool === 'expensive_operation') {
|
|
697
|
+
return 'skip';
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return 'execute';
|
|
701
|
+
},
|
|
702
|
+
|
|
703
|
+
onToolResult: async (result, state) => {
|
|
704
|
+
// Track insights from tool results
|
|
705
|
+
if (result.result?.important) {
|
|
706
|
+
state.insights.push({
|
|
707
|
+
source: result.toolName,
|
|
708
|
+
content: result.result.important,
|
|
709
|
+
confidence: 0.8
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
|
|
714
|
+
onComplete: async (result) => {
|
|
715
|
+
console.log('Workflow complete:', result.success);
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
### Reflection and Metrics
|
|
721
|
+
|
|
722
|
+
Generate execution reports:
|
|
723
|
+
|
|
724
|
+
```typescript
|
|
725
|
+
const executor = new StrategyExecutor(llmClient)
|
|
726
|
+
.withReflection({
|
|
727
|
+
enabled: true,
|
|
728
|
+
outputPath: './reflections',
|
|
729
|
+
format: 'markdown', // or 'json'
|
|
730
|
+
includeRecommendations: true
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
const result = await executor.execute(conversation, tools, strategy);
|
|
734
|
+
|
|
735
|
+
// Access reflection report
|
|
736
|
+
if (result.reflection) {
|
|
737
|
+
console.log('Tool Effectiveness:', result.reflection.toolEffectiveness);
|
|
738
|
+
console.log('Recommendations:', result.reflection.recommendations);
|
|
739
|
+
console.log('Quality Assessment:', result.reflection.qualityAssessment);
|
|
740
|
+
}
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
## Security Features
|
|
744
|
+
|
|
745
|
+
### Path Security
|
|
746
|
+
|
|
747
|
+
Prevent path traversal attacks:
|
|
748
|
+
|
|
749
|
+
```typescript
|
|
750
|
+
import { Security } from '@riotprompt/riotprompt';
|
|
751
|
+
|
|
752
|
+
const pathGuard = Security.createPathGuard({
|
|
753
|
+
allowedPaths: ['/app/data', '/app/uploads'],
|
|
754
|
+
blockedPatterns: ['..', '~'],
|
|
755
|
+
maxPathLength: 255
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
// Validate paths
|
|
759
|
+
const isValid = pathGuard.validate('/app/data/file.txt'); // true
|
|
760
|
+
const isInvalid = pathGuard.validate('../etc/passwd'); // false
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
### Secret Redaction
|
|
764
|
+
|
|
765
|
+
Protect sensitive data in logs:
|
|
766
|
+
|
|
767
|
+
```typescript
|
|
768
|
+
import { configureSecureLogging, maskSensitive } from '@riotprompt/riotprompt';
|
|
769
|
+
|
|
770
|
+
// Configure secure logging
|
|
771
|
+
configureSecureLogging({
|
|
772
|
+
maskPatterns: [
|
|
773
|
+
/api[_-]?key/i,
|
|
774
|
+
/password/i,
|
|
775
|
+
/secret/i,
|
|
776
|
+
/token/i
|
|
777
|
+
],
|
|
778
|
+
replacement: '[REDACTED]'
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
// Mask sensitive data
|
|
782
|
+
const safe = maskSensitive({
|
|
783
|
+
apiKey: 'sk-1234567890',
|
|
784
|
+
data: 'normal data'
|
|
785
|
+
});
|
|
786
|
+
// { apiKey: '[REDACTED]', data: 'normal data' }
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
### Error Handling
|
|
790
|
+
|
|
791
|
+
Sanitize errors before logging:
|
|
792
|
+
|
|
793
|
+
```typescript
|
|
794
|
+
import {
|
|
795
|
+
initializeErrorHandling,
|
|
796
|
+
withErrorHandling,
|
|
797
|
+
formatErrorForDisplay
|
|
798
|
+
} from '@riotprompt/riotprompt';
|
|
799
|
+
|
|
800
|
+
// Initialize
|
|
801
|
+
initializeErrorHandling({
|
|
802
|
+
sanitizePaths: true,
|
|
803
|
+
redactSecrets: true
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
// Wrap async functions
|
|
807
|
+
const safeFunction = withErrorHandling(async () => {
|
|
808
|
+
// Your code here
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
// Format errors for display
|
|
812
|
+
try {
|
|
813
|
+
await riskyOperation();
|
|
814
|
+
} catch (error) {
|
|
815
|
+
const displayError = formatErrorForDisplay(error);
|
|
816
|
+
console.error(displayError); // Sanitized error message
|
|
817
|
+
}
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
## Logging
|
|
821
|
+
|
|
822
|
+
### Secure Logging
|
|
823
|
+
|
|
824
|
+
```typescript
|
|
825
|
+
import {
|
|
826
|
+
configureSecureLogging,
|
|
827
|
+
executeWithCorrelation,
|
|
828
|
+
RiotPromptLogger
|
|
829
|
+
} from '@riotprompt/riotprompt';
|
|
830
|
+
|
|
831
|
+
// Configure
|
|
832
|
+
configureSecureLogging({
|
|
833
|
+
level: 'info',
|
|
834
|
+
maskSecrets: true,
|
|
835
|
+
includeCorrelationId: true
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
// Execute with correlation ID
|
|
839
|
+
await executeWithCorrelation(async (correlationId) => {
|
|
840
|
+
const logger = new RiotPromptLogger({ correlationId });
|
|
841
|
+
logger.info('Processing request', { userId: '123' });
|
|
842
|
+
// All logs in this context share the correlation ID
|
|
843
|
+
});
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
### Custom Logger Integration
|
|
847
|
+
|
|
848
|
+
```typescript
|
|
849
|
+
import { createConsoleLogger, wrapLogger } from '@riotprompt/riotprompt';
|
|
850
|
+
|
|
851
|
+
// Use built-in console logger
|
|
852
|
+
const logger = createConsoleLogger({ level: 'debug' });
|
|
853
|
+
|
|
854
|
+
// Wrap existing logger
|
|
855
|
+
const wrapped = wrapLogger(myExistingLogger, 'MyComponent');
|
|
856
|
+
|
|
857
|
+
// Pass to components
|
|
858
|
+
const conversation = ConversationBuilder.create(
|
|
859
|
+
{ model: 'gpt-4o' },
|
|
860
|
+
logger
|
|
861
|
+
);
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
## Complete Integration Example
|
|
865
|
+
|
|
866
|
+
Here's a complete example showing how to integrate RiotPrompt into an application:
|
|
867
|
+
|
|
868
|
+
```typescript
|
|
869
|
+
import {
|
|
870
|
+
cook,
|
|
871
|
+
registerTemplates,
|
|
872
|
+
ConversationBuilder,
|
|
873
|
+
ToolRegistry,
|
|
874
|
+
StrategyExecutor,
|
|
875
|
+
IterationStrategyFactory,
|
|
876
|
+
configureModel,
|
|
877
|
+
configureSecureLogging
|
|
878
|
+
} from '@riotprompt/riotprompt';
|
|
879
|
+
import { z } from 'zod';
|
|
880
|
+
|
|
881
|
+
// 1. Configure security
|
|
882
|
+
configureSecureLogging({
|
|
883
|
+
maskSecrets: true,
|
|
884
|
+
level: 'info'
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
// 2. Register custom models (if needed)
|
|
888
|
+
configureModel({
|
|
889
|
+
exactMatch: 'my-custom-model',
|
|
890
|
+
personaRole: 'system',
|
|
891
|
+
encoding: 'cl100k_base',
|
|
892
|
+
family: 'custom'
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
// 3. Register templates
|
|
896
|
+
registerTemplates({
|
|
897
|
+
'code-assistant': {
|
|
898
|
+
persona: { content: 'You are an expert software engineer.' },
|
|
899
|
+
constraints: [{ content: 'Write clean, maintainable code.' }],
|
|
900
|
+
tone: [{ content: 'Be helpful and educational.' }]
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
// 4. Define output schema
|
|
905
|
+
const CodeReviewSchema = z.object({
|
|
906
|
+
issues: z.array(z.object({
|
|
907
|
+
severity: z.enum(['critical', 'warning', 'info']),
|
|
908
|
+
line: z.number().optional(),
|
|
909
|
+
message: z.string(),
|
|
910
|
+
suggestion: z.string().optional()
|
|
911
|
+
})),
|
|
912
|
+
summary: z.string(),
|
|
913
|
+
score: z.number().min(0).max(100)
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
// 5. Create tools
|
|
917
|
+
const toolRegistry = ToolRegistry.create({ workingDirectory: process.cwd() });
|
|
918
|
+
|
|
919
|
+
toolRegistry.register({
|
|
920
|
+
name: 'read_file',
|
|
921
|
+
description: 'Read a source file',
|
|
922
|
+
category: 'filesystem',
|
|
923
|
+
parameters: {
|
|
924
|
+
type: 'object',
|
|
925
|
+
properties: {
|
|
926
|
+
path: { type: 'string', description: 'File path' }
|
|
927
|
+
},
|
|
928
|
+
required: ['path']
|
|
929
|
+
},
|
|
930
|
+
execute: async ({ path }) => {
|
|
931
|
+
const fs = await import('fs/promises');
|
|
932
|
+
return await fs.readFile(path, 'utf-8');
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
toolRegistry.register({
|
|
937
|
+
name: 'list_files',
|
|
938
|
+
description: 'List files in a directory',
|
|
939
|
+
category: 'filesystem',
|
|
940
|
+
parameters: {
|
|
941
|
+
type: 'object',
|
|
942
|
+
properties: {
|
|
943
|
+
directory: { type: 'string', description: 'Directory path' }
|
|
944
|
+
},
|
|
945
|
+
required: ['directory']
|
|
946
|
+
},
|
|
947
|
+
execute: async ({ directory }) => {
|
|
948
|
+
const fs = await import('fs/promises');
|
|
949
|
+
return await fs.readdir(directory);
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
// 6. Create prompt
|
|
954
|
+
async function createCodeReviewPrompt(prDescription: string) {
|
|
955
|
+
return await cook({
|
|
956
|
+
basePath: __dirname,
|
|
957
|
+
template: 'code-assistant',
|
|
958
|
+
instructions: [
|
|
959
|
+
{ content: 'Review the code changes in this pull request.' },
|
|
960
|
+
{ content: 'Use tools to read the relevant files.' },
|
|
961
|
+
{ content: 'Identify bugs, security issues, and improvements.' }
|
|
962
|
+
],
|
|
963
|
+
content: [
|
|
964
|
+
{ content: prDescription, title: 'Pull Request' }
|
|
965
|
+
],
|
|
966
|
+
schema: CodeReviewSchema,
|
|
967
|
+
tools: toolRegistry,
|
|
968
|
+
toolGuidance: 'detailed'
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// 7. Create LLM client
|
|
973
|
+
function createLLMClient(apiKey: string) {
|
|
974
|
+
return {
|
|
975
|
+
async complete(messages: any[], tools?: any[]) {
|
|
976
|
+
// Your LLM provider integration
|
|
977
|
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
978
|
+
method: 'POST',
|
|
979
|
+
headers: {
|
|
980
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
981
|
+
'Content-Type': 'application/json'
|
|
982
|
+
},
|
|
983
|
+
body: JSON.stringify({
|
|
984
|
+
model: 'gpt-4o',
|
|
985
|
+
messages,
|
|
986
|
+
tools
|
|
987
|
+
})
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
const data = await response.json();
|
|
991
|
+
return {
|
|
992
|
+
content: data.choices[0].message.content,
|
|
993
|
+
tool_calls: data.choices[0].message.tool_calls
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// 8. Execute agentic workflow
|
|
1000
|
+
async function reviewPullRequest(prDescription: string, apiKey: string) {
|
|
1001
|
+
const prompt = await createCodeReviewPrompt(prDescription);
|
|
1002
|
+
|
|
1003
|
+
const conversation = ConversationBuilder.create({ model: 'gpt-4o' })
|
|
1004
|
+
.fromPrompt(prompt, 'gpt-4o')
|
|
1005
|
+
.withTokenBudget({ max: 100000, reserve: 4000 })
|
|
1006
|
+
.withLogging({ outputPath: './logs', format: 'json' })
|
|
1007
|
+
.build();
|
|
1008
|
+
|
|
1009
|
+
const llmClient = createLLMClient(apiKey);
|
|
1010
|
+
|
|
1011
|
+
const executor = new StrategyExecutor(llmClient)
|
|
1012
|
+
.withReflection({
|
|
1013
|
+
enabled: true,
|
|
1014
|
+
outputPath: './reflections',
|
|
1015
|
+
format: 'markdown'
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
const result = await executor.execute(
|
|
1019
|
+
conversation,
|
|
1020
|
+
toolRegistry,
|
|
1021
|
+
IterationStrategyFactory.investigateThenRespond({
|
|
1022
|
+
maxInvestigationSteps: 10,
|
|
1023
|
+
requireMinimumTools: 2
|
|
1024
|
+
})
|
|
1025
|
+
);
|
|
1026
|
+
|
|
1027
|
+
// Save conversation log
|
|
1028
|
+
await conversation.saveLog();
|
|
1029
|
+
|
|
1030
|
+
return {
|
|
1031
|
+
review: result.finalMessage?.content,
|
|
1032
|
+
iterations: result.totalIterations,
|
|
1033
|
+
toolsUsed: result.toolCallsExecuted,
|
|
1034
|
+
reflection: result.reflection
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// Usage
|
|
1039
|
+
const result = await reviewPullRequest(
|
|
1040
|
+
'Add user authentication with JWT tokens',
|
|
1041
|
+
process.env.OPENAI_API_KEY!
|
|
1042
|
+
);
|
|
1043
|
+
|
|
1044
|
+
console.log('Review:', result.review);
|
|
1045
|
+
console.log('Completed in', result.iterations, 'iterations');
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
## Type Reference
|
|
1049
|
+
|
|
1050
|
+
### Core Types
|
|
1051
|
+
|
|
1052
|
+
```typescript
|
|
1053
|
+
import type {
|
|
1054
|
+
// Prompt structure
|
|
1055
|
+
Prompt,
|
|
1056
|
+
Section,
|
|
1057
|
+
Content,
|
|
1058
|
+
Context,
|
|
1059
|
+
Instruction,
|
|
1060
|
+
Weighted,
|
|
1061
|
+
Parameters,
|
|
1062
|
+
|
|
1063
|
+
// Recipes
|
|
1064
|
+
RecipeConfig,
|
|
1065
|
+
ContentItem,
|
|
1066
|
+
TemplateConfig,
|
|
1067
|
+
ToolGuidanceConfig,
|
|
1068
|
+
|
|
1069
|
+
// Conversation
|
|
1070
|
+
ConversationMessage,
|
|
1071
|
+
ConversationBuilderConfig,
|
|
1072
|
+
ConversationMetadata,
|
|
1073
|
+
ToolCall,
|
|
1074
|
+
InjectOptions,
|
|
1075
|
+
|
|
1076
|
+
// Tools
|
|
1077
|
+
Tool,
|
|
1078
|
+
ToolParameter,
|
|
1079
|
+
ToolContext,
|
|
1080
|
+
ToolDefinition,
|
|
1081
|
+
ToolUsageStats,
|
|
1082
|
+
|
|
1083
|
+
// Strategies
|
|
1084
|
+
IterationStrategy,
|
|
1085
|
+
StrategyPhase,
|
|
1086
|
+
StrategyState,
|
|
1087
|
+
StrategyResult,
|
|
1088
|
+
ToolUsagePolicy,
|
|
1089
|
+
|
|
1090
|
+
// Reflection
|
|
1091
|
+
ReflectionReport,
|
|
1092
|
+
ReflectionConfig,
|
|
1093
|
+
|
|
1094
|
+
// Model config
|
|
1095
|
+
ModelConfig,
|
|
1096
|
+
PersonaRole,
|
|
1097
|
+
|
|
1098
|
+
// Security
|
|
1099
|
+
SecurityConfig,
|
|
1100
|
+
PathSecurityConfig
|
|
1101
|
+
} from '@riotprompt/riotprompt';
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
## Next Steps
|
|
1105
|
+
|
|
1106
|
+
- [Architecture](./architecture.md): Understand the internal design
|
|
1107
|
+
- [Configuration](./configuration.md): Deep dive into configuration options
|
|
1108
|
+
- [Security](./security.md): Security best practices
|
|
1109
|
+
- [Usage Patterns](./usage.md): CLI and common patterns
|