Closes the Phase 5 audit partial: the inline card's prop interface now matches SamplingRequestPanel's, accepting an optional CreateMessageResult draft instead of a flat scalar. Lets future hook-layer wiring share a single draft store between the inline card and the full panel. Rendering: - No draft → existing layout (request preview, model hints, action buttons), with the readonly placeholder textarea removed. - Text draft → 2-line preview of draftResult.content.text (lineClamp 2). - Image / audio draft → "[Image content]" / "[Audio content]" label, matching the ContentViewer fallback convention. Updates the three consumer stories that threaded responseText="" through (PendingClientRequests, ToolsScreen) — no callback signatures changed. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f1d6fbd704
commit
c04f96ffb8
4 changed files with 56 additions and 28 deletions
|
|
@ -1,5 +1,8 @@
|
||||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||||
import type { CreateMessageRequestParams } from "@modelcontextprotocol/sdk/types.js";
|
import type {
|
||||||
|
CreateMessageRequestParams,
|
||||||
|
CreateMessageResult,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
import { fn } from "storybook/test";
|
import { fn } from "storybook/test";
|
||||||
import { InlineSamplingRequest } from "./InlineSamplingRequest";
|
import { InlineSamplingRequest } from "./InlineSamplingRequest";
|
||||||
|
|
||||||
|
|
@ -16,13 +19,31 @@ const defaultRequest: CreateMessageRequestParams = {
|
||||||
maxTokens: 1024,
|
maxTokens: 1024,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const textDraft: CreateMessageResult = {
|
||||||
|
role: "assistant",
|
||||||
|
model: "claude-sonnet-4-20250514",
|
||||||
|
content: {
|
||||||
|
type: "text",
|
||||||
|
text: "The code looks good overall. Consider extracting the repeated logic into a helper function and adding type annotations to the public API.",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const imageDraft: CreateMessageResult = {
|
||||||
|
role: "assistant",
|
||||||
|
model: "claude-sonnet-4-20250514",
|
||||||
|
content: {
|
||||||
|
type: "image",
|
||||||
|
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
|
||||||
|
mimeType: "image/png",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const meta: Meta<typeof InlineSamplingRequest> = {
|
const meta: Meta<typeof InlineSamplingRequest> = {
|
||||||
title: "Groups/InlineSamplingRequest",
|
title: "Groups/InlineSamplingRequest",
|
||||||
component: InlineSamplingRequest,
|
component: InlineSamplingRequest,
|
||||||
args: {
|
args: {
|
||||||
request: defaultRequest,
|
request: defaultRequest,
|
||||||
queuePosition: "1 of 1",
|
queuePosition: "1 of 1",
|
||||||
responseText: "",
|
|
||||||
onAutoRespond: fn(),
|
onAutoRespond: fn(),
|
||||||
onEditAndSend: fn(),
|
onEditAndSend: fn(),
|
||||||
onReject: fn(),
|
onReject: fn(),
|
||||||
|
|
@ -49,10 +70,15 @@ export const WithModelHints: Story = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PrefilledResponse: Story = {
|
export const WithTextDraft: Story = {
|
||||||
args: {
|
args: {
|
||||||
responseText:
|
draftResult: textDraft,
|
||||||
"The code looks good overall. Consider extracting the repeated logic into a helper function.",
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithNonTextDraft: Story = {
|
||||||
|
args: {
|
||||||
|
draftResult: imageDraft,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
import {
|
import { Badge, Button, Group, Paper, Stack, Text } from "@mantine/core";
|
||||||
Badge,
|
import type {
|
||||||
Button,
|
CreateMessageRequestParams,
|
||||||
Group,
|
CreateMessageResult,
|
||||||
Paper,
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
Stack,
|
|
||||||
Text,
|
|
||||||
Textarea,
|
|
||||||
} from "@mantine/core";
|
|
||||||
import type { CreateMessageRequestParams } from "@modelcontextprotocol/sdk/types.js";
|
|
||||||
|
|
||||||
export interface InlineSamplingRequestProps {
|
export interface InlineSamplingRequestProps {
|
||||||
request: CreateMessageRequestParams;
|
request: CreateMessageRequestParams;
|
||||||
queuePosition: string;
|
queuePosition: string;
|
||||||
responseText: string;
|
draftResult?: CreateMessageResult;
|
||||||
onAutoRespond: () => void;
|
onAutoRespond: () => void;
|
||||||
onEditAndSend: () => void;
|
onEditAndSend: () => void;
|
||||||
onReject: () => void;
|
onReject: () => void;
|
||||||
|
|
@ -35,6 +30,11 @@ const PreviewText = Text.withProps({
|
||||||
lineClamp: 2,
|
lineClamp: 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const DraftPreview = Text.withProps({
|
||||||
|
size: "sm",
|
||||||
|
lineClamp: 2,
|
||||||
|
});
|
||||||
|
|
||||||
const DetailButton = Button.withProps({
|
const DetailButton = Button.withProps({
|
||||||
variant: "subtle",
|
variant: "subtle",
|
||||||
size: "xs",
|
size: "xs",
|
||||||
|
|
@ -67,6 +67,17 @@ function extractPreview(request: CreateMessageRequestParams): string {
|
||||||
return content.type === "text" ? content.text : `[${content.type}]`;
|
return content.type === "text" ? content.text : `[${content.type}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractDraftPreview(draft: CreateMessageResult): string {
|
||||||
|
switch (draft.content.type) {
|
||||||
|
case "text":
|
||||||
|
return draft.content.text;
|
||||||
|
case "image":
|
||||||
|
return "[Image content]";
|
||||||
|
case "audio":
|
||||||
|
return "[Audio content]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function extractModelHints(
|
function extractModelHints(
|
||||||
request: CreateMessageRequestParams,
|
request: CreateMessageRequestParams,
|
||||||
): string[] | undefined {
|
): string[] | undefined {
|
||||||
|
|
@ -82,7 +93,7 @@ function formatModelHints(hints: string[]): string {
|
||||||
export function InlineSamplingRequest({
|
export function InlineSamplingRequest({
|
||||||
request,
|
request,
|
||||||
queuePosition,
|
queuePosition,
|
||||||
responseText,
|
draftResult,
|
||||||
onAutoRespond,
|
onAutoRespond,
|
||||||
onEditAndSend,
|
onEditAndSend,
|
||||||
onReject,
|
onReject,
|
||||||
|
|
@ -90,6 +101,7 @@ export function InlineSamplingRequest({
|
||||||
}: InlineSamplingRequestProps) {
|
}: InlineSamplingRequestProps) {
|
||||||
const modelHints = extractModelHints(request);
|
const modelHints = extractModelHints(request);
|
||||||
const messagePreview = extractPreview(request);
|
const messagePreview = extractPreview(request);
|
||||||
|
const draftPreview = draftResult ? extractDraftPreview(draftResult) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RequestContainer>
|
<RequestContainer>
|
||||||
|
|
@ -105,14 +117,7 @@ export function InlineSamplingRequest({
|
||||||
|
|
||||||
<DetailButton onClick={onViewDetails}>View Details</DetailButton>
|
<DetailButton onClick={onViewDetails}>View Details</DetailButton>
|
||||||
|
|
||||||
<Textarea
|
{draftPreview !== null && <DraftPreview>{draftPreview}</DraftPreview>}
|
||||||
size="sm"
|
|
||||||
value={responseText}
|
|
||||||
placeholder="Response..."
|
|
||||||
autosize
|
|
||||||
minRows={2}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ActionsRow>
|
<ActionsRow>
|
||||||
<CompactButton onClick={onAutoRespond}>Auto-respond</CompactButton>
|
<CompactButton onClick={onAutoRespond}>Auto-respond</CompactButton>
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ export const SingleSampling: Story = {
|
||||||
maxTokens: 1024,
|
maxTokens: 1024,
|
||||||
}}
|
}}
|
||||||
queuePosition="1 of 1"
|
queuePosition="1 of 1"
|
||||||
responseText=""
|
|
||||||
onAutoRespond={fn()}
|
onAutoRespond={fn()}
|
||||||
onEditAndSend={fn()}
|
onEditAndSend={fn()}
|
||||||
onReject={fn()}
|
onReject={fn()}
|
||||||
|
|
@ -102,7 +101,6 @@ export const MultipleMixed: Story = {
|
||||||
maxTokens: 1024,
|
maxTokens: 1024,
|
||||||
}}
|
}}
|
||||||
queuePosition="1 of 2"
|
queuePosition="1 of 2"
|
||||||
responseText=""
|
|
||||||
onAutoRespond={fn()}
|
onAutoRespond={fn()}
|
||||||
onEditAndSend={fn()}
|
onEditAndSend={fn()}
|
||||||
onReject={fn()}
|
onReject={fn()}
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,6 @@ export const WithPendingRequests: Story = {
|
||||||
maxTokens: 1024,
|
maxTokens: 1024,
|
||||||
}}
|
}}
|
||||||
queuePosition="1 of 2"
|
queuePosition="1 of 2"
|
||||||
responseText=""
|
|
||||||
onAutoRespond={fn()}
|
onAutoRespond={fn()}
|
||||||
onEditAndSend={fn()}
|
onEditAndSend={fn()}
|
||||||
onReject={fn()}
|
onReject={fn()}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue