@cloudbase/agent-adapter-adp 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 CHANGED
@@ -168,8 +168,8 @@ const observable = agent.run({
168
168
 
169
169
  **Supported file types:**
170
170
 
171
- - **Images**: `image/png`, `image/jpeg`, `image/gif`, `image/webp`, `image/bmp`
172
- - **Documents**: `application/pdf`, `application/msword`, `application/vnd.openxmlformats-officedocument.wordprocessingml.document`, `text/markdown`, `text/plain`
171
+ - **Images**: `image/png`, `image/jpeg`, `image/bmp`
172
+ - **Documents**: `application/pdf`, `application/msword`, `application/vnd.openxmlformats-officedocument.wordprocessingml.document`, `application/vnd.ms-powerpoint`, `application/vnd.openxmlformats-officedocument.presentationml.presentation`, `text/plain`
173
173
 
174
174
  ## API Reference
175
175
 
@@ -200,6 +200,7 @@ interface AdpConfig {
200
200
  request?: {
201
201
  baseUrl?: string; // Base URL for ADP API (default: https://wss.lke.cloud.tencent.com)
202
202
  endpoint?: string; // API endpoint (default: /v1/qbot/chat/sse)
203
+ docParseEndpoint?: string; // Document parse API endpoint (default: /v1/qbot/chat/docParse)
203
204
  body?: Partial<AdpChatRequest>; // Additional request body options
204
205
  };
205
206
  }
package/dist/index.d.mts CHANGED
@@ -59,6 +59,7 @@ type AdpConfig = {
59
59
  baseUrl?: string;
60
60
  endpoint?: string;
61
61
  body?: Partial<AdpChatRequest>;
62
+ docParseEndpoint?: string;
62
63
  };
63
64
  historyCount?: number;
64
65
  enableUpload?: boolean;
package/dist/index.d.ts CHANGED
@@ -59,6 +59,7 @@ type AdpConfig = {
59
59
  baseUrl?: string;
60
60
  endpoint?: string;
61
61
  body?: Partial<AdpChatRequest>;
62
+ docParseEndpoint?: string;
62
63
  };
63
64
  historyCount?: number;
64
65
  enableUpload?: boolean;
package/dist/index.js CHANGED
@@ -171,9 +171,11 @@ var AdpAgent = class extends import_client.AbstractAgent {
171
171
  });
172
172
  }
173
173
  async _run(subscriber, input) {
174
+ let thinkingMessageSet = /* @__PURE__ */ new Set();
175
+ let thinkFinishedMessageSet = /* @__PURE__ */ new Set();
174
176
  try {
175
- const { runId, threadId: _threadId } = input;
176
- const threadId = _threadId || (0, import_crypto.randomUUID)();
177
+ const { runId } = input;
178
+ const threadId = input.threadId || (0, import_crypto.randomUUID)();
177
179
  subscriber.next({
178
180
  type: import_client.EventType.RUN_STARTED,
179
181
  runId,
@@ -185,19 +187,26 @@ var AdpAgent = class extends import_client.AbstractAgent {
185
187
  "MISSING_APP_KEY"
186
188
  );
187
189
  }
188
- const { messages: docExtractedMessages, fileInfos } = await this.extractDocuments(input, subscriber);
189
- const { message, trimmed } = await this.convertAGUIMessagesToAdpMessages(docExtractedMessages);
190
+ const latestUserMessage = input.messages.filter((m) => m.role === "user").pop();
191
+ if (!latestUserMessage) {
192
+ throw new AdpAgentError(
193
+ "Message content format error, or empty content",
194
+ "INVALID_MESSAGE_FORMAT"
195
+ );
196
+ }
197
+ const { message: docExtractedMessage, fileInfos } = await this.extractDocuments(latestUserMessage, threadId, subscriber);
198
+ const message = await this.convertAGUIMessagesToAdpMessages(docExtractedMessage);
190
199
  if (!message) {
191
200
  throw new AdpAgentError(
192
201
  "Message content format error, or empty content",
193
202
  "INVALID_MESSAGE_FORMAT"
194
203
  );
195
204
  }
196
- if (trimmed > 0) {
205
+ if (input.messages.length > 1) {
197
206
  subscriber.next({
198
207
  type: import_client.EventType.RAW,
199
208
  rawEvent: {
200
- message: `ADP handles message history itself, so that a total of ${trimmed} messages before and including last assistant message will be trimmed.`,
209
+ message: `ADP handles message history itself, so that a total of ${input.messages.length - 1} messages before and including last assistant message will be trimmed.`,
201
210
  type: "warn"
202
211
  }
203
212
  });
@@ -216,7 +225,6 @@ var AdpAgent = class extends import_client.AbstractAgent {
216
225
  let buffer = "";
217
226
  let interruptRequested = false;
218
227
  let thinkingStart = false;
219
- let thinkingMessageSet = /* @__PURE__ */ new Set();
220
228
  for await (const chunk of sseStream) {
221
229
  buffer += chunk.toString();
222
230
  const parts = buffer.split("\n\n");
@@ -243,6 +251,22 @@ var AdpAgent = class extends import_client.AbstractAgent {
243
251
  }
244
252
  switch (data.type) {
245
253
  case "reply": {
254
+ const messageId = data.payload.record_id;
255
+ const isFinal = data.payload.is_final;
256
+ if (thinkingStart) {
257
+ thinkingStart = false;
258
+ for (const index of thinkingMessageSet) {
259
+ subscriber.next({
260
+ type: import_client.EventType.THINKING_TEXT_MESSAGE_END,
261
+ messageId: `${messageId}-think-${index}`
262
+ });
263
+ }
264
+ thinkingMessageSet.clear();
265
+ subscriber.next({
266
+ type: import_client.EventType.THINKING_END,
267
+ messageId
268
+ });
269
+ }
246
270
  if (data.payload.is_from_self) {
247
271
  if (data.payload.is_evil) {
248
272
  throw new AdpAgentError(
@@ -253,8 +277,6 @@ var AdpAgent = class extends import_client.AbstractAgent {
253
277
  continue;
254
278
  }
255
279
  }
256
- const messageId = data.payload.record_id;
257
- const isFinal = data.payload.is_final;
258
280
  data.payload.content = data.payload.content.replace(
259
281
  /\\n/g,
260
282
  "\n\n"
@@ -334,51 +356,47 @@ var AdpAgent = class extends import_client.AbstractAgent {
334
356
  });
335
357
  }
336
358
  data.payload.procedures.forEach((procedure) => {
337
- if (!thinkingMessageSet.has(messageId)) {
338
- thinkingMessageSet.add(messageId);
359
+ const index = procedure.index.toString();
360
+ if (!thinkingMessageSet.has(index) && !thinkFinishedMessageSet.has(index)) {
361
+ thinkingMessageSet.add(index);
339
362
  subscriber.next({
340
363
  type: import_client.EventType.THINKING_TEXT_MESSAGE_START,
341
- messageId,
364
+ messageId: `${messageId}-think-${index}`,
342
365
  delta: procedure.debugging.content
343
366
  });
344
367
  } else {
345
368
  if (procedure.status === "processing") {
346
369
  subscriber.next({
347
370
  type: import_client.EventType.THINKING_TEXT_MESSAGE_CONTENT,
348
- messageId,
371
+ messageId: `${messageId}-think-${index}`,
349
372
  delta: procedure.debugging.content
350
373
  });
351
374
  } else {
352
- thinkingMessageSet.delete(messageId);
353
- subscriber.next({
354
- type: import_client.EventType.THINKING_TEXT_MESSAGE_END,
355
- messageId
356
- });
375
+ thinkingMessageSet.delete(index);
376
+ if (!thinkFinishedMessageSet.has(index)) {
377
+ thinkFinishedMessageSet.add(index);
378
+ subscriber.next({
379
+ type: import_client.EventType.THINKING_TEXT_MESSAGE_END,
380
+ messageId: `${messageId}-think-${index}`
381
+ });
382
+ }
357
383
  }
358
384
  }
359
385
  });
360
- const allFinished = data.payload.procedures.every(
361
- (procedure) => procedure.status !== "processing"
362
- );
363
- if (allFinished) {
364
- thinkingStart = false;
365
- thinkingMessageSet.clear();
366
- subscriber.next({
367
- type: import_client.EventType.THINKING_END,
368
- messageId
369
- });
370
- }
371
386
  break;
372
387
  }
373
388
  case "error": {
374
- console.error(JSON.stringify(data));
389
+ console.error(
390
+ "[ERROR] ADP throws error: ",
391
+ JSON.stringify(data)
392
+ );
375
393
  throw new AdpAgentError(
376
394
  data.error.message,
377
395
  data.error.code ? `ADP_ERROR_${data.error.code}` : "ADP_ERROR_-1"
378
396
  );
379
397
  }
380
398
  case "token_stat": {
381
- console.debug(JSON.stringify(data));
399
+ console.debug("[DEBUG] ADP token stat: ", JSON.stringify(data));
382
400
  break;
383
401
  }
384
402
  case "reference": {
@@ -408,7 +426,7 @@ var AdpAgent = class extends import_client.AbstractAgent {
408
426
  }
409
427
  subscriber.complete();
410
428
  } catch (e) {
411
- console.error(JSON.stringify(e));
429
+ console.error("[ERROR] Uncaught error: ", JSON.stringify(e));
412
430
  let code = "UNKNOWN_ERROR";
413
431
  let message = JSON.stringify(e);
414
432
  if (e instanceof import_axios.AxiosError) {
@@ -424,111 +442,105 @@ var AdpAgent = class extends import_client.AbstractAgent {
424
442
  message: `Sorry, an error occurred while running the agent: Error code ${code}, ${message}`
425
443
  });
426
444
  subscriber.complete();
445
+ } finally {
446
+ thinkingMessageSet.clear();
447
+ thinkFinishedMessageSet.clear();
427
448
  }
428
449
  }
429
- async convertAGUIMessagesToAdpMessages(messages) {
450
+ async convertAGUIMessagesToAdpMessages(message) {
430
451
  let result = "";
431
- let trimmed = messages.length;
432
- for (const message of messages.reverse()) {
433
- if (message.role === "assistant") {
434
- break;
435
- }
436
- if (message.role === "user") {
437
- trimmed--;
438
- let content = "";
439
- if (typeof message.content === "string") {
440
- content = message.content;
441
- } else {
442
- if (this.adpConfig.enableUpload) {
443
- if (!this.finalCloudCredential.token) {
444
- if (!this.finalCloudCredential.secretId) {
445
- throw new AdpAgentError(
446
- "TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter",
447
- "MISSING_SECRET_ID"
448
- );
452
+ if (message.role === "user") {
453
+ let content = "";
454
+ if (typeof message.content === "string") {
455
+ content = message.content;
456
+ } else {
457
+ if (this.adpConfig.enableUpload) {
458
+ if (!this.finalCloudCredential.token) {
459
+ if (!this.finalCloudCredential.secretId) {
460
+ throw new AdpAgentError(
461
+ "TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter",
462
+ "MISSING_SECRET_ID"
463
+ );
464
+ }
465
+ if (!this.finalCloudCredential.secretKey) {
466
+ throw new AdpAgentError(
467
+ "TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter",
468
+ "MISSING_SECRET_KEY"
469
+ );
470
+ }
471
+ }
472
+ const imageMap = /* @__PURE__ */ new Map();
473
+ const imagesToUpload = [];
474
+ message.content.forEach((item) => {
475
+ if (item.type === "binary") {
476
+ if (Object.keys(IMAGE_MIME_TYPES).includes(item.mimeType)) {
477
+ imagesToUpload.push(item);
449
478
  }
450
- if (!this.finalCloudCredential.secretKey) {
479
+ }
480
+ });
481
+ if (imagesToUpload.length) {
482
+ await this.uploadToCos(
483
+ imagesToUpload,
484
+ (data, _, file) => {
485
+ imageMap.set(
486
+ file.id || file.filename,
487
+ `https://${data.Location}`
488
+ );
489
+ },
490
+ (fileName, error) => {
451
491
  throw new AdpAgentError(
452
- "TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter",
453
- "MISSING_SECRET_KEY"
492
+ `Upload image ${fileName} failed: ${error}`,
493
+ "UPLOAD_IMAGE_FAILED"
454
494
  );
455
495
  }
456
- }
457
- const imageMap = /* @__PURE__ */ new Map();
458
- const imagesToUpload = [];
459
- message.content.forEach((item) => {
460
- if (item.type === "binary") {
461
- if (Object.keys(IMAGE_MIME_TYPES).includes(item.mimeType)) {
462
- imagesToUpload.push(item);
463
- }
464
- }
465
- });
466
- if (imagesToUpload.length) {
467
- await this.uploadToCos(
468
- imagesToUpload,
469
- (data, _, file) => {
470
- imageMap.set(
471
- file.id || file.filename,
472
- `https://${data.Location}`
473
- );
474
- },
475
- (fileName, error) => {
476
- throw new AdpAgentError(
477
- `Upload image ${fileName} failed: ${error}`,
478
- "UPLOAD_IMAGE_FAILED"
479
- );
496
+ );
497
+ }
498
+ content = message.content.reduce((acc, cur) => {
499
+ if (cur.type === "text") {
500
+ return acc + `${cur.text} `;
501
+ } else if (cur.type === "binary") {
502
+ if (Object.keys(IMAGE_MIME_TYPES).includes(cur.mimeType)) {
503
+ if (imageMap.has(cur.id || cur.filename)) {
504
+ return acc + `![${cur.filename}](${imageMap.get(cur.id || cur.filename)}) `;
505
+ } else {
506
+ return acc;
480
507
  }
481
- );
508
+ } else return acc;
509
+ } else {
510
+ return acc;
482
511
  }
483
- content = message.content.reduce((acc, cur) => {
484
- if (cur.type === "text") {
485
- return acc + `${cur.text} `;
486
- } else if (cur.type === "binary") {
487
- if (Object.keys(IMAGE_MIME_TYPES).includes(cur.mimeType)) {
488
- if (imageMap.has(cur.id || cur.filename)) {
489
- return acc + `![${cur.filename}](${imageMap.get(cur.id || cur.filename)}) `;
490
- } else {
491
- return acc;
492
- }
493
- } else return acc;
494
- } else {
495
- return acc;
496
- }
497
- }, "").trim();
498
- }
512
+ }, "").trim();
499
513
  }
500
- result = `${message.role}: ${content}
514
+ }
515
+ result = `${message.role}: ${content}
501
516
  ${result}`;
502
- } else {
503
- result = `${message.role}: ${message.content}
517
+ } else {
518
+ result = `${message.role}: ${message.content}
504
519
  ${result}`;
505
- }
506
520
  }
507
- return { message: result.trim(), trimmed };
521
+ return result.trim();
508
522
  }
509
- async extractDocuments(input, subscriber) {
510
- const { messages, runId, threadId } = input;
523
+ async extractDocuments(message, threadId, subscriber) {
511
524
  const documentFiles = [];
512
- const newMessages = messages.map((msg) => {
513
- if (msg.role === "user" && Array.isArray(msg.content)) {
514
- let newContent = [];
515
- msg.content.forEach((item) => {
516
- if (item.type === "text") {
525
+ let newMessage;
526
+ if (message.role === "user" && Array.isArray(message.content)) {
527
+ let newContent = [];
528
+ message.content.forEach((item) => {
529
+ if (item.type === "text") {
530
+ newContent.push(item);
531
+ } else if (item.type === "binary") {
532
+ if (Object.keys(DOCUMENT_MIME_TYPES).includes(item.mimeType)) {
533
+ documentFiles.push(item);
534
+ } else {
517
535
  newContent.push(item);
518
- } else if (item.type === "binary") {
519
- if (Object.keys(DOCUMENT_MIME_TYPES).includes(item.mimeType)) {
520
- documentFiles.push(item);
521
- } else {
522
- newContent.push(item);
523
- }
524
536
  }
525
- });
526
- return {
527
- ...msg,
528
- content: newContent
529
- };
530
- } else return msg;
531
- });
537
+ }
538
+ });
539
+ newMessage = {
540
+ ...message,
541
+ content: newContent
542
+ };
543
+ } else newMessage = message;
532
544
  const fileInfos = [];
533
545
  const successedFiles = [];
534
546
  const failedFiles = [];
@@ -559,10 +571,11 @@ ${result}`;
559
571
  }
560
572
  );
561
573
  } catch (e) {
574
+ console.error("Document upload failed: ", JSON.stringify(e));
562
575
  }
563
576
  }
564
577
  if (successedFiles.length) {
565
- successedFiles.forEach(async ({ data: cosData, cosParams, file }) => {
578
+ for (const { data: cosData, cosParams, file } of successedFiles) {
566
579
  const extName = MIME_TYPES[file.mimeType];
567
580
  const requestBody = {
568
581
  sessionId: threadId,
@@ -577,7 +590,7 @@ ${result}`;
577
590
  size: file.data?.length.toString() || "0"
578
591
  };
579
592
  const response = await this.reqAppClient.post(
580
- this.adpConfig.request?.endpoint || "/v1/qbot/chat/docParse",
593
+ this.adpConfig.request?.docParseEndpoint || "/v1/qbot/chat/docParse",
581
594
  camelToSnakeKeys(requestBody),
582
595
  { responseType: "stream" }
583
596
  );
@@ -645,11 +658,11 @@ ${result}`;
645
658
  }
646
659
  }
647
660
  }
648
- });
661
+ }
649
662
  }
650
663
  }
651
664
  return {
652
- messages: newMessages,
665
+ message: newMessage,
653
666
  fileInfos,
654
667
  failedFiles
655
668
  };