Add an @netscript/ai/otel adapter that maps GenAI/MCP calls to OTel GenAI (gen_ai.*) and MCP (mcp.*) semantic-convention spans via an injected TelemetryPort, without pulling telemetry into core.
Context
Part of epic #238 · cluster ENGINE · wave v1 · depends-on E1
E9 sits downstream of the core engine contract (E1) and is the single sanctioned exception to the "core has zero @netscript/* runtime deps" rule: it is scoped now so the port shape in E1 is designed with an observability seam from day one, rather than retrofitted after adapters/fresh-ai land.
Problem / motivation
@netscript/ai core has no tracing story, and the only prior art in-repo (eis-chat) has no GenAI/MCP semconv spans at all — calls are opaque in traces. Left unaddressed, either (a) adapters/providers each hand-roll ad-hoc spans with inconsistent attribute names, or (b) core absorbs a direct @netscript/telemetry dependency to "just wire it in," breaking the zero-dep core invariant every other @netscript/ai slice depends on. This slice closes that gap once, behind a port, so instrumentation is opt-in and centralized.
Scope
Ships
packages/ai/otel/mod.ts (or @netscript/ai ./otel subpath entry) exporting a TelemetryPort-conformant adapter, e.g. createOtelTelemetryAdapter(...).
- Span mapping for GenAI calls (
gen_ai.system, gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, etc.) sourced from the real usage event (per ratified usage decision), not estimated token counts.
- Span mapping for MCP tool/resource invocations (
mcp.tool.name, mcp.method.name, etc.) where core exposes MCP call boundaries.
- Import of
@netscript/telemetry confined to this subpath only.
- Wiring notes/tests showing the adapter satisfies the
TelemetryPort contract defined in E1.
Out of scope
- Defining the
TelemetryPort interface itself and the injection point in the engine — owned by E1.
- In-process vs. gateway execution modes — owned by the ENGINE slice(s) implementing
--gateway.
- Provider-specific span enrichment (e.g. Anthropic-only attributes) — owned by each provider subpath slice (e.g.
@netscript/ai/anthropic).
- fresh/ai or fresh-ui consumption of traces — out of this cluster entirely.
Public surface
- Subpath:
@netscript/ai/otel
- File:
packages/ai/otel/mod.ts (with @module JSDoc, <=20 exports)
- Primary export:
createOtelTelemetryAdapter(options): TelemetryPort (name may be finalized against E1's port signature, but must remain the sole factory export for this subpath)
- No changes to
@netscript/ai's root/core exports; core continues to accept TelemetryPort only as an injected dependency.
Acceptance & fitness gates
Dependencies
Depends on E1 (GitHub numbers tracked in the #238 DAG checklist). Not blocked by #239.
Size
M
Part of #238
Add an
@netscript/ai/oteladapter that maps GenAI/MCP calls to OTel GenAI (gen_ai.*) and MCP (mcp.*) semantic-convention spans via an injectedTelemetryPort, without pulling telemetry into core.Context
Part of epic #238 · cluster ENGINE · wave v1 · depends-on E1
E9 sits downstream of the core engine contract (E1) and is the single sanctioned exception to the "core has zero
@netscript/*runtime deps" rule: it is scoped now so the port shape in E1 is designed with an observability seam from day one, rather than retrofitted after adapters/fresh-ai land.Problem / motivation
@netscript/aicore has no tracing story, and the only prior art in-repo (eis-chat) has no GenAI/MCP semconv spans at all — calls are opaque in traces. Left unaddressed, either (a) adapters/providers each hand-roll ad-hoc spans with inconsistent attribute names, or (b) core absorbs a direct@netscript/telemetrydependency to "just wire it in," breaking the zero-dep core invariant every other@netscript/aislice depends on. This slice closes that gap once, behind a port, so instrumentation is opt-in and centralized.Scope
Ships
packages/ai/otel/mod.ts(or@netscript/ai./otelsubpath entry) exporting aTelemetryPort-conformant adapter, e.g.createOtelTelemetryAdapter(...).gen_ai.system,gen_ai.request.model,gen_ai.usage.input_tokens,gen_ai.usage.output_tokens, etc.) sourced from the real usage event (per ratified usage decision), not estimated token counts.mcp.tool.name,mcp.method.name, etc.) where core exposes MCP call boundaries.@netscript/telemetryconfined to this subpath only.TelemetryPortcontract defined in E1.Out of scope
TelemetryPortinterface itself and the injection point in the engine — owned by E1.--gateway.@netscript/ai/anthropic).Public surface
@netscript/ai/otelpackages/ai/otel/mod.ts(with@moduleJSDoc, <=20 exports)createOtelTelemetryAdapter(options): TelemetryPort(name may be finalized against E1's port signature, but must remain the sole factory export for this subpath)@netscript/ai's root/core exports; core continues to acceptTelemetryPortonly as an injected dependency.Acceptance & fitness gates
deno task arch:checkpasses; onlypackages/ai/otel/**imports@netscript/telemetry, verified by grep/arch:check../otelmod.ts has@moduleJSDoc and public-surface JSDoc; <=20 exports.packages/ai/otelpublishes viadeno task publish:dry-runWITHOUT--allow-slow-types.chars/4estimate.@netscript/aiwithout./otel) has zero transitive dependency on@netscript/telemetry(import-graph check).Dependencies
Depends on E1 (GitHub numbers tracked in the #238 DAG checklist). Not blocked by #239.
Size
M
Part of #238