@cloudbase/agent-adapter-adp 1.0.1-alpha.13 → 1.0.1-alpha.14
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 +52 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +166 -131
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +166 -131
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -8
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ npm install @cloudbase/agent-agents @cloudbase/agent-adapter-adp
|
|
|
15
15
|
- **Thinking Events**: Support for thinking/reasoning process events from the model
|
|
16
16
|
- **Workflow Integration**: Support for ADP workflows with tool call events
|
|
17
17
|
- **Custom Variables**: Pass custom parameters to workflows and knowledge base
|
|
18
|
+
- **File Upload**: Upload images and documents to COS for multimodal conversations (**requires `enableUpload: true`**)
|
|
18
19
|
|
|
19
20
|
## Environment Variables
|
|
20
21
|
|
|
@@ -121,6 +122,55 @@ observable.subscribe({
|
|
|
121
122
|
});
|
|
122
123
|
```
|
|
123
124
|
|
|
125
|
+
### With File Upload (Images and Documents)
|
|
126
|
+
|
|
127
|
+
When `enableUpload` is **set to `true`**, you can send images and documents in messages. Files are automatically uploaded to Tencent Cloud COS and processed by ADP.
|
|
128
|
+
|
|
129
|
+
**Note:** File upload requires Tencent Cloud credentials (`TENCENTCLOUD_SECRETID` and `TENCENTCLOUD_SECRETKEY`).
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { AdpAgent } from "@cloudbase/agent-adapter-adp";
|
|
133
|
+
import { randomUUID } from "crypto";
|
|
134
|
+
import * as fs from "fs";
|
|
135
|
+
|
|
136
|
+
const agent = new AdpAgent({
|
|
137
|
+
name: "my-adp-agent",
|
|
138
|
+
adpConfig: {
|
|
139
|
+
appKey: "your-app-key",
|
|
140
|
+
enableUpload: true, // Enable file upload
|
|
141
|
+
credential: {
|
|
142
|
+
secretId: "your-secret-id",
|
|
143
|
+
secretKey: "your-secret-key",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const observable = agent.run({
|
|
149
|
+
runId: randomUUID(),
|
|
150
|
+
threadId: randomUUID(),
|
|
151
|
+
messages: [
|
|
152
|
+
{
|
|
153
|
+
id: randomUUID(),
|
|
154
|
+
role: "user",
|
|
155
|
+
content: [
|
|
156
|
+
{ type: "text", text: "What's in this image?" },
|
|
157
|
+
{
|
|
158
|
+
type: "binary",
|
|
159
|
+
mimeType: "image/png",
|
|
160
|
+
filename: "screenshot.png",
|
|
161
|
+
data: fs.readFileSync("./screenshot.png"),
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Supported file types:**
|
|
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`
|
|
173
|
+
|
|
124
174
|
## API Reference
|
|
125
175
|
|
|
126
176
|
### AdpAgent
|
|
@@ -146,6 +196,7 @@ interface AdpConfig {
|
|
|
146
196
|
token?: string; // Session token (optional if TENCENTCLOUD_SESSIONTOKEN env is set)
|
|
147
197
|
};
|
|
148
198
|
historyCount?: number; // Number of history messages to retrieve (reserved)
|
|
199
|
+
enableUpload?: boolean; // Enable file upload for images and documents (default: false)
|
|
149
200
|
request?: {
|
|
150
201
|
baseUrl?: string; // Base URL for ADP API (default: https://wss.lke.cloud.tencent.com)
|
|
151
202
|
endpoint?: string; // API endpoint (default: /v1/qbot/chat/sse)
|
|
@@ -187,6 +238,7 @@ The adapter emits the following AG-UI events:
|
|
|
187
238
|
- `axios`: HTTP client for API requests
|
|
188
239
|
- `rxjs`: Reactive extensions for JavaScript
|
|
189
240
|
- `tencentcloud-sdk-nodejs-lke`: Tencent Cloud LKE SDK
|
|
241
|
+
- `cos-nodejs-sdk-v5`: Tencent Cloud COS SDK (for file upload)
|
|
190
242
|
|
|
191
243
|
## Related Resources
|
|
192
244
|
|
package/dist/index.d.mts
CHANGED
|
@@ -61,6 +61,7 @@ type AdpConfig = {
|
|
|
61
61
|
body?: Partial<AdpChatRequest>;
|
|
62
62
|
};
|
|
63
63
|
historyCount?: number;
|
|
64
|
+
enableUpload?: boolean;
|
|
64
65
|
appKey?: string;
|
|
65
66
|
credential?: {
|
|
66
67
|
secretId?: string;
|
|
@@ -282,6 +283,7 @@ declare class AdpAgent extends AbstractAgent {
|
|
|
282
283
|
private reqLkeClient;
|
|
283
284
|
protected adpConfig: AdpConfig;
|
|
284
285
|
private finalAppKey;
|
|
286
|
+
private finalCloudCredential;
|
|
285
287
|
constructor(config: AgentConfig & {
|
|
286
288
|
adpConfig: AdpConfig;
|
|
287
289
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,7 @@ type AdpConfig = {
|
|
|
61
61
|
body?: Partial<AdpChatRequest>;
|
|
62
62
|
};
|
|
63
63
|
historyCount?: number;
|
|
64
|
+
enableUpload?: boolean;
|
|
64
65
|
appKey?: string;
|
|
65
66
|
credential?: {
|
|
66
67
|
secretId?: string;
|
|
@@ -282,6 +283,7 @@ declare class AdpAgent extends AbstractAgent {
|
|
|
282
283
|
private reqLkeClient;
|
|
283
284
|
protected adpConfig: AdpConfig;
|
|
284
285
|
private finalAppKey;
|
|
286
|
+
private finalCloudCredential;
|
|
285
287
|
constructor(config: AgentConfig & {
|
|
286
288
|
adpConfig: AdpConfig;
|
|
287
289
|
});
|
package/dist/index.js
CHANGED
|
@@ -129,18 +129,20 @@ var AdpAgent = class extends import_client.AbstractAgent {
|
|
|
129
129
|
constructor(config) {
|
|
130
130
|
super(config);
|
|
131
131
|
this.finalAppKey = "";
|
|
132
|
+
this.finalCloudCredential = {};
|
|
132
133
|
this.adpConfig = config.adpConfig;
|
|
133
134
|
this.finalAppKey = this.adpConfig.appKey || this.adpConfig.request?.body?.botAppKey || process.env.ADP_APP_KEY || "";
|
|
134
135
|
this.reqAppClient = import_axios.default.create({
|
|
135
136
|
baseURL: this.adpConfig.request?.baseUrl || "https://wss.lke.cloud.tencent.com"
|
|
136
137
|
});
|
|
137
138
|
const LkeClient = import_tencentcloud_sdk_nodejs_lke.lke.v20231130.Client;
|
|
139
|
+
this.finalCloudCredential = {
|
|
140
|
+
secretId: this.adpConfig.credential?.secretId || process.env.TENCENTCLOUD_SECRETID,
|
|
141
|
+
secretKey: this.adpConfig.credential?.secretKey || process.env.TENCENTCLOUD_SECRETKEY,
|
|
142
|
+
token: this.adpConfig.credential?.token || process.env.TENCENTCLOUD_SESSIONTOKEN
|
|
143
|
+
};
|
|
138
144
|
this.reqLkeClient = new LkeClient({
|
|
139
|
-
credential:
|
|
140
|
-
secretId: this.adpConfig.credential?.secretId || process.env.TENCENTCLOUD_SECRETID,
|
|
141
|
-
secretKey: this.adpConfig.credential?.secretKey || process.env.TENCENTCLOUD_SECRETKEY,
|
|
142
|
-
token: this.adpConfig.credential?.token || process.env.TENCENTCLOUD_SESSIONTOKEN
|
|
143
|
-
}
|
|
145
|
+
credential: this.finalCloudCredential
|
|
144
146
|
});
|
|
145
147
|
}
|
|
146
148
|
generateRequestBody({
|
|
@@ -170,7 +172,8 @@ var AdpAgent = class extends import_client.AbstractAgent {
|
|
|
170
172
|
}
|
|
171
173
|
async _run(subscriber, input) {
|
|
172
174
|
try {
|
|
173
|
-
const { runId, threadId } = input;
|
|
175
|
+
const { runId, threadId: _threadId } = input;
|
|
176
|
+
const threadId = _threadId || (0, import_crypto.randomUUID)();
|
|
174
177
|
subscriber.next({
|
|
175
178
|
type: import_client.EventType.RUN_STARTED,
|
|
176
179
|
runId,
|
|
@@ -436,47 +439,63 @@ var AdpAgent = class extends import_client.AbstractAgent {
|
|
|
436
439
|
if (typeof message.content === "string") {
|
|
437
440
|
content = message.content;
|
|
438
441
|
} else {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
});
|
|
448
|
-
if (imagesToUpload.length) {
|
|
449
|
-
await this.uploadToCos(
|
|
450
|
-
imagesToUpload,
|
|
451
|
-
(data, _, file) => {
|
|
452
|
-
imageMap.set(
|
|
453
|
-
file.id || file.filename,
|
|
454
|
-
`https://${data.Location}`
|
|
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"
|
|
455
448
|
);
|
|
456
|
-
}
|
|
457
|
-
(
|
|
449
|
+
}
|
|
450
|
+
if (!this.finalCloudCredential.secretKey) {
|
|
458
451
|
throw new AdpAgentError(
|
|
459
|
-
|
|
460
|
-
"
|
|
452
|
+
"TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter",
|
|
453
|
+
"MISSING_SECRET_KEY"
|
|
461
454
|
);
|
|
462
455
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if (imageMap.has(cur.id || cur.filename)) {
|
|
471
|
-
return acc + `}) `;
|
|
472
|
-
} else {
|
|
473
|
-
return acc;
|
|
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);
|
|
474
463
|
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
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
|
+
);
|
|
480
|
+
}
|
|
481
|
+
);
|
|
478
482
|
}
|
|
479
|
-
|
|
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 + `}) `;
|
|
490
|
+
} else {
|
|
491
|
+
return acc;
|
|
492
|
+
}
|
|
493
|
+
} else return acc;
|
|
494
|
+
} else {
|
|
495
|
+
return acc;
|
|
496
|
+
}
|
|
497
|
+
}, "").trim();
|
|
498
|
+
}
|
|
480
499
|
}
|
|
481
500
|
result = `${message.role}: ${content}
|
|
482
501
|
${result}`;
|
|
@@ -513,105 +532,121 @@ ${result}`;
|
|
|
513
532
|
const fileInfos = [];
|
|
514
533
|
const successedFiles = [];
|
|
515
534
|
const failedFiles = [];
|
|
516
|
-
if (
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
535
|
+
if (this.adpConfig.enableUpload) {
|
|
536
|
+
if (!this.finalCloudCredential.token) {
|
|
537
|
+
if (!this.finalCloudCredential.secretId) {
|
|
538
|
+
throw new AdpAgentError(
|
|
539
|
+
"TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter",
|
|
540
|
+
"MISSING_SECRET_ID"
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
if (!this.finalCloudCredential.secretKey) {
|
|
544
|
+
throw new AdpAgentError(
|
|
545
|
+
"TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter",
|
|
546
|
+
"MISSING_SECRET_KEY"
|
|
547
|
+
);
|
|
548
|
+
}
|
|
528
549
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
fileType: extName,
|
|
539
|
-
fileName: file.filename,
|
|
540
|
-
cosUrl: cosParams.UploadPath,
|
|
541
|
-
cosHash: cosData.headers?.["x-cos-hash-crc64ecma"] || "",
|
|
542
|
-
eTag: cosData.ETag,
|
|
543
|
-
size: file.data?.length.toString() || "0"
|
|
544
|
-
};
|
|
545
|
-
const response = await this.reqAppClient.post(
|
|
546
|
-
this.adpConfig.request?.endpoint || "/v1/qbot/chat/docParse",
|
|
547
|
-
camelToSnakeKeys(requestBody),
|
|
548
|
-
{ responseType: "stream" }
|
|
549
|
-
);
|
|
550
|
-
const sseStream = response.data;
|
|
551
|
-
let buffer = "";
|
|
552
|
-
for await (const chunk of sseStream) {
|
|
553
|
-
buffer += chunk.toString();
|
|
554
|
-
const parts = buffer.split("\n\n");
|
|
555
|
-
buffer = parts.pop() || "";
|
|
556
|
-
for (const part of parts) {
|
|
557
|
-
if (!part.trim()) continue;
|
|
558
|
-
const event = { data: "", event: "" };
|
|
559
|
-
for (const line of part.split("\n")) {
|
|
560
|
-
if (line.startsWith("data:")) {
|
|
561
|
-
event.data += line.slice(5);
|
|
562
|
-
} else if (line.startsWith("event:")) {
|
|
563
|
-
event.event = line.slice(6);
|
|
564
|
-
}
|
|
550
|
+
if (documentFiles.length) {
|
|
551
|
+
try {
|
|
552
|
+
await this.uploadToCos(
|
|
553
|
+
documentFiles,
|
|
554
|
+
(data, cosParams, file) => {
|
|
555
|
+
successedFiles.push({ data, cosParams, file });
|
|
556
|
+
},
|
|
557
|
+
(fileName, error) => {
|
|
558
|
+
failedFiles.push({ fileName, error });
|
|
565
559
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
560
|
+
);
|
|
561
|
+
} catch (e) {
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (successedFiles.length) {
|
|
565
|
+
successedFiles.forEach(async ({ data: cosData, cosParams, file }) => {
|
|
566
|
+
const extName = MIME_TYPES[file.mimeType];
|
|
567
|
+
const requestBody = {
|
|
568
|
+
sessionId: threadId,
|
|
569
|
+
botAppKey: this.finalAppKey,
|
|
570
|
+
requestId: (0, import_crypto.randomUUID)(),
|
|
571
|
+
cosBucket: cosParams.Bucket,
|
|
572
|
+
fileType: extName,
|
|
573
|
+
fileName: file.filename,
|
|
574
|
+
cosUrl: cosParams.UploadPath,
|
|
575
|
+
cosHash: cosData.headers?.["x-cos-hash-crc64ecma"] || "",
|
|
576
|
+
eTag: cosData.ETag,
|
|
577
|
+
size: file.data?.length.toString() || "0"
|
|
578
|
+
};
|
|
579
|
+
const response = await this.reqAppClient.post(
|
|
580
|
+
this.adpConfig.request?.endpoint || "/v1/qbot/chat/docParse",
|
|
581
|
+
camelToSnakeKeys(requestBody),
|
|
582
|
+
{ responseType: "stream" }
|
|
583
|
+
);
|
|
584
|
+
const sseStream = response.data;
|
|
585
|
+
let buffer = "";
|
|
586
|
+
for await (const chunk of sseStream) {
|
|
587
|
+
buffer += chunk.toString();
|
|
588
|
+
const parts = buffer.split("\n\n");
|
|
589
|
+
buffer = parts.pop() || "";
|
|
590
|
+
for (const part of parts) {
|
|
591
|
+
if (!part.trim()) continue;
|
|
592
|
+
const event = { data: "", event: "" };
|
|
593
|
+
for (const line of part.split("\n")) {
|
|
594
|
+
if (line.startsWith("data:")) {
|
|
595
|
+
event.data += line.slice(5);
|
|
596
|
+
} else if (line.startsWith("event:")) {
|
|
597
|
+
event.event = line.slice(6);
|
|
598
|
+
}
|
|
575
599
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
600
|
+
if (event.data) {
|
|
601
|
+
let data;
|
|
602
|
+
try {
|
|
603
|
+
data = JSON.parse(event.data);
|
|
604
|
+
} catch (e) {
|
|
605
|
+
throw new AdpAgentError(
|
|
606
|
+
`ADP returned invalid data: ${event.data}`,
|
|
607
|
+
"INVALID_DATA"
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
switch (data.type) {
|
|
611
|
+
case "parsing": {
|
|
612
|
+
subscriber.next({
|
|
613
|
+
type: import_client.EventType.RAW,
|
|
614
|
+
rawEvent: {
|
|
615
|
+
message: `Parsing document ${file.filename}: ${data.payload.process}%`,
|
|
616
|
+
type: "info"
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
if (data.payload.is_final) {
|
|
620
|
+
if (data.payload.error_message) {
|
|
621
|
+
subscriber.next({
|
|
622
|
+
type: import_client.EventType.RAW,
|
|
623
|
+
rawEvent: {
|
|
624
|
+
message: `Parsing document ${file.filename} failed: ${data.payload.error_message}`,
|
|
625
|
+
type: "error"
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
} else {
|
|
629
|
+
const fileNameNoExt = file.filename.split(".").splice(0, -1).join(".");
|
|
630
|
+
fileInfos.push({
|
|
631
|
+
docId: data.payload.doc_id,
|
|
632
|
+
fileName: fileNameNoExt,
|
|
633
|
+
fileType: extName,
|
|
634
|
+
fileSize: file.data?.length.toString() || "0",
|
|
635
|
+
fileUrl: `https://${cosData.Location}`
|
|
636
|
+
});
|
|
637
|
+
}
|
|
603
638
|
}
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
default: {
|
|
642
|
+
break;
|
|
604
643
|
}
|
|
605
|
-
break;
|
|
606
|
-
}
|
|
607
|
-
default: {
|
|
608
|
-
break;
|
|
609
644
|
}
|
|
610
645
|
}
|
|
611
646
|
}
|
|
612
647
|
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
648
|
+
});
|
|
649
|
+
}
|
|
615
650
|
}
|
|
616
651
|
return {
|
|
617
652
|
messages: newMessages,
|