diff --git a/app/src/Routes.tsx b/app/src/Routes.tsx index d97d015dce..dc6c42057f 100644 --- a/app/src/Routes.tsx +++ b/app/src/Routes.tsx @@ -5,6 +5,7 @@ import { createBrowserRouter } from "react-router-dom"; import { datasetLoaderQuery$data } from "./pages/dataset/__generated__/datasetLoaderQuery.graphql"; import { embeddingLoaderQuery$data } from "./pages/embedding/__generated__/embeddingLoaderQuery.graphql"; import { Layout } from "./pages/Layout"; +import { spanPlaygroundPageLoaderQuery$data } from "./pages/playground/__generated__/spanPlaygroundPageLoaderQuery.graphql"; import { projectLoaderQuery$data } from "./pages/project/__generated__/projectLoaderQuery.graphql"; import { APIsPage, @@ -40,6 +41,8 @@ import { ResetPasswordPage, ResetPasswordWithTokenPage, SettingsPage, + SpanPlaygroundPage, + spanPlaygroundPageLoader, TracePage, TracingRoot, } from "./pages"; @@ -157,11 +160,25 @@ const router = createBrowserRouter( } handle={{ crumb: () => "Playground", }} - /> + > + } /> + } + loader={spanPlaygroundPageLoader} + handle={{ + crumb: (data: spanPlaygroundPageLoaderQuery$data) => { + if (data.span.__typename === "Span") { + return `span ${data.span.context.spanId}`; + } + return "span unknown"; + }, + }} + /> + } diff --git a/app/src/pages/playground/Playground.tsx b/app/src/pages/playground/Playground.tsx index b326596816..4fe7b37344 100644 --- a/app/src/pages/playground/Playground.tsx +++ b/app/src/pages/playground/Playground.tsx @@ -1,25 +1,16 @@ import React from "react"; import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; -import { css } from "@emotion/react"; import { Button, Flex, Heading, View } from "@arizeai/components"; import { resizeHandleCSS } from "@phoenix/components/resize"; -import { PlaygroundProvider } from "@phoenix/contexts/PlaygroundContext"; +import { + PlaygroundProvider, + usePlaygroundContext, +} from "@phoenix/contexts/PlaygroundContext"; -import { PlaygroundInput } from "./PlaygroundInput"; +import { PlaygroundInstance } from "./PlaygroundInstance"; import { PlaygroundOperationTypeRadioGroup } from "./PlaygroundOperationTypeRadioGroup"; -import { PlaygroundOutput } from "./PlaygroundOutput"; -import { PlaygroundTemplate } from "./PlaygroundTemplate"; -import { PlaygroundTools } from "./PlaygroundTools"; - -const panelContentCSS = css` - padding: var(--ac-global-dimension-size-200); - overflow: auto; - display: flex; - flex-direction: column; - gap: var(--ac-global-dimension-size-200); -`; export function Playground() { return ( @@ -39,17 +30,25 @@ export function Playground() { + + + ); +} + +function PlaygroundInstances() { + const instances = usePlaygroundContext((state) => state.instances); + return ( + - - - - - - - - - + {instances.map((instance, i) => ( + <> + {i !== 0 && } + + + + + ))} - + ); } diff --git a/app/src/pages/playground/PlaygroundChatTemplate.tsx b/app/src/pages/playground/PlaygroundChatTemplate.tsx new file mode 100644 index 0000000000..99623e68c8 --- /dev/null +++ b/app/src/pages/playground/PlaygroundChatTemplate.tsx @@ -0,0 +1,53 @@ +import React from "react"; + +import { Card, TextArea } from "@arizeai/components"; + +import { usePlaygroundContext } from "@phoenix/contexts/PlaygroundContext"; + +import { PlaygroundInstanceProps } from "./types"; + +interface PlaygroundChatTemplateProps extends PlaygroundInstanceProps {} +export function PlaygroundChatTemplate(props: PlaygroundChatTemplateProps) { + const id = props.playgroundInstanceId; + // TODO: remove the hard coding of the first instance + const instances = usePlaygroundContext((state) => state.instances); + const updateInstance = usePlaygroundContext((state) => state.updateInstance); + const playground = instances.find((instance) => instance.id === id); + if (!playground) { + throw new Error(`Playground instance ${id} not found`); + } + const { template } = playground; + if (template.__type !== "chat") { + throw new Error(`Invalid template type ${template.__type}`); + } + + return ( +
    + {template.messages.map((message, index) => { + return ( +
  • + +