Class: Protege::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/protege/configuration.rb

Overview

Holds the process-wide Protege configuration set via Protege.configure. A single instance is memoized on the Protege module and read throughout the LOGI pipeline — the Orchestrator reads max_tool_turns, the Inference layer reads provider_id (each provider reads its own model / sampling / credentials from its providers slice), and the Gateway reads console_address. Mutated once at boot from a Rails initializer; treated as read-only thereafter (the Orchestrator even freezes it per delivery via Context).

Examples:

Configure in a Rails initializer

Protege.configure do |config|
  config.provider_id = :openrouter
  config.providers   = { openrouter: { model: 'anthropic/claude-sonnet-4-5' } }
end

Constant Summary collapse

DEFAULT_HTTP_USER_AGENT =

Generic, real-looking browser User-Agent sent by the built-in web tools (+web_search+, web_fetch) by default. Deliberately unbranded — a plain Chrome string that blends in — since some origins reject or fingerprint unusual agents.

'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' \
'(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializevoid

Initialize configuration with engine defaults.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/protege/configuration.rb', line 87

def initialize
  @nav_title         = '🥚 Protege'
  @console_address   = 'console@protege.local'
  @http_user_agent   = DEFAULT_HTTP_USER_AGENT
  @max_tool_turns    = 100
  @recursion_limit   = 50
  @provider_id       = nil
  @logger            = nil
  @tools_path        = 'app/tools'
  @resolvers_path    = 'app/resolvers'
  @hooks_path        = 'app/hooks'
  @agents_path       = 'app/agents'
  @providers_path    = 'app/providers'
  @providers         = nil
  @attachment_policy = nil
  @inbound_access    = nil
  @tracing           = nil
  @failure_alerts    = nil
end

Instance Attribute Details

#agents_pathObject

Destination directories the extension scaffold generators (+protege:tool+, :resolver, :hook, :agent, :provider) write into, each relative to the app root. Defaults to the conventional app/tools, app/resolvers, app/hooks, app/agents, app/providers. Override in the initializer if a host groups its extensions elsewhere (e.g. config.tools_path = 'app/agents/tools'); the target must stay under an autoloaded path so Rails still loads the extension.



64
65
66
# File 'lib/protege/configuration.rb', line 64

def agents_path
  @agents_path
end

#attachment_policyProtege::Gateway::AttachmentPolicy

The inbound attachment limits, assigned in the initializer via config.attachment_policy = Gateway.build_attachment_policy(...). Defaults to the engine's standard limits (10 MB/attachment, 10/message, 25 MB total). Consulted by the inbound mailbox and the send_email tool.

Returns:



151
152
153
# File 'lib/protege/configuration.rb', line 151

def attachment_policy
  @attachment_policy ||= Gateway.build_attachment_policy
end

#console_addressObject

Email address representing the dashboard user in local conversations. Messages from the dashboard use this as their from_address, and outbound replies to this address skip SMTP delivery.



43
44
45
# File 'lib/protege/configuration.rb', line 43

def console_address
  @console_address
end

#failure_alertsHash

Operational failure-alert options, a plain Hash — the opt-in seam for emailing a platform admin when inference fails. Assigned wholesale in the initializer (like #tracing); assignment replaces the whole Hash. Recognised keys:

  • :to — an Array of recipient addresses. Alerting is enabled only when this is present and non-empty, so an unconfigured engine (the default {}) sends nothing.
  • :from — the sender address. For production deliverability this must be an address at a registered EmailDomain so the self-hosted MTA DKIM-signs it and it passes that domain's DMARC policy; there is no safe way to deduce it, so it is set explicitly. Omitted → the ApplicationMailer default sender (adequate only under the :test delivery method).

When :to is set, Protege::Subscribers::Alerter emails those recipients on inference failure.

Examples:

Turn failure alerts on

config.failure_alerts = { to: ['ops@you.com'], from: 'alerts@agent.you.com' }

Returns:

  • (Hash)

    the failure-alert options, defaulting to {} (disabled)



202
203
204
# File 'lib/protege/configuration.rb', line 202

def failure_alerts
  @failure_alerts ||= {}
end

#hooks_pathObject

Destination directories the extension scaffold generators (+protege:tool+, :resolver, :hook, :agent, :provider) write into, each relative to the app root. Defaults to the conventional app/tools, app/resolvers, app/hooks, app/agents, app/providers. Override in the initializer if a host groups its extensions elsewhere (e.g. config.tools_path = 'app/agents/tools'); the target must stay under an autoloaded path so Rails still loads the extension.



64
65
66
# File 'lib/protege/configuration.rb', line 64

def hooks_path
  @hooks_path
end

#http_user_agentObject

User-Agent the built-in web tools (+web_search+, web_fetch) send on outbound HTTP. Defaults to DEFAULT_HTTP_USER_AGENT — a generic browser string, not a Protege-branded one. Override to adopt your host machine's own browser agent, e.g. config.http_user_agent = ENV.fetch('HTTP_USER_AGENT', Protege::Configuration::DEFAULT_HTTP_USER_AGENT).



53
54
55
# File 'lib/protege/configuration.rb', line 53

def http_user_agent
  @http_user_agent
end

#inbound_accessProtege::Gateway::AccessPolicy

The global inbound access policy — the committed, org-wide ceiling on which senders may reach any agent. This is the static layer of the access-control guardrail; the runtime, per-agent layer lives in Protege::AccessRule records, and AccessControl intersects the two (each layer can only narrow, never widen).

Defaults to a bare permit-everyone policy, built lazily on first read so an unconfigured engine imposes no constraint.

Examples:

Restrict every agent to the company domain

config.inbound_access = Protege::Gateway.build_access_policy(allow: ['*@company.co'])

Returns:



167
168
169
# File 'lib/protege/configuration.rb', line 167

def inbound_access
  @inbound_access || Gateway.build_access_policy
end

#loggerLogger

Return the configured logger, lazily resolving a default.

Falls back to Rails.logger when running inside a Rails application, or a plain stdout logger otherwise (useful in isolated tests and scripts).

Returns:

  • (Logger)

    the active logger



113
114
115
# File 'lib/protege/configuration.rb', line 113

def logger
  @logger ||= defined?(Rails) ? Rails.logger : Logger.new($stdout)
end

#max_tool_turnsObject

Maximum tool-calling rounds before returning the last response.



31
32
33
# File 'lib/protege/configuration.rb', line 31

def max_tool_turns
  @max_tool_turns
end

Brand shown in the dashboard nav header. Override to white-label the console, e.g. config.nav_title = 'Acme Support'. Defaults to '🥚 Protege'.



47
48
49
# File 'lib/protege/configuration.rb', line 47

def nav_title
  @nav_title
end

#provider_idObject

Symbolic id of the inference provider extension (e.g. :openrouter). The model, sampling, and credentials for that provider live in its #providers slice, not here.



28
29
30
# File 'lib/protege/configuration.rb', line 28

def provider_id
  @provider_id
end

#providersHash{Symbol=>Hash}

Per-provider options, a plain Hash keyed by provider id — the Rails-style config seam every provider (built-in or host-written) reads its settings from. Assigned wholesale in the initializer; assignment replaces the whole Hash, so include every provider you configure:

config.providers = {
openrouter: { api_key: ENV['OPENROUTER_API_KEY'], base_url: '...' },
my_llm:     { api_key: ENV['MY_LLM_KEY'], region: 'us' }
}

Defaults to { openrouter: {} } so the built-in is harmless when unused. A provider reads its own slice via #provider_options (keyed by its protege_id). Values are opaque to the engine — a host-written provider may put any keys it likes under its own id and read them back here.

Returns:

  • (Hash{Symbol=>Hash})

    per-provider options keyed by provider id



131
132
133
# File 'lib/protege/configuration.rb', line 131

def providers
  @providers ||= { openrouter: {} }
end

#providers_pathObject

Destination directories the extension scaffold generators (+protege:tool+, :resolver, :hook, :agent, :provider) write into, each relative to the app root. Defaults to the conventional app/tools, app/resolvers, app/hooks, app/agents, app/providers. Override in the initializer if a host groups its extensions elsewhere (e.g. config.tools_path = 'app/agents/tools'); the target must stay under an autoloaded path so Rails still loads the extension.



64
65
66
# File 'lib/protege/configuration.rb', line 64

def providers_path
  @providers_path
end

#recursion_limitObject

The X-Protege-Recursion hop count at which inbound mail is silently dropped — the bound on agent-to-agent reply loops (see Gateway::RECURSION_HEADER). Agent-sent mail stamps the header (+1+ fresh, inbound plus one on a reply); a human replying anywhere resets the chain, since mail clients never echo the header back. Defaults to 50 — roomy enough for long agent-to-agent hand-offs while still bounding a true infinite loop.



38
39
40
# File 'lib/protege/configuration.rb', line 38

def recursion_limit
  @recursion_limit
end

#resolvers_pathObject

Destination directories the extension scaffold generators (+protege:tool+, :resolver, :hook, :agent, :provider) write into, each relative to the app root. Defaults to the conventional app/tools, app/resolvers, app/hooks, app/agents, app/providers. Override in the initializer if a host groups its extensions elsewhere (e.g. config.tools_path = 'app/agents/tools'); the target must stay under an autoloaded path so Rails still loads the extension.



64
65
66
# File 'lib/protege/configuration.rb', line 64

def resolvers_path
  @resolvers_path
end

#tools_pathObject

Destination directories the extension scaffold generators (+protege:tool+, :resolver, :hook, :agent, :provider) write into, each relative to the app root. Defaults to the conventional app/tools, app/resolvers, app/hooks, app/agents, app/providers. Override in the initializer if a host groups its extensions elsewhere (e.g. config.tools_path = 'app/agents/tools'); the target must stay under an autoloaded path so Rails still loads the extension.



64
65
66
# File 'lib/protege/configuration.rb', line 64

def tools_path
  @tools_path
end

#tracingHash

Inference tracing options, a plain Hash — the on/off seam for durable turn snapshots. Assigned wholesale in the initializer (like #providers); assignment replaces the whole Hash. Defaults to { enabled: false }, so an unconfigured engine records nothing. When enabled is truthy, the harness emits a per-turn InferenceGeneratedEvent that the tracing subscriber snapshots into Protege::Trace rows.

Examples:

Turn tracing on

config.tracing = { enabled: true }

Returns:

  • (Hash)

    the tracing options, defaulting to { enabled: false }



181
182
183
# File 'lib/protege/configuration.rb', line 181

def tracing
  @tracing ||= { enabled: false }
end

Instance Method Details

#provider_options(id) ⇒ Hash

The options Hash for one provider, by id — the seam a Protege::Provider reads its settings from (typically provider_options(self.class.id)). Nil-safe: returns an empty Hash when the provider has no configured slice.

Parameters:

  • id (Symbol)

    the provider id (its protege_id)

Returns:

  • (Hash)

    that provider's options, or {} when unconfigured



141
142
143
# File 'lib/protege/configuration.rb', line 141

def provider_options(id)
  providers[id] || {}
end