import type { CSSProperties, JSX, ReactNode } from "react"; import { type XAdkSenderProps } from "./XAdkSender"; import { type SendContent } from "./XAiSender"; import { type FileItem } from "./FileGallery"; import { type ToolRenderKind } from "./FunctionCallRender"; import { type ChatPresetInput, type ChatStrategies } from "./ChatStrategies"; /** * XAdkChatbot 命令式 API */ export interface XAdkChatbotHandle { /** 手动滚动到底部 */ scrollToBottom: (behavior?: ScrollBehavior) => void; } /** * 消息分组接口 */ export interface ChatGroup { id: string; role: "user" | "bot"; msgs: IMessage[]; invocationId?: string; allFiles: any[]; /** 点赞状态: 1=赞, -1=踩, 0=未反馈 */ isLike?: number; } export interface IInvocation { id: string; name: string; spanId: string; traceId: string; parentSpanId: string; startTime: number; endTime: number; sessionId: string; invocationId: string; duration: number; attributes: Record; botName: string; workspaceNo: string; status: number; agentName: string; agentNo: string; agentVersionNo: string; userId: string; } export interface AgentRunRequest { stream?: boolean; sessionId: string | undefined; content: { parts: Array<{ text?: string; functionResponse?: { id?: string; name?: string; response?: any; }; }>; role: string; }; files?: Array<{ fileName: string; fileId?: string; tempUrl: string; type?: string; mimeType: string; }>; stateDelta?: any; } export interface Blob { displayName?: string; mimeType?: string; data: string; } export interface FunctionCall { id?: string; name: string; args: { [key: string]: any; }; } export interface FunctionResponse { id?: string; name: string; response: { [key: string]: any; }; } export interface FileData { displayName: string; mimeType: string; fileUri: string; } export interface ExecutableCode { language: "UNKNOWN" | "PYTHON"; code: string; } export interface CodeExecutionResult { outcome: "UNKNOWN" | "OK" | "FAILED" | "DEADLINE_EXCEEDED"; output: string; } export interface Part { text?: string; inlineData?: Blob; functionCall?: FunctionCall; functionResponse?: FunctionResponse; thought?: boolean; fileData?: FileData; executableCode?: ExecutableCode; codeExecutionResult?: CodeExecutionResult; errorMessage?: string; } export interface GenAiContent { role: string; parts: Part[]; } export interface LlmRequest { contents: GenAiContent[]; } export interface LlmResponse { partial?: boolean; content: GenAiContent; error?: string; errorMessage?: string; errorCode?: string; longRunningToolIds?: string[]; } export interface UsageMetadata { candidatesTokenCount?: number; promptTokenCount?: number; totalTokenCount?: number; [key: string]: any; } export interface EventActions { message?: string; artifactDelta?: any; functionCall?: FunctionCall; functionResponse?: FunctionResponse; finishReason?: string; } export interface Event extends LlmResponse { id?: string; author?: string; modelCode?: string; invocationId?: string; actions?: EventActions; longRunningToolIds?: string[]; branch?: string; timestamp?: number; finishReason?: string; usageMetadata?: UsageMetadata; evalStatus?: any; failedMetric?: any; evalScore?: any; evalThreshold?: any; groundingMetadata?: { searchEntryPoint?: { renderedContent?: any; }; }; isLike?: number; sessionId?: string; } export interface SessionState { [key: string]: unknown; } export interface Session { id?: string; appName?: string; userId?: string; state?: SessionState; events?: Event[]; lastUpdateTime?: number; } export interface TimeTick { position: number; label: string; } export interface IMessage { /** 前端生成的唯一标识 */ id: string; /** 单次请求的唯一标识 */ invocationId?: string; /** 单个Event的唯一标识,一个event里有可能有多个parts的消息 */ eventId?: string; /** 消息发起人:智能体名称、user */ author?: string; role: "bot" | "user"; /** 时间戳 */ timestamp?: number; isLoading?: boolean; /** 函数调用 */ functionCall?: FunctionCall; /** 函数调用结果 */ functionResponse?: FunctionResponse; /** 文件上传 */ inlineData?: Blob; /** 文本消息 */ text?: string; /** 文件信息 */ fileData?: FileData[]; /** 思考 */ thought?: boolean; executableCode?: ExecutableCode; codeExecutionResult?: CodeExecutionResult; renderedContent?: any; /** 原始数据 */ raw?: any; /** 模型编码,通常来自 stream 事件或历史消息 */ modelCode?: string; /** 事件级 token 使用量等模型调用元数据 */ usageMetadata?: UsageMetadata; /** 结束原因,通常来自最后一条 stream 事件 */ finishReason?: string; evalStatus?: any; failedMetric?: any; evalScore?: any; evalThreshold?: any; invocationIndex?: any; finalResponsePartIndex?: any; toolUseIndex?: any; /** 是否赞/踩 */ isLike?: number; } export type ActionProps = (data: { message: ChatGroup; isLastBotMsg: boolean; }) => JSX.Element | null; export type ActionExtraProps = (data: { message: ChatGroup; isLastBotMsg: boolean; }) => ReactNode; export interface MarkdownResourceLink { /** 完整链接,如 skill://InnerSkill01 */ href: string; /** Markdown 链接文字,如 @skill-creator */ label: string; /** 协议类型,如 skill/plugin/knowledge */ type: string; /** 协议值,如 InnerSkill01 */ value: string; } export type RenderMarkdownResourceLink = (link: MarkdownResourceLink) => ReactNode | null; /** * 自定义工具调用渲染函数 * - 返回 ReactNode:使用自定义渲染 * - 返回 null:降级使用默认渲染 * * @example * renderFunctionCall={(msg) => { * if (msg.functionCall?.name === 'my_tool') return ; * return null; // 其他工具使用默认渲染 * }} */ export type RenderFunctionCall = (msg: IMessage) => ReactNode | null; /** Markdown 自定义标签经过安全过滤后的结构化节点。 */ export interface MarkdownExtensionNode { tagName: string; attributes: Readonly>; text: string; children: ReactNode; } /** * Markdown 自定义标签扩展。 * 标签及属性只有显式注册后才会交给渲染函数,业务协议无需进入 SDK 核心。 */ export interface MarkdownExtension { tagName: string; allowedAttributes?: readonly string[]; render: (node: MarkdownExtensionNode) => ReactNode | null; } export interface XAdkChatbotProps extends Partial { /** * 自定义工具调用渲染函数 * 返回 null 则降级使用默认渲染 */ renderFunctionCall?: RenderFunctionCall; /** * 工具名 → 渲染类型的解析策略,默认使用 defaultToolKindResolver */ toolKindResolver?: (name: string | undefined) => ToolRenderKind; /** * 聊天策略,可由 Provider preset 自动下发,也可在组件局部覆盖。 */ strategies?: ChatStrategies; /** * 组件直用时的协议预设。默认沿用 xgroup-adk 以兼容既有业务接入; * 需要中立行为时可传入 base。 */ preset?: ChatPresetInput; className?: string; style?: CSSProperties; loading?: boolean; /** 消息列表 */ messages: IMessage[]; /** 开场白 */ prologue?: string; /** 建议回复 */ suggestions?: string[]; /** 欢迎页面 */ welcome?: ReactNode; /** 显示函数调用详情 */ showFnCallDetail?: boolean; /** * 数据是否就绪,就绪后触发首次自动滚底。默认 true。 * 仅在需要等待异步加载历史消息的场景(如 XAdkProvider 内)才需设为 false, * 待数据加载完成后再切换为 true;独立使用时无需关心此属性。 */ initialized?: boolean; /** * 当前会话 ID,切换时自动重置滚动状态并置底。 * 不传则退化为仅依赖 initialized 的单次置底行为。 */ sessionId?: string; /** 提交回调 */ onSubmit?: ({ text, files }: SendContent) => void; /** 函数调用确认回调 */ onConfirm?: (fnCall: FunctionCall, confirmed: boolean) => void; /** 停止回调 */ onStop?: () => void; /** 清除回调 */ onClear?: () => void; /** 建议回复回调 */ onSuggest?: (text: string) => void; /** Agent 名称 (欢迎页面) */ agentName?: string; /** Agent 图标 (欢迎页面) */ agentIcon?: string; /** Agent 描述 (欢迎页面) */ description?: string; /** 是否显示重试按钮 */ showRetry?: boolean; /** 是否显示复制按钮 */ showCopy?: boolean; /** 是否显示日志按钮 */ showLog?: boolean; /** 重试回调 */ onRetry?: () => void; /** 复制回调 */ onCopy?: (text: string) => void; /** 查看日志回调 */ onShowLog?: (invocationId: string, timestamp?: number) => void; /** 是否启用消息分组 (默认 true) */ enableGrouping?: boolean; /** 是否自动解析 process 内容并展示思维链 (默认 true) */ enableProcessParsing?: boolean; /** 消息功能区 */ actions?: ActionProps; /** 追加在消息功能区之后的内容,适合展示 token 消耗等业务扩展信息 */ actionsExtra?: ActionExtraProps; /** * Process 解析选项 * @example * // 业务项目格式 (注释模式) * parseOptions={{ mode: 'comment' }} * * @example * // 自定义格式 * parseOptions={{ * mode: 'custom', * customPatterns: [ * { regex: /\[REASONING\]([\s\S]*?)\[\/REASONING\]/g, type: 'reasoning' } * ] * }} */ parseOptions?: { mode?: "xml" | "comment" | "custom"; customPatterns?: Array<{ regex: RegExp; type: string; }>; finalMarker?: string; }; /** 是否禁用输入 */ disabled?: boolean; /** 是否流式响应 */ stream?: boolean; /** 点击对话中附件卡片的回调(非图片、非音视频文件) */ onFileClick?: (file: FileItem) => void; /** 点击 Markdown 资源链接标签的回调,如 [@skill](skill://xxx) */ onResourceLinkClick?: (link: MarkdownResourceLink) => void; /** 自定义 Markdown 资源链接渲染,返回 null 则降级使用默认标签样式 */ renderResourceLink?: RenderMarkdownResourceLink; /** Markdown/XML 自定义标签扩展 */ markdownExtensions?: readonly MarkdownExtension[]; /** 消息列表为空时展示的自定义空状态组件 */ empty?: ReactNode | (() => ReactNode); }