mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 09:33:10 -07:00
Adding new "Pre-Launch Commands" to the "Advanced" launch tab to allow launching commands before the launch
This commit is contained in:
parent
7a118c9449
commit
6100a4d0f0
15 changed files with 245 additions and 80 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "gerbil",
|
||||
"productName": "Gerbil",
|
||||
"version": "1.12.1",
|
||||
"version": "1.13.0",
|
||||
"description": "Run Large Language Models locally",
|
||||
"main": "out/main/index.js",
|
||||
"homepage": "./",
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ import {
|
|||
NumberInput,
|
||||
Button,
|
||||
SimpleGrid,
|
||||
ActionIcon,
|
||||
} from '@mantine/core';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Plus, Trash2 } from 'lucide-react';
|
||||
import { InfoTooltip } from '@/components/InfoTooltip';
|
||||
import { CheckboxWithTooltip } from '@/components/CheckboxWithTooltip';
|
||||
import { CommandLineArgumentsModal } from '@/components/screens/Launch/CommandLineArgumentsModal';
|
||||
|
|
@ -16,6 +18,7 @@ import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
|||
export const AdvancedTab = () => {
|
||||
const {
|
||||
additionalArguments,
|
||||
preLaunchCommands,
|
||||
noshift,
|
||||
flashattention,
|
||||
noavx2,
|
||||
|
|
@ -28,6 +31,7 @@ export const AdvancedTab = () => {
|
|||
moecpu,
|
||||
moeexperts,
|
||||
handleAdditionalArgumentsChange,
|
||||
handlePreLaunchCommandsChange,
|
||||
handleNoshiftChange,
|
||||
handleFlashattentionChange,
|
||||
handleNoavx2Change,
|
||||
|
|
@ -208,7 +212,7 @@ export const AdvancedTab = () => {
|
|||
<Group mb="xs" justify="space-between">
|
||||
<Group>
|
||||
<Text size="sm" fw={500}>
|
||||
Additional arguments
|
||||
Additional Arguments
|
||||
</Text>
|
||||
<InfoTooltip label="Additional command line arguments to pass to the binary. Leave this empty if you don't know what they are." />
|
||||
</Group>
|
||||
|
|
@ -229,6 +233,57 @@ export const AdvancedTab = () => {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Group mb="xs">
|
||||
<Text size="sm" fw={500}>
|
||||
Pre-Launch Commands
|
||||
</Text>
|
||||
<InfoTooltip label="Shell commands to run before launching. Useful for starting local services or custom APIs." />
|
||||
</Group>
|
||||
<Stack gap="xs">
|
||||
{preLaunchCommands.map((command, index) => (
|
||||
<Group key={index} gap="xs">
|
||||
<TextInput
|
||||
placeholder="Enter a shell command"
|
||||
value={command}
|
||||
onChange={(event) => {
|
||||
const newCommands = [...preLaunchCommands];
|
||||
newCommands[index] = event.currentTarget.value;
|
||||
handlePreLaunchCommandsChange(newCommands);
|
||||
}}
|
||||
style={{ flex: 1 }}
|
||||
/>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="red"
|
||||
disabled={preLaunchCommands.length === 1}
|
||||
onClick={() => {
|
||||
const newCommands = preLaunchCommands.filter(
|
||||
(_, i) => i !== index
|
||||
);
|
||||
handlePreLaunchCommandsChange(
|
||||
newCommands.length === 0 ? [''] : newCommands
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
))}
|
||||
<Button
|
||||
variant="subtle"
|
||||
size="xs"
|
||||
leftSection={<Plus size={14} />}
|
||||
onClick={() => {
|
||||
handlePreLaunchCommandsChange([...preLaunchCommands, '']);
|
||||
}}
|
||||
style={{ alignSelf: 'flex-start' }}
|
||||
>
|
||||
Add Command
|
||||
</Button>
|
||||
</Stack>
|
||||
</div>
|
||||
|
||||
<CommandLineArgumentsModal
|
||||
opened={commandLineModalOpen}
|
||||
onClose={() => setCommandLineModalOpen(false)}
|
||||
|
|
|
|||
|
|
@ -796,7 +796,7 @@ export const CommandLineArgumentsModal = ({
|
|||
<Stack gap="md">
|
||||
<Text size="sm" c="dimmed">
|
||||
These are additional command line arguments that can be added to the
|
||||
"Additional Arguments" field.
|
||||
"Additional Arguments" input field.
|
||||
</Text>
|
||||
|
||||
<TextInput
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
|
|||
contextSize,
|
||||
model,
|
||||
additionalArguments,
|
||||
preLaunchCommands,
|
||||
port,
|
||||
host,
|
||||
multiuser,
|
||||
|
|
@ -159,6 +160,7 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
|
|||
contextsize: contextSize,
|
||||
model,
|
||||
additionalArguments,
|
||||
preLaunchCommands: preLaunchCommands.filter((cmd) => cmd.trim() !== ''),
|
||||
port,
|
||||
host,
|
||||
multiuser: multiuser ? 1 : 0,
|
||||
|
|
@ -301,6 +303,7 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
|
|||
usemmap,
|
||||
debugmode,
|
||||
additionalArguments,
|
||||
preLaunchCommands,
|
||||
sdt5xxl,
|
||||
sdclipl,
|
||||
sdclipg,
|
||||
|
|
@ -338,6 +341,7 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
|
|||
usemmap,
|
||||
debugmode,
|
||||
additionalArguments,
|
||||
preLaunchCommands,
|
||||
sdt5xxl,
|
||||
sdclipl,
|
||||
sdclipg,
|
||||
|
|
|
|||
|
|
@ -77,11 +77,9 @@ export const AppearanceTab = ({
|
|||
|
||||
return (
|
||||
<Stack gap="lg" h="100%">
|
||||
<FrontendInterfaceSelector isOnInterfaceScreen={isOnInterfaceScreen} />
|
||||
<div>
|
||||
<FrontendInterfaceSelector isOnInterfaceScreen={isOnInterfaceScreen} />
|
||||
</div>
|
||||
<div>
|
||||
<Text fw={500} mb="sm">
|
||||
<Text fw={500} mb="xs">
|
||||
Theme
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
|
|
@ -138,7 +136,7 @@ export const AppearanceTab = ({
|
|||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Text fw={500} mb="sm">
|
||||
<Text fw={500} mb="xs">
|
||||
Zoom Level
|
||||
</Text>
|
||||
<Group justify="space-between" align="center" mb="md">
|
||||
|
|
|
|||
|
|
@ -223,69 +223,74 @@ export const FrontendInterfaceSelector = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<Text fw={500} mb="sm">
|
||||
Frontend Interface
|
||||
</Text>
|
||||
<div>
|
||||
<Text fw={500} mb="xs">
|
||||
Frontend Interface
|
||||
</Text>
|
||||
|
||||
{getUnmetRequirements().length === 0 && (
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
Choose which frontend interface to use for interacting with AI
|
||||
models
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{getUnmetRequirements().length > 0 && (
|
||||
<Text size="sm" c="red" mb="md">
|
||||
{getSelectedFrontendConfig()?.label} requires{' '}
|
||||
{getUnmetRequirements().map((req, index) => (
|
||||
<span key={req.id}>
|
||||
<Anchor
|
||||
href={req.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
c="red"
|
||||
td="underline"
|
||||
>
|
||||
{req.name}
|
||||
</Anchor>
|
||||
{index < getUnmetRequirements().length - 1 ? ', ' : ''}
|
||||
</span>
|
||||
))}{' '}
|
||||
to be installed on your system
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Select
|
||||
value={frontendPreference}
|
||||
onChange={handleFrontendPreferenceChange}
|
||||
disabled={isOnInterfaceScreen}
|
||||
data={frontendConfigs.map((config) => ({
|
||||
value: config.value,
|
||||
label: config.label,
|
||||
disabled: !isFrontendAvailable(config.value),
|
||||
}))}
|
||||
leftSection={<Monitor style={{ width: rem(16), height: rem(16) }} />}
|
||||
/>
|
||||
|
||||
{renderDisabledFrontendWarnings()}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text fw={500} mb="xs">
|
||||
Image Generation Frontend
|
||||
</Text>
|
||||
|
||||
{getUnmetRequirements().length === 0 && (
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
Choose which frontend interface to use for interacting with AI models
|
||||
Choose which frontend to use for image generation specifically
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{getUnmetRequirements().length > 0 && (
|
||||
<Text size="sm" c="red" mb="md">
|
||||
{getSelectedFrontendConfig()?.label} requires{' '}
|
||||
{getUnmetRequirements().map((req, index) => (
|
||||
<span key={req.id}>
|
||||
<Anchor
|
||||
href={req.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
c="red"
|
||||
td="underline"
|
||||
>
|
||||
{req.name}
|
||||
</Anchor>
|
||||
{index < getUnmetRequirements().length - 1 ? ', ' : ''}
|
||||
</span>
|
||||
))}{' '}
|
||||
to be installed on your system
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Select
|
||||
value={frontendPreference}
|
||||
onChange={handleFrontendPreferenceChange}
|
||||
disabled={isOnInterfaceScreen}
|
||||
data={frontendConfigs.map((config) => ({
|
||||
value: config.value,
|
||||
label: config.label,
|
||||
disabled: !isFrontendAvailable(config.value),
|
||||
}))}
|
||||
leftSection={<Monitor style={{ width: rem(16), height: rem(16) }} />}
|
||||
/>
|
||||
|
||||
{renderDisabledFrontendWarnings()}
|
||||
|
||||
<Text fw={500} mb="sm" mt="xl">
|
||||
Image Generation Frontend
|
||||
</Text>
|
||||
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
Choose which frontend to use for image generation specifically
|
||||
</Text>
|
||||
|
||||
<Select
|
||||
value={imageGenerationFrontendPreference}
|
||||
onChange={handleImageGenerationFrontendChange}
|
||||
disabled={isOnInterfaceScreen}
|
||||
data={[
|
||||
{ value: 'match', label: 'Match Frontend' },
|
||||
{ value: 'builtin', label: 'Built-in' },
|
||||
]}
|
||||
leftSection={<Image style={{ width: rem(16), height: rem(16) }} />}
|
||||
/>
|
||||
<Select
|
||||
value={imageGenerationFrontendPreference}
|
||||
onChange={handleImageGenerationFrontendChange}
|
||||
disabled={isOnInterfaceScreen}
|
||||
data={[
|
||||
{ value: 'match', label: 'Match Frontend' },
|
||||
{ value: 'builtin', label: 'Built-in' },
|
||||
]}
|
||||
leftSection={<Image style={{ width: rem(16), height: rem(16) }} />}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export const GeneralTab = () => {
|
|||
return (
|
||||
<Stack gap="lg" h="100%">
|
||||
<div>
|
||||
<Text fw={500} mb="sm">
|
||||
<Text fw={500} mb="xs">
|
||||
Status Bar
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
|
|
@ -41,7 +41,7 @@ export const GeneralTab = () => {
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<Text fw={500} mb="sm">
|
||||
<Text fw={500} mb="xs">
|
||||
System Tray
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const TroubleshootingTab = () => {
|
|||
return (
|
||||
<Stack gap="lg" h="100%">
|
||||
<div>
|
||||
<Text fw={500} mb="sm">
|
||||
<Text fw={500} mb="xs">
|
||||
Installation Directory
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
|
|
@ -70,7 +70,7 @@ export const TroubleshootingTab = () => {
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<Text fw={500} mb="sm">
|
||||
<Text fw={500} mb="xs">
|
||||
Diagnostics
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const useLaunchConfig = () => {
|
|||
contextSize: state.contextSize,
|
||||
model: state.model,
|
||||
additionalArguments: state.additionalArguments,
|
||||
preLaunchCommands: state.preLaunchCommands,
|
||||
port: state.port,
|
||||
host: state.host,
|
||||
multiuser: state.multiuser,
|
||||
|
|
@ -65,6 +66,7 @@ export const useLaunchConfig = () => {
|
|||
handleQuantmatmulChange: state.setQuantmatmul,
|
||||
handleUsemmapChange: state.setUsemmap,
|
||||
handleDebugmodeChange: state.setDebugmode,
|
||||
handlePreLaunchCommandsChange: state.setPreLaunchCommands,
|
||||
handleBackendChange: state.setBackend,
|
||||
handleGpuDeviceSelectionChange: state.setGpuDeviceSelection,
|
||||
handleTensorSplitChange: state.setTensorSplit,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ interface LaunchArgs {
|
|||
usemmap: boolean;
|
||||
debugmode: boolean;
|
||||
additionalArguments: string;
|
||||
preLaunchCommands: string[];
|
||||
sdt5xxl: string;
|
||||
sdclipl: string;
|
||||
sdclipg: string;
|
||||
|
|
@ -283,7 +284,14 @@ export const useLaunchLogic = ({
|
|||
args.push(...additionalArgs);
|
||||
}
|
||||
|
||||
const result = await window.electronAPI.kobold.launchKoboldCpp(args);
|
||||
const preLaunchCommands = launchArgs.preLaunchCommands.filter(
|
||||
(cmd) => cmd.trim() !== ''
|
||||
);
|
||||
|
||||
const result = await window.electronAPI.kobold.launchKoboldCpp(
|
||||
args,
|
||||
preLaunchCommands
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
onLaunch();
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ export function setupIPCHandlers() {
|
|||
|
||||
ipcMain.handle('kobold:getPlatform', () => platform);
|
||||
|
||||
ipcMain.handle('kobold:launchKoboldCpp', (_, args) =>
|
||||
launchKoboldCppWithCustomFrontends(args)
|
||||
ipcMain.handle('kobold:launchKoboldCpp', (_, args, preLaunchCommands) =>
|
||||
launchKoboldCppWithCustomFrontends(args, preLaunchCommands)
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:deleteRelease', (_, binaryPath) =>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { spawn, ChildProcess } from 'child_process';
|
||||
import { platform } from 'process';
|
||||
|
||||
import { terminateProcess } from '@/utils/node/process';
|
||||
import { logError, safeExecute } from '@/utils/node/logging';
|
||||
|
|
@ -10,6 +11,7 @@ import { getCurrentVersion } from '../version';
|
|||
import {
|
||||
getCurrentKoboldBinary,
|
||||
get as getConfig,
|
||||
getInstallDir,
|
||||
} from '@/main/modules/config';
|
||||
import { startFrontend as startSillyTavernFrontend } from '@/main/modules/sillytavern';
|
||||
import { startFrontend as startOpenWebUIFrontend } from '@/main/modules/openwebui';
|
||||
|
|
@ -23,6 +25,70 @@ import type {
|
|||
} from '@/types';
|
||||
|
||||
let koboldProcess: ChildProcess | null = null;
|
||||
const preLaunchProcesses = new Set<ChildProcess>();
|
||||
|
||||
function spawnPreLaunchCommands(commands: string[]) {
|
||||
const installDir = getInstallDir();
|
||||
const shell = platform === 'win32' ? 'cmd' : '/bin/sh';
|
||||
const shellFlag = platform === 'win32' ? '/c' : '-c';
|
||||
|
||||
for (const command of commands) {
|
||||
if (!command.trim()) continue;
|
||||
|
||||
sendKoboldOutput(`[PRE-LAUNCH] Running: ${command}\n`);
|
||||
|
||||
try {
|
||||
const child = spawn(shell, [shellFlag, command], {
|
||||
cwd: installDir,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
detached: false,
|
||||
});
|
||||
|
||||
preLaunchProcesses.add(child);
|
||||
|
||||
child.stdout?.on('data', (data) => {
|
||||
sendKoboldOutput(`[PRE-LAUNCH] ${data.toString()}`, true);
|
||||
});
|
||||
|
||||
child.stderr?.on('data', (data) => {
|
||||
sendKoboldOutput(`[PRE-LAUNCH] ${data.toString()}`, true);
|
||||
});
|
||||
|
||||
child.on('error', (error) => {
|
||||
sendKoboldOutput(
|
||||
`[PRE-LAUNCH ERROR] Failed to run "${command}": ${error.message}\n`
|
||||
);
|
||||
preLaunchProcesses.delete(child);
|
||||
});
|
||||
|
||||
child.on('exit', (code, signal) => {
|
||||
preLaunchProcesses.delete(child);
|
||||
if (code !== 0 && code !== null) {
|
||||
sendKoboldOutput(
|
||||
`[PRE-LAUNCH] Command "${command}" exited with code ${code}\n`
|
||||
);
|
||||
} else if (signal) {
|
||||
sendKoboldOutput(
|
||||
`[PRE-LAUNCH] Command "${command}" terminated with signal ${signal}\n`
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
sendKoboldOutput(
|
||||
`[PRE-LAUNCH ERROR] Failed to start "${command}": ${error instanceof Error ? error.message : String(error)}\n`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function stopPreLaunchProcesses() {
|
||||
const terminations = Array.from(preLaunchProcesses).map((process) =>
|
||||
terminateProcess(process)
|
||||
);
|
||||
|
||||
await Promise.all(terminations);
|
||||
preLaunchProcesses.clear();
|
||||
}
|
||||
|
||||
async function resolveModelPaths(args: string[]) {
|
||||
const resolvedArgs: string[] = [];
|
||||
|
|
@ -75,13 +141,18 @@ async function resolveModelPaths(args: string[]) {
|
|||
export async function launchKoboldCpp(
|
||||
args: string[] = [],
|
||||
frontendPreference: FrontendPreference = 'koboldcpp',
|
||||
imageGenerationFrontendPreference?: ImageGenerationFrontendPreference
|
||||
imageGenerationFrontendPreference?: ImageGenerationFrontendPreference,
|
||||
preLaunchCommands: string[] = []
|
||||
) {
|
||||
try {
|
||||
if (koboldProcess) {
|
||||
await stopKoboldCpp();
|
||||
}
|
||||
|
||||
if (preLaunchCommands.length > 0) {
|
||||
spawnPreLaunchCommands(preLaunchCommands);
|
||||
}
|
||||
|
||||
const currentVersion = await getCurrentVersion();
|
||||
if (!currentVersion || !(await pathExists(currentVersion.path))) {
|
||||
const rawPath = getCurrentKoboldBinary();
|
||||
|
|
@ -213,11 +284,15 @@ export async function launchKoboldCpp(
|
|||
|
||||
export async function stopKoboldCpp() {
|
||||
abortActiveDownloads();
|
||||
await stopProxy();
|
||||
stopProxy();
|
||||
stopPreLaunchProcesses();
|
||||
return terminateProcess(koboldProcess);
|
||||
}
|
||||
|
||||
export const launchKoboldCppWithCustomFrontends = async (args: string[] = []) =>
|
||||
export const launchKoboldCppWithCustomFrontends = async (
|
||||
args: string[] = [],
|
||||
preLaunchCommands: string[] = []
|
||||
) =>
|
||||
safeExecute(async () => {
|
||||
const [frontendPreference, imageGenerationFrontendPreference] =
|
||||
(await Promise.all([
|
||||
|
|
@ -233,7 +308,8 @@ export const launchKoboldCppWithCustomFrontends = async (args: string[] = []) =>
|
|||
const result = await launchKoboldCpp(
|
||||
args,
|
||||
frontendPreference,
|
||||
imageGenerationFrontendPreference
|
||||
imageGenerationFrontendPreference,
|
||||
preLaunchCommands
|
||||
);
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ const koboldAPI: KoboldAPI = {
|
|||
ipcRenderer.invoke('kobold:downloadRelease', asset, options),
|
||||
deleteRelease: (binaryPath) =>
|
||||
ipcRenderer.invoke('kobold:deleteRelease', binaryPath),
|
||||
launchKoboldCpp: (args) => ipcRenderer.invoke('kobold:launchKoboldCpp', args),
|
||||
launchKoboldCpp: (args, preLaunchCommands) =>
|
||||
ipcRenderer.invoke('kobold:launchKoboldCpp', args, preLaunchCommands),
|
||||
getConfigFiles: () => ipcRenderer.invoke('kobold:getConfigFiles'),
|
||||
saveConfigFile: (configName, configData) =>
|
||||
ipcRenderer.invoke('kobold:saveConfigFile', configName, configData),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ interface LaunchConfigState {
|
|||
contextSize: number;
|
||||
model: string;
|
||||
additionalArguments: string;
|
||||
preLaunchCommands: string[];
|
||||
port?: number;
|
||||
host: string;
|
||||
multiuser: boolean;
|
||||
|
|
@ -63,6 +64,7 @@ interface LaunchConfigState {
|
|||
setQuantmatmul: (quantmatmul: boolean) => void;
|
||||
setUsemmap: (usemmap: boolean) => void;
|
||||
setDebugmode: (debugmode: boolean) => void;
|
||||
setPreLaunchCommands: (commands: string[]) => void;
|
||||
setBackend: (backend: string) => void;
|
||||
setGpuDeviceSelection: (selection: string) => void;
|
||||
setTensorSplit: (split: string) => void;
|
||||
|
|
@ -103,6 +105,7 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
|||
contextSize: DEFAULT_CONTEXT_SIZE,
|
||||
model: '',
|
||||
additionalArguments: '',
|
||||
preLaunchCommands: [''],
|
||||
port: undefined,
|
||||
host: '',
|
||||
multiuser: false,
|
||||
|
|
@ -162,6 +165,7 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
|||
setQuantmatmul: (quantmatmul) => set({ quantmatmul }),
|
||||
setUsemmap: (usemmap) => set({ usemmap }),
|
||||
setDebugmode: (debugmode) => set({ debugmode }),
|
||||
setPreLaunchCommands: (commands) => set({ preLaunchCommands: commands }),
|
||||
setBackend: (backend) =>
|
||||
set({
|
||||
backend,
|
||||
|
|
@ -225,6 +229,16 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
|||
updates.additionalArguments = '';
|
||||
}
|
||||
|
||||
if (Array.isArray(configData.preLaunchCommands)) {
|
||||
const filteredCommands = configData.preLaunchCommands.filter(
|
||||
(cmd): cmd is string => typeof cmd === 'string'
|
||||
);
|
||||
updates.preLaunchCommands =
|
||||
filteredCommands.length === 0 ? [''] : filteredCommands;
|
||||
} else {
|
||||
updates.preLaunchCommands = [''];
|
||||
}
|
||||
|
||||
if (typeof configData.port === 'number') {
|
||||
updates.port = configData.port;
|
||||
} else {
|
||||
|
|
|
|||
4
src/types/electron.d.ts
vendored
4
src/types/electron.d.ts
vendored
|
|
@ -116,6 +116,7 @@ export interface KoboldConfig {
|
|||
sdvaecpu?: boolean;
|
||||
sdclipgpu?: boolean;
|
||||
additionalArguments?: string;
|
||||
preLaunchCommands?: string[];
|
||||
moecpu?: number;
|
||||
moeexperts?: number;
|
||||
autoGpuLayers?: boolean;
|
||||
|
|
@ -146,7 +147,8 @@ export interface KoboldAPI {
|
|||
binaryPath: string
|
||||
) => Promise<{ success: boolean; error?: string }>;
|
||||
launchKoboldCpp: (
|
||||
args?: string[]
|
||||
args?: string[],
|
||||
preLaunchCommands?: string[]
|
||||
) => Promise<{ success: boolean; pid?: number; error?: string }>;
|
||||
getConfigFiles: () => Promise<{ name: string; path: string; size: number }[]>;
|
||||
saveConfigFile: (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue