e-volv
Contents

e-volv Berserker

Agent observability and evals. Any agent instrumented with OpenTelemetry sends its traces to one endpoint, and Berserker turns the GenAI spans into agent runs: one row per top-level agent span, with tokens, cost, tool calls, session and error. It works on its own; with e-volv Observer on the same workspace, a run sits beside the logs and error groups of the service that ran it.

Opt in. Berserker is opened per workspace while the first partners run it. Every workspace gets the free tier once it is on; see tiers and retention.

1. Create a project and a key

In the app, open Berserker, then Settings, and create a project for the service or agent. Its key is shown once. A key with the agents:write scope can send traces and nothing else; an existing Observer key with logs:write works too. Keys go in the Authorization: Bearer evk_… header.

2. Point your exporter at the endpoint

http
POST https://api.e-volv.io/api/public/v1/logs/otlp/v1/traces
Authorization: Bearer evk_...

OTLP over HTTP, JSON or protobuf, gzip welcome. The resource’s service.name picks the project within the key’s workspace.

OpenTelemetry collector

yaml
exporters:
  otlphttp/evolv:
    endpoint: https://api.e-volv.io/api/public/v1/logs/otlp
    headers:
      Authorization: Bearer ${env:EVOLVE_AGENTS_KEY}
    compression: gzip
service:
  pipelines:
    traces:
      exporters: [otlphttp/evolv]

Vercel AI SDK

Turn on the SDK’s telemetry per call; the functionId becomes the agent name.

typescript
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';

const result = await generateText({
  model: openai('gpt-4o'),
  prompt,
  experimental_telemetry: {
    isEnabled: true,
    functionId: 'support-reply', // becomes the agent name
    metadata: { sessionId, userId },
  },
});

and export the spans to Berserker:

typescript
// instrumentation.ts (Next.js) or your OTel bootstrap
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';

new NodeSDK({
  serviceName: 'support-bot',
  traceExporter: new OTLPTraceExporter({
    url: 'https://api.e-volv.io/api/public/v1/logs/otlp/v1/traces',
    headers: { Authorization: `Bearer ${process.env.EVOLVE_AGENTS_KEY}` },
  }),
}).start();

OpenAI Agents SDK

python
import os
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

provider = TracerProvider(resource=Resource.create({"service.name": "support-bot"}))
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
    endpoint="https://api.e-volv.io/api/public/v1/logs/otlp/v1/traces",
    headers={"Authorization": f"Bearer {os.environ['EVOLVE_AGENTS_KEY']}"},
)))
trace.set_tracer_provider(provider)

then add the openai-agents OpenTelemetry instrumentation as its own docs describe.

What is read

The OpenTelemetry GenAI semantic conventions (current and previous attribute names), the OpenInference vocabulary used by Arize Phoenix and the LangChain and LlamaIndex instrumentations, and the Vercel AI SDK’s own ai.* telemetry.

FactAttribute
Operationgen_ai.operation.name (invoke_agent, chat, execute_tool, embeddings), or openinference.span.kind, or the span name
Agentgen_ai.agent.name, gen_ai.agent.id
Provider and modelgen_ai.provider.name (older: gen_ai.system), gen_ai.request.model, gen_ai.response.model
Tokensgen_ai.usage.input_tokens, gen_ai.usage.output_tokens, and the cache_read and cache_creation variants
Toolgen_ai.tool.name
Session and usergen_ai.conversation.id, enduser.id
Prompt versionevolv.prompt.name, evolv.prompt.version

A run is the subtree under a top-level invoke_agent span, a Vercel ai.generateText root, or an OpenInference AGENT or CHAIN span. A bare chat span with no parent is a run of its own. Nested agents fold into the top-level run, so a session’s tokens are counted once. A root that arrives after its children is caught by a sweep every five minutes; a trace with GenAI spans and no root after an hour becomes an orphan run, so the spend is still counted.

Cost

Tokens are priced per model call from a maintained price list. A workspace that sets its own input and output price per million tokens on a model under Integrations is priced from that instead. Anthropic and Bedrock cache reads and writes are repriced at their cache rates; OpenAI-compatible providers report the discount in their own numbers.

Content

Prompt and completion content is off by default: the rollup reads only the facts above. Where an instrumentation sends gen_ai.input.messages and gen_ai.output.messages (or the older and OpenInference or Vercel equivalents), the run page shows it, cut at 32 KB, and the run can be replayed and saved as an eval fixture. Turning content on is a setting of your SDK or collector.

Runs without spans

An agent that cannot emit OpenTelemetry posts a summary to POST /api/public/v1/runs (scope runs:write) with tokensInput, tokensOutput, costUsd, sessionId and userId. The run appears with no tree.

Alerts

Three rule metrics read the runs: agent spend per day in dollars, agent run error rate in percent over a lookback (one hour by default), and agent run p95 duration in milliseconds over the same lookback. Each takes an optional agent name; without one the rule covers every agent in the workspace. They notify on the same channels as every other alert.

API

Under /api/workspaces/:wsId/logs/agents, with a signed-in session. Projects, sampling and usage live under /api/workspaces/:wsId/ai.

RouteReturns
GET overview?from&to&projectIdTotals, a time series, a per-agent table
GET runs?agent&status&model&sessionId&userId&limit&offsetRuns, newest first
GET runs/:traceIdThe run and its spans, each classified
GET sessions, GET sessions/:idConversations and their runs
GET cost?groupBy=agent|model|daySpend
POST runs/:traceId/replayRead-only replay through the eval harness (needs content)
POST runs/:traceId/fixtureSave the run as an eval fixture (needs content)

Next: evals, prompts or tiers and retention.