Extend copilot with custom content sources

Copilot for Service provides out-of-the-box support to have copilot generate real-time responses from websites, SharePoint, offline files, and third-party knowledge bases. However, your business may use other third-party or proprietary knowledge bases that aren't supported out of the box. You can add those knowledge sources to your copilot by extending it in Microsoft Copilot Studio.

Adding custom content sources in Copilot Studio

To add custom content sources, you need to add a new topic in Microsoft Copilot Studio that uses the Fallback trigger. Complete the following steps:

  1. Launch Extend with Microsoft Copilot Studio from the left nav.
  2. Navigate to Topics from Copilot Studio's left nav.
  3. Select Add and Topic > from blank.
  4. Select Open code editor from the ellipsis on the top-right menu.
  5. Copy and paste the following YAML code into the topic.
kind: AdaptiveDialog
beginDialog:
  kind: OnUnknownIntent
  id: main
  priority: -7
  actions:
    - kind: HttpRequestAction
      id: nXJfks
      method: Post
      url: https://cheetah-facts.me/rest-api-examples/
      body:
        kind: JsonRequestContent
        content: "={query: System.Activity.Text}"

      errorHandling:
        kind: ContinueOnErrorBehavior
        statusCode: Topic.StatusCode
        errorResponseBody: Topic.ErrorResponse

      response: Topic.ServiceResponse
      responseSchema:
        kind: Record
        properties:
          results:
            type:
              kind: Table
              properties:
                dataSource: String
                ID: Number
                link: String
                text: String
                title: String

    - kind: ConditionGroup
      id: lk8b4S
      conditions:
        - id: zTRi0k
          condition: =Topic.StatusCode >= 300
          actions:
            - kind: ParseValue
              id: wqVAK5
              variable: Topic.ParsedError
              valueType:
                kind: Record
                properties:
                  error:
                    type:
                      kind: Record
                      properties:
                        detail: Blank
                        message: String

                  status: String

              value: =Topic.ErrorResponse

            - kind: ConditionGroup
              id: jwQV1G
              conditions:
                - id: ssVMlZ
                  condition: =Topic.ParsedError.error.message = "Requested URI does not represent any resource"
                  actions:
                    - kind: SetVariable
                      id: setVariable_7w8AeR
                      variable: Topic.ErrorCode
                      value: ServiceNotAccessible

                    - kind: SetVariable
                      id: setVariable_ZSqujW
                      variable: Topic.ErrorMessage
                      value: The Service is not accessible

                - id: S6SU02
                  condition: =Topic.StatusCode = 502
                  actions:
                    - kind: SetVariable
                      id: H2xDBa
                      variable: Topic.ErrorCode
                      value: ServerError

                    - kind: SetVariable
                      id: uyFvpV
                      variable: Topic.ErrorMessage
                      value: Unable to search knowledge articles from rest service

              elseActions:
                - kind: SetVariable
                  id: Vke6RY
                  variable: Topic.ErrorCode
                  value: GenericServiceError

                - kind: SetVariable
                  id: setVariable_pQ40KX
                  variable: Topic.ErrorMessage
                  value: =$"The REST service returned status code {Topic.StatusCode} with error message '{Topic.ParsedError.error.message}'"

            - kind: BeginDialog
              id: OiJHUY
              input:
                binding:
                  Details: "=$\"Status code: {Topic.StatusCode}, message: {Topic.ParsedError.error.message}\""
                  ErrorCode: =Topic.ErrorCode
                  ErrorText: =Topic.ErrorMessage
                  Title: Error accessing Service

              dialog: msdyn_AgentCopilot.topic.ShowError

            - kind: EndDialog
              id: prQKRD

      elseActions:
        - kind: BeginDialog
          id: Ahf09m
          input:
            binding:
              Answers: |-
                =ForAll(Topic.ServiceResponse.results As Article,
                  {
                    Content: Article.text,
                    Title: Article.title,
                    ContentLocation: Article.link,
                    SourceName: "CustomRestService"
                  }
                )

          dialog: msdyn_AgentCopilot.topic.AppendAnswers
          output: {}
  1. After you paste the topic, it should look like the following image:

Screenshot of custom content source sample

  1. Review the example HTTP call and the JSON schema for accepted format. Replace with a node to connect to your custom content source. It can be from Power Automate flow, connector or a direct HTTP response.

  2. Make sure your custom content source result matches the schema defined in the sample.

Screenshot of custom content source schema

  1. Review and update the error handling logic based on your system's status code.

  2. Test it by asking a question in the test chat that results in your custom content source returning results.