diff --git a/src/cloudflare/internal/ai-api.ts b/src/cloudflare/internal/ai-api.ts index 5e6b51f9c65..e189f830ac8 100644 --- a/src/cloudflare/internal/ai-api.ts +++ b/src/cloudflare/internal/ai-api.ts @@ -42,7 +42,7 @@ export type AiOptions = { }; export type AiInputReadableStream = { - body: ReadableStream; + body: ReadableStream | FormData; contentType: string; }; @@ -87,14 +87,12 @@ export class AiInternalError extends Error { } } -// TODO: merge this function with the one with images-api.ts function isReadableStream(obj: unknown): obj is ReadableStream { - return !!( - obj && - typeof obj === 'object' && - 'getReader' in obj && - typeof obj.getReader === 'function' - ); + return obj instanceof ReadableStream; +} + +function isFormData(obj: unknown): obj is FormData { + return obj instanceof FormData; } /** @@ -111,9 +109,9 @@ function findReadableStreamKeys( value && typeof value === 'object' && 'body' in value && - isReadableStream(value.body); + (isReadableStream(value.body) || isFormData(value.body)); - if (hasReadableStreamBody || isReadableStream(value)) { + if (hasReadableStreamBody || isReadableStream(value) || isFormData(value)) { readableStreamKeys.push(key); } } diff --git a/src/cloudflare/internal/test/ai/ai-api-test.js b/src/cloudflare/internal/test/ai/ai-api-test.js index ceea08d1761..20e2302dfe5 100644 --- a/src/cloudflare/internal/test/ai/ai-api-test.js +++ b/src/cloudflare/internal/test/ai/ai-api-test.js @@ -214,6 +214,25 @@ export const tests = { ); } + { + // Test form data input + const form = new FormData(); + form.append('prompt', 'cat'); + const resp = await env.ai.run('formDataInputs', { + audio: { + body: form, + contentType: 'multipart/form-data', + }, + }); + + assert.deepStrictEqual(resp, { + inputs: {}, + options: { userInputs: '{}', version: '3' }, + requestUrl: + 'https://workers-binding.ai/run?version=3&userInputs=%7B%7D', + }); + } + { // Test gateway option const resp = await env.ai.run( diff --git a/src/cloudflare/internal/test/ai/ai-mock.js b/src/cloudflare/internal/test/ai/ai-mock.js index 2095d162967..77f29da8504 100644 --- a/src/cloudflare/internal/test/ai/ai-mock.js +++ b/src/cloudflare/internal/test/ai/ai-mock.js @@ -97,6 +97,19 @@ export default { ); } + if (modelName === 'formDataInputs') { + return Response.json( + { + inputs: {}, + options: { ...data.options }, + requestUrl: request.url, + }, + { + headers: respHeaders, + } + ); + } + if (modelName === 'inputErrorModel') { return Response.json( { diff --git a/types/defines/ai.d.ts b/types/defines/ai.d.ts index 23b648cf5c1..90a8671c162 100644 --- a/types/defines/ai.d.ts +++ b/types/defines/ai.d.ts @@ -5415,7 +5415,7 @@ export type AiOptions = { * Maximum 5 tags are allowed each request. * Duplicate tags will removed. */ - tags: string[]; + tags?: string[]; gateway?: GatewayOptions; returnRawResponse?: boolean; prefix?: string; diff --git a/types/generated-snapshot/experimental/index.d.ts b/types/generated-snapshot/experimental/index.d.ts index 5b7541551f5..e4b5a28d60a 100755 --- a/types/generated-snapshot/experimental/index.d.ts +++ b/types/generated-snapshot/experimental/index.d.ts @@ -9932,7 +9932,7 @@ type AiOptions = { * Maximum 5 tags are allowed each request. * Duplicate tags will removed. */ - tags: string[]; + tags?: string[]; gateway?: GatewayOptions; returnRawResponse?: boolean; prefix?: string; diff --git a/types/generated-snapshot/experimental/index.ts b/types/generated-snapshot/experimental/index.ts index 02bc0cefb20..aa8d0376387 100755 --- a/types/generated-snapshot/experimental/index.ts +++ b/types/generated-snapshot/experimental/index.ts @@ -9946,7 +9946,7 @@ export type AiOptions = { * Maximum 5 tags are allowed each request. * Duplicate tags will removed. */ - tags: string[]; + tags?: string[]; gateway?: GatewayOptions; returnRawResponse?: boolean; prefix?: string; diff --git a/types/generated-snapshot/latest/index.d.ts b/types/generated-snapshot/latest/index.d.ts index cf4c1ef9ba0..4a7887dd6e5 100755 --- a/types/generated-snapshot/latest/index.d.ts +++ b/types/generated-snapshot/latest/index.d.ts @@ -9328,7 +9328,7 @@ type AiOptions = { * Maximum 5 tags are allowed each request. * Duplicate tags will removed. */ - tags: string[]; + tags?: string[]; gateway?: GatewayOptions; returnRawResponse?: boolean; prefix?: string; diff --git a/types/generated-snapshot/latest/index.ts b/types/generated-snapshot/latest/index.ts index 41f1457a631..59ff5b53254 100755 --- a/types/generated-snapshot/latest/index.ts +++ b/types/generated-snapshot/latest/index.ts @@ -9340,7 +9340,7 @@ export type AiOptions = { * Maximum 5 tags are allowed each request. * Duplicate tags will removed. */ - tags: string[]; + tags?: string[]; gateway?: GatewayOptions; returnRawResponse?: boolean; prefix?: string;