agentic examples

The Etude Machine

The Etude Machine: deliberate practice for plan-builders. An etude is a small broken plan, a hint, and a hidden test - you fix the plan until the test passes, exactly like an exercism exercise. But the machine holds ITSELF to the practice-room standard before any student arrives: every etude's broken form must FAIL the hidden test (an exercise that passes before you touch it teaches nothing), every etude must carry a model solution that PASSES (unsolvable exercises are …

Testing & Verification Round 18 Katrina Owen exit 0

source on github

bundle exec ruby examples/etude_machine.rb

a real captured run

THE ETUDE MACHINE (scales before songs)

  1. The Missing Thread  (concepts: dependencies)
     hint: greet reads previous_output... from whom?
     broken form fails the hidden test: yes (as an exercise must)
     model solution passes:             yes (solvable, not hazing)

  2. The Swapped Hats  (concepts: dependencies, agents)
     hint: each agent is wearing the other's job description
     broken form fails the hidden test: yes (as an exercise must)
     model solution passes:             yes (solvable, not hazing)

  3. The Stubborn Courier  (concepts: dependencies, agents, retry_policy)
     hint: the courier fails TRANSIENTLY; the plan gives up permanently. one policy line.
     broken form fails the hidden test: yes (as an exercise must)
     model solution passes:             yes (solvable, not hazing)

  curriculum: 1 -> 2 -> 3 concepts per etude - each adds exactly one.

  the machine holds itself to the practice-room standard: every
  broken form FAILS (an exercise that passes before you touch it
  teaches nothing but false confidence), every etude ships a model
  solution that PASSES (unsolvable exercises aren't rigor, they're
  hazing), and difficulty climbs one concept at a time - thread a
  dependency, then assign the right agent, then write a retry
  policy. that ordering is the actual pedagogy: practice is only
  deliberate when the next rung is exactly one reach away, and
  the feedback - a hidden test with an exit code - arrives in
  seconds, not in code review three weeks later. fluency in a
  framework is built the same way as fluency in anything: small
  pieces, immediate feedback, rising difficulty, no free passes.

source

# frozen_string_literal: true

# The Etude Machine: deliberate practice for plan-builders. An etude
# is a small broken plan, a hint, and a hidden test - you fix the
# plan until the test passes, exactly like an exercism exercise. But
# the machine holds ITSELF to the practice-room standard before any
# student arrives: every etude's broken form must FAIL the hidden
# test (an exercise that passes before you touch it teaches
# nothing), every etude must carry a model solution that PASSES
# (unsolvable exercises are hazing), and difficulty must climb one
# concept at a time - scales before songs.
#
#   bundle exec ruby examples/etude_machine.rb
#
# Runs offline; exits 1 unless every etude fails broken, passes
# solved, and the curriculum climbs monotonically.

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

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

# Each etude: a builder that assembles the plan either :broken or
# :solved, a hidden test over the result, a hint, and the concepts
# the solution exercises (the difficulty score is their count)
ETUDES = [
  {
    title: class="s">"1. The Missing Thread",
    hint: class="s">"greet reads previous_output... from whom?",
    concepts: [class="y">:dependencies],
    test: ->(result, tasks) { result.task_result(tasks[class="y">:greet].id)&.output == class="s">"hello, world" },
    build: ->(mode) {
      orchestrator = Agentic:class="y">:PlanOrchestrator.new(concurrency_limit: 2)
      name = Agentic:class="y">:Task.new(description: class="s">"fetch name", agent_spec: {class="s">"name" => class="s">"n", class="s">"instructions" => class="s">"w"})
      greet = Agentic:class="y">:Task.new(description: class="s">"greet", agent_spec: {class="s">"name" => class="s">"g", class="s">"instructions" => class="s">"w"})
      orchestrator.add_task(name, agent: ->(_t) { class="s">"world" })
      deps = (mode == class="y">:solved) ? [name] : [] # the thread, missing
      orchestrator.add_task(greet, deps, agent: ->(t) { class="s">"hello, #{t.previous_output}" })
      [orchestrator, {name: name, greet: greet}]
    }
  },
  {
    title: class="s">"2. The Swapped Hats",
    hint: class="s">"each agent is wearing the other's job description",
    concepts: [class="y">:dependencies, class="y">:agents],
    test: ->(result, tasks) { result.task_result(tasks[class="y">:publish].id)&.output == class="s">"PUBLISHED: draft of 3 words" },
    build: ->(mode) {
      orchestrator = Agentic:class="y">:PlanOrchestrator.new(concurrency_limit: 2)
      write = Agentic:class="y">:Task.new(description: class="s">"write", agent_spec: {class="s">"name" => class="s">"w", class="s">"instructions" => class="s">"w"})
      publish = Agentic:class="y">:Task.new(description: class="s">"publish", agent_spec: {class="s">"name" => class="s">"p", class="s">"instructions" => class="s">"w"})
      writer = ->(_t) { class="s">"draft of 3 words" }
      publisher = ->(t) { class="s">"PUBLISHED: #{t.previous_output}" }
      first, second = (mode == class="y">:solved) ? [writer, publisher] : [publisher, writer]
      orchestrator.add_task(write, agent: first)
      orchestrator.add_task(publish, [write], agent: second)
      [orchestrator, {write: write, publish: publish}]
    }
  },
  {
    title: class="s">"3. The Stubborn Courier",
    hint: class="s">"the courier fails TRANSIENTLY; the plan gives up permanently. one policy line.",
    concepts: [class="y">:dependencies, class="y">:agents, class="y">:retry_policy],
    test: ->(result, tasks) { result.task_result(tasks[class="y">:deliver].id)&.output == class="s">"delivered on attempt 2" },
    build: ->(mode) {
      policy = (mode == class="y">:solved) ? {max_retries: 2, backoff_base: 0.005, retryable_errors: [Agentic:class="y">:Errors:class="y">:LlmRateLimitError]} : {max_retries: 0, retryable_errors: []}
      orchestrator = Agentic:class="y">:PlanOrchestrator.new(concurrency_limit: 1, retry_policy: policy)
      deliver = Agentic:class="y">:Task.new(description: class="s">"deliver", agent_spec: {class="s">"name" => class="s">"d", class="s">"instructions" => class="s">"w"})
      attempts = 0
      orchestrator.add_task(deliver, agent: ->(_t) {
        attempts += 1
        raise Agentic:class="y">:Errors:class="y">:LlmRateLimitError, class="s">"dog at the gate" if attempts == 1
        class="s">"delivered on attempt #{attempts}"
      })
      [orchestrator, {deliver: deliver}]
    }
  }
].freeze

puts class="s">"THE ETUDE MACHINE (scales before songs)"
puts

failures = []
difficulties = []
ETUDES.each do |etude|
  broken_result, broken_tasks = etude[class="y">:build].call(class="y">:broken).then { |o, t| [o.execute_plan, t] }
  solved_result, solved_tasks = etude[class="y">:build].call(class="y">:solved).then { |o, t| [o.execute_plan, t] }
  fails_broken = !etude[class="y">:test].call(broken_result, broken_tasks)
  passes_solved = etude[class="y">:test].call(solved_result, solved_tasks)
  difficulties << etude[class="y">:concepts].size

  puts class="s">"  #{etude[class="y">:title]}  (concepts: #{etude[class="y">:concepts].join(", class="s">")})"
  puts class="s">"     hint: #{etude[class="y">:hint]}"
  puts class="s">"     broken form fails the hidden test: #{fails_broken ? "yes (as an exercise must)class="s">" : "NO - free pass, worthlessclass="s">"}"
  puts class="s">"     model solution passes:             #{passes_solved ? "yes (solvable, not hazing)class="s">" : "NO - unsolvableclass="s">"}"
  puts
  failures << class="s">"#{etude[class="y">:title]} gives a free pass" unless fails_broken
  failures << class="s">"#{etude[class="y">:title]} is unsolvable" unless passes_solved
end

failures << class="s">"curriculum difficulty not monotonic: #{difficulties.inspect}" unless difficulties.each_cons(2).all? { |a, b| a <= b }

puts class="s">"  curriculum: #{difficulties.join(" -> class="s">")} concepts per etude - each adds exactly one."
puts
puts class="s">"  the machine holds itself to the practice-room standard: every"
puts class="s">"  broken form FAILS (an exercise that passes before you touch it"
puts class="s">"  teaches nothing but false confidence), every etude ships a model"
puts class="s">"  solution that PASSES (unsolvable exercises aren't rigor, they're"
puts class="s">"  hazing), and difficulty climbs one concept at a time - thread a"
puts class="s">"  dependency, then assign the right agent, then write a retry"
puts class="s">"  policy. that ordering is the actual pedagogy: practice is only"
puts class="s">"  deliberate when the next rung is exactly one reach away, and"
puts class="s">"  the feedback - a hidden test with an exit code - arrives in"
puts class="s">"  seconds, not in code review three weeks later. fluency in a"
puts class="s">"  framework is built the same way as fluency in anything: small"
puts class="s">"  pieces, immediate feedback, rising difficulty, no free passes."
exit(failures.empty? ? 0 : 1)