[VS Code] GitLab Duo doesn't work when using GITLAB_WORKFLOW_TOKEN variable to provide authentication

Checklist

Summary

Duo chat doesn't work when providing authentication credentials via the GITLAB_WORKFLOW_TOKEN_FILE and the GITLAB_WORKFLOW_INSTANCE_URL environment variables.

Steps to reproduce

  1. Create a Personal Access Token (PAT) with api, read_api, and ai_features permissions.
  2. Save an access token a Personal Access Token in a file with path /Users/[user]/.gitlab_workflow_pat.
  3. Set a global GITLAB_WORKFLOW_TOKEN_FILE variable to the path from the previous step.
  4. Set a global GITLAB_WORKFLOW_INSTANCE_URL variable to the GitLab instance of your choice.
  5. Remove all your registered accounts from the GitLab Workflow extension. In this way, the extension will use an account based on the token file.
  6. Try using Duo Chat. You will notice that a response is never received.

What is the current bug behavior?

Duo Chat never responds to a prompt and it stays in a permanent waiting status.

What is the expected correct behavior?

I'd expect two behaviors:

  1. Duo Chat works correctly when providing access credentials via environment variables.
  2. If the authentication/authorization fails, Duo Chat should report this problem rather than staying in a permanent loading state.

Relevant logs and/or screenshots

bug_demo.mov

Possible fixes

We are extracting a GQLID from the the registered account in gitlab_chat_api.ts. For an account based on environment variables, the account id is not valid. We should probably fetch the user iD via an API call when the account is based on environment variables.

I debugged the underlying Web Socket that receives GraphQL responses, and I noticed that at some point, the backend sends the following response:

'{"identifier":"{\\"channel\\":\\"GraphqlChannel\\",\\"operationName\\":\\"aiCompletionResponse\\",\\"query\\":\\"\\\\n  subscription aiCompletionResponse(\\\\n    $userId: UserID\\\\n    $clientSubscriptionId: String\\\\n    $aiAction: AiAction\\\\n    $htmlResponse: Boolean = true\\\\n  ) {\\\\n    aiCompletionResponse(\\\\n      userId: $userId\\\\n      aiAction: $aiAction\\\\n      clientSubscriptionId: $clientSubscriptionId\\\\n    ) {\\\\n      id\\\\n      requestId\\\\n      content\\\\n      contentHtml @include(if: $htmlResponse)\\\\n      errors\\\\n      role\\\\n      timestamp\\\\n      type\\\\n      chunkId\\\\n      extras {\\\\n        sources\\\\n        additionalContext {\\\\n          id\\\\n          category\\\\n          metadata\\\\n        }\\\\n      }\\\\n    }\\\\n  }\\\\n\\",\\"variables\\":\\"{\\\\\\"htmlResponse\\\\\\":false,\\\\\\"userId\\\\\\":\\\\\\"gid://gitlab/User/environment-variables\\\\\\",\\\\\\"aiAction\\\\\\":\\\\\\"CHAT\\\\\\",\\\\\\"clientSubscriptionId\\\\\\":\\\\\\"c6ff6cbe-13d6-465e-a0c1-613f64ed1820\\\\\\"}\\"}","message":{"result":{"errors":[{"message":"Unauthorized subscription","locations":[{"line":8,"column":5}],"path":["aiCompletionResponse"]}],"data":{"aiCompletionResponse":null}},"more":true}}'

At the end of the code snippet above, you can see that the API returns an error response, but Duo Chat is not handling this error response. You can catch this response by setting a breakpoint in node_modules/@anycable/core/websocket/index.js#115. We should also handle these error responses.

Edited by Kisha Mavryck Richardson