phronomy 0.5.4 → 0.6.0
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 +41 -0
- data/README.md +24 -25
- data/lib/phronomy/agent/base.rb +88 -2
- data/lib/phronomy/agent/fsm.rb +165 -0
- data/lib/phronomy/agent/parallel_tool_chat.rb +75 -0
- data/lib/phronomy/configuration.rb +6 -0
- data/lib/phronomy/context.rb +0 -1
- data/lib/phronomy/event.rb +14 -0
- data/lib/phronomy/event_loop.rb +147 -0
- data/lib/phronomy/fsm_session.rb +194 -0
- data/lib/phronomy/generator_verifier.rb +22 -22
- data/lib/phronomy/guardrail.rb +0 -1
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow.rb +83 -71
- data/lib/phronomy/workflow_context.rb +1 -1
- data/lib/phronomy/workflow_runner.rb +167 -112
- data/lib/phronomy.rb +4 -0
- metadata +7 -6
- data/lib/phronomy/context/builder.rb +0 -92
- data/lib/phronomy/guardrail/builtin/pii_pattern_detector.rb +0 -100
- data/lib/phronomy/guardrail/builtin/prompt_injection_detector.rb +0 -67
- data/lib/phronomy/guardrail/builtin.rb +0 -16
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module Guardrail
|
|
5
|
-
module Builtin
|
|
6
|
-
# Input guardrail that detects common PII patterns in the input string.
|
|
7
|
-
#
|
|
8
|
-
# Four categories are supported and each can be individually toggled:
|
|
9
|
-
#
|
|
10
|
-
# - +:ssn+ — US Social Security Numbers (###-##-####)
|
|
11
|
-
# - +:credit_card+ — Credit / debit card numbers
|
|
12
|
-
# - +:email+ — E-mail addresses
|
|
13
|
-
# - +:phone+ — Phone numbers
|
|
14
|
-
#
|
|
15
|
-
# All four categories are active by default.
|
|
16
|
-
#
|
|
17
|
-
# @example Default — all categories active:
|
|
18
|
-
# agent.add_input_guardrail(Phronomy::Guardrail::Builtin::PIIPatternDetector.new)
|
|
19
|
-
#
|
|
20
|
-
# @example Only check for credit cards and email:
|
|
21
|
-
# detector = Phronomy::Guardrail::Builtin::PIIPatternDetector.new(
|
|
22
|
-
# detect: [:credit_card, :email]
|
|
23
|
-
# )
|
|
24
|
-
class PIIPatternDetector < InputGuardrail
|
|
25
|
-
# Recognised PII categories and their detection patterns.
|
|
26
|
-
PATTERNS = {
|
|
27
|
-
# US Social Security Number: ###-##-#### (hyphens required).
|
|
28
|
-
ssn: {
|
|
29
|
-
pattern: /\b\d{3}-\d{2}-\d{4}\b/,
|
|
30
|
-
label: "SSN"
|
|
31
|
-
},
|
|
32
|
-
# Credit / debit card: 16 digits, optionally separated by spaces or hyphens.
|
|
33
|
-
# Matched candidates are additionally validated with the Luhn algorithm
|
|
34
|
-
# to eliminate false positives from arbitrary 16-digit sequences.
|
|
35
|
-
credit_card: {
|
|
36
|
-
pattern: /\b(?:\d{4}[- ]?){3}\d{4}\b/,
|
|
37
|
-
label: "credit card number",
|
|
38
|
-
validate_luhn: true
|
|
39
|
-
},
|
|
40
|
-
# Email address (simplified RFC 5322).
|
|
41
|
-
email: {
|
|
42
|
-
pattern: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/,
|
|
43
|
-
label: "email address"
|
|
44
|
-
},
|
|
45
|
-
# Phone number: 3-digit area code, 3-4-digit exchange, 4-digit subscriber;
|
|
46
|
-
# optional E.164 country-code prefix (e.g. +1, +44).
|
|
47
|
-
phone: {
|
|
48
|
-
pattern: /(?:\+\d{1,3}[.\- ]?)?\(?\d{3}\)?[.\- ]?\d{3,4}[.\- ]?\d{4}\b/,
|
|
49
|
-
label: "phone number"
|
|
50
|
-
}
|
|
51
|
-
}.freeze
|
|
52
|
-
|
|
53
|
-
ALL_CATEGORIES = PATTERNS.keys.freeze
|
|
54
|
-
|
|
55
|
-
# @param detect [Array<Symbol>] categories to detect.
|
|
56
|
-
# Defaults to all four: +:ssn+, +:credit_card+, +:email+, +:phone+.
|
|
57
|
-
# @raise [ArgumentError] when an unknown category symbol is provided.
|
|
58
|
-
def initialize(detect: ALL_CATEGORIES)
|
|
59
|
-
unknown = Array(detect) - ALL_CATEGORIES
|
|
60
|
-
raise ArgumentError, "Unknown PII categories: #{unknown.inspect}" if unknown.any?
|
|
61
|
-
|
|
62
|
-
@active_patterns = Array(detect).map { |cat| PATTERNS.fetch(cat) }
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# @param value [Object] the input to check
|
|
66
|
-
# @raise [Phronomy::GuardrailError] when a PII pattern is matched,
|
|
67
|
-
# with a message identifying the category.
|
|
68
|
-
def check(value)
|
|
69
|
-
text = value.to_s
|
|
70
|
-
@active_patterns.each do |entry|
|
|
71
|
-
detected = if entry[:validate_luhn]
|
|
72
|
-
# Scan for all candidates then filter by Luhn check-digit validation.
|
|
73
|
-
# This avoids false positives on arbitrary 16-digit strings (e.g. internal IDs).
|
|
74
|
-
text.scan(entry[:pattern]).any? { |m| luhn_valid?(m.gsub(/[- ]/, "")) }
|
|
75
|
-
else
|
|
76
|
-
text.match?(entry[:pattern])
|
|
77
|
-
end
|
|
78
|
-
fail!("PII detected in input: #{entry[:label]}") if detected
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
private
|
|
83
|
-
|
|
84
|
-
# Returns true when +digits+ (a string of decimal digits) satisfies the
|
|
85
|
-
# Luhn check-digit algorithm used by payment card networks.
|
|
86
|
-
def luhn_valid?(digits)
|
|
87
|
-
digits.chars.reverse.each_with_index.sum do |d, i|
|
|
88
|
-
n = d.to_i
|
|
89
|
-
if i.odd?
|
|
90
|
-
doubled = n * 2
|
|
91
|
-
(doubled > 9) ? (doubled - 9) : doubled
|
|
92
|
-
else
|
|
93
|
-
n
|
|
94
|
-
end
|
|
95
|
-
end % 10 == 0
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module Guardrail
|
|
5
|
-
module Builtin
|
|
6
|
-
# Input guardrail that detects common prompt injection attempts.
|
|
7
|
-
#
|
|
8
|
-
# Matches a built-in list of injection patterns (case-insensitive) and raises
|
|
9
|
-
# {Phronomy::GuardrailError} when any pattern is found in the input string.
|
|
10
|
-
# Additional patterns can be supplied via the +additional_patterns:+ argument.
|
|
11
|
-
#
|
|
12
|
-
# **Limitations**: the built-in patterns cover well-known English and Japanese
|
|
13
|
-
# phrasings. Obfuscated, Base64-encoded, or novel injection phrasing may not
|
|
14
|
-
# be detected. For higher-assurance use cases, combine this guardrail with an
|
|
15
|
-
# LLM-based classifier.
|
|
16
|
-
#
|
|
17
|
-
# @example
|
|
18
|
-
# agent.add_input_guardrail(
|
|
19
|
-
# Phronomy::Guardrail::Builtin::PromptInjectionDetector.new
|
|
20
|
-
# )
|
|
21
|
-
#
|
|
22
|
-
# # With extra patterns:
|
|
23
|
-
# detector = Phronomy::Guardrail::Builtin::PromptInjectionDetector.new(
|
|
24
|
-
# additional_patterns: [/do anything now/i]
|
|
25
|
-
# )
|
|
26
|
-
class PromptInjectionDetector < InputGuardrail
|
|
27
|
-
# Default patterns that signal a prompt injection attempt.
|
|
28
|
-
DEFAULT_PATTERNS = [
|
|
29
|
-
# --- English patterns ---
|
|
30
|
-
/ignore\s+(all\s+)?(previous|prior|above)\s+(instructions?|rules?|prompts?)/i,
|
|
31
|
-
/disregard\s+(all\s+)?(previous|prior|above)\s+(instructions?|rules?|prompts?)/i,
|
|
32
|
-
/forget\s+(all\s+)?(previous|prior|above)\s+(instructions?|rules?|prompts?)/i,
|
|
33
|
-
/\bsystem\s*prompt\s*:/i,
|
|
34
|
-
/\byou\s+are\s+now\s+(?:a|an)\b/i,
|
|
35
|
-
/\bact\s+as\s+(?:a|an)\b/i,
|
|
36
|
-
/\bpretend\s+(?:you\s+are|to\s+be)\b/i,
|
|
37
|
-
/\bjailbreak\b/i,
|
|
38
|
-
/\bdan\s*mode\b/i,
|
|
39
|
-
/\bdev(?:eloper)?\s*mode\b/i,
|
|
40
|
-
# --- Japanese patterns ---
|
|
41
|
-
/以前の(指示|ルール|プロンプト)を無視/,
|
|
42
|
-
/指示を無視して/,
|
|
43
|
-
/ルールを無視して/,
|
|
44
|
-
/あなたは今(から)?(?!助けて)/,
|
|
45
|
-
/システムプロンプト/,
|
|
46
|
-
/制約(を|から)無視/,
|
|
47
|
-
/制限(を|から)解除/
|
|
48
|
-
].freeze
|
|
49
|
-
|
|
50
|
-
# @param additional_patterns [Array<Regexp>] extra patterns to check in addition
|
|
51
|
-
# to the built-in list.
|
|
52
|
-
def initialize(additional_patterns: [])
|
|
53
|
-
@patterns = DEFAULT_PATTERNS + Array(additional_patterns)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# @param value [Object] the input to check
|
|
57
|
-
# @raise [Phronomy::GuardrailError] when an injection pattern is matched
|
|
58
|
-
def check(value)
|
|
59
|
-
text = value.to_s
|
|
60
|
-
@patterns.each do |pattern|
|
|
61
|
-
fail!("Potential prompt injection detected") if text.match?(pattern)
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "builtin/prompt_injection_detector"
|
|
4
|
-
require_relative "builtin/pii_pattern_detector"
|
|
5
|
-
|
|
6
|
-
module Phronomy
|
|
7
|
-
module Guardrail
|
|
8
|
-
# Namespace for built-in guardrail implementations shipped with phronomy.
|
|
9
|
-
#
|
|
10
|
-
# Available classes:
|
|
11
|
-
# - {Phronomy::Guardrail::Builtin::PromptInjectionDetector}
|
|
12
|
-
# - {Phronomy::Guardrail::Builtin::PIIPatternDetector}
|
|
13
|
-
module Builtin
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|