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.
51 lines
1.8 KiB
Ruby
51 lines
1.8 KiB
Ruby
# 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
|