@cloudbase/agent-adapter-yuanqi 1.0.1-alpha.14 → 1.0.1-alpha.16
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.d.mts +0 -9
- package/dist/index.d.ts +0 -9
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -128,15 +128,6 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
128
128
|
role?: undefined;
|
|
129
129
|
delta?: undefined;
|
|
130
130
|
toolCallName?: undefined;
|
|
131
|
-
} | {
|
|
132
|
-
type: EventType;
|
|
133
|
-
threadId: string;
|
|
134
|
-
runId: string;
|
|
135
|
-
messageId?: undefined;
|
|
136
|
-
role?: undefined;
|
|
137
|
-
delta?: undefined;
|
|
138
|
-
toolCallId?: undefined;
|
|
139
|
-
toolCallName?: undefined;
|
|
140
131
|
}, void, unknown>;
|
|
141
132
|
|
|
142
133
|
declare function createChatHistory({ tcbClient, chatHistoryEntity, }: {
|
package/dist/index.d.ts
CHANGED
|
@@ -128,15 +128,6 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
128
128
|
role?: undefined;
|
|
129
129
|
delta?: undefined;
|
|
130
130
|
toolCallName?: undefined;
|
|
131
|
-
} | {
|
|
132
|
-
type: EventType;
|
|
133
|
-
threadId: string;
|
|
134
|
-
runId: string;
|
|
135
|
-
messageId?: undefined;
|
|
136
|
-
role?: undefined;
|
|
137
|
-
delta?: undefined;
|
|
138
|
-
toolCallId?: undefined;
|
|
139
|
-
toolCallName?: undefined;
|
|
140
131
|
}, void, unknown>;
|
|
141
132
|
|
|
142
133
|
declare function createChatHistory({ tcbClient, chatHistoryEntity, }: {
|
package/dist/index.js
CHANGED
|
@@ -205,11 +205,6 @@ async function* processYuanqiStream(stream, context) {
|
|
|
205
205
|
toolCallId
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
|
-
yield {
|
|
209
|
-
type: import_client.EventType.RUN_FINISHED,
|
|
210
|
-
threadId,
|
|
211
|
-
runId
|
|
212
|
-
};
|
|
213
208
|
}
|
|
214
209
|
|
|
215
210
|
// src/agent.ts
|
|
@@ -522,6 +517,11 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
522
517
|
userContent,
|
|
523
518
|
fullAssistantContent
|
|
524
519
|
);
|
|
520
|
+
subscriber.next({
|
|
521
|
+
type: import_client2.EventType.RUN_FINISHED,
|
|
522
|
+
threadId,
|
|
523
|
+
runId
|
|
524
|
+
});
|
|
525
525
|
} catch (e) {
|
|
526
526
|
console.error(JSON.stringify(e));
|
|
527
527
|
let code = "UNKNOWN_ERROR";
|
|
@@ -555,7 +555,7 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
555
555
|
type: "warn"
|
|
556
556
|
}
|
|
557
557
|
});
|
|
558
|
-
return [];
|
|
558
|
+
return convertMessagesToOpenAI([latestUserMessage]);
|
|
559
559
|
}
|
|
560
560
|
const tcbClient = import_node_sdk.default.init({
|
|
561
561
|
env: envId,
|
|
@@ -651,7 +651,8 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
651
651
|
const managedTcbClient = import_manager_node.default.init({
|
|
652
652
|
envId,
|
|
653
653
|
secretId: this.finalCloudCredential.secretId,
|
|
654
|
-
secretKey: this.finalCloudCredential.secretKey
|
|
654
|
+
secretKey: this.finalCloudCredential.secretKey,
|
|
655
|
+
token: this.finalCloudCredential.token
|
|
655
656
|
});
|
|
656
657
|
const checkDBRes = await managedTcbClient.database.checkCollectionExists(
|
|
657
658
|
CHAT_HISTORY_DATA_SOURCE
|
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} 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(subscriber: any, input: RunAgentInput): Promise<void> {\n try {\n const { messages, runId, threadId: _threadId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = _threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n });\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 any).delta\n ) {\n fullAssistantContent += (event as any).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 as any).text)\n .join(\"\") || \"\";\n\n await this.saveChatHistory(\n subscriber,\n input,\n userRecordId,\n assistantRecordId,\n userContent,\n fullAssistantContent\n );\n } catch (e: unknown) {\n console.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 any);\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 envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const isDBReady = await this.checkIsDatabaseReady(envId);\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 [];\n }\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\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 envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const isDBReady = await this.checkIsDatabaseReady(envId);\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 const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\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 async checkIsDatabaseReady(envId: string) {\n if (!envId) {\n throw new YuanqiAgentError(\n \"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 \"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 \"TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n\n try {\n const managedTcbClient = managedTcb.init({\n envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\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 }\n } catch (dbError) {\n console.error(\n \"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): OpenAI.Chat.ChatCompletionMessageParam[] {\n const openaiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [];\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: any) => ({\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 // 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 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 // 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 // Emit RUN_FINISHED\n yield {\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\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 donw 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} 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(subscriber: any, input: RunAgentInput): Promise<void> {\n try {\n const { messages, runId, threadId: _threadId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = _threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n });\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 any).delta\n ) {\n fullAssistantContent += (event as any).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 as any).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 any);\n } catch (e: unknown) {\n console.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 any);\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 envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const isDBReady = await this.checkIsDatabaseReady(envId);\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 const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\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 envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const isDBReady = await this.checkIsDatabaseReady(envId);\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 const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\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 async checkIsDatabaseReady(envId: string) {\n if (!envId) {\n throw new YuanqiAgentError(\n \"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 \"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 \"TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n\n try {\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 }\n } catch (dbError) {\n console.error(\n \"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): OpenAI.Chat.ChatCompletionMessageParam[] {\n const openaiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [];\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: any) => ({\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 // 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 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 // 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 donw 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
|
@@ -163,11 +163,6 @@ async function* processYuanqiStream(stream, context) {
|
|
|
163
163
|
toolCallId
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
|
-
yield {
|
|
167
|
-
type: EventType.RUN_FINISHED,
|
|
168
|
-
threadId,
|
|
169
|
-
runId
|
|
170
|
-
};
|
|
171
166
|
}
|
|
172
167
|
|
|
173
168
|
// src/agent.ts
|
|
@@ -480,6 +475,11 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
480
475
|
userContent,
|
|
481
476
|
fullAssistantContent
|
|
482
477
|
);
|
|
478
|
+
subscriber.next({
|
|
479
|
+
type: EventType2.RUN_FINISHED,
|
|
480
|
+
threadId,
|
|
481
|
+
runId
|
|
482
|
+
});
|
|
483
483
|
} catch (e) {
|
|
484
484
|
console.error(JSON.stringify(e));
|
|
485
485
|
let code = "UNKNOWN_ERROR";
|
|
@@ -513,7 +513,7 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
513
513
|
type: "warn"
|
|
514
514
|
}
|
|
515
515
|
});
|
|
516
|
-
return [];
|
|
516
|
+
return convertMessagesToOpenAI([latestUserMessage]);
|
|
517
517
|
}
|
|
518
518
|
const tcbClient = tcb.init({
|
|
519
519
|
env: envId,
|
|
@@ -609,7 +609,8 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
609
609
|
const managedTcbClient = managedTcb.init({
|
|
610
610
|
envId,
|
|
611
611
|
secretId: this.finalCloudCredential.secretId,
|
|
612
|
-
secretKey: this.finalCloudCredential.secretKey
|
|
612
|
+
secretKey: this.finalCloudCredential.secretKey,
|
|
613
|
+
token: this.finalCloudCredential.token
|
|
613
614
|
});
|
|
614
615
|
const checkDBRes = await managedTcbClient.database.checkCollectionExists(
|
|
615
616
|
CHAT_HISTORY_DATA_SOURCE
|
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} 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(subscriber: any, input: RunAgentInput): Promise<void> {\n try {\n const { messages, runId, threadId: _threadId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = _threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n });\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 any).delta\n ) {\n fullAssistantContent += (event as any).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 as any).text)\n .join(\"\") || \"\";\n\n await this.saveChatHistory(\n subscriber,\n input,\n userRecordId,\n assistantRecordId,\n userContent,\n fullAssistantContent\n );\n } catch (e: unknown) {\n console.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 any);\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 envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const isDBReady = await this.checkIsDatabaseReady(envId);\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 [];\n }\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\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 envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const isDBReady = await this.checkIsDatabaseReady(envId);\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 const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\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 async checkIsDatabaseReady(envId: string) {\n if (!envId) {\n throw new YuanqiAgentError(\n \"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 \"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 \"TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n\n try {\n const managedTcbClient = managedTcb.init({\n envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\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 }\n } catch (dbError) {\n console.error(\n \"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): OpenAI.Chat.ChatCompletionMessageParam[] {\n const openaiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [];\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: any) => ({\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 // 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 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 // 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 // Emit RUN_FINISHED\n yield {\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\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 donw 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} 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(subscriber: any, input: RunAgentInput): Promise<void> {\n try {\n const { messages, runId, threadId: _threadId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = _threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n });\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 any).delta\n ) {\n fullAssistantContent += (event as any).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 as any).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 any);\n } catch (e: unknown) {\n console.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 any);\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 envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const isDBReady = await this.checkIsDatabaseReady(envId);\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 const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\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 envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const isDBReady = await this.checkIsDatabaseReady(envId);\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 const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\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 async checkIsDatabaseReady(envId: string) {\n if (!envId) {\n throw new YuanqiAgentError(\n \"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 \"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 \"TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n\n try {\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 }\n } catch (dbError) {\n console.error(\n \"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): OpenAI.Chat.ChatCompletionMessageParam[] {\n const openaiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [];\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: any) => ({\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 // 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 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 // 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 donw 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"]}
|