refac
This commit is contained in:
@@ -1043,37 +1043,49 @@ def process_tool_result(
|
||||
return tool_result, tool_result_files, tool_result_embeds
|
||||
|
||||
|
||||
async def display_file_handler(
|
||||
async def terminal_event_handler(
|
||||
tool_function_name: str,
|
||||
tool_function_params: dict,
|
||||
tool_result,
|
||||
event_emitter,
|
||||
):
|
||||
"""Emit a display_file event if the tool is display_file and the file exists."""
|
||||
if not event_emitter or tool_function_name != "display_file":
|
||||
"""Emit terminal:* events for Open Terminal tools.
|
||||
|
||||
- display_file → emits 'terminal:display_file' to open the file preview.
|
||||
- write_file / replace_file_content → emits 'terminal:write_file' or
|
||||
'terminal:replace_file_content' to silently refresh the file browser.
|
||||
"""
|
||||
if not event_emitter:
|
||||
return
|
||||
|
||||
path = tool_function_params.get("path", "")
|
||||
if not path:
|
||||
return
|
||||
|
||||
# Parse the result to check if the file exists
|
||||
parsed = tool_result
|
||||
if isinstance(parsed, str):
|
||||
try:
|
||||
parsed = json.loads(parsed)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
if tool_function_name == "display_file":
|
||||
# Only emit if the file actually exists
|
||||
parsed = tool_result
|
||||
if isinstance(parsed, str):
|
||||
try:
|
||||
parsed = json.loads(parsed)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
if isinstance(parsed, dict) and parsed.get("exists") is False:
|
||||
return
|
||||
|
||||
if isinstance(parsed, dict) and parsed.get("exists") is False:
|
||||
return
|
||||
|
||||
await event_emitter(
|
||||
{
|
||||
"type": "display_file",
|
||||
"data": {"path": path},
|
||||
}
|
||||
)
|
||||
await event_emitter(
|
||||
{
|
||||
"type": f"terminal:{tool_function_name}",
|
||||
"data": {"path": path},
|
||||
}
|
||||
)
|
||||
elif tool_function_name in ("write_file", "replace_file_content"):
|
||||
await event_emitter(
|
||||
{
|
||||
"type": f"terminal:{tool_function_name}",
|
||||
"data": {"path": path},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def chat_completion_tools_handler(
|
||||
@@ -1230,7 +1242,7 @@ async def chat_completion_tools_handler(
|
||||
)
|
||||
|
||||
if event_emitter:
|
||||
await display_file_handler(
|
||||
await terminal_event_handler(
|
||||
tool_function_name,
|
||||
tool_function_params,
|
||||
tool_result,
|
||||
@@ -4224,7 +4236,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
)
|
||||
)
|
||||
|
||||
await display_file_handler(
|
||||
await terminal_event_handler(
|
||||
tool_function_name,
|
||||
tool_function_params,
|
||||
tool_result,
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
pinnedChats,
|
||||
showEmbeds,
|
||||
selectedTerminalId,
|
||||
showFileNavPath
|
||||
showFileNavPath,
|
||||
showFileNavDir
|
||||
} from '$lib/stores';
|
||||
|
||||
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
||||
@@ -446,6 +447,15 @@
|
||||
saveChatHandler(_chatId, history);
|
||||
};
|
||||
|
||||
const terminalEventHandler = (type: string, data: any) => {
|
||||
if (!data?.path) return;
|
||||
if (type === 'terminal:display_file') {
|
||||
displayFileHandler(data.path, { showControls, showFileNavPath });
|
||||
} else if (type === 'terminal:write_file' || type === 'terminal:replace_file_content') {
|
||||
showFileNavDir.set(data.path);
|
||||
}
|
||||
};
|
||||
|
||||
const chatEventHandler = async (event, cb) => {
|
||||
console.log(event);
|
||||
|
||||
@@ -579,10 +589,8 @@
|
||||
eventConfirmationInputPlaceholder = data.placeholder;
|
||||
eventConfirmationInputValue = data?.value ?? '';
|
||||
eventConfirmationInputType = data?.type ?? '';
|
||||
} else if (type === 'display_file') {
|
||||
if (data?.path) {
|
||||
displayFileHandler(data.path, { showControls, showFileNavPath });
|
||||
}
|
||||
} else if (type.startsWith('terminal:')) {
|
||||
terminalEventHandler(type, data);
|
||||
} else {
|
||||
console.log('Unknown message type', data);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
<script lang="ts">
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { getContext, onMount, onDestroy, tick } from 'svelte';
|
||||
import { terminalServers, settings, showFileNavPath, selectedTerminalId } from '$lib/stores';
|
||||
import {
|
||||
terminalServers,
|
||||
settings,
|
||||
showFileNavPath,
|
||||
showFileNavDir,
|
||||
selectedTerminalId
|
||||
} from '$lib/stores';
|
||||
import {
|
||||
getCwd,
|
||||
listFiles,
|
||||
@@ -342,6 +348,23 @@
|
||||
if (entry) await openEntry(entry);
|
||||
});
|
||||
|
||||
const unsubFileNavDir = showFileNavDir.subscribe(async (filePath) => {
|
||||
if (!filePath || !selectedTerminal) return;
|
||||
showFileNavDir.set(null);
|
||||
|
||||
const lastSlash = filePath.lastIndexOf('/');
|
||||
const dir = lastSlash > 0 ? filePath.substring(0, lastSlash + 1) : '/';
|
||||
|
||||
if (dir === currentPath) {
|
||||
await loadDir(currentPath);
|
||||
}
|
||||
if (filePath === selectedFile) {
|
||||
const fileName = filePath.substring(lastSlash + 1);
|
||||
const entry = entries.find((e) => e.name === fileName);
|
||||
if (entry) await openEntry(entry);
|
||||
}
|
||||
});
|
||||
|
||||
if (!handledDisplayFile) {
|
||||
if (savedPath === '/') {
|
||||
const cwd = await getCwd(terminal.url, terminal.key);
|
||||
@@ -393,12 +416,12 @@
|
||||
/>
|
||||
|
||||
{#if !selectedTerminal}
|
||||
<div class="flex-1 flex flex-col items-center justify-center p-6 text-center gap-3">
|
||||
<Folder className="size-10 text-gray-300 dark:text-gray-600" />
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
<div class="flex-1 flex flex-col items-center justify-center p-6 text-center">
|
||||
<Folder className="size-6 text-gray-300 dark:text-gray-600 mb-2" />
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400 mb-1">
|
||||
{$i18n.t('No Terminal connection configured.')}
|
||||
</div>
|
||||
<div class="text-xs text-gray-400 dark:text-gray-500">
|
||||
<div class="text-[10px] text-gray-400 dark:text-gray-500">
|
||||
{$i18n.t('Add your Open Terminal URL and API key in Settings → Integrations.')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -93,6 +93,7 @@ export const showArtifacts = writable(false);
|
||||
export const showCallOverlay = writable(false);
|
||||
export const showFileNav = writable(false);
|
||||
export const showFileNavPath: Writable<string | null> = writable(null);
|
||||
export const showFileNavDir: Writable<string | null> = writable(null);
|
||||
export const selectedTerminalId: Writable<string | null> = writable(null);
|
||||
|
||||
export const artifactCode = writable(null);
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
channelId,
|
||||
terminalServers,
|
||||
showControls,
|
||||
showFileNavPath
|
||||
showFileNavPath,
|
||||
showFileNavDir
|
||||
} from '$lib/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
@@ -337,6 +338,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (['write_file', 'replace_file_content'].includes(data?.name) && data?.params?.path) {
|
||||
showFileNavDir.set(res?.path ?? data.params.path);
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
cb(JSON.parse(JSON.stringify(res)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user