From be75f9ef4626f062f97093bf7eeec1f27c533064 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 8 May 2026 10:23:51 +0000 Subject: [PATCH] Use object's assetStoreTag to default search_terms --- newIDE/app/src/AiGeneration/Utils.js | 22 +++++++++++ .../EditorFunctionCallRunner.js | 3 ++ .../EditorFunctions/EditorFunctions.spec.js | 1 + newIDE/app/src/EditorFunctions/index.js | 39 ++++++++++++++++--- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/newIDE/app/src/AiGeneration/Utils.js b/newIDE/app/src/AiGeneration/Utils.js index 764727c7d9..8b7c117c79 100644 --- a/newIDE/app/src/AiGeneration/Utils.js +++ b/newIDE/app/src/AiGeneration/Utils.js @@ -36,6 +36,7 @@ import { useSearchAndInstallAsset } from './UseSearchAndInstallAsset'; import { useSearchAndInstallResource } from './UseSearchAndInstallResource'; import { type ResourceManagementProps } from '../ResourcesList/ResourceSource'; import { AiRequestContext } from './AiRequestContext'; +import { ObjectStoreContext } from '../AssetStore/ObjectStoreContext'; import { delay } from '../Utils/Delay'; import { retryIfFailed } from '../Utils/RetryIfFailed'; @@ -185,6 +186,25 @@ export const useProcessFunctionCalls = ({ resourceManagementProps, }); const { generateEvents } = useGenerateEvents({ project }); + + const { translatedObjectShortHeadersByType, fetchObjects } = React.useContext( + ObjectStoreContext + ); + + React.useEffect( + () => { + fetchObjects(); + }, + [fetchObjects] + ); + const getAssetStoreTagForNewObject = React.useCallback( + (objectType: string): string | null => { + const header = translatedObjectShortHeadersByType[objectType]; + return (header && header.assetStoreTag) || null; + }, + [translatedObjectShortHeadersByType] + ); + // In-memory guard against duplicate processing of the same function call. // // The main protection is marking calls as "working" in the ref-backed @@ -263,6 +283,7 @@ export const useProcessFunctionCalls = ({ onExtensionInstalled, searchAndInstallAsset, searchAndInstallResources, + getAssetStoreTagForNewObject, }); // If the request was suspended while we were processing, discard the @@ -306,6 +327,7 @@ export const useProcessFunctionCalls = ({ onExtensionInstalled, searchAndInstallAsset, searchAndInstallResources, + getAssetStoreTagForNewObject, generateEvents, onSendEditorFunctionCallResults, ] diff --git a/newIDE/app/src/EditorFunctions/EditorFunctionCallRunner.js b/newIDE/app/src/EditorFunctions/EditorFunctionCallRunner.js index 9906707034..edd4a6864a 100644 --- a/newIDE/app/src/EditorFunctions/EditorFunctionCallRunner.js +++ b/newIDE/app/src/EditorFunctions/EditorFunctionCallRunner.js @@ -59,6 +59,7 @@ type ProcessEditorFunctionCallsOptions = {| searchAndInstallResources: ( options: ResourceSearchAndInstallOptions ) => Promise, + getAssetStoreTagForNewObject: (objectType: string) => string | null, |}; export const processEditorFunctionCalls = async ({ @@ -79,6 +80,7 @@ export const processEditorFunctionCalls = async ({ onExtensionInstalled, searchAndInstallAsset, searchAndInstallResources, + getAssetStoreTagForNewObject, }: ProcessEditorFunctionCallsOptions): Promise<{| results: Array, createdSceneNames: Array, @@ -178,6 +180,7 @@ export const processEditorFunctionCalls = async ({ onExtensionInstalled, searchAndInstallAsset, searchAndInstallResources, + getAssetStoreTagForNewObject, PixiResourcesLoader, }; diff --git a/newIDE/app/src/EditorFunctions/EditorFunctions.spec.js b/newIDE/app/src/EditorFunctions/EditorFunctions.spec.js index 9a5fdd4bdb..0fd0a55b61 100644 --- a/newIDE/app/src/EditorFunctions/EditorFunctions.spec.js +++ b/newIDE/app/src/EditorFunctions/EditorFunctions.spec.js @@ -80,6 +80,7 @@ describe('editorFunctions', () => { onObjectsModifiedOutsideEditor: jest.fn(), onWillInstallExtension: jest.fn(), onExtensionInstalled: jest.fn(), + getAssetStoreTagForNewObject: () => null, PixiResourcesLoader: PixiResourcesLoaderMock, }); diff --git a/newIDE/app/src/EditorFunctions/index.js b/newIDE/app/src/EditorFunctions/index.js index b614450cb2..ca4aca7c34 100644 --- a/newIDE/app/src/EditorFunctions/index.js +++ b/newIDE/app/src/EditorFunctions/index.js @@ -269,6 +269,14 @@ type LaunchFunctionOptionsWithoutProject = {| searchAndInstallResources: ( options: ResourceSearchAndInstallOptions ) => Promise, + /** + * Returns the asset store tag for a given object type, when the type is + * mainly meant to be picked from the asset store (e.g. premade UI objects). + * Reads from the remote objects registry so it works even before the + * underlying extension is installed. Returns null if no tag is set or if + * the registry is not loaded yet. + */ + getAssetStoreTagForNewObject: (objectType: string) => string | null, |}; export type LaunchFunctionOptionsWithProject = {| @@ -754,6 +762,7 @@ const createOrReplaceObject: EditorFunction = { onWillInstallExtension, onExtensionInstalled, PixiResourcesLoader, + getAssetStoreTagForNewObject, }) => { const scene_name = extractRequiredString(args, 'scene_name'); const object_type = SafeExtractor.extractStringProperty( @@ -863,11 +872,24 @@ const createOrReplaceObject: EditorFunction = { const targetScopeText = target_object_scope === 'global' ? 'global' : `scene "${scene_name}"`; - if (candidateType && !search_terms && !asset_id) { - // Do nothing: there is nothing given apart from an object type, - // which we can still use to fallback to create from scratch. + // If no search_terms or asset_id were provided but the object type has + // an `assetStoreTag` (i.e. the type is mainly meant to be picked from + // the asset store, e.g. premade UI objects), use the tag as default + // search terms. + let effectiveSearchTerms = search_terms; + let assetStoreTag: string | null = null; + if (candidateType && !effectiveSearchTerms && !asset_id) { + assetStoreTag = getAssetStoreTagForNewObject(candidateType); + if (assetStoreTag) { + effectiveSearchTerms = `${assetStoreTag}, default`; + } + } + + if (candidateType && !effectiveSearchTerms && !asset_id) { + // Nothing given apart from an object type without an assetStoreTag: + // fall back to creating from scratch. } else { - if (!search_terms && !asset_id) { + if (!effectiveSearchTerms && !asset_id) { return makeGenericFailure( `No search_terms or asset_id provided for "${targetObjectName}". Not created.` ); @@ -885,7 +907,7 @@ const createOrReplaceObject: EditorFunction = { objectsContainer: targetObjectsContainer, objectName: targetObjectName, objectType: candidateType, - searchTerms: search_terms || '', + searchTerms: effectiveSearchTerms || '', description: description || '', twoDimensionalViewKind: two_dimensional_view_kind || '', exactOrPartialAssetId: asset_id || null, @@ -947,6 +969,13 @@ const createOrReplaceObject: EditorFunction = { ); } + if (assetStoreTag) { + console.warn( + `No asset found from store for object type "${candidateType || + ''}" (assetStoreTag: "${assetStoreTag}"). Falling back to creating "${targetObjectName}" from scratch.` + ); + } + // No asset found - we'll create an object from scratch. } } catch (error) {