Class: HermesAgent::Client::Resources::Runs

Inherits:
Object
  • Object
show all
Defined in:
lib/hermes_agent/client/resources/runs.rb

Overview

The runs resource: the Runs API (/v1/runs) for long-running agent runs. Unlike chat completions and the Responses API, a run is server-side asynchronous: #create returns immediately (HTTP 202) with a minimal Entities::Run carrying only its run_id and status, and progress is tracked by polling #get or by subscribing to its event stream with #stream_events. On a server configured with an API key, these calls require a bearer token (see HermesAgent::Client / Configuration).

Run records are retained only briefly after they reach a terminal status, then evicted, so callers should not assume an older run remains retrievable.

Instance Method Summary collapse

Instance Method Details

#create(input:, instructions: nil, conversation_history: nil, previous_response_id: nil, session_id: nil, **extra) ⇒ Entities::Run

Start a run.

Returns as soon as the run is accepted; the returned Entities::Run carries only its run_id and an initial status of "started". Poll #get with that id to follow the run to a terminal status.

No model is sent: the model is configured server-side. (A caller who really wants to send fields we have not modeled — including model — can pass them through extra.)

Parameters:

  • input (String)

    The user prompt (required).

  • instructions (String, nil) (defaults to: nil)

    A system directive layered over the agent prompt. Omitted from the request when nil.

  • conversation_history (Array<Hash>, nil) (defaults to: nil)

    Prior turns as an OpenAI-style message array ([{role:, content:}, …]), loaded into the run's context. Omitted from the request when nil.

  • previous_response_id (String, nil) (defaults to: nil)

    The id of a stored /v1/responses response whose context should be loaded into the run. Omitted from the request when nil.

  • session_id (String, nil) (defaults to: nil)

    A correlation label, stored and echoed back on the poll. Omitted from the request when nil.

  • extra (Hash)

    Additional request-body fields merged in as-is.

Returns:

  • (Entities::Run)

    The accepted run (minimal: run_id + status).

Raises:

  • (APIError)

    If the server returns a non-2xx response.



58
59
60
61
62
63
64
65
66
# File 'lib/hermes_agent/client/resources/runs.rb', line 58

def create(input:, instructions: nil, conversation_history: nil,
           previous_response_id: nil, session_id: nil, **extra)
  body = {input: input, **extra}
  body[:instructions] = instructions if instructions
  body[:conversation_history] = conversation_history if conversation_history
  body[:previous_response_id] = previous_response_id if previous_response_id
  body[:session_id] = session_id if session_id
  Entities::Run.new(@transport.post("/v1/runs", body).body)
end

#get(run_id) ⇒ Entities::Run

Retrieve a run by id, to poll its progress and status.

Parameters:

  • run_id (String)

    The run id ("run_…").

Returns:

Raises:

  • (NotFoundError)

    If no such run exists (or it was evicted).

  • (APIError)

    If the server returns another non-2xx response.



76
77
78
# File 'lib/hermes_agent/client/resources/runs.rb', line 76

def get(run_id)
  Entities::Run.new(@transport.get("/v1/runs/#{run_id}"))
end

#respond_approval(run_id, choice:) ⇒ Entities::RunApprovalResponse

Answer a run's pending approval, when a gated dangerous command has parked it at waiting_for_approval.

A run has at most one outstanding approval, keyed by its id, so only the run_id and a choice are needed. "once" approves this one invocation; "deny" rejects it (the run still ends completed). Note "always" writes a permanent server-side allowlist entry and "session" auto-approves the pattern for the rest of the gateway session — prefer "once"/"deny" unless those side effects are intended. An invalid choice is rejected by the server.

Parameters:

  • run_id (String)

    The run id ("run_…").

  • choice (String)

    One of "once", "session", "always", or "deny".

Returns:

Raises:

  • (NotFoundError)

    If no such run exists (or it was evicted).

  • (APIError)

    On an invalid choice (400) or another non-2xx response.



149
150
151
152
# File 'lib/hermes_agent/client/resources/runs.rb', line 149

def respond_approval(run_id, choice:)
  body = {choice: choice}
  Entities::RunApprovalResponse.new(@transport.post("/v1/runs/#{run_id}/approval", body).body)
end

#stop(run_id) ⇒ Entities::RunStop

Request that a run stop.

The stop is cooperative: this returns as soon as the request is accepted, with an ack carrying status: "stopping". The run then resolves to a terminal "cancelled" status — poll #get to observe that transition.

Parameters:

  • run_id (String)

    The run id ("run_…").

Returns:

Raises:

  • (NotFoundError)

    If no such run exists (or it was evicted).

  • (APIError)

    If the server returns another non-2xx response.



93
94
95
# File 'lib/hermes_agent/client/resources/runs.rb', line 93

def stop(run_id)
  Entities::RunStop.new(@transport.post("/v1/runs/#{run_id}/stop", {}).body)
end

#stream_events(run_id) {|event| ... } ⇒ Entities::RunEvent, ...

Stream a run's events as they occur (its tool-call progress, token deltas, reasoning, approval prompts, and lifecycle), following the block-or-enumerator pattern.

With a block, each Entities::RunEvent is yielded as it arrives and the terminal run.* event is returned once the stream closes. Without a block, a Stream is returned for the caller to iterate; its Stream#result is that terminal event (see Entities::RunEvent.terminal). Subscribing replays a run from its first event, so an already-terminal run can still be streamed during its (brief) retention window.

Parameters:

  • run_id (String)

    The run id ("run_…").

Yield Parameters:

Returns:

Raises:

  • (NotFoundError)

    If no such run exists (or it was evicted).

  • (APIError)

    If the server returns another non-2xx response.



118
119
120
121
122
123
124
125
126
127
# File 'lib/hermes_agent/client/resources/runs.rb', line 118

def stream_events(run_id, &block)
  chunks = @transport.stream_get("/v1/runs/#{run_id}/events")
  stream = Stream.new(chunks, event_class: Entities::RunEvent) do |events|
    Entities::RunEvent.terminal(events)
  end
  return stream unless block

  stream.each(&block)
  stream.result
end