feat(intelligence): add TypeScript frontend adapter for Rust commands
Provides unified API for calling Tauri intelligence commands:
- memory: store, search, get, delete, stats, export/import
- heartbeat: init, start, stop, tick, config management
- compactor: token estimation, threshold check, compact
- reflection: should_reflect, reflect, history, state
- identity: get/update files, proposals, snapshots
Usage:
```typescript
import { intelligence } from './intelligence-backend';
await intelligence.memory.store({ ... });
await intelligence.heartbeat.start('agent-1');
```
Part of Phase 4: Integration and documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
445
desktop/src/lib/intelligence-backend.ts
Normal file
445
desktop/src/lib/intelligence-backend.ts
Normal file
@@ -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<string, number>;
|
||||
by_agent: Record<string, number>;
|
||||
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<void> {
|
||||
await invoke('memory_init');
|
||||
},
|
||||
|
||||
async store(entry: MemoryEntryInput): Promise<string> {
|
||||
return invoke('memory_store', { entry });
|
||||
},
|
||||
|
||||
async get(id: string): Promise<PersistentMemory | null> {
|
||||
return invoke('memory_get', { id });
|
||||
},
|
||||
|
||||
async search(options: MemorySearchOptions): Promise<PersistentMemory[]> {
|
||||
return invoke('memory_search', { options });
|
||||
},
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await invoke('memory_delete', { id });
|
||||
},
|
||||
|
||||
async deleteAll(agentId: string): Promise<number> {
|
||||
return invoke('memory_delete_all', { agentId });
|
||||
},
|
||||
|
||||
async stats(): Promise<MemoryStats> {
|
||||
return invoke('memory_stats');
|
||||
},
|
||||
|
||||
async export(): Promise<PersistentMemory[]> {
|
||||
return invoke('memory_export');
|
||||
},
|
||||
|
||||
async import(memories: PersistentMemory[]): Promise<number> {
|
||||
return invoke('memory_import', { memories });
|
||||
},
|
||||
|
||||
async dbPath(): Promise<string> {
|
||||
return invoke('memory_db_path');
|
||||
},
|
||||
};
|
||||
|
||||
// === Heartbeat API ===
|
||||
|
||||
export const heartbeat = {
|
||||
async init(agentId: string, config?: HeartbeatConfig): Promise<void> {
|
||||
await invoke('heartbeat_init', { agentId, config });
|
||||
},
|
||||
|
||||
async start(agentId: string): Promise<void> {
|
||||
await invoke('heartbeat_start', { agentId });
|
||||
},
|
||||
|
||||
async stop(agentId: string): Promise<void> {
|
||||
await invoke('heartbeat_stop', { agentId });
|
||||
},
|
||||
|
||||
async tick(agentId: string): Promise<HeartbeatResult> {
|
||||
return invoke('heartbeat_tick', { agentId });
|
||||
},
|
||||
|
||||
async getConfig(agentId: string): Promise<HeartbeatConfig> {
|
||||
return invoke('heartbeat_get_config', { agentId });
|
||||
},
|
||||
|
||||
async updateConfig(agentId: string, config: HeartbeatConfig): Promise<void> {
|
||||
await invoke('heartbeat_update_config', { agentId, config });
|
||||
},
|
||||
|
||||
async getHistory(agentId: string, limit?: number): Promise<HeartbeatResult[]> {
|
||||
return invoke('heartbeat_get_history', { agentId, limit });
|
||||
},
|
||||
};
|
||||
|
||||
// === Compactor API ===
|
||||
|
||||
export const compactor = {
|
||||
estimateTokens(text: string): Promise<number> {
|
||||
return invoke('compactor_estimate_tokens', { text });
|
||||
},
|
||||
|
||||
estimateMessagesTokens(messages: CompactableMessage[]): Promise<number> {
|
||||
return invoke('compactor_estimate_messages_tokens', { messages });
|
||||
},
|
||||
|
||||
checkThreshold(
|
||||
messages: CompactableMessage[],
|
||||
config?: CompactionConfig
|
||||
): Promise<CompactionCheck> {
|
||||
return invoke('compactor_check_threshold', { messages, config });
|
||||
},
|
||||
|
||||
compact(
|
||||
messages: CompactableMessage[],
|
||||
agentId: string,
|
||||
conversationId?: string,
|
||||
config?: CompactionConfig
|
||||
): Promise<CompactionResult> {
|
||||
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<void> {
|
||||
await invoke('reflection_init', { config });
|
||||
},
|
||||
|
||||
async recordConversation(): Promise<void> {
|
||||
await invoke('reflection_record_conversation');
|
||||
},
|
||||
|
||||
async shouldReflect(): Promise<boolean> {
|
||||
return invoke('reflection_should_reflect');
|
||||
},
|
||||
|
||||
async reflect(
|
||||
agentId: string,
|
||||
memories: MemoryEntryForAnalysis[]
|
||||
): Promise<ReflectionResult> {
|
||||
return invoke('reflection_reflect', { agentId, memories });
|
||||
},
|
||||
|
||||
async getHistory(limit?: number): Promise<ReflectionResult[]> {
|
||||
return invoke('reflection_get_history', { limit });
|
||||
},
|
||||
|
||||
async getState(): Promise<ReflectionState> {
|
||||
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<IdentityFiles> {
|
||||
return invoke('identity_get', { agentId });
|
||||
},
|
||||
|
||||
async getFile(agentId: string, file: string): Promise<string> {
|
||||
return invoke('identity_get_file', { agentId, file });
|
||||
},
|
||||
|
||||
async buildPrompt(
|
||||
agentId: string,
|
||||
memoryContext?: string
|
||||
): Promise<string> {
|
||||
return invoke('identity_build_prompt', { agentId, memoryContext });
|
||||
},
|
||||
|
||||
async updateUserProfile(agentId: string, content: string): Promise<void> {
|
||||
await invoke('identity_update_user_profile', { agentId, content });
|
||||
},
|
||||
|
||||
async appendUserProfile(agentId: string, addition: string): Promise<void> {
|
||||
await invoke('identity_append_user_profile', { agentId, addition });
|
||||
},
|
||||
|
||||
async proposeChange(
|
||||
agentId: string,
|
||||
file: 'soul' | 'instructions',
|
||||
suggestedContent: string,
|
||||
reason: string
|
||||
): Promise<IdentityChangeProposal> {
|
||||
return invoke('identity_propose_change', {
|
||||
agentId,
|
||||
file,
|
||||
suggestedContent,
|
||||
reason,
|
||||
});
|
||||
},
|
||||
|
||||
async approveProposal(proposalId: string): Promise<IdentityFiles> {
|
||||
return invoke('identity_approve_proposal', { proposalId });
|
||||
},
|
||||
|
||||
async rejectProposal(proposalId: string): Promise<void> {
|
||||
await invoke('identity_reject_proposal', { proposalId });
|
||||
},
|
||||
|
||||
async getPendingProposals(
|
||||
agentId?: string
|
||||
): Promise<IdentityChangeProposal[]> {
|
||||
return invoke('identity_get_pending_proposals', { agentId });
|
||||
},
|
||||
|
||||
async updateFile(
|
||||
agentId: string,
|
||||
file: string,
|
||||
content: string
|
||||
): Promise<void> {
|
||||
await invoke('identity_update_file', { agentId, file, content });
|
||||
},
|
||||
|
||||
async getSnapshots(
|
||||
agentId: string,
|
||||
limit?: number
|
||||
): Promise<IdentitySnapshot[]> {
|
||||
return invoke('identity_get_snapshots', { agentId, limit });
|
||||
},
|
||||
|
||||
async restoreSnapshot(
|
||||
agentId: string,
|
||||
snapshotId: string
|
||||
): Promise<void> {
|
||||
await invoke('identity_restore_snapshot', { agentId, snapshotId });
|
||||
},
|
||||
|
||||
async listAgents(): Promise<string[]> {
|
||||
return invoke('identity_list_agents');
|
||||
},
|
||||
|
||||
async deleteAgent(agentId: string): Promise<void> {
|
||||
await invoke('identity_delete_agent', { agentId });
|
||||
},
|
||||
};
|
||||
|
||||
// === Unified Export ===
|
||||
|
||||
export const intelligence = {
|
||||
memory,
|
||||
heartbeat,
|
||||
compactor,
|
||||
reflection,
|
||||
identity,
|
||||
};
|
||||
|
||||
export default intelligence;
|
||||
Reference in New Issue
Block a user