feat(intelligence): complete migration to Rust backend
- Unify all intelligence modules to use intelligenceClient - Delete legacy TS implementations (agent-memory, reflection-engine, heartbeat-engine, context-compactor, agent-identity, memory-index) - Update all consumers to use snake_case backend types - Remove deprecated llm-integration.test.ts This eliminates code duplication between frontend and backend, resolves localStorage limitations, and enables persistent intelligence features. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,14 +29,13 @@ import {
|
||||
Settings,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
ReflectionEngine,
|
||||
intelligenceClient,
|
||||
type ReflectionResult,
|
||||
type IdentityChangeProposal,
|
||||
type ReflectionConfig,
|
||||
type PatternObservation,
|
||||
type ImprovementSuggestion,
|
||||
type ReflectionConfig,
|
||||
DEFAULT_REFLECTION_CONFIG,
|
||||
} from '../lib/reflection-engine';
|
||||
import { getAgentIdentityManager, type IdentityChangeProposal } from '../lib/agent-identity';
|
||||
} from '../lib/intelligence-client';
|
||||
|
||||
// === Types ===
|
||||
|
||||
@@ -231,8 +230,8 @@ function ProposalCard({
|
||||
当前内容
|
||||
</h5>
|
||||
<pre className="text-xs text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-800 p-2 rounded overflow-x-auto whitespace-pre-wrap">
|
||||
{proposal.currentContent.slice(0, 500)}
|
||||
{proposal.currentContent.length > 500 && '...'}
|
||||
{proposal.current_content.slice(0, 500)}
|
||||
{proposal.current_content.length > 500 && '...'}
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
@@ -240,8 +239,8 @@ function ProposalCard({
|
||||
建议内容
|
||||
</h5>
|
||||
<pre className="text-xs text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-800 p-2 rounded overflow-x-auto whitespace-pre-wrap">
|
||||
{proposal.suggestedContent.slice(0, 500)}
|
||||
{proposal.suggestedContent.length > 500 && '...'}
|
||||
{proposal.suggested_content.slice(0, 500)}
|
||||
{proposal.suggested_content.length > 500 && '...'}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
@@ -309,9 +308,9 @@ function ReflectionEntry({
|
||||
<span className="text-gray-500 dark:text-gray-400">
|
||||
{result.improvements.length} 建议
|
||||
</span>
|
||||
{result.identityProposals.length > 0 && (
|
||||
{result.identity_proposals.length > 0 && (
|
||||
<span className="text-yellow-600 dark:text-yellow-400">
|
||||
{result.identityProposals.length} 变更
|
||||
{result.identity_proposals.length} 变更
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -362,8 +361,8 @@ function ReflectionEntry({
|
||||
|
||||
{/* Meta */}
|
||||
<div className="flex items-center gap-4 text-xs text-gray-500 dark:text-gray-400 pt-2 border-t border-gray-200 dark:border-gray-700">
|
||||
<span>新增记忆: {result.newMemories}</span>
|
||||
<span>身份变更提议: {result.identityProposals.length}</span>
|
||||
<span>新增记忆: {result.new_memories}</span>
|
||||
<span>身份变更提议: {result.identity_proposals.length}</span>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
@@ -381,56 +380,63 @@ export function ReflectionLog({
|
||||
onProposalApprove,
|
||||
onProposalReject,
|
||||
}: ReflectionLogProps) {
|
||||
const [engine] = useState(() => new ReflectionEngine());
|
||||
const [history, setHistory] = useState<ReflectionResult[]>([]);
|
||||
const [pendingProposals, setPendingProposals] = useState<IdentityChangeProposal[]>([]);
|
||||
const [expandedId, setExpandedId] = useState<string | null>(null);
|
||||
const [isReflecting, setIsReflecting] = useState(false);
|
||||
const [config, setConfig] = useState<ReflectionConfig>(DEFAULT_REFLECTION_CONFIG);
|
||||
const [showConfig, setShowConfig] = useState(false);
|
||||
const [config, setConfig] = useState<ReflectionConfig>({
|
||||
trigger_after_conversations: 5,
|
||||
allow_soul_modification: true,
|
||||
require_approval: true,
|
||||
});
|
||||
|
||||
// Load history and pending proposals
|
||||
useEffect(() => {
|
||||
const loadedHistory = engine.getHistory();
|
||||
setHistory([...loadedHistory].reverse()); // Most recent first
|
||||
const loadData = async () => {
|
||||
try {
|
||||
const loadedHistory = await intelligenceClient.reflection.getHistory();
|
||||
setHistory([...loadedHistory].reverse()); // Most recent first
|
||||
|
||||
const identityManager = getAgentIdentityManager();
|
||||
const proposals = identityManager.getPendingProposals(agentId);
|
||||
setPendingProposals(proposals);
|
||||
}, [engine, agentId]);
|
||||
const proposals = await intelligenceClient.identity.getPendingProposals(agentId);
|
||||
setPendingProposals(proposals);
|
||||
} catch (error) {
|
||||
console.error('[ReflectionLog] Failed to load data:', error);
|
||||
}
|
||||
};
|
||||
loadData();
|
||||
}, [agentId]);
|
||||
|
||||
const handleReflect = useCallback(async () => {
|
||||
setIsReflecting(true);
|
||||
try {
|
||||
const result = await engine.reflect(agentId);
|
||||
const result = await intelligenceClient.reflection.reflect(agentId, []);
|
||||
setHistory((prev) => [result, ...prev]);
|
||||
|
||||
// Update pending proposals
|
||||
if (result.identityProposals.length > 0) {
|
||||
setPendingProposals((prev) => [...prev, ...result.identityProposals]);
|
||||
if (result.identity_proposals.length > 0) {
|
||||
setPendingProposals((prev) => [...prev, ...result.identity_proposals]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[ReflectionLog] Reflection failed:', error);
|
||||
} finally {
|
||||
setIsReflecting(false);
|
||||
}
|
||||
}, [engine, agentId]);
|
||||
}, [agentId]);
|
||||
|
||||
const handleApproveProposal = useCallback(
|
||||
(proposal: IdentityChangeProposal) => {
|
||||
const identityManager = getAgentIdentityManager();
|
||||
identityManager.approveProposal(proposal.id);
|
||||
setPendingProposals((prev) => prev.filter((p) => p.id !== proposal.id));
|
||||
async (proposal: IdentityChangeProposal) => {
|
||||
await intelligenceClient.identity.approveProposal(proposal.id);
|
||||
setPendingProposals((prev: IdentityChangeProposal[]) => prev.filter((p: IdentityChangeProposal) => p.id !== proposal.id));
|
||||
onProposalApprove?.(proposal);
|
||||
},
|
||||
[onProposalApprove]
|
||||
);
|
||||
|
||||
const handleRejectProposal = useCallback(
|
||||
(proposal: IdentityChangeProposal) => {
|
||||
const identityManager = getAgentIdentityManager();
|
||||
identityManager.rejectProposal(proposal.id);
|
||||
setPendingProposals((prev) => prev.filter((p) => p.id !== proposal.id));
|
||||
async (proposal: IdentityChangeProposal) => {
|
||||
await intelligenceClient.identity.rejectProposal(proposal.id);
|
||||
setPendingProposals((prev: IdentityChangeProposal[]) => prev.filter((p: IdentityChangeProposal) => p.id !== proposal.id));
|
||||
onProposalReject?.(proposal);
|
||||
},
|
||||
[onProposalReject]
|
||||
@@ -438,9 +444,9 @@ export function ReflectionLog({
|
||||
|
||||
const stats = useMemo(() => {
|
||||
const totalReflections = history.length;
|
||||
const totalPatterns = history.reduce((sum, r) => sum + r.patterns.length, 0);
|
||||
const totalImprovements = history.reduce((sum, r) => sum + r.improvements.length, 0);
|
||||
const totalIdentityChanges = history.reduce((sum, r) => sum + r.identityProposals.length, 0);
|
||||
const totalPatterns = history.reduce((sum: number, r: ReflectionResult) => sum + r.patterns.length, 0);
|
||||
const totalImprovements = history.reduce((sum: number, r: ReflectionResult) => sum + r.improvements.length, 0);
|
||||
const totalIdentityChanges = history.reduce((sum: number, r: ReflectionResult) => sum + r.identity_proposals.length, 0);
|
||||
return { totalReflections, totalPatterns, totalImprovements, totalIdentityChanges };
|
||||
}, [history]);
|
||||
|
||||
@@ -507,9 +513,9 @@ export function ReflectionLog({
|
||||
type="number"
|
||||
min="1"
|
||||
max="20"
|
||||
value={config.triggerAfterConversations}
|
||||
value={config.trigger_after_conversations || 5}
|
||||
onChange={(e) =>
|
||||
setConfig((prev) => ({ ...prev, triggerAfterConversations: parseInt(e.target.value) || 5 }))
|
||||
setConfig((prev) => ({ ...prev, trigger_after_conversations: parseInt(e.target.value) || 5 }))
|
||||
}
|
||||
className="w-16 px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
|
||||
/>
|
||||
@@ -517,13 +523,13 @@ export function ReflectionLog({
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">允许修改 SOUL.md</span>
|
||||
<button
|
||||
onClick={() => setConfig((prev) => ({ ...prev, allowSoulModification: !prev.allowSoulModification }))}
|
||||
onClick={() => setConfig((prev) => ({ ...prev, allow_soul_modification: !prev.allow_soul_modification }))}
|
||||
className={`relative w-9 h-5 rounded-full transition-colors ${
|
||||
config.allowSoulModification ? 'bg-purple-500' : 'bg-gray-300 dark:bg-gray-600'
|
||||
config.allow_soul_modification ? 'bg-purple-500' : 'bg-gray-300 dark:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
<motion.div
|
||||
animate={{ x: config.allowSoulModification ? 18 : 0 }}
|
||||
animate={{ x: config.allow_soul_modification ? 18 : 0 }}
|
||||
className="absolute top-0.5 left-0.5 w-4 h-4 bg-white rounded-full shadow"
|
||||
/>
|
||||
</button>
|
||||
@@ -531,13 +537,13 @@ export function ReflectionLog({
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">变更需审批</span>
|
||||
<button
|
||||
onClick={() => setConfig((prev) => ({ ...prev, requireApproval: !prev.requireApproval }))}
|
||||
onClick={() => setConfig((prev) => ({ ...prev, require_approval: !prev.require_approval }))}
|
||||
className={`relative w-9 h-5 rounded-full transition-colors ${
|
||||
config.requireApproval ? 'bg-purple-500' : 'bg-gray-300 dark:bg-gray-600'
|
||||
config.require_approval ? 'bg-purple-500' : 'bg-gray-300 dark:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
<motion.div
|
||||
animate={{ x: config.requireApproval ? 18 : 0 }}
|
||||
animate={{ x: config.require_approval ? 18 : 0 }}
|
||||
className="absolute top-0.5 left-0.5 w-4 h-4 bg-white rounded-full shadow"
|
||||
/>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user