Class: ActionAgent::Api::EvaluationsController

Inherits:
BaseController show all
Defined in:
app/controllers/action_agent/api/evaluations_controller.rb

Overview

CRUD + execution for agent evaluations, backing the dashboard Evaluations view. Scoped to the current user's agents.

Constant Summary collapse

DEFAULT_CRITERIA =

Default criteria used when none are supplied — all rule-based, so a new evaluation produces real scores without provider credentials.

[
  { "key" => "response_present", "type" => "response_present", "config" => {} },
  { "key" => "response_length", "type" => "min_length", "config" => { "chars" => 40 } },
  { "key" => "latency", "type" => "max_latency_ms", "config" => { "ms" => 5000 } },
  { "key" => "token_budget", "type" => "token_budget", "config" => { "output_tokens" => 1000 } }
].freeze

Instance Method Summary collapse

Methods inherited from ActionAgent::ApplicationController

allow_unauthenticated_access

Instance Method Details

#createObject

POST /api/evaluations



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/controllers/action_agent/api/evaluations_controller.rb', line 45

def create
  agent = owner_agents.find(params.require(:evaluation)[:agent_id])

  judge_kind = evaluation_params[:judge_kind].presence || "rules"
  config = {}
  config["compare_models"] = compare_models_param if compare_models_param.any?

  evaluation = agent.evaluations.new(
    name: evaluation_params[:name],
    judge_kind: judge_kind,
    judge_model: evaluation_params[:judge_model],
    sample_size: evaluation_params[:sample_size].presence || 20,
    # judge_defined starts with no criteria — the judge authors the
    # KPIs on the first run.
    criteria: judge_kind == "judge_defined" ? explicit_criteria : normalized_criteria,
    config: config
  )

  if evaluation.save
    evaluation.run!
    render json: { evaluation: serialize(evaluation.reload) }, status: :created
  else
    render json: { errors: evaluation.errors.full_messages }, status: :unprocessable_entity
  end
end

#destroyObject

DELETE /api/evaluations/:id



80
81
82
83
# File 'app/controllers/action_agent/api/evaluations_controller.rb', line 80

def destroy
  evaluations_scope.find(params[:id]).destroy!
  head :no_content
end

#indexObject

GET /api/evaluations agent_id scopes to one agent. The filter has to happen before the limit: the agent page reads this endpoint, and filtering an account-wide page of 50 client-side hides an agent whose evaluations are not among the account's 50 most recent. The scope is already restricted to the current user's agents, so an id outside it simply returns nothing.



25
26
27
28
29
30
31
# File 'app/controllers/action_agent/api/evaluations_controller.rb', line 25

def index
  scope = evaluations_scope
  scope = scope.where(agent_id: params[:agent_id]) if params[:agent_id].present?
  evaluations = scope.includes(:agent, :evaluation_runs).recent.limit(50)

  render json: { evaluations: evaluations.map { |evaluation| serialize(evaluation) } }
end

#runObject

POST /api/evaluations/:id/run



72
73
74
75
76
77
# File 'app/controllers/action_agent/api/evaluations_controller.rb', line 72

def run
  evaluation = evaluations_scope.find(params[:id])
  run = evaluation.run!

  render json: { evaluation: serialize(evaluation.reload), run: serialize_run(run) }
end

#showObject

GET /api/evaluations/:id



34
35
36
37
38
39
40
41
42
# File 'app/controllers/action_agent/api/evaluations_controller.rb', line 34

def show
  evaluation = evaluations_scope.find(params[:id])

  render json: {
    evaluation: serialize(evaluation).merge(
      runs: evaluation.evaluation_runs.recent.limit(20).map { |run| serialize_run(run) }
    )
  }
end