refac
This commit is contained in:
@@ -167,15 +167,6 @@ async def create_new_automation(
|
|||||||
|
|
||||||
await check_automation_limits(request, user, form_data.data.rrule, db, is_create=True)
|
await check_automation_limits(request, user, form_data.data.rrule, db, is_create=True)
|
||||||
|
|
||||||
# Validate terminal server exists if linked
|
|
||||||
if form_data.data.terminal and form_data.data.terminal.server_id:
|
|
||||||
connections = request.app.state.config.TERMINAL_SERVER_CONNECTIONS or []
|
|
||||||
if not any(c.get('id') == form_data.data.terminal.server_id for c in connections):
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
detail='Terminal server not found',
|
|
||||||
)
|
|
||||||
|
|
||||||
tz = user.timezone
|
tz = user.timezone
|
||||||
automation = await Automations.insert(user.id, form_data, next_run_ns(form_data.data.rrule, tz=tz), db=db)
|
automation = await Automations.insert(user.id, form_data, next_run_ns(form_data.data.rrule, tz=tz), db=db)
|
||||||
return await enrich_automation(automation, db, tz=tz)
|
return await enrich_automation(automation, db, tz=tz)
|
||||||
@@ -226,15 +217,6 @@ async def update_automation_by_id(
|
|||||||
|
|
||||||
await check_automation_limits(request, user, form_data.data.rrule, db, is_create=False)
|
await check_automation_limits(request, user, form_data.data.rrule, db, is_create=False)
|
||||||
|
|
||||||
# Validate terminal server exists if linked
|
|
||||||
if form_data.data.terminal and form_data.data.terminal.server_id:
|
|
||||||
connections = request.app.state.config.TERMINAL_SERVER_CONNECTIONS or []
|
|
||||||
if not any(c.get('id') == form_data.data.terminal.server_id for c in connections):
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
detail='Terminal server not found',
|
|
||||||
)
|
|
||||||
|
|
||||||
tz = user.timezone
|
tz = user.timezone
|
||||||
updated = await Automations.update_by_id(id, form_data, next_run_ns(form_data.data.rrule, tz=tz), db=db)
|
updated = await Automations.update_by_id(id, form_data, next_run_ns(form_data.data.rrule, tz=tz), db=db)
|
||||||
return await enrich_automation(updated, db, tz=tz)
|
return await enrich_automation(updated, db, tz=tz)
|
||||||
|
|||||||
@@ -224,6 +224,16 @@ def _resolve_model_filter_ids(app, model_id: str) -> list[str]:
|
|||||||
return list(filter_ids) if filter_ids else []
|
return list(filter_ids) if filter_ids else []
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_model_terminal_id(app, model_id: str) -> Optional[str]:
|
||||||
|
"""Read model default terminal_id from model config.
|
||||||
|
|
||||||
|
The frontend does this in Chat.svelte (model.info.meta.terminalId).
|
||||||
|
"""
|
||||||
|
models = getattr(app.state, 'MODELS', {})
|
||||||
|
model = models.get(model_id, {})
|
||||||
|
return model.get('info', {}).get('meta', {}).get('terminalId') or None
|
||||||
|
|
||||||
|
|
||||||
async def _set_terminal_cwd(app, server_id: str, user, cwd: str, chat_id: str) -> None:
|
async def _set_terminal_cwd(app, server_id: str, user, cwd: str, chat_id: str) -> None:
|
||||||
"""Set the working directory on a terminal server via the proxy.
|
"""Set the working directory on a terminal server via the proxy.
|
||||||
|
|
||||||
@@ -357,13 +367,8 @@ async def execute_automation(app, automation: AutomationModel) -> None:
|
|||||||
features = _resolve_model_features(app, model_id)
|
features = _resolve_model_features(app, model_id)
|
||||||
filter_ids = _resolve_model_filter_ids(app, model_id)
|
filter_ids = _resolve_model_filter_ids(app, model_id)
|
||||||
|
|
||||||
# If a terminal is linked, set the CWD before building the payload
|
# Resolve terminal from model config
|
||||||
terminal_id = None
|
terminal_id = _resolve_model_terminal_id(app, model_id)
|
||||||
if terminal_config and terminal_config.get('server_id'):
|
|
||||||
terminal_id = terminal_config['server_id']
|
|
||||||
cwd = terminal_config.get('cwd')
|
|
||||||
if cwd:
|
|
||||||
await _set_terminal_cwd(app, terminal_id, user, cwd, chat.id)
|
|
||||||
|
|
||||||
# Build the same payload the frontend sends to /api/chat/completions
|
# Build the same payload the frontend sends to /api/chat/completions
|
||||||
form_data = {
|
form_data = {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import ScheduleDropdown from '$lib/components/automations/ScheduleDropdown.svelte';
|
import ScheduleDropdown from '$lib/components/automations/ScheduleDropdown.svelte';
|
||||||
import ModelDropdown from '$lib/components/automations/ModelDropdown.svelte';
|
import ModelDropdown from '$lib/components/automations/ModelDropdown.svelte';
|
||||||
import TerminalDropdown from '$lib/components/automations/TerminalDropdown.svelte';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createAutomation,
|
createAutomation,
|
||||||
@@ -16,7 +15,6 @@
|
|||||||
type AutomationForm,
|
type AutomationForm,
|
||||||
type AutomationResponse
|
type AutomationResponse
|
||||||
} from '$lib/apis/automations';
|
} from '$lib/apis/automations';
|
||||||
import { getTerminalServers, type TerminalServer } from '$lib/apis/terminal/index';
|
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
@@ -31,11 +29,6 @@
|
|||||||
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
// Terminal state
|
|
||||||
let terminalServers: TerminalServer[] = [];
|
|
||||||
let terminalServerId = '';
|
|
||||||
let terminalCwd = '';
|
|
||||||
|
|
||||||
// Schedule dropdown ref
|
// Schedule dropdown ref
|
||||||
let scheduleDropdown: ScheduleDropdown;
|
let scheduleDropdown: ScheduleDropdown;
|
||||||
|
|
||||||
@@ -58,15 +51,7 @@
|
|||||||
data: {
|
data: {
|
||||||
prompt: prompt.trim(),
|
prompt: prompt.trim(),
|
||||||
model_id: model_id.trim(),
|
model_id: model_id.trim(),
|
||||||
rrule: scheduleDropdown.buildRrule(),
|
rrule: scheduleDropdown.buildRrule()
|
||||||
...(terminalServerId
|
|
||||||
? {
|
|
||||||
terminal: {
|
|
||||||
server_id: terminalServerId,
|
|
||||||
...(terminalCwd.trim() ? { cwd: terminalCwd.trim() } : {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
},
|
},
|
||||||
is_active
|
is_active
|
||||||
};
|
};
|
||||||
@@ -90,20 +75,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
// Load terminal servers
|
|
||||||
try {
|
|
||||||
terminalServers = await getTerminalServers(localStorage.token);
|
|
||||||
} catch {
|
|
||||||
terminalServers = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (automation) {
|
if (automation) {
|
||||||
name = automation.name;
|
name = automation.name;
|
||||||
prompt = automation.data.prompt;
|
prompt = automation.data.prompt;
|
||||||
model_id = automation.data.model_id;
|
model_id = automation.data.model_id;
|
||||||
is_active = automation.is_active;
|
is_active = automation.is_active;
|
||||||
terminalServerId = automation.data.terminal?.server_id || '';
|
|
||||||
terminalCwd = automation.data.terminal?.cwd || '';
|
|
||||||
if (scheduleDropdown) {
|
if (scheduleDropdown) {
|
||||||
scheduleDropdown.parseRrule(automation.data.rrule);
|
scheduleDropdown.parseRrule(automation.data.rrule);
|
||||||
}
|
}
|
||||||
@@ -112,8 +88,6 @@
|
|||||||
prompt = '';
|
prompt = '';
|
||||||
model_id = '';
|
model_id = '';
|
||||||
is_active = true;
|
is_active = true;
|
||||||
terminalServerId = '';
|
|
||||||
terminalCwd = '';
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,14 +132,6 @@
|
|||||||
<ScheduleDropdown bind:this={scheduleDropdown} side="top" align="start" />
|
<ScheduleDropdown bind:this={scheduleDropdown} side="top" align="start" />
|
||||||
|
|
||||||
<ModelDropdown bind:model_id side="top" align="start" />
|
<ModelDropdown bind:model_id side="top" align="start" />
|
||||||
|
|
||||||
<TerminalDropdown
|
|
||||||
{terminalServers}
|
|
||||||
bind:terminalServerId
|
|
||||||
bind:terminalCwd
|
|
||||||
side="top"
|
|
||||||
align="start"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-2 shrink-0">
|
<div class="flex items-center gap-2 shrink-0">
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
type AutomationResponse,
|
type AutomationResponse,
|
||||||
type AutomationRunModel
|
type AutomationRunModel
|
||||||
} from '$lib/apis/automations';
|
} from '$lib/apis/automations';
|
||||||
import { getTerminalServers, type TerminalServer } from '$lib/apis/terminal/index';
|
|
||||||
|
|
||||||
import Spinner from '$lib/components/common/Spinner.svelte';
|
import Spinner from '$lib/components/common/Spinner.svelte';
|
||||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
@@ -29,7 +29,6 @@
|
|||||||
|
|
||||||
import ScheduleDropdown from '$lib/components/automations/ScheduleDropdown.svelte';
|
import ScheduleDropdown from '$lib/components/automations/ScheduleDropdown.svelte';
|
||||||
import ModelDropdown from '$lib/components/automations/ModelDropdown.svelte';
|
import ModelDropdown from '$lib/components/automations/ModelDropdown.svelte';
|
||||||
import TerminalDropdown from '$lib/components/automations/TerminalDropdown.svelte';
|
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
dayjs.extend(localizedFormat);
|
dayjs.extend(localizedFormat);
|
||||||
@@ -43,9 +42,6 @@
|
|||||||
let model_id = '';
|
let model_id = '';
|
||||||
let is_active = true;
|
let is_active = true;
|
||||||
|
|
||||||
let terminalServers: TerminalServer[] = [];
|
|
||||||
let terminalServerId = '';
|
|
||||||
let terminalCwd = '';
|
|
||||||
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
let saving = false;
|
let saving = false;
|
||||||
@@ -97,15 +93,7 @@
|
|||||||
data: {
|
data: {
|
||||||
prompt: prompt.trim(),
|
prompt: prompt.trim(),
|
||||||
model_id: model_id.trim(),
|
model_id: model_id.trim(),
|
||||||
rrule: scheduleDropdown.buildRrule(),
|
rrule: scheduleDropdown.buildRrule()
|
||||||
...(terminalServerId
|
|
||||||
? {
|
|
||||||
terminal: {
|
|
||||||
server_id: terminalServerId,
|
|
||||||
...(terminalCwd.trim() ? { cwd: terminalCwd.trim() } : {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
},
|
},
|
||||||
is_active
|
is_active
|
||||||
};
|
};
|
||||||
@@ -204,18 +192,11 @@
|
|||||||
prompt = automation.data.prompt;
|
prompt = automation.data.prompt;
|
||||||
model_id = automation.data.model_id;
|
model_id = automation.data.model_id;
|
||||||
is_active = automation.is_active;
|
is_active = automation.is_active;
|
||||||
terminalServerId = automation.data.terminal?.server_id || '';
|
|
||||||
terminalCwd = automation.data.terminal?.cwd || '';
|
|
||||||
|
|
||||||
if (scheduleDropdown) {
|
if (scheduleDropdown) {
|
||||||
scheduleDropdown.parseRrule(automation.data.rrule);
|
scheduleDropdown.parseRrule(automation.data.rrule);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
terminalServers = await getTerminalServers(localStorage.token);
|
|
||||||
} catch {
|
|
||||||
terminalServers = [];
|
|
||||||
}
|
|
||||||
await loadRuns();
|
await loadRuns();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -355,20 +336,6 @@
|
|||||||
<ModelDropdown bind:model_id side="bottom" align="end" onChange={markDirty} />
|
<ModelDropdown bind:model_id side="bottom" align="end" onChange={markDirty} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Terminal -->
|
|
||||||
{#if terminalServers.length > 0}
|
|
||||||
<div class="flex items-center justify-between text-xs">
|
|
||||||
<span class="text-gray-600 dark:text-gray-400">{$i18n.t('Terminal')}</span>
|
|
||||||
<TerminalDropdown
|
|
||||||
{terminalServers}
|
|
||||||
bind:terminalServerId
|
|
||||||
bind:terminalCwd
|
|
||||||
side="bottom"
|
|
||||||
align="end"
|
|
||||||
onChange={markDirty}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -370,6 +370,11 @@
|
|||||||
codeInterpreterEnabled = model.info.meta.defaultFeatureIds.includes('code_interpreter');
|
codeInterpreterEnabled = model.info.meta.defaultFeatureIds.includes('code_interpreter');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set Default Terminal
|
||||||
|
if (model?.info?.meta?.terminalId) {
|
||||||
|
selectedTerminalId.set(model.info.meta.terminalId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
import DefaultFeatures from './DefaultFeatures.svelte';
|
import DefaultFeatures from './DefaultFeatures.svelte';
|
||||||
import BuiltinTools from './BuiltinTools.svelte';
|
import BuiltinTools from './BuiltinTools.svelte';
|
||||||
import PromptSuggestions from './PromptSuggestions.svelte';
|
import PromptSuggestions from './PromptSuggestions.svelte';
|
||||||
|
import TerminalSelector from './TerminalSelector.svelte';
|
||||||
import AccessControlModal from '../common/AccessControlModal.svelte';
|
import AccessControlModal from '../common/AccessControlModal.svelte';
|
||||||
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
||||||
import { updateModelAccessGrants } from '$lib/apis/models';
|
import { updateModelAccessGrants } from '$lib/apis/models';
|
||||||
@@ -102,6 +103,7 @@
|
|||||||
|
|
||||||
let actionIds = [];
|
let actionIds = [];
|
||||||
let accessGrants = [];
|
let accessGrants = [];
|
||||||
|
let terminalId = '';
|
||||||
let tts = { voice: '' };
|
let tts = { voice: '' };
|
||||||
|
|
||||||
const submitHandler = async () => {
|
const submitHandler = async () => {
|
||||||
@@ -206,6 +208,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (terminalId) {
|
||||||
|
info.meta.terminalId = terminalId;
|
||||||
|
} else {
|
||||||
|
if (info.meta.terminalId) {
|
||||||
|
delete info.meta.terminalId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tts.voice !== '') {
|
if (tts.voice !== '') {
|
||||||
if (!info.meta.tts) info.meta.tts = {};
|
if (!info.meta.tts) info.meta.tts = {};
|
||||||
info.meta.tts.voice = tts.voice;
|
info.meta.tts.voice = tts.voice;
|
||||||
@@ -316,6 +326,7 @@
|
|||||||
capabilities = { ...capabilities, ...(model?.meta?.capabilities ?? {}) };
|
capabilities = { ...capabilities, ...(model?.meta?.capabilities ?? {}) };
|
||||||
defaultFeatureIds = model?.meta?.defaultFeatureIds ?? defaultFeatureIds;
|
defaultFeatureIds = model?.meta?.defaultFeatureIds ?? defaultFeatureIds;
|
||||||
builtinTools = model?.meta?.builtinTools ?? builtinTools;
|
builtinTools = model?.meta?.builtinTools ?? builtinTools;
|
||||||
|
terminalId = model?.meta?.terminalId ?? '';
|
||||||
tts = { voice: model?.meta?.tts?.voice ?? '' };
|
tts = { voice: model?.meta?.tts?.voice ?? '' };
|
||||||
|
|
||||||
accessGrants = model?.access_grants ?? [];
|
accessGrants = model?.access_grants ?? [];
|
||||||
@@ -828,6 +839,10 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<div class="my-4">
|
||||||
|
<TerminalSelector bind:terminalId />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="my-4">
|
<div class="my-4">
|
||||||
<div class="flex w-full justify-between mb-1">
|
<div class="flex w-full justify-between mb-1">
|
||||||
<div class="self-center text-xs font-medium text-gray-500">
|
<div class="self-center text-xs font-medium text-gray-500">
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { getContext, onMount } from 'svelte';
|
||||||
|
import { getTerminalServers, type TerminalServer } from '$lib/apis/terminal';
|
||||||
|
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
export let terminalId: string = '';
|
||||||
|
|
||||||
|
let terminals: TerminalServer[] = [];
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
terminals = await getTerminalServers(localStorage.token);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if terminals.length > 0}
|
||||||
|
<div class="flex w-full justify-between mb-1">
|
||||||
|
<div class="self-center text-xs font-medium text-gray-500">{$i18n.t('Terminal')}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<select
|
||||||
|
class="w-full text-sm bg-transparent outline-hidden cursor-pointer"
|
||||||
|
bind:value={terminalId}
|
||||||
|
>
|
||||||
|
<option value="">{$i18n.t('None')}</option>
|
||||||
|
{#each terminals as terminal (terminal.id)}
|
||||||
|
<option value={terminal.id}>{terminal.name || terminal.id}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
{/if}
|
||||||
Reference in New Issue
Block a user