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:
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import type { GatewayClient } from '../lib/gateway-client';
|
||||
import type { AgentTemplateFull } from '../lib/saas-client';
|
||||
import { useChatStore } from './chatStore';
|
||||
|
||||
// === Types ===
|
||||
@@ -33,6 +34,7 @@ export interface Clone {
|
||||
communicationStyle?: string; // 沟通风格描述
|
||||
notes?: string; // 用户备注
|
||||
onboardingCompleted?: boolean; // 是否完成首次引导
|
||||
source_template_id?: string; // 模板来源 ID
|
||||
}
|
||||
|
||||
export interface UsageStats {
|
||||
@@ -83,6 +85,7 @@ export interface AgentStateSlice {
|
||||
export interface AgentActionsSlice {
|
||||
loadClones: () => Promise<void>;
|
||||
createClone: (opts: CloneCreateOptions) => Promise<Clone | undefined>;
|
||||
createFromTemplate: (template: AgentTemplateFull) => Promise<Clone | undefined>;
|
||||
updateClone: (id: string, updates: Partial<Clone>) => Promise<Clone | undefined>;
|
||||
deleteClone: (id: string) => Promise<void>;
|
||||
loadUsageStats: () => Promise<void>;
|
||||
@@ -173,6 +176,43 @@ export const useAgentStore = create<AgentStore>((set, get) => ({
|
||||
}
|
||||
},
|
||||
|
||||
createFromTemplate: async (template: AgentTemplateFull) => {
|
||||
const client = getClient();
|
||||
if (!client) return undefined;
|
||||
|
||||
set({ isLoading: true, error: null });
|
||||
try {
|
||||
const result = await client.createClone({
|
||||
name: template.name,
|
||||
emoji: template.emoji,
|
||||
personality: template.personality,
|
||||
scenarios: template.scenarios,
|
||||
communicationStyle: template.communication_style,
|
||||
model: template.model,
|
||||
});
|
||||
|
||||
const cloneId = result?.clone?.id;
|
||||
|
||||
// Persist SOUL.md via identity system
|
||||
if (cloneId && template.soul_content) {
|
||||
try {
|
||||
const { intelligenceClient } = await import('../lib/intelligence-client');
|
||||
await intelligenceClient.identity.updateFile(cloneId, 'soul', template.soul_content);
|
||||
} catch (e) {
|
||||
console.warn('Failed to persist soul_content:', e);
|
||||
}
|
||||
}
|
||||
|
||||
await get().loadClones();
|
||||
return result?.clone;
|
||||
} catch (error) {
|
||||
set({ error: String(error) });
|
||||
return undefined;
|
||||
} finally {
|
||||
set({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
updateClone: async (id: string, updates: Partial<Clone>) => {
|
||||
const client = getClient();
|
||||
if (!client) {
|
||||
|
||||
Reference in New Issue
Block a user