Files
vf_react/src/views/AgentChat/hooks/useAgentSessions.ts
2025-12-16 08:25:19 +08:00

207 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/views/AgentChat/hooks/useAgentSessions.ts
// 会话管理 Hook - 加载、切换、创建会话
import { useState, useEffect, useCallback } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import axios from 'axios';
import { MessageTypes, type Message } from '../constants/messageTypes';
import { getApiBase } from '@utils/apiConfig';
/**
* 会话数据结构
*/
export interface Session {
session_id: string;
title?: string;
created_at?: string;
timestamp?: string;
message_count?: number;
}
/**
* 用户信息(从 AuthContext 传入)
*/
export interface User {
id: string;
nickname?: string;
avatar?: string;
subscription_type?: string;
}
/**
* useAgentSessions Hook 参数
*/
export interface UseAgentSessionsParams {
/** 当前用户信息 */
user: User | null;
/** 消息列表 setter用于创建新会话时设置欢迎消息 */
setMessages: Dispatch<SetStateAction<Message[]>>;
}
/**
* useAgentSessions Hook 返回值
*/
export interface UseAgentSessionsReturn {
/** 会话列表 */
sessions: Session[];
/** 当前选中的会话 ID */
currentSessionId: string | null;
/** 设置当前会话 ID */
setCurrentSessionId: Dispatch<SetStateAction<string | null>>;
/** 是否正在加载会话列表 */
isLoadingSessions: boolean;
/** 加载会话列表 */
loadSessions: () => Promise<void>;
/** 切换到指定会话 */
switchSession: (sessionId: string) => void;
/** 创建新会话(显示欢迎消息) */
createNewSession: () => void;
/** 加载指定会话的历史消息 */
loadSessionHistory: (sessionId: string) => Promise<void>;
}
/**
* useAgentSessions Hook
*
* 管理会话列表、会话切换、新建会话逻辑
*
* @param params - UseAgentSessionsParams
* @returns UseAgentSessionsReturn
*
* @example
* ```tsx
* const {
* sessions,
* currentSessionId,
* isLoadingSessions,
* switchSession,
* createNewSession,
* } = useAgentSessions({ user, setMessages });
* ```
*/
export const useAgentSessions = ({
user,
setMessages,
}: UseAgentSessionsParams): UseAgentSessionsReturn => {
const [sessions, setSessions] = useState<Session[]>([]);
const [currentSessionId, setCurrentSessionId] = useState<string | null>(null);
const [isLoadingSessions, setIsLoadingSessions] = useState(false);
/**
* 加载用户的会话列表
*/
const loadSessions = useCallback(async () => {
if (!user?.id) return;
setIsLoadingSessions(true);
try {
const response = await axios.get(`${getApiBase()}/mcp/agent/sessions`, {
params: { user_id: String(user.id), limit: 50 },
});
if (response.data.success) {
setSessions(response.data.data);
}
} catch (error) {
console.error('加载会话列表失败:', error);
} finally {
setIsLoadingSessions(false);
}
}, [user?.id]);
/**
* 安全解析 JSON 字符串,如果已经是对象则直接返回
*/
const safeJsonParse = (value: unknown): unknown => {
if (!value) return null;
if (typeof value === 'object') return value;
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch {
console.warn('JSON 解析失败:', value?.toString().substring(0, 100));
return null;
}
}
return null;
};
/**
* 加载指定会话的历史消息
*/
const loadSessionHistory = useCallback(
async (sessionId: string) => {
if (!sessionId) return;
try {
const response = await axios.get(`${getApiBase()}/mcp/agent/history/${sessionId}`, {
params: { limit: 100 },
});
if (response.data.success) {
const history = response.data.data;
const formattedMessages: Message[] = history.map((msg: any, idx: number) => ({
id: `${sessionId}-${idx}`,
type: msg.message_type === 'user' ? MessageTypes.USER : MessageTypes.AGENT_RESPONSE,
content: msg.message || '',
plan: safeJsonParse(msg.plan),
stepResults: safeJsonParse(msg.steps),
timestamp: msg.timestamp,
}));
setMessages(formattedMessages);
}
} catch (error) {
console.error('加载会话历史失败:', error);
}
},
[setMessages]
);
/**
* 切换到指定会话
*/
const switchSession = useCallback(
(sessionId: string) => {
setCurrentSessionId(sessionId);
loadSessionHistory(sessionId);
},
[loadSessionHistory]
);
/**
* 创建新会话(清空消息,显示欢迎消息)
*/
const createNewSession = useCallback(() => {
setCurrentSessionId(null);
setMessages([
{
id: Date.now(),
type: MessageTypes.AGENT_RESPONSE,
content: `你好${user?.nickname || ''}!👋\n\n我是**价小前**,你的 AI 投研助手。\n\n**我能做什么?**\n• 📊 全面分析股票基本面和技术面\n• 🔥 追踪市场热点和涨停板块\n• 📈 研究行业趋势和投资机会\n• 📰 汇总最新财经新闻和研报\n\n直接输入你的问题开始探索`,
timestamp: new Date().toISOString(),
},
]);
}, [user?.nickname, setMessages]);
/**
* 组件挂载时加载会话列表并创建新会话
*/
useEffect(() => {
loadSessions();
createNewSession();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user]);
return {
sessions,
currentSessionId,
setCurrentSessionId,
isLoadingSessions,
loadSessions,
switchSession,
createNewSession,
loadSessionHistory,
};
};