Skip to content

Commit ce0ca89

Browse files
committed
enh: code interpreter pyodide fs
1 parent d1975b7 commit ce0ca89

12 files changed

Lines changed: 730 additions & 80 deletions

File tree

backend/open_webui/config.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2296,20 +2296,31 @@ class BannerModel(BaseModel):
22962296
]
22972297

22982298
DEFAULT_CODE_INTERPRETER_PROMPT = """
2299-
#### Tools Available
2300-
2301-
1. **Code Interpreter**: `<code_interpreter type="code" lang="python"></code_interpreter>`
2302-
- You have access to a Python shell that runs directly in the user's browser, enabling fast execution of code for analysis, calculations, or problem-solving. Use it in this response.
2303-
- The Python code you write can incorporate a wide array of libraries, handle data manipulation or visualization, perform API calls for web-related tasks, or tackle virtually any computational challenge. Use this flexibility to **think outside the box, craft elegant solutions, and harness Python's full potential**.
2304-
- To use it, **you must enclose your code within `<code_interpreter type="code" lang="python">` XML tags** and stop right away. If you don't, the code won't execute.
2305-
- When writing code in the code_interpreter XML tag, Do NOT use the triple backticks code block for markdown formatting, example: ```py # python code ``` will cause an error because it is markdown formatting, it is not python code.
2306-
- When coding, **always aim to print meaningful outputs** (e.g., results, tables, summaries, or visuals) to better interpret and verify the findings. Avoid relying on implicit outputs; prioritize explicit and clear print statements so the results are effectively communicated to the user.
2307-
- After obtaining the printed output, **always provide a concise analysis, interpretation, or next steps to help the user understand the findings or refine the outcome further.**
2308-
- If the results are unclear, unexpected, or require validation, refine the code and execute it again as needed. Always aim to deliver meaningful insights from the results, iterating if necessary.
2309-
- **If a link to an image, audio, or any file is provided in markdown format in the output, ALWAYS regurgitate word for word, explicitly display it as part of the response to ensure the user can access it easily, do NOT change the link.**
2310-
- All responses should be communicated in the chat's primary language, ensuring seamless understanding. If the chat is multilingual, default to English for clarity.
2311-
2312-
Ensure that the tools are effectively utilized to achieve the highest-quality analysis for the user."""
2299+
#### Code Interpreter
2300+
2301+
You have access to a Python code interpreter via: `<code_interpreter type="code" lang="python"></code_interpreter>`
2302+
2303+
- The Python shell runs directly in the user's browser for fast execution of analysis, calculations, or problem-solving. Use it in this response.
2304+
- You can use a wide array of libraries for data manipulation, visualization, API calls, or any computational task. Think outside the box and harness Python's full potential.
2305+
- **You must enclose your code within `<code_interpreter type="code" lang="python">` XML tags** and stop right away. If you don't, the code won't execute.
2306+
- Do NOT use triple backticks (```py ... ```) inside the XML tags — that is markdown formatting, not executable Python code.
2307+
- **Always print meaningful outputs** (results, tables, summaries, visuals). Avoid implicit outputs; use explicit print statements.
2308+
- After obtaining output, **provide a concise analysis, interpretation, or next steps** to help the user understand the findings.
2309+
- If results are unclear or unexpected, refine the code and re-execute. Iterate until you deliver meaningful insights.
2310+
- **If a link to an image, audio, or any file appears in the output, display it exactly as-is** in your response so the user can access it. Do not modify the link.
2311+
- Respond in the chat's primary language. Default to English if multilingual.
2312+
2313+
Ensure the code interpreter is effectively utilized to achieve the highest-quality analysis for the user."""
2314+
2315+
# Appended to the code interpreter prompt only when engine is pyodide (not jupyter)
2316+
CODE_INTERPRETER_PYODIDE_FS_PROMPT = """
2317+
2318+
##### Persistent File System
2319+
2320+
- User-uploaded files are available at `/mnt/uploads/`. When the user asks you to work with their files, read from this directory.
2321+
- You can also write output files to `/mnt/uploads/` so the user can access and download them from the file browser.
2322+
- The file system persists across code executions within the same session.
2323+
- Use `import os; os.listdir('/mnt/uploads')` to discover available files."""
23132324

23142325

23152326
####################################

backend/open_webui/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,7 @@ async def get_app_config(request: Request):
21932193
"user_count": user_count,
21942194
"code": {
21952195
"engine": app.state.config.CODE_EXECUTION_ENGINE,
2196+
"interpreter_engine": app.state.config.CODE_INTERPRETER_ENGINE,
21962197
},
21972198
"audio": {
21982199
"tts": {

backend/open_webui/utils/middleware.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import copy
12
import time
23
import logging
34
import sys
@@ -119,6 +120,7 @@
119120
DEFAULT_VOICE_MODE_PROMPT_TEMPLATE,
120121
DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE,
121122
DEFAULT_CODE_INTERPRETER_PROMPT,
123+
CODE_INTERPRETER_PYODIDE_FS_PROMPT,
122124
CODE_INTERPRETER_BLOCKED_MODULES,
123125
)
124126
from open_webui.env import (
@@ -2352,18 +2354,36 @@ async def process_chat_payload(request, form_data, user, metadata, model):
23522354
)
23532355

23542356
if "code_interpreter" in features and features["code_interpreter"]:
2357+
engine = getattr(
2358+
request.app.state.config, "CODE_INTERPRETER_ENGINE", "pyodide"
2359+
)
2360+
23552361
# Skip XML-tag prompt injection when native FC is enabled —
23562362
# execute_code will be injected as a builtin tool instead
23572363
if metadata.get("params", {}).get("function_calling") != "native":
2364+
prompt = (
2365+
request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE
2366+
if request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE
2367+
!= ""
2368+
else DEFAULT_CODE_INTERPRETER_PROMPT
2369+
)
2370+
2371+
# Append filesystem awareness only for pyodide engine
2372+
if engine != "jupyter":
2373+
prompt += CODE_INTERPRETER_PYODIDE_FS_PROMPT
2374+
23582375
form_data["messages"] = add_or_update_user_message(
2359-
(
2360-
request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE
2361-
if request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE
2362-
!= ""
2363-
else DEFAULT_CODE_INTERPRETER_PROMPT
2364-
),
2376+
prompt,
23652377
form_data["messages"],
23662378
)
2379+
else:
2380+
# Native FC: tool docstring can't be dynamic, so inject
2381+
# filesystem context into messages for pyodide engine
2382+
if engine != "jupyter":
2383+
form_data["messages"] = add_or_update_user_message(
2384+
CODE_INTERPRETER_PYODIDE_FS_PROMPT,
2385+
form_data["messages"],
2386+
)
23672387

23682388
tool_ids = form_data.pop("tool_ids", None)
23692389
terminal_id = form_data.pop("terminal_id", None)

src/lib/components/admin/Settings/CodeExecution.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
>
6868
<option disabled selected value="">{$i18n.t('Select a engine')}</option>
6969
{#each engines as engine}
70-
<option value={engine}>{engine}</option>
70+
<option value={engine}>{engine}{engine === 'jupyter' ? ' (Legacy)' : ''}</option>
7171
{/each}
7272
</select>
7373
</div>
@@ -193,7 +193,7 @@
193193
>
194194
<option disabled selected value="">{$i18n.t('Select a engine')}</option>
195195
{#each engines as engine}
196-
<option value={engine}>{engine}</option>
196+
<option value={engine}>{engine}{engine === 'jupyter' ? ' (Legacy)' : ''}</option>
197197
{/each}
198198
</select>
199199
</div>

src/lib/components/chat/Chat.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@
148148
let webSearchEnabled = false;
149149
let codeInterpreterEnabled = false;
150150
151+
152+
151153
let showCommands = false;
152154
153155
let generating = false;
@@ -2924,6 +2926,7 @@
29242926
{stopResponse}
29252927
{showMessage}
29262928
{eventTarget}
2929+
{codeInterpreterEnabled}
29272930
/>
29282931
</PaneGroup>
29292932
</div>

src/lib/components/chat/ChatControls.svelte

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
import { onDestroy, onMount, tick, getContext } from 'svelte';
1212
import {
13+
config,
1314
terminalServers,
1415
mobile,
1516
showControls,
@@ -31,6 +32,7 @@
3132
import Artifacts from './Artifacts.svelte';
3233
import Embeds from './ChatControls/Embeds.svelte';
3334
import FileNav from './FileNav.svelte';
35+
import PyodideFileNav from './PyodideFileNav.svelte';
3436
import Overview from './Overview.svelte';
3537
3638
const i18n = getContext('i18n');
@@ -50,6 +52,8 @@
5052
export let files;
5153
export let modelId;
5254
55+
export let codeInterpreterEnabled = false;
56+
5357
export let pane: Pane | null = null;
5458
5559
let largeScreen = false;
@@ -67,7 +71,7 @@
6771
$: hasMessages = history?.messages && Object.keys(history.messages).length > 0;
6872
6973
$: showControlsTab = $user?.role === 'admin' || ($user?.permissions?.chat?.controls ?? true);
70-
$: showFilesTab = !!$selectedTerminalId;
74+
$: showFilesTab = !!$selectedTerminalId || (codeInterpreterEnabled && $config?.code?.interpreter_engine !== 'jupyter');
7175
$: showOverviewTab = hasMessages;
7276
7377
// Tab fallback: if active tab becomes hidden, switch to next available
@@ -355,6 +359,8 @@
355359
/>
356360
{:else if activeTab === 'files' && $selectedTerminalId}
357361
<FileNav onAttach={handleTerminalAttach} />
362+
{:else if activeTab === 'files' && codeInterpreterEnabled}
363+
<PyodideFileNav />
358364
{:else}
359365
<Controls embed={true} {models} bind:chatFiles bind:params />
360366
{/if}
@@ -504,6 +510,8 @@
504510
/>
505511
{:else if activeTab === 'files' && $selectedTerminalId}
506512
<FileNav onAttach={handleTerminalAttach} overlay={dragged} />
513+
{:else if activeTab === 'files' && codeInterpreterEnabled}
514+
<PyodideFileNav overlay={dragged} />
507515
{:else}
508516
<Controls embed={true} {models} bind:chatFiles bind:params />
509517
{/if}

src/lib/components/chat/FileNav/FileEntryRow.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
1313
export let entry: FileEntry;
1414
export let currentPath: string;
15-
export let terminalUrl: string;
16-
export let terminalKey: string;
15+
export let terminalUrl: string = '';
16+
export let terminalKey: string = '';
1717
1818
export let onOpen: (entry: FileEntry) => void = () => {};
1919
export let onDownload: (path: string) => void = () => {};

src/lib/components/chat/MessageInput.svelte

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,11 +508,17 @@
508508
509509
let showCodeInterpreterButton = false;
510510
$: showCodeInterpreterButton =
511+
!$selectedTerminalId &&
511512
(atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length ===
512513
codeInterpreterCapableModels.length &&
513514
$config?.features?.enable_code_interpreter &&
514515
($_user.role === 'admin' || $_user?.permissions?.features?.code_interpreter);
515516
517+
// Disable code interpreter when terminal is active (mutually exclusive)
518+
$: if ($selectedTerminalId && codeInterpreterEnabled) {
519+
codeInterpreterEnabled = false;
520+
}
521+
516522
const scrollToBottom = () => {
517523
const element = document.getElementById('messages-container');
518524
element.scrollTo({

0 commit comments

Comments
 (0)