@cloudbase/agent-adapter-yuanqi 0.0.21 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -472,7 +472,7 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
472
472
|
...this.yuanqiConfig.request?.body || {},
|
|
473
473
|
...forwardedProps || {},
|
|
474
474
|
assistantId: this.finalAppId,
|
|
475
|
-
userId: state?.__request_context__?.id || forwardedProps?.userId || (0, import_crypto.randomUUID)(),
|
|
475
|
+
userId: state?.__request_context__?.user?.id || forwardedProps?.userId || (0, import_crypto.randomUUID)(),
|
|
476
476
|
messages
|
|
477
477
|
};
|
|
478
478
|
return requestBody;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/utils.ts","../src/stream.ts","../src/constant.ts","../src/chat_history.ts"],"sourcesContent":["export * from \"./agent\";\n\nexport * from \"./types\";\n\nexport * from \"./stream\";\n\nexport * from \"./chat_history\";\n","import {\n RunAgentInput,\n Message,\n AbstractAgent,\n AgentConfig,\n BaseEvent,\n EventType,\n RunStartedEvent,\n RunFinishedEvent,\n RunErrorEvent,\n TextMessageContentEvent,\n ToolCall,\n} from \"@ag-ui/client\";\nimport tcb from \"@cloudbase/node-sdk\";\nimport managedTcb from \"@cloudbase/manager-node\";\nimport OpenAI from \"openai\";\nimport { randomUUID } from \"crypto\";\nimport { camelToSnakeKeys } from \"./utils\";\nimport { processYuanqiStream } from \"./stream\";\nimport { Observable, Subscriber } from \"rxjs\";\nimport {\n createChatHistory,\n queryForLLM,\n ChatHistoryEntity,\n} from \"./chat_history\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { YuanqiConfig, ChatMessage, YuanqiChatRequest } from \"./types\";\n\nexport class YuanqiAgentError extends Error {\n code?: string;\n constructor(message: string, code?: string) {\n super(message);\n this.name = \"YuanqiAgentError\";\n if (code) this.code = code;\n }\n}\n\nexport class YuanqiAgent extends AbstractAgent {\n protected yuanqiConfig: YuanqiConfig;\n private finalAppId: string;\n private finalCloudCredential: {\n secretId?: string;\n secretKey?: string;\n token?: string;\n } = {};\n private model: OpenAI;\n constructor(config: AgentConfig & { yuanqiConfig: YuanqiConfig }) {\n super(config);\n this.yuanqiConfig = config.yuanqiConfig;\n this.model = new OpenAI({\n apiKey: \"\",\n baseURL:\n this.yuanqiConfig.request?.baseUrl ||\n \"https://yuanqi.tencent.com/openapi/v1/agent\",\n });\n this.finalAppId =\n this.yuanqiConfig.appId ||\n this.yuanqiConfig.request?.body?.assistantId ||\n process.env.YUANQI_APP_ID ||\n \"\";\n this.finalCloudCredential = {\n secretId:\n this.yuanqiConfig.credential?.secretId ||\n process.env.TENCENTCLOUD_SECRETID,\n secretKey:\n this.yuanqiConfig.credential?.secretKey ||\n process.env.TENCENTCLOUD_SECRETKEY,\n token:\n this.yuanqiConfig.credential?.token ||\n process.env.TENCENTCLOUD_SESSIONTOKEN,\n };\n }\n\n generateRequestBody({\n messages,\n input,\n }: {\n messages: ChatMessage[];\n input: RunAgentInput;\n }): YuanqiChatRequest {\n const { state, forwardedProps } = input;\n const requestBody: YuanqiChatRequest = {\n stream: true,\n ...(this.yuanqiConfig.request?.body || {}),\n ...(forwardedProps || {}),\n\n assistantId: this.finalAppId,\n userId:\n state?.__request_context__?.id ||\n forwardedProps?.userId ||\n randomUUID(),\n messages,\n };\n return requestBody;\n }\n\n run(input: RunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n this._run(subscriber, input);\n });\n }\n\n private async _run(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput\n ): Promise<void> {\n try {\n const { messages, runId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = input.threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n } as RunStartedEvent);\n\n if (!this.finalAppId) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_ID\"\n );\n }\n if (!this.yuanqiConfig.appKey && !process.env.YUANQI_APP_KEY) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_KEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_KEY\"\n );\n }\n\n // Warn user if messages are being trimmed (only using latest user message)\n const trimmedCount = messages.length - 1;\n if (trimmedCount > 0) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Yuanqi handles message history itself, so that a total of ${trimmedCount} messages before the last user message will be trimmed.`,\n type: \"warn\",\n },\n });\n }\n\n // Get the latest user message for saving to history\n const latestUserMessage = messages.filter((m) => m.role === \"user\").pop();\n if (!latestUserMessage) {\n throw new YuanqiAgentError(\n \"No user message found, please send a message first.\",\n \"MESSAGE_FORMAT_ERROR\"\n );\n }\n\n const allMessages = await this.getChatHistory(\n subscriber,\n latestUserMessage\n );\n\n const body = this.generateRequestBody({\n messages: allMessages,\n input,\n });\n\n const stream = await openai.chat.completions.create(\n {\n stream: true,\n messages: [],\n model: \"\",\n },\n {\n body: camelToSnakeKeys(body),\n headers: {\n ...this.yuanqiConfig.request?.headers,\n Authorization: `Bearer ${\n this.yuanqiConfig.appKey || process.env.YUANQI_APP_KEY\n }`,\n },\n }\n );\n\n // Process stream and emit AGUI events, collect full response\n const userRecordId = `record-${randomUUID().slice(0, 8)}`;\n const assistantRecordId = `record-${randomUUID().slice(0, 8)}`;\n const context = { threadId, runId, messageId: userRecordId };\n\n let fullAssistantContent = \"\";\n\n for await (const event of processYuanqiStream(stream, context)) {\n subscriber.next(event);\n // Collect assistant content from TEXT_MESSAGE_CONTENT events\n if (\n event.type === EventType.TEXT_MESSAGE_CONTENT &&\n (event as TextMessageContentEvent).delta\n ) {\n fullAssistantContent += (event as TextMessageContentEvent).delta;\n }\n }\n\n const userContent =\n typeof latestUserMessage?.content === \"string\"\n ? latestUserMessage.content\n : latestUserMessage?.content\n ?.filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\") || \"\";\n\n await this.saveChatHistory(\n subscriber,\n input,\n userRecordId,\n assistantRecordId,\n userContent,\n fullAssistantContent\n );\n\n subscriber.next({\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\n } as RunFinishedEvent);\n } catch (e: unknown) {\n console.error(\"[ERROR] Uncaught error: \", JSON.stringify(e));\n let code = \"UNKNOWN_ERROR\";\n let message = JSON.stringify(e);\n if (e instanceof YuanqiAgentError) {\n code = e.code || \"AGENT_ERROR\";\n message = e.message;\n } else if (e instanceof Error) {\n code = e.name || \"ERROR\";\n message = e.message;\n }\n subscriber.next({\n type: EventType.RUN_ERROR,\n code,\n message: `Sorry, an error occurred while running the agent: Error code ${code}, ${message}`,\n } as RunErrorEvent);\n } finally {\n subscriber.complete();\n }\n }\n\n // Can be override by subclasses\n protected async getChatHistory(\n subscriber: Subscriber<BaseEvent>,\n latestUserMessage: Message\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history loading.`,\n type: \"warn\",\n },\n });\n return convertMessagesToOpenAI([latestUserMessage]);\n }\n\n // Fetch chat history from database using queryForLLM\n let historyMessages: ChatMessage[] = [];\n\n const historyCount = this.yuanqiConfig.historyCount ?? 10;\n const historyRecords = await queryForLLM({\n tcbClient,\n botId,\n pageSize: historyCount,\n });\n\n // Convert queryForLLM result to ChatMessage format\n historyMessages = historyRecords.map((record) => ({\n role: record.role as \"user\" | \"assistant\",\n content: [{ type: \"text\" as const, text: record.content }],\n }));\n\n // Combine history messages with current messages\n const allMessages = historyMessages.concat(\n convertMessagesToOpenAI([latestUserMessage])\n );\n return allMessages;\n }\n\n // Can be override by subclasses\n protected async saveChatHistory(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput,\n userRecordId: string,\n assistantRecordId: string,\n userContent: string,\n assistantContent: string\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history saving.`,\n type: \"warn\",\n },\n });\n return;\n }\n\n // Save message pair to history\n const userEntity = new ChatHistoryEntity();\n userEntity.recordId = userRecordId;\n userEntity.botId = botId;\n userEntity.role = \"user\";\n userEntity.content = userContent;\n userEntity.conversation = threadId;\n userEntity.reply = assistantRecordId;\n userEntity.triggerSrc = \"\";\n userEntity.traceId = randomUUID();\n\n await createChatHistory({ tcbClient, chatHistoryEntity: userEntity });\n\n const assistantEntity = new ChatHistoryEntity();\n assistantEntity.recordId = assistantRecordId;\n assistantEntity.botId = botId;\n assistantEntity.role = \"assistant\";\n assistantEntity.content = assistantContent;\n assistantEntity.conversation = threadId;\n assistantEntity.replyTo = userRecordId;\n assistantEntity.triggerSrc = \"\";\n assistantEntity.traceId = runId;\n assistantEntity.status = \"done\";\n\n await createChatHistory({\n tcbClient,\n chatHistoryEntity: assistantEntity,\n });\n }\n\n private getTcbClient() {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n\n const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\n });\n return tcbClient;\n }\n\n private async checkIsDatabaseReady() {\n try {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n if (!envId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, CLOUDBASE_ENV_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_CLOUDBASE_ENV_ID\"\n );\n }\n if (!this.finalCloudCredential.token) {\n if (!this.finalCloudCredential.secretId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_ID\"\n );\n }\n if (!this.finalCloudCredential.secretKey) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n const managedTcbClient = managedTcb.init({\n envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n token: this.finalCloudCredential.token,\n });\n\n const checkDBRes = await managedTcbClient.database.checkCollectionExists(\n CHAT_HISTORY_DATA_SOURCE\n );\n if (checkDBRes && checkDBRes.Exists) {\n return true;\n } else if (checkDBRes && !checkDBRes.Exists) {\n await managedTcbClient.database.createCollection(\n CHAT_HISTORY_DATA_SOURCE\n );\n return true;\n } else {\n throw new Error(\"Check database exists failed\");\n }\n } catch (dbError) {\n console.error(\n \"[ERROR] Failed to check/create chat history collection:\",\n JSON.stringify(dbError)\n );\n return false;\n }\n }\n}\n\nfunction getCloudbaseEnvId() {\n if (process.env.CBR_ENV_ID) {\n return process.env.CBR_ENV_ID;\n } else if (process.env.SCF_NAMESPACE) {\n return process.env.SCF_NAMESPACE;\n } else {\n return process.env.CLOUDBASE_ENV_ID || \"\";\n }\n}\n\n/**\n * Convert AGUI messages to OpenAI chat completion format\n */\nexport function convertMessagesToOpenAI(\n messages: Message[],\n systemPrompt?: string\n): ChatMessage[] {\n const openaiMessages: ChatMessage[] = [];\n\n // Add system prompt if provided\n if (systemPrompt) {\n openaiMessages.push({\n role: \"system\",\n content: systemPrompt,\n });\n }\n\n // Convert messages\n for (const msg of messages) {\n if (msg.role === \"user\") {\n openaiMessages.push({\n role: \"user\",\n content:\n typeof msg.content === \"string\"\n ? [{ type: \"text\", text: msg.content }]\n : msg.content.map((item) => {\n if (item.type === \"text\") {\n return { type: \"text\", text: item.text };\n } else {\n return {\n type: \"image_url\",\n image_url: { url: item.url || \"\" },\n };\n }\n }),\n });\n } else if (msg.role === \"assistant\") {\n openaiMessages.push({\n role: \"assistant\",\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n tool_calls: msg.toolCalls?.map((tc: ToolCall) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n })),\n });\n } else if (msg.role === \"tool\") {\n openaiMessages.push({\n role: \"tool\",\n tool_call_id: msg.toolCallId,\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n });\n }\n }\n\n return openaiMessages;\n}\n","/**\n * 将小驼峰字符串转换为下划线格式\n * 例如: \"userName\" -> \"user_name\"\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * 递归地将对象的所有小驼峰属性名转换为下划线格式\n */\nexport function camelToSnakeKeys<T>(obj: T): T {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => camelToSnakeKeys(item)) as T;\n }\n\n if (typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = camelToSnakeKeys(value);\n }\n return result as T;\n }\n\n return obj;\n}\n\nexport function genRandomStr(length: number): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let result = \"\";\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n","import OpenAI from \"openai\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface StreamContext {\n threadId: string;\n runId: string;\n messageId: string;\n}\n\nexport interface StreamState {\n hasStarted: boolean;\n fullContent: string;\n toolCallsMap: Map<string, { name: string; args: string }>;\n}\n\nexport type Delta =\n OpenAI.Chat.Completions.ChatCompletionChunk[\"choices\"][number][\"delta\"] & {\n reasoning_content?: string;\n };\n\nexport async function* processYuanqiStream(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n context: StreamContext\n) {\n const { threadId, runId, messageId } = context;\n const state: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n const reasoningState: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta as Delta;\n if (!delta) continue;\n\n if (delta.role === \"tool\") {\n const toolCallId = (delta as any).tool_call_id;\n if (toolCallId) {\n if (state.toolCallsMap.has(toolCallId)) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n state.toolCallsMap.delete(toolCallId);\n }\n yield {\n type: EventType.TOOL_CALL_RESULT,\n threadId,\n runId,\n toolCallId,\n content: delta.content || \"\",\n };\n }\n continue;\n }\n\n // Handle text content\n if (delta.content) {\n // End reasoning message if it was started\n if (reasoningState.hasStarted) {\n reasoningState.hasStarted = false;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (!state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n state.hasStarted = true;\n }\n\n state.fullContent += delta.content;\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.content,\n };\n }\n\n // Handle reasoning content\n if (delta.reasoning_content) {\n if (!reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_START,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n reasoningState.hasStarted = true;\n }\n\n reasoningState.fullContent += delta.reasoning_content;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.reasoning_content,\n };\n }\n\n // Handle tool calls\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n const toolCallId = toolCall.id || `tool_${toolCall.index}`;\n\n if (toolCall.function?.name) {\n // Tool call start\n yield {\n type: EventType.TOOL_CALL_START,\n threadId,\n runId,\n toolCallId,\n toolCallName: toolCall.function.name,\n };\n\n // If first chunk contains arguments, emit TOOL_CALL_ARGS event\n if (toolCall.function.arguments) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n\n state.toolCallsMap.set(toolCallId, {\n name: toolCall.function.name,\n args: toolCall.function.arguments || \"\",\n });\n } else if (toolCall.function?.arguments) {\n // Tool call arguments delta\n const existing = state.toolCallsMap.get(toolCallId);\n if (existing) {\n existing.args += toolCall.function.arguments;\n\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n }\n }\n }\n }\n\n // Emit TEXT_MESSAGE_END if we had text content\n if (state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n // Emit TOOL_CALL_END for all tool calls\n for (const [toolCallId] of state.toolCallsMap) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n }\n}\n","// 对话数据模型\nexport const CHAT_HISTORY_DATA_SOURCE = \"ai_bot_chat_history_5hobd2b\";\n","import tcb from \"@cloudbase/node-sdk\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { genRandomStr } from \"./utils\";\n\nfunction genRecordId(): string {\n return \"record-\" + genRandomStr(8);\n}\n\n// Create a new chat history record\nexport async function createChatHistory({\n tcbClient,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const recordId = chatHistoryEntity.recordId || genRecordId();\n const data = {\n record_id: recordId,\n bot_id: chatHistoryEntity.botId,\n role: chatHistoryEntity.role,\n content: chatHistoryEntity.content,\n sender: chatHistoryEntity.sender,\n conversation: chatHistoryEntity.conversation,\n type: chatHistoryEntity.type,\n image: chatHistoryEntity.image,\n trigger_src: chatHistoryEntity.triggerSrc,\n origin_msg: chatHistoryEntity.originMsg,\n reply_to: chatHistoryEntity.replyTo,\n reply: chatHistoryEntity.reply,\n trace_id: chatHistoryEntity.traceId,\n need_async_reply: chatHistoryEntity.needAsyncReply,\n async_reply: chatHistoryEntity.asyncReply,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n const db = tcbClient.database();\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n const result = await collection.add(data);\n\n // console.log(\n // `Create record: chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return recordId;\n } catch (error) {\n console.error(\"Failed to create chat history record, error:\", error);\n return undefined;\n }\n}\n\n// Update chat history by record ID\nexport async function updateChatHistoryByRecordId({\n tcbClient,\n recordId,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n recordId: string;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n const result = await collection\n .where({ record_id: _.eq(recordId) })\n .update({\n content: chatHistoryEntity.content,\n image: chatHistoryEntity.image,\n async_reply: chatHistoryEntity.asyncReply,\n recommend_questions: chatHistoryEntity.recommendQuestions,\n status: chatHistoryEntity.status,\n origin_msg: chatHistoryEntity.originMsg,\n updatedAt: Date.now(),\n });\n\n // console.log(\n // `Update record: recordId: ${recordId}, chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return chatHistoryEntity.recordId;\n } catch (error) {\n console.error(\"Failed to update chat history, error:\", error);\n return undefined;\n }\n}\n\n// Query chat history from database\nexport async function describeChatHistory({\n tcbClient,\n botId,\n sort,\n pageSize = 10,\n pageNumber = 1,\n conversation,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n sort: \"asc\" | \"desc\";\n pageSize?: number;\n pageNumber?: number;\n conversation?: string;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<[ChatHistoryEntity[], number]> {\n if (!sort || sort.length === 0) {\n sort = \"desc\";\n }\n\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n // Build where conditions\n const whereConditions: Record<string, unknown> = {\n bot_id: _.eq(botId),\n };\n\n // Add optional filters\n if (conversation) {\n whereConditions.conversation = _.eq(conversation);\n }\n\n if (startCreatedAt !== undefined) {\n whereConditions.createdAt = _.gt(startCreatedAt);\n }\n\n if (triggerSrc) {\n whereConditions.trigger_src = _.eq(triggerSrc);\n }\n\n // Calculate skip for pagination\n const skip = (pageNumber - 1) * pageSize;\n\n // Query records\n const result = await collection\n .where(whereConditions)\n .orderBy(\"createdAt\", sort)\n .skip(skip)\n .limit(pageSize)\n .get();\n\n // Get total count\n const countResult = await collection.where(whereConditions).count();\n const total = countResult.total || 0;\n\n const records = result?.data || [];\n\n const entityList: ChatHistoryEntity[] = records.map(\n (item: ChatHistoryData) => transDataToChatEntity(item)\n );\n\n return [entityList, total];\n } catch (error) {\n console.error(\"Failed to query chat history, error:\", error);\n return [[], 0];\n }\n}\n\n// Transform data to ChatHistoryEntity structure\nexport function transDataToChatEntity(\n item: ChatHistoryData\n): ChatHistoryEntity {\n if (!item) {\n return new ChatHistoryEntity();\n }\n const chatEntity: ChatHistoryEntity = new ChatHistoryEntity();\n chatEntity.botId = item.bot_id;\n chatEntity.recordId = item.record_id;\n chatEntity.role = item.role;\n chatEntity.status = item.status;\n chatEntity.content = item.content;\n chatEntity.sender = item.sender;\n chatEntity.conversation = item.conversation;\n chatEntity.type = item.type;\n chatEntity.triggerSrc = item.trigger_src;\n chatEntity.originMsg = item.origin_msg;\n chatEntity.replyTo = item.reply_to;\n chatEntity.reply = item.reply;\n chatEntity.traceId = item.trace_id;\n chatEntity.needAsyncReply = item.need_async_reply;\n chatEntity.asyncReply = item.async_reply;\n chatEntity.createdAt = item.createdAt;\n chatEntity.updatedAt = item.updatedAt;\n return chatEntity;\n}\n\n// Query history records for LLM, get the most recent 10 conversation pairs (20 records)\nexport async function queryForLLM({\n tcbClient,\n botId,\n pageSize = 10,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n pageSize?: number;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<{ role: string; content: string }[]> {\n if (startCreatedAt === undefined) {\n startCreatedAt = Date.now() - 24 * 60 * 60 * 1000;\n }\n const recordEntityList: ChatHistoryEntity[] = [];\n\n const [recordList] = await describeChatHistory({\n tcbClient,\n botId,\n sort: \"desc\",\n pageSize,\n startCreatedAt,\n triggerSrc,\n });\n recordEntityList.push(...recordList.reverse());\n\n const entityMap = new Map<string, ChatHistoryEntity>();\n recordEntityList\n .filter((item) => {\n if (item.needAsyncReply === true) {\n return !!item.asyncReply;\n } else {\n return !!item.content;\n }\n })\n .forEach((item) => {\n entityMap.set(item.recordId, item);\n });\n\n const result: { role: string; content: string }[] = [];\n /*\n 1. Strongly depends on database history data, model history data has role order requirements\n 2. Need to ensure that no matter what bug occurs, always get a complete and usable user + assistant pair, otherwise the request will fail\n */\n recordEntityList.forEach((item) => {\n const { role, content, reply } = item;\n // When calling LLM, empty content will cause failure, so filter out conversations with empty content\n if (role === \"user\" && content?.length !== 0) {\n if (entityMap.has(reply)) {\n result.push({ role, content });\n result.push({\n role: entityMap.get(reply)!.role,\n content: entityMap.get(reply)!.content,\n });\n }\n }\n });\n if (result.length % 2 === 1) {\n result.splice(-1, 1);\n }\n return result;\n}\n\nexport interface ChatHistoryData {\n bot_id: string;\n record_id: string;\n role: string;\n status: string;\n content: string;\n sender: string;\n conversation: string;\n type: string;\n trigger_src: string;\n origin_msg: string;\n reply_to: string;\n reply: string;\n trace_id: string;\n need_async_reply: boolean;\n async_reply: string;\n createdAt: number;\n updatedAt: number;\n}\n\nexport class ChatHistoryEntity {\n id: number;\n botId: string;\n // 对话唯一id\n recordId: string;\n role: string;\n content: string;\n recommendQuestions: string[];\n sender: string;\n conversation: string;\n type: string;\n /**\n * 消息状态,pending done error cancel\n */\n status: string;\n image: string;\n triggerSrc: string;\n originMsg: string;\n replyTo: string;\n reply: string;\n traceId: string;\n needAsyncReply: boolean;\n asyncReply: string;\n createTime: string;\n updateTime: string;\n createdAt: number;\n updatedAt: number;\n event: string;\n}\n"],"mappings":"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","names":["import_client","OpenAI","tcb","managedTcb"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/utils.ts","../src/stream.ts","../src/constant.ts","../src/chat_history.ts"],"sourcesContent":["export * from \"./agent\";\n\nexport * from \"./types\";\n\nexport * from \"./stream\";\n\nexport * from \"./chat_history\";\n","import {\n RunAgentInput,\n Message,\n AbstractAgent,\n AgentConfig,\n BaseEvent,\n EventType,\n RunStartedEvent,\n RunFinishedEvent,\n RunErrorEvent,\n TextMessageContentEvent,\n ToolCall,\n} from \"@ag-ui/client\";\nimport tcb from \"@cloudbase/node-sdk\";\nimport managedTcb from \"@cloudbase/manager-node\";\nimport OpenAI from \"openai\";\nimport { randomUUID } from \"crypto\";\nimport { camelToSnakeKeys } from \"./utils\";\nimport { processYuanqiStream } from \"./stream\";\nimport { Observable, Subscriber } from \"rxjs\";\nimport {\n createChatHistory,\n queryForLLM,\n ChatHistoryEntity,\n} from \"./chat_history\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { YuanqiConfig, ChatMessage, YuanqiChatRequest } from \"./types\";\n\nexport class YuanqiAgentError extends Error {\n code?: string;\n constructor(message: string, code?: string) {\n super(message);\n this.name = \"YuanqiAgentError\";\n if (code) this.code = code;\n }\n}\n\nexport class YuanqiAgent extends AbstractAgent {\n protected yuanqiConfig: YuanqiConfig;\n private finalAppId: string;\n private finalCloudCredential: {\n secretId?: string;\n secretKey?: string;\n token?: string;\n } = {};\n private model: OpenAI;\n constructor(config: AgentConfig & { yuanqiConfig: YuanqiConfig }) {\n super(config);\n this.yuanqiConfig = config.yuanqiConfig;\n this.model = new OpenAI({\n apiKey: \"\",\n baseURL:\n this.yuanqiConfig.request?.baseUrl ||\n \"https://yuanqi.tencent.com/openapi/v1/agent\",\n });\n this.finalAppId =\n this.yuanqiConfig.appId ||\n this.yuanqiConfig.request?.body?.assistantId ||\n process.env.YUANQI_APP_ID ||\n \"\";\n this.finalCloudCredential = {\n secretId:\n this.yuanqiConfig.credential?.secretId ||\n process.env.TENCENTCLOUD_SECRETID,\n secretKey:\n this.yuanqiConfig.credential?.secretKey ||\n process.env.TENCENTCLOUD_SECRETKEY,\n token:\n this.yuanqiConfig.credential?.token ||\n process.env.TENCENTCLOUD_SESSIONTOKEN,\n };\n }\n\n generateRequestBody({\n messages,\n input,\n }: {\n messages: ChatMessage[];\n input: RunAgentInput;\n }): YuanqiChatRequest {\n const { state, forwardedProps } = input;\n const requestBody: YuanqiChatRequest = {\n stream: true,\n ...(this.yuanqiConfig.request?.body || {}),\n ...(forwardedProps || {}),\n\n assistantId: this.finalAppId,\n userId:\n state?.__request_context__?.user?.id ||\n forwardedProps?.userId ||\n randomUUID(),\n messages,\n };\n return requestBody;\n }\n\n run(input: RunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n this._run(subscriber, input);\n });\n }\n\n private async _run(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput\n ): Promise<void> {\n try {\n const { messages, runId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = input.threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n } as RunStartedEvent);\n\n if (!this.finalAppId) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_ID\"\n );\n }\n if (!this.yuanqiConfig.appKey && !process.env.YUANQI_APP_KEY) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_KEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_KEY\"\n );\n }\n\n // Warn user if messages are being trimmed (only using latest user message)\n const trimmedCount = messages.length - 1;\n if (trimmedCount > 0) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Yuanqi handles message history itself, so that a total of ${trimmedCount} messages before the last user message will be trimmed.`,\n type: \"warn\",\n },\n });\n }\n\n // Get the latest user message for saving to history\n const latestUserMessage = messages.filter((m) => m.role === \"user\").pop();\n if (!latestUserMessage) {\n throw new YuanqiAgentError(\n \"No user message found, please send a message first.\",\n \"MESSAGE_FORMAT_ERROR\"\n );\n }\n\n const allMessages = await this.getChatHistory(\n subscriber,\n latestUserMessage\n );\n\n const body = this.generateRequestBody({\n messages: allMessages,\n input,\n });\n\n const stream = await openai.chat.completions.create(\n {\n stream: true,\n messages: [],\n model: \"\",\n },\n {\n body: camelToSnakeKeys(body),\n headers: {\n ...this.yuanqiConfig.request?.headers,\n Authorization: `Bearer ${\n this.yuanqiConfig.appKey || process.env.YUANQI_APP_KEY\n }`,\n },\n }\n );\n\n // Process stream and emit AGUI events, collect full response\n const userRecordId = `record-${randomUUID().slice(0, 8)}`;\n const assistantRecordId = `record-${randomUUID().slice(0, 8)}`;\n const context = { threadId, runId, messageId: userRecordId };\n\n let fullAssistantContent = \"\";\n\n for await (const event of processYuanqiStream(stream, context)) {\n subscriber.next(event);\n // Collect assistant content from TEXT_MESSAGE_CONTENT events\n if (\n event.type === EventType.TEXT_MESSAGE_CONTENT &&\n (event as TextMessageContentEvent).delta\n ) {\n fullAssistantContent += (event as TextMessageContentEvent).delta;\n }\n }\n\n const userContent =\n typeof latestUserMessage?.content === \"string\"\n ? latestUserMessage.content\n : latestUserMessage?.content\n ?.filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\") || \"\";\n\n await this.saveChatHistory(\n subscriber,\n input,\n userRecordId,\n assistantRecordId,\n userContent,\n fullAssistantContent\n );\n\n subscriber.next({\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\n } as RunFinishedEvent);\n } catch (e: unknown) {\n console.error(\"[ERROR] Uncaught error: \", JSON.stringify(e));\n let code = \"UNKNOWN_ERROR\";\n let message = JSON.stringify(e);\n if (e instanceof YuanqiAgentError) {\n code = e.code || \"AGENT_ERROR\";\n message = e.message;\n } else if (e instanceof Error) {\n code = e.name || \"ERROR\";\n message = e.message;\n }\n subscriber.next({\n type: EventType.RUN_ERROR,\n code,\n message: `Sorry, an error occurred while running the agent: Error code ${code}, ${message}`,\n } as RunErrorEvent);\n } finally {\n subscriber.complete();\n }\n }\n\n // Can be override by subclasses\n protected async getChatHistory(\n subscriber: Subscriber<BaseEvent>,\n latestUserMessage: Message\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history loading.`,\n type: \"warn\",\n },\n });\n return convertMessagesToOpenAI([latestUserMessage]);\n }\n\n // Fetch chat history from database using queryForLLM\n let historyMessages: ChatMessage[] = [];\n\n const historyCount = this.yuanqiConfig.historyCount ?? 10;\n const historyRecords = await queryForLLM({\n tcbClient,\n botId,\n pageSize: historyCount,\n });\n\n // Convert queryForLLM result to ChatMessage format\n historyMessages = historyRecords.map((record) => ({\n role: record.role as \"user\" | \"assistant\",\n content: [{ type: \"text\" as const, text: record.content }],\n }));\n\n // Combine history messages with current messages\n const allMessages = historyMessages.concat(\n convertMessagesToOpenAI([latestUserMessage])\n );\n return allMessages;\n }\n\n // Can be override by subclasses\n protected async saveChatHistory(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput,\n userRecordId: string,\n assistantRecordId: string,\n userContent: string,\n assistantContent: string\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history saving.`,\n type: \"warn\",\n },\n });\n return;\n }\n\n // Save message pair to history\n const userEntity = new ChatHistoryEntity();\n userEntity.recordId = userRecordId;\n userEntity.botId = botId;\n userEntity.role = \"user\";\n userEntity.content = userContent;\n userEntity.conversation = threadId;\n userEntity.reply = assistantRecordId;\n userEntity.triggerSrc = \"\";\n userEntity.traceId = randomUUID();\n\n await createChatHistory({ tcbClient, chatHistoryEntity: userEntity });\n\n const assistantEntity = new ChatHistoryEntity();\n assistantEntity.recordId = assistantRecordId;\n assistantEntity.botId = botId;\n assistantEntity.role = \"assistant\";\n assistantEntity.content = assistantContent;\n assistantEntity.conversation = threadId;\n assistantEntity.replyTo = userRecordId;\n assistantEntity.triggerSrc = \"\";\n assistantEntity.traceId = runId;\n assistantEntity.status = \"done\";\n\n await createChatHistory({\n tcbClient,\n chatHistoryEntity: assistantEntity,\n });\n }\n\n private getTcbClient() {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n\n const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\n });\n return tcbClient;\n }\n\n private async checkIsDatabaseReady() {\n try {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n if (!envId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, CLOUDBASE_ENV_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_CLOUDBASE_ENV_ID\"\n );\n }\n if (!this.finalCloudCredential.token) {\n if (!this.finalCloudCredential.secretId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_ID\"\n );\n }\n if (!this.finalCloudCredential.secretKey) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n const managedTcbClient = managedTcb.init({\n envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n token: this.finalCloudCredential.token,\n });\n\n const checkDBRes = await managedTcbClient.database.checkCollectionExists(\n CHAT_HISTORY_DATA_SOURCE\n );\n if (checkDBRes && checkDBRes.Exists) {\n return true;\n } else if (checkDBRes && !checkDBRes.Exists) {\n await managedTcbClient.database.createCollection(\n CHAT_HISTORY_DATA_SOURCE\n );\n return true;\n } else {\n throw new Error(\"Check database exists failed\");\n }\n } catch (dbError) {\n console.error(\n \"[ERROR] Failed to check/create chat history collection:\",\n JSON.stringify(dbError)\n );\n return false;\n }\n }\n}\n\nfunction getCloudbaseEnvId() {\n if (process.env.CBR_ENV_ID) {\n return process.env.CBR_ENV_ID;\n } else if (process.env.SCF_NAMESPACE) {\n return process.env.SCF_NAMESPACE;\n } else {\n return process.env.CLOUDBASE_ENV_ID || \"\";\n }\n}\n\n/**\n * Convert AGUI messages to OpenAI chat completion format\n */\nexport function convertMessagesToOpenAI(\n messages: Message[],\n systemPrompt?: string\n): ChatMessage[] {\n const openaiMessages: ChatMessage[] = [];\n\n // Add system prompt if provided\n if (systemPrompt) {\n openaiMessages.push({\n role: \"system\",\n content: systemPrompt,\n });\n }\n\n // Convert messages\n for (const msg of messages) {\n if (msg.role === \"user\") {\n openaiMessages.push({\n role: \"user\",\n content:\n typeof msg.content === \"string\"\n ? [{ type: \"text\", text: msg.content }]\n : msg.content.map((item) => {\n if (item.type === \"text\") {\n return { type: \"text\", text: item.text };\n } else {\n return {\n type: \"image_url\",\n image_url: { url: item.url || \"\" },\n };\n }\n }),\n });\n } else if (msg.role === \"assistant\") {\n openaiMessages.push({\n role: \"assistant\",\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n tool_calls: msg.toolCalls?.map((tc: ToolCall) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n })),\n });\n } else if (msg.role === \"tool\") {\n openaiMessages.push({\n role: \"tool\",\n tool_call_id: msg.toolCallId,\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n });\n }\n }\n\n return openaiMessages;\n}\n","/**\n * 将小驼峰字符串转换为下划线格式\n * 例如: \"userName\" -> \"user_name\"\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * 递归地将对象的所有小驼峰属性名转换为下划线格式\n */\nexport function camelToSnakeKeys<T>(obj: T): T {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => camelToSnakeKeys(item)) as T;\n }\n\n if (typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = camelToSnakeKeys(value);\n }\n return result as T;\n }\n\n return obj;\n}\n\nexport function genRandomStr(length: number): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let result = \"\";\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n","import OpenAI from \"openai\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface StreamContext {\n threadId: string;\n runId: string;\n messageId: string;\n}\n\nexport interface StreamState {\n hasStarted: boolean;\n fullContent: string;\n toolCallsMap: Map<string, { name: string; args: string }>;\n}\n\nexport type Delta =\n OpenAI.Chat.Completions.ChatCompletionChunk[\"choices\"][number][\"delta\"] & {\n reasoning_content?: string;\n };\n\nexport async function* processYuanqiStream(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n context: StreamContext\n) {\n const { threadId, runId, messageId } = context;\n const state: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n const reasoningState: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta as Delta;\n if (!delta) continue;\n\n if (delta.role === \"tool\") {\n const toolCallId = (delta as any).tool_call_id;\n if (toolCallId) {\n if (state.toolCallsMap.has(toolCallId)) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n state.toolCallsMap.delete(toolCallId);\n }\n yield {\n type: EventType.TOOL_CALL_RESULT,\n threadId,\n runId,\n toolCallId,\n content: delta.content || \"\",\n };\n }\n continue;\n }\n\n // Handle text content\n if (delta.content) {\n // End reasoning message if it was started\n if (reasoningState.hasStarted) {\n reasoningState.hasStarted = false;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (!state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n state.hasStarted = true;\n }\n\n state.fullContent += delta.content;\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.content,\n };\n }\n\n // Handle reasoning content\n if (delta.reasoning_content) {\n if (!reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_START,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n reasoningState.hasStarted = true;\n }\n\n reasoningState.fullContent += delta.reasoning_content;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.reasoning_content,\n };\n }\n\n // Handle tool calls\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n const toolCallId = toolCall.id || `tool_${toolCall.index}`;\n\n if (toolCall.function?.name) {\n // Tool call start\n yield {\n type: EventType.TOOL_CALL_START,\n threadId,\n runId,\n toolCallId,\n toolCallName: toolCall.function.name,\n };\n\n // If first chunk contains arguments, emit TOOL_CALL_ARGS event\n if (toolCall.function.arguments) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n\n state.toolCallsMap.set(toolCallId, {\n name: toolCall.function.name,\n args: toolCall.function.arguments || \"\",\n });\n } else if (toolCall.function?.arguments) {\n // Tool call arguments delta\n const existing = state.toolCallsMap.get(toolCallId);\n if (existing) {\n existing.args += toolCall.function.arguments;\n\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n }\n }\n }\n }\n\n // Emit TEXT_MESSAGE_END if we had text content\n if (state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n // Emit TOOL_CALL_END for all tool calls\n for (const [toolCallId] of state.toolCallsMap) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n }\n}\n","// 对话数据模型\nexport const CHAT_HISTORY_DATA_SOURCE = \"ai_bot_chat_history_5hobd2b\";\n","import tcb from \"@cloudbase/node-sdk\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { genRandomStr } from \"./utils\";\n\nfunction genRecordId(): string {\n return \"record-\" + genRandomStr(8);\n}\n\n// Create a new chat history record\nexport async function createChatHistory({\n tcbClient,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const recordId = chatHistoryEntity.recordId || genRecordId();\n const data = {\n record_id: recordId,\n bot_id: chatHistoryEntity.botId,\n role: chatHistoryEntity.role,\n content: chatHistoryEntity.content,\n sender: chatHistoryEntity.sender,\n conversation: chatHistoryEntity.conversation,\n type: chatHistoryEntity.type,\n image: chatHistoryEntity.image,\n trigger_src: chatHistoryEntity.triggerSrc,\n origin_msg: chatHistoryEntity.originMsg,\n reply_to: chatHistoryEntity.replyTo,\n reply: chatHistoryEntity.reply,\n trace_id: chatHistoryEntity.traceId,\n need_async_reply: chatHistoryEntity.needAsyncReply,\n async_reply: chatHistoryEntity.asyncReply,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n const db = tcbClient.database();\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n const result = await collection.add(data);\n\n // console.log(\n // `Create record: chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return recordId;\n } catch (error) {\n console.error(\"Failed to create chat history record, error:\", error);\n return undefined;\n }\n}\n\n// Update chat history by record ID\nexport async function updateChatHistoryByRecordId({\n tcbClient,\n recordId,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n recordId: string;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n const result = await collection\n .where({ record_id: _.eq(recordId) })\n .update({\n content: chatHistoryEntity.content,\n image: chatHistoryEntity.image,\n async_reply: chatHistoryEntity.asyncReply,\n recommend_questions: chatHistoryEntity.recommendQuestions,\n status: chatHistoryEntity.status,\n origin_msg: chatHistoryEntity.originMsg,\n updatedAt: Date.now(),\n });\n\n // console.log(\n // `Update record: recordId: ${recordId}, chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return chatHistoryEntity.recordId;\n } catch (error) {\n console.error(\"Failed to update chat history, error:\", error);\n return undefined;\n }\n}\n\n// Query chat history from database\nexport async function describeChatHistory({\n tcbClient,\n botId,\n sort,\n pageSize = 10,\n pageNumber = 1,\n conversation,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n sort: \"asc\" | \"desc\";\n pageSize?: number;\n pageNumber?: number;\n conversation?: string;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<[ChatHistoryEntity[], number]> {\n if (!sort || sort.length === 0) {\n sort = \"desc\";\n }\n\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n // Build where conditions\n const whereConditions: Record<string, unknown> = {\n bot_id: _.eq(botId),\n };\n\n // Add optional filters\n if (conversation) {\n whereConditions.conversation = _.eq(conversation);\n }\n\n if (startCreatedAt !== undefined) {\n whereConditions.createdAt = _.gt(startCreatedAt);\n }\n\n if (triggerSrc) {\n whereConditions.trigger_src = _.eq(triggerSrc);\n }\n\n // Calculate skip for pagination\n const skip = (pageNumber - 1) * pageSize;\n\n // Query records\n const result = await collection\n .where(whereConditions)\n .orderBy(\"createdAt\", sort)\n .skip(skip)\n .limit(pageSize)\n .get();\n\n // Get total count\n const countResult = await collection.where(whereConditions).count();\n const total = countResult.total || 0;\n\n const records = result?.data || [];\n\n const entityList: ChatHistoryEntity[] = records.map(\n (item: ChatHistoryData) => transDataToChatEntity(item)\n );\n\n return [entityList, total];\n } catch (error) {\n console.error(\"Failed to query chat history, error:\", error);\n return [[], 0];\n }\n}\n\n// Transform data to ChatHistoryEntity structure\nexport function transDataToChatEntity(\n item: ChatHistoryData\n): ChatHistoryEntity {\n if (!item) {\n return new ChatHistoryEntity();\n }\n const chatEntity: ChatHistoryEntity = new ChatHistoryEntity();\n chatEntity.botId = item.bot_id;\n chatEntity.recordId = item.record_id;\n chatEntity.role = item.role;\n chatEntity.status = item.status;\n chatEntity.content = item.content;\n chatEntity.sender = item.sender;\n chatEntity.conversation = item.conversation;\n chatEntity.type = item.type;\n chatEntity.triggerSrc = item.trigger_src;\n chatEntity.originMsg = item.origin_msg;\n chatEntity.replyTo = item.reply_to;\n chatEntity.reply = item.reply;\n chatEntity.traceId = item.trace_id;\n chatEntity.needAsyncReply = item.need_async_reply;\n chatEntity.asyncReply = item.async_reply;\n chatEntity.createdAt = item.createdAt;\n chatEntity.updatedAt = item.updatedAt;\n return chatEntity;\n}\n\n// Query history records for LLM, get the most recent 10 conversation pairs (20 records)\nexport async function queryForLLM({\n tcbClient,\n botId,\n pageSize = 10,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n pageSize?: number;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<{ role: string; content: string }[]> {\n if (startCreatedAt === undefined) {\n startCreatedAt = Date.now() - 24 * 60 * 60 * 1000;\n }\n const recordEntityList: ChatHistoryEntity[] = [];\n\n const [recordList] = await describeChatHistory({\n tcbClient,\n botId,\n sort: \"desc\",\n pageSize,\n startCreatedAt,\n triggerSrc,\n });\n recordEntityList.push(...recordList.reverse());\n\n const entityMap = new Map<string, ChatHistoryEntity>();\n recordEntityList\n .filter((item) => {\n if (item.needAsyncReply === true) {\n return !!item.asyncReply;\n } else {\n return !!item.content;\n }\n })\n .forEach((item) => {\n entityMap.set(item.recordId, item);\n });\n\n const result: { role: string; content: string }[] = [];\n /*\n 1. Strongly depends on database history data, model history data has role order requirements\n 2. Need to ensure that no matter what bug occurs, always get a complete and usable user + assistant pair, otherwise the request will fail\n */\n recordEntityList.forEach((item) => {\n const { role, content, reply } = item;\n // When calling LLM, empty content will cause failure, so filter out conversations with empty content\n if (role === \"user\" && content?.length !== 0) {\n if (entityMap.has(reply)) {\n result.push({ role, content });\n result.push({\n role: entityMap.get(reply)!.role,\n content: entityMap.get(reply)!.content,\n });\n }\n }\n });\n if (result.length % 2 === 1) {\n result.splice(-1, 1);\n }\n return result;\n}\n\nexport interface ChatHistoryData {\n bot_id: string;\n record_id: string;\n role: string;\n status: string;\n content: string;\n sender: string;\n conversation: string;\n type: string;\n trigger_src: string;\n origin_msg: string;\n reply_to: string;\n reply: string;\n trace_id: string;\n need_async_reply: boolean;\n async_reply: string;\n createdAt: number;\n updatedAt: number;\n}\n\nexport class ChatHistoryEntity {\n id: number;\n botId: string;\n // 对话唯一id\n recordId: string;\n role: string;\n content: string;\n recommendQuestions: string[];\n sender: string;\n conversation: string;\n type: string;\n /**\n * 消息状态,pending done error cancel\n */\n status: string;\n image: string;\n triggerSrc: string;\n originMsg: string;\n replyTo: string;\n reply: string;\n traceId: string;\n needAsyncReply: boolean;\n asyncReply: string;\n createTime: string;\n updateTime: string;\n createdAt: number;\n updatedAt: number;\n event: string;\n}\n"],"mappings":"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","names":["import_client","OpenAI","tcb","managedTcb"]}
|
package/dist/index.mjs
CHANGED
|
@@ -430,7 +430,7 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
430
430
|
...this.yuanqiConfig.request?.body || {},
|
|
431
431
|
...forwardedProps || {},
|
|
432
432
|
assistantId: this.finalAppId,
|
|
433
|
-
userId: state?.__request_context__?.id || forwardedProps?.userId || randomUUID(),
|
|
433
|
+
userId: state?.__request_context__?.user?.id || forwardedProps?.userId || randomUUID(),
|
|
434
434
|
messages
|
|
435
435
|
};
|
|
436
436
|
return requestBody;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent.ts","../src/utils.ts","../src/stream.ts","../src/constant.ts","../src/chat_history.ts"],"sourcesContent":["import {\n RunAgentInput,\n Message,\n AbstractAgent,\n AgentConfig,\n BaseEvent,\n EventType,\n RunStartedEvent,\n RunFinishedEvent,\n RunErrorEvent,\n TextMessageContentEvent,\n ToolCall,\n} from \"@ag-ui/client\";\nimport tcb from \"@cloudbase/node-sdk\";\nimport managedTcb from \"@cloudbase/manager-node\";\nimport OpenAI from \"openai\";\nimport { randomUUID } from \"crypto\";\nimport { camelToSnakeKeys } from \"./utils\";\nimport { processYuanqiStream } from \"./stream\";\nimport { Observable, Subscriber } from \"rxjs\";\nimport {\n createChatHistory,\n queryForLLM,\n ChatHistoryEntity,\n} from \"./chat_history\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { YuanqiConfig, ChatMessage, YuanqiChatRequest } from \"./types\";\n\nexport class YuanqiAgentError extends Error {\n code?: string;\n constructor(message: string, code?: string) {\n super(message);\n this.name = \"YuanqiAgentError\";\n if (code) this.code = code;\n }\n}\n\nexport class YuanqiAgent extends AbstractAgent {\n protected yuanqiConfig: YuanqiConfig;\n private finalAppId: string;\n private finalCloudCredential: {\n secretId?: string;\n secretKey?: string;\n token?: string;\n } = {};\n private model: OpenAI;\n constructor(config: AgentConfig & { yuanqiConfig: YuanqiConfig }) {\n super(config);\n this.yuanqiConfig = config.yuanqiConfig;\n this.model = new OpenAI({\n apiKey: \"\",\n baseURL:\n this.yuanqiConfig.request?.baseUrl ||\n \"https://yuanqi.tencent.com/openapi/v1/agent\",\n });\n this.finalAppId =\n this.yuanqiConfig.appId ||\n this.yuanqiConfig.request?.body?.assistantId ||\n process.env.YUANQI_APP_ID ||\n \"\";\n this.finalCloudCredential = {\n secretId:\n this.yuanqiConfig.credential?.secretId ||\n process.env.TENCENTCLOUD_SECRETID,\n secretKey:\n this.yuanqiConfig.credential?.secretKey ||\n process.env.TENCENTCLOUD_SECRETKEY,\n token:\n this.yuanqiConfig.credential?.token ||\n process.env.TENCENTCLOUD_SESSIONTOKEN,\n };\n }\n\n generateRequestBody({\n messages,\n input,\n }: {\n messages: ChatMessage[];\n input: RunAgentInput;\n }): YuanqiChatRequest {\n const { state, forwardedProps } = input;\n const requestBody: YuanqiChatRequest = {\n stream: true,\n ...(this.yuanqiConfig.request?.body || {}),\n ...(forwardedProps || {}),\n\n assistantId: this.finalAppId,\n userId:\n state?.__request_context__?.id ||\n forwardedProps?.userId ||\n randomUUID(),\n messages,\n };\n return requestBody;\n }\n\n run(input: RunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n this._run(subscriber, input);\n });\n }\n\n private async _run(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput\n ): Promise<void> {\n try {\n const { messages, runId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = input.threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n } as RunStartedEvent);\n\n if (!this.finalAppId) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_ID\"\n );\n }\n if (!this.yuanqiConfig.appKey && !process.env.YUANQI_APP_KEY) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_KEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_KEY\"\n );\n }\n\n // Warn user if messages are being trimmed (only using latest user message)\n const trimmedCount = messages.length - 1;\n if (trimmedCount > 0) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Yuanqi handles message history itself, so that a total of ${trimmedCount} messages before the last user message will be trimmed.`,\n type: \"warn\",\n },\n });\n }\n\n // Get the latest user message for saving to history\n const latestUserMessage = messages.filter((m) => m.role === \"user\").pop();\n if (!latestUserMessage) {\n throw new YuanqiAgentError(\n \"No user message found, please send a message first.\",\n \"MESSAGE_FORMAT_ERROR\"\n );\n }\n\n const allMessages = await this.getChatHistory(\n subscriber,\n latestUserMessage\n );\n\n const body = this.generateRequestBody({\n messages: allMessages,\n input,\n });\n\n const stream = await openai.chat.completions.create(\n {\n stream: true,\n messages: [],\n model: \"\",\n },\n {\n body: camelToSnakeKeys(body),\n headers: {\n ...this.yuanqiConfig.request?.headers,\n Authorization: `Bearer ${\n this.yuanqiConfig.appKey || process.env.YUANQI_APP_KEY\n }`,\n },\n }\n );\n\n // Process stream and emit AGUI events, collect full response\n const userRecordId = `record-${randomUUID().slice(0, 8)}`;\n const assistantRecordId = `record-${randomUUID().slice(0, 8)}`;\n const context = { threadId, runId, messageId: userRecordId };\n\n let fullAssistantContent = \"\";\n\n for await (const event of processYuanqiStream(stream, context)) {\n subscriber.next(event);\n // Collect assistant content from TEXT_MESSAGE_CONTENT events\n if (\n event.type === EventType.TEXT_MESSAGE_CONTENT &&\n (event as TextMessageContentEvent).delta\n ) {\n fullAssistantContent += (event as TextMessageContentEvent).delta;\n }\n }\n\n const userContent =\n typeof latestUserMessage?.content === \"string\"\n ? latestUserMessage.content\n : latestUserMessage?.content\n ?.filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\") || \"\";\n\n await this.saveChatHistory(\n subscriber,\n input,\n userRecordId,\n assistantRecordId,\n userContent,\n fullAssistantContent\n );\n\n subscriber.next({\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\n } as RunFinishedEvent);\n } catch (e: unknown) {\n console.error(\"[ERROR] Uncaught error: \", JSON.stringify(e));\n let code = \"UNKNOWN_ERROR\";\n let message = JSON.stringify(e);\n if (e instanceof YuanqiAgentError) {\n code = e.code || \"AGENT_ERROR\";\n message = e.message;\n } else if (e instanceof Error) {\n code = e.name || \"ERROR\";\n message = e.message;\n }\n subscriber.next({\n type: EventType.RUN_ERROR,\n code,\n message: `Sorry, an error occurred while running the agent: Error code ${code}, ${message}`,\n } as RunErrorEvent);\n } finally {\n subscriber.complete();\n }\n }\n\n // Can be override by subclasses\n protected async getChatHistory(\n subscriber: Subscriber<BaseEvent>,\n latestUserMessage: Message\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history loading.`,\n type: \"warn\",\n },\n });\n return convertMessagesToOpenAI([latestUserMessage]);\n }\n\n // Fetch chat history from database using queryForLLM\n let historyMessages: ChatMessage[] = [];\n\n const historyCount = this.yuanqiConfig.historyCount ?? 10;\n const historyRecords = await queryForLLM({\n tcbClient,\n botId,\n pageSize: historyCount,\n });\n\n // Convert queryForLLM result to ChatMessage format\n historyMessages = historyRecords.map((record) => ({\n role: record.role as \"user\" | \"assistant\",\n content: [{ type: \"text\" as const, text: record.content }],\n }));\n\n // Combine history messages with current messages\n const allMessages = historyMessages.concat(\n convertMessagesToOpenAI([latestUserMessage])\n );\n return allMessages;\n }\n\n // Can be override by subclasses\n protected async saveChatHistory(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput,\n userRecordId: string,\n assistantRecordId: string,\n userContent: string,\n assistantContent: string\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history saving.`,\n type: \"warn\",\n },\n });\n return;\n }\n\n // Save message pair to history\n const userEntity = new ChatHistoryEntity();\n userEntity.recordId = userRecordId;\n userEntity.botId = botId;\n userEntity.role = \"user\";\n userEntity.content = userContent;\n userEntity.conversation = threadId;\n userEntity.reply = assistantRecordId;\n userEntity.triggerSrc = \"\";\n userEntity.traceId = randomUUID();\n\n await createChatHistory({ tcbClient, chatHistoryEntity: userEntity });\n\n const assistantEntity = new ChatHistoryEntity();\n assistantEntity.recordId = assistantRecordId;\n assistantEntity.botId = botId;\n assistantEntity.role = \"assistant\";\n assistantEntity.content = assistantContent;\n assistantEntity.conversation = threadId;\n assistantEntity.replyTo = userRecordId;\n assistantEntity.triggerSrc = \"\";\n assistantEntity.traceId = runId;\n assistantEntity.status = \"done\";\n\n await createChatHistory({\n tcbClient,\n chatHistoryEntity: assistantEntity,\n });\n }\n\n private getTcbClient() {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n\n const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\n });\n return tcbClient;\n }\n\n private async checkIsDatabaseReady() {\n try {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n if (!envId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, CLOUDBASE_ENV_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_CLOUDBASE_ENV_ID\"\n );\n }\n if (!this.finalCloudCredential.token) {\n if (!this.finalCloudCredential.secretId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_ID\"\n );\n }\n if (!this.finalCloudCredential.secretKey) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n const managedTcbClient = managedTcb.init({\n envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n token: this.finalCloudCredential.token,\n });\n\n const checkDBRes = await managedTcbClient.database.checkCollectionExists(\n CHAT_HISTORY_DATA_SOURCE\n );\n if (checkDBRes && checkDBRes.Exists) {\n return true;\n } else if (checkDBRes && !checkDBRes.Exists) {\n await managedTcbClient.database.createCollection(\n CHAT_HISTORY_DATA_SOURCE\n );\n return true;\n } else {\n throw new Error(\"Check database exists failed\");\n }\n } catch (dbError) {\n console.error(\n \"[ERROR] Failed to check/create chat history collection:\",\n JSON.stringify(dbError)\n );\n return false;\n }\n }\n}\n\nfunction getCloudbaseEnvId() {\n if (process.env.CBR_ENV_ID) {\n return process.env.CBR_ENV_ID;\n } else if (process.env.SCF_NAMESPACE) {\n return process.env.SCF_NAMESPACE;\n } else {\n return process.env.CLOUDBASE_ENV_ID || \"\";\n }\n}\n\n/**\n * Convert AGUI messages to OpenAI chat completion format\n */\nexport function convertMessagesToOpenAI(\n messages: Message[],\n systemPrompt?: string\n): ChatMessage[] {\n const openaiMessages: ChatMessage[] = [];\n\n // Add system prompt if provided\n if (systemPrompt) {\n openaiMessages.push({\n role: \"system\",\n content: systemPrompt,\n });\n }\n\n // Convert messages\n for (const msg of messages) {\n if (msg.role === \"user\") {\n openaiMessages.push({\n role: \"user\",\n content:\n typeof msg.content === \"string\"\n ? [{ type: \"text\", text: msg.content }]\n : msg.content.map((item) => {\n if (item.type === \"text\") {\n return { type: \"text\", text: item.text };\n } else {\n return {\n type: \"image_url\",\n image_url: { url: item.url || \"\" },\n };\n }\n }),\n });\n } else if (msg.role === \"assistant\") {\n openaiMessages.push({\n role: \"assistant\",\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n tool_calls: msg.toolCalls?.map((tc: ToolCall) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n })),\n });\n } else if (msg.role === \"tool\") {\n openaiMessages.push({\n role: \"tool\",\n tool_call_id: msg.toolCallId,\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n });\n }\n }\n\n return openaiMessages;\n}\n","/**\n * 将小驼峰字符串转换为下划线格式\n * 例如: \"userName\" -> \"user_name\"\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * 递归地将对象的所有小驼峰属性名转换为下划线格式\n */\nexport function camelToSnakeKeys<T>(obj: T): T {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => camelToSnakeKeys(item)) as T;\n }\n\n if (typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = camelToSnakeKeys(value);\n }\n return result as T;\n }\n\n return obj;\n}\n\nexport function genRandomStr(length: number): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let result = \"\";\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n","import OpenAI from \"openai\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface StreamContext {\n threadId: string;\n runId: string;\n messageId: string;\n}\n\nexport interface StreamState {\n hasStarted: boolean;\n fullContent: string;\n toolCallsMap: Map<string, { name: string; args: string }>;\n}\n\nexport type Delta =\n OpenAI.Chat.Completions.ChatCompletionChunk[\"choices\"][number][\"delta\"] & {\n reasoning_content?: string;\n };\n\nexport async function* processYuanqiStream(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n context: StreamContext\n) {\n const { threadId, runId, messageId } = context;\n const state: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n const reasoningState: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta as Delta;\n if (!delta) continue;\n\n if (delta.role === \"tool\") {\n const toolCallId = (delta as any).tool_call_id;\n if (toolCallId) {\n if (state.toolCallsMap.has(toolCallId)) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n state.toolCallsMap.delete(toolCallId);\n }\n yield {\n type: EventType.TOOL_CALL_RESULT,\n threadId,\n runId,\n toolCallId,\n content: delta.content || \"\",\n };\n }\n continue;\n }\n\n // Handle text content\n if (delta.content) {\n // End reasoning message if it was started\n if (reasoningState.hasStarted) {\n reasoningState.hasStarted = false;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (!state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n state.hasStarted = true;\n }\n\n state.fullContent += delta.content;\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.content,\n };\n }\n\n // Handle reasoning content\n if (delta.reasoning_content) {\n if (!reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_START,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n reasoningState.hasStarted = true;\n }\n\n reasoningState.fullContent += delta.reasoning_content;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.reasoning_content,\n };\n }\n\n // Handle tool calls\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n const toolCallId = toolCall.id || `tool_${toolCall.index}`;\n\n if (toolCall.function?.name) {\n // Tool call start\n yield {\n type: EventType.TOOL_CALL_START,\n threadId,\n runId,\n toolCallId,\n toolCallName: toolCall.function.name,\n };\n\n // If first chunk contains arguments, emit TOOL_CALL_ARGS event\n if (toolCall.function.arguments) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n\n state.toolCallsMap.set(toolCallId, {\n name: toolCall.function.name,\n args: toolCall.function.arguments || \"\",\n });\n } else if (toolCall.function?.arguments) {\n // Tool call arguments delta\n const existing = state.toolCallsMap.get(toolCallId);\n if (existing) {\n existing.args += toolCall.function.arguments;\n\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n }\n }\n }\n }\n\n // Emit TEXT_MESSAGE_END if we had text content\n if (state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n // Emit TOOL_CALL_END for all tool calls\n for (const [toolCallId] of state.toolCallsMap) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n }\n}\n","// 对话数据模型\nexport const CHAT_HISTORY_DATA_SOURCE = \"ai_bot_chat_history_5hobd2b\";\n","import tcb from \"@cloudbase/node-sdk\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { genRandomStr } from \"./utils\";\n\nfunction genRecordId(): string {\n return \"record-\" + genRandomStr(8);\n}\n\n// Create a new chat history record\nexport async function createChatHistory({\n tcbClient,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const recordId = chatHistoryEntity.recordId || genRecordId();\n const data = {\n record_id: recordId,\n bot_id: chatHistoryEntity.botId,\n role: chatHistoryEntity.role,\n content: chatHistoryEntity.content,\n sender: chatHistoryEntity.sender,\n conversation: chatHistoryEntity.conversation,\n type: chatHistoryEntity.type,\n image: chatHistoryEntity.image,\n trigger_src: chatHistoryEntity.triggerSrc,\n origin_msg: chatHistoryEntity.originMsg,\n reply_to: chatHistoryEntity.replyTo,\n reply: chatHistoryEntity.reply,\n trace_id: chatHistoryEntity.traceId,\n need_async_reply: chatHistoryEntity.needAsyncReply,\n async_reply: chatHistoryEntity.asyncReply,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n const db = tcbClient.database();\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n const result = await collection.add(data);\n\n // console.log(\n // `Create record: chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return recordId;\n } catch (error) {\n console.error(\"Failed to create chat history record, error:\", error);\n return undefined;\n }\n}\n\n// Update chat history by record ID\nexport async function updateChatHistoryByRecordId({\n tcbClient,\n recordId,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n recordId: string;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n const result = await collection\n .where({ record_id: _.eq(recordId) })\n .update({\n content: chatHistoryEntity.content,\n image: chatHistoryEntity.image,\n async_reply: chatHistoryEntity.asyncReply,\n recommend_questions: chatHistoryEntity.recommendQuestions,\n status: chatHistoryEntity.status,\n origin_msg: chatHistoryEntity.originMsg,\n updatedAt: Date.now(),\n });\n\n // console.log(\n // `Update record: recordId: ${recordId}, chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return chatHistoryEntity.recordId;\n } catch (error) {\n console.error(\"Failed to update chat history, error:\", error);\n return undefined;\n }\n}\n\n// Query chat history from database\nexport async function describeChatHistory({\n tcbClient,\n botId,\n sort,\n pageSize = 10,\n pageNumber = 1,\n conversation,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n sort: \"asc\" | \"desc\";\n pageSize?: number;\n pageNumber?: number;\n conversation?: string;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<[ChatHistoryEntity[], number]> {\n if (!sort || sort.length === 0) {\n sort = \"desc\";\n }\n\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n // Build where conditions\n const whereConditions: Record<string, unknown> = {\n bot_id: _.eq(botId),\n };\n\n // Add optional filters\n if (conversation) {\n whereConditions.conversation = _.eq(conversation);\n }\n\n if (startCreatedAt !== undefined) {\n whereConditions.createdAt = _.gt(startCreatedAt);\n }\n\n if (triggerSrc) {\n whereConditions.trigger_src = _.eq(triggerSrc);\n }\n\n // Calculate skip for pagination\n const skip = (pageNumber - 1) * pageSize;\n\n // Query records\n const result = await collection\n .where(whereConditions)\n .orderBy(\"createdAt\", sort)\n .skip(skip)\n .limit(pageSize)\n .get();\n\n // Get total count\n const countResult = await collection.where(whereConditions).count();\n const total = countResult.total || 0;\n\n const records = result?.data || [];\n\n const entityList: ChatHistoryEntity[] = records.map(\n (item: ChatHistoryData) => transDataToChatEntity(item)\n );\n\n return [entityList, total];\n } catch (error) {\n console.error(\"Failed to query chat history, error:\", error);\n return [[], 0];\n }\n}\n\n// Transform data to ChatHistoryEntity structure\nexport function transDataToChatEntity(\n item: ChatHistoryData\n): ChatHistoryEntity {\n if (!item) {\n return new ChatHistoryEntity();\n }\n const chatEntity: ChatHistoryEntity = new ChatHistoryEntity();\n chatEntity.botId = item.bot_id;\n chatEntity.recordId = item.record_id;\n chatEntity.role = item.role;\n chatEntity.status = item.status;\n chatEntity.content = item.content;\n chatEntity.sender = item.sender;\n chatEntity.conversation = item.conversation;\n chatEntity.type = item.type;\n chatEntity.triggerSrc = item.trigger_src;\n chatEntity.originMsg = item.origin_msg;\n chatEntity.replyTo = item.reply_to;\n chatEntity.reply = item.reply;\n chatEntity.traceId = item.trace_id;\n chatEntity.needAsyncReply = item.need_async_reply;\n chatEntity.asyncReply = item.async_reply;\n chatEntity.createdAt = item.createdAt;\n chatEntity.updatedAt = item.updatedAt;\n return chatEntity;\n}\n\n// Query history records for LLM, get the most recent 10 conversation pairs (20 records)\nexport async function queryForLLM({\n tcbClient,\n botId,\n pageSize = 10,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n pageSize?: number;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<{ role: string; content: string }[]> {\n if (startCreatedAt === undefined) {\n startCreatedAt = Date.now() - 24 * 60 * 60 * 1000;\n }\n const recordEntityList: ChatHistoryEntity[] = [];\n\n const [recordList] = await describeChatHistory({\n tcbClient,\n botId,\n sort: \"desc\",\n pageSize,\n startCreatedAt,\n triggerSrc,\n });\n recordEntityList.push(...recordList.reverse());\n\n const entityMap = new Map<string, ChatHistoryEntity>();\n recordEntityList\n .filter((item) => {\n if (item.needAsyncReply === true) {\n return !!item.asyncReply;\n } else {\n return !!item.content;\n }\n })\n .forEach((item) => {\n entityMap.set(item.recordId, item);\n });\n\n const result: { role: string; content: string }[] = [];\n /*\n 1. Strongly depends on database history data, model history data has role order requirements\n 2. Need to ensure that no matter what bug occurs, always get a complete and usable user + assistant pair, otherwise the request will fail\n */\n recordEntityList.forEach((item) => {\n const { role, content, reply } = item;\n // When calling LLM, empty content will cause failure, so filter out conversations with empty content\n if (role === \"user\" && content?.length !== 0) {\n if (entityMap.has(reply)) {\n result.push({ role, content });\n result.push({\n role: entityMap.get(reply)!.role,\n content: entityMap.get(reply)!.content,\n });\n }\n }\n });\n if (result.length % 2 === 1) {\n result.splice(-1, 1);\n }\n return result;\n}\n\nexport interface ChatHistoryData {\n bot_id: string;\n record_id: string;\n role: string;\n status: string;\n content: string;\n sender: string;\n conversation: string;\n type: string;\n trigger_src: string;\n origin_msg: string;\n reply_to: string;\n reply: string;\n trace_id: string;\n need_async_reply: boolean;\n async_reply: string;\n createdAt: number;\n updatedAt: number;\n}\n\nexport class ChatHistoryEntity {\n id: number;\n botId: string;\n // 对话唯一id\n recordId: string;\n role: string;\n content: string;\n recommendQuestions: string[];\n sender: string;\n conversation: string;\n type: string;\n /**\n * 消息状态,pending done error cancel\n */\n status: string;\n image: string;\n triggerSrc: string;\n originMsg: string;\n replyTo: string;\n reply: string;\n traceId: string;\n needAsyncReply: boolean;\n asyncReply: string;\n createTime: string;\n updateTime: string;\n createdAt: number;\n updatedAt: number;\n event: string;\n}\n"],"mappings":"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","names":["EventType","EventType"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent.ts","../src/utils.ts","../src/stream.ts","../src/constant.ts","../src/chat_history.ts"],"sourcesContent":["import {\n RunAgentInput,\n Message,\n AbstractAgent,\n AgentConfig,\n BaseEvent,\n EventType,\n RunStartedEvent,\n RunFinishedEvent,\n RunErrorEvent,\n TextMessageContentEvent,\n ToolCall,\n} from \"@ag-ui/client\";\nimport tcb from \"@cloudbase/node-sdk\";\nimport managedTcb from \"@cloudbase/manager-node\";\nimport OpenAI from \"openai\";\nimport { randomUUID } from \"crypto\";\nimport { camelToSnakeKeys } from \"./utils\";\nimport { processYuanqiStream } from \"./stream\";\nimport { Observable, Subscriber } from \"rxjs\";\nimport {\n createChatHistory,\n queryForLLM,\n ChatHistoryEntity,\n} from \"./chat_history\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { YuanqiConfig, ChatMessage, YuanqiChatRequest } from \"./types\";\n\nexport class YuanqiAgentError extends Error {\n code?: string;\n constructor(message: string, code?: string) {\n super(message);\n this.name = \"YuanqiAgentError\";\n if (code) this.code = code;\n }\n}\n\nexport class YuanqiAgent extends AbstractAgent {\n protected yuanqiConfig: YuanqiConfig;\n private finalAppId: string;\n private finalCloudCredential: {\n secretId?: string;\n secretKey?: string;\n token?: string;\n } = {};\n private model: OpenAI;\n constructor(config: AgentConfig & { yuanqiConfig: YuanqiConfig }) {\n super(config);\n this.yuanqiConfig = config.yuanqiConfig;\n this.model = new OpenAI({\n apiKey: \"\",\n baseURL:\n this.yuanqiConfig.request?.baseUrl ||\n \"https://yuanqi.tencent.com/openapi/v1/agent\",\n });\n this.finalAppId =\n this.yuanqiConfig.appId ||\n this.yuanqiConfig.request?.body?.assistantId ||\n process.env.YUANQI_APP_ID ||\n \"\";\n this.finalCloudCredential = {\n secretId:\n this.yuanqiConfig.credential?.secretId ||\n process.env.TENCENTCLOUD_SECRETID,\n secretKey:\n this.yuanqiConfig.credential?.secretKey ||\n process.env.TENCENTCLOUD_SECRETKEY,\n token:\n this.yuanqiConfig.credential?.token ||\n process.env.TENCENTCLOUD_SESSIONTOKEN,\n };\n }\n\n generateRequestBody({\n messages,\n input,\n }: {\n messages: ChatMessage[];\n input: RunAgentInput;\n }): YuanqiChatRequest {\n const { state, forwardedProps } = input;\n const requestBody: YuanqiChatRequest = {\n stream: true,\n ...(this.yuanqiConfig.request?.body || {}),\n ...(forwardedProps || {}),\n\n assistantId: this.finalAppId,\n userId:\n state?.__request_context__?.user?.id ||\n forwardedProps?.userId ||\n randomUUID(),\n messages,\n };\n return requestBody;\n }\n\n run(input: RunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n this._run(subscriber, input);\n });\n }\n\n private async _run(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput\n ): Promise<void> {\n try {\n const { messages, runId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = input.threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n } as RunStartedEvent);\n\n if (!this.finalAppId) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_ID\"\n );\n }\n if (!this.yuanqiConfig.appKey && !process.env.YUANQI_APP_KEY) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_KEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_KEY\"\n );\n }\n\n // Warn user if messages are being trimmed (only using latest user message)\n const trimmedCount = messages.length - 1;\n if (trimmedCount > 0) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Yuanqi handles message history itself, so that a total of ${trimmedCount} messages before the last user message will be trimmed.`,\n type: \"warn\",\n },\n });\n }\n\n // Get the latest user message for saving to history\n const latestUserMessage = messages.filter((m) => m.role === \"user\").pop();\n if (!latestUserMessage) {\n throw new YuanqiAgentError(\n \"No user message found, please send a message first.\",\n \"MESSAGE_FORMAT_ERROR\"\n );\n }\n\n const allMessages = await this.getChatHistory(\n subscriber,\n latestUserMessage\n );\n\n const body = this.generateRequestBody({\n messages: allMessages,\n input,\n });\n\n const stream = await openai.chat.completions.create(\n {\n stream: true,\n messages: [],\n model: \"\",\n },\n {\n body: camelToSnakeKeys(body),\n headers: {\n ...this.yuanqiConfig.request?.headers,\n Authorization: `Bearer ${\n this.yuanqiConfig.appKey || process.env.YUANQI_APP_KEY\n }`,\n },\n }\n );\n\n // Process stream and emit AGUI events, collect full response\n const userRecordId = `record-${randomUUID().slice(0, 8)}`;\n const assistantRecordId = `record-${randomUUID().slice(0, 8)}`;\n const context = { threadId, runId, messageId: userRecordId };\n\n let fullAssistantContent = \"\";\n\n for await (const event of processYuanqiStream(stream, context)) {\n subscriber.next(event);\n // Collect assistant content from TEXT_MESSAGE_CONTENT events\n if (\n event.type === EventType.TEXT_MESSAGE_CONTENT &&\n (event as TextMessageContentEvent).delta\n ) {\n fullAssistantContent += (event as TextMessageContentEvent).delta;\n }\n }\n\n const userContent =\n typeof latestUserMessage?.content === \"string\"\n ? latestUserMessage.content\n : latestUserMessage?.content\n ?.filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\") || \"\";\n\n await this.saveChatHistory(\n subscriber,\n input,\n userRecordId,\n assistantRecordId,\n userContent,\n fullAssistantContent\n );\n\n subscriber.next({\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\n } as RunFinishedEvent);\n } catch (e: unknown) {\n console.error(\"[ERROR] Uncaught error: \", JSON.stringify(e));\n let code = \"UNKNOWN_ERROR\";\n let message = JSON.stringify(e);\n if (e instanceof YuanqiAgentError) {\n code = e.code || \"AGENT_ERROR\";\n message = e.message;\n } else if (e instanceof Error) {\n code = e.name || \"ERROR\";\n message = e.message;\n }\n subscriber.next({\n type: EventType.RUN_ERROR,\n code,\n message: `Sorry, an error occurred while running the agent: Error code ${code}, ${message}`,\n } as RunErrorEvent);\n } finally {\n subscriber.complete();\n }\n }\n\n // Can be override by subclasses\n protected async getChatHistory(\n subscriber: Subscriber<BaseEvent>,\n latestUserMessage: Message\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history loading.`,\n type: \"warn\",\n },\n });\n return convertMessagesToOpenAI([latestUserMessage]);\n }\n\n // Fetch chat history from database using queryForLLM\n let historyMessages: ChatMessage[] = [];\n\n const historyCount = this.yuanqiConfig.historyCount ?? 10;\n const historyRecords = await queryForLLM({\n tcbClient,\n botId,\n pageSize: historyCount,\n });\n\n // Convert queryForLLM result to ChatMessage format\n historyMessages = historyRecords.map((record) => ({\n role: record.role as \"user\" | \"assistant\",\n content: [{ type: \"text\" as const, text: record.content }],\n }));\n\n // Combine history messages with current messages\n const allMessages = historyMessages.concat(\n convertMessagesToOpenAI([latestUserMessage])\n );\n return allMessages;\n }\n\n // Can be override by subclasses\n protected async saveChatHistory(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput,\n userRecordId: string,\n assistantRecordId: string,\n userContent: string,\n assistantContent: string\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history saving.`,\n type: \"warn\",\n },\n });\n return;\n }\n\n // Save message pair to history\n const userEntity = new ChatHistoryEntity();\n userEntity.recordId = userRecordId;\n userEntity.botId = botId;\n userEntity.role = \"user\";\n userEntity.content = userContent;\n userEntity.conversation = threadId;\n userEntity.reply = assistantRecordId;\n userEntity.triggerSrc = \"\";\n userEntity.traceId = randomUUID();\n\n await createChatHistory({ tcbClient, chatHistoryEntity: userEntity });\n\n const assistantEntity = new ChatHistoryEntity();\n assistantEntity.recordId = assistantRecordId;\n assistantEntity.botId = botId;\n assistantEntity.role = \"assistant\";\n assistantEntity.content = assistantContent;\n assistantEntity.conversation = threadId;\n assistantEntity.replyTo = userRecordId;\n assistantEntity.triggerSrc = \"\";\n assistantEntity.traceId = runId;\n assistantEntity.status = \"done\";\n\n await createChatHistory({\n tcbClient,\n chatHistoryEntity: assistantEntity,\n });\n }\n\n private getTcbClient() {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n\n const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\n });\n return tcbClient;\n }\n\n private async checkIsDatabaseReady() {\n try {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n if (!envId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, CLOUDBASE_ENV_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_CLOUDBASE_ENV_ID\"\n );\n }\n if (!this.finalCloudCredential.token) {\n if (!this.finalCloudCredential.secretId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_ID\"\n );\n }\n if (!this.finalCloudCredential.secretKey) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n const managedTcbClient = managedTcb.init({\n envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n token: this.finalCloudCredential.token,\n });\n\n const checkDBRes = await managedTcbClient.database.checkCollectionExists(\n CHAT_HISTORY_DATA_SOURCE\n );\n if (checkDBRes && checkDBRes.Exists) {\n return true;\n } else if (checkDBRes && !checkDBRes.Exists) {\n await managedTcbClient.database.createCollection(\n CHAT_HISTORY_DATA_SOURCE\n );\n return true;\n } else {\n throw new Error(\"Check database exists failed\");\n }\n } catch (dbError) {\n console.error(\n \"[ERROR] Failed to check/create chat history collection:\",\n JSON.stringify(dbError)\n );\n return false;\n }\n }\n}\n\nfunction getCloudbaseEnvId() {\n if (process.env.CBR_ENV_ID) {\n return process.env.CBR_ENV_ID;\n } else if (process.env.SCF_NAMESPACE) {\n return process.env.SCF_NAMESPACE;\n } else {\n return process.env.CLOUDBASE_ENV_ID || \"\";\n }\n}\n\n/**\n * Convert AGUI messages to OpenAI chat completion format\n */\nexport function convertMessagesToOpenAI(\n messages: Message[],\n systemPrompt?: string\n): ChatMessage[] {\n const openaiMessages: ChatMessage[] = [];\n\n // Add system prompt if provided\n if (systemPrompt) {\n openaiMessages.push({\n role: \"system\",\n content: systemPrompt,\n });\n }\n\n // Convert messages\n for (const msg of messages) {\n if (msg.role === \"user\") {\n openaiMessages.push({\n role: \"user\",\n content:\n typeof msg.content === \"string\"\n ? [{ type: \"text\", text: msg.content }]\n : msg.content.map((item) => {\n if (item.type === \"text\") {\n return { type: \"text\", text: item.text };\n } else {\n return {\n type: \"image_url\",\n image_url: { url: item.url || \"\" },\n };\n }\n }),\n });\n } else if (msg.role === \"assistant\") {\n openaiMessages.push({\n role: \"assistant\",\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n tool_calls: msg.toolCalls?.map((tc: ToolCall) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n })),\n });\n } else if (msg.role === \"tool\") {\n openaiMessages.push({\n role: \"tool\",\n tool_call_id: msg.toolCallId,\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n });\n }\n }\n\n return openaiMessages;\n}\n","/**\n * 将小驼峰字符串转换为下划线格式\n * 例如: \"userName\" -> \"user_name\"\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * 递归地将对象的所有小驼峰属性名转换为下划线格式\n */\nexport function camelToSnakeKeys<T>(obj: T): T {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => camelToSnakeKeys(item)) as T;\n }\n\n if (typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = camelToSnakeKeys(value);\n }\n return result as T;\n }\n\n return obj;\n}\n\nexport function genRandomStr(length: number): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let result = \"\";\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n","import OpenAI from \"openai\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface StreamContext {\n threadId: string;\n runId: string;\n messageId: string;\n}\n\nexport interface StreamState {\n hasStarted: boolean;\n fullContent: string;\n toolCallsMap: Map<string, { name: string; args: string }>;\n}\n\nexport type Delta =\n OpenAI.Chat.Completions.ChatCompletionChunk[\"choices\"][number][\"delta\"] & {\n reasoning_content?: string;\n };\n\nexport async function* processYuanqiStream(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n context: StreamContext\n) {\n const { threadId, runId, messageId } = context;\n const state: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n const reasoningState: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta as Delta;\n if (!delta) continue;\n\n if (delta.role === \"tool\") {\n const toolCallId = (delta as any).tool_call_id;\n if (toolCallId) {\n if (state.toolCallsMap.has(toolCallId)) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n state.toolCallsMap.delete(toolCallId);\n }\n yield {\n type: EventType.TOOL_CALL_RESULT,\n threadId,\n runId,\n toolCallId,\n content: delta.content || \"\",\n };\n }\n continue;\n }\n\n // Handle text content\n if (delta.content) {\n // End reasoning message if it was started\n if (reasoningState.hasStarted) {\n reasoningState.hasStarted = false;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (!state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n state.hasStarted = true;\n }\n\n state.fullContent += delta.content;\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.content,\n };\n }\n\n // Handle reasoning content\n if (delta.reasoning_content) {\n if (!reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_START,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n reasoningState.hasStarted = true;\n }\n\n reasoningState.fullContent += delta.reasoning_content;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.reasoning_content,\n };\n }\n\n // Handle tool calls\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n const toolCallId = toolCall.id || `tool_${toolCall.index}`;\n\n if (toolCall.function?.name) {\n // Tool call start\n yield {\n type: EventType.TOOL_CALL_START,\n threadId,\n runId,\n toolCallId,\n toolCallName: toolCall.function.name,\n };\n\n // If first chunk contains arguments, emit TOOL_CALL_ARGS event\n if (toolCall.function.arguments) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n\n state.toolCallsMap.set(toolCallId, {\n name: toolCall.function.name,\n args: toolCall.function.arguments || \"\",\n });\n } else if (toolCall.function?.arguments) {\n // Tool call arguments delta\n const existing = state.toolCallsMap.get(toolCallId);\n if (existing) {\n existing.args += toolCall.function.arguments;\n\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n }\n }\n }\n }\n\n // Emit TEXT_MESSAGE_END if we had text content\n if (state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n // Emit TOOL_CALL_END for all tool calls\n for (const [toolCallId] of state.toolCallsMap) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n }\n}\n","// 对话数据模型\nexport const CHAT_HISTORY_DATA_SOURCE = \"ai_bot_chat_history_5hobd2b\";\n","import tcb from \"@cloudbase/node-sdk\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { genRandomStr } from \"./utils\";\n\nfunction genRecordId(): string {\n return \"record-\" + genRandomStr(8);\n}\n\n// Create a new chat history record\nexport async function createChatHistory({\n tcbClient,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const recordId = chatHistoryEntity.recordId || genRecordId();\n const data = {\n record_id: recordId,\n bot_id: chatHistoryEntity.botId,\n role: chatHistoryEntity.role,\n content: chatHistoryEntity.content,\n sender: chatHistoryEntity.sender,\n conversation: chatHistoryEntity.conversation,\n type: chatHistoryEntity.type,\n image: chatHistoryEntity.image,\n trigger_src: chatHistoryEntity.triggerSrc,\n origin_msg: chatHistoryEntity.originMsg,\n reply_to: chatHistoryEntity.replyTo,\n reply: chatHistoryEntity.reply,\n trace_id: chatHistoryEntity.traceId,\n need_async_reply: chatHistoryEntity.needAsyncReply,\n async_reply: chatHistoryEntity.asyncReply,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n const db = tcbClient.database();\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n const result = await collection.add(data);\n\n // console.log(\n // `Create record: chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return recordId;\n } catch (error) {\n console.error(\"Failed to create chat history record, error:\", error);\n return undefined;\n }\n}\n\n// Update chat history by record ID\nexport async function updateChatHistoryByRecordId({\n tcbClient,\n recordId,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n recordId: string;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n const result = await collection\n .where({ record_id: _.eq(recordId) })\n .update({\n content: chatHistoryEntity.content,\n image: chatHistoryEntity.image,\n async_reply: chatHistoryEntity.asyncReply,\n recommend_questions: chatHistoryEntity.recommendQuestions,\n status: chatHistoryEntity.status,\n origin_msg: chatHistoryEntity.originMsg,\n updatedAt: Date.now(),\n });\n\n // console.log(\n // `Update record: recordId: ${recordId}, chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return chatHistoryEntity.recordId;\n } catch (error) {\n console.error(\"Failed to update chat history, error:\", error);\n return undefined;\n }\n}\n\n// Query chat history from database\nexport async function describeChatHistory({\n tcbClient,\n botId,\n sort,\n pageSize = 10,\n pageNumber = 1,\n conversation,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n sort: \"asc\" | \"desc\";\n pageSize?: number;\n pageNumber?: number;\n conversation?: string;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<[ChatHistoryEntity[], number]> {\n if (!sort || sort.length === 0) {\n sort = \"desc\";\n }\n\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n // Build where conditions\n const whereConditions: Record<string, unknown> = {\n bot_id: _.eq(botId),\n };\n\n // Add optional filters\n if (conversation) {\n whereConditions.conversation = _.eq(conversation);\n }\n\n if (startCreatedAt !== undefined) {\n whereConditions.createdAt = _.gt(startCreatedAt);\n }\n\n if (triggerSrc) {\n whereConditions.trigger_src = _.eq(triggerSrc);\n }\n\n // Calculate skip for pagination\n const skip = (pageNumber - 1) * pageSize;\n\n // Query records\n const result = await collection\n .where(whereConditions)\n .orderBy(\"createdAt\", sort)\n .skip(skip)\n .limit(pageSize)\n .get();\n\n // Get total count\n const countResult = await collection.where(whereConditions).count();\n const total = countResult.total || 0;\n\n const records = result?.data || [];\n\n const entityList: ChatHistoryEntity[] = records.map(\n (item: ChatHistoryData) => transDataToChatEntity(item)\n );\n\n return [entityList, total];\n } catch (error) {\n console.error(\"Failed to query chat history, error:\", error);\n return [[], 0];\n }\n}\n\n// Transform data to ChatHistoryEntity structure\nexport function transDataToChatEntity(\n item: ChatHistoryData\n): ChatHistoryEntity {\n if (!item) {\n return new ChatHistoryEntity();\n }\n const chatEntity: ChatHistoryEntity = new ChatHistoryEntity();\n chatEntity.botId = item.bot_id;\n chatEntity.recordId = item.record_id;\n chatEntity.role = item.role;\n chatEntity.status = item.status;\n chatEntity.content = item.content;\n chatEntity.sender = item.sender;\n chatEntity.conversation = item.conversation;\n chatEntity.type = item.type;\n chatEntity.triggerSrc = item.trigger_src;\n chatEntity.originMsg = item.origin_msg;\n chatEntity.replyTo = item.reply_to;\n chatEntity.reply = item.reply;\n chatEntity.traceId = item.trace_id;\n chatEntity.needAsyncReply = item.need_async_reply;\n chatEntity.asyncReply = item.async_reply;\n chatEntity.createdAt = item.createdAt;\n chatEntity.updatedAt = item.updatedAt;\n return chatEntity;\n}\n\n// Query history records for LLM, get the most recent 10 conversation pairs (20 records)\nexport async function queryForLLM({\n tcbClient,\n botId,\n pageSize = 10,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n pageSize?: number;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<{ role: string; content: string }[]> {\n if (startCreatedAt === undefined) {\n startCreatedAt = Date.now() - 24 * 60 * 60 * 1000;\n }\n const recordEntityList: ChatHistoryEntity[] = [];\n\n const [recordList] = await describeChatHistory({\n tcbClient,\n botId,\n sort: \"desc\",\n pageSize,\n startCreatedAt,\n triggerSrc,\n });\n recordEntityList.push(...recordList.reverse());\n\n const entityMap = new Map<string, ChatHistoryEntity>();\n recordEntityList\n .filter((item) => {\n if (item.needAsyncReply === true) {\n return !!item.asyncReply;\n } else {\n return !!item.content;\n }\n })\n .forEach((item) => {\n entityMap.set(item.recordId, item);\n });\n\n const result: { role: string; content: string }[] = [];\n /*\n 1. Strongly depends on database history data, model history data has role order requirements\n 2. Need to ensure that no matter what bug occurs, always get a complete and usable user + assistant pair, otherwise the request will fail\n */\n recordEntityList.forEach((item) => {\n const { role, content, reply } = item;\n // When calling LLM, empty content will cause failure, so filter out conversations with empty content\n if (role === \"user\" && content?.length !== 0) {\n if (entityMap.has(reply)) {\n result.push({ role, content });\n result.push({\n role: entityMap.get(reply)!.role,\n content: entityMap.get(reply)!.content,\n });\n }\n }\n });\n if (result.length % 2 === 1) {\n result.splice(-1, 1);\n }\n return result;\n}\n\nexport interface ChatHistoryData {\n bot_id: string;\n record_id: string;\n role: string;\n status: string;\n content: string;\n sender: string;\n conversation: string;\n type: string;\n trigger_src: string;\n origin_msg: string;\n reply_to: string;\n reply: string;\n trace_id: string;\n need_async_reply: boolean;\n async_reply: string;\n createdAt: number;\n updatedAt: number;\n}\n\nexport class ChatHistoryEntity {\n id: number;\n botId: string;\n // 对话唯一id\n recordId: string;\n role: string;\n content: string;\n recommendQuestions: string[];\n sender: string;\n conversation: string;\n type: string;\n /**\n * 消息状态,pending done error cancel\n */\n status: string;\n image: string;\n triggerSrc: string;\n originMsg: string;\n replyTo: string;\n reply: string;\n traceId: string;\n needAsyncReply: boolean;\n asyncReply: string;\n createTime: string;\n updateTime: string;\n createdAt: number;\n updatedAt: number;\n event: string;\n}\n"],"mappings":"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","names":["EventType","EventType"]}
|