Module: Ask::Ruby::Harness

Defined in:
lib/ask/ruby/harness.rb,
lib/ask/ruby/harness/tool.rb,
lib/ask/ruby/harness/version.rb,
lib/ask/ruby/harness/audit_log.rb,
lib/ask/ruby/harness/configuration.rb,
lib/ask/ruby/harness/tools/read_log.rb,
lib/ask/ruby/harness/tools/run_tests.rb,
lib/ask/ruby/harness/tools/read_model.rb,
lib/ask/ruby/harness/tools/run_command.rb,
lib/ask/ruby/harness/tools/schema_graph.rb,
lib/ask/ruby/harness/tools/query_database.rb,
lib/ask/ruby/harness/minitest_json_reporter.rb,
lib/ask/ruby/harness/environment_permissions.rb

Defined Under Namespace

Modules: AuditLog, Tools Classes: Configuration, EnvironmentPermissions, MinitestJsonReporter, Tool

Constant Summary collapse

HARNESS_TOOLS =

Define after all tool files are loaded so the constants resolve

[
  Ask::Ruby::Harness::Tools::RunCommand, Ask::Ruby::Harness::Tools::QueryDatabase,
  Ask::Ruby::Harness::Tools::ReadModel, Ask::Ruby::Harness::Tools::ReadLog,
  Ask::Ruby::Harness::Tools::SchemaGraph, Ask::Ruby::Harness::Tools::RunTests
].freeze
VERSION =
"0.3.1"

Class Method Summary collapse

Class Method Details

.agent_session(**extra) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/ask/ruby/harness.rb', line 36

def agent_session(**extra)
  # Auto-prune if configured
  cleanup! if configuration.max_session_age || configuration.max_sessions

  tools = configuration.tools.map { |t| t.is_a?(Class) ? t.new : t }
  prompt = extra.delete(:system_prompt) || configuration.system_prompt || default_system_prompt

  # Resolve environment-specific permissions and wire into agent hooks
  hooks = build_environment_hooks

  Ask::Agent::Session.new(
    model: configuration.default_model,
    max_turns: configuration.max_turns,
    system_prompt: prompt,
    tools: tools,
    state: configuration.persistence_adapter,
    hooks: hooks,
    **extra
  )
end

.app_rootObject

The project root the harness serves. Defaults to the current working directory; framework editions set it to the framework's root at boot (ask-rails-harness sets it to ::Rails.root).



23
24
25
# File 'lib/ask/ruby/harness.rb', line 23

def app_root
  @app_root ||= Pathname.new(Dir.pwd)
end

.app_root=(path) ⇒ Object



27
28
29
# File 'lib/ask/ruby/harness.rb', line 27

def app_root=(path)
  @app_root = path ? Pathname.new(path) : nil
end

.cleanup!Object

Prune old sessions and audit logs based on configuration limits.

Removes sessions older than max_session_age seconds, and limits the total number of sessions to max_sessions (deleting the oldest first). Audit log entries older than the oldest kept session are also removed.



66
67
68
69
# File 'lib/ask/ruby/harness.rb', line 66

def cleanup!
  prune_old_sessions
  limit_session_count
end

.configurationObject



16
17
18
# File 'lib/ask/ruby/harness.rb', line 16

def configuration
  @configuration ||= Configuration.new
end

.configure {|configuration| ... } ⇒ Object

Yields:



12
13
14
# File 'lib/ask/ruby/harness.rb', line 12

def configure
  yield configuration
end

.connect_database!Object

Establish a standalone ActiveRecord connection when the host hasn't (Rails apps are already connected and are left untouched).

Connection sources, in order: ASK_DATABASE_URL, config/database.yml.



75
76
77
78
79
80
81
82
# File 'lib/ask/ruby/harness.rb', line 75

def connect_database!
  return if database_configured?

  config = ENV["ASK_DATABASE_URL"] || database_config_from_yaml
  ActiveRecord::Base.establish_connection(config) if config
rescue StandardError => e
  warn "[ask-ruby-harness] database connect failed: #{e.message}"
end

.database_config_for(name) ⇒ Object

Config for a NAMED database. Resolution order:

1. the host app's own configurations registry (Rails multi-DB —
 resolves credentials/ENV for us),
2. config/database.yml, the environment section's key.


101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ask/ruby/harness.rb', line 101

def database_config_for(name)
  name = name.to_s
  if ActiveRecord::Base.respond_to?(:configurations)
    db = ActiveRecord::Base.configurations.configs_for(env_name: env, name: name)
    return sanitize_database_config(db.configuration_hash.transform_keys(&:to_s)) if db
  end

  section = database_yaml_section
  config = section[name] if section.is_a?(Hash) && section[name].is_a?(Hash)
  sanitize_database_config(config)
end

.database_configured?Boolean

Whether a connection spec is defined. Uses the pool presence, not connected? — ActiveRecord's connected? stays false until a connection is actually checked out, while pool.with_connection establishes lazily on first use.

Returns:

  • (Boolean)


88
89
90
91
92
93
94
95
# File 'lib/ask/ruby/harness.rb', line 88

def database_configured?
  defined?(ActiveRecord::Base) &&
    ActiveRecord::Base.connection_handler.retrieve_connection_pool(
      ActiveRecord::Base.connection_specification_name
    )
rescue StandardError
  false
end

.discover_tools!Object



57
58
59
# File 'lib/ask/ruby/harness.rb', line 57

def discover_tools!
  self.configuration.tools = Ask::Tools::Shell::TOOLS.map(&:new) + harness_tools + discovered_user_tools
end

.envObject

Environment detection without Rails: RAILS_ENV, RACK_ENV, APP_ENV.



32
33
34
# File 'lib/ask/ruby/harness.rb', line 32

def env
  ENV["RAILS_ENV"] || ENV["RACK_ENV"] || ENV["APP_ENV"] || "development"
end