Skip to content

feat: add search filter to agent tracer @W-22434499@#207

Merged
marcelinollano merged 2 commits into
mainfrom
ml/w-22434499-tracer-filtering
May 14, 2026
Merged

feat: add search filter to agent tracer @W-22434499@#207
marcelinollano merged 2 commits into
mainfrom
ml/w-22434499-tracer-filtering

Conversation

@marcelinollano
Copy link
Copy Markdown
Collaborator

@marcelinollano marcelinollano commented May 13, 2026

What does this PR do?

Adds a live search input under the tabs in the Agent Tracer panel so PMs and engineers can find specific events in long traces. The query matches against userMessage, sessionId, planId, step display names (e.g. "Action Executed", "Reasoning"), and stringified step content (so any value buried in a step's JSON is searchable).

When the query matches an entry's metadata (userMessage / sessionId / planId), all steps in that entry remain visible to preserve full context. Otherwise only matching steps are shown inside the entry's timeline, and entries with zero matches are hidden entirely. The counter reports matched steps out of total steps across all visible entries.

Also fills in display names and icons for OutputEvaluationStep and BeforeReasoningIterationStep, and renames ReasoningStep's display name from "Output Evaluation" to "Reasoning" (the previous mapping had two step types pointing at the same label).

What issues does this PR fix or reference?

@W-22434499@

Functionality Before

No way to filter the trace history. PMs had to expand each entry and scroll through every step to find a specific event type, variable, or function call.

Functionality After

A search input sits under the tabs when the tracer is selected. Typing live-filters the visible entries and steps; an "X of Y" counter shows matched steps out of total steps; an × button clears the query. Entries that do not match are hidden; inside a matching entry, only matching steps appear unless the query matched the entry's metadata (in which case all steps stay visible).

Testing Setup Notes

Automated

  • npx jest --config jest.config.webview.js test/webview/AgentTracer — 100 passing tests across AgentTracer.test.tsx and AgentTracer.helpers.test.tsx. New coverage:
    • Helper unit tests for entryMetadataMatches, stepMatchesFilter, and buildTimelineItems with a filter argument
    • Component tests for filtering by userMessage / sessionId / planId / step content / step display name
    • Counter behavior (matched steps vs. total steps, hidden when filter is empty)
    • Step-level visibility in the rendered DOM
    • Clear-button behavior
  • npx jest --config jest.config.webview.js — 424 passing tests across 22 suites (no regressions).

Manual verification

  1. Build and launch:

    npm run build && code .

    Press F5 to launch the Extension Development Host.

  2. Open the Agentforce DX side panel, select an agent, and start a session. Send a few messages so multiple traces are recorded.

  3. Switch to the Agent Tracer tab. Confirm a search input is visible directly under the tabs (no top margin, padding/border-radius matches the agent selector style).

  4. Type part of a user message (e.g. weather). The list narrows to entries whose userMessage contains "weather"; all steps inside the matching entry remain visible. The counter shows N of M matched steps.

  5. Clear the input and type part of a step type (e.g. reasoning). Entries that contain a Reasoning step remain, but inside each entry only the Reasoning steps appear; other step types are hidden.

  6. Type a value you know exists in step JSON (e.g. an account id, a function name, a variable name). Confirm only the steps containing that value are shown.

  7. Type a sessionId or planId substring (visible in the expanded entry's info table). Confirm only the matching entry remains and all of its steps stay visible.

  8. Type a string that doesn't exist (e.g. xyz_no_match). Confirm the empty-state message "No traces match …" appears.

  9. Click the × clear button. Confirm the input empties, the counter disappears, and the full unfiltered list returns.

Add a live search input under the tabs in the tracer panel that filters
trace history entries and steps in realtime. The query matches against
userMessage, sessionId, planId, step display names, and stringified step
content. When the query matches entry metadata, all steps in that entry
remain visible; otherwise only matching steps are shown. The counter
reports matched steps out of total steps across all visible entries.

Also adds display names and icons for OutputEvaluationStep and
BeforeReasoningIterationStep, and renames ReasoningStep's display name
from "Output Evaluation" to "Reasoning".
@marcelinollano marcelinollano changed the title W-22434499: feat: add search filter to agent tracer W-22434499: feat: add search filter to agent tracer @W-22434499@ May 13, 2026
@marcelinollano marcelinollano changed the title W-22434499: feat: add search filter to agent tracer @W-22434499@ feat: add search filter to agent tracer @W-22434499@ May 13, 2026
@marcelinollano marcelinollano marked this pull request as ready for review May 13, 2026 11:29
@marcelinollano
Copy link
Copy Markdown
Collaborator Author

Code review

Found 1 issue:

  1. Timeline highlight breaks when a filter is active. buildTimelineItems filters the timeline items but each surviving item's onClick still captures the original plan index. Clicking a step calls setSelectedStepIndex(originalIndex), and Timeline then highlights by comparing selectedIndex against array positions in the compacted items array. After filtering, the original index almost always points outside the compacted array, so the clicked step shows no highlight even though the JSON panel below renders the correct step's data. Either map the stored selection through the surviving items or pass each item its original index and have Timeline compare against that.

const items = traceData.plan.map((step: any, index: number) => {
const stepType = step.type || step.stepType || '';
const stepName = step.name || step.label || step.description || '';
// Determine status - FunctionStep without output indicates an error
let status: 'success' | 'error' | 'pending' | 'incomplete' = 'success';
if (stepType === 'FunctionStep' && step.function && !step.function.output) {
status = 'error';
}
// Get user-friendly display name
const displayType = STEP_DISPLAY_NAMES[stepType] || stepType;
// Get icon for this step type
const icon = STEP_ICONS[stepType];
let label: string;
if (stepType && stepName) {
label = `${displayType}: ${stepName}`;
} else if (stepType) {
label = displayType;
} else if (stepName) {
label = stepName;
} else {
label = `Step ${index + 1}`;
}
const description = getStepDescription(step);
const hasData = step && (step.data || step.message || step.reason || step.function);

Selection state is set here:

}
if (Object.keys(displayData).length > 0) {
return JSON.stringify(displayData, null, 2);
}
return null;
};
const AgentTracer: React.FC<AgentTracerProps> = ({
isVisible = true,
onGoToPreview,
isSessionActive = false,

And passed back into the row from the filtered list:

entry={entry}
index={index}
isExpanded={expandedPlanIds.has(entry.planId)}
onExpandedChange={expanded => handleRowExpandedChange(entry.planId, expanded)}
onOpenJson={() => handleRowOpenJson(entry)}
timelineItems={timelineItems}
message={message}
selectedStepIndex={selectedHistoryIndex === index ? selectedStepIndex ?? undefined : undefined}
/>
);
})}
</div>
) : (
<div className="trace-filter__empty">No traces match "{trimmedFilter}"</div>
)}

Generated with Claude Code

If this code review was useful, please react with thumbs up. Otherwise, react with thumbs down.

Translate the stored selectedStepIndex from the original plan position
into the filtered timeline's compacted position before passing it to
TraceHistoryRow, so the highlight follows the selected step when the
filter is active. If the selected step is filtered out, no item is
highlighted.

Also clear the filter query when traceHistory or sessionStarted resets
the panel state, so a stale filter cannot hide a fresh batch.
@marcelinollano
Copy link
Copy Markdown
Collaborator Author

Code review

No issues found. Re-reviewed commit ad851dc which addresses the prior feedback. The selection-translation logic and the filter-reset placement check out, and the new tests cover the edge cases.

Generated with Claude Code

If this code review was useful, please react with thumbs up. Otherwise, react with thumbs down.

Copy link
Copy Markdown
Contributor

@npiccolo npiccolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manual testing ✅

Setup: Extension Development Host launched from ml/w-22434499-tracer-filtering, agent script project afdx-pro-code-testdrive opened in the test window.

Search input — visible under the tabs with correct placeholder text and styling.

Filter by user message — typing a word from an existing user message narrowed to the matching entry with all steps visible and counter showing matched vs total steps.

Empty state — typing a string with no matches showed "No traces match …" with 0 of N counter.

Clear button — clicking × emptied the input, hides the counter, and restored the full unfiltered list.

New session resets filter — starting a fresh simulation cleared any stale filter automatically.

Display name fixBeforeReasoningIterationStep correctly shows "Before Reasoning Iteration" and ReasoningStep correctly shows "Reasoning" (previously mislabelled "Output Evaluation").

Automated tests: npm run test:backend (381/381) and npm run test:frontend (434/434) all pass.

LGTM ✅

@npiccolo npiccolo requested a review from jshackell-sfdc May 14, 2026 01:39
@marcelinollano marcelinollano merged commit 34f11d8 into main May 14, 2026
9 checks passed
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.

2 participants