11import type { Readable } from 'node:stream'
22
3+ import type {
4+ CompileAssemblyInstructionsOptions ,
5+ CompileAssemblyInstructionsResult ,
6+ } from '@transloadit/utils'
37import type { Delays , Headers , OptionsOfJSONResponseBody , RetryOptions } from 'got'
48
59import type { TransloaditErrorResponseBody } from './ApiError.ts'
@@ -43,6 +47,7 @@ import { access, stat } from 'node:fs/promises'
4347import { basename } from 'node:path'
4448import { setTimeout as delay } from 'node:timers/promises'
4549
50+ import { compileAssemblyInstructionsFromPrompt } from '@transloadit/utils'
4651import { getSignedSmartCdnUrl , signParamsSync } from '@transloadit/utils/node'
4752import debug from 'debug'
4853import FormData from 'form-data'
@@ -62,6 +67,14 @@ import PaginationStream from './PaginationStream.ts'
6267import PollingTimeoutError from './PollingTimeoutError.ts'
6368import { sendTusRequest } from './tus.ts'
6469
70+ export type {
71+ CompileAssemblyInstructionsAttempt ,
72+ CompileAssemblyInstructionsClient ,
73+ CompileAssemblyInstructionsLintIssue ,
74+ CompileAssemblyInstructionsMessage ,
75+ CompileAssemblyInstructionsResult ,
76+ } from '@transloadit/utils'
77+
6578export type { AssemblyStatus } from './alphalib/types/assemblyStatus.ts'
6679export type {
6780 Base64Strategy ,
@@ -81,6 +94,11 @@ export type {
8194 RobotParamHelp ,
8295} from './robots.ts'
8396
97+ export {
98+ buildCompileAssemblyInstructionsSystemPrompt ,
99+ CompileAssemblyInstructionsError ,
100+ parseCompileAssemblyInstructionsResponse ,
101+ } from '@transloadit/utils'
84102// See https://github.com/sindresorhus/got/tree/v11.8.6?tab=readme-ov-file#errors
85103// Expose relevant errors
86104export {
@@ -274,6 +292,13 @@ export interface SmartCDNUrlOptions {
274292 expiresAt ?: number
275293}
276294
295+ export type CompileAssemblyInstructionsFromPromptOptions = Omit <
296+ CompileAssemblyInstructionsOptions ,
297+ 'client'
298+ > & {
299+ timeout ?: number
300+ }
301+
277302export type Fields = Record < string , string | number >
278303
279304// A special promise that lets the user immediately get the assembly ID (synchronously before the request is sent)
@@ -313,6 +338,37 @@ function checkResult<T>(result: T | { error: string }): asserts result is T {
313338 }
314339}
315340
341+ function getResultBilledChargeUsd ( result : unknown ) : number | undefined {
342+ if ( typeof result !== 'object' || result === null || Array . isArray ( result ) ) {
343+ return undefined
344+ }
345+
346+ if ( ! ( 'meta' in result ) ) {
347+ return undefined
348+ }
349+
350+ const { meta } = result
351+ if ( typeof meta !== 'object' || meta === null || Array . isArray ( meta ) ) {
352+ return undefined
353+ }
354+
355+ if ( ! ( 'billed_charge_usd' in meta ) ) {
356+ return undefined
357+ }
358+
359+ const { billed_charge_usd : billedChargeUsd } = meta
360+ return typeof billedChargeUsd === 'number' ? billedChargeUsd : undefined
361+ }
362+
363+ async function fetchJson ( url : string ) : Promise < unknown > {
364+ const response = await fetch ( url )
365+ if ( ! response . ok ) {
366+ throw new Error ( `Failed to fetch AI response: ${ response . status } ${ response . statusText } ` )
367+ }
368+
369+ return await response . json ( )
370+ }
371+
316372type AuthKeySecret = {
317373 authKey : string
318374 authSecret : string
@@ -552,6 +608,56 @@ export class Transloadit {
552608 } )
553609 }
554610
611+ /**
612+ * Compile a natural-language prompt into validated Assembly Instructions.
613+ *
614+ * This creates a zero-upload /ai/chat Assembly, validates the structured response,
615+ * and lints the generated instructions locally before returning them.
616+ */
617+ async compileAssemblyInstructionsFromPrompt (
618+ options : CompileAssemblyInstructionsFromPromptOptions ,
619+ ) : Promise < CompileAssemblyInstructionsResult > {
620+ const timeout = options . timeout ?? 5 * 60 * 1000
621+
622+ return await compileAssemblyInstructionsFromPrompt ( {
623+ ...options ,
624+ mcpServerUrl : options . mcpServerUrl ?? `${ this . _endpoint } /mcp` ,
625+ client : {
626+ runAssemblyInstructionsCompiler : async ( { aiStep } ) => {
627+ const assembly = await this . createAssembly ( {
628+ params : {
629+ steps : {
630+ ai : aiStep ,
631+ } ,
632+ } ,
633+ waitForCompletion : true ,
634+ expectedUploads : 0 ,
635+ timeout,
636+ } )
637+
638+ const result = assembly . results ?. ai ?. [ 0 ]
639+ const resultUrl = result ?. url
640+ if ( ! resultUrl ) {
641+ throw new Error ( 'No AI response in Assembly results.' )
642+ }
643+
644+ return {
645+ response : await fetchJson ( resultUrl ) ,
646+ assemblyUrl : assembly . assembly_ssl_url ?? assembly . assembly_url ?? undefined ,
647+ billedChargeUsd : getResultBilledChargeUsd ( result ) ,
648+ usageBytes : assembly . bytes_usage ?? undefined ,
649+ }
650+ } ,
651+ lintAssemblyInstructions : async ( instructionsJson ) => {
652+ const lintResult = await this . lintAssemblyInstructions ( {
653+ assemblyInstructions : instructionsJson ,
654+ } )
655+ return lintResult . issues
656+ } ,
657+ } ,
658+ } )
659+ }
660+
555661 /**
556662 * Mint a short-lived bearer token via POST /token.
557663 *
0 commit comments