@cloudbase/agent-adapter-yuanqi 0.0.16 → 0.0.18

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 CHANGED
@@ -8,6 +8,7 @@ Tencent Yuanqi adapter for AG-Kit agents. This package provides integration betw
8
8
  - ✅ **Streaming Support**: Real-time streaming responses via OpenAI-compatible API
9
9
  - ✅ **Thinking/Reasoning Support**: Handles reasoning content from Yuanqi models with thinking events
10
10
  - ✅ **Custom Variables**: Pass custom parameters to Yuanqi agents
11
+ - ✅ **Chat History Persistence**: Automatic conversation history storage via Tencent CloudBase
11
12
 
12
13
  ## Installation
13
14
 
@@ -19,9 +20,24 @@ npm install @cloudbase/agent-adapter-yuanqi
19
20
 
20
21
  Configure the following environment variables:
21
22
 
23
+ **Important**: If chat history behavior is not overridden, chat history will be stored in Tencent CloudBase as default. Please ensure that the necessary environment variables are set for CloudBase authentication.
24
+
22
25
  ```bash
23
- YUANQI_APP_ID=your-yuanqi-assistant-id # Yuanqi assistant ID (required)
24
- YUANQI_APP_KEY=your-yuanqi-app-key # Yuanqi application key (required)
26
+ # Yuanqi Configuration (required)
27
+ YUANQI_APP_ID=your-yuanqi-assistant-id # Yuanqi assistant ID
28
+ YUANQI_APP_KEY=your-yuanqi-app-key # Yuanqi application key
29
+
30
+ # CloudBase Configuration (required for chat history persistence)
31
+ CLOUDBASE_ENV_ID=your-cloudbase-env-id # CloudBase environment ID
32
+ # Alternative env names: CBR_ENV_ID or SCF_NAMESPACE are also supported
33
+
34
+ # Tencent Cloud Credentials (required for chat history persistence)
35
+ # Option 1: Use SecretId + SecretKey (permanent credentials)
36
+ TENCENTCLOUD_SECRETID=your-secret-id
37
+ TENCENTCLOUD_SECRETKEY=your-secret-key
38
+
39
+ # Option 2: Use Session Token (temporary credentials, e.g., in cloud functions)
40
+ TENCENTCLOUD_SESSIONTOKEN=your-session-token
25
41
  ```
26
42
 
27
43
  ## Quick Start
@@ -33,13 +49,19 @@ import { YuanqiAgent } from "@cloudbase/agent-adapter-yuanqi";
33
49
 
34
50
  const agent = new YuanqiAgent({
35
51
  yuanqiConfig: {
36
- appId: process.env.YUANQI_APP_ID, // Or set via YUANQI_APP_ID env
37
- appKey: process.env.YUANQI_APP_KEY, // Or set via YUANQI_APP_KEY env
52
+ appId: "your-assistant-id",
53
+ appKey: "your-app-key",
54
+ envId: "your-cloudbase-env-id", // Or set via CLOUDBASE_ENV_ID env
55
+ credential: {
56
+ secretId: "your-secret-id", // Or set via TENCENTCLOUD_SECRETID env
57
+ secretKey: "your-secret-key", // Or set via TENCENTCLOUD_SECRETKEY env
58
+ token: "your-session-token", // Optional, for temporary credentials
59
+ },
38
60
  },
39
61
  });
40
62
  ```
41
63
 
42
- ### With Custom Configuration
64
+ ### With Full Custom Configuration
43
65
 
44
66
  ```typescript
45
67
  import { YuanqiAgent } from "@cloudbase/agent-adapter-yuanqi";
@@ -48,6 +70,11 @@ const agent = new YuanqiAgent({
48
70
  yuanqiConfig: {
49
71
  appId: "your-assistant-id",
50
72
  appKey: "your-app-key",
73
+ envId: "your-cloudbase-env-id",
74
+ credential: {
75
+ secretId: "your-secret-id",
76
+ secretKey: "your-secret-key",
77
+ },
51
78
  request: {
52
79
  baseUrl: "https://yuanqi.tencent.com/openapi/v1/agent", // Default base URL
53
80
  body: {
@@ -106,18 +133,47 @@ Agent class that extends `AbstractAgent` from `@ag-ui/client` and connects to Te
106
133
  constructor(config: AgentConfig & { yuanqiConfig: YuanqiConfig })
107
134
  ```
108
135
 
136
+ **Overridable Methods:**
137
+
138
+ The following protected methods can be overridden in subclasses to customize chat history behavior:
139
+
140
+ ```typescript
141
+ // Get chat history from database and combine with current message
142
+ protected async getChatHistory(
143
+ subscriber: Subscriber<BaseEvent>,
144
+ latestUserMessage: Message
145
+ ): Promise<ChatMessage[]>
146
+
147
+ // Save user and assistant messages to chat history
148
+ protected async saveChatHistory(
149
+ subscriber: Subscriber<BaseEvent>,
150
+ input: RunAgentInput,
151
+ userRecordId: string,
152
+ assistantRecordId: string,
153
+ userContent: string,
154
+ assistantContent: string
155
+ ): Promise<void>
156
+ ```
157
+
109
158
  ### YuanqiConfig
110
159
 
111
160
  Configuration options for the Yuanqi adapter.
112
161
 
113
162
  ```typescript
114
163
  interface YuanqiConfig {
115
- appId?: string; // Yuanqi assistant ID (optional if YUANQI_APP_ID env is set)
116
- appKey?: string; // Yuanqi app key (optional if YUANQI_APP_KEY env is set)
164
+ appId?: string; // Yuanqi assistant ID (optional if YUANQI_APP_ID env is set)
165
+ appKey?: string; // Yuanqi app key (optional if YUANQI_APP_KEY env is set)
166
+ envId?: string; // CloudBase environment ID (optional if CLOUDBASE_ENV_ID env is set)
167
+ historyCount?: number; // Number of history messages to fetch (default: 10)
168
+ credential?: {
169
+ secretId?: string; // Tencent Cloud SecretId (optional if TENCENTCLOUD_SECRETID env is set)
170
+ secretKey?: string; // Tencent Cloud SecretKey (optional if TENCENTCLOUD_SECRETKEY env is set)
171
+ token?: string; // Session token for temporary credentials (optional)
172
+ };
117
173
  request?: {
118
- baseUrl?: string; // Base URL (default: https://yuanqi.tencent.com/openapi/v1/agent)
174
+ baseUrl?: string; // Base URL (default: https://yuanqi.tencent.com/openapi/v1/agent)
119
175
  body?: Partial<YuanqiChatRequest>; // Additional request body options
120
- headers?: Record<string, string>; // Additional request headers
176
+ headers?: Record<string, string>; // Additional request headers
121
177
  };
122
178
  }
123
179
  ```
@@ -138,6 +194,153 @@ interface YuanqiChatRequest {
138
194
  }
139
195
  ```
140
196
 
197
+ ### YuanqiAgentError
198
+
199
+ Custom error class for Yuanqi-specific errors.
200
+
201
+ ```typescript
202
+ class YuanqiAgentError extends Error {
203
+ code?: string;
204
+ constructor(message: string, code?: string);
205
+ }
206
+ ```
207
+
208
+ Error codes include:
209
+ - `MISSING_YUANQI_APP_ID` - Yuanqi assistant ID not provided
210
+ - `MISSING_YUANQI_APP_KEY` - Yuanqi app key not provided
211
+ - `MISSING_CLOUDBASE_ENV_ID` - CloudBase environment ID not provided
212
+ - `MISSING_SECRET_ID` - Tencent Cloud SecretId not provided
213
+ - `MISSING_SECRET_KEY` - Tencent Cloud SecretKey not provided
214
+ - `MESSAGE_FORMAT_ERROR` - No user message found in the request
215
+
216
+ ### processYuanqiStream
217
+
218
+ Utility function to process Yuanqi streaming responses and emit AG-UI events.
219
+
220
+ ```typescript
221
+ async function* processYuanqiStream(
222
+ stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,
223
+ context: StreamContext
224
+ ): AsyncGenerator<BaseEvent>
225
+
226
+ interface StreamContext {
227
+ threadId: string;
228
+ runId: string;
229
+ messageId: string;
230
+ }
231
+ ```
232
+
233
+ ### ChatHistoryEntity
234
+
235
+ Entity class for chat history records stored in CloudBase.
236
+
237
+ ```typescript
238
+ class ChatHistoryEntity {
239
+ id: number;
240
+ botId: string;
241
+ recordId: string; // Unique conversation ID
242
+ role: string; // "user" or "assistant"
243
+ content: string;
244
+ recommendQuestions: string[];
245
+ sender: string;
246
+ conversation: string;
247
+ type: string;
248
+ status: string; // Message status: pending, done, error, cancel
249
+ image: string;
250
+ triggerSrc: string;
251
+ originMsg: string;
252
+ replyTo: string;
253
+ reply: string;
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;
286
+ createdAt: number;
287
+ updatedAt: number;
288
+ }
289
+ ```
290
+
291
+ ### Chat History Utilities
292
+
293
+ The package exports utility functions for chat history management:
294
+
295
+ ```typescript
296
+ // Create a new chat history record
297
+ function createChatHistory(params: {
298
+ tcbClient: tcb.CloudBase;
299
+ chatHistoryEntity: ChatHistoryEntity;
300
+ }): Promise<string | undefined>
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
+
324
+ // Query chat history for LLM context
325
+ function queryForLLM(params: {
326
+ tcbClient: tcb.CloudBase;
327
+ botId: string;
328
+ pageSize?: number;
329
+ startCreatedAt?: number;
330
+ triggerSrc?: string;
331
+ }): Promise<{ role: string; content: string }[]>
332
+ ```
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
+
141
344
  ### Supported Events
142
345
 
143
346
  The adapter emits the following AG-UI events:
@@ -155,9 +358,39 @@ The adapter emits the following AG-UI events:
155
358
  **Tool Calls:**
156
359
  - `TOOL_CALL_START` / `TOOL_CALL_ARGS` / `TOOL_CALL_END` - Tool call events
157
360
 
361
+ **Raw Events:**
362
+ - `RAW` - Custom raw events (e.g., message trimming warnings, database error notifications)
363
+
364
+ ## Message History Handling
365
+
366
+ The adapter manages message history through CloudBase database. When you pass multiple messages to the agent:
367
+
368
+ - **Only the latest user message** is used for the current request
369
+ - Previous messages are trimmed and a `RAW` event with `type: "warn"` is emitted to notify you
370
+ - Historical context is automatically loaded from the database (up to `historyCount` messages, default: 10)
371
+ - History messages are fetched as complete user-assistant pairs to ensure valid conversation context
372
+
373
+ This design ensures consistent conversation context management through the database rather than relying on client-side message arrays.
374
+
375
+ ## Chat History Persistence
376
+
377
+ ### Requirements
378
+
379
+ The adapter uses a collection named `ai_bot_chat_history_5hobd2b` to store chat history. The collection will be automatically created if it doesn't exist. To enable chat history persistence, ensure:
380
+
381
+ 1. `CLOUDBASE_ENV_ID` (or `CBR_ENV_ID`/`SCF_NAMESPACE`) environment variable is set
382
+ 2. Valid Tencent Cloud credentials are configured via:
383
+ - `TENCENTCLOUD_SECRETID` + `TENCENTCLOUD_SECRETKEY`, or
384
+ - `TENCENTCLOUD_SESSIONTOKEN` (for temporary credentials in cloud functions)
385
+ 3. The CloudBase environment has database access enabled
386
+
387
+ **Important**: If chat history behavior is not overridden, chat history will be stored in Tencent CloudBase as default. Please ensure that the necessary environment variables are set for CloudBase authentication.
388
+
158
389
  ## Dependencies
159
390
 
160
391
  - `@ag-ui/client`: AG-UI client protocol (provides `AbstractAgent` base class)
392
+ - `@cloudbase/node-sdk`: Tencent CloudBase Node.js SDK for database operations
393
+ - `@cloudbase/manager-node`: Tencent CloudBase Manager for collection management
161
394
  - `openai`: OpenAI SDK for API compatibility
162
395
  - `rxjs`: Reactive extensions for JavaScript
163
396
 
@@ -165,3 +398,4 @@ The adapter emits the following AG-UI events:
165
398
 
166
399
  - [Tencent Yuanqi](https://yuanqi.tencent.com/)
167
400
  - [Yuanqi API Documentation](https://yuanqi.tencent.com/guide/publish-agent-api-documentation)
401
+ - [Tencent CloudBase Documentation](https://docs.cloudbase.net/)
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
- import { AbstractAgent, AgentConfig, RunAgentInput, BaseEvent, Message } from '@ag-ui/client';
1
+ import { AbstractAgent, AgentConfig, RunAgentInput, BaseEvent, Message, EventType } from '@ag-ui/client';
2
2
  import OpenAI from 'openai';
3
- import { Observable } from 'rxjs';
3
+ import { Observable, Subscriber } from 'rxjs';
4
+ import tcb from '@cloudbase/node-sdk';
4
5
 
5
6
  interface YuanqiConfig {
6
7
  request?: {
@@ -10,6 +11,13 @@ interface YuanqiConfig {
10
11
  };
11
12
  appId?: string;
12
13
  appKey?: string;
14
+ envId?: string;
15
+ credential?: {
16
+ secretId?: string;
17
+ secretKey?: string;
18
+ token?: string;
19
+ };
20
+ historyCount?: number;
13
21
  }
14
22
  type ChatMessage = OpenAI.Chat.Completions.ChatCompletionMessageParam;
15
23
  interface YuanqiChatRequest {
@@ -22,9 +30,15 @@ interface YuanqiChatRequest {
22
30
  chatType?: "published" | "preview";
23
31
  [key: string]: any;
24
32
  }
33
+
34
+ declare class YuanqiAgentError extends Error {
35
+ code?: string;
36
+ constructor(message: string, code?: string);
37
+ }
25
38
  declare class YuanqiAgent extends AbstractAgent {
26
39
  protected yuanqiConfig: YuanqiConfig;
27
40
  private finalAppId;
41
+ private finalCloudCredential;
28
42
  private model;
29
43
  constructor(config: AgentConfig & {
30
44
  yuanqiConfig: YuanqiConfig;
@@ -35,15 +49,180 @@ declare class YuanqiAgent extends AbstractAgent {
35
49
  }): YuanqiChatRequest;
36
50
  run(input: RunAgentInput): Observable<BaseEvent>;
37
51
  private _run;
52
+ protected getChatHistory(subscriber: Subscriber<BaseEvent>, latestUserMessage: Message): Promise<OpenAI.Chat.Completions.ChatCompletionMessageParam[]>;
53
+ protected saveChatHistory(subscriber: Subscriber<BaseEvent>, input: RunAgentInput, userRecordId: string, assistantRecordId: string, userContent: string, assistantContent: string): Promise<void>;
54
+ private getTcbClient;
55
+ private checkIsDatabaseReady;
38
56
  }
39
57
  /**
40
58
  * Convert AGUI messages to OpenAI chat completion format
41
59
  */
42
- declare function convertMessagesToOpenAI(messages: Message[], systemPrompt?: string): OpenAI.Chat.ChatCompletionMessageParam[];
60
+ declare function convertMessagesToOpenAI(messages: Message[], systemPrompt?: string): ChatMessage[];
43
61
 
44
- /**
45
- * 递归地将对象的所有小驼峰属性名转换为下划线格式
46
- */
47
- declare function camelToSnakeKeys<T>(obj: T): T;
62
+ interface StreamContext {
63
+ threadId: string;
64
+ runId: string;
65
+ messageId: string;
66
+ }
67
+ interface StreamState {
68
+ hasStarted: boolean;
69
+ fullContent: string;
70
+ toolCallsMap: Map<string, {
71
+ name: string;
72
+ args: string;
73
+ }>;
74
+ }
75
+ type Delta = OpenAI.Chat.Completions.ChatCompletionChunk["choices"][number]["delta"] & {
76
+ reasoning_content?: string;
77
+ };
78
+ declare function processYuanqiStream(stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>, context: StreamContext): AsyncGenerator<{
79
+ type: EventType;
80
+ threadId: string;
81
+ runId: string;
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;
95
+ role?: undefined;
96
+ delta?: undefined;
97
+ toolCallName?: undefined;
98
+ } | {
99
+ type: EventType;
100
+ threadId: string;
101
+ runId: string;
102
+ messageId: string;
103
+ toolCallId?: undefined;
104
+ content?: undefined;
105
+ role?: undefined;
106
+ delta?: undefined;
107
+ toolCallName?: undefined;
108
+ } | {
109
+ type: EventType;
110
+ threadId: string;
111
+ runId: string;
112
+ messageId: string;
113
+ role: string;
114
+ toolCallId?: undefined;
115
+ content?: undefined;
116
+ delta?: undefined;
117
+ toolCallName?: undefined;
118
+ } | {
119
+ type: EventType;
120
+ threadId: string;
121
+ runId: string;
122
+ messageId: string;
123
+ delta: string;
124
+ toolCallId?: undefined;
125
+ content?: undefined;
126
+ role?: undefined;
127
+ toolCallName?: undefined;
128
+ } | {
129
+ type: EventType;
130
+ threadId: string;
131
+ runId: string;
132
+ toolCallId: string;
133
+ toolCallName: string;
134
+ content?: undefined;
135
+ messageId?: undefined;
136
+ role?: undefined;
137
+ delta?: undefined;
138
+ } | {
139
+ type: EventType;
140
+ threadId: string;
141
+ runId: string;
142
+ toolCallId: string;
143
+ delta: string;
144
+ content?: undefined;
145
+ messageId?: undefined;
146
+ role?: undefined;
147
+ toolCallName?: undefined;
148
+ }, void, unknown>;
149
+
150
+ declare function createChatHistory({ tcbClient, chatHistoryEntity, }: {
151
+ tcbClient: tcb.CloudBase;
152
+ chatHistoryEntity: ChatHistoryEntity;
153
+ }): Promise<string | undefined>;
154
+ declare function updateChatHistoryByRecordId({ tcbClient, recordId, chatHistoryEntity, }: {
155
+ tcbClient: tcb.CloudBase;
156
+ recordId: string;
157
+ chatHistoryEntity: ChatHistoryEntity;
158
+ }): Promise<string | undefined>;
159
+ declare function describeChatHistory({ tcbClient, botId, sort, pageSize, pageNumber, conversation, startCreatedAt, triggerSrc, }: {
160
+ tcbClient: tcb.CloudBase;
161
+ botId: string;
162
+ sort: "asc" | "desc";
163
+ pageSize?: number;
164
+ pageNumber?: number;
165
+ conversation?: string;
166
+ startCreatedAt?: number;
167
+ triggerSrc?: string;
168
+ }): Promise<[ChatHistoryEntity[], number]>;
169
+ declare function transDataToChatEntity(item: ChatHistoryData): ChatHistoryEntity;
170
+ declare function queryForLLM({ tcbClient, botId, pageSize, startCreatedAt, triggerSrc, }: {
171
+ tcbClient: tcb.CloudBase;
172
+ botId: string;
173
+ pageSize?: number;
174
+ startCreatedAt?: number;
175
+ triggerSrc?: string;
176
+ }): Promise<{
177
+ role: string;
178
+ content: string;
179
+ }[]>;
180
+ interface ChatHistoryData {
181
+ bot_id: string;
182
+ record_id: string;
183
+ role: string;
184
+ status: string;
185
+ content: string;
186
+ sender: string;
187
+ conversation: string;
188
+ type: string;
189
+ trigger_src: string;
190
+ origin_msg: string;
191
+ reply_to: string;
192
+ reply: string;
193
+ trace_id: string;
194
+ need_async_reply: boolean;
195
+ async_reply: string;
196
+ createdAt: number;
197
+ updatedAt: number;
198
+ }
199
+ declare class ChatHistoryEntity {
200
+ id: number;
201
+ botId: string;
202
+ recordId: string;
203
+ role: string;
204
+ content: string;
205
+ recommendQuestions: string[];
206
+ sender: string;
207
+ conversation: string;
208
+ type: string;
209
+ /**
210
+ * 消息状态,pending done error cancel
211
+ */
212
+ status: string;
213
+ image: string;
214
+ triggerSrc: string;
215
+ originMsg: string;
216
+ replyTo: string;
217
+ reply: string;
218
+ traceId: string;
219
+ needAsyncReply: boolean;
220
+ asyncReply: string;
221
+ createTime: string;
222
+ updateTime: string;
223
+ createdAt: number;
224
+ updatedAt: number;
225
+ event: string;
226
+ }
48
227
 
49
- export { type ChatMessage, YuanqiAgent, type YuanqiChatRequest, type YuanqiConfig, camelToSnakeKeys, convertMessagesToOpenAI };
228
+ export { type ChatHistoryData, ChatHistoryEntity, type ChatMessage, type Delta, type StreamContext, type StreamState, YuanqiAgent, YuanqiAgentError, type YuanqiChatRequest, type YuanqiConfig, convertMessagesToOpenAI, createChatHistory, describeChatHistory, processYuanqiStream, queryForLLM, transDataToChatEntity, updateChatHistoryByRecordId };