actionagent 1.8.0 → 1.9.0
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.
- checksums.yaml +4 -4
- data/app/assets/builds/action_agent.css +1 -1
- data/app/assets/builds/action_agent.js +76 -73
- data/app/assets/builds/action_agent_recorder.js +78 -0
- data/app/assets/builds/action_agent_replay.js +226 -0
- data/app/controllers/action_agent/api/agent_runs_controller.rb +3 -1
- data/app/controllers/action_agent/api/agents_controller.rb +1 -0
- data/app/controllers/action_agent/api/api_keys_controller.rb +12 -2
- data/app/controllers/action_agent/api/base_controller.rb +63 -2
- data/app/controllers/action_agent/api/claude_logins_controller.rb +93 -0
- data/app/controllers/action_agent/api/code_sessions_controller.rb +71 -12
- data/app/controllers/action_agent/api/dashboard_assistant_controller.rb +2 -2
- data/app/controllers/action_agent/api/draft_pull_requests_controller.rb +248 -0
- data/app/controllers/action_agent/api/evaluation_fixes_controller.rb +27 -0
- data/app/controllers/action_agent/api/evaluations_controller.rb +58 -7
- data/app/controllers/action_agent/api/explorations_controller.rb +213 -0
- data/app/controllers/action_agent/api/github_app_manifests_controller.rb +125 -0
- data/app/controllers/action_agent/api/github_connections_controller.rb +40 -2
- data/app/controllers/action_agent/api/github_installations_controller.rb +280 -0
- data/app/controllers/action_agent/api/input_requests_controller.rb +77 -0
- data/app/controllers/action_agent/api/mcp_controller.rb +46 -12
- data/app/controllers/action_agent/api/members_controller.rb +36 -0
- data/app/controllers/action_agent/api/project_explorations_controller.rb +80 -0
- data/app/controllers/action_agent/api/project_install_pull_requests_controller.rb +305 -0
- data/app/controllers/action_agent/api/project_secrets_controller.rb +96 -0
- data/app/controllers/action_agent/api/project_setup_controller.rb +151 -0
- data/app/controllers/action_agent/api/project_sign_ins_controller.rb +112 -0
- data/app/controllers/action_agent/api/projects_controller.rb +512 -0
- data/app/controllers/action_agent/api/provider_keys_controller.rb +176 -24
- data/app/controllers/action_agent/api/provider_models_controller.rb +37 -15
- data/app/controllers/action_agent/api/recording_event_ingest_controller.rb +67 -0
- data/app/controllers/action_agent/api/sandbox_browser_tickets_controller.rb +50 -0
- data/app/controllers/action_agent/api/sandbox_browsers_controller.rb +65 -0
- data/app/controllers/action_agent/api/sandboxes_controller.rb +148 -8
- data/app/controllers/action_agent/api/scenario_catalog_entries_controller.rb +188 -0
- data/app/controllers/action_agent/api/scenario_catalogs_controller.rb +302 -0
- data/app/controllers/action_agent/api/session_recordings_controller.rb +165 -34
- data/app/controllers/action_agent/api/sessions_controller.rb +111 -0
- data/app/controllers/action_agent/api/telemetry_keys_controller.rb +21 -0
- data/app/controllers/action_agent/dashboard_controller.rb +17 -6
- data/app/controllers/action_agent/session_player_controller.rb +58 -0
- data/app/controllers/concerns/action_agent/api/agent_serialization.rb +1 -0
- data/app/controllers/concerns/action_agent/api/mcp_dashboard_tools.rb +627 -20
- data/app/controllers/concerns/action_agent/api/project_browser.rb +46 -0
- data/app/controllers/concerns/action_agent/api/project_secret_authorization.rb +57 -0
- data/app/jobs/action_agent/agent_execution_job.rb +9 -39
- data/app/jobs/action_agent/agent_resume_job.rb +84 -0
- data/app/jobs/action_agent/code_session_job.rb +39 -10
- data/app/jobs/action_agent/draft_pull_request_job.rb +43 -0
- data/app/jobs/action_agent/exploration_job.rb +80 -0
- data/app/jobs/action_agent/input_request_expiry_job.rb +22 -0
- data/app/jobs/action_agent/project_evaluation_job.rb +59 -0
- data/app/jobs/action_agent/project_setup_job.rb +21 -0
- data/app/jobs/action_agent/sandbox_cleanup_job.rb +20 -3
- data/app/jobs/action_agent/sandbox_provision_job.rb +77 -10
- data/app/jobs/action_agent/sandbox_run_job.rb +9 -37
- data/app/jobs/action_agent/verify_evaluation_fix_job.rb +37 -0
- data/app/models/action_agent/agent.rb +72 -26
- data/app/models/action_agent/agent_run.rb +134 -23
- data/app/models/action_agent/agent_template.rb +35 -1
- data/app/models/action_agent/api_key.rb +14 -0
- data/app/models/action_agent/catalog_scenario.rb +75 -0
- data/app/models/action_agent/code_session.rb +21 -5
- data/app/models/action_agent/draft_pull_request.rb +131 -0
- data/app/models/action_agent/evaluation.rb +148 -0
- data/app/models/action_agent/evaluation_run.rb +143 -53
- data/app/models/action_agent/evaluation_scenario_result.rb +15 -3
- data/app/models/action_agent/exploration.rb +847 -0
- data/app/models/action_agent/github_installation.rb +159 -0
- data/app/models/action_agent/input_request.rb +291 -0
- data/app/models/action_agent/model_pricing.rb +214 -34
- data/app/models/action_agent/project.rb +789 -0
- data/app/models/action_agent/project_secret.rb +339 -0
- data/app/models/action_agent/provider_key.rb +207 -4
- data/app/models/action_agent/recording_event.rb +145 -0
- data/app/models/action_agent/recording_snapshot.rb +7 -7
- data/app/models/action_agent/sandbox_session.rb +300 -16
- data/app/models/action_agent/scenario_catalog.rb +172 -0
- data/app/models/action_agent/scenario_product.rb +57 -0
- data/app/models/action_agent/scenario_set.rb +138 -0
- data/app/models/action_agent/session_recording.rb +121 -14
- data/app/models/action_agent/telemetry_trace.rb +74 -19
- data/app/models/concerns/action_agent/ownable.rb +84 -13
- data/app/serializers/action_agent/evaluation_serializer.rb +41 -10
- data/app/serializers/action_agent/input_request_serializer.rb +47 -0
- data/app/serializers/action_agent/scenario_catalog_serializer.rb +23 -0
- data/app/serializers/action_agent/session_summary_serializer.rb +146 -0
- data/app/services/action_agent/agent_execution_service.rb +450 -72
- data/app/services/action_agent/agent_scorecard.rb +50 -21
- data/app/services/action_agent/agent_sync.rb +5 -2
- data/app/services/action_agent/agent_tool_roster.rb +19 -4
- data/app/services/action_agent/agent_toolbox.rb +215 -9
- data/app/services/action_agent/browser_live_ticket.rb +78 -0
- data/app/services/action_agent/browser_sidecar.rb +213 -0
- data/app/services/action_agent/browser_sign_in.rb +163 -0
- data/app/services/action_agent/browser_tool_redaction.rb +92 -0
- data/app/services/action_agent/claude_code_auth.rb +70 -4
- data/app/services/action_agent/codex_session_events.rb +37 -0
- data/app/services/action_agent/dashboard_assistant_service.rb +24 -10
- data/app/services/action_agent/draft_pull_request_publisher.rb +719 -0
- data/app/services/action_agent/evaluation_fix.rb +101 -0
- data/app/services/action_agent/evaluation_fix_comparison.rb +66 -0
- data/app/services/action_agent/evaluation_report_import.rb +84 -5
- data/app/services/action_agent/evaluation_run_cost.rb +609 -0
- data/app/services/action_agent/evaluation_runner_service.rb +29 -10
- data/app/services/action_agent/evaluation_standing.rb +152 -0
- data/app/services/action_agent/explorer_execution_service.rb +517 -0
- data/app/services/action_agent/github_client.rb +405 -64
- data/app/services/action_agent/live_updates.rb +31 -0
- data/app/services/action_agent/local_sandbox_backend.rb +1263 -102
- data/app/services/action_agent/local_sandbox_claude_login.rb +151 -0
- data/app/services/action_agent/mcp_client.rb +6 -2
- data/app/services/action_agent/mcp_recording_middleware.rb +104 -145
- data/app/services/action_agent/mcp_tool_dispatcher.rb +36 -13
- data/app/services/action_agent/mock_sandbox_backend.rb +3 -1
- data/app/services/action_agent/playwright_mcp_client.rb +7 -0
- data/app/services/action_agent/project_boot_fix.rb +309 -0
- data/app/services/action_agent/project_capabilities.rb +200 -0
- data/app/services/action_agent/project_install_pull_request.rb +225 -0
- data/app/services/action_agent/project_preflight.rb +178 -0
- data/app/services/action_agent/project_secret_discovery.rb +142 -0
- data/app/services/action_agent/project_setup.rb +429 -0
- data/app/services/action_agent/provider_credentials.rb +102 -0
- data/app/services/action_agent/recording_event_ingest.rb +181 -0
- data/app/services/action_agent/runtime_tool_roster.rb +52 -0
- data/app/services/action_agent/sample_data/conference_ticket.rb +516 -0
- data/app/services/action_agent/sandbox_boot_spec.rb +558 -0
- data/app/services/action_agent/sandbox_browser.rb +299 -0
- data/app/services/action_agent/sandbox_browser_driver.rb +85 -0
- data/app/services/action_agent/sandbox_credential_paths.rb +26 -0
- data/app/services/action_agent/sandbox_mail.rb +103 -0
- data/app/services/action_agent/sandbox_manifest.rb +166 -13
- data/app/services/action_agent/sandbox_orchestrator.rb +290 -23
- data/app/services/action_agent/sandbox_patch.rb +253 -0
- data/app/services/action_agent/scenario_catalog_import.rb +255 -0
- data/app/services/action_agent/scenario_catalog_repository_import.rb +81 -0
- data/app/services/action_agent/scenario_evaluation_runner.rb +121 -17
- data/app/services/action_agent/secret_scrubber.rb +33 -4
- data/app/services/action_agent/session_index.rb +270 -0
- data/app/services/action_agent/session_recording_service.rb +11 -0
- data/app/services/action_agent/session_timeline.rb +505 -0
- data/app/views/action_agent/github_app_manifests/created.html.erb +55 -0
- data/app/views/action_agent/session_player/show.html.erb +19 -0
- data/config/routes.rb +153 -2
- data/lib/action_agent/claude_login_process.rb +107 -0
- data/lib/action_agent/engine.rb +55 -5
- data/lib/action_agent/secret_requests.rb +80 -0
- data/lib/action_agent/version.rb +1 -1
- data/lib/action_agent.rb +513 -22
- data/lib/generators/action_agent/install_generator.rb +45 -5
- data/lib/generators/action_agent/templates/action_agent.rb.erb +161 -0
- data/lib/generators/action_agent/templates/add_code_session_runner.rb.erb +9 -0
- data/lib/generators/action_agent/templates/migrations/015_add_provider_key_scope.rb.erb +72 -0
- data/lib/generators/action_agent/templates/migrations/016_create_active_agent_input_requests.rb.erb +85 -0
- data/lib/generators/action_agent/templates/migrations/017_create_active_agent_recording_events.rb.erb +57 -0
- data/lib/generators/action_agent/templates/migrations/018_add_browser_to_active_agent_sandbox_sessions.rb.erb +25 -0
- data/lib/generators/action_agent/templates/migrations/019_create_active_agent_projects.rb.erb +79 -0
- data/lib/generators/action_agent/templates/migrations/020_add_github_app_installations.rb.erb +62 -0
- data/lib/generators/action_agent/templates/migrations/021_create_active_agent_explorations.rb.erb +63 -0
- data/lib/generators/action_agent/templates/migrations/023_create_active_agent_draft_pull_requests.rb.erb +75 -0
- data/lib/generators/action_agent/templates/migrations/024_add_kind_to_active_agent_project_secrets.rb.erb +14 -0
- data/lib/generators/action_agent/templates/migrations/025_create_active_agent_scenario_catalogs.rb.erb +110 -0
- data/lib/generators/action_agent/templates/migrations/026_add_evaluation_fixes_to_code_sessions.rb.erb +21 -0
- data/lib/tasks/action_agent.rake +33 -0
- data/lib/tasks/browser.rake +22 -0
- data/lib/tasks/sandbox.rake +1 -1
- data/lib/tasks/scenario_catalogs.rake +71 -0
- metadata +100 -2
|
@@ -9,15 +9,29 @@ module ActionAgent
|
|
|
9
9
|
class EvaluationRun < ApplicationRecord
|
|
10
10
|
belongs_to :evaluation
|
|
11
11
|
# The version of the evaluated agent this run scored, so a pass rate is
|
|
12
|
-
# a statement about a release rather than about "the agent".
|
|
12
|
+
# a statement about a release rather than about "the agent". A run the
|
|
13
|
+
# engine executes scored the agent as it is now; an imported run scored
|
|
14
|
+
# the publishing application's code, which only its report can name
|
|
15
|
+
# (EvaluationReportImport sets the version from `report.release`), so
|
|
16
|
+
# a release-less import stays unrecorded rather than claiming the
|
|
17
|
+
# dashboard's latest version.
|
|
13
18
|
belongs_to :agent_version, optional: true
|
|
14
|
-
before_create { self.agent_version_id ||= evaluation&.agent&.latest_version&.id }
|
|
19
|
+
before_create { self.agent_version_id ||= evaluation&.agent&.latest_version&.id unless imported? }
|
|
20
|
+
# A run started on an archived evaluation brings it back: archiving says
|
|
21
|
+
# "no longer maintained", which a new run contradicts.
|
|
22
|
+
after_create { evaluation.unarchive! if evaluation&.archived? }
|
|
15
23
|
has_many :scenario_results, class_name: "EvaluationScenarioResult", dependent: :destroy
|
|
16
24
|
|
|
17
25
|
enum :status, { pending: 0, running: 1, complete: 2, failed: 3 }
|
|
18
26
|
|
|
19
27
|
scope :recent, -> { order(created_at: :desc) }
|
|
20
28
|
|
|
29
|
+
# Whether this run was published by an application that ran it itself
|
|
30
|
+
# (EvaluationReportImport) rather than executed here.
|
|
31
|
+
def imported?
|
|
32
|
+
external_run_id.present?
|
|
33
|
+
end
|
|
34
|
+
|
|
21
35
|
# Which scenarios and models a scenario run covered; empty for a
|
|
22
36
|
# generation-sampling run.
|
|
23
37
|
def selection
|
|
@@ -92,14 +106,37 @@ module ActionAgent
|
|
|
92
106
|
(values.sum.to_f / values.size).round(3)
|
|
93
107
|
end
|
|
94
108
|
|
|
95
|
-
# The judge's own spend on this run
|
|
96
|
-
# how many calls served each purpose
|
|
97
|
-
# for a run
|
|
98
|
-
|
|
109
|
+
# The judge's own spend on this run as the engine's meter recorded it —
|
|
110
|
+
# calls, tokens, estimated cost and how many calls served each purpose
|
|
111
|
+
# — or nil for a run the engine did not judge (a rules-only run, or an
|
|
112
|
+
# imported one, whose judge the application ran).
|
|
113
|
+
def judge_usage_meter
|
|
99
114
|
value = scores&.dig("_judge_usage")
|
|
100
115
|
value.is_a?(Hash) ? value : nil
|
|
101
116
|
end
|
|
102
117
|
|
|
118
|
+
# The judge's spend on this run from whatever recorded it: the meter,
|
|
119
|
+
# the publishing application's figures, or the judge traces priced
|
|
120
|
+
# (EvaluationRunCost). nil for a run no judge was asked about.
|
|
121
|
+
def judge_usage
|
|
122
|
+
cost_breakdown.judge_usage
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Every cost figure of this run — per result, per scenario, per model
|
|
126
|
+
# and in total — worked out once (EvaluationRunCost). A controller that
|
|
127
|
+
# lists runs preloads it (EvaluationRunCost.preload) and hands it in.
|
|
128
|
+
def cost_breakdown
|
|
129
|
+
@cost_breakdown ||= EvaluationRunCost.for(self)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
attr_writer :cost_breakdown
|
|
133
|
+
|
|
134
|
+
# Forgets the breakdown, so a run whose results just changed is priced again.
|
|
135
|
+
def reload(*)
|
|
136
|
+
@cost_breakdown = nil
|
|
137
|
+
super
|
|
138
|
+
end
|
|
139
|
+
|
|
103
140
|
# Per-model summaries of a generation-sampling run's cohorts, keyed by
|
|
104
141
|
# model; empty for a scenario run or a run recorded before they were.
|
|
105
142
|
def cohorts
|
|
@@ -107,59 +144,51 @@ module ActionAgent
|
|
|
107
144
|
value.is_a?(Hash) ? value : {}
|
|
108
145
|
end
|
|
109
146
|
|
|
147
|
+
# Per-model summaries of a scenario run, keyed by label, as the runner
|
|
148
|
+
# recorded them under "_models", each with its cost as it stands now:
|
|
149
|
+
# the effective "cost" over its results (reported, else estimated), the
|
|
150
|
+
# "priced", "reported" and "estimated" counts behind it, and the
|
|
151
|
+
# judge's "judge_cost" and "judge_calls" on them (EvaluationRunCost). A
|
|
152
|
+
# recorded summary no result maps to is served as recorded. Empty for a
|
|
153
|
+
# generation-sampling run.
|
|
154
|
+
def model_summaries
|
|
155
|
+
summaries = scores&.dig("_models")
|
|
156
|
+
return {} unless summaries.is_a?(Hash)
|
|
157
|
+
|
|
158
|
+
costed = cost_breakdown.by_label(summaries.keys)
|
|
159
|
+
summaries.to_h do |label, stats|
|
|
160
|
+
next [ label, stats ] unless stats.is_a?(Hash) && costed.key?(label)
|
|
161
|
+
|
|
162
|
+
[ label, stats.merge(costed[label]) ]
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
110
166
|
# What the run spent, for display after it: the agent's side and the
|
|
111
167
|
# judge's, kept apart because they answer different questions.
|
|
112
168
|
#
|
|
113
169
|
# The agent's side is the operating figure — what the interactions cost
|
|
114
|
-
# to serve. For a scenario run that is
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
#
|
|
170
|
+
# to serve. For a scenario run that is its replays' cost, tokens and
|
|
171
|
+
# summed model time (`replays` of them); for a generation-sampling run
|
|
172
|
+
# it is the sampled generations' (`samples`), which were served before
|
|
173
|
+
# the run and cost it nothing.
|
|
174
|
+
#
|
|
175
|
+
# Every interaction with tokens is priced (EvaluationRunCost): `cost`
|
|
176
|
+
# sums the reported costs and, where none was reported, the estimates
|
|
177
|
+
# from tokens × model rates. `priced` and `unpriced` count the
|
|
178
|
+
# interactions either way, `reported` and `estimated` say how the priced
|
|
179
|
+
# ones were priced, and `cost_basis` sums that up as "reported",
|
|
180
|
+
# "estimated" or "mixed". `per_interaction` is the cost per priced
|
|
181
|
+
# interaction, the number a per-conversation budget is set against.
|
|
120
182
|
#
|
|
121
183
|
# `judge` is the evaluation's own overhead: the judge model's calls
|
|
122
184
|
# (scoring, recommending, the verdict, authoring KPIs), which run
|
|
123
|
-
# agent-to-agent and offline
|
|
185
|
+
# agent-to-agent and offline — from the engine's meter, the publishing
|
|
186
|
+
# application's figures or the judge traces, with `source` naming which
|
|
187
|
+
# and `run` the calls no result owns. `total` is the two sides together.
|
|
124
188
|
#
|
|
125
189
|
# Returns nil for a run that recorded nothing on either side.
|
|
126
190
|
def usage
|
|
127
|
-
|
|
128
|
-
Arel.sql("COUNT(*)"), Arel.sql("SUM(cost)"), Arel.sql("SUM(input_tokens)"),
|
|
129
|
-
Arel.sql("SUM(output_tokens)"), Arel.sql("SUM(duration_ms)")
|
|
130
|
-
)
|
|
131
|
-
replays = totals&.first.to_i
|
|
132
|
-
judge = judge_usage
|
|
133
|
-
runtime_ms = completed_at.present? ? ((completed_at - created_at) * 1000).round : nil
|
|
134
|
-
|
|
135
|
-
if replays.positive?
|
|
136
|
-
cost = totals[1]&.to_f
|
|
137
|
-
{
|
|
138
|
-
replays: replays,
|
|
139
|
-
cost: cost,
|
|
140
|
-
per_interaction: cost && (cost / replays).round(6),
|
|
141
|
-
input_tokens: totals[2].to_i,
|
|
142
|
-
output_tokens: totals[3].to_i,
|
|
143
|
-
model_time_ms: totals[4].to_i,
|
|
144
|
-
runtime_ms: runtime_ms,
|
|
145
|
-
judge: judge
|
|
146
|
-
}.compact
|
|
147
|
-
elsif cohorts.any?
|
|
148
|
-
samples = cohorts.values.sum { |cohort| cohort["samples"].to_i }
|
|
149
|
-
costs = cohorts.values.filter_map { |cohort| cohort["cost"] }
|
|
150
|
-
cost = costs.any? ? costs.sum.to_f.round(6) : nil
|
|
151
|
-
{
|
|
152
|
-
samples: samples,
|
|
153
|
-
cost: cost,
|
|
154
|
-
per_interaction: cost && samples.positive? ? (cost / samples).round(6) : nil,
|
|
155
|
-
input_tokens: cohorts.values.sum { |cohort| cohort["input_tokens"].to_i },
|
|
156
|
-
output_tokens: cohorts.values.sum { |cohort| cohort["output_tokens"].to_i },
|
|
157
|
-
runtime_ms: runtime_ms,
|
|
158
|
-
judge: judge
|
|
159
|
-
}.compact
|
|
160
|
-
elsif judge
|
|
161
|
-
{ runtime_ms: runtime_ms, judge: judge }.compact
|
|
162
|
-
end
|
|
191
|
+
cost_breakdown.usage
|
|
163
192
|
end
|
|
164
193
|
|
|
165
194
|
# Route templates for the report's fix item actions, relative to the
|
|
@@ -194,10 +223,21 @@ module ActionAgent
|
|
|
194
223
|
# the suite panel does. Raises ActiveRecord::RecordNotFound via the
|
|
195
224
|
# caller for a run of a generation-sampling evaluation, which has no
|
|
196
225
|
# scenario results to report on.
|
|
197
|
-
|
|
226
|
+
#
|
|
227
|
+
# With `estimate` (the default) each replay carries its effective cost
|
|
228
|
+
# and how it was priced (EvaluationRunCost), and the report is told the
|
|
229
|
+
# judge's run-level spend, so the page shows every cost the dashboard
|
|
230
|
+
# does. `estimate: false` rebuilds the report from what was recorded
|
|
231
|
+
# alone — the import summarizes a published run that way, so the
|
|
232
|
+
# summaries it stores stay the application's own figures.
|
|
233
|
+
#
|
|
234
|
+
# The engine runs against every activeagent since 1.4, so the report
|
|
235
|
+
# kwargs that arrived later are passed only when Report.new takes them.
|
|
236
|
+
def to_report(links: report_links, estimate: true)
|
|
198
237
|
rows = scenario_results.includes(:scenario).sort_by do |row|
|
|
199
238
|
[ row.evaluated_scenario["position"].to_i, row.evaluation_scenario_id, row.model ]
|
|
200
239
|
end
|
|
240
|
+
breakdown = cost_breakdown if estimate
|
|
201
241
|
selected = selected_specs
|
|
202
242
|
specs = {}
|
|
203
243
|
results = rows.map do |row|
|
|
@@ -210,14 +250,15 @@ module ActionAgent
|
|
|
210
250
|
replay: ActiveAgent::Evals::Replay.new(
|
|
211
251
|
answer: row.output, tool_calls: Array(row.tool_calls), duration_ms: row.duration_ms,
|
|
212
252
|
input_tokens: row.input_tokens, output_tokens: row.output_tokens,
|
|
213
|
-
cost: row.cost&.to_f, error: row.error_message,
|
|
253
|
+
cost: breakdown ? breakdown.result(row)["cost"] : row.cost&.to_f, error: row.error_message,
|
|
254
|
+
metadata: replay_metadata_for(row, breakdown)
|
|
214
255
|
),
|
|
215
256
|
scores: row.scores.to_h, score: row.score, status: row.status,
|
|
216
257
|
diagnosis: row.evaluation_diagnosis.presence
|
|
217
258
|
)
|
|
218
259
|
end
|
|
219
260
|
|
|
220
|
-
|
|
261
|
+
kwargs = {
|
|
221
262
|
results: results,
|
|
222
263
|
models: (selected.values & specs.values) + (specs.values - selected.values),
|
|
223
264
|
metadata: {
|
|
@@ -232,7 +273,40 @@ module ActionAgent
|
|
|
232
273
|
tool_resolver: EvaluationToolResolver.new(evaluation.agent),
|
|
233
274
|
agent_name: evaluation.agent&.name,
|
|
234
275
|
links: links
|
|
235
|
-
|
|
276
|
+
}
|
|
277
|
+
kwargs[:judge_usage] = breakdown.judge_usage_run if breakdown && self.class.report_accepts?(:judge_usage)
|
|
278
|
+
kwargs[:release] = release_summary if release_summary && self.class.report_accepts?(:release)
|
|
279
|
+
self.class.report_class.new(**kwargs)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# The framework's Report, as installed.
|
|
283
|
+
def self.report_class
|
|
284
|
+
ActiveAgent::Evals::Report
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Whether the installed framework's Report.new declares +keyword+.
|
|
288
|
+
def self.report_accepts?(keyword)
|
|
289
|
+
report_class.instance_method(:initialize).parameters.any? { |type, name| name == keyword && %i[key keyreq].include?(type) }
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# The release this run scored, as the report names it — `{ "digest",
|
|
293
|
+
# "revision", "label" }` — or nil for a run pinned to a dashboard edit
|
|
294
|
+
# or to no version.
|
|
295
|
+
def release_summary
|
|
296
|
+
version = agent_version
|
|
297
|
+
return nil unless version&.release?
|
|
298
|
+
|
|
299
|
+
{ "digest" => version.release_digest, "revision" => version.revision, "label" => "v#{version.version_number}" }.compact
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# The agent version this run scored, for the run's JSON: `{ id, number,
|
|
303
|
+
# release_digest, revision, release }`, or nil when none was recorded.
|
|
304
|
+
def agent_version_summary
|
|
305
|
+
version = agent_version
|
|
306
|
+
return nil unless version
|
|
307
|
+
|
|
308
|
+
{ id: version.id, number: version.version_number, release_digest: version.release_digest,
|
|
309
|
+
revision: version.revision, release: version.release? }
|
|
236
310
|
end
|
|
237
311
|
|
|
238
312
|
private
|
|
@@ -240,6 +314,22 @@ module ActionAgent
|
|
|
240
314
|
ModelSpec = ActiveAgent::Evals::ModelSpec
|
|
241
315
|
private_constant :ModelSpec
|
|
242
316
|
|
|
317
|
+
# The replay metadata the rebuilt report reads a result's costs from:
|
|
318
|
+
# what the result recorded, the judge usage the application reported
|
|
319
|
+
# for it, and — when estimating — how its cost was priced.
|
|
320
|
+
def replay_metadata_for(row, breakdown)
|
|
321
|
+
metadata = row.replay_metadata.dup
|
|
322
|
+
reported_judge = row.diagnosis.is_a?(Hash) ? row.diagnosis["_judge_usage"] : nil
|
|
323
|
+
metadata["judge_usage"] = reported_judge if reported_judge.is_a?(Hash)
|
|
324
|
+
return metadata unless breakdown
|
|
325
|
+
|
|
326
|
+
entry = breakdown.result(row)
|
|
327
|
+
metadata["cost_source"] = entry["cost_source"]
|
|
328
|
+
metadata["cost_rate"] = entry["cost_rate"] if entry["cost_rate"]
|
|
329
|
+
metadata["judge_usage"] = entry["judge_usage"] if entry["judge_usage"]
|
|
330
|
+
metadata
|
|
331
|
+
end
|
|
332
|
+
|
|
243
333
|
# How the report's header names the sandbox: its checkout and session.
|
|
244
334
|
def sandbox_label
|
|
245
335
|
return nil unless sandbox
|
|
@@ -44,8 +44,11 @@ module ActionAgent
|
|
|
44
44
|
value.is_a?(Hash) ? value : {}
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
# The diagnosis as the dashboard shows it: without the storage keys —
|
|
48
|
+
# the replay metadata, the scenario snapshot and the judge usage the
|
|
49
|
+
# publishing application reported (served as `judge_usage` instead).
|
|
47
50
|
def evaluation_diagnosis
|
|
48
|
-
(diagnosis || {}).except("_replay_metadata", "_scenario_snapshot")
|
|
51
|
+
(diagnosis || {}).except("_replay_metadata", "_scenario_snapshot", "_judge_usage")
|
|
49
52
|
end
|
|
50
53
|
|
|
51
54
|
# A catalog can be refreshed without changing what an earlier run asked
|
|
@@ -55,7 +58,12 @@ module ActionAgent
|
|
|
55
58
|
snapshot.is_a?(Hash) ? snapshot : scenario.as_json_summary.stringify_keys
|
|
56
59
|
end
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
# The result for the JSON API. Its cost is the effective one — reported,
|
|
62
|
+
# else estimated — with `reported_cost`, `cost_source`, `cost_rate` and
|
|
63
|
+
# the judge's `judge_usage` on it (EvaluationRunCost). A caller listing
|
|
64
|
+
# a run's results hands in the run's breakdown so nothing is priced per row.
|
|
65
|
+
def as_json_summary(costs: nil)
|
|
66
|
+
costs ||= evaluation_run.cost_breakdown.result(self)
|
|
59
67
|
{
|
|
60
68
|
id: id,
|
|
61
69
|
scenario_id: evaluation_scenario_id,
|
|
@@ -73,7 +81,11 @@ module ActionAgent
|
|
|
73
81
|
duration_ms: duration_ms,
|
|
74
82
|
input_tokens: input_tokens,
|
|
75
83
|
output_tokens: output_tokens,
|
|
76
|
-
cost: cost
|
|
84
|
+
cost: costs["cost"],
|
|
85
|
+
reported_cost: costs["reported_cost"],
|
|
86
|
+
cost_source: costs["cost_source"],
|
|
87
|
+
cost_rate: costs["cost_rate"],
|
|
88
|
+
judge_usage: costs["judge_usage"],
|
|
77
89
|
fault: fault,
|
|
78
90
|
recommendation: recommendation,
|
|
79
91
|
diagnosis: evaluation_diagnosis,
|