45 lines
1.8 KiB
TypeScript
45 lines
1.8 KiB
TypeScript
import { apiFetch, readSSE, type SSESummary } from "@/lib/api";
|
||||
|
|
|
|||
|
|
/**
|
|||
|
|
* 客户端两个 Agent 的会话适配层。
|
|||
|
|
*
|
|||
|
|
* 两者都是「打开建会话 → 带 session_id 对话 → 关闭结束会话」的三段式,
|
|||
|
|
* 后端的会话归属校验会拒绝未创建或不属于自己的 session_id(SessionOwnershipError),
|
|||
|
|
* 所以 session_id 必须来自 session/create,不能在前端自己造。
|
|||
|
|
*
|
|||
|
|
* - customer:匿名客服 Agent(/api/agent/customer/*),游客与登录用户都可用,无需 token
|
|||
|
|
* - client :登录客户 Agent(/api/agent/client/*),需 require_customer,
|
|||
|
|
* 能读到本人持仓 / 交易(匿名版没有 customer_id,数据查询会被引导去登录)
|
|||
|
|
*/
|
|||
|
|
export type ChatAgentMode = "customer" | "client";
|
|||
|
|
|
|||
|
|
const PREFIX: Record<ChatAgentMode, string> = {
|
|||
|
|
customer: "/agent/customer",
|
|||
|
|
client: "/agent/client",
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export interface AgentSession {
|
|||
|
|
session_id: string;
|
|||
|
|
customer_id: number | null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const chatAgentApi = {
|
|||
|
|
/** POST /session/create —— 建立会话,返回后端签发的 session_id。 */
|
|||
|
|
createSession: (mode: ChatAgentMode) =>
|
|||
|
|
apiFetch<AgentSession>(`${PREFIX[mode]}/session/create`, { method: "POST" }),
|
|||
|
|
|
|||
|
|
/** POST /chat —— 响应是 SSE 包装,但内容为 {answer, sources, intent...}。 */
|
|||
|
|
chat: (
|
|||
|
|
mode: ChatAgentMode,
|
|||
|
|
body: { session_id: string; query: string },
|
|||
|
|
signal?: AbortSignal
|
|||
|
|
): Promise<SSESummary> => readSSE(`${PREFIX[mode]}/chat`, body, signal),
|
|||
|
|
|
|||
|
|
/** POST /session/end —— 关闭会话并清理服务端上下文与限流键。 */
|
|||
|
|
endSession: (mode: ChatAgentMode, sessionId: string) =>
|
|||
|
|
apiFetch<{ session_id: string; archived?: boolean }>(`${PREFIX[mode]}/session/end`, {
|
|||
|
|
method: "POST",
|
|||
|
|
body: JSON.stringify({ session_id: sessionId }),
|
|||
|
|
}),
|
|||
|
|
};
|