Use object's assetStoreTag to default search_terms

This commit is contained in:
Claude
2026-05-08 10:23:51 +00:00
committed by Florian Rival
parent 383249b697
commit be75f9ef46
4 changed files with 60 additions and 5 deletions
+22
View File
@@ -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,
]
@@ -59,6 +59,7 @@ type ProcessEditorFunctionCallsOptions = {|
searchAndInstallResources: (
options: ResourceSearchAndInstallOptions
) => Promise<ResourceSearchAndInstallResult>,
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<EditorFunctionCallResult>,
createdSceneNames: Array<string>,
@@ -178,6 +180,7 @@ export const processEditorFunctionCalls = async ({
onExtensionInstalled,
searchAndInstallAsset,
searchAndInstallResources,
getAssetStoreTagForNewObject,
PixiResourcesLoader,
};
@@ -80,6 +80,7 @@ describe('editorFunctions', () => {
onObjectsModifiedOutsideEditor: jest.fn(),
onWillInstallExtension: jest.fn(),
onExtensionInstalled: jest.fn(),
getAssetStoreTagForNewObject: () => null,
PixiResourcesLoader: PixiResourcesLoaderMock,
});
+34 -5
View File
@@ -269,6 +269,14 @@ type LaunchFunctionOptionsWithoutProject = {|
searchAndInstallResources: (
options: ResourceSearchAndInstallOptions
) => Promise<ResourceSearchAndInstallResult>,
/**
* 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) {