Class: Insika::Safety::Factory

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/safety/factory.rb

Overview

Composition helper for the guardrail subsystem. Keeps the wiring (config.ru / deployment.rb) a one-liner and the Executor decoupled from Safety: the Executor only ever sees a duck-typed content_filter_factory callable and reads plain Hash fields (guardrail_block/guardrail_flags) off the state.

The LLM tiers (moderator + validator) resolve their model from the per-agent guardrails.moderator ref, falling back to the platform utility_model (SettingsStore, #18). RubyLLM is required LAZILY (only when an ask is actually built), mirroring the Executor's create_chat — the core loads without the gem.

Instance Method Summary collapse

Constructor Details

#initialize(settings_store: nil, llm: nil) ⇒ Factory

settings_store (optional): source of the platform utility_model fallback. nil = no fallback (moderator only when the agent pins its own model ref). llm (optional): the graph's own RubyLLM context. nil = the process-wide RubyLLM constant. A guardrail asking on the global while the turn asks on the graph's key is a leak with a false sense of isolation, so this seam is part of and not a follow-up.



32
33
34
35
# File 'lib/insika/safety/factory.rb', line 32

def initialize(settings_store: nil, llm: nil)
  @settings_store = settings_store
  @llm = llm
end

Instance Method Details

#content_filter_factoryObject

Injected into the Executor. ->(state) { OutputFilter | nil }: a fresh stateful filter per turn when the agent has output guardrails on; nil = off (parity).



57
58
59
60
61
62
# File 'lib/insika/safety/factory.rb', line 57

def content_filter_factory
  lambda do |state|
    config = Config.from_profile(state.profile)
    config.output ? OutputFilter.new(corpus: config.corpus) : nil
  end
end

#grounding_enforcerObject

the :enforce boundary step the Executor calls between stages 6 and 8. Inert unless the profile's grounding.mode is :enforce.



53
# File 'lib/insika/safety/factory.rb', line 53

def grounding_enforcer = GroundingEnforcer.new

#input_guardrailObject

The single input-side Middleware for the global MiddlewareStack.



38
39
40
# File 'lib/insika/safety/factory.rb', line 38

def input_guardrail
  InputGuardrail.new(moderator_factory: ->(config) { moderator_for(config) })
end

#output_validatorObject

The after_task hook (register with hooks.register(:task, after: ...)). the grounding validator is the OutputValidator's FIRST step — it runs before the output gate (D9), so grounding is independent of the guardrails opt-in.



46
47
48
49
# File 'lib/insika/safety/factory.rb', line 46

def output_validator
  OutputValidator.new(ask_factory: ->(config) { ask_for(config) },
                      grounding: GroundingValidator.new)
end