Skip to content

fix(agents): gate tool-span I/O behind DATAPIZZA_TRACE_CLIENT_IO - #141

Open
antoniociccia wants to merge 1 commit into
datapizza-labs:mainfrom
antoniociccia:fix/gate-tool-span-io
Open

fix(agents): gate tool-span I/O behind DATAPIZZA_TRACE_CLIENT_IO#141
antoniociccia wants to merge 1 commit into
datapizza-labs:mainfrom
antoniociccia:fix/gate-tool-span-io

Conversation

@antoniociccia

Copy link
Copy Markdown

Problem

When an agent runs a tool, AgentRunner._execute_tool / _a_execute_tool attach the tool arguments and result to the tracing span unconditionally. Span attributes are the export surface of tracing: once the SDK's OTLP instrumentor is enabled (DATAPIZZA_OTLP_ENDPOINT), every span - tool spans included - is shipped to a remote collector via BatchSpanProcessor, carrying those attributes. So sensitive data a tool handles (file contents, DB rows, PII) is exported off-box.

Client I/O is already protected: core/clients/client.py gates input/output/memory span attributes behind DATAPIZZA_TRACE_CLIENT_IO (default false), and it's documented. Tool spans were simply not covered by the same gate.

Fix

Gate the two set_attribute("tool_arguments" / "tool_result", …) calls in both the sync and async tool executors behind the same existing DATAPIZZA_TRACE_CLIENT_IO flag (default off), via a small _trace_tool_io_enabled() helper. No new dependency, no public API change. The span attributes are pure observability - no code path reads them back (get_token_usage only reads type=="generation" spans), so control flow and the returned FunctionCallResultBlock are unchanged.

Scope / follow-up

The console log_panel output is intentionally left unchanged (different sink, developer UX). In containerized deployments stdout is often shipped to a persistent aggregator, so gating the console channel could be a sensible follow-up - kept out of this PR to stay minimal. Reusing the client flag also means enabling client-I/O tracing re-enables tool-I/O tracing; a separate DATAPIZZA_TRACE_TOOL_IO flag is an easy alternative if maintainers prefer.

Tests

Adds test_tool_span_privacy.py (9 tests, sync + async): default omits tool I/O from spans; =true/=TRUE includes it; non-true values (1) don't enable it; falsy results never set tool_result; and invariants that the return value and console output are preserved. Full agents+tracing suite: 93 passing.

Tool spans exported tool arguments and results unconditionally, so
sensitive data handled by tools (file contents, DB rows, PII) leaked to
trace exporters by default. Client I/O is already gated behind
DATAPIZZA_TRACE_CLIENT_IO in core/clients/client.py; tool spans were
simply not covered. Gate the two set_attribute calls in _execute_tool
and _a_execute_tool behind the same flag (default off). The console
log_panel output is intentionally left unchanged.

Adds sync+async regression tests and documents the flag's tool coverage.
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.

1 participant