Skip to content

[#923] OTel improvements: Instrument copilotstudio-client#1018

Open
ceciliaavila wants to merge 4 commits intosouthworks/feature/otelfrom
southworks/add/copilotstudio-client-otel
Open

[#923] OTel improvements: Instrument copilotstudio-client#1018
ceciliaavila wants to merge 4 commits intosouthworks/feature/otelfrom
southworks/add/copilotstudio-client-otel

Conversation

@ceciliaavila
Copy link
Copy Markdown
Collaborator

@ceciliaavila ceciliaavila commented Mar 27, 2026

Addresses #923

Description

Adds OpenTelemetry tracing/metrics instrumentation for @microsoft/agents-copilotstudio-client and extends @microsoft/agents-telemetry to support manually managed spans for long-lived/streaming operations.

Detailed Changes:

  • Introduces managedSpan (manual span lifecycle) in agents-telemetry and exports related types.
  • Adds Copilot Studio Client span/metric constants and wires new metrics/tracing into client + webchat flows.
  • Updates copilotstudio-client browser build target and dependencies to support the new telemetry integration.

Testing

These images show the traces, events, and metrics exported from the library.
image
image
image
image

Copilot AI review requested due to automatic review settings March 27, 2026 19:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds OpenTelemetry tracing/metrics instrumentation for @microsoft/agents-copilotstudio-client by extending @microsoft/agents-telemetry with a manually-managed span helper and introducing new Copilot Studio span/metric names.

Changes:

  • Added managedSpan support in agents-telemetry for long-lived operations that can’t use startActiveSpan callbacks (e.g., async generators/streaming).
  • Added new Copilot Studio Client span + metric constants and client-side instrumentation (request, streaming, webchat connection).
  • Introduced a Copilot Studio Client metrics module and wired telemetry dependency into the client package.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/agents-telemetry/src/trace.ts Adds startManagedSpan helper and managed span types.
packages/agents-telemetry/src/index.mts Exports managedSpan and managed span types (ESM).
packages/agents-telemetry/src/index.cts Exports managedSpan and managed span types (CJS).
packages/agents-telemetry/src/constants.ts Adds Copilot Studio Client span and metric names.
packages/agents-copilotstudio-client/src/observability/metrics.ts Defines Copilot Studio Client meters/counters/histograms.
packages/agents-copilotstudio-client/src/observability/index.ts Re-exports observability helpers.
packages/agents-copilotstudio-client/src/copilotStudioWebChat.ts Adds connection-level managed span + webchat metrics/events.
packages/agents-copilotstudio-client/src/copilotStudioClient.ts Adds managed spans + request/streaming metrics instrumentation.
packages/agents-copilotstudio-client/package.json Adds @microsoft/agents-telemetry dependency and updates browser build target.
package-lock.json Locks the new dependency.
Comments suppressed due to low confidence (1)

packages/agents-copilotstudio-client/src/copilotStudioWebChat.ts:319

  • The connection-level managed span is only ended in the explicit end() method. If startConversationStreaming() throws inside activity$, or if a consumer unsubscribes / the observable errors, the span can remain open. Consider adding teardown/error handling so the span ends on observable completion/error/unsubscribe (and use endWithError when appropriate).
    const managed = managedSpan(SpanNames.COPILOT_CREATE_CONNECTION, {
      attributes: {
        'copilot.webchat.show_typing': settings?.showTyping ?? 'unknown'
      }
    })

    const connectionStatus$ = new BehaviorSubject(0)
    const activity$ = createObservable<Partial<Activity>>(async (subscriber) => {
      activitySubscriber = subscriber

      const handleAcknowledgementOnce = once(async (): Promise<void> => {
        connectionStatus$.next(2)
        await Promise.resolve() // Webchat requires an extra tick to process the connection status change
      })

      // When resuming (shouldStart === false), transition straight to connected
      if (!shouldStart || started) {
        await handleAcknowledgementOnce()
        return
      }
      started = true

      logger.debug('--> Connection established.')
      CopilotStudioClientMetrics.webchatConnectionsCounter.add(1)
      notifyTyping()

      for await (const activity of client.startConversationStreaming()) {
        delete activity.replyToId
        if (!conversation && activity.conversation) {
          conversation = activity.conversation
        }
        if (activity.conversation?.id) {
          activeConversationId = activity.conversation.id
        }
        await handleAcknowledgementOnce()
        notifyActivity(activity)
        managed.span.addEvent('Activity received from Copilot Studio', {
          'copilot.webchat.activity.type': activity.type,
          'copilot.webchat.activity.conversation_id': activity.conversation?.id ?? 'unknown'
        })
      }
      // If no activities received from bot, we should still acknowledge.
      await handleAcknowledgementOnce()
    })

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ceciliaavila ceciliaavila requested a review from benbrown March 27, 2026 21:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants