429 lines
13 KiB
TypeScript
429 lines
13 KiB
TypeScript
|
|
// API 客户端 - 与后端交互
|
||
|
|
|
||
|
|
import type {
|
||
|
|
Agent,
|
||
|
|
AgentState,
|
||
|
|
FileLock,
|
||
|
|
Heartbeat,
|
||
|
|
Meeting,
|
||
|
|
MeetingQueue,
|
||
|
|
Workflow,
|
||
|
|
AgentResourceStatus,
|
||
|
|
} from '../types';
|
||
|
|
|
||
|
|
// API 基础地址
|
||
|
|
const API_BASE = 'http://localhost:8000/api';
|
||
|
|
|
||
|
|
// 通用请求函数
|
||
|
|
async function request<T>(
|
||
|
|
endpoint: string,
|
||
|
|
options?: RequestInit
|
||
|
|
): Promise<T> {
|
||
|
|
const url = `${API_BASE}${endpoint}`;
|
||
|
|
const response = await fetch(url, {
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
},
|
||
|
|
...options,
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
const error = await response.json().catch(() => ({
|
||
|
|
error: {
|
||
|
|
code: 'UNKNOWN_ERROR',
|
||
|
|
message: `HTTP ${response.status}: ${response.statusText}`,
|
||
|
|
},
|
||
|
|
}));
|
||
|
|
throw new Error(error.error?.message || '请求失败');
|
||
|
|
}
|
||
|
|
|
||
|
|
return response.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==================== Agent API ====================
|
||
|
|
|
||
|
|
export const agentApi = {
|
||
|
|
// 列出所有 Agent
|
||
|
|
list: () => request<{ agents: Agent[] }>('/agents'),
|
||
|
|
|
||
|
|
// 注册新 Agent
|
||
|
|
register: (agent: Omit<Agent, 'status' | 'created_at'>) =>
|
||
|
|
request<Agent>('/agents/register', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(agent),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取 Agent 详情
|
||
|
|
get: (agentId: string) => request<Agent>(`/agents/${agentId}`),
|
||
|
|
|
||
|
|
// 获取 Agent 状态
|
||
|
|
getState: (agentId: string) =>
|
||
|
|
request<AgentState>(`/agents/${agentId}/state`),
|
||
|
|
|
||
|
|
// 更新 Agent 状态
|
||
|
|
updateState: (
|
||
|
|
agentId: string,
|
||
|
|
state: { task: string; progress: number; working_files?: string[] }
|
||
|
|
) =>
|
||
|
|
request<{ success: boolean }>(`/agents/${agentId}/state`, {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(state),
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==================== 文件锁 API ====================
|
||
|
|
|
||
|
|
export const lockApi = {
|
||
|
|
// 获取所有锁
|
||
|
|
list: () => request<{ locks: FileLock[] }>('/locks'),
|
||
|
|
|
||
|
|
// 获取文件锁
|
||
|
|
acquire: (filePath: string, agentId: string, agentName: string) =>
|
||
|
|
request<{ success: boolean }>('/locks/acquire', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ file_path: filePath, agent_id: agentId, agent_name: agentName }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 释放文件锁
|
||
|
|
release: (filePath: string, agentId: string) =>
|
||
|
|
request<{ success: boolean }>('/locks/release', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ file_path: filePath, agent_id: agentId }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 检查文件锁定状态
|
||
|
|
check: (filePath: string) =>
|
||
|
|
request<{ file_path: string; locked: boolean; locked_by?: string }>(
|
||
|
|
`/locks/check?file_path=${encodeURIComponent(filePath)}`
|
||
|
|
),
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==================== 心跳 API ====================
|
||
|
|
|
||
|
|
export const heartbeatApi = {
|
||
|
|
// 获取所有心跳
|
||
|
|
list: () => request<{ heartbeats: Record<string, Heartbeat> }>('/heartbeats'),
|
||
|
|
|
||
|
|
// 更新心跳
|
||
|
|
update: (
|
||
|
|
agentId: string,
|
||
|
|
data: { status: Heartbeat['status']; current_task: string; progress: number }
|
||
|
|
) =>
|
||
|
|
request<{ success: boolean }>(`/heartbeats/${agentId}`, {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 检查超时 Agent
|
||
|
|
checkTimeouts: (timeoutSeconds: number = 60) =>
|
||
|
|
request<{ timeout_seconds: number; timeout_agents: string[] }>(
|
||
|
|
`/heartbeats/timeouts?timeout_seconds=${timeoutSeconds}`
|
||
|
|
),
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==================== 会议 API ====================
|
||
|
|
|
||
|
|
export const meetingApi = {
|
||
|
|
// 创建会议
|
||
|
|
create: (data: {
|
||
|
|
meeting_id: string;
|
||
|
|
title: string;
|
||
|
|
expected_attendees: string[];
|
||
|
|
min_required?: number;
|
||
|
|
}) =>
|
||
|
|
request<{ success: boolean }>('/meetings/create', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取会议队列
|
||
|
|
getQueue: (meetingId: string) =>
|
||
|
|
request<MeetingQueue>(`/meetings/${meetingId}/queue`),
|
||
|
|
|
||
|
|
// 等待会议开始
|
||
|
|
wait: (meetingId: string, agentId: string, timeout?: number) =>
|
||
|
|
request<{ result: 'started' | 'timeout' | 'error'; meeting_id: string; agent_id: string }>(
|
||
|
|
`/meetings/${meetingId}/wait`,
|
||
|
|
{
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ agent_id: agentId, timeout }),
|
||
|
|
}
|
||
|
|
),
|
||
|
|
|
||
|
|
// 结束会议
|
||
|
|
end: (meetingId: string) =>
|
||
|
|
request<{ success: boolean }>(`/meetings/${meetingId}/end`, {
|
||
|
|
method: 'POST',
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 创建会议记录
|
||
|
|
createRecord: (data: {
|
||
|
|
meeting_id: string;
|
||
|
|
title: string;
|
||
|
|
attendees: string[];
|
||
|
|
steps?: string[];
|
||
|
|
}) =>
|
||
|
|
request<Meeting>('/meetings/record/create', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 添加讨论
|
||
|
|
addDiscussion: (
|
||
|
|
meetingId: string,
|
||
|
|
data: { agent_id: string; agent_name: string; content: string; step?: string }
|
||
|
|
) =>
|
||
|
|
request<{ success: boolean }>(`/meetings/${meetingId}/discuss`, {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 更新进度
|
||
|
|
updateProgress: (meetingId: string, step: string) =>
|
||
|
|
request<{ success: boolean }>(`/meetings/${meetingId}/progress`, {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ step }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取会议详情
|
||
|
|
get: (meetingId: string, date?: string) => {
|
||
|
|
const query = date ? `?date=${date}` : '';
|
||
|
|
return request<Meeting>(`/meetings/${meetingId}${query}`);
|
||
|
|
},
|
||
|
|
|
||
|
|
// 完成会议
|
||
|
|
finish: (meetingId: string, consensus: string) =>
|
||
|
|
request<{ success: boolean }>(`/meetings/${meetingId}/finish`, {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ consensus }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 列出今日会议
|
||
|
|
listToday: () => {
|
||
|
|
const today = new Date().toISOString().split('T')[0];
|
||
|
|
return request<{ meetings: Meeting[] }>(`/meetings?date=${today}`);
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==================== 资源管理 API ====================
|
||
|
|
|
||
|
|
export const resourceApi = {
|
||
|
|
// 执行任务
|
||
|
|
execute: (agentId: string, task: string, timeout?: number) =>
|
||
|
|
request<{
|
||
|
|
success: boolean;
|
||
|
|
message: string;
|
||
|
|
files_locked: string[];
|
||
|
|
duration_seconds: number;
|
||
|
|
}>('/execute', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ agent_id: agentId, task, timeout }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取所有 Agent 状态
|
||
|
|
getAllStatus: () => request<{ agents: AgentResourceStatus[] }>('/status'),
|
||
|
|
|
||
|
|
// 解析任务文件
|
||
|
|
parseTask: (task: string) =>
|
||
|
|
request<{ task: string; files: string[] }>('/parse-task', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ task }),
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==================== 工作流 API ====================
|
||
|
|
|
||
|
|
export const workflowApi = {
|
||
|
|
// 列出工作流文件
|
||
|
|
listFiles: () =>
|
||
|
|
request<{ files: Array<{ name: string; path: string; size: number; modified: number }> }>('/workflows/files'),
|
||
|
|
|
||
|
|
// 列出已加载的工作流
|
||
|
|
list: () =>
|
||
|
|
request<{ workflows: Array<{ workflow_id: string; name: string; status: string; progress: string }> }>('/workflows/list'),
|
||
|
|
|
||
|
|
// 启动工作流
|
||
|
|
start: (path: string) =>
|
||
|
|
request<Workflow>(`/workflows/start/${path}`, {
|
||
|
|
method: 'POST',
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取工作流详情
|
||
|
|
get: (workflowId: string) =>
|
||
|
|
request<Workflow>(`/workflows/${workflowId}`),
|
||
|
|
|
||
|
|
// 获取工作流状态
|
||
|
|
getStatus: (workflowId: string) =>
|
||
|
|
request<Workflow>(`/workflows/${workflowId}/status`),
|
||
|
|
|
||
|
|
// 获取下一个节点
|
||
|
|
getNext: (workflowId: string) =>
|
||
|
|
request<{ meeting: { meeting_id: string; title: string; node_type: string; attendees: string[] } | null; message?: string }>(`/workflows/${workflowId}/next`),
|
||
|
|
|
||
|
|
// 标记节点完成
|
||
|
|
complete: (workflowId: string, meetingId: string) =>
|
||
|
|
request<{ success: boolean; message: string }>(`/workflows/${workflowId}/complete/${meetingId}`, {
|
||
|
|
method: 'POST',
|
||
|
|
}),
|
||
|
|
|
||
|
|
// Agent 加入执行节点
|
||
|
|
join: (workflowId: string, meetingId: string, agentId: string) =>
|
||
|
|
request<{ status: 'ready' | 'waiting' | 'error'; progress: string; message: string; missing?: string[] }>(`/workflows/${workflowId}/join/${meetingId}`, {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ agent_id: agentId }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取执行节点状态
|
||
|
|
getExecutionStatus: (workflowId: string, meetingId: string) =>
|
||
|
|
request<{ meeting_id: string; title: string; node_type: string; progress: string; is_ready: boolean; completed_attendees: string[]; missing: string[] }>(`/workflows/${workflowId}/execution/${meetingId}`),
|
||
|
|
|
||
|
|
// 强制跳转到指定节点
|
||
|
|
jump: (workflowId: string, targetMeetingId: string) =>
|
||
|
|
request<{ success: boolean; message: string; detail?: Workflow }>(`/workflows/${workflowId}/jump`, {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ target_meeting_id: targetMeetingId }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 处理节点失败
|
||
|
|
handleFailure: (workflowId: string, meetingId: string) =>
|
||
|
|
request<{ success: boolean; message: string; target?: string; detail?: Workflow }>(`/workflows/${workflowId}/fail/${meetingId}`, {
|
||
|
|
method: 'POST',
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==================== 角色分配 API ====================
|
||
|
|
|
||
|
|
export const roleApi = {
|
||
|
|
// 获取任务主要角色
|
||
|
|
getPrimary: (task: string) =>
|
||
|
|
request<{
|
||
|
|
task: string;
|
||
|
|
primary_role: string;
|
||
|
|
role_scores: Record<string, number>;
|
||
|
|
}>('/roles/primary', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ task }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 分配角色
|
||
|
|
allocate: (task: string, agents: string[]) =>
|
||
|
|
request<{
|
||
|
|
task: string;
|
||
|
|
primary_role: string;
|
||
|
|
allocation: Record<string, string>;
|
||
|
|
}>('/roles/allocate', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ task, agents }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 解释角色分配
|
||
|
|
explain: (task: string, agents: string[]) =>
|
||
|
|
request<{ explanation: string }>('/roles/explain', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ task, agents }),
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==================== 系统 API ====================
|
||
|
|
|
||
|
|
export const systemApi = {
|
||
|
|
// 健康检查
|
||
|
|
health: () =>
|
||
|
|
request<{
|
||
|
|
status: string;
|
||
|
|
version: string;
|
||
|
|
services: Record<string, string>;
|
||
|
|
}>('/health'),
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==================== 人类输入 API ====================
|
||
|
|
|
||
|
|
export const humanApi = {
|
||
|
|
// 获取摘要
|
||
|
|
summary: () =>
|
||
|
|
request<{ participants: number; online_users: number; pending_tasks: number; urgent_tasks: number; pending_comments: number; last_updated: string }>('/humans/summary'),
|
||
|
|
|
||
|
|
// 注册参与者
|
||
|
|
register: (userId: string, name: string, role?: string, avatar?: string) =>
|
||
|
|
request<{ success: boolean; user_id: string }>('/humans/register', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ user_id: userId, name, role, avatar }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取参与者列表
|
||
|
|
getParticipants: () =>
|
||
|
|
request<{ participants: Array<{ id: string; name: string; role: string; status: string; avatar: string }> }>('/humans/participants'),
|
||
|
|
|
||
|
|
// 添加任务请求
|
||
|
|
addTask: (content: string, options?: { from_user?: string; priority?: string; title?: string; target_files?: string[]; suggested_agent?: string; urgent?: boolean }) =>
|
||
|
|
request<{ success: boolean; task_id: string }>('/humans/tasks', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ content, ...options }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取待处理任务
|
||
|
|
getPendingTasks: (options?: { priority?: string; agent?: string }) => {
|
||
|
|
const params = new URLSearchParams();
|
||
|
|
if (options?.priority) params.append('priority', options.priority);
|
||
|
|
if (options?.agent) params.append('agent', options.agent);
|
||
|
|
return request<{ tasks: Array<{ id: string; from_user: string; timestamp: string; priority: string; title: string; content: string; suggested_agent: string; urgent: boolean; is_urgent: boolean }>; count: number }>(`/humans/tasks?${params}`);
|
||
|
|
},
|
||
|
|
|
||
|
|
// 获取紧急任务
|
||
|
|
getUrgentTasks: () =>
|
||
|
|
request<{ tasks: Array<{ id: string; from_user: string; content: string; title: string; suggested_agent: string }>; count: number }>('/humans/tasks/urgent'),
|
||
|
|
|
||
|
|
// 标记任务处理中
|
||
|
|
markTaskProcessing: (taskId: string) =>
|
||
|
|
request<{ success: boolean }>(`/humans/tasks/${taskId}/processing`, {
|
||
|
|
method: 'PUT',
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 标记任务完成
|
||
|
|
markTaskComplete: (taskId: string) =>
|
||
|
|
request<{ success: boolean }>(`/humans/tasks/${taskId}/complete`, {
|
||
|
|
method: 'PUT',
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 添加会议评论
|
||
|
|
addComment: (meetingId: string, content: string, options?: { from_user?: string; comment_type?: string; priority?: string }) =>
|
||
|
|
request<{ success: boolean; comment_id: string }>('/humans/comments', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ meeting_id: meetingId, content, ...options }),
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 获取待处理评论
|
||
|
|
getPendingComments: (meetingId?: string) => {
|
||
|
|
const params = meetingId ? `?meeting_id=${meetingId}` : '';
|
||
|
|
return request<{ comments: Array<{ id: string; from_user: string; meeting_id: string; timestamp: string; type: string; priority: string; content: string }>; count: string }>(`/humans/comments${params}`);
|
||
|
|
},
|
||
|
|
|
||
|
|
// 标记评论已处理
|
||
|
|
markCommentAddressed: (commentId: string) =>
|
||
|
|
request<{ success: boolean }>(`/humans/comments/${commentId}/addressed`, {
|
||
|
|
method: 'PUT',
|
||
|
|
}),
|
||
|
|
|
||
|
|
// 更新用户状态
|
||
|
|
updateUserStatus: (userId: string, status: string, currentFocus?: string) =>
|
||
|
|
request<{ success: boolean }>(`/humans/users/${userId}/status`, {
|
||
|
|
method: 'PUT',
|
||
|
|
body: JSON.stringify({ status, current_focus: currentFocus }),
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
// 导出所有 API
|
||
|
|
export const api = {
|
||
|
|
agent: agentApi,
|
||
|
|
lock: lockApi,
|
||
|
|
heartbeat: heartbeatApi,
|
||
|
|
meeting: meetingApi,
|
||
|
|
resource: resourceApi,
|
||
|
|
workflow: workflowApi,
|
||
|
|
role: roleApi,
|
||
|
|
system: systemApi,
|
||
|
|
human: humanApi,
|
||
|
|
};
|
||
|
|
|
||
|
|
export default api;
|