prompt_manager 0.5.7 → 0.5.8
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/COMMITS.md +196 -0
- data/README.md +485 -203
- data/docs/.keep +0 -0
- data/docs/advanced/custom-keywords.md +421 -0
- data/docs/advanced/dynamic-directives.md +535 -0
- data/docs/advanced/performance.md +612 -0
- data/docs/advanced/search-integration.md +635 -0
- data/docs/api/configuration.md +355 -0
- data/docs/api/directive-processor.md +431 -0
- data/docs/api/prompt-class.md +354 -0
- data/docs/api/storage-adapters.md +462 -0
- data/docs/assets/favicon.ico +1 -0
- data/docs/assets/logo.svg +24 -0
- data/docs/core-features/comments.md +48 -0
- data/docs/core-features/directive-processing.md +38 -0
- data/docs/core-features/erb-integration.md +68 -0
- data/docs/core-features/error-handling.md +197 -0
- data/docs/core-features/parameter-history.md +76 -0
- data/docs/core-features/parameterized-prompts.md +500 -0
- data/docs/core-features/shell-integration.md +79 -0
- data/docs/development/architecture.md +544 -0
- data/docs/development/contributing.md +425 -0
- data/docs/development/roadmap.md +234 -0
- data/docs/development/testing.md +822 -0
- data/docs/examples/advanced.md +523 -0
- data/docs/examples/basic.md +688 -0
- data/docs/examples/real-world.md +776 -0
- data/docs/examples.md +337 -0
- data/docs/getting-started/basic-concepts.md +318 -0
- data/docs/getting-started/installation.md +97 -0
- data/docs/getting-started/quick-start.md +256 -0
- data/docs/index.md +230 -0
- data/docs/migration/v0.9.0.md +459 -0
- data/docs/migration/v1.0.0.md +591 -0
- data/docs/storage/activerecord-adapter.md +348 -0
- data/docs/storage/custom-adapters.md +176 -0
- data/docs/storage/filesystem-adapter.md +236 -0
- data/docs/storage/overview.md +427 -0
- data/examples/advanced_integrations.rb +52 -0
- data/examples/prompts_dir/advanced_demo.txt +79 -0
- data/examples/prompts_dir/directive_example.json +1 -0
- data/examples/prompts_dir/directive_example.txt +8 -0
- data/examples/prompts_dir/todo.json +1 -1
- data/improvement_plan.md +996 -0
- data/lib/prompt_manager/storage/file_system_adapter.rb +8 -2
- data/lib/prompt_manager/version.rb +1 -1
- data/mkdocs.yml +146 -0
- data/prompt_manager_logo.png +0 -0
- metadata +46 -3
- data/LICENSE.txt +0 -21
data/docs/examples.md
ADDED
@@ -0,0 +1,337 @@
|
|
1
|
+
# Examples
|
2
|
+
|
3
|
+
This section provides comprehensive examples demonstrating various features and use cases of PromptManager.
|
4
|
+
|
5
|
+
## Basic Usage
|
6
|
+
|
7
|
+
The simplest way to get started with PromptManager:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# examples/simple.rb
|
11
|
+
require 'prompt_manager'
|
12
|
+
|
13
|
+
# Configure storage adapter
|
14
|
+
PromptManager::Prompt.storage_adapter =
|
15
|
+
PromptManager::Storage::FileSystemAdapter.config do |config|
|
16
|
+
config.prompts_dir = '~/.prompts'
|
17
|
+
end.new
|
18
|
+
|
19
|
+
# Create and use a prompt
|
20
|
+
prompt = PromptManager::Prompt.new(id: 'greeting')
|
21
|
+
prompt.parameters = {
|
22
|
+
"[NAME]" => "Alice",
|
23
|
+
"[LANGUAGE]" => "English"
|
24
|
+
}
|
25
|
+
|
26
|
+
# Get the processed prompt text
|
27
|
+
puts prompt.to_s
|
28
|
+
```
|
29
|
+
|
30
|
+
## Advanced Integration with LLM and Streaming
|
31
|
+
|
32
|
+
The [advanced_integrations.rb](https://github.com/MadBomber/prompt_manager/blob/main/examples/advanced_integrations.rb) example demonstrates a complete integration with OpenAI's API, showcasing:
|
33
|
+
|
34
|
+
### Features Demonstrated
|
35
|
+
|
36
|
+
- **ERB templating** for dynamic content generation
|
37
|
+
- **Shell integration** for environment variable substitution
|
38
|
+
- **OpenAI API integration** with streaming responses
|
39
|
+
- **Professional UI** with spinner feedback using `tty-spinner`
|
40
|
+
- **Real-time streaming** of LLM responses
|
41
|
+
|
42
|
+
### Code Overview
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
#!/usr/bin/env ruby
|
46
|
+
# frozen_string_literal: true
|
47
|
+
|
48
|
+
require 'bundler/inline'
|
49
|
+
|
50
|
+
gemfile do
|
51
|
+
source 'https://rubygems.org'
|
52
|
+
gem 'prompt_manager'
|
53
|
+
gem 'ruby-openai'
|
54
|
+
gem 'tty-spinner'
|
55
|
+
end
|
56
|
+
|
57
|
+
require 'prompt_manager'
|
58
|
+
require 'openai'
|
59
|
+
require 'erb'
|
60
|
+
require 'time'
|
61
|
+
require 'tty-spinner'
|
62
|
+
|
63
|
+
# Configure PromptManager with filesystem adapter
|
64
|
+
PromptManager::Prompt.storage_adapter = PromptManager::Storage::FileSystemAdapter.config do |config|
|
65
|
+
config.prompts_dir = File.join(__dir__, 'prompts_dir')
|
66
|
+
end.new
|
67
|
+
|
68
|
+
# Configure OpenAI client
|
69
|
+
client = OpenAI::Client.new(
|
70
|
+
access_token: ENV['OPENAI_API_KEY']
|
71
|
+
)
|
72
|
+
|
73
|
+
# Get prompt instance with advanced features enabled
|
74
|
+
prompt = PromptManager::Prompt.new(
|
75
|
+
id: 'advanced_demo',
|
76
|
+
erb_flag: true, # Enable ERB templating
|
77
|
+
envar_flag: true # Enable environment variable substitution
|
78
|
+
)
|
79
|
+
|
80
|
+
# Show spinner while waiting for response
|
81
|
+
spinner = TTY::Spinner.new("[:spinner] Waiting for response...")
|
82
|
+
spinner.auto_spin
|
83
|
+
|
84
|
+
# Stream the response from OpenAI
|
85
|
+
response = client.chat(
|
86
|
+
parameters: {
|
87
|
+
model: 'gpt-4o-mini',
|
88
|
+
messages: [{ role: 'user', content: prompt.to_s }],
|
89
|
+
stream: proc do |chunk, _bytesize|
|
90
|
+
spinner.stop
|
91
|
+
content = chunk.dig("choices", 0, "delta", "content")
|
92
|
+
print content if content
|
93
|
+
$stdout.flush
|
94
|
+
end
|
95
|
+
}
|
96
|
+
)
|
97
|
+
|
98
|
+
puts
|
99
|
+
```
|
100
|
+
|
101
|
+
### Prompt Template
|
102
|
+
|
103
|
+
The example uses a sophisticated prompt template ([advanced_demo.txt](https://github.com/MadBomber/prompt_manager/blob/main/examples/prompts_dir/advanced_demo.txt)) that demonstrates:
|
104
|
+
|
105
|
+
```text
|
106
|
+
# System Analysis and Historical Comparison Report
|
107
|
+
# Generated with PromptManager - ERB + Shell Integration Demo
|
108
|
+
|
109
|
+
```markdown
|
110
|
+
## Current System Information
|
111
|
+
|
112
|
+
**Timestamp**: <%= Time.now.strftime('%A, %B %d, %Y at %I:%M:%S %p %Z') %>
|
113
|
+
**Analysis Duration**: <%= Time.now - Time.parse('2024-01-01') %> seconds since 2024 began
|
114
|
+
|
115
|
+
### Hardware Platform Details
|
116
|
+
**Architecture**: $HOSTTYPE$MACHTYPE
|
117
|
+
**Hostname**: $HOSTNAME
|
118
|
+
**Operating System**: $OSTYPE
|
119
|
+
**Shell**: $SHELL (version: $BASH_VERSION)
|
120
|
+
**User**: $USER
|
121
|
+
**Home Directory**: $HOME
|
122
|
+
**Current Path**: $PWD
|
123
|
+
**Terminal**: $TERM
|
124
|
+
|
125
|
+
### Detailed System Profile
|
126
|
+
<% if RUBY_PLATFORM.include?('darwin') %>
|
127
|
+
**Platform**: macOS/Darwin System
|
128
|
+
**Ruby Platform**: <%= RUBY_PLATFORM %>
|
129
|
+
**Ruby Version**: <%= RUBY_VERSION %>
|
130
|
+
**Ruby Engine**: <%= RUBY_ENGINE %>
|
131
|
+
<% elsif RUBY_PLATFORM.include?('linux') %>
|
132
|
+
**Platform**: Linux System
|
133
|
+
**Ruby Platform**: <%= RUBY_PLATFORM %>
|
134
|
+
**Ruby Version**: <%= RUBY_VERSION %>
|
135
|
+
**Ruby Engine**: <%= RUBY_ENGINE %>
|
136
|
+
<% else %>
|
137
|
+
**Platform**: Other Unix-like System
|
138
|
+
**Ruby Platform**: <%= RUBY_PLATFORM %>
|
139
|
+
**Ruby Version**: <%= RUBY_VERSION %>
|
140
|
+
**Ruby Engine**: <%= RUBY_ENGINE %>
|
141
|
+
<% end %>
|
142
|
+
|
143
|
+
### Performance Context
|
144
|
+
**Load Average**: <%= `uptime`.strip rescue 'Unable to determine' %>
|
145
|
+
**Memory Info**: <%= `vm_stat | head -5`.strip rescue 'Unable to determine' if RUBY_PLATFORM.include?('darwin') %>
|
146
|
+
**Disk Usage**: <%= `df -h / | tail -1`.strip rescue 'Unable to determine' %>
|
147
|
+
|
148
|
+
## Analysis Request
|
149
|
+
|
150
|
+
You are a technology historian and systems analyst. Please provide a comprehensive comparison between this current system and **the most powerful Apple computer created in the 20th century** (which would be from the 1990s).
|
151
|
+
```
|
152
|
+
|
153
|
+
### Key Benefits
|
154
|
+
|
155
|
+
1. **Dynamic Content**: ERB templating allows for real-time system information gathering
|
156
|
+
2. **Environment Awareness**: Shell integration provides current system context
|
157
|
+
3. **Professional UX**: Spinner provides visual feedback during API calls
|
158
|
+
4. **Real-time Streaming**: Users see responses as they're generated
|
159
|
+
5. **Comprehensive Analysis**: The prompt generates detailed technical comparisons
|
160
|
+
|
161
|
+
## Search Integration
|
162
|
+
|
163
|
+
See [using_search_proc.rb](https://github.com/MadBomber/prompt_manager/blob/main/examples/using_search_proc.rb) for advanced search capabilities:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
# Configure custom search with ripgrep
|
167
|
+
PromptManager::Storage::FileSystemAdapter.config do |config|
|
168
|
+
config.prompts_dir = '~/.prompts'
|
169
|
+
config.search_proc = ->(query) {
|
170
|
+
# Use ripgrep for fast searching
|
171
|
+
`rg -l "#{query}" #{config.prompts_dir}`.split("\n")
|
172
|
+
.map { |path| File.basename(path, '.txt') }
|
173
|
+
}
|
174
|
+
end.new
|
175
|
+
|
176
|
+
# Search for prompts containing specific terms
|
177
|
+
results = PromptManager::Prompt.search("database queries")
|
178
|
+
puts "Found prompts: #{results.join(', ')}"
|
179
|
+
```
|
180
|
+
|
181
|
+
## Parameter Management
|
182
|
+
|
183
|
+
### Basic Parameters
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
prompt = PromptManager::Prompt.new(id: 'template')
|
187
|
+
prompt.parameters = {
|
188
|
+
"[NAME]" => "John",
|
189
|
+
"[ROLE]" => "developer",
|
190
|
+
"[PROJECT]" => "web application"
|
191
|
+
}
|
192
|
+
```
|
193
|
+
|
194
|
+
### Parameter History
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
# Parameters support history tracking
|
198
|
+
prompt.parameters = {
|
199
|
+
"[NAME]" => ["Alice", "Bob", "Charlie"] # Charlie is most recent
|
200
|
+
}
|
201
|
+
|
202
|
+
# Access current value
|
203
|
+
current_name = prompt.parameters["[NAME]"].last
|
204
|
+
|
205
|
+
# Access history
|
206
|
+
name_history = prompt.parameters["[NAME]"]
|
207
|
+
```
|
208
|
+
|
209
|
+
## Custom Storage Adapters
|
210
|
+
|
211
|
+
### Redis Storage Example
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
require 'redis'
|
215
|
+
require 'json'
|
216
|
+
|
217
|
+
class RedisAdapter
|
218
|
+
def initialize(redis_client)
|
219
|
+
@redis = redis_client
|
220
|
+
end
|
221
|
+
|
222
|
+
def get(id:)
|
223
|
+
{
|
224
|
+
id: id,
|
225
|
+
text: @redis.get("prompt:#{id}:text") || "",
|
226
|
+
parameters: JSON.parse(@redis.get("prompt:#{id}:params") || '{}')
|
227
|
+
}
|
228
|
+
end
|
229
|
+
|
230
|
+
def save(id:, text:, parameters:)
|
231
|
+
@redis.set("prompt:#{id}:text", text)
|
232
|
+
@redis.set("prompt:#{id}:params", parameters.to_json)
|
233
|
+
end
|
234
|
+
|
235
|
+
def delete(id:)
|
236
|
+
@redis.del("prompt:#{id}:text", "prompt:#{id}:params")
|
237
|
+
end
|
238
|
+
|
239
|
+
def search(query)
|
240
|
+
# Simple search implementation
|
241
|
+
@redis.keys("prompt:*:text").select do |key|
|
242
|
+
content = @redis.get(key)
|
243
|
+
content&.include?(query)
|
244
|
+
end.map { |key| key.split(':')[1] }
|
245
|
+
end
|
246
|
+
|
247
|
+
def list
|
248
|
+
@redis.keys("prompt:*:text").map { |key| key.split(':')[1] }
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# Usage
|
253
|
+
redis = Redis.new
|
254
|
+
PromptManager::Prompt.storage_adapter = RedisAdapter.new(redis)
|
255
|
+
```
|
256
|
+
|
257
|
+
## Directive Processing
|
258
|
+
|
259
|
+
### Custom Directives
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
class CustomDirectiveProcessor < PromptManager::DirectiveProcessor
|
263
|
+
def process_directive(directive, prompt)
|
264
|
+
case directive
|
265
|
+
when /^\/\/model (.+)$/
|
266
|
+
set_model($1)
|
267
|
+
when /^\/\/temperature (.+)$/
|
268
|
+
set_temperature($1.to_f)
|
269
|
+
when /^\/\/max_tokens (\d+)$/
|
270
|
+
set_max_tokens($1.to_i)
|
271
|
+
else
|
272
|
+
super # Handle built-in directives
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
|
278
|
+
def set_model(model)
|
279
|
+
@model = model
|
280
|
+
end
|
281
|
+
|
282
|
+
def set_temperature(temp)
|
283
|
+
@temperature = temp
|
284
|
+
end
|
285
|
+
|
286
|
+
def set_max_tokens(tokens)
|
287
|
+
@max_tokens = tokens
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# Usage
|
292
|
+
prompt = PromptManager::Prompt.new(
|
293
|
+
id: 'ai_prompt',
|
294
|
+
directives_processor: CustomDirectiveProcessor.new
|
295
|
+
)
|
296
|
+
```
|
297
|
+
|
298
|
+
## Error Handling
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
begin
|
302
|
+
prompt = PromptManager::Prompt.new(id: 'nonexistent')
|
303
|
+
result = prompt.to_s
|
304
|
+
rescue PromptManager::StorageError => e
|
305
|
+
puts "Storage error: #{e.message}"
|
306
|
+
rescue PromptManager::ParameterError => e
|
307
|
+
puts "Parameter error: #{e.message}"
|
308
|
+
rescue PromptManager::ConfigurationError => e
|
309
|
+
puts "Configuration error: #{e.message}"
|
310
|
+
end
|
311
|
+
```
|
312
|
+
|
313
|
+
## Testing Integration
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
# Test helper for prompt testing
|
317
|
+
def test_prompt(id, params = {})
|
318
|
+
prompt = PromptManager::Prompt.new(id: id)
|
319
|
+
prompt.parameters = params
|
320
|
+
prompt.to_s
|
321
|
+
end
|
322
|
+
|
323
|
+
# Example test
|
324
|
+
describe "greeting prompt" do
|
325
|
+
it "personalizes the greeting" do
|
326
|
+
result = test_prompt('greeting', {
|
327
|
+
"[NAME]" => "Alice",
|
328
|
+
"[TIME]" => "morning"
|
329
|
+
})
|
330
|
+
|
331
|
+
expect(result).to include("Hello Alice")
|
332
|
+
expect(result).to include("Good morning")
|
333
|
+
end
|
334
|
+
end
|
335
|
+
```
|
336
|
+
|
337
|
+
For more examples and advanced usage patterns, see the complete examples in the [examples/](https://github.com/MadBomber/prompt_manager/tree/main/examples) directory.
|
@@ -0,0 +1,318 @@
|
|
1
|
+
# Basic Concepts
|
2
|
+
|
3
|
+
Understanding these core concepts will help you make the most of PromptManager.
|
4
|
+
|
5
|
+
## The Prompt Lifecycle
|
6
|
+
|
7
|
+
Every prompt in PromptManager follows a predictable lifecycle:
|
8
|
+
|
9
|
+
```mermaid
|
10
|
+
graph TD
|
11
|
+
A[Create/Load Prompt] --> B[Parse Keywords]
|
12
|
+
B --> C[Set Parameters]
|
13
|
+
C --> D[Process Directives]
|
14
|
+
D --> E[Apply ERB Templates]
|
15
|
+
E --> F[Substitute Variables]
|
16
|
+
F --> G[Generate Final Text]
|
17
|
+
G --> H[Save Changes]
|
18
|
+
```
|
19
|
+
|
20
|
+
## Core Components
|
21
|
+
|
22
|
+
### 1. Prompts
|
23
|
+
|
24
|
+
A **Prompt** is the central entity in PromptManager. It represents a template with:
|
25
|
+
|
26
|
+
- **Text content** with embedded keywords
|
27
|
+
- **Parameters** (values for keywords)
|
28
|
+
- **Metadata** (directives, comments, configuration)
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
prompt = PromptManager::Prompt.new(
|
32
|
+
id: 'example', # Unique identifier
|
33
|
+
erb_flag: true, # Enable ERB processing
|
34
|
+
envar_flag: true # Enable environment variables
|
35
|
+
)
|
36
|
+
```
|
37
|
+
|
38
|
+
### 2. Keywords
|
39
|
+
|
40
|
+
**Keywords** are placeholders in your prompt text that get replaced with actual values:
|
41
|
+
|
42
|
+
```text
|
43
|
+
Hello [NAME], today is [DATE] and the weather is [WEATHER].
|
44
|
+
```
|
45
|
+
|
46
|
+
Default keyword format: `[UPPERCASE_WITH_UNDERSCORES]`
|
47
|
+
|
48
|
+
You can customize this pattern:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
# Use {{mustache}} style
|
52
|
+
PromptManager::Prompt.parameter_regex = /(\{\{[a-z_]+\}\})/
|
53
|
+
|
54
|
+
# Use :symbol style
|
55
|
+
PromptManager::Prompt.parameter_regex = /(:[a-z_]+)/
|
56
|
+
```
|
57
|
+
|
58
|
+
### 3. Parameters
|
59
|
+
|
60
|
+
**Parameters** are the actual values that replace keywords:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
prompt.parameters = {
|
64
|
+
"[NAME]" => "Alice",
|
65
|
+
"[DATE]" => Date.today.to_s,
|
66
|
+
"[WEATHER]" => "sunny"
|
67
|
+
}
|
68
|
+
```
|
69
|
+
|
70
|
+
Since v0.3.0, parameters store history as arrays:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
prompt.parameters = {
|
74
|
+
"[NAME]" => ["Alice", "Bob", "Charlie"] # Charlie is most recent
|
75
|
+
}
|
76
|
+
```
|
77
|
+
|
78
|
+
### 4. Storage Adapters
|
79
|
+
|
80
|
+
**Storage Adapters** handle how prompts are persisted:
|
81
|
+
|
82
|
+
=== "FileSystem"
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
PromptManager::Storage::FileSystemAdapter.config do |config|
|
86
|
+
config.prompts_dir = '~/.prompts'
|
87
|
+
config.prompt_extension = '.txt'
|
88
|
+
config.params_extension = '.json'
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
=== "ActiveRecord"
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
PromptManager::Storage::ActiveRecordAdapter.config do |config|
|
96
|
+
config.model = PromptModel
|
97
|
+
config.id_column = :name
|
98
|
+
config.text_column = :content
|
99
|
+
config.parameters_column = :params
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
### 5. Directives
|
104
|
+
|
105
|
+
**Directives** are special instructions that start with `//`:
|
106
|
+
|
107
|
+
```text
|
108
|
+
//include common/header.txt
|
109
|
+
//import templates/[TEMPLATE_TYPE].txt
|
110
|
+
|
111
|
+
Your main prompt content here...
|
112
|
+
```
|
113
|
+
|
114
|
+
## File Structure (FileSystem Adapter)
|
115
|
+
|
116
|
+
When using the FileSystem adapter, your prompts are organized like this:
|
117
|
+
|
118
|
+
```
|
119
|
+
~/.prompts/
|
120
|
+
├── greeting.txt # Prompt text
|
121
|
+
├── greeting.json # Parameters
|
122
|
+
├── translation.txt
|
123
|
+
├── translation.json
|
124
|
+
└── common/
|
125
|
+
├── header.txt # Shared components
|
126
|
+
└── footer.txt
|
127
|
+
```
|
128
|
+
|
129
|
+
### Prompt Files (`.txt`)
|
130
|
+
|
131
|
+
```text title="greeting.txt"
|
132
|
+
# Description: Friendly greeting prompt
|
133
|
+
# Tags: customer-service, greeting
|
134
|
+
# Version: 1.2
|
135
|
+
|
136
|
+
//include common/header.txt
|
137
|
+
|
138
|
+
Hello [CUSTOMER_NAME]!
|
139
|
+
|
140
|
+
Thank you for contacting [COMPANY_NAME]. I'm here to help you with
|
141
|
+
[REQUEST_TYPE]. Let me know how I can assist you today.
|
142
|
+
|
143
|
+
Best regards,
|
144
|
+
[AGENT_NAME]
|
145
|
+
|
146
|
+
__END__
|
147
|
+
Internal notes: This prompt is used for all initial customer contacts.
|
148
|
+
Update the company name parameter when client changes.
|
149
|
+
```
|
150
|
+
|
151
|
+
### Parameter Files (`.json`)
|
152
|
+
|
153
|
+
```json title="greeting.json"
|
154
|
+
{
|
155
|
+
"[CUSTOMER_NAME]": ["Alice Johnson", "Bob Smith"],
|
156
|
+
"[COMPANY_NAME]": ["Acme Corp"],
|
157
|
+
"[REQUEST_TYPE]": ["general inquiry", "technical support", "billing"],
|
158
|
+
"[AGENT_NAME]": ["Sarah", "Mike", "Jennifer"]
|
159
|
+
}
|
160
|
+
```
|
161
|
+
|
162
|
+
## Processing Pipeline
|
163
|
+
|
164
|
+
PromptManager processes prompts through several stages:
|
165
|
+
|
166
|
+
### 1. Text Loading
|
167
|
+
- Load raw prompt text from storage
|
168
|
+
- Parse out comments and `__END__` sections
|
169
|
+
|
170
|
+
### 2. Keyword Extraction
|
171
|
+
- Scan text for keyword patterns
|
172
|
+
- Build list of required parameters
|
173
|
+
|
174
|
+
### 3. Directive Processing
|
175
|
+
- Process `//include` and `//import` directives
|
176
|
+
- Handle loop protection for circular includes
|
177
|
+
- Substitute keywords in directive paths
|
178
|
+
|
179
|
+
### 4. Template Processing
|
180
|
+
- Apply ERB templates if `erb_flag` is true
|
181
|
+
- Substitute environment variables if `envar_flag` is true
|
182
|
+
|
183
|
+
### 5. Parameter Substitution
|
184
|
+
- Replace keywords with parameter values
|
185
|
+
- Handle missing parameters (error or warning)
|
186
|
+
|
187
|
+
### 6. Final Assembly
|
188
|
+
- Combine processed components
|
189
|
+
- Return final prompt text
|
190
|
+
|
191
|
+
## Error Handling
|
192
|
+
|
193
|
+
PromptManager provides specific error types:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
begin
|
197
|
+
prompt = PromptManager::Prompt.new(id: 'example')
|
198
|
+
puts prompt.to_s
|
199
|
+
rescue PromptManager::StorageError => e
|
200
|
+
puts "Storage problem: #{e.message}"
|
201
|
+
rescue PromptManager::ParameterError => e
|
202
|
+
puts "Parameter issue: #{e.message}"
|
203
|
+
rescue PromptManager::ConfigurationError => e
|
204
|
+
puts "Config problem: #{e.message}"
|
205
|
+
end
|
206
|
+
```
|
207
|
+
|
208
|
+
### Common Error Scenarios
|
209
|
+
|
210
|
+
| Error Type | Common Cause | Solution |
|
211
|
+
|------------|--------------|----------|
|
212
|
+
| `StorageError` | File not found, permission denied | Check file paths and permissions |
|
213
|
+
| `ParameterError` | Missing parameter value | Set all required parameters |
|
214
|
+
| `ConfigurationError` | Invalid adapter config | Review adapter configuration |
|
215
|
+
|
216
|
+
## Best Practices
|
217
|
+
|
218
|
+
### 1. Organize Your Prompts
|
219
|
+
|
220
|
+
```
|
221
|
+
prompts/
|
222
|
+
├── common/ # Shared components
|
223
|
+
│ ├── headers/
|
224
|
+
│ ├── footers/
|
225
|
+
│ └── signatures/
|
226
|
+
├── customer-service/ # Domain-specific prompts
|
227
|
+
├── technical/
|
228
|
+
└── templates/ # Reusable templates
|
229
|
+
```
|
230
|
+
|
231
|
+
### 2. Use Meaningful Keywords
|
232
|
+
|
233
|
+
```text
|
234
|
+
# Good - descriptive and clear
|
235
|
+
[CUSTOMER_NAME], [ORDER_NUMBER], [DELIVERY_DATE]
|
236
|
+
|
237
|
+
# Avoid - unclear abbreviations
|
238
|
+
[CN], [ON], [DD]
|
239
|
+
```
|
240
|
+
|
241
|
+
### 3. Document Your Prompts
|
242
|
+
|
243
|
+
```text
|
244
|
+
# Description: What this prompt does
|
245
|
+
# Tags: classification, tags
|
246
|
+
# Version: 1.0
|
247
|
+
# Author: Your Name
|
248
|
+
# Last Updated: 2024-01-15
|
249
|
+
|
250
|
+
//include common/disclaimer.txt
|
251
|
+
|
252
|
+
Your prompt content...
|
253
|
+
|
254
|
+
__END__
|
255
|
+
Internal notes, change history, and documentation go here.
|
256
|
+
This section is ignored by the processor.
|
257
|
+
```
|
258
|
+
|
259
|
+
### 4. Version Your Parameters
|
260
|
+
|
261
|
+
```json
|
262
|
+
{
|
263
|
+
"_meta": {
|
264
|
+
"version": "1.0",
|
265
|
+
"updated": "2024-01-15",
|
266
|
+
"notes": "Added new product categories"
|
267
|
+
},
|
268
|
+
"[CATEGORY]": ["electronics", "books", "clothing"]
|
269
|
+
}
|
270
|
+
```
|
271
|
+
|
272
|
+
## Advanced Concepts
|
273
|
+
|
274
|
+
### Parameter Validation
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
# Custom validation in your application
|
278
|
+
def validate_parameters(prompt)
|
279
|
+
required = prompt.keywords
|
280
|
+
provided = prompt.parameters.keys
|
281
|
+
missing = required - provided
|
282
|
+
|
283
|
+
raise "Missing parameters: #{missing.join(', ')}" unless missing.empty?
|
284
|
+
end
|
285
|
+
```
|
286
|
+
|
287
|
+
### Dynamic Prompts
|
288
|
+
|
289
|
+
```text
|
290
|
+
# Template selection based on parameters
|
291
|
+
//include templates/[TEMPLATE_TYPE].txt
|
292
|
+
|
293
|
+
# Conditional content using ERB
|
294
|
+
<% if '[URGENCY]' == 'high' %>
|
295
|
+
🚨 URGENT: Immediate attention required
|
296
|
+
<% end %>
|
297
|
+
```
|
298
|
+
|
299
|
+
### Search Integration
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
# Configure custom search
|
303
|
+
adapter.search_proc = ->(query) {
|
304
|
+
# Use ripgrep for fast search
|
305
|
+
`rg -l "#{query}" #{prompts_dir}`.split("\n").map { |f|
|
306
|
+
File.basename(f, '.txt')
|
307
|
+
}
|
308
|
+
}
|
309
|
+
```
|
310
|
+
|
311
|
+
## Next Steps
|
312
|
+
|
313
|
+
Now that you understand the basics:
|
314
|
+
|
315
|
+
1. **Try the examples** in [Core Features](../core-features/parameterized-prompts.md)
|
316
|
+
2. **Choose a storage adapter** in [Storage Adapters](../storage/overview.md)
|
317
|
+
3. **Explore advanced features** in [Advanced Usage](../advanced/custom-keywords.md)
|
318
|
+
4. **See real applications** in [Examples](../examples/basic.md)
|