title: How to get Session Entities to work as part of Dialogflow detect intent
body: <p>I have an Entity that is supposed to be updated on a per-session basis with user-specific information. This had worked when I was using Dialogflow v1, and I thought it had worked with v2, but I'm now having significant problems with it.</p>
  
  <p>I believe I am setting the Session Entity information correctly, but for the Intent that uses it, it only matches when a value from the Developer Entity is used.</p>
  
  <p>How can I get it to use the Session Entity? Am I doing something wrong when updating it? Am I using the wrong Session ID? Is there a way I can better verify or test that I'm using the correct ID or that I'm updating the Entity correctly? Is this just a bug?</p>
  
  <p>Documentation of everything follows.</p>
  
  <p>The project is configured to use v2 and to allow for beta features, although I've tried this without the beta features as well.</p>
  
  <p><a href="https://i.stack.imgur.com/z9JQq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/z9JQq.png" alt="configuration"></a></p>
  
  <p>There are only three Intents. A Fallback Intent to capture failures, a Welcome Intent that gets the welcome event, and the "entry" intent that is supposed to capture the entry code which should match the "code" Entity. All of them use a webhook for fulfillment.
  <a href="https://i.stack.imgur.com/dun2e.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/dun2e.png" alt="intent list"></a></p>
  
  <p>The Fallback Intent
  <a href="https://i.stack.imgur.com/mPjGf.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/mPjGf.png" alt="fallback intent"></a></p>
  
  <p>The Welcome Intent
  <a href="https://i.stack.imgur.com/05CZG.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/05CZG.png" alt="welcome intent"></a></p>
  
  <p>The "entry" Intent
  <a href="https://i.stack.imgur.com/T73wR.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/T73wR.png" alt="entry intent"></a></p>
  
  <p>As shown in the "entry" Intent, it uses the "code" Entity, which is the only Developer Entity in the system</p>
  
  <p><a href="https://i.stack.imgur.com/SQqKY.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/SQqKY.png" alt="code entity"></a></p>
  
  <p>The code has most of the Dialogflow specific work in a separate module that uses the <a href="https://www.npmjs.com/package/dialogflow" rel="nofollow noreferrer">"dialogflow" module from npm</a> to set the Session Entity. (Note this is different than the dialogflow-fulfillment module, which is used to handle fulfillment. I'm using the multivocal library for fulfillment, but that shouldn't matter.) (It also uses firebase functions to run on, but I don't think any of these are relevant.)</p>
  
  <p>From the package.json:</p>
  
  <pre><code>  "dependencies": {
      "dialogflow": "^0.9.0",
      "firebase-admin": "~7.0.0",
      "firebase-functions": "^2.2.0",
      "multivocal": "^0.11.1"
    },
  </code></pre>
  
  <p>This is imported as <code>dialogflow</code>, specifying the API version to use:</p>
  
  <pre><code>const dialogflow = require('dialogflow').v2beta1;
  </code></pre>
  
  <p>The functions I show below call <code>envToConfig(env)</code> which takes the environment (a multivocal concept that just stores relevant information, including the Dialogflow <code>parent</code> and certificate information) and returns the configuration that needs to be passed to <code>dialogflow.SessionEntityTypesClient( config )</code>. Given no errors are thrown in further calls, it appears to work correctly.</p>
  
  <p>The <code>makeEntityType( name, entityMap )</code> function takes a map of values to be used for the <code>entities</code> in a <a href="https://cloud.google.com/dialogflow-enterprise/docs/reference/rest/v2beta1/projects.agent.environments.users.sessions.entityTypes#resource-sessionentitytype" rel="nofollow noreferrer">SessionEntityType</a> and returns an object that will be used to build a full SessionEntityType. The <code>name</code> provided here is the display name.</p>
  
  <pre><code>function makeEntityType( name, entityMap ){
    let ret = {
      displayName: name,
      entities: []
    };
  
    Object.keys( entityMap ).map( key =&gt; {
      let val = entityMap[key];
      let entity = {
        value: key,
        synonyms: [key, ...val]
      };
      ret.entities.push( entity );
    });
  
    return ret;
  }
  exports.makeEntityType = makeEntityType;
  </code></pre>
  
  <p>The result from this is passed to <code>setSessionEntity( env, entityType )</code> along with the multivocal environment, which contains some information we use in the session. It makes sure the <code>name</code> and <code>entityOverrideMode</code> are set correctly in the <code>entityType</code> and then tries to create it. I've tried using PATCH as well, and it behaves the same way. It also does a bunch of logging, that I'll show later when it runs to prove it actually works.</p>
  
  <pre><code>function setSessionEntity( env, entityType ){
    const config = envToConfig( env );
    const client = new dialogflow.SessionEntityTypesClient( config );
  
    let parent = env.dialogflow.parent;
    if( entityType.displayName &amp;&amp; !entityType.name ){
      entityType.name = `${parent}/entityTypes/${entityType.displayName}`;
    }
    if( !entityType.entityOverrideMode ){
      entityType.entityOverrideMode = 'ENTITY_OVERRIDE_MODE_OVERRIDE';
    }
  
    console.log('setSessionEntity parent',parent);
    const request = {
      parent: parent,
      sessionEntityType: entityType
    };
    console.log('setSessionEntity request',JSON.stringify(request,null,1));
    return client.createSessionEntityType( request )
      .then( create =&gt; {
        console.log('setSessionEntity created',JSON.stringify(create,null,1));
        return Promise.resolve( env );
      })
      .catch( err =&gt; {
        console.error('setSessionEntity problem creating',err);
        return Promise.resolve( env );
      })
  }
  exports.setSessionEntity = setSessionEntity;
  </code></pre>
  
  <p>For debugging, I also have a function that lists the session entities:</p>
  
  <pre><code>function listSessionEntities( env ){
    let parent = env.dialogflow &amp;&amp; env.dialogflow.parent;
    console.log('listSessionEntities parent', parent);
    if( !parent ){
      return Promise.resolve( env );
    }
  
    const config = envToConfig( env );
    const client = new dialogflow.SessionEntityTypesClient( config );
    const request = {
      parent: parent
    };
    return client.listSessionEntityTypes(request)
      .then( result =&gt; {
        console.log('listSessionEntities', JSON.stringify(result,null,1));
      })
      .catch( err =&gt; {
        console.log('listSessionEntities err', err);
      })
      .then( () =&gt; Promise.resolve( env ) );
  }
  exports.listSessionEntities = listSessionEntities;
  </code></pre>
  
  <p>The code that calls this imports it as <code>Dialogflow</code>:</p>
  
  <pre><code>const Dialogflow = require('./dialogflow');
  </code></pre>
  
  <p>As part of all the webhook calls, the <code>listSessionEntities()</code> function is called before any specific handler is:</p>
  
  <pre><code>function debugSessionEntities( env ){
    return Dialogflow.listSessionEntities( env );
  }
  </code></pre>
  
  <p>When the Welcome Intent is triggered, it sets the "code" Session Entity to have two new types that should override the type that was defined in the "code" Developer Entity:</p>
  
  <pre><code>function handleWelcome( env ){
    const entityType = Dialogflow.makeEntityType('code',{
      'alpha': [],
      'bravo': []
    });
    return Dialogflow.setSessionEntity( env, entityType )
      .then( env =&gt; Multivocal.handleDefault( env ) );
  }
  </code></pre>
  
  <p>When I run this through the simulator, it doesn't pick up on the Session Entity Types that are set, but do still respond to the Developer Entity Type. (Using a real device works the same way.)</p>
  
  <p><a href="https://i.stack.imgur.com/blOiB.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/blOiB.png" alt="simulator conversation"></a></p>
  
  <p>In the simulator, this is what it reports in the Request tab for the Welcome Intent:</p>
  
  <pre><code>{
    "responseId": "55a9eb06-ce05-48f9-8a56-b993fa512aee",
    "queryResult": {
      "queryText": "GOOGLE_ASSISTANT_WELCOME",
      "action": "multivocal.welcome",
      "parameters": {},
      "allRequiredParamsPresent": true,
      "fulfillmentText": "Hello! How can I help you?",
      "fulfillmentMessages": [
        {
          "text": {
            "text": [
              "Greetings! How can I assist?"
            ]
          }
        }
      ],
      "outputContexts": [
        {
          "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/google_assistant_welcome"
        },
        {
          "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_screen_output"
        },
        {
          "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_audio_output"
        },
        {
          "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_account_linking"
        },
        {
          "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/google_assistant_input_type_keyboard"
        },
        {
          "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_media_response_audio"
        },
        {
          "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_web_browser"
        }
      ],
      "intent": {
        "name": "projects/session-test-XXXXX/agent/intents/ca79c951-4d75-4b2b-acd4-7dac2f81856e",
        "displayName": "welcome"
      },
      "intentDetectionConfidence": 1,
      "languageCode": "en-us"
    },
    "originalDetectIntentRequest": {
      "source": "google",
      "version": "2",
      "payload": {
        "isInSandbox": true,
        "surface": {
          "capabilities": [
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.ACCOUNT_LINKING"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        },
        "requestType": "SIMULATOR",
        "inputs": [
          {
            "rawInputs": [
              {
                "query": "Talk to my test app",
                "inputType": "KEYBOARD"
              }
            ],
            "intent": "actions.intent.MAIN"
          }
        ],
        "user": {
          "userStorage": "{\"UserId\":\"ABwppHHd40lIZ1o0bRERAKlHNtNcS2qFtz7NbRQnb31AQDFuV41VPFQivXwwpQGtv_5SlsZNp0N3kxalIIXXXXXX\",\"NumVisits\":1}",
          "lastSeen": "2019-05-18T19:12:38Z",
          "locale": "en-US",
          "userId": "ABwppHHd40lIZ1o0bRERAKlHNtNcS2qFtz7NbRQnb31AQDFuV41VPFQivXwwpQGtv_5SlsZNp0N3kxalIIXXXXXX"
        },
        "conversation": {
          "conversationId": "ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX",
          "type": "NEW"
        },
        "availableSurfaces": [
          {
            "capabilities": [
              {
                "name": "actions.capability.AUDIO_OUTPUT"
              },
              {
                "name": "actions.capability.WEB_BROWSER"
              },
              {
                "name": "actions.capability.SCREEN_OUTPUT"
              }
            ]
          }
        ]
      }
    },
    "session": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX"
  }
  </code></pre>
  
  <p>Most notable from that is the <code>session</code> attribute set at the bottom from that. The code uses this as the <code>parent</code> and <code>session</code> values when building the </p>
  
  <p>The request objects for the other two Intents are similar, and all have the same value for <code>session</code>. None of the response objects are notable in any way.</p>
  
  <p>When the Welcome Intent is triggered, the call to <code>listSessionEntities()</code>, unsurprisingly, shows there aren't any yet:</p>
  
  <pre><code>info: listSessionEntities parent projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX
  info: listSessionEntities [
   [],
   null,
   null
  ]
  </code></pre>
  
  <p>The <code>parent</code> appears to have the correct value from the <code>session</code> however.</p>
  
  <p>When the handler for the Welcome Intent goes and creates the Session Entity, things appear to work ok:</p>
  
  <pre><code>info: setSessionEntity request {
   "parent": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX",
   "sessionEntityType": {
    "displayName": "code",
    "entities": [
     {
      "value": "alpha",
      "synonyms": [
       "alpha"
      ]
     },
     {
      "value": "bravo",
      "synonyms": [
       "bravo"
      ]
     }
    ],
    "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/entityTypes/code",
    "entityOverrideMode": "ENTITY_OVERRIDE_MODE_OVERRIDE"
   }
  }
  info: setSessionEntity created [
   {
    "entities": [
     {
      "synonyms": [
       "alpha"
      ],
      "value": "alpha"
     },
     {
      "synonyms": [
       "bravo"
      ],
      "value": "bravo"
     }
    ],
    "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/entityTypes/code",
    "entityOverrideMode": "ENTITY_OVERRIDE_MODE_OVERRIDE"
   },
   null,
   null
  ]
  </code></pre>
  
  <p>The <code>parent</code> appears to be the same as the <code>session</code>, and the <code>name</code> appears to follow the correct format, including the additional part that has the "/entityTypes/" followed by the display name.</p>
  
  <p>When I try calling it with the code "alpha", which should trigger the "entry" Intent, it instead triggers the Fallback Intent. The call to <code>listSessionEntities()</code> seems to show the "code" Entity with the Entity Types we expect, even tho there was no match for "alpha".</p>
  
  <pre><code>info: listSessionEntities parent projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX
  info: listSessionEntities [
   [
    {
     "entities": [
      {
       "synonyms": [
        "alpha"
       ],
       "value": "alpha"
      },
      {
       "synonyms": [
        "bravo"
       ],
       "value": "bravo"
      }
     ],
     "name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/entityTypes/code",
     "entityOverrideMode": "ENTITY_OVERRIDE_MODE_OVERRIDE"
    }
   ],
   null,
   null
  ]
  </code></pre>
  
  <p>Again, everything looks correct. When I try it again with "zulu", it shows the same thing for the call to <code>listSessionEntites()</code>, but this time it matches the "entry" Intent, since "zulu" is one of the Entity Types for "code" that is defined as a Developer Entity.</p>
  
  <p>This is where I am stuck. Everything <em>looks</em> correct. It looks like the Session Entity should be set correctly <strong>for this session</strong>. It looks like it should be using those values. But it never seems to do so.</p>
  
  <p>What is going on? All help would be <em>greatly</em> appreciated. (Did you even read till the end of the question? If so - thank you! I know it's long, but wanted to be as complete as possible.)</p>