agentic examples

Carrier Quotes

Carrier Quotes: the most common integration problem in commerce - ask three shipping carriers for rates, and cope with the fact that on any given afternoon one is slow, one is down, and one has quietly changed its response format. The confident-code answer: ALL defensiveness lives at the boundary. Each carrier adapter converts whatever happened - success, timeout, garbage - into an object with the same face (a Quote or an Unavailable), so the core that compares and chooses …

Reliability & Recovery Round 20 Avdi Grimm exit 0

source on github

bundle exec ruby examples/carrier_quotes.rb

a real captured run

CARRIER QUOTES (confidence is suspicion, spent once, at the door)

  an ordinary afternoon (one slow, one down, one confused):
    TurtleShip: $8.99 in 5d
    FedUp: unavailable (no answer within 50ms)
    ParcelPanic: unavailable (malformed response: [:cost, :eta])
    -> checkout shows: TurtleShip: $8.99 in 5d (2 carriers degraded, sale not lost)

  the apocalypse (every carrier asleep):
    -> checkout shows: FlatRate fallback: $12.0 in 7d (fallback: true - the store stays OPEN)

  the architecture in one sentence: quote_from is the only method
  allowed to be afraid. it converts every real-world outcome -
  timeout, schema drift, exception - into an object with the same
  FACE (available?, cents, to_s), so choose_rate reads like the
  business rule it is: pick the cheapest available, fall back to
  flat rate, never lose the sale. the degraded carriers keep their
  REASONS (ops will want them), the fan-out means the slow carrier
  never delays the fast one, and nil - the billion-dollar
  non-answer - is stopped at the door like it should be. timid
  code checks everything everywhere; confident code has a
  doorman.

source

# frozen_string_literal: true

# Carrier Quotes: the most common integration problem in commerce -
# ask three shipping carriers for rates, and cope with the fact that
# on any given afternoon one is slow, one is down, and one has
# quietly changed its response format. The confident-code answer:
# ALL defensiveness lives at the boundary. Each carrier adapter
# converts whatever happened - success, timeout, garbage - into an
# object with the same face (a Quote or an Unavailable), so the core
# that compares and chooses contains not one nil check, not one
# rescue, not one question mark it didn't want. Timid code asks
# "but what if?" at every line; confident code asks it ONCE, at the
# door.
#
#   bundle exec ruby examples/carrier_quotes.rb
#
# Runs offline; exits 1 unless checkout survives every weather.

require class="s">"bundler/setup"
require class="s">"agentic"

Agentic.logger.level = class="y">:fatal

Quote = Struct.new(class="y">:carrier, class="y">:cents, class="y">:days) do
  def available? = true

  def to_s = class="s">"#{carrier}: $#{cents / 100.0} in #{days}d"
end

Unavailable = Struct.new(class="y">:carrier, class="y">:reason) do
  def available? = false

  def cents = Float:class="y">:INFINITY

  def to_s = class="s">"#{carrier}: unavailable (#{reason})"
end

BUDGET = 0.05

# The carriers, as found in nature
CARRIERS = {
  class="s">"TurtleShip" => -> {
                    sleep(0.01)
                    {price_cents: 899, transit_days: 5}
                  },
  class="s">"FedUp" => -> {
               sleep(0.2)
               {price_cents: 1499, transit_days: 1}
             }, # asleep at the desk
  class="s">"ParcelPanic" => -> { {cost: class="s">"cheap!!", eta: class="s">"soon"} } # changed their API. again.
}.freeze

# The boundary: one adapter, all the suspicion in the file
def quote_from(carrier, raw_call)
  raw = nil
  thread = Thread.new { raw = raw_call.call }
  unless thread.join(BUDGET)
    thread.kill
    return Unavailable.new(carrier, class="s">"no answer within #{(BUDGET * 1000).round}ms")
  end
  cents = raw[class="y">:price_cents]
  days = raw[class="y">:transit_days]
  return Unavailable.new(carrier, class="s">"malformed response: #{raw.keys.inspect}") unless cents.is_a?(Integer) && days.is_a?(Integer)
  Quote.new(carrier, cents, days)
rescue => e
  Unavailable.new(carrier, class="s">"adapter caught: #{e.class}")
end

# The core: reads like the business rule it is. No nils survive to here.
def choose_rate(quotes)
  available = quotes.select(&class="y">:available?)
  return {choice: Quote.new(class="s">"FlatRate fallback", 1200, 7), degraded: quotes, fallback: true} if available.empty?
  {choice: available.min_by(&class="y">:cents), degraded: quotes.reject(&class="y">:available?), fallback: false}
end

def fetch_quotes(carriers)
  orchestrator = Agentic:class="y">:PlanOrchestrator.new(concurrency_limit: 3)
  tasks = carriers.to_h do |name, api|
    task = Agentic:class="y">:Task.new(description: name, agent_spec: {class="s">"name" => name, class="s">"instructions" => class="s">"quote"})
    orchestrator.add_task(task, agent: ->(_t) { quote_from(name, api) })
    [name, task]
  end
  result = orchestrator.execute_plan
  tasks.values.map { |t| result.task_result(t.id).output }
end

puts class="s">"CARRIER QUOTES (confidence is suspicion, spent once, at the door)"
puts

quotes = fetch_quotes(CARRIERS)
verdict = choose_rate(quotes)
puts class="s">"  an ordinary afternoon (one slow, one down, one confused):"
quotes.each { |q| puts class="s">"    #{q}" }
puts class="s">"    -> checkout shows: #{verdict[class="y">:choice]} (#{verdict[class="y">:degraded].size} carriers degraded, sale not lost)"
puts

apocalypse = fetch_quotes(CARRIERS.transform_values { -> { sleep(0.2) } })
end_times = choose_rate(apocalypse)
puts class="s">"  the apocalypse (every carrier asleep):"
puts class="s">"    -> checkout shows: #{end_times[class="y">:choice]} (fallback: #{end_times[class="y">:fallback]} - the store stays OPEN)"
puts

failures = []
failures << class="s">"wrong quote chosen" unless verdict[class="y">:choice].carrier == class="s">"TurtleShip" && verdict[class="y">:choice].cents == 899
failures << class="s">"degradation reasons lost" unless verdict[class="y">:degraded].map(&class="y">:reason).join.match?(/no answer/) && verdict[class="y">:degraded].map(&class="y">:reason).join.match?(/malformed/)
failures << class="s">"apocalypse broke checkout" unless end_times[class="y">:fallback] && end_times[class="y">:choice].cents == 1200
failures << class="s">"a nil escaped the boundary" if quotes.any?(&class="y">:nil?) || apocalypse.any?(&class="y">:nil?)

puts class="s">"  the architecture in one sentence: quote_from is the only method"
puts class="s">"  allowed to be afraid. it converts every real-world outcome -"
puts class="s">"  timeout, schema drift, exception - into an object with the same"
puts class="s">"  FACE (available?, cents, to_s), so choose_rate reads like the"
puts class="s">"  business rule it is: pick the cheapest available, fall back to"
puts class="s">"  flat rate, never lose the sale. the degraded carriers keep their"
puts class="s">"  REASONS (ops will want them), the fan-out means the slow carrier"
puts class="s">"  never delays the fast one, and nil - the billion-dollar"
puts class="s">"  non-answer - is stopped at the door like it should be. timid"
puts class="s">"  code checks everything everywhere; confident code has a"
puts class="s">"  doorman."
exit(failures.empty? ? 0 : 1)