feat(domains): add Intelligence Domain with Valtio store and caching

- Create types.ts with frontend-friendly types
- Create cache.ts with LRU cache + TTL support
- Create store.ts wrapping intelligence-client with reactive state
- Create hooks.ts for React component integration
- Re-export backend types for compatibility

Intelligence Domain provides:
- Memory: store, search, delete with caching
- Heartbeat: init, start, stop, tick operations
- Compaction: threshold check and compact
- Reflection: conversation tracking and reflection
- Identity: load, build prompt, propose changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-21 20:01:47 +08:00
parent e2fb79917b
commit 32b9b41144
5 changed files with 1181 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
/**
* Intelligence Domain Cache
*
* LRU cache with TTL support for intelligence operations.
* Reduces redundant API calls and improves responsiveness.
*/
import type { CacheEntry, CacheStats } from './types';
/**
* Simple LRU cache with TTL support
*/
export class IntelligenceCache {
private cache = new Map<string, CacheEntry<unknown>>();
private accessOrder: string[] = [];
private maxSize: number;
private defaultTTL: number;
// Stats tracking
private hits = 0;
private misses = 0;
constructor(options?: { maxSize?: number; defaultTTL?: number }) {
this.maxSize = options?.maxSize ?? 100;
this.defaultTTL = options?.defaultTTL ?? 5 * 60 * 1000; // 5 minutes default
}
/**
* Get a value from cache
*/
get<T>(key: string): T | null {
const entry = this.cache.get(key) as CacheEntry<T> | undefined;
if (!entry) {
this.misses++;
return null;
}
// Check TTL
if (Date.now() > entry.timestamp + entry.ttl) {
this.cache.delete(key);
this.accessOrder = this.accessOrder.filter(k => k !== key);
this.misses++;
return null;
}
// Update access order (move to end = most recently used)
this.accessOrder = this.accessOrder.filter(k => k !== key);
this.accessOrder.push(key);
this.hits++;
return entry.data;
}
/**
* Set a value in cache
*/
set<T>(key: string, data: T, ttl?: number): void {
// Remove if exists (to update access order)
if (this.cache.has(key)) {
this.accessOrder = this.accessOrder.filter(k => k !== key);
}
// Evict oldest if at capacity
while (this.cache.size >= this.maxSize && this.accessOrder.length > 0) {
const oldestKey = this.accessOrder.shift();
if (oldestKey) {
this.cache.delete(oldestKey);
}
}
this.cache.set(key, {
data,
timestamp: Date.now(),
ttl: ttl ?? this.defaultTTL,
});
this.accessOrder.push(key);
}
/**
* Check if key exists and is not expired
*/
has(key: string): boolean {
const entry = this.cache.get(key);
if (!entry) return false;
if (Date.now() > entry.timestamp + entry.ttl) {
this.cache.delete(key);
this.accessOrder = this.accessOrder.filter(k => k !== key);
return false;
}
return true;
}
/**
* Delete a specific key
*/
delete(key: string): boolean {
if (this.cache.has(key)) {
this.cache.delete(key);
this.accessOrder = this.accessOrder.filter(k => k !== key);
return true;
}
return false;
}
/**
* Clear all cache entries
*/
clear(): void {
this.cache.clear();
this.accessOrder = [];
// Don't reset hits/misses to maintain historical stats
}
/**
* Get cache statistics
*/
getStats(): CacheStats {
const total = this.hits + this.misses;
return {
entries: this.cache.size,
hits: this.hits,
misses: this.misses,
hitRate: total > 0 ? this.hits / total : 0,
};
}
/**
* Reset statistics
*/
resetStats(): void {
this.hits = 0;
this.misses = 0;
}
/**
* Get all keys (for debugging)
*/
keys(): string[] {
return Array.from(this.cache.keys());
}
/**
* Get cache size
*/
get size(): number {
return this.cache.size;
}
}
// === Cache Key Generators ===
/**
* Generate cache key for memory search
*/
export function memorySearchKey(options: Record<string, unknown>): string {
const sorted = Object.entries(options)
.filter(([, v]) => v !== undefined)
.sort(([a], [b]) => a.localeCompare(b))
.map(([k, v]) => `${k}=${JSON.stringify(v)}`)
.join('&');
return `memory:search:${sorted}`;
}
/**
* Generate cache key for identity
*/
export function identityKey(agentId: string): string {
return `identity:${agentId}`;
}
/**
* Generate cache key for heartbeat config
*/
export function heartbeatConfigKey(agentId: string): string {
return `heartbeat:config:${agentId}`;
}
/**
* Generate cache key for reflection state
*/
export function reflectionStateKey(): string {
return 'reflection:state';
}
// === Singleton Instance ===
let cacheInstance: IntelligenceCache | null = null;
/**
* Get the global cache instance
*/
export function getIntelligenceCache(): IntelligenceCache {
if (!cacheInstance) {
cacheInstance = new IntelligenceCache({
maxSize: 200,
defaultTTL: 5 * 60 * 1000, // 5 minutes
});
}
return cacheInstance;
}
/**
* Clear the global cache instance
*/
export function clearIntelligenceCache(): void {
if (cacheInstance) {
cacheInstance.clear();
}
}

View File

@@ -0,0 +1,253 @@
/**
* Intelligence Domain Hooks
*
* React hooks for accessing intelligence state with Valtio.
* Provides reactive access to memory, heartbeat, reflection, and identity.
*/
import { useSnapshot } from 'valtio';
import { intelligenceStore } from './store';
import type { MemoryEntry, CacheStats } from './types';
// === Memory Hooks ===
/**
* Hook to access memories list
*/
export function useMemories() {
const { memories } = useSnapshot(intelligenceStore);
return memories as readonly MemoryEntry[];
}
/**
* Hook to access memory stats
*/
export function useMemoryStats() {
const { memoryStats } = useSnapshot(intelligenceStore);
return memoryStats;
}
/**
* Hook to check if memories are loading
*/
export function useMemoryLoading(): boolean {
const { isMemoryLoading } = useSnapshot(intelligenceStore);
return isMemoryLoading;
}
// === Heartbeat Hooks ===
/**
* Hook to access heartbeat config
*/
export function useHeartbeatConfig() {
const { heartbeatConfig } = useSnapshot(intelligenceStore);
return heartbeatConfig;
}
/**
* Hook to access heartbeat history
*/
export function useHeartbeatHistory() {
const { heartbeatHistory } = useSnapshot(intelligenceStore);
return heartbeatHistory;
}
/**
* Hook to check if heartbeat is running
*/
export function useHeartbeatRunning(): boolean {
const { isHeartbeatRunning } = useSnapshot(intelligenceStore);
return isHeartbeatRunning;
}
// === Compaction Hooks ===
/**
* Hook to access last compaction result
*/
export function useLastCompaction() {
const { lastCompaction } = useSnapshot(intelligenceStore);
return lastCompaction;
}
/**
* Hook to access compaction check
*/
export function useCompactionCheck() {
const { compactionCheck } = useSnapshot(intelligenceStore);
return compactionCheck;
}
// === Reflection Hooks ===
/**
* Hook to access reflection state
*/
export function useReflectionState() {
const { reflectionState } = useSnapshot(intelligenceStore);
return reflectionState;
}
/**
* Hook to access last reflection result
*/
export function useLastReflection() {
const { lastReflection } = useSnapshot(intelligenceStore);
return lastReflection;
}
// === Identity Hooks ===
/**
* Hook to access current identity
*/
export function useIdentity() {
const { currentIdentity } = useSnapshot(intelligenceStore);
return currentIdentity;
}
/**
* Hook to access pending identity proposals
*/
export function usePendingProposals() {
const { pendingProposals } = useSnapshot(intelligenceStore);
return pendingProposals;
}
// === Cache Hooks ===
/**
* Hook to access cache stats
*/
export function useCacheStats(): CacheStats {
const { cacheStats } = useSnapshot(intelligenceStore);
return cacheStats;
}
// === General Hooks ===
/**
* Hook to check if any intelligence operation is loading
*/
export function useIntelligenceLoading(): boolean {
const { isLoading, isMemoryLoading } = useSnapshot(intelligenceStore);
return isLoading || isMemoryLoading;
}
/**
* Hook to access intelligence error
*/
export function useIntelligenceError(): string | null {
const { error } = useSnapshot(intelligenceStore);
return error;
}
/**
* Hook to access the full intelligence state snapshot
*/
export function useIntelligenceState() {
return useSnapshot(intelligenceStore);
}
/**
* Hook to access intelligence actions
* Returns the store directly for calling actions.
* Does not cause re-renders.
*/
export function useIntelligenceActions() {
return intelligenceStore;
}
// === Convenience Hooks ===
/**
* Hook for memory operations with loading state
*/
export function useMemoryOperations() {
const memories = useMemories();
const isLoading = useMemoryLoading();
const stats = useMemoryStats();
const actions = useIntelligenceActions();
return {
memories,
isLoading,
stats,
loadMemories: actions.loadMemories,
storeMemory: actions.storeMemory,
deleteMemory: actions.deleteMemory,
loadStats: actions.loadMemoryStats,
};
}
/**
* Hook for heartbeat operations
*/
export function useHeartbeatOperations() {
const config = useHeartbeatConfig();
const isRunning = useHeartbeatRunning();
const history = useHeartbeatHistory();
const actions = useIntelligenceActions();
return {
config,
isRunning,
history,
init: actions.initHeartbeat,
start: actions.startHeartbeat,
stop: actions.stopHeartbeat,
tick: actions.tickHeartbeat,
};
}
/**
* Hook for compaction operations
*/
export function useCompactionOperations() {
const lastCompaction = useLastCompaction();
const check = useCompactionCheck();
const actions = useIntelligenceActions();
return {
lastCompaction,
check,
checkThreshold: actions.checkCompaction,
compact: actions.compact,
};
}
/**
* Hook for reflection operations
*/
export function useReflectionOperations() {
const state = useReflectionState();
const lastReflection = useLastReflection();
const actions = useIntelligenceActions();
return {
state,
lastReflection,
recordConversation: actions.recordConversation,
shouldReflect: actions.shouldReflect,
reflect: actions.reflect,
};
}
/**
* Hook for identity operations
*/
export function useIdentityOperations() {
const identity = useIdentity();
const pendingProposals = usePendingProposals();
const actions = useIntelligenceActions();
return {
identity,
pendingProposals,
loadIdentity: actions.loadIdentity,
buildPrompt: actions.buildPrompt,
proposeChange: actions.proposeIdentityChange,
approveProposal: actions.approveProposal,
rejectProposal: actions.rejectProposal,
};
}

View File

@@ -0,0 +1,118 @@
/**
* Intelligence Domain
*
* Unified intelligence layer for memory, heartbeat, compaction,
* reflection, and identity management.
*
* @example
* // Using hooks
* import { useMemoryOperations, useIdentityOperations } from '@/domains/intelligence';
*
* function IntelligenceComponent() {
* const { memories, loadMemories, storeMemory } = useMemoryOperations();
* const { identity, loadIdentity } = useIdentityOperations();
*
* useEffect(() => {
* loadMemories({ agentId: 'agent-1', limit: 10 });
* loadIdentity('agent-1');
* }, []);
*
* // ...
* }
*
* @example
* // Using store directly (outside React)
* import { intelligenceStore } from '@/domains/intelligence';
*
* async function storeMemory(content: string) {
* await intelligenceStore.storeMemory({
* agentId: 'agent-1',
* type: 'fact',
* content,
* importance: 5,
* source: 'user',
* tags: [],
* });
* }
*/
// Types - Domain-specific
export type {
MemoryEntry,
MemoryType,
MemorySource,
MemorySearchOptions,
MemoryStats,
// Cache
CacheEntry,
CacheStats,
// Store
IntelligenceState,
IntelligenceStore,
} from './types';
// Types - Re-exported from backend
export type {
HeartbeatConfig,
HeartbeatAlert,
HeartbeatResult,
CompactableMessage,
CompactionConfig,
CompactionCheck,
CompactionResult,
PatternObservation,
ImprovementSuggestion,
ReflectionResult,
ReflectionState,
ReflectionConfig,
MemoryEntryForAnalysis,
IdentityFiles,
IdentityChangeProposal,
IdentitySnapshot,
} from '../../lib/intelligence-backend';
// Store
export { intelligenceStore } from './store';
// Cache utilities
export {
IntelligenceCache,
getIntelligenceCache,
clearIntelligenceCache,
memorySearchKey,
identityKey,
heartbeatConfigKey,
reflectionStateKey,
} from './cache';
// Hooks - State accessors
export {
useMemories,
useMemoryStats,
useMemoryLoading,
useHeartbeatConfig,
useHeartbeatHistory,
useHeartbeatRunning,
useLastCompaction,
useCompactionCheck,
useReflectionState,
useLastReflection,
useIdentity,
usePendingProposals,
useCacheStats,
useIntelligenceLoading,
useIntelligenceError,
useIntelligenceState,
useIntelligenceActions,
} from './hooks';
// Hooks - Operation bundles
export {
useMemoryOperations,
useHeartbeatOperations,
useCompactionOperations,
useReflectionOperations,
useIdentityOperations,
} from './hooks';

View File

@@ -0,0 +1,415 @@
/**
* Intelligence Domain Store
*
* Valtio-based state management for intelligence operations.
* Wraps intelligence-client with caching and reactive state.
*/
import { proxy } from 'valtio';
import { intelligenceClient } from '../../lib/intelligence-client';
import {
getIntelligenceCache,
memorySearchKey,
identityKey,
} from './cache';
import type {
IntelligenceStore,
IntelligenceState,
MemoryEntry,
MemoryType,
MemorySource,
MemorySearchOptions,
MemoryStats,
CacheStats,
} from './types';
// === Initial State ===
const initialState: IntelligenceState = {
// Memory
memories: [],
memoryStats: null,
isMemoryLoading: false,
// Heartbeat
heartbeatConfig: null,
heartbeatHistory: [],
isHeartbeatRunning: false,
// Compaction
lastCompaction: null,
compactionCheck: null,
// Reflection
reflectionState: null,
lastReflection: null,
// Identity
currentIdentity: null,
pendingProposals: [],
// Cache
cacheStats: {
entries: 0,
hits: 0,
misses: 0,
hitRate: 0,
},
// General
isLoading: false,
error: null,
};
// === Store Implementation ===
export const intelligenceStore = proxy<IntelligenceStore>({
...initialState,
// === Memory Actions ===
loadMemories: async (options: MemorySearchOptions): Promise<void> => {
const cache = getIntelligenceCache();
const key = memorySearchKey(options as Record<string, unknown>);
// Check cache first
const cached = cache.get<MemoryEntry[]>(key);
if (cached) {
intelligenceStore.memories = cached;
intelligenceStore.cacheStats = cache.getStats();
return;
}
intelligenceStore.isMemoryLoading = true;
intelligenceStore.error = null;
try {
const rawMemories = await intelligenceClient.memory.search({
agentId: options.agentId,
type: options.type,
tags: options.tags,
query: options.query,
limit: options.limit,
minImportance: options.minImportance,
});
// Convert to frontend format
const memories: MemoryEntry[] = rawMemories.map(m => ({
id: m.id,
agentId: m.agentId,
content: m.content,
type: m.type as MemoryType,
importance: m.importance,
source: m.source as MemorySource,
tags: m.tags,
createdAt: m.createdAt,
lastAccessedAt: m.lastAccessedAt,
accessCount: m.accessCount,
conversationId: m.conversationId,
}));
cache.set(key, memories);
intelligenceStore.memories = memories;
intelligenceStore.cacheStats = cache.getStats();
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to load memories';
} finally {
intelligenceStore.isMemoryLoading = false;
}
},
storeMemory: async (entry): Promise<string> => {
const cache = getIntelligenceCache();
try {
const id = await intelligenceClient.memory.store({
agent_id: entry.agentId,
memory_type: entry.type,
content: entry.content,
importance: entry.importance,
source: entry.source,
tags: entry.tags,
conversation_id: entry.conversationId,
});
// Invalidate relevant cache entries
cache.delete(memorySearchKey({ agentId: entry.agentId }));
return id;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to store memory';
throw err;
}
},
deleteMemory: async (id: string): Promise<void> => {
const cache = getIntelligenceCache();
try {
await intelligenceClient.memory.delete(id);
// Clear all memory search caches
cache.clear();
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to delete memory';
throw err;
}
},
loadMemoryStats: async (): Promise<void> => {
try {
const rawStats = await intelligenceClient.memory.stats();
const stats: MemoryStats = {
totalEntries: rawStats.totalEntries,
byType: rawStats.byType,
byAgent: rawStats.byAgent,
oldestEntry: rawStats.oldestEntry,
newestEntry: rawStats.newestEntry,
};
intelligenceStore.memoryStats = stats;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to load memory stats';
}
},
// === Heartbeat Actions ===
initHeartbeat: async (agentId: string, config?: import('../../lib/intelligence-backend').HeartbeatConfig): Promise<void> => {
try {
await intelligenceClient.heartbeat.init(agentId, config);
if (config) {
intelligenceStore.heartbeatConfig = config;
}
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to init heartbeat';
}
},
startHeartbeat: async (agentId: string): Promise<void> => {
try {
await intelligenceClient.heartbeat.start(agentId);
intelligenceStore.isHeartbeatRunning = true;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to start heartbeat';
}
},
stopHeartbeat: async (agentId: string): Promise<void> => {
try {
await intelligenceClient.heartbeat.stop(agentId);
intelligenceStore.isHeartbeatRunning = false;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to stop heartbeat';
}
},
tickHeartbeat: async (agentId: string): Promise<import('../../lib/intelligence-backend').HeartbeatResult> => {
try {
const result = await intelligenceClient.heartbeat.tick(agentId);
intelligenceStore.heartbeatHistory = [
result,
...intelligenceStore.heartbeatHistory.slice(0, 99),
];
return result;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Heartbeat tick failed';
throw err;
}
},
// === Compaction Actions ===
checkCompaction: async (messages: Array<{ id?: string; role: string; content: string; timestamp?: string }>): Promise<import('../../lib/intelligence-backend').CompactionCheck> => {
try {
const compactableMessages = messages.map(m => ({
id: m.id || `msg_${Date.now()}`,
role: m.role,
content: m.content,
timestamp: m.timestamp,
}));
const check = await intelligenceClient.compactor.checkThreshold(compactableMessages);
intelligenceStore.compactionCheck = check;
return check;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Compaction check failed';
throw err;
}
},
compact: async (
messages: Array<{ id?: string; role: string; content: string; timestamp?: string }>,
agentId: string,
conversationId?: string
): Promise<import('../../lib/intelligence-backend').CompactionResult> => {
try {
const compactableMessages = messages.map(m => ({
id: m.id || `msg_${Date.now()}`,
role: m.role,
content: m.content,
timestamp: m.timestamp,
}));
const result = await intelligenceClient.compactor.compact(
compactableMessages,
agentId,
conversationId
);
intelligenceStore.lastCompaction = result;
return result;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Compaction failed';
throw err;
}
},
// === Reflection Actions ===
recordConversation: async (): Promise<void> => {
try {
await intelligenceClient.reflection.recordConversation();
} catch (err) {
console.warn('[IntelligenceStore] Failed to record conversation:', err);
}
},
shouldReflect: async (): Promise<boolean> => {
try {
return intelligenceClient.reflection.shouldReflect();
} catch {
return false;
}
},
reflect: async (agentId: string): Promise<import('../../lib/intelligence-backend').ReflectionResult> => {
try {
// Get memories for reflection
const memories = await intelligenceClient.memory.search({
agentId,
limit: 50,
minImportance: 3,
});
const analysisMemories = memories.map(m => ({
id: m.id,
memory_type: m.type,
content: m.content,
importance: m.importance,
created_at: m.createdAt,
access_count: m.accessCount,
tags: m.tags,
}));
const result = await intelligenceClient.reflection.reflect(agentId, analysisMemories);
intelligenceStore.lastReflection = result;
// Invalidate caches
getIntelligenceCache().clear();
return result;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Reflection failed';
throw err;
}
},
// === Identity Actions ===
loadIdentity: async (agentId: string): Promise<void> => {
const cache = getIntelligenceCache();
const key = identityKey(agentId);
// Check cache
const cached = cache.get<import('../../lib/intelligence-backend').IdentityFiles>(key);
if (cached) {
intelligenceStore.currentIdentity = cached;
intelligenceStore.cacheStats = cache.getStats();
return;
}
try {
const identity = await intelligenceClient.identity.get(agentId);
cache.set(key, identity, 10 * 60 * 1000); // 10 minute TTL
intelligenceStore.currentIdentity = identity;
intelligenceStore.cacheStats = cache.getStats();
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to load identity';
}
},
buildPrompt: async (agentId: string, memoryContext?: string): Promise<string> => {
try {
return intelligenceClient.identity.buildPrompt(agentId, memoryContext);
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to build prompt';
throw err;
}
},
proposeIdentityChange: async (
agentId: string,
file: 'soul' | 'instructions',
content: string,
reason: string
): Promise<import('../../lib/intelligence-backend').IdentityChangeProposal> => {
try {
const proposal = await intelligenceClient.identity.proposeChange(
agentId,
file,
content,
reason
);
intelligenceStore.pendingProposals.push(proposal);
return proposal;
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to propose change';
throw err;
}
},
approveProposal: async (proposalId: string): Promise<void> => {
try {
const identity = await intelligenceClient.identity.approveProposal(proposalId);
intelligenceStore.pendingProposals = intelligenceStore.pendingProposals.filter(
p => p.id !== proposalId
);
intelligenceStore.currentIdentity = identity;
getIntelligenceCache().clear();
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to approve proposal';
throw err;
}
},
rejectProposal: async (proposalId: string): Promise<void> => {
try {
await intelligenceClient.identity.rejectProposal(proposalId);
intelligenceStore.pendingProposals = intelligenceStore.pendingProposals.filter(
p => p.id !== proposalId
);
} catch (err) {
intelligenceStore.error = err instanceof Error ? err.message : 'Failed to reject proposal';
throw err;
}
},
// === Cache Actions ===
clearCache: (): void => {
getIntelligenceCache().clear();
intelligenceStore.cacheStats = getIntelligenceCache().getStats();
},
getCacheStats: (): CacheStats => {
return getIntelligenceCache().getStats();
},
// === General Actions ===
clearError: (): void => {
intelligenceStore.error = null;
},
reset: (): void => {
Object.assign(intelligenceStore, initialState);
getIntelligenceCache().clear();
},
});
export type { IntelligenceStore };

View File

@@ -0,0 +1,183 @@
/**
* Intelligence Domain Types
*
* Re-exports types from intelligence-backend for consistency.
* Domain-specific extensions are added here.
*/
// === Re-export Backend Types ===
export type {
MemoryEntryInput,
PersistentMemory,
MemorySearchOptions as BackendMemorySearchOptions,
MemoryStats as BackendMemoryStats,
HeartbeatConfig,
HeartbeatAlert,
HeartbeatResult,
CompactableMessage,
CompactionResult,
CompactionCheck,
CompactionConfig,
PatternObservation,
ImprovementSuggestion,
ReflectionResult,
ReflectionState,
ReflectionConfig,
MemoryEntryForAnalysis,
IdentityFiles,
IdentityChangeProposal,
IdentitySnapshot,
} from '../../lib/intelligence-backend';
// === Frontend-Specific Types ===
export type MemoryType = 'fact' | 'preference' | 'lesson' | 'context' | 'task';
export type MemorySource = 'auto' | 'user' | 'reflection' | 'llm-reflection';
/**
* Frontend-friendly memory entry
*/
export interface MemoryEntry {
id: string;
agentId: string;
content: string;
type: MemoryType;
importance: number;
source: MemorySource;
tags: string[];
createdAt: string;
lastAccessedAt: string;
accessCount: number;
conversationId?: string;
}
/**
* Frontend memory search options
*/
export interface MemorySearchOptions {
agentId?: string;
type?: MemoryType;
types?: MemoryType[];
tags?: string[];
query?: string;
limit?: number;
minImportance?: number;
}
/**
* Frontend memory stats
*/
export interface MemoryStats {
totalEntries: number;
byType: Record<string, number>;
byAgent: Record<string, number>;
oldestEntry: string | null;
newestEntry: string | null;
}
// === Cache Types ===
export interface CacheEntry<T> {
data: T;
timestamp: number;
ttl: number;
}
export interface CacheStats {
entries: number;
hits: number;
misses: number;
hitRate: number;
}
// === Store Types ===
export interface IntelligenceState {
// Memory
memories: MemoryEntry[];
memoryStats: MemoryStats | null;
isMemoryLoading: boolean;
// Heartbeat
heartbeatConfig: HeartbeatConfig | null;
heartbeatHistory: HeartbeatResult[];
isHeartbeatRunning: boolean;
// Compaction
lastCompaction: CompactionResult | null;
compactionCheck: CompactionCheck | null;
// Reflection
reflectionState: ReflectionState | null;
lastReflection: ReflectionResult | null;
// Identity
currentIdentity: IdentityFiles | null;
pendingProposals: IdentityChangeProposal[];
// Cache
cacheStats: CacheStats;
// General
isLoading: boolean;
error: string | null;
}
// Import types that need to be used in store interface
import type {
HeartbeatConfig,
HeartbeatResult,
CompactionResult,
CompactionCheck,
ReflectionState,
ReflectionResult,
IdentityFiles,
IdentityChangeProposal,
} from '../../lib/intelligence-backend';
export interface IntelligenceStore extends IntelligenceState {
// Memory Actions
loadMemories: (options: MemorySearchOptions) => Promise<void>;
storeMemory: (entry: {
agentId: string;
type: MemoryType;
content: string;
importance: number;
source: MemorySource;
tags: string[];
conversationId?: string;
}) => Promise<string>;
deleteMemory: (id: string) => Promise<void>;
loadMemoryStats: () => Promise<void>;
// Heartbeat Actions
initHeartbeat: (agentId: string, config?: HeartbeatConfig) => Promise<void>;
startHeartbeat: (agentId: string) => Promise<void>;
stopHeartbeat: (agentId: string) => Promise<void>;
tickHeartbeat: (agentId: string) => Promise<HeartbeatResult>;
// Compaction Actions
checkCompaction: (messages: Array<{ id?: string; role: string; content: string; timestamp?: string }>) => Promise<CompactionCheck>;
compact: (messages: Array<{ id?: string; role: string; content: string; timestamp?: string }>, agentId: string, conversationId?: string) => Promise<CompactionResult>;
// Reflection Actions
recordConversation: () => Promise<void>;
shouldReflect: () => Promise<boolean>;
reflect: (agentId: string) => Promise<ReflectionResult>;
// Identity Actions
loadIdentity: (agentId: string) => Promise<void>;
buildPrompt: (agentId: string, memoryContext?: string) => Promise<string>;
proposeIdentityChange: (agentId: string, file: 'soul' | 'instructions', content: string, reason: string) => Promise<IdentityChangeProposal>;
approveProposal: (proposalId: string) => Promise<void>;
rejectProposal: (proposalId: string) => Promise<void>;
// Cache Actions
clearCache: () => void;
getCacheStats: () => CacheStats;
// General
clearError: () => void;
reset: () => void;
}