> This page is for Tools.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.moveworks.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.moveworks.com/_mcp/server.

# Resolver Strategies

# What are resolver strategies?

Resolver strategies instruct AI agents how to convert the user’s provided value (e.g. “this week's most important bug”) to a [Data Type](/tool-studio/core-concepts/data-types) the system wants (e.g. `<JiraIssue>_BUG-732`).

Resolver strategies are how you configure **slot resolvers**, the Plugin part that turns what a user says into a real record.

# How slot resolvers work

LLMs hallucinate. When a user says "Jamie" and there are 12 Jamies in your directory, the LLM picks the most probable one, which may not be the right one. One wrong ID passed to ServiceNow means the wrong person loses access. Slot resolvers exist to make this impossible.

The way users reference your business objects seldom matches how business systems store them. For example:

* "Tomorrow's Standup" is a `GoogleCalendarEvent` with ID = `4s567d8s908f87654sa678ds`
* "Jamie" is a `User` with ID = `9e107d9d-372b-4ac9-b4e9-0fbccd3029ab`

![](https://files.readme.io/24b4e8795e72b5c671a9f536ecd7e4ec1cbe92559915381fdcefd98135e71658-CleanShot_2024-10-24_at_18.18.212x.png)

A slot resolver works in three stages:

1. **Candidate retrieval.** The AI agent retrieves possible values that satisfy the constraints of your slot, using the methods in the slot's resolver strategy (see [Methods](#methods) below).

   ![](https://files.readme.io/3d741695b6e7dbf01a267e14f57d29e9d3d0c0303ece9a23d9c4ba7e6fe2cd3a-CleanShot_2025-02-05_at_12.17.08.png)
2. **Disambiguation.** When the AI agent finds multiple possible matches, it presents them (with [citations](/tool-studio/plugins/citations)) so the user can pick the right one.

   ![](https://files.readme.io/b760cb0254cda14f5fadf33ea042da84213e6e7dad75264af606eff348d1d096-CleanShot_2024-10-24_at_18.29.322x.png)
3. **Stable memory.** Slot resolvers use a symbolic working memory to track both the list of possible values and the selected value, so the AI agent won't change an ID or make up a new one when it passes the value to your actions.

[Plugins](/tool-studio/core-concepts/conversational-plugins) built with slot resolvers perform substantially better in production. [Why Plugins](/tool-studio/why-plugins) shows where slot resolvers fit alongside Policy Validators and the Action Orchestrator.

> **Info**
>
> Looking for a complete worked example? [Quickstart #2: Slots & Resolvers](/tool-studio/quickstart-guide/quickstart-2-slots-resolvers-copy) walks through building a `feature_request` Data Type with a dynamic resolver end-to-end, including the HTTP action, the resolver configuration, output mapping, cardinality, and using the resolved object in a conversation process.

# One Strategy, One Data Type

Each resolver strategy produces one [data type](/tool-studio/core-concepts/data-types). For example, if I have a resolver strategy that is bound to the `JiraIssue` data type, then it can **NOT** also return an `AsanaTask`

# Methods

Resolver strategies are made up of multiple “methods.” Each method provides a list of possible values that matches the data type.

> **Resolver Strategy Limitation**
>
> A Resolver Strategy can only have **1 Static Method** or **multiple Dynamic Methods**.
>
> It is not possible to have multiple Static Methods or a mix of Static & Dynamic Methods. If this something you think you need, reach out to your CSE or [support@moveworks.ai](mailto:support@moveworks.ai)!

## Type of Methods

You can build two types of methods:

1. **Static methods** - preconfigure a multiple choice list of possible values.
   For example, if you're changing the status of a `JiraIssue`, you might specify a few status options
   * Not Started (`id=4`)
   * In Progress (`id=8`)
   * Done (`id=10`)
     The AI agent will offer these options as part of [how slot resolvers work](#how-slot-resolvers-work).
2. **Dynamic methods** - use an action to retrieve possible values.
   For example, if you're trying to get a list of `JiraIssue` records that are assigned to the user, you can fetch them from the Jira Issues API and offer them to the user. You can send data from your
   > 🚧 Warning
   >
   > You can not currently use **compound actions**, but other action types are valid.

> **Warning**
>
> Dynamic resolver methods do not support pagination. The action must return the complete list of candidates in a single response. If your source system returns large datasets, apply filtering at the HTTP action level (query parameters, request body filters) before the data reaches the resolver.

## Output Cardinality

For a given resolver, the action, after output mappings are applied, should return an instance of your data type.

For example, a resolver strategy for `JiraIssue`  might return

* **A single`JiraIssue` record** - for example, if the user specified the issue by it's ID (e.g. "I want to close BUG-732"), then you can return the content as
  ```json
  {
    "id": "BUG-732",
    "title": "Set HTTP Status code correctly on custom REST API",
    ...
  }
  ```

If you always retrieve a single object in your output and want the entire object select the below setting: **Interpret output as the exact value**.

![](https://files.readme.io/b164c96b08eb83f26db4a384bef6c7e6594e4da5002a4a54501e794f8242bc3d-Screenshot_2025-10-08_at_1.09.33_PM.png)

\


* **A list of`JiraIssue` records**, for example, if the user said "Show me my tasks," you would return a list of records. (Note: you can return 0, or 1 records, but it must be a list).
  ```json
  [
    {
      "id": "BUG-732",
      "title": "Set HTTP Status code correctly on custom REST API",
      ...
    },
    {
      "id": "BUG-733",
      "title": "Envelope response under 'data' keyword",
      ...
    },
    ...
  ]
  ```

If you always retrieve a list in your output and want the user to make a selection from the list choose the below setting:**Interpret output as a list of candidate values**.

![](https://files.readme.io/189ba591877ef0425ae1fb3d21f14fdc988af0f6c48ef3c7436964f1140c56c8-Screenshot_2025-10-08_at_1.09.27_PM.png)

## Method Selection

During the conversation, the AI agent picks the best method to use based on the conversation. For example, if you the following methods

* Get `JiraIssue` by ID
* Get `JiraIssue` assigned to user
* Get `JiraIssue` by status & project

Then the AI agent will choose the right method based on the conversation

| Example Utterance                                                                                  | Resolver Strategy Method Selected   |
| :------------------------------------------------------------------------------------------------- | :---------------------------------- |
| "Can you please update the due date of BUG-732 to next week"                                       | Get `JiraIssue` by ID               |
| "I need to update the due date of my tasks"                                                        | Get `JiraIssue` assigned to user    |
| "I'm preparing for a stand-up. Can we update the due date of in progress tasks for Project Orion?" | Get `JiraIssue` by status & project |

# How do I configure Resolver Strategies?

## Where to Configure Resolvers

You can attach resolver strategies in two places:

### On a Data Type (recommended for reuse)

Configure the resolver strategy directly on a [custom data type](/tool-studio/core-concepts/data-types). Every slot that uses that data type automatically inherits the resolver. This is ideal when multiple plugins need to resolve the same business object (e.g., a `JiraIssue` or `SalesforceAccount`).

A single data type can have **multiple resolver strategies** — for example, a `JiraIssue` type might have:

* "Search by issue key" (user says "BUG-732")
* "Search by title" (user says "the login bug")
* "Search by assignee" (user says "my open tickets")

The AI agent selects the best method based on conversation context.

### Inline on a Slot

Configure the resolver strategy directly on a specific [slot](/tool-studio/conversation-process/slots). This is useful for one-off resolvers that are specific to a single plugin and don't need to be reused.

### Which should I use?

| Scenario                                                            | Recommended Location |
| ------------------------------------------------------------------- | -------------------- |
| Business object used across multiple plugins                        | Data type            |
| One-off lookup specific to a single plugin                          | Inline on the slot   |
| Need to override a data type's default resolver for a specific slot | Inline on the slot   |

> **Info**
>
> If a slot has an inline resolver AND its data type has a resolver, the **inline resolver takes precedence** for that slot.

## Resolver Basic Info

![](https://files.readme.io/ce78092350fed79ca1dc68bfdcd357a5c57b447816c6f1556d6315f22ef5d698-CleanShot_2025-04-09_at_04.35.582x.png)

It's important to provide a detailed **Method Name** as this helps the AI Assistant choose which Method is best for each conversation with the user. The Method Name must be in snake_case format.

## Configuring a Static Resolver

Static Resolvers allow you to configure a list of options to show the user every time. Each option has a **Display Value** (what the end user will see) and a **Raw Value** (what will be used in your Activities).

![](https://files.readme.io/a7985bae1fa22f39993c35b8e24ecfd02db8a30f03ee18a827621602a138d351-CleanShot_2025-04-09_at_04.38.502x.png)

## Configuring a Dynamic Resolver

Dynamic Resolvers require you to select an Action in order to dynamically lookup slot values.

### Setting

![](https://files.readme.io/ad92efce386ddf6e770d815ac0e418ca5949083b4458fd1da5b6ecc9d081f285-CleanShot_2025-04-09_at_04.43.322x.png)

### Selecting an Action

It's recommended to only use HTTP Actions for Dynamic Resolvers; Compound Actions are currently not supported. Script and Built-in actions are also available but HTTP Actions are preferred.

### Input Arguments & Input Mapping

![](https://files.readme.io/d1c89e217d5176508cf07c92a045b107aefc1583994caf88ba5086cc4fa1807d-CleanShot_2025-04-07_at_16.06.512x.png)

You can configure input arguments for your resolver method using a JSON schema. Inputs are added to the [resolver method's data bank](/tool-studio/conversation-process/resolver-strategies#datainput_arg). For example, the following schema would provide a single `feature_request_id` string as `data.feature_request_id`. These will be collected from the user whenever the resolver slot is collected.

The names of these are important as that is how the reasoning engine infers what it is collecting from the user similarly to slots in a conversational process.  **Do not** create additional slots in your conversational process for resolvers input variables, treat the input variables as if they are slots contained within the resolver itself.

```json
{
  "type": "object",
  "properties": {
    "feature_request_id": {
      "type": "string"
    },
    "feature_request_name":{
      "type": "string"
    }
  }
}
```

Learn more about how to write JSON schemas at the [official JSON schema docs](https://json-schema.org/learn/getting-started-step-by-step).

### Context Passing into Dynamic Resolvers

A dynamic resolver cannot read the conversation process data bank. To use a value from an earlier slot or activity, pass it through two mappings:

1. On the slot, use **Strategy Mapping** to copy the process value into the resolver:

   ```yaml
   building_sys_ids: data.eligible_building_sys_ids
   ```

   This creates `data.building_sys_ids` inside the resolver.

2. In the resolver method, use **Input Mapping** to pass the local value to the action argument:

   ```yaml
   building_sys_ids: data.building_sys_ids
   ```

> **Warning**
>
> The source slot must be collected or the source activity must finish before the resolver runs. Otherwise, Strategy Mapping passes a null or empty value.

Do not add a context-passed key to the resolver's **Input Variables**. Input Variables are for values the assistant should collect or infer while resolving the slot.

Follow the [Strategy Mapping walkthrough](/tool-studio/guides/getting-started/pass-data-to-dynamic-resolvers-with-strategy-mapping) for the complete building example, screenshots, testing steps, and troubleshooting.

### Output Mapping

This represents the output structure of your resolver method. By default, it will capture all of the data that the action you selected returns. However, you can "dot walk" into the object if you want to limit the data returned.

The output value from the http action in the resolver is stored as `response` when referencing it in the output mapper

Clicking "Switch to data mapper" will take you to a [Data Mapper](/api-reference/configuration-languages/moveworks-bender-language-reference#overview) editor where you have more controls to fully define a custom output object.

> **Error**
>
> Note: the output mapper must always point to an array if the output cardinality is set to **interpret as a list of candidate values**. This is how we build the list of option the user can select from
>
> For example given an action with an output like
>
> ```json
> {
>   "hasErrors": false,
>   "results": [
>     {
>       "referenceId": "ref1",
>       "id": "0015g00000N1ABC",
>       "success": true,
>       "errors": [],
>       "fields": {
>         "Name": "Acme Corporation",
>         "Industry": "Technology",
>         "BillingCity": "San Francisco",
>         "Phone": "+1-415-555-1234",
>         "Website": "https://www.acme.com"
>       }
>     },
>     {
>       "referenceId": "ref2",
>       "id": "0035g00000M9XYZ",
>       "success": true,
>       "errors": [],
>       "fields": {
>         "FirstName": "John",
>         "LastName": "Doe",
>         "Title": "CTO",
>         "Email": "john.doe@example.com",
>         "Phone": "+1-415-555-1111"
>       }
>     }
>   ]
> }
> ```

**The output mapping would be `response.results`**

![](https://files.readme.io/f24144b948aac1c150ba128afeb9db347ff96ba6337707c87659caeaec744253-396a7ceb38d533e11227771d519f4b626fa7c77b35dfdf87c3e93ea39b19936a-Screenshot_2025-09-25_at_4.08.53_PM_1.png)

### Output Cardinality

See the [Output Cardinality reference](/tool-studio/conversation-process/resolver-strategies#output-cardinality) for guidance on which option to choose.

![](https://files.readme.io/2b88781ca1e18239d52e294acee239a51f011095414204730577ca03b2552143-CleanShot_2025-04-09_at_04.51.242x.png)

# Data Bank Inside Of Dynamic Resolvers

## `data.<input_arg>`

Resolver methods reference local inputs as `data.<input_arg>`. Input Variables add values the assistant collects or infers. [Strategy Mapping](/tool-studio/guides/getting-started/pass-data-to-dynamic-resolvers-with-strategy-mapping) adds values from the conversation process.

## `meta_info.user`

You can reference user attributes about the current user (ie. the user that triggered the plugin) with the notation `meta_info.user`

See [User Attributes Reference](/platform-management/user-identity/user-attribute-reference) for examples.

# How To Reference The Output Of Resolvers

### Static Resolvers

Once the user selects one of the presented static options you can reference the output in the conversational process in 2 ways.

To reference the **display value** of the user's static resolver choice use:

`data.<slot_name>.display_name`

To reference the **raw value** of the user's static resolver choice use:

`data.<slot_name>.value`

### Dynamic Resolvers

Once the user selects one of the presented dynamic options, the **entire object** is bound to the slot. Reference it directly — there is no `.value.` indirection like there is on static resolvers.

To reference the **whole selected object**:

`data.<slot_name>`

To reference a **field on the selected object**:

`data.<slot_name>.<field_name>`

For example, given a slot named `feature_request` resolved by a dynamic resolver whose action returns objects with `id`, `name`, and `current_status` fields:

| Reference                             | Returns                         |
| ------------------------------------- | ------------------------------- |
| `data.feature_request`                | The full feature request object |
| `data.feature_request.id`             | `"FR-12345"`                    |
| `data.feature_request.name`           | `"Add Dark Mode"`               |
| `data.feature_request.current_status` | `"New"`                         |

> **Warning**
>
> Do not write `data.feature_request.value.current_status` for dynamic resolvers — that pattern only applies to **static** resolvers (see above). On a dynamic resolver, fields hang directly off the slot name.

For how resolver strategies fit into slot configuration, see [Slots](/tool-studio/conversation-process/slots).

For a complete end-to-end walkthrough — creating a custom Data Type, configuring a dynamic resolver against an HTTP action, mapping the output, and using the resolved object in a conversation process — see [Quickstart #2: Slots & Resolvers](/tool-studio/quickstart-guide/quickstart-2-slots-resolvers-copy).