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 +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +40 -40
- data/examples/directives.rb +20 -16
- data/examples/prompts_dir/todo.json +1 -1
- data/examples/simple.rb +10 -9
- data/lib/prompt_manager/prompt.rb +1 -1
- data/lib/prompt_manager/version.rb +1 -1
- data/lib/prompt_manager.rb +8 -4
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0006a09365e6585250c1b22f102502d22bad785f8b6de23ac440a5669779a79e
|
4
|
+
data.tar.gz: 646b4bc31e96bff683a3ef9f177f60a8b81bc7c892de9d0c32a13cb2fd1ebfda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
- [
|
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
|
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
|
-
- [
|
29
|
-
- [
|
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
|
-
- [
|
38
|
-
- [
|
39
|
-
- [
|
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
|
-
|
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`
|
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
|
125
|
+
##### Accessing and Setting Parameter Values
|
122
126
|
|
123
|
-
Getting
|
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
|
-
#
|
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
|
-
#
|
137
|
-
#
|
138
|
-
#
|
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
|
-
#
|
144
|
+
# Save any parameter changes back to storage
|
144
145
|
prompt.save
|
145
146
|
```
|
146
147
|
|
147
|
-
|
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
|
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
|
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
|
-
|
278
|
-
|
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
|
327
|
+
There are many possibilities to expand this plugin concept of the storage adapter. Here are some for consideration:
|
329
328
|
|
330
|
-
|
331
|
-
|
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
|
|
data/examples/directives.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
70
|
-
|
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 "
|
73
|
-
|
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
|
-
|
91
|
-
|
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
|
-
|
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.
|
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
|
-
#
|
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.
|
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
|
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
|
-
#{
|
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
|
149
|
+
input_text = input_text.gsub(key, value)
|
150
150
|
end
|
151
151
|
end
|
152
152
|
input_text
|
data/lib/prompt_manager.rb
CHANGED
@@ -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
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
#
|
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
|