Skip to content

Commit cbc4087

Browse files
updated preview
1 parent 1945903 commit cbc4087

File tree

7 files changed

+138
-103
lines changed

7 files changed

+138
-103
lines changed

app/api/code/execute/route.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextResponse } from 'next/server'
2+
import { evaluateCode } from '@/app/api/chat/codeInterpreter'
3+
4+
export async function POST(req: Request) {
5+
try {
6+
const { sessionID, code } = await req.json()
7+
8+
if (!sessionID || !code) {
9+
return NextResponse.json(
10+
{ error: 'sessionID and code are required' },
11+
{ status: 400 },
12+
)
13+
}
14+
15+
const result = await evaluateCode(sessionID, code)
16+
return NextResponse.json(result)
17+
} catch (error: any) {
18+
return NextResponse.json(
19+
{ error: error.message || 'An unexpected error occurred' },
20+
{ status: 500 },
21+
)
22+
}
23+
}

app/api/files/content/route.ts

Lines changed: 0 additions & 36 deletions
This file was deleted.

app/api/files/route.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

app/page.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { experimental_useObject as useObject } from 'ai/react'
2424
import { usePostHog } from 'posthog-js/react'
2525
import { SetStateAction, useCallback, useEffect, useState } from 'react'
2626
import { useLocalStorage } from 'usehooks-ts'
27+
import { useEnhancedChat } from '@/hooks/use-enhanced-chat'
2728

2829
export default function Home() {
2930
const supabase = createBrowserClient()
@@ -54,6 +55,14 @@ export default function Home() {
5455

5556
const { session, userTeam } = useAuth(setAuthDialog, setAuthView)
5657

58+
const { executeCode } = useEnhancedChat({
59+
userID: session?.user?.id,
60+
teamID: userTeam?.id,
61+
template: templates,
62+
model: modelsList.models.find(m => m.id === languageModel.model)!,
63+
config: languageModel,
64+
})
65+
5766
const handleChatSelected = async (chatId: string) => {
5867
const project = await getProject(chatId);
5968
if (project) {
@@ -369,6 +378,7 @@ export default function Home() {
369378
messages={messages}
370379
isLoading={isLoading}
371380
setCurrentPreview={setCurrentPreview}
381+
executeCode={executeCode}
372382
/>
373383
)}
374384

components/chat.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
import { Message } from '@/lib/messages'
22
import { FragmentSchema } from '@/lib/schema'
3-
import { ExecutionResult } from '@/lib/types'
3+
import { ExecutionResult, ExecutionResultInterpreter } from '@/lib/types'
44
import { DeepPartial } from 'ai'
55
import { LoaderIcon, Terminal } from 'lucide-react'
66
import Image from 'next/image'
77
import { useEffect } from 'react'
8+
import { FragmentInterpreter } from './fragment-interpreter'
89

910
export function Chat({
1011
messages,
1112
isLoading,
1213
setCurrentPreview,
14+
executeCode,
1315
}: {
1416
messages: Message[]
1517
isLoading: boolean
1618
setCurrentPreview: (preview: {
1719
fragment: DeepPartial<FragmentSchema> | undefined
1820
result: ExecutionResult | undefined
1921
}) => void
22+
executeCode: (code: string) => Promise<void>
2023
}) {
2124
const messagesString = JSON.stringify(messages)
2225
useEffect(() => {
@@ -53,7 +56,7 @@ export function Chat({
5356
)
5457
}
5558
})}
56-
{message.object && (
59+
{message.object && message.object.template !== 'code-interpreter-v1' && (
5760
<div
5861
onClick={() =>
5962
setCurrentPreview({
@@ -76,6 +79,13 @@ export function Chat({
7679
</div>
7780
</div>
7881
)}
82+
{message.object && message.object.template === 'code-interpreter-v1' && (
83+
<FragmentInterpreter
84+
result={message.result as ExecutionResultInterpreter}
85+
code={message.object.code || ''}
86+
executeCode={executeCode}
87+
/>
88+
)}
7989
</div>
8090
))}
8191
{isLoading && (

components/fragment-interpreter.tsx

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { Alert, AlertTitle, AlertDescription } from '@/components/ui/alert'
2+
import { Button } from '@/components/ui/button'
23
import { ExecutionResultInterpreter } from '@/lib/types'
34
import { Result as CellResultData } from '@e2b/code-interpreter'
4-
import { Terminal } from 'lucide-react'
5+
import { Terminal, PlayIcon, LoaderIcon } from 'lucide-react'
56
import Image from 'next/image'
7+
import { useState } from 'react'
68

79
function CellResult({ result }: { result: CellResultData }) {
810
// Order of checks is important
@@ -92,46 +94,54 @@ function LogsOutput({
9294

9395
export function FragmentInterpreter({
9496
result,
97+
code,
98+
executeCode,
9599
}: {
96100
result: ExecutionResultInterpreter
101+
code: string
102+
executeCode: (code: string) => Promise<void>
97103
}) {
98-
const { cellResults, stdout, stderr, runtimeError } = result
104+
const [isLoading, setIsLoading] = useState(false)
105+
const { cellResults, stdout, stderr, runtimeError } = result || {}
99106

100-
// The AI-generated code experienced runtime error
101-
if (runtimeError) {
102-
const { name, value, traceback } = runtimeError
103-
return (
104-
<div className="p-4">
105-
<Alert variant="destructive">
106-
<Terminal className="h-4 w-4" />
107-
<AlertTitle>
108-
{name}: {value}
109-
</AlertTitle>
110-
<AlertDescription className="font-mono whitespace-pre-wrap">
111-
{traceback}
112-
</AlertDescription>
113-
</Alert>
114-
</div>
115-
)
107+
const handleExecute = async () => {
108+
setIsLoading(true)
109+
await executeCode(code)
110+
setIsLoading(false)
116111
}
117112

118-
if (cellResults.length > 0) {
119-
return (
120-
<div className="flex flex-col h-full">
121-
<div className="w-full flex-1 p-4 flex flex-col items-start justify-center border-b space-y-4">
122-
{cellResults.map((cellResult, index) => (
123-
<CellResult key={index} result={cellResult} />
124-
))}
125-
</div>
126-
<LogsOutput stdout={stdout} stderr={stderr} />
113+
return (
114+
<div className="flex flex-col h-full">
115+
<div className="w-full flex-1 p-4 flex flex-col items-start justify-center border-b space-y-4">
116+
{cellResults && cellResults.length > 0 && cellResults.map((cellResult, index) => (
117+
<CellResult key={index} result={cellResult} />
118+
))}
119+
{runtimeError && (
120+
<Alert variant="destructive">
121+
<Terminal className="h-4 w-4" />
122+
<AlertTitle>
123+
{runtimeError.name}: {runtimeError.value}
124+
</AlertTitle>
125+
<AlertDescription className="font-mono whitespace-pre-wrap">
126+
{runtimeError.traceback}
127+
</AlertDescription>
128+
</Alert>
129+
)}
130+
{(!cellResults || cellResults.length === 0) && !runtimeError && (
131+
<span>No output or logs</span>
132+
)}
127133
</div>
128-
)
129-
}
130-
131-
// No cell results, but there is stdout or stderr
132-
if (stdout.length > 0 || stderr.length > 0) {
133-
return <LogsOutput stdout={stdout} stderr={stderr} />
134-
}
135-
136-
return <span>No output or logs</span>
134+
<LogsOutput stdout={stdout || []} stderr={stderr || []} />
135+
<div className="p-4 border-t">
136+
<Button onClick={handleExecute} disabled={isLoading}>
137+
{isLoading ? (
138+
<LoaderIcon className="animate-spin mr-2" />
139+
) : (
140+
<PlayIcon className="mr-2" />
141+
)}
142+
Execute
143+
</Button>
144+
</div>
145+
</div>
146+
)
137147
}

hooks/use-enhanced-chat.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface EnhancedChatConfig {
2323

2424
export function useEnhancedChat(chatConfig: EnhancedChatConfig) {
2525
const [isSubmitting, setIsSubmitting] = useState(false)
26+
const [isExecuting, setIsExecuting] = useState(false)
2627
const [context, setContext] = useState({
2728
cwd: '/home/project',
2829
projectFiles: [] as string[],
@@ -31,7 +32,7 @@ export function useEnhancedChat(chatConfig: EnhancedChatConfig) {
3132
supabase: undefined as any
3233
})
3334

34-
const { messages, input, setInput, append, isLoading, stop, error } = useChat({
35+
const { messages, input, setInput, append, isLoading, stop, error, setMessages } = useChat({
3536
api: '/api/chat',
3637
body: {
3738
userID: chatConfig.userID,
@@ -100,6 +101,48 @@ export function useEnhancedChat(chatConfig: EnhancedChatConfig) {
100101
}))
101102
}, [])
102103

104+
const executeCode = useCallback(
105+
async (code: string) => {
106+
if (isExecuting) return
107+
setIsExecuting(true)
108+
109+
try {
110+
const response = await fetch('/api/code/execute', {
111+
method: 'POST',
112+
headers: {
113+
'Content-Type': 'application/json',
114+
},
115+
body: JSON.stringify({
116+
sessionID: chatConfig.userID,
117+
code,
118+
}),
119+
})
120+
121+
if (!response.ok) {
122+
const errorData = await response.json()
123+
throw new Error(errorData.error || 'Failed to execute code')
124+
}
125+
126+
const result = await response.json()
127+
128+
const lastMessage = messages[messages.length - 1]
129+
if (lastMessage) {
130+
const updatedMessage = {
131+
...lastMessage,
132+
result: result,
133+
}
134+
setMessages([...messages.slice(0, -1), updatedMessage])
135+
}
136+
137+
} catch (error: any) {
138+
trackError(error.message)
139+
} finally {
140+
setIsExecuting(false)
141+
}
142+
},
143+
[isExecuting, chatConfig.userID, trackError, messages, setMessages],
144+
)
145+
103146
useEffect(() => {
104147
if (error) {
105148
trackError(error.message)
@@ -111,11 +154,12 @@ export function useEnhancedChat(chatConfig: EnhancedChatConfig) {
111154
input,
112155
setInput,
113156
submitMessage,
114-
isLoading: isLoading || isSubmitting,
157+
isLoading: isLoading || isSubmitting || isExecuting,
115158
stop,
116159
error,
117160
context,
118161
updateContext,
119-
trackError
162+
trackError,
163+
executeCode,
120164
}
121165
}

0 commit comments

Comments
 (0)