Skip to content

[Bug]: Span attributes record prompts and tool inputs even with prompt/context capture disabled #144

Open

Description

@jasoncarreira

Describe the bug

With prompt and model-context capture both off (OPENCODE_CAPTURE_PROMPT_IN_LOGS and OPENCODE_CAPTURE_MODEL_CONTEXT unset), spans still record prompt text and tool inputs. The README describes prompt logging as off by default. Today those flags only gate the prompt attribute on the user_prompt log event; nothing gates the span attributes.

In the published @devtheops/opencode-plugin-otel@2.1.0 dist/index.js:

  • handleToolCalled sets tool.parameters and input.value to safeJson(d.input) after the span is constructed, so it also overrides anything set through spanAttributes. For a subagent or task call, d.input includes the full subagent prompt.
  • handleExecutionStarted sets input.value and llm.input_messages to the session's prompt text.
  • handleStepStarted does the same for LLM spans.
  • Output text is also attached to spans without a content check.

Neither handler reads capturePromptInLogs / captureModelContext. The only way to keep prompt content out of exported telemetry is OPENCODE_DISABLE_TRACES, which drops the spans entirely.

Steps to reproduce

  1. Enable telemetry with both capture flags unset.
  2. Run a session that dispatches a subagent with a distinctive prompt.
  3. Inspect the exported opencode.tool.* span for the subagent call, and the opencode.session span. tool.parameters / input.value and llm.input_messages contain the prompt text.

We also reproduced it offline by running the published handleToolCalled body against an in-memory span sink with capturePromptInLogs: false and captureModelContext: false. Both input.value and tool.parameters contained the synthetic prompt. They still did when spanAttributes set those keys to empty strings, because the later setAttributes call wins.

Expected behavior

Prompt-bearing and content-bearing span attributes follow the same opt-in as prompt logging:

  • With content capture off: spans still emit, with structure, timings, token counts, tool name and agent name. Content attributes are omitted or replaced with lengths or hashes. That covers input.value, tool.parameters, llm.input_messages, and output values.
  • With content capture on: today's behaviour.

A single switch for span content, such as OPENCODE_CAPTURE_SPAN_CONTENT or reusing OPENCODE_CAPTURE_MODEL_CONTEXT, would work. Off by default would match the README's privacy stance.

Environment

  • @devtheops/opencode-plugin-otel 2.1.0
  • OpenCode 2.2.7 (@opencode/cli)
  • OTLP http/protobuf

Additional context

For now our deployment disables every trace type unless the operator opts in to content capture, keeping metrics and logs. We'd switch traces back on by default once spans can run content-free. We're also following #109; per-session trace context would let these spans nest under the calling service's trace.

Activity

  1. jasoncarreira commented on Nov 11, 2026

    @jasoncarreira
    Author

    The same applies to OTLP logs in 2.1.0, not only spans:

    • Session and tool failure summaries (errorSummary) concatenate the error type with the raw error.message, which is unrestricted text. They're emitted as log attributes, for example the session.error event and the tool result error attribute, and also written to the console.
    • Log emission is gated only by logsEnabled, not by the capture flags or disabledTraces.

    So the only way to keep content out of exported telemetry today is to disable both traces and logs and keep metrics only, which is what we've done.

    It would help if failure text followed the same content gate: with capture off, export the error type, a code and a hashed or length-only message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions