Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(prompts): Render prompt messages on prompt detail view #5786

Merged
Merged
7 changes: 6 additions & 1 deletion app/src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { PromptLayout } from "./pages/prompt/PromptLayout";
import { PromptPlaygroundPage } from "./pages/prompt/PromptPlaygroundPage";
import { PromptVersionDetailsPage } from "./pages/prompt/PromptVersionDetailsPage";
import { promptVersionLoader } from "./pages/prompt/promptVersionLoader";
import { promptVersionsLoader } from "./pages/prompt/promptVersionsLoader";
import { PromptVersionsPage } from "./pages/prompt/PromptVersionsPage";
import { sessionLoader } from "./pages/trace/sessionLoader";
import { SessionPage } from "./pages/trace/SessionPage";
Expand Down Expand Up @@ -224,7 +225,11 @@ const router = createBrowserRouter(
>
<Route element={<PromptLayout />}>
<Route index element={<PromptIndexPage />} />
<Route path="versions" element={<PromptVersionsPage />}>
<Route
path="versions"
loader={promptVersionsLoader}
element={<PromptVersionsPage />}
>
<Route
path=":versionId"
loader={promptVersionLoader}
Expand Down
1 change: 0 additions & 1 deletion app/src/components/CopyToClipboardButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export function CopyToClipboardButton({
disabled = false,
}: {
text: string;

size?: ButtonProps["size"];
disabled?: boolean;
}) {
Expand Down
28 changes: 28 additions & 0 deletions app/src/components/templateEditor/TemplateEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import CodeMirror, {
EditorView,
ReactCodeMirrorProps,
} from "@uiw/react-codemirror";
import { css } from "@emotion/react";

import { useTheme } from "@phoenix/contexts";
import { assertUnreachable } from "@phoenix/typeUtils";
Expand Down Expand Up @@ -59,3 +60,30 @@ export const TemplateEditor = ({
/>
);
};

export const TemplateEditorWrap = ({
children,
}: {
children: React.ReactNode;
}) => {
return (
<div
css={css`
& .cm-content {
padding: var(--ac-global-dimension-size-100)
var(--ac-global-dimension-size-250);
}
& .cm-gutter,
cephalization marked this conversation as resolved.
Show resolved Hide resolved
& .cm-content {
min-height: 75px;
cephalization marked this conversation as resolved.
Show resolved Hide resolved
}
& .cm-line {
padding-left: 0;
padding-right: 0;
}
`}
>
{children}
</div>
);
};
24 changes: 6 additions & 18 deletions app/src/pages/playground/PlaygroundChatTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ import {
import { CopyToClipboardButton } from "@phoenix/components";
import { CodeWrap, JSONEditor } from "@phoenix/components/code";
import { DragHandle } from "@phoenix/components/dnd/DragHandle";
import { TemplateEditor } from "@phoenix/components/templateEditor";
import {
TemplateEditor,
TemplateEditorWrap,
} from "@phoenix/components/templateEditor";
import { TemplateLanguage } from "@phoenix/components/templateEditor/types";
import { usePlaygroundContext } from "@phoenix/contexts/PlaygroundContext";
import { useChatMessageStyles } from "@phoenix/hooks/useChatMessageStyles";
Expand Down Expand Up @@ -262,22 +265,7 @@ function MessageEditor({
);
}
return (
<div
css={css`
& .cm-content {
padding: var(--ac-global-dimension-size-100)
var(--ac-global-dimension-size-250);
}
& .cm-gutter,
& .cm-content {
min-height: 75px;
}
& .cm-line {
padding-left: 0;
padding-right: 0;
}
`}
>
<TemplateEditorWrap>
<TemplateEditor
height="100%"
value={
Expand All @@ -296,7 +284,7 @@ function MessageEditor({
: "What is the weather in San Francisco?"
}
/>
</div>
</TemplateEditorWrap>
);
}

Expand Down
29 changes: 19 additions & 10 deletions app/src/pages/prompt/ChatTemplateMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,44 @@
import React from "react";

import { Button, Card, Icon, Icons } from "@arizeai/components";
import { Card } from "@arizeai/components";

import { CopyToClipboardButton } from "@phoenix/components";
import {
TemplateEditor,
TemplateEditorWrap,
} from "@phoenix/components/templateEditor";
import { TemplateLanguage } from "@phoenix/components/templateEditor/types";
import { useChatMessageStyles } from "@phoenix/hooks/useChatMessageStyles";

export type ChatTemplateMessageProps = {
role: string;
content: string;
templateFormat: TemplateLanguage;
};

/**
* A Read-Only CodeMirror component for the chat template message
* E.x. a system or user message template part
*/
export function ChatTemplateMessage(props: ChatTemplateMessageProps) {
const { role, content } = props;
const { role, content, templateFormat } = props;
const styles = useChatMessageStyles(role);
return (
<Card
title={role}
variant="compact"
{...styles}
extra={
<Button
variant="default"
size="compact"
icon={<Icon svg={<Icons.ClipboardCopy />} />}
/>
}
bodyStyle={{ padding: 0 }}
extra={<CopyToClipboardButton text={content} />}
>
{content}
<TemplateEditorWrap>
<TemplateEditor
readOnly
height="100%"
value={content}
templateLanguage={templateFormat}
/>
</TemplateEditorWrap>
</Card>
);
}
81 changes: 81 additions & 0 deletions app/src/pages/prompt/PromptChatMessages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useMemo } from "react";
import { useFragment } from "react-relay";
import { graphql } from "relay-runtime";

import { Flex, Text } from "@arizeai/components";

import { TemplateLanguages } from "@phoenix/components/templateEditor/constants";
import { TemplateLanguage } from "@phoenix/components/templateEditor/types";

import {
PromptChatMessages__main$key,
PromptTemplateFormat,
} from "./__generated__/PromptChatMessages__main.graphql";
import { ChatTemplateMessage } from "./ChatTemplateMessage";
import { PromptChatTemplate, PromptChatTemplateSchema } from "./schemas";

const convertTemplateFormat = (
templateFormat: PromptTemplateFormat
): TemplateLanguage => {
if (templateFormat === "FSTRING") {
return TemplateLanguages.FString;
} else if (templateFormat === "MUSTACHE") {
return TemplateLanguages.Mustache;
}
return TemplateLanguages.NONE;
};

export function PromptChatMessages({
promptVersion,
}: {
promptVersion: PromptChatMessages__main$key;
}) {
const { template, templateType, templateFormat } = useFragment(
graphql`
fragment PromptChatMessages__main on PromptVersion {
template
templateType
templateFormat
}
`,
promptVersion
);

if (templateType === "STRING") {
return <Text>{template}</Text>;
}

return (
<ChatMessages
template={template}
templateFormat={convertTemplateFormat(templateFormat)}
/>
);
}

function ChatMessages({
template,
templateFormat,
}: {
template: PromptChatTemplate | unknown;
templateFormat: TemplateLanguage;
}) {
const messages = useMemo(() => {
const parsedTemplate = PromptChatTemplateSchema.safeParse(template);
if (!parsedTemplate.success) {
return [];
Copy link
Contributor

Choose a reason for hiding this comment

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

thought: display an error if you fail to parse? I guess this code will go away

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this is intended to be deleted next PR ideally

}
return parsedTemplate.data.messages;
}, [template]);
return (
<Flex direction="column" gap="size-200">
{messages.map((message, i) => (
<ChatTemplateMessage
key={i}
{...message}
templateFormat={templateFormat}
/>
))}
</Flex>
);
}
19 changes: 11 additions & 8 deletions app/src/pages/prompt/PromptIndexPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {

import { PromptIndexPage__aside$key } from "./__generated__/PromptIndexPage__aside.graphql";
import { PromptIndexPage__main$key } from "./__generated__/PromptIndexPage__main.graphql";
import { ChatTemplateMessage } from "./ChatTemplateMessage";
import { PromptChatMessages } from "./PromptChatMessages";
import { PromptInvocationParameters } from "./PromptInvocationParameters";
import { usePromptIdLoader } from "./usePromptIdLoader";

Expand All @@ -40,6 +40,7 @@ export function PromptIndexPageContent({
edges {
node {
...PromptInvocationParameters__main
...PromptChatMessages__main
}
}
}
Expand All @@ -53,20 +54,22 @@ export function PromptIndexPageContent({

return (
<Flex direction="row" height="100%">
<View height="100%" overflow="auto" data-testid="scroll-container">
<View
height="100%"
overflow="auto"
width="100%"
data-testid="scroll-container"
>
<View padding="size-200">
<Flex
direction="column"
gap="size-200"
maxWidth={900}
marginStart="auto"
marginEnd="auto"
maxWidth={900}
>
<Card title="Prompt Template" variant="compact">
<Flex direction="column" gap="size-100">
<ChatTemplateMessage role="system" content="System message" />
<ChatTemplateMessage role="user" content="User message" />
</Flex>
<PromptChatMessages promptVersion={latestVersion} />
</Card>
<Card
title="Model Configuration"
Expand Down Expand Up @@ -125,7 +128,7 @@ function PromptIndexPageAside({
return (
<View
flex="none"
width="400px"
width={400}
borderStartColor="dark"
borderStartWidth="thin"
>
Expand Down
4 changes: 2 additions & 2 deletions app/src/pages/prompt/PromptInvocationParameters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ export function PromptInvocationParameters({

return (
<List listSize="small">
{parameters.map(({ key, value }) => (
<ListItem key="key">
{parameters.map(({ key, value }, i) => (
<ListItem key={`${key}-${i}`}>
<PromptInvocationParameterItem keyName={key} value={value} />
</ListItem>
))}
Expand Down
4 changes: 4 additions & 0 deletions app/src/pages/prompt/PromptVersionDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "@arizeai/components";

import { promptVersionLoaderQuery$data } from "./__generated__/promptVersionLoaderQuery.graphql";
import { PromptChatMessages } from "./PromptChatMessages";
import { PromptInvocationParameters } from "./PromptInvocationParameters";

export function PromptVersionDetailsPage() {
Expand All @@ -31,6 +32,9 @@ function PromptVersionDetailsPageContent({
marginStart="auto"
marginEnd="auto"
>
<Card title="Prompt">
<PromptChatMessages promptVersion={promptVersion} />
</Card>
<Card
title="Model Configuration"
variant="compact"
Expand Down
15 changes: 12 additions & 3 deletions app/src/pages/prompt/PromptVersionsList.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { useFragment } from "react-relay";
import { graphql } from "react-relay";
import { useNavigate } from "react-router";
import { useNavigate, useParams } from "react-router";
import { css } from "@emotion/react";

import { Button, Flex, Text, View } from "@arizeai/components";
Expand All @@ -26,6 +26,8 @@ const promptVersionItemCSS = css`
width: 100%;
justify-content: flex-start;
padding: 0;
border-radius: 0;
border: none;
}
`;

Expand All @@ -35,10 +37,15 @@ const promptVersionItemCSS = css`
* add /:versionId to the current path
*/
export const PromptVersionItem = ({ version }: PromptVersionItemProps) => {
const { versionId } = useParams();
cephalization marked this conversation as resolved.
Show resolved Hide resolved
const navigate = useNavigate();
const active = versionId === version.id;
cephalization marked this conversation as resolved.
Show resolved Hide resolved
return (
<div css={promptVersionItemCSS}>
<Button onClick={() => navigate(`${version.id}`)} variant="quiet">
<Button
onClick={() => navigate(`${version.id}`)}
variant={active ? "default" : "quiet"}
>
cephalization marked this conversation as resolved.
Show resolved Hide resolved
<Flex width="100%" height={96} direction="row">
<View padding="size-200">
<Flex direction="column">
Expand Down Expand Up @@ -85,9 +92,11 @@ export const PromptVersionsList = ({ prompt }: PromptVersionsListProps) => {
return (
<View
height="100%"
overflow="scroll"
overflow="auto"
width={PROMPT_VERSIONS_LIST_WIDTH}
minWidth={PROMPT_VERSIONS_LIST_WIDTH}
borderRightWidth="thin"
borderColor="grey-300"
>
<Flex direction="column">
{promptVersions.edges.map(({ version }) => (
Expand Down
Loading
Loading