Documentation
¶
Overview ¶
Package agent adapts Agent Framework events to the official OpenTelemetry tracing and metrics APIs. The Agent Kernel does not import OpenTelemetry.
Each Process activation is an in-process invoke_agent span named after its Deployment, with matching gen_ai.invoke_agent.duration. A restored activation starts a new observation interval; the process activation attribute separates it from an initial invocation. Process IDs remain runtime attributes, not stable gen_ai.agent.id values. Model selection stays at the model boundary. Durable Process, Step, and Effect spans are keyed by the active incarnation, so overlapping old and restored instances never share span ownership. Effect spans and dropped-Delta events carry the Engine's physical AttemptID. Replays keep the logical EffectID and receive a fresh AttemptID. Unknown resolution is a Process event with the definite settlement, not another invocation or an extension of the original duration. These identities never become metric dimensions.
Register an Observer as an Engine EventListener and wrap each Deployment's Dispatcher with Observer.WrapDispatcher to make downstream model and tool spans children of their Effect span. Close the Engine before the Observer. Wrap the selected TreeCommitter with Observer.WrapTreeCommitter to observe protocol acknowledgment duration, proposed snapshot bytes, and conflict or unresolved outcomes. This integration does not select storage, read heads, infer rollback, or measure the age of stored state.
Failed invocations use the declared Failure code as error.type. Other error
terminations use agent.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var (
ErrInvalidObserverConfig = errors.New("agent otel: invalid observer configuration")
)
Functions ¶
This section is empty.
Types ¶
type Observer ¶
type Observer struct {
// contains filtered or unexported fields
}
Observer projects immutable Framework Event facts into OpenTelemetry spans and metrics. It implements agent.EventListener and is safe for concurrent calls. Observer never receives Process behavior or application state. Observer values must be constructed with NewObserver and must not be copied after first use.
func NewObserver ¶
func NewObserver(config ObserverConfig) (*Observer, error)
NewObserver wraps instrument construction failures with ErrInvalidObserverConfig. Export failures remain with the providers and never change Agent state.
func (*Observer) Close ¶
func (o *Observer) Close()
Close prevents new observation, waits for callbacks already in flight, and then ends any incomplete spans. It is safe to call concurrently and is idempotent; normally Engine.Close leaves no incomplete Process spans.
func (*Observer) WrapDispatcher ¶ added in v0.15.0
func (o *Observer) WrapDispatcher(next agent.Dispatcher) (agent.Dispatcher, error)
WrapDispatcher propagates the observed Effect span into downstream calls. Register this same Observer as an Engine EventListener: the Engine publishes EffectStarted before dispatch and EffectFinished after dispatch returns. Without an active observed Effect, the caller's context passes through. The returned decorator preserves replay policy, settlement, and Delta delivery.
func (*Observer) WrapTreeCommitter ¶ added in v0.32.0
func (o *Observer) WrapTreeCommitter(next agent.TreeCommitter) (agent.TreeCommitter, error)
WrapTreeCommitter observes the existing port so instrumentation cannot select a different commit or fencing path. Metric labels stay bounded to avoid one time series per tree; identities belong only in traces. Adapter diagnostics are excluded because they can contain credentials or payloads. An error other than an explicit conflict remains unresolved because a lost response cannot prove whether storage committed.
Example ¶
package main
import (
"context"
"fmt"
agent "github.com/Tangerg/scope/agent"
agentotel "github.com/Tangerg/scope/otel/agent"
)
func main() {
observer, err := agentotel.NewObserver(agentotel.ObserverConfig{})
if err != nil {
panic(err)
}
defer observer.Close()
committer, err := observer.WrapTreeCommitter(agent.NewMemoryTreeCommitter())
if err != nil {
panic(err)
}
engine, err := agent.NewEngine(agent.EngineConfig{
TreeCommitter: committer,
EventListeners: []agent.EventListener{observer},
})
if err != nil {
panic(err)
}
if err := engine.Close(context.Background()); err != nil {
panic(err)
}
fmt.Println("committer observation configured")
}
Output: committer observation configured
type ObserverConfig ¶
type ObserverConfig struct {
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
}
Nil providers use the corresponding OpenTelemetry global providers.