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