Files
leocrm/frontend/src/api/comm.ts
T
Agent Zero cc3ac9a43d feat: Unified Messaging System — kommunikation plugin, AI/Proactive/System participants, MessageSidebar, Rich Content Renderer
Phase 1: Backend plugin kommunikation (13 files, 10 tables, REST API, WebSocket, RBAC, DMS Bridge, Participant Registry, Mini-App Registry, Search Provider)
Phase 2: AI plugins as participants (ai_assistant + ai_proactive dock as participants, heartbeat job)
Phase 3: system_notif plugin (system events → chat messages, pinned System room)
Phase 4: Frontend MessageSidebar (replaces AISidebar, same design, comm API client, WebSocket hook, commStore)
Phase 5: Rich Content Block Renderer (11 components: Markdown, HTML, Image, Audio, Video, File, ActionCard, ContactCard, MiniApp, BlockRenderer)
BasePlugin: added services property + _container in on_activate
2026-07-22 01:22:15 +02:00

200 lines
5.6 KiB
TypeScript

/**
* Communication plugin API client.
*
* All requests use the shared `apiClient` (`baseURL: '/api/v1'`) and target the
* kommunikation plugin routes under `/comm/...`.
*/
import { apiDelete, apiGet, apiPatch, apiPost } from './client';
// ─── Types ───
export interface Participant {
id: string;
conversation_id: string;
participant_id: string | null;
participant_type: string;
display_name: string | null;
role: string;
}
export interface Conversation {
id: string;
title: string | null;
is_locked: boolean;
locked_by: string | null;
is_direct: boolean;
is_archived: boolean;
is_pinned: boolean;
created_by: string | null;
created_by_type: string;
last_msg_at: string | null;
last_msg_preview: string | null;
last_msg_sender_type: string | null;
participants: Participant[];
unread_count: number;
metadata: Record<string, any>;
}
export interface MessageBlock {
id: string;
block_type: string;
block_data: Record<string, any>;
sort_order: number;
}
export interface MessageAttachment {
id: string;
file_id: string | null;
file_source: string;
file_name: string;
file_type: string;
file_size: number | null;
thumbnail_path: string | null;
}
export interface Message {
id: string;
conversation_id: string;
sender_id: string | null;
sender_type: string;
content: string;
content_format: string;
metadata: Record<string, any>;
reply_to_id: string | null;
is_pinned: boolean;
created_at: string | null;
edited_at: string | null;
blocks: MessageBlock[];
attachments: MessageAttachment[];
reactions: any[];
}
export interface ConversationListResponse {
items: Conversation[];
total: number;
}
export interface MessageListResponse {
items: Message[];
total: number;
page: number;
page_size: number;
}
export interface BlockType {
type: string;
label: string;
schema: Record<string, any>;
}
export interface MiniApp {
id: string;
name: string;
description: string;
config_schema: Record<string, any>;
}
// ─── Conversations ───
export const listConversations = (archived?: boolean) =>
apiGet<ConversationListResponse>('/comm/conversations', {
params: archived !== undefined ? { archived } : {},
});
export const createConversation = (data: {
title?: string;
participant_ids?: string[];
is_direct?: boolean;
initial_message?: string;
}) => apiPost<Conversation>('/comm/conversations', data);
export const getConversation = (id: string) =>
apiGet<Conversation>(`/comm/conversations/${id}`);
export const updateConversation = (id: string, data: { title?: string; is_archived?: boolean }) =>
apiPatch<Conversation>(`/comm/conversations/${id}`, data);
export const leaveConversation = (id: string) =>
apiDelete<{ success: boolean }>(`/comm/conversations/${id}`);
export const pinConversation = (id: string) =>
apiPost<{ success: boolean }>(`/comm/conversations/${id}/pin`);
export const unpinConversation = (id: string) =>
apiDelete<{ success: boolean }>(`/comm/conversations/${id}/pin`);
export const muteConversation = (id: string) =>
apiPost<{ success: boolean }>(`/comm/conversations/${id}/mute`);
export const unmuteConversation = (id: string) =>
apiDelete<{ success: boolean }>(`/comm/conversations/${id}/mute`);
// ─── Participants ───
export const addParticipant = (
convId: string,
data: { participant_id: string; participant_type: string; role?: string },
) => apiPost<Participant>(`/comm/conversations/${convId}/participants`, data);
export const removeParticipant = (convId: string, pid: string) =>
apiDelete<{ success: boolean }>(`/comm/conversations/${convId}/participants/${pid}`);
export const changeParticipantRole = (convId: string, pid: string, role: string) =>
apiPatch<Participant>(`/comm/conversations/${convId}/participants/${pid}`, { role });
// ─── Messages ───
export const getMessages = (convId: string, page = 1, pageSize = 50, before?: string) =>
apiGet<MessageListResponse>(`/comm/conversations/${convId}/messages`, {
params: { page, page_size: pageSize, ...(before ? { before } : {}) },
});
export const sendMessage = (
convId: string,
data: {
content: string;
content_format?: string;
blocks?: Array<{ block_type: string; block_data: Record<string, any> }>;
reply_to_id?: string;
attachments?: Array<Record<string, any>>;
},
) => apiPost<Message>(`/comm/conversations/${convId}/messages`, data);
export const editMessage = (id: string, data: { content?: string }) =>
apiPatch<Message>(`/comm/messages/${id}`, data);
export const deleteMessage = (id: string) =>
apiDelete<{ success: boolean }>(`/comm/messages/${id}`);
// ─── Reactions ───
export const addReaction = (msgId: string, emoji: string) =>
apiPost<any>(`/comm/messages/${msgId}/reactions`, { emoji });
export const removeReaction = (msgId: string, emoji: string) =>
apiDelete<{ success: boolean }>(`/comm/messages/${msgId}/reactions/${encodeURIComponent(emoji)}`);
// ─── Read State ───
export const markRead = (convId: string, lastReadMsgId?: string) =>
apiPost<{ success: boolean }>(`/comm/conversations/${convId}/read`, {
last_read_msg_id: lastReadMsgId,
});
// ─── Mini-Apps ───
export const listMiniApps = () =>
apiGet<{ items: MiniApp[] }>('/comm/miniapps');
export const startMiniApp = (convId: string, appId: string, config?: Record<string, any>) =>
apiPost<Message>(`/comm/conversations/${convId}/miniapps`, {
app_id: appId,
config: config || {},
});
// ─── Block Types ───
export const getBlockTypes = () =>
apiGet<{ items: BlockType[] }>('/comm/block-types');