Class: Insika::Safety::Config
- Inherits:
-
Object
- Object
- Insika::Safety::Config
- Defined in:
- lib/insika/safety/config.rb
Overview
Per-agent guardrail configuration, read from
profile.guardrails. OPT-IN like capabilities: an agent that says nothing
gets the CONSERVATIVE default — deterministic detectors ON, LLM moderator OFF.
Tolerant of the JSON round-trip (string OR symbol keys / values), same discipline as ModelPolicy — the StoredProfileSource persists this as a plain Hash and it comes back stringified.
guardrails: {
input: true|false, # run the input guardrail middleware (default true)
output: true|false, # run the output filter + validator (default true)
moderator: "provider/model"|nil, # LLM moderator model; nil = deterministic only
strictness: "low"|"medium"|"high", # which input categories fire (default medium)
responses: { <category> => "<safe reply>", ... } # per-agent override, see below
corpora: { "languages" => ["en"], "extra" => { "abuse" => ["/\\bdupa\\b/i"] } }
}
corpora is the removability knob for the shipped
pt-BR corpus: languages filters the shipped families (nil = all,
[] = none, ["en"] = the EN-only corpus — dropping the pt-BR input
heuristics AND the CPF/CNPJ output redaction, a documented consequence),
extra adds source-string patterns per family. Absent = the full
shipped default, byte-for-byte today's behavior (parity). Validation
fails loud (Insika::ValidationError naming the value): the doctor's
guardrail-corpora check compiles every declaration, so a typo'd language
surfaces at boot — insika doctor exits non-zero — never mid-turn.
responses is the CONFIGURATION-OVER-CONVENTION knob. The engine
ships neutral built-in refusals (Safety::SafeResponses::DEFAULTS), but this is
OSS across arbitrary businesses/languages, so we never hard-bake tone: an agent
overrides the safe reply per category (injection/sexual/abuse/escalate/
…) or sets a single catch-all default. Resolution order (SafeResponses.for):
agent → agent → built-in → built-in.
Constant Summary collapse
- STRICTNESS_CATEGORIES =
strictness -> input categories that the deterministic scan runs. low = only injection (+ output redaction) — highest confidence, fewest FPs medium = injection + sexual + abuse (the default) high = same families, reserved for future broader lists
{ low: %i[injection], medium: %i[injection sexual abuse], high: %i[injection sexual abuse] }.freeze
- DEFAULT_STRICTNESS =
:medium
Instance Attribute Summary collapse
-
#corpora ⇒ Object
readonly
Returns the value of attribute corpora.
-
#input ⇒ Object
readonly
Returns the value of attribute input.
-
#moderator ⇒ Object
readonly
Returns the value of attribute moderator.
-
#output ⇒ Object
readonly
Returns the value of attribute output.
-
#responses ⇒ Object
readonly
Returns the value of attribute responses.
-
#strictness ⇒ Object
readonly
Returns the value of attribute strictness.
Class Method Summary collapse
- .from_hash(raw) ⇒ Object
-
.from_profile(profile) ⇒ Object
Builds a Config from a profile.
Instance Method Summary collapse
-
#corpus ⇒ Object
The compiled corpus for this agent — never nil: absent corpora -> the full shipped default.
-
#corpus_languages ⇒ Object
The resolved corpus languages (for the doctor's enumeration, C3): nil corpora (or nil languages) = ALL shipped languages.
-
#enabled? ⇒ Boolean
A guardrail is fully off only when BOTH sides are disabled — cheap early-out.
-
#initialize(input:, output:, moderator:, strictness:, responses: {}, corpora: nil) ⇒ Config
constructor
A new instance of Config.
-
#input_categories ⇒ Object
Input categories the deterministic scan should run, per strictness.
- #moderator? ⇒ Boolean
Constructor Details
#initialize(input:, output:, moderator:, strictness:, responses: {}, corpora: nil) ⇒ Config
Returns a new instance of Config.
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/insika/safety/config.rb', line 53 def initialize(input:, output:, moderator:, strictness:, responses: {}, corpora: nil) @input = input @output = output @moderator = moderator @strictness = strictness @responses = responses # { "category" => "safe reply" }, agent override map @corpora = corpora # { "languages" => [...]?, "extra" => {...}? } | nil (nil = the shipped default) # Built ONCE at construction: the compiled corpus the whole turn reads. @corpus = Corpus.compile(languages: corpora && corpora["languages"], extra: (corpora && corpora["extra"]) || {}) end |
Instance Attribute Details
#corpora ⇒ Object (readonly)
Returns the value of attribute corpora.
51 52 53 |
# File 'lib/insika/safety/config.rb', line 51 def corpora @corpora end |
#input ⇒ Object (readonly)
Returns the value of attribute input.
51 52 53 |
# File 'lib/insika/safety/config.rb', line 51 def input @input end |
#moderator ⇒ Object (readonly)
Returns the value of attribute moderator.
51 52 53 |
# File 'lib/insika/safety/config.rb', line 51 def moderator @moderator end |
#output ⇒ Object (readonly)
Returns the value of attribute output.
51 52 53 |
# File 'lib/insika/safety/config.rb', line 51 def output @output end |
#responses ⇒ Object (readonly)
Returns the value of attribute responses.
51 52 53 |
# File 'lib/insika/safety/config.rb', line 51 def responses @responses end |
#strictness ⇒ Object (readonly)
Returns the value of attribute strictness.
51 52 53 |
# File 'lib/insika/safety/config.rb', line 51 def strictness @strictness end |
Class Method Details
.from_hash(raw) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/insika/safety/config.rb', line 69 def self.from_hash(raw) h = symbolize(raw) new( input: bool(h.fetch(:input, true)), output: bool(h.fetch(:output, true)), moderator: presence(h[:moderator]), strictness: normalize_strictness(h[:strictness]), responses: normalize_responses(h[:responses]), corpora: normalize_corpora(h[:corpora]) ) end |
.from_profile(profile) ⇒ Object
Builds a Config from a profile. A nil/empty guardrails -> the
conservative default (see from_hash).
67 |
# File 'lib/insika/safety/config.rb', line 67 def self.from_profile(profile) = from_hash(profile.guardrails) |
Instance Method Details
#corpus ⇒ Object
The compiled corpus for this agent — never nil: absent corpora -> the full shipped default.
83 |
# File 'lib/insika/safety/config.rb', line 83 def corpus = @corpus |
#corpus_languages ⇒ Object
The resolved corpus languages (for the doctor's enumeration, C3): nil corpora (or nil languages) = ALL shipped languages.
87 88 89 90 |
# File 'lib/insika/safety/config.rb', line 87 def corpus_languages langs = @corpora && @corpora["languages"] langs.nil? ? Corpus::DEFAULTS.keys : langs end |
#enabled? ⇒ Boolean
A guardrail is fully off only when BOTH sides are disabled — cheap early-out.
96 |
# File 'lib/insika/safety/config.rb', line 96 def enabled? = @input || @output |
#input_categories ⇒ Object
Input categories the deterministic scan should run, per strictness.
93 |
# File 'lib/insika/safety/config.rb', line 93 def input_categories = STRICTNESS_CATEGORIES.fetch(@strictness, STRICTNESS_CATEGORIES[DEFAULT_STRICTNESS]) |
#moderator? ⇒ Boolean
98 |
# File 'lib/insika/safety/config.rb', line 98 def moderator? = !@moderator.nil? |