prompt_manager 0.4.0 → 0.4.2
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/.irbrc +14 -0
- data/CHANGELOG.md +17 -6
- data/README.md +45 -7
- data/Rakefile +0 -1
- data/examples/directives.rb +98 -0
- data/examples/prompts_dir/directive_example.txt +14 -0
- data/examples/using_search_proc.rb +0 -3
- data/lib/prompt_manager/prompt.rb +28 -26
- data/lib/prompt_manager/version.rb +1 -1
- data/lib/prompt_manager.rb +2 -0
- metadata +49 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c566743ba6741a0787db6ea680e77676ab18282013e3475cad1c30b85b9ce1b
|
4
|
+
data.tar.gz: 1e9e57eecaf97d05799d6b173b1ce90518dc02abeeddbd50eed90c34c376509f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1bcda6797d895b4dd78baf6c6c6cd2b83e2f06bb3446f9112795a6d216eb9450af9f1c2d0b3f762d4f21ee40a1257fec8610eadec33f7f19dabf078e7a859bf
|
7
|
+
data.tar.gz: f69ed112a2b22801dc830d87b11f0a231755141fa4eccded5ee2dc8019343cf6cf61705af560fed211866869940029bbde88cca7c821423da245593839515e03
|
data/.irbrc
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'lib/prompt_manager'
|
2
|
+
require_relative 'lib/prompt_manager/storage/file_system_adapter'
|
3
|
+
|
4
|
+
HERE = Pathname.new __dir__
|
5
|
+
|
6
|
+
PromptManager::Storage::FileSystemAdapter.config do |config|
|
7
|
+
config.prompts_dir = HERE + 'examples/prompts_dir'
|
8
|
+
# config.search_proc = nil # default
|
9
|
+
# config.prompt_extension = '.txt' # default
|
10
|
+
# config.parms+_extension = '.json' # default
|
11
|
+
end
|
12
|
+
|
13
|
+
PromptManager::Prompt.storage_adapter = PromptManager::Storage::FileSystemAdapter.new
|
14
|
+
|
data/CHANGELOG.md
CHANGED
@@ -1,23 +1,34 @@
|
|
1
|
-
##
|
1
|
+
## Unreleased
|
2
|
+
|
3
|
+
## Released
|
4
|
+
|
5
|
+
### [0.4.2] = 2024-10-26
|
6
|
+
- Added configurable parameter_regex to customize keyword pattern
|
7
|
+
|
8
|
+
### [0.4.1] = 2023-12-29
|
9
|
+
- Changed @directives from Hash to an Array
|
10
|
+
- Fixed keywords not being substituted in directives
|
11
|
+
|
12
|
+
### [0.4.0] = 2023-12-19
|
2
13
|
- Add "//directives param(s)" with keywords just like the prompt text.
|
3
14
|
|
4
|
-
|
15
|
+
### [0.3.3] = 2023-12-01
|
5
16
|
- Added example of using the `search_proc` config parameter with the FileSystemAdapter.
|
6
17
|
|
7
|
-
|
18
|
+
### [0.3.2] = 2023-12-01
|
8
19
|
|
9
20
|
- The ActiveRecordAdapter is passing its unit tests
|
10
21
|
- Dropped the concept of an sqlite3 adapter since active record can be used to access sqlite3 databases as well as the big boys.
|
11
22
|
|
12
|
-
|
23
|
+
### [0.3.0] = 2023-11-28
|
13
24
|
|
14
25
|
- **Breaking change** 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
|
15
26
|
|
16
|
-
|
27
|
+
### [0.2.0] - 2023-11-21
|
17
28
|
|
18
29
|
- **Breaking change to FileSystemAdapter config process**
|
19
30
|
- added list and path as extra methods in FileSystemAdapter
|
20
31
|
|
21
|
-
|
32
|
+
### [0.1.0] - 2023-11-16
|
22
33
|
|
23
34
|
- Initial release using the FileSystemAdapter
|
data/README.md
CHANGED
@@ -15,6 +15,10 @@ Manage the parameterized prompts (text) used in generative AI (aka chatGPT, Open
|
|
15
15
|
- [Generative AI (gen-AI)](#generative-ai-gen-ai)
|
16
16
|
- [What does a keyword look like?](#what-does-a-keyword-look-like)
|
17
17
|
- [All about directives](#all-about-directives)
|
18
|
+
- [Example Prompt with Directives](#example-prompt-with-directives)
|
19
|
+
- [Accessing Directives](#accessing-directives)
|
20
|
+
- [Dynamic Directives](#dynamic-directives)
|
21
|
+
- [Executing Directives](#executing-directives)
|
18
22
|
- [Comments Are Ignored](#comments-are-ignored)
|
19
23
|
- [Storage Adapters](#storage-adapters)
|
20
24
|
- [FileSystemAdapter](#filesystemadapter)
|
@@ -66,17 +70,25 @@ The prompt_manager uses a regular expression to identify these keywords within t
|
|
66
70
|
|
67
71
|
#### What does a keyword look like?
|
68
72
|
|
69
|
-
|
73
|
+
By default, any text matching `[UPPERCASE_TEXT]` enclosed in square brackets is treated as a keyword. [KEYWORDS CAN ALSO HAVE SPACES] as well as the underscore character.
|
70
74
|
|
71
|
-
|
75
|
+
You can customize the keyword pattern by setting a different regular expression:
|
72
76
|
|
77
|
+
```ruby
|
78
|
+
# Use {{param}} style instead of [PARAM]
|
79
|
+
PromptManager::Prompt.parameter_regex = /(\{\{[A-Za-z_]+\}\})/
|
80
|
+
```
|
81
|
+
|
82
|
+
The regex must include capturing parentheses () to extract the keyword. The default regex is `/(\[[A-Z _|]+\])/`.
|
73
83
|
#### All about directives
|
74
84
|
|
75
85
|
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.
|
76
86
|
|
77
|
-
The `prompt_manager` only
|
87
|
+
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.
|
88
|
+
|
89
|
+
##### Example Prompt with Directives
|
78
90
|
|
79
|
-
Here is an example
|
91
|
+
Here is an example prompt text file with comments, directives and keywords:
|
80
92
|
|
81
93
|
```
|
82
94
|
# prompts/sing_a_song.txt
|
@@ -90,12 +102,14 @@ __END__
|
|
90
102
|
Computers will never replace Frank Sinatra
|
91
103
|
```
|
92
104
|
|
105
|
+
##### Accessing Directives
|
106
|
+
|
93
107
|
Getting directives from a prompt is as easy as getting the kewyords:
|
94
108
|
|
95
109
|
```ruby
|
96
110
|
prompt = PromptManager::Prompt.new(...)
|
97
111
|
prompt.keywords #=> an Array
|
98
|
-
prompt.directives #=>
|
112
|
+
prompt.directives #=> an Array of entries like: ['directive', 'parameters']
|
99
113
|
|
100
114
|
# to_s builds the prompt by substituting
|
101
115
|
# values for keywords amd removing comments.
|
@@ -104,9 +118,33 @@ prompt.directives #=> a Hash
|
|
104
118
|
puts prompt.to_s
|
105
119
|
```
|
106
120
|
|
107
|
-
The
|
121
|
+
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:
|
122
|
+
|
123
|
+
- directive name (without the // characters)
|
124
|
+
- parameter string for the directive
|
125
|
+
|
126
|
+
##### Dynamic Directives
|
127
|
+
|
128
|
+
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:
|
129
|
+
|
130
|
+
```
|
131
|
+
//[COMMAND] [OPTIONS]
|
132
|
+
# or
|
133
|
+
[SOMETHING]
|
134
|
+
```
|
135
|
+
... where [COMMAND] gets replaced by some directive name. [SOMETHING] could be replaced by "//directive options"
|
136
|
+
|
137
|
+
##### Executing Directives
|
138
|
+
|
139
|
+
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:
|
140
|
+
|
141
|
+
- "//model gpt-5" could be used to set the LLM model to be used for a specific prompt.
|
142
|
+
- "//backend mods" could be used to set the backend prompt processor on the command line to be the `mods` utility.
|
143
|
+
- "//include path_to_file" could be used to add the contents of a file to the prompt.
|
144
|
+
- "//chat" could be used to send the prompts and then start up a chat session about the prompt and its response.
|
145
|
+
|
146
|
+
Its all up to how your application wants to support directives or not.
|
108
147
|
|
109
|
-
The value for each key is a String exactly as entered in the prompt file.
|
110
148
|
|
111
149
|
#### Comments Are Ignored
|
112
150
|
|
data/Rakefile
CHANGED
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
# frozen_string_literal: true
|
4
|
+
# warn_indent: true
|
5
|
+
##########################################################
|
6
|
+
###
|
7
|
+
## File: directives.rb
|
8
|
+
## Desc: Demo of the PromptManager and FileStorageAdapter
|
9
|
+
## By: Dewayne VanHoozer (dvanhoozer@gmail.com)
|
10
|
+
##
|
11
|
+
#
|
12
|
+
|
13
|
+
param1 = "param_one"
|
14
|
+
param2 = "param_two"
|
15
|
+
|
16
|
+
|
17
|
+
class MyDirectives
|
18
|
+
def self.good_directive(*args)
|
19
|
+
puts "inside #{__method__} with these parameters:"
|
20
|
+
puts args.join(",\n")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def concept_break = print "\n------------------------\n\n\n"
|
25
|
+
|
26
|
+
require_relative '../lib/prompt_manager'
|
27
|
+
require_relative '../lib/prompt_manager/storage/file_system_adapter'
|
28
|
+
|
29
|
+
require 'amazing_print'
|
30
|
+
require 'pathname'
|
31
|
+
|
32
|
+
require 'debug_me'
|
33
|
+
include DebugMe
|
34
|
+
|
35
|
+
HERE = Pathname.new( __dir__ )
|
36
|
+
PROMPTS_DIR = HERE + "prompts_dir"
|
37
|
+
|
38
|
+
|
39
|
+
######################################################
|
40
|
+
# Main
|
41
|
+
|
42
|
+
at_exit do
|
43
|
+
puts
|
44
|
+
puts "Done."
|
45
|
+
puts
|
46
|
+
end
|
47
|
+
|
48
|
+
# Configure the Storage Adapter to use
|
49
|
+
PromptManager::Storage::FileSystemAdapter.config do |config|
|
50
|
+
config.prompts_dir = PROMPTS_DIR
|
51
|
+
# config.search_proc = nil # default
|
52
|
+
# config.prompt_extension = '.txt' # default
|
53
|
+
# config.parms+_extension = '.json' # default
|
54
|
+
end
|
55
|
+
|
56
|
+
PromptManager::Prompt.storage_adapter = PromptManager::Storage::FileSystemAdapter.new
|
57
|
+
|
58
|
+
# Use {parameter name} brackets to define a parameter
|
59
|
+
PromptManager::Prompt.parameter_regex = /\{[A-Za-z _|]+\}/
|
60
|
+
|
61
|
+
# Retrieve a prompt
|
62
|
+
prompt = PromptManager::Prompt.get(id: 'directive_example')
|
63
|
+
|
64
|
+
# Shows prompt without comments or directives
|
65
|
+
# It still has its parameter placeholders
|
66
|
+
puts prompt
|
67
|
+
concept_break
|
68
|
+
|
69
|
+
puts "Directives in the prompt:"
|
70
|
+
ap prompt.directives
|
71
|
+
|
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
|
81
|
+
|
82
|
+
concept_break
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
puts "Parameters in the prompt:"
|
87
|
+
ap prompt.parameters
|
88
|
+
puts "-"*16
|
89
|
+
|
90
|
+
puts "keywords:"
|
91
|
+
ap prompt.keywords
|
92
|
+
concept_break
|
93
|
+
|
94
|
+
prompt.parameters['{language}'] << 'French'
|
95
|
+
|
96
|
+
puts "After Substitution"
|
97
|
+
puts prompt
|
98
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# directive_example.txt
|
2
|
+
# Desc: Shows how directives work
|
3
|
+
|
4
|
+
//good_directive param1 param2
|
5
|
+
//bad_directive param3 param4
|
6
|
+
|
7
|
+
say hello to me in {language} as well as English.
|
8
|
+
|
9
|
+
# The default parameter is delimited by square brackets
|
10
|
+
# and is all uppercase
|
11
|
+
|
12
|
+
write a [PROGRAMMING LANGUAGE] program that predicts the lottery.
|
13
|
+
|
14
|
+
|
@@ -6,23 +6,27 @@
|
|
6
6
|
# comment removal. It communicates with a storage system through a storage
|
7
7
|
# adapter.
|
8
8
|
#
|
9
|
-
# Directives
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
9
|
+
# Directives are collected into an Array where each entry is an Array
|
10
|
+
# of two elements. The first is the directive name as a String. The
|
11
|
+
# second is a string of parameters used by the directive.
|
12
|
+
#
|
13
|
+
# Directives are collected from the prompt after keyword
|
14
|
+
# substitution has occured. This means that directives within a
|
15
|
+
# prompt can be dynamic.
|
13
16
|
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
+
# PromptManager does not execute directives. They
|
18
|
+
# are made available to be passed on to down stream
|
19
|
+
# process.
|
17
20
|
|
18
21
|
class PromptManager::Prompt
|
19
22
|
COMMENT_SIGNAL = '#' # lines beginning with this are a comment
|
20
23
|
DIRECTIVE_SIGNAL = '//' # Like the old IBM JCL
|
21
|
-
|
24
|
+
DEFAULT_PARAMETER_REGEX = /(\[[A-Z _|]+\])/
|
22
25
|
@storage_adapter = nil
|
26
|
+
@parameter_regex = DEFAULT_PARAMETER_REGEX
|
23
27
|
|
24
28
|
class << self
|
25
|
-
attr_accessor :storage_adapter
|
29
|
+
attr_accessor :storage_adapter, :parameter_regex
|
26
30
|
|
27
31
|
alias_method :get, :new
|
28
32
|
|
@@ -58,7 +62,7 @@ class PromptManager::Prompt
|
|
58
62
|
|
59
63
|
# SMELL: Does the db (aka storage adapter) really need
|
60
64
|
# to be accessible by the main program?
|
61
|
-
attr_accessor :db, :id, :text, :parameters
|
65
|
+
attr_accessor :db, :id, :text, :parameters, :directives
|
62
66
|
|
63
67
|
|
64
68
|
# Retrieve the specific prompt ID from the Storage system.
|
@@ -76,10 +80,9 @@ class PromptManager::Prompt
|
|
76
80
|
@text = @record[:text]
|
77
81
|
@parameters = @record[:parameters]
|
78
82
|
@keywords = [] # Array of String
|
79
|
-
@directives =
|
83
|
+
@directives = [] # Array of arrays. directive is first entry, rest are parameters
|
80
84
|
|
81
85
|
update_keywords
|
82
|
-
update_directives
|
83
86
|
|
84
87
|
build
|
85
88
|
end
|
@@ -121,11 +124,12 @@ class PromptManager::Prompt
|
|
121
124
|
# the comments.
|
122
125
|
#
|
123
126
|
def build
|
124
|
-
@prompt = text.gsub(
|
127
|
+
@prompt = text.gsub(self.class.parameter_regex) do |match|
|
125
128
|
param_name = match
|
126
129
|
Array(parameters[param_name]).last || match
|
127
130
|
end
|
128
|
-
|
131
|
+
|
132
|
+
save_directives(@prompt)
|
129
133
|
remove_comments
|
130
134
|
end
|
131
135
|
|
@@ -135,16 +139,11 @@ class PromptManager::Prompt
|
|
135
139
|
end
|
136
140
|
|
137
141
|
|
138
|
-
def directives
|
139
|
-
update_directives
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
142
|
######################################
|
144
143
|
private
|
145
144
|
|
146
145
|
def update_keywords
|
147
|
-
@keywords = @text.scan(
|
146
|
+
@keywords = @text.scan(self.class.parameter_regex).flatten.uniq
|
148
147
|
@keywords.each do |kw|
|
149
148
|
@parameters[kw] = [] unless @parameters.has_key?(kw)
|
150
149
|
end
|
@@ -153,14 +152,16 @@ class PromptManager::Prompt
|
|
153
152
|
end
|
154
153
|
|
155
154
|
|
156
|
-
def
|
157
|
-
@
|
155
|
+
def save_directives(keyword_substituted_string)
|
156
|
+
@directives = []
|
157
|
+
|
158
|
+
keyword_substituted_string.split("\n").each do |a_line|
|
158
159
|
line = a_line.strip
|
159
160
|
next unless line.start_with?(DIRECTIVE_SIGNAL)
|
160
161
|
|
161
|
-
parts
|
162
|
-
directive
|
163
|
-
@directives[directive
|
162
|
+
parts = line.split(' ')
|
163
|
+
directive = parts.shift[DIRECTIVE_SIGNAL.length..] # drop the directive signal
|
164
|
+
@directives << [directive, parts.join(' ')]
|
164
165
|
end
|
165
166
|
|
166
167
|
@directives
|
@@ -171,7 +172,8 @@ class PromptManager::Prompt
|
|
171
172
|
lines = @prompt
|
172
173
|
.split("\n")
|
173
174
|
.reject{|a_line|
|
174
|
-
a_line.strip.start_with?(COMMENT_SIGNAL)
|
175
|
+
a_line.strip.start_with?(COMMENT_SIGNAL) ||
|
176
|
+
a_line.strip.start_with?(DIRECTIVE_SIGNAL)
|
175
177
|
}
|
176
178
|
|
177
179
|
# Remove empty lines at the start of the prompt
|
data/lib/prompt_manager.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prompt_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dewayne VanHoozer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ostruct
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: tocer
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,8 +94,36 @@ dependencies:
|
|
80
94
|
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
83
125
|
description: "Manage the parameterized prompts (text) used in generative AI (aka chatGPT,
|
84
|
-
\nOpenAI, et.al.) using storage adapters such as FileSystemAdapter, \nSqliteAdapter
|
126
|
+
\nOpenAI, et.al.) using storage adapters such as FileSystemAdapter, \nSqliteAdapter,
|
85
127
|
and ActiveRecordAdapter.\n"
|
86
128
|
email:
|
87
129
|
- dvanhoozer@gmail.com
|
@@ -90,11 +132,14 @@ extensions: []
|
|
90
132
|
extra_rdoc_files: []
|
91
133
|
files:
|
92
134
|
- ".envrc"
|
135
|
+
- ".irbrc"
|
93
136
|
- CHANGELOG.md
|
94
137
|
- LICENSE
|
95
138
|
- LICENSE.txt
|
96
139
|
- README.md
|
97
140
|
- Rakefile
|
141
|
+
- examples/directives.rb
|
142
|
+
- examples/prompts_dir/directive_example.txt
|
98
143
|
- examples/prompts_dir/todo.json
|
99
144
|
- examples/prompts_dir/todo.txt
|
100
145
|
- examples/prompts_dir/toy/8-ball.txt
|
@@ -130,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
175
|
- !ruby/object:Gem::Version
|
131
176
|
version: '0'
|
132
177
|
requirements: []
|
133
|
-
rubygems_version: 3.5.
|
178
|
+
rubygems_version: 3.5.22
|
134
179
|
signing_key:
|
135
180
|
specification_version: 4
|
136
181
|
summary: Manage prompts for use with gen-AI processes
|