Class: Ask::AppServer::Config
- Inherits:
-
Object
- Object
- Ask::AppServer::Config
- Defined in:
- lib/ask/app_server/config.rb
Overview
Configuration loader for ask-app-server.
Reads from a JSON config file, then merges environment variable overrides. Config file search order (first found wins):
1. ASK_APP_SERVER_CONFIG env var (explicit path)
2. ./.ask-app-server.json (project-local)
3. ~/.ask-app-server/config.json (user-global)
Environment variable overrides:
ASK_APP_SERVER_MODEL — model identifier (e.g., "opencode_go/deepseek-v4-flash")
ASK_APP_SERVER_PERMISSIONS — permission mode (on_request, never)
DEBUG — debug logging
Example config file (~/.ask-app-server/config.json):
{
"model": "opencode_go/deepseek-v4-flash",
"tools": ["bash", "read", "write", "edit", "glob", "grep"],
"permissions": {
"mode": "on_request",
"blocked_tools": ["write", "edit", "bash", "destroy"],
"timeout": 300
},
"system_prompt": "You are a helpful AI coding assistant.",
"session": { "timeout": 600 },
"custom_models": {
"deepseek-v4-flash": {
"provider": "opencode_go",
"context": 1000000,
"output": 384000
}
}
}
Constant Summary collapse
- DEFAULTS =
{ model: "opencode_go/deepseek-v4-flash", tools: %w[bash read write edit glob grep].freeze, permissions: { mode: :on_request, blocked_tools: %w[write edit bash destroy].freeze, timeout: 300 }.freeze, system_prompt: nil, session: { timeout: 600 }.freeze, custom_models: {}.freeze }.freeze
- CONFIG_FILE_PATHS =
[ -> { ENV["ASK_APP_SERVER_CONFIG"] }, -> { File.(".ask-app-server.json") }, -> { File.("~/.ask-app-server/config.json") } ].freeze
Instance Attribute Summary collapse
-
#source_path ⇒ Object
readonly
Returns the value of attribute source_path.
Instance Method Summary collapse
-
#blocked_tools ⇒ Object
List of tool names that require permission.
-
#custom_models ⇒ Object
Custom model definitions from config.
-
#debug? ⇒ Boolean
Whether debug logging is enabled.
-
#initialize(config_path: nil) ⇒ Config
constructor
A new instance of Config.
-
#model ⇒ Object
Resolved model identifier (may include provider prefix).
-
#model_id ⇒ Object
The model ID (without provider prefix).
-
#model_provider ⇒ Object
The provider slug (nil if not specified).
-
#parsed_model ⇒ Object
Parse model into [provider, model_id].
-
#permission_mode ⇒ Object
Permission mode symbol (:on_request, :never).
-
#permission_timeout ⇒ Object
Permission request timeout in seconds.
-
#register_models! ⇒ Object
Register custom models into Ask::ModelCatalog so ask-agent can find them.
-
#session_timeout ⇒ Object
Session timeout in seconds.
-
#state_config ⇒ Object
State persistence configuration.
-
#state_sqlite_path ⇒ Object
Path for SQLite state database (if configured).
-
#system_prompt ⇒ Object
System prompt for the agent.
-
#to_h ⇒ Object
All config as a hash (for display).
-
#tools ⇒ Object
List of tool names to load.
Constructor Details
#initialize(config_path: nil) ⇒ Config
Returns a new instance of Config.
63 64 65 66 67 |
# File 'lib/ask/app_server/config.rb', line 63 def initialize(config_path: nil) @source_path = nil @data = load_config(config_path) @registered = false end |
Instance Attribute Details
#source_path ⇒ Object (readonly)
Returns the value of attribute source_path.
61 62 63 |
# File 'lib/ask/app_server/config.rb', line 61 def source_path @source_path end |
Instance Method Details
#blocked_tools ⇒ Object
List of tool names that require permission.
111 112 113 |
# File 'lib/ask/app_server/config.rb', line 111 def blocked_tools @data.dig(:permissions, :blocked_tools)&.map(&:to_s) || DEFAULTS.dig(:permissions, :blocked_tools) end |
#custom_models ⇒ Object
Custom model definitions from config.
150 151 152 |
# File 'lib/ask/app_server/config.rb', line 150 def custom_models @data[:custom_models] || {} end |
#debug? ⇒ Boolean
Whether debug logging is enabled.
145 146 147 |
# File 'lib/ask/app_server/config.rb', line 145 def debug? ENV["DEBUG"] == "1" end |
#model ⇒ Object
Resolved model identifier (may include provider prefix).
70 71 72 |
# File 'lib/ask/app_server/config.rb', line 70 def model ENV.fetch("ASK_APP_SERVER_MODEL", @data[:model]) end |
#model_id ⇒ Object
The model ID (without provider prefix).
87 88 89 |
# File 'lib/ask/app_server/config.rb', line 87 def model_id parsed_model[1] end |
#model_provider ⇒ Object
The provider slug (nil if not specified).
92 93 94 |
# File 'lib/ask/app_server/config.rb', line 92 def model_provider parsed_model[0] end |
#parsed_model ⇒ Object
Parse model into [provider, model_id]. Supports "provider/model" format and bare model names.
76 77 78 79 80 81 82 83 84 |
# File 'lib/ask/app_server/config.rb', line 76 def parsed_model raw = model if raw.include?("/") parts = raw.split("/", 2) [parts[0], parts[1]] else [nil, raw] end end |
#permission_mode ⇒ Object
Permission mode symbol (:on_request, :never).
102 103 104 105 106 107 108 |
# File 'lib/ask/app_server/config.rb', line 102 def env_mode = ENV["ASK_APP_SERVER_PERMISSIONS"] return env_mode.to_sym if env_mode raw = @data.dig(:permissions, :mode) raw ? raw.to_sym : DEFAULTS.dig(:permissions, :mode) end |
#permission_timeout ⇒ Object
Permission request timeout in seconds.
116 117 118 |
# File 'lib/ask/app_server/config.rb', line 116 def @data.dig(:permissions, :timeout) || DEFAULTS.dig(:permissions, :timeout) end |
#register_models! ⇒ Object
Register custom models into Ask::ModelCatalog so ask-agent can find them. Safe to call multiple times — models are registered only once.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/ask/app_server/config.rb', line 156 def register_models! return if @registered @registered = true custom_models.each do |model_id, cfg| provider = cfg[:provider] || cfg["provider"] context = cfg[:context] || cfg["context"] || 4096 output = cfg[:output] || cfg["output"] || 4096 # Build a ModelInfo-compatible struct and register it model_info = OpenStruct.new( id: model_id.to_s, provider: provider.to_s, chat?: true, context: context, output: output ) # Use the singleton's register if available if Ask::ModelCatalog.respond_to?(:instance) catalog = Ask::ModelCatalog.instance catalog.register(model_info) if catalog.respond_to?(:register) end if debug? warn "[ask-app-server] Registered custom model: #{provider}/#{model_id} (#{context}ctx)" end end end |
#session_timeout ⇒ Object
Session timeout in seconds.
126 127 128 |
# File 'lib/ask/app_server/config.rb', line 126 def session_timeout @data.dig(:session, :timeout) || DEFAULTS.dig(:session, :timeout) end |
#state_config ⇒ Object
State persistence configuration. Returns nil if no state config is set (use in-memory defaults).
132 133 134 |
# File 'lib/ask/app_server/config.rb', line 132 def state_config @data[:state] end |
#state_sqlite_path ⇒ Object
Path for SQLite state database (if configured).
137 138 139 140 141 142 |
# File 'lib/ask/app_server/config.rb', line 137 def state_sqlite_path cfg = state_config return nil unless cfg cfg[:sqlite_path] || cfg["sqlite_path"] || cfg[:path] || cfg["path"] end |
#system_prompt ⇒ Object
System prompt for the agent.
121 122 123 |
# File 'lib/ask/app_server/config.rb', line 121 def system_prompt @data[:system_prompt] end |
#to_h ⇒ Object
All config as a hash (for display).
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/ask/app_server/config.rb', line 187 def to_h prov, mod = parsed_model { model: mod, provider: prov, tools: tools, permissions: { mode: , blocked_tools: blocked_tools, timeout: }, system_prompt: system_prompt, session: { timeout: session_timeout }, custom_models: custom_models.keys, source: source_path || "(defaults)" } end |
#tools ⇒ Object
List of tool names to load.
97 98 99 |
# File 'lib/ask/app_server/config.rb', line 97 def tools @data[:tools] || DEFAULTS[:tools] end |