function instrumentStream({ agent, shim, request, response, segment, transaction, err = null }) {
  if (!agent.config.ai_monitoring.streaming.enabled) {
    shim.logger.warn(
      '`ai_monitoring.streaming.enabled` is set to `false`, stream will not be instrumented.'
    )
    agent.metrics.getOrCreateMetric(AI.STREAMING_DISABLED).incrementCallCount()
    return
  }

  if (err) {
    // If there is an error already e.g. APIConnectionError,
    // the iterator will not be called, so we have to
    // record the chat completion messages with the error now.
    segment.touch()
    recordChatCompletionMessages({
      agent,
      shim,
      segment,
      transaction,
      request,
      response,
      err
    })
    return
  }

  shim.wrap(response, 'iterator', function wrapIterator(shim, orig) {
    return async function * wrappedIterator() {
      let content = ''
      let role = ''
      let chunk
      try {
        const iterator = orig.apply(this, arguments)

        for await (chunk of iterator) {
          if (chunk.choices?.[0]?.delta?.role) {
            role = chunk.choices[0].delta.role
          }

          content += chunk.choices?.[0]?.delta?.content ?? ''
          yield chunk
        }
      } catch (streamErr) {
        err = streamErr
        throw err
      } finally {
        if (chunk?.choices) {
          chunk.choices[0].message = { role, content }
        } else if (chunk?.response) {
          chunk = chunk.response
        }

        // update segment duration since we want to extend the time it took to
        // handle the stream
        segment.touch()

        recordChatCompletionMessages({
          agent: shim.agent,
          shim,
          segment,
          transaction,
          request,
          response: chunk,
          err
        })
      }
    }
  })
}
`chat.completions.create` can return a stream once promise resolves.
This wraps the iterator which is a generator function.
We will call the original iterator, intercept chunks and yield
to the original. On complete, we will construct the new message object
with what we have seen in the stream and create the chat completion
messages.
@param {object} params input params
@param {Agent} params.agent NR agent instance
@param {Shim} params.shim the current shim instance
@param {object} params.request chat completion params
@param {object} params.response chat completion response
@param {TraceSegment} params.segment active segment from chat completion
@param {Transaction} params.transaction active transaction
@param {Error} params.err error if it exists