@cloudbase/agent-adapter-yuanqi 1.0.1-alpha.23 → 1.0.1-alpha.25
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/README.md +72 -4
- package/dist/index.d.mts +31 -14
- package/dist/index.d.ts +31 -14
- package/dist/index.js +86 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +86 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -238,17 +238,53 @@ Entity class for chat history records stored in CloudBase.
|
|
|
238
238
|
class ChatHistoryEntity {
|
|
239
239
|
id: number;
|
|
240
240
|
botId: string;
|
|
241
|
-
recordId: string;
|
|
242
|
-
role: string;
|
|
241
|
+
recordId: string; // Unique conversation ID
|
|
242
|
+
role: string; // "user" or "assistant"
|
|
243
243
|
content: string;
|
|
244
|
-
|
|
244
|
+
recommendQuestions: string[];
|
|
245
|
+
sender: string;
|
|
245
246
|
conversation: string;
|
|
247
|
+
type: string;
|
|
248
|
+
status: string; // Message status: pending, done, error, cancel
|
|
249
|
+
image: string;
|
|
250
|
+
triggerSrc: string;
|
|
251
|
+
originMsg: string;
|
|
246
252
|
replyTo: string;
|
|
247
253
|
reply: string;
|
|
248
254
|
traceId: string;
|
|
255
|
+
needAsyncReply: boolean;
|
|
256
|
+
asyncReply: string;
|
|
257
|
+
createTime: string;
|
|
258
|
+
updateTime: string;
|
|
259
|
+
createdAt: number;
|
|
260
|
+
updatedAt: number;
|
|
261
|
+
event: string;
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### ChatHistoryData
|
|
266
|
+
|
|
267
|
+
Interface for raw chat history data from CloudBase database.
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
interface ChatHistoryData {
|
|
271
|
+
bot_id: string;
|
|
272
|
+
record_id: string;
|
|
273
|
+
role: string;
|
|
274
|
+
status: string;
|
|
275
|
+
content: string;
|
|
276
|
+
sender: string;
|
|
277
|
+
conversation: string;
|
|
278
|
+
type: string;
|
|
279
|
+
trigger_src: string;
|
|
280
|
+
origin_msg: string;
|
|
281
|
+
reply_to: string;
|
|
282
|
+
reply: string;
|
|
283
|
+
trace_id: string;
|
|
284
|
+
need_async_reply: boolean;
|
|
285
|
+
async_reply: string;
|
|
249
286
|
createdAt: number;
|
|
250
287
|
updatedAt: number;
|
|
251
|
-
// ... additional fields
|
|
252
288
|
}
|
|
253
289
|
```
|
|
254
290
|
|
|
@@ -263,6 +299,28 @@ function createChatHistory(params: {
|
|
|
263
299
|
chatHistoryEntity: ChatHistoryEntity;
|
|
264
300
|
}): Promise<string | undefined>
|
|
265
301
|
|
|
302
|
+
// Update chat history by record ID
|
|
303
|
+
function updateChatHistoryByRecordId(params: {
|
|
304
|
+
tcbClient: tcb.CloudBase;
|
|
305
|
+
recordId: string;
|
|
306
|
+
chatHistoryEntity: ChatHistoryEntity;
|
|
307
|
+
}): Promise<string | undefined>
|
|
308
|
+
|
|
309
|
+
// Query chat history from database (paginated)
|
|
310
|
+
function describeChatHistory(params: {
|
|
311
|
+
tcbClient: tcb.CloudBase;
|
|
312
|
+
botId: string;
|
|
313
|
+
sort: "asc" | "desc";
|
|
314
|
+
pageSize?: number;
|
|
315
|
+
pageNumber?: number;
|
|
316
|
+
conversation?: string;
|
|
317
|
+
startCreatedAt?: number;
|
|
318
|
+
triggerSrc?: string;
|
|
319
|
+
}): Promise<[ChatHistoryEntity[], number]>
|
|
320
|
+
|
|
321
|
+
// Transform raw database data to ChatHistoryEntity
|
|
322
|
+
function transDataToChatEntity(item: ChatHistoryData): ChatHistoryEntity
|
|
323
|
+
|
|
266
324
|
// Query chat history for LLM context
|
|
267
325
|
function queryForLLM(params: {
|
|
268
326
|
tcbClient: tcb.CloudBase;
|
|
@@ -273,6 +331,16 @@ function queryForLLM(params: {
|
|
|
273
331
|
}): Promise<{ role: string; content: string }[]>
|
|
274
332
|
```
|
|
275
333
|
|
|
334
|
+
### Message Conversion Utility
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
// Convert AG-UI messages to OpenAI chat completion format
|
|
338
|
+
function convertMessagesToOpenAI(
|
|
339
|
+
messages: Message[],
|
|
340
|
+
systemPrompt?: string
|
|
341
|
+
): ChatMessage[]
|
|
342
|
+
```
|
|
343
|
+
|
|
276
344
|
### Supported Events
|
|
277
345
|
|
|
278
346
|
The adapter emits the following AG-UI events:
|
package/dist/index.d.mts
CHANGED
|
@@ -51,12 +51,13 @@ declare class YuanqiAgent extends AbstractAgent {
|
|
|
51
51
|
private _run;
|
|
52
52
|
protected getChatHistory(subscriber: Subscriber<BaseEvent>, latestUserMessage: Message): Promise<OpenAI.Chat.Completions.ChatCompletionMessageParam[]>;
|
|
53
53
|
protected saveChatHistory(subscriber: Subscriber<BaseEvent>, input: RunAgentInput, userRecordId: string, assistantRecordId: string, userContent: string, assistantContent: string): Promise<void>;
|
|
54
|
+
private getTcbClient;
|
|
54
55
|
private checkIsDatabaseReady;
|
|
55
56
|
}
|
|
56
57
|
/**
|
|
57
58
|
* Convert AGUI messages to OpenAI chat completion format
|
|
58
59
|
*/
|
|
59
|
-
declare function convertMessagesToOpenAI(messages: Message[], systemPrompt?: string):
|
|
60
|
+
declare function convertMessagesToOpenAI(messages: Message[], systemPrompt?: string): ChatMessage[];
|
|
60
61
|
|
|
61
62
|
interface StreamContext {
|
|
62
63
|
threadId: string;
|
|
@@ -78,10 +79,31 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
78
79
|
type: EventType;
|
|
79
80
|
threadId: string;
|
|
80
81
|
runId: string;
|
|
81
|
-
|
|
82
|
+
toolCallId: any;
|
|
83
|
+
content?: undefined;
|
|
84
|
+
messageId?: undefined;
|
|
85
|
+
role?: undefined;
|
|
86
|
+
delta?: undefined;
|
|
87
|
+
toolCallName?: undefined;
|
|
88
|
+
} | {
|
|
89
|
+
type: EventType;
|
|
90
|
+
threadId: string;
|
|
91
|
+
runId: string;
|
|
92
|
+
toolCallId: any;
|
|
93
|
+
content: string;
|
|
94
|
+
messageId?: undefined;
|
|
82
95
|
role?: undefined;
|
|
83
96
|
delta?: undefined;
|
|
97
|
+
toolCallName?: undefined;
|
|
98
|
+
} | {
|
|
99
|
+
type: EventType;
|
|
100
|
+
threadId: string;
|
|
101
|
+
runId: string;
|
|
102
|
+
messageId: string;
|
|
84
103
|
toolCallId?: undefined;
|
|
104
|
+
content?: undefined;
|
|
105
|
+
role?: undefined;
|
|
106
|
+
delta?: undefined;
|
|
85
107
|
toolCallName?: undefined;
|
|
86
108
|
} | {
|
|
87
109
|
type: EventType;
|
|
@@ -89,8 +111,9 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
89
111
|
runId: string;
|
|
90
112
|
messageId: string;
|
|
91
113
|
role: string;
|
|
92
|
-
delta?: undefined;
|
|
93
114
|
toolCallId?: undefined;
|
|
115
|
+
content?: undefined;
|
|
116
|
+
delta?: undefined;
|
|
94
117
|
toolCallName?: undefined;
|
|
95
118
|
} | {
|
|
96
119
|
type: EventType;
|
|
@@ -98,8 +121,9 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
98
121
|
runId: string;
|
|
99
122
|
messageId: string;
|
|
100
123
|
delta: string;
|
|
101
|
-
role?: undefined;
|
|
102
124
|
toolCallId?: undefined;
|
|
125
|
+
content?: undefined;
|
|
126
|
+
role?: undefined;
|
|
103
127
|
toolCallName?: undefined;
|
|
104
128
|
} | {
|
|
105
129
|
type: EventType;
|
|
@@ -107,6 +131,7 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
107
131
|
runId: string;
|
|
108
132
|
toolCallId: string;
|
|
109
133
|
toolCallName: string;
|
|
134
|
+
content?: undefined;
|
|
110
135
|
messageId?: undefined;
|
|
111
136
|
role?: undefined;
|
|
112
137
|
delta?: undefined;
|
|
@@ -116,18 +141,10 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
116
141
|
runId: string;
|
|
117
142
|
toolCallId: string;
|
|
118
143
|
delta: string;
|
|
144
|
+
content?: undefined;
|
|
119
145
|
messageId?: undefined;
|
|
120
146
|
role?: undefined;
|
|
121
147
|
toolCallName?: undefined;
|
|
122
|
-
} | {
|
|
123
|
-
type: EventType;
|
|
124
|
-
threadId: string;
|
|
125
|
-
runId: string;
|
|
126
|
-
toolCallId: string;
|
|
127
|
-
messageId?: undefined;
|
|
128
|
-
role?: undefined;
|
|
129
|
-
delta?: undefined;
|
|
130
|
-
toolCallName?: undefined;
|
|
131
148
|
}, void, unknown>;
|
|
132
149
|
|
|
133
150
|
declare function createChatHistory({ tcbClient, chatHistoryEntity, }: {
|
|
@@ -190,7 +207,7 @@ declare class ChatHistoryEntity {
|
|
|
190
207
|
conversation: string;
|
|
191
208
|
type: string;
|
|
192
209
|
/**
|
|
193
|
-
* 消息状态,pending
|
|
210
|
+
* 消息状态,pending done error cancel
|
|
194
211
|
*/
|
|
195
212
|
status: string;
|
|
196
213
|
image: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -51,12 +51,13 @@ declare class YuanqiAgent extends AbstractAgent {
|
|
|
51
51
|
private _run;
|
|
52
52
|
protected getChatHistory(subscriber: Subscriber<BaseEvent>, latestUserMessage: Message): Promise<OpenAI.Chat.Completions.ChatCompletionMessageParam[]>;
|
|
53
53
|
protected saveChatHistory(subscriber: Subscriber<BaseEvent>, input: RunAgentInput, userRecordId: string, assistantRecordId: string, userContent: string, assistantContent: string): Promise<void>;
|
|
54
|
+
private getTcbClient;
|
|
54
55
|
private checkIsDatabaseReady;
|
|
55
56
|
}
|
|
56
57
|
/**
|
|
57
58
|
* Convert AGUI messages to OpenAI chat completion format
|
|
58
59
|
*/
|
|
59
|
-
declare function convertMessagesToOpenAI(messages: Message[], systemPrompt?: string):
|
|
60
|
+
declare function convertMessagesToOpenAI(messages: Message[], systemPrompt?: string): ChatMessage[];
|
|
60
61
|
|
|
61
62
|
interface StreamContext {
|
|
62
63
|
threadId: string;
|
|
@@ -78,10 +79,31 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
78
79
|
type: EventType;
|
|
79
80
|
threadId: string;
|
|
80
81
|
runId: string;
|
|
81
|
-
|
|
82
|
+
toolCallId: any;
|
|
83
|
+
content?: undefined;
|
|
84
|
+
messageId?: undefined;
|
|
85
|
+
role?: undefined;
|
|
86
|
+
delta?: undefined;
|
|
87
|
+
toolCallName?: undefined;
|
|
88
|
+
} | {
|
|
89
|
+
type: EventType;
|
|
90
|
+
threadId: string;
|
|
91
|
+
runId: string;
|
|
92
|
+
toolCallId: any;
|
|
93
|
+
content: string;
|
|
94
|
+
messageId?: undefined;
|
|
82
95
|
role?: undefined;
|
|
83
96
|
delta?: undefined;
|
|
97
|
+
toolCallName?: undefined;
|
|
98
|
+
} | {
|
|
99
|
+
type: EventType;
|
|
100
|
+
threadId: string;
|
|
101
|
+
runId: string;
|
|
102
|
+
messageId: string;
|
|
84
103
|
toolCallId?: undefined;
|
|
104
|
+
content?: undefined;
|
|
105
|
+
role?: undefined;
|
|
106
|
+
delta?: undefined;
|
|
85
107
|
toolCallName?: undefined;
|
|
86
108
|
} | {
|
|
87
109
|
type: EventType;
|
|
@@ -89,8 +111,9 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
89
111
|
runId: string;
|
|
90
112
|
messageId: string;
|
|
91
113
|
role: string;
|
|
92
|
-
delta?: undefined;
|
|
93
114
|
toolCallId?: undefined;
|
|
115
|
+
content?: undefined;
|
|
116
|
+
delta?: undefined;
|
|
94
117
|
toolCallName?: undefined;
|
|
95
118
|
} | {
|
|
96
119
|
type: EventType;
|
|
@@ -98,8 +121,9 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
98
121
|
runId: string;
|
|
99
122
|
messageId: string;
|
|
100
123
|
delta: string;
|
|
101
|
-
role?: undefined;
|
|
102
124
|
toolCallId?: undefined;
|
|
125
|
+
content?: undefined;
|
|
126
|
+
role?: undefined;
|
|
103
127
|
toolCallName?: undefined;
|
|
104
128
|
} | {
|
|
105
129
|
type: EventType;
|
|
@@ -107,6 +131,7 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
107
131
|
runId: string;
|
|
108
132
|
toolCallId: string;
|
|
109
133
|
toolCallName: string;
|
|
134
|
+
content?: undefined;
|
|
110
135
|
messageId?: undefined;
|
|
111
136
|
role?: undefined;
|
|
112
137
|
delta?: undefined;
|
|
@@ -116,18 +141,10 @@ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completio
|
|
|
116
141
|
runId: string;
|
|
117
142
|
toolCallId: string;
|
|
118
143
|
delta: string;
|
|
144
|
+
content?: undefined;
|
|
119
145
|
messageId?: undefined;
|
|
120
146
|
role?: undefined;
|
|
121
147
|
toolCallName?: undefined;
|
|
122
|
-
} | {
|
|
123
|
-
type: EventType;
|
|
124
|
-
threadId: string;
|
|
125
|
-
runId: string;
|
|
126
|
-
toolCallId: string;
|
|
127
|
-
messageId?: undefined;
|
|
128
|
-
role?: undefined;
|
|
129
|
-
delta?: undefined;
|
|
130
|
-
toolCallName?: undefined;
|
|
131
148
|
}, void, unknown>;
|
|
132
149
|
|
|
133
150
|
declare function createChatHistory({ tcbClient, chatHistoryEntity, }: {
|
|
@@ -190,7 +207,7 @@ declare class ChatHistoryEntity {
|
|
|
190
207
|
conversation: string;
|
|
191
208
|
type: string;
|
|
192
209
|
/**
|
|
193
|
-
* 消息状态,pending
|
|
210
|
+
* 消息状态,pending done error cancel
|
|
194
211
|
*/
|
|
195
212
|
status: string;
|
|
196
213
|
image: string;
|
package/dist/index.js
CHANGED
|
@@ -97,6 +97,28 @@ async function* processYuanqiStream(stream, context) {
|
|
|
97
97
|
for await (const chunk of stream) {
|
|
98
98
|
const delta = chunk.choices[0]?.delta;
|
|
99
99
|
if (!delta) continue;
|
|
100
|
+
if (delta.role === "tool") {
|
|
101
|
+
const toolCallId = delta.tool_call_id;
|
|
102
|
+
if (toolCallId) {
|
|
103
|
+
if (state.toolCallsMap.has(toolCallId)) {
|
|
104
|
+
yield {
|
|
105
|
+
type: import_client.EventType.TOOL_CALL_END,
|
|
106
|
+
threadId,
|
|
107
|
+
runId,
|
|
108
|
+
toolCallId
|
|
109
|
+
};
|
|
110
|
+
state.toolCallsMap.delete(toolCallId);
|
|
111
|
+
}
|
|
112
|
+
yield {
|
|
113
|
+
type: import_client.EventType.TOOL_CALL_RESULT,
|
|
114
|
+
threadId,
|
|
115
|
+
runId,
|
|
116
|
+
toolCallId,
|
|
117
|
+
content: delta.content || ""
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
100
122
|
if (delta.content) {
|
|
101
123
|
if (reasoningState.hasStarted) {
|
|
102
124
|
reasoningState.hasStarted = false;
|
|
@@ -169,6 +191,15 @@ async function* processYuanqiStream(stream, context) {
|
|
|
169
191
|
toolCallId,
|
|
170
192
|
toolCallName: toolCall.function.name
|
|
171
193
|
};
|
|
194
|
+
if (toolCall.function.arguments) {
|
|
195
|
+
yield {
|
|
196
|
+
type: import_client.EventType.TOOL_CALL_ARGS,
|
|
197
|
+
threadId,
|
|
198
|
+
runId,
|
|
199
|
+
toolCallId,
|
|
200
|
+
delta: toolCall.function.arguments
|
|
201
|
+
};
|
|
202
|
+
}
|
|
172
203
|
state.toolCallsMap.set(toolCallId, {
|
|
173
204
|
name: toolCall.function.name,
|
|
174
205
|
args: toolCall.function.arguments || ""
|
|
@@ -197,6 +228,20 @@ async function* processYuanqiStream(stream, context) {
|
|
|
197
228
|
messageId
|
|
198
229
|
};
|
|
199
230
|
}
|
|
231
|
+
if (reasoningState.hasStarted) {
|
|
232
|
+
yield {
|
|
233
|
+
type: import_client.EventType.THINKING_TEXT_MESSAGE_END,
|
|
234
|
+
threadId,
|
|
235
|
+
runId,
|
|
236
|
+
messageId
|
|
237
|
+
};
|
|
238
|
+
yield {
|
|
239
|
+
type: import_client.EventType.THINKING_END,
|
|
240
|
+
threadId,
|
|
241
|
+
runId,
|
|
242
|
+
messageId
|
|
243
|
+
};
|
|
244
|
+
}
|
|
200
245
|
for (const [toolCallId] of state.toolCallsMap) {
|
|
201
246
|
yield {
|
|
202
247
|
type: import_client.EventType.TOOL_CALL_END,
|
|
@@ -439,9 +484,9 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
439
484
|
}
|
|
440
485
|
async _run(subscriber, input) {
|
|
441
486
|
try {
|
|
442
|
-
const { messages, runId
|
|
487
|
+
const { messages, runId } = input;
|
|
443
488
|
const openai = this.model;
|
|
444
|
-
const threadId =
|
|
489
|
+
const threadId = input.threadId || (0, import_crypto.randomUUID)();
|
|
445
490
|
subscriber.next({
|
|
446
491
|
type: import_client2.EventType.RUN_STARTED,
|
|
447
492
|
threadId,
|
|
@@ -523,7 +568,7 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
523
568
|
runId
|
|
524
569
|
});
|
|
525
570
|
} catch (e) {
|
|
526
|
-
console.error(JSON.stringify(e));
|
|
571
|
+
console.error("[ERROR] Uncaught error: ", JSON.stringify(e));
|
|
527
572
|
let code = "UNKNOWN_ERROR";
|
|
528
573
|
let message = JSON.stringify(e);
|
|
529
574
|
if (e instanceof YuanqiAgentError) {
|
|
@@ -544,9 +589,9 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
544
589
|
}
|
|
545
590
|
// Can be override by subclasses
|
|
546
591
|
async getChatHistory(subscriber, latestUserMessage) {
|
|
547
|
-
const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();
|
|
548
592
|
const botId = `bot-yuanqi-${this.finalAppId}`;
|
|
549
|
-
const
|
|
593
|
+
const tcbClient = this.getTcbClient();
|
|
594
|
+
const isDBReady = await this.checkIsDatabaseReady();
|
|
550
595
|
if (!isDBReady) {
|
|
551
596
|
subscriber.next({
|
|
552
597
|
type: import_client2.EventType.RAW,
|
|
@@ -557,12 +602,6 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
557
602
|
});
|
|
558
603
|
return convertMessagesToOpenAI([latestUserMessage]);
|
|
559
604
|
}
|
|
560
|
-
const tcbClient = import_node_sdk.default.init({
|
|
561
|
-
env: envId,
|
|
562
|
-
secretId: this.finalCloudCredential.secretId,
|
|
563
|
-
secretKey: this.finalCloudCredential.secretKey,
|
|
564
|
-
sessionToken: this.finalCloudCredential.token
|
|
565
|
-
});
|
|
566
605
|
let historyMessages = [];
|
|
567
606
|
const historyCount = this.yuanqiConfig.historyCount ?? 10;
|
|
568
607
|
const historyRecords = await queryForLLM({
|
|
@@ -581,10 +620,10 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
581
620
|
}
|
|
582
621
|
// Can be override by subclasses
|
|
583
622
|
async saveChatHistory(subscriber, input, userRecordId, assistantRecordId, userContent, assistantContent) {
|
|
584
|
-
const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();
|
|
585
623
|
const botId = `bot-yuanqi-${this.finalAppId}`;
|
|
586
624
|
const { threadId, runId } = input;
|
|
587
|
-
const
|
|
625
|
+
const tcbClient = this.getTcbClient();
|
|
626
|
+
const isDBReady = await this.checkIsDatabaseReady();
|
|
588
627
|
if (!isDBReady) {
|
|
589
628
|
subscriber.next({
|
|
590
629
|
type: import_client2.EventType.RAW,
|
|
@@ -595,12 +634,6 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
595
634
|
});
|
|
596
635
|
return;
|
|
597
636
|
}
|
|
598
|
-
const tcbClient = import_node_sdk.default.init({
|
|
599
|
-
env: envId,
|
|
600
|
-
secretId: this.finalCloudCredential.secretId,
|
|
601
|
-
secretKey: this.finalCloudCredential.secretKey,
|
|
602
|
-
sessionToken: this.finalCloudCredential.token
|
|
603
|
-
});
|
|
604
637
|
const userEntity = new ChatHistoryEntity();
|
|
605
638
|
userEntity.recordId = userRecordId;
|
|
606
639
|
userEntity.botId = botId;
|
|
@@ -626,28 +659,39 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
626
659
|
chatHistoryEntity: assistantEntity
|
|
627
660
|
});
|
|
628
661
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
662
|
+
getTcbClient() {
|
|
663
|
+
const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();
|
|
664
|
+
const tcbClient = import_node_sdk.default.init({
|
|
665
|
+
env: envId,
|
|
666
|
+
secretId: this.finalCloudCredential.secretId,
|
|
667
|
+
secretKey: this.finalCloudCredential.secretKey,
|
|
668
|
+
sessionToken: this.finalCloudCredential.token
|
|
669
|
+
});
|
|
670
|
+
return tcbClient;
|
|
671
|
+
}
|
|
672
|
+
async checkIsDatabaseReady() {
|
|
673
|
+
try {
|
|
674
|
+
const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();
|
|
675
|
+
if (!envId) {
|
|
638
676
|
throw new YuanqiAgentError(
|
|
639
|
-
"
|
|
640
|
-
"
|
|
677
|
+
"When saving chat history to CloudBase, CLOUDBASE_ENV_ID is required, check your env variables or config passed with the adapter",
|
|
678
|
+
"MISSING_CLOUDBASE_ENV_ID"
|
|
641
679
|
);
|
|
642
680
|
}
|
|
643
|
-
if (!this.finalCloudCredential.
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
681
|
+
if (!this.finalCloudCredential.token) {
|
|
682
|
+
if (!this.finalCloudCredential.secretId) {
|
|
683
|
+
throw new YuanqiAgentError(
|
|
684
|
+
"When saving chat history to CloudBase, TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter",
|
|
685
|
+
"MISSING_SECRET_ID"
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
if (!this.finalCloudCredential.secretKey) {
|
|
689
|
+
throw new YuanqiAgentError(
|
|
690
|
+
"When saving chat history to CloudBase, TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter",
|
|
691
|
+
"MISSING_SECRET_KEY"
|
|
692
|
+
);
|
|
693
|
+
}
|
|
648
694
|
}
|
|
649
|
-
}
|
|
650
|
-
try {
|
|
651
695
|
const managedTcbClient = import_manager_node.default.init({
|
|
652
696
|
envId,
|
|
653
697
|
secretId: this.finalCloudCredential.secretId,
|
|
@@ -664,10 +708,12 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
664
708
|
CHAT_HISTORY_DATA_SOURCE
|
|
665
709
|
);
|
|
666
710
|
return true;
|
|
711
|
+
} else {
|
|
712
|
+
throw new Error("Check database exists failed");
|
|
667
713
|
}
|
|
668
714
|
} catch (dbError) {
|
|
669
715
|
console.error(
|
|
670
|
-
"Failed to check/create chat history collection:",
|
|
716
|
+
"[ERROR] Failed to check/create chat history collection:",
|
|
671
717
|
JSON.stringify(dbError)
|
|
672
718
|
);
|
|
673
719
|
return false;
|
|
@@ -675,9 +721,9 @@ var YuanqiAgent = class extends import_client2.AbstractAgent {
|
|
|
675
721
|
}
|
|
676
722
|
};
|
|
677
723
|
function getCloudbaseEnvId() {
|
|
678
|
-
if (
|
|
724
|
+
if (process.env.CBR_ENV_ID) {
|
|
679
725
|
return process.env.CBR_ENV_ID;
|
|
680
|
-
} else if (
|
|
726
|
+
} else if (process.env.SCF_NAMESPACE) {
|
|
681
727
|
return process.env.SCF_NAMESPACE;
|
|
682
728
|
} else {
|
|
683
729
|
return process.env.CLOUDBASE_ENV_ID || "";
|
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\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/utils.ts","../src/stream.ts","../src/constant.ts","../src/chat_history.ts"],"sourcesContent":["export * from \"./agent\";\n\nexport * from \"./types\";\n\nexport * from \"./stream\";\n\nexport * from \"./chat_history\";\n","import {\n RunAgentInput,\n Message,\n AbstractAgent,\n AgentConfig,\n BaseEvent,\n EventType,\n RunStartedEvent,\n RunFinishedEvent,\n RunErrorEvent,\n TextMessageContentEvent,\n ToolCall,\n} from \"@ag-ui/client\";\nimport tcb from \"@cloudbase/node-sdk\";\nimport managedTcb from \"@cloudbase/manager-node\";\nimport OpenAI from \"openai\";\nimport { randomUUID } from \"crypto\";\nimport { camelToSnakeKeys } from \"./utils\";\nimport { processYuanqiStream } from \"./stream\";\nimport { Observable, Subscriber } from \"rxjs\";\nimport {\n createChatHistory,\n queryForLLM,\n ChatHistoryEntity,\n} from \"./chat_history\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { YuanqiConfig, ChatMessage, YuanqiChatRequest } from \"./types\";\n\nexport class YuanqiAgentError extends Error {\n code?: string;\n constructor(message: string, code?: string) {\n super(message);\n this.name = \"YuanqiAgentError\";\n if (code) this.code = code;\n }\n}\n\nexport class YuanqiAgent extends AbstractAgent {\n protected yuanqiConfig: YuanqiConfig;\n private finalAppId: string;\n private finalCloudCredential: {\n secretId?: string;\n secretKey?: string;\n token?: string;\n } = {};\n private model: OpenAI;\n constructor(config: AgentConfig & { yuanqiConfig: YuanqiConfig }) {\n super(config);\n this.yuanqiConfig = config.yuanqiConfig;\n this.model = new OpenAI({\n apiKey: \"\",\n baseURL:\n this.yuanqiConfig.request?.baseUrl ||\n \"https://yuanqi.tencent.com/openapi/v1/agent\",\n });\n this.finalAppId =\n this.yuanqiConfig.appId ||\n this.yuanqiConfig.request?.body?.assistantId ||\n process.env.YUANQI_APP_ID ||\n \"\";\n this.finalCloudCredential = {\n secretId:\n this.yuanqiConfig.credential?.secretId ||\n process.env.TENCENTCLOUD_SECRETID,\n secretKey:\n this.yuanqiConfig.credential?.secretKey ||\n process.env.TENCENTCLOUD_SECRETKEY,\n token:\n this.yuanqiConfig.credential?.token ||\n process.env.TENCENTCLOUD_SESSIONTOKEN,\n };\n }\n\n generateRequestBody({\n messages,\n input,\n }: {\n messages: ChatMessage[];\n input: RunAgentInput;\n }): YuanqiChatRequest {\n const { state, forwardedProps } = input;\n const requestBody: YuanqiChatRequest = {\n stream: true,\n ...(this.yuanqiConfig.request?.body || {}),\n ...(forwardedProps || {}),\n\n assistantId: this.finalAppId,\n userId:\n state?.__request_context__?.id ||\n forwardedProps?.userId ||\n randomUUID(),\n messages,\n };\n return requestBody;\n }\n\n run(input: RunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n this._run(subscriber, input);\n });\n }\n\n private async _run(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput\n ): Promise<void> {\n try {\n const { messages, runId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = input.threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n } as RunStartedEvent);\n\n if (!this.finalAppId) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_ID\"\n );\n }\n if (!this.yuanqiConfig.appKey && !process.env.YUANQI_APP_KEY) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_KEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_KEY\"\n );\n }\n\n // Warn user if messages are being trimmed (only using latest user message)\n const trimmedCount = messages.length - 1;\n if (trimmedCount > 0) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Yuanqi handles message history itself, so that a total of ${trimmedCount} messages before the last user message will be trimmed.`,\n type: \"warn\",\n },\n });\n }\n\n // Get the latest user message for saving to history\n const latestUserMessage = messages.filter((m) => m.role === \"user\").pop();\n if (!latestUserMessage) {\n throw new YuanqiAgentError(\n \"No user message found, please send a message first.\",\n \"MESSAGE_FORMAT_ERROR\"\n );\n }\n\n const allMessages = await this.getChatHistory(\n subscriber,\n latestUserMessage\n );\n\n const body = this.generateRequestBody({\n messages: allMessages,\n input,\n });\n\n const stream = await openai.chat.completions.create(\n {\n stream: true,\n messages: [],\n model: \"\",\n },\n {\n body: camelToSnakeKeys(body),\n headers: {\n ...this.yuanqiConfig.request?.headers,\n Authorization: `Bearer ${\n this.yuanqiConfig.appKey || process.env.YUANQI_APP_KEY\n }`,\n },\n }\n );\n\n // Process stream and emit AGUI events, collect full response\n const userRecordId = `record-${randomUUID().slice(0, 8)}`;\n const assistantRecordId = `record-${randomUUID().slice(0, 8)}`;\n const context = { threadId, runId, messageId: userRecordId };\n\n let fullAssistantContent = \"\";\n\n for await (const event of processYuanqiStream(stream, context)) {\n subscriber.next(event);\n // Collect assistant content from TEXT_MESSAGE_CONTENT events\n if (\n event.type === EventType.TEXT_MESSAGE_CONTENT &&\n (event as TextMessageContentEvent).delta\n ) {\n fullAssistantContent += (event as TextMessageContentEvent).delta;\n }\n }\n\n const userContent =\n typeof latestUserMessage?.content === \"string\"\n ? latestUserMessage.content\n : latestUserMessage?.content\n ?.filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\") || \"\";\n\n await this.saveChatHistory(\n subscriber,\n input,\n userRecordId,\n assistantRecordId,\n userContent,\n fullAssistantContent\n );\n\n subscriber.next({\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\n } as RunFinishedEvent);\n } catch (e: unknown) {\n console.error(\"[ERROR] Uncaught error: \", JSON.stringify(e));\n let code = \"UNKNOWN_ERROR\";\n let message = JSON.stringify(e);\n if (e instanceof YuanqiAgentError) {\n code = e.code || \"AGENT_ERROR\";\n message = e.message;\n } else if (e instanceof Error) {\n code = e.name || \"ERROR\";\n message = e.message;\n }\n subscriber.next({\n type: EventType.RUN_ERROR,\n code,\n message: `Sorry, an error occurred while running the agent: Error code ${code}, ${message}`,\n } as RunErrorEvent);\n } finally {\n subscriber.complete();\n }\n }\n\n // Can be override by subclasses\n protected async getChatHistory(\n subscriber: Subscriber<BaseEvent>,\n latestUserMessage: Message\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history loading.`,\n type: \"warn\",\n },\n });\n return convertMessagesToOpenAI([latestUserMessage]);\n }\n\n // Fetch chat history from database using queryForLLM\n let historyMessages: ChatMessage[] = [];\n\n const historyCount = this.yuanqiConfig.historyCount ?? 10;\n const historyRecords = await queryForLLM({\n tcbClient,\n botId,\n pageSize: historyCount,\n });\n\n // Convert queryForLLM result to ChatMessage format\n historyMessages = historyRecords.map((record) => ({\n role: record.role as \"user\" | \"assistant\",\n content: [{ type: \"text\" as const, text: record.content }],\n }));\n\n // Combine history messages with current messages\n const allMessages = historyMessages.concat(\n convertMessagesToOpenAI([latestUserMessage])\n );\n return allMessages;\n }\n\n // Can be override by subclasses\n protected async saveChatHistory(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput,\n userRecordId: string,\n assistantRecordId: string,\n userContent: string,\n assistantContent: string\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history saving.`,\n type: \"warn\",\n },\n });\n return;\n }\n\n // Save message pair to history\n const userEntity = new ChatHistoryEntity();\n userEntity.recordId = userRecordId;\n userEntity.botId = botId;\n userEntity.role = \"user\";\n userEntity.content = userContent;\n userEntity.conversation = threadId;\n userEntity.reply = assistantRecordId;\n userEntity.triggerSrc = \"\";\n userEntity.traceId = randomUUID();\n\n await createChatHistory({ tcbClient, chatHistoryEntity: userEntity });\n\n const assistantEntity = new ChatHistoryEntity();\n assistantEntity.recordId = assistantRecordId;\n assistantEntity.botId = botId;\n assistantEntity.role = \"assistant\";\n assistantEntity.content = assistantContent;\n assistantEntity.conversation = threadId;\n assistantEntity.replyTo = userRecordId;\n assistantEntity.triggerSrc = \"\";\n assistantEntity.traceId = runId;\n assistantEntity.status = \"done\";\n\n await createChatHistory({\n tcbClient,\n chatHistoryEntity: assistantEntity,\n });\n }\n\n private getTcbClient() {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n\n const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\n });\n return tcbClient;\n }\n\n private async checkIsDatabaseReady() {\n try {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n if (!envId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, CLOUDBASE_ENV_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_CLOUDBASE_ENV_ID\"\n );\n }\n if (!this.finalCloudCredential.token) {\n if (!this.finalCloudCredential.secretId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_ID\"\n );\n }\n if (!this.finalCloudCredential.secretKey) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n const managedTcbClient = managedTcb.init({\n envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n token: this.finalCloudCredential.token,\n });\n\n const checkDBRes = await managedTcbClient.database.checkCollectionExists(\n CHAT_HISTORY_DATA_SOURCE\n );\n if (checkDBRes && checkDBRes.Exists) {\n return true;\n } else if (checkDBRes && !checkDBRes.Exists) {\n await managedTcbClient.database.createCollection(\n CHAT_HISTORY_DATA_SOURCE\n );\n return true;\n } else {\n throw new Error(\"Check database exists failed\");\n }\n } catch (dbError) {\n console.error(\n \"[ERROR] Failed to check/create chat history collection:\",\n JSON.stringify(dbError)\n );\n return false;\n }\n }\n}\n\nfunction getCloudbaseEnvId() {\n if (process.env.CBR_ENV_ID) {\n return process.env.CBR_ENV_ID;\n } else if (process.env.SCF_NAMESPACE) {\n return process.env.SCF_NAMESPACE;\n } else {\n return process.env.CLOUDBASE_ENV_ID || \"\";\n }\n}\n\n/**\n * Convert AGUI messages to OpenAI chat completion format\n */\nexport function convertMessagesToOpenAI(\n messages: Message[],\n systemPrompt?: string\n): ChatMessage[] {\n const openaiMessages: ChatMessage[] = [];\n\n // Add system prompt if provided\n if (systemPrompt) {\n openaiMessages.push({\n role: \"system\",\n content: systemPrompt,\n });\n }\n\n // Convert messages\n for (const msg of messages) {\n if (msg.role === \"user\") {\n openaiMessages.push({\n role: \"user\",\n content:\n typeof msg.content === \"string\"\n ? [{ type: \"text\", text: msg.content }]\n : msg.content.map((item) => {\n if (item.type === \"text\") {\n return { type: \"text\", text: item.text };\n } else {\n return {\n type: \"image_url\",\n image_url: { url: item.url || \"\" },\n };\n }\n }),\n });\n } else if (msg.role === \"assistant\") {\n openaiMessages.push({\n role: \"assistant\",\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n tool_calls: msg.toolCalls?.map((tc: ToolCall) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n })),\n });\n } else if (msg.role === \"tool\") {\n openaiMessages.push({\n role: \"tool\",\n tool_call_id: msg.toolCallId,\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n });\n }\n }\n\n return openaiMessages;\n}\n","/**\n * 将小驼峰字符串转换为下划线格式\n * 例如: \"userName\" -> \"user_name\"\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * 递归地将对象的所有小驼峰属性名转换为下划线格式\n */\nexport function camelToSnakeKeys<T>(obj: T): T {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => camelToSnakeKeys(item)) as T;\n }\n\n if (typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = camelToSnakeKeys(value);\n }\n return result as T;\n }\n\n return obj;\n}\n\nexport function genRandomStr(length: number): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let result = \"\";\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n","import OpenAI from \"openai\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface StreamContext {\n threadId: string;\n runId: string;\n messageId: string;\n}\n\nexport interface StreamState {\n hasStarted: boolean;\n fullContent: string;\n toolCallsMap: Map<string, { name: string; args: string }>;\n}\n\nexport type Delta =\n OpenAI.Chat.Completions.ChatCompletionChunk[\"choices\"][number][\"delta\"] & {\n reasoning_content?: string;\n };\n\nexport async function* processYuanqiStream(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n context: StreamContext\n) {\n const { threadId, runId, messageId } = context;\n const state: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n const reasoningState: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta as Delta;\n if (!delta) continue;\n\n if (delta.role === \"tool\") {\n const toolCallId = (delta as any).tool_call_id;\n if (toolCallId) {\n if (state.toolCallsMap.has(toolCallId)) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n state.toolCallsMap.delete(toolCallId);\n }\n yield {\n type: EventType.TOOL_CALL_RESULT,\n threadId,\n runId,\n toolCallId,\n content: delta.content || \"\",\n };\n }\n continue;\n }\n\n // Handle text content\n if (delta.content) {\n // End reasoning message if it was started\n if (reasoningState.hasStarted) {\n reasoningState.hasStarted = false;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (!state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n state.hasStarted = true;\n }\n\n state.fullContent += delta.content;\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.content,\n };\n }\n\n // Handle reasoning content\n if (delta.reasoning_content) {\n if (!reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_START,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n reasoningState.hasStarted = true;\n }\n\n reasoningState.fullContent += delta.reasoning_content;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.reasoning_content,\n };\n }\n\n // Handle tool calls\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n const toolCallId = toolCall.id || `tool_${toolCall.index}`;\n\n if (toolCall.function?.name) {\n // Tool call start\n yield {\n type: EventType.TOOL_CALL_START,\n threadId,\n runId,\n toolCallId,\n toolCallName: toolCall.function.name,\n };\n\n // If first chunk contains arguments, emit TOOL_CALL_ARGS event\n if (toolCall.function.arguments) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n\n state.toolCallsMap.set(toolCallId, {\n name: toolCall.function.name,\n args: toolCall.function.arguments || \"\",\n });\n } else if (toolCall.function?.arguments) {\n // Tool call arguments delta\n const existing = state.toolCallsMap.get(toolCallId);\n if (existing) {\n existing.args += toolCall.function.arguments;\n\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n }\n }\n }\n }\n\n // Emit TEXT_MESSAGE_END if we had text content\n if (state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n // Emit TOOL_CALL_END for all tool calls\n for (const [toolCallId] of state.toolCallsMap) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n }\n}\n","// 对话数据模型\nexport const CHAT_HISTORY_DATA_SOURCE = \"ai_bot_chat_history_5hobd2b\";\n","import tcb from \"@cloudbase/node-sdk\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { genRandomStr } from \"./utils\";\n\nfunction genRecordId(): string {\n return \"record-\" + genRandomStr(8);\n}\n\n// Create a new chat history record\nexport async function createChatHistory({\n tcbClient,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const recordId = chatHistoryEntity.recordId || genRecordId();\n const data = {\n record_id: recordId,\n bot_id: chatHistoryEntity.botId,\n role: chatHistoryEntity.role,\n content: chatHistoryEntity.content,\n sender: chatHistoryEntity.sender,\n conversation: chatHistoryEntity.conversation,\n type: chatHistoryEntity.type,\n image: chatHistoryEntity.image,\n trigger_src: chatHistoryEntity.triggerSrc,\n origin_msg: chatHistoryEntity.originMsg,\n reply_to: chatHistoryEntity.replyTo,\n reply: chatHistoryEntity.reply,\n trace_id: chatHistoryEntity.traceId,\n need_async_reply: chatHistoryEntity.needAsyncReply,\n async_reply: chatHistoryEntity.asyncReply,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n const db = tcbClient.database();\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n const result = await collection.add(data);\n\n // console.log(\n // `Create record: chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return recordId;\n } catch (error) {\n console.error(\"Failed to create chat history record, error:\", error);\n return undefined;\n }\n}\n\n// Update chat history by record ID\nexport async function updateChatHistoryByRecordId({\n tcbClient,\n recordId,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n recordId: string;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n const result = await collection\n .where({ record_id: _.eq(recordId) })\n .update({\n content: chatHistoryEntity.content,\n image: chatHistoryEntity.image,\n async_reply: chatHistoryEntity.asyncReply,\n recommend_questions: chatHistoryEntity.recommendQuestions,\n status: chatHistoryEntity.status,\n origin_msg: chatHistoryEntity.originMsg,\n updatedAt: Date.now(),\n });\n\n // console.log(\n // `Update record: recordId: ${recordId}, chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return chatHistoryEntity.recordId;\n } catch (error) {\n console.error(\"Failed to update chat history, error:\", error);\n return undefined;\n }\n}\n\n// Query chat history from database\nexport async function describeChatHistory({\n tcbClient,\n botId,\n sort,\n pageSize = 10,\n pageNumber = 1,\n conversation,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n sort: \"asc\" | \"desc\";\n pageSize?: number;\n pageNumber?: number;\n conversation?: string;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<[ChatHistoryEntity[], number]> {\n if (!sort || sort.length === 0) {\n sort = \"desc\";\n }\n\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n // Build where conditions\n const whereConditions: Record<string, unknown> = {\n bot_id: _.eq(botId),\n };\n\n // Add optional filters\n if (conversation) {\n whereConditions.conversation = _.eq(conversation);\n }\n\n if (startCreatedAt !== undefined) {\n whereConditions.createdAt = _.gt(startCreatedAt);\n }\n\n if (triggerSrc) {\n whereConditions.trigger_src = _.eq(triggerSrc);\n }\n\n // Calculate skip for pagination\n const skip = (pageNumber - 1) * pageSize;\n\n // Query records\n const result = await collection\n .where(whereConditions)\n .orderBy(\"createdAt\", sort)\n .skip(skip)\n .limit(pageSize)\n .get();\n\n // Get total count\n const countResult = await collection.where(whereConditions).count();\n const total = countResult.total || 0;\n\n const records = result?.data || [];\n\n const entityList: ChatHistoryEntity[] = records.map(\n (item: ChatHistoryData) => transDataToChatEntity(item)\n );\n\n return [entityList, total];\n } catch (error) {\n console.error(\"Failed to query chat history, error:\", error);\n return [[], 0];\n }\n}\n\n// Transform data to ChatHistoryEntity structure\nexport function transDataToChatEntity(\n item: ChatHistoryData\n): ChatHistoryEntity {\n if (!item) {\n return new ChatHistoryEntity();\n }\n const chatEntity: ChatHistoryEntity = new ChatHistoryEntity();\n chatEntity.botId = item.bot_id;\n chatEntity.recordId = item.record_id;\n chatEntity.role = item.role;\n chatEntity.status = item.status;\n chatEntity.content = item.content;\n chatEntity.sender = item.sender;\n chatEntity.conversation = item.conversation;\n chatEntity.type = item.type;\n chatEntity.triggerSrc = item.trigger_src;\n chatEntity.originMsg = item.origin_msg;\n chatEntity.replyTo = item.reply_to;\n chatEntity.reply = item.reply;\n chatEntity.traceId = item.trace_id;\n chatEntity.needAsyncReply = item.need_async_reply;\n chatEntity.asyncReply = item.async_reply;\n chatEntity.createdAt = item.createdAt;\n chatEntity.updatedAt = item.updatedAt;\n return chatEntity;\n}\n\n// Query history records for LLM, get the most recent 10 conversation pairs (20 records)\nexport async function queryForLLM({\n tcbClient,\n botId,\n pageSize = 10,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n pageSize?: number;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<{ role: string; content: string }[]> {\n if (startCreatedAt === undefined) {\n startCreatedAt = Date.now() - 24 * 60 * 60 * 1000;\n }\n const recordEntityList: ChatHistoryEntity[] = [];\n\n const [recordList] = await describeChatHistory({\n tcbClient,\n botId,\n sort: \"desc\",\n pageSize,\n startCreatedAt,\n triggerSrc,\n });\n recordEntityList.push(...recordList.reverse());\n\n const entityMap = new Map<string, ChatHistoryEntity>();\n recordEntityList\n .filter((item) => {\n if (item.needAsyncReply === true) {\n return !!item.asyncReply;\n } else {\n return !!item.content;\n }\n })\n .forEach((item) => {\n entityMap.set(item.recordId, item);\n });\n\n const result: { role: string; content: string }[] = [];\n /*\n 1. Strongly depends on database history data, model history data has role order requirements\n 2. Need to ensure that no matter what bug occurs, always get a complete and usable user + assistant pair, otherwise the request will fail\n */\n recordEntityList.forEach((item) => {\n const { role, content, reply } = item;\n // When calling LLM, empty content will cause failure, so filter out conversations with empty content\n if (role === \"user\" && content?.length !== 0) {\n if (entityMap.has(reply)) {\n result.push({ role, content });\n result.push({\n role: entityMap.get(reply)!.role,\n content: entityMap.get(reply)!.content,\n });\n }\n }\n });\n if (result.length % 2 === 1) {\n result.splice(-1, 1);\n }\n return result;\n}\n\nexport interface ChatHistoryData {\n bot_id: string;\n record_id: string;\n role: string;\n status: string;\n content: string;\n sender: string;\n conversation: string;\n type: string;\n trigger_src: string;\n origin_msg: string;\n reply_to: string;\n reply: string;\n trace_id: string;\n need_async_reply: boolean;\n async_reply: string;\n createdAt: number;\n updatedAt: number;\n}\n\nexport class ChatHistoryEntity {\n id: number;\n botId: string;\n // 对话唯一id\n recordId: string;\n role: string;\n content: string;\n recommendQuestions: string[];\n sender: string;\n conversation: string;\n type: string;\n /**\n * 消息状态,pending done error cancel\n */\n status: string;\n image: string;\n triggerSrc: string;\n originMsg: string;\n replyTo: string;\n reply: string;\n traceId: string;\n needAsyncReply: boolean;\n asyncReply: string;\n createTime: string;\n updateTime: string;\n createdAt: number;\n updatedAt: number;\n event: string;\n}\n"],"mappings":"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","names":["import_client","OpenAI","tcb","managedTcb"]}
|
package/dist/index.mjs
CHANGED
|
@@ -55,6 +55,28 @@ async function* processYuanqiStream(stream, context) {
|
|
|
55
55
|
for await (const chunk of stream) {
|
|
56
56
|
const delta = chunk.choices[0]?.delta;
|
|
57
57
|
if (!delta) continue;
|
|
58
|
+
if (delta.role === "tool") {
|
|
59
|
+
const toolCallId = delta.tool_call_id;
|
|
60
|
+
if (toolCallId) {
|
|
61
|
+
if (state.toolCallsMap.has(toolCallId)) {
|
|
62
|
+
yield {
|
|
63
|
+
type: EventType.TOOL_CALL_END,
|
|
64
|
+
threadId,
|
|
65
|
+
runId,
|
|
66
|
+
toolCallId
|
|
67
|
+
};
|
|
68
|
+
state.toolCallsMap.delete(toolCallId);
|
|
69
|
+
}
|
|
70
|
+
yield {
|
|
71
|
+
type: EventType.TOOL_CALL_RESULT,
|
|
72
|
+
threadId,
|
|
73
|
+
runId,
|
|
74
|
+
toolCallId,
|
|
75
|
+
content: delta.content || ""
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
58
80
|
if (delta.content) {
|
|
59
81
|
if (reasoningState.hasStarted) {
|
|
60
82
|
reasoningState.hasStarted = false;
|
|
@@ -127,6 +149,15 @@ async function* processYuanqiStream(stream, context) {
|
|
|
127
149
|
toolCallId,
|
|
128
150
|
toolCallName: toolCall.function.name
|
|
129
151
|
};
|
|
152
|
+
if (toolCall.function.arguments) {
|
|
153
|
+
yield {
|
|
154
|
+
type: EventType.TOOL_CALL_ARGS,
|
|
155
|
+
threadId,
|
|
156
|
+
runId,
|
|
157
|
+
toolCallId,
|
|
158
|
+
delta: toolCall.function.arguments
|
|
159
|
+
};
|
|
160
|
+
}
|
|
130
161
|
state.toolCallsMap.set(toolCallId, {
|
|
131
162
|
name: toolCall.function.name,
|
|
132
163
|
args: toolCall.function.arguments || ""
|
|
@@ -155,6 +186,20 @@ async function* processYuanqiStream(stream, context) {
|
|
|
155
186
|
messageId
|
|
156
187
|
};
|
|
157
188
|
}
|
|
189
|
+
if (reasoningState.hasStarted) {
|
|
190
|
+
yield {
|
|
191
|
+
type: EventType.THINKING_TEXT_MESSAGE_END,
|
|
192
|
+
threadId,
|
|
193
|
+
runId,
|
|
194
|
+
messageId
|
|
195
|
+
};
|
|
196
|
+
yield {
|
|
197
|
+
type: EventType.THINKING_END,
|
|
198
|
+
threadId,
|
|
199
|
+
runId,
|
|
200
|
+
messageId
|
|
201
|
+
};
|
|
202
|
+
}
|
|
158
203
|
for (const [toolCallId] of state.toolCallsMap) {
|
|
159
204
|
yield {
|
|
160
205
|
type: EventType.TOOL_CALL_END,
|
|
@@ -397,9 +442,9 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
397
442
|
}
|
|
398
443
|
async _run(subscriber, input) {
|
|
399
444
|
try {
|
|
400
|
-
const { messages, runId
|
|
445
|
+
const { messages, runId } = input;
|
|
401
446
|
const openai = this.model;
|
|
402
|
-
const threadId =
|
|
447
|
+
const threadId = input.threadId || randomUUID();
|
|
403
448
|
subscriber.next({
|
|
404
449
|
type: EventType2.RUN_STARTED,
|
|
405
450
|
threadId,
|
|
@@ -481,7 +526,7 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
481
526
|
runId
|
|
482
527
|
});
|
|
483
528
|
} catch (e) {
|
|
484
|
-
console.error(JSON.stringify(e));
|
|
529
|
+
console.error("[ERROR] Uncaught error: ", JSON.stringify(e));
|
|
485
530
|
let code = "UNKNOWN_ERROR";
|
|
486
531
|
let message = JSON.stringify(e);
|
|
487
532
|
if (e instanceof YuanqiAgentError) {
|
|
@@ -502,9 +547,9 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
502
547
|
}
|
|
503
548
|
// Can be override by subclasses
|
|
504
549
|
async getChatHistory(subscriber, latestUserMessage) {
|
|
505
|
-
const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();
|
|
506
550
|
const botId = `bot-yuanqi-${this.finalAppId}`;
|
|
507
|
-
const
|
|
551
|
+
const tcbClient = this.getTcbClient();
|
|
552
|
+
const isDBReady = await this.checkIsDatabaseReady();
|
|
508
553
|
if (!isDBReady) {
|
|
509
554
|
subscriber.next({
|
|
510
555
|
type: EventType2.RAW,
|
|
@@ -515,12 +560,6 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
515
560
|
});
|
|
516
561
|
return convertMessagesToOpenAI([latestUserMessage]);
|
|
517
562
|
}
|
|
518
|
-
const tcbClient = tcb.init({
|
|
519
|
-
env: envId,
|
|
520
|
-
secretId: this.finalCloudCredential.secretId,
|
|
521
|
-
secretKey: this.finalCloudCredential.secretKey,
|
|
522
|
-
sessionToken: this.finalCloudCredential.token
|
|
523
|
-
});
|
|
524
563
|
let historyMessages = [];
|
|
525
564
|
const historyCount = this.yuanqiConfig.historyCount ?? 10;
|
|
526
565
|
const historyRecords = await queryForLLM({
|
|
@@ -539,10 +578,10 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
539
578
|
}
|
|
540
579
|
// Can be override by subclasses
|
|
541
580
|
async saveChatHistory(subscriber, input, userRecordId, assistantRecordId, userContent, assistantContent) {
|
|
542
|
-
const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();
|
|
543
581
|
const botId = `bot-yuanqi-${this.finalAppId}`;
|
|
544
582
|
const { threadId, runId } = input;
|
|
545
|
-
const
|
|
583
|
+
const tcbClient = this.getTcbClient();
|
|
584
|
+
const isDBReady = await this.checkIsDatabaseReady();
|
|
546
585
|
if (!isDBReady) {
|
|
547
586
|
subscriber.next({
|
|
548
587
|
type: EventType2.RAW,
|
|
@@ -553,12 +592,6 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
553
592
|
});
|
|
554
593
|
return;
|
|
555
594
|
}
|
|
556
|
-
const tcbClient = tcb.init({
|
|
557
|
-
env: envId,
|
|
558
|
-
secretId: this.finalCloudCredential.secretId,
|
|
559
|
-
secretKey: this.finalCloudCredential.secretKey,
|
|
560
|
-
sessionToken: this.finalCloudCredential.token
|
|
561
|
-
});
|
|
562
595
|
const userEntity = new ChatHistoryEntity();
|
|
563
596
|
userEntity.recordId = userRecordId;
|
|
564
597
|
userEntity.botId = botId;
|
|
@@ -584,28 +617,39 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
584
617
|
chatHistoryEntity: assistantEntity
|
|
585
618
|
});
|
|
586
619
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
620
|
+
getTcbClient() {
|
|
621
|
+
const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();
|
|
622
|
+
const tcbClient = tcb.init({
|
|
623
|
+
env: envId,
|
|
624
|
+
secretId: this.finalCloudCredential.secretId,
|
|
625
|
+
secretKey: this.finalCloudCredential.secretKey,
|
|
626
|
+
sessionToken: this.finalCloudCredential.token
|
|
627
|
+
});
|
|
628
|
+
return tcbClient;
|
|
629
|
+
}
|
|
630
|
+
async checkIsDatabaseReady() {
|
|
631
|
+
try {
|
|
632
|
+
const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();
|
|
633
|
+
if (!envId) {
|
|
596
634
|
throw new YuanqiAgentError(
|
|
597
|
-
"
|
|
598
|
-
"
|
|
635
|
+
"When saving chat history to CloudBase, CLOUDBASE_ENV_ID is required, check your env variables or config passed with the adapter",
|
|
636
|
+
"MISSING_CLOUDBASE_ENV_ID"
|
|
599
637
|
);
|
|
600
638
|
}
|
|
601
|
-
if (!this.finalCloudCredential.
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
639
|
+
if (!this.finalCloudCredential.token) {
|
|
640
|
+
if (!this.finalCloudCredential.secretId) {
|
|
641
|
+
throw new YuanqiAgentError(
|
|
642
|
+
"When saving chat history to CloudBase, TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter",
|
|
643
|
+
"MISSING_SECRET_ID"
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
if (!this.finalCloudCredential.secretKey) {
|
|
647
|
+
throw new YuanqiAgentError(
|
|
648
|
+
"When saving chat history to CloudBase, TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter",
|
|
649
|
+
"MISSING_SECRET_KEY"
|
|
650
|
+
);
|
|
651
|
+
}
|
|
606
652
|
}
|
|
607
|
-
}
|
|
608
|
-
try {
|
|
609
653
|
const managedTcbClient = managedTcb.init({
|
|
610
654
|
envId,
|
|
611
655
|
secretId: this.finalCloudCredential.secretId,
|
|
@@ -622,10 +666,12 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
622
666
|
CHAT_HISTORY_DATA_SOURCE
|
|
623
667
|
);
|
|
624
668
|
return true;
|
|
669
|
+
} else {
|
|
670
|
+
throw new Error("Check database exists failed");
|
|
625
671
|
}
|
|
626
672
|
} catch (dbError) {
|
|
627
673
|
console.error(
|
|
628
|
-
"Failed to check/create chat history collection:",
|
|
674
|
+
"[ERROR] Failed to check/create chat history collection:",
|
|
629
675
|
JSON.stringify(dbError)
|
|
630
676
|
);
|
|
631
677
|
return false;
|
|
@@ -633,9 +679,9 @@ var YuanqiAgent = class extends AbstractAgent {
|
|
|
633
679
|
}
|
|
634
680
|
};
|
|
635
681
|
function getCloudbaseEnvId() {
|
|
636
|
-
if (
|
|
682
|
+
if (process.env.CBR_ENV_ID) {
|
|
637
683
|
return process.env.CBR_ENV_ID;
|
|
638
|
-
} else if (
|
|
684
|
+
} else if (process.env.SCF_NAMESPACE) {
|
|
639
685
|
return process.env.SCF_NAMESPACE;
|
|
640
686
|
} else {
|
|
641
687
|
return process.env.CLOUDBASE_ENV_ID || "";
|
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\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent.ts","../src/utils.ts","../src/stream.ts","../src/constant.ts","../src/chat_history.ts"],"sourcesContent":["import {\n RunAgentInput,\n Message,\n AbstractAgent,\n AgentConfig,\n BaseEvent,\n EventType,\n RunStartedEvent,\n RunFinishedEvent,\n RunErrorEvent,\n TextMessageContentEvent,\n ToolCall,\n} from \"@ag-ui/client\";\nimport tcb from \"@cloudbase/node-sdk\";\nimport managedTcb from \"@cloudbase/manager-node\";\nimport OpenAI from \"openai\";\nimport { randomUUID } from \"crypto\";\nimport { camelToSnakeKeys } from \"./utils\";\nimport { processYuanqiStream } from \"./stream\";\nimport { Observable, Subscriber } from \"rxjs\";\nimport {\n createChatHistory,\n queryForLLM,\n ChatHistoryEntity,\n} from \"./chat_history\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { YuanqiConfig, ChatMessage, YuanqiChatRequest } from \"./types\";\n\nexport class YuanqiAgentError extends Error {\n code?: string;\n constructor(message: string, code?: string) {\n super(message);\n this.name = \"YuanqiAgentError\";\n if (code) this.code = code;\n }\n}\n\nexport class YuanqiAgent extends AbstractAgent {\n protected yuanqiConfig: YuanqiConfig;\n private finalAppId: string;\n private finalCloudCredential: {\n secretId?: string;\n secretKey?: string;\n token?: string;\n } = {};\n private model: OpenAI;\n constructor(config: AgentConfig & { yuanqiConfig: YuanqiConfig }) {\n super(config);\n this.yuanqiConfig = config.yuanqiConfig;\n this.model = new OpenAI({\n apiKey: \"\",\n baseURL:\n this.yuanqiConfig.request?.baseUrl ||\n \"https://yuanqi.tencent.com/openapi/v1/agent\",\n });\n this.finalAppId =\n this.yuanqiConfig.appId ||\n this.yuanqiConfig.request?.body?.assistantId ||\n process.env.YUANQI_APP_ID ||\n \"\";\n this.finalCloudCredential = {\n secretId:\n this.yuanqiConfig.credential?.secretId ||\n process.env.TENCENTCLOUD_SECRETID,\n secretKey:\n this.yuanqiConfig.credential?.secretKey ||\n process.env.TENCENTCLOUD_SECRETKEY,\n token:\n this.yuanqiConfig.credential?.token ||\n process.env.TENCENTCLOUD_SESSIONTOKEN,\n };\n }\n\n generateRequestBody({\n messages,\n input,\n }: {\n messages: ChatMessage[];\n input: RunAgentInput;\n }): YuanqiChatRequest {\n const { state, forwardedProps } = input;\n const requestBody: YuanqiChatRequest = {\n stream: true,\n ...(this.yuanqiConfig.request?.body || {}),\n ...(forwardedProps || {}),\n\n assistantId: this.finalAppId,\n userId:\n state?.__request_context__?.id ||\n forwardedProps?.userId ||\n randomUUID(),\n messages,\n };\n return requestBody;\n }\n\n run(input: RunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n this._run(subscriber, input);\n });\n }\n\n private async _run(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput\n ): Promise<void> {\n try {\n const { messages, runId } = input;\n\n const openai = this.model as OpenAI;\n const threadId = input.threadId || randomUUID();\n\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId,\n runId,\n } as RunStartedEvent);\n\n if (!this.finalAppId) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_ID\"\n );\n }\n if (!this.yuanqiConfig.appKey && !process.env.YUANQI_APP_KEY) {\n throw new YuanqiAgentError(\n \"YUANQI_APP_KEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_YUANQI_APP_KEY\"\n );\n }\n\n // Warn user if messages are being trimmed (only using latest user message)\n const trimmedCount = messages.length - 1;\n if (trimmedCount > 0) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Yuanqi handles message history itself, so that a total of ${trimmedCount} messages before the last user message will be trimmed.`,\n type: \"warn\",\n },\n });\n }\n\n // Get the latest user message for saving to history\n const latestUserMessage = messages.filter((m) => m.role === \"user\").pop();\n if (!latestUserMessage) {\n throw new YuanqiAgentError(\n \"No user message found, please send a message first.\",\n \"MESSAGE_FORMAT_ERROR\"\n );\n }\n\n const allMessages = await this.getChatHistory(\n subscriber,\n latestUserMessage\n );\n\n const body = this.generateRequestBody({\n messages: allMessages,\n input,\n });\n\n const stream = await openai.chat.completions.create(\n {\n stream: true,\n messages: [],\n model: \"\",\n },\n {\n body: camelToSnakeKeys(body),\n headers: {\n ...this.yuanqiConfig.request?.headers,\n Authorization: `Bearer ${\n this.yuanqiConfig.appKey || process.env.YUANQI_APP_KEY\n }`,\n },\n }\n );\n\n // Process stream and emit AGUI events, collect full response\n const userRecordId = `record-${randomUUID().slice(0, 8)}`;\n const assistantRecordId = `record-${randomUUID().slice(0, 8)}`;\n const context = { threadId, runId, messageId: userRecordId };\n\n let fullAssistantContent = \"\";\n\n for await (const event of processYuanqiStream(stream, context)) {\n subscriber.next(event);\n // Collect assistant content from TEXT_MESSAGE_CONTENT events\n if (\n event.type === EventType.TEXT_MESSAGE_CONTENT &&\n (event as TextMessageContentEvent).delta\n ) {\n fullAssistantContent += (event as TextMessageContentEvent).delta;\n }\n }\n\n const userContent =\n typeof latestUserMessage?.content === \"string\"\n ? latestUserMessage.content\n : latestUserMessage?.content\n ?.filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\") || \"\";\n\n await this.saveChatHistory(\n subscriber,\n input,\n userRecordId,\n assistantRecordId,\n userContent,\n fullAssistantContent\n );\n\n subscriber.next({\n type: EventType.RUN_FINISHED,\n threadId,\n runId,\n } as RunFinishedEvent);\n } catch (e: unknown) {\n console.error(\"[ERROR] Uncaught error: \", JSON.stringify(e));\n let code = \"UNKNOWN_ERROR\";\n let message = JSON.stringify(e);\n if (e instanceof YuanqiAgentError) {\n code = e.code || \"AGENT_ERROR\";\n message = e.message;\n } else if (e instanceof Error) {\n code = e.name || \"ERROR\";\n message = e.message;\n }\n subscriber.next({\n type: EventType.RUN_ERROR,\n code,\n message: `Sorry, an error occurred while running the agent: Error code ${code}, ${message}`,\n } as RunErrorEvent);\n } finally {\n subscriber.complete();\n }\n }\n\n // Can be override by subclasses\n protected async getChatHistory(\n subscriber: Subscriber<BaseEvent>,\n latestUserMessage: Message\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history loading.`,\n type: \"warn\",\n },\n });\n return convertMessagesToOpenAI([latestUserMessage]);\n }\n\n // Fetch chat history from database using queryForLLM\n let historyMessages: ChatMessage[] = [];\n\n const historyCount = this.yuanqiConfig.historyCount ?? 10;\n const historyRecords = await queryForLLM({\n tcbClient,\n botId,\n pageSize: historyCount,\n });\n\n // Convert queryForLLM result to ChatMessage format\n historyMessages = historyRecords.map((record) => ({\n role: record.role as \"user\" | \"assistant\",\n content: [{ type: \"text\" as const, text: record.content }],\n }));\n\n // Combine history messages with current messages\n const allMessages = historyMessages.concat(\n convertMessagesToOpenAI([latestUserMessage])\n );\n return allMessages;\n }\n\n // Can be override by subclasses\n protected async saveChatHistory(\n subscriber: Subscriber<BaseEvent>,\n input: RunAgentInput,\n userRecordId: string,\n assistantRecordId: string,\n userContent: string,\n assistantContent: string\n ) {\n const botId = `bot-yuanqi-${this.finalAppId}`;\n\n const { threadId, runId } = input;\n\n const tcbClient = this.getTcbClient();\n\n const isDBReady = await this.checkIsDatabaseReady();\n if (!isDBReady) {\n subscriber.next({\n type: EventType.RAW,\n rawEvent: {\n message: `Chat history database is not ready, skip history saving.`,\n type: \"warn\",\n },\n });\n return;\n }\n\n // Save message pair to history\n const userEntity = new ChatHistoryEntity();\n userEntity.recordId = userRecordId;\n userEntity.botId = botId;\n userEntity.role = \"user\";\n userEntity.content = userContent;\n userEntity.conversation = threadId;\n userEntity.reply = assistantRecordId;\n userEntity.triggerSrc = \"\";\n userEntity.traceId = randomUUID();\n\n await createChatHistory({ tcbClient, chatHistoryEntity: userEntity });\n\n const assistantEntity = new ChatHistoryEntity();\n assistantEntity.recordId = assistantRecordId;\n assistantEntity.botId = botId;\n assistantEntity.role = \"assistant\";\n assistantEntity.content = assistantContent;\n assistantEntity.conversation = threadId;\n assistantEntity.replyTo = userRecordId;\n assistantEntity.triggerSrc = \"\";\n assistantEntity.traceId = runId;\n assistantEntity.status = \"done\";\n\n await createChatHistory({\n tcbClient,\n chatHistoryEntity: assistantEntity,\n });\n }\n\n private getTcbClient() {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n\n const tcbClient = tcb.init({\n env: envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n sessionToken: this.finalCloudCredential.token,\n });\n return tcbClient;\n }\n\n private async checkIsDatabaseReady() {\n try {\n const envId = this.yuanqiConfig.envId || getCloudbaseEnvId();\n if (!envId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, CLOUDBASE_ENV_ID is required, check your env variables or config passed with the adapter\",\n \"MISSING_CLOUDBASE_ENV_ID\"\n );\n }\n if (!this.finalCloudCredential.token) {\n if (!this.finalCloudCredential.secretId) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_ID\"\n );\n }\n if (!this.finalCloudCredential.secretKey) {\n throw new YuanqiAgentError(\n \"When saving chat history to CloudBase, TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter\",\n \"MISSING_SECRET_KEY\"\n );\n }\n }\n const managedTcbClient = managedTcb.init({\n envId,\n secretId: this.finalCloudCredential.secretId,\n secretKey: this.finalCloudCredential.secretKey,\n token: this.finalCloudCredential.token,\n });\n\n const checkDBRes = await managedTcbClient.database.checkCollectionExists(\n CHAT_HISTORY_DATA_SOURCE\n );\n if (checkDBRes && checkDBRes.Exists) {\n return true;\n } else if (checkDBRes && !checkDBRes.Exists) {\n await managedTcbClient.database.createCollection(\n CHAT_HISTORY_DATA_SOURCE\n );\n return true;\n } else {\n throw new Error(\"Check database exists failed\");\n }\n } catch (dbError) {\n console.error(\n \"[ERROR] Failed to check/create chat history collection:\",\n JSON.stringify(dbError)\n );\n return false;\n }\n }\n}\n\nfunction getCloudbaseEnvId() {\n if (process.env.CBR_ENV_ID) {\n return process.env.CBR_ENV_ID;\n } else if (process.env.SCF_NAMESPACE) {\n return process.env.SCF_NAMESPACE;\n } else {\n return process.env.CLOUDBASE_ENV_ID || \"\";\n }\n}\n\n/**\n * Convert AGUI messages to OpenAI chat completion format\n */\nexport function convertMessagesToOpenAI(\n messages: Message[],\n systemPrompt?: string\n): ChatMessage[] {\n const openaiMessages: ChatMessage[] = [];\n\n // Add system prompt if provided\n if (systemPrompt) {\n openaiMessages.push({\n role: \"system\",\n content: systemPrompt,\n });\n }\n\n // Convert messages\n for (const msg of messages) {\n if (msg.role === \"user\") {\n openaiMessages.push({\n role: \"user\",\n content:\n typeof msg.content === \"string\"\n ? [{ type: \"text\", text: msg.content }]\n : msg.content.map((item) => {\n if (item.type === \"text\") {\n return { type: \"text\", text: item.text };\n } else {\n return {\n type: \"image_url\",\n image_url: { url: item.url || \"\" },\n };\n }\n }),\n });\n } else if (msg.role === \"assistant\") {\n openaiMessages.push({\n role: \"assistant\",\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n tool_calls: msg.toolCalls?.map((tc: ToolCall) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n })),\n });\n } else if (msg.role === \"tool\") {\n openaiMessages.push({\n role: \"tool\",\n tool_call_id: msg.toolCallId,\n content: msg.content ? [{ type: \"text\", text: msg.content }] : [],\n });\n }\n }\n\n return openaiMessages;\n}\n","/**\n * 将小驼峰字符串转换为下划线格式\n * 例如: \"userName\" -> \"user_name\"\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * 递归地将对象的所有小驼峰属性名转换为下划线格式\n */\nexport function camelToSnakeKeys<T>(obj: T): T {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => camelToSnakeKeys(item)) as T;\n }\n\n if (typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n const snakeKey = camelToSnake(key);\n result[snakeKey] = camelToSnakeKeys(value);\n }\n return result as T;\n }\n\n return obj;\n}\n\nexport function genRandomStr(length: number): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let result = \"\";\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n","import OpenAI from \"openai\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface StreamContext {\n threadId: string;\n runId: string;\n messageId: string;\n}\n\nexport interface StreamState {\n hasStarted: boolean;\n fullContent: string;\n toolCallsMap: Map<string, { name: string; args: string }>;\n}\n\nexport type Delta =\n OpenAI.Chat.Completions.ChatCompletionChunk[\"choices\"][number][\"delta\"] & {\n reasoning_content?: string;\n };\n\nexport async function* processYuanqiStream(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n context: StreamContext\n) {\n const { threadId, runId, messageId } = context;\n const state: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n const reasoningState: StreamState = {\n hasStarted: false,\n fullContent: \"\",\n toolCallsMap: new Map(),\n };\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta as Delta;\n if (!delta) continue;\n\n if (delta.role === \"tool\") {\n const toolCallId = (delta as any).tool_call_id;\n if (toolCallId) {\n if (state.toolCallsMap.has(toolCallId)) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n state.toolCallsMap.delete(toolCallId);\n }\n yield {\n type: EventType.TOOL_CALL_RESULT,\n threadId,\n runId,\n toolCallId,\n content: delta.content || \"\",\n };\n }\n continue;\n }\n\n // Handle text content\n if (delta.content) {\n // End reasoning message if it was started\n if (reasoningState.hasStarted) {\n reasoningState.hasStarted = false;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (!state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n state.hasStarted = true;\n }\n\n state.fullContent += delta.content;\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.content,\n };\n }\n\n // Handle reasoning content\n if (delta.reasoning_content) {\n if (!reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_START,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_START,\n threadId,\n runId,\n messageId,\n role: \"assistant\",\n };\n reasoningState.hasStarted = true;\n }\n\n reasoningState.fullContent += delta.reasoning_content;\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_CONTENT,\n threadId,\n runId,\n messageId,\n delta: delta.reasoning_content,\n };\n }\n\n // Handle tool calls\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n const toolCallId = toolCall.id || `tool_${toolCall.index}`;\n\n if (toolCall.function?.name) {\n // Tool call start\n yield {\n type: EventType.TOOL_CALL_START,\n threadId,\n runId,\n toolCallId,\n toolCallName: toolCall.function.name,\n };\n\n // If first chunk contains arguments, emit TOOL_CALL_ARGS event\n if (toolCall.function.arguments) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n\n state.toolCallsMap.set(toolCallId, {\n name: toolCall.function.name,\n args: toolCall.function.arguments || \"\",\n });\n } else if (toolCall.function?.arguments) {\n // Tool call arguments delta\n const existing = state.toolCallsMap.get(toolCallId);\n if (existing) {\n existing.args += toolCall.function.arguments;\n\n yield {\n type: EventType.TOOL_CALL_ARGS,\n threadId,\n runId,\n toolCallId,\n delta: toolCall.function.arguments,\n };\n }\n }\n }\n }\n }\n\n // Emit TEXT_MESSAGE_END if we had text content\n if (state.hasStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n if (reasoningState.hasStarted) {\n yield {\n type: EventType.THINKING_TEXT_MESSAGE_END,\n threadId,\n runId,\n messageId,\n };\n yield {\n type: EventType.THINKING_END,\n threadId,\n runId,\n messageId,\n };\n }\n\n // Emit TOOL_CALL_END for all tool calls\n for (const [toolCallId] of state.toolCallsMap) {\n yield {\n type: EventType.TOOL_CALL_END,\n threadId,\n runId,\n toolCallId,\n };\n }\n}\n","// 对话数据模型\nexport const CHAT_HISTORY_DATA_SOURCE = \"ai_bot_chat_history_5hobd2b\";\n","import tcb from \"@cloudbase/node-sdk\";\nimport { CHAT_HISTORY_DATA_SOURCE } from \"./constant\";\nimport { genRandomStr } from \"./utils\";\n\nfunction genRecordId(): string {\n return \"record-\" + genRandomStr(8);\n}\n\n// Create a new chat history record\nexport async function createChatHistory({\n tcbClient,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const recordId = chatHistoryEntity.recordId || genRecordId();\n const data = {\n record_id: recordId,\n bot_id: chatHistoryEntity.botId,\n role: chatHistoryEntity.role,\n content: chatHistoryEntity.content,\n sender: chatHistoryEntity.sender,\n conversation: chatHistoryEntity.conversation,\n type: chatHistoryEntity.type,\n image: chatHistoryEntity.image,\n trigger_src: chatHistoryEntity.triggerSrc,\n origin_msg: chatHistoryEntity.originMsg,\n reply_to: chatHistoryEntity.replyTo,\n reply: chatHistoryEntity.reply,\n trace_id: chatHistoryEntity.traceId,\n need_async_reply: chatHistoryEntity.needAsyncReply,\n async_reply: chatHistoryEntity.asyncReply,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n const db = tcbClient.database();\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n const result = await collection.add(data);\n\n // console.log(\n // `Create record: chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return recordId;\n } catch (error) {\n console.error(\"Failed to create chat history record, error:\", error);\n return undefined;\n }\n}\n\n// Update chat history by record ID\nexport async function updateChatHistoryByRecordId({\n tcbClient,\n recordId,\n chatHistoryEntity,\n}: {\n tcbClient: tcb.CloudBase;\n recordId: string;\n chatHistoryEntity: ChatHistoryEntity;\n}): Promise<string | undefined> {\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n const result = await collection\n .where({ record_id: _.eq(recordId) })\n .update({\n content: chatHistoryEntity.content,\n image: chatHistoryEntity.image,\n async_reply: chatHistoryEntity.asyncReply,\n recommend_questions: chatHistoryEntity.recommendQuestions,\n status: chatHistoryEntity.status,\n origin_msg: chatHistoryEntity.originMsg,\n updatedAt: Date.now(),\n });\n\n // console.log(\n // `Update record: recordId: ${recordId}, chatHistoryEntity:${JSON.stringify(\n // chatHistoryEntity\n // )}, result: ${JSON.stringify(result)}`\n // );\n return chatHistoryEntity.recordId;\n } catch (error) {\n console.error(\"Failed to update chat history, error:\", error);\n return undefined;\n }\n}\n\n// Query chat history from database\nexport async function describeChatHistory({\n tcbClient,\n botId,\n sort,\n pageSize = 10,\n pageNumber = 1,\n conversation,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n sort: \"asc\" | \"desc\";\n pageSize?: number;\n pageNumber?: number;\n conversation?: string;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<[ChatHistoryEntity[], number]> {\n if (!sort || sort.length === 0) {\n sort = \"desc\";\n }\n\n try {\n const db = tcbClient.database();\n const _ = db.command;\n const collection = db.collection(CHAT_HISTORY_DATA_SOURCE);\n\n // Build where conditions\n const whereConditions: Record<string, unknown> = {\n bot_id: _.eq(botId),\n };\n\n // Add optional filters\n if (conversation) {\n whereConditions.conversation = _.eq(conversation);\n }\n\n if (startCreatedAt !== undefined) {\n whereConditions.createdAt = _.gt(startCreatedAt);\n }\n\n if (triggerSrc) {\n whereConditions.trigger_src = _.eq(triggerSrc);\n }\n\n // Calculate skip for pagination\n const skip = (pageNumber - 1) * pageSize;\n\n // Query records\n const result = await collection\n .where(whereConditions)\n .orderBy(\"createdAt\", sort)\n .skip(skip)\n .limit(pageSize)\n .get();\n\n // Get total count\n const countResult = await collection.where(whereConditions).count();\n const total = countResult.total || 0;\n\n const records = result?.data || [];\n\n const entityList: ChatHistoryEntity[] = records.map(\n (item: ChatHistoryData) => transDataToChatEntity(item)\n );\n\n return [entityList, total];\n } catch (error) {\n console.error(\"Failed to query chat history, error:\", error);\n return [[], 0];\n }\n}\n\n// Transform data to ChatHistoryEntity structure\nexport function transDataToChatEntity(\n item: ChatHistoryData\n): ChatHistoryEntity {\n if (!item) {\n return new ChatHistoryEntity();\n }\n const chatEntity: ChatHistoryEntity = new ChatHistoryEntity();\n chatEntity.botId = item.bot_id;\n chatEntity.recordId = item.record_id;\n chatEntity.role = item.role;\n chatEntity.status = item.status;\n chatEntity.content = item.content;\n chatEntity.sender = item.sender;\n chatEntity.conversation = item.conversation;\n chatEntity.type = item.type;\n chatEntity.triggerSrc = item.trigger_src;\n chatEntity.originMsg = item.origin_msg;\n chatEntity.replyTo = item.reply_to;\n chatEntity.reply = item.reply;\n chatEntity.traceId = item.trace_id;\n chatEntity.needAsyncReply = item.need_async_reply;\n chatEntity.asyncReply = item.async_reply;\n chatEntity.createdAt = item.createdAt;\n chatEntity.updatedAt = item.updatedAt;\n return chatEntity;\n}\n\n// Query history records for LLM, get the most recent 10 conversation pairs (20 records)\nexport async function queryForLLM({\n tcbClient,\n botId,\n pageSize = 10,\n startCreatedAt,\n triggerSrc,\n}: {\n tcbClient: tcb.CloudBase;\n botId: string;\n pageSize?: number;\n startCreatedAt?: number;\n triggerSrc?: string;\n}): Promise<{ role: string; content: string }[]> {\n if (startCreatedAt === undefined) {\n startCreatedAt = Date.now() - 24 * 60 * 60 * 1000;\n }\n const recordEntityList: ChatHistoryEntity[] = [];\n\n const [recordList] = await describeChatHistory({\n tcbClient,\n botId,\n sort: \"desc\",\n pageSize,\n startCreatedAt,\n triggerSrc,\n });\n recordEntityList.push(...recordList.reverse());\n\n const entityMap = new Map<string, ChatHistoryEntity>();\n recordEntityList\n .filter((item) => {\n if (item.needAsyncReply === true) {\n return !!item.asyncReply;\n } else {\n return !!item.content;\n }\n })\n .forEach((item) => {\n entityMap.set(item.recordId, item);\n });\n\n const result: { role: string; content: string }[] = [];\n /*\n 1. Strongly depends on database history data, model history data has role order requirements\n 2. Need to ensure that no matter what bug occurs, always get a complete and usable user + assistant pair, otherwise the request will fail\n */\n recordEntityList.forEach((item) => {\n const { role, content, reply } = item;\n // When calling LLM, empty content will cause failure, so filter out conversations with empty content\n if (role === \"user\" && content?.length !== 0) {\n if (entityMap.has(reply)) {\n result.push({ role, content });\n result.push({\n role: entityMap.get(reply)!.role,\n content: entityMap.get(reply)!.content,\n });\n }\n }\n });\n if (result.length % 2 === 1) {\n result.splice(-1, 1);\n }\n return result;\n}\n\nexport interface ChatHistoryData {\n bot_id: string;\n record_id: string;\n role: string;\n status: string;\n content: string;\n sender: string;\n conversation: string;\n type: string;\n trigger_src: string;\n origin_msg: string;\n reply_to: string;\n reply: string;\n trace_id: string;\n need_async_reply: boolean;\n async_reply: string;\n createdAt: number;\n updatedAt: number;\n}\n\nexport class ChatHistoryEntity {\n id: number;\n botId: string;\n // 对话唯一id\n recordId: string;\n role: string;\n content: string;\n recommendQuestions: string[];\n sender: string;\n conversation: string;\n type: string;\n /**\n * 消息状态,pending done error cancel\n */\n status: string;\n image: string;\n triggerSrc: string;\n originMsg: string;\n replyTo: string;\n reply: string;\n traceId: string;\n needAsyncReply: boolean;\n asyncReply: string;\n createTime: string;\n updateTime: string;\n createdAt: number;\n updatedAt: number;\n event: string;\n}\n"],"mappings":";AAAA;AAAA,EAGE;AAAA,EAGA,aAAAA;AAAA,OAMK;AACP,OAAO,SAAS;AAChB,OAAO,gBAAgB;AACvB,OAAO,YAAY;AACnB,SAAS,kBAAkB;;;ACZ3B,SAAS,aAAa,KAAqB;AACzC,SAAO,IAAI,QAAQ,UAAU,CAAC,WAAW,IAAI,OAAO,YAAY,CAAC,EAAE;AACrE;AAKO,SAAS,iBAAoB,KAAW;AAC7C,MAAI,QAAQ,QAAQ,QAAQ,QAAW;AACrC,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,CAAC,SAAS,iBAAiB,IAAI,CAAC;AAAA,EACjD;AAEA,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,SAAkC,CAAC;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,YAAM,WAAW,aAAa,GAAG;AACjC,aAAO,QAAQ,IAAI,iBAAiB,KAAK;AAAA,IAC3C;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,aAAa,QAAwB;AACnD,QAAM,QAAQ;AACd,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,cAAU,MAAM,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,CAAC;AAAA,EACjE;AACA,SAAO;AACT;;;ACtCA,SAAS,iBAAiB;AAmB1B,gBAAuB,oBACrB,QACA,SACA;AACA,QAAM,EAAE,UAAU,OAAO,UAAU,IAAI;AACvC,QAAM,QAAqB;AAAA,IACzB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,cAAc,oBAAI,IAAI;AAAA,EACxB;AACA,QAAM,iBAA8B;AAAA,IAClC,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,cAAc,oBAAI,IAAI;AAAA,EACxB;AAEA,mBAAiB,SAAS,QAAQ;AAChC,UAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG;AAChC,QAAI,CAAC,MAAO;AAEZ,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM,aAAc,MAAc;AAClC,UAAI,YAAY;AACd,YAAI,MAAM,aAAa,IAAI,UAAU,GAAG;AACtC,gBAAM;AAAA,YACJ,MAAM,UAAU;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AACA,gBAAM,aAAa,OAAO,UAAU;AAAA,QACtC;AACA,cAAM;AAAA,UACJ,MAAM,UAAU;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,UACA,SAAS,MAAM,WAAW;AAAA,QAC5B;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,MAAM,SAAS;AAEjB,UAAI,eAAe,YAAY;AAC7B,uBAAe,aAAa;AAC5B,cAAM;AAAA,UACJ,MAAM,UAAU;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,cAAM;AAAA,UACJ,MAAM,UAAU;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,MAAM,YAAY;AACrB,cAAM;AAAA,UACJ,MAAM,UAAU;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,UACA,MAAM;AAAA,QACR;AACA,cAAM,aAAa;AAAA,MACrB;AAEA,YAAM,eAAe,MAAM;AAC3B,YAAM;AAAA,QACJ,MAAM,UAAU;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAGA,QAAI,MAAM,mBAAmB;AAC3B,UAAI,CAAC,eAAe,YAAY;AAC9B,cAAM;AAAA,UACJ,MAAM,UAAU;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,cAAM;AAAA,UACJ,MAAM,UAAU;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,UACA,MAAM;AAAA,QACR;AACA,uBAAe,aAAa;AAAA,MAC9B;AAEA,qBAAe,eAAe,MAAM;AACpC,YAAM;AAAA,QACJ,MAAM,UAAU;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAGA,QAAI,MAAM,YAAY;AACpB,iBAAW,YAAY,MAAM,YAAY;AACvC,cAAM,aAAa,SAAS,MAAM,QAAQ,SAAS,KAAK;AAExD,YAAI,SAAS,UAAU,MAAM;AAE3B,gBAAM;AAAA,YACJ,MAAM,UAAU;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,YACA,cAAc,SAAS,SAAS;AAAA,UAClC;AAGA,cAAI,SAAS,SAAS,WAAW;AAC/B,kBAAM;AAAA,cACJ,MAAM,UAAU;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA,OAAO,SAAS,SAAS;AAAA,YAC3B;AAAA,UACF;AAEA,gBAAM,aAAa,IAAI,YAAY;AAAA,YACjC,MAAM,SAAS,SAAS;AAAA,YACxB,MAAM,SAAS,SAAS,aAAa;AAAA,UACvC,CAAC;AAAA,QACH,WAAW,SAAS,UAAU,WAAW;AAEvC,gBAAM,WAAW,MAAM,aAAa,IAAI,UAAU;AAClD,cAAI,UAAU;AACZ,qBAAS,QAAQ,SAAS,SAAS;AAEnC,kBAAM;AAAA,cACJ,MAAM,UAAU;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA,OAAO,SAAS,SAAS;AAAA,YAC3B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,MAAM,YAAY;AACpB,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,eAAe,YAAY;AAC7B,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,aAAW,CAAC,UAAU,KAAK,MAAM,cAAc;AAC7C,UAAM;AAAA,MACJ,MAAM,UAAU;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;AFpMA,SAAS,kBAA8B;;;AGlBhC,IAAM,2BAA2B;;;ACGxC,SAAS,cAAsB;AAC7B,SAAO,YAAY,aAAa,CAAC;AACnC;AAGA,eAAsB,kBAAkB;AAAA,EACtC;AAAA,EACA;AACF,GAGgC;AAC9B,MAAI;AACF,UAAM,WAAW,kBAAkB,YAAY,YAAY;AAC3D,UAAM,OAAO;AAAA,MACX,WAAW;AAAA,MACX,QAAQ,kBAAkB;AAAA,MAC1B,MAAM,kBAAkB;AAAA,MACxB,SAAS,kBAAkB;AAAA,MAC3B,QAAQ,kBAAkB;AAAA,MAC1B,cAAc,kBAAkB;AAAA,MAChC,MAAM,kBAAkB;AAAA,MACxB,OAAO,kBAAkB;AAAA,MACzB,aAAa,kBAAkB;AAAA,MAC/B,YAAY,kBAAkB;AAAA,MAC9B,UAAU,kBAAkB;AAAA,MAC5B,OAAO,kBAAkB;AAAA,MACzB,UAAU,kBAAkB;AAAA,MAC5B,kBAAkB,kBAAkB;AAAA,MACpC,aAAa,kBAAkB;AAAA,MAC/B,WAAW,KAAK,IAAI;AAAA,MACpB,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,UAAM,KAAK,UAAU,SAAS;AAC9B,UAAM,aAAa,GAAG,WAAW,wBAAwB;AACzD,UAAM,SAAS,MAAM,WAAW,IAAI,IAAI;AAOxC,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,MAAM,gDAAgD,KAAK;AACnE,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,4BAA4B;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AACF,GAIgC;AAC9B,MAAI;AACF,UAAM,KAAK,UAAU,SAAS;AAC9B,UAAM,IAAI,GAAG;AACb,UAAM,aAAa,GAAG,WAAW,wBAAwB;AAEzD,UAAM,SAAS,MAAM,WAClB,MAAM,EAAE,WAAW,EAAE,GAAG,QAAQ,EAAE,CAAC,EACnC,OAAO;AAAA,MACN,SAAS,kBAAkB;AAAA,MAC3B,OAAO,kBAAkB;AAAA,MACzB,aAAa,kBAAkB;AAAA,MAC/B,qBAAqB,kBAAkB;AAAA,MACvC,QAAQ,kBAAkB;AAAA,MAC1B,YAAY,kBAAkB;AAAA,MAC9B,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAOH,WAAO,kBAAkB;AAAA,EAC3B,SAAS,OAAO;AACd,YAAQ,MAAM,yCAAyC,KAAK;AAC5D,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,oBAAoB;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AACF,GAS2C;AACzC,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC9B,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,KAAK,UAAU,SAAS;AAC9B,UAAM,IAAI,GAAG;AACb,UAAM,aAAa,GAAG,WAAW,wBAAwB;AAGzD,UAAM,kBAA2C;AAAA,MAC/C,QAAQ,EAAE,GAAG,KAAK;AAAA,IACpB;AAGA,QAAI,cAAc;AAChB,sBAAgB,eAAe,EAAE,GAAG,YAAY;AAAA,IAClD;AAEA,QAAI,mBAAmB,QAAW;AAChC,sBAAgB,YAAY,EAAE,GAAG,cAAc;AAAA,IACjD;AAEA,QAAI,YAAY;AACd,sBAAgB,cAAc,EAAE,GAAG,UAAU;AAAA,IAC/C;AAGA,UAAM,QAAQ,aAAa,KAAK;AAGhC,UAAM,SAAS,MAAM,WAClB,MAAM,eAAe,EACrB,QAAQ,aAAa,IAAI,EACzB,KAAK,IAAI,EACT,MAAM,QAAQ,EACd,IAAI;AAGP,UAAM,cAAc,MAAM,WAAW,MAAM,eAAe,EAAE,MAAM;AAClE,UAAM,QAAQ,YAAY,SAAS;AAEnC,UAAM,UAAU,QAAQ,QAAQ,CAAC;AAEjC,UAAM,aAAkC,QAAQ;AAAA,MAC9C,CAAC,SAA0B,sBAAsB,IAAI;AAAA,IACvD;AAEA,WAAO,CAAC,YAAY,KAAK;AAAA,EAC3B,SAAS,OAAO;AACd,YAAQ,MAAM,wCAAwC,KAAK;AAC3D,WAAO,CAAC,CAAC,GAAG,CAAC;AAAA,EACf;AACF;AAGO,SAAS,sBACd,MACmB;AACnB,MAAI,CAAC,MAAM;AACT,WAAO,IAAI,kBAAkB;AAAA,EAC/B;AACA,QAAM,aAAgC,IAAI,kBAAkB;AAC5D,aAAW,QAAQ,KAAK;AACxB,aAAW,WAAW,KAAK;AAC3B,aAAW,OAAO,KAAK;AACvB,aAAW,SAAS,KAAK;AACzB,aAAW,UAAU,KAAK;AAC1B,aAAW,SAAS,KAAK;AACzB,aAAW,eAAe,KAAK;AAC/B,aAAW,OAAO,KAAK;AACvB,aAAW,aAAa,KAAK;AAC7B,aAAW,YAAY,KAAK;AAC5B,aAAW,UAAU,KAAK;AAC1B,aAAW,QAAQ,KAAK;AACxB,aAAW,UAAU,KAAK;AAC1B,aAAW,iBAAiB,KAAK;AACjC,aAAW,aAAa,KAAK;AAC7B,aAAW,YAAY,KAAK;AAC5B,aAAW,YAAY,KAAK;AAC5B,SAAO;AACT;AAGA,eAAsB,YAAY;AAAA,EAChC;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAMiD;AAC/C,MAAI,mBAAmB,QAAW;AAChC,qBAAiB,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK;AAAA,EAC/C;AACA,QAAM,mBAAwC,CAAC;AAE/C,QAAM,CAAC,UAAU,IAAI,MAAM,oBAAoB;AAAA,IAC7C;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,mBAAiB,KAAK,GAAG,WAAW,QAAQ,CAAC;AAE7C,QAAM,YAAY,oBAAI,IAA+B;AACrD,mBACG,OAAO,CAAC,SAAS;AAChB,QAAI,KAAK,mBAAmB,MAAM;AAChC,aAAO,CAAC,CAAC,KAAK;AAAA,IAChB,OAAO;AACL,aAAO,CAAC,CAAC,KAAK;AAAA,IAChB;AAAA,EACF,CAAC,EACA,QAAQ,CAAC,SAAS;AACjB,cAAU,IAAI,KAAK,UAAU,IAAI;AAAA,EACnC,CAAC;AAEH,QAAM,SAA8C,CAAC;AAKrD,mBAAiB,QAAQ,CAAC,SAAS;AACjC,UAAM,EAAE,MAAM,SAAS,MAAM,IAAI;AAEjC,QAAI,SAAS,UAAU,SAAS,WAAW,GAAG;AAC5C,UAAI,UAAU,IAAI,KAAK,GAAG;AACxB,eAAO,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC7B,eAAO,KAAK;AAAA,UACV,MAAM,UAAU,IAAI,KAAK,EAAG;AAAA,UAC5B,SAAS,UAAU,IAAI,KAAK,EAAG;AAAA,QACjC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AACD,MAAI,OAAO,SAAS,MAAM,GAAG;AAC3B,WAAO,OAAO,IAAI,CAAC;AAAA,EACrB;AACA,SAAO;AACT;AAsBO,IAAM,oBAAN,MAAwB;AA4B/B;;;AJ1RO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAE1C,YAAY,SAAiB,MAAe;AAC1C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,QAAI,KAAM,MAAK,OAAO;AAAA,EACxB;AACF;AAEO,IAAM,cAAN,cAA0B,cAAc;AAAA,EAS7C,YAAY,QAAsD;AAChE,UAAM,MAAM;AAPd,SAAQ,uBAIJ,CAAC;AAIH,SAAK,eAAe,OAAO;AAC3B,SAAK,QAAQ,IAAI,OAAO;AAAA,MACtB,QAAQ;AAAA,MACR,SACE,KAAK,aAAa,SAAS,WAC3B;AAAA,IACJ,CAAC;AACD,SAAK,aACH,KAAK,aAAa,SAClB,KAAK,aAAa,SAAS,MAAM,eACjC,QAAQ,IAAI,iBACZ;AACF,SAAK,uBAAuB;AAAA,MAC1B,UACE,KAAK,aAAa,YAAY,YAC9B,QAAQ,IAAI;AAAA,MACd,WACE,KAAK,aAAa,YAAY,aAC9B,QAAQ,IAAI;AAAA,MACd,OACE,KAAK,aAAa,YAAY,SAC9B,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,oBAAoB;AAAA,IAClB;AAAA,IACA;AAAA,EACF,GAGsB;AACpB,UAAM,EAAE,OAAO,eAAe,IAAI;AAClC,UAAM,cAAiC;AAAA,MACrC,QAAQ;AAAA,MACR,GAAI,KAAK,aAAa,SAAS,QAAQ,CAAC;AAAA,MACxC,GAAI,kBAAkB,CAAC;AAAA,MAEvB,aAAa,KAAK;AAAA,MAClB,QACE,OAAO,qBAAqB,MAC5B,gBAAgB,UAChB,WAAW;AAAA,MACb;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,OAA6C;AAC/C,WAAO,IAAI,WAAsB,CAAC,eAAe;AAC/C,WAAK,KAAK,YAAY,KAAK;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,KACZ,YACA,OACe;AACf,QAAI;AACF,YAAM,EAAE,UAAU,MAAM,IAAI;AAE5B,YAAM,SAAS,KAAK;AACpB,YAAM,WAAW,MAAM,YAAY,WAAW;AAE9C,iBAAW,KAAK;AAAA,QACd,MAAMC,WAAU;AAAA,QAChB;AAAA,QACA;AAAA,MACF,CAAoB;AAEpB,UAAI,CAAC,KAAK,YAAY;AACpB,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,KAAK,aAAa,UAAU,CAAC,QAAQ,IAAI,gBAAgB;AAC5D,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAGA,YAAM,eAAe,SAAS,SAAS;AACvC,UAAI,eAAe,GAAG;AACpB,mBAAW,KAAK;AAAA,UACd,MAAMA,WAAU;AAAA,UAChB,UAAU;AAAA,YACR,SAAS,6DAA6D,YAAY;AAAA,YAClF,MAAM;AAAA,UACR;AAAA,QACF,CAAC;AAAA,MACH;AAGA,YAAM,oBAAoB,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,IAAI;AACxE,UAAI,CAAC,mBAAmB;AACtB,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,YAAM,cAAc,MAAM,KAAK;AAAA,QAC7B;AAAA,QACA;AAAA,MACF;AAEA,YAAM,OAAO,KAAK,oBAAoB;AAAA,QACpC,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAED,YAAM,SAAS,MAAM,OAAO,KAAK,YAAY;AAAA,QAC3C;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,CAAC;AAAA,UACX,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,MAAM,iBAAiB,IAAI;AAAA,UAC3B,SAAS;AAAA,YACP,GAAG,KAAK,aAAa,SAAS;AAAA,YAC9B,eAAe,UACb,KAAK,aAAa,UAAU,QAAQ,IAAI,cAC1C;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,YAAM,eAAe,UAAU,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC;AACvD,YAAM,oBAAoB,UAAU,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC;AAC5D,YAAM,UAAU,EAAE,UAAU,OAAO,WAAW,aAAa;AAE3D,UAAI,uBAAuB;AAE3B,uBAAiB,SAAS,oBAAoB,QAAQ,OAAO,GAAG;AAC9D,mBAAW,KAAK,KAAK;AAErB,YACE,MAAM,SAASA,WAAU,wBACxB,MAAkC,OACnC;AACA,kCAAyB,MAAkC;AAAA,QAC7D;AAAA,MACF;AAEA,YAAM,cACJ,OAAO,mBAAmB,YAAY,WAClC,kBAAkB,UAClB,mBAAmB,SACf,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAChC,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,EAAE,KAAK;AAErB,YAAM,KAAK;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,iBAAW,KAAK;AAAA,QACd,MAAMA,WAAU;AAAA,QAChB;AAAA,QACA;AAAA,MACF,CAAqB;AAAA,IACvB,SAAS,GAAY;AACnB,cAAQ,MAAM,4BAA4B,KAAK,UAAU,CAAC,CAAC;AAC3D,UAAI,OAAO;AACX,UAAI,UAAU,KAAK,UAAU,CAAC;AAC9B,UAAI,aAAa,kBAAkB;AACjC,eAAO,EAAE,QAAQ;AACjB,kBAAU,EAAE;AAAA,MACd,WAAW,aAAa,OAAO;AAC7B,eAAO,EAAE,QAAQ;AACjB,kBAAU,EAAE;AAAA,MACd;AACA,iBAAW,KAAK;AAAA,QACd,MAAMA,WAAU;AAAA,QAChB;AAAA,QACA,SAAS,gEAAgE,IAAI,KAAK,OAAO;AAAA,MAC3F,CAAkB;AAAA,IACpB,UAAE;AACA,iBAAW,SAAS;AAAA,IACtB;AAAA,EACF;AAAA;AAAA,EAGA,MAAgB,eACd,YACA,mBACA;AACA,UAAM,QAAQ,cAAc,KAAK,UAAU;AAE3C,UAAM,YAAY,KAAK,aAAa;AAEpC,UAAM,YAAY,MAAM,KAAK,qBAAqB;AAClD,QAAI,CAAC,WAAW;AACd,iBAAW,KAAK;AAAA,QACd,MAAMA,WAAU;AAAA,QAChB,UAAU;AAAA,UACR,SAAS;AAAA,UACT,MAAM;AAAA,QACR;AAAA,MACF,CAAC;AACD,aAAO,wBAAwB,CAAC,iBAAiB,CAAC;AAAA,IACpD;AAGA,QAAI,kBAAiC,CAAC;AAEtC,UAAM,eAAe,KAAK,aAAa,gBAAgB;AACvD,UAAM,iBAAiB,MAAM,YAAY;AAAA,MACvC;AAAA,MACA;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAGD,sBAAkB,eAAe,IAAI,CAAC,YAAY;AAAA,MAChD,MAAM,OAAO;AAAA,MACb,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,QAAQ,CAAC;AAAA,IAC3D,EAAE;AAGF,UAAM,cAAc,gBAAgB;AAAA,MAClC,wBAAwB,CAAC,iBAAiB,CAAC;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAgB,gBACd,YACA,OACA,cACA,mBACA,aACA,kBACA;AACA,UAAM,QAAQ,cAAc,KAAK,UAAU;AAE3C,UAAM,EAAE,UAAU,MAAM,IAAI;AAE5B,UAAM,YAAY,KAAK,aAAa;AAEpC,UAAM,YAAY,MAAM,KAAK,qBAAqB;AAClD,QAAI,CAAC,WAAW;AACd,iBAAW,KAAK;AAAA,QACd,MAAMA,WAAU;AAAA,QAChB,UAAU;AAAA,UACR,SAAS;AAAA,UACT,MAAM;AAAA,QACR;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAGA,UAAM,aAAa,IAAI,kBAAkB;AACzC,eAAW,WAAW;AACtB,eAAW,QAAQ;AACnB,eAAW,OAAO;AAClB,eAAW,UAAU;AACrB,eAAW,eAAe;AAC1B,eAAW,QAAQ;AACnB,eAAW,aAAa;AACxB,eAAW,UAAU,WAAW;AAEhC,UAAM,kBAAkB,EAAE,WAAW,mBAAmB,WAAW,CAAC;AAEpE,UAAM,kBAAkB,IAAI,kBAAkB;AAC9C,oBAAgB,WAAW;AAC3B,oBAAgB,QAAQ;AACxB,oBAAgB,OAAO;AACvB,oBAAgB,UAAU;AAC1B,oBAAgB,eAAe;AAC/B,oBAAgB,UAAU;AAC1B,oBAAgB,aAAa;AAC7B,oBAAgB,UAAU;AAC1B,oBAAgB,SAAS;AAEzB,UAAM,kBAAkB;AAAA,MACtB;AAAA,MACA,mBAAmB;AAAA,IACrB,CAAC;AAAA,EACH;AAAA,EAEQ,eAAe;AACrB,UAAM,QAAQ,KAAK,aAAa,SAAS,kBAAkB;AAE3D,UAAM,YAAY,IAAI,KAAK;AAAA,MACzB,KAAK;AAAA,MACL,UAAU,KAAK,qBAAqB;AAAA,MACpC,WAAW,KAAK,qBAAqB;AAAA,MACrC,cAAc,KAAK,qBAAqB;AAAA,IAC1C,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,uBAAuB;AACnC,QAAI;AACF,YAAM,QAAQ,KAAK,aAAa,SAAS,kBAAkB;AAC3D,UAAI,CAAC,OAAO;AACV,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,KAAK,qBAAqB,OAAO;AACpC,YAAI,CAAC,KAAK,qBAAqB,UAAU;AACvC,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,YAAI,CAAC,KAAK,qBAAqB,WAAW;AACxC,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,YAAM,mBAAmB,WAAW,KAAK;AAAA,QACvC;AAAA,QACA,UAAU,KAAK,qBAAqB;AAAA,QACpC,WAAW,KAAK,qBAAqB;AAAA,QACrC,OAAO,KAAK,qBAAqB;AAAA,MACnC,CAAC;AAED,YAAM,aAAa,MAAM,iBAAiB,SAAS;AAAA,QACjD;AAAA,MACF;AACA,UAAI,cAAc,WAAW,QAAQ;AACnC,eAAO;AAAA,MACT,WAAW,cAAc,CAAC,WAAW,QAAQ;AAC3C,cAAM,iBAAiB,SAAS;AAAA,UAC9B;AAAA,QACF;AACA,eAAO;AAAA,MACT,OAAO;AACL,cAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AAAA,IACF,SAAS,SAAS;AAChB,cAAQ;AAAA,QACN;AAAA,QACA,KAAK,UAAU,OAAO;AAAA,MACxB;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB;AAC3B,MAAI,QAAQ,IAAI,YAAY;AAC1B,WAAO,QAAQ,IAAI;AAAA,EACrB,WAAW,QAAQ,IAAI,eAAe;AACpC,WAAO,QAAQ,IAAI;AAAA,EACrB,OAAO;AACL,WAAO,QAAQ,IAAI,oBAAoB;AAAA,EACzC;AACF;AAKO,SAAS,wBACd,UACA,cACe;AACf,QAAM,iBAAgC,CAAC;AAGvC,MAAI,cAAc;AAChB,mBAAe,KAAK;AAAA,MAClB,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,aAAW,OAAO,UAAU;AAC1B,QAAI,IAAI,SAAS,QAAQ;AACvB,qBAAe,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,SACE,OAAO,IAAI,YAAY,WACnB,CAAC,EAAE,MAAM,QAAQ,MAAM,IAAI,QAAQ,CAAC,IACpC,IAAI,QAAQ,IAAI,CAAC,SAAS;AACxB,cAAI,KAAK,SAAS,QAAQ;AACxB,mBAAO,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK;AAAA,UACzC,OAAO;AACL,mBAAO;AAAA,cACL,MAAM;AAAA,cACN,WAAW,EAAE,KAAK,KAAK,OAAO,GAAG;AAAA,YACnC;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACT,CAAC;AAAA,IACH,WAAW,IAAI,SAAS,aAAa;AACnC,qBAAe,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,SAAS,IAAI,UAAU,CAAC,EAAE,MAAM,QAAQ,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC;AAAA,QAChE,YAAY,IAAI,WAAW,IAAI,CAAC,QAAkB;AAAA,UAChD,IAAI,GAAG;AAAA,UACP,MAAM;AAAA,UACN,UAAU;AAAA,YACR,MAAM,GAAG,SAAS;AAAA,YAClB,WAAW,GAAG,SAAS;AAAA,UACzB;AAAA,QACF,EAAE;AAAA,MACJ,CAAC;AAAA,IACH,WAAW,IAAI,SAAS,QAAQ;AAC9B,qBAAe,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,cAAc,IAAI;AAAA,QAClB,SAAS,IAAI,UAAU,CAAC,EAAE,MAAM,QAAQ,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC;AAAA,MAClE,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;","names":["EventType","EventType"]}
|