Initial public release v0.0.1.alpha2
Some checks failed
Test / test (3.2) (push) Failing after 9m43s
Test / test (3.3) (push) Failing after 9m43s
Test / test (3.4) (push) Failing after 9m42s

opencode-ruby — idiomatic Ruby client for OpenCode (HTTP + SSE).

Hand-rolled, opinionated Ruby SDK with block-form streaming, value-
object responses, and automatic SSE reconnection. Pluggable
Opencode::Instrumentation adapter for routing events to
ActiveSupport::Notifications, OpenTelemetry, stdout, or any custom
emitter. Companion to opencode-rails for AR-coupled Rails apps.

What this version ships:
  - Opencode::Client (Net::HTTP + SSE)
  - Opencode::Reply / Reply::Result / ReplyObserver
  - Opencode::Tracer, Opencode::Prompts
  - Opencode::ResponseParser, ToolPart, PartSource, Todo
  - Opencode::Instrumentation (instrument + notify)
  - Opencode::Error and seven subclasses
  - examples/conversation_recipe.rb — canonical Rails wiring blueprint

15 smoke tests. CI on Ruby 3.2/3.3/3.4.

Ruby >= 3.2. Runtime dep: activesupport >= 6.1, < 9.0.

See CHANGELOG.md for the alpha1 -> alpha2 delta.
This commit is contained in:
2026-05-20 21:41:30 -07:00
commit 889d38332f
24 changed files with 2616 additions and 0 deletions

50
lib/opencode/tracer.rb Normal file
View File

@@ -0,0 +1,50 @@
# frozen_string_literal: true
module Opencode
# A namespacing trace emitter.
#
# Opencode::Turn emits unprefixed event names like "response.started"
# and "session.recreated". The host product wraps Turn in a Tracer
# whose job is to prepend a product prefix and forward to whatever
# actually emits trace events (typically the host job's
# `EventTraceable#trace_event`).
#
# Two responsibilities live here, and only here:
#
# 1. Callable interface: `tracer.call(name, **payload)` — the
# contract Turn relies on.
# 2. Namespacing strategy: prepend "<prefix>." to every event name.
#
# A closure-based alternative that mixes both concerns looks like:
#
# tracer: ->(name, **payload) { trace_event("myapp.#{name}", **payload) }
#
# That closure conflates the two responsibilities; every caller has
# to rediscover the prefix-with-period rule, and a typo only shows up
# in production trace data. Making it a real role removes that risk
# and makes the rule visible in one place.
#
# Usage:
#
# Opencode::Tracer.new(prefix: "myapp", emitter: self)
#
# `emitter` must respond to `trace_event(name, **payload)`.
class Tracer
def initialize(prefix:, emitter:)
@prefix = prefix
@emitter = emitter
end
# Tracer is callable so existing call sites that treated the tracer
# as a lambda (`tracer.call(name, **payload)`) keep working without
# change. Turn uses this exclusively.
#
# Uses `send` because EventTraceable's `trace_event` is a private
# method of the including class — the convention is "private inside
# the job, but the substrate's Tracer is allowed to dispatch to it
# the same way the job's own perform method would."
def call(name, **payload)
@emitter.send(:trace_event, "#{@prefix}.#{name}", **payload)
end
end
end