[Employee Works] Scoped control of the user object in Moveworks Studio
Summary
Add an optional input to the built-in user lookup actions (mw.get_user_by_email and mw.batch_get_users_by_email) so the caller can state up front which user attributes they want. The action should retrieve and return only those attributes. Today both actions return the full user object, including custom attributes, and the only option is to filter the result after the full payload is already in memory. That is too late to prevent the memory and size problems.
Problem
The full user object is large, and the combined payload from batch lookups is approaching the 4 MB limit. If a plugin’s return payload exceeds 4 MB of memory, the plugin can stop working. There have been a few instances where the 4 MB limit was hit and caused a failure.
- The largest known common payload is 3.6 MB.
- Compound actions have reached 3.8 MB.
- Every new ingestion point added to the user object pushes these numbers higher.
If the payload keeps growing, other plugins that depend on user objects could fail entirely.
A second problem is that ingested user attributes can bleed into plugin results. When the full user object is in context, a plugin may use a profile value it was never meant to use. For example, it may assume a location from the user’s profile when the plugin requires the user to state the location explicitly.
Current mitigations and why they fall short
- Filtering in a compound action: We call the built-in, then filter the result inside a compound action so the conversation process receives a minimal payload. The full object is still loaded first, so the compound action can itself reach about 3.8 MB and crash.
- Output mapping: Conversation processes support it (compound actions do not), but it also trims only after the full payload has been returned.
Both approaches filter after the call. Neither prevents the full-size payload from being created.
Proposed solution: specify attributes in the call, not after it
1. mw.get_user_by_email
Add an optional fields input. When provided, only those attributes are retrieved and returned. When omitted, behavior is unchanged.
| Parameter | Type | Required | Description |
|---|---|---|---|
user_email | string | Yes | The email address of the user to retrieve |
fields | List[string] | No | New. User attributes to return. If omitted, all attributes are returned. |
yaml
- action:
output_key: user_result
action_name: mw.get_user_by_email
input_args:
user_email: meta_info.user.email_addr
fields:
- full_name
- email_addr
- departmentProposed response:
json
{
"user": {
"full_name": "John Doe",
"email_addr": "john.doe@moveworks.ai",
"department": "Engineering"
}
}2. mw.batch_get_users_by_email
Add the same optional fields input, applied to every user in the batch.
| Parameter | Type | Required | Description |
|---|---|---|---|
user_emails | List[string] | Yes | The email addresses of the users to retrieve |
fields | List[string] | No | New. User attributes to return for every user in the batch. If omitted, all attributes are returned. |
yaml
- action:
output_key: target_users
action_name: mw.batch_get_users_by_email
input_args:
user_emails:
- data.manager_email
- data.employee_email
fields:
- full_name
- email_addr
- record_idProposed response:
json
{
"user_records": [
{
"lookup_id": "12345",
"user": {
"full_name": "John Doe",
"email_addr": "john.doe@moveworks.ai",
"record_id": "10769610738892443"
}
},
{
"lookup_id": "67890",
"user": {
"full_name": "Jane Smith",
"email_addr": "jane.smith@moveworks.ai",
"record_id": "10769610738892444"
}
}
]
}Behavior requirements
- Selection happens at the source. The full user object must never be built or loaded into working memory when
fieldsis set. - Custom attributes are selectable. Both standard and custom attributes are supported, using the names in the User Attribute Reference.
- Ordering is preserved. For the batch action, results return in the same order as the input email list, and
lookup_idis always included. - Validation. Invalid field names return a clear error (or have a documented ignore behavior) so typos are caught early.
- Backward compatible. Omitting
fieldsreturns the full object exactly as today.
Related request: user object schema in Studio
As a complementary feature, allow builders to define a user object schema (an allowlist of permitted user attributes) and apply it to actions, plugins, and conversation processes in Moveworks Studio. Anything outside the schema is not available to that scope.
yaml
user_object_schema:
allowed_fields:
- full_name
- email_addr
- department- Built-in lookups and any other path that exposes the user object return only the allowed attributes for that scope.
- The model cannot draw on unlisted attributes (for example, location) when generating a response or filling inputs, so a plugin that needs one must ask the user.
- The schema sets the maximum set of fields for a scope, and
fieldson an individual call can narrow it but never widen it. - Schemas could be named and reusable (for example, “basic identity”) so teams can share them across plugins.
Expected benefits
- Stays under the 4 MB limit. The full payload is never created, so the 3.6 to 3.8 MB peaks drop significantly, and new ingestion points no longer push us toward the limit.
- Removes crash and failure risk. Plugins and compound actions are no longer exposed to an oversized return payload, preventing a repeat of the failures we have already seen.
- Stops compounding memory growth. Working memory holds only the needed fields, so there is much less contextual memory to expand each time the payload is touched.
- Faster response times. Smaller working memory means faster processing.
- More predictable results. Plugins cannot silently pick up unrelated profile values, so behavior depends only on what the plugin was designed to use.
- Simpler solutions. The compound action workaround is no longer needed just to shrink the payload, and we can use conversation processes with output mapping directly.
- Scales with future ingestion. New data sources can be added to the user object without increasing what each plugin retrieves.