@assistant-ui/react 0.10.21 → 0.10.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloud/AssistantCloud.d.ts +2 -0
- package/dist/cloud/AssistantCloud.d.ts.map +1 -1
- package/dist/cloud/AssistantCloud.js +3 -0
- package/dist/cloud/AssistantCloud.js.map +1 -1
- package/dist/cloud/AssistantCloudFiles.d.ts +27 -0
- package/dist/cloud/AssistantCloudFiles.d.ts.map +1 -0
- package/dist/cloud/AssistantCloudFiles.js +22 -0
- package/dist/cloud/AssistantCloudFiles.js.map +1 -0
- package/dist/runtimes/local/useLocalRuntime.d.ts +2 -1
- package/dist/runtimes/local/useLocalRuntime.d.ts.map +1 -1
- package/dist/runtimes/local/useLocalRuntime.js +2 -1
- package/dist/runtimes/local/useLocalRuntime.js.map +1 -1
- package/package.json +2 -2
- package/src/cloud/AssistantCloud.tsx +3 -0
- package/src/cloud/AssistantCloudFiles.tsx +45 -0
- package/src/runtimes/local/useLocalRuntime.tsx +2 -2
- package/src/tests/AssistantCloudFiles.test.ts +521 -0
@@ -2,12 +2,14 @@ import { AssistantCloudConfig } from "./AssistantCloudAPI";
|
|
2
2
|
import { AssistantCloudAuthTokens } from "./AssistantCloudAuthTokens";
|
3
3
|
import { AssistantCloudRuns } from "./AssistantCloudRuns";
|
4
4
|
import { AssistantCloudThreads } from "./AssistantCloudThreads";
|
5
|
+
import { AssistantCloudFiles } from "./AssistantCloudFiles";
|
5
6
|
export declare class AssistantCloud {
|
6
7
|
readonly threads: AssistantCloudThreads;
|
7
8
|
readonly auth: {
|
8
9
|
tokens: AssistantCloudAuthTokens;
|
9
10
|
};
|
10
11
|
readonly runs: AssistantCloudRuns;
|
12
|
+
readonly files: AssistantCloudFiles;
|
11
13
|
constructor(config: AssistantCloudConfig);
|
12
14
|
}
|
13
15
|
//# sourceMappingURL=AssistantCloud.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"AssistantCloud.d.ts","sourceRoot":"","sources":["../../src/cloud/AssistantCloud.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;
|
1
|
+
{"version":3,"file":"AssistantCloud.d.ts","sourceRoot":"","sources":["../../src/cloud/AssistantCloud.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,qBAAa,cAAc;IACzB,SAAgB,OAAO,wBAAC;IACxB,SAAgB,IAAI;;MAAC;IACrB,SAAgB,IAAI,qBAAC;IACrB,SAAgB,KAAK,sBAAC;gBAEV,MAAM,EAAE,oBAAoB;CASzC"}
|
@@ -3,10 +3,12 @@ import { AssistantCloudAPI } from "./AssistantCloudAPI.js";
|
|
3
3
|
import { AssistantCloudAuthTokens } from "./AssistantCloudAuthTokens.js";
|
4
4
|
import { AssistantCloudRuns } from "./AssistantCloudRuns.js";
|
5
5
|
import { AssistantCloudThreads } from "./AssistantCloudThreads.js";
|
6
|
+
import { AssistantCloudFiles } from "./AssistantCloudFiles.js";
|
6
7
|
var AssistantCloud = class {
|
7
8
|
threads;
|
8
9
|
auth;
|
9
10
|
runs;
|
11
|
+
files;
|
10
12
|
constructor(config) {
|
11
13
|
const api = new AssistantCloudAPI(config);
|
12
14
|
this.threads = new AssistantCloudThreads(api);
|
@@ -14,6 +16,7 @@ var AssistantCloud = class {
|
|
14
16
|
tokens: new AssistantCloudAuthTokens(api)
|
15
17
|
};
|
16
18
|
this.runs = new AssistantCloudRuns(api);
|
19
|
+
this.files = new AssistantCloudFiles(api);
|
17
20
|
}
|
18
21
|
};
|
19
22
|
export {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/cloud/AssistantCloud.tsx"],"sourcesContent":["import { AssistantCloudAPI, AssistantCloudConfig } from \"./AssistantCloudAPI\";\nimport { AssistantCloudAuthTokens } from \"./AssistantCloudAuthTokens\";\nimport { AssistantCloudRuns } from \"./AssistantCloudRuns\";\nimport { AssistantCloudThreads } from \"./AssistantCloudThreads\";\n\nexport class AssistantCloud {\n public readonly threads;\n public readonly auth;\n public readonly runs;\n\n constructor(config: AssistantCloudConfig) {\n const api = new AssistantCloudAPI(config);\n this.threads = new AssistantCloudThreads(api);\n this.auth = {\n tokens: new AssistantCloudAuthTokens(api),\n };\n this.runs = new AssistantCloudRuns(api);\n }\n}\n"],"mappings":";AAAA,SAAS,yBAA+C;AACxD,SAAS,gCAAgC;AACzC,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;
|
1
|
+
{"version":3,"sources":["../../src/cloud/AssistantCloud.tsx"],"sourcesContent":["import { AssistantCloudAPI, AssistantCloudConfig } from \"./AssistantCloudAPI\";\nimport { AssistantCloudAuthTokens } from \"./AssistantCloudAuthTokens\";\nimport { AssistantCloudRuns } from \"./AssistantCloudRuns\";\nimport { AssistantCloudThreads } from \"./AssistantCloudThreads\";\nimport { AssistantCloudFiles } from \"./AssistantCloudFiles\";\n\nexport class AssistantCloud {\n public readonly threads;\n public readonly auth;\n public readonly runs;\n public readonly files;\n\n constructor(config: AssistantCloudConfig) {\n const api = new AssistantCloudAPI(config);\n this.threads = new AssistantCloudThreads(api);\n this.auth = {\n tokens: new AssistantCloudAuthTokens(api),\n };\n this.runs = new AssistantCloudRuns(api);\n this.files = new AssistantCloudFiles(api);\n }\n}\n"],"mappings":";AAAA,SAAS,yBAA+C;AACxD,SAAS,gCAAgC;AACzC,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AAE7B,IAAM,iBAAN,MAAqB;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEhB,YAAY,QAA8B;AACxC,UAAM,MAAM,IAAI,kBAAkB,MAAM;AACxC,SAAK,UAAU,IAAI,sBAAsB,GAAG;AAC5C,SAAK,OAAO;AAAA,MACV,QAAQ,IAAI,yBAAyB,GAAG;AAAA,IAC1C;AACA,SAAK,OAAO,IAAI,mBAAmB,GAAG;AACtC,SAAK,QAAQ,IAAI,oBAAoB,GAAG;AAAA,EAC1C;AACF;","names":[]}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { AssistantCloudAPI } from "./AssistantCloudAPI";
|
2
|
+
type PdfToImagesRequestBody = {
|
3
|
+
file_blob?: string | undefined;
|
4
|
+
file_url?: string | undefined;
|
5
|
+
};
|
6
|
+
type PdfToImagesResponse = {
|
7
|
+
success: boolean;
|
8
|
+
urls: string[];
|
9
|
+
message: string;
|
10
|
+
};
|
11
|
+
type GeneratePresignedUploadUrlRequestBody = {
|
12
|
+
filename: string;
|
13
|
+
};
|
14
|
+
type GeneratePresignedUploadUrlResponse = {
|
15
|
+
success: boolean;
|
16
|
+
signedUrl: string;
|
17
|
+
expiresAt: string;
|
18
|
+
publicUrl: string;
|
19
|
+
};
|
20
|
+
export declare class AssistantCloudFiles {
|
21
|
+
private cloud;
|
22
|
+
constructor(cloud: AssistantCloudAPI);
|
23
|
+
pdfToImages(body: PdfToImagesRequestBody): Promise<PdfToImagesResponse>;
|
24
|
+
generatePresignedUploadUrl(body: GeneratePresignedUploadUrlRequestBody): Promise<GeneratePresignedUploadUrlResponse>;
|
25
|
+
}
|
26
|
+
export {};
|
27
|
+
//# sourceMappingURL=AssistantCloudFiles.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"AssistantCloudFiles.d.ts","sourceRoot":"","sources":["../../src/cloud/AssistantCloudFiles.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,KAAK,sBAAsB,GAAG;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,qCAAqC,GAAG;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,kCAAkC,GAAG;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,mBAAmB;IAClB,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,iBAAiB;IAE/B,WAAW,CACtB,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,mBAAmB,CAAC;IAOlB,0BAA0B,CACrC,IAAI,EAAE,qCAAqC,GAC1C,OAAO,CAAC,kCAAkC,CAAC;CAM/C"}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// src/cloud/AssistantCloudFiles.tsx
|
2
|
+
var AssistantCloudFiles = class {
|
3
|
+
constructor(cloud) {
|
4
|
+
this.cloud = cloud;
|
5
|
+
}
|
6
|
+
async pdfToImages(body) {
|
7
|
+
return this.cloud.makeRequest("/files/pdf-to-images", {
|
8
|
+
method: "POST",
|
9
|
+
body
|
10
|
+
});
|
11
|
+
}
|
12
|
+
async generatePresignedUploadUrl(body) {
|
13
|
+
return this.cloud.makeRequest("/files/attachments/generate-presigned-upload-url", {
|
14
|
+
method: "POST",
|
15
|
+
body
|
16
|
+
});
|
17
|
+
}
|
18
|
+
};
|
19
|
+
export {
|
20
|
+
AssistantCloudFiles
|
21
|
+
};
|
22
|
+
//# sourceMappingURL=AssistantCloudFiles.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../../src/cloud/AssistantCloudFiles.tsx"],"sourcesContent":["import { AssistantCloudAPI } from \"./AssistantCloudAPI\";\n\ntype PdfToImagesRequestBody = {\n file_blob?: string | undefined;\n file_url?: string | undefined;\n};\n\ntype PdfToImagesResponse = {\n success: boolean;\n urls: string[];\n message: string;\n};\n\ntype GeneratePresignedUploadUrlRequestBody = {\n filename: string;\n};\n\ntype GeneratePresignedUploadUrlResponse = {\n success: boolean;\n signedUrl: string;\n expiresAt: string;\n publicUrl: string;\n};\n\nexport class AssistantCloudFiles {\n constructor(private cloud: AssistantCloudAPI) {}\n\n public async pdfToImages(\n body: PdfToImagesRequestBody,\n ): Promise<PdfToImagesResponse> {\n return this.cloud.makeRequest(\"/files/pdf-to-images\", {\n method: \"POST\",\n body,\n });\n }\n\n public async generatePresignedUploadUrl(\n body: GeneratePresignedUploadUrlRequestBody,\n ): Promise<GeneratePresignedUploadUrlResponse> {\n return this.cloud.makeRequest(\"/files/attachments/generate-presigned-upload-url\", {\n method: \"POST\",\n body,\n });\n }\n} "],"mappings":";AAwBO,IAAM,sBAAN,MAA0B;AAAA,EAC/B,YAAoB,OAA0B;AAA1B;AAAA,EAA2B;AAAA,EAE/C,MAAa,YACX,MAC8B;AAC9B,WAAO,KAAK,MAAM,YAAY,wBAAwB;AAAA,MACpD,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAa,2BACX,MAC6C;AAC7C,WAAO,KAAK,MAAM,YAAY,oDAAoD;AAAA,MAChF,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":[]}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import type { ChatModelAdapter } from "./ChatModelAdapter";
|
2
|
-
import { LocalRuntimeOptions } from "./LocalRuntimeOptions";
|
2
|
+
import type { LocalRuntimeOptions } from "./LocalRuntimeOptions";
|
3
3
|
import { AssistantRuntimeImpl } from "../../internal";
|
4
|
+
export declare const useLocalThreadRuntime: (adapter: ChatModelAdapter, { initialMessages, ...options }: LocalRuntimeOptions) => AssistantRuntimeImpl;
|
4
5
|
export declare const useLocalRuntime: (adapter: ChatModelAdapter, { cloud, ...options }?: LocalRuntimeOptions) => AssistantRuntimeImpl;
|
5
6
|
//# sourceMappingURL=useLocalRuntime.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"useLocalRuntime.d.ts","sourceRoot":"","sources":["../../../src/runtimes/local/useLocalRuntime.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;
|
1
|
+
{"version":3,"file":"useLocalRuntime.d.ts","sourceRoot":"","sources":["../../../src/runtimes/local/useLocalRuntime.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAIjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,eAAO,MAAM,qBAAqB,GAChC,SAAS,gBAAgB,EACzB,iCAAiC,mBAAmB,yBAkCrD,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,SAAS,gBAAgB,EACzB,wBAAuB,mBAAwB,yBAShD,CAAC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../../src/runtimes/local/useLocalRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { ChatModelAdapter } from \"./ChatModelAdapter\";\nimport { LocalRuntimeCore } from \"./LocalRuntimeCore\";\nimport { LocalRuntimeOptions } from \"./LocalRuntimeOptions\";\nimport { useRuntimeAdapters } from \"../adapters/RuntimeAdapterProvider\";\nimport { useRemoteThreadListRuntime } from \"../remote-thread-list/useRemoteThreadListRuntime\";\nimport { useCloudThreadListAdapter } from \"../remote-thread-list/adapter/cloud\";\nimport { AssistantRuntimeImpl } from \"../../internal\";\n\
|
1
|
+
{"version":3,"sources":["../../../src/runtimes/local/useLocalRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { ChatModelAdapter } from \"./ChatModelAdapter\";\nimport { LocalRuntimeCore } from \"./LocalRuntimeCore\";\nimport type { LocalRuntimeOptions } from \"./LocalRuntimeOptions\";\nimport { useRuntimeAdapters } from \"../adapters/RuntimeAdapterProvider\";\nimport { useRemoteThreadListRuntime } from \"../remote-thread-list/useRemoteThreadListRuntime\";\nimport { useCloudThreadListAdapter } from \"../remote-thread-list/adapter/cloud\";\nimport { AssistantRuntimeImpl } from \"../../internal\";\n\nexport const useLocalThreadRuntime = (\n adapter: ChatModelAdapter,\n { initialMessages, ...options }: LocalRuntimeOptions,\n) => {\n const { modelContext, ...threadListAdapters } = useRuntimeAdapters() ?? {};\n const opt = useMemo(\n () => ({\n ...options,\n adapters: {\n ...threadListAdapters,\n ...options.adapters,\n chatModel: adapter,\n },\n }),\n [adapter, options, threadListAdapters],\n );\n\n const [runtime] = useState(() => new LocalRuntimeCore(opt, initialMessages));\n\n useEffect(() => {\n return () => {\n runtime.threads.getMainThreadRuntimeCore().detach();\n };\n }, [runtime]);\n\n useEffect(() => {\n runtime.threads.getMainThreadRuntimeCore().__internal_setOptions(opt);\n runtime.threads.getMainThreadRuntimeCore().__internal_load();\n }, [runtime, opt]);\n\n useEffect(() => {\n if (!modelContext) return undefined;\n return runtime.registerModelContextProvider(modelContext);\n }, [modelContext, runtime]);\n\n return useMemo(() => new AssistantRuntimeImpl(runtime), [runtime]);\n};\n\nexport const useLocalRuntime = (\n adapter: ChatModelAdapter,\n { cloud, ...options }: LocalRuntimeOptions = {},\n) => {\n const cloudAdapter = useCloudThreadListAdapter({ cloud });\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useLocalThreadRuntime(adapter, options);\n },\n adapter: cloudAdapter,\n });\n};\n"],"mappings":";;;AAEA,SAAS,WAAW,SAAS,gBAAgB;AAE7C,SAAS,wBAAwB;AAEjC,SAAS,0BAA0B;AACnC,SAAS,kCAAkC;AAC3C,SAAS,iCAAiC;AAC1C,SAAS,4BAA4B;AAE9B,IAAM,wBAAwB,CACnC,SACA,EAAE,iBAAiB,GAAG,QAAQ,MAC3B;AACH,QAAM,EAAE,cAAc,GAAG,mBAAmB,IAAI,mBAAmB,KAAK,CAAC;AACzE,QAAM,MAAM;AAAA,IACV,OAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,QACR,GAAG;AAAA,QACH,GAAG,QAAQ;AAAA,QACX,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA,CAAC,SAAS,SAAS,kBAAkB;AAAA,EACvC;AAEA,QAAM,CAAC,OAAO,IAAI,SAAS,MAAM,IAAI,iBAAiB,KAAK,eAAe,CAAC;AAE3E,YAAU,MAAM;AACd,WAAO,MAAM;AACX,cAAQ,QAAQ,yBAAyB,EAAE,OAAO;AAAA,IACpD;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAU,MAAM;AACd,YAAQ,QAAQ,yBAAyB,EAAE,sBAAsB,GAAG;AACpE,YAAQ,QAAQ,yBAAyB,EAAE,gBAAgB;AAAA,EAC7D,GAAG,CAAC,SAAS,GAAG,CAAC;AAEjB,YAAU,MAAM;AACd,QAAI,CAAC,aAAc,QAAO;AAC1B,WAAO,QAAQ,6BAA6B,YAAY;AAAA,EAC1D,GAAG,CAAC,cAAc,OAAO,CAAC;AAE1B,SAAO,QAAQ,MAAM,IAAI,qBAAqB,OAAO,GAAG,CAAC,OAAO,CAAC;AACnE;AAEO,IAAM,kBAAkB,CAC7B,SACA,EAAE,OAAO,GAAG,QAAQ,IAAyB,CAAC,MAC3C;AACH,QAAM,eAAe,0BAA0B,EAAE,MAAM,CAAC;AACxD,SAAO,2BAA2B;AAAA,IAChC,aAAa,SAAS,cAAc;AAClC,aAAO,sBAAsB,SAAS,OAAO;AAAA,IAC/C;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AACH;","names":[]}
|
package/package.json
CHANGED
@@ -28,7 +28,7 @@
|
|
28
28
|
"conversational-ui",
|
29
29
|
"conversational-ai"
|
30
30
|
],
|
31
|
-
"version": "0.10.
|
31
|
+
"version": "0.10.22",
|
32
32
|
"license": "MIT",
|
33
33
|
"type": "module",
|
34
34
|
"exports": {
|
@@ -57,7 +57,7 @@
|
|
57
57
|
"@radix-ui/react-use-callback-ref": "^1.1.1",
|
58
58
|
"@radix-ui/react-use-escape-keydown": "^1.1.1",
|
59
59
|
"@standard-schema/spec": "^1.0.0",
|
60
|
-
"assistant-stream": "^0.2.
|
60
|
+
"assistant-stream": "^0.2.15",
|
61
61
|
"json-schema": "^0.4.0",
|
62
62
|
"nanoid": "5.1.5",
|
63
63
|
"react-textarea-autosize": "^8.5.9",
|
@@ -2,11 +2,13 @@ import { AssistantCloudAPI, AssistantCloudConfig } from "./AssistantCloudAPI";
|
|
2
2
|
import { AssistantCloudAuthTokens } from "./AssistantCloudAuthTokens";
|
3
3
|
import { AssistantCloudRuns } from "./AssistantCloudRuns";
|
4
4
|
import { AssistantCloudThreads } from "./AssistantCloudThreads";
|
5
|
+
import { AssistantCloudFiles } from "./AssistantCloudFiles";
|
5
6
|
|
6
7
|
export class AssistantCloud {
|
7
8
|
public readonly threads;
|
8
9
|
public readonly auth;
|
9
10
|
public readonly runs;
|
11
|
+
public readonly files;
|
10
12
|
|
11
13
|
constructor(config: AssistantCloudConfig) {
|
12
14
|
const api = new AssistantCloudAPI(config);
|
@@ -15,5 +17,6 @@ export class AssistantCloud {
|
|
15
17
|
tokens: new AssistantCloudAuthTokens(api),
|
16
18
|
};
|
17
19
|
this.runs = new AssistantCloudRuns(api);
|
20
|
+
this.files = new AssistantCloudFiles(api);
|
18
21
|
}
|
19
22
|
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import { AssistantCloudAPI } from "./AssistantCloudAPI";
|
2
|
+
|
3
|
+
type PdfToImagesRequestBody = {
|
4
|
+
file_blob?: string | undefined;
|
5
|
+
file_url?: string | undefined;
|
6
|
+
};
|
7
|
+
|
8
|
+
type PdfToImagesResponse = {
|
9
|
+
success: boolean;
|
10
|
+
urls: string[];
|
11
|
+
message: string;
|
12
|
+
};
|
13
|
+
|
14
|
+
type GeneratePresignedUploadUrlRequestBody = {
|
15
|
+
filename: string;
|
16
|
+
};
|
17
|
+
|
18
|
+
type GeneratePresignedUploadUrlResponse = {
|
19
|
+
success: boolean;
|
20
|
+
signedUrl: string;
|
21
|
+
expiresAt: string;
|
22
|
+
publicUrl: string;
|
23
|
+
};
|
24
|
+
|
25
|
+
export class AssistantCloudFiles {
|
26
|
+
constructor(private cloud: AssistantCloudAPI) {}
|
27
|
+
|
28
|
+
public async pdfToImages(
|
29
|
+
body: PdfToImagesRequestBody,
|
30
|
+
): Promise<PdfToImagesResponse> {
|
31
|
+
return this.cloud.makeRequest("/files/pdf-to-images", {
|
32
|
+
method: "POST",
|
33
|
+
body,
|
34
|
+
});
|
35
|
+
}
|
36
|
+
|
37
|
+
public async generatePresignedUploadUrl(
|
38
|
+
body: GeneratePresignedUploadUrlRequestBody,
|
39
|
+
): Promise<GeneratePresignedUploadUrlResponse> {
|
40
|
+
return this.cloud.makeRequest("/files/attachments/generate-presigned-upload-url", {
|
41
|
+
method: "POST",
|
42
|
+
body,
|
43
|
+
});
|
44
|
+
}
|
45
|
+
}
|
@@ -3,13 +3,13 @@
|
|
3
3
|
import { useEffect, useMemo, useState } from "react";
|
4
4
|
import type { ChatModelAdapter } from "./ChatModelAdapter";
|
5
5
|
import { LocalRuntimeCore } from "./LocalRuntimeCore";
|
6
|
-
import { LocalRuntimeOptions } from "./LocalRuntimeOptions";
|
6
|
+
import type { LocalRuntimeOptions } from "./LocalRuntimeOptions";
|
7
7
|
import { useRuntimeAdapters } from "../adapters/RuntimeAdapterProvider";
|
8
8
|
import { useRemoteThreadListRuntime } from "../remote-thread-list/useRemoteThreadListRuntime";
|
9
9
|
import { useCloudThreadListAdapter } from "../remote-thread-list/adapter/cloud";
|
10
10
|
import { AssistantRuntimeImpl } from "../../internal";
|
11
11
|
|
12
|
-
const useLocalThreadRuntime = (
|
12
|
+
export const useLocalThreadRuntime = (
|
13
13
|
adapter: ChatModelAdapter,
|
14
14
|
{ initialMessages, ...options }: LocalRuntimeOptions,
|
15
15
|
) => {
|
@@ -0,0 +1,521 @@
|
|
1
|
+
import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
|
2
|
+
import { AssistantCloudFiles } from "../cloud/AssistantCloudFiles";
|
3
|
+
import { AssistantCloudAPI } from "../cloud/AssistantCloudAPI";
|
4
|
+
|
5
|
+
// Mock the AssistantCloudAPI to avoid making real HTTP requests (except for integration tests)
|
6
|
+
vi.mock("../cloud/AssistantCloudAPI");
|
7
|
+
|
8
|
+
describe("AssistantCloudFiles", () => {
|
9
|
+
let cloudFiles: AssistantCloudFiles;
|
10
|
+
let mockApi: AssistantCloudAPI;
|
11
|
+
|
12
|
+
beforeEach(() => {
|
13
|
+
// Create a mock API instance
|
14
|
+
mockApi = {
|
15
|
+
makeRequest: vi.fn(),
|
16
|
+
makeRawRequest: vi.fn(),
|
17
|
+
_auth: { getAuthHeaders: vi.fn() },
|
18
|
+
_baseUrl: "https://backend.assistant-api.com",
|
19
|
+
} as unknown as AssistantCloudAPI;
|
20
|
+
|
21
|
+
// Create the AssistantCloudFiles instance with the mock API
|
22
|
+
cloudFiles = new AssistantCloudFiles(mockApi);
|
23
|
+
});
|
24
|
+
|
25
|
+
afterEach(() => {
|
26
|
+
vi.clearAllMocks();
|
27
|
+
});
|
28
|
+
|
29
|
+
describe("pdfToImages", () => {
|
30
|
+
/**
|
31
|
+
* Tests successful PDF to images conversion with file_url
|
32
|
+
* This matches the curl request structure provided
|
33
|
+
*/
|
34
|
+
it("should successfully convert PDF to images using file_url", async () => {
|
35
|
+
const mockResponse = {
|
36
|
+
success: true,
|
37
|
+
urls: [
|
38
|
+
"https://aui-pdf-processing.5c52327048f352f85fb041947c406ab4.r2.cloudflarestorage.com/images/8eb81c61-dc76-48fd-ab66-25cd84a28c97/page-1.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=8698a7e98d990c6edd11fee3a9d0f3f0%2F20250606%2Fauto%2Fs3%2Faws4_request&X-Amz-Date=20250606T035428Z&X-Amz-Expires=3600&X-Amz-Signature=ea26cdd5ff7dc85eba12970137606484b9a8ab2c520f31ddba9cbe5941b20793&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",
|
39
|
+
"https://aui-pdf-processing.5c52327048f352f85fb041947c406ab4.r2.cloudflarestorage.com/images/8eb81c61-dc76-48fd-ab66-25cd84a28c97/page-2.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=8698a7e98d990c6edd11fee3a9d0f3f0%2F20250606%2Fauto%2Fs3%2Faws4_request&X-Amz-Date=20250606T035428Z&X-Amz-Expires=3600&X-Amz-Signature=3499237770cc4402a60e6cc9b8ce8bd460faade9adf456d2773009f7d07af9cb&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",
|
40
|
+
"https://aui-pdf-processing.5c52327048f352f85fb041947c406ab4.r2.cloudflarestorage.com/images/8eb81c61-dc76-48fd-ab66-25cd84a28c97/page-3.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=8698a7e98d990c6edd11fee3a9d0f3f0%2F20250606%2Fauto%2Fs3%2Faws4_request&X-Amz-Date=20250606T035429Z&X-Amz-Expires=3600&X-Amz-Signature=663ee073972f1b7b82cede9039ed4bc0a6c08118533a9586e871807baf032bc2&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject"
|
41
|
+
],
|
42
|
+
message: "PDF successfully converted to images"
|
43
|
+
};
|
44
|
+
|
45
|
+
// Mock the API call to return our expected response
|
46
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
47
|
+
|
48
|
+
const requestBody = {
|
49
|
+
file_url: "https://files.testfile.org/PDF/10MB-TESTFILE.ORG.pdf"
|
50
|
+
};
|
51
|
+
|
52
|
+
const result = await cloudFiles.pdfToImages(requestBody);
|
53
|
+
|
54
|
+
// Verify the API was called correctly
|
55
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/pdf-to-images", {
|
56
|
+
method: "POST",
|
57
|
+
body: requestBody,
|
58
|
+
});
|
59
|
+
|
60
|
+
// Verify the response structure
|
61
|
+
expect(result).toEqual(mockResponse);
|
62
|
+
expect(result.success).toBe(true);
|
63
|
+
expect(result.urls).toHaveLength(3);
|
64
|
+
expect(result.message).toBe("PDF successfully converted to images");
|
65
|
+
expect(result.urls[0]).toContain("page-1.png");
|
66
|
+
expect(result.urls[1]).toContain("page-2.png");
|
67
|
+
expect(result.urls[2]).toContain("page-3.png");
|
68
|
+
});
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Tests successful PDF to images conversion with file_blob
|
72
|
+
*/
|
73
|
+
it("should successfully convert PDF to images using file_blob", async () => {
|
74
|
+
const mockResponse = {
|
75
|
+
success: true,
|
76
|
+
urls: [
|
77
|
+
"https://example.com/converted-image-1.png",
|
78
|
+
"https://example.com/converted-image-2.png"
|
79
|
+
],
|
80
|
+
message: "PDF successfully converted to images"
|
81
|
+
};
|
82
|
+
|
83
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
84
|
+
|
85
|
+
const requestBody = {
|
86
|
+
file_blob: "data:application/pdf;base64,JVBERi0xLjQKJdPr6eEKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKL01lZGlhQm94IFswIDAgNTk1IDg0Ml0KPj4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCA1OTUgODQyXQovQ29udGVudHMgNCAwIFIKPj4KZW5kb2JqCjQgMCBvYmoKPDwKL0xlbmd0aCA0NAo+PgpzdHJlYW0KQlQKL0YxIDEyIFRmCjEwMCA3MDAgVGQKKFRlc3QgUERGKSBUagoKRVQKZW5kc3RyZWFtCmVuZG9iago1IDAgb2JqCjw8Ci9UeXBlIC9Gb250Ci9CYXNlRm9udCAvSGVsdmV0aWNhCi9TdWJ0eXBlIC9UeXBlMQo+PgplbmRvYmoKNiAwIG9iago8PAovVHlwZSAvRm9udERlc2NyaXB0b3IKL0ZvbnROYW1lIC9IZWx2ZXRpY2EKPj4KZW5kb2JqCnhyZWYKMCA3CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDc0IDAwMDAwIG4gCjAwMDAwMDAxMzMgMDAwMDAgbiAKMDAwMDAwMDIwNCAwMDAwMCBuIAowMDAwMDAwMjk5IDAwMDAwIG4gCjAwMDAwMDAzNzYgMDAwMDAgbiAKdHJhaWxlcgo8PAovU2l6ZSA3Ci9Sb290IDEgMCBSCj4+CnN0YXJ0eHJlZgo0MzQKJSVFT0YK"
|
87
|
+
};
|
88
|
+
|
89
|
+
const result = await cloudFiles.pdfToImages(requestBody);
|
90
|
+
|
91
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/pdf-to-images", {
|
92
|
+
method: "POST",
|
93
|
+
body: requestBody,
|
94
|
+
});
|
95
|
+
|
96
|
+
expect(result).toEqual(mockResponse);
|
97
|
+
expect(result.success).toBe(true);
|
98
|
+
expect(result.urls).toHaveLength(2);
|
99
|
+
});
|
100
|
+
|
101
|
+
/**
|
102
|
+
* Tests API error handling
|
103
|
+
*/
|
104
|
+
it("should handle API errors gracefully", async () => {
|
105
|
+
const errorMessage = "Invalid PDF file";
|
106
|
+
vi.mocked(mockApi.makeRequest).mockRejectedValue(new Error(errorMessage));
|
107
|
+
|
108
|
+
const requestBody = {
|
109
|
+
file_url: "https://invalid-url.com/not-a-pdf.txt"
|
110
|
+
};
|
111
|
+
|
112
|
+
await expect(cloudFiles.pdfToImages(requestBody)).rejects.toThrow(errorMessage);
|
113
|
+
|
114
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/pdf-to-images", {
|
115
|
+
method: "POST",
|
116
|
+
body: requestBody,
|
117
|
+
});
|
118
|
+
});
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Tests handling of failed conversion response
|
122
|
+
*/
|
123
|
+
it("should handle failed conversion response", async () => {
|
124
|
+
const mockResponse = {
|
125
|
+
success: false,
|
126
|
+
urls: [],
|
127
|
+
message: "Failed to convert PDF: File too large"
|
128
|
+
};
|
129
|
+
|
130
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
131
|
+
|
132
|
+
const requestBody = {
|
133
|
+
file_url: "https://example.com/huge-file.pdf"
|
134
|
+
};
|
135
|
+
|
136
|
+
const result = await cloudFiles.pdfToImages(requestBody);
|
137
|
+
|
138
|
+
expect(result.success).toBe(false);
|
139
|
+
expect(result.urls).toHaveLength(0);
|
140
|
+
expect(result.message).toBe("Failed to convert PDF: File too large");
|
141
|
+
});
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Tests that the method works with both file_url and file_blob undefined (edge case)
|
145
|
+
*/
|
146
|
+
it("should handle empty request body", async () => {
|
147
|
+
const mockResponse = {
|
148
|
+
success: false,
|
149
|
+
urls: [],
|
150
|
+
message: "No file provided"
|
151
|
+
};
|
152
|
+
|
153
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
154
|
+
|
155
|
+
const requestBody = {};
|
156
|
+
|
157
|
+
const result = await cloudFiles.pdfToImages(requestBody);
|
158
|
+
|
159
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/pdf-to-images", {
|
160
|
+
method: "POST",
|
161
|
+
body: requestBody,
|
162
|
+
});
|
163
|
+
|
164
|
+
expect(result.success).toBe(false);
|
165
|
+
expect(result.urls).toHaveLength(0);
|
166
|
+
});
|
167
|
+
|
168
|
+
/**
|
169
|
+
* Tests that the method sends the correct request headers and structure
|
170
|
+
* This ensures compatibility with the API key authentication shown in the curl example
|
171
|
+
*/
|
172
|
+
it("should make request to correct endpoint with proper structure", async () => {
|
173
|
+
const mockResponse = {
|
174
|
+
success: true,
|
175
|
+
urls: ["https://example.com/image.png"],
|
176
|
+
message: "Success"
|
177
|
+
};
|
178
|
+
|
179
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
180
|
+
|
181
|
+
const requestBody = {
|
182
|
+
file_url: "https://files.testfile.org/PDF/10MB-TESTFILE.ORG.pdf"
|
183
|
+
};
|
184
|
+
|
185
|
+
await cloudFiles.pdfToImages(requestBody);
|
186
|
+
|
187
|
+
// Verify the endpoint and method are correct
|
188
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/pdf-to-images", {
|
189
|
+
method: "POST",
|
190
|
+
body: requestBody,
|
191
|
+
});
|
192
|
+
|
193
|
+
// Verify it was called exactly once
|
194
|
+
expect(mockApi.makeRequest).toHaveBeenCalledTimes(1);
|
195
|
+
});
|
196
|
+
|
197
|
+
/**
|
198
|
+
* Tests that both file_url and file_blob can be provided simultaneously
|
199
|
+
*/
|
200
|
+
it("should handle request with both file_url and file_blob", async () => {
|
201
|
+
const mockResponse = {
|
202
|
+
success: true,
|
203
|
+
urls: ["https://example.com/image.png"],
|
204
|
+
message: "Success"
|
205
|
+
};
|
206
|
+
|
207
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
208
|
+
|
209
|
+
const requestBody = {
|
210
|
+
file_url: "https://example.com/file.pdf",
|
211
|
+
file_blob: "base64data..."
|
212
|
+
};
|
213
|
+
|
214
|
+
const result = await cloudFiles.pdfToImages(requestBody);
|
215
|
+
|
216
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/pdf-to-images", {
|
217
|
+
method: "POST",
|
218
|
+
body: requestBody,
|
219
|
+
});
|
220
|
+
|
221
|
+
expect(result).toEqual(mockResponse);
|
222
|
+
});
|
223
|
+
});
|
224
|
+
|
225
|
+
describe("generatePresignedUploadUrl", () => {
|
226
|
+
/**
|
227
|
+
* Tests successful generation of presigned upload URL
|
228
|
+
* This matches the curl request structure provided
|
229
|
+
*/
|
230
|
+
it("should successfully generate presigned upload URL", async () => {
|
231
|
+
const mockResponse = {
|
232
|
+
success: true,
|
233
|
+
signedUrl: "https://aui-cloud-attachments.5c52327048f352f85fb041947c406ab4.r2.cloudflarestorage.com/attachments/0204c5a7-cd09-470c-9488-96cf0be9db92.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=8698a7e98d990c6edd11fee3a9d0f3f0%2F20250606%2Fauto%2Fs3%2Faws4_request&X-Amz-Date=20250606T051813Z&X-Amz-Expires=900&X-Amz-Signature=b0d27e7bee6200eb1964ad1d7f4a8ad76db15a3d99bd4fb47ff4b0b08fee5ca5&X-Amz-SignedHeaders=content-length%3Bhost&x-amz-checksum-crc32=AAAAAA%3D%3D&x-amz-meta-original-filename=hello.pdf&x-amz-meta-project-id=proj_09369w56dnge&x-amz-meta-user-id=676767&x-amz-sdk-checksum-algorithm=CRC32&x-id=PutObject",
|
234
|
+
expiresAt: "2025-06-06T05:33:13.322Z",
|
235
|
+
publicUrl: "https://storage.assistant-api.com/attachments/0204c5a7-cd09-470c-9488-96cf0be9db92.pdf"
|
236
|
+
};
|
237
|
+
|
238
|
+
// Mock the API call to return our expected response
|
239
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
240
|
+
|
241
|
+
const requestBody = {
|
242
|
+
filename: "hello.pdf"
|
243
|
+
};
|
244
|
+
|
245
|
+
const result = await cloudFiles.generatePresignedUploadUrl(requestBody);
|
246
|
+
|
247
|
+
// Verify the API was called correctly
|
248
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/attachments/generate-presigned-upload-url", {
|
249
|
+
method: "POST",
|
250
|
+
body: requestBody,
|
251
|
+
});
|
252
|
+
|
253
|
+
// Verify the response structure
|
254
|
+
expect(result).toEqual(mockResponse);
|
255
|
+
expect(result.success).toBe(true);
|
256
|
+
expect(result.signedUrl).toContain("aui-cloud-attachments");
|
257
|
+
expect(result.signedUrl).toContain("X-Amz-Algorithm=AWS4-HMAC-SHA256");
|
258
|
+
expect(result.expiresAt).toBe("2025-06-06T05:33:13.322Z");
|
259
|
+
expect(result.publicUrl).toBe("https://storage.assistant-api.com/attachments/0204c5a7-cd09-470c-9488-96cf0be9db92.pdf");
|
260
|
+
});
|
261
|
+
|
262
|
+
/**
|
263
|
+
* Tests generation with different file types
|
264
|
+
*/
|
265
|
+
it("should successfully generate presigned upload URL for different file types", async () => {
|
266
|
+
const mockResponse = {
|
267
|
+
success: true,
|
268
|
+
signedUrl: "https://aui-cloud-attachments.5c52327048f352f85fb041947c406ab4.r2.cloudflarestorage.com/attachments/test-image.png",
|
269
|
+
expiresAt: "2025-06-06T05:33:13.322Z",
|
270
|
+
publicUrl: "https://storage.assistant-api.com/attachments/test-image.png"
|
271
|
+
};
|
272
|
+
|
273
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
274
|
+
|
275
|
+
const requestBody = {
|
276
|
+
filename: "test-image.png"
|
277
|
+
};
|
278
|
+
|
279
|
+
const result = await cloudFiles.generatePresignedUploadUrl(requestBody);
|
280
|
+
|
281
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/attachments/generate-presigned-upload-url", {
|
282
|
+
method: "POST",
|
283
|
+
body: requestBody,
|
284
|
+
});
|
285
|
+
|
286
|
+
expect(result).toEqual(mockResponse);
|
287
|
+
expect(result.success).toBe(true);
|
288
|
+
expect(result.publicUrl).toContain("test-image.png");
|
289
|
+
});
|
290
|
+
|
291
|
+
/**
|
292
|
+
* Tests API error handling
|
293
|
+
*/
|
294
|
+
it("should handle API errors gracefully", async () => {
|
295
|
+
const errorMessage = "Invalid filename";
|
296
|
+
vi.mocked(mockApi.makeRequest).mockRejectedValue(new Error(errorMessage));
|
297
|
+
|
298
|
+
const requestBody = {
|
299
|
+
filename: ""
|
300
|
+
};
|
301
|
+
|
302
|
+
await expect(cloudFiles.generatePresignedUploadUrl(requestBody)).rejects.toThrow(errorMessage);
|
303
|
+
|
304
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/attachments/generate-presigned-upload-url", {
|
305
|
+
method: "POST",
|
306
|
+
body: requestBody,
|
307
|
+
});
|
308
|
+
});
|
309
|
+
|
310
|
+
/**
|
311
|
+
* Tests handling of failed response
|
312
|
+
*/
|
313
|
+
it("should handle failed upload URL generation response", async () => {
|
314
|
+
const mockResponse = {
|
315
|
+
success: false,
|
316
|
+
signedUrl: "",
|
317
|
+
expiresAt: "",
|
318
|
+
publicUrl: ""
|
319
|
+
};
|
320
|
+
|
321
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
322
|
+
|
323
|
+
const requestBody = {
|
324
|
+
filename: "invalid-file-type.exe"
|
325
|
+
};
|
326
|
+
|
327
|
+
const result = await cloudFiles.generatePresignedUploadUrl(requestBody);
|
328
|
+
|
329
|
+
expect(result.success).toBe(false);
|
330
|
+
expect(result.signedUrl).toBe("");
|
331
|
+
expect(result.publicUrl).toBe("");
|
332
|
+
});
|
333
|
+
|
334
|
+
/**
|
335
|
+
* Tests that the method sends the correct request headers and structure
|
336
|
+
*/
|
337
|
+
it("should make request to correct endpoint with proper structure", async () => {
|
338
|
+
const mockResponse = {
|
339
|
+
success: true,
|
340
|
+
signedUrl: "https://example.com/signed-url",
|
341
|
+
expiresAt: "2025-06-06T05:33:13.322Z",
|
342
|
+
publicUrl: "https://example.com/public-url"
|
343
|
+
};
|
344
|
+
|
345
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
346
|
+
|
347
|
+
const requestBody = {
|
348
|
+
filename: "document.pdf"
|
349
|
+
};
|
350
|
+
|
351
|
+
await cloudFiles.generatePresignedUploadUrl(requestBody);
|
352
|
+
|
353
|
+
// Verify the endpoint and method are correct
|
354
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/attachments/generate-presigned-upload-url", {
|
355
|
+
method: "POST",
|
356
|
+
body: requestBody,
|
357
|
+
});
|
358
|
+
|
359
|
+
// Verify it was called exactly once
|
360
|
+
expect(mockApi.makeRequest).toHaveBeenCalledTimes(1);
|
361
|
+
});
|
362
|
+
|
363
|
+
/**
|
364
|
+
* Tests filename validation scenarios
|
365
|
+
*/
|
366
|
+
it("should handle various filename formats", async () => {
|
367
|
+
const mockResponse = {
|
368
|
+
success: true,
|
369
|
+
signedUrl: "https://example.com/signed-url",
|
370
|
+
expiresAt: "2025-06-06T05:33:13.322Z",
|
371
|
+
publicUrl: "https://example.com/public-url"
|
372
|
+
};
|
373
|
+
|
374
|
+
vi.mocked(mockApi.makeRequest).mockResolvedValue(mockResponse);
|
375
|
+
|
376
|
+
// Test with filename containing spaces and special characters
|
377
|
+
const requestBody = {
|
378
|
+
filename: "my document (final version).pdf"
|
379
|
+
};
|
380
|
+
|
381
|
+
const result = await cloudFiles.generatePresignedUploadUrl(requestBody);
|
382
|
+
|
383
|
+
expect(mockApi.makeRequest).toHaveBeenCalledWith("/files/attachments/generate-presigned-upload-url", {
|
384
|
+
method: "POST",
|
385
|
+
body: requestBody,
|
386
|
+
});
|
387
|
+
|
388
|
+
expect(result).toEqual(mockResponse);
|
389
|
+
});
|
390
|
+
});
|
391
|
+
|
392
|
+
// Integration test that actually calls the real API
|
393
|
+
describe("Integration Tests", () => {
|
394
|
+
/**
|
395
|
+
* Integration test that actually calls the real API endpoint
|
396
|
+
* This test requires real API credentials to be set in environment variables:
|
397
|
+
* - AUI_API_KEY: Your API key (e.g., sk_aui_proj_...)
|
398
|
+
* - AUI_USER_ID: Your user ID
|
399
|
+
* - AUI_WORKSPACE_ID: Your workspace ID
|
400
|
+
*/
|
401
|
+
it.skipIf(!process.env.AUI_API_KEY || !process.env.AUI_USER_ID || !process.env.AUI_WORKSPACE_ID)(
|
402
|
+
"should actually convert PDF to images using real API", async () => {
|
403
|
+
// Unmock all modules for this test to use real implementations
|
404
|
+
vi.doUnmock("../cloud/AssistantCloudAPI");
|
405
|
+
vi.doUnmock("../cloud/AssistantCloudFiles");
|
406
|
+
vi.doUnmock("../cloud/AssistantCloud");
|
407
|
+
|
408
|
+
// Clear all mocks and reload modules
|
409
|
+
vi.resetModules();
|
410
|
+
|
411
|
+
// Import real modules
|
412
|
+
const { AssistantCloud: RealAssistantCloud } = await import("../cloud/AssistantCloud");
|
413
|
+
|
414
|
+
const realCloud = new RealAssistantCloud({
|
415
|
+
apiKey: process.env.AUI_API_KEY!,
|
416
|
+
userId: process.env.AUI_USER_ID!,
|
417
|
+
workspaceId: process.env.AUI_WORKSPACE_ID!,
|
418
|
+
});
|
419
|
+
|
420
|
+
const requestBody = {
|
421
|
+
file_url: "https://files.testfile.org/PDF/10MB-TESTFILE.ORG.pdf"
|
422
|
+
};
|
423
|
+
|
424
|
+
console.log("Making API call to convert PDF...");
|
425
|
+
const result = await realCloud.files.pdfToImages(requestBody);
|
426
|
+
console.log("API call result:", result);
|
427
|
+
|
428
|
+
// Verify the response structure
|
429
|
+
expect(result).toHaveProperty("success");
|
430
|
+
expect(result).toHaveProperty("urls");
|
431
|
+
expect(result).toHaveProperty("message");
|
432
|
+
|
433
|
+
if (result.success) {
|
434
|
+
expect(Array.isArray(result.urls)).toBe(true);
|
435
|
+
expect(result.urls.length).toBeGreaterThan(0);
|
436
|
+
expect(typeof result.message).toBe("string");
|
437
|
+
|
438
|
+
// Verify URLs are valid image URLs
|
439
|
+
result.urls.forEach(url => {
|
440
|
+
expect(url).toMatch(/^https:\/\/.+\.(png|jpg|jpeg)(\?.*)?$/i);
|
441
|
+
});
|
442
|
+
} else {
|
443
|
+
// If it fails, at least verify the error message is a string
|
444
|
+
expect(typeof result.message).toBe("string");
|
445
|
+
console.log("API call failed:", result.message);
|
446
|
+
}
|
447
|
+
|
448
|
+
// Restore mocks after the test
|
449
|
+
vi.doMock("../cloud/AssistantCloudAPI");
|
450
|
+
},
|
451
|
+
60000 // 60 second timeout for real API calls
|
452
|
+
);
|
453
|
+
|
454
|
+
/**
|
455
|
+
* Integration test for generatePresignedUploadUrl that actually calls the real API endpoint
|
456
|
+
* This test requires real API credentials to be set in environment variables:
|
457
|
+
* - AUI_API_KEY: Your API key (e.g., sk_aui_proj_...)
|
458
|
+
* - AUI_USER_ID: Your user ID
|
459
|
+
* - AUI_WORKSPACE_ID: Your workspace ID
|
460
|
+
*/
|
461
|
+
it.skipIf(!process.env.AUI_API_KEY || !process.env.AUI_USER_ID || !process.env.AUI_WORKSPACE_ID)(
|
462
|
+
"should actually generate presigned upload URL using real API", async () => {
|
463
|
+
// Unmock all modules for this test to use real implementations
|
464
|
+
vi.doUnmock("../cloud/AssistantCloudAPI");
|
465
|
+
vi.doUnmock("../cloud/AssistantCloudFiles");
|
466
|
+
vi.doUnmock("../cloud/AssistantCloud");
|
467
|
+
|
468
|
+
// Clear all mocks and reload modules
|
469
|
+
vi.resetModules();
|
470
|
+
|
471
|
+
// Import real modules
|
472
|
+
const { AssistantCloud: RealAssistantCloud } = await import("../cloud/AssistantCloud");
|
473
|
+
|
474
|
+
const realCloud = new RealAssistantCloud({
|
475
|
+
apiKey: process.env.AUI_API_KEY!,
|
476
|
+
userId: process.env.AUI_USER_ID!,
|
477
|
+
workspaceId: process.env.AUI_WORKSPACE_ID!,
|
478
|
+
});
|
479
|
+
|
480
|
+
const requestBody = {
|
481
|
+
filename: "test-upload.pdf"
|
482
|
+
};
|
483
|
+
|
484
|
+
console.log("Making API call to generate presigned upload URL...");
|
485
|
+
const result = await realCloud.files.generatePresignedUploadUrl(requestBody);
|
486
|
+
console.log("API call result:", result);
|
487
|
+
|
488
|
+
// Verify the response structure
|
489
|
+
expect(result).toHaveProperty("success");
|
490
|
+
expect(result).toHaveProperty("signedUrl");
|
491
|
+
expect(result).toHaveProperty("expiresAt");
|
492
|
+
expect(result).toHaveProperty("publicUrl");
|
493
|
+
|
494
|
+
if (result.success) {
|
495
|
+
expect(typeof result.signedUrl).toBe("string");
|
496
|
+
expect(typeof result.expiresAt).toBe("string");
|
497
|
+
expect(typeof result.publicUrl).toBe("string");
|
498
|
+
expect(result.signedUrl.length).toBeGreaterThan(0);
|
499
|
+
expect(result.publicUrl.length).toBeGreaterThan(0);
|
500
|
+
|
501
|
+
// Verify URLs are valid HTTPS URLs
|
502
|
+
expect(result.signedUrl).toMatch(/^https:\/\/.+/);
|
503
|
+
expect(result.publicUrl).toMatch(/^https:\/\/.+/);
|
504
|
+
|
505
|
+
// Verify the signed URL contains expected AWS signature parameters
|
506
|
+
expect(result.signedUrl).toContain("X-Amz-Algorithm");
|
507
|
+
expect(result.signedUrl).toContain("X-Amz-Signature");
|
508
|
+
|
509
|
+
// Verify expiresAt is a valid ISO date string
|
510
|
+
expect(() => new Date(result.expiresAt)).not.toThrow();
|
511
|
+
} else {
|
512
|
+
console.log("API call failed - this may be expected for some test cases");
|
513
|
+
}
|
514
|
+
|
515
|
+
// Restore mocks after the test
|
516
|
+
vi.doMock("../cloud/AssistantCloudAPI");
|
517
|
+
},
|
518
|
+
30000 // 30 second timeout for real API calls
|
519
|
+
);
|
520
|
+
});
|
521
|
+
});
|