fix(site/src/pages/AgentsPage): lead find_tools header with the match count (#29178)

This commit is contained in:
Michael Suchacz
2026-09-16 22:17:48 +02:00
committed by GitHub
parent 6c7f6b855b
commit 6967259af4
3 changed files with 128 additions and 7 deletions
@@ -602,7 +602,7 @@ export const FindToolsSearchResult: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const summary = canvas.getByRole("button", {
name: "Searched tools: github issues, pull requests, name:github__list_issues -> 2 matched",
name: "Matched 2 tools: github__list_issues, github__list_pull_requests",
});
await userEvent.click(summary);
},
@@ -0,0 +1,110 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { FindToolsTool } from "./FindToolsTool";
const githubMatches = [
{
name: "github__list_issues",
description: "List issues in a GitHub repository.",
},
{
name: "github__list_pull_requests",
description: "List pull requests in a GitHub repository.",
},
];
const meta: Meta<typeof FindToolsTool> = {
title: "pages/AgentsPage/ChatElements/tools/FindToolsTool",
component: FindToolsTool,
args: {
queries: ["github issues", "pull requests"],
names: ["github__list_issues"],
matches: githubMatches,
status: "completed",
isError: false,
},
decorators: [
(Story) => (
<div className="mx-auto w-full max-w-3xl py-6 font-sans text-xs">
<Story />
</div>
),
],
};
export default meta;
type Story = StoryObj<typeof FindToolsTool>;
export const Running: Story = {
args: { status: "running", matches: [] },
};
export const ManyMatches: Story = {};
export const SingleMatch: Story = {
args: {
queries: ["github issues"],
names: [],
matches: githubMatches.slice(0, 1),
},
};
export const NoMatches: Story = {
args: {
queries: ["nonexistent capability"],
names: [],
matches: [],
},
};
// A long match list overflows the header, so the match count leads the
// label and only the tool names are truncated.
export const LongMatchListTruncates: Story = {
decorators: [
(Story) => (
<div className="w-80">
<Story />
</div>
),
],
args: {
queries: ["microsoft documentation", "code samples"],
names: [],
matches: [
"mslearn__microsoft_docs_search",
"mslearn__microsoft_docs_fetch",
"mslearn__microsoft_code_sample_search",
"mslearn__microsoft_learn_catalog",
].map((name) => ({ name, description: `${name} description` })),
},
};
// A long search with no results falls back to showing the search terms.
export const LongSearchNoMatchesTruncates: Story = {
decorators: [
(Story) => (
<div className="w-80">
<Story />
</div>
),
],
args: {
queries: [
"list github issues for a repository",
"open pull requests assigned to me",
"comment on a pull request review thread",
],
names: ["github__list_issues"],
matches: [],
},
};
export const Failed: Story = {
args: {
queries: ["github issues"],
names: [],
matches: [],
status: "error",
isError: true,
errorMessage:
"The schema budget for this step is exhausted; call the tools already activated or retry next step.",
},
};
@@ -24,12 +24,23 @@ export const FindToolsTool: FC<FindToolsToolProps> = ({
isError,
errorMessage,
}) => {
const queryLabel =
[...queries, ...names.map((name) => `name:${name}`)].join(", ") || "tools";
const label =
status === "running"
? `Searching tools: ${queryLabel}`
: `Searched tools: ${queryLabel} -> ${matches.length} matched`;
// The header label truncates from the end, so the outcome leads and
// the list absorbs any overflow. Search terms only appear when there
// are no matched tool names to show instead.
const searchTerms = [...queries, ...names].join(", ");
const searchSuffix = searchTerms ? `: ${searchTerms}` : "";
let label: string;
if (status === "running") {
label = `Searching tools${searchSuffix}`;
} else if (isError) {
label = `Failed to search tools${searchSuffix}`;
} else if (matches.length === 0) {
label = `No tools matched${searchSuffix}`;
} else {
const noun = matches.length === 1 ? "tool" : "tools";
const matchedNames = matches.map((match) => match.name).join(", ");
label = `Matched ${matches.length} ${noun}: ${matchedNames}`;
}
return (
<ToolCall.Root