Skip to content

feat(otel): OpenTelemetry for a2a-* + shared mock-ollama cookout - #52

Merged
shashikanth-gs merged 13 commits into
mainfrom
otel
Oct 15, 2026
Merged

shashikanth-gs merged 13 commits into
mainfrom
otel

Conversation

@shashikanth-gs

@shashikanth-gs shashikanth-gs commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

What and why

Introduces optional OpenTelemetry (OTel) tracing across @a2a-wrapper/core and all five a2a-* wrappers (a2a-claude, a2a-codex, a2a-copilot, a2a-opencode, a2a-antigravity), plus a shared fake Ollama (mock-ollama) for local zero-cloud-key verification and Phoenix cookouts.

Key Capabilities

  • Core OTel Bridge (Hook A & E): Emits a2a.task.execute spans per inbound A2A request, tagging gen_ai.conversation.id, gen_ai.agent.name, gen_ai.agent.id, session.id, a2a.task.id, and a2a.message.id.
  • Anti-Double-Counting Token Accounting: When backend OTel is active (Hook F), the wrapper suppresses gen_ai.usage.* on parent spans to avoid double counting vendor LLM spans, emitting a2a.task.usage.* rollups instead. If backend OTel is off, the wrapper promotes rollups to gen_ai.usage.* (including input, output, cache, and reasoning tokens).
  • Backend Passthrough (Hook F): Injects W3C traceparent / tracestate into:
    • Claude Code CLI subprocess (CLAUDE_CODE_ENABLE_TELEMETRY=1, TRACEPARENT, TRACESTATE)
    • Copilot SDK via onGetTraceContext
    • Codex SDK via configOverrides.otel
  • Multi-Turn Turn Correlation: Correlates retries and resumptions via stable conversation/session IDs and OTel span links (a2a.task.prior_invocation) instead of creating artificial infinite parent spans.
  • CLI Bootstrap: Optional dynamic import of @opentelemetry/sdk-node and OTLP exporters when otel.enabled is configured; keeps core lightweight with zero hard dependencies on OTel SDK.
  • Shared mock-ollama Cookout: Reusable LLM stub under examples/mock-ollama providing OpenAI Responses API and Anthropic Messages API endpoints for local OTel testing without external keys or GPUs.

Packages touched

  • @a2a-wrapper/core
  • a2a-claude / a2a-codex / a2a-copilot / a2a-opencode / a2a-antigravity
  • examples / docs only

Checklist

  • npm run build && npm test pass
  • Added a changeset (npm run changeset) if a published package changed
  • Updated docs / README if behaviour or config changed

cursoragent and others added 11 commits October 10, 2026 18:02
Add optional peer @opentelemetry/api and core hooks so createA2AServer
wraps executors with a2a.task.* spans. Hosts register TracerProvider /
OTLP exporters; without them instrumentation is a no-op.

Align factory A2AExecutor with executor/types so instrumentExecutor
typechecks. Ship OSS docs/observability.md (not research notes).

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Hook E applies task usage to a2a.task.execute as a2a.task.usage.* always,
and gen_ai.usage.* only when backend OTel is off — so Copilot/Claude/Codex
LLM spans do not double-count with the parent in Tempo SUMs.

Also adds createExecutionObservability (Hook B), session span attrs,
injectW3cTraceHeaders, wires Copilot/Antigravity, migrates all wrappers,
and documents the anti-dupe rules.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Default model is ~99% one a2a.task.execute per inbound request — not a
multi-span factory. When the orchestrator calls again (resume/retry),
still one new span with the same conversation/task ids plus
a2a.task.invocation(_kind) and a2a.message.id for platform joins.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Wire Copilot telemetry + onGetTraceContext, Claude subprocess OTel/TRACEPARENT,
and Codex otel configOverrides via core helpers. Activate real OTel context in
withSpan so parent-link works. Document OpenCode/Antigravity limits.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
createCli dynamically bootstraps NodeSDK when otel.exporter.endpoint is set
(optional peers). Continue/retry invocations get span links. Ship
examples/otel-stack (Jaeger OTLP) and fix withSpan not to re-run on errors.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Document who owns which attrs vs draft GenAI A2A #254. Stamp
gen_ai.operation.name, session.id, a2a.method.name, and a2a.gateway.* from
orchestrator metadata. Claude/Codex now apply per-request usage rollups.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Drop the Jaeger-required compose stack for a lightweight Arize Phoenix
demo (pip/uv; optional Docker). CLI bootstrap defaults to OTLP protobuf
(`exporter-trace-otlp-proto`) so Phoenix ingest works.

Stamp a2a.wrapper.core.version plus a2a.wrapper.sdk / .sdk.version on
task spans and wire every wrapper server with its package identity.

Add otel.taskUsageRollup (default on) and otel.annotateUsageCalls
(default off; Claude/Codex call applyUsageCallToActiveSpan). Verified
live against phoenix serve in this environment.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Add examples/otel-stack/smoke-providers.mjs that drives a2a-copilot and
a2a-claude executors under instrumentExecutor against a live Phoenix
collector. Backends are faked (this environment has no Copilot policy
access / Claude login); wrapper spans still show sdk identity + usage.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Add a fake Ollama (OpenAI Responses + Anthropic Messages) and cookout-byok
that boots real a2a-copilot / a2a-claude CLIs against it into Phoenix — no
cloud keys or GPU. Wire bootstrapOtelSdkFromConfig into all hand-rolled
wrapper CLIs (they were skipping SDK start) and use SimpleSpanProcessor
for reliable short-lived export.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
Move the fake Ollama stub out of otel-stack into examples/mock-ollama so
any feature can cook out against real a2a-copilot / a2a-claude without
cloud keys. OTel cookout now layers Phoenix config on those shared agents.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
cursoragent and others added 2 commits October 11, 2026 09:23
Common settings stay on otel.*; Hook F knobs are only otel.backend.<this
package>. OpenCode schema no longer lists Codex/Claude/Copilot backends
(and peers). Regenerated agent-config.schema.json for all wrappers.

Co-authored-by: Shashi Kanth G S <shashikanth-gs@users.noreply.github.com>
@shashikanth-gs
shashikanth-gs marked this pull request as ready for review October 15, 2026 23:20
@shashikanth-gs
shashikanth-gs merged commit a2bfdd2 into main Oct 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants