artificial 0.0.1
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 +7 -0
- data/README.md +303 -0
- data/Rakefile +101 -0
- data/examples/demo.rb +138 -0
- data/lib/artificial/parsers/json_parser.rb +103 -0
- data/lib/artificial/parsers/string_parser.rb +31 -0
- data/lib/artificial/parsers/xml_parser.rb +132 -0
- data/lib/artificial/parsers/yaml_parser.rb +87 -0
- data/lib/artificial/prompt.rb +440 -0
- data/lib/artificial/validators/message_validator.rb +72 -0
- data/lib/artificial/validators/role_validator.rb +128 -0
- data/lib/artificial/version.rb +5 -0
- data/lib/artificial.rb +68 -0
- data/sig/artificial.rbs +4 -0
- metadata +155 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Artificial
|
4
|
+
module Validators
|
5
|
+
class MessageValidator
|
6
|
+
VALID_ROLES = %w[system user assistant].freeze
|
7
|
+
|
8
|
+
attr_reader :messages, :errors
|
9
|
+
|
10
|
+
def initialize(messages)
|
11
|
+
@messages = messages
|
12
|
+
@errors = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate
|
16
|
+
@errors.clear
|
17
|
+
|
18
|
+
return add_error('Messages must be an array') unless @messages.is_a?(Array)
|
19
|
+
return add_error('Messages array cannot be empty') if @messages.empty?
|
20
|
+
|
21
|
+
@messages.each_with_index do |message, index|
|
22
|
+
validate_message(message, index)
|
23
|
+
end
|
24
|
+
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid?
|
29
|
+
validate if @errors.empty?
|
30
|
+
@errors.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def error_messages
|
34
|
+
@errors
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def validate_message(message, index)
|
40
|
+
return add_error("Message at index #{index} must be a hash") unless message.is_a?(Hash)
|
41
|
+
|
42
|
+
validate_role(message, index)
|
43
|
+
validate_content(message, index)
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate_role(message, index)
|
47
|
+
role = message[:role] || message['role']
|
48
|
+
|
49
|
+
if role.nil?
|
50
|
+
add_error("Message at index #{index} must have a 'role' key")
|
51
|
+
elsif !VALID_ROLES.include?(role.to_s)
|
52
|
+
add_error("Message at index #{index} has invalid role '#{role}'. Must be one of: #{VALID_ROLES.join(', ')}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_content(message, index)
|
57
|
+
content = message[:content] || message['content']
|
58
|
+
|
59
|
+
if content.nil?
|
60
|
+
add_error("Message at index #{index} must have a 'content' key")
|
61
|
+
elsif !content.is_a?(String) || content.strip.empty?
|
62
|
+
add_error("Message at index #{index} must have non-empty string content")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_error(message)
|
67
|
+
@errors << message
|
68
|
+
false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Artificial
|
4
|
+
module Validators
|
5
|
+
class RoleValidator
|
6
|
+
VALID_SYSTEM_ROLES = %w[
|
7
|
+
expert assistant helper instructor teacher guide analyst
|
8
|
+
specialist consultant advisor reviewer critic evaluator
|
9
|
+
researcher scientist engineer developer programmer
|
10
|
+
writer editor translator interpreter
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
ROLE_PATTERNS = {
|
14
|
+
domain_expert: /^you are (?:a|an) (.+) expert/i,
|
15
|
+
professional: /^you are (?:a|an) (.+) professional/i,
|
16
|
+
specialist: /^you are (?:a|an) (.+) specialist/i,
|
17
|
+
assistant: /^you are (?:a|an) (?:helpful|knowledgeable|.+) assistant/i
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
attr_reader :system_prompt, :role_type, :errors, :suggestions
|
21
|
+
|
22
|
+
def initialize(system_prompt)
|
23
|
+
@system_prompt = system_prompt
|
24
|
+
@role_type = nil
|
25
|
+
@errors = []
|
26
|
+
@suggestions = []
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate
|
30
|
+
@errors.clear
|
31
|
+
@suggestions.clear
|
32
|
+
|
33
|
+
return add_error('System prompt cannot be empty') if @system_prompt.nil? || @system_prompt.strip.empty?
|
34
|
+
|
35
|
+
analyze_role_effectiveness
|
36
|
+
check_role_clarity
|
37
|
+
provide_optimization_suggestions
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def valid?
|
43
|
+
validate if @errors.empty?
|
44
|
+
@errors.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
def effective?
|
48
|
+
validate unless @role_type
|
49
|
+
@role_type != :generic
|
50
|
+
end
|
51
|
+
|
52
|
+
def error_messages
|
53
|
+
@errors
|
54
|
+
end
|
55
|
+
|
56
|
+
def optimization_suggestions
|
57
|
+
@suggestions
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def analyze_role_effectiveness
|
63
|
+
@role_type = determine_role_type
|
64
|
+
|
65
|
+
case @role_type
|
66
|
+
when :domain_expert
|
67
|
+
add_suggestion('Excellent! Domain expert roles typically improve response quality by 20-30%')
|
68
|
+
when :professional
|
69
|
+
add_suggestion('Good! Professional roles help establish expertise and context')
|
70
|
+
when :specialist
|
71
|
+
add_suggestion('Good! Specialist roles provide focused domain knowledge')
|
72
|
+
when :assistant
|
73
|
+
add_suggestion('Adequate. Consider making the assistant role more specific for better performance')
|
74
|
+
when :generic
|
75
|
+
add_suggestion('Generic roles may reduce AI performance. Consider specifying domain expertise')
|
76
|
+
else
|
77
|
+
add_suggestion('Consider using established role patterns for optimal performance')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def determine_role_type
|
82
|
+
ROLE_PATTERNS.each do |type, pattern|
|
83
|
+
return type if @system_prompt.match?(pattern)
|
84
|
+
end
|
85
|
+
|
86
|
+
return :generic if @system_prompt.downcase.include?('you are')
|
87
|
+
|
88
|
+
:undefined
|
89
|
+
end
|
90
|
+
|
91
|
+
def check_role_clarity
|
92
|
+
unless @system_prompt.downcase.start_with?('you are')
|
93
|
+
add_suggestion("Consider starting with 'You are...' for clearer role definition")
|
94
|
+
end
|
95
|
+
|
96
|
+
if @system_prompt.length < 10
|
97
|
+
add_error('System prompt too short. Add more context about the role and capabilities')
|
98
|
+
elsif @system_prompt.length > 500
|
99
|
+
add_suggestion("Consider shortening system prompt for better focus (current: #{@system_prompt.length} chars)")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def provide_optimization_suggestions
|
104
|
+
if @role_type == :generic || @role_type == :undefined
|
105
|
+
add_suggestion("Try: 'You are a [domain] expert with [X] years of experience in [specialization]'")
|
106
|
+
end
|
107
|
+
|
108
|
+
unless @system_prompt.include?('expert') || @system_prompt.include?('specialist')
|
109
|
+
add_suggestion("Adding 'expert' or 'specialist' can improve response authority")
|
110
|
+
end
|
111
|
+
|
112
|
+
return unless @system_prompt.count('.') < 2
|
113
|
+
|
114
|
+
add_suggestion('Consider adding specific capabilities or constraints to the role')
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_error(message)
|
118
|
+
@errors << message
|
119
|
+
false
|
120
|
+
end
|
121
|
+
|
122
|
+
def add_suggestion(message)
|
123
|
+
@suggestions << message
|
124
|
+
true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/artificial.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'artificial/version'
|
4
|
+
require_relative 'artificial/prompt'
|
5
|
+
|
6
|
+
# Load parsers
|
7
|
+
require_relative 'artificial/parsers/string_parser'
|
8
|
+
require_relative 'artificial/parsers/xml_parser'
|
9
|
+
require_relative 'artificial/parsers/yaml_parser'
|
10
|
+
require_relative 'artificial/parsers/json_parser'
|
11
|
+
|
12
|
+
# Load validators
|
13
|
+
require_relative 'artificial/validators/message_validator'
|
14
|
+
require_relative 'artificial/validators/role_validator'
|
15
|
+
|
16
|
+
module Artificial
|
17
|
+
class Error < StandardError; end
|
18
|
+
|
19
|
+
# Factory method for creating prompts
|
20
|
+
def self.create_prompt(input = nil, **options)
|
21
|
+
Prompt.new(input, **options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse input using appropriate parser
|
25
|
+
def self.parse(input, format: :auto)
|
26
|
+
case format
|
27
|
+
when :auto
|
28
|
+
auto_parse(input)
|
29
|
+
when :string
|
30
|
+
Parsers::StringParser.new(input).parse
|
31
|
+
when :xml
|
32
|
+
Parsers::XMLParser.new(input).parse
|
33
|
+
when :yaml
|
34
|
+
Parsers::YAMLParser.new(input).parse
|
35
|
+
when :json
|
36
|
+
Parsers::JSONParser.new(input).parse
|
37
|
+
else
|
38
|
+
raise ArgumentError, "Unknown format: #{format}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Validate messages
|
43
|
+
def self.validate_messages(messages)
|
44
|
+
Validators::MessageValidator.new(messages).validate
|
45
|
+
end
|
46
|
+
|
47
|
+
# Validate role
|
48
|
+
def self.validate_role(system_prompt)
|
49
|
+
Validators::RoleValidator.new(system_prompt).validate
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.auto_parse(input)
|
53
|
+
return Parsers::StringParser.new(input).parse unless input.is_a?(String)
|
54
|
+
|
55
|
+
# Try to detect format from string content
|
56
|
+
input_trimmed = input.strip
|
57
|
+
|
58
|
+
if input_trimmed.start_with?('<') && input_trimmed.end_with?('>')
|
59
|
+
Parsers::XMLParser.new(input).parse
|
60
|
+
elsif input_trimmed.start_with?('{') && input_trimmed.end_with?('}')
|
61
|
+
Parsers::JSONParser.new(input).parse
|
62
|
+
elsif input_trimmed.include?(':') && (input_trimmed.include?('-') || input_trimmed.include?('|') || input_trimmed.include?("\n"))
|
63
|
+
Parsers::YAMLParser.new(input).parse
|
64
|
+
else
|
65
|
+
Parsers::StringParser.new(input).parse
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/sig/artificial.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: artificial
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matt Solt
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: json
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '2.6'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '2.6'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: psych
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '5.0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: rexml
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.2'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.2'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: minitest
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '5.0'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '5.0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: rake
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '13.0'
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '13.0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: rubocop
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '1.21'
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '1.21'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: yard
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0.9'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0.9'
|
110
|
+
description: Artificial intelligence library for prompting - not production-ready.
|
111
|
+
email:
|
112
|
+
- mattsolt@gmail.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- README.md
|
118
|
+
- Rakefile
|
119
|
+
- examples/demo.rb
|
120
|
+
- lib/artificial.rb
|
121
|
+
- lib/artificial/parsers/json_parser.rb
|
122
|
+
- lib/artificial/parsers/string_parser.rb
|
123
|
+
- lib/artificial/parsers/xml_parser.rb
|
124
|
+
- lib/artificial/parsers/yaml_parser.rb
|
125
|
+
- lib/artificial/prompt.rb
|
126
|
+
- lib/artificial/validators/message_validator.rb
|
127
|
+
- lib/artificial/validators/role_validator.rb
|
128
|
+
- lib/artificial/version.rb
|
129
|
+
- sig/artificial.rbs
|
130
|
+
homepage: https://github.com/roboruby/artificial
|
131
|
+
licenses: []
|
132
|
+
metadata:
|
133
|
+
allowed_push_host: https://rubygems.org
|
134
|
+
homepage_uri: https://github.com/roboruby/artificial
|
135
|
+
source_code_uri: https://github.com/roboruby/artificial
|
136
|
+
changelog_uri: https://github.com/roboruby/artificial/blob/main/CHANGELOG.md
|
137
|
+
documentation_uri: https://rubydoc.info/gems/artificial
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 3.1.0
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubygems_version: 3.6.7
|
153
|
+
specification_version: 4
|
154
|
+
summary: Artificial intelligence library for prompting
|
155
|
+
test_files: []
|