Skip to content

Commit 6fbe9f9

Browse files
Add full Code interpreter output, fixing #17 and #32
1 parent fb1f30f commit 6fbe9f9

File tree

12 files changed

+192
-79
lines changed

12 files changed

+192
-79
lines changed

playground/markdown-react-demo/src/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { CodeHighlight } from './utils/highlight';
66
import Callout from './components/Callout'
77
import './index.css';
88
import 'highlight.js/styles/github.css';
9-
import { getTextFromChildren } from './utils/utility'
9+
import { getScriptContentFromChildren } from './utils/utility'
1010
import { Clipboard, ClipboardCheck } from 'lucide-react';
1111

1212
const markdown = `
@@ -36,7 +36,7 @@ function App() {
3636
code(props) {
3737
const { children } = props;
3838
console.log('props', props);
39-
const text = getTextFromChildren(children);
39+
const text = getScriptContentFromChildren(children);
4040
return (
4141
<Callout title='Code' icon='FileCode2' foldable content={
4242
<>

playground/markdown-react-demo/src/utils/utility.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export function getTextFromChildren(children: React.ReactNode): string {
1+
export function getScriptContentFromChildren(children: React.ReactNode): string {
22
if (typeof children === 'string') return children;
33
if (Array.isArray(children)) {
44
return children.map((c) => (typeof c === 'string' ? c : '')).join('');

workshop-ui/src/app/api/chat/codeExecutionTool.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ export type ExecutePythonOutput = {
2323
executionResult: string;
2424
};
2525

26+
export type ResultFile = {
27+
fileName: string;
28+
targetFileName: string;
29+
url: string;
30+
originalFileName: string;
31+
};
32+
2633
export const executePythonTool: FunctionTool = {
2734
type: 'function',
2835
name: 'execute_python',
@@ -39,13 +46,6 @@ will return alongside the script output.`,
3946
export async function executePython(script: string, filePaths: string[], instanceId?: string) {
4047
var dynamicSession = new DynamicSession(instanceId);
4148

42-
type ResultFile = {
43-
fileName: string;
44-
targetFileName: string;
45-
url: string;
46-
originalFileName: string;
47-
};
48-
4949
const result = await dynamicSession.executeScript(script, filePaths);
5050
const resultFiles: ResultFile[] = (await dynamicSession.getExistingFiles())
5151
.filter(f => !filePaths.map(fp => fp.split('/').pop()).includes(f))

workshop-ui/src/app/api/chat/openaiRunner.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export async function runOpenAI(message: string, instructions: string,
7272
if (event.item.type === 'function_call') {
7373
currentFunctionName = event.item.name;
7474
currentFunctionCallId = event.item.call_id;
75-
messageDeltaCallback('\n\n```py\n');
75+
messageDeltaCallback('\n\n```py\n<|TOOL_CODE_INTERPRETER|>\n');
7676
}
7777
break;
7878
}
@@ -83,13 +83,22 @@ export async function runOpenAI(message: string, instructions: string,
8383
}
8484
case 'response.function_call_arguments.done': {
8585
if (enableCodeInterpreter && runScriptCallback) {
86-
messageDeltaCallback('\n```\n\n');
86+
messageDeltaCallback('\n<|OUTPUT|>\n');
8787
const script: ExecutePythonParameters = JSON.parse(currentScript);
88-
const result = await runScriptCallback(script.script);
88+
const result = JSON.parse(await runScriptCallback(script.script));
89+
messageDeltaCallback(JSON.stringify(result));
90+
messageDeltaCallback('\n```\n\n');
91+
if (result.resultFiles) {
92+
for (const resultFile of result.resultFiles) {
93+
// TODO: handle non-image files differently (see GH issue #29)
94+
const markdownImage = `![Generated Image](${resultFile.url})`;
95+
messageDeltaCallback(markdownImage);
96+
}
97+
}
8998
input.push({
9099
type: 'function_call_output',
91100
call_id: currentFunctionCallId!,
92-
output: result,
101+
output: JSON.stringify(result),
93102
})
94103
}
95104
break;

workshop-ui/src/app/api/chat/prompt-engineering/route.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,7 @@ export async function POST(request: NextRequest) {
8585

8686
// Update session with new response ID
8787
// Encrypt previousResponseId before sending to client
88-
let encryptedResponseId: string | undefined;
89-
// console.log('New previousResponseId:', newPreviousResponseId);
90-
// console.log('Encryption key:', process.env.PREVIOUS_RESPONSE_ID_SECRET);
91-
// Revert key.toString('hex') first
92-
93-
encryptedResponseId = encrypt(newPreviousResponseId, Buffer.from(process.env.PREVIOUS_RESPONSE_ID_SECRET!, 'hex'));
88+
let encryptedResponseId = encrypt(newPreviousResponseId, Buffer.from(process.env.PREVIOUS_RESPONSE_ID_SECRET!, 'hex'));
9489

9590
const data = JSON.stringify({ encryptedResponseId });
9691
controller.enqueue(encoder.encode(`data: ${data}\n\n`));

workshop-ui/src/app/api/chat/route.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,9 @@ export async function POST(request: NextRequest) {
5858

5959
let previousResponseId: string | undefined = undefined;
6060
if (encryptedPreviousResponseId) {
61-
// console.log('Received encryptedPreviousResponseId:', encryptedPreviousResponseId);
6261
try {
6362
previousResponseId = decrypt(encryptedPreviousResponseId, Buffer.from(process.env.PREVIOUS_RESPONSE_ID_SECRET!, 'hex'));
64-
} catch {
65-
}
63+
} catch {}
6664
}
6765

6866
// Read system prompt
@@ -106,29 +104,13 @@ Achtung! Die Dateien haben mehr Zeilen als hier gezeigt. Alle Dateien sind im Or
106104
exerciseData.data_files.map(f => path.join(process.cwd(), 'prompts', exerciseData.folder, f)),
107105
sessionId
108106
);
109-
if (result.resultFiles) {
110-
for (const resultFile of result.resultFiles) {
111-
// TODO: handle non-image files differently (see GH issue #29)
112-
const markdownImage = `![Generated Image](${resultFile.url})`;
113-
const data = JSON.stringify({ delta: `\n\n${markdownImage}\n\n` });
114-
controller.enqueue(encoder.encode(`data: ${data}\n\n`));
115-
}
116-
}
117-
if (result.stdout || result.stderr) {
118-
// TODO: send the output as a collapsed section (see GH issue #17)
119-
}
120107
return JSON.stringify(result);
121108
},
122109
);
123110

124111
// Update session with new response ID
125112
// Encrypt previousResponseId before sending to client
126-
let encryptedResponseId: string | undefined;
127-
// console.log('New previousResponseId:', newPreviousResponseId);
128-
// console.log('Encryption key:', process.env.PREVIOUS_RESPONSE_ID_SECRET);
129-
// Revert key.toString('hex') first
130-
131-
encryptedResponseId = encrypt(newPreviousResponseId, Buffer.from(process.env.PREVIOUS_RESPONSE_ID_SECRET!, 'hex'));
113+
let encryptedResponseId = encrypt(newPreviousResponseId, Buffer.from(process.env.PREVIOUS_RESPONSE_ID_SECRET!, 'hex'));
132114

133115
const data = JSON.stringify({ encryptedResponseId });
134116
controller.enqueue(encoder.encode(`data: ${data}\n\n`));

workshop-ui/src/app/chat/[exercise]/page.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export default function Home() {
188188

189189
for (const line of lines) {
190190
if (line.startsWith('data: ')) {
191-
const data = line.slice(6);
191+
const data = line.slice(6); // Remove 'data: ' prefix
192192
if (data === '[DONE]') {
193193
// Finalize the assistant message
194194
const assistantMsg: MessageType = {
@@ -312,11 +312,22 @@ export default function Home() {
312312
))}
313313

314314
{currentBotMessage &&
315-
<Message message={{
316-
role: 'assistant',
317-
content: currentBotMessage,
318-
type: 'text'
319-
}} />
315+
<>
316+
<Message message={{
317+
role: 'assistant',
318+
content: currentBotMessage,
319+
type: 'text'
320+
}} />
321+
{isLoading && (
322+
<div className={`${styles.message} ${styles.assistantMessage}`}>
323+
<div className={styles.loader}>
324+
<div className={styles.dot} />
325+
<div className={styles.dot} />
326+
<div className={styles.dot} />
327+
</div>
328+
</div>
329+
)}
330+
</>
320331
}
321332

322333
<div ref={messagesEndRef} />

workshop-ui/src/app/prompt-engineering/page.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ export default function Home() {
223223
}
224224
if (parsed.encryptedResponseId) {
225225
setResponseId(parsed.encryptedResponseId);
226-
console.log('Received encryptedResponseId:', parsed.encryptedResponseId);
227226
}
228227
} catch {
229228
// Ignore parsing errors for SSE data
@@ -311,7 +310,6 @@ export default function Home() {
311310
}
312311
if (parsed.encryptedResponseId) {
313312
setMetaResponseId(parsed.encryptedResponseId);
314-
console.log('Received encryptedResponseId:', parsed.encryptedResponseId);
315313
}
316314
} catch {
317315
// Ignore parsing errors for SSE data

workshop-ui/src/components/SystemPrompt.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useState, useEffect, useMemo } from 'react';
44
import styles from './SystemPrompt.module.css';
55
import Markdown from 'react-markdown';
66
import remarkGfm from "remark-gfm";
7-
import { getTextFromChildren, hashString } from '@/lib/utility';
7+
import { getScriptContentFromChildren, hashString } from '@/lib/utility';
88
import { Clipboard, ClipboardCheck } from 'lucide-react';
99
import Callout from './Callout';
1010
import CodeHighlight from './CodeHighlight';
@@ -30,7 +30,7 @@ export default function SystemPrompt({ exerciseId, type = 'system-prompt' }: Rea
3030
// eslint-disable-next-line react/no-unstable-nested-components
3131
code(props: any) {
3232
const { children } = props;
33-
const text = getTextFromChildren(children);
33+
const text = getScriptContentFromChildren(children);
3434
const key = `code-${hashString(text || '')}`;
3535
return (
3636
<Callout

workshop-ui/src/components/chat/Message.module.css

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,43 @@
8686
margin-top: 8px;
8787
}
8888

89+
.outputContainer {
90+
display: flex;
91+
flex-direction: column;
92+
gap: 10px;
93+
94+
.stderr {
95+
color: red;
96+
background-color: #ffe6e6;
97+
}
98+
99+
.resultFilesContainer {
100+
padding: .5em;
101+
display: block;
102+
overflow-x: auto;
103+
background: #f8f8f8;
104+
105+
border-radius: 5px;
106+
107+
.resultFile {
108+
color: #333;
109+
font-size: 16px;
110+
display: block;
111+
112+
&:not(:last-child) {
113+
margin-bottom: 8px;
114+
}
115+
}
116+
}
117+
}
118+
119+
.loadingContainer {
120+
display: flex;
121+
justify-content: center;
122+
align-items: center;
123+
height: 70px;
124+
}
125+
89126
.copyButton {
90127
background: none;
91128
border: none;
@@ -97,4 +134,4 @@
97134
z-index: 1;
98135
padding: 0;
99136
margin: 0;
100-
}
137+
}

0 commit comments

Comments
 (0)