Documentation
¶
Overview ¶
Package middleware provides the tracing and metrics of agent runs, which plug into an agent with agent.WithMiddleware, and the types other middleware builds on. Tracing and metrics follow the OpenTelemetry GenAI semantic conventions without depending on OpenTelemetry; the github.com/nostosx/agentx-contrib/otel module adapts them, and github.com/nostosx/agentx-contrib/middleware provides logging and retries.
For model calls outside the agent loop, such as the model of a actx.Summarize strategy, the package also provides plain decorators: TraceModel and MeterModel wrap a model.Model, and TraceTools and MeterTools are tool.Middleware.
Index ¶
- func AddEvent(ctx context.Context, name string, attrs ...Attr)
- func ErrorType(err error) string
- func MarkCompacted(ctx context.Context, run *loop.Run)
- func MeterTools(m Meter, opts ...MetricsOption) tool.Middleware
- func Metrics(m Meter, opts ...MetricsOption) loop.Middleware
- func RecordSpanError(span Span, err error)
- func TraceTools(t Tracer, opts ...TraceOption) tool.Middleware
- func Tracing(t Tracer, opts ...TraceOption) loop.Middleware
- func Wrap(m model.Model, mws ...Model) model.Model
- type Attr
- type EventSpan
- type Float64Histogram
- type Funcs
- type Instrument
- type Int64Counter
- type Int64Histogram
- type Meter
- type MetricsOption
- type Model
- type NoopMeter
- type NoopTracer
- type Span
- type SpanKind
- type TraceOption
- type Tracer
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ErrorType ¶
ErrorType returns the low-cardinality error.type the spans and metrics of this package record for err: "timeout", "canceled", the provider's error type or HTTP status code, "panic" or "_OTHER". Middleware that records errors, such as retries, uses it to stay consistent.
func MarkCompacted ¶
MarkCompacted records that run compacted its conversation; ctx must belong to the run. Its later model spans carry gen_ai.conversation.compacted.
func MeterTools ¶
func MeterTools(m Meter, opts ...MetricsOption) tool.Middleware
MeterTools records gen_ai.execute_tool.duration for each tool call.
func Metrics ¶
func Metrics(m Meter, opts ...MetricsOption) loop.Middleware
Metrics returns runtime middleware that records the metrics described at Meter for each run and its model and tool calls.
Register it after Tracing, so measurements carry the spans, and before retries, so a model call's duration includes them.
func RecordSpanError ¶
RecordSpanError records err on span with a low-cardinality error.type, as the spans of this package do.
func TraceTools ¶
func TraceTools(t Tracer, opts ...TraceOption) tool.Middleware
TraceTools records a span for each tool call.
func Tracing ¶
func Tracing(t Tracer, opts ...TraceOption) loop.Middleware
Tracing returns runtime middleware that records an invoke_agent span for each run, with the spans of TraceModel and TraceTools as its children. The spans carry the agent name, the session ID as gen_ai.conversation.id, the run ID and the turn.
The run's context carries the tracer, so hooks and compaction add their spans with StartSpan, and a sub-agent traced the same way nests under the execute_tool span that runs it.
Types ¶
type EventSpan ¶
EventSpan is a Span that records events. Spans that do not implement it drop the events of this package, such as the retries of a model call.
type Float64Histogram ¶
Float64Histogram records a distribution of floats.
type Funcs ¶
type Funcs struct {
Next model.Model
GenerateFunc func(ctx context.Context, req *model.Request) (*model.Response, error)
StreamFunc func(ctx context.Context, req *model.Request) iter.Seq2[*model.StreamEvent, error]
}
Funcs builds a model from functions. A nil function delegates to Next, and Describe reports Next's description.
func (*Funcs) Describe ¶
func (f *Funcs) Describe() model.Description
Describe implements model.Describer.
type Instrument ¶
type Instrument struct {
Name string
Description string
// Unit is a UCUM unit, such as "s" or "{token}".
Unit string
// Buckets are the explicit bucket boundaries the conventions advise for
// a histogram. Adapters may ignore them.
Buckets []float64
}
Instrument describes a metric instrument.
type Int64Counter ¶
Int64Counter adds to a monotonic sum.
type Int64Histogram ¶
Int64Histogram records a distribution of integers.
type Meter ¶
type Meter interface {
Int64Counter(Instrument) Int64Counter
Int64Histogram(Instrument) Int64Histogram
Float64Histogram(Instrument) Float64Histogram
}
Meter creates metric instruments. Adapt OpenTelemetry or another metrics library to it; agentx itself has no metrics dependency. Implementations and their instruments must be safe for concurrent use. The context of a measurement holds the span of the measured operation, for exemplars.
Metrics and MeterModel record these instruments of the OpenTelemetry GenAI semantic conventions (https://github.com/open-telemetry/semantic-conventions-genai):
- gen_ai.client.inference.duration (s), and for streaming calls gen_ai.client.inference.time_to_first_chunk and gen_ai.client.inference.time_per_output_chunk;
- the gen_ai.client.inference.usage.input_tokens, .output_tokens, .cache_read.input_tokens, .cache_write.input_tokens and .reasoning.output_tokens counters, with gen_ai.token.modality "unknown", as providers do not break usage down by modality;
- the gen_ai.client.inference.operation.input_tokens and .output_tokens histograms;
- gen_ai.execute_tool.duration (s), whose count is the number of tool calls;
- gen_ai.invoke_agent.duration (s), with agentx.run.status, and the gen_ai.invoke_agent.inference_calls and .tool_calls histograms, which count only a run's own calls, not those of its sub-agents.
Model metrics carry gen_ai.operation.name, gen_ai.provider.name, gen_ai.request.model, gen_ai.response.model and server.address and server.port; run and tool metrics carry gen_ai.agent.name. Failed operations add error.type as spans do.
type MetricsOption ¶
type MetricsOption func(*metricsConfig)
MetricsOption configures metrics.
func LegacyMetrics ¶
func LegacyMetrics() MetricsOption
LegacyMetrics also records the model metrics that earlier releases of the conventions defined and the current ones replaced, for dashboards that still query them: the gen_ai.client.token.usage histogram, with gen_ai.token.type "input" or "output", and gen_ai.client.operation.duration.
type Model ¶
Model wraps a model.Model.
func MeterModel ¶
func MeterModel(m Meter, opts ...MetricsOption) Model
MeterModel records the model metrics described at Meter for each call.
func TraceModel ¶
func TraceModel(t Tracer, opts ...TraceOption) Model
TraceModel records a span for each model call. The provider, operation and default model come from the model's model.Describer.
type NoopMeter ¶
type NoopMeter struct{}
NoopMeter discards measurements.
func (NoopMeter) Float64Histogram ¶
func (NoopMeter) Float64Histogram(Instrument) Float64Histogram
Float64Histogram implements Meter.
func (NoopMeter) Int64Counter ¶
func (NoopMeter) Int64Counter(Instrument) Int64Counter
Int64Counter implements Meter.
func (NoopMeter) Int64Histogram ¶
func (NoopMeter) Int64Histogram(Instrument) Int64Histogram
Int64Histogram implements Meter.
type Span ¶
type Span interface {
SetAttributes(attrs ...Attr)
// RecordError records err and marks the span as failed: adapters should
// set the span status to error.
RecordError(err error)
End()
}
Span is an in-progress trace span.
func SpanFromContext ¶
SpanFromContext returns the innermost span the tracing of this package started in ctx, or a span that discards everything.
func StartSpan ¶
func StartSpan(ctx context.Context, name string, kind SpanKind, attrs ...Attr) (context.Context, Span)
StartSpan starts a span with the tracer of the run ctx belongs to, as installed by Tracing, for work done inside the run, such as hooks. Without such a tracer it returns ctx and a span that discards everything.
type TraceOption ¶
type TraceOption func(*traceConfig)
TraceOption configures tracing.
func RecordContent ¶
func RecordContent() TraceOption
RecordContent records the content of model and tool calls: the system prompt, messages and tool names of model calls and runs (gen_ai.system_instructions, gen_ai.input.messages, gen_ai.output.messages and gen_ai.tool.definitions, as JSON strings), and the arguments and results of tool calls (gen_ai.tool.call.arguments and gen_ai.tool.call.result). They may contain sensitive data and can be large, so the conventions make them opt-in.
type Tracer ¶
type Tracer interface {
Start(ctx context.Context, name string, kind SpanKind, attrs ...Attr) (context.Context, Span)
}
Tracer starts spans. Adapt OpenTelemetry or another tracing library to it; agentx itself has no tracing dependency.
Spans follow the OpenTelemetry GenAI semantic conventions (https://github.com/open-telemetry/semantic-conventions-genai):
- "invoke_agent {agent}" (internal) covers a run of the agent loop;
- "{operation} {model}" (client), such as "chat gpt-6-astra", covers a model call;
- "execute_tool {tool}" (internal) covers a tool call. A sub-agent run by agent.AsTool is a child of its execute_tool span.
Work the conventions do not cover gets agentx spans: "hook {event}" for the hooks of a lifecycle event and "compact_context" for an automatic compaction. Retries of a model call are "agentx.retry" events.
Attributes use the gen_ai.* names of the conventions, plus agentx.run_id, agentx.turn and agentx.run.status. The span of an agent a run was handed off to has agentx.handoff.from, the agent that handed it off; a run that a guardrail blocked has agentx.guardrail.name and agentx.guardrail.kind and an "agentx.guardrail" event, which also holds the guardrail's message when content is recorded. A failed operation sets error.type to the provider's error code, "timeout", "canceled", "panic", "tool_error" for a tool that returned an error result, or "_OTHER".