Class: SimpleAcp::Client::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/simple_acp/client/base.rb

Overview

HTTP client for communicating with ACP servers.

Provides methods for agent discovery, run execution (sync, async, stream), run management, and session handling.

Examples:

Basic usage

client = SimpleAcp::Client::Base.new(base_url: "http://localhost:8000")
run = client.run_sync(agent: "echo", input: "Hello!")
puts run.output.first.text_content

Streaming

client.run_stream(agent: "echo", input: "Hello") do |event|
  case event
  when Models::MessagePartEvent
    print event.part.content
  end
end

With session

client.use_session("my-session-id")
client.run_sync(agent: "counter", input: "increment")

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base_url:, **options) ⇒ Base

Create a new ACP client.

Parameters:

  • base_url (String) —

    the base URL of the ACP server

  • options (Hash) —

    additional options

Options Hash (**options):

  • :headers (Hash) —

    custom HTTP headers

  • :auth (Array) —

    authentication credentials for Faraday

  • :timeout (Integer) —

    request timeout in seconds (default: 30)

  • :open_timeout (Integer) —

    connection timeout in seconds (default: 10)



41
42
43
44
45
46
# File 'lib/simple_acp/client/base.rb', line 41

def initialize(base_url:, **options)
  @base_url = base_url.chomp("/")
  @options = options
  @session_id = nil
  @connection = build_connection
end

Instance Attribute Details

#base_url ⇒ String (readonly)

Returns the base URL of the ACP server.

Returns:

  • (String) —

    the base URL of the ACP server



31
32
33
# File 'lib/simple_acp/client/base.rb', line 31

def base_url
  @base_url
end

Instance Method Details

#agent(name) ⇒ Models::AgentManifest

Get a specific agent's manifest.

Parameters:

  • name (String) —

    the agent name

Returns:

Raises:



79
80
81
82
83
# File 'lib/simple_acp/client/base.rb', line 79

def agent(name)
  response = @connection.get("/agents/#{name}")
  data = handle_response(response)
  Models::AgentManifest.from_hash(data)
end

#agents(limit: 10, offset: 0) ⇒ Models::AgentListResponse

List available agents on the server.

Parameters:

  • limit (Integer) (defaults to: 10) —

    maximum number of agents to return (default: 10)

  • offset (Integer) (defaults to: 0) —

    number of agents to skip (default: 0)

Returns:



64
65
66
67
68
69
70
71
72
# File 'lib/simple_acp/client/base.rb', line 64

def agents(limit: 10, offset: 0)
  response = @connection.get("/agents") do |req|
    req.params["limit"] = limit
    req.params["offset"] = offset
  end

  data = handle_response(response)
  Models::AgentListResponse.from_hash(data)
end

#clear_session ⇒ self

Clear the current session ID.

Returns:

  • (self) —

    for chaining



263
264
265
266
# File 'lib/simple_acp/client/base.rb', line 263

def clear_session
  @session_id = nil
  self
end

#close ⇒ void

This method returns an undefined value.

Close the HTTP connection.



291
292
293
# File 'lib/simple_acp/client/base.rb', line 291

def close
  @connection.close if @connection.respond_to?(:close)
end

#ping ⇒ Boolean

Check if the server is reachable.

Returns:

  • (Boolean) —

    true if server responds to ping



51
52
53
54
55
56
57
# File 'lib/simple_acp/client/base.rb', line 51

def ping
  response = @connection.get("/ping")
  handle_response(response)
  true
rescue StandardError
  false
end

#run_async(agent:, input:, session_id: nil) ⇒ Models::Run

Run an agent asynchronously, returning immediately.

Use #run_status or #wait_for_run to check completion.

Parameters:

  • agent (String) —

    the agent name

  • input (Array<Models::Message>, Models::Message, String) —

    input messages

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

    optional session ID

Returns:

  • (Models::Run) —

    the run (status will be :created or :in_progress)

Raises:



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/simple_acp/client/base.rb', line 120

def run_async(agent:, input:, session_id: nil)
  input_messages = normalize_input(input)

  response = @connection.post("/runs") do |req|
    req.headers["Content-Type"] = "application/json"
    req.body = {
      agent_name: agent,
      input: input_messages.map(&:to_h),
      mode: Models::Types::RunMode::ASYNC,
      session_id: session_id || @session_id
    }.to_json
  end

  data = handle_response(response)
  run = Models::Run.from_hash(data)
  @session_id = run.session_id if run.session_id
  run
end

#run_cancel(run_id) ⇒ Models::Run

Cancel a running agent execution.

Parameters:

  • run_id (String) —

    the run ID to cancel

Returns:

Raises:



198
199
200
201
202
# File 'lib/simple_acp/client/base.rb', line 198

def run_cancel(run_id)
  response = @connection.post("/runs/#{run_id}/cancel")
  data = handle_response(response)
  Models::Run.from_hash(data)
end

#run_events(run_id, limit: 100, offset: 0) ⇒ Array<Models::Event>

Get events that occurred during a run.

Parameters:

  • run_id (String) —

    the run ID

  • limit (Integer) (defaults to: 100) —

    maximum number of events to return (default: 100)

  • offset (Integer) (defaults to: 0) —

    number of events to skip (default: 0)

Returns:



183
184
185
186
187
188
189
190
191
# File 'lib/simple_acp/client/base.rb', line 183

def run_events(run_id, limit: 100, offset: 0)
  response = @connection.get("/runs/#{run_id}/events") do |req|
    req.params["limit"] = limit
    req.params["offset"] = offset
  end

  data = handle_response(response)
  (data["events"] || []).map { |e| Models::Events.from_hash(e) }
end

#run_resume_stream(run_id:, await_resume:) {|Models::Event| ... } ⇒ Enumerator<Models::Event>

Resume an awaited run with streaming output.

Parameters:

  • run_id (String) —

    the run ID to resume

  • await_resume (Models::AwaitResume) —

    the resume payload with client response

Yields:

Returns:

Raises:



232
233
234
235
236
237
238
# File 'lib/simple_acp/client/base.rb', line 232

def run_resume_stream(run_id:, await_resume:, &block)
  if block_given?
    resume_stream_with_block(run_id, await_resume, &block)
  else
    resume_stream_enumerable(run_id, await_resume)
  end
end

#run_resume_sync(run_id:, await_resume:) ⇒ Models::Run

Resume an awaited run synchronously.

Parameters:

  • run_id (String) —

    the run ID to resume

  • await_resume (Models::AwaitResume) —

    the resume payload with client response

Returns:

Raises:



211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/simple_acp/client/base.rb', line 211

def run_resume_sync(run_id:, await_resume:)
  response = @connection.post("/runs/#{run_id}") do |req|
    req.headers["Content-Type"] = "application/json"
    req.body = {
      await_resume: await_resume.to_h,
      mode: Models::Types::RunMode::SYNC
    }.to_json
  end

  data = handle_response(response)
  Models::Run.from_hash(data)
end

#run_status(run_id) ⇒ Models::Run

Get the current status of a run.

Parameters:

  • run_id (String) —

    the run ID

Returns:

Raises:



171
172
173
174
175
# File 'lib/simple_acp/client/base.rb', line 171

def run_status(run_id)
  response = @connection.get("/runs/#{run_id}")
  data = handle_response(response)
  Models::Run.from_hash(data)
end

#run_stream(agent:, input:, session_id: nil) {|Models::Event| ... } ⇒ Enumerator<Models::Event>

Run an agent with streaming response via Server-Sent Events.

Examples:

With block

client.run_stream(agent: "echo", input: "Hello") do |event|
  puts event.class.name
end

As enumerator

events = client.run_stream(agent: "echo", input: "Hello")
events.each { |e| puts e }

Parameters:

  • agent (String) —

    the agent name

  • input (Array<Models::Message>, Models::Message, String) —

    input messages

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

    optional session ID

Yields:

Returns:

Raises:



156
157
158
159
160
161
162
163
164
# File 'lib/simple_acp/client/base.rb', line 156

def run_stream(agent:, input:, session_id: nil, &block)
  input_messages = normalize_input(input)

  if block_given?
    run_stream_with_block(agent, input_messages, session_id, &block)
  else
    run_stream_enumerable(agent, input_messages, session_id)
  end
end

#run_sync(agent:, input:, session_id: nil) ⇒ Models::Run

Run an agent synchronously, blocking until completion.

Parameters:

  • agent (String) —

    the agent name

  • input (Array<Models::Message>, Models::Message, String) —

    input messages

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

    optional session ID

Returns:

Raises:



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/simple_acp/client/base.rb', line 92

def run_sync(agent:, input:, session_id: nil)
  input_messages = normalize_input(input)

  response = @connection.post("/runs") do |req|
    req.headers["Content-Type"] = "application/json"
    req.body = {
      agent_name: agent,
      input: input_messages.map(&:to_h),
      mode: Models::Types::RunMode::SYNC,
      session_id: session_id || @session_id
    }.to_json
  end

  data = handle_response(response)
  run = Models::Run.from_hash(data)
  @session_id = run.session_id if run.session_id
  run
end

#session(session_id) ⇒ Models::SessionResponse

Get session details.

Parameters:

  • session_id (String) —

    the session ID

Returns:

Raises:



245
246
247
248
249
# File 'lib/simple_acp/client/base.rb', line 245

def session(session_id)
  response = @connection.get("/session/#{session_id}")
  data = handle_response(response)
  Models::SessionResponse.from_hash(data)
end

#use_session(session_id) ⇒ self

Set a session ID for subsequent requests.

Parameters:

  • session_id (String) —

    the session ID to use

Returns:

  • (self) —

    for chaining



255
256
257
258
# File 'lib/simple_acp/client/base.rb', line 255

def use_session(session_id)
  @session_id = session_id
  self
end

#wait_for_run(run_id, timeout: 60, interval: 1) ⇒ Models::Run

Poll until a run completes or times out.

Parameters:

  • run_id (String) —

    the run ID to wait for

  • timeout (Integer) (defaults to: 60) —

    maximum seconds to wait (default: 60)

  • interval (Integer) (defaults to: 1) —

    seconds between polls (default: 1)

Returns:

Raises:

  • (Error) —

    if timeout is exceeded



275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/simple_acp/client/base.rb', line 275

def wait_for_run(run_id, timeout: 60, interval: 1)
  deadline = Time.now + timeout

  loop do
    run = run_status(run_id)
    return run if run.terminal?

    raise SimpleAcp::Error, "Timeout waiting for run to complete" if Time.now > deadline

    sleep(interval)
  end
end