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,544 @@
1
+ # Architecture
2
+
3
+ PromptManager follows a modular, layered architecture designed for flexibility, extensibility, and maintainability.
4
+
5
+ ## High-Level Architecture
6
+
7
+ ```mermaid
8
+ graph TB
9
+ subgraph "Application Layer"
10
+ APP[Your Application]
11
+ CLI[CLI Tools]
12
+ WEB[Web Interface]
13
+ end
14
+
15
+ subgraph "Core Layer"
16
+ PROMPT[PromptManager::Prompt]
17
+ DP[DirectiveProcessor]
18
+ ERB[ERB Engine]
19
+ PARAM[Parameter Manager]
20
+ end
21
+
22
+ subgraph "Storage Layer"
23
+ SA[Storage Adapter Interface]
24
+ FS[FileSystemAdapter]
25
+ AR[ActiveRecordAdapter]
26
+ CUSTOM[Custom Adapters]
27
+ end
28
+
29
+ subgraph "Data Layer"
30
+ FILES[File System]
31
+ DB[Database]
32
+ API[External APIs]
33
+ end
34
+
35
+ APP --> PROMPT
36
+ CLI --> PROMPT
37
+ WEB --> PROMPT
38
+
39
+ PROMPT --> DP
40
+ PROMPT --> ERB
41
+ PROMPT --> PARAM
42
+ PROMPT --> SA
43
+
44
+ SA --> FS
45
+ SA --> AR
46
+ SA --> CUSTOM
47
+
48
+ FS --> FILES
49
+ AR --> DB
50
+ CUSTOM --> API
51
+ ```
52
+
53
+ ## Core Components
54
+
55
+ ### 1. Prompt Class
56
+
57
+ The central `PromptManager::Prompt` class orchestrates all functionality:
58
+
59
+ ```ruby
60
+ class PromptManager::Prompt
61
+ attr_accessor :id, :parameters, :context
62
+ attr_reader :keywords, :directives
63
+
64
+ def initialize(options = {})
65
+ @id = options[:id]
66
+ @context = options[:context] || []
67
+ @directives_processor = options[:directives_processor]
68
+ @erb_flag = options[:erb_flag] || false
69
+ @envar_flag = options[:envar_flag] || false
70
+ end
71
+
72
+ def to_s
73
+ # Processing pipeline
74
+ text = load_raw_text
75
+ text = process_directives(text)
76
+ text = process_erb(text) if @erb_flag
77
+ text = substitute_envars(text) if @envar_flag
78
+ text = substitute_parameters(text)
79
+ text
80
+ end
81
+ end
82
+ ```
83
+
84
+ ### 2. Storage Adapter Pattern
85
+
86
+ Storage adapters implement a common interface:
87
+
88
+ ```mermaid
89
+ classDiagram
90
+ class StorageAdapter {
91
+ <<interface>>
92
+ +get(id) String, Hash
93
+ +save(id, text, params) void
94
+ +delete(id) void
95
+ +list() Array~String~
96
+ +search(query) Array~String~
97
+ }
98
+
99
+ class FileSystemAdapter {
100
+ +prompts_dir Path
101
+ +prompt_extension String
102
+ +params_extension String
103
+ +search_proc Proc
104
+ +get(id) String, Hash
105
+ +save(id, text, params) void
106
+ }
107
+
108
+ class ActiveRecordAdapter {
109
+ +model Class
110
+ +id_column Symbol
111
+ +text_column Symbol
112
+ +parameters_column Symbol
113
+ +get(id) String, Hash
114
+ +save(id, text, params) void
115
+ }
116
+
117
+ StorageAdapter <|-- FileSystemAdapter
118
+ StorageAdapter <|-- ActiveRecordAdapter
119
+ ```
120
+
121
+ ### 3. Processing Pipeline
122
+
123
+ The prompt processing follows a well-defined pipeline:
124
+
125
+ ```mermaid
126
+ graph LR
127
+ A[Raw Text] --> B[Parse Comments]
128
+ B --> C[Extract Keywords]
129
+ C --> D[Process Directives]
130
+ D --> E[Apply ERB]
131
+ E --> F[Substitute Envars]
132
+ F --> G[Replace Parameters]
133
+ G --> H[Final Text]
134
+
135
+ subgraph "Error Handling"
136
+ I[Validation]
137
+ J[Error Recovery]
138
+ end
139
+
140
+ C --> I
141
+ D --> I
142
+ E --> I
143
+ F --> I
144
+ G --> I
145
+ I --> J
146
+ ```
147
+
148
+ ## Design Patterns
149
+
150
+ ### 1. Adapter Pattern
151
+
152
+ Storage adapters use the Adapter pattern to provide a consistent interface across different storage backends:
153
+
154
+ ```ruby
155
+ # Common interface
156
+ module StorageAdapter
157
+ def get(id)
158
+ raise NotImplementedError
159
+ end
160
+
161
+ def save(id, text, parameters)
162
+ raise NotImplementedError
163
+ end
164
+ end
165
+
166
+ # Specific implementations
167
+ class FileSystemAdapter
168
+ include StorageAdapter
169
+
170
+ def get(id)
171
+ text = File.read(prompt_path(id))
172
+ params = JSON.parse(File.read(params_path(id)))
173
+ [text, params]
174
+ end
175
+ end
176
+ ```
177
+
178
+ ### 2. Strategy Pattern
179
+
180
+ Directive processing uses the Strategy pattern for different directive types:
181
+
182
+ ```ruby
183
+ class DirectiveProcessor
184
+ def process_directive(directive, prompt)
185
+ case directive
186
+ when /^\/\/include (.+)$/
187
+ IncludeStrategy.new.process($1, prompt)
188
+ when /^\/\/import (.+)$/
189
+ ImportStrategy.new.process($1, prompt)
190
+ else
191
+ raise "Unknown directive: #{directive}"
192
+ end
193
+ end
194
+ end
195
+ ```
196
+
197
+ ### 3. Template Method Pattern
198
+
199
+ The prompt generation uses Template Method pattern:
200
+
201
+ ```ruby
202
+ class Prompt
203
+ def to_s
204
+ template_method
205
+ end
206
+
207
+ private
208
+
209
+ def template_method
210
+ text = load_text # Hook 1
211
+ text = preprocess(text) # Hook 2
212
+ text = process(text) # Hook 3
213
+ text = postprocess(text) # Hook 4
214
+ text
215
+ end
216
+
217
+ # Hooks can be overridden by subclasses
218
+ def preprocess(text); text; end
219
+ def process(text); substitute_parameters(text); end
220
+ def postprocess(text); text; end
221
+ end
222
+ ```
223
+
224
+ ### 4. Configuration Object Pattern
225
+
226
+ Storage adapters use configuration objects for flexible setup:
227
+
228
+ ```ruby
229
+ class FileSystemAdapter
230
+ attr_reader :config
231
+
232
+ def self.config(&block)
233
+ @config ||= Configuration.new
234
+ block.call(@config) if block_given?
235
+ self
236
+ end
237
+
238
+ class Configuration
239
+ attr_accessor :prompts_dir, :prompt_extension, :params_extension
240
+
241
+ def initialize
242
+ @prompts_dir = nil
243
+ @prompt_extension = '.txt'
244
+ @params_extension = '.json'
245
+ end
246
+ end
247
+ end
248
+ ```
249
+
250
+ ## Data Flow
251
+
252
+ ### 1. Prompt Loading
253
+
254
+ ```mermaid
255
+ sequenceDiagram
256
+ participant App as Application
257
+ participant P as Prompt
258
+ participant SA as StorageAdapter
259
+ participant FS as FileSystem
260
+
261
+ App->>P: new(id: 'greeting')
262
+ P->>SA: get('greeting')
263
+ SA->>FS: read greeting.txt
264
+ FS-->>SA: raw text
265
+ SA->>FS: read greeting.json
266
+ FS-->>SA: parameters
267
+ SA-->>P: text, parameters
268
+ P-->>App: Prompt instance
269
+ ```
270
+
271
+ ### 2. Prompt Processing
272
+
273
+ ```mermaid
274
+ sequenceDiagram
275
+ participant App as Application
276
+ participant P as Prompt
277
+ participant DP as DirectiveProcessor
278
+ participant ERB as ERB Engine
279
+
280
+ App->>P: to_s()
281
+ P->>P: extract_keywords()
282
+ P->>DP: process_directives(text)
283
+ DP-->>P: processed text
284
+ P->>ERB: process_erb(text)
285
+ ERB-->>P: templated text
286
+ P->>P: substitute_parameters()
287
+ P-->>App: final text
288
+ ```
289
+
290
+ ### 3. Parameter Management
291
+
292
+ ```mermaid
293
+ graph TD
294
+ A[Set Parameters] --> B{New Format?}
295
+ B -->|v0.3.0+| C[Store as Array]
296
+ B -->|Legacy| D[Convert to Array]
297
+ C --> E[Parameter History]
298
+ D --> E
299
+ E --> F[Get Latest Value]
300
+ E --> G[Get Full History]
301
+ F --> H[Parameter Substitution]
302
+ G --> I[UI Dropdowns]
303
+ ```
304
+
305
+ ## Extension Points
306
+
307
+ The architecture provides several extension points for customization:
308
+
309
+ ### 1. Custom Storage Adapters
310
+
311
+ ```ruby
312
+ class RedisAdapter
313
+ include PromptManager::StorageAdapter
314
+
315
+ def initialize(redis_client)
316
+ @redis = redis_client
317
+ end
318
+
319
+ def get(id)
320
+ text = @redis.get("prompt:#{id}:text")
321
+ params_json = @redis.get("prompt:#{id}:params")
322
+ params = JSON.parse(params_json || '{}')
323
+ [text, params]
324
+ end
325
+ end
326
+ ```
327
+
328
+ ### 2. Custom Directive Processors
329
+
330
+ ```ruby
331
+ class CustomDirectiveProcessor < PromptManager::DirectiveProcessor
332
+ def process_directive(directive, prompt)
333
+ case directive
334
+ when /^\/\/model (.+)$/
335
+ @model = $1
336
+ "" # Remove directive from output
337
+ when /^\/\/temperature (.+)$/
338
+ @temperature = $1.to_f
339
+ ""
340
+ else
341
+ super # Delegate to parent
342
+ end
343
+ end
344
+ end
345
+ ```
346
+
347
+ ### 3. Custom Keyword Patterns
348
+
349
+ ```ruby
350
+ # Support multiple keyword formats
351
+ class MultiPatternPrompt < PromptManager::Prompt
352
+ PATTERNS = [
353
+ /(\[[A-Z _|]+\])/, # [KEYWORD]
354
+ /(\{\{[a-z_]+\}\})/, # {{keyword}}
355
+ /(:[a-z_]+)/ # :keyword
356
+ ]
357
+
358
+ def extract_keywords(text)
359
+ keywords = []
360
+ PATTERNS.each do |pattern|
361
+ keywords.concat(text.scan(pattern).flatten)
362
+ end
363
+ keywords.uniq
364
+ end
365
+ end
366
+ ```
367
+
368
+ ## Performance Considerations
369
+
370
+ ### 1. Lazy Loading
371
+
372
+ ```ruby
373
+ class Prompt
374
+ def keywords
375
+ @keywords ||= extract_keywords(@raw_text)
376
+ end
377
+
378
+ def raw_text
379
+ @raw_text ||= storage_adapter.get(@id).first
380
+ end
381
+ end
382
+ ```
383
+
384
+ ### 2. Caching
385
+
386
+ ```ruby
387
+ class CachingStorageAdapter
388
+ def initialize(adapter, cache_store = {})
389
+ @adapter = adapter
390
+ @cache = cache_store
391
+ end
392
+
393
+ def get(id)
394
+ @cache[id] ||= @adapter.get(id)
395
+ end
396
+ end
397
+ ```
398
+
399
+ ### 3. Batch Operations
400
+
401
+ ```ruby
402
+ class BatchProcessor
403
+ def process_prompts(prompt_ids)
404
+ # Load all prompts at once
405
+ prompts_data = storage_adapter.get_batch(prompt_ids)
406
+
407
+ # Process in parallel
408
+ results = prompts_data.map do |id, (text, params)|
409
+ Thread.new { process_single_prompt(id, text, params) }
410
+ end.map(&:value)
411
+
412
+ results
413
+ end
414
+ end
415
+ ```
416
+
417
+ ## Error Handling Architecture
418
+
419
+ ```mermaid
420
+ graph TD
421
+ A[Operation] --> B{Success?}
422
+ B -->|Yes| C[Return Result]
423
+ B -->|No| D[Classify Error]
424
+ D --> E{Error Type}
425
+ E -->|Storage| F[StorageError]
426
+ E -->|Parameter| G[ParameterError]
427
+ E -->|Configuration| H[ConfigurationError]
428
+ E -->|Processing| I[ProcessingError]
429
+
430
+ F --> J[Log & Report]
431
+ G --> J
432
+ H --> J
433
+ I --> J
434
+
435
+ J --> K{Recoverable?}
436
+ K -->|Yes| L[Apply Recovery Strategy]
437
+ K -->|No| M[Propagate Error]
438
+
439
+ L --> A
440
+ ```
441
+
442
+ ### Error Hierarchy
443
+
444
+ ```ruby
445
+ module PromptManager
446
+ class Error < StandardError; end
447
+
448
+ class StorageError < Error
449
+ attr_reader :operation, :id
450
+
451
+ def initialize(message, operation: nil, id: nil)
452
+ super(message)
453
+ @operation = operation
454
+ @id = id
455
+ end
456
+ end
457
+
458
+ class ParameterError < Error
459
+ attr_reader :missing_params, :invalid_params
460
+ end
461
+
462
+ class ConfigurationError < Error
463
+ attr_reader :setting, :value
464
+ end
465
+
466
+ class ProcessingError < Error
467
+ attr_reader :stage, :directive
468
+ end
469
+ end
470
+ ```
471
+
472
+ ## Security Considerations
473
+
474
+ ### 1. Parameter Sanitization
475
+
476
+ ```ruby
477
+ class SecurePrompt < Prompt
478
+ def substitute_parameters(text)
479
+ safe_params = sanitize_parameters(@parameters)
480
+ super(text, safe_params)
481
+ end
482
+
483
+ private
484
+
485
+ def sanitize_parameters(params)
486
+ params.transform_values do |value|
487
+ # Remove potential injection attacks
488
+ value.gsub(/[<>'"&]/, '')
489
+ end
490
+ end
491
+ end
492
+ ```
493
+
494
+ ### 2. File System Security
495
+
496
+ ```ruby
497
+ class SecureFileSystemAdapter < FileSystemAdapter
498
+ def prompt_path(id)
499
+ # Prevent directory traversal
500
+ sanitized_id = id.gsub(/[^a-zA-Z0-9_-]/, '')
501
+ raise SecurityError, "Invalid prompt ID" if sanitized_id != id
502
+
503
+ File.join(@config.prompts_dir, "#{sanitized_id}.txt")
504
+ end
505
+ end
506
+ ```
507
+
508
+ ## Testing Architecture
509
+
510
+ The architecture supports comprehensive testing at multiple levels:
511
+
512
+ ### 1. Unit Tests
513
+ - Individual component testing
514
+ - Mock storage adapters for isolation
515
+ - Parameter validation testing
516
+
517
+ ### 2. Integration Tests
518
+ - End-to-end prompt processing
519
+ - Multiple storage adapter combinations
520
+ - Error handling scenarios
521
+
522
+ ### 3. Performance Tests
523
+ - Large prompt collections
524
+ - Concurrent access patterns
525
+ - Memory usage optimization
526
+
527
+ ## Future Architecture Goals
528
+
529
+ ### 1. Plugin System
530
+ - Dynamic directive loading
531
+ - Community-contributed processors
532
+ - Runtime plugin management
533
+
534
+ ### 2. Distributed Storage
535
+ - Multi-node prompt storage
536
+ - Replication and consistency
537
+ - Fault tolerance
538
+
539
+ ### 3. Real-time Updates
540
+ - Live prompt editing
541
+ - Change notification system
542
+ - Collaborative editing support
543
+
544
+ This architecture provides a solid foundation for current needs while remaining flexible enough to support future enhancements and extensions.