prompt_manager 0.5.2 → 0.5.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9520d380488f2d4ef62d07dfc4a9b27bcc66086f5adb1f2d6fa874e8e179cfd3
4
- data.tar.gz: 1df0ea5efe721cd24293ed2172a72406b0e649e61a6778bb25615121c0ab39cb
3
+ metadata.gz: 0006a09365e6585250c1b22f102502d22bad785f8b6de23ac440a5669779a79e
4
+ data.tar.gz: 646b4bc31e96bff683a3ef9f177f60a8b81bc7c892de9d0c32a13cb2fd1ebfda
5
5
  SHA512:
6
- metadata.gz: ed5b5fdb6592797bd3bb5a564f13235360e8fde690e0781d51b39deb5f2d26590173bc2257f78dae132d2d91b12c27bf246d392c7cb9a84b1f22c1b409b88004
7
- data.tar.gz: 76425c4b30f68977dd4e16513c53bac2bc84e277e7e209dc1eb57f5f9f2267d23b354fd8d2fe79f871c05c0672198b53db4fe687b38966350c1aa0540e158913
6
+ metadata.gz: 94756fc51e3f52c8cdcbc0695569b0d8c3c2ac5f2ae1adbcf9c9a8c4854c80a2ae40cde4e09fe2186dd478d758bf1f7d847353824bfc9648013b8142c28c67a8
7
+ data.tar.gz: e00d4f971f0a5830dfc4cae7ff439965e02be05756e0ccaf3c37fe93df8e0709abc19061debef78f7e4c9746294a1b58ed26a7c22b121c8f1061ab727dbbf4c6
data/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
1
  ## Unreleased
2
2
 
3
3
  ## Released
4
+
5
+ ### [0.5.3] = 2025-05-14
6
+ - fixed issue were directives were not getting their content added to the prompt text
7
+ - Updated documentation and versioning.
8
+ - Added new error classes for better error handling.
9
+ - Improved parameter handling and directive processing.
10
+
4
11
  ### [0.5.0] = 2025-03-29
5
12
  - Major refactoring of to improve processing of parameters and directives.
6
13
  - Added PromptManager::DirectiveProcessor as an example of how to implement custom directives.
data/README.md CHANGED
@@ -1,32 +1,33 @@
1
1
  # PromptManager
2
2
 
3
- Manage the parameterized prompts (text) used in generative AI (aka chatGPT, OpenAI, _et.al._) using storage adapters such as FileSystemAdapter, SqliteAdapter and ActiveRecordAdapter.
4
-
5
- **Breaking Change** in version 0.3.0 - The value of the parameters Hash for a keyword is now an Array instead of a single value. The last value in the Array is always the most recent value used for the given keyword. This was done to support the use of a Readline::History object editing in the [aia](https://github.com/MadBomber/aia) CLI tool
3
+ Manage the parameterized prompts (text) used in generative AI (aka chatGPT, OpenAI, _et.al._) using storage adapters such as FileSystemAdapter and ActiveRecordAdapter.
6
4
 
5
+ **Current Version**: 0.5.3
7
6
 
7
+ **Breaking Change** in version 0.3.0 - The value of the parameters Hash for a keyword is now an Array instead of a single value. The last value in the Array is always the most recent value used for the given keyword. This was done to support the use of a Readline::History object editing in the [aia](https://github.com/MadBomber/aia) CLI tool
8
+ ### Latest Capabilities
8
9
  <!-- Tocer[start]: Auto-generated, don't remove. -->
9
10
 
10
11
  ## Table of Contents
11
12
 
12
- - [PromptManager](#promptmanager)
13
- - [Table of Contents](#table-of-contents)
13
+ - [Latest Capabilities](#latest-capabilities)
14
14
  - [Installation](#installation)
15
15
  - [Usage](#usage)
16
16
  - [Overview](#overview)
17
+ - [Prompt Initialization Options](#prompt-initialization-options)
17
18
  - [Generative AI (gen-AI)](#generative-ai-gen-ai)
18
19
  - [What does a keyword look like?](#what-does-a-keyword-look-like)
19
20
  - [All about directives](#all-about-directives)
20
21
  - [Example Prompt with Directives](#example-prompt-with-directives)
21
- - [Accessing Directives and Setting Parameter Values](#accessing-directives-and-setting-parameter-values)
22
+ - [Accessing and Setting Parameter Values](#accessing-and-setting-parameter-values)
22
23
  - [Dynamic Directives](#dynamic-directives)
23
24
  - [Executing Directives](#executing-directives)
24
25
  - [Comments Are Ignored](#comments-are-ignored)
25
26
  - [Storage Adapters](#storage-adapters)
26
27
  - [FileSystemAdapter](#filesystemadapter)
27
28
  - [Configuration](#configuration)
28
- - [prompts\_dir](#prompts_dir)
29
- - [search\_proc](#search_proc)
29
+ - [prompts_dir](#prompts_dir)
30
+ - [search_proc](#search_proc)
30
31
  - [File Extensions](#file-extensions)
31
32
  - [Example Prompt Text File](#example-prompt-text-file)
32
33
  - [Example Prompt Parameters JSON File](#example-prompt-parameters-json-file)
@@ -34,21 +35,24 @@ Manage the parameterized prompts (text) used in generative AI (aka chatGPT, Open
34
35
  - [ActiveRecordAdapter](#activerecordadapter)
35
36
  - [Configuration](#configuration-1)
36
37
  - [model](#model)
37
- - [id\_column](#id_column)
38
- - [text\_column](#text_column)
39
- - [parameters\_column](#parameters_column)
38
+ - [id_column](#id_column)
39
+ - [text_column](#text_column)
40
+ - [parameters_column](#parameters_column)
40
41
  - [Other Potential Storage Adapters](#other-potential-storage-adapters)
41
42
  - [Development](#development)
42
43
  - [Contributing](#contributing)
43
44
  - [License](#license)
44
45
 
45
46
  <!-- Tocer[finish]: Auto-generated, don't remove. -->
46
- ### Latest Capabilities
47
+
48
+
47
49
  - **Directive Processing:** Processes directives such as `//include` (aliased as `//import`) with loop protection.
48
50
  - **ERB Processing:** Supports ERB templating within prompts.
49
51
  - **Environment Variable Embedding:** Automatically substitutes system environment variables in prompts.
50
- - **Improved Parameter Handling:** Refactored to maintain a history of parameter values.
52
+ - **Improved Parameter Handling:** Refactored to maintain a history of parameter values and added error handling for parameter substitution.
51
53
  - **ActiveRecord Adapter:** Facilitates storing and retrieving prompts via an ActiveRecord model.
54
+ - **Enhanced Error Handling:** Added specific error classes for better error handling, including StorageError, ParameterError, and ConfigurationError.
55
+ - **Customizable Keyword Pattern:** Ability to customize the pattern used for detecting keywords in prompts.
52
56
 
53
57
  ## Installation
54
58
 
@@ -100,13 +104,13 @@ The regex must include capturing parentheses () to extract the keyword. The defa
100
104
 
101
105
  A directive is a line in the prompt text that starts with the two characters '//' - slash slash - just like in the old days of IBM JCL - Job Control Language. A prompt can have zero or more directives. Directives can have parameters and can make use of keywords.
102
106
 
103
- The `prompt_manager` only collects directives. It extracts keywords from directive lines and provides the substitution of those keywords with other text just like it does for the prompt.
107
+ The `prompt_manager` collects directives and provides a DirectiveProcessor class that currently implements the `//include` directive (also aliased as `//import`), which allows including content from other files with loop protection. It extracts keywords from directive lines and provides the substitution of those keywords with other text just like it does for the prompt.
104
108
 
105
109
  ##### Example Prompt with Directives
106
110
 
107
111
  Here is an example prompt text file with comments, directives and keywords:
108
112
 
109
- ```
113
+ ```text
110
114
  # prompts/sing_a_song.txt
111
115
  # Desc: Has the computer sing a song
112
116
 
@@ -118,42 +122,36 @@ __END__
118
122
  Computers will never replace Frank Sinatra
119
123
  ```
120
124
 
121
- ##### Accessing Directives and Setting Parameter Values
125
+ ##### Accessing and Setting Parameter Values
122
126
 
123
- Getting directives and keywords from a prompt is straightforward:
127
+ Getting and setting keywords from a prompt is straightforward:
124
128
 
125
129
  ```ruby
126
130
  prompt = PromptManager::Prompt.new(id: 'some_id')
127
131
  prompt.keywords #=> an Array of keywords found in the prompt text
128
- prompt.directives #=> an Array of entries like: ['directive', 'parameters']
129
132
 
130
- # Or directly update the parameters hash
133
+ # Update the parameters hash with keyword values
131
134
  prompt.parameters = {
132
135
  "[KEYWORD1]" => "value1",
133
136
  "[KEYWORD2]" => "value2"
134
137
  }
135
138
 
136
- # After setting parameter values, call to_s to build the final prompt
137
- # to_s builds the prompt by substituting
138
- # values for keywords and removing comments.
139
- # The resulting text contains directives and
140
- # prompt text ready for the LLM process.
139
+ # Build the final prompt text
140
+ # This substitutes values for keywords and processes directives
141
+ # Comments are removed and the result is ready for the LLM
141
142
  final_text = prompt.to_s
142
143
 
143
- # To persist any parameter changes to storage
144
+ # Save any parameter changes back to storage
144
145
  prompt.save
145
146
  ```
146
147
 
147
- The entries in the Array returned by the `prompt.directives` method is in the order that the directives were defined within the prompt. Each entry has two elements:
148
-
149
- - directive name (without the // characters)
150
- - parameter string for the directive
148
+ Internally, directives are stored in a Hash where each key is the full directive line (including the // characters) and the value is the result string from executing that directive. The directives are processed in the order they appear in the prompt text.
151
149
 
152
150
  ##### Dynamic Directives
153
151
 
154
152
  Since directies are collected after the keywords in the prompt have been substituted for their values, it is possible to have dynamically generated directives as part of a prompt. For example:
155
153
 
156
- ```
154
+ ```text
157
155
  //[COMMAND] [OPTIONS]
158
156
  # or
159
157
  [SOMETHING]
@@ -162,11 +160,12 @@ Since directies are collected after the keywords in the prompt have been substit
162
160
 
163
161
  ##### Executing Directives
164
162
 
165
- The `prompt_manager` gem only collects directives. Executing those directives is left up to some down stream process. Here are some ideas on how directives could be used in prompt downstream process:
163
+ The `prompt_manager` gem provides a basic DirectiveProcessor class that handles the `//include` directive (aliased as `//import`), which adds the contents of a file to the prompt with loop protection to prevent circular includes.
164
+
165
+ Additionally, you can extend with your own directives or downstream processes. Here are some ideas on how directives could be used in prompt downstream process:
166
166
 
167
167
  - "//model gpt-5" could be used to set the LLM model to be used for a specific prompt.
168
168
  - "//backend mods" could be used to set the backend prompt processor on the command line to be the `mods` utility.
169
- - "//include path_to_file" could be used to add the contents of a file to the prompt.
170
169
  - "//chat" could be used to send the prompts and then start up a chat session about the prompt and its response.
171
170
 
172
171
  Its all up to how your application wants to support directives or not.
@@ -180,7 +179,7 @@ The gem also ignores blank lines.
180
179
 
181
180
  ## Storage Adapters
182
181
 
183
- A storage adapter is a class instance that ties the `PromptManager::Prompt` class to a storage facility that holds the actual prompts. Currently there are 3 storage adapters planned for implementation.
182
+ A storage adapter is a class instance that ties the `PromptManager::Prompt` class to a storage facility that holds the actual prompts. Currently there are 2 storage adapters implemented: FileSystemAdapter and ActiveRecordAdapter.
184
183
 
185
184
  The `PromptManager::Prompt` to support a small set of methods. A storage adapter can provide "extra" class or instance methods that can be used through the Prompt class. See the `test/prompt_manager/prompt_test.rb` for guidance on creating a new storage adapter.
186
185
 
@@ -274,8 +273,9 @@ The last value in the keyword's Array is the most recent value used for that key
274
273
  #### Extra Functionality
275
274
 
276
275
  The `FileSystemAdapter` adds two new methods for use by the `Prompt` class:
277
- * list - returns an Array of prompt IDs
278
- * path and path(prompt_id) - returns a `Pathname` object to the prompt file
276
+
277
+ - list - returns an Array of prompt IDs
278
+ - path and path(prompt_id) - returns a `Pathname` object to the prompt file
279
279
 
280
280
  Use the `path(prompt_id)` form against the `Prompt` class
281
281
  Use `prompt.path` when you have an instance of a `Prompt`
@@ -322,13 +322,13 @@ The `parameters_column` contains the name of the column that contains the parame
322
322
 
323
323
  TODO: fix the kludge so that any serialization can be used.
324
324
 
325
-
326
325
  ### Other Potential Storage Adapters
327
326
 
328
- There are many possibilities to example this plugin concept of the storage adapter. Here are some for consideration:
327
+ There are many possibilities to expand this plugin concept of the storage adapter. Here are some for consideration:
329
328
 
330
- * RedisAdapter - Not sure; isn't redis more temporary oriented?
331
- * ApiAdapter - use some end-point to CRUD a prompt
329
+ - RedisAdapter - For caching prompts or temporary storage
330
+ - ApiAdapter - Use some end-point to CRUD a prompt
331
+ - CloudStorageAdapter - Store prompts in cloud storage services
332
332
 
333
333
  ## Development
334
334
 
@@ -336,7 +336,7 @@ Looking for feedback and contributors to enhance the capability of prompt_manage
336
336
 
337
337
  ## Contributing
338
338
 
339
- Bug reports and pull requests are welcome on GitHub at https://github.com/MadBomber/prompt_manager.
339
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/MadBomber/prompt_manager](https://github.com/MadBomber/prompt_manager).
340
340
 
341
341
  ## License
342
342
 
@@ -56,28 +56,25 @@ end
56
56
  PromptManager::Prompt.storage_adapter = PromptManager::Storage::FileSystemAdapter.new
57
57
 
58
58
  # Use {parameter name} brackets to define a parameter
59
- PromptManager::Prompt.parameter_regex = /\{[A-Za-z _|]+\}/
59
+ # Note: must include capturing parentheses to make scan return arrays
60
+ PromptManager::Prompt.parameter_regex = /(\{[A-Za-z _|]+\})/
60
61
 
61
62
  # Retrieve a prompt
62
- prompt = PromptManager::Prompt.get(id: 'directive_example')
63
+ # Note: The 'get' method returns a Hash, not a Prompt object
64
+ # Use 'find' instead to get a Prompt object with methods
65
+ prompt = PromptManager::Prompt.find(id: 'directive_example')
63
66
 
64
67
  # Shows prompt without comments or directives
65
68
  # It still has its parameter placeholders
66
69
  puts prompt
67
70
  concept_break
68
71
 
69
- puts "Directives in the prompt:"
70
- ap prompt.directives
72
+ puts "Directives are processed automatically when you call to_s on a prompt"
73
+ puts "The DirectiveProcessor class handles directives like //include"
74
+ puts "You don't need to process them manually"
71
75
 
72
- puts "Processing directives ..."
73
- prompt.directives.each do |entry|
74
- if MyDirectives.respond_to? entry.first.to_sym
75
- ruby = "MyDirectives.#{entry.first}(#{entry.last.gsub(' ', ',')})"
76
- eval "#{ruby}"
77
- else
78
- puts "ERROR: there is no method: #{entry.first}"
79
- end
80
- end
76
+ puts "Custom directive processing can be done by creating a custom DirectiveProcessor"
77
+ puts "and setting it when creating a Prompt instance:"
81
78
 
82
79
  concept_break
83
80
 
@@ -87,12 +84,19 @@ puts "Parameters in the prompt:"
87
84
  ap prompt.parameters
88
85
  puts "-"*16
89
86
 
90
- puts "keywords:"
91
- ap prompt.keywords
87
+ # Extract parameters from the prompt text using the parameter_regex
88
+ puts "Parameters identified in the prompt text:"
89
+ # With a capturing group, scan returns an array of arrays, so we need to flatten
90
+ prompt_params = prompt.text.scan(PromptManager::Prompt.parameter_regex).flatten
91
+ ap prompt_params
92
92
  concept_break
93
93
 
94
- prompt.parameters['{language}'] << 'French'
94
+ # Set a parameter value (should be a string, not appending to an array)
95
+ prompt.parameters['{language}'] = 'French'
95
96
 
96
97
  puts "After Substitution"
97
98
  puts prompt
98
99
 
100
+ # Save the updated parameters
101
+ prompt.save
102
+
@@ -1 +1 @@
1
- {"[LANGUAGE]":"ruby"}
1
+ {"[LANGUAGE]":"ruby","[KEYWORD_AKA_TODO]":"TODO"}
data/examples/simple.rb CHANGED
@@ -40,8 +40,10 @@ end
40
40
  PromptManager::Prompt.storage_adapter = PromptManager::Storage::FileSystemAdapter.new
41
41
 
42
42
  # Get a prompt
43
+ # Note: The 'get' method returns a Hash, not a Prompt object
44
+ # Use 'find' instead to get a Prompt object with methods
43
45
 
44
- todo = PromptManager::Prompt.get(id: 'todo')
46
+ todo = PromptManager::Prompt.find(id: 'todo')
45
47
 
46
48
  # This sequence simulates presenting each of the previously
47
49
  # used values for each keyword to the user to accept or
@@ -55,10 +57,9 @@ todo = PromptManager::Prompt.get(id: 'todo')
55
57
 
56
58
  todo.parameters["[KEYWORD_AKA_TODO]"] = "TODO"
57
59
 
58
- # When the parameter values change, the prompt must
59
- # must be rebuilt using the build method.
60
-
61
- todo.build
60
+ # When the parameter values change, the prompt must
61
+ # be saved to persist the changes
62
+ todo.save
62
63
 
63
64
 
64
65
  puts <<~EOS
@@ -98,7 +99,7 @@ puts <<~EOS
98
99
 
99
100
  EOS
100
101
 
101
- magic = PromptManager::Prompt.get( id: 'toy/8-ball' )
102
+ magic = PromptManager::Prompt.find(id: 'toy/8-ball')
102
103
 
103
104
  puts "The magic PROMPT is:"
104
105
  puts magic
@@ -110,9 +111,9 @@ puts "="*64
110
111
 
111
112
  puts <<~EOS
112
113
 
113
- The FileSystemAdapter also adds two new methods to the Prompt class:
114
+ The FileSystemAdapter also adds two new class methods to the Prompt class:
114
115
 
115
- list - provides an Array of pompt IDs
116
+ list - provides an Array of prompt IDs
116
117
  path(prompt_id) - Returns a Pathname object to the prompt file
117
118
 
118
119
  EOS
@@ -126,7 +127,7 @@ puts <<~EOS
126
127
 
127
128
  And the path to the "toy/8-ball" prompt file is:
128
129
 
129
- #{magic.path}
130
+ #{PromptManager::Prompt.path('toy/8-ball')}
130
131
 
131
132
  Use "your_prompt.path" for when you want to do something with the
132
133
  the prompt file like send it to a text editor.
@@ -146,7 +146,7 @@ class PromptManager::Prompt
146
146
  def substitute_values(input_text, values_hash)
147
147
  if values_hash.is_a?(Hash) && !values_hash.empty?
148
148
  values_hash.each do |key, value|
149
- input_text = input_text.gsub(key, value.last)
149
+ input_text = input_text.gsub(key, value)
150
150
  end
151
151
  end
152
152
  input_text
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PromptManager
4
- VERSION = "0.5.2"
4
+ VERSION = "0.5.3"
5
5
  end
@@ -17,8 +17,12 @@ module PromptManager
17
17
  # Base error class for all PromptManager-specific errors
18
18
  class Error < StandardError; end
19
19
 
20
- # TODO: Add additional module-specific error classes such as:
21
- # - StorageError - For issues with storing or retrieving prompts
22
- # - ParameterError - For issues with parameter substitution
23
- # - ConfigurationError - For setup and configuration issues
20
+ # Error class for storage-related issues
21
+ class StorageError < Error; end
22
+
23
+ # Error class for parameter substitution issues
24
+ class ParameterError < Error; end
25
+
26
+ # Error class for configuration issues
27
+ class ConfigurationError < Error; end
24
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prompt_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer