agent-Specialization/static/src/auth/LoginApp.vue
JOJO 4fcd0ccc4d feat(multi-agent): 子智能体系统升级
- 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/路径修复
2026-07-14 02:28:45 +08:00

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>