a836082de8
Add ToolSelector for enabling sandboxed python per agent, drop unsafe filesystem/bash tools, bundle fetchUrl with web search, and return Monty's last expression value so agents need not print.
141 lines
7.5 KiB
Vue
141 lines
7.5 KiB
Vue
<script setup lang="ts">
|
|
import { DialogType } from '~/composables/useDialog';
|
|
|
|
const { openDialog } = await useDialog();
|
|
|
|
const props = defineProps<{
|
|
enabled: boolean;
|
|
maxResults: number;
|
|
rerank: boolean;
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
'update:enabled': [value: boolean];
|
|
'update:maxResults': [value: number];
|
|
'update:rerank': [value: boolean];
|
|
}>();
|
|
|
|
const adjustMaxResults = (delta: number) => {
|
|
const next = Math.min(50, Math.max(1, props.maxResults + delta));
|
|
emit('update:maxResults', next);
|
|
};
|
|
|
|
const { settings } = await useUserSettings();
|
|
|
|
const systemAssistantsRerank = computed(() => {
|
|
return settings.value.systemAssistants?.rerank ?? null;
|
|
});
|
|
|
|
const isRerankConfigured = computed(() => {
|
|
const sa = systemAssistantsRerank.value;
|
|
return sa?.enabled === true && sa?.modelId != null && sa.modelId !== '';
|
|
});
|
|
|
|
const openSettings = () => {
|
|
openDialog(DialogType.Settings, undefined, { page: 'systemAssistants' });
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Dropdown dropdownClass="text-sm" placement="top">
|
|
<template #default="{ toggle, setRef }">
|
|
<button :ref="setRef" @click="toggle"
|
|
class="flex items-center justify-center h-8.5 w-8.5 @hover:bg-[var(--color-hover)] rounded-lg transition-colors duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)]">
|
|
<span class="pointer-events-none i-tabler-world text-5 transition-colors duration-200"
|
|
:class="enabled ? 'text-[var(--color-accent)]' : 'text-[var(--text-secondary)]'"></span>
|
|
</button>
|
|
</template>
|
|
|
|
<template #dropdown="{ close }">
|
|
<div class="flex p-1 gap-4">
|
|
<!-- Left: mode toggle group -->
|
|
<div class="flex flex-col gap-1">
|
|
<button @click="emit('update:enabled', false)"
|
|
class="flex items-start gap-3 rounded-xl px-3 py-2.5 text-left transition-colors duration-150"
|
|
:class="!enabled
|
|
? 'bg-[var(--color-active)]'
|
|
: '@hover:bg-[var(--color-hover)]'">
|
|
<span class="i-tabler-world-off text-5 mt-0.5 shrink-0"
|
|
:class="!enabled ? 'text-[var(--text-primary)]' : 'text-[var(--text-dim)]'"></span>
|
|
<div class="flex flex-col gap-0.5">
|
|
<span class="text-sm font-medium"
|
|
:class="!enabled ? 'text-[var(--text-primary)]' : 'text-[var(--text-secondary)]'">
|
|
Off
|
|
</span>
|
|
<span class="text-xs leading-snug"
|
|
:class="!enabled ? 'text-[var(--text-secondary)]' : 'text-[var(--text-dim)]'">
|
|
Disable web access
|
|
</span>
|
|
</div>
|
|
</button>
|
|
|
|
<button @click="emit('update:enabled', true)"
|
|
class="flex items-start gap-3 rounded-xl px-3 py-2.5 text-left transition-colors duration-150"
|
|
:class="enabled
|
|
? 'bg-[var(--color-active)]'
|
|
: '@hover:bg-[var(--color-hover)]'">
|
|
<span class="i-tabler-world text-5 mt-0.5 shrink-0"
|
|
:class="enabled ? 'text-[var(--color-accent)]' : 'text-[var(--text-dim)]'"></span>
|
|
<div class="flex flex-col gap-0.5">
|
|
<span class="text-sm font-medium"
|
|
:class="enabled ? 'text-[var(--text-primary)]' : 'text-[var(--text-secondary)]'">
|
|
Auto
|
|
</span>
|
|
<span class="text-xs leading-snug"
|
|
:class="enabled ? 'text-[var(--text-secondary)]' : 'text-[var(--text-dim)]'">
|
|
Search the web and fetch URLs when needed
|
|
</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Right: settings (only when enabled) -->
|
|
<div v-if="enabled" class="flex flex-col gap-3 border-l border-[var(--color-border)] pl-4">
|
|
<!-- Max results stepper -->
|
|
<div class="flex flex-col gap-1.5">
|
|
<span class="text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider">
|
|
Max results
|
|
</span>
|
|
<div class="flex items-center gap-2">
|
|
<button @click="adjustMaxResults(-1)"
|
|
class="h-7 w-7 flex items-center justify-center rounded-lg @hover:bg-[var(--color-hover)] text-[var(--text-secondary)] @hover:text-[var(--text-primary)] transition-colors duration-150">
|
|
<span class="text-sm i-mynaui-minus"></span>
|
|
</button>
|
|
<span class="w-8 text-center text-sm font-medium tabular-nums text-[var(--text-primary)]">
|
|
{{ maxResults }}
|
|
</span>
|
|
<button @click="adjustMaxResults(1)"
|
|
class="h-7 w-7 flex items-center justify-center rounded-lg @hover:bg-[var(--color-hover)] text-[var(--text-secondary)] @hover:text-[var(--text-primary)] transition-colors duration-150">
|
|
<span class="text-sm i-mynaui-plus-solid"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rerank toggle -->
|
|
<div class="flex flex-col gap-1.5">
|
|
<span class="text-xs font-medium text-[var(--color-tertiary)] uppercase tracking-wider">
|
|
Rerank
|
|
</span>
|
|
<div v-if="!isRerankConfigured"
|
|
class="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-[var(--bg-container)] border border-[var(--color-border)]">
|
|
<button @click="() => { openSettings(); close() }"
|
|
class="flex items-center gap-2 text-xs text-[var(--text-dim)] hover:text-[var(--text-primary)] transition-colors duration-150">
|
|
<span class="i-mynaui-sparkles text-3.5"></span>
|
|
<span>Setup reranking</span>
|
|
<span class="i-mynaui-arrow-right text-3 ml-auto"></span>
|
|
</button>
|
|
</div>
|
|
<label v-else
|
|
class="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-[var(--bg-container)] border border-[var(--color-border)] cursor-pointer @hover:border-[var(--color-hover)] transition-colors duration-150">
|
|
<input type="checkbox" :checked="props.rerank"
|
|
@change="emit('update:rerank', ($event.target as HTMLInputElement).checked)"
|
|
class="w-4 h-4 rounded border-[var(--color-border)] bg-transparent text-[var(--color-accent)] focus:ring-[var(--color-accent)] focus:ring-offset-0 cursor-pointer" />
|
|
<span class="text-xs text-[var(--text-secondary)]">Rerank results</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Dropdown>
|
|
</template>
|