mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
feat: enhance onboarding steps to include computer access configuration and related help information
This commit is contained in:
@@ -12,11 +12,21 @@
|
||||
"onboard": {
|
||||
"title": "Quick Onboarding",
|
||||
"subtitle": "Complete initialization directly on the welcome page.",
|
||||
"step1Title": "Configure Platform Bot",
|
||||
"step1Desc": "Connect AstrBot to IM platforms like QQ, Lark, Slack, Telegram, etc.",
|
||||
"step2Title": "Configure AI Model",
|
||||
"step2Desc": "Configure AI models for AstrBot.",
|
||||
"step1Title": "Configure AI Model",
|
||||
"step1Desc": "Configure AI models for AstrBot.",
|
||||
"step2Title": "Configure Platform Bot",
|
||||
"step2Desc": "Connect AstrBot to IM platforms like QQ, Lark, Slack, Telegram, etc.",
|
||||
"step3Title": "Allow Agent to Use the Computer",
|
||||
"step3Desc": "Set whether the Agent can access and use this computer.",
|
||||
"step3HelpTitle": "Access Details",
|
||||
"step3HelpItem1": "The Agent can access and use the workspace directory, which is isolated for each user, as well as Skills to handle more complex tasks.",
|
||||
"step3HelpItem2": "For AstrBot administrators, the Agent is additionally allowed to execute shell commands, run Python code, and access all local directories on this machine.",
|
||||
"step3HelpClose": "Close",
|
||||
"step3SelectLabel": "Computer Access",
|
||||
"step3Allow": "Allow",
|
||||
"step3Deny": "Disallow",
|
||||
"configure": "Configure",
|
||||
"save": "Save",
|
||||
"skip": "Skip",
|
||||
"pending": "Pending",
|
||||
"completed": "Completed",
|
||||
@@ -24,7 +34,10 @@
|
||||
"platformLoadFailed": "Failed to load platform configuration",
|
||||
"providerLoadFailed": "Failed to load provider configuration",
|
||||
"providerUpdateFailed": "Failed to update default chat provider in config file \"default\"",
|
||||
"providerDefaultUpdated": "Default chat provider in config file \"default\" has been set to {id}"
|
||||
"providerDefaultUpdated": "Default chat provider in config file \"default\" has been set to {id}",
|
||||
"computerAccessUpdateFailed": "Failed to update Agent computer access",
|
||||
"computerAccessAllowed": "Agent is now allowed to access and use the computer",
|
||||
"computerAccessDenied": "Agent is no longer allowed to access and use the computer"
|
||||
},
|
||||
"resources": {
|
||||
"title": "Resources",
|
||||
|
||||
@@ -12,11 +12,21 @@
|
||||
"onboard": {
|
||||
"title": "Быстрый старт",
|
||||
"subtitle": "Вы можете выполнить первичную настройку прямо здесь.",
|
||||
"step1Title": "Настройка платформ",
|
||||
"step1Desc": "Подключите AstrBot к QQ, Lark, WeChat, Telegram и другим мессенджерам.",
|
||||
"step2Title": "Настройка AI моделей",
|
||||
"step2Desc": "Выберите и настройте AI провайдеров для AstrBot.",
|
||||
"step1Title": "Настройка AI моделей",
|
||||
"step1Desc": "Выберите и настройте AI провайдеров для AstrBot.",
|
||||
"step2Title": "Настройка платформ",
|
||||
"step2Desc": "Подключите AstrBot к QQ, Lark, WeChat, Telegram и другим мессенджерам.",
|
||||
"step3Title": "Разрешить Agent использовать компьютер",
|
||||
"step3Desc": "Укажите, может ли Agent получать доступ к этому компьютеру и использовать его.",
|
||||
"step3HelpTitle": "Сведения о доступе",
|
||||
"step3HelpItem1": "Agent сможет получать доступ к каталогу рабочего пространства и использовать его, при этом рабочие каталоги разных пользователей изолированы друг от друга, а также использовать Skills для выполнения более сложных задач.",
|
||||
"step3HelpItem2": "Для администраторов AstrBot Agent дополнительно сможет выполнять shell-команды, запускать Python-код и получать доступ ко всем локальным каталогам на этом компьютере.",
|
||||
"step3HelpClose": "Закрыть",
|
||||
"step3SelectLabel": "Доступ к компьютеру",
|
||||
"step3Allow": "Разрешить",
|
||||
"step3Deny": "Запретить",
|
||||
"configure": "Настроить",
|
||||
"save": "Сохранить",
|
||||
"skip": "Пропустить",
|
||||
"pending": "Ожидает",
|
||||
"completed": "Готово",
|
||||
@@ -24,7 +34,10 @@
|
||||
"platformLoadFailed": "Ошибка загрузки конфигурации платформ",
|
||||
"providerLoadFailed": "Ошибка загрузки конфигурации провайдеров",
|
||||
"providerUpdateFailed": "Ошибка обновления провайдера по умолчанию в файле default",
|
||||
"providerDefaultUpdated": "Провайдер {id} установлен по умолчанию в файле default"
|
||||
"providerDefaultUpdated": "Провайдер {id} установлен по умолчанию в файле default",
|
||||
"computerAccessUpdateFailed": "Не удалось обновить доступ Agent к компьютеру",
|
||||
"computerAccessAllowed": "Agent теперь может получать доступ к компьютеру и использовать его",
|
||||
"computerAccessDenied": "Agent больше не может получать доступ к компьютеру и использовать его"
|
||||
},
|
||||
"resources": {
|
||||
"title": "Ресурсы",
|
||||
@@ -34,4 +47,4 @@
|
||||
"afdianTitle": "Afdian",
|
||||
"afdianDesc": "Поддержите команду AstrBot через Afdian."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,21 @@
|
||||
"onboard": {
|
||||
"title": "快速引导",
|
||||
"subtitle": "欢迎页可直接完成初始化。",
|
||||
"step1Title": "配置平台机器人",
|
||||
"step1Desc": "将 AstrBot 连接到 QQ、飞书、企业微信、Telegram 等 IM 平台。",
|
||||
"step2Title": "配置 AI 模型",
|
||||
"step2Desc": "为 AstrBot 配置 AI 模型。",
|
||||
"step1Title": "配置 AI 模型",
|
||||
"step1Desc": "为 AstrBot 配置 AI 模型。",
|
||||
"step2Title": "配置平台机器人",
|
||||
"step2Desc": "将 AstrBot 连接到 QQ、飞书、企业微信、Telegram 等 IM 平台。",
|
||||
"step3Title": "允许 Agent 使用电脑",
|
||||
"step3Desc": "设置 Agent 是否可以访问和使用当前电脑。",
|
||||
"step3HelpTitle": "允许 Agent 使用电脑",
|
||||
"step3HelpItem1": "Agent 将可以访问和使用工作区目录(每个用户的工作区目录相互独立)以及 Skills 来执行更多复杂任务。",
|
||||
"step3HelpItem2": "对于 AstrBot 管理员,会额外允许 Agent 执行 Shell 命令、Python 代码,以及访问本机的所有目录。",
|
||||
"step3HelpClose": "关闭",
|
||||
"step3SelectLabel": "电脑访问权限",
|
||||
"step3Allow": "允许",
|
||||
"step3Deny": "不允许",
|
||||
"configure": "去配置",
|
||||
"save": "保存",
|
||||
"skip": "跳过",
|
||||
"pending": "待处理",
|
||||
"completed": "已完成",
|
||||
@@ -24,7 +34,10 @@
|
||||
"platformLoadFailed": "加载平台配置失败",
|
||||
"providerLoadFailed": "加载提供商配置失败",
|
||||
"providerUpdateFailed": "更新 default 配置文件默认对话提供商失败",
|
||||
"providerDefaultUpdated": "已将 default 配置文件的默认对话提供商设置为 {id}"
|
||||
"providerDefaultUpdated": "已将 default 配置文件的默认对话提供商设置为 {id}",
|
||||
"computerAccessUpdateFailed": "更新 Agent 电脑访问权限失败",
|
||||
"computerAccessAllowed": "已允许 Agent 访问和使用电脑",
|
||||
"computerAccessDenied": "已禁止 Agent 访问和使用电脑"
|
||||
},
|
||||
"resources": {
|
||||
"title": "相关资源",
|
||||
|
||||
@@ -20,11 +20,28 @@
|
||||
</div>
|
||||
|
||||
<v-timeline align="start" side="end" density="compact" class="welcome-timeline" truncate-line="both">
|
||||
<v-timeline-item :dot-color="platformStepState === 'completed' ? 'success' : 'primary'"
|
||||
:icon="platformStepState === 'completed' ? 'mdi-check' : 'mdi-numeric-1'" fill-dot size="small">
|
||||
<v-timeline-item :dot-color="providerStepState === 'completed' ? 'success' : 'primary'"
|
||||
icon="mdi-numeric-1" fill-dot size="small">
|
||||
<div class="pl-2">
|
||||
<div class="text-h6 font-weight-bold mb-1">{{ tm('onboard.step1Title') }}</div>
|
||||
<p class="text-body-2 text-medium-emphasis mb-3">{{ tm('onboard.step1Desc') }}</p>
|
||||
<div class="d-flex align-center">
|
||||
<v-btn color="primary" variant="flat" rounded="pill" class="px-6" @click="openProviderDialog">
|
||||
{{ tm('onboard.configure') }}
|
||||
</v-btn>
|
||||
<div v-if="providerStepState === 'completed'"
|
||||
class="text-success d-flex align-center text-body-2 font-weight-medium ml-3">
|
||||
{{ tm('onboard.completed') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-timeline-item>
|
||||
|
||||
<v-timeline-item :dot-color="platformStepState === 'completed' ? 'success' : 'primary'"
|
||||
icon="mdi-numeric-2" fill-dot size="small">
|
||||
<div class="pl-2">
|
||||
<div class="text-h6 font-weight-bold mb-1">{{ tm('onboard.step2Title') }}</div>
|
||||
<p class="text-body-2 text-medium-emphasis mb-3">{{ tm('onboard.step2Desc') }}</p>
|
||||
<div class="d-flex align-center">
|
||||
<v-btn color="primary" variant="flat" rounded="pill" class="px-6" :loading="loadingPlatformDialog"
|
||||
@click="openPlatformDialog">
|
||||
@@ -38,22 +55,37 @@
|
||||
</div>
|
||||
</v-timeline-item>
|
||||
|
||||
<v-timeline-item :dot-color="providerStepState === 'completed' ? 'success' : 'primary'"
|
||||
:icon="providerStepState === 'completed' ? 'mdi-check' : 'mdi-numeric-2'" fill-dot size="small">
|
||||
<v-timeline-item :dot-color="computerAccessStepState === 'completed' ? 'success' : 'primary'"
|
||||
icon="mdi-numeric-3" fill-dot size="small">
|
||||
<div class="pl-2">
|
||||
<div class="text-h6 font-weight-bold mb-1"
|
||||
:class="{ 'text-medium-emphasis': platformStepState !== 'completed' }">{{ tm('onboard.step2Title')
|
||||
}}
|
||||
</div>
|
||||
<p class="text-body-2 text-medium-emphasis mb-3">{{ tm('onboard.step2Desc') }}</p>
|
||||
<div class="d-flex align-center">
|
||||
<v-btn color="primary" variant="flat" rounded="pill" class="px-6" @click="openProviderDialog">
|
||||
{{ tm('onboard.configure') }}
|
||||
<div class="d-flex align-center mb-1">
|
||||
<div class="text-h6 font-weight-bold">{{ tm('onboard.step3Title') }}</div>
|
||||
<v-btn
|
||||
icon
|
||||
variant="text"
|
||||
density="comfortable"
|
||||
size="small"
|
||||
class="ml-1"
|
||||
@click="showComputerAccessHelpDialog = true"
|
||||
>
|
||||
<span class="text-body-2 font-weight-bold">?</span>
|
||||
</v-btn>
|
||||
<div v-if="providerStepState === 'completed'"
|
||||
class="text-success d-flex align-center text-body-2 font-weight-medium ml-3">
|
||||
{{ tm('onboard.completed') }}
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-body-2 text-medium-emphasis mb-3">{{ tm('onboard.step3Desc') }}</p>
|
||||
<div class="d-flex flex-wrap align-center ga-3">
|
||||
<v-select
|
||||
v-model="computerAccessRuntime"
|
||||
:items="computerAccessOptions"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:label="tm('onboard.step3SelectLabel')"
|
||||
:loading="savingComputerAccess"
|
||||
:disabled="savingComputerAccess"
|
||||
hide-details
|
||||
density="comfortable"
|
||||
variant="outlined"
|
||||
class="computer-access-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</v-timeline-item>
|
||||
@@ -136,6 +168,25 @@
|
||||
<AddNewPlatform v-model:show="showAddPlatformDialog" :metadata="platformMetadata" :config_data="platformConfigData"
|
||||
@refresh-config="loadPlatformConfigBase" />
|
||||
<ProviderConfigDialog v-model="showProviderDialog" />
|
||||
<v-dialog v-model="showComputerAccessHelpDialog" max-width="640">
|
||||
<v-card>
|
||||
<v-card-title class="text-h3 font-weight-bold pa-4">
|
||||
{{ tm('onboard.step3HelpTitle') }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<ol class="computer-access-help-list">
|
||||
<li>{{ tm('onboard.step3HelpItem1') }}</li>
|
||||
<li>{{ tm('onboard.step3HelpItem2') }}</li>
|
||||
</ol>
|
||||
</v-card-text>
|
||||
<v-card-actions class="px-6 pb-4">
|
||||
<v-spacer />
|
||||
<v-btn color="primary" variant="text" @click="showComputerAccessHelpDialog = false">
|
||||
{{ tm('onboard.step3HelpClose') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -151,6 +202,7 @@ import 'markstream-vue/index.css';
|
||||
import 'highlight.js/styles/github.css';
|
||||
|
||||
type StepState = 'pending' | 'completed' | 'skipped';
|
||||
type ComputerAccessRuntime = 'local' | 'none';
|
||||
|
||||
const { tm } = useModuleI18n('features/welcome');
|
||||
const { locale } = useI18n();
|
||||
@@ -158,6 +210,7 @@ const { success: showSuccess, error: showError } = useToast();
|
||||
|
||||
const showAddPlatformDialog = ref(false);
|
||||
const showProviderDialog = ref(false);
|
||||
const showComputerAccessHelpDialog = ref(false);
|
||||
const loadingPlatformDialog = ref(false);
|
||||
|
||||
const platformMetadata = ref<Record<string, any>>({});
|
||||
@@ -167,6 +220,10 @@ const providerCountBeforeOpen = ref(0);
|
||||
|
||||
const platformStepState = ref<StepState>('pending');
|
||||
const providerStepState = ref<StepState>('pending');
|
||||
const computerAccessStepState = ref<StepState>('pending');
|
||||
const computerAccessRuntime = ref<ComputerAccessRuntime>('none');
|
||||
const savedComputerAccessRuntime = ref<ComputerAccessRuntime>('none');
|
||||
const savingComputerAccess = ref(false);
|
||||
const welcomeAnnouncementRaw = ref<unknown>(null);
|
||||
|
||||
function resolveWelcomeAnnouncement(raw: unknown, currentLocale: string) {
|
||||
@@ -276,6 +333,11 @@ async function loadPlatformConfigBase() {
|
||||
platformConfigData.value = res.data.data.config || {};
|
||||
}
|
||||
|
||||
async function fetchDefaultConfig() {
|
||||
const res = await axios.get('/api/config/abconf', { params: { id: 'default' } });
|
||||
return res.data?.data?.config || {};
|
||||
}
|
||||
|
||||
function getChatProvidersFromTemplatePayload(payload: any) {
|
||||
const providers = payload?.providers || [];
|
||||
const sources = payload?.provider_sources || [];
|
||||
@@ -315,8 +377,7 @@ async function syncDefaultConfigProviderIfNeeded() {
|
||||
const targetProviderId = pickDefaultProviderId(providers);
|
||||
if (!targetProviderId) return;
|
||||
|
||||
const configRes = await axios.get('/api/config/abconf', { params: { id: 'default' } });
|
||||
const configData = configRes.data?.data?.config || {};
|
||||
const configData = await fetchDefaultConfig();
|
||||
if (!configData.provider_settings) {
|
||||
configData.provider_settings = {};
|
||||
}
|
||||
@@ -336,6 +397,62 @@ async function syncDefaultConfigProviderIfNeeded() {
|
||||
showSuccess(tm('onboard.providerDefaultUpdated', { id: targetProviderId }));
|
||||
}
|
||||
|
||||
function normalizeComputerAccessRuntime(runtime: unknown): ComputerAccessRuntime {
|
||||
return runtime === 'local' || runtime === 'sandbox' ? 'local' : 'none';
|
||||
}
|
||||
|
||||
function syncComputerAccessRuntime(configData: any) {
|
||||
const providerSettings = configData?.provider_settings || {};
|
||||
const currentRuntime = providerSettings?.computer_use_runtime;
|
||||
const normalizedRuntime = normalizeComputerAccessRuntime(currentRuntime);
|
||||
|
||||
computerAccessRuntime.value = normalizedRuntime;
|
||||
savedComputerAccessRuntime.value = normalizedRuntime;
|
||||
computerAccessStepState.value =
|
||||
currentRuntime === 'local' || currentRuntime === 'none' || currentRuntime === 'sandbox'
|
||||
? 'completed'
|
||||
: 'pending';
|
||||
}
|
||||
|
||||
const computerAccessOptions = computed(() => [
|
||||
{ title: tm('onboard.step3Allow'), value: 'local' },
|
||||
{ title: tm('onboard.step3Deny'), value: 'none' }
|
||||
]);
|
||||
|
||||
async function saveComputerAccessRuntime() {
|
||||
savingComputerAccess.value = true;
|
||||
try {
|
||||
const configData = await fetchDefaultConfig();
|
||||
if (!configData.provider_settings) {
|
||||
configData.provider_settings = {};
|
||||
}
|
||||
|
||||
configData.provider_settings.computer_use_runtime = computerAccessRuntime.value;
|
||||
|
||||
const updateRes = await axios.post('/api/config/astrbot/update', {
|
||||
conf_id: 'default',
|
||||
config: configData
|
||||
});
|
||||
if (updateRes.data.status !== 'ok') {
|
||||
throw new Error(updateRes.data.message || tm('onboard.computerAccessUpdateFailed'));
|
||||
}
|
||||
|
||||
savedComputerAccessRuntime.value = computerAccessRuntime.value;
|
||||
computerAccessStepState.value = 'completed';
|
||||
showSuccess(
|
||||
tm(
|
||||
computerAccessRuntime.value === 'local'
|
||||
? 'onboard.computerAccessAllowed'
|
||||
: 'onboard.computerAccessDenied'
|
||||
)
|
||||
);
|
||||
} catch (err: any) {
|
||||
showError(err?.response?.data?.message || err?.message || tm('onboard.computerAccessUpdateFailed'));
|
||||
} finally {
|
||||
savingComputerAccess.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadWelcomeAnnouncement() {
|
||||
try {
|
||||
const res = await axios.get('https://cloud.astrbot.app/api/v1/announcement');
|
||||
@@ -366,6 +483,13 @@ onMounted(async () => {
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
try {
|
||||
const defaultConfig = await fetchDefaultConfig();
|
||||
syncComputerAccessRuntime(defaultConfig);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
async function openPlatformDialog() {
|
||||
@@ -416,6 +540,18 @@ watch(showProviderDialog, async (visible, wasVisible) => {
|
||||
showError(err?.response?.data?.message || err?.message || tm('onboard.providerUpdateFailed'));
|
||||
}
|
||||
});
|
||||
|
||||
watch(computerAccessRuntime, async (value, oldValue) => {
|
||||
if (value === oldValue) return;
|
||||
if (value === savedComputerAccessRuntime.value) return;
|
||||
if (savingComputerAccess.value) return;
|
||||
|
||||
try {
|
||||
await saveComputerAccessRuntime();
|
||||
} catch {
|
||||
computerAccessRuntime.value = savedComputerAccessRuntime.value;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -430,4 +566,14 @@ watch(showProviderDialog, async (visible, wasVisible) => {
|
||||
.welcome-announcement-markdown {
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.computer-access-select {
|
||||
max-width: 240px;
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
.computer-access-help-list {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user