Copilot Chat OTel exports tool call arguments/results (terminal output, file contents) to OTLP regardless of captureContent
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
### Environment
- VS Code `1.128.0`
- Copilot Chat extension `v0.56.0`
- OTLP export to Datadog (`http/protobuf`)
- macOS
### Summary
The VS Code Copilot Chat extension exports **tool call inputs and outputs** — `gen_ai.tool.call.arguments` and `gen_ai.tool.call.result` — to the configured OTLP endpoint **unconditionally**, with no `captureContent` gating. In agent mode this includes the full `run_in_terminal` command **and its terminal output**, file read/write contents, and MCP tool I/O. This means prompts/secrets/file contents can flow to a third-party observability backend even when content capture is disabled.
This is closely related to #307407 (which covers `input.messages` / `output.messages` / `system_instructions` / `user_request` / `reasoning_content`) and its proposed fix microsoft/vscode-copilot-chat#4938. **That fix does not address the tool-call attributes**, so this is filed separately to track the remaining, higher-risk gap.
### Affected code (post-merge into core)
- `extensions/copilot/src/extension/intents/node/toolCallingLoop.ts`
- `extensions/copilot/src/extension/prompt/node/chatMLFetcher.ts`
The content attributes are set on the span gated only on the span existing, not on `captureContent`; because `ReadableSpan` is immutable, downstream exporters cannot strip them.
### Steps to reproduce
1. Enable Copilot OTel export to an OTLP endpoint (e.g. an OpenTelemetry Collector with debug logging, or Datadog), with `captureContent` **false** (the default).
2. In VS Code Copilot Chat **Agent mode**, ask it to run a shell command, e.g. *"Run `whoami && pwd` in the terminal."*
3. Inspect the exported span for the `execute_tool run_in_terminal` operation.
### Expected
With `captureContent=false`, no user/tool content is exported — only metadata (tool name, timing, tokens).
### Actual
The exported span contains:
- `gen_ai.tool.call.arguments` — the full command (`whoami && pwd`)
- `gen_ai.tool.call.result` — the full terminal output (username, working directory)
With real usage this includes file contents (via read/edit tools), infrastructure identifiers, and any credentials/tokens printed to the terminal — all verbatim in the observability backend.
### Impact
This is a **blocker for enterprise OTel adoption**. Tool results are one of the highest-sensitivity surfaces: terminal output and file contents routinely contain secrets, PII, and proprietary code. An organization cannot enable OTel export while this data is transmitted regardless of `captureContent`. Gating the message attributes alone (#307407 / https://github.com/microsoft/vscode-copilot-chat/pull/4938) is necessary but **not sufficient**.
### Scope — what works
We tested the **Copilot CLI** (Rust agent host) both standalone and running inside VS Code's Copilot (select Copilot CLI as the session location instead of Local): both are **content-clean** (metadata only). The issue is specific to the **VS Code Chat extension** OTel instrumentation, in **both Ask and Agent mode**.
### Requested fix
Gate `gen_ai.tool.call.arguments` and `gen_ai.tool.call.result` (and `gen_ai.tool.definitions` descriptions) behind `captureContent`, consistent with the message-attribute fix — or strip them at the exporter level so `captureContent=false` guarantees no content reaches OTLP.
Contributor guide
Assessment
This issue has not been assessed yet.