agentic examples

A renga circle

A renga circle: three poet agents compose a linked-verse poem, each verse responding to the one before it. The dependency graph IS the poem's form - verse 2 cannot begin until verse 1 exists, and the orchestrator pipes each verse into the poet who answers it.

Plans & Graphs Round 2 Matz exit 0

source on github

bundle exec ruby examples/renga_circle.rb

a real captured run

  ~ a renga on "autumn wind" ~

  first light, autumn wind -
  the pond remembers
  last night's moon

  answering first:
  autumn wind paints the hillside
  in a brush of geese

  yes, geese - and yet
  even this autumn wind
  is home to someone small

  (completed in 108ms)

source

# frozen_string_literal: true

# A renga circle: three poet agents compose a linked-verse poem, each
# verse responding to the one before it. The dependency graph IS the
# poem's form - verse 2 cannot begin until verse 1 exists, and the
# orchestrator pipes each verse into the poet who answers it.
#
#   bundle exec ruby examples/renga_circle.rb
#
# Runs offline: each poet's craft is a lambda-backed capability.

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

STYLES = {
  class="s">"Basho" => ->(theme, previous) {
    previous ? class="s">"#{previous.split.last} lingers -\n#{theme} on the temple bell\na crow shakes off rain" : class="s">"first light, #{theme} -\nthe pond remembers\nlast night's moon"
  },
  class="s">"Buson" => ->(theme, previous) {
    class="s">"answering #{previous.split.first}:\n#{theme} paints the hillside\nin a brush of geese"
  },
  class="s">"Issa" => ->(theme, previous) {
    class="s">"yes, #{previous.split.last} - and yet\neven this #{theme}\nis home to someone small"
  }
}.freeze

# Each poet is an agent with a single "verse" capability
poets = STYLES.to_h do |name, craft|
  spec = Agentic:class="y">:CapabilitySpecification.new(
    name: class="s">"verse_#{name.downcase}",
    description: class="s">"Compose a linked verse in #{name}'s voice",
    version: class="s">"1.0.0",
    inputs: {
      theme: {type: class="s">"string", required: true},
      previous: {type: class="s">"string", description: class="s">"The verse being answered"}
    },
    outputs: {verse: {type: class="s">"string", required: true}}
  )

  provider = Agentic:class="y">:CapabilityProvider.new(
    capability: spec,
    implementation: ->(inputs) { {verse: craft.call(inputs[class="y">:theme], inputs[class="y">:previous])} }
  )
  Agentic.register_capability(spec, provider)

  poet = Agentic:class="y">:Agent.build do |a|
    a.name = name
    a.role = class="s">"Renga poet"
  end
  poet.add_capability(class="s">"verse_#{name.downcase}")

  [name, poet]
end

theme = ARGV.first || class="s">"autumn wind"
orchestrator = Agentic:class="y">:PlanOrchestrator.new

# The circle: each poet's task depends on the previous poet's, and the
# previous verse arrives through the dependency pipe - no shared state
tasks = []
%w[Basho Buson Issa].each do |name|
  task = Agentic:class="y">:Task.new(
    description: name,
    agent_spec: Agentic:class="y">:AgentSpecification.new(
      name: name, description: class="s">"Renga poet", instructions: class="s">"Compose one linked verse"
    ),
    payload: theme
  )

  orchestrator.add_task(task, tasks.empty? ? [] : [tasks.last], agent: ->(t) {
    previous = t.dependency_outputs.values.first
    poets[t.description].execute_capability(
      class="s">"verse_#{t.description.downcase}",
      {theme: t.payload, previous: previous}.compact
    )[class="y">:verse]
  })
  tasks << task
end

result = orchestrator.execute_plan

puts class="s">"  ~ a renga on \"#{theme}\class="s">" ~"
puts
tasks.each do |task|
  puts result.results[task.id].output.split(class="s">"\n").map { |line| class="s">"  #{line}" }
  puts
end
puts class="s">"  (#{result.status} in #{(result.execution_time * 1000).round}ms)"