actionagent 1.7.2 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/builds/action_agent.css +1 -1
  3. data/app/assets/builds/action_agent.js +59 -54
  4. data/app/controllers/action_agent/api/agents_controller.rb +19 -3
  5. data/app/controllers/action_agent/api/code_sessions_controller.rb +168 -0
  6. data/app/controllers/action_agent/api/evaluations_controller.rb +74 -131
  7. data/app/controllers/action_agent/api/github_connections_controller.rb +147 -0
  8. data/app/controllers/action_agent/api/mcp_controller.rb +38 -5
  9. data/app/controllers/action_agent/api/mcp_servers_controller.rb +10 -1
  10. data/app/controllers/action_agent/api/provider_keys_controller.rb +54 -3
  11. data/app/controllers/action_agent/api/provider_models_controller.rb +10 -6
  12. data/app/controllers/action_agent/api/sandboxes_controller.rb +105 -6
  13. data/app/controllers/concerns/action_agent/api/evaluation_run_starting.rb +93 -0
  14. data/app/controllers/concerns/action_agent/api/mcp_dashboard_tools.rb +509 -0
  15. data/app/controllers/concerns/action_agent/api/run_sandbox.rb +65 -0
  16. data/app/jobs/action_agent/code_session_job.rb +171 -0
  17. data/app/jobs/action_agent/sandbox_cleanup_job.rb +80 -11
  18. data/app/jobs/action_agent/sandbox_provision_job.rb +122 -14
  19. data/app/jobs/action_agent/sandbox_run_job.rb +10 -3
  20. data/app/models/action_agent/agent.rb +49 -6
  21. data/app/models/action_agent/agent_run.rb +20 -1
  22. data/app/models/action_agent/code_session.rb +145 -0
  23. data/app/models/action_agent/evaluation.rb +64 -0
  24. data/app/models/action_agent/evaluation_run.rb +166 -54
  25. data/app/models/action_agent/evaluation_scenario_result.rb +15 -3
  26. data/app/models/action_agent/github_connection.rb +75 -0
  27. data/app/models/action_agent/model_pricing.rb +214 -34
  28. data/app/models/action_agent/provider_key.rb +148 -10
  29. data/app/models/action_agent/sandbox_session.rb +194 -17
  30. data/app/serializers/action_agent/evaluation_serializer.rb +149 -0
  31. data/app/serializers/action_agent/telemetry_trace_serializer.rb +10 -2
  32. data/app/services/action_agent/agent_execution_service.rb +4 -2
  33. data/app/services/action_agent/agent_scorecard.rb +50 -21
  34. data/app/services/action_agent/agent_tool_roster.rb +20 -9
  35. data/app/services/action_agent/claude_code_auth.rb +86 -0
  36. data/app/services/action_agent/codex_session_events.rb +37 -0
  37. data/app/services/action_agent/dashboard_assistant_service.rb +47 -5
  38. data/app/services/action_agent/evaluation_report_import.rb +84 -5
  39. data/app/services/action_agent/evaluation_run_cost.rb +609 -0
  40. data/app/services/action_agent/evaluation_runner_service.rb +25 -5
  41. data/app/services/action_agent/evaluation_standing.rb +145 -0
  42. data/app/services/action_agent/evaluation_tool_resolver.rb +18 -0
  43. data/app/services/action_agent/github_client.rb +111 -0
  44. data/app/services/action_agent/local_sandbox_backend.rb +1715 -0
  45. data/app/services/action_agent/local_sandbox_databases.rb +257 -0
  46. data/app/services/action_agent/mcp_client.rb +5 -1
  47. data/app/services/action_agent/mcp_tool_dispatcher.rb +137 -17
  48. data/app/services/action_agent/mock_sandbox_backend.rb +39 -0
  49. data/app/services/action_agent/ollama_host_probe.rb +75 -0
  50. data/app/services/action_agent/payload_bounds.rb +36 -0
  51. data/app/services/action_agent/sandbox_manifest.rb +67 -0
  52. data/app/services/action_agent/sandbox_orchestrator.rb +82 -14
  53. data/app/services/action_agent/scenario_evaluation_runner.rb +52 -5
  54. data/app/services/action_agent/secret_scrubber.rb +37 -0
  55. data/app/services/action_agent/tool_discovery.rb +19 -5
  56. data/config/routes.rb +23 -4
  57. data/lib/action_agent/engine.rb +1 -0
  58. data/lib/action_agent/version.rb +1 -1
  59. data/lib/action_agent.rb +153 -3
  60. data/lib/generators/action_agent/install_generator.rb +35 -5
  61. data/lib/generators/action_agent/templates/action_agent.rb.erb +47 -0
  62. data/lib/generators/action_agent/templates/add_code_session_runner.rb.erb +9 -0
  63. data/lib/generators/action_agent/templates/add_provider_key_api_key.rb.erb +25 -0
  64. data/lib/generators/action_agent/templates/create_active_agent_code_sessions.rb.erb +59 -0
  65. data/lib/generators/action_agent/templates/create_active_agent_dashboard_tables.rb.erb +2 -0
  66. data/lib/generators/action_agent/templates/create_active_agent_github_connections.rb.erb +61 -0
  67. data/lib/tasks/claude_code.rake +16 -0
  68. data/lib/tasks/sandbox.rake +26 -0
  69. metadata +28 -2
data/lib/action_agent.rb CHANGED
@@ -104,6 +104,9 @@ require "action_agent/compatibility"
104
104
  # end
105
105
  #
106
106
  module ActionAgent
107
+ # What ActionAgent.claude_code_auth may be set to.
108
+ CLAUDE_CODE_AUTH_MODES = %i[api_key local_login].freeze
109
+
107
110
  class << self
108
111
  # Deprecation warnings for this gem, routed through Rails' machinery so a
109
112
  # host app can silence or escalate them like any other.
@@ -194,9 +197,10 @@ module ActionAgent
194
197
  # @return [String, nil]
195
198
  attr_accessor :layout
196
199
 
197
- # Which sandbox backend to provision with: :mock (the only one the
198
- # engine ships — an in-memory fake that runs nothing) or the name of a
199
- # backend the host registered in sandbox_backends. An unregistered name
200
+ # Which sandbox backend to provision with: :mock (an in-memory fake that
201
+ # runs nothing), :local (checkouts cloned and booted as child processes
202
+ # of the dashboard itself — see local_sandboxes_enabled), or the name of
203
+ # a backend the host registered in sandbox_backends. An unregistered name
200
204
  # falls back to :mock with a logged warning.
201
205
  # @return [Symbol]
202
206
  attr_accessor :sandbox_service
@@ -304,6 +308,78 @@ module ActionAgent
304
308
  # @return [Hash{String => String}]
305
309
  attr_accessor :sandbox_backends
306
310
 
311
+ # Whether the :local sandbox backend may run. It clones the owner's
312
+ # repository onto the dashboard's own machine and runs its setup and
313
+ # server as child processes — the owner's code, with the dashboard's
314
+ # privileges — so it is for a developer's machine or a single-user
315
+ # install. Unset, it follows the environment: on in development and
316
+ # test, off everywhere else.
317
+ # @return [Boolean, nil]
318
+ attr_writer :local_sandboxes_enabled
319
+
320
+ # Where the :local backend keeps each sandbox's checkout, logs and
321
+ # process state (one directory per session). Unset, tmp/action_agent/sandboxes
322
+ # under the host app.
323
+ # @return [String, Pathname, nil]
324
+ attr_writer :local_sandbox_root
325
+
326
+ # How long the :local backend waits for a checkout's setup and server to
327
+ # come up before giving up, in seconds.
328
+ # @return [Integer]
329
+ attr_accessor :local_sandbox_boot_timeout
330
+
331
+ # The Claude Code executable a sandbox backend runs headless sessions
332
+ # with. The :local backend runs it on the dashboard's machine.
333
+ # @return [String]
334
+ attr_accessor :claude_code_command
335
+
336
+ # The permission mode Claude Code sessions run in. "acceptEdits" lets a
337
+ # session edit files in the checkout and run filesystem commands; with
338
+ # nobody to answer prompts, anything else that would ask is denied.
339
+ # @return [String]
340
+ attr_accessor :claude_code_permission_mode
341
+
342
+ # A cap on agentic turns per Claude Code session (nil for Claude Code's
343
+ # own default).
344
+ # @return [Integer, nil]
345
+ attr_accessor :claude_code_max_turns
346
+
347
+ # How long a Claude Code session may run before it is stopped, in
348
+ # seconds.
349
+ # @return [Integer]
350
+ attr_accessor :claude_code_timeout
351
+
352
+ # Codex CLI sessions use the owner's OpenAI API key and workspace-write
353
+ # sandboxing. They share checkout lifecycle and cancellation with Claude.
354
+ attr_accessor :codex_command, :codex_timeout
355
+
356
+ # How Claude Code sessions authenticate.
357
+ #
358
+ # :api_key (the default) runs them on the Anthropic API key the owner
359
+ # connected in Settings -> Integrations, handed to the session as
360
+ # ANTHROPIC_API_KEY. It is the only credential the dashboard stores:
361
+ # Anthropic does not let third-party products collect, store or route
362
+ # requests through Claude.ai subscription credentials
363
+ # (https://code.claude.com/docs/en/legal-and-compliance.md).
364
+ #
365
+ # :local_login runs `claude` on whatever login this machine's user set up
366
+ # with `claude /login` (or `claude auth login`), which Claude Code keeps
367
+ # under ~/.claude or in the keychain. The dashboard never reads, copies
368
+ # or stores it; it only asks `claude auth status` whether there is one.
369
+ # That login is the dashboard user's own, so this works with the :local
370
+ # sandbox backend only, and other backends refuse Claude Code sessions.
371
+ # @return [Symbol] :api_key or :local_login
372
+ attr_reader :claude_code_auth
373
+
374
+ def claude_code_auth=(value)
375
+ mode = value.to_s.to_sym
376
+ unless CLAUDE_CODE_AUTH_MODES.include?(mode)
377
+ raise ArgumentError, "ActionAgent.claude_code_auth must be :api_key or :local_login, not #{value.inspect}"
378
+ end
379
+
380
+ @claude_code_auth = mode
381
+ end
382
+
307
383
  # Whether the dashboard may execute agents against real providers.
308
384
  # Disable to run the dashboard as a read-only observability surface.
309
385
  # @return [Boolean]
@@ -415,6 +491,20 @@ module ActionAgent
415
491
  # @return [Boolean]
416
492
  attr_accessor :encrypt_credentials
417
493
 
494
+ # The GitHub OAuth App the dashboard's "Connect GitHub" flow authorizes
495
+ # against (Settings -> Integrations). Unset, each falls back to
496
+ # GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET, and the dashboard offers no
497
+ # connection when neither is present. Register the app's callback URL as
498
+ # <mount>/api/github_connection/callback.
499
+ # @return [String, nil]
500
+ attr_writer :github_client_id, :github_client_secret
501
+
502
+ # OAuth scopes requested on connect. +repo+ reaches private repositories
503
+ # so a sandbox can clone them; narrow it to "public_repo read:user" for
504
+ # public checkouts only.
505
+ # @return [String]
506
+ attr_accessor :github_oauth_scopes
507
+
418
508
  # MCP servers the host app itself serves or connects, appended to the
419
509
  # built-in catalog (MCPCatalog) so the MCP Services view lists them and
420
510
  # telemetry traffic attributes to them. Each entry is a hash shaped like
@@ -452,6 +542,17 @@ module ActionAgent
452
542
  # @return [Boolean]
453
543
  attr_accessor :mcp_schema_tools
454
544
 
545
+ # Whether the MCP facade (POST <mount>/mcp) offers the dashboard's own
546
+ # evaluation and telemetry tools — evaluations_list, evaluations_get,
547
+ # evaluations_run, evaluation_runs_get, evaluation_runs_compare,
548
+ # traces_search, traces_get — so a client's coding harness can run an
549
+ # agent's evaluations and read its traces while it edits the agent. Each
550
+ # reads under the key's owner, as the dashboard's JSON API reads under the
551
+ # signed-in owner. On by default; set it to false to leave the facade
552
+ # serving agents and schema tools only.
553
+ # @return [Boolean]
554
+ attr_accessor :mcp_dashboard_tools
555
+
455
556
  # Directory scanned for SchemaTools subclasses when {#schema_tools} is
456
557
  # unset. Relative to the host's root. Set to nil to disable discovery and
457
558
  # require an explicit declaration. Classes built at runtime with
@@ -471,6 +572,20 @@ module ActionAgent
471
572
  # Returns whether multi-tenant mode is enabled.
472
573
  #
473
574
  # @return [Boolean]
575
+ def github_client_id
576
+ @github_client_id.presence || ENV["GITHUB_CLIENT_ID"].presence
577
+ end
578
+
579
+ def github_client_secret
580
+ @github_client_secret.presence || ENV["GITHUB_CLIENT_SECRET"].presence
581
+ end
582
+
583
+ # Whether the GitHub OAuth flow can run on this install.
584
+ # @return [Boolean]
585
+ def github_oauth_configured?
586
+ github_client_id.present? && github_client_secret.present?
587
+ end
588
+
474
589
  def multi_tenant?
475
590
  @multi_tenant == true
476
591
  end
@@ -482,6 +597,14 @@ module ActionAgent
482
597
  @mcp_schema_tools != false
483
598
  end
484
599
 
600
+ # Whether the MCP facade serves the dashboard's evaluation and telemetry
601
+ # tools.
602
+ #
603
+ # @return [Boolean]
604
+ def mcp_dashboard_tools?
605
+ @mcp_dashboard_tools != false
606
+ end
607
+
485
608
  # Returns whether agent execution is permitted.
486
609
  #
487
610
  # @return [Boolean]
@@ -499,6 +622,19 @@ module ActionAgent
499
622
  Rails.env.local?
500
623
  end
501
624
 
625
+ # Whether the :local sandbox backend may run on this install.
626
+ # @return [Boolean]
627
+ def local_sandboxes_enabled?
628
+ return @local_sandboxes_enabled == true unless @local_sandboxes_enabled.nil?
629
+
630
+ Rails.env.local?
631
+ end
632
+
633
+ # @return [Pathname]
634
+ def local_sandbox_root
635
+ Pathname.new(@local_sandbox_root.presence || Rails.root.join("tmp", "action_agent", "sandboxes"))
636
+ end
637
+
502
638
  # Tells the host app that +owner+ performed +kind+. Never raises: a
503
639
  # bookkeeping failure must not fail the action that was already taken.
504
640
  def record_usage(owner, kind)
@@ -633,6 +769,16 @@ module ActionAgent
633
769
  @quota_checker = nil
634
770
  @provider_credentials_resolver = nil
635
771
  @sandbox_backends = {}
772
+ @local_sandboxes_enabled = nil
773
+ @local_sandbox_root = nil
774
+ @local_sandbox_boot_timeout = 600
775
+ @claude_code_command = "claude"
776
+ @claude_code_permission_mode = "acceptEdits"
777
+ @claude_code_max_turns = nil
778
+ @claude_code_timeout = 1800
779
+ @codex_command = "codex"
780
+ @codex_timeout = 1800
781
+ @claude_code_auth = :api_key
636
782
  @execution_enabled = true
637
783
  @run_host_agent_classes = false
638
784
  @assistant_enabled = nil
@@ -641,6 +787,9 @@ module ActionAgent
641
787
  @table_name_prefix = "active_agent_"
642
788
  @agent_polymorphic_name = nil
643
789
  @encrypt_credentials = true
790
+ @github_client_id = nil
791
+ @github_client_secret = nil
792
+ @github_oauth_scopes = "repo read:user"
644
793
  @trace_retention = nil
645
794
  @trace_owner_resolver = nil
646
795
  @usage_recorder = nil
@@ -653,6 +802,7 @@ module ActionAgent
653
802
  @schema_tools = nil
654
803
  @schema_tools_path = "app/agent_tools"
655
804
  @mcp_schema_tools = nil
805
+ @mcp_dashboard_tools = nil
656
806
  end
657
807
 
658
808
  # Host-declared schema tool classes, resolved from names and filtered to
@@ -102,12 +102,42 @@ module ActionAgent
102
102
  # shipped. Emitted after them, so on a fresh install it runs once the
103
103
  # table exists, finds the columns the create-table migration made, and
104
104
  # changes nothing.
105
- return if existing_migration?("add_evaluation_report_identity")
105
+ unless existing_migration?("add_evaluation_report_identity")
106
+ migration_template(
107
+ "add_evaluation_report_identity.rb.erb",
108
+ "db/migrate/add_evaluation_report_identity.rb"
109
+ )
110
+ end
106
111
 
107
- migration_template(
108
- "add_evaluation_report_identity.rb.erb",
109
- "db/migrate/add_evaluation_report_identity.rb"
110
- )
112
+ # A remote Ollama's optional API key arrived after the dashboard tables
113
+ # shipped. Guarded, so on a fresh install it finds the column the
114
+ # create-table migration made and changes nothing.
115
+ unless existing_migration?("add_provider_key_api_key")
116
+ migration_template(
117
+ "add_provider_key_api_key.rb.erb",
118
+ "db/migrate/add_provider_key_api_key.rb"
119
+ )
120
+ end
121
+
122
+ # GitHub connections and checkout sandboxes, likewise later than the
123
+ # dashboard tables.
124
+ unless existing_migration?("create_active_agent_github_connections")
125
+ migration_template(
126
+ "create_active_agent_github_connections.rb.erb",
127
+ "db/migrate/create_active_agent_github_connections.rb"
128
+ )
129
+ end
130
+
131
+ # Claude Code sessions inside those checkouts.
132
+ unless existing_migration?("create_active_agent_code_sessions")
133
+ migration_template(
134
+ "create_active_agent_code_sessions.rb.erb",
135
+ "db/migrate/create_active_agent_code_sessions.rb"
136
+ )
137
+ end
138
+ unless existing_migration?("add_code_session_runner")
139
+ migration_template("add_code_session_runner.rb.erb", "db/migrate/add_code_session_runner.rb")
140
+ end
111
141
  end
112
142
 
113
143
  def add_route
@@ -106,6 +106,53 @@ ActionAgent.configure do |config|
106
106
  #
107
107
  # config.assistant_enabled = true
108
108
 
109
+ # ==========================================================================
110
+ # Sandboxes
111
+ # ==========================================================================
112
+ #
113
+ # Which backend boots sandboxes: :mock (the default, in memory, runs
114
+ # nothing), :local, or one you register in sandbox_backends to run them in
115
+ # containers. The SANDBOX_BACKEND environment variable overrides it.
116
+ #
117
+ # config.sandbox_service = :local
118
+ # config.sandbox_backends = { "cloud_run" => "CloudRunService" }
119
+ #
120
+ # :local clones a repository connected in Settings -> Integrations onto
121
+ # this machine and boots it as child processes of the dashboard, as the
122
+ # checkout's .activeagents/sandbox.yml says. That runs the repository's
123
+ # code, and Claude Code sessions in it, with the dashboard's privileges, so
124
+ # it is off outside development and test until you enable it here.
125
+ #
126
+ # config.local_sandboxes_enabled = true
127
+ # config.local_sandbox_root = Rails.root.join("tmp/action_agent/sandboxes")
128
+ # config.local_sandbox_boot_timeout = 600 # seconds, for checkout, setup and boot
129
+ #
130
+ # Claude Code sessions in a ready checkout. Nobody is there to answer a
131
+ # permission prompt: "acceptEdits" lets a session edit files in the
132
+ # checkout and run filesystem commands, and anything else that would ask
133
+ # is denied.
134
+ #
135
+ # config.claude_code_command = "claude"
136
+ # config.claude_code_permission_mode = "acceptEdits"
137
+ # config.claude_code_max_turns = nil # Claude Code's own default
138
+ # config.claude_code_timeout = 1800 # seconds
139
+ # Codex uses a separate API-key connection in Settings -> Integrations.
140
+ # config.codex_command = "codex"
141
+ # config.codex_timeout = 1800 # seconds
142
+ #
143
+ # How sessions authenticate. :api_key (the default) uses the Anthropic API
144
+ # key connected in Settings -> Integrations (from the Claude Console,
145
+ # https://platform.claude.com). :local_login, with the :local backend only,
146
+ # uses this machine's own Claude Code login (`claude /login`); the dashboard
147
+ # never reads or stores it. Claude subscription tokens (`claude
148
+ # setup-token`) are not accepted: Anthropic does not allow third-party apps
149
+ # to hold Claude.ai credentials.
150
+ #
151
+ # config.claude_code_auth = :local_login
152
+ #
153
+ # Expired sandboxes are stopped by `bin/rails action_agent:sandbox:reap`.
154
+ # Schedule it every few minutes.
155
+
109
156
  # ==========================================================================
110
157
  # UI
111
158
  # ==========================================================================
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddCodeSessionRunner < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ table = "#{ActionAgent.table_name_prefix}code_sessions"
6
+ add_column table, :runner, :string, null: false, default: "claude_code" unless column_exists?(table, :runner)
7
+ add_column table, :runner_session_id, :string unless column_exists?(table, :runner_session_id)
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Adds the optional api_key column to provider keys: a host-based provider
4
+ # (Ollama) can be a remote server behind an authenticating proxy, or Ollama
5
+ # Cloud, and then needs a Bearer key alongside its host URL. Emitted for an
6
+ # install whose dashboard tables predate it; the create-table migration
7
+ # carries the column for a fresh install. Guarded, so it is safe to re-run.
8
+ class AddProviderKeyApiKey < ActiveRecord::Migration<%= migration_version %>
9
+ def up
10
+ return unless table_exists?(table)
11
+ return if column_exists?(table, :api_key)
12
+
13
+ add_column table, :api_key, :string
14
+ end
15
+
16
+ def down
17
+ remove_column table, :api_key if table_exists?(table) && column_exists?(table, :api_key)
18
+ end
19
+
20
+ private
21
+
22
+ def table
23
+ "#{ActionAgent.table_name_prefix}provider_keys"
24
+ end
25
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Claude Code sessions run inside an app_runtime sandbox's checkout: the
4
+ # prompt, the scrubbed stream-json transcript, the reported outcome and the
5
+ # resulting diff. Emitted alongside the dashboard tables on a fresh install,
6
+ # and on its own for an install that predates it.
7
+ #
8
+ # Table names follow ActionAgent.table_name_prefix, and JSON columns are
9
+ # jsonb on PostgreSQL and json elsewhere, the same way as
10
+ # create_active_agent_dashboard_tables.
11
+ class CreateActiveAgentCodeSessions < ActiveRecord::Migration<%= migration_version %>
12
+ def change
13
+ prefix = ActionAgent.table_name_prefix
14
+
15
+ create_table "#{prefix}code_sessions" do |t|
16
+ t.bigint :sandbox_session_id, null: false
17
+ t.text :prompt, null: false
18
+ t.integer :status, default: 0, null: false
19
+ t.column :events, json_type, **json_default([])
20
+ t.integer :dropped_events_count, default: 0, null: false
21
+ t.text :result
22
+ t.text :diff
23
+ t.text :error_message
24
+ t.string :model
25
+ t.string :claude_session_id
26
+ t.integer :num_turns
27
+ t.integer :duration_ms
28
+ t.decimal :total_cost_usd, precision: 12, scale: 6
29
+ t.integer :input_tokens
30
+ t.integer :output_tokens
31
+ t.datetime :started_at
32
+ t.datetime :finished_at
33
+ t.bigint :user_id
34
+ t.bigint :account_id
35
+ t.timestamps
36
+ t.index :sandbox_session_id
37
+ t.index :user_id
38
+ t.index :account_id
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def json_type
45
+ @json_type ||= postgres? ? :jsonb : :json
46
+ end
47
+
48
+ # MySQL rejects a default on a JSON column outright, so the column is
49
+ # created without one there.
50
+ def json_default(value, null: nil)
51
+ return {} unless postgres?
52
+
53
+ null.nil? ? { default: value } : { default: value, null: null }
54
+ end
55
+
56
+ def postgres?
57
+ connection.adapter_name.to_s.downcase.include?("postgres")
58
+ end
59
+ end
@@ -326,6 +326,8 @@ class CreateActiveAgentDashboardTables < ActiveRecord::Migration<%= migration_ve
326
326
  create_table "#{prefix}provider_keys" do |t|
327
327
  t.string :provider, null: false
328
328
  t.string :credential, null: false
329
+ # Optional Bearer key for a host-based provider (remote Ollama).
330
+ t.string :api_key
329
331
  t.bigint :user_id
330
332
  t.bigint :account_id
331
333
  t.timestamps
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # GitHub connections: an owner's OAuth grant (Settings -> Integrations), the
4
+ # repositories they made available to the workspace, and the checkout a
5
+ # sandbox session boots its app runtime from. Emitted alongside the dashboard
6
+ # tables on a fresh install, and on its own for an install that predates it.
7
+ #
8
+ # Table names follow ActionAgent.table_name_prefix, and JSON columns are
9
+ # jsonb on PostgreSQL and json elsewhere, the same way as
10
+ # create_active_agent_dashboard_tables.
11
+ class CreateActiveAgentGithubConnections < ActiveRecord::Migration<%= migration_version %>
12
+ def change
13
+ prefix = ActionAgent.table_name_prefix
14
+
15
+ create_table "#{prefix}github_connections" do |t|
16
+ # The OAuth access token, encrypted at rest (text: ciphertext is longer
17
+ # than the token).
18
+ t.text :access_token, null: false
19
+ t.bigint :github_user_id, null: false
20
+ t.string :login, null: false
21
+ t.string :avatar_url
22
+ t.string :scopes
23
+ # The repositories the owner made available, as GitHub described them
24
+ # when they were chosen: full_name, id, private, default_branch.
25
+ t.column :repositories, json_type, **json_default([])
26
+ t.bigint :user_id
27
+ t.bigint :account_id
28
+ t.timestamps
29
+ t.index :account_id
30
+ t.index :user_id
31
+ end
32
+
33
+ # A sandbox booted from a checkout of one of those repositories, and the
34
+ # app runtime's MCP endpoint (and the bearer token it expects, encrypted)
35
+ # once the backend reports them.
36
+ change_table "#{prefix}sandbox_sessions" do |t|
37
+ t.string :repository
38
+ t.string :repository_ref
39
+ t.string :runtime_mcp_url
40
+ t.text :runtime_mcp_token
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def json_type
47
+ @json_type ||= postgres? ? :jsonb : :json
48
+ end
49
+
50
+ # MySQL rejects a default on a JSON column outright, so the column is
51
+ # created without one there.
52
+ def json_default(value, null: nil)
53
+ return {} unless postgres?
54
+
55
+ null.nil? ? { default: value } : { default: value, null: null }
56
+ end
57
+
58
+ def postgres?
59
+ connection.adapter_name.to_s.downcase.include?("postgres")
60
+ end
61
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :action_agent do
4
+ namespace :claude_code do
5
+ # Earlier versions accepted a `claude setup-token` token (a Claude
6
+ # subscription credential) for the Claude Code connection. Anthropic does
7
+ # not let third-party products store those, and they are no longer used;
8
+ # this removes the ones still stored. Run it once after upgrading.
9
+ desc "Delete stored Claude Code connections holding a Claude subscription token (sk-ant-oat…), " \
10
+ "which are no longer used; their owners connect an Anthropic API key instead"
11
+ task purge_subscription_tokens: :environment do
12
+ count = ActionAgent::ProviderKey.purge_subscription_tokens!
13
+ puts "Deleted #{count} stored Claude subscription token(s)"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :action_agent do
4
+ namespace :sandbox do
5
+ desc "Write this app's checkout sandbox runtime manifest ({mcp_path, mcp_token}) to " \
6
+ "$ACTION_AGENT_SANDBOX_MANIFEST, or print it"
7
+ task manifest: :environment do
8
+ manifest = JSON.generate(ActionAgent::SandboxManifest.generate)
9
+
10
+ if (path = ENV[ActionAgent::SandboxManifest::PATH_ENV].presence)
11
+ File.write(path, manifest)
12
+ else
13
+ puts manifest
14
+ end
15
+ rescue ActionAgent::SandboxManifest::Error => e
16
+ abort "action_agent:sandbox:manifest: #{e.message}"
17
+ end
18
+
19
+ desc "Expire sandbox sessions past their expiry and release what their backend holds " \
20
+ "(processes, containers). Schedule it, e.g. every few minutes."
21
+ task reap: :environment do
22
+ count = ActionAgent::SandboxCleanupJob.cleanup_expired!
23
+ puts "Expired #{count.to_i} sandbox session(s)"
24
+ end
25
+ end
26
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actionagent
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.2
4
+ version: 1.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Bowen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-30 00:00:00.000000000 Z
11
+ date: 2026-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeagent
@@ -129,9 +129,11 @@ files:
129
129
  - app/controllers/action_agent/api/analytics_controller.rb
130
130
  - app/controllers/action_agent/api/api_keys_controller.rb
131
131
  - app/controllers/action_agent/api/base_controller.rb
132
+ - app/controllers/action_agent/api/code_sessions_controller.rb
132
133
  - app/controllers/action_agent/api/dashboard_assistant_controller.rb
133
134
  - app/controllers/action_agent/api/evaluation_reports_controller.rb
134
135
  - app/controllers/action_agent/api/evaluations_controller.rb
136
+ - app/controllers/action_agent/api/github_connections_controller.rb
135
137
  - app/controllers/action_agent/api/instance_tiers_controller.rb
136
138
  - app/controllers/action_agent/api/interaction_messages_controller.rb
137
139
  - app/controllers/action_agent/api/interactions_controller.rb
@@ -151,9 +153,13 @@ files:
151
153
  - app/controllers/action_agent/dashboard_controller.rb
152
154
  - app/controllers/action_agent/traces_controller.rb
153
155
  - app/controllers/concerns/action_agent/api/agent_serialization.rb
156
+ - app/controllers/concerns/action_agent/api/evaluation_run_starting.rb
154
157
  - app/controllers/concerns/action_agent/api/ingest_authentication.rb
158
+ - app/controllers/concerns/action_agent/api/mcp_dashboard_tools.rb
159
+ - app/controllers/concerns/action_agent/api/run_sandbox.rb
155
160
  - app/jobs/action_agent/agent_execution_job.rb
156
161
  - app/jobs/action_agent/application_job.rb
162
+ - app/jobs/action_agent/code_session_job.rb
157
163
  - app/jobs/action_agent/evaluation_run_job.rb
158
164
  - app/jobs/action_agent/process_telemetry_traces_job.rb
159
165
  - app/jobs/action_agent/sandbox_cleanup_job.rb
@@ -171,10 +177,12 @@ files:
171
177
  - app/models/action_agent/agent_version.rb
172
178
  - app/models/action_agent/api_key.rb
173
179
  - app/models/action_agent/application_record.rb
180
+ - app/models/action_agent/code_session.rb
174
181
  - app/models/action_agent/evaluation.rb
175
182
  - app/models/action_agent/evaluation_run.rb
176
183
  - app/models/action_agent/evaluation_scenario.rb
177
184
  - app/models/action_agent/evaluation_scenario_result.rb
185
+ - app/models/action_agent/github_connection.rb
178
186
  - app/models/action_agent/model_pricing.rb
179
187
  - app/models/action_agent/provider_key.rb
180
188
  - app/models/action_agent/recording_action.rb
@@ -190,6 +198,7 @@ files:
190
198
  - app/queries/action_agent/agent_executions.rb
191
199
  - app/queries/action_agent/metrics_report.rb
192
200
  - app/serializers/action_agent/agent_message_serializer.rb
201
+ - app/serializers/action_agent/evaluation_serializer.rb
193
202
  - app/serializers/action_agent/interaction_preview.rb
194
203
  - app/serializers/action_agent/telemetry_trace_serializer.rb
195
204
  - app/serializers/action_agent/trace_interaction_serializer.rb
@@ -200,19 +209,30 @@ files:
200
209
  - app/services/action_agent/agent_sync.rb
201
210
  - app/services/action_agent/agent_tool_roster.rb
202
211
  - app/services/action_agent/agent_toolbox.rb
212
+ - app/services/action_agent/claude_code_auth.rb
213
+ - app/services/action_agent/codex_session_events.rb
203
214
  - app/services/action_agent/dashboard_assistant_service.rb
204
215
  - app/services/action_agent/evaluation_evidence.rb
205
216
  - app/services/action_agent/evaluation_report_import.rb
217
+ - app/services/action_agent/evaluation_run_cost.rb
206
218
  - app/services/action_agent/evaluation_runner_service.rb
219
+ - app/services/action_agent/evaluation_standing.rb
207
220
  - app/services/action_agent/evaluation_tool_resolver.rb
221
+ - app/services/action_agent/github_client.rb
222
+ - app/services/action_agent/local_sandbox_backend.rb
223
+ - app/services/action_agent/local_sandbox_databases.rb
208
224
  - app/services/action_agent/mcp_catalog.rb
209
225
  - app/services/action_agent/mcp_client.rb
210
226
  - app/services/action_agent/mcp_recording_middleware.rb
211
227
  - app/services/action_agent/mcp_tool_dispatcher.rb
212
228
  - app/services/action_agent/mock_sandbox_backend.rb
229
+ - app/services/action_agent/ollama_host_probe.rb
230
+ - app/services/action_agent/payload_bounds.rb
213
231
  - app/services/action_agent/playwright_mcp_client.rb
232
+ - app/services/action_agent/sandbox_manifest.rb
214
233
  - app/services/action_agent/sandbox_orchestrator.rb
215
234
  - app/services/action_agent/scenario_evaluation_runner.rb
235
+ - app/services/action_agent/secret_scrubber.rb
216
236
  - app/services/action_agent/session_recording_service.rb
217
237
  - app/services/action_agent/tool_discovery.rb
218
238
  - app/views/action_agent/dashboard/index.html.erb
@@ -233,12 +253,18 @@ files:
233
253
  - lib/generators/action_agent/templates/action_agent.rb.erb
234
254
  - lib/generators/action_agent/templates/add_agent_id_to_active_agent_telemetry_traces.rb.erb
235
255
  - lib/generators/action_agent/templates/add_agent_releases.rb.erb
256
+ - lib/generators/action_agent/templates/add_code_session_runner.rb.erb
236
257
  - lib/generators/action_agent/templates/add_evaluation_report_identity.rb.erb
258
+ - lib/generators/action_agent/templates/add_provider_key_api_key.rb.erb
259
+ - lib/generators/action_agent/templates/create_active_agent_code_sessions.rb.erb
237
260
  - lib/generators/action_agent/templates/create_active_agent_dashboard_tables.rb.erb
238
261
  - lib/generators/action_agent/templates/create_active_agent_evaluation_scenarios.rb.erb
262
+ - lib/generators/action_agent/templates/create_active_agent_github_connections.rb.erb
239
263
  - lib/generators/action_agent/templates/create_active_agent_telemetry_traces.rb.erb
240
264
  - lib/generators/action_agent/templates/ensure_agent_release_columns.rb.erb
241
265
  - lib/tasks/action_agent.rake
266
+ - lib/tasks/claude_code.rake
267
+ - lib/tasks/sandbox.rake
242
268
  homepage: https://activeagents.ai
243
269
  licenses:
244
270
  - MIT