feat(desktop): DeerFlow visual redesign + stream hang fix + intelligence client
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
DeerFlow frontend visual overhaul: - Card-style input box (white rounded card, textarea top, actions bottom) - Dropdown mode selector (闪速/思考/Pro/Ultra with icons+descriptions) - Colored quick-action chips (小惊喜/写作/研究/收集/学习) - Minimal top bar (title + token count + export) - Warm gray color system (#faf9f6 bg, #f5f4f1 sidebar, #e8e6e1 border) - DeerFlow-style sidebar (新对话/对话/智能体 nav) - Reasoning block, tool call chain, task progress visualization - Streaming text, model selector, suggestion chips components - Resizable artifact panel with drag handle - Virtualized message list for 100+ messages Bug fixes: - Stream hang: GatewayClient onclose code 1000 now calls onComplete - WebView2 textarea border: CSS !important override for UA styles - Gateway stream event handling (response/phase/tool_call types) Intelligence client: - Unified client with fallback drivers (compactor/heartbeat/identity/memory/reflection) - Gateway API types and type conversions
This commit is contained in:
561
desktop/src/lib/intelligence-client/unified-client.ts
Normal file
561
desktop/src/lib/intelligence-client/unified-client.ts
Normal file
@@ -0,0 +1,561 @@
|
||||
/**
|
||||
* Intelligence Layer Unified Client
|
||||
*
|
||||
* Provides a unified API for intelligence operations that:
|
||||
* - Uses Rust backend (via Tauri commands) when running in Tauri environment
|
||||
* - Falls back to localStorage-based implementation in browser/dev environment
|
||||
*
|
||||
* Degradation strategy:
|
||||
* - In Tauri mode: if a Tauri invoke fails, the error is logged and re-thrown.
|
||||
* The caller is responsible for handling the error. We do NOT silently fall
|
||||
* back to localStorage, because that would give users degraded functionality
|
||||
* (localStorage instead of SQLite, rule-based instead of LLM-based, no-op
|
||||
* instead of real execution) without any indication that something is wrong.
|
||||
* - In browser/dev mode: localStorage fallback is the intended behavior for
|
||||
* development and testing without a Tauri backend.
|
||||
*
|
||||
* This replaces direct usage of:
|
||||
* - agent-memory.ts
|
||||
* - heartbeat-engine.ts
|
||||
* - context-compactor.ts
|
||||
* - reflection-engine.ts
|
||||
* - agent-identity.ts
|
||||
*
|
||||
* Usage:
|
||||
* ```typescript
|
||||
* import { intelligenceClient, toFrontendMemory, toBackendMemoryInput } from './intelligence-client';
|
||||
*
|
||||
* // Store memory
|
||||
* const id = await intelligenceClient.memory.store({
|
||||
* agent_id: 'agent-1',
|
||||
* memory_type: 'fact',
|
||||
* content: 'User prefers concise responses',
|
||||
* importance: 7,
|
||||
* });
|
||||
*
|
||||
* // Search memories
|
||||
* const memories = await intelligenceClient.memory.search({
|
||||
* agent_id: 'agent-1',
|
||||
* query: 'user preference',
|
||||
* limit: 10,
|
||||
* });
|
||||
*
|
||||
* // Convert to frontend format if needed
|
||||
* const frontendMemories = memories.map(toFrontendMemory);
|
||||
* ```
|
||||
*/
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
import { isTauriRuntime } from '../tauri-gateway';
|
||||
import { intelligence } from './type-conversions';
|
||||
import type { PersistentMemory } from '../intelligence-backend';
|
||||
import type {
|
||||
HeartbeatConfig,
|
||||
HeartbeatResult,
|
||||
CompactableMessage,
|
||||
CompactionResult,
|
||||
CompactionCheck,
|
||||
CompactionConfig,
|
||||
ReflectionConfig,
|
||||
ReflectionResult,
|
||||
ReflectionState,
|
||||
MemoryEntryForAnalysis,
|
||||
IdentityFiles,
|
||||
IdentityChangeProposal,
|
||||
IdentitySnapshot,
|
||||
} from '../intelligence-backend';
|
||||
|
||||
import type { MemoryEntry, MemorySearchOptions, MemoryStats } from './types';
|
||||
import { toFrontendMemory, toBackendSearchOptions, toFrontendStats } from './type-conversions';
|
||||
import { fallbackMemory } from './fallback-memory';
|
||||
import { fallbackCompactor } from './fallback-compactor';
|
||||
import { fallbackReflection } from './fallback-reflection';
|
||||
import { fallbackIdentity } from './fallback-identity';
|
||||
import { fallbackHeartbeat } from './fallback-heartbeat';
|
||||
|
||||
/**
|
||||
* Helper: wrap a Tauri invoke call so that failures are logged and re-thrown
|
||||
* instead of silently falling back to localStorage implementations.
|
||||
*/
|
||||
function tauriInvoke<T>(label: string, fn: () => Promise<T>): Promise<T> {
|
||||
return fn().catch((e: unknown) => {
|
||||
console.warn(`[IntelligenceClient] Tauri invoke failed (${label}):`, e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unified intelligence client that automatically selects backend or fallback.
|
||||
*
|
||||
* - In Tauri mode: calls Rust backend via invoke(). On failure, logs a warning
|
||||
* and re-throws -- does NOT fall back to localStorage.
|
||||
* - In browser/dev mode: uses localStorage-based fallback implementations.
|
||||
*/
|
||||
export const intelligenceClient = {
|
||||
memory: {
|
||||
init: async (): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('memory.init', () => intelligence.memory.init());
|
||||
} else {
|
||||
await fallbackMemory.init();
|
||||
}
|
||||
},
|
||||
|
||||
store: async (entry: import('../intelligence-backend').MemoryEntryInput): Promise<string> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('memory.store', () => intelligence.memory.store(entry));
|
||||
}
|
||||
return fallbackMemory.store(entry);
|
||||
},
|
||||
|
||||
get: async (id: string): Promise<MemoryEntry | null> => {
|
||||
if (isTauriRuntime()) {
|
||||
const result = await tauriInvoke('memory.get', () => intelligence.memory.get(id));
|
||||
return result ? toFrontendMemory(result) : null;
|
||||
}
|
||||
return fallbackMemory.get(id);
|
||||
},
|
||||
|
||||
search: async (options: MemorySearchOptions): Promise<MemoryEntry[]> => {
|
||||
if (isTauriRuntime()) {
|
||||
const results = await tauriInvoke('memory.search', () =>
|
||||
intelligence.memory.search(toBackendSearchOptions(options))
|
||||
);
|
||||
return results.map(toFrontendMemory);
|
||||
}
|
||||
return fallbackMemory.search(options);
|
||||
},
|
||||
|
||||
delete: async (id: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('memory.delete', () => intelligence.memory.delete(id));
|
||||
} else {
|
||||
await fallbackMemory.delete(id);
|
||||
}
|
||||
},
|
||||
|
||||
deleteAll: async (agentId: string): Promise<number> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('memory.deleteAll', () => intelligence.memory.deleteAll(agentId));
|
||||
}
|
||||
return fallbackMemory.deleteAll(agentId);
|
||||
},
|
||||
|
||||
stats: async (): Promise<MemoryStats> => {
|
||||
if (isTauriRuntime()) {
|
||||
const stats = await tauriInvoke('memory.stats', () => intelligence.memory.stats());
|
||||
return toFrontendStats(stats);
|
||||
}
|
||||
return fallbackMemory.stats();
|
||||
},
|
||||
|
||||
export: async (): Promise<MemoryEntry[]> => {
|
||||
if (isTauriRuntime()) {
|
||||
const results = await tauriInvoke('memory.export', () => intelligence.memory.export());
|
||||
return results.map(toFrontendMemory);
|
||||
}
|
||||
return fallbackMemory.export();
|
||||
},
|
||||
|
||||
import: async (memories: MemoryEntry[]): Promise<number> => {
|
||||
if (isTauriRuntime()) {
|
||||
const backendMemories = memories.map(m => ({
|
||||
...m,
|
||||
agent_id: m.agentId,
|
||||
memory_type: m.type,
|
||||
last_accessed_at: m.lastAccessedAt,
|
||||
created_at: m.createdAt,
|
||||
access_count: m.accessCount,
|
||||
conversation_id: m.conversationId ?? null,
|
||||
tags: JSON.stringify(m.tags),
|
||||
embedding: null,
|
||||
}));
|
||||
return tauriInvoke('memory.import', () =>
|
||||
intelligence.memory.import(backendMemories as PersistentMemory[])
|
||||
);
|
||||
}
|
||||
return fallbackMemory.import(memories);
|
||||
},
|
||||
|
||||
dbPath: async (): Promise<string> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('memory.dbPath', () => intelligence.memory.dbPath());
|
||||
}
|
||||
return fallbackMemory.dbPath();
|
||||
},
|
||||
|
||||
buildContext: async (
|
||||
agentId: string,
|
||||
query: string,
|
||||
maxTokens?: number,
|
||||
): Promise<{ systemPromptAddition: string; totalTokens: number; memoriesUsed: number }> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('memory.buildContext', () =>
|
||||
intelligence.memory.buildContext(agentId, query, maxTokens ?? null)
|
||||
);
|
||||
}
|
||||
// Browser/dev fallback: use basic search
|
||||
const memories = await fallbackMemory.search({
|
||||
agentId,
|
||||
query,
|
||||
limit: 8,
|
||||
minImportance: 3,
|
||||
});
|
||||
const addition = memories.length > 0
|
||||
? `## 相关记忆\n${memories.map(m => `- [${m.type}] ${m.content}`).join('\n')}`
|
||||
: '';
|
||||
return { systemPromptAddition: addition, totalTokens: 0, memoriesUsed: memories.length };
|
||||
},
|
||||
},
|
||||
|
||||
heartbeat: {
|
||||
init: async (agentId: string, config?: HeartbeatConfig): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('heartbeat.init', () => intelligence.heartbeat.init(agentId, config));
|
||||
} else {
|
||||
await fallbackHeartbeat.init(agentId, config);
|
||||
}
|
||||
},
|
||||
|
||||
start: async (agentId: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('heartbeat.start', () => intelligence.heartbeat.start(agentId));
|
||||
} else {
|
||||
await fallbackHeartbeat.start(agentId);
|
||||
}
|
||||
},
|
||||
|
||||
stop: async (agentId: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('heartbeat.stop', () => intelligence.heartbeat.stop(agentId));
|
||||
} else {
|
||||
await fallbackHeartbeat.stop(agentId);
|
||||
}
|
||||
},
|
||||
|
||||
tick: async (agentId: string): Promise<HeartbeatResult> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('heartbeat.tick', () => intelligence.heartbeat.tick(agentId));
|
||||
}
|
||||
return fallbackHeartbeat.tick(agentId);
|
||||
},
|
||||
|
||||
getConfig: async (agentId: string): Promise<HeartbeatConfig> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('heartbeat.getConfig', () => intelligence.heartbeat.getConfig(agentId));
|
||||
}
|
||||
return fallbackHeartbeat.getConfig(agentId);
|
||||
},
|
||||
|
||||
updateConfig: async (agentId: string, config: HeartbeatConfig): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('heartbeat.updateConfig', () =>
|
||||
intelligence.heartbeat.updateConfig(agentId, config)
|
||||
);
|
||||
} else {
|
||||
await fallbackHeartbeat.updateConfig(agentId, config);
|
||||
}
|
||||
},
|
||||
|
||||
getHistory: async (agentId: string, limit?: number): Promise<HeartbeatResult[]> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('heartbeat.getHistory', () =>
|
||||
intelligence.heartbeat.getHistory(agentId, limit)
|
||||
);
|
||||
}
|
||||
return fallbackHeartbeat.getHistory(agentId, limit);
|
||||
},
|
||||
|
||||
updateMemoryStats: async (
|
||||
agentId: string,
|
||||
taskCount: number,
|
||||
totalEntries: number,
|
||||
storageSizeBytes: number
|
||||
): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('heartbeat.updateMemoryStats', () =>
|
||||
invoke('heartbeat_update_memory_stats', {
|
||||
agent_id: agentId,
|
||||
task_count: taskCount,
|
||||
total_entries: totalEntries,
|
||||
storage_size_bytes: storageSizeBytes,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Browser/dev fallback only
|
||||
const cache = {
|
||||
taskCount,
|
||||
totalEntries,
|
||||
storageSizeBytes,
|
||||
lastUpdated: new Date().toISOString(),
|
||||
};
|
||||
localStorage.setItem(`zclaw-memory-stats-${agentId}`, JSON.stringify(cache));
|
||||
}
|
||||
},
|
||||
|
||||
recordCorrection: async (agentId: string, correctionType: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('heartbeat.recordCorrection', () =>
|
||||
invoke('heartbeat_record_correction', {
|
||||
agent_id: agentId,
|
||||
correction_type: correctionType,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Browser/dev fallback only
|
||||
const key = `zclaw-corrections-${agentId}`;
|
||||
const stored = localStorage.getItem(key);
|
||||
const counters = stored ? JSON.parse(stored) : {};
|
||||
counters[correctionType] = (counters[correctionType] || 0) + 1;
|
||||
localStorage.setItem(key, JSON.stringify(counters));
|
||||
}
|
||||
},
|
||||
|
||||
recordInteraction: async (agentId: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('heartbeat.recordInteraction', () =>
|
||||
invoke('heartbeat_record_interaction', {
|
||||
agent_id: agentId,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Browser/dev fallback only
|
||||
localStorage.setItem(`zclaw-last-interaction-${agentId}`, new Date().toISOString());
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
compactor: {
|
||||
estimateTokens: async (text: string): Promise<number> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('compactor.estimateTokens', () =>
|
||||
intelligence.compactor.estimateTokens(text)
|
||||
);
|
||||
}
|
||||
return fallbackCompactor.estimateTokens(text);
|
||||
},
|
||||
|
||||
estimateMessagesTokens: async (messages: CompactableMessage[]): Promise<number> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('compactor.estimateMessagesTokens', () =>
|
||||
intelligence.compactor.estimateMessagesTokens(messages)
|
||||
);
|
||||
}
|
||||
return fallbackCompactor.estimateMessagesTokens(messages);
|
||||
},
|
||||
|
||||
checkThreshold: async (
|
||||
messages: CompactableMessage[],
|
||||
config?: CompactionConfig
|
||||
): Promise<CompactionCheck> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('compactor.checkThreshold', () =>
|
||||
intelligence.compactor.checkThreshold(messages, config)
|
||||
);
|
||||
}
|
||||
return fallbackCompactor.checkThreshold(messages, config);
|
||||
},
|
||||
|
||||
compact: async (
|
||||
messages: CompactableMessage[],
|
||||
agentId: string,
|
||||
conversationId?: string,
|
||||
config?: CompactionConfig
|
||||
): Promise<CompactionResult> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('compactor.compact', () =>
|
||||
intelligence.compactor.compact(messages, agentId, conversationId, config)
|
||||
);
|
||||
}
|
||||
return fallbackCompactor.compact(messages, agentId, conversationId, config);
|
||||
},
|
||||
},
|
||||
|
||||
reflection: {
|
||||
init: async (config?: ReflectionConfig): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('reflection.init', () => intelligence.reflection.init(config));
|
||||
} else {
|
||||
await fallbackReflection.init(config);
|
||||
}
|
||||
},
|
||||
|
||||
recordConversation: async (): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('reflection.recordConversation', () =>
|
||||
intelligence.reflection.recordConversation()
|
||||
);
|
||||
} else {
|
||||
await fallbackReflection.recordConversation();
|
||||
}
|
||||
},
|
||||
|
||||
shouldReflect: async (): Promise<boolean> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('reflection.shouldReflect', () =>
|
||||
intelligence.reflection.shouldReflect()
|
||||
);
|
||||
}
|
||||
return fallbackReflection.shouldReflect();
|
||||
},
|
||||
|
||||
reflect: async (agentId: string, memories: MemoryEntryForAnalysis[]): Promise<ReflectionResult> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('reflection.reflect', () =>
|
||||
intelligence.reflection.reflect(agentId, memories)
|
||||
);
|
||||
}
|
||||
return fallbackReflection.reflect(agentId, memories);
|
||||
},
|
||||
|
||||
getHistory: async (limit?: number, agentId?: string): Promise<ReflectionResult[]> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('reflection.getHistory', () =>
|
||||
intelligence.reflection.getHistory(limit, agentId)
|
||||
);
|
||||
}
|
||||
return fallbackReflection.getHistory(limit, agentId);
|
||||
},
|
||||
|
||||
getState: async (): Promise<ReflectionState> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('reflection.getState', () => intelligence.reflection.getState());
|
||||
}
|
||||
return fallbackReflection.getState();
|
||||
},
|
||||
},
|
||||
|
||||
identity: {
|
||||
get: async (agentId: string): Promise<IdentityFiles> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('identity.get', () => intelligence.identity.get(agentId));
|
||||
}
|
||||
return fallbackIdentity.get(agentId);
|
||||
},
|
||||
|
||||
getFile: async (agentId: string, file: string): Promise<string> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('identity.getFile', () => intelligence.identity.getFile(agentId, file));
|
||||
}
|
||||
return fallbackIdentity.getFile(agentId, file);
|
||||
},
|
||||
|
||||
buildPrompt: async (agentId: string, memoryContext?: string): Promise<string> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('identity.buildPrompt', () =>
|
||||
intelligence.identity.buildPrompt(agentId, memoryContext)
|
||||
);
|
||||
}
|
||||
return fallbackIdentity.buildPrompt(agentId, memoryContext);
|
||||
},
|
||||
|
||||
updateUserProfile: async (agentId: string, content: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('identity.updateUserProfile', () =>
|
||||
intelligence.identity.updateUserProfile(agentId, content)
|
||||
);
|
||||
} else {
|
||||
await fallbackIdentity.updateUserProfile(agentId, content);
|
||||
}
|
||||
},
|
||||
|
||||
appendUserProfile: async (agentId: string, addition: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('identity.appendUserProfile', () =>
|
||||
intelligence.identity.appendUserProfile(agentId, addition)
|
||||
);
|
||||
} else {
|
||||
await fallbackIdentity.appendUserProfile(agentId, addition);
|
||||
}
|
||||
},
|
||||
|
||||
proposeChange: async (
|
||||
agentId: string,
|
||||
file: 'soul' | 'instructions',
|
||||
suggestedContent: string,
|
||||
reason: string
|
||||
): Promise<IdentityChangeProposal> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('identity.proposeChange', () =>
|
||||
intelligence.identity.proposeChange(agentId, file, suggestedContent, reason)
|
||||
);
|
||||
}
|
||||
return fallbackIdentity.proposeChange(agentId, file, suggestedContent, reason);
|
||||
},
|
||||
|
||||
approveProposal: async (proposalId: string): Promise<IdentityFiles> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('identity.approveProposal', () =>
|
||||
intelligence.identity.approveProposal(proposalId)
|
||||
);
|
||||
}
|
||||
return fallbackIdentity.approveProposal(proposalId);
|
||||
},
|
||||
|
||||
rejectProposal: async (proposalId: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('identity.rejectProposal', () =>
|
||||
intelligence.identity.rejectProposal(proposalId)
|
||||
);
|
||||
} else {
|
||||
await fallbackIdentity.rejectProposal(proposalId);
|
||||
}
|
||||
},
|
||||
|
||||
getPendingProposals: async (agentId?: string): Promise<IdentityChangeProposal[]> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('identity.getPendingProposals', () =>
|
||||
intelligence.identity.getPendingProposals(agentId)
|
||||
);
|
||||
}
|
||||
return fallbackIdentity.getPendingProposals(agentId);
|
||||
},
|
||||
|
||||
updateFile: async (agentId: string, file: string, content: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('identity.updateFile', () =>
|
||||
intelligence.identity.updateFile(agentId, file, content)
|
||||
);
|
||||
} else {
|
||||
await fallbackIdentity.updateFile(agentId, file, content);
|
||||
}
|
||||
},
|
||||
|
||||
getSnapshots: async (agentId: string, limit?: number): Promise<IdentitySnapshot[]> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('identity.getSnapshots', () =>
|
||||
intelligence.identity.getSnapshots(agentId, limit)
|
||||
);
|
||||
}
|
||||
return fallbackIdentity.getSnapshots(agentId, limit);
|
||||
},
|
||||
|
||||
restoreSnapshot: async (agentId: string, snapshotId: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('identity.restoreSnapshot', () =>
|
||||
intelligence.identity.restoreSnapshot(agentId, snapshotId)
|
||||
);
|
||||
} else {
|
||||
await fallbackIdentity.restoreSnapshot(agentId, snapshotId);
|
||||
}
|
||||
},
|
||||
|
||||
listAgents: async (): Promise<string[]> => {
|
||||
if (isTauriRuntime()) {
|
||||
return tauriInvoke('identity.listAgents', () => intelligence.identity.listAgents());
|
||||
}
|
||||
return fallbackIdentity.listAgents();
|
||||
},
|
||||
|
||||
deleteAgent: async (agentId: string): Promise<void> => {
|
||||
if (isTauriRuntime()) {
|
||||
await tauriInvoke('identity.deleteAgent', () => intelligence.identity.deleteAgent(agentId));
|
||||
} else {
|
||||
await fallbackIdentity.deleteAgent(agentId);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default intelligenceClient;
|
||||
Reference in New Issue
Block a user