Class: ResumeRunJob

Inherits:
ApplicationJob show all
Defined in:
app/jobs/resume_run_job.rb

Instance Method Summary collapse

Instance Method Details

#perform(run_id, message, approve: false) ⇒ Object

Resumes honor the column's WIP limit like any other start (§8): if the column is full, the answer is recorded and the card rejoins the queue; Column#kick_queue fires the pending resume when a slot frees.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'app/jobs/resume_run_job.rb', line 7

def perform(run_id, message, approve: false)
  run = Run.find(run_id)
  return unless run.needs_input?
  card = run.card

  if card.column.execution? && card.column.at_wip_limit?
    pending = run.briefing["pending_resume"]
    combined = [pending&.dig("message"), message].compact_blank.join("\n\n")
    run.update!(briefing: run.briefing.merge(
      "pending_resume" => { "message" => combined, "approve" => approve || pending&.dig("approve") || false }
    ))
    card.update!(status: "queued")
    card.log!("status_change", run: run, text: "Answer recorded — waiting for a free agent slot")
    return
  end

  # Atomic claim (§ races): two finishing runs can both kick the queue and
  # double-fire this job — exactly one claimer resumes the session. The
  # claim value is "running", which is what a resume sets anyway.
  return unless Run.where(id: run.id, status: "needs_input")
                   .update_all(status: "running", updated_at: Time.current) == 1
  run.reload

  if (pending = run.briefing["pending_resume"])
    run.update!(briefing: run.briefing.except("pending_resume"))
    message = [pending["message"], message].compact_blank.join("\n\n")
    approve ||= pending["approve"]
  end

  # Steering notes queued while the agent streamed (card #47) ride along on
  # whatever resumes the session — an answer, plan feedback, or an approval.
  if (steering = Array(run.briefing["steering"])).any?
    run.update!(briefing: run.briefing.except("steering"))
    notes = "Notes the user left while you were working:\n- #{steering.join("\n- ")}"
    message = [notes, message].compact_blank.join("\n\n")
  end
  Agent::Runner.resume(run, message, approve: approve)
end