Class: Vangrail::Rail
- Inherits:
-
Object
- Object
- Vangrail::Rail
- Defined in:
- lib/vangrail/rail.rb
Overview
The whole rail protocol: a name, the sides it applies to, and call.
class ShoutRail < Vangrail::Rail
def decide(text, _context)
return pass if text == text.downcase
modify(text.downcase, reason: 'lowered')
end
end
Deliberately not a DSL. A rail is an object with one method, so a Ruby
application can write one in five lines, test it without a network, and put
it in the same ordered list as the model-backed ones. Subclasses implement
#decide; #call scrubs the bytes first so every rail sees readable text.
Direct Known Subclasses
Vangrail::Rails::Alignment, Vangrail::Rails::Bayes, Vangrail::Rails::Budget, Vangrail::Rails::Canary, Vangrail::Rails::ColangFlow, Vangrail::Rails::Escalation, Vangrail::Rails::Exfiltration, Vangrail::Rails::Grounding, Vangrail::Rails::GuardModel, Vangrail::Rails::Hidden, Vangrail::Rails::InjectedInstructions, Vangrail::Rails::Jailbreak, Vangrail::Rails::KnownAnswer, Vangrail::Rails::Language, Vangrail::Rails::Linear, Vangrail::Rails::ManyShot, Vangrail::Rails::Markup, Vangrail::Rails::Missing, Vangrail::Rails::Obfuscation, Vangrail::Rails::Paraphrase, Vangrail::Rails::Pattern, Vangrail::Rails::Perplexity, Vangrail::Rails::PersonalData, Vangrail::Rails::PromptLeak, Vangrail::Rails::Remote, Vangrail::Rails::Secrets, Vangrail::Rails::SelfCheck, Vangrail::Rails::Semantic, Vangrail::Rails::Similarity, Vangrail::Rails::Trajectory
Constant Summary collapse
- SIDES =
Three sides, not two.
:contextis text the application retrieved and is about to put in a prompt: a wiki page, a search result, a file. It is the side an attacker usually reaches without touching the application at all, and a stack that checks only what the user typed and what the model answered never looks at it. %i[input context output].freeze
- DEFAULT_SIDES =
What a rail gets by default. Context is opt-in per rail, because a rail written to judge a question is rarely the right one to judge a document.
%i[input output].freeze
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#sides ⇒ Object
readonly
Returns the value of attribute sides.
Class Method Summary collapse
-
.usable(text) ⇒ Object
UTF-8 or something that can be read as it.
Instance Method Summary collapse
- #applies_to?(side) ⇒ Boolean
- #cache_key(_text, _context) ⇒ Object
-
#call(text, context = {}) ⇒ Object
Returns a Result.
-
#decide(_text, _context) ⇒ Object
Subclasses implement this.
-
#initialize(name: nil, sides: DEFAULT_SIDES) ⇒ Rail
constructor
A new instance of Rail.
-
#language_agnostic? ⇒ Boolean
True when a hit or a silence is meaningful even if the page is not in a language the lexicons cover.
-
#offline? ⇒ Boolean
Does this rail need the network.
-
#placeholder? ⇒ Boolean
A rail that stands in for one that could not be built, rather than a rail that ran.
-
#posture? ⇒ Boolean
True when this rail's job is to say whether the other rails apply, not to contribute a hit.
- #quantifies? ⇒ Boolean
- #to_s ⇒ Object
Constructor Details
#initialize(name: nil, sides: DEFAULT_SIDES) ⇒ Rail
Returns a new instance of Rail.
34 35 36 37 38 39 |
# File 'lib/vangrail/rail.rb', line 34 def initialize(name: nil, sides: DEFAULT_SIDES) @name = (name || default_name).to_s @sides = Array(sides).map(&:to_sym) unknown = @sides - SIDES raise ArgumentError, "unknown side(s): #{unknown.join(', ')}" unless unknown.empty? end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
32 33 34 |
# File 'lib/vangrail/rail.rb', line 32 def name @name end |
#sides ⇒ Object (readonly)
Returns the value of attribute sides.
32 33 34 |
# File 'lib/vangrail/rail.rb', line 32 def sides @sides end |
Class Method Details
.usable(text) ⇒ Object
UTF-8 or something that can be read as it. A body off a socket arrives tagged ASCII-8BIT whatever is in it, so the tag is corrected before the bytes are judged; only genuinely broken sequences are scrubbed, and the scrub leaves a replacement character where the byte was, which Rails::Obfuscation then treats as the evasion it is.
59 60 61 62 63 |
# File 'lib/vangrail/rail.rb', line 59 def self.usable(text) body = text.to_s body = body.dup.force_encoding(Encoding::UTF_8) unless body.encoding == Encoding::UTF_8 body.valid_encoding? ? body : body.scrub end |
Instance Method Details
#applies_to?(side) ⇒ Boolean
41 42 43 |
# File 'lib/vangrail/rail.rb', line 41 def applies_to?(side) sides.include?(side.to_sym) end |
#cache_key(_text, _context) ⇒ Object
70 |
# File 'lib/vangrail/rail.rb', line 70 def cache_key(_text, _context) = nil |
#call(text, context = {}) ⇒ Object
Returns a Result. context is a hash the engine threads through:
:side, :user_input, :passages, :history, plus anything a caller adds.
Scrubs here so rail.call(page, side: :context) (the shape the README
and the tutorial teach) never hands a subclass bytes it cannot read.
50 51 52 |
# File 'lib/vangrail/rail.rb', line 50 def call(text, context = {}) decide(Rail.usable(text), context) end |
#decide(_text, _context) ⇒ Object
Subclasses implement this. text is already readable UTF-8.
66 67 68 |
# File 'lib/vangrail/rail.rb', line 66 def decide(_text, _context) raise NotImplementedError, "#{self.class} must implement #decide" end |
#language_agnostic? ⇒ Boolean
True when a hit or a silence is meaningful even if the page is not in a language the lexicons cover. Markup, budgets, and secrets do not care what language the words are in. Pattern and concept rails do.
98 99 100 |
# File 'lib/vangrail/rail.rb', line 98 def language_agnostic? false end |
#offline? ⇒ Boolean
Does this rail need the network. Used to report a posture and to let a caller build a model-free engine on purpose. The rare case is networked.
76 77 78 |
# File 'lib/vangrail/rail.rb', line 76 def offline? true end |
#placeholder? ⇒ Boolean
A rail that stands in for one that could not be built, rather than a rail that ran. The engine prefers the reason from something that actually ran when both are uncertain, because "the endpoint refused the connection" is more actionable than "no endpoint was resolved".
84 85 86 |
# File 'lib/vangrail/rail.rb', line 84 def placeholder? false end |
#posture? ⇒ Boolean
True when this rail's job is to say whether the other rails apply, not to contribute a hit. Language is the case: it never blocks, and a miss means the lexicon rails did not read the page.
91 92 93 |
# File 'lib/vangrail/rail.rb', line 91 def posture? false end |
#quantifies? ⇒ Boolean
72 |
# File 'lib/vangrail/rail.rb', line 72 def quantifies? = false |
#to_s ⇒ Object
102 103 104 |
# File 'lib/vangrail/rail.rb', line 102 def to_s name end |