- prompt改造:子智能体注入AGENTS.md/执行环境/工作区信息/skills/项目记忆 - 工具增加:read_skill/recall_project_memory/todo_create/todo_update_task/save_webpage - 上下文压缩:深度压缩机制,记录current_context_tokens,默认150k阈值可配置 - 模型升级:sub_agent_models.json支持thinkmode_status/extra_parameter,与主智能体对齐 - 角色管理三层结构:源码树预设multi_agent_roles/ + 运行态host/web预设 + web按用户隔离 - 启动同步:initialize_system调用sync_preset_roles同步预设到host和web运行态 - 模式判断:API用session.host_mode,工具用data_dir路径判断,不依赖IS_HOST_MODE - 前端:个人空间新增子智能体管理页(角色CRUD/压缩阈值/模型选择),复用个人空间样式 - 入口改造:登录页移除多智能体按钮,QuickMenu加模式切换项,运行中对话禁止切换 - 工具调整:多智能体模式create_sub_agent去掉timeout/deliverables_dir参数 - skill禁止:sub-agent-guide在多智能体模式下禁止阅读 - .agents/统一为.astrion/路径修复
156 lines
3.7 KiB
Vue
156 lines
3.7 KiB
Vue
<template>
|
|
<main class="auth-page">
|
|
<section class="auth-card">
|
|
<h1 class="auth-title">Astrion 登录</h1>
|
|
<p class="auth-subtitle">使用账号继续访问工作台</p>
|
|
|
|
<div class="auth-form-group">
|
|
<label class="auth-label" for="email">邮箱</label>
|
|
<input
|
|
id="email"
|
|
v-model.trim="email"
|
|
type="email"
|
|
class="auth-input"
|
|
autocomplete="email"
|
|
/>
|
|
</div>
|
|
|
|
<div class="auth-form-group">
|
|
<label class="auth-label" for="password">密码</label>
|
|
<input
|
|
id="password"
|
|
v-model="password"
|
|
type="password"
|
|
class="auth-input"
|
|
autocomplete="current-password"
|
|
@keydown.enter="login"
|
|
/>
|
|
</div>
|
|
|
|
<button class="auth-button" :disabled="submitting" @click="login">登录</button>
|
|
|
|
<button
|
|
v-if="hostModeEnabled"
|
|
class="auth-secondary-button"
|
|
:disabled="hostSubmitting"
|
|
@click="hostLogin"
|
|
>
|
|
宿主机模式(免登录)
|
|
</button>
|
|
|
|
<div class="auth-error">{{ error }}</div>
|
|
<div class="auth-link">还没有账号?<a href="/register">点击注册</a></div>
|
|
</section>
|
|
</main>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { onMounted, ref } from 'vue';
|
|
import { applyTheme, loadTheme } from './theme';
|
|
|
|
declare global {
|
|
interface Window {
|
|
ensureCsrfToken?: () => Promise<unknown>;
|
|
}
|
|
}
|
|
|
|
const email = ref('');
|
|
const password = ref('');
|
|
const error = ref('');
|
|
const submitting = ref(false);
|
|
const hostSubmitting = ref(false);
|
|
const hostModeEnabled = ref(false);
|
|
|
|
const doLogin = async (redirectUrl = '/') => {
|
|
if (!email.value || !password.value) {
|
|
error.value = '请输入邮箱和密码';
|
|
return;
|
|
}
|
|
|
|
submitting.value = true;
|
|
error.value = '';
|
|
|
|
try {
|
|
const resp = await fetch('/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email: email.value, password: password.value })
|
|
});
|
|
|
|
if (resp.status === 503) {
|
|
window.location.href = '/resource_busy';
|
|
return;
|
|
}
|
|
|
|
const data = await resp.json();
|
|
if (data.success) {
|
|
window.location.href = redirectUrl;
|
|
return;
|
|
}
|
|
|
|
error.value = data.error || '登录失败';
|
|
} catch (_err) {
|
|
error.value = '网络错误,请重试';
|
|
} finally {
|
|
submitting.value = false;
|
|
}
|
|
};
|
|
|
|
const login = () => doLogin('/');
|
|
|
|
const doHostLogin = async (redirectUrl = '/') => {
|
|
hostSubmitting.value = true;
|
|
error.value = '';
|
|
|
|
try {
|
|
const resp = await fetch('/host-login', { method: 'POST' });
|
|
if (resp.status === 503) {
|
|
window.location.href = '/resource_busy';
|
|
return;
|
|
}
|
|
|
|
const data = await resp.json();
|
|
if (data.success) {
|
|
window.location.href = redirectUrl;
|
|
return;
|
|
}
|
|
|
|
error.value = data.error || '宿主机模式不可用';
|
|
} catch (_err) {
|
|
error.value = '网络错误,请重试';
|
|
} finally {
|
|
hostSubmitting.value = false;
|
|
}
|
|
};
|
|
|
|
const hostLogin = () => doHostLogin('/');
|
|
|
|
onMounted(async () => {
|
|
applyTheme(loadTheme());
|
|
|
|
if (window.ensureCsrfToken) {
|
|
try {
|
|
await window.ensureCsrfToken();
|
|
} catch (_err) {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
try {
|
|
const resp = await fetch('/api/host-mode-enabled');
|
|
const data = await resp.json();
|
|
hostModeEnabled.value = !!(data && data.success && data.enabled);
|
|
} catch (_err) {
|
|
hostModeEnabled.value = false;
|
|
}
|
|
|
|
try {
|
|
const resp = await fetch('/api/session-status', { credentials: 'same-origin' });
|
|
const data = await resp.json();
|
|
console.info('[auth-debug] login page session-status:', data);
|
|
} catch (err) {
|
|
console.warn('[auth-debug] login page session-status failed:', err);
|
|
}
|
|
});
|
|
</script>
|