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/improvement_plan.md
ADDED
@@ -0,0 +1,996 @@
|
|
1
|
+
# PromptManager Gem Improvement Plan
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
This document outlines potential improvements for the PromptManager gem based on a comprehensive code review conducted on 2025-09-01. The gem is currently at version 0.5.8 and is a key component of the AIA (AI Assistant) toolchain.
|
5
|
+
|
6
|
+
## Current State Assessment
|
7
|
+
- **Version**: 0.5.8
|
8
|
+
- **Overall Rating**: 8.5/10
|
9
|
+
- **Status**: Production-ready, actively maintained
|
10
|
+
- **Core Strengths**: Clean architecture, flexible storage adapters, thoughtful parameter management
|
11
|
+
|
12
|
+
## Improvement Categories
|
13
|
+
|
14
|
+
### 1. Parameter Format Flexibility
|
15
|
+
**Priority: HIGH**
|
16
|
+
**Effort: Low-Medium**
|
17
|
+
|
18
|
+
#### Support Multiple Parameter Formats
|
19
|
+
- Add support for `{{keyword}}` format (Liquid/Handlebars style)
|
20
|
+
- Maintain backward compatibility with `[KEYWORD]` format
|
21
|
+
- Allow users to configure their preferred format
|
22
|
+
- Auto-detect format from prompt content
|
23
|
+
|
24
|
+
#### Implementation Approach
|
25
|
+
```ruby
|
26
|
+
# Configuration options
|
27
|
+
PromptManager::Prompt.parameter_regex = :liquid # Use {{param}} style
|
28
|
+
PromptManager::Prompt.parameter_regex = :square # Use [PARAM] style (current)
|
29
|
+
PromptManager::Prompt.parameter_regex = :auto # Auto-detect from content
|
30
|
+
|
31
|
+
# Or custom regex
|
32
|
+
PromptManager::Prompt.parameter_regex = /\{\{([^}]+)\}\}/
|
33
|
+
|
34
|
+
# Pre-defined format constants
|
35
|
+
PARAM_FORMATS = {
|
36
|
+
square: /(\[[A-Z _|]+\])/, # Current: [KEYWORD]
|
37
|
+
liquid: /\{\{([^}]+)\}\}/, # Liquid: {{keyword}}
|
38
|
+
handlebars: /\{\{([^}]+)\}\}/, # Same as liquid
|
39
|
+
erb: /<%=\s*([^%>]+)\s*%>/, # ERB style: <%= keyword %>
|
40
|
+
dollar: /\$\{([^}]+)\}/ # Shell style: ${keyword}
|
41
|
+
}
|
42
|
+
```
|
43
|
+
|
44
|
+
#### Auto-detection Logic
|
45
|
+
- Scan prompt for different formats
|
46
|
+
- Use the most prevalent format found
|
47
|
+
- Warn if multiple formats detected
|
48
|
+
|
49
|
+
### 2. Markdown as First-Class Format
|
50
|
+
**Priority: HIGH**
|
51
|
+
**Effort: Medium**
|
52
|
+
|
53
|
+
#### Native Markdown Support
|
54
|
+
- Treat Markdown as the default prompt format
|
55
|
+
- Parse and preserve Markdown structure
|
56
|
+
- Special handling for:
|
57
|
+
- Code blocks (preserve without parameter substitution)
|
58
|
+
- Headers for prompt metadata
|
59
|
+
- Lists for structured content
|
60
|
+
- Front matter (YAML) for prompt configuration
|
61
|
+
|
62
|
+
#### Markdown-Aware Features with YAML Front Matter
|
63
|
+
```markdown
|
64
|
+
---
|
65
|
+
# Prompt Metadata (always preserved, never sent to LLM)
|
66
|
+
title: Customer Support Response
|
67
|
+
description: Template for responding to customer service inquiries with empathy and professionalism
|
68
|
+
version: 2.1
|
69
|
+
keywords: [customer-service, support, response-template]
|
70
|
+
|
71
|
+
# LLM Configuration (can be used by the calling application)
|
72
|
+
model: gpt-4
|
73
|
+
temperature: 0.7
|
74
|
+
max_tokens: 500
|
75
|
+
top_p: 0.9
|
76
|
+
frequency_penalty: 0.0
|
77
|
+
presence_penalty: 0.0
|
78
|
+
|
79
|
+
# Parameter Descriptions (for documentation and validation)
|
80
|
+
parameters:
|
81
|
+
company_name:
|
82
|
+
description: The name of the company providing support
|
83
|
+
type: string
|
84
|
+
required: true
|
85
|
+
product:
|
86
|
+
description: The product the customer is asking about
|
87
|
+
type: string
|
88
|
+
required: true
|
89
|
+
customer_tier:
|
90
|
+
description: Customer tier level (bronze, silver, gold, platinum)
|
91
|
+
type: string
|
92
|
+
default: silver
|
93
|
+
enum: [bronze, silver, gold, platinum]
|
94
|
+
customer_message:
|
95
|
+
description: The customer's inquiry or complaint
|
96
|
+
type: string
|
97
|
+
required: true
|
98
|
+
max_length: 1000
|
99
|
+
max_words:
|
100
|
+
description: Maximum words for the response
|
101
|
+
type: integer
|
102
|
+
default: 200
|
103
|
+
min: 50
|
104
|
+
max: 500
|
105
|
+
---
|
106
|
+
|
107
|
+
# System Prompt
|
108
|
+
You are a helpful customer support agent for {{company_name}}.
|
109
|
+
|
110
|
+
## Context
|
111
|
+
- Product: {{product}}
|
112
|
+
- Customer tier: {{customer_tier}}
|
113
|
+
|
114
|
+
## Task
|
115
|
+
Respond to the following customer inquiry:
|
116
|
+
|
117
|
+
```
|
118
|
+
{{customer_message}}
|
119
|
+
```
|
120
|
+
|
121
|
+
Keep your response under {{max_words}} words.
|
122
|
+
```
|
123
|
+
|
124
|
+
#### YAML Front Matter Standard Fields
|
125
|
+
|
126
|
+
##### Core Metadata
|
127
|
+
```yaml
|
128
|
+
---
|
129
|
+
# Required fields
|
130
|
+
title: Short descriptive title
|
131
|
+
description: One-line description of what this prompt does
|
132
|
+
|
133
|
+
# Optional but recommended
|
134
|
+
version: Semantic version (e.g., 1.2.3)
|
135
|
+
keywords: [tag1, tag2, tag3] # For search and categorization
|
136
|
+
author: Developer name or team
|
137
|
+
created: 2024-01-15
|
138
|
+
updated: 2024-12-20
|
139
|
+
---
|
140
|
+
```
|
141
|
+
|
142
|
+
##### LLM Configuration
|
143
|
+
```yaml
|
144
|
+
---
|
145
|
+
# Common LLM parameters that apps can use
|
146
|
+
model: gpt-4 # or claude-3, llama-2, etc.
|
147
|
+
temperature: 0.7
|
148
|
+
max_tokens: 1000
|
149
|
+
top_p: 0.9
|
150
|
+
frequency_penalty: 0.0
|
151
|
+
presence_penalty: 0.0
|
152
|
+
stream: false
|
153
|
+
system_prompt: "You are a helpful assistant" # If separate from main prompt
|
154
|
+
---
|
155
|
+
```
|
156
|
+
|
157
|
+
##### Parameter Documentation
|
158
|
+
```yaml
|
159
|
+
---
|
160
|
+
parameters:
|
161
|
+
parameter_name:
|
162
|
+
description: What this parameter is for
|
163
|
+
type: string|integer|number|boolean|array
|
164
|
+
required: true|false
|
165
|
+
default: Default value if not provided
|
166
|
+
enum: [option1, option2, option3] # If limited choices
|
167
|
+
min: 0 # For numbers
|
168
|
+
max: 100 # For numbers
|
169
|
+
max_length: 500 # For strings
|
170
|
+
pattern: "^[A-Z]+$" # Regex validation
|
171
|
+
example: "Example value"
|
172
|
+
---
|
173
|
+
```
|
174
|
+
|
175
|
+
#### Benefits of YAML Front Matter
|
176
|
+
- **Self-documenting**: Parameters are documented where they're used
|
177
|
+
- **Validation-ready**: Type information enables runtime validation
|
178
|
+
- **Tool-friendly**: IDEs can provide better autocomplete with parameter descriptions
|
179
|
+
- **Searchable**: Keywords make prompts discoverable
|
180
|
+
- **Configuration**: LLM settings travel with the prompt
|
181
|
+
|
182
|
+
#### Implementation
|
183
|
+
```ruby
|
184
|
+
class PromptManager::Prompt
|
185
|
+
attr_reader :metadata, :llm_config, :parameter_specs
|
186
|
+
|
187
|
+
def initialize(id:, storage_adapter: nil)
|
188
|
+
@storage_adapter = storage_adapter || self.class.storage_adapter
|
189
|
+
load_prompt(id)
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
|
194
|
+
def load_prompt(id)
|
195
|
+
content = @storage_adapter.get(id: id)
|
196
|
+
parse_markdown_prompt(content[:text])
|
197
|
+
end
|
198
|
+
|
199
|
+
def parse_markdown_prompt(text)
|
200
|
+
# Extract front matter
|
201
|
+
if text =~ /\A---\n(.*?)\n---\n(.*)/m
|
202
|
+
front_matter = YAML.safe_load($1)
|
203
|
+
prompt_body = $2
|
204
|
+
|
205
|
+
# Separate metadata categories
|
206
|
+
@metadata = extract_metadata(front_matter)
|
207
|
+
@llm_config = extract_llm_config(front_matter)
|
208
|
+
@parameter_specs = front_matter['parameters'] || {}
|
209
|
+
|
210
|
+
# Process the prompt body
|
211
|
+
@text = process_prompt_body(prompt_body)
|
212
|
+
else
|
213
|
+
@text = process_prompt_body(text)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def extract_metadata(fm)
|
218
|
+
{
|
219
|
+
title: fm['title'],
|
220
|
+
description: fm['description'],
|
221
|
+
version: fm['version'],
|
222
|
+
keywords: fm['keywords'] || [],
|
223
|
+
author: fm['author'],
|
224
|
+
created: fm['created'],
|
225
|
+
updated: fm['updated']
|
226
|
+
}.compact
|
227
|
+
end
|
228
|
+
|
229
|
+
def extract_llm_config(fm)
|
230
|
+
{
|
231
|
+
model: fm['model'],
|
232
|
+
temperature: fm['temperature'],
|
233
|
+
max_tokens: fm['max_tokens'],
|
234
|
+
top_p: fm['top_p'],
|
235
|
+
frequency_penalty: fm['frequency_penalty'],
|
236
|
+
presence_penalty: fm['presence_penalty']
|
237
|
+
}.compact
|
238
|
+
end
|
239
|
+
|
240
|
+
def validate_parameters(params)
|
241
|
+
@parameter_specs.each do |name, spec|
|
242
|
+
value = params[name] || params["{{#{name}}}"]
|
243
|
+
|
244
|
+
# Check required
|
245
|
+
if spec['required'] && value.nil?
|
246
|
+
raise ParameterError, "Required parameter '#{name}' is missing"
|
247
|
+
end
|
248
|
+
|
249
|
+
# Apply default if needed
|
250
|
+
if value.nil? && spec['default']
|
251
|
+
params[name] = spec['default']
|
252
|
+
next
|
253
|
+
end
|
254
|
+
|
255
|
+
# Type validation
|
256
|
+
validate_type(name, value, spec['type']) if value && spec['type']
|
257
|
+
|
258
|
+
# Enum validation
|
259
|
+
if spec['enum'] && value && !spec['enum'].include?(value)
|
260
|
+
raise ParameterError, "Parameter '#{name}' must be one of: #{spec['enum'].join(', ')}"
|
261
|
+
end
|
262
|
+
|
263
|
+
# Range validation for numbers
|
264
|
+
if spec['type'] == 'integer' || spec['type'] == 'number'
|
265
|
+
validate_range(name, value, spec['min'], spec['max'])
|
266
|
+
end
|
267
|
+
|
268
|
+
# Length validation for strings
|
269
|
+
if spec['type'] == 'string' && spec['max_length'] && value.length > spec['max_length']
|
270
|
+
raise ParameterError, "Parameter '#{name}' exceeds maximum length of #{spec['max_length']}"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
```
|
276
|
+
|
277
|
+
#### Usage Example
|
278
|
+
```ruby
|
279
|
+
prompt = PromptManager::Prompt.new(id: 'customer_support')
|
280
|
+
|
281
|
+
# Access metadata
|
282
|
+
puts prompt.metadata[:title] # "Customer Support Response"
|
283
|
+
puts prompt.metadata[:description] # "Template for responding to..."
|
284
|
+
|
285
|
+
# Access LLM configuration
|
286
|
+
puts prompt.llm_config[:temperature] # 0.7
|
287
|
+
puts prompt.llm_config[:model] # "gpt-4"
|
288
|
+
|
289
|
+
# Get parameter documentation
|
290
|
+
prompt.parameter_specs.each do |name, spec|
|
291
|
+
puts "#{name}: #{spec['description']}"
|
292
|
+
puts " Type: #{spec['type']}, Required: #{spec['required']}"
|
293
|
+
end
|
294
|
+
|
295
|
+
# Parameters are validated before substitution
|
296
|
+
prompt.parameters = {
|
297
|
+
'company_name' => 'Acme Corp',
|
298
|
+
'product' => 'Widget Pro',
|
299
|
+
'customer_tier' => 'gold',
|
300
|
+
'customer_message' => 'My widget is broken!'
|
301
|
+
} # Validates against parameter_specs
|
302
|
+
```
|
303
|
+
|
304
|
+
#### Benefits
|
305
|
+
- Prompts are more readable and maintainable
|
306
|
+
- Can leverage Markdown editors and preview tools
|
307
|
+
- Better documentation within prompts
|
308
|
+
- Supports rich formatting for complex prompts
|
309
|
+
- Self-contained prompt packages with all configuration
|
310
|
+
|
311
|
+
### 2a. Comment Handling in Markdown Prompts
|
312
|
+
**Priority: HIGH**
|
313
|
+
**Effort: Low-Medium**
|
314
|
+
|
315
|
+
#### The Challenge
|
316
|
+
Markdown files (`.md`) don't have a standard inline comment syntax that's hidden from rendering. We need a way to include developer notes that won't be sent to the LLM.
|
317
|
+
|
318
|
+
#### Proposed Solutions
|
319
|
+
|
320
|
+
##### Option 1: HTML Comments (Recommended)
|
321
|
+
```markdown
|
322
|
+
<!-- DEVELOPER NOTE: This prompt requires customer_name to be validated -->
|
323
|
+
# Customer Service Response
|
324
|
+
|
325
|
+
<!-- TODO: Add tone parameter to control formality -->
|
326
|
+
Hello {{customer_name}},
|
327
|
+
|
328
|
+
<!-- The following section is critical for compliance -->
|
329
|
+
We understand your concern about {{issue}}.
|
330
|
+
```
|
331
|
+
**Pros:**
|
332
|
+
- Standard HTML/Markdown convention
|
333
|
+
- Invisible in rendered Markdown
|
334
|
+
- Supported by all Markdown editors
|
335
|
+
- GitHub/GitLab render them as hidden
|
336
|
+
|
337
|
+
**Cons:**
|
338
|
+
- More verbose than `#` comments
|
339
|
+
- Can be accidentally included if not stripped properly
|
340
|
+
|
341
|
+
##### Option 2: Custom Markers
|
342
|
+
```markdown
|
343
|
+
%% DEVELOPER: This is a comment that won't be sent to LLM %%
|
344
|
+
# System Prompt
|
345
|
+
|
346
|
+
%% TODO: Add parameter validation %%
|
347
|
+
You are {{role}}.
|
348
|
+
|
349
|
+
### OR using different markers ###
|
350
|
+
|
351
|
+
[//]: # (This is a comment using Markdown's link reference syntax)
|
352
|
+
[//]: # (It's completely hidden in rendered output)
|
353
|
+
```
|
354
|
+
**Pros:**
|
355
|
+
- `%%` is used by Obsidian for comments
|
356
|
+
- `[//]: #` is valid Markdown that renders as nothing
|
357
|
+
- Can choose syntax that suits the team
|
358
|
+
|
359
|
+
**Cons:**
|
360
|
+
- Not universally recognized
|
361
|
+
- May confuse developers unfamiliar with the convention
|
362
|
+
|
363
|
+
##### Option 3: Front Matter Comments
|
364
|
+
```yaml
|
365
|
+
---
|
366
|
+
title: Customer Support
|
367
|
+
# Comments in YAML front matter
|
368
|
+
# These are for developers only
|
369
|
+
_dev_notes: |
|
370
|
+
This prompt requires the following parameters:
|
371
|
+
- customer_name: validated email
|
372
|
+
- issue: max 500 chars
|
373
|
+
_todo:
|
374
|
+
- Add sentiment analysis
|
375
|
+
- Test with GPT-4
|
376
|
+
---
|
377
|
+
```
|
378
|
+
**Pros:**
|
379
|
+
- Keeps all metadata in one place
|
380
|
+
- YAML supports comments natively
|
381
|
+
- Can have structured developer notes
|
382
|
+
|
383
|
+
**Cons:**
|
384
|
+
- Only works for header comments, not inline
|
385
|
+
- Might clutter front matter
|
386
|
+
|
387
|
+
##### Option 4: Special Code Blocks
|
388
|
+
````markdown
|
389
|
+
```comment
|
390
|
+
This is a developer comment block.
|
391
|
+
It will be stripped before sending to LLM.
|
392
|
+
Can contain multiple lines and formatting.
|
393
|
+
```
|
394
|
+
|
395
|
+
# Actual Prompt
|
396
|
+
Hello {{name}}
|
397
|
+
|
398
|
+
```dev-note
|
399
|
+
Remember to validate the name parameter
|
400
|
+
```
|
401
|
+
````
|
402
|
+
**Pros:**
|
403
|
+
- Clear visual distinction
|
404
|
+
- Can contain formatted content
|
405
|
+
- Easy to parse and remove
|
406
|
+
|
407
|
+
**Cons:**
|
408
|
+
- Takes more vertical space
|
409
|
+
- Not standard Markdown
|
410
|
+
|
411
|
+
#### Implementation Strategy
|
412
|
+
```ruby
|
413
|
+
class MarkdownPromptProcessor
|
414
|
+
COMMENT_PATTERNS = {
|
415
|
+
html: /<!--.*?-->/m,
|
416
|
+
obsidian: /%%.*?%%/m,
|
417
|
+
link_ref: /\[\/\/\]: # \(.*?\)/,
|
418
|
+
code_block: /```(?:comment|dev-note|note).*?```/m
|
419
|
+
}
|
420
|
+
|
421
|
+
def strip_comments(content, style: :html)
|
422
|
+
content.gsub(COMMENT_PATTERNS[style], '')
|
423
|
+
end
|
424
|
+
|
425
|
+
# Support multiple comment styles simultaneously
|
426
|
+
def strip_all_comments(content)
|
427
|
+
COMMENT_PATTERNS.values.reduce(content) do |text, pattern|
|
428
|
+
text.gsub(pattern, '')
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
```
|
433
|
+
|
434
|
+
#### Configuration Options
|
435
|
+
```ruby
|
436
|
+
PromptManager.configure do |config|
|
437
|
+
config.prompt_extension = '.md'
|
438
|
+
config.comment_style = :html # or :obsidian, :all
|
439
|
+
config.preserve_comments_in_storage = true # Keep comments in .md file
|
440
|
+
config.strip_comments_for_llm = true # Remove before sending to LLM
|
441
|
+
end
|
442
|
+
```
|
443
|
+
|
444
|
+
### 2b. The __END__ Marker in Markdown
|
445
|
+
**Priority: HIGH**
|
446
|
+
**Effort: Low**
|
447
|
+
|
448
|
+
#### Preserving the __END__ Convention
|
449
|
+
The `__END__` marker is a valuable convention from Ruby (and Perl) that provides a clear demarcation for "everything after this is not part of the main content." This is especially useful for:
|
450
|
+
- Extensive developer notes
|
451
|
+
- Test data and examples
|
452
|
+
- Changelog for the prompt
|
453
|
+
- Scratchpad for prompt iterations
|
454
|
+
- Reference materials
|
455
|
+
|
456
|
+
#### Implementation in Markdown Context
|
457
|
+
```markdown
|
458
|
+
---
|
459
|
+
title: Customer Support Agent
|
460
|
+
version: 3.2
|
461
|
+
---
|
462
|
+
|
463
|
+
# System Prompt
|
464
|
+
You are a helpful customer support agent for {{company_name}}.
|
465
|
+
|
466
|
+
<!-- inline comment about the tone parameter -->
|
467
|
+
Maintain a {{tone}} tone throughout your response.
|
468
|
+
|
469
|
+
## Your Task
|
470
|
+
Respond to: {{customer_message}}
|
471
|
+
|
472
|
+
__END__
|
473
|
+
|
474
|
+
# Developer Notes
|
475
|
+
This prompt has gone through several iterations:
|
476
|
+
- v3.2: Added tone parameter
|
477
|
+
- v3.1: Simplified the system prompt
|
478
|
+
- v3.0: Complete rewrite for GPT-4
|
479
|
+
|
480
|
+
# Test Cases
|
481
|
+
- customer_message: "I'm angry about my broken product!"
|
482
|
+
tone: "empathetic"
|
483
|
+
expected: Should acknowledge frustration
|
484
|
+
|
485
|
+
# Random thoughts
|
486
|
+
Maybe we should add a parameter for response length?
|
487
|
+
The client mentioned they want more formal responses for enterprise customers.
|
488
|
+
|
489
|
+
# Old version we might want to reference
|
490
|
+
You are a customer support representative who always...
|
491
|
+
(this was too verbose)
|
492
|
+
```
|
493
|
+
|
494
|
+
#### Benefits of Keeping __END__
|
495
|
+
1. **Unstructured Space**: Everything after `__END__` can be free-form without worrying about syntax
|
496
|
+
2. **Backward Compatible**: Existing prompts using this convention still work
|
497
|
+
3. **Clear Separation**: Visually obvious where the prompt ends
|
498
|
+
4. **No Escaping Needed**: After `__END__`, no need to worry about HTML comment syntax
|
499
|
+
5. **Markdown Friendly**: Can still use Markdown formatting in the notes section for readability
|
500
|
+
|
501
|
+
#### Processing Logic
|
502
|
+
```ruby
|
503
|
+
class MarkdownPromptProcessor
|
504
|
+
def process(content)
|
505
|
+
# Split at __END__ marker
|
506
|
+
parts = content.split(/^__END__$/m, 2)
|
507
|
+
|
508
|
+
prompt_content = parts[0]
|
509
|
+
developer_notes = parts[1] # Everything after __END__ (if present)
|
510
|
+
|
511
|
+
# Process only the prompt content
|
512
|
+
prompt_content = strip_html_comments(prompt_content)
|
513
|
+
prompt_content = substitute_parameters(prompt_content)
|
514
|
+
|
515
|
+
# Return processed prompt (developer_notes are never sent to LLM)
|
516
|
+
prompt_content
|
517
|
+
end
|
518
|
+
|
519
|
+
def save_to_storage(content)
|
520
|
+
# When saving, preserve everything including __END__ section
|
521
|
+
content
|
522
|
+
end
|
523
|
+
end
|
524
|
+
```
|
525
|
+
|
526
|
+
#### Combined Comment Strategy
|
527
|
+
```markdown
|
528
|
+
<!-- Quick inline comment -->
|
529
|
+
# Main Prompt
|
530
|
+
|
531
|
+
Here's the prompt with {{parameters}}.
|
532
|
+
|
533
|
+
<!-- Another inline note about the section below -->
|
534
|
+
## Special Instructions
|
535
|
+
|
536
|
+
Follow these guidelines:
|
537
|
+
<!-- TODO: Add more guidelines -->
|
538
|
+
- Be concise
|
539
|
+
- Be helpful
|
540
|
+
|
541
|
+
__END__
|
542
|
+
|
543
|
+
Everything down here is free-form developer notes.
|
544
|
+
No need for <!-- --> syntax.
|
545
|
+
Can paste examples, old versions, test cases, etc.
|
546
|
+
|
547
|
+
This section is NEVER sent to the LLM but is preserved in the .md file.
|
548
|
+
```
|
549
|
+
|
550
|
+
#### Configuration
|
551
|
+
```ruby
|
552
|
+
PromptManager.configure do |config|
|
553
|
+
config.prompt_extension = '.md'
|
554
|
+
config.comment_style = :html # For inline comments
|
555
|
+
config.honor_end_marker = true # Respect __END__ marker
|
556
|
+
config.end_marker = '__END__' # Customizable if needed
|
557
|
+
config.strip_comments_for_llm = true # Remove both HTML comments and __END__ section
|
558
|
+
end
|
559
|
+
```
|
560
|
+
|
561
|
+
### 3. Performance Optimizations
|
562
|
+
**Priority: Medium**
|
563
|
+
**Effort: Medium**
|
564
|
+
|
565
|
+
#### Optimize Parameter Parsing
|
566
|
+
- Current: Regex scanning on every parameter extraction
|
567
|
+
- Proposed: Cache parsed parameters with dirty tracking
|
568
|
+
- Implement lazy evaluation for large prompts
|
569
|
+
|
570
|
+
#### Benchmark-Driven Improvements
|
571
|
+
- Add performance benchmarks to test suite
|
572
|
+
- Profile regex operations for large prompts (>10KB)
|
573
|
+
- Consider using StringScanner for improved parsing performance
|
574
|
+
|
575
|
+
### 3. Storage Adapter Enhancements
|
576
|
+
**Priority: High**
|
577
|
+
**Effort: Low-Medium**
|
578
|
+
|
579
|
+
#### Formalize Storage Adapter Interface
|
580
|
+
```ruby
|
581
|
+
# lib/prompt_manager/storage/base_adapter.rb
|
582
|
+
module PromptManager
|
583
|
+
module Storage
|
584
|
+
class BaseAdapter
|
585
|
+
def get(id:)
|
586
|
+
raise NotImplementedError
|
587
|
+
end
|
588
|
+
|
589
|
+
def save(id:, text:, parameters:)
|
590
|
+
raise NotImplementedError
|
591
|
+
end
|
592
|
+
|
593
|
+
def delete(id:)
|
594
|
+
raise NotImplementedError
|
595
|
+
end
|
596
|
+
|
597
|
+
def list
|
598
|
+
raise NotImplementedError
|
599
|
+
end
|
600
|
+
|
601
|
+
def search(term:)
|
602
|
+
raise NotImplementedError
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
```
|
608
|
+
|
609
|
+
#### Add New Storage Adapters
|
610
|
+
- **RedisAdapter**: For high-performance caching
|
611
|
+
- **S3Adapter**: For cloud storage
|
612
|
+
- **PostgreSQLAdapter**: With JSONB support for parameters
|
613
|
+
- **MemoryAdapter**: For testing and temporary storage
|
614
|
+
|
615
|
+
### 4. Serialization Flexibility
|
616
|
+
**Priority: Medium**
|
617
|
+
**Effort: Low**
|
618
|
+
|
619
|
+
#### Make Serialization Pluggable
|
620
|
+
- Extract serialization into strategy pattern
|
621
|
+
- Support multiple formats:
|
622
|
+
- JSON (current)
|
623
|
+
- YAML
|
624
|
+
- MessagePack (for performance)
|
625
|
+
- Custom serializers
|
626
|
+
|
627
|
+
```ruby
|
628
|
+
class FileSystemAdapter
|
629
|
+
def initialize(serializer: JSONSerializer.new)
|
630
|
+
@serializer = serializer
|
631
|
+
end
|
632
|
+
end
|
633
|
+
```
|
634
|
+
|
635
|
+
### 5. Enhanced Directive System
|
636
|
+
**Priority: Medium-High**
|
637
|
+
**Effort: High**
|
638
|
+
|
639
|
+
#### Directive Registry
|
640
|
+
- Allow registration of custom directives
|
641
|
+
- Plugin architecture for directive processors
|
642
|
+
- Built-in directives:
|
643
|
+
- `//include` (existing)
|
644
|
+
- `//template` - ERB template processing
|
645
|
+
- `//exec` - Execute shell commands
|
646
|
+
- `//fetch` - Fetch content from URLs
|
647
|
+
- `//cache` - Cache directive results
|
648
|
+
|
649
|
+
#### Directive Middleware Chain
|
650
|
+
```ruby
|
651
|
+
class DirectiveProcessor
|
652
|
+
def register(name, handler)
|
653
|
+
@handlers[name] = handler
|
654
|
+
end
|
655
|
+
|
656
|
+
def process(directive_line)
|
657
|
+
middleware_chain.call(directive_line)
|
658
|
+
end
|
659
|
+
end
|
660
|
+
```
|
661
|
+
|
662
|
+
### 6. Parameter Management Improvements
|
663
|
+
**Priority: High**
|
664
|
+
**Effort: Medium**
|
665
|
+
|
666
|
+
#### Parameter Validation
|
667
|
+
- Add parameter type hints: `[NAME:string]`, `[AGE:number]`, `[ACTIVE:boolean]`
|
668
|
+
- Validation rules: required, optional, default values
|
669
|
+
- Pattern matching: `[EMAIL:email]`, `[URL:url]`
|
670
|
+
|
671
|
+
#### Parameter Inheritance
|
672
|
+
- Support prompt templates with parameter inheritance
|
673
|
+
- Base prompts that other prompts can extend
|
674
|
+
|
675
|
+
### 7. Testing and Quality Improvements
|
676
|
+
**Priority: Medium**
|
677
|
+
**Effort: Low**
|
678
|
+
|
679
|
+
#### Enhanced Test Coverage
|
680
|
+
- Add integration tests for storage adapters
|
681
|
+
- Property-based testing for parameter substitution
|
682
|
+
- Mutation testing to ensure test quality
|
683
|
+
|
684
|
+
#### CI/CD Improvements
|
685
|
+
- Add GitHub Actions for automated testing
|
686
|
+
- Code coverage badges
|
687
|
+
- Automated gem releases
|
688
|
+
|
689
|
+
### 8. Documentation and Examples
|
690
|
+
**Priority: Low-Medium**
|
691
|
+
**Effort: Low**
|
692
|
+
|
693
|
+
#### Improve Documentation
|
694
|
+
- Add YARD documentation to all public methods
|
695
|
+
- Create a documentation site (GitHub Pages)
|
696
|
+
- Video tutorials for common use cases
|
697
|
+
- Migration guides for version upgrades
|
698
|
+
|
699
|
+
#### Extended Examples
|
700
|
+
- Real-world use cases
|
701
|
+
- Integration examples with popular AI libraries
|
702
|
+
- Best practices guide
|
703
|
+
|
704
|
+
### 9. Backwards Compatibility Strategy
|
705
|
+
**Priority: High**
|
706
|
+
**Effort: Ongoing**
|
707
|
+
|
708
|
+
#### Versioning Strategy
|
709
|
+
- Follow Semantic Versioning strictly
|
710
|
+
- Deprecation warnings for breaking changes
|
711
|
+
- Migration tools for major version upgrades
|
712
|
+
|
713
|
+
### 10. New Features
|
714
|
+
**Priority: Low-Medium**
|
715
|
+
**Effort: Variable**
|
716
|
+
|
717
|
+
#### Prompt Versioning
|
718
|
+
- Track prompt history
|
719
|
+
- Rollback capabilities
|
720
|
+
- Diff viewing between versions
|
721
|
+
|
722
|
+
#### Prompt Marketplace/Sharing
|
723
|
+
- Export/import prompt packages
|
724
|
+
- Prompt templates repository
|
725
|
+
- Community sharing features
|
726
|
+
|
727
|
+
## Breaking Changes for v0.9.0
|
728
|
+
|
729
|
+
Since we're making format changes, let's bundle all breaking changes into v0.9.0:
|
730
|
+
|
731
|
+
### 1. File Format Changes (BREAKING)
|
732
|
+
- **Default extension**: `.txt` → `.md`
|
733
|
+
- **Parameter format**: `[KEYWORD]` → `{{keyword}}` (auto-detect for migration)
|
734
|
+
- **Front matter**: Add YAML front matter support
|
735
|
+
- **Serialization**: Keep JSON as default, add pluggable support (YAML, MessagePack optional)
|
736
|
+
|
737
|
+
### 2. API Changes (BREAKING)
|
738
|
+
```ruby
|
739
|
+
# Current v0.5.x API
|
740
|
+
prompt = PromptManager::Prompt.new(id: 'test')
|
741
|
+
prompt.parameters['[NAME]'] = 'value'
|
742
|
+
|
743
|
+
# New v0.9.0 API
|
744
|
+
prompt = PromptManager::Prompt.new(id: 'test')
|
745
|
+
prompt.set_parameter('name', 'value') # Cleaner API, but keeps '[NAME]' internally
|
746
|
+
prompt.metadata[:title] # Access to front matter
|
747
|
+
prompt.llm_config[:temperature] # LLM configuration
|
748
|
+
```
|
749
|
+
|
750
|
+
### 3. Storage Adapter Interface (BREAKING)
|
751
|
+
```ruby
|
752
|
+
# v0.5.x - informal interface
|
753
|
+
class MyAdapter
|
754
|
+
def get(id:); end
|
755
|
+
def save(id:, text:, parameters:); end
|
756
|
+
end
|
757
|
+
|
758
|
+
# v0.9.0 - formal interface with base class
|
759
|
+
class MyAdapter < PromptManager::Storage::BaseAdapter
|
760
|
+
def get(id:); end
|
761
|
+
def save(id:, text:, parameters:, metadata: {}, llm_config: {}); end
|
762
|
+
def delete(id:); end
|
763
|
+
def list(filter: {}); end
|
764
|
+
def search(query:, filters: {}); end
|
765
|
+
end
|
766
|
+
```
|
767
|
+
|
768
|
+
### 4. Parameter Handling (BREAKING)
|
769
|
+
```ruby
|
770
|
+
# v0.5.x - manual parameter management
|
771
|
+
prompt.parameters['[NAME]'] = ['value1', 'value2']
|
772
|
+
|
773
|
+
# v0.9.0 - simplified with validation
|
774
|
+
prompt.set_parameter('name', 'value2') # Automatically manages history, stores as '[NAME]'
|
775
|
+
prompt.validate_parameters! # Based on front matter specs
|
776
|
+
```
|
777
|
+
|
778
|
+
### 5. Configuration Changes (BREAKING)
|
779
|
+
```ruby
|
780
|
+
# v0.5.x
|
781
|
+
PromptManager::Storage::FileSystemAdapter.config do |config|
|
782
|
+
config.prompts_dir = 'path'
|
783
|
+
config.prompt_extension = '.txt'
|
784
|
+
config.params_extension = '.json'
|
785
|
+
end
|
786
|
+
|
787
|
+
# v0.9.0
|
788
|
+
PromptManager.configure do |config|
|
789
|
+
config.storage_adapter = :file_system
|
790
|
+
config.prompts_dir = 'path'
|
791
|
+
config.prompt_extension = '.md'
|
792
|
+
config.parameter_format = :liquid # {{}} style
|
793
|
+
config.serializer = :json # Keep JSON as default
|
794
|
+
config.validate_parameters = true
|
795
|
+
end
|
796
|
+
```
|
797
|
+
|
798
|
+
### 6. What We're NOT Changing (Staying Backward Compatible)
|
799
|
+
|
800
|
+
#### Keep JCL-Style Directives (NO CHANGE)
|
801
|
+
```ruby
|
802
|
+
# Keeping current JCL-style directives
|
803
|
+
//include path/to/file.txt
|
804
|
+
//import another/file.md
|
805
|
+
|
806
|
+
# These remain unchanged - familiar and working well
|
807
|
+
```
|
808
|
+
|
809
|
+
#### Keep Parameter Key Format (NO CHANGE)
|
810
|
+
```ruby
|
811
|
+
# Internal storage keeps current format
|
812
|
+
{
|
813
|
+
'[NAME]' => ['Alice', 'Bob'],
|
814
|
+
'[AGE]' => ['25', '30']
|
815
|
+
}
|
816
|
+
|
817
|
+
# New API abstracts this away:
|
818
|
+
prompt.set_parameter('name', 'Bob') # Becomes '[NAME]' internally
|
819
|
+
prompt.get_parameter('name') # Returns value for '[NAME]'
|
820
|
+
```
|
821
|
+
|
822
|
+
#### Keep JSON as Default Serializer (NO CHANGE)
|
823
|
+
```ruby
|
824
|
+
# JSON remains the default for .json parameter files
|
825
|
+
# YAML support added as optional feature for those who want it
|
826
|
+
```
|
827
|
+
|
828
|
+
#### Option C: Error Handling Overhaul
|
829
|
+
```ruby
|
830
|
+
# v0.5.x - basic errors
|
831
|
+
begin
|
832
|
+
prompt.to_s
|
833
|
+
rescue PromptManager::Error => e
|
834
|
+
# Generic error
|
835
|
+
end
|
836
|
+
|
837
|
+
# v1.0 - specific error types
|
838
|
+
begin
|
839
|
+
prompt.to_s
|
840
|
+
rescue PromptManager::ParameterValidationError => e
|
841
|
+
puts "Invalid parameter: #{e.parameter_name}"
|
842
|
+
rescue PromptManager::TemplateParsingError => e
|
843
|
+
puts "Template error at line #{e.line_number}"
|
844
|
+
rescue PromptManager::DirectiveError => e
|
845
|
+
puts "Directive '#{e.directive}' failed: #{e.message}"
|
846
|
+
end
|
847
|
+
```
|
848
|
+
|
849
|
+
#### Option D: Prompt Class Restructure
|
850
|
+
```ruby
|
851
|
+
# v0.5.x - monolithic Prompt class
|
852
|
+
class Prompt
|
853
|
+
# Everything mixed together
|
854
|
+
end
|
855
|
+
|
856
|
+
# v1.0 - separation of concerns
|
857
|
+
class Prompt
|
858
|
+
include Parameterizable
|
859
|
+
include Validatable
|
860
|
+
include Serializable
|
861
|
+
|
862
|
+
attr_reader :metadata, :llm_config, :content
|
863
|
+
end
|
864
|
+
```
|
865
|
+
|
866
|
+
## Implementation Roadmap (Revised)
|
867
|
+
|
868
|
+
### v0.9.0 - Breaking Changes Release (The Big Jump)
|
869
|
+
- [ ] Default to new formats (.md, {{}} parameters)
|
870
|
+
- [ ] YAML front matter support with metadata and LLM config
|
871
|
+
- [ ] New cleaner API (`set_parameter`, `get_parameter`)
|
872
|
+
- [ ] Formal storage adapter interface with base class
|
873
|
+
- [ ] Parameter validation system based on front matter
|
874
|
+
- [ ] Migration tools for automatic format conversion
|
875
|
+
- [ ] Backward compatibility for existing parameter access
|
876
|
+
- [ ] Keep JCL directives, bracket storage, JSON serialization
|
877
|
+
|
878
|
+
### v1.0.0 - Stability Release
|
879
|
+
- [ ] Performance optimizations and bug fixes
|
880
|
+
- [ ] Complete documentation with migration guide
|
881
|
+
- [ ] Production hardening based on v0.9 feedback
|
882
|
+
|
883
|
+
### v1.1.0 - Enhanced Features
|
884
|
+
- [ ] New storage adapters (Redis, S3)
|
885
|
+
- [ ] Performance optimizations
|
886
|
+
- [ ] Directive registry system
|
887
|
+
- [ ] Template inheritance
|
888
|
+
|
889
|
+
## Migration Strategy
|
890
|
+
|
891
|
+
### Automated Migration Tool
|
892
|
+
```bash
|
893
|
+
# Convert existing prompts to v0.9.0 format
|
894
|
+
prompt_manager migrate --from=0.5.x --to=0.9 --path=~/.prompts
|
895
|
+
|
896
|
+
# Preview changes without applying
|
897
|
+
prompt_manager migrate --dry-run --path=~/.prompts
|
898
|
+
|
899
|
+
# Convert specific aspects
|
900
|
+
prompt_manager migrate --parameters-only --path=~/.prompts
|
901
|
+
prompt_manager migrate --add-frontmatter --path=~/.prompts
|
902
|
+
```
|
903
|
+
|
904
|
+
### Migration Process
|
905
|
+
1. **Backup**: Always backup existing prompt directory
|
906
|
+
2. **Convert files**: `.txt` → `.md` with front matter injection
|
907
|
+
3. **Update parameters**: `[KEYWORD]` → `{{keyword}}`
|
908
|
+
4. **Generate specs**: Create parameter documentation in front matter
|
909
|
+
5. **Update JSON**: Convert parameter files to YAML (optional)
|
910
|
+
|
911
|
+
### Migration Example
|
912
|
+
```ruby
|
913
|
+
# Before migration: joke.txt
|
914
|
+
Tell me a [KIND] joke about [SUBJECT]
|
915
|
+
|
916
|
+
# joke.json
|
917
|
+
{
|
918
|
+
"[KIND]": ["pun", "family friendly"],
|
919
|
+
"[SUBJECT]": ["parrot", "garbage man"]
|
920
|
+
}
|
921
|
+
```
|
922
|
+
|
923
|
+
```markdown
|
924
|
+
# After migration: joke.md
|
925
|
+
---
|
926
|
+
title: Joke Generator
|
927
|
+
description: Generates jokes of specified type about a subject
|
928
|
+
version: 0.9.0
|
929
|
+
parameters:
|
930
|
+
kind:
|
931
|
+
description: Type of joke to generate
|
932
|
+
type: string
|
933
|
+
required: true
|
934
|
+
example: "pun"
|
935
|
+
subject:
|
936
|
+
description: Subject of the joke
|
937
|
+
type: string
|
938
|
+
required: true
|
939
|
+
example: "parrot"
|
940
|
+
---
|
941
|
+
|
942
|
+
Tell me a {{kind}} joke about {{subject}}
|
943
|
+
```
|
944
|
+
|
945
|
+
### Backward Compatibility Layer (v0.9.x)
|
946
|
+
```ruby
|
947
|
+
# Support both old and new syntax during transition
|
948
|
+
class Prompt
|
949
|
+
def parameters=(params)
|
950
|
+
if params.keys.first&.include?('[')
|
951
|
+
# Old format: convert automatically
|
952
|
+
deprecation_warning "Bracket format deprecated. Use set_parameter() instead."
|
953
|
+
params.each do |key, value|
|
954
|
+
clean_key = key.gsub(/[\[\]]/, '').downcase
|
955
|
+
set_parameter(clean_key, value)
|
956
|
+
end
|
957
|
+
else
|
958
|
+
# New format
|
959
|
+
params.each { |key, value| set_parameter(key, value) }
|
960
|
+
end
|
961
|
+
end
|
962
|
+
end
|
963
|
+
```
|
964
|
+
|
965
|
+
## Discussion Points
|
966
|
+
|
967
|
+
### Questions to Consider
|
968
|
+
1. Should {{keyword}} format become the default in v1.0?
|
969
|
+
2. How should we handle mixed parameter formats in a single prompt?
|
970
|
+
3. Should Markdown front matter replace the current comment-based metadata?
|
971
|
+
4. Is there value in supporting Liquid filters like {{name | upcase}}?
|
972
|
+
5. Should code blocks in Markdown always be parameter-substitution-free zones?
|
973
|
+
6. What other Markdown features need special handling (tables, links, images)?
|
974
|
+
|
975
|
+
### Trade-offs
|
976
|
+
- **Format Flexibility vs Complexity**: Supporting multiple formats adds parsing complexity
|
977
|
+
- **Markdown Features vs Performance**: Full Markdown parsing may impact performance
|
978
|
+
- **Backward Compatibility vs Modern Standards**: Moving to {{}} format may break existing prompts
|
979
|
+
- **Features vs Maintenance**: More formats mean more edge cases to handle
|
980
|
+
|
981
|
+
## Next Steps
|
982
|
+
1. Prioritize improvements based on user feedback
|
983
|
+
2. Create GitHub issues for each improvement
|
984
|
+
3. Set up a project board for tracking progress
|
985
|
+
4. Establish contribution guidelines for community involvement
|
986
|
+
5. Consider creating a beta release channel for testing new features
|
987
|
+
|
988
|
+
## Notes
|
989
|
+
- This plan is a living document and should be updated as development progresses
|
990
|
+
- Community feedback should be actively sought and incorporated
|
991
|
+
- Breaking changes should be minimized and well-documented when necessary
|
992
|
+
|
993
|
+
---
|
994
|
+
|
995
|
+
*Last Updated: 2025-09-01*
|
996
|
+
*Version: 1.0*
|