feat(desktop): integrate SaaS llm_routing, template API, and onboarding template selection

- Add AgentTemplateAvailable/AgentTemplateFull types and fetchAvailableTemplates/fetchTemplateFull API methods to saas-client
- Add llm_routing field to SaaSAccountInfo for admin-configured routing priority
- Add availableTemplates state and fetchAvailableTemplates action to saasStore with background fetch on login
- Add admin llm_routing priority check in connectionStore connect() to force relay or local mode
- Add createFromTemplate action to agentStore with SOUL.md persistence
- Add Step 0 template selection to AgentOnboardingWizard with grid layout for template browsing
This commit is contained in:
iven
2026-03-31 03:15:45 +08:00
parent 9fb9c3204c
commit c9b9c5231b
6 changed files with 927 additions and 1025 deletions

View File

@@ -350,6 +350,70 @@ export const useConnectionStore = create<ConnectionStore>((set, get) => {
try {
set({ error: null });
// === Admin Routing Priority ===
// Admin-configured llm_routing takes priority over localStorage connectionMode.
// This allows admins to force all clients to use relay or local mode.
let adminForceLocal = false;
try {
const storedAccount = JSON.parse(localStorage.getItem('zclaw-saas-account') || '{}');
const adminRouting = storedAccount?.account?.llm_routing;
if (adminRouting === 'relay') {
// Force SaaS Relay mode — admin override
// Set connection mode to 'saas' so the SaaS relay section below activates
localStorage.setItem('zclaw-connection-mode', 'saas');
log.debug('Admin llm_routing=relay: forcing SaaS relay mode');
} else if (adminRouting === 'local' && isTauriRuntime()) {
// Force local Kernel mode — skip SaaS relay entirely
adminForceLocal = true;
localStorage.setItem('zclaw-connection-mode', 'tauri');
log.debug('Admin llm_routing=local: forcing local Kernel mode');
}
} catch { /* ignore parse errors, fall through to default logic */ }
// === Internal Kernel Mode: Admin forced local ===
// If admin forced local mode, skip directly to Tauri Kernel section
if (adminForceLocal) {
const kernelClient = getKernelClient();
const modelConfig = await getDefaultModelConfigAsync();
if (!modelConfig) {
throw new Error('请先在"模型与 API"设置页面添加自定义模型配置');
}
if (!modelConfig.apiKey) {
throw new Error(`模型 ${modelConfig.model} 未配置 API Key请在"模型与 API"设置页面配置`);
}
kernelClient.setConfig({
provider: modelConfig.provider,
model: modelConfig.model,
apiKey: modelConfig.apiKey,
baseUrl: modelConfig.baseUrl,
apiProtocol: modelConfig.apiProtocol,
});
kernelClient.onStateChange = (state: ConnectionState) => {
set({ connectionState: state });
};
kernelClient.onLog = (level, message) => {
set((s) => ({
logs: [...s.logs.slice(-99), { timestamp: Date.now(), level, message }],
}));
};
set({ client: kernelClient });
const { initializeStores } = await import('./index');
initializeStores();
await kernelClient.connect();
set({ gatewayVersion: '0.1.0-internal' });
log.debug('Connected to internal ZCLAW Kernel (admin forced local)');
return;
}
// === SaaS Relay Mode ===
// Check connection mode from localStorage (set by saasStore).
// When SaaS is unreachable, gracefully degrade to local kernel mode