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 }),
|
||
}),
|
||
};
|