@@ -50,8 +50,9 @@ import {
5050 sendAiRequestMessageSent ,
5151 sendAiRequestStarted ,
5252} from '../Utils/Analytics/EventSender' ;
53- import { useCreateAiProjectDialog } from './UseCreateAiProjectDialog' ;
5453import { type ExampleShortHeader } from '../Utils/GDevelopServices/Example' ;
54+ import { listAllExamples } from '../Utils/GDevelopServices/Example' ;
55+ import UrlStorageProvider from '../ProjectsStorage/UrlStorageProvider' ;
5556import { prepareAiUserContent } from './PrepareAiUserContent' ;
5657import { AiRequestContext } from './AiRequestContext' ;
5758import { getAiConfigurationPresetsWithAvailability } from './AiConfiguration' ;
@@ -199,7 +200,7 @@ const useProcessFunctionCalls = ({
199200 editorFunctionCallResults : getEditorFunctionCallResults (
200201 selectedAiRequest . id
201202 ) ,
202- } )
203+ } ) . filter ( functionCall => functionCall . name !== 'initialize_project' )
203204 : [ ] ,
204205 [ selectedAiRequest , getEditorFunctionCallResults ]
205206 ) ;
@@ -334,7 +335,6 @@ type Props = {|
334335 storageProvider : ?StorageProvider ,
335336 setToolbar : ( ?React . Node ) => void ,
336337 i18n : I18nType ,
337- onCreateEmptyProject : ( newProjectSetup : NewProjectSetup ) => Promise < void > ,
338338 onCreateProjectFromExample : (
339339 exampleShortHeader : ExampleShortHeader ,
340340 newProjectSetup : NewProjectSetup ,
@@ -410,7 +410,6 @@ export const AskAiEditor = React.memo<Props>(
410410 fileMetadata ,
411411 storageProvider ,
412412 i18n ,
413- onCreateEmptyProject ,
414413 onCreateProjectFromExample ,
415414 onOpenLayout ,
416415 onSceneEventsModifiedOutsideEditor ,
@@ -502,10 +501,7 @@ export const AskAiEditor = React.memo<Props>(
502501 setLastSendError ,
503502 } = aiRequestStorage ;
504503
505- const {
506- createAiProject ,
507- renderCreateAiProjectDialog ,
508- } = useCreateAiProjectDialog ( ) ;
504+
509505
510506 const updateToolbar = React . useCallback (
511507 ( ) => {
@@ -597,28 +593,7 @@ export const AskAiEditor = React.memo<Props>(
597593 } = newAiRequestOptions ;
598594 startNewAiRequest ( null ) ;
599595
600- // If no project is opened, create a new empty one if the request is for
601- // the AI agent.
602- if ( mode === 'agent' && ! project ) {
603- try {
604- console . info (
605- 'No project opened, opening the dialog to create a new project.'
606- ) ;
607- const result = await createAiProject ( ) ;
608- if ( result === 'canceled' ) {
609- return ;
610- }
611- console . info ( 'New project created - starting AI request.' ) ;
612- startNewAiRequest ( {
613- mode,
614- userRequest,
615- aiConfigurationPresetId,
616- } ) ;
617- } catch ( error ) {
618- console . error ( 'Error creating a new empty project:' , error ) ;
619- }
620- return ;
621- }
596+ // Do not create a project automatically anymore.
622597
623598 // Ensure the user has enough credits to pay for the request, or ask them
624599 // to buy some more.
@@ -920,6 +895,107 @@ export const AskAiEditor = React.memo<Props>(
920895 [ onSendMessage ]
921896 ) ;
922897
898+ const processInitializeProjectFunctionCalls = React . useCallback (
899+ async (
900+ functionCalls : Array < AiRequestMessageAssistantFunctionCall >
901+ ) => {
902+ if ( ! selectedAiRequest ) return ;
903+
904+ // Mark all provided calls as working.
905+ addEditorFunctionCallResults (
906+ selectedAiRequest . id ,
907+ functionCalls . map ( functionCall => ( {
908+ status : 'working' ,
909+ call_id : functionCall . call_id ,
910+ } ) )
911+ ) ;
912+
913+ const results : Array < EditorFunctionCallResult > = [];
914+
915+ for (const functionCall of functionCalls) {
916+ let args : any = null ;
917+ try {
918+ args = JSON . parse ( functionCall . arguments ) ;
919+ } catch ( error ) {
920+ results . push ( {
921+ status : 'finished' ,
922+ call_id : functionCall . call_id ,
923+ success : false ,
924+ output : { message : 'Invalid arguments (not a valid JSON string).' } ,
925+ } ) ;
926+ continue ;
927+ }
928+
929+ const name : ?string = args && args . name ;
930+ const slug : ?string = args && args . slug ;
931+ if ( ! name || ! slug ) {
932+ results . push ( {
933+ status : 'finished' ,
934+ call_id : functionCall . call_id ,
935+ success : false ,
936+ output : { message : 'Missing required arguments: name and slug.' } ,
937+ } ) ;
938+ continue ;
939+ }
940+
941+ try {
942+ const fetchedAllExamples = await listAllExamples ( ) ;
943+ const exampleShortHeader : ?ExampleShortHeader = fetchedAllExamples . exampleShortHeaders . find (
944+ exampleShortHeader => exampleShortHeader . slug === slug
945+ ) ;
946+
947+ if ( ! exampleShortHeader ) {
948+ results . push ( {
949+ status : 'finished' ,
950+ call_id : functionCall . call_id ,
951+ success : false ,
952+ output : { message : `Unable to find the example with slug "${ slug } ".` } ,
953+ } ) ;
954+ continue ;
955+ }
956+
957+ const newProjectSetup : NewProjectSetup = {
958+ storageProvider : UrlStorageProvider ,
959+ saveAsLocation : null ,
960+ projectName : name ,
961+ dontOpenAnySceneOrProjectManager : true ,
962+ } ;
963+ await onCreateProjectFromExample (
964+ exampleShortHeader ,
965+ newProjectSetup ,
966+ i18n ,
967+ false
968+ ) ;
969+
970+ results . push ( {
971+ status : 'finished' ,
972+ call_id : functionCall . call_id ,
973+ success : true ,
974+ output : { message : `Initialized project "${ name } " from example "${ slug } ".` } ,
975+ } ) ;
976+ } catch ( error ) {
977+ console . error ( 'Error initializing project from example:' , error ) ;
978+ results . push ( {
979+ status : 'finished' ,
980+ call_id : functionCall . call_id ,
981+ success : false ,
982+ output : { message : error && error . message ? error . message : 'Unknown error while initializing project.' } ,
983+ } ) ;
984+ }
985+ }
986+
987+ addEditorFunctionCallResults ( selectedAiRequest . id , results ) ;
988+ await onSendEditorFunctionCallResults ( null ) ;
989+ } ,
990+ [
991+ selectedAiRequest ,
992+ addEditorFunctionCallResults ,
993+ onCreateProjectFromExample ,
994+ i18n ,
995+ onSendEditorFunctionCallResults ,
996+ ]
997+ ) ;
998+
923999 const onSendFeedback = React . useCallback (
9241000 async (
9251001 aiRequestId ,
@@ -965,6 +1041,55 @@ export const AskAiEditor = React.memo<Props>(
9651041 onExtensionInstalled,
9661042 } ) ;
9671043
1044+ const onProcessFunctionCallsWithInit = React . useCallback (
1045+ async (
1046+ functionCalls : Array < AiRequestMessageAssistantFunctionCall > ,
1047+ options : ?{ | ignore ?: boolean | }
1048+ ) => {
1049+ const initializeCalls = functionCalls . filter (
1050+ functionCall => functionCall . name === 'initialize_project'
1051+ ) ;
1052+ const otherCalls = functionCalls . filter (
1053+ functionCall => functionCall . name !== 'initialize_project'
1054+ ) ;
1055+
1056+ if ( initializeCalls . length > 0 ) {
1057+ await processInitializeProjectFunctionCalls ( initializeCalls ) ;
1058+ }
1059+ if ( otherCalls . length > 0 ) {
1060+ await onProcessFunctionCalls ( otherCalls , options ) ;
1061+ }
1062+ } ,
1063+ [ processInitializeProjectFunctionCalls , onProcessFunctionCalls ]
1064+ ) ;
1065+
1066+ // Auto-process initialize_project calls even without an opened project.
1067+ React . useEffect (
1068+ ( ) => {
1069+ ( async ( ) => {
1070+ if ( ! selectedAiRequest ) return ;
1071+ const functionCallsToProcess = getFunctionCallsToProcess ( {
1072+ aiRequest : selectedAiRequest ,
1073+ editorFunctionCallResults : getEditorFunctionCallResults (
1074+ selectedAiRequest . id
1075+ ) ,
1076+ } ) ;
1077+ const initializeCalls = functionCallsToProcess . filter (
1078+ functionCall => functionCall . name === 'initialize_project'
1079+ ) ;
1080+ if ( initializeCalls . length === 0 ) return ;
1081+
1082+ console . info ( 'Processing initialize_project AI function calls...' ) ;
1083+ await processInitializeProjectFunctionCalls ( initializeCalls ) ;
1084+ } ) ( ) ;
1085+ } ,
1086+ [
1087+ selectedAiRequest ,
1088+ getEditorFunctionCallResults ,
1089+ processInitializeProjectFunctionCalls ,
1090+ ]
1091+ ) ;
1092+
9681093 return (
9691094 < >
9701095 < Paper square background = "dark" style = { styles . paper } >
@@ -988,7 +1113,7 @@ export const AskAiEditor = React.memo<Props>(
9881113 ? 'upgrade'
9891114 : 'none'
9901115 }
991- onProcessFunctionCalls = { onProcessFunctionCalls }
1116+ onProcessFunctionCalls = { onProcessFunctionCallsWithInit }
9921117 editorFunctionCallResults = {
9931118 ( selectedAiRequest &&
9941119 getEditorFunctionCallResults ( selectedAiRequest . id ) ) ||
@@ -1017,10 +1142,6 @@ export const AskAiEditor = React.memo<Props>(
10171142 />
10181143 </ div >
10191144 </ Paper >
1020- { renderCreateAiProjectDialog ( {
1021- onCreateEmptyProject,
1022- onCreateProjectFromExample,
1023- } ) }
10241145 < AskAiHistory
10251146 open = { isHistoryOpen }
10261147 onClose = { onCloseHistory }
@@ -1055,7 +1176,6 @@ export const renderAskAiEditorContainer = (
10551176 storageProvider = { props . storageProvider }
10561177 setToolbar = { props . setToolbar }
10571178 isActive = { props . isActive }
1058- onCreateEmptyProject = { props . onCreateEmptyProject }
10591179 onCreateProjectFromExample = { props . onCreateProjectFromExample }
10601180 onOpenLayout = { props . onOpenLayout }
10611181 onSceneEventsModifiedOutsideEditor = {
0 commit comments