The tool-call inspector
Arguments and results are the most useful thing in the trace and the most dangerous — the inspector needs a redaction model decided at the data layer, not a truncation applied in the view.
A reviewer clicks into a row and reads what the agent sent to a tool and what came back. This is the altitude where the panel stops summarising and starts showing evidence, and it is the reason anyone builds a trace view at all: a step list tells you the agent called update_record, and only the arguments tell you what it wrote and to which record.
It is also the surface with the entire privacy exposure of the system on it. Whatever the agent handled, this is where it appears in full: the customer’s address, the contract text, the credential a badly-written tool accepted as a parameter.
The instinct is to solve that in the inspector. Truncate long values, collapse a big object, mask anything that looks like a key. This lesson is the argument that none of that is redaction, and that the decision was already made one layer down whether or not anyone made it deliberately.
What the conventions actually say
Names first, dated, because this document moves. As read on 2026-09-05 from the main branch of open-telemetry/semantic-conventions-genai, which has no tagged release and is marked Status: Development — an execute-tool span requires gen_ai.tool.name and may carry gen_ai.tool.call.id, gen_ai.tool.type (which has no closed enum; function, extension and datastore are footnoted examples), and the two that matter here: gen_ai.tool.call.arguments and gen_ai.tool.call.result. Both are marked Opt-In.
Opt-In is the whole lesson in one word. It means the arguments and the result are not captured unless somebody turned them on where the telemetry is produced. The general policy the same document states for message content is the same shape: instrumentation “SHOULD NOT capture them by default, but SHOULD provide an option for users to opt in.”
Then the second control, which is the one people miss. The specification’s data-capture guidance says instrumentation “MAY provide a configuration option allowing to truncate properties,” and, of the hook it describes for modifying captured content, that “The hook SHOULD operate independently of the opt-in flags that control capturing” of that content. Two separate knobs, both on the instrumentation side, deliberately decoupled from each other.
Nothing in that document mentions a renderer. That is the point. By the time a payload reaches your component, both decisions — whether this content exists at all, and whether it was cut down — have already been taken somewhere else.
Why truncating in the view is not redaction
The argument that follows is this course’s own reasoning. The specification establishes only that capture and truncation are instrumentation-side concerns, independent of one another. It prescribes no redaction pattern — no masking, no hashing, no field-level allowlist — and a lesson that dressed one of those up as a standard would be inventing authority. What follows is three consequences that hold on their own.
The payload already left the process. If the value is in the span, it is in your collector, your backend and your retention window. A component that declines to draw it has changed what one person sees on one screen. It has not changed what was recorded, who can query it, or what appears in an export.
Altitude 04 exists. Your own component ships a raw payload view whose entire purpose is showing the unrendered records in the runtime’s own field names. A secret hidden at altitude 03 and visible at altitude 04 was never hidden; it was styled. The altitudes reference page states the rule in the form you will need when someone argues the other way: if that altitude can show a secret, the redaction was a view-layer truncation and therefore was not redaction.
Truncation cuts by length, and secrets are short. A thousand-character document body gets clipped. A forty-character API key passed as a tool argument survives every truncation rule you would plausibly write, because it is shorter than the limit. Length is uncorrelated with sensitivity, which makes truncation a readability feature that has been mistaken for a safety one.
Where people get burned
The specific way this bites: someone builds the inspector, adds a sensible 200-character clamp, and everyone in the review reads that clamp as the privacy story. Nobody says so out loud, so nobody checks it, and the component ships into a product where a tool takes a token as a parameter. The clamp is fine. Calling it redaction is what fails, and it fails silently, in a meeting, months before the consequence.
Three states the inspector has to distinguish
Once redaction moves to the data layer, the component inherits a different job, and it is a job it can actually do well. Empty is not one state. It is three, and they mean entirely different things to the person reading:
- Not captured. The Opt-In attribute was never turned on. Nothing about this run is known. The honest rendering names the reason, because the reader’s next action is a configuration change rather than an investigation.
- Redacted. The value existed, and a rule at the data layer removed or replaced it. The reader should be told that something was there and what class of thing it was, because a redaction is evidence and an absence is not.
- Genuinely empty. The tool takes no arguments, or returned nothing. A real fact about the run.
Collapsing those into one grey dash is the small dishonesty this component is most likely to ship, and it is the same failure as the green check on an Unset status: a state that means “nobody made a claim” rendered as a claim.
There is a fourth state that is not about privacy at all. Attribute values are constrained to strings, booleans, numbers and arrays of those, with no object type — so a structured argument arrives as a serialized string, and the parse can fail. A truncated JSON string is the common cause, which is where the two halves of this lesson meet: upstream truncation produces invalid JSON downstream. The inspector needs a state that shows the raw string and says it could not be parsed, rather than rendering nothing and letting the reader conclude the tool was called with no arguments.
What the inspector should actually do
Given all that, the inspector’s responsibilities are narrower than they first appear, and each one is achievable.
Render what it was given, completely, with the structure it has. Show the four empty states as four different things. Make the value copyable, because the real use of this altitude is pasting it somewhere else. And state the provenance of the content on screen — which attribute it came from, and that the attribute is Opt-In, so a reader looking at a blank panel knows whether they are looking at a quiet run or an unconfigured one.
What it must not do is imply a safety property it does not have. A “sensitive values hidden” label on a view-layer clamp is worse than no label, because it converts a readability decision into a promise.
Retrieval check
Your team decides tool arguments are too sensitive to show. Someone proposes the component filter out any argument key matching /token|secret|key|password/i before rendering. What does that get you, and what does it not?
Check your answer
It gets you a cleaner inspector and a reader who is less likely to read a credential by accident while debugging something else. That is worth having, and it is a view-layer feature honestly described.
It does not reduce exposure by one byte. The value is still in the span, still in the backend, still in the retention window, still in any export or query anyone runs, and still at altitude 04 in your own component unless you filtered there too — at which point altitude 04 no longer shows what the runtime emitted and has stopped being the layer that lets you catch an invented fact. The filter also misses every key that does not match the pattern, and matches keys that are not sensitive, both of which are unavoidable properties of guessing from names.
The version that changes the exposure sits where the specification puts it: capture is Opt-In, and the instrumentation is where a value is dropped or replaced before it becomes telemetry. The conventions describe a third pattern worth knowing about — store the content externally and reference it from the span — which turns “who can read this” into an access-control question with a real answer, and is recommended for production.
Hands on
Write the redaction model down, then make the component honest about it
Done when: ARTIFACT.md’s “Redaction model” section names what is redacted, at which layer it happens, and how the inspector distinguishes not-captured from redacted from empty from unparseable — and the component renders all four differently against your own captured payload.
- Check your captured payload for the two attributes by name. If
gen_ai.tool.call.argumentsandgen_ai.tool.call.resultare absent, that is the Opt-In default doing its job, and turning them on is the first thing to record inARTIFACT.md, with the date, because you are reading names off a document with no tagged release. - Write the redaction model as prose, in two columns: what gets removed, and where. Every row’s “where” should be the instrumentation or an ingest step. Any row that says “in the component” is a readability rule, and it belongs on a separate list with a heading that says so.
- Implement the four states. Not captured, redacted, empty, unparseable. Give each one different words, not different shades of grey. Then delete the attribute from a copy of your payload and confirm the panel says what happened rather than showing a blank.
- Test the parse-failure state on purpose by truncating a serialized argument mid-object. This is the case that will really happen, because upstream truncation is a documented instrumentation option, and it is the one nobody builds until they meet it.
- Add the provenance line: name the attribute the value came from, and say it is Opt-In. One line of text that turns “this panel is empty” into “this run was not configured to capture arguments,” which is the difference between a reader filing a bug and a reader changing a setting.
- Bring the two-column model into the chat, especially anything that landed in the readability column. The question worth answering out loud is what your component would do in a product where a tool takes a credential as a parameter, since that product exists and it is not the one you are testing against.
What this does not cover
The module ends here. You have four altitudes with a written assignment, a summary rule that survives a partial failure, a tree that does not lie about order, sameness or liveness, and an inspector that is honest about what it was and was not given.
Everything so far has rendered records of things that happened. What comes next renders claims: a sentence the agent produced, a source it says supports that sentence, and a number it offers as its own confidence. Those are a different kind of object, they fail in different ways, and the failures have actually been measured. The citations and confidence module opens with inline anchors and hover previews, on the problem of letting a reader check a source without leaving the page.
This lesson also left access control alone entirely. Who may open the inspector, and whether altitude 04 is reachable at all in a given product, are product decisions rather than component ones, and a course about rendering traces is the wrong place to pretend otherwise.
Read this next — primary source
Semantic conventions for generative AI spansThe OpenTelemetry Authors / CNCF — the specification itself, not a vendor. Free. Retrieved 2026-09-05 from the main branch of open-telemetry/semantic-conventions-genai, which carries no tagged release and is marked Status: Development.
This lesson takes two things from it: that tool arguments and results are Opt-In attributes, and that truncation is a separate instrumentation-side control from capture. The document is worth reading in full for the section around them, “Capturing instructions, inputs, and outputs”, which lays out three named patterns — record nothing, record on spans, or store externally and reference — and recommends the third for production. Reading those three side by side is the fastest way to see that the interesting decisions in this area were all made before any renderer existed. Read it with the Development badge in view: every attribute name on the page is a name that has already moved once, and this document has no release to pin to.
Stuck, curious, or think this lesson is wrong? Ask your teaching agent. The lessons are the scaffold; the conversation is where the learning gets unstuck.