Merge pull request #1213 from modelcontextprotocol/v2/phase-2-prompts

Phase 2: Refactor Prompts cluster to MCP SDK types
This commit is contained in:
Cliff Hall 2026-04-18 18:17:43 -04:00 • committed by GitHub
commit 61230d533c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 291 additions and 240 deletions

View file

@ -78,6 +78,7 @@ const BubbleContainer = Paper.withProps({
const RoleLabel = Text.withProps({ const RoleLabel = Text.withProps({
size: "xs", size: "xs",
c: "dimmed", c: "dimmed",
ff: "monospace",
}); });
const PreviewImage = Image.withProps({ const PreviewImage = Image.withProps({

View file

@ -1,4 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react-vite"; import type { Meta, StoryObj } from "@storybook/react-vite";
import type { Prompt } from "@modelcontextprotocol/sdk/types.js";
import { fn } from "storybook/test"; import { fn } from "storybook/test";
import { PromptArgumentsForm } from "./PromptArgumentsForm"; import { PromptArgumentsForm } from "./PromptArgumentsForm";
@ -14,64 +15,73 @@ const meta: Meta<typeof PromptArgumentsForm> = {
export default meta; export default meta;
type Story = StoryObj<typeof PromptArgumentsForm>; type Story = StoryObj<typeof PromptArgumentsForm>;
const summarizePrompt: Prompt = {
name: "summarize",
description: "Summarize the given text into key points",
};
const translatePrompt: Prompt = {
name: "translate",
description: "Translate text from one language to another",
arguments: [
{ name: "text", required: true, description: "The text to translate" },
{
name: "targetLanguage",
required: true,
description: "The language to translate into",
},
],
};
const summarizeWithArgsPrompt: Prompt = {
name: "summarize",
description: "Summarize the given text into key points",
arguments: [
{ name: "text", required: true, description: "The text to summarize" },
{
name: "maxLength",
required: true,
description: "Maximum length of summary in words",
},
{
name: "format",
required: false,
description: "Output format (bullets or paragraph)",
},
],
};
const codeReviewPrompt: Prompt = {
name: "code-review",
arguments: [
{ name: "code", required: true, description: "The code to review" },
],
};
export const NoArguments: Story = { export const NoArguments: Story = {
args: { args: {
name: "summarize", prompt: summarizePrompt,
description: "Summarize the given text into key points",
arguments: [],
argumentValues: {}, argumentValues: {},
}, },
}; };
export const WithArguments: Story = { export const WithArguments: Story = {
args: { args: {
name: "translate", prompt: translatePrompt,
description: "Translate text from one language to another",
arguments: [
{ name: "text", required: true, description: "The text to translate" },
{
name: "targetLanguage",
required: true,
description: "The language to translate into",
},
],
argumentValues: {}, argumentValues: {},
}, },
}; };
export const WithRequiredAndOptional: Story = { export const WithRequiredAndOptional: Story = {
args: { args: {
name: "summarize", prompt: summarizeWithArgsPrompt,
description: "Summarize the given text into key points",
arguments: [
{ name: "text", required: true, description: "The text to summarize" },
{
name: "maxLength",
required: true,
description: "Maximum length of summary in words",
},
{
name: "format",
required: false,
description: "Output format (bullets or paragraph)",
},
],
argumentValues: {}, argumentValues: {},
}, },
}; };
export const AllFilled: Story = { export const AllFilled: Story = {
args: { args: {
name: "translate", prompt: translatePrompt,
description: "Translate text from one language to another",
arguments: [
{ name: "text", required: true, description: "The text to translate" },
{
name: "targetLanguage",
required: true,
description: "The language to translate into",
},
],
argumentValues: { argumentValues: {
text: "Hello, how are you?", text: "Hello, how are you?",
targetLanguage: "Spanish", targetLanguage: "Spanish",
@ -81,10 +91,7 @@ export const AllFilled: Story = {
export const NoDescription: Story = { export const NoDescription: Story = {
args: { args: {
name: "code-review", prompt: codeReviewPrompt,
arguments: [
{ name: "code", required: true, description: "The code to review" },
],
argumentValues: {}, argumentValues: {},
}, },
}; };

View file

@ -1,20 +1,19 @@
import { Button, Group, Stack, Text, TextInput, Title } from "@mantine/core"; import { Button, Group, Stack, Text, TextInput, Title } from "@mantine/core";
import type { Prompt } from "@modelcontextprotocol/sdk/types.js";
export interface PromptArgument {
name: string;
required: boolean;
description?: string;
}
export interface PromptArgumentsFormProps { export interface PromptArgumentsFormProps {
name: string; prompt: Prompt;
description?: string;
arguments: PromptArgument[];
argumentValues: Record<string, string>; argumentValues: Record<string, string>;
onArgumentChange: (name: string, value: string) => void; onArgumentChange: (name: string, value: string) => void;
onGetPrompt: () => void; onGetPrompt: () => void;
} }
const PromptTitle = Text.withProps({
fw: 700,
size: "lg",
truncate: "end",
});
const DescriptionText = Text.withProps({ const DescriptionText = Text.withProps({
size: "sm", size: "sm",
c: "dimmed", c: "dimmed",
@ -25,32 +24,36 @@ function formatPlaceholder(name: string): string {
} }
export function PromptArgumentsForm({ export function PromptArgumentsForm({
description, prompt,
arguments: promptArguments,
argumentValues, argumentValues,
onArgumentChange, onArgumentChange,
onGetPrompt, onGetPrompt,
}: PromptArgumentsFormProps) { }: PromptArgumentsFormProps) {
const { name, title, description, arguments: promptArguments } = prompt;
return ( return (
<Stack gap="md"> <Stack gap="md">
<Title order={4}>Prompt Arguments</Title> <PromptTitle>{title ?? name}</PromptTitle>
{description && <DescriptionText>{description}</DescriptionText>} {description && <DescriptionText>{description}</DescriptionText>}
{promptArguments.length > 0 && ( {promptArguments && promptArguments.length > 0 && (
<Stack gap="sm"> <>
{promptArguments.map((arg) => ( <Title order={4}>Arguments</Title>
<TextInput <Stack gap="sm">
key={arg.name} {promptArguments.map((arg) => (
label={arg.name} <TextInput
withAsterisk={arg.required} key={arg.name}
description={arg.description} label={arg.name}
placeholder={formatPlaceholder(arg.name)} withAsterisk={arg.required === true}
value={argumentValues[arg.name] || ""} description={arg.description}
onChange={(event) => placeholder={formatPlaceholder(arg.name)}
onArgumentChange(arg.name, event.currentTarget.value) value={argumentValues[arg.name] || ""}
} onChange={(event) =>
/> onArgumentChange(arg.name, event.currentTarget.value)
))} }
</Stack> />
))}
</Stack>
</>
)} )}
<Group justify="flex-end"> <Group justify="flex-end">
<Button size="sm" onClick={onGetPrompt}> <Button size="sm" onClick={onGetPrompt}>

View file

@ -1,4 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react-vite"; import type { Meta, StoryObj } from "@storybook/react-vite";
import type { Prompt } from "@modelcontextprotocol/sdk/types.js";
import { fn } from "storybook/test"; import { fn } from "storybook/test";
import { PromptControls } from "./PromptControls"; import { PromptControls } from "./PromptControls";
@ -15,28 +16,24 @@ const meta: Meta<typeof PromptControls> = {
export default meta; export default meta;
type Story = StoryObj<typeof PromptControls>; type Story = StoryObj<typeof PromptControls>;
const samplePrompts = [ const samplePrompts: Prompt[] = [
{ {
name: "summarize", name: "summarize",
description: "Summarize the given text into key points", description: "Summarize the given text into key points",
selected: false,
}, },
{ {
name: "translate", name: "translate",
description: "Translate text from one language to another", description: "Translate text from one language to another",
selected: false,
}, },
{ {
name: "analyze", name: "analyze",
description: "Analyze sentiment and tone of the text", description: "Analyze sentiment and tone of the text",
selected: false,
}, },
{ {
name: "code-review", name: "code-review",
description: "Review code for issues", description: "Review code for issues",
selected: false,
}, },
{ name: "refactor", selected: false }, { name: "refactor" },
]; ];
export const Default: Story = { export const Default: Story = {
@ -47,9 +44,8 @@ export const Default: Story = {
export const WithSelection: Story = { export const WithSelection: Story = {
args: { args: {
prompts: samplePrompts.map((p) => prompts: samplePrompts,
p.name === "translate" ? { ...p, selected: true } : p, selectedName: "translate",
),
}, },
}; };

View file

@ -1,22 +1,23 @@
import { useState } from "react"; import { useState } from "react";
import { Group, ScrollArea, Stack, TextInput, Title } from "@mantine/core"; import { Group, ScrollArea, Stack, TextInput, Title } from "@mantine/core";
import type { Prompt } from "@modelcontextprotocol/sdk/types.js";
import { ListChangedIndicator } from "../../elements/ListChangedIndicator/ListChangedIndicator"; import { ListChangedIndicator } from "../../elements/ListChangedIndicator/ListChangedIndicator";
import { PromptListItem } from "../PromptListItem/PromptListItem"; import { PromptListItem } from "../PromptListItem/PromptListItem";
import type { PromptItem } from "../../screens/PromptsScreen/PromptsScreen";
export interface PromptControlsProps { export interface PromptControlsProps {
prompts: PromptItem[]; prompts: Prompt[];
selectedName?: string;
listChanged: boolean; listChanged: boolean;
onRefreshList: () => void; onRefreshList: () => void;
onSelectPrompt: (name: string) => void; onSelectPrompt: (name: string) => void;
} }
function listMaxHeight(): string { const LIST_MAX_HEIGHT =
return "calc(100vh - var(--app-shell-header-height, 0px) - var(--mantine-spacing-xl) * 2 - 160px)"; "calc(100vh - var(--app-shell-header-height, 0px) - var(--mantine-spacing-xl) * 2 - 160px)";
}
export function PromptControls({ export function PromptControls({
prompts, prompts,
selectedName,
listChanged, listChanged,
onRefreshList, onRefreshList,
onSelectPrompt, onSelectPrompt,
@ -26,6 +27,7 @@ export function PromptControls({
const filteredPrompts = prompts.filter( const filteredPrompts = prompts.filter(
(p) => (p) =>
p.name.toLowerCase().includes(query) || p.name.toLowerCase().includes(query) ||
(p.title?.toLowerCase().includes(query) ?? false) ||
(p.description?.toLowerCase().includes(query) ?? false), (p.description?.toLowerCase().includes(query) ?? false),
); );
@ -40,15 +42,16 @@ export function PromptControls({
value={searchText} value={searchText}
onChange={(e) => setSearchText(e.currentTarget.value)} onChange={(e) => setSearchText(e.currentTarget.value)}
/> />
<ScrollArea.Autosize mah={listMaxHeight()}> <ScrollArea.Autosize mah={LIST_MAX_HEIGHT}>
<Stack gap="xs"> <Stack gap="xs">
{filteredPrompts.map((prompt) => ( {filteredPrompts.map((prompt) => (
<PromptListItem <PromptListItem
key={prompt.name} key={prompt.name}
name={prompt.name} prompt={prompt}
description={prompt.description} selected={prompt.name === selectedName}
selected={prompt.selected} onClick={() => {
onClick={() => onSelectPrompt(prompt.name)} if (prompt.name !== selectedName) onSelectPrompt(prompt.name);
}}
/> />
))} ))}
</Stack> </Stack>

View file

@ -15,23 +15,40 @@ type Story = StoryObj<typeof PromptListItem>;
export const Default: Story = { export const Default: Story = {
args: { args: {
name: "summarize", prompt: {
description: "Summarize the given text into key points", name: "summarize",
description: "Summarize the given text into key points",
},
selected: false, selected: false,
}, },
}; };
export const Selected: Story = { export const Selected: Story = {
args: { args: {
name: "translate", prompt: {
description: "Translate text from one language to another", name: "translate",
description: "Translate text from one language to another",
},
selected: true, selected: true,
}, },
}; };
export const WithTitle: Story = {
args: {
prompt: {
name: "code-review",
title: "Code Review",
description: "Review code for issues and best practices",
},
selected: false,
},
};
export const NoDescription: Story = { export const NoDescription: Story = {
args: { args: {
name: "code-review", prompt: {
name: "code-review",
},
selected: false, selected: false,
}, },
}; };

View file

@ -1,8 +1,8 @@
import { Stack, Text, UnstyledButton } from "@mantine/core"; import { Stack, Text, UnstyledButton } from "@mantine/core";
import type { Prompt } from "@modelcontextprotocol/sdk/types.js";
export interface PromptListItemProps { export interface PromptListItemProps {
name: string; prompt: Prompt;
description?: string;
selected: boolean; selected: boolean;
onClick: () => void; onClick: () => void;
} }
@ -18,11 +18,11 @@ const DescriptionText = Text.withProps({
}); });
export function PromptListItem({ export function PromptListItem({
name, prompt,
description,
selected, selected,
onClick, onClick,
}: PromptListItemProps) { }: PromptListItemProps) {
const { name, title, description } = prompt;
return ( return (
<UnstyledButton <UnstyledButton
w="100%" w="100%"
@ -32,7 +32,7 @@ export function PromptListItem({
onClick={onClick} onClick={onClick}
> >
<Stack gap={2}> <Stack gap={2}>
<NameText>{name}</NameText> <NameText>{title ?? name}</NameText>
{description && <DescriptionText>{description}</DescriptionText>} {description && <DescriptionText>{description}</DescriptionText>}
</Stack> </Stack>
</UnstyledButton> </UnstyledButton>

View file

@ -52,17 +52,11 @@ export const WithImage: Story = {
messages: [ messages: [
{ {
role: "user", role: "user",
content: [ content: {
{ type: "image",
type: "text", data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
text: "Here is a photo for you to analyze.", mimeType: "image/png",
}, },
{
type: "image",
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
mimeType: "image/png",
},
],
}, },
], ],
}, },

View file

@ -1,20 +1,17 @@
import { Button, Group, Stack, Text, Title } from "@mantine/core"; import { Button, Group, Stack, Text, Title } from "@mantine/core";
import type { import type { PromptMessage } from "@modelcontextprotocol/sdk/types.js";
PromptMessage,
SamplingMessage,
} from "@modelcontextprotocol/sdk/types.js";
import { MessageBubble } from "../../elements/MessageBubble/MessageBubble"; import { MessageBubble } from "../../elements/MessageBubble/MessageBubble";
export interface PromptMessagesDisplayProps {
messages: PromptMessage[];
onCopyAll?: () => void;
}
const CopyAllButton = Button.withProps({ const CopyAllButton = Button.withProps({
variant: "subtle", variant: "subtle",
size: "sm", size: "sm",
}); });
export interface PromptMessagesDisplayProps {
messages: (PromptMessage | SamplingMessage)[];
onCopyAll?: () => void;
}
export function PromptMessagesDisplay({ export function PromptMessagesDisplay({
messages, messages,
onCopyAll, onCopyAll,

View file

@ -1,7 +1,8 @@
import type { Meta, StoryObj } from "@storybook/react-vite"; import type { Meta, StoryObj } from "@storybook/react-vite";
import type { Prompt } from "@modelcontextprotocol/sdk/types.js";
import { fn } from "storybook/test"; import { fn } from "storybook/test";
import { PromptsScreen } from "./PromptsScreen"; import { PromptsScreen } from "./PromptsScreen";
import type { PromptItem, SelectedPrompt } from "./PromptsScreen"; import type { GetPromptState } from "./PromptsScreen";
const meta: Meta<typeof PromptsScreen> = { const meta: Meta<typeof PromptsScreen> = {
title: "Screens/PromptsScreen", title: "Screens/PromptsScreen",
@ -10,8 +11,8 @@ const meta: Meta<typeof PromptsScreen> = {
args: { args: {
onRefreshList: fn(), onRefreshList: fn(),
onSelectPrompt: fn(), onSelectPrompt: fn(),
onArgumentChange: fn(),
onGetPrompt: fn(), onGetPrompt: fn(),
onCopyMessages: fn(),
listChanged: false, listChanged: false,
}, },
}; };
@ -19,42 +20,54 @@ const meta: Meta<typeof PromptsScreen> = {
export default meta; export default meta;
type Story = StoryObj<typeof PromptsScreen>; type Story = StoryObj<typeof PromptsScreen>;
const samplePrompts: PromptItem[] = [ const samplePrompts: Prompt[] = [
{ {
name: "summarize", name: "summarize",
description: "Summarize the given text into key points", description: "Summarize the given text into key points",
selected: false,
}, },
{ {
name: "translate", name: "translate",
description: "Translate text from one language to another", description: "Translate text from one language to another",
selected: false, arguments: [
{ name: "text", required: true, description: "The text to translate" },
{
name: "targetLanguage",
required: true,
description: "Target language code",
},
],
}, },
{ {
name: "code-review", name: "code-review",
description: "Review code for issues", description: "Review code for issues",
selected: false,
}, },
{ {
name: "analyze", name: "analyze",
description: "Analyze sentiment and tone of the text", description: "Analyze sentiment and tone of the text",
selected: false,
}, },
{ name: "refactor", selected: false }, { name: "refactor" },
]; ];
const selectedTranslate: SelectedPrompt = { const translateResult: GetPromptState = {
name: "translate", status: "ok",
description: "Translate text from one language to another", result: {
arguments: [ messages: [
{ name: "text", required: true, description: "The text to translate" }, {
{ role: "user",
name: "targetLanguage", content: {
required: true, type: "text",
description: "Target language code", text: 'Translate the following text to Spanish: "Hello, how are you?"',
}, },
], },
argumentValues: {}, {
role: "assistant",
content: {
type: "text",
text: "Hola, como estas?",
},
},
],
},
}; };
export const NoSelection: Story = { export const NoSelection: Story = {
@ -65,43 +78,35 @@ export const NoSelection: Story = {
export const PromptSelected: Story = { export const PromptSelected: Story = {
args: { args: {
prompts: samplePrompts.map((p) => prompts: samplePrompts,
p.name === "translate" ? { ...p, selected: true } : p, selectedPromptName: "translate",
),
selectedPrompt: selectedTranslate,
}, },
}; };
export const WithResult: Story = { export const WithResult: Story = {
args: { args: {
prompts: samplePrompts.map((p) => prompts: samplePrompts,
p.name === "translate" ? { ...p, selected: true } : p, selectedPromptName: "translate",
), getPromptState: translateResult,
selectedPrompt: { },
...selectedTranslate, };
argumentValues: {
text: "Hello, how are you?", export const Loading: Story = {
targetLanguage: "es", args: {
}, prompts: samplePrompts,
}, selectedPromptName: "translate",
messages: { getPromptState: { status: "pending" },
onCopyAll: fn(), },
messages: [ };
{
role: "user", export const WithError: Story = {
content: { args: {
type: "text", prompts: samplePrompts,
text: 'Translate the following text to Spanish: "Hello, how are you?"', selectedPromptName: "translate",
}, getPromptState: {
}, status: "error",
{ error:
role: "assistant", 'Prompt "translate" requires argument "text" but none was provided. Please fill in all required arguments before submitting.',
content: {
type: "text",
text: "Hola, como estas?",
},
},
],
}, },
}, },
}; };

View file

@ -1,32 +1,37 @@
import { Card, Flex, Group, ScrollArea, Stack, Text } from "@mantine/core"; import { useState } from "react";
import {
Alert,
Card,
Flex,
Group,
Loader,
ScrollArea,
Stack,
Text,
} from "@mantine/core";
import type {
GetPromptResult,
Prompt,
} from "@modelcontextprotocol/sdk/types.js";
import { PromptControls } from "../../groups/PromptControls/PromptControls"; import { PromptControls } from "../../groups/PromptControls/PromptControls";
import { PromptArgumentsForm } from "../../groups/PromptArgumentsForm/PromptArgumentsForm"; import { PromptArgumentsForm } from "../../groups/PromptArgumentsForm/PromptArgumentsForm";
import { PromptMessagesDisplay } from "../../groups/PromptMessagesDisplay/PromptMessagesDisplay"; import { PromptMessagesDisplay } from "../../groups/PromptMessagesDisplay/PromptMessagesDisplay";
import type { PromptArgument } from "../../groups/PromptArgumentsForm/PromptArgumentsForm";
import type { PromptMessagesDisplayProps } from "../../groups/PromptMessagesDisplay/PromptMessagesDisplay";
export interface PromptItem { export interface GetPromptState {
name: string; status: "idle" | "pending" | "ok" | "error";
description?: string; result?: GetPromptResult;
selected: boolean; error?: string;
}
export interface SelectedPrompt {
name: string;
description?: string;
arguments: PromptArgument[];
argumentValues: Record<string, string>;
} }
export interface PromptsScreenProps { export interface PromptsScreenProps {
prompts: PromptItem[]; prompts: Prompt[];
selectedPrompt?: SelectedPrompt; selectedPromptName?: string;
messages?: PromptMessagesDisplayProps; getPromptState?: GetPromptState;
listChanged: boolean; listChanged: boolean;
onRefreshList: () => void; onRefreshList: () => void;
onSelectPrompt: (name: string) => void; onSelectPrompt: (name: string) => void;
onArgumentChange: (name: string, value: string) => void; onGetPrompt: (name: string, args: Record<string, string>) => void;
onGetPrompt: () => void; onCopyMessages?: () => void;
} }
const ScreenLayout = Flex.withProps({ const ScreenLayout = Flex.withProps({
@ -60,23 +65,34 @@ const EmptyState = Text.withProps({
export function PromptsScreen({ export function PromptsScreen({
prompts, prompts,
selectedPrompt, selectedPromptName,
messages, getPromptState,
listChanged, listChanged,
onRefreshList, onRefreshList,
onSelectPrompt, onSelectPrompt,
onArgumentChange,
onGetPrompt, onGetPrompt,
onCopyMessages,
}: PromptsScreenProps) { }: PromptsScreenProps) {
const [argumentValues, setArgumentValues] = useState<Record<string, string>>(
{},
);
const selectedPrompt = selectedPromptName
? prompts.find((p) => p.name === selectedPromptName)
: undefined;
return ( return (
<ScreenLayout> <ScreenLayout>
<Sidebar> <Sidebar>
<SidebarCard> <SidebarCard>
<PromptControls <PromptControls
prompts={prompts} prompts={prompts}
selectedName={selectedPromptName}
listChanged={listChanged} listChanged={listChanged}
onRefreshList={onRefreshList} onRefreshList={onRefreshList}
onSelectPrompt={onSelectPrompt} onSelectPrompt={(name) => {
setArgumentValues({});
onSelectPrompt(name);
}}
/> />
</SidebarCard> </SidebarCard>
</Sidebar> </Sidebar>
@ -90,17 +106,37 @@ export function PromptsScreen({
<> <>
<DetailCard> <DetailCard>
<PromptArgumentsForm <PromptArgumentsForm
name={selectedPrompt.name} prompt={selectedPrompt}
description={selectedPrompt.description} argumentValues={argumentValues}
arguments={selectedPrompt.arguments} onArgumentChange={(name, value) =>
argumentValues={selectedPrompt.argumentValues} setArgumentValues((prev) => ({ ...prev, [name]: value }))
onArgumentChange={onArgumentChange} }
onGetPrompt={onGetPrompt} onGetPrompt={() =>
onGetPrompt(selectedPrompt.name, argumentValues)
}
/> />
</DetailCard> </DetailCard>
{messages && ( {getPromptState?.status === "pending" && (
<DetailCard> <DetailCard>
<PromptMessagesDisplay {...messages} /> <Stack align="center" py="xl">
<Loader size="sm" />
<Text c="dimmed">Loading prompt...</Text>
</Stack>
</DetailCard>
)}
{getPromptState?.status === "error" && (
<DetailCard>
<Alert color="red" variant="light" title="Prompt Error">
{getPromptState.error ?? "Failed to get prompt"}
</Alert>
</DetailCard>
)}
{getPromptState?.result && (
<DetailCard>
<PromptMessagesDisplay
messages={getPromptState.result.messages}
onCopyAll={onCopyMessages}
/>
</DetailCard> </DetailCard>
)} )}
</> </>

View file

@ -594,60 +594,52 @@ export const PromptsActive: Story = {
{ {
name: "summarize", name: "summarize",
description: "Summarize a document", description: "Summarize a document",
selected: false,
}, },
{ {
name: "translate", name: "translate",
description: "Translate text to another language", description: "Translate text to another language",
selected: true, arguments: [
{
name: "text",
required: true,
description: "The text to translate",
},
{
name: "targetLanguage",
required: true,
description: "Target language code",
},
],
}, },
{ {
name: "code-review", name: "code-review",
description: "Review code for issues", description: "Review code for issues",
selected: false,
}, },
]} ]}
selectedPrompt={{ selectedPromptName="translate"
name: "translate", getPromptState={{
description: "Translate text to another language", status: "ok",
arguments: [ result: {
{ messages: [
name: "text", {
required: true, role: "user",
description: "The text to translate", content: {
}, type: "text",
{ text: 'Translate the following text to Spanish: "Hello, how are you?"',
name: "targetLanguage", },
required: true,
description: "Target language code",
},
],
argumentValues: {
text: "Hello, how are you?",
targetLanguage: "es",
},
}}
messages={{
onCopyAll: fn(),
messages: [
{
role: "user",
content: {
type: "text",
text: 'Translate the following text to Spanish: "Hello, how are you?"',
}, },
}, {
{ role: "assistant",
role: "assistant", content: { type: "text", text: "Hola, como estas?" },
content: { type: "text", text: "Hola, como estas?" }, },
}, ],
], },
}} }}
listChanged={true} listChanged={true}
onRefreshList={fn()} onRefreshList={fn()}
onSelectPrompt={fn()} onSelectPrompt={fn()}
onArgumentChange={fn()}
onGetPrompt={fn()} onGetPrompt={fn()}
onCopyMessages={fn()}
/> />
), ),
}, },