diff --git a/desktop/src/lib/intelligence-backend.ts b/desktop/src/lib/intelligence-backend.ts new file mode 100644 index 0000000..6ab94b5 --- /dev/null +++ b/desktop/src/lib/intelligence-backend.ts @@ -0,0 +1,445 @@ +/** + * Intelligence Layer Backend Adapter + * + * Provides TypeScript API for calling Rust intelligence commands. + * This replaces the localStorage-based implementations in: + * - agent-memory.ts (Phase 1) + * - heartbeat-engine.ts (Phase 2) + * - context-compactor.ts (Phase 2) + * - reflection-engine.ts (Phase 3) + * - agent-identity.ts (Phase 3) + * + * Usage: + * ```typescript + * import { intelligence } from './intelligence-backend'; + * + * // Memory + * const memoryId = await intelligence.memory.store({ ... }); + * const memories = await intelligence.memory.search({ query: '...' }); + * + * // Heartbeat + * await intelligence.heartbeat.init('agent-1'); + * await intelligence.heartbeat.start('agent-1'); + * + * // Reflection + * const result = await intelligence.reflection.reflect('agent-1', memories); + * ``` + */ + +import { invoke } from '@tauri-apps/api/core'; + +// === Types === + +export interface MemoryEntryInput { + agent_id: string; + memory_type: string; + content: string; + importance?: number; + source?: string; + tags?: string[]; + conversation_id?: string; +} + +export interface PersistentMemory { + id: string; + agent_id: string; + memory_type: string; + content: string; + importance: number; + source: string; + tags: string; + conversation_id: string | null; + created_at: string; + last_accessed_at: string; + access_count: number; + embedding: string | null; +} + +export interface MemorySearchOptions { + agent_id?: string; + memory_type?: string; + tags?: string[]; + query?: string; + min_importance?: number; + limit?: number; + offset?: number; +} + +export interface MemoryStats { + total_memories: number; + by_type: Record; + by_agent: Record; + oldest_memory: string | null; + newest_memory: string | null; +} + +// Heartbeat types +export interface HeartbeatConfig { + enabled: boolean; + interval_minutes: number; + quiet_hours_start: string | null; + quiet_hours_end: string | null; + notify_channel: 'ui' | 'desktop' | 'all'; + proactivity_level: 'silent' | 'light' | 'standard' | 'autonomous'; + max_alerts_per_tick: number; +} + +export interface HeartbeatAlert { + title: string; + content: string; + urgency: 'low' | 'medium' | 'high'; + source: string; + timestamp: string; +} + +export interface HeartbeatResult { + status: 'ok' | 'alert'; + alerts: HeartbeatAlert[]; + checked_items: number; + timestamp: string; +} + +// Compactor types +export interface CompactableMessage { + role: string; + content: string; + id?: string; + timestamp?: string; +} + +export interface CompactionResult { + compacted_messages: CompactableMessage[]; + summary: string; + original_count: number; + retained_count: number; + flushed_memories: number; + tokens_before_compaction: number; + tokens_after_compaction: number; +} + +export interface CompactionCheck { + should_compact: boolean; + current_tokens: number; + threshold: number; + urgency: 'none' | 'soft' | 'hard'; +} + +// Reflection types +export interface MemoryEntryForAnalysis { + memory_type: string; + content: string; + importance: number; + access_count: number; + tags: string[]; +} + +export interface PatternObservation { + observation: string; + frequency: number; + sentiment: 'positive' | 'negative' | 'neutral'; + evidence: string[]; +} + +export interface ImprovementSuggestion { + area: string; + suggestion: string; + priority: 'high' | 'medium' | 'low'; +} + +export interface ReflectionResult { + patterns: PatternObservation[]; + improvements: ImprovementSuggestion[]; + identity_proposals: IdentityChangeProposal[]; + new_memories: number; + timestamp: string; +} + +export interface ReflectionState { + conversations_since_reflection: number; + last_reflection_time: string | null; + last_reflection_agent_id: string | null; +} + +// Identity types +export interface IdentityFiles { + soul: string; + instructions: string; + user_profile: string; + heartbeat?: string; +} + +export interface IdentityChangeProposal { + id: string; + agent_id: string; + file: 'soul' | 'instructions'; + reason: string; + current_content: string; + suggested_content: string; + status: 'pending' | 'approved' | 'rejected'; + created_at: string; +} + +export interface IdentitySnapshot { + id: string; + agent_id: string; + files: IdentityFiles; + timestamp: string; + reason: string; +} + +// === Memory API === + +export const memory = { + async init(): Promise { + await invoke('memory_init'); + }, + + async store(entry: MemoryEntryInput): Promise { + return invoke('memory_store', { entry }); + }, + + async get(id: string): Promise { + return invoke('memory_get', { id }); + }, + + async search(options: MemorySearchOptions): Promise { + return invoke('memory_search', { options }); + }, + + async delete(id: string): Promise { + await invoke('memory_delete', { id }); + }, + + async deleteAll(agentId: string): Promise { + return invoke('memory_delete_all', { agentId }); + }, + + async stats(): Promise { + return invoke('memory_stats'); + }, + + async export(): Promise { + return invoke('memory_export'); + }, + + async import(memories: PersistentMemory[]): Promise { + return invoke('memory_import', { memories }); + }, + + async dbPath(): Promise { + return invoke('memory_db_path'); + }, +}; + +// === Heartbeat API === + +export const heartbeat = { + async init(agentId: string, config?: HeartbeatConfig): Promise { + await invoke('heartbeat_init', { agentId, config }); + }, + + async start(agentId: string): Promise { + await invoke('heartbeat_start', { agentId }); + }, + + async stop(agentId: string): Promise { + await invoke('heartbeat_stop', { agentId }); + }, + + async tick(agentId: string): Promise { + return invoke('heartbeat_tick', { agentId }); + }, + + async getConfig(agentId: string): Promise { + return invoke('heartbeat_get_config', { agentId }); + }, + + async updateConfig(agentId: string, config: HeartbeatConfig): Promise { + await invoke('heartbeat_update_config', { agentId, config }); + }, + + async getHistory(agentId: string, limit?: number): Promise { + return invoke('heartbeat_get_history', { agentId, limit }); + }, +}; + +// === Compactor API === + +export const compactor = { + estimateTokens(text: string): Promise { + return invoke('compactor_estimate_tokens', { text }); + }, + + estimateMessagesTokens(messages: CompactableMessage[]): Promise { + return invoke('compactor_estimate_messages_tokens', { messages }); + }, + + checkThreshold( + messages: CompactableMessage[], + config?: CompactionConfig + ): Promise { + return invoke('compactor_check_threshold', { messages, config }); + }, + + compact( + messages: CompactableMessage[], + agentId: string, + conversationId?: string, + config?: CompactionConfig + ): Promise { + return invoke('compactor_compact', { + messages, + agentId, + conversationId, + config, + }); + }, +}; + +export interface CompactionConfig { + soft_threshold_tokens?: number; + hard_threshold_tokens?: number; + reserve_tokens?: number; + memory_flush_enabled?: boolean; + keep_recent_messages?: number; + summary_max_tokens?: number; + use_llm?: boolean; + llm_fallback_to_rules?: boolean; +} + +// === Reflection API === + +export const reflection = { + async init(config?: ReflectionConfig): Promise { + await invoke('reflection_init', { config }); + }, + + async recordConversation(): Promise { + await invoke('reflection_record_conversation'); + }, + + async shouldReflect(): Promise { + return invoke('reflection_should_reflect'); + }, + + async reflect( + agentId: string, + memories: MemoryEntryForAnalysis[] + ): Promise { + return invoke('reflection_reflect', { agentId, memories }); + }, + + async getHistory(limit?: number): Promise { + return invoke('reflection_get_history', { limit }); + }, + + async getState(): Promise { + return invoke('reflection_get_state'); + }, +}; + +export interface ReflectionConfig { + trigger_after_conversations?: number; + trigger_after_hours?: number; + allow_soul_modification?: boolean; + require_approval?: boolean; + use_llm?: boolean; + llm_fallback_to_rules?: boolean; +} + +// === Identity API === + +export const identity = { + async get(agentId: string): Promise { + return invoke('identity_get', { agentId }); + }, + + async getFile(agentId: string, file: string): Promise { + return invoke('identity_get_file', { agentId, file }); + }, + + async buildPrompt( + agentId: string, + memoryContext?: string + ): Promise { + return invoke('identity_build_prompt', { agentId, memoryContext }); + }, + + async updateUserProfile(agentId: string, content: string): Promise { + await invoke('identity_update_user_profile', { agentId, content }); + }, + + async appendUserProfile(agentId: string, addition: string): Promise { + await invoke('identity_append_user_profile', { agentId, addition }); + }, + + async proposeChange( + agentId: string, + file: 'soul' | 'instructions', + suggestedContent: string, + reason: string + ): Promise { + return invoke('identity_propose_change', { + agentId, + file, + suggestedContent, + reason, + }); + }, + + async approveProposal(proposalId: string): Promise { + return invoke('identity_approve_proposal', { proposalId }); + }, + + async rejectProposal(proposalId: string): Promise { + await invoke('identity_reject_proposal', { proposalId }); + }, + + async getPendingProposals( + agentId?: string + ): Promise { + return invoke('identity_get_pending_proposals', { agentId }); + }, + + async updateFile( + agentId: string, + file: string, + content: string + ): Promise { + await invoke('identity_update_file', { agentId, file, content }); + }, + + async getSnapshots( + agentId: string, + limit?: number + ): Promise { + return invoke('identity_get_snapshots', { agentId, limit }); + }, + + async restoreSnapshot( + agentId: string, + snapshotId: string + ): Promise { + await invoke('identity_restore_snapshot', { agentId, snapshotId }); + }, + + async listAgents(): Promise { + return invoke('identity_list_agents'); + }, + + async deleteAgent(agentId: string): Promise { + await invoke('identity_delete_agent', { agentId }); + }, +}; + +// === Unified Export === + +export const intelligence = { + memory, + heartbeat, + compactor, + reflection, + identity, +}; + +export default intelligence;