Class: Vangrail::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/vangrail/builder.rb,
lib/vangrail/builder.rb

Overview

Reads the environment into an engine. A class rather than a method so each decision is separable and testable on its own.

Constant Summary collapse

DEFAULT_RAILS =

Watermark is in the defaults rather than opt-in. Article 50(2) of the AI Act is not a preference a deployment expresses, and a mark nobody switched on is a mark that is not there. Naming a list without it turns it off, for a caller guarding text that no model generated.

%i[input context output watermark].freeze
ALL_RAILS =
%i[input context output grounding secrets patterns links multiturn privacy
markup budget semantic perplexity bayes linear watermark
task_relation task_drift].freeze
INJECTION_PATTERNS =

Deterministic input patterns, kept small on purpose. Each is a phrase whose presence is itself the violation; anything needing judgement belongs in a policy rail, where a false positive is a model's opinion rather than a hard rule.

{
  'instruction_override' => /
    \b(?:ignore|disregard)\s+
    (?:(?:all|any|the|your|those|these)\s+)?
    (?:previous|prior|above|earlier)\s+instructions?\b
  /ix,
  'prompt_disclosure' => /\b(?:reveal|print|repeat|show|output)\s+(?:me\s+)?(?:your|the|its)?\s*
                          (?:system\s+prompt|initial\s+instructions|developer\s+message)\b/xi,
  'role_reset' => /\byou\s+are\s+now\s+(?:a|an|in)\b.{0,40}\b(?:mode|persona|dan|jailbreak)\b/i,
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env = ENV) ⇒ Builder

Returns a new instance of Builder.



33
34
35
# File 'lib/vangrail/builder.rb', line 33

def initialize(env = ENV)
  @env = env
end

Instance Attribute Details

#envObject (readonly)

Returns the value of attribute env.



31
32
33
# File 'lib/vangrail/builder.rb', line 31

def env
  @env
end

Class Method Details

.deterministic(side, patterns: true) ⇒ Object

The offline stack that does not need a folder or an endpoint: patterns, concepts, near-copies, the decoding pass, and the language posture. Config#engine(stdlib: true) prepends the same list so a NeMo folder does not certain-pass a question nothing here can read.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/vangrail/builder.rb', line 53

def self.deterministic(side, patterns: true)
  side = side.to_sym
  return [] if side == :output

  core = [
    (Rails::InjectedInstructions.new if side == :context),
    (if side == :input && patterns
       Rails::Pattern.new(patterns: INJECTION_PATTERNS, name: 'injection_patterns',
                          sides: [side])
     end),
    Rails::Jailbreak.new(sides: [side]),
    Rails::Paraphrase.new(sides: [side]),
    Rails::Alignment.new(sides: [side]),
    Rails::Similarity.new(sides: [side]),
    Rails::ManyShot.new(sides: [side]),
  ].compact
  extras = [Rails::Obfuscation.new(rails: core, sides: [side])]
  extras << Rails::Hidden.new(rails: core) if side == :context
  extras << Rails::Language.new(sides: [side])
  core + extras
end

Instance Method Details

#cache?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/vangrail/builder.rb', line 107

def cache?
  !off_value?(env['GUARDRAILS_CACHE'])
end

#config_dirObject



111
112
113
# File 'lib/vangrail/builder.rb', line 111

def config_dir
  present(env['GUARDRAILS_CONFIG'])
end

#enabledObject

Raises:

  • (ArgumentError)


75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/vangrail/builder.rb', line 75

def enabled
  text = env['GUARDRAILS_RAILS'].to_s.strip
  return DEFAULT_RAILS if text.empty?
  return [] if off_value?(text) || text.casecmp('none').zero?
  return ALL_RAILS.dup if text.casecmp('all').zero?

  names = text.split(/[,\s]+/).map { |s| s.strip.downcase.to_sym }
  unknown = names - ALL_RAILS
  raise ArgumentError, "unknown rail name(s): #{unknown.join(', ')}" unless unknown.empty?

  names & ALL_RAILS
end

#engineObject



37
38
39
40
41
42
43
# File 'lib/vangrail/builder.rb', line 37

def engine
  return Engine.new(on_error: on_error, on_uncertain: on_uncertain, cache: cache?) if off?
  return config_engine if config_dir

  Engine.new(input: input_rails, context: context_rails, output: output_rails,
             on_error: on_error, on_uncertain: on_uncertain, cache: cache?)
end

#off?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/vangrail/builder.rb', line 92

def off?
  off_value?(env['GUARDRAILS'])
end

#on?(rail) ⇒ Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/vangrail/builder.rb', line 88

def on?(rail)
  enabled.include?(rail)
end

#on_errorObject



96
97
98
# File 'lib/vangrail/builder.rb', line 96

def on_error
  env['GUARDRAILS_ON_ERROR'].to_s.strip.casecmp('block').zero? ? :block : :allow
end

#on_uncertainObject

A rail that ran and could not decide is a different fact from a rail that raised, and this is the switch for it. See Engine for why the default is the way it is.



103
104
105
# File 'lib/vangrail/builder.rb', line 103

def on_uncertain
  env['GUARDRAILS_ON_UNCERTAIN'].to_s.strip.casecmp('block').zero? ? :block : :allow
end

#providerObject

The endpoint the model-backed rails call, or nil when none is reachable.



120
121
122
123
124
# File 'lib/vangrail/builder.rb', line 120

def provider
  return @provider if defined?(@provider)

  @provider = Provider.resolve(env)
end

#server_urlObject



115
116
117
# File 'lib/vangrail/builder.rb', line 115

def server_url
  present(env['GUARDRAILS_SERVER'])
end

#session(prior:, **kwargs) ⇒ Object



45
46
47
# File 'lib/vangrail/builder.rb', line 45

def session(prior:, **kwargs)
  Session.new(engine: engine, prior: prior, **kwargs)
end