1- import { CpuChipIcon } from "@heroicons/react/20/solid" ;
1+ import { BookOpenIcon , CpuChipIcon } from "@heroicons/react/20/solid" ;
22import { json , type MetaFunction } from "@remix-run/node" ;
33import { Outlet , useNavigate , useParams , useLoaderData } from "@remix-run/react" ;
44import { type LoaderFunctionArgs } from "@remix-run/server-runtime" ;
5+ import { CodeBlock } from "~/components/code/CodeBlock" ;
6+ import { InlineCode } from "~/components/code/InlineCode" ;
57import { MainCenteredContainer , PageBody , PageContainer } from "~/components/layout/AppLayout" ;
8+ import { LinkButton } from "~/components/primitives/Buttons" ;
69import { Header2 } from "~/components/primitives/Headers" ;
7- import { NavBar , PageAccessories , PageTitle } from "~/components/primitives/PageHeader" ;
10+ import { InfoPanel } from "~/components/primitives/InfoPanel" ;
11+ import { NavBar , PageTitle } from "~/components/primitives/PageHeader" ;
812import { Paragraph } from "~/components/primitives/Paragraph" ;
913import {
1014 Select ,
@@ -15,12 +19,9 @@ import { useOrganization } from "~/hooks/useOrganizations";
1519import { useProject } from "~/hooks/useProject" ;
1620import { findProjectBySlug } from "~/models/project.server" ;
1721import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server" ;
18- import {
19- type PlaygroundAgent ,
20- playgroundPresenter ,
21- } from "~/presenters/v3/PlaygroundPresenter.server" ;
22+ import { playgroundPresenter } from "~/presenters/v3/PlaygroundPresenter.server" ;
2223import { requireUserId } from "~/services/session.server" ;
23- import { EnvironmentParamSchema , v3PlaygroundAgentPath } from "~/utils/pathBuilder" ;
24+ import { docsPath , EnvironmentParamSchema , v3PlaygroundAgentPath } from "~/utils/pathBuilder" ;
2425
2526export const meta : MetaFunction = ( ) => {
2627 return [ { title : "Playground | Trigger.dev" } ] ;
@@ -64,15 +65,52 @@ export default function PlaygroundPage() {
6465 < PageTitle title = "Playground" />
6566 </ NavBar >
6667 < PageBody >
67- < MainCenteredContainer >
68- < div className = "flex flex-col items-center gap-4 py-20" >
69- < CpuChipIcon className = "size-12 text-indigo-500" />
70- < Header2 > No agents deployed</ Header2 >
71- < Paragraph variant = "small" className = "max-w-md text-center" >
72- Create a chat agent using < code > chat.agent()</ code > from{ " " }
73- < code > @trigger.dev/sdk/ai</ code > and deploy it to see it here.
68+ < MainCenteredContainer className = "max-w-2xl" >
69+ < InfoPanel
70+ title = "Create your first agent"
71+ icon = { CpuChipIcon }
72+ iconClassName = "text-indigo-500"
73+ panelClassName = "max-w-2xl"
74+ accessory = {
75+ < LinkButton
76+ to = { docsPath ( "ai-chat/overview" ) }
77+ variant = "docs/small"
78+ LeadingIcon = { BookOpenIcon }
79+ >
80+ Agent docs
81+ </ LinkButton >
82+ }
83+ >
84+ < Paragraph spacing variant = "small" >
85+ The Playground lets you test your AI agents with an interactive chat interface,
86+ realtime streaming, and conversation history.
7487 </ Paragraph >
75- </ div >
88+ < Paragraph spacing variant = "small" >
89+ Define a chat agent using{ " " }
90+ < InlineCode variant = "small" > chat.agent()</ InlineCode > :
91+ </ Paragraph >
92+ < CodeBlock
93+ code = { `import { chat } from "@trigger.dev/sdk/ai";
94+ import { streamText } from "ai";
95+ import { openai } from "@ai-sdk/openai";
96+
97+ export const myAgent = chat.agent({
98+ id: "my-agent",
99+ run: async ({ messages, signal }) => {
100+ return streamText({
101+ model: openai("gpt-4o"),
102+ messages,
103+ abortSignal: signal,
104+ });
105+ },
106+ });` }
107+ showLineNumbers = { false }
108+ showOpenInModal = { false }
109+ />
110+ < Paragraph variant = "small" className = "mt-2" >
111+ Deploy your project and your agents will appear here ready to test.
112+ </ Paragraph >
113+ </ InfoPanel >
76114 </ MainCenteredContainer >
77115 </ PageBody >
78116 </ PageContainer >
@@ -83,35 +121,6 @@ export default function PlaygroundPage() {
83121 < PageContainer >
84122 < NavBar >
85123 < PageTitle title = "Playground" />
86- < PageAccessories >
87- < Select
88- value = { selectedAgent }
89- setValue = { ( slug ) => {
90- if ( slug && typeof slug === "string" ) {
91- navigate ( v3PlaygroundAgentPath ( organization , project , environment , slug ) ) ;
92- }
93- } }
94- icon = { < CpuChipIcon className = "size-4 text-indigo-500" /> }
95- text = { ( val ) => val || undefined }
96- placeholder = "Select an agent..."
97- variant = "tertiary/small"
98- items = { agents }
99- filter = { ( item , search ) =>
100- item . slug . toLowerCase ( ) . includes ( search . toLowerCase ( ) )
101- }
102- >
103- { ( matches ) =>
104- matches . map ( ( agent , index ) => (
105- < SelectItem key = { agent . slug } value = { agent . slug } >
106- < div className = "flex items-center gap-2" >
107- < CpuChipIcon className = "size-3.5 text-indigo-500" />
108- < span > { agent . slug } </ span >
109- </ div >
110- </ SelectItem >
111- ) )
112- }
113- </ Select >
114- </ PageAccessories >
115124 </ NavBar >
116125 < PageBody scrollable = { false } >
117126 { selectedAgent ? (
@@ -121,9 +130,36 @@ export default function PlaygroundPage() {
121130 < div className = "flex flex-col items-center gap-4 py-20" >
122131 < CpuChipIcon className = "size-10 text-indigo-500/50" />
123132 < Header2 className = "text-text-dimmed" > Select an agent</ Header2 >
124- < Paragraph variant = "small" className = "max-w-md text-center text-text-dimmed" >
125- Choose an agent from the dropdown to start a conversation.
133+ < Paragraph variant = "small" className = "mb-2 max-w-md text-center text-text-dimmed" >
134+ Choose an agent to start a conversation.
126135 </ Paragraph >
136+ < Select
137+ value = { selectedAgent }
138+ setValue = { ( slug ) => {
139+ if ( slug && typeof slug === "string" ) {
140+ navigate ( v3PlaygroundAgentPath ( organization , project , environment , slug ) ) ;
141+ }
142+ } }
143+ icon = { < CpuChipIcon className = "size-4 text-indigo-500" /> }
144+ text = { ( val ) => val || undefined }
145+ placeholder = "Select an agent..."
146+ variant = "tertiary/small"
147+ items = { agents }
148+ filter = { ( item , search ) =>
149+ item . slug . toLowerCase ( ) . includes ( search . toLowerCase ( ) )
150+ }
151+ >
152+ { ( matches ) =>
153+ matches . map ( ( agent ) => (
154+ < SelectItem key = { agent . slug } value = { agent . slug } >
155+ < div className = "flex items-center gap-2" >
156+ < CpuChipIcon className = "size-3.5 text-indigo-500" />
157+ < span > { agent . slug } </ span >
158+ </ div >
159+ </ SelectItem >
160+ ) )
161+ }
162+ </ Select >
127163 </ div >
128164 </ MainCenteredContainer >
129165 ) }
0 commit comments