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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/COMMITS.md +196 -0
  4. data/README.md +485 -203
  5. data/docs/.keep +0 -0
  6. data/docs/advanced/custom-keywords.md +421 -0
  7. data/docs/advanced/dynamic-directives.md +535 -0
  8. data/docs/advanced/performance.md +612 -0
  9. data/docs/advanced/search-integration.md +635 -0
  10. data/docs/api/configuration.md +355 -0
  11. data/docs/api/directive-processor.md +431 -0
  12. data/docs/api/prompt-class.md +354 -0
  13. data/docs/api/storage-adapters.md +462 -0
  14. data/docs/assets/favicon.ico +1 -0
  15. data/docs/assets/logo.svg +24 -0
  16. data/docs/core-features/comments.md +48 -0
  17. data/docs/core-features/directive-processing.md +38 -0
  18. data/docs/core-features/erb-integration.md +68 -0
  19. data/docs/core-features/error-handling.md +197 -0
  20. data/docs/core-features/parameter-history.md +76 -0
  21. data/docs/core-features/parameterized-prompts.md +500 -0
  22. data/docs/core-features/shell-integration.md +79 -0
  23. data/docs/development/architecture.md +544 -0
  24. data/docs/development/contributing.md +425 -0
  25. data/docs/development/roadmap.md +234 -0
  26. data/docs/development/testing.md +822 -0
  27. data/docs/examples/advanced.md +523 -0
  28. data/docs/examples/basic.md +688 -0
  29. data/docs/examples/real-world.md +776 -0
  30. data/docs/examples.md +337 -0
  31. data/docs/getting-started/basic-concepts.md +318 -0
  32. data/docs/getting-started/installation.md +97 -0
  33. data/docs/getting-started/quick-start.md +256 -0
  34. data/docs/index.md +230 -0
  35. data/docs/migration/v0.9.0.md +459 -0
  36. data/docs/migration/v1.0.0.md +591 -0
  37. data/docs/storage/activerecord-adapter.md +348 -0
  38. data/docs/storage/custom-adapters.md +176 -0
  39. data/docs/storage/filesystem-adapter.md +236 -0
  40. data/docs/storage/overview.md +427 -0
  41. data/examples/advanced_integrations.rb +52 -0
  42. data/examples/prompts_dir/advanced_demo.txt +79 -0
  43. data/examples/prompts_dir/directive_example.json +1 -0
  44. data/examples/prompts_dir/directive_example.txt +8 -0
  45. data/examples/prompts_dir/todo.json +1 -1
  46. data/improvement_plan.md +996 -0
  47. data/lib/prompt_manager/storage/file_system_adapter.rb +8 -2
  48. data/lib/prompt_manager/version.rb +1 -1
  49. data/mkdocs.yml +146 -0
  50. data/prompt_manager_logo.png +0 -0
  51. metadata +46 -3
  52. data/LICENSE.txt +0 -21
@@ -0,0 +1,431 @@
1
+ # Directive Processor API Reference
2
+
3
+ The Directive Processor handles special instructions in prompts that begin with `//` and enable powerful prompt composition capabilities.
4
+
5
+ ## Core Classes
6
+
7
+ ### `PromptManager::DirectiveProcessor`
8
+
9
+ The main class responsible for processing directives within prompts.
10
+
11
+ #### Constructor
12
+
13
+ ```ruby
14
+ processor = PromptManager::DirectiveProcessor.new(
15
+ storage: storage_adapter,
16
+ max_depth: 10,
17
+ timeout: 30
18
+ )
19
+ ```
20
+
21
+ **Parameters:**
22
+ - `storage` (Storage::Base): Storage adapter for resolving includes
23
+ - `max_depth` (Integer): Maximum include depth to prevent circular references (default: 10)
24
+ - `timeout` (Numeric): Processing timeout in seconds (default: 30)
25
+
26
+ #### Instance Methods
27
+
28
+ ##### `process(content, context = {})`
29
+
30
+ Processes all directives in the given content.
31
+
32
+ **Parameters:**
33
+ - `content` (String): The prompt content containing directives
34
+ - `context` (Hash): Processing context and variables
35
+
36
+ **Returns:** String - Processed content with directives resolved
37
+
38
+ **Raises:**
39
+ - `PromptManager::DirectiveProcessingError` - If directive processing fails
40
+ - `PromptManager::CircularIncludeError` - If circular includes are detected
41
+
42
+ ```ruby
43
+ processor = PromptManager::DirectiveProcessor.new(storage: adapter)
44
+ result = processor.process("//include header.txt\nHello World!")
45
+ ```
46
+
47
+ ##### `register_directive(name, handler)`
48
+
49
+ Registers a custom directive handler.
50
+
51
+ **Parameters:**
52
+ - `name` (String): Directive name (without //)
53
+ - `handler` (Proc): Handler that processes the directive
54
+
55
+ ```ruby
56
+ processor.register_directive('timestamp') do |args, context|
57
+ Time.current.strftime('%Y-%m-%d %H:%M:%S')
58
+ end
59
+ ```
60
+
61
+ ## Built-in Directives
62
+
63
+ ### `//include` (alias: `//import`)
64
+
65
+ Includes content from another prompt file.
66
+
67
+ **Syntax:**
68
+ ```text
69
+ //include path/to/file.txt
70
+ //include [VARIABLE_PATH].txt
71
+ //import common/header.txt
72
+ ```
73
+
74
+ **Features:**
75
+ - Parameter substitution in paths: `//include templates/[TEMPLATE_TYPE].txt`
76
+ - Relative and absolute path resolution
77
+ - Circular include detection
78
+ - Nested include support
79
+
80
+ **Examples:**
81
+
82
+ ```text
83
+ # Basic include
84
+ //include common/header.txt
85
+
86
+ # With parameter substitution
87
+ //include templates/[EMAIL_TYPE].txt
88
+
89
+ # Nested directory structure
90
+ //include emails/marketing/[CAMPAIGN_TYPE]/template.txt
91
+ ```
92
+
93
+ ### `//set`
94
+
95
+ Sets variables for use within the current prompt.
96
+
97
+ **Syntax:**
98
+ ```text
99
+ //set VARIABLE_NAME value
100
+ //set CURRENT_DATE <%= Date.today %>
101
+ ```
102
+
103
+ **Examples:**
104
+
105
+ ```text
106
+ //set COMPANY_NAME Acme Corporation
107
+ //set SUPPORT_EMAIL support@[COMPANY_DOMAIN]
108
+ //set GREETING Hello [CUSTOMER_NAME]
109
+
110
+ Your message: [GREETING]
111
+ Contact us: [SUPPORT_EMAIL]
112
+ ```
113
+
114
+ ### `//if` / `//endif`
115
+
116
+ Conditional content inclusion.
117
+
118
+ **Syntax:**
119
+ ```text
120
+ //if CONDITION
121
+ content to include if condition is true
122
+ //endif
123
+ ```
124
+
125
+ **Examples:**
126
+
127
+ ```text
128
+ //if [USER_TYPE] == 'premium'
129
+ 🌟 Premium features are available!
130
+ //endif
131
+
132
+ //if [ORDER_TOTAL] > 100
133
+ 🚚 Free shipping applied!
134
+ //endif
135
+ ```
136
+
137
+ ## Custom Directive Development
138
+
139
+ ### Simple Directive Handler
140
+
141
+ ```ruby
142
+ # Register a simple directive
143
+ processor.register_directive('upper') do |args, context|
144
+ args.upcase
145
+ end
146
+
147
+ # Usage in prompt:
148
+ # //upper hello world
149
+ # Result: HELLO WORLD
150
+ ```
151
+
152
+ ### Complex Directive Handler
153
+
154
+ ```ruby
155
+ # Register directive with parameter processing
156
+ processor.register_directive('format_currency') do |args, context|
157
+ amount, currency = args.split(',').map(&:strip)
158
+ formatted_amount = sprintf('%.2f', amount.to_f)
159
+
160
+ case currency.downcase
161
+ when 'usd', '$'
162
+ "$#{formatted_amount}"
163
+ when 'eur', '€'
164
+ "€#{formatted_amount}"
165
+ else
166
+ "#{formatted_amount} #{currency}"
167
+ end
168
+ end
169
+
170
+ # Usage in prompt:
171
+ # //format_currency [ORDER_TOTAL], USD
172
+ # Result: $123.45
173
+ ```
174
+
175
+ ### Directive with Context Access
176
+
177
+ ```ruby
178
+ processor.register_directive('user_greeting') do |args, context|
179
+ user_name = context.dig(:parameters, :user_name) || 'Guest'
180
+ time_of_day = Time.current.hour < 12 ? 'morning' : 'afternoon'
181
+
182
+ "Good #{time_of_day}, #{user_name}!"
183
+ end
184
+
185
+ # Usage in prompt:
186
+ # //user_greeting
187
+ # Result: Good morning, Alice!
188
+ ```
189
+
190
+ ## Error Handling
191
+
192
+ ### Directive Processing Errors
193
+
194
+ ```ruby
195
+ begin
196
+ result = processor.process(content)
197
+ rescue PromptManager::DirectiveProcessingError => e
198
+ puts "Directive error at line #{e.line_number}: #{e.message}"
199
+ puts "Directive: #{e.directive}"
200
+ rescue PromptManager::CircularIncludeError => e
201
+ puts "Circular include detected: #{e.include_chain.join(' -> ')}"
202
+ end
203
+ ```
204
+
205
+ ### Custom Error Handling
206
+
207
+ ```ruby
208
+ processor.register_directive('safe_include') do |args, context|
209
+ begin
210
+ storage.read(args)
211
+ rescue PromptManager::PromptNotFoundError
212
+ "<!-- Template #{args} not found -->"
213
+ end
214
+ end
215
+ ```
216
+
217
+ ## Advanced Features
218
+
219
+ ### Conditional Directives
220
+
221
+ ```ruby
222
+ processor.register_directive('feature_flag') do |args, context|
223
+ feature_name, content = args.split(':', 2)
224
+
225
+ if FeatureFlag.enabled?(feature_name)
226
+ processor.process(content.strip, context)
227
+ else
228
+ ''
229
+ end
230
+ end
231
+
232
+ # Usage:
233
+ # //feature_flag new_ui: Welcome to our new interface!
234
+ ```
235
+
236
+ ### Loop Directives
237
+
238
+ ```ruby
239
+ processor.register_directive('foreach') do |args, context|
240
+ array_name, template = args.split(':', 2)
241
+ array_data = context.dig(:parameters, array_name.to_sym) || []
242
+
243
+ array_data.map.with_index do |item, index|
244
+ item_context = context.merge(
245
+ parameters: context[:parameters].merge(
246
+ item: item,
247
+ index: index,
248
+ first: index == 0,
249
+ last: index == array_data.length - 1
250
+ )
251
+ )
252
+ processor.process(template.strip, item_context)
253
+ end.join("\n")
254
+ end
255
+
256
+ # Usage:
257
+ # //foreach items: - [ITEM.NAME]: $[ITEM.PRICE]
258
+ ```
259
+
260
+ ### Template Inheritance
261
+
262
+ ```ruby
263
+ class TemplateInheritanceProcessor < PromptManager::DirectiveProcessor
264
+ def initialize(**options)
265
+ super(**options)
266
+ register_built_in_directives
267
+ end
268
+
269
+ private
270
+
271
+ def register_built_in_directives
272
+ register_directive('extends') do |args, context|
273
+ parent_content = storage.read(args)
274
+ context[:parent_content] = parent_content
275
+ '' # Don't include anything at this point
276
+ end
277
+
278
+ register_directive('block') do |args, context|
279
+ block_name, content = args.split(':', 2)
280
+ context[:blocks] ||= {}
281
+ context[:blocks][block_name] = content.strip
282
+ '' # Blocks are processed later
283
+ end
284
+
285
+ register_directive('yield') do |args, context|
286
+ block_name = args.strip
287
+ context.dig(:blocks, block_name) || ''
288
+ end
289
+ end
290
+
291
+ def process(content, context = {})
292
+ # First pass: extract blocks and parent template
293
+ super(content, context)
294
+
295
+ # Second pass: process parent template with blocks
296
+ if context[:parent_content]
297
+ super(context[:parent_content], context)
298
+ else
299
+ super(content, context)
300
+ end
301
+ end
302
+ end
303
+
304
+ # Usage:
305
+ # child.txt:
306
+ # //extends parent.txt
307
+ # //block content: This is child content
308
+ # //block title: Child Page
309
+
310
+ # parent.txt:
311
+ # <h1>//yield title</h1>
312
+ # <div>//yield content</div>
313
+ ```
314
+
315
+ ## Configuration
316
+
317
+ ### Global Configuration
318
+
319
+ ```ruby
320
+ PromptManager.configure do |config|
321
+ config.directive_processor_class = CustomDirectiveProcessor
322
+ config.max_include_depth = 5
323
+ config.directive_timeout = 60
324
+ end
325
+ ```
326
+
327
+ ### Custom Processor
328
+
329
+ ```ruby
330
+ class CustomDirectiveProcessor < PromptManager::DirectiveProcessor
331
+ def initialize(**options)
332
+ super(**options)
333
+ register_custom_directives
334
+ end
335
+
336
+ private
337
+
338
+ def register_custom_directives
339
+ register_directive('env') { |args, context| ENV[args] }
340
+ register_directive('random') { |args, context| rand(args.to_i) }
341
+ register_directive('uuid') { |args, context| SecureRandom.uuid }
342
+ end
343
+ end
344
+ ```
345
+
346
+ ## Performance Optimization
347
+
348
+ ### Caching Directive Results
349
+
350
+ ```ruby
351
+ class CachedDirectiveProcessor < PromptManager::DirectiveProcessor
352
+ def initialize(**options)
353
+ super(**options)
354
+ @directive_cache = {}
355
+ end
356
+
357
+ def register_directive(name, &handler)
358
+ cached_handler = lambda do |args, context|
359
+ cache_key = "#{name}:#{args}:#{context.hash}"
360
+
361
+ @directive_cache[cache_key] ||= handler.call(args, context)
362
+ end
363
+
364
+ super(name, &cached_handler)
365
+ end
366
+
367
+ def clear_cache
368
+ @directive_cache.clear
369
+ end
370
+ end
371
+ ```
372
+
373
+ ### Parallel Processing
374
+
375
+ ```ruby
376
+ class ParallelDirectiveProcessor < PromptManager::DirectiveProcessor
377
+ def process_includes(content, context)
378
+ includes = extract_includes(content)
379
+
380
+ # Process includes in parallel
381
+ results = Parallel.map(includes) do |include_directive|
382
+ process_single_include(include_directive, context)
383
+ end
384
+
385
+ # Replace includes with results
386
+ replace_includes(content, includes, results)
387
+ end
388
+ end
389
+ ```
390
+
391
+ ## Testing Directives
392
+
393
+ ### RSpec Examples
394
+
395
+ ```ruby
396
+ describe 'Custom Directive' do
397
+ let(:processor) { PromptManager::DirectiveProcessor.new(storage: storage) }
398
+ let(:storage) { instance_double(PromptManager::Storage::Base) }
399
+
400
+ before do
401
+ processor.register_directive('test') do |args, context|
402
+ "processed: #{args}"
403
+ end
404
+ end
405
+
406
+ it 'processes custom directive' do
407
+ content = "//test hello world"
408
+ result = processor.process(content)
409
+
410
+ expect(result).to eq "processed: hello world"
411
+ end
412
+
413
+ it 'handles directive errors gracefully' do
414
+ processor.register_directive('error') { |args, context| raise 'test error' }
415
+
416
+ expect {
417
+ processor.process("//error test")
418
+ }.to raise_error(PromptManager::DirectiveProcessingError)
419
+ end
420
+ end
421
+ ```
422
+
423
+ ## Best Practices
424
+
425
+ 1. **Error Handling**: Always handle errors gracefully in directive handlers
426
+ 2. **Performance**: Cache expensive operations in directive handlers
427
+ 3. **Security**: Validate and sanitize directive arguments
428
+ 4. **Documentation**: Document custom directive syntax and behavior
429
+ 5. **Testing**: Write comprehensive tests for custom directives
430
+ 6. **Naming**: Use descriptive names for custom directives
431
+ 7. **Context**: Use context parameter to access prompt rendering state