Loading
Issue #3583059: Pass config entities across handle boundaries as machine names
What changed
An invoker that asks for handles now sends and receives machine names for config entities:
// Input schema for entity:user_role, before and after.
{"$comment": "No schema is defined for property of type ConfigEntityAdapter..."}
{"type": "string", "description": "Role: A user role. (pass the machine name of the user_role)"}
// Published outputs, before and after.
{"role": {}, "roles": [{}]}
{"role": "editor", "roles": ["editor", "reviewer"]}Why
#3583028 (closed) let entity: inputs take config entities, but the handle subscriber only knew content entities. Over MCP or the AI connector, a config entity input had no schema, a machine name failed validation, and config entity outputs came back as {}. Closes #3583059.
How
EntityHandleTransformer::isConfigEntityDefinition()matchesentity:TYPEwhen TYPE is a config entity type. The bareentitytype is left alone, since loading by ID needs the type.transformInputDefinition()andtransformOutputDefinition()swap those definitions for strings and name the entity type in the description.resolveConfigInput()loads the machine name through the entity type's storage and throwsMachineNameNotFoundExceptionwhen it does not exist. It implementsHandleExceptionInterface, so the runner still reports an input failure on the input's path, but it is not aHandleNotFoundException: the runner adds handle ownership and expiry advice to that one (#3582977), which is wrong for a machine name.transformConfigOutput()publishes the ID with a hint naming the entity type, without the label, so noview labelaccess check is needed.EntityHandleTransformSubscriberdoes the same for each config entity in a list output: "Outputrolescontains 2 user_role machine name(s)."- A list of config entities needs nothing extra. A
multiple: TRUEinput is converted to aListInputDefinitionwhen it is declared (#3583049 (closed)), so the subscriber only ever sees the single item definition. Coercion decodes or wraps the list first, and each item resolves as a machine name. docs/developers/entity-handles.mdhas a "Config entities" section.
Invokers without EntitiesAsHandles see no change.
Testing
EntityHandleTransformSubscriberTest::testConfigEntitiesCrossAsMachineNamesrunsconfig_entity_toolwith a machine name and a list of machine names in, and a single role and a list of roles out.- The list-shape tests mirror the content ones:
testBareMachineNameForListInputIsWrappedThenResolved,testJsonEncodedMachineNameListIsDecodedThenResolved, andtestEmptyStringForOptionalListInputIsNoValue. testUnknownMachineNameIsRejectedcovers theMachineNameNotFoundException, andToolRunnerTest::testUnknownMachineNameNamesTheInputWithoutHandleAdvicechecks the violation the model sees has no handle advice. It fails when the exception is swapped back.EntityHandleTransformerTestcovers the transformer methods and the schema swap.AdvertisedOutputSchemaConformanceTestnow runsconfig_entity_toolwith a saved role instead of skipping it, so the formattedroleandrolesvalues are validated against their string schemas. BreakingtransformConfigOutput()locally fails it.AdvertisedSchemaAcceptanceTestgets role overrides for the new tool.
Edited by Matt Glaman