Merge remote-tracking branch 'origin/v2/main' into v2/sdk-v2-migration-1624

# Conflicts:
#	clients/web/src/components/groups/ResourceLink/ResourceLink.tsx
#	clients/web/src/components/groups/ToolResultPanel/ToolResultPanel.stories.tsx
#	clients/web/src/components/screens/ToolsScreen/ToolsScreen.tsx
This commit is contained in:
cliffhall 2026-07-15 14:15:50 -04:00
commit 39362dd5ff
2 changed files with 591 additions and 197 deletions

View file

@ -163,7 +163,7 @@ describe("ToolsScreen", () => {
expect(screen.queryByText("Results")).toBeNull();
});
it("renders the result panel when callState has a result", () => {
it("renders a content-sized result card for a plain text result", () => {
renderWithMantine(
<ToolsScreen
{...baseProps}
@ -174,6 +174,34 @@ describe("ToolsScreen", () => {
/>,
);
expect(screen.getByText("Results")).toBeInTheDocument();
// No links → the result card is NOT flex-filled (sizes to content).
const card = screen.getByText("Results").closest(".mantine-Card-root");
expect(card).not.toHaveStyle({ flex: "1" });
});
it("fills the result card with a Resource Links box when the result has links", () => {
// A resource_link result takes the full-height (`flex={1}`) card branch so
// the Resource Links box can grow and scroll within.
renderWithMantine(
<ToolsScreen
{...baseProps}
callState={{
status: "ok",
result: {
content: [
{ type: "resource_link", uri: "demo://r/1", name: "Linked" },
],
},
}}
/>,
);
expect(
screen.getByRole("heading", { name: "Resource Links" }),
).toBeInTheDocument();
// Links → the result card fills the pane (`flex: 1`), distinguishing this
// branch from the content-sized text-result card above.
const card = screen.getByText("Results").closest(".mantine-Card-root");
expect(card).toHaveStyle({ flex: "1" });
});
it("invokes onCallTool with form values on Execute", async () => {

View file

@ -10,6 +10,7 @@ import {
type ToolProgress,
} from "../../groups/ToolDetailPanel/ToolDetailPanel";
import { ToolResultPanel } from "../../groups/ToolResultPanel/ToolResultPanel";
import { resultHasResourceLinks } from "../../groups/ToolResultPanel/toolResultUtils";
import { collectSchemaDefaults, toFormSchema } from "../../../utils/jsonUtils";
export interface ToolCallState {
@ -184,7 +185,14 @@ export function ToolsScreen({
// `result` (App.tsx), so the executing form (progress + cancel) shows
// until the result lands.
<ContentPane mah={SCROLL_MAX_HEIGHT}>
<ContentCard>
{/* Fill the pane's full height only when the result renders a
"Resource Links" box, so that box can expand into the available
space and scroll within. Plain text/image/error results keep the
content-sized card (matching the input-form state) instead of
reserving a tall empty card. */}
<ContentCard
flex={resultHasResourceLinks(callState.result) ? 1 : undefined}
>
<ToolResultPanel
result={callState.result}
onClear={() => onClearResult?.()}