Phase 4: KI-UI-Steuerung — AI agent UI control via WebSocket

- New ai_ui_control plugin: WS endpoint /ws/ai-ui-control, REST API (POST /command, GET /command/{id}/status, GET /online-users)
- UI-Command-Protocol: 6 command types (navigate, filter, open_contact, modal, tab, settings) with Pydantic schemas
- WebSocket manager: per-user connections, command delivery, feedback storage, stale cleanup
- Frontend useAIUIControl hook: WS client with auto-reconnect, command dispatch, feedback sending
- aiUIControlStore: Zustand store for command state, active modal/tab, pending filter/settings
- AIUIControlIndicator: visual KI indication (Bot icon, toast, pulse animation)
- ContactDetail integration: syncs activeTab and personModalOpen from AI control store
- AppShell integration: useAIUIControl hook + AIUIControlIndicator
- i18n keys for DE/EN
- 18 Vitest tests: command protocol, store actions, feedback, visual indication
- TSC: 0 new errors (only 2 pre-existing Dms.tsx errors)
This commit is contained in:
Agent Zero
2026-07-23 20:13:39 +02:00
parent 5dc6f29ac1
commit 903d649a0f
15 changed files with 1582 additions and 5 deletions
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
@@ -11,6 +11,7 @@ import { Loader2 } from 'lucide-react';
import * as LucideIcons from 'lucide-react';
import { HistoryViewer } from '@/components/HistoryViewer';
import { usePluginStore } from '@/store/pluginStore';
import { useAIUIControlStore } from '@/store/aiUIControlStore';
import { PluginPage } from '@/components/plugins/PluginLoader';
import { useAuthStore } from '@/store/authStore';
import {
@@ -155,6 +156,25 @@ export function ContactDetail({ contact, loading, onEdit, onDeleted }: ContactDe
const [editingPerson, setEditingPerson] = useState<ContactPerson | null>(null);
const [activeTab, setActiveTab] = useState('details');
const pluginTabs = usePluginStore(s => s.getDetailTabsForEntity('contact'));
const aiActiveTab = useAIUIControlStore(s => s.activeTab);
const aiActiveModal = useAIUIControlStore(s => s.activeModal);
// Sync tab from AI UI Control (Phase 4.8)
useEffect(() => {
if (aiActiveTab) {
setActiveTab(aiActiveTab);
}
}, [aiActiveTab]);
// Sync modal from AI UI Control (Phase 4.7)
useEffect(() => {
if (aiActiveModal === 'edit' || aiActiveModal === 'create') {
setEditingPerson(null);
setPersonModalOpen(true);
} else if (aiActiveModal === 'close') {
setPersonModalOpen(false);
}
}, [aiActiveModal]);
const user = useAuthStore(s => s.user);
if (loading) {