Guide to task agents¶
Agents are responsible for monitoring the state of a project’s resources in order to respond to upstream workflow changes and to determine when users may mark the agent’s parent task completed.
The following sections describe the different agents that a task may own.
Agent¶
The base agent class is abstract and may not
be instantiated, but every concrete subclass of agent must have the
type JSON configuration parameter and may have a name:
type: the type-name of a concrete agent subclass to instantiate (chosen from those listed below.name: an arbitrary name that can be used to distinguish agents within the same parent task from one another. Multiple instances of the same type of agent are allowed within the same task. (Presumably they would be configured differently.)
FillOutAttributesAgent¶
The FillOutAttributesAgent monitors attribute resources provided to it either by its static configuration or an input port (if the agent is configured with one). When an operation creates or modifies attributes matching the agent’s configuration, the task checks whether the attributes are valid. If so, the agent is Completable. If not, it is Incomplete. If no attribute resources with matching attributes are configured, then the agent is Irrelevant.
This agent accepts all the JSON configuration that the base agent class does, plus:
attribute-sets: a JSON array of required attributes, organized by role. Each array entry must be a JSON object holding:role: an optional string holding an attribute-resource role name. If omitted, any role is allowed.definitions: a set of smtk::attribute::Definition type-names specifying which types of attributes to validate before allowing completion.output-data: an enumerant from smtk::task::FillOutAttributesAgent::PortDataObjects specifying whether to broadcast resources, attributes, or both on the agent’s output port (if any is configured). This defaults to broadcast only resources if omitted.auto-configure: either true or false (the default), depending on whether resources with matching roles should automatically be added. The default is true. If false, your static configuration must provide the UUID of an attribute or attribute resource.
Example¶
{
"type": "smtk::task::FillOutAttributesAgent",
"attribute-sets": [
{
"role": "simulation attribute",
"definitions": ["SolidMaterial", "FluidMaterial"],
"output-data": "smtk::task::FillOutAttributesAgent::Attributes"
},
{
"role": "meshing attribute",
"definitions": [
"GlobalSizingParameters",
"FaceSize",
"EdgeSize"
]
}
]
}
In the example above, you can see that two different attribute resources (one for the simulation and one for a mesh generator) are specified with different roles and the definitions that should be checked for resources in those roles are different.
Note the output-data specifies that any valid SolidMaterial or
FluidMaterial attributes should be included in the task’s output
port-data (in the “simulation attribute” role) if an output port is
configured.
SubmitOperationAgent¶
The SubmitOperationAgent monitors the operation manager to ensure an operation (specified by type-name) has run successfully since its parameters were last modified. The agent may require an operation be run only once or iteratively until the user finds the results acceptable.
The operation being managed by the agent is created by the agent and its parameters are maintained as part of the agent’s state. Its parameters may also be overridden from data on input ports provided to the agent.
Objects from the most recent successful execution of the agent’s operation are made available on the output port.
Next we’ll discuss the JSON configuration parameters. Because the number of parameters is large, we’ll break this into three groups of parameters: the minimal set required to function, typical additional parameters workflow developers will specify, and finally the remaining parameters, which are mostly programmatic ones used to preserve the state of the task across modeling sessions.
Minimal Parameters¶
In addition to the type parameter inherited from the base Agent class,
you must specify these parameters for the SubmitOperationAgent to be functional:
operation: The typename of the operation the agent should create and maintain. If no operation is specified, this agent’s state will always be irrelevant.run-style: Determine how running the agent’s operation affects the task state. This must be one of the following values:smtk::task::SubmitOperationAgent::RunStyle::Iterativelyoriteratively-by-user: indicates the operation may be run as many times as users see fit, but it must be run at least once and the task will not be completable as long as the parameters have been edited more recently than the operation last ran.smtk::task::SubmitOperationAgent::RunStyle::Onceoronce-only: indicates the operation must only be run once. Once the operation completes successfully (by clickingApplyin the operation parameter-editor panel), the task is marked as completed. If the user un-checks the “completed” button on the task, the operation must be run again.smtk::task::SubmitOperationAgent::RunStyle::OnCompletionorupon-completion: indicates the operation should be run only once – immediately after the user marks the task as completed. If the operation fails, the task will return to an Incomplete state. TheApplybutton in the operation parameter-editor panel will be hidden and so that users must mark the task completed in order to run the operation. Furthermore, the task will be incomplete until the operation’s parameters are in a valid state.
Minimal Example¶
{
"type": "smtk::task::SubmitOperationAgent",
"run-style": "smtk::task::SubmitOperationAgent::RunStyle::Once",
"operation": "math_op.MathOp"
}
Typical Parameters¶
In addition to the parameters above, these parameters exist to describe how port-data should affect the parameters of the operation managed by SubmitOperationAgent.
parameters: a map of maps holding an array of ParameterSpec objects. The keys of the outer map are port names from the parent task. The keys of the inner map are role names on that port from which operation-parameter information should be extracted. TheParameterSpecvalues include the following parameters that describe how to convert port data into values for the parameterhandler: One of the following values:smtk::task::SubmitOperationAgent::PortDataHandler::AddObjects(oradd): Append the objects to the item (or associations) at the given item path.smtk::task::SubmitOperationAgent::PortDataHandler::SetObjects(orset): Reset the reference-item (or associations) at the given item path to the objects on the named port in the named role.smtk::task::SubmitOperationAgent::PortDataHandler::AssignFromAttribute(orassign-from-attribute): Assign an attribute’s item to an operation-parameter’s item.smtk::task::SubmitOperationAgent::PortDataHandler::AssignFromAttributeResource(orassign-from-attribute-resource): Find an attribute in an attribute resource and assign one of its its items to an item of the operation-parameter attribute.smtk::task::SubmitOperationAgent::PortDataHandler::AssignMatchingAttributes(orassign-from-matching-attributes): Any matching attribute resource with a matching attribute or any matching attribute should have the given item assigned to an item of the operation-parameter attribute. This mimics the behavior of bothAssignFromAttributeandAssignFromAttributeResource.
resource-type: For a port-data object to be used as a parameter value, the object (if it is a resource) or its parent resource (if it is a component) must match the type-name provided here.resource-template: If provided, the port-data object’s resource must have a matching template-type (see Resource::templateType()) in order to provide values to the operation.component-selector: A filter-query string (passed to Resource::queryOperation()) that specifies objects to extract from a resource on the port-data. This is used to select attributes from an attribute resource whose values should be provided to an operation parameter.source-path: The path to an attribute-item whose value should be assigned to an operation parameter. This is ignored whenhandlerisAddObjectsorSetObjects.target-path: The path to an attribute-item in the operation’s parameters. This is the item to which values should be assigned. IfhandlerisAddObjectsorSetObjects, the item at this path must be a reference-item (or the name of the associations for the operation).configured-by: One of the followingsmtk::task::SubmitOperationAgent::ConfiguredBy::Static(orstatic): The operation parameter should be fixed to the value inop-params.smtk::task::SubmitOperationAgent::ConfiguredBy::Port(orport): The operation parameter should be pinned to the port data specified via the parameters above.smtk::task::SubmitOperationAgent::ConfiguredBy::User(oruser): The user may override values provided by the input port. Once the user overrides the port-data, theParameterSpecis marked to prevent port-data from being assigned. WARNING: This is not implemented yet.
user-override:truewhen the user-provided value overrides the port data andfalseotherwise.visibility: Choose whether the operation parameter attarget-pathis visible to the user in the operation parameter-editor panel. One of the following values must be chosen if this is specified. WARNING: This is not implemented yet.smtk::task::SubmitOperationAgent::ItemVisibility::On: The item (and its children, if any) should be visible in the parameter editor.smtk::task::SubmitOperationAgent::ItemVisibility::Off: The item (but not any children marked as visible, if any) should be hidden in the parameter editor.smtk::task::SubmitOperationAgent::ItemVisibility::RecursiveOff: The item (and all children) should be hidden in the parameter editor.
output-port: is the name of an output port on which this agent should provide a set of resources mentioned in the operation’s result object. Resources are only available to the output port when the operation succeeds; if the operation fails, the list of resources will be cleared. In either case, the port will be notified its data has changed. The port name is optional, but if provided you must also provideoutput-role.output-role: is the role in which operation results should be added to output port-data.
Typical Example¶
{
"type": "smtk::task::SubmitOperationAgent",
"run-style": "smtk::task::SubmitOperationAgent::RunStyle::Once",
"operation": "math_op.MathOp",
"parameters": [
[
"parameters",
[
[
"attributes",
[
{
"component-selector": "attribute[type='Stage1Data']",
"configured-by": "smtk::task::SubmitOperationAgent::ConfiguredBy::User",
"handler": "smtk::task::SubmitOperationAgent::PortDataHandler::AssignMatchingAttributes",
"resource-type": "smtk::attribute::Resource",
"source-path": "/DoubleValue",
"target-path": "/DoubleValue"
},
{
"component-selector": "attribute[type='Stage1Data']",
"configured-by": "smtk::task::SubmitOperationAgent::ConfiguredBy::Port",
"handler": "smtk::task::SubmitOperationAgent::PortDataHandler::AssignMatchingAttributes",
"resource-type": "smtk::attribute::Resource",
"source-path": "/IntValue",
"target-path": "/IntValue",
"visibility": "smtk::task::SubmitOperationAgent::ItemVisibility::On"
}
]
]
]
]
],
"output-port": "results",
"output-role": "stage 1 math op"
}
Remaining Parameters¶
These parameters are mostly values written when users save a project’s state but are not necessarily of interest to workflow developers. However, there is nothing precluding workflow developers from using these:
run-since-edited:truewhen the operation has been run since the parameters have been modified andfalseotherwise. This defaults to false.internal-state: records the state at the time the project was saved. This allows projects to “remember” whether the operation has been successfully run.op-params: A serialized attribute holding the operation’s parameters. If none is provided, the default parameters are used.op-links: A serialized set of resource links used to hold association and reference-item values for the operation’s parameters. If none is provided, associations and reference-items will be unset.watching: is a map holding the UUIDs of persistent objects that, when modified, should be used to update the operation’s parameters. This is used to keep the task’s operation-parameters up-to-date when objects provided via upstream port-data are modified by other operations.output-resources: is an array of UUIDs of resources provided from any prior, successful run of the operation. This allows the output port-data (if one has been configured) to be preserved across sessions so that even when the parent task is completed in a previous session, the port-data is available in the current and future sessions.
Complete Example¶
{
"type": "smtk::task::SubmitOperationAgent",
"run-style": "smtk::task::SubmitOperationAgent::RunStyle::Once",
"run-since-edited": true,
"operation": "math_op.MathOp",
"internal-state": "completable",
"op-links": null,
"op-params": {
"ID": "96873123-1758-439d-990d-09636ff55b79",
"Items": [
{
"Enabled": false,
"ForceRequired": false,
"Name": "debug level",
"SpecifiedVal": "0",
"Val": 0
},
{
"Name": "IntValue",
"SpecifiedVal": "8",
"Val": 8
},
{
"Name": "DoubleValue",
"SpecifiedVal": "49",
"Val": 49.0
}
],
"Name": "math_op.MathOp8",
"Type": "MathOp"
},
"parameters": [
[
"parameters",
[
[
"attributes",
[
{
"component-selector": "attribute[type='Stage1Data']",
"configured-by": "smtk::task::SubmitOperationAgent::ConfiguredBy::User",
"handler": "smtk::task::SubmitOperationAgent::PortDataHandler::AssignMatchingAttributes",
"resource-type": "smtk::attribute::Resource",
"source-path": "/DoubleValue",
"target-path": "/DoubleValue"
},
{
"component-selector": "attribute[type='Stage1Data']",
"configured-by": "smtk::task::SubmitOperationAgent::ConfiguredBy::Port",
"handler": "smtk::task::SubmitOperationAgent::PortDataHandler::AssignMatchingAttributes",
"resource-type": "smtk::attribute::Resource",
"source-path": "/IntValue",
"target-path": "/IntValue",
"visibility": "smtk::task::SubmitOperationAgent::ItemVisibility::On"
}
]
]
]
]
],
"watching": [
[
"5cd08eef-ee59-477d-8eec-c7cacd768deb",
[
{
"idx": 0,
"port": "parameters",
"role": "attributes"
},
{
"idx": 1,
"port": "parameters",
"role": "attributes"
}
]
]
]
}
The JSON above is based on the example project in data/projects/SimpleWorkletExample/agentWorklet.smtk
so that you can load the project and explore how the mentioned UUIDs relate to the attribute resource
included in the project.
GatherObjectsAgent¶
The GatherObjectsAgent simply collects persistent objects with roles and makes them available on the specified output port of the parent task.
To add objects to the agent programmatically, you should call GatherObjectsAgent::addObjectInRole(), GatherObjectsAgent::removeObjectFromRole(), or GatherObjectsAgent::setObjectsInRoles(). Note that you should not provide the broadcast port unless this method is being called from an observer. If you call these methods from within an operation, simply add the modified port to the operation’s results.
The following JSON configuration parameters are available for this agent:
output-port: is the name of the parent-task’s port on which this agent should broadcast its data.objects: is a map from a role name to a set of persistent-object specifiers. If an object is a resource, each specifier is a tuple holding a UUID andnull. If an object is a component, each specified is a tuple holding the UUID of the component’s parent resource and the component’s UUID.
Example¶
{
"type": "smtk::task::GatherObjectsAgent",
"output-port": "gathered resources",
"objects": [
[ "thermal simulation parameters",
[
[ "96873123-1758-439d-990d-09636ff55b79", null ]
],
],
[ "thermal materials",
[
[ "96873123-1758-439d-990d-09636ff55b79", "e87115f1-585b-4572-b81b-289b4db5e5cd" ],
[ "96873123-1758-439d-990d-09636ff55b79", "61418aa2-f130-4472-8ca0-e9e7b3c622d3" ]
]
]
]
}
The JSON above provides a resource in the “thermal simulation parameters” role and two components from within that resource in the “thermal materials” role.
TrivialProducerAgent¶
The TrivialProducerAgent is nearly
identical to the GatherObjectsAgent
but holds the data to be broadcast to its output port in an
ObjectsInRoles instance owned by the agent.
Use TrivialProducerAgent when you do not wish the overhead of looking up large
numbers of persistent objects by UUID each time portData() is called.
However, be aware that because TrivialProducerAgent holds raw pointers and does
not monitor operations, you must be sure to remove objects before the pointers
become invalid.
To add objects to the agent programmatically, you should
call TrivialProducerAgent::addObjectInRole(),
TrivialProducerAgent::removeObjectFromRole(),
or TrivialProducerAgent::resetData().
Note that these methods do not call portDataUpdated() on the agent’s output port.
If you call these methods from within an operation, simply add the modified port to the operation’s
results to indicate port data has been updated.
The following JSON configuration parameters are available for this agent:
output-port: is the name of the parent-task’s port on which this agent should broadcast its data.objects: is a map from a role name to an array of persistent-object specifiers. If an object is a resource, each specifier is a tuple holding a UUID andnull. If an object is a component, each specified is a tuple holding the UUID of the component’s parent resource and the component’s UUID.required-counts: is a map from a role name to an array of 2 integers specifying the minimum and maximum number of objects permitted in the given role. A-1for the second array value indicates there is no maximum. If both numbers are-1, then no objects are allowed in the given role.
Example¶
The GatherObjectsAgent example above may be used identically for TrivialProducerAgent by changing the “type” parameter to TrivialProducerAgent.
PortForwardingAgent¶
The PortForwardingAgent copies port data from a set of input ports to a set of output ports and – if the port data is formatted as ObjectsInRoles – is able to filter what is copied based on role and object type-name.
This agent accepts all the JSON configuration that the base agent class does, plus:
forwards: an _optional_ JSON array of objects specifying information to copy. If no array is provided, the agent will do nothing but will not impede progress. Each object in theforwardsarray holds a dictionary with:input-port: the name of an input port (internal or external) associated to the task from which port data is drawn. This key is _mandatory_.output-port: the name of an output port (internal or external) associated to the task to which port data is copied. This key is _mandatory_.output-role: if provided, all matching input objects are broadcast on this role. This item is _optional_ and is only used if the port data is of type ObjectsInRoles.filters: an _optional_ dictionary mapping role names to an array of filters that specify the types of persistent objects which should be forwarded. If no filters are provided, all data from the input port is copied to the output port. An asterisk (*) serves as a wildcard to accept objects in any role so long as they are of the specified type(s). Whenrolesis not provided, it is identical to passing"*": [ ["*", null], ["*", "*"] ]as the role filter. Thefilterslist is only used if the port data is of type ObjectsInRoles. Rather than passing an array with two filter strings for each role, you may pass dictionaries with “resource” and “component” entries that hold filter strings for resource types and component types. If no “component” entry exists, then only resources match (not components).
Example¶
{
"type": "smtk::task::PortForwardingAgent",
"forward": [
{ "input-port": "setup", "output-port": "result", "output-role": "simulation" },
{ "input-port": "model", "output-port": "parts-of-interest",
"roles": {
"resource": [
{ "resource": "smtk::markup::Resource" }
],
"images": [
["smtk::markup::Resource", "smtk::markup::ImageData"]
],
"meshes": [
{
"resource": "smtk::markup::Resource",
"component": "smtk::markup::UnstructuredData"
}
]
}
}
]
}
The JSON above forwards objects from the “setup” input port to the “result” output port, regardless of the object type or role. Assuming the “setup” input data is formatted as ObjectsInRoles, the “result” port data will be under the role “simulation” (regardless of its input role).
It also forwards objects
from the “model” port to the “parts-of-interest” port.
If the “model” input port is ObjectsInRoles
then objects are only forwarded if
(1) they have a role of “meshes” and inherit UnstructuredData or
(2) they have a role of “images” and inherit ImageData, or
(3) they have a role of “resource” and are a markup resource.
Otherwise, all data on the input port is forwarded without modification.